static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; unsigned int numPages, poll_count, status; unsigned long flags; DBG(3, "%s: %s\n", dev->name, __func__); BUG_ON(lp->pending_tx_skb != NULL); numPages = ((skb->len & ~1) + (6 - 1)) >> 8; if (unlikely(numPages > 7)) { printk("%s: Far too big packet error.\n", dev->name); dev->stats.tx_errors++; dev->stats.tx_dropped++; dev_kfree_skb(skb); return NETDEV_TX_OK; } smc_special_lock(&lp->lock, flags); SMC_SET_MMU_CMD(lp, MC_ALLOC | numPages); poll_count = MEMORY_WAIT_TIME; do { status = SMC_GET_INT(lp); if (status & IM_ALLOC_INT) { SMC_ACK_INT(lp, IM_ALLOC_INT); break; } } while (--poll_count); smc_special_unlock(&lp->lock, flags); lp->pending_tx_skb = skb; if (!poll_count) { netif_stop_queue(dev); DBG(2, "%s: TX memory allocation deferred.\n", dev->name); SMC_ENABLE_INT(lp, IM_ALLOC_INT); } else { smc_hardware_send_pkt((unsigned long)dev); } return NETDEV_TX_OK; }
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) {
/* * Since I am not sure if I will have enough room in the chip's ram * to store the packet, I call this routine which either sends it * now, or set the card to generates an interrupt when ready * for the packet. */ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct smc_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; unsigned int numPages, poll_count, status; unsigned long flags; DBG(3, "%s: %s\n", dev->name, __func__); BUG_ON(lp->pending_tx_skb != NULL); /* * The MMU wants the number of pages to be the number of 256 bytes * 'pages', minus 1 (since a packet can't ever have 0 pages :)) * * The 91C111 ignores the size bits, but earlier models don't. * * Pkt size for allocating is data length +6 (for additional status * words, length and ctl) * * If odd size then last byte is included in ctl word. */ numPages = ((skb->len & ~1) + (6 - 1)) >> 8; if (unlikely(numPages > 7)) { printk("%s: Far too big packet error.\n", dev->name); dev->stats.tx_errors++; dev->stats.tx_dropped++; dev_kfree_skb(skb); return NETDEV_TX_OK; } smc_special_lock(&lp->lock, flags); /* now, try to allocate the memory */ SMC_SET_MMU_CMD(lp, MC_ALLOC | numPages); /* * Poll the chip for a short amount of time in case the * allocation succeeds quickly. */ poll_count = MEMORY_WAIT_TIME; do { status = SMC_GET_INT(lp); if (status & IM_ALLOC_INT) { SMC_ACK_INT(lp, IM_ALLOC_INT); break; } } while (--poll_count); smc_special_unlock(&lp->lock, flags); lp->pending_tx_skb = skb; if (!poll_count) { /* oh well, wait until the chip finds memory later */ netif_stop_queue(dev); DBG(2, "%s: TX memory allocation deferred.\n", dev->name); SMC_ENABLE_INT(lp, IM_ALLOC_INT); } else { /* * Allocation succeeded: push packet to the chip's own memory * immediately. */ smc_hardware_send_pkt((unsigned long)dev); } return NETDEV_TX_OK; }
/* * 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) {