Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Finn Thain and committed by
Linus Torvalds
f4d86754 d74472f0

+61 -33
+19 -4
drivers/net/jazzsonic.c
··· 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; ··· 186 169 lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS 187 170 * SONIC_BUS_SCALE(lp->dma_bitmode)); 188 171 189 - dev->open = sonic_open; 190 - dev->stop = sonic_close; 172 + dev->open = jazzsonic_open; 173 + dev->stop = jazzsonic_close; 191 174 dev->hard_start_xmit = sonic_send_packet; 192 175 dev->get_stats = sonic_get_stats; 193 176 dev->set_multicast_list = &sonic_multicast_list; ··· 276 259 MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); 277 260 module_param(sonic_debug, int, 0); 278 261 MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); 279 - 280 - #define SONIC_IRQ_FLAG IRQF_DISABLED 281 262 282 263 #include "sonic.c" 283 264
+42 -4
drivers/net/macsonic.c
··· 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); ··· 200 160 lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS 201 161 * SONIC_BUS_SCALE(lp->dma_bitmode)); 202 162 203 - dev->open = sonic_open; 204 - dev->stop = sonic_close; 163 + dev->open = macsonic_open; 164 + dev->stop = macsonic_close; 205 165 dev->hard_start_xmit = sonic_send_packet; 206 166 dev->get_stats = sonic_get_stats; 207 167 dev->set_multicast_list = &sonic_multicast_list; ··· 611 571 MODULE_DESCRIPTION("Macintosh SONIC ethernet driver"); 612 572 module_param(sonic_debug, int, 0); 613 573 MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); 614 - 615 - #define SONIC_IRQ_FLAG IRQ_FLG_FAST 616 574 617 575 #include "sonic.c" 618 576
-25
drivers/net/sonic.c
··· 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) { ··· 145 168 lp->rx_skb[i] = NULL; 146 169 } 147 170 } 148 - 149 - free_irq(dev->irq, dev); /* release the IRQ */ 150 171 151 172 return 0; 152 173 }