diff options
Diffstat (limited to 'debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff')
-rw-r--r-- | debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff b/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff new file mode 100644 index 000000000000..fb367101d197 --- /dev/null +++ b/debian/patches/bugfix/m68k/mac68k-irq-plan-e.diff @@ -0,0 +1,270 @@ +Subject: [PATCH 7/13] m68k: Mac nubus IRQ fixes (plan E) + +From: Finn Thain <fthain@telegraphics.com.au> + +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> +--- + arch/m68k/mac/via.c | 141 +++++++++++++++++++++++++++++----------------------- + 1 file changed, 80 insertions(+), 61 deletions(-) + +--- linux-m68k-2.6.21.orig/arch/m68k/mac/via.c ++++ linux-m68k-2.6.21/arch/m68k/mac/via.c +@@ -64,7 +64,19 @@ static int gIER,gIFR,gBufA,gBufB; + #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) + #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); + irqreturn_t via1_irq(int, void *); +@@ -383,9 +395,6 @@ int via_get_cache_disable(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 */ + + if ((macintosh_config->adb_type != MAC_ADB_PB1) && +@@ -399,28 +408,35 @@ void __init via_nubus_init(void) + via2[gBufB] |= 0x02; + } + +- /* disable nubus slot interrupts. */ +- if (rbv_present) { ++ /* Disable all the slot interrupts (where possible). */ ++ ++ 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; ++ } ++ break; ++ case MAC_VIA_IIci: ++ /* RBV. Disable all the slot interrupts. SIER works like IER. */ + via2[rSIER] = 0x7F; +- via2[rSIER] = nubus_active | 0x80; +- } else { +- /* These are ADB bits on PMU */ ++ 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)) { +- switch(macintosh_config->ident) +- { +- case MAC_MODEL_II: +- case MAC_MODEL_IIX: +- case MAC_MODEL_IICX: +- case MAC_MODEL_SE30: +- via2[vBufA] |= 0x3F; +- via2[vDirA] = ~nubus_active | 0xc0; +- break; +- default: +- via2[vBufA] = 0xFF; +- via2[vDirA] = ~nubus_active; +- } ++ (macintosh_config->adb_type != MAC_ADB_PB2)) { ++ via2[vBufA] |= 0x7F; ++ via2[vDirA] |= 0x7F; + } ++ break; + } + } + +@@ -489,7 +505,8 @@ irqreturn_t via2_irq(int irq, void *dev_ + via2[gIER] = irq_bit; + via2[gIFR] = irq_bit | rbv_clear; + m68k_handle_int(irq_num); +- via2[gIER] = irq_bit | 0x80; ++ if (irq_num != IRQ_MAC_NUBUS || nubus_disabled == 0) ++ via2[gIER] = irq_bit | 0x80; + } + ++irq_num; + irq_bit <<= 1; +@@ -511,7 +528,7 @@ irqreturn_t via_nubus_irq(int irq, void + if (rbv_present) + events &= via2[rSIER]; + else +- events &= nubus_active; ++ events &= ~via2[vDirA]; + if (!events) + return IRQ_NONE; + +@@ -533,7 +550,7 @@ irqreturn_t via_nubus_irq(int irq, void + if (rbv_present) + events &= via2[rSIER]; + else +- events &= nubus_active; ++ events &= ~via2[vDirA]; + } while (events); + return IRQ_HANDLED; + } +@@ -541,38 +558,38 @@ irqreturn_t via_nubus_irq(int irq, void + void via_irq_enable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); +- int irq_bit = 1 << irq_idx; + + #ifdef DEBUG_IRQUSE + printk(KERN_DEBUG "via_irq_enable(%d)\n", irq); + #endif + + if (irq_src == 1) { +- via1[vIER] = irq_bit | 0x80; ++ via1[vIER] = IER_SET_BIT(irq_idx); + } 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) { +- nubus_active |= irq_bit; +- if (rbv_present) { +- /* enable the slot interrupt. SIER works like IER. */ ++ switch (macintosh_config->via_type) { ++ case MAC_VIA_II: ++ 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); +- } else { +- /* Make sure the bit is an input, to enable the irq */ +- /* But not on PowerBooks, that's ADB... */ ++ 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)) { +- switch(macintosh_config->ident) +- { +- case MAC_MODEL_II: +- case MAC_MODEL_IIX: +- case MAC_MODEL_IICX: +- case MAC_MODEL_SE30: +- via2[vDirA] &= (~irq_bit | 0xc0); +- break; +- default: +- via2[vDirA] &= ~irq_bit; +- } +- } ++ (macintosh_config->adb_type != MAC_ADB_PB2)) ++ via2[vDirA] &= ~(1 << irq_idx); ++ break; + } + } + } +@@ -580,29 +597,31 @@ void via_irq_enable(int irq) { + void via_irq_disable(int irq) { + int irq_src = IRQ_SRC(irq); + int irq_idx = IRQ_IDX(irq); +- int irq_bit = 1 << irq_idx; + + #ifdef DEBUG_IRQUSE + printk(KERN_DEBUG "via_irq_disable(%d)\n", irq); + #endif + + if (irq_src == 1) { +- via1[vIER] = irq_bit & 0x7F; ++ via1[vIER] = IER_CLR_BIT(irq_idx); + } else if (irq_src == 2) { +- via2[gIER] = irq_bit & 0x7F; ++ via2[gIER] = IER_CLR_BIT(irq_idx); + } else if (irq_src == 7) { +- if (rbv_present) { +- /* disable the slot interrupt. SIER works like IER. */ ++ switch (macintosh_config->via_type) { ++ 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); +- } else { +- /* disable the nubus irq by changing dir to output */ +- /* except on PMU */ ++ break; ++ case MAC_VIA_QUADRA: + if ((macintosh_config->adb_type != MAC_ADB_PB1) && +- (macintosh_config->adb_type != MAC_ADB_PB2)) { +- via2[vDirA] |= irq_bit; +- } ++ (macintosh_config->adb_type != MAC_ADB_PB2)) ++ via2[vDirA] |= 1 << irq_idx; ++ break; + } +- nubus_active &= ~irq_bit; + } + } + +@@ -638,7 +657,7 @@ int via_irq_pending(int irq) + } else if (irq_src == 2) { + return via2[gIFR] & irq_bit; + } 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 0; |