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

📄 via-rhine.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
			   dev->name, np->cur_tx, entry);	}	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs){	struct device *dev = (struct device *)dev_instance;	struct netdev_private *np;	long ioaddr, boguscnt = max_interrupt_work;	ioaddr = dev->base_addr;	np = (struct netdev_private *)dev->priv;#if defined(__i386__)	/* A lock to prevent simultaneous entry bug on Intel SMP machines. */	if (test_and_set_bit(0, (void*)&dev->interrupt)) {		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",			   dev->name);		dev->interrupt = 0;	/* Avoid halting machine. */		return;	}#else	if (dev->interrupt) {		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);		return;	}	dev->interrupt = 1;#endif	do {		u32 intr_status = readw(ioaddr + IntrStatus);		/* Acknowledge all of the current interrupt sources ASAP. */		writew(intr_status & 0xffff, ioaddr + IntrStatus);		if (debug > 4)			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",				   dev->name, intr_status);		if (intr_status == 0)			break;		if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |						   IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))			netdev_rx(dev);		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {			int entry = np->dirty_tx % TX_RING_SIZE;			int txstatus;			if (np->tx_ring[entry].tx_own)				break;			txstatus = np->tx_ring[entry].tx_status;			if (debug > 6)				printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",					   entry, txstatus);			if (txstatus & 0x8000) {				if (debug > 1)					printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",						   dev->name, txstatus);				np->stats.tx_errors++;				if (txstatus & 0x0400) np->stats.tx_carrier_errors++;				if (txstatus & 0x0200) np->stats.tx_window_errors++;				if (txstatus & 0x0100) np->stats.tx_aborted_errors++;				if (txstatus & 0x0080) np->stats.tx_heartbeat_errors++;				if (txstatus & 0x0002) np->stats.tx_fifo_errors++;#ifdef ETHER_STATS				if (txstatus & 0x0100) np->stats.collisions16++;#endif				/* Transmitter restarted in 'abnormal' handler. */			} else {#ifdef ETHER_STATS				if (txstatus & 0x0001) np->stats.tx_deferred++;#endif				np->stats.collisions += (txstatus >> 3) & 15;#if defined(NETSTATS_VER2)				np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;#endif				np->stats.tx_packets++;			}			/* Free the original skb. */			dev_free_skb(np->tx_skbuff[entry]);			np->tx_skbuff[entry] = 0;		}		if (np->tx_full && dev->tbusy			&& np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {			/* The ring is no longer full, clear tbusy. */			np->tx_full = 0;			clear_bit(0, (void*)&dev->tbusy);			mark_bh(NET_BH);		}		/* Abnormal error summary/uncommon events handlers. */		if (intr_status & (IntrPCIErr | IntrLinkChange | IntrMIIChange |						   IntrStatsMax | IntrTxAbort | IntrTxUnderrun))			netdev_error(dev, intr_status);		if (--boguscnt < 0) {			printk(KERN_WARNING "%s: Too much work at interrupt, "				   "status=0x%4.4x.\n",				   dev->name, intr_status);			break;		}	} while (1);	if (debug > 3)		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",			   dev->name, readw(ioaddr + IntrStatus));#if defined(__i386__)	clear_bit(0, (void*)&dev->interrupt);#else	dev->interrupt = 0;#endif	return;}/* This routine is logically part of the interrupt handler, but isolated   for clarity and better register allocation. */static int netdev_rx(struct device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	int entry = np->cur_rx % RX_RING_SIZE;	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;	if (debug > 4) {		printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",			   entry, np->rx_head_desc->rx_length);	}	/* If EOP is set on the next entry, it's a new packet. Send it up. */	while ( ! (np->rx_head_desc->rx_length & DescOwn)) {		struct rx_desc *desc = np->rx_head_desc;		int data_size = desc->rx_length;		u16 desc_status = desc->rx_status;		if (debug > 4)			printk(KERN_DEBUG "  netdev_rx() status is %4.4x.\n",				   desc_status);		if (--boguscnt < 0)			break;		if ( (desc_status & (RxWholePkt | RxErr)) !=  RxWholePkt) {			if ((desc_status & RxWholePkt) !=  RxWholePkt) {				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned "					   "multiple buffers, entry %#x length %d status %4.4x!\n",					   dev->name, np->cur_rx, data_size, desc_status);				printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n",					   dev->name, np->rx_head_desc,					   &np->rx_ring[np->cur_rx % RX_RING_SIZE]);				np->stats.rx_length_errors++;			} else if (desc_status & RxErr) {				/* There was a error. */				if (debug > 2)					printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",						   desc_status);				np->stats.rx_errors++;				if (desc_status & 0x0030) np->stats.rx_length_errors++;				if (desc_status & 0x0048) np->stats.rx_fifo_errors++;				if (desc_status & 0x0004) np->stats.rx_frame_errors++;				if (desc_status & 0x0002) np->stats.rx_crc_errors++;			}		} else {			struct sk_buff *skb;			/* Length should omit the CRC */			u16 pkt_len = data_size - 4;			/* Check if the packet is long enough to accept without copying			   to a minimally-sized skbuff. */			if (pkt_len < rx_copybreak				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {				skb->dev = dev;				skb_reserve(skb, 2);	/* 16 byte align the IP header */#if ! defined(__alpha__) || USE_IP_COPYSUM		/* Avoid misaligned on Alpha */				eth_copy_and_sum(skb, bus_to_virt(desc->addr),								 pkt_len, 0);				skb_put(skb, pkt_len);#else				memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len);#endif			} else {				skb_put(skb = np->rx_skbuff[entry], pkt_len);				np->rx_skbuff[entry] = NULL;			}			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			dev->last_rx = jiffies;			np->stats.rx_packets++;		}		entry = (++np->cur_rx) % RX_RING_SIZE;		np->rx_head_desc = &np->rx_ring[entry];	}	/* Refill the Rx ring buffers. */	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {		struct sk_buff *skb;		entry = np->dirty_rx % RX_RING_SIZE;		if (np->rx_skbuff[entry] == NULL) {			skb = dev_alloc_skb(np->rx_buf_sz);			np->rx_skbuff[entry] = skb;			if (skb == NULL)				break;			/* Better luck next round. */			skb->dev = dev;			/* Mark as being used by this device. */			np->rx_ring[entry].addr = virt_to_bus(skb->tail);		}		np->rx_ring[entry].rx_status = 0;		np->rx_ring[entry].rx_length = DescOwn;	}	/* Pre-emptively restart Rx engine. */	writew(CmdRxDemand | np->chip_cmd, dev->base_addr + ChipCmd);	return 0;}static void netdev_error(struct device *dev, int intr_status){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	if (intr_status & (IntrMIIChange | IntrLinkChange)) {		if (readb(ioaddr + MIIStatus) & 0x02)			/* Link failed, restart autonegotiation. */			mdio_write(dev, np->phys[0], 0, 0x3300);		else			check_duplex(dev);		if (debug)			printk(KERN_ERR "%s: MII status changed: Autonegotiation "				   "advertising %4.4x  partner %4.4x.\n", dev->name,			   mdio_read(dev, np->phys[0], 4),			   mdio_read(dev, np->phys[0], 5));	}	if (intr_status & IntrStatsMax) {		np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);		writel(0, RxMissed);	}	if (intr_status & IntrTxAbort) {		/* Stats counted in Tx-done handler, just restart Tx. */		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);	}	if (intr_status & IntrTxUnderrun) {		if (np->tx_thresh < 0xE0)			writeb(np->tx_thresh += 0x20, ioaddr + TxConfig);		if (debug > 1)			printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "				   "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);	}	if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) {		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",			   dev->name, intr_status);		/* Recovery for other fault sources not known. */		writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);	}}static struct enet_statistics *get_stats(struct device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	/* Nominally we should lock this segment of code for SMP, although	   the vulnerability window is very small and statistics are	   non-critical. */	np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);	np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);	writel(0, RxMissed);	return &np->stats;}/* The big-endian AUTODIN II ethernet CRC calculation.   N.B. Do not use for bulk data, use a table-based routine instead.   This is common code and should be moved to net/core/crc.c */static unsigned const ethernet_polynomial = 0x04c11db7U;static inline u32 ether_crc(int length, unsigned char *data){    int crc = -1;    while(--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {			crc = (crc << 1) ^				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);		}    }    return crc;}static void set_rx_mode(struct device *dev){	struct netdev_private *np = (struct netdev_private *)dev->priv;	long ioaddr = dev->base_addr;	u32 mc_filter[2];			/* Multicast hash filter */	u8 rx_mode;					/* Note: 0x02=accept runt, 0x01=accept errs */	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		/* Unconditionally log net taps. */		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);		rx_mode = 0x1C;	} else if ((dev->mc_count > multicast_filter_limit)			   ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to match, or accept all multicasts. */		rx_mode = 0x0C;	} else {		struct dev_mc_list *mclist;		int i;		memset(mc_filter, 0, sizeof(mc_filter));		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next) {			set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26,					mc_filter);		}		writel(mc_filter[0], ioaddr + MulticastFilter0);		writel(mc_filter[1], ioaddr + MulticastFilter1);		rx_mode = 0x0C;	}	writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);}static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd){	u16 *data = (u16 *)&rq->ifr_data;	switch(cmd) {	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */		data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f;		/* Fall Through */	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);		return 0;	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */		if (!suser())			return -EPERM;		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);		return 0;	default:		return -EOPNOTSUPP;	}}static int netdev_close(struct device *dev){	long ioaddr = dev->base_addr;	struct netdev_private *np = (struct netdev_private *)dev->priv;	int i;	dev->start = 0;	dev->tbusy = 1;	if (debug > 1)		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",			   dev->name, readw(ioaddr + ChipCmd));	/* Disable interrupts by clearing the interrupt mask. */	writew(0x0000, ioaddr + IntrEnable);	/* Stop the chip's Tx and Rx processes. */	writew(CmdStop, ioaddr + ChipCmd);	del_timer(&np->timer);	free_irq(dev->irq, dev);	/* Free all the skbuffs in the Rx queue. */	for (i = 0; i < RX_RING_SIZE; i++) {		np->rx_ring[i].rx_length = 0;		np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */		if (np->rx_skbuff[i]) {#if LINUX_VERSION_CODE < 0x20100			np->rx_skbuff[i]->free = 1;#endif			dev_free_skb(np->rx_skbuff[i]);		}		np->rx_skbuff[i] = 0;	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (np->tx_skbuff[i])			dev_free_skb(np->tx_skbuff[i]);		np->tx_skbuff[i] = 0;	}	MOD_DEC_USE_COUNT;	return 0;}#ifdef MODULEint init_module(void){	if (debug)					/* Emit version even if no cards detected. */		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);#ifdef CARDBUS	register_driver(&etherdev_ops);	return 0;#else	return pci_etherdev_probe(NULL, pci_tbl);#endif}void cleanup_module(void){#ifdef CARDBUS	unregister_driver(&etherdev_ops);#endif	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (root_net_dev) {		struct netdev_private *np =			(struct netdev_private *)(root_net_dev->priv);		unregister_netdev(root_net_dev);#ifdef VIA_USE_IO		release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size);#else		iounmap((char *)(root_net_dev->base_addr));#endif		kfree(root_net_dev);		root_net_dev = np->next_module;#if 0		kfree(np);				/* Assumption: no struct realignment. */#endif	}}#endif  /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c via-rhine.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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