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

📄 sunhme.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
			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->tx_cfg,		    hme_read32(hp, &hp->bigmacregs->tx_cfg) &		    ~(BIGMAC_TXCFG_ENABLE));	while(hme_read32(hp, &hp->bigmacregs->tx_cfg) & BIGMAC_TXCFG_ENABLE)		barrier();	if(full) {		hp->happy_flags |= HFLAG_FULL;		hme_write32(hp, &hp->bigmacregs->tx_cfg,			    hme_read32(hp, &hp->bigmacregs->tx_cfg) |			    BIGMAC_TXCFG_FULLDPLX);	} else {		hp->happy_flags &= ~(HFLAG_FULL);		hme_write32(hp, &hp->bigmacregs->tx_cfg,			    hme_read32(hp, &hp->bigmacregs->tx_cfg) &			    ~(BIGMAC_TXCFG_FULLDPLX));	}	hme_write32(hp, &hp->bigmacregs->tx_cfg,		    hme_read32(hp, &hp->bigmacregs->tx_cfg) |		    BIGMAC_TXCFG_ENABLE);	return 0;no_response:	return 1;}static int happy_meal_init(struct happy_meal *hp, int from_irq);static void happy_meal_timer(unsigned long data){	struct happy_meal *hp = (struct happy_meal *) data;	struct hmeal_tcvregs *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("%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);			/* 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("%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) {			/* 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) {			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("%s: Link down, cable problem?\n",					       hp->dev->name);					ret = happy_meal_init(hp, 0);					if(ret) {						/* ho hum... */						printk("%s: Error, cannot re-init the "						       "Happy Meal.\n", hp->dev->name);					}					return;				}				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("%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 inline void happy_meal_tx_reset(struct happy_meal *hp,				       struct hmeal_bigmacregs *bregs){	int tries = TX_RESET_TRIES;	HMD(("happy_meal_tx_reset: reset, "));	/* Would you like to try our SMCC Delux? */	hme_write32(hp, &bregs->tx_swreset, 0);	while((hme_read32(hp, &bregs->tx_swreset) & 1) && --tries)		udelay(20);	/* Lettuce, tomato, buggy hardware (no extra charge)? */	if(!tries)		printk("happy meal: Transceiver BigMac ATTACK!");	/* Take care. */	HMD(("done\n"));}static inline void happy_meal_rx_reset(struct happy_meal *hp,				       struct hmeal_bigmacregs *bregs){	int tries = RX_RESET_TRIES;	HMD(("happy_meal_rx_reset: reset, "));	/* We have a special on GNU/Viking hardware bugs today. */	hme_write32(hp, &bregs->rx_swreset, 0);	while((hme_read32(hp, &bregs->rx_swreset) & 1) && --tries)		udelay(20);	/* Will that be all? */	if(!tries)		printk("happy meal: Receiver BigMac ATTACK!");	/* Don't forget your vik_1137125_wa.  Have a nice day. */	HMD(("done\n"));}#define STOP_TRIES         16static inline void happy_meal_stop(struct happy_meal *hp,				   struct hmeal_gregs *gregs){	int tries = STOP_TRIES;	HMD(("happy_meal_stop: reset, "));	/* We're consolidating our STB products, it's your lucky day. */	hme_write32(hp, &gregs->sw_reset, GREG_RESET_ALL);	while(hme_read32(hp, &gregs->sw_reset) && --tries)		udelay(20);	/* Come back next week when we are "Sun Microelectronics". */	if(!tries)		printk("happy meal: Fry guys.");	/* Remember: "Different name, same old buggy as shit hardware." */	HMD(("done\n"));}static void happy_meal_get_counters(struct happy_meal *hp,				    struct hmeal_bigmacregs *bregs){	struct net_device_stats *stats = &hp->net_stats;	stats->rx_crc_errors += hme_read32(hp, &bregs->rcrce_ctr);	hme_write32(hp, &bregs->rcrce_ctr, 0);	stats->rx_frame_errors += hme_read32(hp, &bregs->unale_ctr);	hme_write32(hp, &bregs->unale_ctr, 0);	stats->rx_length_errors += hme_read32(hp, &bregs->gle_ctr);	hme_write32(hp, &bregs->gle_ctr, 0);	stats->tx_aborted_errors += hme_read32(hp, &bregs->ex_ctr);	stats->collisions +=		(hme_read32(hp, &bregs->ex_ctr) +		 hme_read32(hp, &bregs->lt_ctr));	hme_write32(hp, &bregs->ex_ctr, 0);	hme_write32(hp, &bregs->lt_ctr, 0);}static inline void happy_meal_poll_start(struct happy_meal *hp,					 struct hmeal_tcvregs *tregs){	unsigned long tmp;	int speed;	ASD(("happy_meal_poll_start: "));	if(!(hp->happy_flags & HFLAG_POLLENABLE)) {		HMD(("polling disabled, return\n"));		return;	}	/* Start the MIF polling on the external transceiver. */	ASD(("polling on, "));	tmp = hme_read32(hp, &tregs->cfg);	tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);	tmp |= ((hp->paddr & 0x1f) << 10);	tmp |= (TCV_PADDR_ETX << 3);	tmp |= TCV_CFG_PENABLE;	hme_write32(hp, &tregs->cfg, tmp);	/* Let the bits set. */	udelay(200);	/* We are polling now. */	ASD(("now polling, "));	hp->happy_flags |= HFLAG_POLL;	/* Clear the poll flags, get the basic status as of now. */	hp->poll_flag = 0;	hp->poll_data = tregs->status >> 16;	if(hp->happy_flags & HFLAG_AUTO)		speed = hp->auto_speed;	else		speed = hp->forced_speed;	/* Listen only for the MIF interrupts we want to hear. */	ASD(("mif ints on, "));	if(speed == 100)		hme_write32(hp, &tregs->int_mask, 0xfffb);	else		hme_write32(hp, &tregs->int_mask, 0xfff9);	ASD(("done\n"));}static inline void happy_meal_poll_stop(struct happy_meal *hp,					struct hmeal_tcvregs *tregs){	ASD(("happy_meal_poll_stop: "));	/* If polling disabled or not polling already, nothing to do. */	if((hp->happy_flags & (HFLAG_POLLENABLE | HFLAG_POLL)) !=	   (HFLAG_POLLENABLE | HFLAG_POLL)) {		HMD(("not polling, return\n"));		return;	}	/* Shut up the MIF. */	ASD(("were polling, mif ints off, "));	hme_write32(hp, &tregs->int_mask, 0xffff);	/* Turn off polling. */	ASD(("polling off, "));	hme_write32(hp, &tregs->cfg,		    hme_read32(hp, &tregs->cfg) & ~(TCV_CFG_PENABLE));	/* We are no longer polling. */	hp->happy_flags &= ~(HFLAG_POLL);	/* Let the bits set. */	udelay(200);	ASD(("done\n"));}/* Only Sun can take such nice parts and fuck up the programming interface * like this.  Good job guys... */#define TCVR_RESET_TRIES       16 /* It should reset quickly        */#define TCVR_UNISOLATE_TRIES   32 /* Dis-isolation can take longer. */static int happy_meal_tcvr_reset(struct happy_meal *hp,				 struct hmeal_tcvregs *tregs){	unsigned long tconfig;	int result, tries = TCVR_RESET_TRIES;	tconfig = hme_read32(hp, &tregs->cfg);	ASD(("happy_meal_tcvr_reset: tcfg<%08lx> ", tconfig));	if(hp->tcvr_type == external) {		ASD(("external<"));		hme_write32(hp, &tregs->cfg, tconfig & ~(TCV_CFG_PSELECT));		hp->tcvr_type = internal;		hp->paddr = TCV_PADDR_ITX;		ASD(("ISOLATE,"));		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,				      (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);		if(result == TCVR_FAILURE) {			ASD(("phyread_fail>\n"));			return -1;		}		ASD(("phyread_ok,PSELECT>"));		hme_write32(hp, &tregs->cfg, tconfig | TCV_CFG_PSELECT);		hp->tcvr_type = external;		hp->paddr = TCV_PADDR_ETX;	} else {		if(tconfig & TCV_CFG_MDIO1) {			ASD(("internal<PSELECT,"));			hme_write32(hp, &tregs->cfg, (tconfig | TCV_CFG_PSELECT));			ASD(("ISOLATE,"));			happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,					      (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));			result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);			if(result == TCVR_FAILURE) {				ASD(("phyread_fail>\n"));				return -1;			}			ASD(("phyread_ok,~PSELECT>"));			hme_write32(hp, &tregs->cfg, (tconfig & ~(TCV_CFG_PSELECT)));			hp->tcvr_type = internal;			hp->paddr = TCV_PADDR_ITX;		}	}	ASD(("BMCR_RESET "));	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, BMCR_RESET);	while(--tries) {		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);		if(result == TCVR_FAILURE)			return -1;		hp->sw_bmcr = result;		if(!(result & BMCR_RESET))			break;		udelay(20);	}	if(!tries) {		ASD(("BMCR RESET FAILED!\n"));		return -1;	}	ASD(("RESET_OK\n"));	/* Get fresh copies of the PHY registers. */	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID1);	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID2);	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);	ASD(("UNISOLATE"));	hp->sw_bmcr &= ~(BMCR_ISOLATE);	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);	tries = TCVR_UNISOLATE_TRIES;	while(--tries) {		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);		if(result == TCVR_FAILURE)			return -1;		if(!(result & BMCR_ISOLATE))			break;		udelay(20);	}	if(!tries) {		ASD((" FAILED!\n"));		return -1;	}	ASD((" SUCCESS and CSCONFIG_DFBYPASS\n"));	result = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);	happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, (result | CSCONFIG_DFBYPASS));

⌨️ 快捷键说明

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