[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
@ -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
|
* SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR
|
||||||
* register.
|
* 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;
|
struct aaci *aaci = ac97->private_data;
|
||||||
u32 v;
|
u32 v;
|
||||||
|
int timeout = 5000;
|
||||||
|
|
||||||
if (ac97->num >= 4)
|
if (ac97->num >= 4)
|
||||||
return;
|
return;
|
||||||
@ -89,7 +91,11 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned
|
|||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
v = readl(aaci->base + AACI_SLFR);
|
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);
|
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;
|
struct aaci *aaci = ac97->private_data;
|
||||||
u32 v;
|
u32 v;
|
||||||
|
int timeout = 5000;
|
||||||
|
int retries = 10;
|
||||||
|
|
||||||
if (ac97->num >= 4)
|
if (ac97->num >= 4)
|
||||||
return ~0;
|
return ~0;
|
||||||
@ -119,7 +127,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
|
|||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
v = readl(aaci->base + AACI_SLFR);
|
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
|
* 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.
|
* Wait for slot 2 to indicate data.
|
||||||
*/
|
*/
|
||||||
|
timeout = 5000;
|
||||||
do {
|
do {
|
||||||
cond_resched();
|
cond_resched();
|
||||||
v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
|
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 (!timeout) {
|
||||||
if (v == reg) {
|
dev_err(&aaci->dev->dev, "timeout on RX valid\n");
|
||||||
v = readl(aaci->base + AACI_SL2RX) >> 4;
|
|
||||||
} else {
|
|
||||||
dev_err(&aaci->dev->dev,
|
|
||||||
"wrong ac97 register read back (%x != %x)\n",
|
|
||||||
v, reg);
|
|
||||||
v = ~0;
|
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);
|
mutex_unlock(&aaci->ac97_sem);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user