📄 pcnet32.c
字号:
if (pcnet32_debug & NETIF_MSG_PROBE) { for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i]); /* Version 0x2623 and 0x2624 */ if (((chip_version + 1) & 0xfffe) == 0x2624) { i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ printk("\n" KERN_INFO " tx_start_pt(0x%04x):",i); switch(i>>10) { case 0: printk(" 20 bytes,"); break; case 1: printk(" 64 bytes,"); break; case 2: printk(" 128 bytes,"); break; case 3: printk("~220 bytes,"); break; } i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */ printk(" BCR18(%x):",i&0xffff); if (i & (1<<5)) printk("BurstWrEn "); if (i & (1<<6)) printk("BurstRdEn "); if (i & (1<<7)) printk("DWordIO "); if (i & (1<<11)) printk("NoUFlow "); i = a->read_bcr(ioaddr, 25); printk("\n" KERN_INFO " SRAMSIZE=0x%04x,",i<<8); i = a->read_bcr(ioaddr, 26); printk(" SRAM_BND=0x%04x,",i<<8); i = a->read_bcr(ioaddr, 27); if (i & (1<<14)) printk("LowLatRx"); } } dev->base_addr = ioaddr; /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); ret = -ENOMEM; goto err_free_netdev; } memset(lp, 0, sizeof(*lp)); lp->dma_addr = lp_dma_addr; lp->pci_dev = pdev; spin_lock_init(&lp->lock); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ lp->rx_ring_size = RX_RING_SIZE; /* default rx ring size */ lp->tx_mod_mask = lp->tx_ring_size - 1; lp->rx_mod_mask = lp->rx_ring_size - 1; lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12); lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4); lp->mii_if.full_duplex = fdx; lp->mii_if.phy_id_mask = 0x1f; lp->mii_if.reg_num_mask = 0x1f; lp->dxsuflo = dxsuflo; lp->mii = mii; lp->msg_enable = pcnet32_debug; if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping))) lp->options = PCNET32_PORT_ASEL; else lp->options = options_mapping[options[cards_found]]; lp->mii_if.dev = dev; lp->mii_if.mdio_read = mdio_read; lp->mii_if.mdio_write = mdio_write; if (fdx && !(lp->options & PCNET32_PORT_ASEL) && ((cards_found>=MAX_UNITS) || full_duplex[cards_found])) lp->options |= PCNET32_PORT_FD; if (!a) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_ERR PFX "No access methods\n"); ret = -ENODEV; goto err_free_consistent; } lp->a = *a; /* prior to register_netdev, dev->name is not yet correct */ if (pcnet32_alloc_ring(dev, pci_name(lp->pci_dev))) { ret = -ENOMEM; goto err_free_ring; } /* detect special T1/E1 WAN card by checking for MAC address */ if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ 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.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; 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); /* switch pcnet32 to 32bit mode */ a->write_bcr(ioaddr, 20, 2); a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) & 0xffff); a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16); if (pdev) { /* use the IRQ provided by PCI */ dev->irq = pdev->irq; if (pcnet32_debug & NETIF_MSG_PROBE) printk(" assigned IRQ %d.\n", dev->irq); } else { unsigned long irq_mask = probe_irq_on(); /* * To auto-IRQ we enable the initialization-done and DMA error * interrupts. For ISA boards we get a DMA error, but VLB and PCI * boards will work. */ /* Trigger an initialization just for the interrupt. */ a->write_csr (ioaddr, 0, 0x41); mdelay (1); dev->irq = probe_irq_off (irq_mask); if (!dev->irq) { if (pcnet32_debug & NETIF_MSG_PROBE) printk(", failed to detect IRQ line.\n"); ret = -ENODEV; goto err_free_ring; } if (pcnet32_debug & NETIF_MSG_PROBE) printk(", probed IRQ %d.\n", dev->irq); } /* Set the mii phy_id so that we can query the link state */ if (lp->mii) lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f; init_timer (&lp->watchdog_timer); lp->watchdog_timer.data = (unsigned long) dev; lp->watchdog_timer.function = (void *) &pcnet32_watchdog; /* The PCNET32-specific entries in the device structure. */ dev->open = &pcnet32_open; dev->hard_start_xmit = &pcnet32_start_xmit; dev->stop = &pcnet32_close; dev->get_stats = &pcnet32_get_stats; dev->set_multicast_list = &pcnet32_set_multicast_list; dev->do_ioctl = &pcnet32_ioctl; dev->ethtool_ops = &pcnet32_ethtool_ops; dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5*HZ);#ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = pcnet32_poll_controller;#endif /* Fill in the generic fields of the device structure. */ if( myregister_netdev(dev) ) goto err_free_ring; if (pdev) { pci_set_drvdata(pdev, dev); } else { lp->next = pcnet32_dev; pcnet32_dev = dev; } if (pcnet32_debug & NETIF_MSG_PROBE) printk(KERN_INFO "%s: registered as %s\n", dev->name, lp->name); cards_found++; /* enable LED writes */ a->write_bcr(ioaddr, 2, a->read_bcr(ioaddr, 2) | 0x1000); return 0;err_free_ring: pcnet32_free_ring(dev);err_free_consistent: pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);err_free_netdev: free_netdev(dev);err_release_region: release_region(ioaddr, PCNET32_TOTAL_SIZE); return ret;}/* if any allocation fails, caller must also call pcnet32_free_ring */static int pcnet32_alloc_ring(struct net_device *dev, char *name){ struct pcnet32_private *lp = dev->priv; lp->tx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, &lp->tx_ring_dma_addr); if (lp->tx_ring == NULL) { if (pcnet32_debug & NETIF_MSG_DRV) printk("\n" KERN_ERR PFX "%s: Consistent memory allocation failed.\n", name); return -ENOMEM; } lp->rx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, &lp->rx_ring_dma_addr); if (lp->rx_ring == NULL) { if (pcnet32_debug & NETIF_MSG_DRV) printk("\n" KERN_ERR PFX "%s: Consistent memory allocation failed.\n", name); return -ENOMEM; } lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size, GFP_ATOMIC); if (!lp->tx_dma_addr) { if (pcnet32_debug & NETIF_MSG_DRV) printk("\n" KERN_ERR PFX "%s: Memory allocation failed.\n", name); return -ENOMEM; } memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size); lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size, GFP_ATOMIC); if (!lp->rx_dma_addr) { if (pcnet32_debug & NETIF_MSG_DRV) printk("\n" KERN_ERR PFX "%s: Memory allocation failed.\n", name); return -ENOMEM; } memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size); lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size, GFP_ATOMIC); if (!lp->tx_skbuff) { if (pcnet32_debug & NETIF_MSG_DRV) printk("\n" KERN_ERR PFX "%s: Memory allocation failed.\n", name); return -ENOMEM; } memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size); lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size, GFP_ATOMIC); if (!lp->rx_skbuff) { if (pcnet32_debug & NETIF_MSG_DRV) printk("\n" KERN_ERR PFX "%s: Memory allocation failed.\n", name); return -ENOMEM; } memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size); return 0;}static void pcnet32_free_ring(struct net_device *dev){ struct pcnet32_private *lp = dev->priv; kfree(lp->tx_skbuff); lp->tx_skbuff = NULL; kfree(lp->rx_skbuff); lp->rx_skbuff = NULL; kfree(lp->tx_dma_addr); lp->tx_dma_addr = NULL; kfree(lp->rx_dma_addr); lp->rx_dma_addr = NULL; if (lp->tx_ring) { 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 = NULL; } if (lp->rx_ring) { 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 = NULL; }}static intpcnet32_open(struct net_device *dev){ struct pcnet32_private *lp = dev->priv; unsigned long ioaddr = dev->base_addr; u16 val; int i; int rc; unsigned long flags; if (request_irq(dev->irq, &pcnet32_interrupt, lp->shared_irq ? SA_SHIRQ : 0, dev->name, (void *)dev)) { return -EAGAIN; } spin_lock_irqsave(&lp->lock, flags); /* Check for a valid station address */ if (!is_valid_ether_addr(dev->dev_addr)) { rc = -EINVAL; goto err_free_irq; } /* Reset the PCNET32 */ lp->a.reset (ioaddr); /* switch pcnet32 to 32bit mode */ lp->a.write_bcr (ioaddr, 20, 2); if (netif_msg_ifup(lp)) printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr), (u32) (lp->rx_ring_dma_addr), (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block))); /* set/reset autoselect bit */ val = lp->a.read_bcr (ioaddr, 2) & ~2; if (lp->options & PCNET32_PORT_ASEL) val |= 2; lp->a.write_bcr (ioaddr, 2, val); /* handle full duplex setting */ if (lp->mii_if.full_duplex) { val = lp->a.read_bcr (ioaddr, 9) & ~3; if (lp->options & PCNET32_PORT_FD) { val |= 1; if (lp->options == (PCNET32_PORT_FD | PCNET32_PORT_AUI)) val |= 2; } else if (lp->options & PCNET32_PORT_ASEL) { /* workaround of xSeries250, turn on for 79C975 only */ i = ((lp->a.read_csr(ioaddr, 88) | (lp->a.read_csr(ioaddr,89) << 16)) >> 12) & 0xffff; if (i == 0x2627) val |= 3; } lp->a.write_bcr (ioaddr, 9, val); } /* set/reset GPSI bit in test register */ val = lp->a.read_csr (ioaddr, 124) & ~0x10; if ((lp->options & PCNET32_PORT_PORTSEL) == PCNET32_PORT_GPSI) val |= 0x10; lp->a.write_csr (ioaddr, 124, val); /* Allied Telesyn AT 2700/2701 FX are 100Mbit only and do not negotiate */ if (lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT && (lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX || lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX)) { if (lp->options & PCNET32_PORT_ASEL) { lp->options = PCNET32_PORT_FD | PCNET32_PORT_100; if (netif_msg_link(lp)) printk(KERN_DEBUG "%s: Setting 100Mb-Full Duplex.\n", dev->name); } } { /* * 24 Jun 2004 according AMD, in order to change the PHY, * DANAS (or DISPM for 79C976) must be set; then select the speed, * duplex, and/or enable auto negotiation, and clear DANAS */ if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); /* disable Auto Negotiation, set 10Mpbs, HD */ val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; if (lp->options & PCNET32_PORT_FD) val |= 0x10; if (lp->options & PCNET32_PORT_100) val |= 0x08; lp->a.write_bcr (ioaddr, 32, val); } else { if (lp->options & PCNET32_PORT_ASEL) { lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); /* enable auto negotiate, setup, disable fd */ val = lp->a.read_bcr(ioaddr, 32) & ~0x98; val |= 0x20; lp->a.write_bcr(ioaddr, 32, val); } } }#ifdef DO_DXSUFLO if (lp->dxsuflo) { /* Disable transmit stop on underflow */ val = lp->a.read_csr (ioaddr, 3); val |= 0x40; lp->a.write_csr (ioaddr, 3, val); }#endif lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); pcnet32_load_multicast(dev); if (pcnet32_init_ring(dev)) { rc = -ENOMEM; goto err_free_ring; } /* Re-initialize the PCNET32, and start it when done. */ lp->a.write_csr (ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) & 0xffff); lp->a.write_csr (ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, init_block)) >> 16); lp->a.write_csr (ioaddr, 4, 0x0915); lp->a.write_csr (ioaddr, 0, 0x0001); netif_start_queue(dev); /* If we have mii, print the link status and start the watchdog */ if (lp->mii) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -