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

📄 8139too.c

📁 rtl8139网卡
💻 C
📖 第 1 页 / 共 5 页
字号:
enum TwisterParamVals {	PARA78_default	= 0x78fa8388,	PARA7c_default	= 0xcb38de43,	/* param[0][3] */	PARA7c_xxx	= 0xcb38de43,};static const unsigned long param[4][4] = {	{0xcb39de43, 0xcb39ce43, 0xfb38de03, 0xcb38de43},	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},	{0xcb39de43, 0xcb39ce43, 0xcb39ce83, 0xcb39ce83},	{0xbb39de43, 0xbb39ce43, 0xbb39ce83, 0xbb39ce83}};static void rtl8139_tune_twister (struct net_device *dev,				  struct rtl8139_private *tp){	int linkcase;	void __iomem *ioaddr = tp->mmio_addr;	/* This is a complicated state machine to configure the "twister" for	   impedance/echos based on the cable length.	   All of this is magic and undocumented.	 */	switch (tp->twistie) {	case 1:		if (RTL_R16 (CSCR) & CSCR_LinkOKBit) {			/* We have link beat, let us tune the twister. */			RTL_W16 (CSCR, CSCR_LinkDownOffCmd);			tp->twistie = 2;	/* Change to state 2. */			next_tick = HZ / 10;		} else {			/* Just put in some reasonable defaults for when beat returns. */			RTL_W16 (CSCR, CSCR_LinkDownCmd);			RTL_W32 (FIFOTMS, 0x20);	/* Turn on cable test mode. */			RTL_W32 (PARA78, PARA78_default);			RTL_W32 (PARA7c, PARA7c_default);			tp->twistie = 0;	/* Bail from future actions. */		}		break;	case 2:		/* Read how long it took to hear the echo. */		linkcase = RTL_R16 (CSCR) & CSCR_LinkStatusBits;		if (linkcase == 0x7000)			tp->twist_row = 3;		else if (linkcase == 0x3000)			tp->twist_row = 2;		else if (linkcase == 0x1000)			tp->twist_row = 1;		else			tp->twist_row = 0;		tp->twist_col = 0;		tp->twistie = 3;	/* Change to state 2. */		next_tick = HZ / 10;		break;	case 3:		/* Put out four tuning parameters, one per 100msec. */		if (tp->twist_col == 0)			RTL_W16 (FIFOTMS, 0);		RTL_W32 (PARA7c, param[(int) tp->twist_row]			 [(int) tp->twist_col]);		next_tick = HZ / 10;		if (++tp->twist_col >= 4) {			/* For short cables we are done.			   For long cables (row == 3) check for mistune. */			tp->twistie =			    (tp->twist_row == 3) ? 4 : 0;		}		break;	case 4:		/* Special case for long cables: check for mistune. */		if ((RTL_R16 (CSCR) &		     CSCR_LinkStatusBits) == 0x7000) {			tp->twistie = 0;			break;		} else {			RTL_W32 (PARA7c, 0xfb38de03);			tp->twistie = 5;			next_tick = HZ / 10;		}		break;	case 5:		/* Retune for shorter cable (column 2). */		RTL_W32 (FIFOTMS, 0x20);		RTL_W32 (PARA78, PARA78_default);		RTL_W32 (PARA7c, PARA7c_default);		RTL_W32 (FIFOTMS, 0x00);		tp->twist_row = 2;		tp->twist_col = 0;		tp->twistie = 3;		next_tick = HZ / 10;		break;	default:		/* do nothing */		break;	}}#endif /* CONFIG_8139TOO_TUNE_TWISTER */static inline void rtl8139_thread_iter (struct net_device *dev,				 struct rtl8139_private *tp,				 void __iomem *ioaddr){	int mii_lpa;	mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA);	if (!tp->mii.force_media && mii_lpa != 0xffff) {		int duplex = (mii_lpa & LPA_100FULL)		    || (mii_lpa & 0x01C0) == 0x0040;		if (tp->mii.full_duplex != duplex) {			tp->mii.full_duplex = duplex;			if (mii_lpa) {				printk (KERN_INFO					"%s: Setting %s-duplex based on MII #%d link"					" partner ability of %4.4x.\n",					dev->name,					tp->mii.full_duplex ? "full" : "half",					tp->phys[0], mii_lpa);			} else {				printk(KERN_INFO"%s: media is unconnected, link down, or incompatible connection\n",				       dev->name);			}#if 0			RTL_W8 (Cfg9346, Cfg9346_Unlock);			RTL_W8 (Config1, tp->mii.full_duplex ? 0x60 : 0x20);			RTL_W8 (Cfg9346, Cfg9346_Lock);#endif		}	}	next_tick = HZ * 60;	rtl8139_tune_twister (dev, tp);	DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",		 dev->name, RTL_R16 (NWayLPAR));	DPRINTK ("%s:  Other registers are IntMask %4.4x IntStatus %4.4x\n",		 dev->name, RTL_R16 (IntrMask), RTL_R16 (IntrStatus));	DPRINTK ("%s:  Chip config %2.2x %2.2x.\n",		 dev->name, RTL_R8 (Config0),		 RTL_R8 (Config1));}static void rtl8139_thread (struct work_struct *work){	struct rtl8139_private *tp =		container_of(work, struct rtl8139_private, thread.work);	struct net_device *dev = tp->mii.dev;	unsigned long thr_delay = next_tick;	rtnl_lock();	if (!netif_running(dev))		goto out_unlock;	if (tp->watchdog_fired) {		tp->watchdog_fired = 0;		rtl8139_tx_timeout_task(work);	} else		rtl8139_thread_iter(dev, tp, tp->mmio_addr);	if (tp->have_thread)		schedule_delayed_work(&tp->thread, thr_delay);out_unlock:	rtnl_unlock ();}static void rtl8139_start_thread(struct rtl8139_private *tp){	tp->twistie = 0;	if (tp->chipset == CH_8139_K)		tp->twistie = 1;	else if (tp->drv_flags & HAS_LNK_CHNG)		return;	tp->have_thread = 1;	tp->watchdog_fired = 0;	schedule_delayed_work(&tp->thread, next_tick);}static inline void rtl8139_tx_clear (struct rtl8139_private *tp){	tp->cur_tx = 0;	tp->dirty_tx = 0;	/* XXX account for unsent Tx packets in tp->stats.tx_dropped */}static void rtl8139_tx_timeout_task (struct work_struct *work){	struct rtl8139_private *tp =		container_of(work, struct rtl8139_private, thread.work);	struct net_device *dev = tp->mii.dev;	void __iomem *ioaddr = tp->mmio_addr;	int i;	u8 tmp8;	printk (KERN_DEBUG "%s: Transmit timeout, status %2.2x %4.4x %4.4x "		"media %2.2x.\n", dev->name, RTL_R8 (ChipCmd),		RTL_R16(IntrStatus), RTL_R16(IntrMask), RTL_R8(MediaStatus));	/* Emit info to figure out what went wrong. */	printk (KERN_DEBUG "%s: Tx queue start entry %ld  dirty entry %ld.\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.8lx.%s\n",			dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),			i == tp->dirty_tx % NUM_TX_DESC ?				" (queue head)" : "");	tp->xstats.tx_timeouts++;	/* disable Tx ASAP, if not already */	tmp8 = RTL_R8 (ChipCmd);	if (tmp8 & CmdTxEnb)		RTL_W8 (ChipCmd, CmdRxEnb);	spin_lock_bh(&tp->rx_lock);	/* Disable interrupts by clearing the interrupt mask. */	RTL_W16 (IntrMask, 0x0000);	/* Stop a shared interrupt from scavenging while we are. */	spin_lock_irq(&tp->lock);	rtl8139_tx_clear (tp);	spin_unlock_irq(&tp->lock);	/* ...and finally, reset everything */	if (netif_running(dev)) {		rtl8139_hw_start (dev);		netif_wake_queue (dev);	}	spin_unlock_bh(&tp->rx_lock);}static void rtl8139_tx_timeout (struct net_device *dev){	struct rtl8139_private *tp = netdev_priv(dev);	tp->watchdog_fired = 1;	if (!tp->have_thread) {		INIT_DELAYED_WORK(&tp->thread, rtl8139_thread);		schedule_delayed_work(&tp->thread, next_tick);	}}static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev){	struct rtl8139_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->mmio_addr;	unsigned int entry;	unsigned int len = skb->len;	unsigned long flags;	/* Calculate the next Tx descriptor entry. */	entry = tp->cur_tx % NUM_TX_DESC;	/* Note: the chip doesn't have auto-pad! */	if (likely(len < TX_BUF_SIZE)) {		if (len < ETH_ZLEN)			memset(tp->tx_buf[entry], 0, ETH_ZLEN);		skb_copy_and_csum_dev(skb, tp->tx_buf[entry]);		dev_kfree_skb(skb);	} else {		dev_kfree_skb(skb);		tp->stats.tx_dropped++;		return 0;	}	spin_lock_irqsave(&tp->lock, flags);	RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),		   tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));	dev->trans_start = jiffies;	tp->cur_tx++;	wmb();	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)		netif_stop_queue (dev);	spin_unlock_irqrestore(&tp->lock, flags);	if (netif_msg_tx_queued(tp))		printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",			dev->name, len, entry);	return 0;}static void rtl8139_tx_interrupt (struct net_device *dev,				  struct rtl8139_private *tp,				  void __iomem *ioaddr){	unsigned long dirty_tx, tx_left;	assert (dev != NULL);	assert (ioaddr != NULL);	dirty_tx = tp->dirty_tx;	tx_left = tp->cur_tx - dirty_tx;	while (tx_left > 0) {		int entry = dirty_tx % NUM_TX_DESC;		int txstatus;		txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));		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 (netif_msg_tx_err(tp))				printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",					dev->name, txstatus);			tp->stats.tx_errors++;			if (txstatus & TxAborted) {				tp->stats.tx_aborted_errors++;				RTL_W32 (TxConfig, TxClearAbt);				RTL_W16 (IntrStatus, TxErr);				wmb();			}			if (txstatus & TxCarrierLost)				tp->stats.tx_carrier_errors++;			if (txstatus & TxOutOfWindow)				tp->stats.tx_window_errors++;		} 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;			tp->stats.tx_bytes += txstatus & 0x7ff;			tp->stats.tx_packets++;		}		dirty_tx++;		tx_left--;	}#ifndef RTL8139_NDEBUG	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",		        dev->name, dirty_tx, tp->cur_tx);		dirty_tx += NUM_TX_DESC;	}#endif /* RTL8139_NDEBUG */	/* only wake the queue if we did work, and the queue is stopped */	if (tp->dirty_tx != dirty_tx) {		tp->dirty_tx = dirty_tx;		mb();		netif_wake_queue (dev);	}}/* TODO: clean this up!  Rx reset need not be this intensive */static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,			    struct rtl8139_private *tp, void __iomem *ioaddr){	u8 tmp8;#ifdef CONFIG_8139_OLD_RX_RESET	int tmp_work;#endif	if (netif_msg_rx_err (tp))		printk(KERN_DEBUG "%s: Ethernet frame had errors, status %8.8x.\n",			dev->name, rx_status);	tp->stats.rx_errors++;	if (!(rx_status & RxStatusOK)) {		if (rx_status & RxTooLong) {			DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n",			 	dev->name, rx_status);			/* A.C.: The chip hangs here. */		}		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++;	} else {		tp->xstats.rx_lost_in_ring++;	}#ifndef CONFIG_8139_OLD_RX_RESET	tmp8 = RTL_R8 (ChipCmd);	RTL_W8 (ChipCmd, tmp8 & ~CmdRxEnb);	RTL_W8 (ChipCmd, tmp8);	RTL_W32 (RxConfig, tp->rx_config);	tp->cur_rx = 0;#else	/* Reset the receiver, based on RealTek recommendation. (Bug?) */	/* disable receive */	RTL_W8_F (ChipCmd, CmdTxEnb);	tmp_work = 200;	while (--tmp_work > 0) {		udelay(1);		tmp8 = RTL_R8 (ChipCmd);		if (!(tmp8 & CmdRxEnb))			break;	}	if (tmp_work <= 0)		printk (KERN_WARNING PFX "rx stop wait too long\n");	/* restart receive */	tmp_work = 200;	while (--tmp_work > 0) {		RTL_W8_F (ChipCmd, CmdRxEnb | CmdTxEnb);		udelay(1);		tmp8 = RTL_R8 (ChipCmd);		if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb))			break;	}	if (tmp_work <= 0)		printk (KERN_WARNING PFX "tx/rx enable wait too long\n");	/* and reinitialize all rx related registers */	RTL_W8_F (Cfg9346, Cfg9346_Unlock);	/* Must enable Tx/Rx before setting transfer thresholds! */	RTL_W8 (ChipCmd, CmdRxEnb | CmdTxEnb);	tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;	RTL_W32 (RxConfig, tp->rx_config);	tp->cur_rx = 0;	DPRINTK("init buffer addresses\n");	/* Lock Config[01234] and BMCR register writes */	RTL_W8 (Cfg9346, Cfg9346_Lock);	/* init Rx ring buffer DMA address */	RTL_W32_F (RxBuf, tp->rx_ring_dma);	/* A.C.: Reset the multicast list. */	__set_rx_mode (dev);#endif}#if RX_BUF_IDX == 3static __inline__ void wrap_copy(struct sk_buff *skb, const unsigned char *ring,				 u32 offset, unsigned int size){	u32 left = RX_BUF_LEN - offset;	if (size > left) {		skb_copy_to_linear_data(skb, ring + offset, left);		skb_copy_to_linear_data_offset(skb, left, ring, size - left);	} else		skb_copy_to_linear_data(skb, ring + offset, size);}#endifstatic void rtl8139_isr_ack(struct rtl8139_private *tp){	void __iomem *ioaddr = tp->mmio_addr;	u16 status;	status = RTL_R16 (IntrStatus) & RxAckBits;	/* Clear out errors and receive interrupts */	if (likely(status != 0)) {		if (unlikely(status & (RxFIFOOver | RxOverflow))) {			tp->stats.rx_errors++;			if (status & RxFIFOOver)				tp->stats.rx_fifo_errors++;		}		RTL_W16_F (IntrStatus, RxAckBits);	}}static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp,		      int budget){	void __iomem *ioaddr = tp->mmio_addr;	int received = 0;	unsigned char *rx_ring = tp->rx_ring;	unsigned int cur_rx = tp->cur_rx;	unsigned int rx_size = 0;

⌨️ 快捷键说明

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