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

📄 3c515.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
			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. */	dev->tbusy = 0;	dev->interrupt = 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 | 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);	MOD_INC_USE_COUNT;	return 0;}static void vortex_timer(unsigned long data){#ifdef AUTOMEDIA	struct device *dev = (struct device *)data;	struct vortex_private *vp = (struct vortex_private *)dev->priv;	int ioaddr = dev->base_addr;	unsigned long flags;	int ok = 0;	if (vortex_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 (vortex_debug > 1)			printk("%s: Media %s has link beat, %x.\n",				   dev->name, media_tbl[dev->if_port].name, media_status);		} else if (vortex_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 (vortex_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 (vortex_debug > 1)			printk("%s: Media selection failing, using default %s port.\n",				   dev->name, media_tbl[dev->if_port].name);		} else {		  if (vortex_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 (vortex_debug > 1)	  printk("%s: Media selection timer finished, %s.\n",			 dev->name, media_tbl[dev->if_port].name);#endif /* AUTOMEDIA*/	return;}static intvortex_start_xmit(struct sk_buff *skb, struct device *dev){	struct vortex_private *vp = (struct vortex_private *)dev->priv;	int ioaddr = dev->base_addr;	if (dev->tbusy) {		int tickssofar = jiffies - dev->trans_start;		int i;		/* Min. wait before assuming a Tx failed == 400ms. */		if (tickssofar < 400*HZ/1000)		/* We probably aren't empty. */			return 1;		printk("%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("%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;		/* dev->tbusy = 0;*/		vp->stats.tx_errors++;		vp->stats.tx_dropped++;		return 0;			/* Yes, silently *drop* the packet! */	}	/* 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) {		printk("%s: Transmitter access conflict.\n", dev->name);		return 1;	}	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 (vortex_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;		  dev->tbusy = 0;		}		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);		/* dev->tbusy will be cleared 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) {			dev->tbusy = 0;		} 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) {		dev->tbusy = 0;	} 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 (vortex_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. */		}	}	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs){	/* Use the now-standard shared IRQ implementation. */	struct device *dev = dev_id;	struct vortex_private *lp;	int ioaddr, status;	int latency;	int i = max_interrupt_work;	if (test_and_set_bit(0, (void*)&dev->interrupt)) {		printk("%s: Re-entering the interrupt handler.\n", dev->name);		return;	}	ioaddr = dev->base_addr;	latency = inb(ioaddr + Timer);	lp = (struct vortex_private *)dev->priv;	status = inw(ioaddr + EL3_STATUS);	if (vortex_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("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",				   dev->name, status, dev->start);			FREE_IRQ(dev->irq, dev);		}	}	do {		if (vortex_debug > 5)				printk("%s: In interrupt loop, status %4.4x.\n",					   dev->name, status);		if (status & RxComplete)			vortex_rx(dev);		if (status & TxAvailable) {			if (vortex_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 & 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(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)) {				lp->tx_full= 0;				dev->tbusy = 0;				mark_bh(NET_BH);			}		}#ifdef VORTEX_BUS_MASTER		if (status & DMADone) {			outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */			dev->tbusy = 0;			dev_kfree_skb (lp->tx_skb); /* Release the transfered buffer */			mark_bh(NET_BH);		}#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. */				vortex_rx(dev);				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);			}			if (status & StatsFull) { 	/* Empty statistics. */				static int DoneDidThat = 0;				if (vortex_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++) {

⌨️ 快捷键说明

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