⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcnet32.c

📁 一个基于linux的TCP/IP协议栈的实现
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -