📄 8139too.c
字号:
DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, (u16)cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); while (netif_running(dev) && received < budget && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { u32 ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; unsigned int pkt_size; struct sk_buff *skb; rmb(); /* read size+status of next frame from DMA ring buffer */ rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); rx_size = rx_status >> 16; pkt_size = rx_size - 4; if (netif_msg_rx_status(tp)) printk(KERN_DEBUG "%s: rtl8139_rx() status %4.4x, size %4.4x," " cur %4.4x.\n", dev->name, rx_status, rx_size, cur_rx);#if RTL8139_DEBUG > 2 { int i; DPRINTK ("%s: Frame contents ", dev->name); for (i = 0; i < 70; i++) printk (" %2.2x", rx_ring[ring_offset + i]); printk (".\n"); }#endif /* Packet copy from FIFO still in progress. * Theoretically, this should never happen * since EarlyRx is disabled. */ if (unlikely(rx_size == 0xfff0)) { if (!tp->fifo_copy_timeout) tp->fifo_copy_timeout = jiffies + 2; else if (time_after(jiffies, tp->fifo_copy_timeout)) { DPRINTK ("%s: hung FIFO. Reset.", dev->name); rx_size = 0; goto no_early_rx; } if (netif_msg_intr(tp)) { printk(KERN_DEBUG "%s: fifo copy in progress.", dev->name); } tp->xstats.early_rx++; break; }no_early_rx: tp->fifo_copy_timeout = 0; /* If Rx err or invalid rx_size/rx_status received * (which happens if we get lost in the ring), * Rx process gets reset, so we abort any further * Rx processing. */ if (unlikely((rx_size > (MAX_ETH_FRAME_SIZE+4)) || (rx_size < 8) || (!(rx_status & RxStatusOK)))) { rtl8139_rx_err (rx_status, dev, tp, ioaddr); received = -1; goto out; } /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ skb = dev_alloc_skb (pkt_size + 2); if (likely(skb)) { skb_reserve (skb, 2); /* 16 byte align the IP fields. */#if RX_BUF_IDX == 3 wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);#else eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);#endif skb_put (skb, pkt_size); skb->protocol = eth_type_trans (skb, dev); dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; netif_receive_skb (skb); } else { if (net_ratelimit()) printk (KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); tp->stats.rx_dropped++; } received++; cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; RTL_W16 (RxBufPtr, (u16) (cur_rx - 16)); rtl8139_isr_ack(tp); } if (unlikely(!received || rx_size == 0xfff0)) rtl8139_isr_ack(tp);#if RTL8139_DEBUG > 1 DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd));#endif tp->cur_rx = cur_rx; /* * The receive buffer should be mostly empty. * Tell NAPI to reenable the Rx irq. */ if (tp->fifo_copy_timeout) received = budget;out: return received;}static void rtl8139_weird_interrupt (struct net_device *dev, struct rtl8139_private *tp, void __iomem *ioaddr, int status, int link_changed){ DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", dev->name, status); assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); /* Update the error count. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); if ((status & RxUnderrun) && link_changed && (tp->drv_flags & HAS_LNK_CHNG)) { rtl_check_media(dev, 0); status &= ~RxUnderrun; } if (status & (RxUnderrun | RxErr)) tp->stats.rx_errors++; if (status & PCSTimeout) tp->stats.rx_length_errors++; if (status & RxUnderrun) tp->stats.rx_fifo_errors++; if (status & PCIErr) { u16 pci_cmd_status; pci_read_config_word (tp->pci_dev, PCI_STATUS, &pci_cmd_status); pci_write_config_word (tp->pci_dev, PCI_STATUS, pci_cmd_status); printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", dev->name, pci_cmd_status); }}static int rtl8139_poll(struct net_device *dev, int *budget){ struct rtl8139_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; int orig_budget = min(*budget, dev->quota); int done = 1; spin_lock(&tp->rx_lock); if (likely(RTL_R16(IntrStatus) & RxAckBits)) { int work_done; work_done = rtl8139_rx(dev, tp, orig_budget); if (likely(work_done > 0)) { *budget -= work_done; dev->quota -= work_done; done = (work_done < orig_budget); } } if (done) { unsigned long flags; /* * Order is important since data can get interrupted * again when we think we are done. */ local_irq_save(flags); RTL_W16_F(IntrMask, rtl8139_intr_mask); __netif_rx_complete(dev); local_irq_restore(flags); } spin_unlock(&tp->rx_lock); return !done;}/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance){ struct net_device *dev = (struct net_device *) dev_instance; struct rtl8139_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; u16 status, ackstat; int link_changed = 0; /* avoid bogus "uninit" warning */ int handled = 0; spin_lock (&tp->lock); status = RTL_R16 (IntrStatus); /* shared irq? */ if (unlikely((status & rtl8139_intr_mask) == 0)) goto out; handled = 1; /* h/w no longer present (hotplug?) or major error, bail */ if (unlikely(status == 0xFFFF)) goto out; /* close possible race's with dev_close */ if (unlikely(!netif_running(dev))) { RTL_W16 (IntrMask, 0); goto out; } /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (unlikely(status & RxUnderrun)) link_changed = RTL_R16 (CSCR) & CSCR_LinkChangeBit; ackstat = status & ~(RxAckBits | TxErr); if (ackstat) RTL_W16 (IntrStatus, ackstat); /* Receive packets are processed by poll routine. If not running start it now. */ if (status & RxAckBits){ if (netif_rx_schedule_prep(dev)) { RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); __netif_rx_schedule (dev); } } /* Check uncommon events with one test. */ if (unlikely(status & (PCIErr | PCSTimeout | RxUnderrun | RxErr))) rtl8139_weird_interrupt (dev, tp, ioaddr, status, link_changed); if (status & (TxOK | TxErr)) { rtl8139_tx_interrupt (dev, tp, ioaddr); if (status & TxErr) RTL_W16 (IntrStatus, TxErr); } out: spin_unlock (&tp->lock); DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); return IRQ_RETVAL(handled);}#ifdef CONFIG_NET_POLL_CONTROLLER/* * Polling receive - used by netconsole and other diagnostic tools * to allow network i/o with interrupts disabled. */static void rtl8139_poll_controller(struct net_device *dev){ disable_irq(dev->irq); rtl8139_interrupt(dev->irq, dev); enable_irq(dev->irq);}#endifstatic int rtl8139_close (struct net_device *dev){ struct rtl8139_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; unsigned long flags; netif_stop_queue (dev); if (netif_msg_ifdown(tp)) printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); spin_lock_irqsave (&tp->lock, flags); /* Stop the chip's Tx and Rx DMA processes. */ RTL_W8 (ChipCmd, 0); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0); /* Update the error counts. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); synchronize_irq (dev->irq); /* racy, but that's ok here */ free_irq (dev->irq, dev); rtl8139_tx_clear (tp); pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, tp->rx_ring, tp->rx_ring_dma); pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN, tp->tx_bufs, tp->tx_bufs_dma); tp->rx_ring = NULL; tp->tx_bufs = NULL; /* Green! Put the chip in low-power mode. */ RTL_W8 (Cfg9346, Cfg9346_Unlock); if (rtl_chip_info[tp->chipset].flags & HasHltClk) RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ return 0;}/* Get the ethtool Wake-on-LAN settings. Assumes that wol points to kernel memory, *wol has been initialized as {ETHTOOL_GWOL}, and other threads or interrupts aren't messing with the 8139. */static void rtl8139_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol){ struct rtl8139_private *np = netdev_priv(dev); void __iomem *ioaddr = np->mmio_addr; spin_lock_irq(&np->lock); if (rtl_chip_info[np->chipset].flags & HasLWake) { u8 cfg3 = RTL_R8 (Config3); u8 cfg5 = RTL_R8 (Config5); wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; wol->wolopts = 0; if (cfg3 & Cfg3_LinkUp) wol->wolopts |= WAKE_PHY; if (cfg3 & Cfg3_Magic) wol->wolopts |= WAKE_MAGIC; /* (KON)FIXME: See how netdev_set_wol() handles the following constants. */ if (cfg5 & Cfg5_UWF) wol->wolopts |= WAKE_UCAST; if (cfg5 & Cfg5_MWF) wol->wolopts |= WAKE_MCAST; if (cfg5 & Cfg5_BWF) wol->wolopts |= WAKE_BCAST; } spin_unlock_irq(&np->lock);}/* Set the ethtool Wake-on-LAN settings. Return 0 or -errno. Assumes that wol points to kernel memory and other threads or interrupts aren't messing with the 8139. */static int rtl8139_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol){ struct rtl8139_private *np = netdev_priv(dev); void __iomem *ioaddr = np->mmio_addr; u32 support; u8 cfg3, cfg5; support = ((rtl_chip_info[np->chipset].flags & HasLWake) ? (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST) : 0); if (wol->wolopts & ~support) return -EINVAL; spin_lock_irq(&np->lock); cfg3 = RTL_R8 (Config3) & ~(Cfg3_LinkUp | Cfg3_Magic); if (wol->wolopts & WAKE_PHY) cfg3 |= Cfg3_LinkUp; if (wol->wolopts & WAKE_MAGIC) cfg3 |= Cfg3_Magic; RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config3, cfg3); RTL_W8 (Cfg9346, Cfg9346_Lock); cfg5 = RTL_R8 (Config5) & ~(Cfg5_UWF | Cfg5_MWF | Cfg5_BWF); /* (KON)FIXME: These are untested. We may have to set the CRC0, Wakeup0 and LSBCRC0 registers too, but I have no documentation. */ if (wol->wolopts & WAKE_UCAST) cfg5 |= Cfg5_UWF; if (wol->wolopts & WAKE_MCAST) cfg5 |= Cfg5_MWF; if (wol->wolopts & WAKE_BCAST) cfg5 |= Cfg5_BWF; RTL_W8 (Config5, cfg5); /* need not unlock via Cfg9346 */ spin_unlock_irq(&np->lock); return 0;}static void rtl8139_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct rtl8139_private *np = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); strcpy(info->bus_info, pci_name(np->pci_dev)); info->regdump_len = np->regs_len;}static int rtl8139_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8139_private *np = netdev_priv(dev); spin_lock_irq(&np->lock); mii_ethtool_gset(&np->mii, cmd); spin_unlock_irq(&np->lock); return 0;}static int rtl8139_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct rtl8139_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); rc = mii_ethtool_sset(&np->mii, cmd); spin_unlock_irq(&np->lock); return rc;}static int rtl8139_nway_reset(struct net_device *dev){ struct rtl8139_private *np = netdev_priv(dev); return mii_nway_restart(&np->mii);}static u32 rtl8139_get_link(struct net_device *dev){ struct rtl8139_private *np = netdev_priv(dev); return mii_link_ok(&np->mii);}static u32 rtl8139_get_msglevel(struct net_device *dev){ struct rtl8139_private *np = netdev_priv(dev); return np->msg_enable;}static void rtl8139_set_msglevel(struct net_device *dev, u32 datum){ struct rtl8139_private *np = netdev_priv(dev); np->msg_enable = datum;}/* TODO: we are too slack to do reg dumping for pio, for now */#ifdef CONFIG_8139TOO_PIO#define rtl8139_get_regs_len NULL#define rtl8139_get_regs NULL#elsestatic int rtl8139_get_regs_len(struct net_device *dev){ struct rtl8139_private *np = netdev_priv(dev); return np->regs_len;}static void rtl8139_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf){ struct rtl8139_private *np = netdev_priv(dev); regs->version = RTL_REGS_VER; spin_lock_irq(&np->lock); memcpy_fromio(regbuf, np->mmio_addr, regs->len); spin_unlock_irq(&np->lock);}#endif /* CONFIG_8139
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -