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

📄 rtl8139.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
		tp->tx_full = 1;	}	dev->trans_start = jiffies;	if (rtl8129_debug > 4)		printk(KERN_DEBUG"%s: Queued Tx packet at %p size %ld to slot %d.\n",			   dev->name, skb->data, skb->len, entry);	return 0;}/* The interrupt handler does all of the Rx thread work and cleans up   after the Tx thread. */static void rtl8129_interrupt(int irq, void *dev_instance, struct pt_regs *regs){	struct device *dev = (struct device *)dev_instance;	struct rtl8129_private *tp;	int ioaddr, boguscnt = max_interrupt_work;	int status;	if (dev == NULL) {		printk (KERN_ERR"rtl8139_interrupt(): IRQ %d for unknown device.\n",				irq);		return;	}	ioaddr = dev->base_addr;	tp = (struct rtl8129_private *)dev->priv;	if (test_and_set_bit(0, (void*)&tp->in_interrupt)) {		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);		return;	}	dev->interrupt = 1;	do {		status = inw(ioaddr + IntrStatus);		/* Acknowledge all of the current interrupt sources ASAP. */		outw(status, ioaddr + IntrStatus);		if (rtl8129_debug > 4)			printk(KERN_DEBUG"%s: interrupt  status=%#4.4x new intstat=%#4.4x.\n",				   dev->name, status, inw(ioaddr + IntrStatus));		if ((status & (PCIErr|PCSTimeout|RxUnderrun|RxOverflow|RxFIFOOver					   |TxErr|TxOK|RxErr|RxOK)) == 0)			break;		if (status & (RxOK|RxUnderrun|RxOverflow|RxFIFOOver))/* Rx interrupt */			rtl8129_rx(dev);		if (status & (TxOK | TxErr)) {			unsigned int dirty_tx;			for (dirty_tx = tp->dirty_tx; dirty_tx < tp->cur_tx; dirty_tx++) {				int entry = dirty_tx % NUM_TX_DESC;				int txstatus = inl(ioaddr + TxStat0 + entry*4);				if ( ! (txstatus & TxHostOwns))					break;			/* It still hasn't been Txed */				/* Note: TxCarrierLost is always asserted at 100mbps. */				if (txstatus & (TxOutOfWindow | TxAborted)) {					/* There was an major error, log it. */#ifndef final_version					if (rtl8129_debug > 1)						printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",							   dev->name, txstatus);#endif					tp->stats.tx_errors++;					if (txstatus&TxAborted) {						tp->stats.tx_aborted_errors++;						outl((TX_DMA_BURST<<8)|0x03000001, ioaddr + TxConfig);					}					if (txstatus&TxCarrierLost) tp->stats.tx_carrier_errors++;					if (txstatus&TxOutOfWindow) tp->stats.tx_window_errors++;#ifdef ETHER_STATS					if ((txstatus & 0x0f000000) == 0x0f000000)						tp->stats.collisions16++;#endif				} else {#ifdef ETHER_STATS					/* No count for tp->stats.tx_deferred */#endif					if (txstatus & TxUnderrun) {						/* Todo: increase the Tx FIFO threshold. */						tp->stats.tx_fifo_errors++;					}					tp->stats.collisions += (txstatus >> 24) & 15;#if LINUX_VERSION_CODE > 0x20119					tp->stats.tx_bytes += txstatus & 0x7ff;#endif					tp->stats.tx_packets++;				}				/* Free the original skb. */				dev_kfree_skb(tp->tx_skbuff[entry], FREE_WRITE);				tp->tx_skbuff[entry] = 0;			}#ifndef final_version			if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {				printk(KERN_ERR"%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);				dirty_tx += NUM_TX_DESC;			}#endif			if (tp->tx_full && dev->tbusy				&& dirty_tx > tp->cur_tx - NUM_TX_DESC) {				/* The ring is no longer full, clear tbusy. */				tp->tx_full = 0;				dev->tbusy = 0;				mark_bh(NET_BH);			}			tp->dirty_tx = dirty_tx;		}		/* Check uncommon events with one test. */		if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver					  |TxErr|RxErr)) {			/* Update the error count. */			tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);			outl(0, ioaddr + RxMissed);			if (status & (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))				tp->stats.rx_errors++;			if (status & (PCSTimeout)) tp->stats.rx_length_errors++;			if (status & (RxUnderrun|RxFIFOOver)) tp->stats.rx_fifo_errors++;			if (status & RxOverflow) {				tp->stats.rx_over_errors++;				tp->cur_rx = inw(ioaddr + RxBufAddr) % RX_BUF_LEN;				outw(tp->cur_rx - 16, ioaddr + RxBufPtr);			}			/* Error sources cleared above. */		}		if (--boguscnt < 0) {			printk(KERN_WARNING"%s: Too much work at interrupt, "				   "IntrStatus=0x%4.4x.\n",				   dev->name, status);			/* Clear all interrupt sources. */			outw(0xffff, ioaddr + IntrStatus);			break;		}	} while (1);	if (rtl8129_debug > 3)		printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",			   dev->name, inl(ioaddr + IntrStatus));	dev->interrupt = 0;	clear_bit(0, (void*)&tp->in_interrupt);	return;}/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the   field alignments and semantics. */static intrtl8129_rx(struct device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	int ioaddr = dev->base_addr;	unsigned char *rx_ring = tp->rx_ring;	u16 cur_rx = tp->cur_rx;	if (rtl8129_debug > 4)		printk(KERN_DEBUG"%s: In rtl8129_rx(), current %4.4x BufAddr %4.4x,"			   " free to %4.4x, Cmd %2.2x.\n",			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));	while ((inb(ioaddr + ChipCmd) & 1) == 0) {		int ring_offset = cur_rx % RX_BUF_LEN;		u32 rx_status = *(u32*)(rx_ring + ring_offset);		int rx_size = rx_status >> 16;		if (rtl8129_debug > 4) {			int i;			printk(KERN_DEBUG"%s:  rtl8129_rx() status %4.4x, size %4.4x, cur %4.4x.\n",				   dev->name, rx_status, rx_size, cur_rx);			printk(KERN_DEBUG"%s: Frame contents ", dev->name);			for (i = 0; i < 70; i++)				printk(" %2.2x", rx_ring[ring_offset + i]);			printk(".\n");		}		if (rx_status & RxTooLong) {			if (rtl8129_debug > 0)				printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n",					   dev->name, rx_status);			tp->stats.rx_length_errors++;		} else if (rx_status &				   (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {			if (rtl8129_debug > 1)				printk(KERN_DEBUG"%s: Ethernet frame had errors,"					   " status %4.4x.\n", dev->name, rx_status);			tp->stats.rx_errors++;			if (rx_status & (RxBadSymbol|RxBadAlign))				tp->stats.rx_frame_errors++;			if (rx_status & (RxRunt|RxTooLong)) tp->stats.rx_length_errors++;			if (rx_status & RxCRCErr) tp->stats.rx_crc_errors++;			/* Reset the receiver, based on RealTek recommendation. (Bug?) */			tp->cur_rx = 0;			outb(CmdTxEnb, ioaddr + ChipCmd);			outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);			outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) |				 (RX_DMA_BURST<<8), ioaddr + RxConfig);		} else {			/* Malloc up new buffer, compatible with net-2e. */			/* Omit the four octet CRC from the length. */			struct sk_buff *skb;			skb = dev_alloc_skb(rx_size + 2);			if (skb == NULL) {				printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n",					   dev->name);				/* We should check that some rx space is free.				   If not, free one and mark stats->rx_dropped++. */				tp->stats.rx_dropped++;				break;			}			skb->dev = dev;			skb_reserve(skb, 2);	/* 16 byte align the IP fields. */			if (ring_offset+rx_size+4 > RX_BUF_LEN) {				int semi_count = RX_BUF_LEN - ring_offset - 4;				memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4],					   semi_count);				memcpy(skb_put(skb, rx_size-semi_count), rx_ring,					   rx_size-semi_count);				if (rtl8129_debug > 4) {					int i;					printk(KERN_DEBUG"%s:  Frame wrap @%d",						   dev->name, semi_count);					for (i = 0; i < 16; i++)						printk(" %2.2x", rx_ring[i]);					printk(".\n");					memset(rx_ring, 0xcc, 16);				}			} else				memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4],					   rx_size);			skb->protocol = eth_type_trans(skb, dev);			netif_rx(skb);#if LINUX_VERSION_CODE > 0x20119			tp->stats.rx_bytes += rx_size;#endif			tp->stats.rx_packets++;		}		cur_rx += rx_size + 4;		cur_rx = (cur_rx + 3) & ~3;		outw(cur_rx - 16, ioaddr + RxBufPtr);	}	if (rtl8129_debug > 4)		printk(KERN_DEBUG"%s: Done rtl8129_rx(), current %4.4x BufAddr %4.4x,"			   " free to %4.4x, Cmd %2.2x.\n",			   dev->name, cur_rx, inw(ioaddr + RxBufAddr),			   inw(ioaddr + RxBufPtr), inb(ioaddr + ChipCmd));	tp->cur_rx = cur_rx;	return 0;}static intrtl8129_close(struct device *dev){	int ioaddr = dev->base_addr;	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	int i;	dev->start = 0;	dev->tbusy = 1;	if (rtl8129_debug > 1)		printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n",			   dev->name, inw(ioaddr + IntrStatus));	/* Disable interrupts by clearing the interrupt mask. */	outw(0x0000, ioaddr + IntrMask);	/* Stop the chip's Tx and Rx DMA processes. */	outb(0x00, ioaddr + ChipCmd);	/* Update the error counts. */	tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);	outl(0, ioaddr + RxMissed);	del_timer(&tp->timer);	free_irq(dev->irq, dev);	for (i = 0; i < NUM_TX_DESC; i++) {		if (tp->tx_skbuff[i])			dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE);		tp->tx_skbuff[i] = 0;	}	kfree(tp->rx_ring);	kfree(tp->tx_bufs);	/* Green! Put the chip in low-power mode. */	outb(0xC0, ioaddr + Cfg9346);	outb(0x03, ioaddr + Config1);	outb('H', ioaddr + HltClk);		/* 'R' would leave the clock running. */	MOD_DEC_USE_COUNT;	return 0;}static struct enet_statistics *rtl8129_get_stats(struct device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	int ioaddr = dev->base_addr;	if (dev->start) {		tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);		outl(0, ioaddr + RxMissed);	}	return &tp->stats;}/* Set or clear the multicast filter for this adaptor.   Note that we only use exclusion around actually queueing the   new frame, not around filling tp->setup_frame.  This is non-deterministic   when re-entered but still correct. *//* The little-endian AUTODIN II ethernet CRC calculation.   N.B. Do not use for bulk data, use a table-based routine instead.   This is common code and should be moved to net/core/crc.c */static unsigned const ethernet_polynomial_le = 0xedb88320U;static inline unsigned ether_crc_le(int length, unsigned char *data){	unsigned int crc = 0xffffffff;	/* Initial value. */	while(--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 8; --bit >= 0; current_octet >>= 1) {			if ((crc ^ current_octet) & 1) {				crc >>= 1;				crc ^= ethernet_polynomial_le;			} else				crc >>= 1;		}	}	return crc;}static void set_rx_mode(struct device *dev){	int ioaddr = dev->base_addr;	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	unsigned char mc_filter[8];		 /* Multicast hash filter */	int i;	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */		/* Unconditionally log net taps. */		printk(KERN_NOTICE"%s: Promiscuous mode enabled.\n", dev->name);		memset(mc_filter, 0xff, sizeof(mc_filter));		outb(0x0F, ioaddr + RxConfig);	} else if ((dev->mc_count > 1000)  ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter perfectly -- accept all multicasts. */		memset(mc_filter, 0xff, sizeof(mc_filter));		outb(0x0E, ioaddr + RxConfig);	} else if (dev->mc_count == 0) {		outb(0x0A, ioaddr + RxConfig);		return;	} else {		struct dev_mc_list *mclist;		memset(mc_filter, 0, sizeof(mc_filter));		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next)			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,					mc_filter);	}	/* ToDo: perhaps we need to stop the Tx and Rx process here? */	if (memcmp(mc_filter, tp->mc_filter, sizeof(mc_filter))) {		for (i = 0; i < 2; i++)			outl(((u32 *)mc_filter)[i], ioaddr + MAR0 + i*4);		memcpy(tp->mc_filter, mc_filter, sizeof(mc_filter));	}	if (rtl8129_debug > 3)		printk(KERN_DEBUG"%s:   set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",			   dev->name, dev->flags, inl(ioaddr + RxConfig));	return;}#ifdef MODULE/* An additional parameter that may be passed in... */static int debug = -1;intinit_module(void){	int cards_found;	if (debug >= 0)		rtl8129_debug = debug;	root_rtl8129_dev = NULL;	cards_found = rtl8139_probe(0);	return cards_found ? 0 : -ENODEV;}voidcleanup_module(void){	struct device *next_dev;	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */	while (root_rtl8129_dev) {		next_dev = ((struct rtl8129_private *)root_rtl8129_dev->priv)->next_module;		unregister_netdev(root_rtl8129_dev);		release_region(root_rtl8129_dev->base_addr, RTL8129_TOTAL_SIZE);		kfree(root_rtl8129_dev);		root_rtl8129_dev = next_dev;	}}#endif  /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" *  c-indent-level: 4 *  c-basic-offset: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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