static irqreturn_t smc_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; int status, mask, timeout, card_stats; int saved_pointer; DBG(3, "%s: %s\n", dev->name, __func__); spin_lock(&lp->lock); SMC_INTERRUPT_PREAMBLE; saved_pointer = SMC_GET_PTR(lp); mask = SMC_GET_INT_MASK(lp); SMC_SET_INT_MASK(lp, 0); timeout = MAX_IRQ_LOOPS; do { status = SMC_GET_INT(lp); DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", dev->name, status, mask, ({ int meminfo; SMC_SELECT_BANK(lp, 0); meminfo = SMC_GET_MIR(lp); SMC_SELECT_BANK(lp, 2); meminfo; }), SMC_GET_FIFO(lp)); status &= mask; if (!status) break; if (status & IM_TX_INT) { DBG(3, "%s: TX int\n", dev->name); smc_tx(dev); SMC_ACK_INT(lp, IM_TX_INT); if (THROTTLE_TX_PKTS) netif_wake_queue(dev); } else if (status & IM_RCV_INT) { DBG(3, "%s: RX irq\n", dev->name); smc_rcv(dev); } else if (status & IM_ALLOC_INT) { DBG(3, "%s: Allocation irq\n", dev->name); tasklet_hi_schedule(&lp->tx_task); mask &= ~IM_ALLOC_INT; } else if (status & IM_TX_EMPTY_INT) { DBG(3, "%s: TX empty\n", dev->name); mask &= ~IM_TX_EMPTY_INT; SMC_SELECT_BANK(lp, 0); card_stats = SMC_GET_COUNTER(lp); SMC_SELECT_BANK(lp, 2); dev->stats.collisions += card_stats & 0xF; card_stats >>= 4; dev->stats.collisions += card_stats & 0xF; } else if (status & IM_RX_OVRN_INT) {
/* * This is the main routine of the driver, to handle the device when * it needs some attention. */ static irqreturn_t smc_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; int status, mask, timeout, card_stats; int saved_pointer; DBG(3, "%s: %s\n", dev->name, __func__); spin_lock(&lp->lock); /* A preamble may be used when there is a potential race * between the interruptible transmit functions and this * ISR. */ SMC_INTERRUPT_PREAMBLE; saved_pointer = SMC_GET_PTR(lp); mask = SMC_GET_INT_MASK(lp); SMC_SET_INT_MASK(lp, 0); /* set a timeout value, so I don't stay here forever */ timeout = MAX_IRQ_LOOPS; do { status = SMC_GET_INT(lp); DBG(2, "%s: INT 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n", dev->name, status, mask, ({ int meminfo; SMC_SELECT_BANK(lp, 0); meminfo = SMC_GET_MIR(lp); SMC_SELECT_BANK(lp, 2); meminfo; }), SMC_GET_FIFO(lp)); status &= mask; if (!status) break; if (status & IM_TX_INT) { /* do this before RX as it will free memory quickly */ DBG(3, "%s: TX int\n", dev->name); smc_tx(dev); SMC_ACK_INT(lp, IM_TX_INT); if (THROTTLE_TX_PKTS) netif_wake_queue(dev); } else if (status & IM_RCV_INT) { DBG(3, "%s: RX irq\n", dev->name); smc_rcv(dev); } else if (status & IM_ALLOC_INT) { DBG(3, "%s: Allocation irq\n", dev->name); tasklet_hi_schedule(&lp->tx_task); mask &= ~IM_ALLOC_INT; } else if (status & IM_TX_EMPTY_INT) { DBG(3, "%s: TX empty\n", dev->name); mask &= ~IM_TX_EMPTY_INT; /* update stats */ SMC_SELECT_BANK(lp, 0); card_stats = SMC_GET_COUNTER(lp); SMC_SELECT_BANK(lp, 2); /* single collisions */ dev->stats.collisions += card_stats & 0xF; card_stats >>= 4; /* multiple collisions */ dev->stats.collisions += card_stats & 0xF; } else if (status & IM_RX_OVRN_INT) {