diff options
author | Finn Thain <fthain@telegraphics.com.au> | 2011-10-23 10:11:17 -0400 |
---|---|---|
committer | Geert Uytterhoeven <geert@linux-m68k.org> | 2011-12-10 13:52:47 -0500 |
commit | c4af5da7f24ff1bf60db2d6ff3e9d9bd912ca47a (patch) | |
tree | 2f653a61672f5720e436411526ab6339838fb3bc /arch/m68k/mac | |
parent | 8d9f014ad16711d79c8a575f2d3d009d2a16c7b7 (diff) |
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: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'arch/m68k/mac')
-rw-r--r-- | arch/m68k/mac/macints.c | 27 | ||||
-rw-r--r-- | arch/m68k/mac/via.c | 123 |
2 files changed, 108 insertions, 42 deletions
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c index 41dd164aac27..74f5a97c9860 100644 --- a/arch/m68k/mac/macints.c +++ b/arch/m68k/mac/macints.c | |||
@@ -151,10 +151,15 @@ irqreturn_t mac_debug_handler(int, void *); | |||
151 | 151 | ||
152 | /* #define DEBUG_MACINTS */ | 152 | /* #define DEBUG_MACINTS */ |
153 | 153 | ||
154 | static unsigned int mac_irq_startup(struct irq_data *); | ||
155 | static void mac_irq_shutdown(struct irq_data *); | ||
156 | |||
154 | static struct irq_chip mac_irq_chip = { | 157 | static struct irq_chip mac_irq_chip = { |
155 | .name = "mac", | 158 | .name = "mac", |
156 | .irq_enable = mac_irq_enable, | 159 | .irq_enable = mac_irq_enable, |
157 | .irq_disable = mac_irq_disable, | 160 | .irq_disable = mac_irq_disable, |
161 | .irq_startup = mac_irq_startup, | ||
162 | .irq_shutdown = mac_irq_shutdown, | ||
158 | }; | 163 | }; |
159 | 164 | ||
160 | void __init mac_init_IRQ(void) | 165 | void __init mac_init_IRQ(void) |
@@ -274,6 +279,28 @@ void mac_irq_disable(struct irq_data *data) | |||
274 | } | 279 | } |
275 | } | 280 | } |
276 | 281 | ||
282 | static unsigned int mac_irq_startup(struct irq_data *data) | ||
283 | { | ||
284 | int irq = data->irq; | ||
285 | |||
286 | if (IRQ_SRC(irq) == 7 && !oss_present) | ||
287 | via_nubus_irq_startup(irq); | ||
288 | else | ||
289 | mac_irq_enable(data); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static void mac_irq_shutdown(struct irq_data *data) | ||
295 | { | ||
296 | int irq = data->irq; | ||
297 | |||
298 | if (IRQ_SRC(irq) == 7 && !oss_present) | ||
299 | via_nubus_irq_shutdown(irq); | ||
300 | else | ||
301 | mac_irq_disable(data); | ||
302 | } | ||
303 | |||
277 | static int num_debug[8]; | 304 | static int num_debug[8]; |
278 | 305 | ||
279 | irqreturn_t mac_debug_handler(int irq, void *dev_id) | 306 | irqreturn_t mac_debug_handler(int irq, void *dev_id) |
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index 642b44615f78..97996a48b048 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c | |||
@@ -63,18 +63,47 @@ static int gIER,gIFR,gBufA,gBufB; | |||
63 | #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) | 63 | #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) |
64 | #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) | 64 | #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) |
65 | 65 | ||
66 | /* To disable a NuBus slot on Quadras we make that slot IRQ line an output set | 66 | |
67 | * high. On RBV we just use the slot interrupt enable register. On Macs with | 67 | /* |
68 | * genuine VIA chips we must use nubus_disabled to keep track of disabled slot | 68 | * On Macs with a genuine VIA chip there is no way to mask an individual slot |
69 | * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1 | 69 | * interrupt. This limitation also seems to apply to VIA clone logic cores in |
70 | * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt. | 70 | * Quadra-like ASICs. (RBV and OSS machines don't have this limitation.) |
71 | * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble, | 71 | * |
72 | * because closing one of those drivers can mask all of the NuBus interrupts. | 72 | * We used to fake it by configuring the relevent VIA pin as an output |
73 | * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's | 73 | * (to mask the interrupt) or input (to unmask). That scheme did not work on |
74 | * possible to get interrupts from cards that MacOS or the ROM has configured | 74 | * (at least) the Quadra 700. A NuBus card's /NMRQ signal is an open-collector |
75 | * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and | 75 | * circuit (see Designing Cards and Drivers for Macintosh II and Macintosh SE, |
76 | * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS. | 76 | * p. 10-11 etc) but VIA outputs are not (see datasheet). |
77 | * | ||
78 | * Driving these outputs high must cause the VIA to source current and the | ||
79 | * card to sink current when it asserts /NMRQ. Current will flow but the pin | ||
80 | * voltage is uncertain and so the /NMRQ condition may still cause a transition | ||
81 | * at the VIA2 CA1 input (which explains the lost interrupts). A side effect | ||
82 | * is that a disabled slot IRQ can never be tested as pending or not. | ||
83 | * | ||
84 | * Driving these outputs low doesn't work either. All the slot /NMRQ lines are | ||
85 | * (active low) OR'd together to generate the CA1 (aka "SLOTS") interrupt (see | ||
86 | * The Guide To Macintosh Family Hardware, 2nd edition p. 167). If we drive a | ||
87 | * disabled /NMRQ line low, the falling edge immediately triggers a CA1 | ||
88 | * interrupt and all slot interrupts after that will generate no transition | ||
89 | * and therefore no interrupt, even after being re-enabled. | ||
90 | * | ||
91 | * So we make the VIA port A I/O lines inputs and use nubus_disabled to keep | ||
92 | * track of their states. When any slot IRQ becomes disabled we mask the CA1 | ||
93 | * umbrella interrupt. Only when all slot IRQs become enabled do we unmask | ||
94 | * the CA1 interrupt. It must remain enabled even when cards have no interrupt | ||
95 | * handler registered. Drivers must therefore disable a slot interrupt at the | ||
96 | * device before they call free_irq (like shared and autovector interrupts). | ||
97 | * | ||
98 | * There is also a related problem when MacOS is used to boot Linux. A network | ||
99 | * card brought up by a MacOS driver may raise an interrupt while Linux boots. | ||
100 | * This can be fatal since it can't be handled until the right driver loads | ||
101 | * (if such a driver exists at all). Apparently related to this hardware | ||
102 | * limitation, "Designing Cards and Drivers", p. 9-8, says that a slot | ||
103 | * interrupt with no driver would crash MacOS (the book was written before | ||
104 | * the appearance of Macs with RBV or OSS). | ||
77 | */ | 105 | */ |
106 | |||
78 | static u8 nubus_disabled; | 107 | static u8 nubus_disabled; |
79 | 108 | ||
80 | void via_debug_dump(void); | 109 | void via_debug_dump(void); |
@@ -354,34 +383,55 @@ void __init via_nubus_init(void) | |||
354 | via2[gBufB] |= 0x02; | 383 | via2[gBufB] |= 0x02; |
355 | } | 384 | } |
356 | 385 | ||
357 | /* Disable all the slot interrupts (where possible). */ | 386 | /* |
387 | * Disable the slot interrupts. On some hardware that's not possible. | ||
388 | * On some hardware it's unclear what all of these I/O lines do. | ||
389 | */ | ||
358 | 390 | ||
359 | switch (macintosh_config->via_type) { | 391 | switch (macintosh_config->via_type) { |
360 | case MAC_VIA_II: | 392 | case MAC_VIA_II: |
361 | /* Just make the port A lines inputs. */ | 393 | case MAC_VIA_QUADRA: |
362 | switch(macintosh_config->ident) { | 394 | pr_debug("VIA2 vDirA is 0x%02X\n", via2[vDirA]); |
363 | case MAC_MODEL_II: | ||
364 | case MAC_MODEL_IIX: | ||
365 | case MAC_MODEL_IICX: | ||
366 | case MAC_MODEL_SE30: | ||
367 | /* The top two bits are RAM size outputs. */ | ||
368 | via2[vDirA] &= 0xC0; | ||
369 | break; | ||
370 | default: | ||
371 | via2[vDirA] &= 0x80; | ||
372 | } | ||
373 | break; | 395 | break; |
374 | case MAC_VIA_IIci: | 396 | case MAC_VIA_IIci: |
375 | /* RBV. Disable all the slot interrupts. SIER works like IER. */ | 397 | /* RBV. Disable all the slot interrupts. SIER works like IER. */ |
376 | via2[rSIER] = 0x7F; | 398 | via2[rSIER] = 0x7F; |
377 | break; | 399 | break; |
400 | } | ||
401 | } | ||
402 | |||
403 | void via_nubus_irq_startup(int irq) | ||
404 | { | ||
405 | int irq_idx = IRQ_IDX(irq); | ||
406 | |||
407 | switch (macintosh_config->via_type) { | ||
408 | case MAC_VIA_II: | ||
378 | case MAC_VIA_QUADRA: | 409 | case MAC_VIA_QUADRA: |
379 | /* Disable the inactive slot interrupts by making those lines outputs. */ | 410 | /* Make the port A line an input. Probably redundant. */ |
380 | if ((macintosh_config->adb_type != MAC_ADB_PB1) && | 411 | if (macintosh_config->via_type == MAC_VIA_II) { |
381 | (macintosh_config->adb_type != MAC_ADB_PB2)) { | 412 | /* The top two bits are RAM size outputs. */ |
382 | via2[vBufA] |= 0x7F; | 413 | via2[vDirA] &= 0xC0 | ~(1 << irq_idx); |
383 | via2[vDirA] |= 0x7F; | 414 | } else { |
415 | /* Allow NuBus slots 9 through F. */ | ||
416 | via2[vDirA] &= 0x80 | ~(1 << irq_idx); | ||
384 | } | 417 | } |
418 | /* fall through */ | ||
419 | case MAC_VIA_IIci: | ||
420 | via_irq_enable(irq); | ||
421 | break; | ||
422 | } | ||
423 | } | ||
424 | |||
425 | void via_nubus_irq_shutdown(int irq) | ||
426 | { | ||
427 | switch (macintosh_config->via_type) { | ||
428 | case MAC_VIA_II: | ||
429 | case MAC_VIA_QUADRA: | ||
430 | /* Ensure that the umbrella CA1 interrupt remains enabled. */ | ||
431 | via_irq_enable(irq); | ||
432 | break; | ||
433 | case MAC_VIA_IIci: | ||
434 | via_irq_disable(irq); | ||
385 | break; | 435 | break; |
386 | } | 436 | } |
387 | } | 437 | } |
@@ -507,6 +557,7 @@ void via_irq_enable(int irq) { | |||
507 | } else if (irq_src == 7) { | 557 | } else if (irq_src == 7) { |
508 | switch (macintosh_config->via_type) { | 558 | switch (macintosh_config->via_type) { |
509 | case MAC_VIA_II: | 559 | case MAC_VIA_II: |
560 | case MAC_VIA_QUADRA: | ||
510 | nubus_disabled &= ~(1 << irq_idx); | 561 | nubus_disabled &= ~(1 << irq_idx); |
511 | /* Enable the CA1 interrupt when no slot is disabled. */ | 562 | /* Enable the CA1 interrupt when no slot is disabled. */ |
512 | if (!nubus_disabled) | 563 | if (!nubus_disabled) |
@@ -518,14 +569,6 @@ void via_irq_enable(int irq) { | |||
518 | */ | 569 | */ |
519 | via2[rSIER] = IER_SET_BIT(irq_idx); | 570 | via2[rSIER] = IER_SET_BIT(irq_idx); |
520 | break; | 571 | break; |
521 | case MAC_VIA_QUADRA: | ||
522 | /* Make the port A line an input to enable the slot irq. | ||
523 | * But not on PowerBooks, that's ADB. | ||
524 | */ | ||
525 | if ((macintosh_config->adb_type != MAC_ADB_PB1) && | ||
526 | (macintosh_config->adb_type != MAC_ADB_PB2)) | ||
527 | via2[vDirA] &= ~(1 << irq_idx); | ||
528 | break; | ||
529 | } | 572 | } |
530 | } | 573 | } |
531 | } | 574 | } |
@@ -545,6 +588,7 @@ void via_irq_disable(int irq) { | |||
545 | } else if (irq_src == 7) { | 588 | } else if (irq_src == 7) { |
546 | switch (macintosh_config->via_type) { | 589 | switch (macintosh_config->via_type) { |
547 | case MAC_VIA_II: | 590 | case MAC_VIA_II: |
591 | case MAC_VIA_QUADRA: | ||
548 | nubus_disabled |= 1 << irq_idx; | 592 | nubus_disabled |= 1 << irq_idx; |
549 | if (nubus_disabled) | 593 | if (nubus_disabled) |
550 | via2[gIER] = IER_CLR_BIT(1); | 594 | via2[gIER] = IER_CLR_BIT(1); |
@@ -552,11 +596,6 @@ void via_irq_disable(int irq) { | |||
552 | case MAC_VIA_IIci: | 596 | case MAC_VIA_IIci: |
553 | via2[rSIER] = IER_CLR_BIT(irq_idx); | 597 | via2[rSIER] = IER_CLR_BIT(irq_idx); |
554 | break; | 598 | break; |
555 | case MAC_VIA_QUADRA: | ||
556 | if ((macintosh_config->adb_type != MAC_ADB_PB1) && | ||
557 | (macintosh_config->adb_type != MAC_ADB_PB2)) | ||
558 | via2[vDirA] |= 1 << irq_idx; | ||
559 | break; | ||
560 | } | 599 | } |
561 | } | 600 | } |
562 | } | 601 | } |