]> Pileus Git - ~andy/linux/blobdiff - arch/m68k/mac/via.c
mac_scsi: fix mac_scsi on some powerbooks
[~andy/linux] / arch / m68k / mac / via.c
index 974c3e9ac7f3a3af5dbb7ac4b6e282c62d1099ea..7a2993bb092dee36e17f6f6ebc608c2841b55416 100644 (file)
@@ -63,18 +63,47 @@ static int gIER,gIFR,gBufA,gBufB;
 #define MAC_CLOCK_LOW          (MAC_CLOCK_TICK&0xFF)
 #define MAC_CLOCK_HIGH         (MAC_CLOCK_TICK>>8)
 
-/* To disable a NuBus slot on Quadras we make that slot IRQ line an output set
- * high. On RBV we just use the slot interrupt enable register. On Macs with
- * genuine VIA chips we must use nubus_disabled to keep track of disabled slot
- * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1
- * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt.
- * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble,
- * because closing one of those drivers can mask all of the NuBus interrupts.
- * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's
- * possible to get interrupts from cards that MacOS or the ROM has configured
- * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and
- * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS.
+
+/*
+ * On Macs with a genuine VIA chip there is no way to mask an individual slot
+ * interrupt. This limitation also seems to apply to VIA clone logic cores in
+ * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.)
+ *
+ * We used to fake it by configuring the relevent VIA pin as an output
+ * (to mask the interrupt) or input (to unmask). That scheme did not work on
+ * (at least) the Quadra 700. A NuBus card's /NMRQ signal is an open-collector
+ * circuit (see Designing Cards and Drivers for Macintosh II and Macintosh SE,
+ * p. 10-11 etc) but VIA outputs are not (see datasheet).
+ *
+ * Driving these outputs high must cause the VIA to source current and the
+ * card to sink current when it asserts /NMRQ. Current will flow but the pin
+ * voltage is uncertain and so the /NMRQ condition may still cause a transition
+ * at the VIA2 CA1 input (which explains the lost interrupts). A side effect
+ * is that a disabled slot IRQ can never be tested as pending or not.
+ *
+ * Driving these outputs low doesn't work either. All the slot /NMRQ lines are
+ * (active low) OR'd together to generate the CA1 (aka "SLOTS") interrupt (see
+ * The Guide To Macintosh Family Hardware, 2nd edition p. 167). If we drive a
+ * disabled /NMRQ line low, the falling edge immediately triggers a CA1
+ * interrupt and all slot interrupts after that will generate no transition
+ * and therefore no interrupt, even after being re-enabled.
+ *
+ * So we make the VIA port A I/O lines inputs and use nubus_disabled to keep
+ * track of their states. When any slot IRQ becomes disabled we mask the CA1
+ * umbrella interrupt. Only when all slot IRQs become enabled do we unmask
+ * the CA1 interrupt. It must remain enabled even when cards have no interrupt
+ * handler registered. Drivers must therefore disable a slot interrupt at the
+ * device before they call free_irq (like shared and autovector interrupts).
+ *
+ * There is also a related problem when MacOS is used to boot Linux. A network
+ * card brought up by a MacOS driver may raise an interrupt while Linux boots.
+ * This can be fatal since it can't be handled until the right driver loads
+ * (if such a driver exists at all). Apparently related to this hardware
+ * limitation, "Designing Cards and Drivers", p. 9-8, says that a slot
+ * interrupt with no driver would crash MacOS (the book was written before
+ * the appearance of Macs with RBV or OSS).
  */
+
 static u8 nubus_disabled;
 
 void via_debug_dump(void);
@@ -194,38 +223,17 @@ void __init via_init(void)
        if (oss_present)
                return;
 
