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

📄 3c509.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	EL3WINDOW(1);	/* Accept b-case and phys addr only. */	outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */	dev->interrupt = 0;	dev->tbusy = 0;	dev->start = 1;	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */	/* Allow status bits to be seen. */	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);	/* Ack all pending events, and set active indicator mask. */	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,		 ioaddr + EL3_CMD);	outw(SetIntrEnb | IntLatch|TxAvailable|TxComplete|RxComplete|StatsFull,		 ioaddr + EL3_CMD);	if (el3_debug > 3)		printk("%s: Opened 3c509  IRQ %d  status %4.4x.\n",			   dev->name, dev->irq, inw(ioaddr + EL3_STATUS));	MOD_INC_USE_COUNT;	return 0;					/* Always succeed */}static intel3_start_xmit(struct sk_buff *skb, struct device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	/* Transmitter timeout, serious problems. */	if (dev->tbusy) {		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < TX_TIMEOUT)			return 1;		printk("%s: transmit timed out, Tx_status %2.2x status %4.4x "			   "Tx FIFO room %d.\n",			   dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),			   inw(ioaddr + TX_FREE));		lp->stats.tx_errors++;		dev->trans_start = jiffies;		/* Issue TX_RESET and TX_START commands. */		outw(TxReset, ioaddr + EL3_CMD);		outw(TxEnable, ioaddr + EL3_CMD);		dev->tbusy = 0;	}	lp->stats.tx_bytes += skb->len;		if (el3_debug > 4) {		printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",			   dev->name, skb->len, inw(ioaddr + EL3_STATUS));	}#if 0#ifndef final_version	{	/* Error-checking code, delete someday. */		ushort status = inw(ioaddr + EL3_STATUS);		if (status & 0x0001 		/* IRQ line active, missed one. */			&& inw(ioaddr + EL3_STATUS) & 1) { 			/* Make sure. */			printk("%s: Missed interrupt, status then %04x now %04x"				   "  Tx %2.2x Rx %4.4x.\n", dev->name, status,				   inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS),				   inw(ioaddr + RX_STATUS));			/* Fake interrupt trigger by masking, acknowledge interrupts. */			outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);			outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,				 ioaddr + EL3_CMD);			outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);		}	}#endif#endif	/* Avoid timer-based retransmission conflicts. */	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)		printk("%s: Transmitter access conflict.\n", dev->name);	else {		/*		 *	We lock the driver against other processors. Note		 *	we don't need to lock versus the IRQ as we suspended		 *	that. This means that we lose the ability to take		 *	an RX during a TX upload. That sucks a bit with SMP		 *	on an original 3c509 (2K buffer)		 *		 *	Using disable_irq stops us crapping on other		 *	time sensitive devices.		 */#ifdef __SMP__		disable_irq(dev->irq);	    	spin_lock(&lp->lock);#endif	    		    		/* Put out the doubleword header... */		outw(skb->len, ioaddr + TX_FIFO);		outw(0x00, ioaddr + TX_FIFO);		/* ... and the packet rounded to a doubleword. */#ifdef  __powerpc__		outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);#else		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);#endif		dev->trans_start = jiffies;		if (inw(ioaddr + TX_FREE) > 1536) {			dev->tbusy = 0;		} else			/* Interrupt us when the FIFO has room for max-sized packet. */			outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);#ifdef __SMP__		spin_unlock(&lp->lock);		enable_irq(dev->irq);#endif			}	dev_kfree_skb (skb);	/* Clear the Tx status stack. */	{		short tx_status;		int i = 4;		while (--i > 0	&&	(tx_status = inb(ioaddr + TX_STATUS)) > 0) {			if (tx_status & 0x38) lp->stats.tx_aborted_errors++;			if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);			if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);			outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */		}	}	return 0;}/* The EL3 interrupt handler. */static voidel3_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct device *dev = (struct device *)dev_id;	struct el3_private *lp;	int ioaddr, status;	int i = max_interrupt_work;	if (dev == NULL) {		printk ("el3_interrupt(): irq %d for unknown device.\n", irq);		return;	}	lp = (struct el3_private *)dev->priv;	spin_lock(&lp->lock);	if (dev->interrupt)		printk("%s: Re-entering the interrupt handler.\n", dev->name);	dev->interrupt = 1;	ioaddr = dev->base_addr;	if (el3_debug > 4) {		status = inw(ioaddr + EL3_STATUS);		printk("%s: interrupt, status %4.4x.\n", dev->name, status);	}	while ((status = inw(ioaddr + EL3_STATUS)) &		   (IntLatch | RxComplete | StatsFull)) {		if (status & RxComplete)			el3_rx(dev);		if (status & TxAvailable) {			if (el3_debug > 5)				printk("	TX room bit was handled.\n");			/* There's room in the FIFO for a full-sized packet. */			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);			dev->tbusy = 0;			mark_bh(NET_BH);		}		if (status & (AdapterFailure | RxEarly | StatsFull | TxComplete)) {			/* Handle all uncommon interrupts. */			if (status & StatsFull)				/* Empty statistics. */				update_stats(dev);			if (status & RxEarly) {				/* Rx early is unused. */				el3_rx(dev);				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);			}			if (status & TxComplete) {			/* Really Tx error. */				struct el3_private *lp = (struct el3_private *)dev->priv;				short tx_status;				int i = 4;				while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {					if (tx_status & 0x38) lp->stats.tx_aborted_errors++;					if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);					if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);					outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */				}			}			if (status & AdapterFailure) {				/* Adapter failure requires Rx reset and reinit. */				outw(RxReset, ioaddr + EL3_CMD);				/* Set the Rx filter to the current state. */				outw(SetRxFilter | RxStation | RxBroadcast					 | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0)					 | (dev->flags & IFF_PROMISC ? RxProm : 0),					 ioaddr + EL3_CMD);				outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);			}		}		if (--i < 0) {			printk("%s: Infinite loop in interrupt, status %4.4x.\n",				   dev->name, status);			/* Clear all interrupts. */			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);			break;		}		/* Acknowledge the IRQ. */		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); /* Ack IRQ */	}	if (el3_debug > 4) {		printk("%s: exiting interrupt, status %4.4x.\n", dev->name,			   inw(ioaddr + EL3_STATUS));	}	spin_unlock(&lp->lock);	dev->interrupt = 0;	return;}static struct enet_statistics *el3_get_stats(struct device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	unsigned long flags;	/*	 *	This is fast enough not to bother with disable IRQ	 *	stuff.	 */	 	spin_lock_irqsave(&lp->lock, flags);	update_stats(dev);	spin_unlock_irqrestore(&lp->lock, flags);	return &lp->stats;}/*  Update statistics.  We change to register window 6, so this should be run	single-threaded if the device is active. This is expected to be a rare	operation, and it's simpler for the rest of the driver to assume that	window 1 is always valid rather than use a special window-state variable.	*/static void update_stats(struct device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	if (el3_debug > 5)		printk("   Updating the statistics.\n");	/* Turn off statistics updates while reading. */	outw(StatsDisable, ioaddr + EL3_CMD);	/* Switch to the stats window, and read everything. */	EL3WINDOW(6);	lp->stats.tx_carrier_errors 	+= inb(ioaddr + 0);	lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);	/* Multiple collisions. */	   inb(ioaddr + 2);	lp->stats.collisions		+= inb(ioaddr + 3);	lp->stats.tx_window_errors	+= inb(ioaddr + 4);	lp->stats.rx_fifo_errors	+= inb(ioaddr + 5);	lp->stats.tx_packets		+= inb(ioaddr + 6);	/* Rx packets	*/		   inb(ioaddr + 7);	/* Tx deferrals */		   inb(ioaddr + 8);	inw(ioaddr + 10);	/* Total Rx and Tx octets. */	inw(ioaddr + 12);	/* Back to window 1, and turn statistics back on. */	EL3WINDOW(1);	outw(StatsEnable, ioaddr + EL3_CMD);	return;}static intel3_rx(struct device *dev){	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	short rx_status;	if (el3_debug > 5)		printk("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));	while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) {		if (rx_status & 0x4000) { /* Error, update stats. */			short error = rx_status & 0x3800;			outw(RxDiscard, ioaddr + EL3_CMD);			lp->stats.rx_errors++;			switch (error) {			case 0x0000:		lp->stats.rx_over_errors++; break;			case 0x0800:		lp->stats.rx_length_errors++; break;			case 0x1000:		lp->stats.rx_frame_errors++; break;			case 0x1800:		lp->stats.rx_length_errors++; break;			case 0x2000:		lp->stats.rx_frame_errors++; break;			case 0x2800:		lp->stats.rx_crc_errors++; break;			}		} else {			short pkt_len = rx_status & 0x7ff;			struct sk_buff *skb;			skb = dev_alloc_skb(pkt_len+5);			lp->stats.rx_bytes += pkt_len;			if (el3_debug > 4)				printk("Receiving packet size %d status %4.4x.\n",					   pkt_len, rx_status);			if (skb != NULL) {				skb->dev = dev;				skb_reserve(skb, 2);     /* Align IP on 16 byte */				/* 'skb->data' points to the start of sk_buff data area. */#ifdef  __powerpc__				insl_unswapped(ioaddr+RX_FIFO, skb_put(skb,pkt_len),							   (pkt_len + 3) >> 2);#else				insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),					 (pkt_len + 3) >> 2);#endif				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */				skb->protocol = eth_type_trans(skb,dev);				netif_rx(skb);				lp->stats.rx_packets++;				continue;			}			outw(RxDiscard, ioaddr + EL3_CMD);			lp->stats.rx_dropped++;			if (el3_debug)				printk("%s: Couldn't allocate a sk_buff of size %d.\n",					   dev->name, pkt_len);		}		inw(ioaddr + EL3_STATUS); 				/* Delay. */		while (inw(ioaddr + EL3_STATUS) & 0x1000)			printk(KERN_DEBUG "	Waiting for 3c509 to discard packet, status %x.\n",				   inw(ioaddr + EL3_STATUS) );	}	return 0;}/* *     Set or clear the multicast filter for this adaptor. */static voidset_multicast_list(struct device *dev){	unsigned long flags;	struct el3_private *lp = (struct el3_private *)dev->priv;	int ioaddr = dev->base_addr;	if (el3_debug > 1) {		static int old = 0;		if (old != dev->mc_count) {			old = dev->mc_count;			printk("%s: Setting Rx mode to %d addresses.\n", dev->name, dev->mc_count);		}	}	spin_lock_irqsave(&lp->lock, flags);	if (dev->flags&IFF_PROMISC) {		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,			 ioaddr + EL3_CMD);	}	else if (dev->mc_count || (dev->flags&IFF_ALLMULTI)) {		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);	}	else                outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);	spin_unlock_irqrestore(&lp->lock, flags);}static intel3_close(struct device *dev){	int ioaddr = dev->base_addr;	if (el3_debug > 2)		printk("%s: Shutting down ethercard.\n", dev->name);	dev->tbusy = 1;	dev->start = 0;	/* Turn off statistics ASAP.  We update lp->stats below. */	outw(StatsDisable, ioaddr + EL3_CMD);	/* Disable the receiver and transmitter. */	outw(RxDisable, ioaddr + EL3_CMD);	outw(TxDisable, ioaddr + EL3_CMD);	if (dev->if_port == 3)		/* Turn off thinnet power.  Green! */		outw(StopCoax, ioaddr + EL3_CMD);	else if (dev->if_port == 0) {		/* Disable link beat and jabber, if_port may change ere next open(). */		EL3WINDOW(4);		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);	}	free_irq(dev->irq, dev);	/* Switching back to window 0 disables the IRQ. */	EL3WINDOW(0);	/* But we explicitly zero the IRQ line select anyway. */	outw(0x0f00, ioaddr + WN0_IRQ);	update_stats(dev);	MOD_DEC_USE_COUNT;	return 0;}#ifdef MODULE/* Parameters that may be passed into the module. */static int debug = -1;static int irq[] = {-1, -1, -1, -1, -1, -1, -1, -1};static int xcvr[] = {-1, -1, -1, -1, -1, -1, -1, -1};MODULE_PARM(debug,"i");MODULE_PARM(irq,"1-8i");MODULE_PARM(xcvr,"1-8i");intinit_module(void){	int el3_cards = 0;	if (debug >= 0)		el3_debug = debug;	el3_root_dev = NULL;	while (el3_probe(0) == 0) {		if (irq[el3_cards] > 1)			el3_root_dev->irq = irq[el3_cards];		if (xcvr[el3_cards] >= 0)			el3_root_dev->if_port = xcvr[el3_cards];		el3_cards++;	}	return el3_cards ? 0 : -ENODEV;}voidcleanup_module(void){	struct device *next_dev;	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (el3_root_dev) {		struct el3_private *lp = (struct el3_private *)el3_root_dev->priv;#ifdef CONFIG_MCA				if(lp->mca_slot!=-1)			mca_mark_as_unused(lp->mca_slot);#endif					next_dev = lp->next_dev;		unregister_netdev(el3_root_dev);		release_region(el3_root_dev->base_addr, EL3_IO_EXTENT);		kfree(el3_root_dev);		el3_root_dev = next_dev;	}}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c509.c" *  version-control: t *  kept-new-versions: 5 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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