pcnet32.c
来自「linux 内核源代码」· C语言 代码 · 共 2,361 行 · 第 1/5 页
C
2,361 行
* Any failure keeps old resources. * Must be called with lp->lock held. */static void pcnet32_realloc_tx_ring(struct net_device *dev, struct pcnet32_private *lp, unsigned int size){ dma_addr_t new_ring_dma_addr; dma_addr_t *new_dma_addr_list; struct pcnet32_tx_head *new_tx_ring; struct sk_buff **new_skb_list; pcnet32_purge_tx_ring(dev); new_tx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * (1 << size), &new_ring_dma_addr); if (new_tx_ring == NULL) { if (netif_msg_drv(lp)) printk("\n" KERN_ERR "%s: Consistent memory allocation failed.\n", dev->name); return; } memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size)); new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t), GFP_ATOMIC); if (!new_dma_addr_list) { if (netif_msg_drv(lp)) printk("\n" KERN_ERR "%s: Memory allocation failed.\n", dev->name); goto free_new_tx_ring; } new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *), GFP_ATOMIC); if (!new_skb_list) { if (netif_msg_drv(lp)) printk("\n" KERN_ERR "%s: Memory allocation failed.\n", dev->name); goto free_new_lists; } kfree(lp->tx_skbuff); kfree(lp->tx_dma_addr); pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, lp->tx_ring, lp->tx_ring_dma_addr); lp->tx_ring_size = (1 << size); lp->tx_mod_mask = lp->tx_ring_size - 1; lp->tx_len_bits = (size << 12); lp->tx_ring = new_tx_ring; lp->tx_ring_dma_addr = new_ring_dma_addr; lp->tx_dma_addr = new_dma_addr_list; lp->tx_skbuff = new_skb_list; return; free_new_lists: kfree(new_dma_addr_list); free_new_tx_ring: pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * (1 << size), new_tx_ring, new_ring_dma_addr); return;}/* * Allocate space for the new sized rx ring. * Re-use old receive buffers. * alloc extra buffers * free unneeded buffers * free unneeded buffers * Save new resources. * Any failure keeps old resources. * Must be called with lp->lock held. */static void pcnet32_realloc_rx_ring(struct net_device *dev, struct pcnet32_private *lp, unsigned int size){ dma_addr_t new_ring_dma_addr; dma_addr_t *new_dma_addr_list; struct pcnet32_rx_head *new_rx_ring; struct sk_buff **new_skb_list; int new, overlap; new_rx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * (1 << size), &new_ring_dma_addr); if (new_rx_ring == NULL) { if (netif_msg_drv(lp)) printk("\n" KERN_ERR "%s: Consistent memory allocation failed.\n", dev->name); return; } memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size)); new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t), GFP_ATOMIC); if (!new_dma_addr_list) { if (netif_msg_drv(lp)) printk("\n" KERN_ERR "%s: Memory allocation failed.\n", dev->name); goto free_new_rx_ring; } new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *), GFP_ATOMIC); if (!new_skb_list) { if (netif_msg_drv(lp)) printk("\n" KERN_ERR "%s: Memory allocation failed.\n", dev->name); goto free_new_lists; } /* first copy the current receive buffers */ overlap = min(size, lp->rx_ring_size); for (new = 0; new < overlap; new++) { new_rx_ring[new] = lp->rx_ring[new]; new_dma_addr_list[new] = lp->rx_dma_addr[new]; new_skb_list[new] = lp->rx_skbuff[new]; } /* now allocate any new buffers needed */ for (; new < size; new++ ) { struct sk_buff *rx_skbuff; new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ); if (!(rx_skbuff = new_skb_list[new])) { /* keep the original lists and buffers */ if (netif_msg_drv(lp)) printk(KERN_ERR "%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n", dev->name); goto free_all_new; } skb_reserve(rx_skbuff, 2); new_dma_addr_list[new] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]); new_rx_ring[new].buf_length = cpu_to_le16(2 - PKT_BUF_SZ); new_rx_ring[new].status = cpu_to_le16(0x8000); } /* and free any unneeded buffers */ for (; new < lp->rx_ring_size; new++) { if (lp->rx_skbuff[new]) { pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new], PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_skbuff[new]); } } kfree(lp->rx_skbuff); kfree(lp->rx_dma_addr); pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, lp->rx_ring, lp->rx_ring_dma_addr); lp->rx_ring_size = (1 << size); lp->rx_mod_mask = lp->rx_ring_size - 1; lp->rx_len_bits = (size << 4); lp->rx_ring = new_rx_ring; lp->rx_ring_dma_addr = new_ring_dma_addr; lp->rx_dma_addr = new_dma_addr_list; lp->rx_skbuff = new_skb_list; return; free_all_new: for (; --new >= lp->rx_ring_size; ) { if (new_skb_list[new]) { pci_unmap_single(lp->pci_dev, new_dma_addr_list[new], PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); dev_kfree_skb(new_skb_list[new]); } } kfree(new_skb_list); free_new_lists: kfree(new_dma_addr_list); free_new_rx_ring: pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * (1 << size), new_rx_ring, new_ring_dma_addr); return;}static void pcnet32_purge_rx_ring(struct net_device *dev){ struct pcnet32_private *lp = netdev_priv(dev); int i; /* free all allocated skbuffs */ for (i = 0; i < lp->rx_ring_size; i++) { lp->rx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ 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_any(lp->rx_skbuff[i]); } lp->rx_skbuff[i] = NULL; lp->rx_dma_addr[i] = 0; }}#ifdef CONFIG_NET_POLL_CONTROLLERstatic void pcnet32_poll_controller(struct net_device *dev){ disable_irq(dev->irq); pcnet32_interrupt(0, dev); enable_irq(dev->irq);}#endifstatic int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; int r = -EOPNOTSUPP; if (lp->mii) { spin_lock_irqsave(&lp->lock, flags); mii_ethtool_gset(&lp->mii_if, cmd); spin_unlock_irqrestore(&lp->lock, flags); r = 0; } return r;}static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){ struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; int r = -EOPNOTSUPP; if (lp->mii) { spin_lock_irqsave(&lp->lock, flags); r = mii_ethtool_sset(&lp->mii_if, cmd); spin_unlock_irqrestore(&lp->lock, flags); } return r;}static void pcnet32_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct pcnet32_private *lp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); if (lp->pci_dev) strcpy(info->bus_info, pci_name(lp->pci_dev)); else sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr);}static u32 pcnet32_get_link(struct net_device *dev){ struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; int r; spin_lock_irqsave(&lp->lock, flags); if (lp->mii) { r = mii_link_ok(&lp->mii_if); } else if (lp->chip_version >= PCNET32_79C970A) { ulong ioaddr = dev->base_addr; /* card base I/O address */ r = (lp->a.read_bcr(ioaddr, 4) != 0xc0); } else { /* can not detect link on really old chips */ r = 1; } spin_unlock_irqrestore(&lp->lock, flags); return r;}static u32 pcnet32_get_msglevel(struct net_device *dev){ struct pcnet32_private *lp = netdev_priv(dev); return lp->msg_enable;}static void pcnet32_set_msglevel(struct net_device *dev, u32 value){ struct pcnet32_private *lp = netdev_priv(dev); lp->msg_enable = value;}static int pcnet32_nway_reset(struct net_device *dev){ struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; int r = -EOPNOTSUPP; if (lp->mii) { spin_lock_irqsave(&lp->lock, flags); r = mii_nway_restart(&lp->mii_if); spin_unlock_irqrestore(&lp->lock, flags); } return r;}static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering){ struct pcnet32_private *lp = netdev_priv(dev); ering->tx_max_pending = TX_MAX_RING_SIZE; ering->tx_pending = lp->tx_ring_size; ering->rx_max_pending = RX_MAX_RING_SIZE; ering->rx_pending = lp->rx_ring_size;}static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering){ struct pcnet32_private *lp = netdev_priv(dev); unsigned long flags; unsigned int size; ulong ioaddr = dev->base_addr; int i; if (ering->rx_mini_pending || ering->rx_jumbo_pending) return -EINVAL; if (netif_running(dev)) pcnet32_netif_stop(dev); spin_lock_irqsave(&lp->lock, flags); lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */ size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE); /* set the minimum ring size to 4, to allow the loopback test to work * unchanged. */ for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) { if (size <= (1 << i)) break; } if ((1 << i) != lp->tx_ring_size) pcnet32_realloc_tx_ring(dev, lp, i); size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE); for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) { if (size <= (1 << i)) break; } if ((1 << i) != lp->rx_ring_size) pcnet32_realloc_rx_ring(dev, lp, i); lp->napi.weight = lp->rx_ring_size / 2; if (netif_running(dev)) { pcnet32_netif_start(dev); pcnet32_restart(dev, CSR0_NORMAL); } spin_unlock_irqrestore(&lp->lock, flags); if (netif_msg_drv(lp)) printk(KERN_INFO "%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name, lp->rx_ring_size, lp->tx_ring_size); return 0;}static void pcnet32_get_strings(struct net_device *dev, u32 stringset, u8 * data){ memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test));}static int pcnet32_get_sset_count(struct net_device *dev, int sset){ switch (sset) { case ETH_SS_TEST: return PCNET32_TEST_LEN; default: return -EOPNOTSUPP; }}static void pcnet32_ethtool_test(struct net_device *dev, struct ethtool_test *test, u64 * data){ struct pcnet32_private *lp = netdev_priv(dev); int rc; if (test->flags == ETH_TEST_FL_OFFLINE) { rc = pcnet32_loopback_test(dev, data); if (rc) { if (netif_msg_hw(lp)) printk(KERN_DEBUG "%s: Loopback test failed.\n", dev->name); test->flags |= ETH_TEST_FL_FAILED; } else if (netif_msg_hw(lp)) printk(KERN_DEBUG "%s: Loopback test passed.\n", dev->name); } else if (netif_msg_hw(lp)) printk(KERN_DEBUG "%s: No tests to run (specify 'Offline' on ethtool).", dev->name);} /* end pcnet32_ethtool_test */static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1){ struct pcnet32_private *lp = netdev_priv(dev); struct pcnet32_access *a = &lp->a; /* access to registers */ ulong ioaddr = dev->base_addr; /* card base I/O address */ struct sk_buff *skb; /* sk buff */ int x, i; /* counters */ int numbuffs = 4; /* number of TX/RX buffers and descs */ u16 status = 0x8300; /* TX ring status */ __le16 teststatus; /* test of ring status */ int rc; /* return code */ int size; /* size of packets */ unsigned char *packet; /* source packet data */ static const int data_len = 60; /* length of source packets */ unsigned long flags; unsigned long ticks; rc = 1; /* default to fail */ if (netif_running(dev))#ifdef CONFIG_PCNET32_NAPI pcnet32_netif_stop(dev);#else pcnet32_close(dev);#endif spin_lock_irqsave(&lp->lock, flags); lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */ numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size)); /* Reset the PCNET32 */ lp->a.reset(ioaddr); lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */ /* switch pcnet32 to 32bit mode */ lp->a.write_bcr(ioaddr, 20, 2); /* purge & init rings but don't actually restart */ pcnet32_restart(dev, 0x0000); lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */ /* Initialize Transmit buffers. */ size = data_len + 15; for (x = 0; x < numbuffs; x++) { if (!(skb = dev_alloc_skb(size))) { if (netif_msg_hw(lp)) printk(KERN_DEBUG "%s: Cannot allocate skb at line: %d!\n", dev->name, __LINE__); goto clean_up; } else { packet = skb->data; skb_put(skb, size); /* create space for data */ lp->tx_skbuff[x] = skb; lp->tx_ring[x].length = cpu_to_le16(-skb->len);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?