-       /* Some machines support an alternate IRQ mapping that spreads  */
-       /* Ethernet and Sound out to their own autolevel IRQs and moves */
-       /* VIA1 to level 6. A/UX uses this mapping and we do too.  Note */
-       /* that the IIfx emulates this alternate mapping using the OSS. */
-
-       via_alt_mapping = 0;
-       if (macintosh_config->via_type == MAC_VIA_QUADRA)
-               switch (macintosh_config->ident) {
-               case MAC_MODEL_C660:
-               case MAC_MODEL_Q840:
-                       /* not applicable */
-                       break;
-               case MAC_MODEL_P588:
-               case MAC_MODEL_TV:
-               case MAC_MODEL_PB140:
-               case MAC_MODEL_PB145:
-               case MAC_MODEL_PB160:
-               case MAC_MODEL_PB165:
-               case MAC_MODEL_PB165C:
-               case MAC_MODEL_PB170:
-               case MAC_MODEL_PB180:
-               case MAC_MODEL_PB180C:
-               case MAC_MODEL_PB190:
-               case MAC_MODEL_PB520:
-                       /* not yet tested */
-                       break;
-               default:
-                       via_alt_mapping = 1;
-                       via1[vDirB] |= 0x40;
-                       via1[vBufB] &= ~0x40;
-                       break;
-               }
+       if ((macintosh_config->via_type == MAC_VIA_QUADRA) &&
+           (macintosh_config->adb_type != MAC_ADB_PB1) &&
+           (macintosh_config->adb_type != MAC_ADB_PB2) &&
+           (macintosh_config->ident    != MAC_MODEL_C660) &&
+           (macintosh_config->ident    != MAC_MODEL_Q840)) {
+               via_alt_mapping = 1;
+               via1[vDirB] |= 0x40;
+               via1[vBufB] &= ~0x40;
+       } else {
+               via_alt_mapping = 0;
+       }
 
        /*
         * Now initialize VIA2. For RBV we just kill all interrupts;
@@ -245,22 +253,28 @@ void __init via_init(void)
                via2[vACR] &= ~0x03; /* disable port A & B latches */
        }
 
+       /* Everything below this point is VIA2 only... */
+
+       if (rbv_present)
+               return;
+
        /*
-        * Set vPCR for control line interrupts (but not on RBV)
+        * Set vPCR for control line interrupts.
+        *
+        * CA1 (SLOTS IRQ), CB1 (ASC IRQ): negative edge trigger.
+        *
+        * Macs with ESP SCSI have a negative edge triggered SCSI interrupt.
+        * Testing reveals that PowerBooks do too. However, the SE/30
+        * schematic diagram shows an active high NCR5380 IRQ line.
         */
-       if (!rbv_present) {
-               /* For all VIA types, CA1 (SLOTS IRQ) and CB1 (ASC IRQ)
-                * are made negative edge triggered here.
-                */
-               if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
-                       /* CB2 (IRQ) indep. input, positive edge */
-                       /* CA2 (DRQ) indep. input, positive edge */
-                       via2[vPCR] = 0x66;
-               } else {
-                       /* CB2 (IRQ) indep. input, negative edge */
-                       /* CA2 (DRQ) indep. input, negative edge */
-                       via2[vPCR] = 0x22;
-               }
+
+       pr_debug("VIA2 vPCR is 0x%02X\n", via2[vPCR]);
+       if (macintosh_config->via_type == MAC_VIA_II) {
+               /* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, pos. edge */
+               via2[vPCR] = 0x66;
+       } else {
+               /* CA2 (SCSI DRQ), CB2 (SCSI IRQ): indep. input, neg. edge */
+               via2[vPCR] = 0x22;
        }
 }
 
@@ -375,34 +389,55 @@ void __init via_nubus_init(void)
                via2[gBufB] |= 0x02;
        }
 
