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

📄 3c515.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	EL3WINDOW(4);	outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP | Media_SQE)) |	     media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);	/* Switch to the stats window, and clear all stats by reading. */	outw(StatsDisable, ioaddr + EL3_CMD);	EL3WINDOW(6);	for (i = 0; i < 10; i++)		inb(ioaddr + i);	inw(ioaddr + 10);	inw(ioaddr + 12);	/* New: On the Vortex we must also clear the BadSSD counter. */	EL3WINDOW(4);	inb(ioaddr + 12);	/* ..and on the Boomerang we enable the extra statistics bits. */	outw(0x0040, ioaddr + Wn4_NetDiag);	/* Switch to register set 7 for normal use. */	EL3WINDOW(7);	if (vp->full_bus_master_rx) {	/* Boomerang bus master. */		vp->cur_rx = vp->dirty_rx = 0;		if (corkscrew_debug > 2)			printk("%s:  Filling in the Rx ring.\n",			       dev->name);		for (i = 0; i < RX_RING_SIZE; i++) {			struct sk_buff *skb;			if (i < (RX_RING_SIZE - 1))				vp->rx_ring[i].next =				    virt_to_bus(&vp->rx_ring[i + 1]);			else				vp->rx_ring[i].next = 0;			vp->rx_ring[i].status = 0;	/* Clear complete bit. */			vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000;			skb = dev_alloc_skb(PKT_BUF_SZ);			vp->rx_skbuff[i] = skb;			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[i].addr = virt_to_bus(skb->tail);		}		vp->rx_ring[i - 1].next = virt_to_bus(&vp->rx_ring[0]);	/* Wrap the ring. */		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);	}	if (vp->full_bus_master_tx) {	/* Boomerang bus master Tx. */		vp->cur_tx = vp->dirty_tx = 0;		outb(PKT_BUF_SZ >> 8, ioaddr + TxFreeThreshold);	/* Room for a packet. */		/* Clear the Tx ring. */		for (i = 0; i < TX_RING_SIZE; i++)			vp->tx_skbuff[i] = 0;		outl(0, ioaddr + DownListPtr);	}	/* Set receiver mode: presumably accept b-case and phys addr only. */	set_rx_mode(dev);	outw(StatsEnable, ioaddr + EL3_CMD);	/* Turn on statistics. */	netif_start_queue(dev);	outw(RxEnable, ioaddr + EL3_CMD);	/* Enable the receiver. */	outw(TxEnable, ioaddr + EL3_CMD);	/* Enable transmitter. */	/* Allow status bits to be seen. */	outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull |	     (vp->full_bus_master_tx ? DownComplete : TxAvailable) |	     (vp->full_bus_master_rx ? UpComplete : RxComplete) |	     (vp->bus_master ? DMADone : 0), 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 | RxComplete | StatsFull	     | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,	     ioaddr + EL3_CMD);	return 0;}static void corkscrew_timer(unsigned long data){#ifdef AUTOMEDIA	struct net_device *dev = (struct net_device *) data;	struct corkscrew_private *vp =	    (struct corkscrew_private *) dev->priv;	int ioaddr = dev->base_addr;	unsigned long flags;	int ok = 0;	if (corkscrew_debug > 1)		printk("%s: Media selection timer tick happened, %s.\n",		       dev->name, media_tbl[dev->if_port].name);	save_flags(flags);	cli(); {		int old_window = inw(ioaddr + EL3_CMD) >> 13;		int media_status;		EL3WINDOW(4);		media_status = inw(ioaddr + Wn4_Media);		switch (dev->if_port) {		case 0:		case 4:		case 5:	/* 10baseT, 100baseTX, 100baseFX  */			if (media_status & Media_LnkBeat) {				ok = 1;				if (corkscrew_debug > 1)					printk("%s: Media %s has link beat, %x.\n",						dev->name,						media_tbl[dev->if_port].name,						media_status);			} else if (corkscrew_debug > 1)				printk("%s: Media %s is has no link beat, %x.\n",					dev->name,					media_tbl[dev->if_port].name,					media_status);			break;		default:	/* Other media types handled by Tx timeouts. */			if (corkscrew_debug > 1)				printk("%s: Media %s is has no indication, %x.\n",					dev->name,					media_tbl[dev->if_port].name,					media_status);			ok = 1;		}		if (!ok) {			union wn3_config config;			do {				dev->if_port =				    media_tbl[dev->if_port].next;			}			while (!(vp->available_media & media_tbl[dev->if_port].mask));						if (dev->if_port == 8) {	/* Go back to default. */				dev->if_port = vp->default_media;				if (corkscrew_debug > 1)					printk("%s: Media selection failing, using default %s port.\n",						dev->name,						media_tbl[dev->if_port].name);			} else {				if (corkscrew_debug > 1)					printk("%s: Media selection failed, now trying %s port.\n",						dev->name,						media_tbl[dev->if_port].name);				vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait);				add_timer(&vp->timer);			}			outw((media_status & ~(Media_10TP | Media_SQE)) |			     media_tbl[dev->if_port].media_bits,			     ioaddr + Wn4_Media);			EL3WINDOW(3);			config.i = inl(ioaddr + Wn3_Config);			config.u.xcvr = dev->if_port;			outl(config.i, ioaddr + Wn3_Config);			outw(dev->if_port == 3 ? StartCoax : StopCoax,			     ioaddr + EL3_CMD);		}		EL3WINDOW(old_window);	}	restore_flags(flags);	if (corkscrew_debug > 1)		printk("%s: Media selection timer finished, %s.\n",		       dev->name, media_tbl[dev->if_port].name);#endif				/* AUTOMEDIA */	return;}static void corkscrew_timeout(struct net_device *dev){	int i;	struct corkscrew_private *vp =	    (struct corkscrew_private *) dev->priv;	int ioaddr = dev->base_addr;	printk(KERN_WARNING	       "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",	       dev->name, inb(ioaddr + TxStatus),	       inw(ioaddr + EL3_STATUS));	/* Slight code bloat to be user friendly. */	if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)		printk(KERN_WARNING		       "%s: Transmitter encountered 16 collisions -- network"		       " network cable problem?\n", dev->name);#ifndef final_version	printk("  Flags; bus-master %d, full %d; dirty %d current %d.\n",	       vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx,	       vp->cur_tx);	printk("  Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),	       &vp->tx_ring[0]);	for (i = 0; i < TX_RING_SIZE; i++) {		printk("  %d: %p  length %8.8x status %8.8x\n", i,		       &vp->tx_ring[i],		       vp->tx_ring[i].length, vp->tx_ring[i].status);	}#endif	/* Issue TX_RESET and TX_START commands. */	outw(TxReset, ioaddr + EL3_CMD);	for (i = 20; i >= 0; i--)		if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))			break;	outw(TxEnable, ioaddr + EL3_CMD);	dev->trans_start = jiffies;	vp->stats.tx_errors++;	vp->stats.tx_dropped++;	netif_wake_queue(dev);}static int corkscrew_start_xmit(struct sk_buff *skb,				struct net_device *dev){	struct corkscrew_private *vp =	    (struct corkscrew_private *) dev->priv;	int ioaddr = dev->base_addr;	/* Block a timer-based transmit from overlapping. */	netif_stop_queue(dev);	if (vp->full_bus_master_tx) {	/* BOOMERANG bus-master */		/* Calculate the next Tx descriptor entry. */		int entry = vp->cur_tx % TX_RING_SIZE;		struct boom_tx_desc *prev_entry;		unsigned long flags, i;		if (vp->tx_full)	/* No room to transmit with */			return 1;		if (vp->cur_tx != 0)			prev_entry =			    &vp->tx_ring[(vp->cur_tx - 1) % TX_RING_SIZE];		else			prev_entry = NULL;		if (corkscrew_debug > 3)			printk("%s: Trying to send a packet, Tx index %d.\n",				dev->name, vp->cur_tx);		/* vp->tx_full = 1; */		vp->tx_skbuff[entry] = skb;		vp->tx_ring[entry].next = 0;		vp->tx_ring[entry].addr = virt_to_bus(skb->data);		vp->tx_ring[entry].length = skb->len | 0x80000000;		vp->tx_ring[entry].status = skb->len | 0x80000000;		save_flags(flags);		cli();		outw(DownStall, ioaddr + EL3_CMD);		/* Wait for the stall to complete. */		for (i = 20; i >= 0; i--)			if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) ==			    0) break;		if (prev_entry)			prev_entry->next =			    virt_to_bus(&vp->tx_ring[entry]);		if (inl(ioaddr + DownListPtr) == 0) {			outl(virt_to_bus(&vp->tx_ring[entry]),			     ioaddr + DownListPtr);			queued_packet++;		}		outw(DownUnstall, ioaddr + EL3_CMD);		restore_flags(flags);		vp->cur_tx++;		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)			vp->tx_full = 1;		else {		/* Clear previous interrupt enable. */			if (prev_entry)				prev_entry->status &= ~0x80000000;			netif_wake_queue(dev);		}		dev->trans_start = jiffies;		return 0;	}	/* Put out the doubleword header... */	outl(skb->len, ioaddr + TX_FIFO);#ifdef VORTEX_BUS_MASTER	if (vp->bus_master) {		/* Set the bus-master controller to transfer the packet. */		outl((int) (skb->data), ioaddr + Wn7_MasterAddr);		outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);		vp->tx_skb = skb;		outw(StartDMADown, ioaddr + EL3_CMD);		/* queue will be woken at the DMADone interrupt. */	} else {		/* ... and the packet rounded to a doubleword. */		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);		dev_kfree_skb(skb);		if (inw(ioaddr + TxFree) > 1536) {			netif_wake_queue(dev);		} else			/* Interrupt us when the FIFO has room for max-sized packet. */			outw(SetTxThreshold + (1536 >> 2),			     ioaddr + EL3_CMD);	}#else	/* ... and the packet rounded to a doubleword. */	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);	dev_kfree_skb(skb);	if (inw(ioaddr + TxFree) > 1536) {		netif_wake_queue(dev);	} else		/* Interrupt us when the FIFO has room for max-sized packet. */		outw(SetTxThreshold + (1536 >> 2), ioaddr + EL3_CMD);#endif				/* bus master */	dev->trans_start = jiffies;	/* Clear the Tx status stack. */	{		short tx_status;		int i = 4;		while (--i > 0 && (tx_status = inb(ioaddr + TxStatus)) > 0) {			if (tx_status & 0x3C) {	/* A Tx-disabling error occurred.  */				if (corkscrew_debug > 2)					printk("%s: Tx error, status %2.2x.\n",						dev->name, tx_status);				if (tx_status & 0x04)					vp->stats.tx_fifo_errors++;				if (tx_status & 0x38)					vp->stats.tx_aborted_errors++;				if (tx_status & 0x30) {					int j;					outw(TxReset, ioaddr + EL3_CMD);					for (j = 20; j >= 0; j--)						if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress)) 							break;				}				outw(TxEnable, ioaddr + EL3_CMD);			}			outb(0x00, ioaddr + TxStatus);	/* Pop the status stack. */		}	}	vp->stats.tx_bytes += skb->len;	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void corkscrew_interrupt(int irq, void *dev_id,				    struct pt_regs *regs){	/* Use the now-standard shared IRQ implementation. */	struct net_device *dev = dev_id;	struct corkscrew_private *lp;	int ioaddr, status;	int latency;	int i = max_interrupt_work;	ioaddr = dev->base_addr;	latency = inb(ioaddr + Timer);	lp = (struct corkscrew_private *) dev->priv;	status = inw(ioaddr + EL3_STATUS);	if (corkscrew_debug > 4)		printk("%s: interrupt, status %4.4x, timer %d.\n",			dev->name, status, latency);	if ((status & 0xE000) != 0xE000) {		static int donedidthis = 0;		/* Some interrupt controllers store a bogus interrupt from boot-time.		   Ignore a single early interrupt, but don't hang the machine for		   other interrupt problems. */		if (donedidthis++ > 100) {			printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",				   dev->name, status, netif_running(dev));			free_irq(dev->irq, dev);		}	}	do {		if (corkscrew_debug > 5)			printk("%s: In interrupt loop, status %4.4x.\n",			       dev->name, status);		if (status & RxComplete)			corkscrew_rx(dev);		if (status & TxAvailable) {			if (corkscrew_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);			netif_wake_queue(dev);		}		if (status & DownComplete) {			unsigned int dirty_tx = lp->dirty_tx;			while (lp->cur_tx - dirty_tx > 0) {				int entry = dirty_tx % TX_RING_SIZE;				if (inl(ioaddr + DownListPtr) ==				    virt_to_bus(&lp->tx_ring[entry]))					break;	/* It still hasn't been processed. */				if (lp->tx_skbuff[entry]) {					dev_kfree_skb_irq(lp->							  tx_skbuff							  [entry]);					lp->tx_skbuff[entry] = 0;				}				dirty_tx++;			}			lp->dirty_tx = dirty_tx;			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);			if (lp->tx_full			    && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {

⌨️ 快捷键说明

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