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

📄 ioc3-eth.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
 * if the auto negotiation has completed, we assume here that the DP83840 PHY * will time out at some point and just tell us what (didn't) happen.  For * complete coverage we only allow so many of the ticks at this level to run, * when this has expired we print a warning message and try another strategy. * This "other" strategy is to force the interface into various speed/duplex * configurations and we stop when we see a link-up condition before the * maximum number of "peek" ticks have occurred. * * Once a valid link status has been detected we configure the IOC3 to speak * the most efficient protocol we could get a clean link for.  The priority * for link configurations, highest first is: * *     100 Base-T Full Duplex *     100 Base-T Half Duplex *     10 Base-T Full Duplex *     10 Base-T Half Duplex * * We start a new timer now, after a successful auto negotiation status has * been detected.  This timer just waits for the link-up bit to get set in * the BMCR of the DP83840.  When this occurs we print a kernel log message * describing the link type in use and the fact that it is up. * * If a fatal error of some sort is signalled and detected in the interrupt * service routine, and the chip is reset, or the link is ifconfig'd down * and then back up, this entire process repeats itself all over again. */static int ioc3_try_next_permutation(struct ioc3_private *ip){	ip->sw_bmcr = mii_read(ip, MII_BMCR);	/* Downgrade from full to half duplex.  Only possible via ethtool.  */	if (ip->sw_bmcr & BMCR_FULLDPLX) {		ip->sw_bmcr &= ~BMCR_FULLDPLX;		mii_write(ip, MII_BMCR, ip->sw_bmcr);		return 0;	}	/* Downgrade from 100 to 10. */	if (ip->sw_bmcr & BMCR_SPEED100) {		ip->sw_bmcr &= ~BMCR_SPEED100;		mii_write(ip, MII_BMCR, ip->sw_bmcr);		return 0;	}	/* We've tried everything. */	return -1;}static voidioc3_display_link_mode(struct ioc3_private *ip){	char *tmode = "";	ip->sw_lpa = mii_read(ip, MII_LPA);	if (ip->sw_lpa & (LPA_100HALF | LPA_100FULL)) {		if (ip->sw_lpa & LPA_100FULL)			tmode = "100Mb/s, Full Duplex";		else			tmode = "100Mb/s, Half Duplex";	} else {		if (ip->sw_lpa & LPA_10FULL)			tmode = "10Mb/s, Full Duplex";		else			tmode = "10Mb/s, Half Duplex";	}	printk(KERN_INFO "%s: Link is up at %s.\n", ip->dev->name, tmode);}static voidioc3_display_forced_link_mode(struct ioc3_private *ip){	char *speed = "", *duplex = "";	ip->sw_bmcr = mii_read(ip, MII_BMCR);	if (ip->sw_bmcr & BMCR_SPEED100)		speed = "100Mb/s, ";	else		speed = "10Mb/s, ";	if (ip->sw_bmcr & BMCR_FULLDPLX)		duplex = "Full Duplex.\n";	else		duplex = "Half Duplex.\n";	printk(KERN_INFO "%s: Link has been forced up at %s%s", ip->dev->name,	       speed, duplex);}static int ioc3_set_link_modes(struct ioc3_private *ip){	struct ioc3 *ioc3 = ip->regs;	int full;	/*	 * All we care about is making sure the bigmac tx_cfg has a	 * proper duplex setting.	 */	if (ip->timer_state == arbwait) {		ip->sw_lpa = mii_read(ip, MII_LPA);		if (!(ip->sw_lpa & (LPA_10HALF | LPA_10FULL |		                    LPA_100HALF | LPA_100FULL)))			goto no_response;		if (ip->sw_lpa & LPA_100FULL)			full = 1;		else if (ip->sw_lpa & LPA_100HALF)			full = 0;		else if (ip->sw_lpa & LPA_10FULL)			full = 1;		else			full = 0;	} else {		/* Forcing a link mode. */		ip->sw_bmcr = mii_read(ip, MII_BMCR);		if (ip->sw_bmcr & BMCR_FULLDPLX)			full = 1;		else			full = 0;	}	if (full)		ip->emcr |= EMCR_DUPLEX;	else		ip->emcr &= ~EMCR_DUPLEX;	ioc3->emcr = ip->emcr;	ioc3->emcr;	return 0;no_response:	return 1;}static int is_lucent_phy(struct ioc3_private *ip){	unsigned short mr2, mr3;	int ret = 0;	mr2 = mii_read(ip, MII_PHYSID1);	mr3 = mii_read(ip, MII_PHYSID2);	if ((mr2 & 0xffff) == 0x0180 && ((mr3 & 0xffff) >> 10) == 0x1d) {		ret = 1;	}	return ret;}static void ioc3_timer(unsigned long data){	struct ioc3_private *ip = (struct ioc3_private *) data;	int restart_timer = 0;	ip->timer_ticks++;	switch (ip->timer_state) {	case arbwait:		/*		 * Only allow for 5 ticks, thats 10 seconds and much too		 * long to wait for arbitration to complete.		 */		if (ip->timer_ticks >= 10) {			/* Enter force mode. */	do_force_mode:			ip->sw_bmcr = mii_read(ip, MII_BMCR);			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"			       " trying force link mode\n", ip->dev->name);			ip->sw_bmcr = BMCR_SPEED100;			mii_write(ip, MII_BMCR, ip->sw_bmcr);			if (!is_lucent_phy(ip)) {				/*				 * OK, seems we need do disable the transceiver				 * for the first tick to make sure we get an				 * accurate link state at the second tick.				 */				ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);				ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);				mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);			}			ip->timer_state = ltrywait;			ip->timer_ticks = 0;			restart_timer = 1;		} else {			/* Anything interesting happen? */			ip->sw_bmsr = mii_read(ip, MII_BMSR);			if (ip->sw_bmsr & BMSR_ANEGCOMPLETE) {				int ret;				/* Just what we've been waiting for... */				ret = ioc3_set_link_modes(ip);				if (ret) {					/* Ooops, something bad happened, go to					 * force mode.					 *					 * XXX Broken hubs which don't support					 * XXX 802.3u auto-negotiation make this					 * XXX happen as well.					 */					goto do_force_mode;				}				/*				 * Success, at least so far, advance our state				 * engine.				 */				ip->timer_state = lupwait;				restart_timer = 1;			} else {				restart_timer = 1;			}		}		break;	case lupwait:		/*		 * Auto negotiation was successful and we are awaiting a		 * link up status.  I have decided to let this timer run		 * forever until some sort of error is signalled, reporting		 * a message to the user at 10 second intervals.		 */		ip->sw_bmsr = mii_read(ip, MII_BMSR);		if (ip->sw_bmsr & BMSR_LSTATUS) {			/*			 * Wheee, it's up, display the link mode in use and put			 * the timer to sleep.			 */			ioc3_display_link_mode(ip);			ip->timer_state = asleep;			restart_timer = 0;		} else {			if (ip->timer_ticks >= 10) {				printk(KERN_NOTICE "%s: Auto negotiation successful, link still "				       "not completely up.\n", ip->dev->name);				ip->timer_ticks = 0;				restart_timer = 1;			} else {				restart_timer = 1;			}		}		break;	case ltrywait:		/*		 * Making the timeout here too long can make it take		 * annoyingly long to attempt all of the link mode		 * permutations, but then again this is essentially		 * error recovery code for the most part.		 */		ip->sw_bmsr = mii_read(ip, MII_BMSR);		ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);		if (ip->timer_ticks == 1) {			if (!is_lucent_phy(ip)) {				/*				 * Re-enable transceiver, we'll re-enable the				 * transceiver next tick, then check link state				 * on the following tick.				 */				ip->sw_csconfig |= CSCONFIG_TCVDISAB;				mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);			}			restart_timer = 1;			break;		}		if (ip->timer_ticks == 2) {			if (!is_lucent_phy(ip)) {				ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);				mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);			}			restart_timer = 1;			break;		}		if (ip->sw_bmsr & BMSR_LSTATUS) {			/* Force mode selection success. */			ioc3_display_forced_link_mode(ip);			ioc3_set_link_modes(ip);  /* XXX error? then what? */			ip->timer_state = asleep;			restart_timer = 0;		} else {			if (ip->timer_ticks >= 4) { /* 6 seconds or so... */				int ret;				ret = ioc3_try_next_permutation(ip);				if (ret == -1) {					/*					 * Aieee, tried them all, reset the					 * chip and try all over again.					 */					printk(KERN_NOTICE "%s: Link down, "					       "cable problem?\n",					       ip->dev->name);					ioc3_init(ip);					return;				}				if (!is_lucent_phy(ip)) {					ip->sw_csconfig = mii_read(ip,					                    MII_CSCONFIG);					ip->sw_csconfig |= CSCONFIG_TCVDISAB;					mii_write(ip, MII_CSCONFIG,					          ip->sw_csconfig);				}				ip->timer_ticks = 0;				restart_timer = 1;			} else {				restart_timer = 1;			}		}		break;	case asleep:	default:		/* Can't happens.... */		printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "		       "one anyways!\n", ip->dev->name);		restart_timer = 0;		ip->timer_ticks = 0;		ip->timer_state = asleep; /* foo on you */		break;	};	if (restart_timer) {		ip->ioc3_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2s */		add_timer(&ip->ioc3_timer);	}}static voidioc3_start_auto_negotiation(struct ioc3_private *ip, struct ethtool_cmd *ep){	int timeout;	/* Read all of the registers we are interested in now. */	ip->sw_bmsr      = mii_read(ip, MII_BMSR);	ip->sw_bmcr      = mii_read(ip, MII_BMCR);	ip->sw_physid1   = mii_read(ip, MII_PHYSID1);	ip->sw_physid2   = mii_read(ip, MII_PHYSID2);	/* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */	ip->sw_advertise = mii_read(ip, MII_ADVERTISE);	if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {		/* Advertise everything we can support. */		if (ip->sw_bmsr & BMSR_10HALF)			ip->sw_advertise |= ADVERTISE_10HALF;		else			ip->sw_advertise &= ~ADVERTISE_10HALF;		if (ip->sw_bmsr & BMSR_10FULL)			ip->sw_advertise |= ADVERTISE_10FULL;		else			ip->sw_advertise &= ~ADVERTISE_10FULL;		if (ip->sw_bmsr & BMSR_100HALF)			ip->sw_advertise |= ADVERTISE_100HALF;		else			ip->sw_advertise &= ~ADVERTISE_100HALF;		if (ip->sw_bmsr & BMSR_100FULL)			ip->sw_advertise |= ADVERTISE_100FULL;		else			ip->sw_advertise &= ~ADVERTISE_100FULL;		mii_write(ip, MII_ADVERTISE, ip->sw_advertise);		/*		 * XXX Currently no IOC3 card I know off supports 100BaseT4,		 * XXX and this is because the DP83840 does not support it,		 * XXX changes XXX would need to be made to the tx/rx logic in		 * XXX the driver as well so I completely skip checking for it		 * XXX in the BMSR for now.		 */#ifdef AUTO_SWITCH_DEBUG		ASD(("%s: Advertising [ ", ip->dev->name));		if (ip->sw_advertise & ADVERTISE_10HALF)			ASD(("10H "));		if (ip->sw_advertise & ADVERTISE_10FULL)			ASD(("10F "));		if (ip->sw_advertise & ADVERTISE_100HALF)			ASD(("100H "));		if (ip->sw_advertise & ADVERTISE_100FULL)			ASD(("100F "));#endif		/* Enable Auto-Negotiation, this is usually on already... */		ip->sw_bmcr |= BMCR_ANENABLE;		mii_write(ip, MII_BMCR, ip->sw_bmcr);		/* Restart it to make sure it is going. */		ip->sw_bmcr |= BMCR_ANRESTART;		mii_write(ip, MII_BMCR, ip->sw_bmcr);		/* BMCR_ANRESTART self clears when the process has begun. */		timeout = 64;  /* More than enough. */		while (--timeout) {			ip->sw_bmcr = mii_read(ip, MII_BMCR);			if (!(ip->sw_bmcr & BMCR_ANRESTART))				break; /* got it. */			udelay(10);		}		if (!timeout) {			printk(KERN_ERR "%s: IOC3 would not start auto "			       "negotiation BMCR=0x%04x\n",			       ip->dev->name, ip->sw_bmcr);			printk(KERN_NOTICE "%s: Performing force link "			       "detection.\n", ip->dev->name);			goto force_link;		} else {			ip->timer_state = arbwait;		}	} else {force_link:		/*		 * Force the link up, trying first a particular mode.  Either		 * we are here at the request of ethtool or because the IOC3		 * would not start to autoneg.		 */		/*		 * Disable auto-negotiation in BMCR, enable the duplex and		 * speed setting, init the timer state machine, and fire it off.		 */		if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {			ip->sw_bmcr = BMCR_SPEED100;		} else {			if (ep->speed == SPEED_100)				ip->sw_bmcr = BMCR_SPEED100;			else				ip->sw_bmcr = 0;			if (ep->duplex == DUPLEX_FULL)				ip->sw_bmcr |= BMCR_FULLDPLX;		}		mii_write(ip, MII_BMCR, ip->sw_bmcr);		if (!is_lucent_phy(ip)) {			/*			 * OK, seems we need do disable the transceiver for the			 * first tick to make sure we get an accurate link			 * state at the second tick.			 */			ip->sw_csconfig = mii_read(ip, MII_CSCONFIG);			ip->sw_csconfig &= ~(CSCONFIG_TCVDISAB);			mii_write(ip, MII_CSCONFIG, ip->sw_csconfig);		}		ip->timer_state = ltrywait;	}	del_timer(&ip->ioc3_timer);	ip->timer_ticks = 0;	ip->ioc3_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */	ip->ioc3_timer.data = (unsigned long) ip;	ip->ioc3_timer.function = &ioc3_timer;	add_timer(&ip->ioc3_timer);}static int ioc3_mii_init(struct ioc3_private *ip){	int i, found;	u16 word;	found = 0;	spin_lock_irq(&ip->ioc3_lock);	for (i = 0; i < 32; i++) {		ip->phy = i;		word = mii_read(ip, 2);		if ((word != 0xffff) && (word != 0x0000)) {			found = 1;			break;			/* Found a PHY		*/		}	}	if (!found) {		spin_unlock_irq(&ip->ioc3_lock);		return -ENODEV;	}	ioc3_start_auto_negotiation(ip, NULL);		// XXX ethtool	spin_unlock_irq(&ip->ioc3_lock);	return 0;}static inline voidioc3_clean_rx_ring(struct ioc3_private *ip){	struct sk_buff *skb;	int i;	for (i = ip->rx_ci; i & 15; i++) {		ip->rx_skbs[ip->rx_pi] = ip->rx_skbs[ip->rx_ci];		ip->rxr[ip->rx_pi++] = ip->rxr[ip->rx_ci++];	}	ip->rx_pi &= 511;	ip->rx_ci &= 511;	for (i = ip->rx_ci; i != ip->rx_pi; i = (i+1) & 511) {		struct ioc3_erxbuf *rxb;		skb = ip->rx_skbs[i];		rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);		rxb->w0 = 0;	}}static inline voidioc3_clean_tx_ring(struct ioc3_private *ip){	struct sk_buff *skb;	int i;	for (i=0; i < 128; i++) {		skb = ip->tx_skbs[i];		if (skb) {			ip->tx_skbs[i] = NULL;			dev_kfree_skb_any(skb);		}		ip->txr[i].cmd = 0;	}	ip->tx_pi = 0;	ip->tx_ci = 0;}static voidioc3_free_rings(struct ioc3_private *ip){	struct sk_buff *skb;	int rx_entry, n_entry;	if (ip->txr) {		ioc3_clean_tx_ring(ip);		free_pages((unsigned long)ip->txr, 2);		ip->txr = NULL;	}	if (ip->rxr) {		n_entry = ip->rx_ci;		rx_entry = ip->rx_pi;		while (n_entry != rx_entry) {			skb = ip->rx_skbs[n_entry];			if (skb)				dev_kfree_skb_any(skb);			n_entry = (n_entry + 1) & 511;		}		free_page((unsigned long)ip->rxr);		ip->rxr = NULL;	}}static voidioc3_alloc_rings(struct net_device *dev, struct ioc3_private *ip,		 struct ioc3 *ioc3){	struct ioc3_erxbuf *rxb;	unsigned long *rxr;	int i;	if (ip->rxr == NULL) {		/* Allocate and initialize rx ring.  4kb = 512 entries  */		ip->rxr = (unsigned long *) get_free_page(GFP_ATOMIC);		rxr = (unsigned long *) ip->rxr;		if (!rxr)			printk("ioc3_alloc_rings(): get_free_page() failed!\n");		/* Now the rx buffers.  The RX ring may be larger but		   we only allocate 16 buffers for now.  Need to tune		   this for performance and memory later.  */		for (i = 0; i < RX_BUFFS; i++) {			struct sk_buff *skb;			skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);			if (!skb) {				show_free_areas();				continue;			}			ip->rx_skbs[i] = skb;			skb->dev = dev;			/* Because we reserve afterwards. */			skb_put(skb, (1664 + RX_OFFSET));			rxb = (struct ioc3_erxbuf *) skb->data;			rxr[i] = (0xa5UL << 56)				| ((unsigned long) rxb & TO_PHYS_MASK);			skb_reserve(skb, RX_OFFSET);		}		ip->rx_ci = 0;		ip->rx_pi = RX_BUFFS;	}	if (ip->txr == NULL) {		/* Allocate and initialize tx rings.  16kb = 128 bufs.  */		ip->txr = (struct ioc3_etxd *)__get_free_pages(GFP_KERNEL, 2);		if (!ip->txr)			printk("ioc3_alloc_rings(): get_free_page() failed!\n");		ip->tx_pi = 0;		ip->tx_ci = 0;	}}static voidioc3_init_rings(struct net_device *dev, struct ioc3_private *ip,	        struct ioc3 *ioc3){	unsigned long ring;	ioc3_free_rings(ip);

⌨️ 快捷键说明

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