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

📄 pmcmspeth.c

📁 175dswitch的驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
				break;			}		}	} else {		/* no acceptable PROM settings so we have to make something up */		if (lp->option & MSP_OPT_SWITCH) { 			/* commandline set us to a switch so no phy settings required.			 * consider changing this later so that we can access the registers			 * in the switch through MDIO etc.  Could be autoprobed too.			 */		}  else { 			/* search through the list of phys and use the first unassigned one */			for (phyindex = 0; phyindex < MSPETH_MAX_UNITS;			     phyindex++) {				if (!phy_ctrl[phyindex].assigned) {					lp->phyindex = phyindex;					phy_ctrl[phyindex].assigned = true;					break;				}			}		}		/* rudimentary error checking */		if (phystr != NULL) {			printk(KERN_INFO			       "MSPETH (init_phyaddr) %s: bad phyaddr value %s\n",			       dev->name, phystr);		}	}}/************************************************************************** * Scan the environment to get the kernel command line options for ethernet */static void __init mspeth_init_cmdline(struct net_device *dev){	struct mspeth_local *lp = (struct mspeth_local *) dev->priv;	int index;	int unit;	char c = ' ';	char command_line[COMMAND_LINE_SIZE];	char *ptr = &command_line[0];	char *ethptr = NULL;	/* default options */	lp->option = MSP_OPT_AUTO;	/* scan the command line looking for static configurations */	strcpy(command_line, prom_getcmdline());	while (c != '\0') {		if (c != ' ' || memcmp(ptr, "ip=", 3) != 0) {			c = *ptr++;			continue;		}		c = *ptr++;		index = 0;		unit = -1;		while (index < 8) {			c = *ptr++;			if (c == '\0' || c == ' ') {				if (index == 7) {					index++;					*--ptr = '\0';					ptr++;				}				break;			}			if (c == ':') {				index++;				if (index == 5) {					if (memcmp(ptr, "eth", 3) != 0) {						break;					}					ethptr = &ptr[3];					ptr = ethptr;				}				if (index == 6) {					*--ptr = '\0';					ptr++;					unit =					    simple_strtol(ethptr, NULL, 0);				}				if (index == 7) {					ethptr = ptr;				}				if (index == 8) {					*--ptr = '\0';					ptr++;				}			}		}		if (index < 8 || unit < 0 || unit > MSPETH_MAX_UNITS)			continue;		/* check to see if this our option and parse them out */		if (lp->unit == unit) {			if (memcmp(ethptr, "100fs", 5) == 0) {				/* 100M full-duplex switch */				lp->option =				    MSP_OPT_100M | MSP_OPT_FDUP |				    MSP_OPT_SWITCH;			} else if (memcmp(ethptr, "100hs", 5) == 0) {				/* 100M half-duplex switch */				lp->option =				    MSP_OPT_100M | MSP_OPT_HDUP |				    MSP_OPT_SWITCH;			} else if (memcmp(ethptr, "10fs", 4) == 0) {				/* 10M full-duplex switch */				lp->option =				    MSP_OPT_10M | MSP_OPT_FDUP |				    MSP_OPT_SWITCH;			} else if (memcmp(ethptr, "10hs", 4) == 0) {				/* 10M half-duplex switch */				lp->option =				    MSP_OPT_100M | MSP_OPT_HDUP |				    MSP_OPT_SWITCH;			} else if (memcmp(ethptr, "100f", 4) == 0)				/* 100M full-duplex */				lp->option = MSP_OPT_100M | MSP_OPT_FDUP;			else if (memcmp(ethptr, "100h", 4) == 0)				/* 100M half-duplex */				lp->option = MSP_OPT_100M | MSP_OPT_HDUP;			else if (memcmp(ethptr, "10f", 3) == 0)				/* 10M full-duplex */				lp->option = MSP_OPT_10M | MSP_OPT_FDUP;			else if (memcmp(ethptr, "10h", 3) == 0)				/* 100M half-duplex */				lp->option = MSP_OPT_10M | MSP_OPT_HDUP;		}		if (mspeth_debug > 0)			printk(KERN_INFO			       "MSPETH (init_cmdline)%s: boot = %s, option = %02x\n",			       dev->name, command_line, lp->option);	}}/************************************************************************** * Probe the hardware and fill out the array of PHY control elements */static void mspeth_phyprobe(){	u32 reg1;	int hwindex, phyindex, phyaddr;	/* scan the phys and build the phy_ctrl array */	for (phyindex = 0, hwindex = 0; hwindex < MSPETH_MAX_UNITS;	     hwindex++) {		/* if the hardware actually exists then ... */		if (identify_enet(hwindex) != FEATURE_NOEXIST) {			for (phyaddr = 0; phyaddr < MD_MAX_PHY; phyaddr++) {				phy_ctrl[phyindex].hwindex = hwindex;				phy_ctrl[phyindex].phyaddr = phyaddr;				phy_ctrl[phyindex].lock =				    SPIN_LOCK_UNLOCKED;				phy_ctrl[phyindex].assigned = false;				reg1 = read_mspphyreg(phyindex, MII_BMSR);				if (reg1 != 0 && reg1 != 0xffff				    && (reg1 & BMSR_MEDIAMASK) != 0) {					printk(KERN_INFO					       "MSPETH (phyprobe): phyindex = %d, phyaddr = %d, hwindex = %d\n",					       phyindex, phyaddr, hwindex);					if (read_mspphyreg					    (phyindex,					     MII_BMSR) & BMSR_LSTATUS)						phy_ctrl[phyindex].linkup =						    true;					else						phy_ctrl[phyindex].linkup =						    false;					phyindex++;					/* Show MII status register */					if (MSPETH_DEBUG > 1) {						printk(KERN_INFO							"MSPETH (phyprobe): MII status register = %08x\n", reg1);					}				}			}		}	}}/************************************************************************** * Reset the phy */static void mspeth_phy_reset(struct net_device *dev){	struct mspeth_local *lp = (struct mspeth_local *) dev->priv;	u32 id0, id1;	/* reset the phy */	write_mspphyreg(BMCR_RESET, lp->phyindex, MII_BMCR);	while ((read_mspphyreg(lp->phyindex, MII_BMCR) & BMCR_RESET) != 0)		udelay(100);	if (mspeth_debug > 0) {		printk(KERN_INFO			"MSPETH (phy_chip_init) %s: phyindex = %d\n",			dev->name, lp->phyindex);		id0 = read_mspphyreg(lp->phyindex, MII_PHYSID1);		id1 = read_mspphyreg(lp->phyindex, MII_PHYSID2);		printk(KERN_INFO		       "MSPETH (phy_chip_init) %s: PHY ID %04x %04x\n",		       dev->name, id0, id1);		printk(KERN_INFO		       "MSPETH (phy_chip_init) %s: speed = %d, duplex = %s\n",		       dev->name, lp->speed,		       (lp->fullduplex ? "FULL" : "HALF"));	}}/************************************************************************** * Initialize the phy -- set the speed and duplex.  Wait for autonegotiation * to complete.  If it doesn't then force the renegotiation.  If *that* fails * then reset the phy and try again.  Finally just make some assumptions.  If * autonegotiation is disabled then just force values */static void mspeth_phy_init(struct net_device *dev){	struct mspeth_local *lp = (struct mspeth_local *) dev->priv;	struct mspeth_regs *tr = (struct mspeth_regs *) dev->base_addr;	u32 ctl, neg_result;	int i;	enum { AUTONEG, AUTONEG_FORCE, PHYRESET } auto_status;	char *link_type;	char *link_stat;	/* check for defaults and autonegotiate */	if (lp->option == MSP_OPT_AUTO) {		/* make sure the autonegotiation is enabled and then wait for the		 * autonegotion to complete		 */		link_type = "Autoneg";		for (auto_status = AUTONEG; auto_status <= PHYRESET;		     auto_status++) {			/* run through all the various autonegotion methods until we fail */			switch (auto_status) {			case AUTONEG:				write_mspphyreg(BMCR_ANENABLE,						lp->phyindex, MII_BMCR);				break;			case AUTONEG_FORCE:				printk(KERN_WARNING				       "MSPETH %s: Forcing autonegotiation\n",				       dev->name);				write_mspphyreg(BMCR_ANENABLE |						BMCR_ANRESTART,						lp->phyindex, MII_BMCR);				break;			case PHYRESET:				printk(KERN_WARNING				       "MSPETH %s: Resetting phy\n",				       dev->name);				write_mspphyreg(BMCR_RESET, lp->phyindex,						MII_BMCR);				while ((read_mspphyreg					(lp->phyindex,					 MII_BMCR) & BMCR_RESET) != 0)					udelay(100);				write_mspphyreg(BMCR_ANENABLE |						BMCR_ANRESTART,						lp->phyindex, MII_BMCR);				break;			default:				printk(KERN_DEBUG				       "MSPETH %s: Unknown autonegotation mode??\n",				       dev->name);				return;			}			/* ok.  Autoneg should be underway, so lets do the loop thingy and wait			 * for it to exit			 */			printk(KERN_INFO "MSPETH %s: Auto Negotiation...",			       dev->name);			for (i = 0;			     i < 2000			     && !(read_mspphyreg(lp->phyindex, MII_BMSR) &				  BMSR_ANEGCOMPLETE); i++) {				mdelay(1);			}			if (i == 2000) {				/* autonegotiation failed to complete so go to next level of 				 * negotiation.				 */				printk(" failed.\n");				continue;			}			/* must have succeeded so we can set the speed etc */			printk(" done.\n");			neg_result = read_mspphyreg(lp->phyindex, MII_LPA);			if (neg_result & (LPA_100FULL | LPA_100HALF))				lp->speed = 100;			else				lp->speed = 10;			if (neg_result & (LPA_100FULL | LPA_10FULL))				lp->fullduplex = true;			else				lp->fullduplex = false;			break;		}		/* check to see if *everything* failed and try to set some default values */		if (auto_status > PHYRESET) {			printk			    ("Autonegotion failed.  Assume 10Mbps, half-duplex\n");			link_type = "Autoneg (failed)";			lp->speed = 10;			lp->fullduplex = false;		}	} else {		/* if speed and duplex are statically configured then set that here */		link_type = "Static";		ctl = 0;		if (lp->option & MSP_OPT_100M) {			lp->speed = 100;			ctl |= BMCR_SPEED100;		} else {			lp->speed = 10;			ctl &= ~BMCR_SPEED100;		}		if (lp->option & MSP_OPT_FDUP) {			lp->fullduplex = true;			ctl |= BMCR_FULLDPLX;		} else {			lp->fullduplex = false;			ctl &= ~BMCR_FULLDPLX;		}		if (!(lp->option & MSP_OPT_SWITCH))			write_mspphyreg(ctl, lp->phyindex, MII_BMCR);	}	if (!(lp->option & MSP_OPT_SWITCH)) {		/* wait for a little bit to see if we've got a carrier -- don't go crazy though */		printk(KERN_INFO "MSPETH %s: Waiting for carrier ...", dev->name);		for (i = 0;		     i < 2000		     && !(read_mspphyreg(lp->phyindex, MII_BMSR) & BMSR_LSTATUS);		     i++) {			mdelay(1);		}			if (i == 2000) {			printk(" no carrier.\n");			phy_ctrl[lp->phyindex].linkup = false;			netif_carrier_off(dev);			link_stat = "Link down";		}		else {			printk(" carrier detected.\n");			phy_ctrl[lp->phyindex].linkup = true;			netif_carrier_on(dev);			link_stat = "Link up";		}	}	else {		/* Assume we're connected. If we're using a switch we always should be.*/		printk(KERN_INFO "MSPETH %s: Using internal switch\n", dev->name);		phy_ctrl[lp->phyindex].linkup = true;		//netif_carrier_off(dev);		link_stat = "Link up";	}	/* configure the MAC with the duplex setting -- it doesn't care about speed */	if (lp->fullduplex) {		write_mspreg(read_mspreg(&tr->MAC_Ctl) | MAC_FullDup,			     &tr->MAC_Ctl);	} else {		write_mspreg(read_mspreg(&tr->MAC_Ctl) & ~MAC_FullDup,			     &tr->MAC_Ctl);	}	if (mspeth_debug > 2) {		printk(KERN_INFO "MSPETH %s: PHY control register: 0x%08x\n", 		dev->name, read_mspphyreg(lp->phyindex, MII_BMCR));		printk(KERN_INFO "MSPETH %s: PHY status register: 0x%08x\n",		dev->name, read_mspphyreg(lp->phyindex, MII_BMSR));	}			printk(KERN_INFO	       "MSPETH %s: %s, %s, linkspeed %dMbps, %s Duplex\n",	       dev->name, link_type, link_stat, lp->speed,	       (lp->fullduplex) ? "Full" : "Half");}/************************************************************************** * Check the link for a carrier when the link check timer expires.  If the  * link is down and it has been down for a while (at least 1 timer delay) * then change the upper layer link state to match.  Do a soft-restart if * we're bringing the link up.  Reschedule the timer of course. */static void mspeth_link_check(unsigned long data){	struct net_device *dev = (struct net_device *) data;	struct mspeth_local *lp = (struct mspeth_local *) dev->priv;	enum { LINKGOOD, LINKBAD, LINKUNKNOWN } linkstatus;	/* check the current link status */	linkstatus = LINKUNKNOWN;	if (read_mspphyreg(lp->phyindex, MII_BMSR) & BMSR_LSTATUS) {		if (phy_ctrl[lp->phyindex].linkup)			linkstatus = LINKGOOD;		phy_ctrl[lp->phyindex].linkup = true;	} else {		if (!phy_ctrl[lp->phyindex].linkup)			linkstatus = LINKBAD;		phy_ctrl[lp->phyindex].linkup = false;	}	/* check the upper layer status */	if (netif_carrier_ok(dev)) {		/* upper layer thinks we're ok but the link is bad, so 		 * take the link down		 */		if (linkstatus == LINKBAD) {			printk(KERN_INFO "%s: NO LINK DETECTED\n",			       dev->name);			netif_stop_queue(dev);			netif_carrier_off(dev);		}	} else {		/* the upper layer thinks we're broken but we've recovered so		 * do a soft-restart and bring the link back up		 */		if (linkstatus == LINKGOOD) {			printk(KERN_INFO "%s: LINK DETECTED\n", dev->name);			mspeth_soft_restart(dev);

⌨️ 快捷键说明

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