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

📄 pcnet32.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* Log misc errors. */	if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */	if (csr0 & 0x1000) {	    /*	     * this happens when our receive ring is full. This shouldn't	     * be a problem as we will see normal rx interrupts for the frames	     * in the receive ring. But there are some PCI chipsets (I can reproduce	     * this on SP3G with Intel saturn chipset) which have sometimes problems	     * and will fill up the receive ring with error descriptors. In this	     * situation we don't get a rx interrupt, but a missed frame interrupt sooner	     * or later. So we try to clean up our receive ring here.	     */	    pcnet32_rx(dev);	    lp->stats.rx_errors++; /* Missed a Rx frame. */	}	if (csr0 & 0x0800) {	    printk(KERN_ERR "%s: Bus master arbitration failure, status %4.4x.\n",		   dev->name, csr0);	    /* unlike for the lance, there is no restart needed */	}	if (must_restart) {	    /* stop the chip to clear the error condition, then restart */	    lp->a.write_csr (ioaddr, 0, 0x0004);	    pcnet32_restart(dev, 0x0002);	}    }    /* Clear any other interrupt, and set interrupt enable. */    lp->a.write_csr (ioaddr, 0, 0x7940);    lp->a.write_rap(ioaddr,rap);        if (pcnet32_debug > 4)	printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",	       dev->name, lp->a.read_csr (ioaddr, 0));    spin_unlock(&lp->lock);}static intpcnet32_rx(struct net_device *dev){    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    int entry = lp->cur_rx & RX_RING_MOD_MASK;    /* If we own the next entry, it's a new packet. Send it up. */    while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {	int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;	if (status != 0x03) {			/* There was an error. */	    /* 	     * There is a tricky error noted by John Murphy,	     * <murf@perftech.com> to Russ Nelson: Even with full-sized	     * buffers it's possible for a jabber packet to use two	     * buffers, with only the last correctly noting the error.	     */	    if (status & 0x01)	/* Only count a general error at the */		lp->stats.rx_errors++; /* end of a packet.*/	    if (status & 0x20) lp->stats.rx_frame_errors++;	    if (status & 0x10) lp->stats.rx_over_errors++;	    if (status & 0x08) lp->stats.rx_crc_errors++;	    if (status & 0x04) lp->stats.rx_fifo_errors++;	    lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);	} else {	    /* Malloc up new buffer, compatible with net-2e. */	    short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;	    struct sk_buff *skb;				    if(pkt_len < 60) {		printk(KERN_ERR "%s: Runt packet!\n",dev->name);		lp->stats.rx_errors++;	    } else {		int rx_in_place = 0;		if (pkt_len > rx_copybreak) {		    struct sk_buff *newskb;						    if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {			skb_reserve (newskb, 2);			skb = lp->rx_skbuff[entry];			skb_put (skb, pkt_len);			lp->rx_skbuff[entry] = newskb;			newskb->dev = dev;                        lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->tail, newskb->len, PCI_DMA_FROMDEVICE);			lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);			rx_in_place = 1;		    } else			skb = NULL;		} else {		    skb = dev_alloc_skb(pkt_len+2);                }			    		if (skb == NULL) {                    int i;		    printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name);		    for (i = 0; i < RX_RING_SIZE; i++)			if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)			    break;		    if (i > RX_RING_SIZE -2) {			lp->stats.rx_dropped++;			lp->rx_ring[entry].status |= le16_to_cpu(0x8000);			lp->cur_rx++;		    }		    break;		}		skb->dev = dev;		if (!rx_in_place) {		    skb_reserve(skb,2); /* 16 byte align */		    skb_put(skb,pkt_len);	/* Make room */		    eth_copy_and_sum(skb,				     (unsigned char *)(lp->rx_skbuff[entry]->tail),				     pkt_len,0);		}		lp->stats.rx_bytes += skb->len;		skb->protocol=eth_type_trans(skb,dev);		netif_rx(skb);		lp->stats.rx_packets++;	    }	}	/*	 * The docs say that the buffer length isn't touched, but Andrew Boyd	 * of QNX reports that some revs of the 79C965 clear it.	 */	lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);	lp->rx_ring[entry].status |= le16_to_cpu(0x8000);	entry = (++lp->cur_rx) & RX_RING_MOD_MASK;    }    return 0;}static intpcnet32_close(struct net_device *dev){    unsigned long ioaddr = dev->base_addr;    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    int i;    netif_stop_queue(dev);    lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);    if (pcnet32_debug > 1)	printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",	       dev->name, lp->a.read_csr (ioaddr, 0));    /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */    lp->a.write_csr (ioaddr, 0, 0x0004);    /*     * Switch back to 16bit mode to avoid problems with dumb      * DOS packet driver after a warm reboot     */    lp->a.write_bcr (ioaddr, 20, 4);    free_irq(dev->irq, dev);        /* free all allocated skbuffs */    for (i = 0; i < RX_RING_SIZE; i++) {	lp->rx_ring[i].status = 0;			    	if (lp->rx_skbuff[i]) {            pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], lp->rx_skbuff[i]->len, PCI_DMA_FROMDEVICE);	    dev_kfree_skb(lp->rx_skbuff[i]);        }	lp->rx_skbuff[i] = NULL;        lp->rx_dma_addr[i] = 0;    }        for (i = 0; i < TX_RING_SIZE; i++) {	if (lp->tx_skbuff[i]) {            pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE);	    dev_kfree_skb(lp->tx_skbuff[i]);        }	lp->tx_skbuff[i] = NULL;        lp->tx_dma_addr[i] = 0;    }        MOD_DEC_USE_COUNT;    return 0;}static struct net_device_stats *pcnet32_get_stats(struct net_device *dev){    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    unsigned long ioaddr = dev->base_addr;    u16 saved_addr;    unsigned long flags;    spin_lock_irqsave(&lp->lock, flags);    saved_addr = lp->a.read_rap(ioaddr);    lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);    lp->a.write_rap(ioaddr, saved_addr);    spin_unlock_irqrestore(&lp->lock, flags);    return &lp->stats;}/* taken from the sunlance driver, which it took from the depca driver */static void pcnet32_load_multicast (struct net_device *dev){    struct pcnet32_private *lp = (struct pcnet32_private *) dev->priv;    volatile struct pcnet32_init_block *ib = &lp->init_block;    volatile u16 *mcast_table = (u16 *)&ib->filter;    struct dev_mc_list *dmi=dev->mc_list;    char *addrs;    int i, j, bit, byte;    u32 crc, poly = CRC_POLYNOMIAL_LE;	    /* set all multicast bits */    if (dev->flags & IFF_ALLMULTI){ 	ib->filter [0] = 0xffffffff;	ib->filter [1] = 0xffffffff;	return;    }    /* clear the multicast filter */    ib->filter [0] = 0;    ib->filter [1] = 0;    /* Add addresses */    for (i = 0; i < dev->mc_count; i++){	addrs = dmi->dmi_addr;	dmi   = dmi->next;		/* multicast address? */	if (!(*addrs & 1))	    continue;		crc = 0xffffffff;	for (byte = 0; byte < 6; byte++)	    for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {		int test;				test = ((bit ^ crc) & 0x01);		crc >>= 1;				if (test) {		    crc = crc ^ poly;		}	    }		crc = crc >> 26;	mcast_table [crc >> 4] |= 1 << (crc & 0xf);    }    return;}/* * Set or clear the multicast filter for this adaptor. */static void pcnet32_set_multicast_list(struct net_device *dev){    unsigned long ioaddr = dev->base_addr;    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;	     if (dev->flags&IFF_PROMISC) {	/* Log any net taps. */	printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);	lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7);    } else {	lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);	pcnet32_load_multicast (dev);    }        lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */    pcnet32_restart(dev, 0x0042); /*  Resume normal operation */}#ifdef HAVE_PRIVATE_IOCTLstatic int pcnet32_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd){    unsigned long ioaddr = dev->base_addr;    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;	     u16 *data = (u16 *)&rq->ifr_data;    int phyaddr = lp->a.read_bcr (ioaddr, 33);    if (lp->mii) {	switch(cmd) {	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */	    data[0] = (phyaddr >> 5) & 0x1f;	    /* Fall Through */	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */	    lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));	    data[3] = lp->a.read_bcr (ioaddr, 34);	    lp->a.write_bcr (ioaddr, 33, phyaddr);	    return 0;	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */	    if (!capable(CAP_NET_ADMIN))		return -EPERM;	    lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));	    lp->a.write_bcr (ioaddr, 34, data[2]);	    lp->a.write_bcr (ioaddr, 33, phyaddr);	    return 0;	default:	    return -EOPNOTSUPP;	}    }    return -EOPNOTSUPP;}#endif	/* HAVE_PRIVATE_IOCTL */					    static struct pci_driver pcnet32_driver = {    name:  "pcnet32",    probe: pcnet32_probe_pci,    remove: NULL,    id_table: pcnet32_pci_tbl,};MODULE_PARM(debug, "i");MODULE_PARM(max_interrupt_work, "i");MODULE_PARM(rx_copybreak, "i");MODULE_PARM(tx_start_pt, "i");MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_AUTHOR("Thomas Bogendoerfer");MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards");/* An additional parameter that may be passed in... */static int debug = -1;static int tx_start_pt = -1;static int __init pcnet32_init_module(void){    int cards_found = 0;    int err;    if (debug > 0)	pcnet32_debug = debug;    if ((tx_start_pt >= 0) && (tx_start_pt <= 3))	tx_start = tx_start_pt;        pcnet32_dev = NULL;    /* find the PCI devices */#define USE_PCI_REGISTER_DRIVER#ifdef USE_PCI_REGISTER_DRIVER    if ((err = pci_module_init(&pcnet32_driver)) < 0 )       return err;#else    {        struct pci_device_id *devid = pcnet32_pci_tbl;        for (devid = pcnet32_pci_tbl; devid != NULL && devid->vendor != 0; devid++) {            struct pci_dev *pdev = pci_find_subsys(devid->vendor, devid->device, devid->subvendor, devid->subdevice, NULL);            if (pdev != NULL) {                if (pcnet32_probe_pci(pdev, devid) >= 0) {                    cards_found++;                }            }        }    }#endif    return 0;    /* find any remaining VLbus devices */    return pcnet32_probe_vlbus(cards_found);}static void __exit pcnet32_cleanup_module(void){    struct net_device *next_dev;    /* No need to check MOD_IN_USE, as sys_delete_module() checks. */    while (pcnet32_dev) {        struct pcnet32_private *lp = (struct pcnet32_private *) pcnet32_dev->priv;	next_dev = lp->next;	unregister_netdev(pcnet32_dev);	release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);        pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);	kfree(pcnet32_dev);	pcnet32_dev = next_dev;    }}module_init(pcnet32_init_module);module_exit(pcnet32_cleanup_module);/* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c" *  c-indent-level: 4 *  tab-width: 8 * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -