Commit c4af5da7 authored by Finn Thain's avatar Finn Thain Committed by Geert Uytterhoeven

m68k/mac: fix nubus slot irq disable and shutdown

Improve NuBus slot interrupt handling code and documentation. This patch fixes the NuBus NIC (mac8390) in my Quadra 700.
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
parent 8d9f014a
...@@ -257,6 +257,8 @@ extern int rbv_present,via_alt_mapping; ...@@ -257,6 +257,8 @@ extern int rbv_present,via_alt_mapping;
extern void via_register_interrupts(void); extern void via_register_interrupts(void);
extern void via_irq_enable(int); extern void via_irq_enable(int);
extern void via_irq_disable(int); extern void via_irq_disable(int);
extern void via_nubus_irq_startup(int irq);
extern void via_nubus_irq_shutdown(int irq);
extern void via1_irq(unsigned int irq, struct irq_desc *desc); extern void via1_irq(unsigned int irq, struct irq_desc *desc);
extern void via1_set_head(int); extern void via1_set_head(int);
extern int via2_scsi_drq_pending(void); extern int via2_scsi_drq_pending(void);
......
...@@ -151,10 +151,15 @@ irqreturn_t mac_debug_handler(int, void *); ...@@ -151,10 +151,15 @@ irqreturn_t mac_debug_handler(int, void *);
/* #define DEBUG_MACINTS */ /* #define DEBUG_MACINTS */
static unsigned int mac_irq_startup(struct irq_data *);
static void mac_irq_shutdown(struct irq_data *);
static struct irq_chip mac_irq_chip = { static struct irq_chip mac_irq_chip = {
.name = "mac", .name = "mac",
.irq_enable = mac_irq_enable, .irq_enable = mac_irq_enable,
.irq_disable = mac_irq_disable, .irq_disable = mac_irq_disable,
.irq_startup = mac_irq_startup,
.irq_shutdown = mac_irq_shutdown,
}; };
void __init mac_init_IRQ(void) void __init mac_init_IRQ(void)
...@@ -274,6 +279,28 @@ void mac_irq_disable(struct irq_data *data) ...@@ -274,6 +279,28 @@ void mac_irq_disable(struct irq_data *data)
} }
} }
static unsigned int mac_irq_startup(struct irq_data *data)
{
int irq = data->irq;
if (IRQ_SRC(irq) == 7 && !oss_present)
via_nubus_irq_startup(irq);
else
mac_irq_enable(data);
return 0;
}
static void mac_irq_shutdown(struct irq_data *data)
{
int irq = data->irq;
if (IRQ_SRC(irq) == 7 && !oss_present)
via_nubus_irq_shutdown(irq);
else
mac_irq_disable(data);
}
static int num_debug[8]; static int num_debug[8];
irqreturn_t mac_debug_handler(int irq, void *dev_id) irqreturn_t mac_debug_handler(int irq, void *dev_id)
......
...@@ -63,18 +63,47 @@ static int gIER,gIFR,gBufA,gBufB; ...@@ -63,18 +63,47 @@ static int gIER,gIFR,gBufA,gBufB;
#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) #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 * On Macs with a genuine VIA chip there is no way to mask an individual slot
* interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1 * interrupt. This limitation also seems to apply to VIA clone logic cores in
* or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt. * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.)
* 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. * We used to fake it by configuring the relevent VIA pin as an output
* Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's * (to mask the interrupt) or input (to unmask). That scheme did not work on
* possible to get interrupts from cards that MacOS or the ROM has configured * (at least) the Quadra 700. A NuBus card's /NMRQ signal is an open-collector
* but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and * circuit (see Designing Cards and Drivers for Macintosh II and Macintosh SE,
* Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS. * 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; static u8 nubus_disabled;
void via_debug_dump(void); void via_debug_dump(void);
...@@ -354,34 +383,55 @@ void __init via_nubus_init(void) ...@@ -354,34 +383,55 @@ void __init via_nubus_init(void)
via2[gBufB] |= 0x02; 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) { switch (macintosh_config->via_type) {
case MAC_VIA_II: case MAC_VIA_II:
/* Just make the port A lines inputs. */ case MAC_VIA_QUADRA:
switch(macintosh_config->ident) { pr_debug("VIA2 vDirA is 0x%02X\n", via2[vDirA]);
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;
}
break; break;
case MAC_VIA_IIci: case MAC_VIA_IIci:
/* RBV. Disable all the slot interrupts. SIER works like IER. */ /* RBV. Disable all the slot interrupts. SIER works like IER. */
via2[rSIER] = 0x7F; via2[rSIER] = 0x7F;
break; 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: case MAC_VIA_QUADRA:
/* Disable the inactive slot interrupts by making those lines outputs. */ /* Make the port A line an input. Probably redundant. */
if ((macintosh_config->adb_type != MAC_ADB_PB1) && if (macintosh_config->via_type == MAC_VIA_II) {
(macintosh_config->adb_type != MAC_ADB_PB2)) { /* The top two bits are RAM size outputs. */
via2[vBufA] |= 0x7F; via2[vDirA] &= 0xC0 | ~(1 << irq_idx);
via2[vDirA] |= 0x7F; } 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; break;
} }
} }
...@@ -507,6 +557,7 @@ void via_irq_enable(int irq) { ...@@ -507,6 +557,7 @@ void via_irq_enable(int irq) {
} else if (irq_src == 7) { } else if (irq_src == 7) {
switch (macintosh_config->via_type) { switch (macintosh_config->via_type) {
case MAC_VIA_II: case MAC_VIA_II:
case MAC_VIA_QUADRA:
nubus_disabled &= ~(1 << irq_idx); nubus_disabled &= ~(1 << irq_idx);
/* Enable the CA1 interrupt when no slot is disabled. */ /* Enable the CA1 interrupt when no slot is disabled. */
if (!nubus_disabled) if (!nubus_disabled)
...@@ -518,14 +569,6 @@ void via_irq_enable(int irq) { ...@@ -518,14 +569,6 @@ void via_irq_enable(int irq) {
*/ */
via2[rSIER] = IER_SET_BIT(irq_idx); via2[rSIER] = IER_SET_BIT(irq_idx);
break; 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;
} }
} }
} }
...@@ -545,6 +588,7 @@ void via_irq_disable(int irq) { ...@@ -545,6 +588,7 @@ void via_irq_disable(int irq) {
} else if (irq_src == 7) { } else if (irq_src == 7) {
switch (macintosh_config->via_type) { switch (macintosh_config->via_type) {
case MAC_VIA_II: case MAC_VIA_II:
case MAC_VIA_QUADRA:
nubus_disabled |= 1 << irq_idx; nubus_disabled |= 1 << irq_idx;
if (nubus_disabled) if (nubus_disabled)
via2[gIER] = IER_CLR_BIT(1); via2[gIER] = IER_CLR_BIT(1);
...@@ -552,11 +596,6 @@ void via_irq_disable(int irq) { ...@@ -552,11 +596,6 @@ void via_irq_disable(int irq) {
case MAC_VIA_IIci: case MAC_VIA_IIci:
via2[rSIER] = IER_CLR_BIT(irq_idx); via2[rSIER] = IER_CLR_BIT(irq_idx);
break; 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;
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment