cpmac.c
来自「linux 内核源代码」· C语言 代码 · 共 1,197 行 · 第 1/3 页
C
1,197 行
"%s: low on skbs, dropping packet\n", priv->dev->name); priv->dev->stats.rx_dropped++; } desc->buflen = CPMAC_SKB_SIZE; desc->dataflags = CPMAC_OWN; return result;}static int cpmac_poll(struct napi_struct *napi, int budget){ struct sk_buff *skb; struct cpmac_desc *desc; int received = 0; struct cpmac_priv *priv = container_of(napi, struct cpmac_priv, napi); spin_lock(&priv->rx_lock); if (unlikely(!priv->rx_head)) { if (netif_msg_rx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: rx: polling, but no queue\n", priv->dev->name); netif_rx_complete(priv->dev, napi); return 0; } desc = priv->rx_head; while (((desc->dataflags & CPMAC_OWN) == 0) && (received < budget)) { skb = cpmac_rx_one(priv, desc); if (likely(skb)) { netif_receive_skb(skb); received++; } desc = desc->next; } priv->rx_head = desc; spin_unlock(&priv->rx_lock); if (unlikely(netif_msg_rx_status(priv))) printk(KERN_DEBUG "%s: poll processed %d packets\n", priv->dev->name, received); if (desc->dataflags & CPMAC_OWN) { netif_rx_complete(priv->dev, napi); cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping); cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); return 0; } return 1;}static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev){ int queue, len; struct cpmac_desc *desc; struct cpmac_priv *priv = netdev_priv(dev); if (unlikely(skb_padto(skb, ETH_ZLEN))) return NETDEV_TX_OK; len = max(skb->len, ETH_ZLEN); queue = skb_get_queue_mapping(skb);#ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_stop_subqueue(dev, queue);#else netif_stop_queue(dev);#endif desc = &priv->desc_ring[queue]; if (unlikely(desc->dataflags & CPMAC_OWN)) { if (netif_msg_tx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: tx dma ring full\n", dev->name); return NETDEV_TX_BUSY; } spin_lock(&priv->lock); dev->trans_start = jiffies; spin_unlock(&priv->lock); desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN; desc->skb = skb; desc->data_mapping = dma_map_single(&dev->dev, skb->data, len, DMA_TO_DEVICE); desc->hw_data = (u32)desc->data_mapping; desc->datalen = len; desc->buflen = len; if (unlikely(netif_msg_tx_queued(priv))) printk(KERN_DEBUG "%s: sending 0x%p, len=%d\n", dev->name, skb, skb->len); if (unlikely(netif_msg_hw(priv))) cpmac_dump_desc(dev, desc); if (unlikely(netif_msg_pktdata(priv))) cpmac_dump_skb(dev, skb); cpmac_write(priv->regs, CPMAC_TX_PTR(queue), (u32)desc->mapping); return NETDEV_TX_OK;}static void cpmac_end_xmit(struct net_device *dev, int queue){ struct cpmac_desc *desc; struct cpmac_priv *priv = netdev_priv(dev); desc = &priv->desc_ring[queue]; cpmac_write(priv->regs, CPMAC_TX_ACK(queue), (u32)desc->mapping); if (likely(desc->skb)) { spin_lock(&priv->lock); dev->stats.tx_packets++; dev->stats.tx_bytes += desc->skb->len; spin_unlock(&priv->lock); dma_unmap_single(&dev->dev, desc->data_mapping, desc->skb->len, DMA_TO_DEVICE); if (unlikely(netif_msg_tx_done(priv))) printk(KERN_DEBUG "%s: sent 0x%p, len=%d\n", dev->name, desc->skb, desc->skb->len); dev_kfree_skb_irq(desc->skb); desc->skb = NULL;#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue);#else if (netif_queue_stopped(dev)) netif_wake_queue(dev);#endif } else { if (netif_msg_tx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: end_xmit: spurious interrupt\n", dev->name);#ifdef CONFIG_NETDEVICES_MULTIQUEUE if (netif_subqueue_stopped(dev, queue)) netif_wake_subqueue(dev, queue);#else if (netif_queue_stopped(dev)) netif_wake_queue(dev);#endif }}static void cpmac_hw_stop(struct net_device *dev){ int i; struct cpmac_priv *priv = netdev_priv(dev); struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data; ar7_device_reset(pdata->reset_bit); cpmac_write(priv->regs, CPMAC_RX_CONTROL, cpmac_read(priv->regs, CPMAC_RX_CONTROL) & ~1); cpmac_write(priv->regs, CPMAC_TX_CONTROL, cpmac_read(priv->regs, CPMAC_TX_CONTROL) & ~1); for (i = 0; i < 8; i++) { cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0); cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0); } cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff); cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff); cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff); cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff); cpmac_write(priv->regs, CPMAC_MAC_CONTROL, cpmac_read(priv->regs, CPMAC_MAC_CONTROL) & ~MAC_MII);}static void cpmac_hw_start(struct net_device *dev){ int i; struct cpmac_priv *priv = netdev_priv(dev); struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data; ar7_device_reset(pdata->reset_bit); for (i = 0; i < 8; i++) { cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0); cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0); } cpmac_write(priv->regs, CPMAC_RX_PTR(0), priv->rx_head->mapping); cpmac_write(priv->regs, CPMAC_MBP, MBP_RXSHORT | MBP_RXBCAST | MBP_RXMCAST); cpmac_write(priv->regs, CPMAC_BUFFER_OFFSET, 0); for (i = 0; i < 8; i++) cpmac_write(priv->regs, CPMAC_MAC_ADDR_LO(i), dev->dev_addr[5]); cpmac_write(priv->regs, CPMAC_MAC_ADDR_MID, dev->dev_addr[4]); cpmac_write(priv->regs, CPMAC_MAC_ADDR_HI, dev->dev_addr[0] | (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) | (dev->dev_addr[3] << 24)); cpmac_write(priv->regs, CPMAC_MAX_LENGTH, CPMAC_SKB_SIZE); cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff); cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff); cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff); cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff); cpmac_write(priv->regs, CPMAC_UNICAST_ENABLE, 1); cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); cpmac_write(priv->regs, CPMAC_TX_INT_ENABLE, 0xff); cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3); cpmac_write(priv->regs, CPMAC_RX_CONTROL, cpmac_read(priv->regs, CPMAC_RX_CONTROL) | 1); cpmac_write(priv->regs, CPMAC_TX_CONTROL, cpmac_read(priv->regs, CPMAC_TX_CONTROL) | 1); cpmac_write(priv->regs, CPMAC_MAC_CONTROL, cpmac_read(priv->regs, CPMAC_MAC_CONTROL) | MAC_MII | MAC_FDX);}static void cpmac_clear_rx(struct net_device *dev){ struct cpmac_priv *priv = netdev_priv(dev); struct cpmac_desc *desc; int i; if (unlikely(!priv->rx_head)) return; desc = priv->rx_head; for (i = 0; i < priv->ring_size; i++) { if ((desc->dataflags & CPMAC_OWN) == 0) { if (netif_msg_rx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: packet dropped\n", dev->name); if (unlikely(netif_msg_hw(priv))) cpmac_dump_desc(dev, desc); desc->dataflags = CPMAC_OWN; dev->stats.rx_dropped++; } desc = desc->next; }}static void cpmac_clear_tx(struct net_device *dev){ struct cpmac_priv *priv = netdev_priv(dev); int i; if (unlikely(!priv->desc_ring)) return; for (i = 0; i < CPMAC_QUEUES; i++) { priv->desc_ring[i].dataflags = 0; if (priv->desc_ring[i].skb) { dev_kfree_skb_any(priv->desc_ring[i].skb); if (netif_subqueue_stopped(dev, i)) netif_wake_subqueue(dev, i); } }}static void cpmac_hw_error(struct work_struct *work){ struct cpmac_priv *priv = container_of(work, struct cpmac_priv, reset_work); spin_lock(&priv->rx_lock); cpmac_clear_rx(priv->dev); spin_unlock(&priv->rx_lock); cpmac_clear_tx(priv->dev); cpmac_hw_start(priv->dev); napi_enable(&priv->napi); netif_start_queue(priv->dev);}static irqreturn_t cpmac_irq(int irq, void *dev_id){ struct net_device *dev = dev_id; struct cpmac_priv *priv; int queue; u32 status; if (!dev) return IRQ_NONE; priv = netdev_priv(dev); status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR); if (unlikely(netif_msg_intr(priv))) printk(KERN_DEBUG "%s: interrupt status: 0x%08x\n", dev->name, status); if (status & MAC_INT_TX) cpmac_end_xmit(dev, (status & 7)); if (status & MAC_INT_RX) { queue = (status >> 8) & 7; if (netif_rx_schedule_prep(dev, &priv->napi)) { cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue); __netif_rx_schedule(dev, &priv->napi); } } cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0); if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) { if (netif_msg_drv(priv) && net_ratelimit()) printk(KERN_ERR "%s: hw error, resetting...\n", dev->name); netif_stop_queue(dev); napi_disable(&priv->napi); cpmac_hw_stop(dev); schedule_work(&priv->reset_work); if (unlikely(netif_msg_hw(priv))) cpmac_dump_regs(dev); } return IRQ_HANDLED;}static void cpmac_tx_timeout(struct net_device *dev){ struct cpmac_priv *priv = netdev_priv(dev); int i; spin_lock(&priv->lock); dev->stats.tx_errors++; spin_unlock(&priv->lock); if (netif_msg_tx_err(priv) && net_ratelimit()) printk(KERN_WARNING "%s: transmit timeout\n", dev->name); /* * FIXME: waking up random queue is not the best thing to * do... on the other hand why we got here at all? */#ifdef CONFIG_NETDEVICES_MULTIQUEUE for (i = 0; i < CPMAC_QUEUES; i++) if (priv->desc_ring[i].skb) { priv->desc_ring[i].dataflags = 0; dev_kfree_skb_any(priv->desc_ring[i].skb); netif_wake_subqueue(dev, i); break; }#else priv->desc_ring[0].dataflags = 0; if (priv->desc_ring[0].skb) dev_kfree_skb_any(priv->desc_ring[0].skb); netif_wake_queue(dev);#endif}static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct cpmac_priv *priv = netdev_priv(dev); if (!(netif_running(dev))) return -EINVAL; if (!priv->phy) return -EINVAL; if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) || (cmd == SIOCSMIIREG)) return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd); return -EOPNOTSUPP;}static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct cpmac_priv *priv = netdev_priv(dev); if (priv->phy) return phy_ethtool_gset(priv->phy, cmd); return -EINVAL;}static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct cpmac_priv *priv = netdev_priv(dev); if (!capable(CAP_NET_ADMIN)) return -EPERM; if (priv->phy) return phy_ethtool_sset(priv->phy, cmd); return -EINVAL;}static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring){ struct cpmac_priv *priv = netdev_priv(dev); ring->rx_max_pending = 1024; ring->rx_mini_max_pending = 1; ring->rx_jumbo_max_pending = 1; ring->tx_max_pending = 1; ring->rx_pending = priv->ring_size; ring->rx_mini_pending = 1; ring->rx_jumbo_pending = 1; ring->tx_pending = 1;}static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring){ struct cpmac_priv *priv = netdev_priv(dev); if (netif_running(dev)) return -EBUSY; priv->ring_size = ring->rx_pending; return 0;}static void cpmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strcpy(info->driver, "cpmac");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?