📄 pcnet32.c
字号:
mii_check_media (&lp->mii_if, netif_msg_link(lp), 1); mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); } i = 0; while (i++ < 100) if (lp->a.read_csr (ioaddr, 0) & 0x0100) break; /* * We used to clear the InitDone bit, 0x0100, here but Mark Stockton * reports that doing so triggers a bug in the '974. */ lp->a.write_csr (ioaddr, 0, 0x0042); if (netif_msg_ifup(lp)) printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", dev->name, i, (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block)), lp->a.read_csr(ioaddr, 0)); spin_unlock_irqrestore(&lp->lock, flags); return 0; /* Always succeed */err_free_ring: /* free any allocated skbuffs */ for (i = 0; i < lp->rx_ring_size; i++) { lp->rx_ring[i].status = 0; if (lp->rx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_skbuff[i]); } lp->rx_skbuff[i] = NULL; lp->rx_dma_addr[i] = 0; } pcnet32_free_ring(dev); /* * Switch back to 16bit mode to avoid problems with dumb * DOS packet driver after a warm reboot */ lp->a.write_bcr (ioaddr, 20, 4);err_free_irq: spin_unlock_irqrestore(&lp->lock, flags); free_irq(dev->irq, dev); return rc;}/* * The LANCE has been halted for one reason or another (busmaster memory * arbitration error, Tx FIFO underflow, driver stopped it to reconfigure, * etc.). Modern LANCE variants always reload their ring-buffer * configuration when restarted, so we must reinitialize our ring * context before restarting. As part of this reinitialization, * find all packets still on the Tx ring and pretend that they had been * sent (in effect, drop the packets on the floor) - the higher-level * protocols will time out and retransmit. It'd be better to shuffle * these skbs to a temp list and then actually re-Tx them after * restarting the chip, but I'm too lazy to do so right now. dplatt@3do.com */static voidpcnet32_purge_tx_ring(struct net_device *dev){ struct pcnet32_private *lp = dev->priv; int i; for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE); dev_kfree_skb_any(lp->tx_skbuff[i]); } lp->tx_skbuff[i] = NULL; lp->tx_dma_addr[i] = 0; }}/* Initialize the PCNET32 Rx and Tx rings. */static intpcnet32_init_ring(struct net_device *dev){ struct pcnet32_private *lp = dev->priv; int i; lp->tx_full = 0; lp->cur_rx = lp->cur_tx = 0; lp->dirty_rx = lp->dirty_tx = 0; for (i = 0; i < lp->rx_ring_size; i++) { struct sk_buff *rx_skbuff = lp->rx_skbuff[i]; if (rx_skbuff == NULL) { if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { /* there is not much, we can do at this point */ if (pcnet32_debug & NETIF_MSG_DRV) printk(KERN_ERR "%s: pcnet32_init_ring dev_alloc_skb failed.\n", dev->name); return -1; } skb_reserve (rx_skbuff, 2); } rmb(); if (lp->rx_dma_addr[i] == 0) lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ); wmb(); /* Make sure owner changes after all others are visible */ lp->rx_ring[i].status = le16_to_cpu(0x8000); } /* The Tx buffer address is filled in as needed, but we do need to clear * the upper ownership bit. */ for (i = 0; i < lp->tx_ring_size; i++) { lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ lp->tx_ring[i].base = 0; lp->tx_dma_addr[i] = 0; } lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); for (i = 0; i < 6; i++) lp->init_block.phys_addr[i] = dev->dev_addr[i]; lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); wmb(); /* Make sure all changes are visible */ return 0;}/* the pcnet32 has been issued a stop or reset. Wait for the stop bit * then flush the pending transmit operations, re-initialize the ring, * and tell the chip to initialize. */static voidpcnet32_restart(struct net_device *dev, unsigned int csr0_bits){ struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; int i; /* wait for stop */ for (i=0; i<100; i++) if (lp->a.read_csr(ioaddr, 0) & 0x0004) break; if (i >= 100 && netif_msg_drv(lp)) printk(KERN_ERR "%s: pcnet32_restart timed out waiting for stop.\n", dev->name); pcnet32_purge_tx_ring(dev); if (pcnet32_init_ring(dev)) return; /* ReInit Ring */ lp->a.write_csr (ioaddr, 0, 1); i = 0; while (i++ < 1000) if (lp->a.read_csr (ioaddr, 0) & 0x0100) break; lp->a.write_csr (ioaddr, 0, csr0_bits);}static voidpcnet32_tx_timeout (struct net_device *dev){ struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr, flags; spin_lock_irqsave(&lp->lock, flags); /* Transmitter timeout, serious problems. */ if (pcnet32_debug & NETIF_MSG_DRV) printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n", dev->name, lp->a.read_csr(ioaddr, 0)); lp->a.write_csr (ioaddr, 0, 0x0004); lp->stats.tx_errors++; if (netif_msg_tx_err(lp)) { int i; printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", lp->cur_rx); for (i = 0 ; i < lp->rx_ring_size; i++) printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", le32_to_cpu(lp->rx_ring[i].base), (-le16_to_cpu(lp->rx_ring[i].buf_length)) & 0xffff, le32_to_cpu(lp->rx_ring[i].msg_length), le16_to_cpu(lp->rx_ring[i].status)); for (i = 0 ; i < lp->tx_ring_size; i++) printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", le32_to_cpu(lp->tx_ring[i].base), (-le16_to_cpu(lp->tx_ring[i].length)) & 0xffff, le32_to_cpu(lp->tx_ring[i].misc), le16_to_cpu(lp->tx_ring[i].status)); printk("\n"); } pcnet32_restart(dev, 0x0042); dev->trans_start = jiffies; netif_wake_queue(dev); spin_unlock_irqrestore(&lp->lock, flags);}static intpcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 status; int entry; unsigned long flags; spin_lock_irqsave(&lp->lock, flags); if (netif_msg_tx_queued(lp)) { printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name, lp->a.read_csr(ioaddr, 0)); } /* Default status -- will not enable Successful-TxDone * interrupt when that option is available to us. */ status = 0x8300; /* Fill in a Tx ring entry */ /* Mask to ring buffer boundary. */ entry = lp->cur_tx & lp->tx_mod_mask; /* Caution: the write order is important here, set the status * with the "ownership" bits last. */ lp->tx_ring[entry].length = le16_to_cpu(-skb->len); lp->tx_ring[entry].misc = 0x00000000; lp->tx_skbuff[entry] = skb; lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); lp->tx_ring[entry].base = (u32)le32_to_cpu(lp->tx_dma_addr[entry]); wmb(); /* Make sure owner changes after all others are visible */ lp->tx_ring[entry].status = le16_to_cpu(status); lp->cur_tx++; lp->stats.tx_bytes += skb->len; /* Trigger an immediate send poll. */ lp->a.write_csr (ioaddr, 0, 0x0048); dev->trans_start = jiffies; if (lp->tx_ring[(entry+1) & lp->tx_mod_mask].base != 0) { lp->tx_full = 1; netif_stop_queue(dev); } spin_unlock_irqrestore(&lp->lock, flags); return 0;}/* The PCNET32 interrupt handler. */static irqreturn_tpcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct net_device *dev = dev_id; struct pcnet32_private *lp; unsigned long ioaddr; u16 csr0,rap; int boguscnt = max_interrupt_work; int must_restart; if (!dev) { if (pcnet32_debug & NETIF_MSG_INTR) printk (KERN_DEBUG "%s(): irq %d for unknown device\n", __FUNCTION__, irq); return IRQ_NONE; } ioaddr = dev->base_addr; lp = dev->priv; spin_lock(&lp->lock); rap = lp->a.read_rap(ioaddr); while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) { if (csr0 == 0xffff) { break; /* PCMCIA remove happened */ } /* Acknowledge all of the current interrupt sources ASAP. */ lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f); must_restart = 0; if (netif_msg_intr(lp)) printk(KERN_DEBUG "%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", dev->name, csr0, lp->a.read_csr (ioaddr, 0)); if (csr0 & 0x0400) /* Rx interrupt */ pcnet32_rx(dev); if (csr0 & 0x0200) { /* Tx-done interrupt */ unsigned int dirty_tx = lp->dirty_tx; int delta; while (dirty_tx != lp->cur_tx) { int entry = dirty_tx & lp->tx_mod_mask; int status = (short)le16_to_cpu(lp->tx_ring[entry].status); if (status < 0) break; /* It still hasn't been Txed */ lp->tx_ring[entry].base = 0; if (status & 0x4000) { /* There was an major error, log it. */ int err_status = le32_to_cpu(lp->tx_ring[entry].misc); lp->stats.tx_errors++; if (netif_msg_tx_err(lp)) printk(KERN_ERR "%s: Tx error status=%04x err_status=%08x\n", dev->name, status, err_status); if (err_status & 0x04000000) lp->stats.tx_aborted_errors++; if (err_status & 0x08000000) lp->stats.tx_carrier_errors++; if (err_status & 0x10000000) lp->stats.tx_window_errors++;#ifndef DO_DXSUFLO if (err_status & 0x40000000) { lp->stats.tx_fifo_errors++; /* Ackk! On FIFO errors the Tx unit is turned off! */ /* Remove this verbosity later! */ if (netif_msg_tx_err(lp)) printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n", dev->name, csr0); must_restart = 1; }#else if (err_status & 0x40000000) { lp->stats.tx_fifo_errors++; if (! lp->dxsuflo) { /* If controller doesn't recover ... */ /* Ackk! On FIFO errors the Tx unit is turned off! */ /* Remove this verbosity later! */ if (netif_msg_tx_err(lp)) printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n", dev->name, csr0); must_restart = 1; } }#endif } else { if (status & 0x1800) lp->stats.collisions++; lp->stats.tx_packets++; } /* We must free the original skb */ if (lp->tx_skbuff[entry]) { pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(lp->tx_skbuff[entry]); lp->tx_skbuff[entry] = NULL; lp->tx_dma_addr[entry] = 0; } dirty_tx++; } delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size); if (delta > lp->tx_ring_size) { if (netif_msg_drv(lp)) printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", dev->name, dirty_tx, lp->cur_tx, lp->tx_full); dirty_tx += lp->tx_ring_size; delta -= lp->tx_ring_size; } if (lp->tx_full && netif_queue_stopped(dev) && delta < lp->tx_ring_size - 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; netif_wake_queue (dev); } lp->dirty_tx = dirty_tx; } /* Log misc errors. */ if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */ if (csr0 & 0x1000) { /* * this happens when our receive ring is full. This shouldn't * be a problem as we will see normal rx interrupts for the frames * in the receive ring. But there are some PCI chipsets (I can * reproduce this on SP3G with Intel saturn chipset) which have * sometimes problems and will fill up the receive ring with * error descriptors. In this situation we don't get a rx * interrupt, but a missed frame interrupt sooner or later. * So we try to clean up our receive ring here. */ pcnet32_rx(dev); lp->stats.rx_errors++; /* Missed a Rx frame. */ } if (csr0 & 0x0800) { if (netif_msg_drv(lp)) printk(KERN_ERR "%s: Bus master arbitration failure, status %4.4x.\n", dev->name, csr0); /* unlike for the lance, there is no restart needed */ } if (must_restart) { /* reset the chip to clear the error condition, then restart */ lp->a.reset(ioaddr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -