Commit cd713ddc authored by Finn Thain's avatar Finn Thain Committed by Linus Torvalds

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: default avatarFinn Thain <fthain@telegraphics.com.au>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 67dfb153
...@@ -64,7 +64,19 @@ static int gIER,gIFR,gBufA,gBufB; ...@@ -64,7 +64,19 @@ 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)
static int nubus_active; /* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, 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.
*/
static u8 nubus_disabled;
void via_debug_dump(void); void via_debug_dump(void);
irqreturn_t via1_irq(int, void *); irqreturn_t via1_irq(int, void *);
...@@ -383,9 +395,6 @@ int via_get_cache_disable(void) ...@@ -383,9 +395,6 @@ int via_get_cache_disable(void)
void __init via_nubus_init(void) void __init via_nubus_init(void)
{ {
/* don't set nubus_active = 0 here, it kills the Baboon */
/* interrupt that we've already registered. */
/* unlock nubus transactions */ /* unlock nubus transactions */
if ((macintosh_config->adb_type != MAC_ADB_PB1) && if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
...@@ -399,28 +408,35 @@ void __init via_nubus_init(void) ...@@ -399,28 +408,35 @@ void __init via_nubus_init(void)
via2[gBufB] |= 0x02; via2[gBufB] |= 0x02;
} }
/* disable nubus slot interrupts. */ /* Disable all the slot interrupts (where possible). */
if (rbv_present) {
via2[rSIER] = 0x7F; switch (macintosh_config->via_type) {
via2[rSIER] = nubus_active | 0x80; case MAC_VIA_II:
} else { /* Just make the port A lines inputs. */
/* These are ADB bits on PMU */ switch(macintosh_config->ident) {
if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
(macintosh_config->adb_type != MAC_ADB_PB2)) {
switch(macintosh_config->ident)
{
case MAC_MODEL_II: case MAC_MODEL_II:
case MAC_MODEL_IIX: case MAC_MODEL_IIX:
case MAC_MODEL_IICX: case MAC_MODEL_IICX:
case MAC_MODEL_SE30: case MAC_MODEL_SE30:
via2[vBufA] |= 0x3F; /* The top two bits are RAM size outputs. */
via2[vDirA] = ~nubus_active | 0xc0; via2[vDirA] &= 0xC0;
break; break;
default: default:
via2[vBufA] = 0xFF; via2[vDirA] &= 0x80;
via2[vDirA] = ~nubus_active;
} }
break;
case MAC_VIA_IIci:
/* RBV. Disable all the slot interrupts. SIER works like IER. */
via2[rSIER] = 0x7F;
break;
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;
} }
break;
} }
} }
...@@ -489,6 +505,7 @@ irqreturn_t via2_irq(int irq, void *dev_id) ...@@ -489,6 +505,7 @@ irqreturn_t via2_irq(int irq, void *dev_id)
via2[gIER] = irq_bit; via2[gIER] = irq_bit;
via2[gIFR] = irq_bit | rbv_clear; via2[gIFR] = irq_bit | rbv_clear;
m68k_handle_int(irq_num); m68k_handle_int(irq_num);
if (irq_num != IRQ_MAC_NUBUS || nubus_disabled == 0)
via2[gIER] = irq_bit | 0x80; via2[gIER] = irq_bit | 0x80;
} }
++irq_num; ++irq_num;
...@@ -511,7 +528,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id) ...@@ -511,7 +528,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
if (rbv_present) if (rbv_present)
events &= via2[rSIER]; events &= via2[rSIER];
else else
events &= nubus_active; events &= ~via2[vDirA];
if (!events) if (!events)
return IRQ_NONE; return IRQ_NONE;
...@@ -533,7 +550,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id) ...@@ -533,7 +550,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
if (rbv_present) if (rbv_present)
events &= via2[rSIER]; events &= via2[rSIER];
else else
events &= nubus_active; events &= ~via2[vDirA];
} while (events); } while (events);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -541,38 +558,38 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id) ...@@ -541,38 +558,38 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id)
void via_irq_enable(int irq) { void via_irq_enable(int irq) {
int irq_src = IRQ_SRC(irq); int irq_src = IRQ_SRC(irq);
int irq_idx = IRQ_IDX(irq); int irq_idx = IRQ_IDX(irq);
int irq_bit = 1 << irq_idx;
#ifdef DEBUG_IRQUSE #ifdef DEBUG_IRQUSE
printk(KERN_DEBUG "via_irq_enable(%d)\n", irq); printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
#endif #endif
if (irq_src == 1) { if (irq_src == 1) {
via1[vIER] = irq_bit | 0x80; via1[vIER] = IER_SET_BIT(irq_idx);
} else if (irq_src == 2) { } else if (irq_src == 2) {
via2[gIER] = irq_bit | 0x80; if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
via2[gIER] = IER_SET_BIT(irq_idx);
} else if (irq_src == 7) { } else if (irq_src == 7) {
nubus_active |= irq_bit; switch (macintosh_config->via_type) {
if (rbv_present) { case MAC_VIA_II:
/* enable the slot interrupt. SIER works like IER. */ nubus_disabled &= ~(1 << irq_idx);
/* Enable the CA1 interrupt when no slot is disabled. */
if (!nubus_disabled)
via2[gIER] = IER_SET_BIT(1);
break;
case MAC_VIA_IIci:
/* On RBV, enable the slot interrupt.
* SIER works like IER.
*/
via2[rSIER] = IER_SET_BIT(irq_idx); via2[rSIER] = IER_SET_BIT(irq_idx);
} else { break;
/* Make sure the bit is an input, to enable the irq */ case MAC_VIA_QUADRA:
/* But not on PowerBooks, that's ADB... */ /* 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) && if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
(macintosh_config->adb_type != MAC_ADB_PB2)) { (macintosh_config->adb_type != MAC_ADB_PB2))
switch(macintosh_config->ident) via2[vDirA] &= ~(1 << irq_idx);
{
case MAC_MODEL_II:
case MAC_MODEL_IIX:
case MAC_MODEL_IICX:
case MAC_MODEL_SE30:
via2[vDirA] &= (~irq_bit | 0xc0);
break; break;
default:
via2[vDirA] &= ~irq_bit;
}
}
} }
} }
} }
...@@ -580,29 +597,31 @@ void via_irq_enable(int irq) { ...@@ -580,29 +597,31 @@ void via_irq_enable(int irq) {
void via_irq_disable(int irq) { void via_irq_disable(int irq) {
int irq_src = IRQ_SRC(irq); int irq_src = IRQ_SRC(irq);
int irq_idx = IRQ_IDX(irq); int irq_idx = IRQ_IDX(irq);
int irq_bit = 1 << irq_idx;
#ifdef DEBUG_IRQUSE #ifdef DEBUG_IRQUSE
printk(KERN_DEBUG "via_irq_disable(%d)\n", irq); printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
#endif #endif
if (irq_src == 1) { if (irq_src == 1) {
via1[vIER] = irq_bit & 0x7F; via1[vIER] = IER_CLR_BIT(irq_idx);
} else if (irq_src == 2) { } else if (irq_src == 2) {
via2[gIER] = irq_bit & 0x7F; via2[gIER] = IER_CLR_BIT(irq_idx);
} else if (irq_src == 7) { } else if (irq_src == 7) {
if (rbv_present) { switch (macintosh_config->via_type) {
/* disable the slot interrupt. SIER works like IER. */ case MAC_VIA_II:
nubus_disabled |= 1 << irq_idx;
if (nubus_disabled)
via2[gIER] = IER_CLR_BIT(1);
break;
case MAC_VIA_IIci:
via2[rSIER] = IER_CLR_BIT(irq_idx); via2[rSIER] = IER_CLR_BIT(irq_idx);
} else { break;
/* disable the nubus irq by changing dir to output */ case MAC_VIA_QUADRA:
/* except on PMU */
if ((macintosh_config->adb_type != MAC_ADB_PB1) && if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
(macintosh_config->adb_type != MAC_ADB_PB2)) { (macintosh_config->adb_type != MAC_ADB_PB2))
via2[vDirA] |= irq_bit; via2[vDirA] |= 1 << irq_idx;
} break;
} }
nubus_active &= ~irq_bit;
} }
} }
...@@ -638,7 +657,7 @@ int via_irq_pending(int irq) ...@@ -638,7 +657,7 @@ int via_irq_pending(int irq)
} else if (irq_src == 2) { } else if (irq_src == 2) {
return via2[gIFR] & irq_bit; return via2[gIFR] & irq_bit;
} else if (irq_src == 7) { } else if (irq_src == 7) {
/* FIXME: this can't work while a slot irq is disabled! */ /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */
return ~via2[gBufA] & irq_bit; return ~via2[gBufA] & irq_bit;
} }
return 0; return 0;
......
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