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

📄 rtl8139.c

📁 44b0uclinux下的8319网卡芯片驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
			np->twistie = 2;	/* Change to state 2. */			next_tick = HZ/10;		} else {			/* Just put in some reasonable defaults for when beat returns. */			outw(CSCR_LinkDownCmd, ioaddr + CSCR);			outl(0x20,ioaddr + FIFOTMS);	/* Turn on cable test mode. */			outl(PARA78_default ,ioaddr + PARA78);			outl(PARA7c_default ,ioaddr + PARA7c);			np->twistie = 0;	/* Bail from future actions. */		}	} break;	case 2: {		/* Read how long it took to hear the echo. */		int linkcase = inw(ioaddr + CSCR) & CSCR_LinkStatusBits;		if (linkcase == 0x7000) np->twist_row = 3;		else if (linkcase == 0x3000) np->twist_row = 2;		else if (linkcase == 0x1000) np->twist_row = 1;		else np->twist_row = 0;		np->twist_col = 0;		np->twistie = 3;	/* Change to state 2. */		next_tick = HZ/10;	} break;	case 3: {		/* Put out four tuning parameters, one per 100msec. */		if (np->twist_col == 0) outw(0, ioaddr + FIFOTMS);		outl(param[(int)np->twist_row][(int)np->twist_col], ioaddr + PARA7c);		next_tick = HZ/10;		if (++np->twist_col >= 4) {			/* For short cables we are done.			   For long cables (row == 3) check for mistune. */			np->twistie = (np->twist_row == 3) ? 4 : 0;		}	} break;	case 4: {		/* Special case for long cables: check for mistune. */		if ((inw(ioaddr + CSCR) & CSCR_LinkStatusBits) == 0x7000) {			np->twistie = 0;			break;		} else {			outl(0xfb38de03, ioaddr + PARA7c);			np->twistie = 5;			next_tick = HZ/10;		}	} break;	case 5: {		/* Retune for shorter cable (column 2). */		outl(0x20,ioaddr + FIFOTMS);		outl(PARA78_default,  ioaddr + PARA78);		outl(PARA7c_default,  ioaddr + PARA7c);		outl(0x00,ioaddr + FIFOTMS);		np->twist_row = 2;		np->twist_col = 0;		np->twistie = 3;		next_tick = HZ/10;	} break;	}#endif	if (debug > 2) {		if (np->drv_flags & HAS_MII_XCVR)			printk(KERN_DEBUG"%s: Media selection tick, GP pins %2.2x.\n",				   dev->name, inb(ioaddr + GPPinData));		else			printk(KERN_DEBUG"%s: Media selection tick, Link partner %4.4x.\n",				   dev->name, inw(ioaddr + NWayLPAR));		printk(KERN_DEBUG"%s:  Other registers are IntMask %4.4x IntStatus %4.4x"			   " RxStatus %4.4x.\n",			   dev->name, inw(ioaddr + IntrMask), inw(ioaddr + IntrStatus),			   inl(ioaddr + RxEarlyStatus));		printk(KERN_DEBUG"%s:  Chip config %2.2x %2.2x.\n",			   dev->name, inb(ioaddr + Config0), inb(ioaddr + Config1));	}	np->timer.expires = jiffies + next_tick;	add_timer(&np->timer);}static void rtl8129_tx_timeout(struct net_device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	int mii_reg, i;	if (debug > 0)		printk(KERN_ERR "%s: Transmit timeout, status %2.2x %4.4x "			   "media %2.2x.\n",			   dev->name, inb(ioaddr + ChipCmd), inw(ioaddr + IntrStatus),			   inb(ioaddr + GPPinData));	/* Disable interrupts by clearing the interrupt mask. */	outw(0x0000, ioaddr + IntrMask);	/* Emit info to figure out what went wrong. */	printk(KERN_DEBUG "%s: Tx queue start entry %d  dirty entry %d%s.\n",		   dev->name, tp->cur_tx, tp->dirty_tx, tp->tx_full ? ", full" : "");	for (i = 0; i < NUM_TX_DESC; i++)		printk(KERN_DEBUG "%s:  Tx descriptor %d is %8.8x.%s\n",			   dev->name, i, inl(ioaddr + TxStatus0 + i*4),			   i == tp->dirty_tx % NUM_TX_DESC ? " (queue head)" : "");	printk(KERN_DEBUG "%s: MII #%d registers are:", dev->name, tp->phys[0]);	for (mii_reg = 0; mii_reg < 8; mii_reg++)		printk(" %4.4x", mdio_read(dev, tp->phys[0], mii_reg));	printk(".\n");	/* Stop a shared interrupt from scavenging while we are. */	tp->dirty_tx = tp->cur_tx = 0;	/* Dump the unsent Tx packets. */	for (i = 0; i < NUM_TX_DESC; i++) {		if (tp->tx_skbuff[i]) {			dev_free_skb(tp->tx_skbuff[i]);			tp->tx_skbuff[i] = 0;			tp->stats.tx_dropped++;		}	}	rtl_hw_start(dev);	netif_unpause_tx_queue(dev);	tp->tx_full = 0;	return;}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static voidrtl8129_init_ring(struct net_device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	int i;	tp->tx_full = 0;	tp->dirty_tx = tp->cur_tx = 0;	for (i = 0; i < NUM_TX_DESC; i++) {		tp->tx_skbuff[i] = 0;		tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];	}}static intrtl8129_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	int entry;#ifdef CONFIG_LEDMAN	ledman_cmd(LEDMAN_CMD_SET,		(dev->name[3] == '0') ? LEDMAN_LAN1_TX : LEDMAN_LAN2_TX);#endif	if (netif_pause_tx_queue(dev) != 0) {		/* This watchdog code is redundant with the media monitor timer. */		if (jiffies - dev->trans_start > TX_TIMEOUT)			rtl8129_tx_timeout(dev);		return 1;	}	/* Calculate the next Tx descriptor entry. */	entry = tp->cur_tx % NUM_TX_DESC;	tp->tx_skbuff[entry] = skb;	if ((long)skb->data & 3) {			/* Must use alignment buffer. */		memcpy(tp->tx_buf[entry], skb->data, skb->len);		outl(virt_to_bus(tp->tx_buf[entry]), ioaddr + TxAddr0 + entry*4);	} else		outl(virt_to_bus(skb->data), ioaddr + TxAddr0 + entry*4);	/* Note: the chip doesn't have auto-pad! */	outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),		 ioaddr + TxStatus0 + entry*4);	/* There is a race condition here -- we might read dirty_tx, take an	   interrupt that clears the Tx queue, and only then set tx_full.	   So we do this in two phases. */	if (++tp->cur_tx - tp->dirty_tx >= NUM_TX_DESC) {		set_bit(0, &tp->tx_full);		if (tp->cur_tx - (volatile unsigned int)tp->dirty_tx < NUM_TX_DESC) {			clear_bit(0, &tp->tx_full);			netif_unpause_tx_queue(dev);		} else			netif_stop_tx_queue(dev);	} else		netif_unpause_tx_queue(dev);	dev->trans_start = jiffies;	if (debug > 4)		printk(KERN_DEBUG"%s: Queued Tx packet at %p size %d to slot %d.\n",			   dev->name, skb->data, (int)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 net_device *dev = (struct net_device *)dev_instance;	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	int boguscnt = max_interrupt_work;	long ioaddr = dev->base_addr;	int link_changed = 0;		/* Grrr, avoid bogus "uninitialized" warning */#if defined(__i386__)  &&  LINUX_VERSION_CODE < 0x20123	/* A lock to prevent simultaneous entry bug on Intel SMP machines. */	if (test_and_set_bit(0, (void*)&dev->interrupt)) {		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",			   dev->name);		dev->interrupt = 0;	/* Avoid halting machine. */		return;	}#endif	do {		int status = inw(ioaddr + IntrStatus);		/* Acknowledge all of the current interrupt sources ASAP, but		   an first get an additional status bit from CSCR. */		if (status & RxUnderrun)			link_changed = inw(ioaddr+CSCR) & CSCR_LinkChangeBit;		outw(status, ioaddr + IntrStatus);		if (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 = tp->dirty_tx;			while (tp->cur_tx - dirty_tx > 0) {				int entry = dirty_tx % NUM_TX_DESC;				int txstatus = inl(ioaddr + TxStatus0 + entry*4);				if ( ! (txstatus & (TxStatOK | TxUnderrun | TxAborted)))					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. */					if (debug > 1)						printk(KERN_NOTICE"%s: Transmit error, Tx status %8.8x.\n",							   dev->name, txstatus);					tp->stats.tx_errors++;					if (txstatus&TxAborted) {						tp->stats.tx_aborted_errors++;						outl(TX_DMA_BURST << 8, 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 {					if (txstatus & TxUnderrun) {						/* Add 64 to the Tx FIFO threshold. */						if (tp->tx_flag <  0x00300000)							tp->tx_flag += 0x00020000;						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_free_skb_irq(tp->tx_skbuff[entry]);				tp->tx_skbuff[entry] = 0;				if (test_bit(0, &tp->tx_full)) {					/* The ring is no longer full, clear tbusy. */					clear_bit(0, &tp->tx_full);					netif_resume_tx_queue(dev);				}				dirty_tx++;			}#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, (int)tp->tx_full);				dirty_tx += NUM_TX_DESC;			}#endif			tp->dirty_tx = dirty_tx;		}		/* Check uncommon events with one test. */		if (status & (PCIErr|PCSTimeout |RxUnderrun|RxOverflow|RxFIFOOver					  |TxErr|RxErr)) {			if (debug > 2)				printk(KERN_NOTICE"%s: Abnormal interrupt, status %8.8x.\n",					   dev->name, status);			if (status == 0xffff)				break;			/* Update the error count. */			tp->stats.rx_missed_errors += inl(ioaddr + RxMissed);			outl(0, ioaddr + RxMissed);			if ((status & RxUnderrun)  &&  link_changed  &&				(tp->drv_flags & HAS_LNK_CHNG)) {				/* Really link-change on new chips. */				int lpar = inw(ioaddr + NWayLPAR);				int duplex = (lpar&0x0100) || (lpar & 0x01C0) == 0x0040					|| tp->duplex_lock;				if (debug > 1)					printk(KERN_DEBUG "%s: Link changed, link partner "						   "%4.4x new duplex %d.\n",						   dev->name, lpar, duplex);				if (tp->full_duplex != duplex) {					tp->full_duplex = duplex;					outb(0xC0, ioaddr + Cfg9346);					outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);					outb(0x00, ioaddr + Cfg9346);				}				status &= ~RxUnderrun;			}			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) % tp->rx_buf_len;				outw(tp->cur_rx - 16, ioaddr + RxBufPtr);			}			if (status & PCIErr) {				u32 pci_cmd_status;				pci_read_config_dword(tp->pci_dev, PCI_COMMAND, &pci_cmd_status);				printk(KERN_ERR "%s: PCI Bus error %4.4x.\n",					   dev->name, pci_cmd_status);			}		}		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 (debug > 3)		printk(KERN_DEBUG"%s: exiting interrupt, intr_status=%#4.4x.\n",			   dev->name, inw(ioaddr + IntrStatus));#if defined(__i386__)  &&  LINUX_VERSION_CODE < 0x20123	clear_bit(0, (void*)&dev->interrupt);#endif	return;}/* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the   field alignments and semantics. */static int rtl8129_rx(struct net_device *dev){	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	unsigned char *rx_ring = tp->rx_ring;	u16 cur_rx = tp->cur_rx;	if (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));#ifdef CONFIG_LEDMAN	ledman_cmd(LEDMAN_CMD_SET,		(dev->name[3] == '0') ? LEDMAN_LAN1_RX : LEDMAN_LAN2_RX);#endif	while ((inb(ioaddr + ChipCmd) & RxBufEmpty) == 0) {		int ring_offset = cur_rx % tp->rx_buf_len;		u32 rx_status = le32_to_cpu(*(u32*)(rx_ring + ring_offset));		int rx_size = rx_status >> 16; 				/* Includes the CRC. */		if (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 & (RxBadSymbol|RxRunt|RxTooLong|RxCRCErr|RxBadAlign)) {			if (debug > 1)				printk(KERN_DEBUG"%s: Ethernet frame had errors,"					   " status %8.8x.\n", dev->name, rx_status);			if (rx_status == 0xffffffff) {				if (debug > 0)					printk(KERN_NOTICE"%s: Invalid receive status at ring "						   "offset %4.4x\n", dev->name, ring_offset);				rx_status = 0;			}			if (rx_status & RxTooLong) {				if (debug > 0)					printk(KERN_NOTICE"%s: Oversized Ethernet frame, status %4.4x!\n",						   dev->name, rx_status);				/* A.C.: The chip hangs here. */			}

⌨️ 快捷键说明

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