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

📄 yellowfin.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
}static struct device *yellowfin_probe1(struct device *dev, int ioaddr, int irq,								   int chip_id, int options){	static int did_version = 0;			/* Already printed version info. */	struct yellowfin_private *yp;	int i;	if (yellowfin_debug > 0  &&  did_version++ == 0)		printk(version);	dev = init_etherdev(dev, sizeof(struct yellowfin_private));	printk("%s: P-E Yellowfin type %8x at %#3x, ",		   dev->name, inl(ioaddr + ChipRev), ioaddr);	for (i = 0; i < 5; i++)		printk("%2.2x:", inb(ioaddr + StnAddr + i));	printk("%2.2x, IRQ %d.\n", inb(ioaddr + StnAddr + i), irq);	for (i = 0; i < 6; i++)		dev->dev_addr[i] = inb(ioaddr + StnAddr + i);	/* Reset the chip. */	outl(0x80000000, ioaddr + DMACtrl);	/* We do a request_region() only to register /proc/ioports info. */	request_region(ioaddr, YELLOWFIN_TOTAL_SIZE, card_name);	dev->base_addr = ioaddr;	dev->irq = irq;	/* Make certain the descriptor lists are aligned. */	yp = (void *)(((long)kmalloc(sizeof(*yp), GFP_KERNEL) + 31) & ~31);	memset(yp, 0, sizeof(*yp));	dev->priv = yp;#ifdef MODULE	yp->next_module = root_yellowfin_dev;	root_yellowfin_dev = dev;#endif	yp->chip_id = chip_id;	yp->full_duplex = 1;#ifdef YELLOWFIN_DEFAULT_MEDIA	yp->default_port = YELLOWFIN_DEFAULT_MEDIA;#endif#ifdef YELLOWFIN_NO_MEDIA_SWITCH	yp->medialock = 1;#endif	/* The lower four bits are the media type. */	if (options > 0) {		yp->full_duplex = (options & 16) ? 1 : 0;		yp->default_port = options & 15;		if (yp->default_port)			yp->medialock = 1;	}	/* The Yellowfin-specific entries in the device structure. */	dev->open = &yellowfin_open;	dev->hard_start_xmit = &yellowfin_start_xmit;	dev->stop = &yellowfin_close;	dev->get_stats = &yellowfin_get_stats;	dev->set_multicast_list = &set_rx_mode;	if (mtu)		dev->mtu = mtu;	/* todo: Reset the xcvr interface and turn on heartbeat. */	return dev;}static intyellowfin_open(struct device *dev){	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	int ioaddr = dev->base_addr;	/* Reset the chip. */	outl(0x80000000, ioaddr + DMACtrl);#ifdef SA_SHIRQ	if (request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ,					card_name, dev)) {		return -EAGAIN;	}#else	if (irq2dev_map[dev->irq] != NULL		|| (irq2dev_map[dev->irq] = dev) == NULL		|| dev->irq == 0		|| request_irq(dev->irq, &yellowfin_interrupt, 0, card_name)) {		return -EAGAIN;	}#endif	if (yellowfin_debug > 1)		printk("%s: yellowfin_open() irq %d.\n", dev->name, dev->irq);	MOD_INC_USE_COUNT;	yellowfin_init_ring(dev);	outl(virt_to_bus(yp->rx_ring), ioaddr + RxPtr);	outl(virt_to_bus(yp->tx_ring), ioaddr + TxPtr);	/* Set up various condition 'select' registers.	   There are no options here. */	outl(0x00800080, ioaddr + TxIntrSel); 	/* Interrupt on Tx abort */	outl(0x00800080, ioaddr + TxBranchSel);	/* Branch on Tx abort */	outl(0x00400040, ioaddr + TxWaitSel); 	/* Wait on Tx status */	outl(0x00400040, ioaddr + RxIntrSel);	/* Interrupt on Rx done */	outl(0x00400040, ioaddr + RxBranchSel);	/* Branch on Rx error */	outl(0x00400040, ioaddr + RxWaitSel);	/* Wait on Rx done */	/* Initialize other registers: with so many this eventually this will	   converted to an offset/value list. */	outl(dma_ctrl, ioaddr + DMACtrl);	outw(fifo_cfg, ioaddr + FIFOcfg);	/* Enable automatic generation of flow control frames, period 0xffff. */	outl(0x0030FFFF, ioaddr + FlowCtrl);	if (dev->if_port == 0)		dev->if_port = yp->default_port;	dev->tbusy = 0;	dev->interrupt = 0;	yp->in_interrupt = 0;	/* We are always in full-duplex mode with the current chip! */	yp->full_duplex = 1;	/* Setting the Rx mode will start the Rx process. */	outw(0x01CD | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);#ifdef NEW_MULTICAST	set_rx_mode(dev);#else	set_rx_mode(dev, 0, 0);#endif	dev->start = 1;	/* Enable interrupts by setting the interrupt mask. */	outw(0x81ff, ioaddr + IntrEnb);			/* See enum intr_status_bits */	outw(0x0000, ioaddr + EventStatus);		/* Clear non-interrupting events */	outl(0x80008000, ioaddr + RxCtrl);		/* Start Rx and Tx channels. */	outl(0x80008000, ioaddr + TxCtrl);	if (yellowfin_debug > 2) {		printk("%s: Done yellowfin_open().\n",			   dev->name);	}	/* Set the timer to check for link beat. */	init_timer(&yp->timer);	yp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */	yp->timer.data = (unsigned long)dev;	yp->timer.function = &yellowfin_timer;				/* timer handler */	add_timer(&yp->timer);	return 0;}static void yellowfin_timer(unsigned long data){	struct device *dev = (struct device *)data;	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	int ioaddr = dev->base_addr;	int next_tick = 0;	if (yellowfin_debug > 3) {		printk("%s: Yellowfin timer tick, status %8.8x.\n",			   dev->name, inl(ioaddr + IntrStatus));	}	if (next_tick) {		yp->timer.expires = RUN_AT(next_tick);		add_timer(&yp->timer);	}}static void yellowfin_tx_timeout(struct device *dev){	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	int ioaddr = dev->base_addr;	printk("%s: Yellowfin transmit timed out, status %8.8x, resetting...\n",		   dev->name, inl(ioaddr));#ifndef __alpha__	{		int i;		printk("  Rx ring %8.8x: ", (int)yp->rx_ring);		for (i = 0; i < RX_RING_SIZE; i++)			printk(" %8.8x", (unsigned int)yp->rx_ring[i].status);		printk("\n  Tx ring %8.8x: ", (int)yp->tx_ring);		for (i = 0; i < TX_RING_SIZE; i++)			printk(" %4.4x /%4.4x", yp->tx_status[i].tx_errs, yp->tx_ring[i].status);		printk("\n");	}#endif  /* Perhaps we should reinitialize the hardware here. */  dev->if_port = 0;  /* Stop and restart the chip's Tx processes . */  /* Trigger an immediate transmit demand. */  dev->trans_start = jiffies;  yp->stats.tx_errors++;  return;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static voidyellowfin_init_ring(struct device *dev){	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	int i;	yp->tx_full = 0;	yp->cur_rx = yp->cur_tx = 0;	yp->dirty_rx = yp->dirty_tx = 0;	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb;		int pkt_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);		yp->rx_ring[i].request_cnt = pkt_buf_sz;		yp->rx_ring[i].cmd = CMD_RX_BUF | INTR_ALWAYS;		skb = DEV_ALLOC_SKB(pkt_buf_sz);		skb_reserve(skb, 2);	/* 16 byte align the IP header. */		yp->rx_skbuff[i] = skb;		if (skb == NULL)			break;			/* Bad news!  */		skb->dev = dev;			/* Mark as being used by this device. */#if LINUX_VERSION_CODE > 0x10300		yp->rx_ring[i].addr = virt_to_bus(skb->tail);#else		yp->rx_ring[i].addr = virt_to_bus(skb->data);#endif		yp->rx_ring[i].branch_addr = virt_to_bus(&yp->rx_ring[i+1]);	}	/* Mark the last entry as wrapping the ring. */	yp->rx_ring[i-1].cmd = CMD_RX_BUF | INTR_ALWAYS | BRANCH_ALWAYS;	yp->rx_ring[i-1].branch_addr = virt_to_bus(&yp->rx_ring[0]);/*#define NO_TXSTATS*/#ifdef NO_TXSTATS	/* In this mode the Tx ring needs only a single descriptor. */	for (i = 0; i < TX_RING_SIZE; i++) {		yp->tx_skbuff[i] = 0;		yp->tx_ring[i].cmd = CMD_STOP;		yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);	}	yp->tx_ring[--i].cmd = CMD_STOP | BRANCH_ALWAYS; /* Wrap ring */	yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);#else	/* Tx ring needs a pair of descriptors, the second for the status. */	for (i = 0; i < TX_RING_SIZE*2; i++) {		yp->tx_skbuff[i/2] = 0;		yp->tx_ring[i].cmd = CMD_STOP; /* Branch on Tx error. */		yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);		i++;		yp->tx_ring[i].cmd = CMD_TXSTATUS; /* Interrupt, no wait. */		yp->tx_ring[i].request_cnt = sizeof(yp->tx_status[i]);		yp->tx_ring[i].addr = virt_to_bus(&yp->tx_status[i/2]);		yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[i+1]);	}	/* Wrap ring */	yp->tx_ring[--i].cmd = CMD_TXSTATUS | BRANCH_ALWAYS | INTR_ALWAYS;	yp->tx_ring[i].branch_addr = virt_to_bus(&yp->tx_ring[0]);#endif}static intyellowfin_start_xmit(struct sk_buff *skb, struct device *dev){	struct yellowfin_private *yp = (struct yellowfin_private *)dev->priv;	unsigned entry;	/* Block a timer-based transmit from overlapping.  This could better be	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {		if (jiffies - dev->trans_start < TX_TIMEOUT)			return 1;		yellowfin_tx_timeout(dev);		return 1;	}	/* Caution: the write order is important here, set the base address	   with the "ownership" bits last. */	/* Calculate the next Tx descriptor entry. */	entry = yp->cur_tx % TX_RING_SIZE;	yp->tx_skbuff[entry] = skb;#ifdef NO_TXSTATS	yp->tx_ring[entry].request_cnt = skb->len;	yp->tx_ring[entry].addr = virt_to_bus(skb->data);	yp->tx_ring[entry].status = 0;	if (entry >= TX_RING_SIZE-1) {		yp->tx_ring[0].cmd = CMD_STOP; /* New stop command. */		yp->tx_ring[TX_RING_SIZE-1].cmd = CMD_TX_PKT | BRANCH_ALWAYS;	} else {		yp->tx_ring[entry+1].cmd = CMD_STOP; /* New stop command. */		yp->tx_ring[entry].cmd = CMD_TX_PKT | BRANCH_IFTRUE;	}	yp->cur_tx++;#else	yp->tx_ring[entry<<1].request_cnt = skb->len;	yp->tx_ring[entry<<1].addr = virt_to_bus(skb->data);	/* The input_last (status-write) command is constant, but we must rewrite	   the subsequent 'stop' command. */	yp->cur_tx++;	{		unsigned next_entry = yp->cur_tx % TX_RING_SIZE;		yp->tx_ring[next_entry<<1].cmd = CMD_STOP;	}	/* Final step -- overwrite the old 'stop' command. */	yp->tx_ring[entry<<1].cmd =		(entry % 6) == 0 ? CMD_TX_PKT | INTR_ALWAYS | BRANCH_IFTRUE :		CMD_TX_PKT | BRANCH_IFTRUE;#endif	/* Todo: explicitly flush cache lines here. */	/* Wake the potentially-idle transmit channel. */	outl(0x10001000, dev->base_addr + TxCtrl);	if (yp->cur_tx - yp->dirty_tx < TX_RING_SIZE - 1)		clear_bit(0, (void*)&dev->tbusy);		/* Typical path */	else		yp->tx_full = 1;	dev->trans_start = jiffies;	if (yellowfin_debug > 4) {		printk("%s: Yellowfin transmit frame #%d queued in slot %d.\n",			   dev->name, yp->cur_tx, entry);	}	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void yellowfin_interrupt IRQ(int irq, void *dev_instance, struct pt_regs *regs){#ifdef SA_SHIRQ		/* Use the now-standard shared IRQ implementation. */	struct device *dev = (struct device *)dev_instance;#else	struct device *dev = (struct device *)(irq2dev_map[irq]);#endif	struct yellowfin_private *lp;	int ioaddr, boguscnt = max_interrupt_work;	if (dev == NULL) {		printk ("yellowfin_interrupt(): irq %d for unknown device.\n", irq);		return;	}	ioaddr = dev->base_addr;	lp = (struct yellowfin_private *)dev->priv;	if (test_and_set_bit(0, (void*)&lp->in_interrupt)) {		dev->interrupt = 1;		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);		return;	}	do {		u16 intr_status = inw(ioaddr + IntrClear);		unsigned dirty_tx = lp->dirty_tx;		if (yellowfin_debug > 4)			printk("%s: Yellowfin interrupt, status %4.4x.\n",				   dev->name, intr_status);		if (intr_status == 0)			break;		if (intr_status & (IntrRxDone | IntrEarlyRx))			yellowfin_rx(dev);#ifdef NO_TXSTATS		for (; lp->cur_tx - dirty_tx > 0; dirty_tx++) {			int entry = dirty_tx % TX_RING_SIZE;			if (lp->tx_ring[entry].status == 0)				break;			/* Free the original skb. */			dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);			lp->tx_skbuff[entry] = 0;			lp->stats.tx_packets++;		}		if (lp->tx_full && dev->tbusy			&& lp->cur_tx - dirty_tx < TX_RING_SIZE - 4) {			/* 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;#else		if (intr_status & IntrTxDone			|| lp->tx_status[dirty_tx % TX_RING_SIZE].tx_errs) {			for (dirty_tx = lp->dirty_tx; lp->cur_tx - dirty_tx > 0;				 dirty_tx++) {				/* Todo: optimize this. */				int entry = dirty_tx % TX_RING_SIZE;				u16 tx_errs = lp->tx_status[entry].tx_errs;				if (tx_errs == 0)					break;			/* It still hasn't been Txed */				if (tx_errs & 0xF8100000) {					/* There was an major error, log it. */#ifndef final_version					if (yellowfin_debug > 1)						printk("%s: Transmit error, Tx status %4.4x.\n",							   dev->name, tx_errs);#endif					lp->stats.tx_errors++;					if (tx_errs & 0xF800) lp->stats.tx_aborted_errors++;					if (tx_errs & 0x0800) lp->stats.tx_carrier_errors++;					if (tx_errs & 0x2000) lp->stats.tx_window_errors++;					if (tx_errs & 0x8000) lp->stats.tx_fifo_errors++;#ifdef ETHER_STATS					if (tx_errs & 0x1000) lp->stats.collisions16++;#endif				} else {

⌨️ 快捷键说明

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