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

📄 eepro100.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	dev->if_port = sp->default_port;	dev->tbusy = 0;	dev->interrupt = 0;	dev->start = 1;	/* Start the chip's Tx process and unmask interrupts. */	/* Todo: verify that we must wait for previous command completion. */	wait_for_cmd_done(ioaddr + SCBCmd);	outl(virt_to_bus(&sp->tx_ring[0]), ioaddr + SCBPointer);	outw(CU_START, ioaddr + SCBCmd);	/* Setup the chip and configure the multicast list. */	sp->mc_setup_frm = NULL;	sp->mc_setup_frm_len = 0;	sp->mc_setup_busy = 0;	sp->rx_mode = -1;			/* Invalid -> always reset the mode. */	set_rx_mode(dev);	if (speedo_debug > 2) {		printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",			   dev->name, inw(ioaddr + SCBStatus));	}	wait_for_cmd_done(ioaddr + SCBCmd);	outw(CU_DUMPSTATS, ioaddr + SCBCmd);	/*	 * Request the IRQ last, after we have set up all data structures.	 * It would be bad to get an interrupt before we're ready.	 */	if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ,					"Intel EtherExpress Pro 10/100 Ethernet", dev)) {		return -EAGAIN;	}	/* No need to wait for the command unit to accept here. */	if ((sp->phy[0] & 0x8000) == 0)		mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);	MOD_INC_USE_COUNT;	/* Set the timer.  The timer serves a dual purpose:	   1) to monitor the media interface (e.g. link beat) and perhaps switch	   to an alternate media type	   2) to monitor Rx activity, and restart the Rx process if the receiver	   hangs. */	init_timer(&sp->timer);	sp->timer.expires = RUN_AT((24*HZ)/10); 			/* 2.4 sec. */	sp->timer.data = (unsigned long)dev;	sp->timer.function = &speedo_timer;					/* timer handler */	add_timer(&sp->timer);	return 0;}/* Media monitoring and control. */static void speedo_timer(unsigned long data){	struct device *dev = (struct device *)data;	struct speedo_private *sp = (struct speedo_private *)dev->priv;	if (speedo_debug > 3) {		long ioaddr = dev->base_addr;		printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n",			   dev->name, inw(ioaddr + SCBStatus));	}	if (sp->rx_mode < 0  ||		(sp->rx_bug  && jiffies - sp->last_rx_time > 2*HZ)) {		/* We haven't received a packet in a Long Time.  We might have been		   bitten by the receiver hang bug.  This can be cleared by sending		   a set multicast list command. */		set_rx_mode(dev);	}	/* We must continue to monitor the media. */	sp->timer.expires = RUN_AT(2*HZ); 			/* 2.0 sec. */	add_timer(&sp->timer);}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static voidspeedo_init_rx_ring(struct device *dev){	struct speedo_private *sp = (struct speedo_private *)dev->priv;	struct RxFD *rxf, *last_rxf = NULL;	int i;	sp->cur_rx = 0;	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb;		skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD));		sp->rx_skbuff[i] = skb;		if (skb == NULL)			break;			/* OK.  Just initially short of Rx bufs. */		skb->dev = dev;			/* Mark as being used by this device. */		rxf = (struct RxFD *)skb->tail;		sp->rx_ringp[i] = rxf;		skb_reserve(skb, sizeof(struct RxFD));		if (last_rxf)			last_rxf->link = virt_to_bus(rxf);		last_rxf = rxf;		rxf->status = 0x00000001; 			/* '1' is flag value only. */		rxf->link = 0;						/* None yet. */		/* This field unused by i82557, we use it as a consistency check. */#ifdef final_version		rxf->rx_buf_addr = 0xffffffff;#else		rxf->rx_buf_addr = virt_to_bus(skb->tail);#endif		rxf->count = 0;		rxf->size = PKT_BUF_SZ;	}	sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);	/* Mark the last entry as end-of-list. */	last_rxf->status = 0xC0000002; 			/* '2' is flag value only. */	sp->last_rxf = last_rxf;}static void speedo_tx_timeout(struct device *dev){	struct speedo_private *sp = (struct speedo_private *)dev->priv;	long ioaddr = dev->base_addr;	printk(KERN_WARNING "%s: Transmit timed out: status %4.4x "		   " %4.4x at %d/%d command %8.8x.\n",		   dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd),		   sp->dirty_tx, sp->cur_tx,		   sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status);	if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) {		printk(KERN_WARNING "%s: Trying to restart the transmitter...\n",			   dev->name);		outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),			 ioaddr + SCBPointer);		outw(CU_START, ioaddr + SCBCmd);	} else {		outw(DRVR_INT, ioaddr + SCBCmd);	}#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */	if ((sp->phy[0] & 0x8000) == 0) {		int phy_addr = sp->phy[0] & 0x1f;		mdio_write(ioaddr, phy_addr, 0, 0x0400);		mdio_write(ioaddr, phy_addr, 1, 0x0000);		mdio_write(ioaddr, phy_addr, 4, 0x0000);		mdio_write(ioaddr, phy_addr, 0, 0x8000);#ifdef honor_default_port		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);#endif	}#endif	sp->stats.tx_errors++;	dev->trans_start = jiffies;	return;}static intspeedo_start_xmit(struct sk_buff *skb, struct device *dev){	struct speedo_private *sp = (struct speedo_private *)dev->priv;	long ioaddr = dev->base_addr;	int 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 this ever occurs the queue layer is doing something evil! */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < TX_TIMEOUT - 2)			return 1;		if (tickssofar < TX_TIMEOUT) {			/* Reap sent packets from the full Tx queue. */			outw(DRVR_INT, ioaddr + SCBCmd);			return 1;		}		speedo_tx_timeout(dev);		return 1;	}	/* Caution: the write order is important here, set the base address	   with the "ownership" bits last. */	{	/* Prevent interrupts from changing the Tx ring from underneath us. */		unsigned long flags;		spin_lock_irqsave(&sp->lock, flags);		/* Calculate the Tx descriptor entry. */		entry = sp->cur_tx++ % TX_RING_SIZE;		sp->tx_skbuff[entry] = skb;		/* Todo: be a little more clever about setting the interrupt bit. */		sp->tx_ring[entry].status =			(CmdSuspend | CmdTx | CmdTxFlex) << 16;		sp->tx_ring[entry].link =		  virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]);		sp->tx_ring[entry].tx_desc_addr =		  virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0);		/* The data region is always in one buffer descriptor, Tx FIFO		   threshold of 256. */		sp->tx_ring[entry].count = 0x01208000;		sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data);		sp->tx_ring[entry].tx_buf_size0 = skb->len;		/* Todo: perhaps leave the interrupt bit set if the Tx queue is more		   than half full.  Argument against: we should be receiving packets		   and scavenging the queue.  Argument for: if so, it shouldn't		   matter. */		sp->last_cmd->command &= ~(CmdSuspend | CmdIntr);		sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry];		/* Trigger the command unit resume. */		wait_for_cmd_done(ioaddr + SCBCmd);		outw(CU_RESUME, ioaddr + SCBCmd);		spin_unlock_irqrestore(&sp->lock, flags);	}	/* Leave room for set_rx_mode() to fill two entries. */	if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3)		sp->tx_full = 1;	else		clear_bit(0, (void*)&dev->tbusy);	dev->trans_start = jiffies;	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs){	struct device *dev = (struct device *)dev_instance;	struct speedo_private *sp;	long ioaddr, boguscnt = max_interrupt_work;	unsigned short status;#ifndef final_version	if (dev == NULL) {		printk(KERN_ERR "speedo_interrupt(): irq %d for unknown device.\n", irq);		return;	}#endif	ioaddr = dev->base_addr;	sp = (struct speedo_private *)dev->priv;	spin_lock(&sp->lock);#ifndef final_version	dev->interrupt = 1;#endif	do {		status = inw(ioaddr + SCBStatus);		/* Acknowledge all of the current interrupt sources ASAP. */		outw(status & 0xfc00, ioaddr + SCBStatus);		if (speedo_debug > 4)			printk(KERN_DEBUG "%s: interrupt  status=%#4.4x.\n",				   dev->name, status);		if ((status & 0xfc00) == 0)			break;		if (status & 0x4000)	 /* Packet received. */			speedo_rx(dev);		if (status & 0x1000) {		  if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */			outw(RX_RESUMENR, ioaddr + SCBCmd);		  else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */			/* No idea of what went wrong.  Restart the receiver. */			outl(virt_to_bus(sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]),				 ioaddr + SCBPointer);			outw(RX_START, ioaddr + SCBCmd);		  }		  sp->stats.rx_errors++;		}		/* User interrupt, Command/Tx unit interrupt or CU not active. */		if (status & 0xA400) {			unsigned int dirty_tx = sp->dirty_tx;			while (sp->cur_tx - dirty_tx > 0) {				int entry = dirty_tx % TX_RING_SIZE;				int status = sp->tx_ring[entry].status;				if (speedo_debug > 5)					printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n",						   entry, status);				if ((status & StatusComplete) == 0)					break;			/* It still hasn't been processed. */				/* Free the original skb. */				if (sp->tx_skbuff[entry]) {					sp->stats.tx_packets++;	/* Count only user packets. */					sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; /* Count transmitted bytes */					dev_free_skb(sp->tx_skbuff[entry]);					sp->tx_skbuff[entry] = 0;				} else if ((sp->tx_ring[entry].status&0x70000) == CmdNOp << 16)					sp->mc_setup_busy = 0;				dirty_tx++;			}#ifndef final_version			if (sp->cur_tx - dirty_tx > TX_RING_SIZE) {				printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d,"					   " full=%d.\n",					   dirty_tx, sp->cur_tx, sp->tx_full);				dirty_tx += TX_RING_SIZE;			}#endif			if (sp->tx_full && dev->tbusy				&& dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) {				/* The ring is no longer full, clear tbusy. */				sp->tx_full = 0;				clear_bit(0, (void*)&dev->tbusy);				mark_bh(NET_BH);			}			sp->dirty_tx = dirty_tx;		}		if (--boguscnt < 0) {			printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",				   dev->name, status);			/* Clear all interrupt sources. */			outl(0xfc00, ioaddr + SCBStatus);			break;		}	} while (1);	if (speedo_debug > 3)		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",			   dev->name, inw(ioaddr + SCBStatus));	dev->interrupt = 0;	spin_unlock(&sp->lock);	return;}static intspeedo_rx(struct device *dev){	struct speedo_private *sp = (struct speedo_private *)dev->priv;	int entry = sp->cur_rx % RX_RING_SIZE;	int status;	int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx;	if (speedo_debug > 4)		printk(KERN_DEBUG " In speedo_rx().\n");	/* If we own the next entry, it's a new packet. Send it up. */	while (sp->rx_ringp[entry] != NULL &&		   (status = sp->rx_ringp[entry]->status) & RxComplete) {		if (--rx_work_limit < 0)			break;		if (speedo_debug > 4)			printk(KERN_DEBUG "  speedo_rx() status %8.8x len %d.\n", status,				   sp->rx_ringp[entry]->count & 0x3fff);		if ((status & (RxErrTooBig|RxOK)) != RxOK) {			if (status & RxErrTooBig)				printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, "					   "status %8.8x!\n", dev->name, status);			else if ( ! (status & 0x2000)) {				/* There was a fatal error.  This *should* be impossible. */				sp->stats.rx_errors++;				printk(KERN_ERR "%s: Anomalous event in speedo_rx(), "					   "status %8.8x.\n",					   dev->name, status);			}		} else {			int pkt_len = sp->rx_ringp[entry]->count & 0x3fff;			struct sk_buff *skb;			/* Check if the packet is long enough to just accept without			   copying to a properly sized skbuff. */			if (pkt_len < rx_copybreak				&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {				skb->dev = dev;				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */				/* 'skb_put()' points to the start of sk_buff data area. */#if 1 || USE_IP_CSUM				/* Packet is in one chunk -- we can copy + cksum. */				eth_copy_and_sum(skb,								 bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),								 pkt_len, 0);				skb_put(skb, pkt_len);#else				memcpy(skb_put(skb, pkt_len),					   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len);#endif			} else {				void *temp;				/* Pass up the already-filled skbuff. */				skb = sp->rx_skbuff[entry];				if (skb == NULL) {					printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n",						   dev->name);					break;				}				sp->rx_skbuff[entry] = NULL;				temp = skb_put(skb, pkt_len);				if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp)					printk(KERN_ERR "%s: Rx consistency error -- the skbuff "						   "addresses do not match in speedo_rx: %p vs. %p "						   "/ %p.\n", dev->name,						   bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr),						   skb->head, temp);

⌨️ 快捷键说明

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