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

📄 3c515.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
				lp->tx_full = 0;				netif_wake_queue(dev);			}		}#ifdef VORTEX_BUS_MASTER		if (status & DMADone) {			outw(0x1000, ioaddr + Wn7_MasterStatus);	/* Ack the event. */			dev_kfree_skb_irq(lp->tx_skb);	/* Release the transfered buffer */			netif_wake_queue(dev);		}#endif		if (status & UpComplete) {			boomerang_rx(dev);			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);		}		if (status & (AdapterFailure | RxEarly | StatsFull)) {			/* Handle all uncommon interrupts at once. */			if (status & RxEarly) {	/* Rx early is unused. */				corkscrew_rx(dev);				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);			}			if (status & StatsFull) {	/* Empty statistics. */				static int DoneDidThat = 0;				if (corkscrew_debug > 4)					printk("%s: Updating stats.\n",					       dev->name);				update_stats(ioaddr, dev);				/* DEBUG HACK: Disable statistics as an interrupt source. */				/* This occurs when we have the wrong media type! */				if (DoneDidThat == 0 &&				    inw(ioaddr + EL3_STATUS) & StatsFull) {					int win, reg;					printk("%s: Updating stats failed, disabling stats as an"					     " interrupt source.\n",					     dev->name);					for (win = 0; win < 8; win++) {						EL3WINDOW(win);						printk("\n Vortex window %d:", win);						for (reg = 0; reg < 16; reg++)							printk(" %2.2x",							       inb(ioaddr + reg));					}					EL3WINDOW(7);					outw(SetIntrEnb | TxAvailable |					     RxComplete | AdapterFailure |					     UpComplete | DownComplete |					     TxComplete, ioaddr + EL3_CMD);					DoneDidThat++;				}			}			if (status & AdapterFailure) {				/* Adapter failure requires Rx reset and reinit. */				outw(RxReset, ioaddr + EL3_CMD);				/* Set the Rx filter to the current state. */				set_rx_mode(dev);				outw(RxEnable, ioaddr + EL3_CMD);	/* Re-enable the receiver. */				outw(AckIntr | AdapterFailure,				     ioaddr + EL3_CMD);			}		}		if (--i < 0) {			printk(KERN_ERR "%s: Too much work in interrupt, status %4.4x.  "			     "Disabling functions (%4.4x).\n", dev->name,			     status, SetStatusEnb | ((~status) & 0x7FE));			/* Disable all pending interrupts. */			outw(SetStatusEnb | ((~status) & 0x7FE),			     ioaddr + EL3_CMD);			outw(AckIntr | 0x7FF, ioaddr + EL3_CMD);			break;		}		/* Acknowledge the IRQ. */		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);	} while ((status = inw(ioaddr + EL3_STATUS)) &		 (IntLatch | RxComplete));	if (corkscrew_debug > 4)		printk("%s: exiting interrupt, status %4.4x.\n", dev->name,		       status);}static int corkscrew_rx(struct net_device *dev){	struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv;	int ioaddr = dev->base_addr;	int i;	short rx_status;	if (corkscrew_debug > 5)		printk("   In rx_packet(), status %4.4x, rx_status %4.4x.\n",		     inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {		if (rx_status & 0x4000) {	/* Error, update stats. */			unsigned char rx_error = inb(ioaddr + RxErrors);			if (corkscrew_debug > 2)				printk(" Rx error: status %2.2x.\n",				       rx_error);			vp->stats.rx_errors++;			if (rx_error & 0x01)				vp->stats.rx_over_errors++;			if (rx_error & 0x02)				vp->stats.rx_length_errors++;			if (rx_error & 0x04)				vp->stats.rx_frame_errors++;			if (rx_error & 0x08)				vp->stats.rx_crc_errors++;			if (rx_error & 0x10)				vp->stats.rx_length_errors++;		} else {			/* The packet length: up to 4.5K!. */			short pkt_len = rx_status & 0x1fff;			struct sk_buff *skb;			skb = dev_alloc_skb(pkt_len + 5 + 2);			if (corkscrew_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 boundaries */				/* 'skb_put()' points to the start of sk_buff data area. */				insl(ioaddr + RX_FIFO,				     skb_put(skb, pkt_len),				     (pkt_len + 3) >> 2);				outw(RxDiscard, ioaddr + EL3_CMD);	/* Pop top Rx packet. */				skb->protocol = eth_type_trans(skb, dev);				netif_rx(skb);				dev->last_rx = jiffies;				vp->stats.rx_packets++;				vp->stats.rx_bytes += skb->len;				/* Wait a limited time to go to next packet. */				for (i = 200; i >= 0; i--)					if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) 						break;				continue;			} else if (corkscrew_debug)				printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);		}		outw(RxDiscard, ioaddr + EL3_CMD);		vp->stats.rx_dropped++;		/* Wait a limited time to skip this packet. */		for (i = 200; i >= 0; i--)			if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))				break;	}	return 0;}static int boomerang_rx(struct net_device *dev){	struct corkscrew_private *vp =	    (struct corkscrew_private *) dev->priv;	int entry = vp->cur_rx % RX_RING_SIZE;	int ioaddr = dev->base_addr;	int rx_status;	if (corkscrew_debug > 5)		printk("   In boomerang_rx(), status %4.4x, rx_status %4.4x.\n",			inw(ioaddr + EL3_STATUS), inw(ioaddr + RxStatus));	while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {		if (rx_status & RxDError) {	/* Error, update stats. */			unsigned char rx_error = rx_status >> 16;			if (corkscrew_debug > 2)				printk(" Rx error: status %2.2x.\n",				       rx_error);			vp->stats.rx_errors++;			if (rx_error & 0x01)				vp->stats.rx_over_errors++;			if (rx_error & 0x02)				vp->stats.rx_length_errors++;			if (rx_error & 0x04)				vp->stats.rx_frame_errors++;			if (rx_error & 0x08)				vp->stats.rx_crc_errors++;			if (rx_error & 0x10)				vp->stats.rx_length_errors++;		} else {			/* The packet length: up to 4.5K!. */			short pkt_len = rx_status & 0x1fff;			struct sk_buff *skb;			vp->stats.rx_bytes += pkt_len;			if (corkscrew_debug > 4)				printk("Receiving packet size %d status %4.4x.\n",				     pkt_len, rx_status);			/* 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 + 4)) != 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. */				memcpy(skb_put(skb, pkt_len),				       bus_to_virt(vp->rx_ring[entry].						   addr), pkt_len);				rx_copy++;			} else {				void *temp;				/* Pass up the skbuff already on the Rx ring. */				skb = vp->rx_skbuff[entry];				vp->rx_skbuff[entry] = NULL;				temp = skb_put(skb, pkt_len);				/* Remove this checking code for final release. */				if (bus_to_virt(vp->rx_ring[entry].addr) != temp)					    printk("%s: Warning -- the skbuff addresses do not match"					     " in boomerang_rx: %p vs. %p / %p.\n",					     dev->name,					     bus_to_virt(vp->							 rx_ring[entry].							 addr), skb->head,					     temp);				rx_nocopy++;			}			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);			dev->last_rx = jiffies;			vp->stats.rx_packets++;		}		entry = (++vp->cur_rx) % RX_RING_SIZE;	}	/* Refill the Rx ring buffers. */	for (; vp->cur_rx - vp->dirty_rx > 0; vp->dirty_rx++) {		struct sk_buff *skb;		entry = vp->dirty_rx % RX_RING_SIZE;		if (vp->rx_skbuff[entry] == NULL) {			skb = dev_alloc_skb(PKT_BUF_SZ);			if (skb == NULL)				break;	/* Bad news!  */			skb->dev = dev;	/* Mark as being used by this device. */			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */			vp->rx_ring[entry].addr = virt_to_bus(skb->tail);			vp->rx_skbuff[entry] = skb;		}		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */	}	return 0;}static int corkscrew_close(struct net_device *dev){	struct corkscrew_private *vp =	    (struct corkscrew_private *) dev->priv;	int ioaddr = dev->base_addr;	int i;	netif_stop_queue(dev);	if (corkscrew_debug > 1) {		printk("%s: corkscrew_close() status %4.4x, Tx status %2.2x.\n",		     dev->name, inw(ioaddr + EL3_STATUS),		     inb(ioaddr + TxStatus));		printk("%s: corkscrew close stats: rx_nocopy %d rx_copy %d"		       " tx_queued %d.\n", dev->name, rx_nocopy, rx_copy,		       queued_packet);	}	del_timer(&vp->timer);	/* 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 == XCVR_10base2)		/* Turn off thinnet power.  Green! */		outw(StopCoax, ioaddr + EL3_CMD);	free_irq(dev->irq, dev);	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);	update_stats(ioaddr, dev);	if (vp->full_bus_master_rx) {	/* Free Boomerang bus master Rx buffers. */		outl(0, ioaddr + UpListPtr);		for (i = 0; i < RX_RING_SIZE; i++)			if (vp->rx_skbuff[i]) {				dev_kfree_skb(vp->rx_skbuff[i]);				vp->rx_skbuff[i] = 0;			}	}	if (vp->full_bus_master_tx) {	/* Free Boomerang bus master Tx buffers. */		outl(0, ioaddr + DownListPtr);		for (i = 0; i < TX_RING_SIZE; i++)			if (vp->tx_skbuff[i]) {				dev_kfree_skb(vp->tx_skbuff[i]);				vp->tx_skbuff[i] = 0;			}	}	return 0;}static struct net_device_stats *corkscrew_get_stats(struct net_device *dev){	struct corkscrew_private *vp =	    (struct corkscrew_private *) dev->priv;	unsigned long flags;	if (netif_running(dev)) {		save_flags(flags);		cli();		update_stats(dev->base_addr, dev);		restore_flags(flags);	}	return &vp->stats;}/*  Update statistics.	Unlike with the EL3 we need not worry about interrupts changing	the window setting from underneath us, but we must still guard	against a race condition with a StatsUpdate interrupt updating the	table.  This is done by checking that the ASM (!) code generated uses	atomic updates with '+='.	*/static void update_stats(int ioaddr, struct net_device *dev){	struct corkscrew_private *vp =	    (struct corkscrew_private *) dev->priv;	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */	/* Switch to the stats window, and read everything. */	EL3WINDOW(6);	vp->stats.tx_carrier_errors += inb(ioaddr + 0);	vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);	/* Multiple collisions. */ inb(ioaddr + 2);	vp->stats.collisions += inb(ioaddr + 3);	vp->stats.tx_window_errors += inb(ioaddr + 4);	vp->stats.rx_fifo_errors += inb(ioaddr + 5);	vp->stats.tx_packets += inb(ioaddr + 6);	vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;						/* Rx packets   */ inb(ioaddr + 7);						/* Must read to clear */	/* Tx deferrals */ inb(ioaddr + 8);	/* Don't bother with register 9, an extension of registers 6&7.	   If we do use the 6&7 values the atomic update assumption above	   is invalid. */	inw(ioaddr + 10);	/* Total Rx and Tx octets. */	inw(ioaddr + 12);	/* New: On the Vortex we must also clear the BadSSD counter. */	EL3WINDOW(4);	inb(ioaddr + 12);	/* We change back to window 7 (not 1) with the Vortex. */	EL3WINDOW(7);	return;}/* This new version of set_rx_mode() supports v1.4 kernels.   The Vortex chip has no documented multicast filter, so the only   multicast setting is to receive all multicast frames.  At least   the chip has a very clean way to set the mode, unlike many others. */static void set_rx_mode(struct net_device *dev){	int ioaddr = dev->base_addr;	short new_mode;	if (dev->flags & IFF_PROMISC) {		if (corkscrew_debug > 3)			printk("%s: Setting promiscuous mode.\n",			       dev->name);		new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm;	} else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {		new_mode = SetRxFilter | RxStation | RxMulticast | RxBroadcast;	} else		new_mode = SetRxFilter | RxStation | RxBroadcast;	outw(new_mode, ioaddr + EL3_CMD);}#ifdef MODULEvoid cleanup_module(void){	struct net_device *next_dev;	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (root_corkscrew_dev) {		next_dev =		    ((struct corkscrew_private *) root_corkscrew_dev->		     priv)->next_module;		if (root_corkscrew_dev->dma)			free_dma(root_corkscrew_dev->dma);		unregister_netdev(root_corkscrew_dev);		outw(TotalReset, root_corkscrew_dev->base_addr + EL3_CMD);		release_region(root_corkscrew_dev->base_addr,			       CORKSCREW_TOTAL_SIZE);		kfree(root_corkscrew_dev);		root_corkscrew_dev = next_dev;	}}#endif				/* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c" *  c-indent-level: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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