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

📄 lance.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	int entry;	unsigned long flags;	/* Transmitter timeout, serious problems. */	if (dev->tbusy) {		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 20)			return 1;		outw(0, ioaddr+LANCE_ADDR);		printk("%s: transmit timed out, status %4.4x, resetting.\n",			   dev->name, inw(ioaddr+LANCE_DATA));		outw(0x0004, ioaddr+LANCE_DATA);		lp->stats.tx_errors++;#ifndef final_version		{			int i;			printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",				   lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",				   lp->cur_rx);			for (i = 0 ; i < RX_RING_SIZE; i++)				printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",					   lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,					   lp->rx_ring[i].msg_length);			for (i = 0 ; i < TX_RING_SIZE; i++)				printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",					   lp->tx_ring[i].base, -lp->tx_ring[i].length,					   lp->tx_ring[i].misc);			printk("\n");		}#endif		lance_restart(dev, 0x0043, 1);		dev->tbusy=0;		dev->trans_start = jiffies;		return 0;	}	if (lance_debug > 3) {		outw(0x0000, ioaddr+LANCE_ADDR);		printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,			   inw(ioaddr+LANCE_DATA));		outw(0x0000, ioaddr+LANCE_DATA);	}	/* 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 (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {		printk("%s: Transmitter access conflict.\n", dev->name);		return 1;	}	if (test_and_set_bit(0, (void*)&lp->lock) != 0) {		if (lance_debug > 0)			printk("%s: tx queue lock!.\n", dev->name);		/* don't clear dev->tbusy flag. */		return 1;	}	/* Fill in a Tx ring entry */	/* Mask to ring buffer boundary. */	entry = lp->cur_tx & TX_RING_MOD_MASK;	/* Caution: the write order is important here, set the base address	   with the "ownership" bits last. */	/* The old LANCE chips doesn't automatically pad buffers to min. size. */	if (chip_table[lp->chip_version].flags & LANCE_MUST_PAD) {		lp->tx_ring[entry].length =			-(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);	} else		lp->tx_ring[entry].length = -skb->len;	lp->tx_ring[entry].misc = 0x0000;	/* If any part of this buffer is >16M we must copy it to a low-memory	   buffer. */	if ((u32)virt_to_bus(skb->data) + skb->len > 0x01000000) {		if (lance_debug > 5)			printk("%s: bouncing a high-memory packet (%#x).\n",				   dev->name, (u32)virt_to_bus(skb->data));		memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len);		lp->tx_ring[entry].base =			((u32)virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000;		dev_kfree_skb(skb);	} else {		lp->tx_skbuff[entry] = skb;		lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000;	}	lp->cur_tx++;	lp->stats.tx_bytes += skb->len;	/* Trigger an immediate send poll. */	outw(0x0000, ioaddr+LANCE_ADDR);	outw(0x0048, ioaddr+LANCE_DATA);	dev->trans_start = jiffies;	save_flags(flags);	cli();	lp->lock = 0;	if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)		dev->tbusy=0;	else		lp->tx_full = 1;	restore_flags(flags);	return 0;}/* The LANCE interrupt handler. */static voidlance_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct device *dev = dev_id;	struct lance_private *lp;	int csr0, ioaddr, boguscnt=10;	int must_restart;	if (dev == NULL) {		printk ("lance_interrupt(): irq %d for unknown device.\n", irq);		return;	}	ioaddr = dev->base_addr;	lp = (struct lance_private *)dev->priv;	if (dev->interrupt)		printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);	dev->interrupt = 1;	outw(0x00, dev->base_addr + LANCE_ADDR);	while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600		   && --boguscnt >= 0) {		/* Acknowledge all of the current interrupt sources ASAP. */		outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA);		must_restart = 0;		if (lance_debug > 5)			printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",				   dev->name, csr0, inw(dev->base_addr + LANCE_DATA));		if (csr0 & 0x0400)			/* Rx interrupt */			lance_rx(dev);		if (csr0 & 0x0200) {		/* Tx-done interrupt */			int dirty_tx = lp->dirty_tx;			while (dirty_tx < lp->cur_tx) {				int entry = dirty_tx & TX_RING_MOD_MASK;				int status = lp->tx_ring[entry].base;							if (status < 0)					break;			/* It still hasn't been Txed */				lp->tx_ring[entry].base = 0;				if (status & 0x40000000) {					/* There was an major error, log it. */					int err_status = lp->tx_ring[entry].misc;					lp->stats.tx_errors++;					if (err_status & 0x0400) lp->stats.tx_aborted_errors++;					if (err_status & 0x0800) lp->stats.tx_carrier_errors++;					if (err_status & 0x1000) lp->stats.tx_window_errors++;					if (err_status & 0x4000) {						/* Ackk!  On FIFO errors the Tx unit is turned off! */						lp->stats.tx_fifo_errors++;						/* Remove this verbosity later! */						printk("%s: Tx FIFO error! Status %4.4x.\n",							   dev->name, csr0);						/* Restart the chip. */						must_restart = 1;					}				} else {					if (status & 0x18000000)						lp->stats.collisions++;					lp->stats.tx_packets++;				}				/* We must free the original skb if it's not a data-only copy				   in the bounce buffer. */				if (lp->tx_skbuff[entry]) {					dev_kfree_skb(lp->tx_skbuff[entry]);					lp->tx_skbuff[entry] = 0;				}				dirty_tx++;			}#ifndef final_version			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {				printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",					   dirty_tx, lp->cur_tx, lp->tx_full);				dirty_tx += TX_RING_SIZE;			}#endif			if (lp->tx_full && dev->tbusy				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {				/* The ring is no longer full, clear tbusy. */				lp->tx_full = 0;				dev->tbusy = 0;				mark_bh(NET_BH);			}			lp->dirty_tx = dirty_tx;		}		/* Log misc errors. */		if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */		if (csr0 & 0x1000) lp->stats.rx_errors++; /* Missed a Rx frame. */		if (csr0 & 0x0800) {			printk("%s: Bus master arbitration failure, status %4.4x.\n",				   dev->name, csr0);			/* Restart the chip. */			must_restart = 1;		}		if (must_restart) {			/* stop the chip to clear the error condition, then restart */			outw(0x0000, dev->base_addr + LANCE_ADDR);			outw(0x0004, dev->base_addr + LANCE_DATA);			lance_restart(dev, 0x0002, 0);		}	}	/* Clear any other interrupt, and set interrupt enable. */	outw(0x0000, dev->base_addr + LANCE_ADDR);	outw(0x7940, dev->base_addr + LANCE_DATA);	if (lance_debug > 4)		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",			   dev->name, inw(ioaddr + LANCE_ADDR),			   inw(dev->base_addr + LANCE_DATA));	dev->interrupt = 0;	return;}static intlance_rx(struct device *dev){	struct lance_private *lp = (struct lance_private *)dev->priv;	int entry = lp->cur_rx & RX_RING_MOD_MASK;	int i;			/* If we own the next entry, it's a new packet. Send it up. */	while (lp->rx_ring[entry].base >= 0) {		int status = lp->rx_ring[entry].base >> 24;		if (status != 0x03) {			/* There was an error. */			/* There is a tricky error noted by John Murphy,			   <murf@perftech.com> to Russ Nelson: Even with full-sized			   buffers it's possible for a jabber packet to use two			   buffers, with only the last correctly noting the error. */			if (status & 0x01)	/* Only count a general error at the */				lp->stats.rx_errors++; /* end of a packet.*/			if (status & 0x20) lp->stats.rx_frame_errors++;			if (status & 0x10) lp->stats.rx_over_errors++;			if (status & 0x08) lp->stats.rx_crc_errors++;			if (status & 0x04) lp->stats.rx_fifo_errors++;			lp->rx_ring[entry].base &= 0x03ffffff;		}		else 		{			/* Malloc up new buffer, compatible with net3. */			short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;			struct sk_buff *skb;						if(pkt_len<60)			{				printk("%s: Runt packet!\n",dev->name);				lp->stats.rx_errors++;			}			else			{				skb = dev_alloc_skb(pkt_len+2);				if (skb == NULL) 				{					printk("%s: Memory squeeze, deferring packet.\n", dev->name);					for (i=0; i < RX_RING_SIZE; i++)						if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0)							break;					if (i > RX_RING_SIZE -2) 					{						lp->stats.rx_dropped++;						lp->rx_ring[entry].base |= 0x80000000;						lp->cur_rx++;					}					break;				}				skb->dev = dev;				skb_reserve(skb,2);	/* 16 byte align */				skb_put(skb,pkt_len);	/* Make room */				eth_copy_and_sum(skb,					(unsigned char *)bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)),					pkt_len,0);				lp->stats.rx_bytes+=skb->len;				skb->protocol=eth_type_trans(skb,dev);				lp->stats.rx_packets++;				netif_rx(skb);			}		}		/* The docs say that the buffer length isn't touched, but Andrew Boyd		   of QNX reports that some revs of the 79C965 clear it. */		lp->rx_ring[entry].buf_length = -PKT_BUF_SZ;		lp->rx_ring[entry].base |= 0x80000000;		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;	}	/* We should check that at least two ring entries are free.	 If not,	   we should free one and mark stats->rx_dropped++. */	return 0;}static intlance_close(struct device *dev){	int ioaddr = dev->base_addr;	struct lance_private *lp = (struct lance_private *)dev->priv;	int i;	dev->start = 0;	dev->tbusy = 1;	if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {		outw(112, ioaddr+LANCE_ADDR);		lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);	}	outw(0, ioaddr+LANCE_ADDR);	if (lance_debug > 1)		printk("%s: Shutting down ethercard, status was %2.2x.\n",			   dev->name, inw(ioaddr+LANCE_DATA));	/* We stop the LANCE here -- it occasionally polls	   memory if we don't. */	outw(0x0004, ioaddr+LANCE_DATA);	if (dev->dma != 4)	{		unsigned long flags=claim_dma_lock();		disable_dma(dev->dma);		release_dma_lock(flags);	}	free_irq(dev->irq, dev);	/* Free all the skbuffs in the Rx and Tx queues. */	for (i = 0; i < RX_RING_SIZE; i++) {		struct sk_buff *skb = lp->rx_skbuff[i];		lp->rx_skbuff[i] = 0;		lp->rx_ring[i].base = 0;		/* Not owned by LANCE chip. */		if (skb)			dev_kfree_skb(skb);	}	for (i = 0; i < TX_RING_SIZE; i++) {		if (lp->tx_skbuff[i])			dev_kfree_skb(lp->tx_skbuff[i]);		lp->tx_skbuff[i] = 0;	}	MOD_DEC_USE_COUNT;	return 0;}static struct net_device_stats *lance_get_stats(struct device *dev){	struct lance_private *lp = (struct lance_private *)dev->priv;	short ioaddr = dev->base_addr;	short saved_addr;	unsigned long flags;	if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) {		save_flags(flags);		cli();		saved_addr = inw(ioaddr+LANCE_ADDR);		outw(112, ioaddr+LANCE_ADDR);		lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);		outw(saved_addr, ioaddr+LANCE_ADDR);		restore_flags(flags);	}	return &lp->stats;}/* Set or clear the multicast filter for this adaptor. */static void set_multicast_list(struct device *dev){	short ioaddr = dev->base_addr;	outw(0, ioaddr+LANCE_ADDR);	outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.	 */	if (dev->flags&IFF_PROMISC) {		/* Log any net taps. */		printk("%s: Promiscuous mode enabled.\n", dev->name);		outw(15, ioaddr+LANCE_ADDR);		outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */	} else {		short multicast_table[4];		int i;		int num_addrs=dev->mc_count;		if(dev->flags&IFF_ALLMULTI)			num_addrs=1;		/* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */		memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table));		for (i = 0; i < 4; i++) {			outw(8 + i, ioaddr+LANCE_ADDR);			outw(multicast_table[i], ioaddr+LANCE_DATA);		}		outw(15, ioaddr+LANCE_ADDR);		outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */	}	lance_restart(dev, 0x0142, 0); /*  Resume normal operation */}

⌨️ 快捷键说明

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