aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2007-05-01 16:33:00 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-04 20:59:07 -0400
commit0251c38ce503de01f5bc07917a824021b86b4ada (patch)
treec0fe5742ca88d7334f02eae5a7835c07df2c03ba
parentd95fd5fce88f05fd36004f2a0c317e665549e54c (diff)
CUDA ADB fixes
Fix the flakiness in the CUDA ADB driver on m68k macs (keypresses getting wedged down or ADB just going AWOL altogether). The only IRQ used by this driver is the VIA shift register IRQ. The PowerMac conditional code disables the other VIA IRQ sources, so don't mess with the other IRQ flags in the common code -- m68k macs need them. When polling, don't disable local interrupts when we only need to disable the CUDA interrupt. Unless polling, don't clear the shift register IRQ flag. On m68k macs this creates a race that often breaks CUDA ADB. Tested on Quadra 840av and LC630 (both m68k); also Beige G3 (powerpc). Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/macintosh/via-cuda.c58
1 files changed, 32 insertions, 26 deletions
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 76d21775fc35..741a93a3eb61 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -82,6 +82,7 @@ static unsigned char cuda_rbuf[16];
82static unsigned char *reply_ptr; 82static unsigned char *reply_ptr;
83static int reading_reply; 83static int reading_reply;
84static int data_index; 84static int data_index;
85static int cuda_irq;
85#ifdef CONFIG_PPC 86#ifdef CONFIG_PPC
86static struct device_node *vias; 87static struct device_node *vias;
87#endif 88#endif
@@ -160,10 +161,8 @@ int __init find_via_cuda(void)
160 /* Clear and enable interrupts, but only on PPC. On 68K it's done */ 161 /* Clear and enable interrupts, but only on PPC. On 68K it's done */
161 /* for us by the main VIA driver in arch/m68k/mac/via.c */ 162 /* for us by the main VIA driver in arch/m68k/mac/via.c */
162 163
163#ifndef CONFIG_MAC
164 out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */ 164 out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */
165 out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ 165 out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
166#endif
167 166
168 /* enable autopoll */ 167 /* enable autopoll */
169 cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); 168 cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
@@ -181,24 +180,22 @@ int __init find_via_cuda(void)
181 180
182static int __init via_cuda_start(void) 181static int __init via_cuda_start(void)
183{ 182{
184 unsigned int irq;
185
186 if (via == NULL) 183 if (via == NULL)
187 return -ENODEV; 184 return -ENODEV;
188 185
189#ifdef CONFIG_MAC 186#ifdef CONFIG_MAC
190 irq = IRQ_MAC_ADB; 187 cuda_irq = IRQ_MAC_ADB;
191#else /* CONFIG_MAC */ 188#else /* CONFIG_MAC */
192 irq = irq_of_parse_and_map(vias, 0); 189 cuda_irq = irq_of_parse_and_map(vias, 0);
193 if (irq == NO_IRQ) { 190 if (cuda_irq == NO_IRQ) {
194 printk(KERN_ERR "via-cuda: can't map interrupts for %s\n", 191 printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
195 vias->full_name); 192 vias->full_name);
196 return -ENODEV; 193 return -ENODEV;
197 } 194 }
198#endif /* CONFIG_MAP */ 195#endif /* CONFIG_MAC */
199 196
200 if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { 197 if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
201 printk(KERN_ERR "via-cuda: can't request irq %d\n", irq); 198 printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq);
202 return -EAGAIN; 199 return -EAGAIN;
203 } 200 }
204 201
@@ -238,6 +235,7 @@ cuda_init(void)
238 printk(KERN_ERR "cuda_init_via() failed\n"); 235 printk(KERN_ERR "cuda_init_via() failed\n");
239 return -ENODEV; 236 return -ENODEV;
240 } 237 }
238 out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
241 239
242 return via_cuda_start(); 240 return via_cuda_start();
243#endif 241#endif
@@ -263,15 +261,17 @@ cuda_init_via(void)
263 out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */ 261 out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */
264 out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */ 262 out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
265 (void)in_8(&via[SR]); /* clear any left-over data */ 263 (void)in_8(&via[SR]); /* clear any left-over data */
266#ifndef CONFIG_MAC 264#ifdef CONFIG_PPC
267 out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ 265 out_8(&via[IER], 0x7f); /* disable interrupts from VIA */
268 (void)in_8(&via[IER]); 266 (void)in_8(&via[IER]);
267#else
268 out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */
269#endif 269#endif
270 270
271 /* delay 4ms and then clear any pending interrupt */ 271 /* delay 4ms and then clear any pending interrupt */
272 mdelay(4); 272 mdelay(4);
273 (void)in_8(&via[SR]); 273 (void)in_8(&via[SR]);
274 out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); 274 out_8(&via[IFR], SR_INT);
275 275
276 /* sync with the CUDA - assert TACK without TIP */ 276 /* sync with the CUDA - assert TACK without TIP */
277 out_8(&via[B], in_8(&via[B]) & ~TACK); 277 out_8(&via[B], in_8(&via[B]) & ~TACK);
@@ -282,7 +282,7 @@ cuda_init_via(void)
282 /* wait for the interrupt and then clear it */ 282 /* wait for the interrupt and then clear it */
283 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)"); 283 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
284 (void)in_8(&via[SR]); 284 (void)in_8(&via[SR]);
285 out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); 285 out_8(&via[IFR], SR_INT);
286 286
287 /* finish the sync by negating TACK */ 287 /* finish the sync by negating TACK */
288 out_8(&via[B], in_8(&via[B]) | TACK); 288 out_8(&via[B], in_8(&via[B]) | TACK);
@@ -291,7 +291,7 @@ cuda_init_via(void)
291 WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)"); 291 WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)");
292 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)"); 292 WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
293 (void)in_8(&via[SR]); 293 (void)in_8(&via[SR]);
294 out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); 294 out_8(&via[IFR], SR_INT);
295 out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */ 295 out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */
296 296
297 return 0; 297 return 0;
@@ -428,16 +428,12 @@ cuda_start(void)
428void 428void
429cuda_poll(void) 429cuda_poll(void)
430{ 430{
431 unsigned long flags;
432
433 /* cuda_interrupt only takes a normal lock, we disable 431 /* cuda_interrupt only takes a normal lock, we disable
434 * interrupts here to avoid re-entering and thus deadlocking. 432 * interrupts here to avoid re-entering and thus deadlocking.
435 * An option would be to disable only the IRQ source with
436 * disable_irq(), would that work on m68k ? --BenH
437 */ 433 */
438 local_irq_save(flags); 434 disable_irq(cuda_irq);
439 cuda_interrupt(0, NULL); 435 cuda_interrupt(0, NULL);
440 local_irq_restore(flags); 436 enable_irq(cuda_irq);
441} 437}
442 438
443static irqreturn_t 439static irqreturn_t
@@ -448,15 +444,25 @@ cuda_interrupt(int irq, void *arg)
448 unsigned char ibuf[16]; 444 unsigned char ibuf[16];
449 int ibuf_len = 0; 445 int ibuf_len = 0;
450 int complete = 0; 446 int complete = 0;
451 unsigned char virq;
452 447
453 spin_lock(&cuda_lock); 448 spin_lock(&cuda_lock);
454 449
455 virq = in_8(&via[IFR]) & 0x7f; 450 /* On powermacs, this handler is registered for the VIA IRQ. But it uses
456 out_8(&via[IFR], virq); 451 * just the shift register IRQ -- other VIA interrupt sources are disabled.
457 if ((virq & SR_INT) == 0) { 452 * On m68k macs, the VIA IRQ sources are dispatched individually. Unless
458 spin_unlock(&cuda_lock); 453 * we are polling, the shift register IRQ flag has already been cleared.
459 return IRQ_NONE; 454 */
455
456#ifdef CONFIG_MAC
457 if (!arg)
458#endif
459 {
460 if ((in_8(&via[IFR]) & SR_INT) == 0) {
461 spin_unlock(&cuda_lock);
462 return IRQ_NONE;
463 } else {
464 out_8(&via[IFR], SR_INT);
465 }
460 } 466 }
461 467
462 status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT); 468 status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT);