/* Get a packet queued to go onto the wire. */ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct sunqe *qep = netdev_priv(dev); struct sunqe_buffers *qbufs = qep->buffers; __u32 txbuf_dvma, qbufs_dvma = qep->buffers_dvma; unsigned char *txbuf; int len, entry; spin_lock_irq(&qep->lock); qe_tx_reclaim(qep); len = skb->len; entry = qep->tx_new; txbuf = &qbufs->tx_buf[entry & (TX_RING_SIZE - 1)][0]; txbuf_dvma = qbufs_dvma + qebuf_offset(tx_buf, (entry & (TX_RING_SIZE - 1))); /* Avoid a race... */ qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE; skb_copy_from_linear_data(skb, txbuf, len); qep->qe_block->qe_txd[entry].tx_addr = txbuf_dvma; qep->qe_block->qe_txd[entry].tx_flags = (TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH)); qep->tx_new = NEXT_TX(entry); /* Get it going. */ dev->trans_start = jiffies; sbus_writel(CREG_CTRL_TWAKEUP, qep->qcregs + CREG_CTRL); dev->stats.tx_packets++; dev->stats.tx_bytes += len; if (TX_BUFFS_AVAIL(qep) <= 0) { /* Halt the net queue and enable tx interrupts. * When the tx queue empties the tx irq handler * will wake up the queue and return us back to * the lazy tx reclaim scheme. */ netif_stop_queue(dev); sbus_writel(0, qep->qcregs + CREG_TIMASK); } spin_unlock_irq(&qep->lock); dev_kfree_skb(skb); return NETDEV_TX_OK; }
/* Interrupts for all QE's get filtered out via the QEC master controller, * so we just run through each qe and check to see who is signaling * and thus needs to be serviced. */ static irqreturn_t qec_interrupt(int irq, void *dev_id) { struct sunqec *qecp = dev_id; u32 qec_status; int channel = 0; /* Latch the status now. */ qec_status = sbus_readl(qecp->gregs + GLOB_STAT); while (channel < 4) { if (qec_status & 0xf) { struct sunqe *qep = qecp->qes[channel]; u32 qe_status; qe_status = sbus_readl(qep->qcregs + CREG_STAT); if (qe_status & CREG_STAT_ERRORS) { if (qe_is_bolixed(qep, qe_status)) goto next; } if (qe_status & CREG_STAT_RXIRQ) qe_rx(qep); if (netif_queue_stopped(qep->dev) && (qe_status & CREG_STAT_TXIRQ)) { spin_lock(&qep->lock); qe_tx_reclaim(qep); if (TX_BUFFS_AVAIL(qep) > 0) { /* Wake net queue and return to * lazy tx reclaim. */ netif_wake_queue(qep->dev); sbus_writel(1, qep->qcregs + CREG_TIMASK); } spin_unlock(&qep->lock); } next: ; } qec_status >>= 4; channel++; } return IRQ_HANDLED; }
static void qe_tx_timeout(struct net_device *dev) { struct sunqe *qep = netdev_priv(dev); int tx_full; spin_lock_irq(&qep->lock); /* Try to reclaim, if that frees up some tx * entries, we're fine. */ qe_tx_reclaim(qep); tx_full = TX_BUFFS_AVAIL(qep) <= 0; spin_unlock_irq(&qep->lock); if (! tx_full) goto out; printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); qe_init(qep, 1); out: netif_wake_queue(dev); }