aboutsummaryrefslogtreecommitdiffstats
path: root/sound/arm
diff options
context:
space:
mode:
authorKevin Hilman <khilman@mvista.com>2007-02-06 23:46:47 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-02-18 05:59:50 -0500
commit14d178a143568f3651a40af6defadd44fb0b6b81 (patch)
tree491c7ad0258ac5852131d23815dbaf13d0ecaaa9 /sound/arm
parent41762b8ca9e16c7443d8348ec53daddbe940cdcc (diff)
[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>
Diffstat (limited to 'sound/arm')
-rw-r--r--sound/arm/aaci.c50
1 files changed, 39 insertions, 11 deletions
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)
65 * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR 65 * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR
66 * register. 66 * register.
67 */ 67 */
68static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) 68static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
69 unsigned short val)
69{ 70{
70 struct aaci *aaci = ac97->private_data; 71 struct aaci *aaci = ac97->private_data;
71 u32 v; 72 u32 v;
73 int timeout = 5000;
72 74
73 if (ac97->num >= 4) 75 if (ac97->num >= 4)
74 return; 76 return;
@@ -89,7 +91,11 @@ static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned
89 */ 91 */
90 do { 92 do {
91 v = readl(aaci->base + AACI_SLFR); 93 v = readl(aaci->base + AACI_SLFR);
92 } while (v & (SLFR_1TXB|SLFR_2TXB)); 94 } while ((v & (SLFR_1TXB|SLFR_2TXB)) && timeout--);
95
96 if (!timeout)
97 dev_err(&aaci->dev->dev,
98 "timeout waiting for write to complete\n");
93 99
94 mutex_unlock(&aaci->ac97_sem); 100 mutex_unlock(&aaci->ac97_sem);
95} 101}
@@ -101,6 +107,8 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
101{ 107{
102 struct aaci *aaci = ac97->private_data; 108 struct aaci *aaci = ac97->private_data;
103 u32 v; 109 u32 v;
110 int timeout = 5000;
111 int retries = 10;
104 112
105 if (ac97->num >= 4) 113 if (ac97->num >= 4)
106 return ~0; 114 return ~0;
@@ -119,7 +127,13 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
119 */ 127 */
120 do { 128 do {
121 v = readl(aaci->base + AACI_SLFR); 129 v = readl(aaci->base + AACI_SLFR);
122 } while (v & SLFR_1TXB); 130 } while ((v & SLFR_1TXB) && timeout--);
131
132 if (!timeout) {
133 dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
134 v = ~0;
135 goto out;
136 }
123 137
124 /* 138 /*
125 * Give the AC'97 codec more than enough time 139 * 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)
130 /* 144 /*
131 * Wait for slot 2 to indicate data. 145 * Wait for slot 2 to indicate data.
132 */ 146 */
147 timeout = 5000;
133 do { 148 do {
134 cond_resched(); 149 cond_resched();
135 v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); 150 v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
136 } while (v != (SLFR_1RXV|SLFR_2RXV)); 151 } while ((v != (SLFR_1RXV|SLFR_2RXV)) && timeout--);
137 152
138 v = readl(aaci->base + AACI_SL1RX) >> 12; 153 if (!timeout) {
139 if (v == reg) { 154 dev_err(&aaci->dev->dev, "timeout on RX valid\n");
140 v = readl(aaci->base + AACI_SL2RX) >> 4;
141 } else {
142 dev_err(&aaci->dev->dev,
143 "wrong ac97 register read back (%x != %x)\n",
144 v, reg);
145 v = ~0; 155 v = ~0;
156 goto out;
146 } 157 }
147 158
159 do {
160 v = readl(aaci->base + AACI_SL1RX) >> 12;
161 if (v == reg) {
162 v = readl(aaci->base + AACI_SL2RX) >> 4;
163 break;
164 } else if (--retries) {
165 dev_warn(&aaci->dev->dev,
166 "ac97 read back fail. retry\n");
167 continue;
168 } else {
169 dev_warn(&aaci->dev->dev,
170 "wrong ac97 register read back (%x != %x)\n",
171 v, reg);
172 v = ~0;
173 }
174 } while (retries);
175 out:
148 mutex_unlock(&aaci->ac97_sem); 176 mutex_unlock(&aaci->ac97_sem);
149 return v; 177 return v;
150} 178}