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

📄 rtl8129.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	outb(0xC0, ioaddr + Cfg9346);	outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);	outb(0x00, ioaddr + Cfg9346);	outl(tp->rx_ring_dma, ioaddr + RxBuf);	/* Start the chip's Tx and Rx process. */	outl(0, ioaddr + RxMissed);	set_rx_mode(dev);	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);	/* Enable all known interrupts by setting the interrupt mask. */	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);	if (rtl8129_debug > 1)		printk(KERN_DEBUG"%s: rtl8129_open() ioaddr %#lx IRQ %d"			   " GP Pins %2.2x %s-duplex.\n",			   dev->name, ioaddr, dev->irq, inb(ioaddr + GPPinData),			   tp->full_duplex ? "full" : "half");	/* Set the timer to switch to check for link beat and perhaps switch	   to an alternate media type. */	init_timer(&tp->timer);	tp->timer.expires = RUN_AT((24*HZ)/10);			/* 2.4 sec. */	tp->timer.data = (unsigned long)dev;	tp->timer.function = &rtl8129_timer;	add_timer(&tp->timer);	return 0;}static void rtl8129_timer(unsigned long data){	struct net_device *dev = (struct net_device *)data;	struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv;	long ioaddr = dev->base_addr;	int next_tick = 60*HZ;	int mii_reg5 = mdio_read(dev, tp->phys[0], 5);	if (! tp->duplex_lock  &&  mii_reg5 != 0xffff) {		int duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040;		if (tp->full_duplex != duplex) {			tp->full_duplex = duplex;			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d link"				   " partner ability of %4.4x.\n", dev->name,				   tp->full_duplex ? "full" : "half", tp->phys[0], mii_reg5);			outb(0xC0, ioaddr + Cfg9346);			outb(tp->full_duplex ? 0x60 : 0x20, ioaddr + Config1);			outb(0x00, ioaddr + Cfg9346);		}	}	/* Check for bogusness. */	if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {		int status = inw(ioaddr + IntrStatus);		if (status & (TxOK | RxOK)) {	/* Double check */			printk(KERN_ERR "%s: RTL8129 Interrupt line blocked, status %x.\n",				   dev->name, status);			rtl8129_interrupt(dev->irq, dev, 0);		}	}	if (netif_queue_stopped(dev) &&		(jiffies - dev->trans_start) >= 2*TX_TIMEOUT)		rtl8129_tx_timeout(dev);#if 0	if (tp->twistie) {		unsigned int CSCRval = inw(ioaddr + CSCR);		/* Read link status. */		if (tp->twistie == 1) {			if (CSCRval & CSCR_LinkOKBit) {				outw(CSCR_LinkDownOffCmd, ioaddr + CSCR);				tp->twistie = 2;				next_tick = HZ/10;			} else {				outw(CSCR_LinkDownCmd, ioaddr + CSCR);				outl(FIFOTMS_default,ioaddr + FIFOTMS);				outl(PARA78_default ,ioaddr + PARA78);				outl(PARA7c_default ,ioaddr + PARA7c);				tp->twistie = 0;			}		} else if (tp->twistie == 2) {			int linkcase = (CSCRval & CSCR_LinkStatusBits) >> 12;			int row;			if (linkcase >= 0x7000) row = 3;			else if (linkcase >= 0x3000) row = 2;			else if (linkcase >= 0x1000) row = 1;			else row = 0;			tp->twistie == row + 3;			outw(0,ioaddr+FIFOTMS);			outl(param[row][0], ioaddr+PARA7c);			tp->twist_cnt = 1;		} else {			outl(param[tp->twistie-3][tp->twist_cnt], ioaddr+PARA7c);			if (++tp->twist_cnt < 4) {				next_tick = HZ/10;			} else if (tp->twistie-3 == 3) {				if ((CSCRval & CSCR_LinkStatusBits) != 0x7000) {					outl(PARA7c_xxx, ioaddr+PARA7c);					next_tick = HZ/10; 		/* 100ms. */					outl(FIFOTMS_default, ioaddr+FIFOTMS);					outl(PARA78_default,  ioaddr+PARA78);					outl(PARA7c_default,  ioaddr+PARA7c);					tp->twistie == 3 + 3;					outw(0,ioaddr+FIFOTMS);					outl(param[3][0], ioaddr+PARA7c);					tp->twist_cnt = 1;				}			}		}	}#endif	if (rtl8129_debug > 2) {		if (rtl_cap_tbl[tp->chip_id] & 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));	}	tp->timer.expires = RUN_AT(next_tick);	add_timer(&tp->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 (rtl8129_debug > 0)		printk(KERN_WARNING "%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("%s: Tx queue start entry %d  dirty entry %d.\n",		   dev->name, tp->cur_tx, tp->dirty_tx);	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");	/* Soft reset the chip. */	outb(CmdReset, ioaddr + ChipCmd);	/* Check that the chip has finished the reset. */	for (i = 1000; i > 0; i--)		if ((inb(ioaddr + ChipCmd) & CmdReset) == 0)			break;	for (i = 0; i < 6; i++)		outb(dev->dev_addr[i], ioaddr + MAC0 + i);	outb(0x00, ioaddr + Cfg9346);	tp->cur_rx = 0;	/* Must enable Tx/Rx before setting transfer thresholds! */	outb(CmdRxEnb | CmdTxEnb, ioaddr + ChipCmd);	outl((RX_FIFO_THRESH << 13) | (RX_BUF_LEN_IDX << 11) | (RX_DMA_BURST<<8),		 ioaddr + RxConfig);	outl((TX_DMA_BURST<<8), ioaddr + TxConfig);	set_rx_mode(dev);	{							/* Save the unsent Tx packets. */		struct sk_buff *saved_skb[NUM_TX_DESC], *skb;		int j;		for (j = 0; tp->cur_tx - tp->dirty_tx > 0 ; j++, tp->dirty_tx++) {			struct ring_info *rp = &tp->tx_info[tp->dirty_tx % NUM_TX_DESC];			saved_skb[j] = rp->skb;			if (rp->mapping != 0) {				pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE);				rp->mapping = 0;			}		}		tp->dirty_tx = tp->cur_tx = 0;		for (i = 0; i < j; i++) {			skb = tp->tx_info[i].skb = saved_skb[i];			if ((long)skb->data & 3) {		/* Must use alignment buffer. */				memcpy(tp->tx_buf[i], skb->data, skb->len);				outl(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs),					 ioaddr + TxAddr0 + i*4);			} else {				tp->tx_info[i].mapping =					pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);				outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4);			}			/* Note: the chip doesn't have auto-pad! */			outl(tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN),				 ioaddr + TxStatus0 + i*4);		}		tp->cur_tx = i;		while (i < NUM_TX_DESC) {			tp->tx_info[i].skb = NULL;			tp->tx_info[i].mapping = 0;			i++;		}		if (tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {/* Typical path */			netif_wake_queue(dev);			tp->tx_full = 0;		} else {			tp->tx_full = 1;			netif_stop_queue(dev);		}	}	dev->trans_start = jiffies;	tp->stats.tx_errors++;	/* Enable all known interrupts by setting the interrupt mask. */	outw(PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver		 | TxErr | TxOK | RxErr | RxOK, ioaddr + IntrMask);	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->cur_rx = 0;	tp->dirty_tx = tp->cur_tx = 0;	for (i = 0; i < NUM_TX_DESC; i++) {		tp->tx_buf[i] = &tp->tx_bufs[i*TX_BUF_SIZE];		tp->tx_info[i].skb = NULL;		tp->tx_info[i].mapping = 0;	}}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;	netif_stop_queue(dev);	/* Calculate the next Tx descriptor entry. */	entry = tp->cur_tx % NUM_TX_DESC;	tp->tx_info[entry].skb = skb;	if ((long)skb->data & 3) {			/* Must use alignment buffer. */		tp->tx_info[entry].mapping = 0;		memcpy(tp->tx_buf[entry], skb->data, skb->len);		outl(tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs),			 ioaddr + TxAddr0 + entry*4);	} else {		tp->tx_info[entry].mapping =			pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);		outl(tp->tx_info[entry].mapping, 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);	if (++tp->cur_tx - tp->dirty_tx < NUM_TX_DESC) {	/* Typical path */		netif_start_queue(dev);	} else {		tp->tx_full = 1;	}	dev->trans_start = jiffies;	if (rtl8129_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;	int status, link_changed = 0;	long ioaddr = dev->base_addr;	do {		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)  &&  inw(ioaddr+CSCR) & CSCR_LinkChangeBit)			link_changed = 1;		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 = 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 (rtl8129_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)|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 {					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++;				}				if (tp->tx_info[entry].mapping != 0) {					pci_unmap_single(tp->pdev,									 tp->tx_info[entry].mapping,									 tp->tx_info[entry].skb->len,									 PCI_DMA_TODEVICE);					tp->tx_info[entry].mapping = 0;				}				/* Free the original skb. */				dev_kfree_skb_irq(tp->tx_info[entry].skb);				tp->tx_info[entry].skb = NULL;				if (tp->tx_full) {					/* The ring is no longer full, wake the queue. */					tp->tx_full = 0;

⌨️ 快捷键说明

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