-       /* Disable all the slot interrupts (where possible). */
+       /*
+        * Disable the slot interrupts. On some hardware that's not possible.
+        * On some hardware it's unclear what all of these I/O lines do.
+        */
 
        switch (macintosh_config->via_type) {
        case MAC_VIA_II:
-               /* Just make the port A lines inputs. */
-               switch(macintosh_config->ident) {
-               case MAC_MODEL_II:
-               case MAC_MODEL_IIX:
-               case MAC_MODEL_IICX:
-               case MAC_MODEL_SE30:
-                       /* The top two bits are RAM size outputs. */
-                       via2[vDirA] &= 0xC0;
-                       break;
-               default:
-                       via2[vDirA] &= 0x80;
-               }
+       case MAC_VIA_QUADRA:
+               pr_debug("VIA2 vDirA is 0x%02X\n", via2[vDirA]);
                break;
        case MAC_VIA_IIci:
                /* RBV. Disable all the slot interrupts. SIER works like IER. */
                via2[rSIER] = 0x7F;
                break;
+       }
+}
+
+void via_nubus_irq_startup(int irq)
+{
+       int irq_idx = IRQ_IDX(irq);
+
+       switch (macintosh_config->via_type) {
+       case MAC_VIA_II:
        case MAC_VIA_QUADRA:
-               /* Disable the inactive slot interrupts by making those lines outputs. */
-               if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
-                   (macintosh_config->adb_type != MAC_ADB_PB2)) {
-                       via2[vBufA] |= 0x7F;
-                       via2[vDirA] |= 0x7F;
+               /* Make the port A line an input. Probably redundant. */
+               if (macintosh_config->via_type == MAC_VIA_II) {
+                       /* The top two bits are RAM size outputs. */
+                       via2[vDirA] &= 0xC0 | ~(1 << irq_idx);
+               } else {
+                       /* Allow NuBus slots 9 through F. */
+                       via2[vDirA] &= 0x80 | ~(1 << irq_idx);
                }
+               /* fall through */
+       case MAC_VIA_IIci:
+               via_irq_enable(irq);
+               break;
+       }
+}
+
+void via_nubus_irq_shutdown(int irq)
+{
+       switch (macintosh_config->via_type) {
+       case MAC_VIA_II:
+       case MAC_VIA_QUADRA:
+               /* Ensure that the umbrella CA1 interrupt remains enabled. */
+               via_irq_enable(irq);
+               break;
+       case MAC_VIA_IIci:
+               via_irq_disable(irq);
                break;
        }
 }
@@ -528,6 +563,7 @@ void via_irq_enable(int irq) {
        } else if (irq_src == 7) {
                switch (macintosh_config->via_type) {
                case MAC_VIA_II:
+               case MAC_VIA_QUADRA:
                        nubus_disabled &= ~(1 << irq_idx);
                        /* Enable the CA1 interrupt when no slot is disabled. */
                        if (!nubus_disabled)
@@ -539,14 +575,6 @@ void via_irq_enable(int irq) {
                         */
                        via2[rSIER] = IER_SET_BIT(irq_idx);
                        break;
-               case MAC_VIA_QUADRA:
-                       /* Make the port A line an input to enable the slot irq.
-                        * But not on PowerBooks, that's ADB.
-                        */
-                       if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
-                           (macintosh_config->adb_type != MAC_ADB_PB2))
-                               via2[vDirA] &= ~(1 << irq_idx);
-                       break;
                }
        }
 }
@@ -566,6 +594,7 @@ void via_irq_disable(int irq) {
        } else if (irq_src == 7) {
                switch (macintosh_config->via_type) {
                case MAC_VIA_II:
+               case MAC_VIA_QUADRA:
                        nubus_disabled |= 1 << irq_idx;
                        if (nubus_disabled)
                                via2[gIER] = IER_CLR_BIT(1);
@@ -573,11 +602,6 @@ void via_irq_disable(int irq) {
                case MAC_VIA_IIci:
                        via2[rSIER] = IER_CLR_BIT(irq_idx);
                        break;
-               case MAC_VIA_QUADRA:
-                       if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
-                           (macintosh_config->adb_type != MAC_ADB_PB2))
-                               via2[vDirA] |= 1 << irq_idx;
-                       break;
                }
        }
 }