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

📄 eexpress.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
		}	}  	if (test_and_set_bit(0,(void *)&dev->tbusy))	{		lp->stats.tx_dropped++;	}	else	{		unsigned short length = (ETH_ZLEN < buf->len) ? buf->len :			ETH_ZLEN;		unsigned short *data = (unsigned short *)buf->data;		lp->stats.tx_bytes += length;	        eexp_hw_tx_pio(dev,data,length);	}	dev_kfree_skb(buf);	enable_irq(dev->irq);	return 0;}/* * Handle an EtherExpress interrupt * If we've finished initializing, start the RU and CU up. * If we've already started, reap tx buffers, handle any received packets, * check to make sure we've not become wedged. *//* * Handle an EtherExpress interrupt * If we've finished initializing, start the RU and CU up. * If we've already started, reap tx buffers, handle any received packets, * check to make sure we've not become wedged. */static unsigned short eexp_start_irq(struct device *dev,				     unsigned short status){	unsigned short ack_cmd = SCB_ack(status);	struct net_local *lp = (struct net_local *)dev->priv;	unsigned short ioaddr = dev->base_addr;	if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) {		short diag_status, tdr_status;		while (SCB_CUstat(status)==2)			status = scb_status(dev);#if NET_DEBUG > 4		printk("%s: CU went non-active (status %04x)\n",		       dev->name, status);#endif		outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);		diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));		if (diag_status & 1<<11) {			printk(KERN_WARNING "%s: 82586 failed self-test\n", 			       dev->name);		} else if (!(diag_status & 1<<13)) {			printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);		}		outw(CONF_TDR_RESULT & ~31, ioaddr + SM_PTR);		tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));		if (tdr_status & (TDR_SHORT|TDR_OPEN)) {			printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");		} 		else if (tdr_status & TDR_XCVRPROBLEM) {			printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);		}		else if (tdr_status & TDR_LINKOK) {#if NET_DEBUG > 4			printk(KERN_DEBUG "%s: TDR reports link OK\n", dev->name);#endif		} else {			printk("%s: TDR is ga-ga (status %04x)\n", dev->name,			       tdr_status);		}					lp->started |= STARTED_CU;		scb_wrcbl(dev, lp->tx_link);		/* if the RU isn't running, start it now */		if (!(lp->started & STARTED_RU)) {			ack_cmd |= SCB_RUstart;			scb_wrrfa(dev, lp->rx_buf_start);			lp->rx_ptr = lp->rx_buf_start;		}		ack_cmd |= SCB_CUstart | 0x2000;	}	if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4) 		lp->started|=STARTED_RU;	return ack_cmd;}static void eexp_cmd_clear(struct device *dev){	unsigned long int oldtime = jiffies;	while (scb_rdcmd(dev) && ((jiffies-oldtime)<10));	if (scb_rdcmd(dev)) {		printk("%s: command didn't clear\n", dev->name);	}}	static void eexp_irq(int irq, void *dev_info, struct pt_regs *regs){	struct device *dev = dev_info;	struct net_local *lp;	unsigned short ioaddr,status,ack_cmd;	unsigned short old_read_ptr, old_write_ptr;	if (dev==NULL)	{		printk(KERN_WARNING "eexpress: irq %d for unknown device\n",		       irq);		return;	}	lp = (struct net_local *)dev->priv;	ioaddr = dev->base_addr;	old_read_ptr = inw(ioaddr+READ_PTR);	old_write_ptr = inw(ioaddr+WRITE_PTR);	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);	dev->interrupt = 1;	status = scb_status(dev);#if NET_DEBUG > 4	printk(KERN_DEBUG "%s: interrupt (status %x)\n", dev->name, status);#endif	if (lp->started == (STARTED_CU | STARTED_RU)) {		do {			eexp_cmd_clear(dev);			ack_cmd = SCB_ack(status);			scb_command(dev, ack_cmd);			outb(0,ioaddr+SIGNAL_CA);			eexp_cmd_clear(dev);			if (SCB_complete(status)) {				if (!eexp_hw_lasttxstat(dev)) {					printk("%s: tx interrupt but no status\n", dev->name);				}			}						if (SCB_rxdframe(status)) 				eexp_hw_rx_pio(dev);			status = scb_status(dev);		} while (status & 0xc000);		if (SCB_RUdead(status)) 		{			printk(KERN_WARNING "%s: RU stopped: status %04x\n",			       dev->name,status);#if 0			printk(KERN_WARNING "%s: cur_rfd=%04x, cur_rbd=%04x\n", dev->name, lp->cur_rfd, lp->cur_rbd);			outw(lp->cur_rfd, ioaddr+READ_PTR);			printk(KERN_WARNING "%s: [%04x]\n", dev->name, inw(ioaddr+DATAPORT));			outw(lp->cur_rfd+6, ioaddr+READ_PTR);			printk(KERN_WARNING "%s: rbd is %04x\n", dev->name, rbd= inw(ioaddr+DATAPORT));			outw(rbd, ioaddr+READ_PTR);			printk(KERN_WARNING "%s: [%04x %04x] ", dev->name, inw(ioaddr+DATAPORT), inw(ioaddr+DATAPORT));			outw(rbd+8, ioaddr+READ_PTR);			printk("[%04x]\n", inw(ioaddr+DATAPORT));#endif			lp->stats.rx_errors++;#if 1		        eexp_hw_rxinit(dev);#else			lp->cur_rfd = lp->first_rfd;#endif			scb_wrrfa(dev, lp->rx_buf_start);			scb_command(dev, SCB_RUstart);			outb(0,ioaddr+SIGNAL_CA);		} 	} else {		if (status & 0x8000) 			ack_cmd = eexp_start_irq(dev, status);		else			ack_cmd = SCB_ack(status);		scb_command(dev, ack_cmd);		outb(0,ioaddr+SIGNAL_CA);	}	eexp_cmd_clear(dev);	outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ); 	dev->interrupt = 0;#if NET_DEBUG > 6 	printk("%s: leaving eexp_irq()\n", dev->name);#endif	outw(old_read_ptr, ioaddr+READ_PTR);	outw(old_write_ptr, ioaddr+WRITE_PTR);	return;}/* * Hardware access functions *//* * Set the cable type to use. */static void eexp_hw_set_interface(struct device *dev){	unsigned char oldval = inb(dev->base_addr + 0x300e);	oldval &= ~0x82;	switch (dev->if_port) {	case TPE:		oldval |= 0x2;	case BNC:		oldval |= 0x80;		break;	}	outb(oldval, dev->base_addr+0x300e);	mdelay(20);}/* * Check all the receive buffers, and hand any received packets * to the upper levels. Basic sanity check on each frame * descriptor, though we don't bother trying to fix broken ones. */static void eexp_hw_rx_pio(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned short rx_block = lp->rx_ptr;	unsigned short boguscount = lp->num_rx_bufs;	unsigned short ioaddr = dev->base_addr;	unsigned short status;#if NET_DEBUG > 6	printk(KERN_DEBUG "%s: eexp_hw_rx()\n", dev->name);#endif 	do { 		unsigned short rfd_cmd, rx_next, pbuf, pkt_len;  		outw(rx_block, ioaddr + READ_PTR);		status = inw(ioaddr + DATAPORT);		if (FD_Done(status))		{			rfd_cmd = inw(ioaddr + DATAPORT);			rx_next = inw(ioaddr + DATAPORT);			pbuf = inw(ioaddr + DATAPORT); 			outw(pbuf, ioaddr + READ_PTR);			pkt_len = inw(ioaddr + DATAPORT);			if (rfd_cmd!=0x0000)  			{				printk(KERN_WARNING "%s: rfd_cmd not zero:0x%04x\n",				       dev->name, rfd_cmd);				continue;			}			else if (pbuf!=rx_block+0x16)			{				printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n", 				       dev->name, rx_block+0x16, pbuf);				continue;			}			else if ((pkt_len & 0xc000)!=0xc000) 			{				printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",				       dev->name, pkt_len & 0xc000);  				continue;  			}  			else if (!FD_OK(status)) 			{				lp->stats.rx_errors++;				if (FD_CRC(status))					lp->stats.rx_crc_errors++;				if (FD_Align(status))					lp->stats.rx_frame_errors++;				if (FD_Resrc(status))					lp->stats.rx_fifo_errors++;				if (FD_DMA(status))					lp->stats.rx_over_errors++;				if (FD_Short(status))					lp->stats.rx_length_errors++;			}			else			{				struct sk_buff *skb;				pkt_len &= 0x3fff;				skb = dev_alloc_skb(pkt_len+16);				if (skb == NULL)				{					printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);					lp->stats.rx_dropped++;					break;				}				skb->dev = dev;				skb_reserve(skb, 2);				outw(pbuf+10, ioaddr+READ_PTR);			        insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1);				skb->protocol = eth_type_trans(skb,dev);				netif_rx(skb);				lp->stats.rx_packets++;				lp->stats.rx_bytes += pkt_len;			}			outw(rx_block, ioaddr+WRITE_PTR);			outw(0, ioaddr+DATAPORT);			outw(0, ioaddr+DATAPORT);			rx_block = rx_next;		}	} while (FD_Done(status) && boguscount--);	lp->rx_ptr = rx_block;}/* * Hand a packet to the card for transmission * If we get here, we MUST have already checked * to make sure there is room in the transmit * buffer region. */static void eexp_hw_tx_pio(struct device *dev, unsigned short *buf,		       unsigned short len){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned short ioaddr = dev->base_addr;	if (lp->width) {		/* Stop the CU so that there is no chance that it		   jumps off to a bogus address while we are writing the		   pointer to the next transmit packet in 8-bit mode -- 		   this eliminates the "CU wedged" errors in 8-bit mode.		   (Zoltan Szilagyi 10-12-96) */ 		scb_command(dev, SCB_CUsuspend);		outw(0xFFFF, ioaddr+SIGNAL_CA);	} 	outw(lp->tx_head, ioaddr + WRITE_PTR);	outw(0x0000, ioaddr + DATAPORT);        outw(Cmd_INT|Cmd_Xmit, ioaddr + DATAPORT);	outw(lp->tx_head+0x08, ioaddr + DATAPORT);	outw(lp->tx_head+0x0e, ioaddr + DATAPORT);	outw(0x0000, ioaddr + DATAPORT);	outw(0x0000, ioaddr + DATAPORT);	outw(lp->tx_head+0x08, ioaddr + DATAPORT);	outw(0x8000|len, ioaddr + DATAPORT);	outw(-1, ioaddr + DATAPORT);	outw(lp->tx_head+0x16, ioaddr + DATAPORT);	outw(0, ioaddr + DATAPORT);        outsw(ioaddr + DATAPORT, buf, (len+1)>>1);	outw(lp->tx_tail+0xc, ioaddr + WRITE_PTR);	outw(lp->tx_head, ioaddr + DATAPORT);	dev->trans_start = jiffies;	lp->tx_tail = lp->tx_head;	if (lp->tx_head==TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))		lp->tx_head = TX_BUF_START;	else		lp->tx_head += TX_BUF_SIZE;	if (lp->tx_head != lp->tx_reap)		dev->tbusy = 0;	if (lp->width) {		/* Restart the CU so that the packet can actually		   be transmitted. (Zoltan Szilagyi 10-12-96) */		scb_command(dev, SCB_CUresume);		outw(0xFFFF, ioaddr+SIGNAL_CA);	}	lp->stats.tx_packets++;	lp->last_tx = jiffies;}/* * Sanity check the suspected EtherExpress card * Read hardware address, reset card, size memory and initialize buffer * memory pointers. These are held in dev->priv, in case someone has more * than one card in a machine. */__initfunc(static int eexp_hw_probe(struct device *dev, unsigned short ioaddr)){	unsigned short hw_addr[3];	unsigned char buswidth;	unsigned int memory_size;	int i;	unsigned short xsum = 0;	struct net_local *lp;	printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr);	outb(ASIC_RST, ioaddr+EEPROM_Ctrl);	outb(0, ioaddr+EEPROM_Ctrl);	udelay(500);	outb(i586_RST, ioaddr+EEPROM_Ctrl);	hw_addr[0] = eexp_hw_readeeprom(ioaddr,2);	hw_addr[1] = eexp_hw_readeeprom(ioaddr,3);	hw_addr[2] = eexp_hw_readeeprom(ioaddr,4);	/* Standard Address or Compaq LTE Address */	if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||	      (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00)))) 	{		printk(" rejected: invalid address %04x%04x%04x\n",			hw_addr[2],hw_addr[1],hw_addr[0]);		return -ENODEV;	}	/* Calculate the EEPROM checksum.  Carry on anyway if it's bad,	 * though.	 */	for (i = 0; i < 64; i++)		xsum += eexp_hw_readeeprom(ioaddr, i);	if (xsum != 0xbaba)		printk(" (bad EEPROM xsum 0x%02x)", xsum);	dev->base_addr = ioaddr;	for ( i=0 ; i<6 ; i++ )		dev->dev_addr[i] = ((unsigned char *)hw_addr)[5-i];	{		static char irqmap[]={0, 9, 3, 4, 5, 10, 11, 0};		unsigned short setupval = eexp_hw_readeeprom(ioaddr,0);		/* Use the IRQ from EEPROM if none was given */		if (!dev->irq)			dev->irq = irqmap[setupval>>13];		dev->if_port = !(setupval & 0x1000) ? AUI :			eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC;		buswidth = !((setupval & 0x400) >> 10);	}	dev->priv = lp = kmalloc(sizeof(struct net_local), GFP_KERNEL);	if (!dev->priv)		return ENOMEM;	memset(dev->priv, 0, sizeof(struct net_local)); 	printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,  	       eexp_ifmap[dev->if_port], buswidth?8:16);  	eexp_hw_set_interface(dev);  	/* Find out how much RAM we have on the card */	outw(0, dev->base_addr + WRITE_PTR);	for (i = 0; i < 32768; i++)		outw(0, dev->base_addr + DATAPORT);        for (memory_size = 0; memory_size < 64; memory_size++)	{		outw(memory_size<<10, dev->base_addr + READ_PTR);		if (inw(dev->base_addr+DATAPORT))			break;		outw(memory_size<<10, dev->base_addr + WRITE_PTR);		outw(memory_size | 0x5000, dev->base_addr+DATAPORT);		outw(memory_size<<10, dev->base_addr + READ_PTR);		if (inw(dev->base_addr+DATAPORT) != (memory_size | 0x5000))			break;	}	/* Sort out the number of buffers.  We may have 16, 32, 48 or 64k	 * of RAM to play with.	 */	lp->num_tx_bufs = 4;	lp->rx_buf_end = 0x3ff6;	switch (memory_size)	{	case 64:		lp->rx_buf_end += 0x4000;	case 48:		lp->num_tx_bufs += 4;		lp->rx_buf_end += 0x4000;	case 32:		lp->rx_buf_end += 0x4000;	case 16:		printk(", %dk RAM)\n", memory_size);		break;	default:		printk(") bad memory size (%dk).\n", memory_size);		kfree(dev->priv);		return ENODEV;		break;	}	lp->rx_buf_start = TX_BUF_START + (lp->num_tx_bufs*TX_BUF_SIZE);	lp->width = buswidth;	dev->open = eexp_open;	dev->stop = eexp_close;	dev->hard_start_xmit = eexp_xmit;	dev->get_stats = eexp_stats;	dev->set_multicast_list = &eexp_set_multicast;	ether_setup(dev);	return 0;}/* * Read a word from the EtherExpress on-board serial EEPROM. * The EEPROM contains 64 words of 16 bits. */__initfunc(static unsigned short eexp_hw_readeeprom(unsigned short ioaddr,						    unsigned char location)){	unsigned short cmd = 0x180|(location&0x7f);	unsigned short rval = 0,wval = EC_CS|i586_RST;	int i;	outb(EC_CS|i586_RST,ioaddr+EEPROM_Ctrl);	for (i=0x100 ; i ; i>>=1 )	{		if (cmd&i)			wval |= EC_Wr;		else			wval &= ~EC_Wr;

⌨️ 快捷键说明

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