Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14d178a1 authored by Kevin Hilman's avatar Kevin Hilman Committed by Russell King
Browse files

[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: default avatarKevin Hilman <khilman@mvista.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 41762b8c
Loading
Loading
Loading
Loading
+39 −11
Original line number Diff line number Diff line
@@ -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--);

	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_err(&aaci->dev->dev,
			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;
}