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

📄 yellowfin.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
#ifdef ETHER_STATS					if (status & 0x0400) lp->stats.tx_deferred++;#endif					lp->stats.collisions += tx_errs & 15;					lp->stats.tx_packets++;				}				/* Free the original skb. */				dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);				lp->tx_skbuff[entry] = 0;				/* Mark status as empty. */				lp->tx_status[entry].tx_errs = 0;			}#ifndef final_version			if (lp->cur_tx - dirty_tx > TX_RING_SIZE) {				printk("%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",					   dev->name, dirty_tx, lp->cur_tx, lp->tx_full);				dirty_tx += TX_RING_SIZE;			}#endif			if (lp->tx_full && dev->tbusy				&& lp->cur_tx - dirty_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;		}#endif		/* Log errors and other events. */		if (intr_status & 0x2ee) {	/* Abnormal error summary. */			printk("%s: Something Wicked happened! %4.4x.\n",				   dev->name, intr_status);			/* Hmmmmm, it's not clear what to do here. */			if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))				lp->stats.tx_errors++;			if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))				lp->stats.rx_errors++;		}		if (--boguscnt < 0) {			printk("%s: Too much work at interrupt, status=0x%4.4x.\n",				   dev->name, intr_status);			break;		}	} while (1);	if (yellowfin_debug > 3)		printk("%s: exiting interrupt, status=%#4.4x.\n",			   dev->name, inw(ioaddr + IntrStatus));	/* Code that should never be run!  Perhaps remove after testing.. */	{		static int stopit = 10;		if (dev->start == 0  &&  --stopit < 0) {			printk("%s: Emergency stop, looping startup interrupt.\n",				   dev->name);#ifdef SA_SHIRQ			free_irq(irq, dev);#else			free_irq(irq);#endif		}	}	dev->interrupt = 0;	clear_bit(0, (void*)&lp->in_interrupt);	return;}/* This routine is logically part of the interrupt handler, but separated   for clarity and better register allocation. */static intyellowfin_rx(struct device *dev){	struct yellowfin_private *lp = (struct yellowfin_private *)dev->priv;	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	int entry = lp->cur_rx % RX_RING_SIZE;	int boguscnt = 20;	if (yellowfin_debug > 4) {		printk(" In yellowfin_rx(), entry %d status %4.4x.\n", entry,			   yp->rx_ring[entry].status);		printk("   #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x.\n",			   entry, yp->rx_ring[entry].cmd,			   yp->rx_ring[entry].request_cnt, yp->rx_ring[entry].addr,			   yp->rx_ring[entry].result_cnt, yp->rx_ring[entry].status);	}	/* If EOP is set on the next entry, it's a new packet. Send it up. */	while (yp->rx_ring[entry].status) {		/* Todo: optimize this mess. */		u16 desc_status = yp->rx_ring[entry].status;		struct yellowfin_desc *desc = &lp->rx_ring[entry];		int frm_size = desc->request_cnt - desc->result_cnt;		u8 *buf_addr = bus_to_virt(lp->rx_ring[entry].addr);		s16 frame_status = *(s16*)&(buf_addr[frm_size - 2]);		if (yellowfin_debug > 4)			printk("  yellowfin_rx() status was %4.4x.\n", frame_status);		if (--boguscnt < 0)			break;		if ( ! (desc_status & RX_EOP)) {			printk("%s: Oversized Ethernet frame spanned multiple buffers,"				   " status %4.4x!\n", dev->name, desc_status);			  lp->stats.rx_length_errors++;		} else if (frame_status & 0x0038) {			/* There was a error. */			if (yellowfin_debug > 3)				printk("  yellowfin_rx() Rx error was %4.4x.\n", frame_status);			lp->stats.rx_errors++;			if (frame_status & 0x0060) lp->stats.rx_length_errors++;			if (frame_status & 0x0008) lp->stats.rx_frame_errors++;			if (frame_status & 0x0010) lp->stats.rx_crc_errors++;			if (frame_status < 0) lp->stats.rx_dropped++;#ifdef YF_PROTOTYPE			/* Support for prototype hardware errata. */		} else if (memcmp(bus_to_virt(lp->rx_ring[entry].addr),						  dev->dev_addr, 6) != 0				   && memcmp(bus_to_virt(lp->rx_ring[entry].addr),							 "\377\377\377\377\377\377", 6) != 0) {			printk("%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",				   dev->name,				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[0],				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[1],				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[2],				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[3],				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[4],				   ((char *)bus_to_virt(lp->rx_ring[entry].addr))[5]);			bogus_rx++;#endif		} else {			u8 bogus_cnt = buf_addr[frm_size - 8];			int pkt_len = frm_size - 8 - bogus_cnt;			struct sk_buff *skb;			int rx_in_place = 0;			/* Check if the packet is long enough to just accept without			   copying to a properly sized skbuff. */			if (pkt_len > rx_copybreak) {				struct sk_buff *newskb;				char *temp;				/* Get a fresh skbuff to replace the filled one. */				newskb = DEV_ALLOC_SKB(dev->mtu <= 1500 ? PKT_BUF_SZ									   : dev->mtu + 32);				if (newskb == NULL) {					skb = 0;		/* No memory, drop the packet. */					goto memory_squeeze;				}				/* Pass up the skb already on the Rx ring. */				skb = lp->rx_skbuff[entry];				temp = skb_put(skb, pkt_len);				if (bus_to_virt(lp->rx_ring[entry].addr) != temp)					printk("%s: Warning -- the skbuff addresses do not match"						   " in yellowfin_rx: %p vs. %p / %p.\n", dev->name,						   bus_to_virt(lp->rx_ring[entry].addr),						   skb->head, temp);				rx_in_place = 1;				lp->rx_skbuff[entry] = newskb;				newskb->dev = dev;				skb_reserve(newskb, 2);	/* 16 byte align IP header */				lp->rx_ring[entry].addr = virt_to_bus(newskb->tail);			} else				skb = DEV_ALLOC_SKB(pkt_len + 2);			memory_squeeze:			if (skb == NULL) {				printk("%s: Memory squeeze, deferring packet.\n", dev->name);				/* todo: Check that at least two ring entries are free.				   If not, free one and mark stats->rx_dropped++. */				break;			}			skb->dev = dev;			if (! rx_in_place) {				skb_reserve(skb, 2);	/* 16 byte align the data fields */				memcpy(skb_put(skb, pkt_len),					   bus_to_virt(lp->rx_ring[entry].addr), pkt_len);			}#if LINUX_VERSION_CODE > 0x10300			skb->protocol = eth_type_trans(skb, dev);#else			skb->len = pkt_len;#endif			netif_rx(skb);			lp->stats.rx_packets++;		}		/* Mark this entry as being the end-of-list, and the prior entry		   as now valid. */		lp->rx_ring[entry].cmd = CMD_STOP;		yp->rx_ring[entry].status = 0;		{			int prev_entry = entry - 1;			if (prev_entry < 0)				lp->rx_ring[RX_RING_SIZE - 1].cmd =					CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;			else				lp->rx_ring[prev_entry].cmd = CMD_RX_BUF | INTR_ALWAYS;		}		entry = (++lp->cur_rx) % RX_RING_SIZE;	}	/* todo: restart Rx engine if stopped.  For now we just make the Rx ring	   large enough to avoid this. */	return 0;}static intyellowfin_close(struct device *dev){	int ioaddr = dev->base_addr;	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	int i;	dev->start = 0;	dev->tbusy = 1;	if (yellowfin_debug > 1) {		printk("%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n",			   dev->name, inw(ioaddr + TxStatus),			   inw(ioaddr + RxStatus), inl(ioaddr + IntrStatus));		printk("%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",			   dev->name, yp->cur_tx, yp->dirty_tx, yp->cur_rx, yp->dirty_rx);	}	/* Disable interrupts by clearing the interrupt mask. */	outw(0x0000, ioaddr + IntrEnb);	/* Stop the chip's Tx and Rx processes. */	outl(0x80000000, ioaddr + RxCtrl);	outl(0x80000000, ioaddr + TxCtrl);	del_timer(&yp->timer);#ifdef __i386__	if (yellowfin_debug > 2) {		printk("\n  Tx ring at %8.8x:\n", (int)virt_to_bus(yp->tx_ring));		for (i = 0; i < TX_RING_SIZE*2; i++)			printk(" %c #%d desc. %4.4x %4.4x %8.8x %8.8x %4.4x %4.4x.\n",				   inl(ioaddr + TxPtr) == (long)&yp->tx_ring[i] ? '>' : ' ',				   i, yp->tx_ring[i].cmd,				   yp->tx_ring[i].request_cnt, yp->tx_ring[i].addr,				   yp->tx_ring[i].branch_addr,				   yp->tx_ring[i].result_cnt, yp->tx_ring[i].status);		printk("  Tx status %p:\n", yp->tx_status);		for (i = 0; i < TX_RING_SIZE; i++)			printk("   #%d status %4.4x %4.4x %4.4x %4.4x.\n",				   i, yp->tx_status[i].tx_cnt, yp->tx_status[i].tx_errs,				   yp->tx_status[i].total_tx_cnt, yp->tx_status[i].paused);		printk("\n  Rx ring %8.8x:\n", (int)virt_to_bus(yp->rx_ring));		for (i = 0; i < RX_RING_SIZE; i++) {			printk(" %c #%d desc. %4.4x %4.4x %8.8x %4.4x %4.4x\n",				   inl(ioaddr + RxPtr) == (long)&yp->rx_ring[i] ? '>' : ' ',				   i, yp->rx_ring[i].cmd,				   yp->rx_ring[i].request_cnt, yp->rx_ring[i].addr,				   yp->rx_ring[i].result_cnt, yp->rx_ring[i].status);			if (yellowfin_debug > 5) {				if (*(u8*)yp->rx_ring[i].addr != 0x69) {					int j;					for (j = 0; j < 0x50; j++)						printk(" %4.4x", ((u16*)yp->rx_ring[i].addr)[j]);					printk("\n");				}			}		}	}#endif /* __i386__ debugging only */#ifdef SA_SHIRQ	free_irq(dev->irq, dev);#else	free_irq(dev->irq);	irq2dev_map[dev->irq] = 0;#endif	/* Free all the skbuffs in the Rx queue. */	for (i = 0; i < RX_RING_SIZE; i++) {		yp->rx_ring[i].cmd = CMD_STOP;		yp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */		if (yp->rx_skbuff[i]) {#if LINUX_VERSION_CODE < 0x20100			yp->rx_skbuff[i]->free = 1;#endif			dev_kfree_skb(yp->rx_skbuff[i], FREE_WRITE);		}		yp->rx_skbuff[i] = 0;	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (yp->tx_skbuff[i])			dev_kfree_skb(yp->tx_skbuff[i], FREE_WRITE);		yp->tx_skbuff[i] = 0;	}#ifdef YF_PROTOTYPE			/* Support for prototype hardware errata. */	if (yellowfin_debug > 0) {		printk("%s: Received %d frames that we should not have.\n",			   dev->name, bogus_rx);	}#endif	MOD_DEC_USE_COUNT;	return 0;}static struct enet_statistics *yellowfin_get_stats(struct device *dev){	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	return &yp->stats;}/* Set or clear the multicast filter for this adaptor. *//* The little-endian AUTODIN32 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_le = 0xedb88320U;static inline unsigned ether_crc_le(int length, unsigned char *data){	unsigned int crc = 0xffffffff;	/* Initial value. */	while(--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 8; --bit >= 0; current_octet >>= 1) {			if ((crc ^ current_octet) & 1) {				crc >>= 1;				crc ^= ethernet_polynomial_le;			} else				crc >>= 1;		}	}	return crc;}#ifdef NEW_MULTICASTstatic void set_rx_mode(struct device *dev)#elsestatic void set_rx_mode(struct device *dev, int num_addrs, void *addrs);#endif{	int ioaddr = dev->base_addr;	u16 cfg_value = inw(ioaddr + Cnfg);	/* Stop the Rx process to change any value. */	outw(cfg_value & ~0x1000, ioaddr + Cnfg);	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		/* Unconditionally log net taps. */		printk("%s: Promiscuous mode enabled.\n", dev->name);		outw(0x000F, ioaddr + AddrMode);	} else if ((dev->mc_count > 64)  ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter well, or accept all multicasts. */		outw(0x000B, ioaddr + AddrMode);	} else if (dev->mc_count > 0) { /* Must use the multicast hash table. */		struct dev_mc_list *mclist;		u16 hash_table[4];		int i;		memset(hash_table, 0, sizeof(hash_table));		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next) {			/* Due to a bug in the early chip versions, multiple filter			   slots must be set for each address. */			set_bit((ether_crc_le(3, mclist->dmi_addr) >> 3) & 0x3f,					hash_table);			set_bit((ether_crc_le(4, mclist->dmi_addr) >> 3) & 0x3f,					hash_table);			set_bit((ether_crc_le(5, mclist->dmi_addr) >> 3) & 0x3f,					hash_table);			set_bit((ether_crc_le(6, mclist->dmi_addr) >> 3) & 0x3f,					hash_table);		}		/* Copy the hash table to the chip. */		for (i = 0; i < 4; i++)			outw(hash_table[i], ioaddr + HashTbl + i*2);		outw(0x0003, ioaddr + AddrMode);	} else {					/* Normal, unicast/broadcast-only mode. */		outw(0x0001, ioaddr + AddrMode);	}	/* Restart the Rx process. */	outw(cfg_value | 0x1000, ioaddr + Cnfg);}#ifdef MODULE/* An additional parameter that may be passed in... */static int debug = -1;intinit_module(void){	int cards_found;	if (debug >= 0)		yellowfin_debug = debug;	root_yellowfin_dev = NULL;	cards_found = yellowfin_probe(0);	return cards_found ? 0 : -ENODEV;}voidcleanup_module(void){	struct device *next_dev;	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (root_yellowfin_dev) {		next_dev = ((struct yellowfin_private *)root_yellowfin_dev->priv)->next_module;		unregister_netdev(root_yellowfin_dev);		release_region(root_yellowfin_dev->base_addr, YELLOWFIN_TOTAL_SIZE);		kfree(root_yellowfin_dev);		root_yellowfin_dev = next_dev;	}}#endif  /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c yellowfin.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 yellowfin.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 + -