aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/mac/via.c
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2007-05-01 16:32:57 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-04 20:59:07 -0400
commitcd713ddc93bf2f612783aea8eff6d0df6107765e (patch)
treecef9702ef5e70be0ccc0dbbec94316b3929713ca /arch/m68k/mac/via.c
parent67dfb153a352e57e71404d550be7eb60d15d7f2d (diff)
m68k: Mac nubus IRQ fixes (plan E)
Some Macs lack a slot interrupt enable register. So the existing code makes disabled and unregistered slot IRQ lines outputs set high. This seems to work on quadras, but does not work on genuine VIAs (perhaps the card still succeeds in pulling the line low, or perhaps because this increases the settle time on the port A input, meaning that the CA1 IRQ could fire before the slot line reads active). Because of this, the nubus_active flags were used to mask IRQs, which is actually worse than the problem it tries to solve. Any interrupt masked by nubus_active will remain asserted and prevent further transitions on CA1. And so the nubus gets wedged regardless of hardware (emulated VIA ASIC, real VIA chip or RBV). The best solution to this hardware limitation of genuine VIAs is to disable the umbrella SLOTS IRQ when disabling a slot on those machines. Unfortunately, this means all slot IRQs get disabled when any slot IRQ is disabled. But it is only a problem when there's more than 1 device using nubus interrupts. Another potential problem for genuine VIAs is an unregistered nubus IRQ. Eventually it will be possible to enable the CA1 interrupt by installing its handler only _after_ all nubus drivers have loaded but _before_ the kernel needs them, at which time this last problem can be fixed. For now it can be worked around: - disable MacOS extensions - don't boot MacOS (use the Emile bootloader instead) - get the bootloaders to disable ROM drivers (Penguin does this for video cards already, don't know about Emile) - physically remove unsupported cards 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>
Diffstat (limited to 'arch/m68k/mac/via.c')
-rw-r--r--arch/m68k/mac/via.c141
1 files changed, 80 insertions, 61 deletions
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index 0c1cc45c570d..83a3bb0c0325 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -64,7 +64,19 @@ static int gIER,gIFR,gBufA,gBufB;
64#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) 64#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
65#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) 65#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
66 66
67static int nubus_active; 67/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set
68 * high. On RBV we just use the slot interrupt enable register. On Macs with
69 * genuine VIA chips we must use nubus_disabled to keep track of disabled slot
70 * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1
71 * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt.
72 * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble,
73 * because closing one of those drivers can mask all of the NuBus interrupts.
74 * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's
75 * possible to get interrupts from cards that MacOS or the ROM has configured
76 * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and
77 * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS.
78 */
79static u8 nubus_disabled;
68 80
69void via_debug_dump(void); 81void via_debug_dump(void);
70irqreturn_t via1_irq(int, void *); 82irqreturn_t via1_irq(int, void *);
@@ -383,9 +395,6 @@ int via_get_cache_disable(void)
383 395
384void __init via_nubus_init(void) 396void __init via_nubus_init(void)
385{ 397{
386 /* don't set nubus_active = 0 here, it kills the Baboon */
387 /* interrupt that we've already registered. */
388
389 /* unlock nubus transactions */ 398 /* unlock nubus transactions */
390 399
391 if ((macintosh_config->adb_type != MAC_ADB_PB1) && 400 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
@@ -399,28 +408,35 @@ void __init via_nubus_init(void)
399 via2[gBufB] |= 0x02; 408 via2[gBufB] |= 0x02;
400 } 409 }
401 410
402 /* disable nubus slot interrupts. */ 411 /* Disable all the slot interrupts (where possible). */
403 if (rbv_present) { 412
413 switch (macintosh_config->via_type) {
414 case MAC_VIA_II:
415 /* Just make the port A lines inputs. */
416 switch(macintosh_config->ident) {
417 case MAC_MODEL_II:
418 case MAC_MODEL_IIX:
419 case MAC_MODEL_IICX:
420 case MAC_MODEL_SE30:
421 /* The top two bits are RAM size outputs. */
422 via2[vDirA] &= 0xC0;
423 break;
424 default:
425 via2[vDirA] &= 0x80;
426 }
427 break;
428 case MAC_VIA_IIci:
429 /* RBV. Disable all the slot interrupts. SIER works like IER. */
404 via2[rSIER] = 0x7F; 430 via2[rSIER] = 0x7F;
405 via2[rSIER] = nubus_active | 0x80; 431 break;
406 } else { 432 case MAC_VIA_QUADRA:
407 /* These are ADB bits on PMU */ 433 /* Disable the inactive slot interrupts by making those lines outputs. */
408 if ((macintosh_config->adb_type != MAC_ADB_PB1) && 434 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
409 (macintosh_config->adb_type != MAC_ADB_PB2)) { 435 (macintosh_config->adb_type != MAC_ADB_PB2)) {
410 switch(macintosh_config->ident) 436 via2[vBufA] |= 0x7F;
411 { 437 via2[vDirA] |= 0x7F;
412 case MAC_MODEL_II:
413 case MAC_MODEL_IIX:
414 case MAC_MODEL_IICX:
415 case MAC_MODEL_SE30:
416 via2[vBufA] |= 0x3F;
417 via2[vDirA] = ~nubus_active | 0xc0;
418 break;
419 default:
420 via2[vBufA] = 0xFF;
421 via2[vDirA] = ~nubus_active;
422 }
423 } 438 }
439 break;
424 } 440 }
425} 441}
426 442
@@ -489,7 +505,8 @@ irqreturn_t via2_irq(int irq, void *dev_id)
489 via2[gIER] = irq_bit; 505 via2[gIER] = irq_bit;
490 via2[gIFR] = irq_bit | rbv_clear; 506 via2[gIFR] = irq_bit | rbv_clear;
491 m68k_handle_int(irq_num); 507 m68k_handle_int(irq_num);
492 via2[gIER] = irq_bit | 0x80; 508 if (irq_num != IRQ_MAC_NUBUS || nubus_disabled == 0)
509 via2[gIER] = irq_bit | 0x80;
493 } 510 }
494 ++irq_num; 511 ++irq_num;
495 irq_bit <<= 1; 512 irq_bit <<= 1;
@@ -511,7 +528,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
511 if (rbv_present) 528 if (rbv_present)
512 events &= via2[rSIER]; 529 events &= via2[rSIER];
513 else 530 else
514 events &= nubus_active; 531 events &= ~via2[vDirA];
515 if (!events) 532 if (!events)
516 return IRQ_NONE; 533 return IRQ_NONE;
517 534
@@ -533,7 +550,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
533 if (rbv_present) 550 if (rbv_present)
534 events &= via2[rSIER]; 551 events &= via2[rSIER];
535 else 552 else
536 events &= nubus_active; 553 events &= ~via2[vDirA];
537 } while (events); 554 } while (events);
538 return IRQ_HANDLED; 555 return IRQ_HANDLED;
539} 556}
@@ -541,38 +558,38 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
541void via_irq_enable(int irq) { 558void via_irq_enable(int irq) {
542 int irq_src = IRQ_SRC(irq); 559 int irq_src = IRQ_SRC(irq);
543 int irq_idx = IRQ_IDX(irq); 560 int irq_idx = IRQ_IDX(irq);
544 int irq_bit = 1 << irq_idx;
545 561
546#ifdef DEBUG_IRQUSE 562#ifdef DEBUG_IRQUSE
547 printk(KERN_DEBUG "via_irq_enable(%d)\n", irq); 563 printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
548#endif 564#endif
549 565
550 if (irq_src == 1) { 566 if (irq_src == 1) {
551 via1[vIER] = irq_bit | 0x80; 567 via1[vIER] = IER_SET_BIT(irq_idx);
552 } else if (irq_src == 2) { 568 } else if (irq_src == 2) {
553 via2[gIER] = irq_bit | 0x80; 569 if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
570 via2[gIER] = IER_SET_BIT(irq_idx);
554 } else if (irq_src == 7) { 571 } else if (irq_src == 7) {
555 nubus_active |= irq_bit; 572 switch (macintosh_config->via_type) {
556 if (rbv_present) { 573 case MAC_VIA_II:
557 /* enable the slot interrupt. SIER works like IER. */ 574 nubus_disabled &= ~(1 << irq_idx);
575 /* Enable the CA1 interrupt when no slot is disabled. */
576 if (!nubus_disabled)
577 via2[gIER] = IER_SET_BIT(1);
578 break;
579 case MAC_VIA_IIci:
580 /* On RBV, enable the slot interrupt.
581 * SIER works like IER.
582 */
558 via2[rSIER] = IER_SET_BIT(irq_idx); 583 via2[rSIER] = IER_SET_BIT(irq_idx);
559 } else { 584 break;
560 /* Make sure the bit is an input, to enable the irq */ 585 case MAC_VIA_QUADRA:
561 /* But not on PowerBooks, that's ADB... */ 586 /* Make the port A line an input to enable the slot irq.
587 * But not on PowerBooks, that's ADB.
588 */
562 if ((macintosh_config->adb_type != MAC_ADB_PB1) && 589 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
563 (macintosh_config->adb_type != MAC_ADB_PB2)) { 590 (macintosh_config->adb_type != MAC_ADB_PB2))
564 switch(macintosh_config->ident) 591 via2[vDirA] &= ~(1 << irq_idx);
565 { 592 break;
566 case MAC_MODEL_II:
567 case MAC_MODEL_IIX:
568 case MAC_MODEL_IICX:
569 case MAC_MODEL_SE30:
570 via2[vDirA] &= (~irq_bit | 0xc0);
571 break;
572 default:
573 via2[vDirA] &= ~irq_bit;
574 }
575 }
576 } 593 }
577 } 594 }
578} 595}
@@ -580,29 +597,31 @@ void via_irq_enable(int irq) {
580void via_irq_disable(int irq) { 597void via_irq_disable(int irq) {
581 int irq_src = IRQ_SRC(irq); 598 int irq_src = IRQ_SRC(irq);
582 int irq_idx = IRQ_IDX(irq); 599 int irq_idx = IRQ_IDX(irq);
583 int irq_bit = 1 << irq_idx;
584 600
585#ifdef DEBUG_IRQUSE 601#ifdef DEBUG_IRQUSE
586 printk(KERN_DEBUG "via_irq_disable(%d)\n", irq); 602 printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
587#endif 603#endif
588 604
589 if (irq_src == 1) { 605 if (irq_src == 1) {
590 via1[vIER] = irq_bit & 0x7F; 606 via1[vIER] = IER_CLR_BIT(irq_idx);
591 } else if (irq_src == 2) { 607 } else if (irq_src == 2) {
592 via2[gIER] = irq_bit & 0x7F; 608 via2[gIER] = IER_CLR_BIT(irq_idx);
593 } else if (irq_src == 7) { 609 } else if (irq_src == 7) {
594 if (rbv_present) { 610 switch (macintosh_config->via_type) {
595 /* disable the slot interrupt. SIER works like IER. */ 611 case MAC_VIA_II:
612 nubus_disabled |= 1 << irq_idx;
613 if (nubus_disabled)
614 via2[gIER] = IER_CLR_BIT(1);
615 break;
616 case MAC_VIA_IIci:
596 via2[rSIER] = IER_CLR_BIT(irq_idx); 617 via2[rSIER] = IER_CLR_BIT(irq_idx);
597 } else { 618 break;
598 /* disable the nubus irq by changing dir to output */ 619 case MAC_VIA_QUADRA:
599 /* except on PMU */
600 if ((macintosh_config->adb_type != MAC_ADB_PB1) && 620 if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
601 (macintosh_config->adb_type != MAC_ADB_PB2)) { 621 (macintosh_config->adb_type != MAC_ADB_PB2))
602 via2[vDirA] |= irq_bit; 622 via2[vDirA] |= 1 << irq_idx;
603 } 623 break;
604 } 624 }
605 nubus_active &= ~irq_bit;
606 } 625 }
607} 626}
608 627
@@ -638,7 +657,7 @@ int via_irq_pending(int irq)
638 } else if (irq_src == 2) { 657 } else if (irq_src == 2) {
639 return via2[gIFR] & irq_bit; 658 return via2[gIFR] & irq_bit;
640 } else if (irq_src == 7) { 659 } else if (irq_src == 7) {
641 /* FIXME: this can't work while a slot irq is disabled! */ 660 /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */
642 return ~via2[gBufA] & irq_bit; 661 return ~via2[gBufA] & irq_bit;
643 } 662 }
644 return 0; 663 return 0;