From 14d178a143568f3651a40af6defadd44fb0b6b81 Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Wed, 7 Feb 2007 05:46:47 +0100 Subject: [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 Signed-off-by: Russell King --- sound/arm/aaci.c | 50 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 11 deletions(-) (limited to 'sound/arm') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index a032aee82adf..5190d7acdb9f 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -65,10 +65,12 @@ static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97) * 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 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned */ 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 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { struct aaci *aaci = ac97->private_data; u32 v; + int timeout = 5000; + int retries = 10; if (ac97->num >= 4) return ~0; @@ -119,7 +127,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) */ 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 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) /* * 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; } -- cgit v1.2.3