mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
[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>
This commit is contained in:
parent
41762b8ca9
commit
14d178a143
1 changed files with 39 additions and 11 deletions
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue