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

📄 sunhme.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	BB_PUT_BIT(hp, tregs, 0);	BB_PUT_BIT(hp, tregs, 1);	BB_PUT_BIT(hp, tregs, 0);	BB_PUT_BIT(hp, tregs, 1);	/* Give it the PHY address. */	tmp = (hp->paddr & 0xff);	for (i = 4; i >= 0; i--)		BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1));	/* Tell it what register we will be writing. */	tmp = (reg & 0xff);	for (i = 4; i >= 0; i--)		BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1));	/* Tell it to become ready for the bits. */	BB_PUT_BIT(hp, tregs, 1);	BB_PUT_BIT(hp, tregs, 0);	for (i = 15; i >= 0; i--)		BB_PUT_BIT(hp, tregs, ((value >> i) & 1));	/* Close down the MIF BitBang outputs. */	hme_write32(hp, tregs + TCVR_BBOENAB, 0);}#define TCVR_READ_TRIES   16static int happy_meal_tcvr_read(struct happy_meal *hp,				unsigned long tregs, int reg){	int tries = TCVR_READ_TRIES;	int retval;	ASD(("happy_meal_tcvr_read: reg=0x%02x ", reg));	if (hp->tcvr_type == none) {		ASD(("no transceiver, value=TCVR_FAILURE\n"));		return TCVR_FAILURE;	}	if (!(hp->happy_flags & HFLAG_FENABLE)) {		ASD(("doing bit bang\n"));		return happy_meal_bb_read(hp, tregs, reg);	}	hme_write32(hp, tregs + TCVR_FRAME,		    (FRAME_READ | (hp->paddr << 23) | ((reg & 0xff) << 18)));	while (!(hme_read32(hp, tregs + TCVR_FRAME) & 0x10000) && --tries)		udelay(20);	if (!tries) {		printk(KERN_ERR "happy meal: Aieee, transceiver MIF read bolixed\n");		return TCVR_FAILURE;	}	retval = hme_read32(hp, tregs + TCVR_FRAME) & 0xffff;	ASD(("value=%04x\n", retval));	return retval;}#define TCVR_WRITE_TRIES  16static void happy_meal_tcvr_write(struct happy_meal *hp,				  unsigned long tregs, int reg,				  unsigned short value){	int tries = TCVR_WRITE_TRIES;		ASD(("happy_meal_tcvr_write: reg=0x%02x value=%04x\n", reg, value));	/* Welcome to Sun Microsystems, can I take your order please? */	if (!hp->happy_flags & HFLAG_FENABLE)		return happy_meal_bb_write(hp, tregs, reg, value);	/* Would you like fries with that? */	hme_write32(hp, tregs + TCVR_FRAME,		    (FRAME_WRITE | (hp->paddr << 23) |		     ((reg & 0xff) << 18) | (value & 0xffff)));	while (!(hme_read32(hp, tregs + TCVR_FRAME) & 0x10000) && --tries)		udelay(20);	/* Anything else? */	if (!tries)		printk(KERN_ERR "happy meal: Aieee, transceiver MIF write bolixed\n");	/* Fifty-two cents is your change, have a nice day. */}/* Auto negotiation.  The scheme is very simple.  We have a timer routine * that keeps watching the auto negotiation process as it progresses. * The DP83840 is first told to start doing it's thing, we set up the time * and place the timer state machine in it's initial state. * * Here the timer peeks at the DP83840 status registers at each click to see * 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 BigMAC and * the rest of the Happy Meal 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 try_next_permutation(struct happy_meal *hp, unsigned long tregs){	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);	/* Downgrade from full to half duplex.  Only possible	 * via ethtool.	 */	if (hp->sw_bmcr & BMCR_FULLDPLX) {		hp->sw_bmcr &= ~(BMCR_FULLDPLX);		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);		return 0;	}	/* Downgrade from 100 to 10. */	if (hp->sw_bmcr & BMCR_SPEED100) {		hp->sw_bmcr &= ~(BMCR_SPEED100);		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);		return 0;	}	/* We've tried everything. */	return -1;}static void display_link_mode(struct happy_meal *hp, unsigned long tregs){	printk(KERN_INFO "%s: Link is up using ", hp->dev->name);	if (hp->tcvr_type == external)		printk("external ");	else		printk("internal ");	printk("transceiver at ");	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);	if (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) {		if (hp->sw_lpa & LPA_100FULL)			printk("100Mb/s, Full Duplex.\n");		else			printk("100Mb/s, Half Duplex.\n");	} else {		if (hp->sw_lpa & LPA_10FULL)			printk("10Mb/s, Full Duplex.\n");		else			printk("10Mb/s, Half Duplex.\n");	}}static void display_forced_link_mode(struct happy_meal *hp, unsigned long tregs){	printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name);	if (hp->tcvr_type == external)		printk("external ");	else		printk("internal ");	printk("transceiver at ");	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);	if (hp->sw_bmcr & BMCR_SPEED100)		printk("100Mb/s, ");	else		printk("10Mb/s, ");	if (hp->sw_bmcr & BMCR_FULLDPLX)		printk("Full Duplex.\n");	else		printk("Half Duplex.\n");}static int set_happy_link_modes(struct happy_meal *hp, unsigned long tregs){	int full;	/* All we care about is making sure the bigmac tx_cfg has a	 * proper duplex setting.	 */	if (hp->timer_state == arbwait) {		hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);		if (!(hp->sw_lpa & (LPA_10HALF | LPA_10FULL | LPA_100HALF | LPA_100FULL)))			goto no_response;		if (hp->sw_lpa & LPA_100FULL)			full = 1;		else if (hp->sw_lpa & LPA_100HALF)			full = 0;		else if (hp->sw_lpa & LPA_10FULL)			full = 1;		else			full = 0;	} else {		/* Forcing a link mode. */		hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);		if (hp->sw_bmcr & BMCR_FULLDPLX)			full = 1;		else			full = 0;	}	/* Before changing other bits in the tx_cfg register, and in	 * general any of other the TX config registers too, you	 * must:	 * 1) Clear Enable	 * 2) Poll with reads until that bit reads back as zero	 * 3) Make TX configuration changes	 * 4) Set Enable once more	 */	hme_write32(hp, hp->bigmacregs + BMAC_TXCFG,		    hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) &		    ~(BIGMAC_TXCFG_ENABLE));	while (hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) & BIGMAC_TXCFG_ENABLE)		barrier();	if (full) {		hp->happy_flags |= HFLAG_FULL;		hme_write32(hp, hp->bigmacregs + BMAC_TXCFG,			    hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) |			    BIGMAC_TXCFG_FULLDPLX);	} else {		hp->happy_flags &= ~(HFLAG_FULL);		hme_write32(hp, hp->bigmacregs + BMAC_TXCFG,			    hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) &			    ~(BIGMAC_TXCFG_FULLDPLX));	}	hme_write32(hp, hp->bigmacregs + BMAC_TXCFG,		    hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) |		    BIGMAC_TXCFG_ENABLE);	return 0;no_response:	return 1;}static int happy_meal_init(struct happy_meal *hp, int from_irq);static int is_lucent_phy(struct happy_meal *hp){	unsigned long tregs = hp->tcvregs;	unsigned short mr2, mr3;	int ret = 0;	mr2 = happy_meal_tcvr_read(hp, tregs, 2);	mr3 = happy_meal_tcvr_read(hp, tregs, 3);	if ((mr2 & 0xffff) == 0x0180 &&	    ((mr3 & 0xffff) >> 10) == 0x1d) {#if 0		printk("HMEDEBUG: Lucent PHY detected.\n");#endif		ret = 1;	}	return ret;}static void happy_meal_timer(unsigned long data){	struct happy_meal *hp = (struct happy_meal *) data;	unsigned long tregs = hp->tcvregs;	int restart_timer = 0;	hp->timer_ticks++;	switch(hp->timer_state) {	case arbwait:		/* Only allow for 5 ticks, thats 10 seconds and much too		 * long to wait for arbitration to complete.		 */		if (hp->timer_ticks >= 10) {			/* Enter force mode. */	do_force_mode:			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful, trying force link mode\n",			       hp->dev->name);			hp->sw_bmcr = BMCR_SPEED100;			happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);			if (!is_lucent_phy(hp)) {				/* 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.				 */				hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);				hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);				happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig);			}			hp->timer_state = ltrywait;			hp->timer_ticks = 0;			restart_timer = 1;		} else {			/* Anything interesting happen? */			hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);			if (hp->sw_bmsr & BMSR_ANEGCOMPLETE) {				int ret;				/* Just what we've been waiting for... */				ret = set_happy_link_modes(hp, tregs);				if (ret) {					/* Ooops, something bad happened, go to force					 * mode.					 *					 * XXX Broken hubs which don't support 802.3u					 * XXX auto-negotiation make this happen as well.					 */					goto do_force_mode;				}				/* Success, at least so far, advance our state engine. */				hp->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.		 */		hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);		if (hp->sw_bmsr & BMSR_LSTATUS) {			/* Wheee, it's up, display the link mode in use and put			 * the timer to sleep.			 */			display_link_mode(hp, tregs);			hp->timer_state = asleep;			restart_timer = 0;		} else {			if (hp->timer_ticks >= 10) {				printk(KERN_NOTICE "%s: Auto negotiation successful, link still "				       "not completely up.\n", hp->dev->name);				hp->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.		 */		hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);		hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);		if (hp->timer_ticks == 1) {			if (!is_lucent_phy(hp)) {				/* Re-enable transceiver, we'll re-enable the transceiver next				 * tick, then check link state on the following tick.				 */				hp->sw_csconfig |= CSCONFIG_TCVDISAB;				happy_meal_tcvr_write(hp, tregs,						      DP83840_CSCONFIG, hp->sw_csconfig);			}			restart_timer = 1;			break;		}		if (hp->timer_ticks == 2) {			if (!is_lucent_phy(hp)) {				hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);				happy_meal_tcvr_write(hp, tregs,						      DP83840_CSCONFIG, hp->sw_csconfig);			}			restart_timer = 1;			break;		}		if (hp->sw_bmsr & BMSR_LSTATUS) {			/* Force mode selection success. */			display_forced_link_mode(hp, tregs);			set_happy_link_modes(hp, tregs); /* XXX error? then what? */			hp->timer_state = asleep;			restart_timer = 0;		} else {			if (hp->timer_ticks >= 4) { /* 6 seconds or so... */				int ret;				ret = try_next_permutation(hp, tregs);				if (ret == -1) {					/* Aieee, tried them all, reset the					 * chip and try all over again.					 */					/* Let the user know... */					printk(KERN_NOTICE "%s: Link down, cable problem?\n",					       hp->dev->name);					ret = happy_meal_init(hp, 0);					if (ret) {						/* ho hum... */						printk(KERN_ERR "%s: Error, cannot re-init the "						       "Happy Meal.\n", hp->dev->name);					}					return;				}				if (!is_lucent_phy(hp)) {					hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,									       DP83840_CSCONFIG);					hp->sw_csconfig |= CSCONFIG_TCVDISAB;					happy_meal_tcvr_write(hp, tregs,							      DP83840_CSCONFIG, hp->sw_csconfig);				}				hp->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",		       hp->dev->name);		restart_timer = 0;		hp->timer_ticks = 0;		hp->timer_state = asleep; /* foo on you */		break;	};	if (restart_timer) {		hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */		add_timer(&hp->happy_timer);	}}#define TX_RESET_TRIES     32#define RX_RESET_TRIES     32static void happy_meal_tx_reset(struct happy_meal *hp, unsigned long bregs){	int tries = TX_RESET_TRIES;	HMD(("happy_meal_tx_reset: reset, "));	/* Would you like to try our SMCC Delux? */	hme_write32(hp, bregs + BMAC_TXSWRESET, 0);

⌨️ 快捷键说明

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