[ARM] 4140/1: AACI stability add ac97 timeout and retries

Add timeouts to hardware read/write/probe functions in order
to avoid lockups on buggy/broken hardware.

Signed-off-by: Kevin Hilman <khilman@mvista.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index a032aee..5190d7a 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -65,10 +65,12 @@
  *  SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR
  *  register.
  */
-static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
+static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+			    unsigned short val)
 {
 	struct aaci *aaci = ac97->private_data;
 	u32 v;
+	int timeout = 5000;
 
 	if (ac97->num >= 4)
 		return;
@@ -89,7 +91,11 @@
 	 */
 	do {
 		v = readl(aaci->base + AACI_SLFR);
-	} while (v & (SLFR_1TXB|SLFR_2TXB));
+	} while ((v & (SLFR_1TXB|SLFR_2TXB)) && timeout--);
+
+	if (!timeout)
+		dev_err(&aaci->dev->dev,
+			"timeout waiting for write to complete\n");
 
 	mutex_unlock(&aaci->ac97_sem);
 }
@@ -101,6 +107,8 @@
 {
 	struct aaci *aaci = ac97->private_data;
 	u32 v;
+	int timeout = 5000;
+	int retries = 10;
 
 	if (ac97->num >= 4)
 		return ~0;
@@ -119,7 +127,13 @@
 	 */
 	do {
 		v = readl(aaci->base + AACI_SLFR);
-	} while (v & SLFR_1TXB);
+	} while ((v & SLFR_1TXB) && timeout--);
+
+	if (!timeout) {
+		dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
+		v = ~0;
+		goto out;
+	}
 
 	/*
 	 * Give the AC'97 codec more than enough time
@@ -130,21 +144,35 @@
 	/*
 	 * Wait for slot 2 to indicate data.
 	 */
+	timeout = 5000;
 	do {
 		cond_resched();
 		v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
-	} while (v != (SLFR_1RXV|SLFR_2RXV));
+	} while ((v != (SLFR_1RXV|SLFR_2RXV)) && timeout--);
 
-	v = readl(aaci->base + AACI_SL1RX) >> 12;
-	if (v == reg) {
-		v = readl(aaci->base + AACI_SL2RX) >> 4;
-	} else {
-		dev_err(&aaci->dev->dev,
-			"wrong ac97 register read back (%x != %x)\n",
-			v, reg);
+	if (!timeout) {
+		dev_err(&aaci->dev->dev, "timeout on RX valid\n");
 		v = ~0;
+		goto out;
 	}
 
+	do {
+		v = readl(aaci->base + AACI_SL1RX) >> 12;
+		if (v == reg) {
+			v = readl(aaci->base + AACI_SL2RX) >> 4;
+			break;
+		} else if (--retries) {
+			dev_warn(&aaci->dev->dev,
+				 "ac97 read back fail.  retry\n");
+			continue;
+		} else {
+			dev_warn(&aaci->dev->dev,
+				"wrong ac97 register read back (%x != %x)\n",
+				v, reg);
+			v = ~0;
+		}
+	} while (retries);
+ out:
 	mutex_unlock(&aaci->ac97_sem);
 	return v;
 }