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

📄 pcnet32.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
				int status = (short)le16_to_cpu(lp->tx_ring[entry].status);							if (status < 0)					break;			/* It still hasn't been Txed */				lp->tx_ring[entry].base = 0;				if (status & 0x4000) {					/* There was an major error, log it. */					int err_status = le32_to_cpu(lp->tx_ring[entry].misc);					lp->stats.tx_errors++;					if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;					if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;					if (err_status & 0x10000000) lp->stats.tx_window_errors++;					if (err_status & 0x40000000) {						/* Ackk!  On FIFO errors the Tx unit is turned off! */						lp->stats.tx_fifo_errors++;						/* Remove this verbosity later! */						printk("%s: Tx FIFO error! Status %4.4x.\n",							   dev->name, csr0);						must_restart = 1;					}				} else {					if (status & 0x1800)						lp->stats.collisions++;					lp->stats.tx_packets++;				}				/* We must free the original skb */				if (lp->tx_skbuff[entry]) {					dev_kfree_skb(lp->tx_skbuff[entry]);					lp->tx_skbuff[entry] = 0;				}				dirty_tx++;			}#ifndef final_version			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {				printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",					   dirty_tx, lp->cur_tx, lp->tx_full);				dirty_tx += TX_RING_SIZE;			}#endif			if (lp->tx_full && dev->tbusy				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {				/* The ring is no longer full, clear tbusy. */				lp->tx_full = 0;				clear_bit(0, (void *)&dev->tbusy);				mark_bh(NET_BH);			}			lp->dirty_tx = dirty_tx;		}		/* 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("%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 */		        outw(0x0000, dev->base_addr + PCNET32_ADDR);		        outw(0x0004, dev->base_addr + PCNET32_DATA);		        pcnet32_restart(dev, 0x0002);		}	}    /* Clear any other interrupt, and set interrupt enable. */    outw(0x0000, dev->base_addr + PCNET32_ADDR);    outw(0x7940, dev->base_addr + PCNET32_DATA);	if (pcnet32_debug > 4)		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",			   dev->name, inw(ioaddr + PCNET32_ADDR),			   inw(dev->base_addr + PCNET32_DATA));	dev->interrupt = 0;	return;}static intpcnet32_rx(struct device *dev){	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;	int entry = lp->cur_rx & RX_RING_MOD_MASK;	int i;	/* 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("%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_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail));				    rx_in_place = 1;				} else				    skb = NULL;			    } else				skb = dev_alloc_skb(pkt_len+2);			    			    if (skb == NULL) {				printk("%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 *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),					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;	}	/* We should check that at least two ring entries are free.	 If not,	   we should free one and mark stats->rx_dropped++. */	return 0;}static intpcnet32_close(struct device *dev){	unsigned int ioaddr = dev->base_addr;	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;        int i;	dev->start = 0;	set_bit (0, (void *)&dev->tbusy);	outw(112, ioaddr+PCNET32_ADDR);	lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);	outw(0, ioaddr+PCNET32_ADDR);	if (pcnet32_debug > 1)		printk("%s: Shutting down ethercard, status was %2.2x.\n",			   dev->name, inw(ioaddr+PCNET32_DATA));	/* We stop the PCNET32 here -- it occasionally polls	   memory if we don't. */	outw(0x0004, ioaddr+PCNET32_DATA);	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])		dev_kfree_skb(lp->rx_skbuff[i]);	    lp->rx_skbuff[i] = NULL;	}            for (i = 0; i < TX_RING_SIZE; i++) {	    if (lp->tx_skbuff[i])		dev_kfree_skb(lp->tx_skbuff[i]);	    lp->rx_skbuff[i] = NULL;	}            MOD_DEC_USE_COUNT;	return 0;}static struct net_device_stats *pcnet32_get_stats(struct device *dev){	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;	unsigned int ioaddr = dev->base_addr;	unsigned short saved_addr;	unsigned long flags;	save_flags(flags);	cli();	saved_addr = inw(ioaddr+PCNET32_ADDR);	outw(112, ioaddr+PCNET32_ADDR);	lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);	outw(saved_addr, ioaddr+PCNET32_ADDR);	restore_flags(flags);	return &lp->stats;}/* taken from the sunlance driver, which it took from the depca driver */static void pcnet32_load_multicast (struct 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 device *dev){	unsigned int ioaddr = dev->base_addr;	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    	if (dev->flags&IFF_PROMISC) {		/* Log any net taps. */		printk("%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);	}    	outw(0, ioaddr+PCNET32_ADDR);	outw(0x0004, ioaddr+PCNET32_DATA); /* Temporarily stop the lance.	 */	pcnet32_restart(dev, 0x0042); /*  Resume normal operation */}#ifdef MODULEMODULE_PARM(debug, "i");MODULE_PARM(options, "i");MODULE_PARM(max_interrupt_work, "i");MODULE_PARM(rx_copybreak, "i");/* An additional parameter that may be passed in... */static int debug = -1;intinit_module(void){        if (debug > 0)	        pcnet32_debug = debug;    	pcnet32_dev = NULL;	return pcnet32_probe(NULL);}voidcleanup_module(void){	struct device *next_dev;	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (pcnet32_dev) {		next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next;		unregister_netdev(pcnet32_dev);		release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);	        kfree(pcnet32_dev->priv);		kfree(pcnet32_dev);		pcnet32_dev = next_dev;	}}#endif /* 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: 4 * End: */

⌨️ 快捷键说明

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