Commit f4d86754f956ab5ea73aa91759a0d89a2f0e3f2a
Committed by
Linus Torvalds
1 parent
d74472f0b2
Exists in
master
and in
4 other branches
SONIC interrupt handling
Install the built-in macsonic interrupt handler on both IRQs when using via_alt_mapping. Otherwise the rare interrupt that still comes from the nubus slot will wedge the nubus. $ cat /proc/interrupts auto 2: 89176 via2 auto 3: 744367 sonic auto 4: 0 scc auto 6: 318363 via1 auto 7: 0 NMI mac 9: 119413 framebuffer vbl mac 10: 1971 ADB mac 14: 198517 timer mac 17: 89104 nubus mac 19: 72 Mac ESP SCSI mac 56: 629 sonic mac 62: 1142593 ide0 Version 1 of this patch had a bug where a nubus sonic card would register two interrupt handlers. Only a built-in sonic needs both. Versions 2 and 3 needed some cleanups, as Raylynn Knight and Christoph Hellwig pointed out (thanks). Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 61 additions and 33 deletions Side-by-side Diff
drivers/net/jazzsonic.c
| ... | ... | @@ -88,6 +88,23 @@ |
| 88 | 88 | 0xffff /* end of list */ |
| 89 | 89 | }; |
| 90 | 90 | |
| 91 | +static int jazzsonic_open(struct net_device* dev) | |
| 92 | +{ | |
| 93 | + if (request_irq(dev->irq, &sonic_interrupt, IRQF_DISABLED, "sonic", dev)) { | |
| 94 | + printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); | |
| 95 | + return -EAGAIN; | |
| 96 | + } | |
| 97 | + return sonic_open(dev); | |
| 98 | +} | |
| 99 | + | |
| 100 | +static int jazzsonic_close(struct net_device* dev) | |
| 101 | +{ | |
| 102 | + int err; | |
| 103 | + err = sonic_close(dev); | |
| 104 | + free_irq(dev->irq, dev); | |
| 105 | + return err; | |
| 106 | +} | |
| 107 | + | |
| 91 | 108 | static int __init sonic_probe1(struct net_device *dev) |
| 92 | 109 | { |
| 93 | 110 | static unsigned version_printed; |
| ... | ... | @@ -169,8 +186,8 @@ |
| 169 | 186 | lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS |
| 170 | 187 | * SONIC_BUS_SCALE(lp->dma_bitmode)); |
| 171 | 188 | |
| 172 | - dev->open = sonic_open; | |
| 173 | - dev->stop = sonic_close; | |
| 189 | + dev->open = jazzsonic_open; | |
| 190 | + dev->stop = jazzsonic_close; | |
| 174 | 191 | dev->hard_start_xmit = sonic_send_packet; |
| 175 | 192 | dev->get_stats = sonic_get_stats; |
| 176 | 193 | dev->set_multicast_list = &sonic_multicast_list; |
| ... | ... | @@ -259,8 +276,6 @@ |
| 259 | 276 | MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); |
| 260 | 277 | module_param(sonic_debug, int, 0); |
| 261 | 278 | MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); |
| 262 | - | |
| 263 | -#define SONIC_IRQ_FLAG IRQF_DISABLED | |
| 264 | 279 | |
| 265 | 280 | #include "sonic.c" |
| 266 | 281 |
drivers/net/macsonic.c
| ... | ... | @@ -130,6 +130,46 @@ |
| 130 | 130 | addr[i] = bitrev8(addr[i]); |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | +static irqreturn_t macsonic_interrupt(int irq, void *dev_id) | |
| 134 | +{ | |
| 135 | + irqreturn_t result; | |
| 136 | + unsigned long flags; | |
| 137 | + | |
| 138 | + local_irq_save(flags); | |
| 139 | + result = sonic_interrupt(irq, dev_id); | |
| 140 | + local_irq_restore(flags); | |
| 141 | + return result; | |
| 142 | +} | |
| 143 | + | |
| 144 | +static int macsonic_open(struct net_device* dev) | |
| 145 | +{ | |
| 146 | + if (request_irq(dev->irq, &sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { | |
| 147 | + printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); | |
| 148 | + return -EAGAIN; | |
| 149 | + } | |
| 150 | + /* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes | |
| 151 | + * in at priority level 3. However, we sometimes get the level 2 inter- | |
| 152 | + * rupt as well, which must prevent re-entrance of the sonic handler. | |
| 153 | + */ | |
| 154 | + if (dev->irq == IRQ_AUTO_3) | |
| 155 | + if (request_irq(IRQ_NUBUS_9, &macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { | |
| 156 | + printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9); | |
| 157 | + free_irq(dev->irq, dev); | |
| 158 | + return -EAGAIN; | |
| 159 | + } | |
| 160 | + return sonic_open(dev); | |
| 161 | +} | |
| 162 | + | |
| 163 | +static int macsonic_close(struct net_device* dev) | |
| 164 | +{ | |
| 165 | + int err; | |
| 166 | + err = sonic_close(dev); | |
| 167 | + free_irq(dev->irq, dev); | |
| 168 | + if (dev->irq == IRQ_AUTO_3) | |
| 169 | + free_irq(IRQ_NUBUS_9, dev); | |
| 170 | + return err; | |
| 171 | +} | |
| 172 | + | |
| 133 | 173 | int __init macsonic_init(struct net_device* dev) |
| 134 | 174 | { |
| 135 | 175 | struct sonic_local* lp = netdev_priv(dev); |
| ... | ... | @@ -160,8 +200,8 @@ |
| 160 | 200 | lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS |
| 161 | 201 | * SONIC_BUS_SCALE(lp->dma_bitmode)); |
| 162 | 202 | |
| 163 | - dev->open = sonic_open; | |
| 164 | - dev->stop = sonic_close; | |
| 203 | + dev->open = macsonic_open; | |
| 204 | + dev->stop = macsonic_close; | |
| 165 | 205 | dev->hard_start_xmit = sonic_send_packet; |
| 166 | 206 | dev->get_stats = sonic_get_stats; |
| 167 | 207 | dev->set_multicast_list = &sonic_multicast_list; |
| ... | ... | @@ -571,8 +611,6 @@ |
| 571 | 611 | MODULE_DESCRIPTION("Macintosh SONIC ethernet driver"); |
| 572 | 612 | module_param(sonic_debug, int, 0); |
| 573 | 613 | MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); |
| 574 | - | |
| 575 | -#define SONIC_IRQ_FLAG IRQ_FLG_FAST | |
| 576 | 614 | |
| 577 | 615 | #include "sonic.c" |
| 578 | 616 |
drivers/net/sonic.c
| ... | ... | @@ -50,29 +50,6 @@ |
| 50 | 50 | if (sonic_debug > 2) |
| 51 | 51 | printk("sonic_open: initializing sonic driver.\n"); |
| 52 | 52 | |
| 53 | - /* | |
| 54 | - * We don't need to deal with auto-irq stuff since we | |
| 55 | - * hardwire the sonic interrupt. | |
| 56 | - */ | |
| 57 | -/* | |
| 58 | - * XXX Horrible work around: We install sonic_interrupt as fast interrupt. | |
| 59 | - * This means that during execution of the handler interrupt are disabled | |
| 60 | - * covering another bug otherwise corrupting data. This doesn't mean | |
| 61 | - * this glue works ok under all situations. | |
| 62 | - * | |
| 63 | - * Note (dhd): this also appears to prevent lockups on the Macintrash | |
| 64 | - * when more than one Ethernet card is installed (knock on wood) | |
| 65 | - * | |
| 66 | - * Note (fthain): whether the above is still true is anyones guess. Certainly | |
| 67 | - * the buffer handling algorithms will not tolerate re-entrance without some | |
| 68 | - * mutual exclusion added. Anyway, the memcpy has now been eliminated from the | |
| 69 | - * rx code to make this a faster "fast interrupt". | |
| 70 | - */ | |
| 71 | - if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) { | |
| 72 | - printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); | |
| 73 | - return -EAGAIN; | |
| 74 | - } | |
| 75 | - | |
| 76 | 53 | for (i = 0; i < SONIC_NUM_RRS; i++) { |
| 77 | 54 | struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2); |
| 78 | 55 | if (skb == NULL) { |
| ... | ... | @@ -168,8 +145,6 @@ |
| 168 | 145 | lp->rx_skb[i] = NULL; |
| 169 | 146 | } |
| 170 | 147 | } |
| 171 | - | |
| 172 | - free_irq(dev->irq, dev); /* release the IRQ */ | |
| 173 | 148 | |
| 174 | 149 | return 0; |
| 175 | 150 | } |