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

📄 e100_phy.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 2 页
字号:
/*******************************************************************************    Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.    This program is free software; you can redistribute it and/or modify it   under the terms of the GNU General Public License as published by the Free   Software Foundation; either version 2 of the License, or (at your option)   any later version.    This program is distributed in the hope that it will be useful, but WITHOUT   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for   more details.    You should have received a copy of the GNU General Public License along with  this program; if not, write to the Free Software Foundation, Inc., 59   Temple Place - Suite 330, Boston, MA  02111-1307, USA.    The full GNU General Public License is included in this distribution in the  file called LICENSE.    Contact Information:  Linux NICS <linux.nics@intel.com>  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************/#include "e100_phy.h"void e100_handle_zlock(struct e100_private *bdp);/*  * Procedure:	e100_mdi_write * * Description: This routine will write a value to the specified MII register *		of an external MDI compliant device (e.g. PHY 100).  The *		command will execute in polled mode. * * Arguments: *	bdp - Ptr to this card's e100_bdconfig structure *	reg_addr - The MII register that we are writing to *	phy_addr - The MDI address of the Phy component. *	data - The value that we are writing to the MII register. * * Returns: *	NOTHING */inte100_mdi_write(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 data){	int e100_retry;	u32 temp_val;	unsigned int mdi_cntrl;	spin_lock_bh(&bdp->mdi_access_lock);	temp_val = (((u32) data) | (reg_addr << 16) |		    (phy_addr << 21) | (MDI_WRITE << 26));	writel(temp_val, &bdp->scb->scb_mdi_cntrl);	readw(&bdp->scb->scb_status);	/* wait 20usec before checking status */	udelay(20);	/* poll for the mdi write to complete */	e100_retry = E100_CMD_WAIT;	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {		udelay(20);		e100_retry--;	}	spin_unlock_bh(&bdp->mdi_access_lock);	if (mdi_cntrl & MDI_PHY_READY) 		return 0;	else {		printk(KERN_ERR "e100: MDI write timeout\n");		return 1;	}}/*  * Procedure:	e100_mdi_read * * Description: This routine will read a value from the specified MII register *		of an external MDI compliant device (e.g. PHY 100), and return *		it to the calling routine.  The command will execute in polled *		mode. * * Arguments: *	bdp - Ptr to this card's e100_bdconfig structure *	reg_addr - The MII register that we are reading from *	phy_addr - The MDI address of the Phy component. * * Results: *	data - The value that we read from the MII register. * * Returns: *	NOTHING */inte100_mdi_read(struct e100_private *bdp, u32 reg_addr, u32 phy_addr, u16 *data){	int e100_retry;	u32 temp_val;	unsigned int mdi_cntrl;	spin_lock_bh(&bdp->mdi_access_lock);	/* Issue the read command to the MDI control register. */	temp_val = ((reg_addr << 16) | (phy_addr << 21) | (MDI_READ << 26));	writel(temp_val, &bdp->scb->scb_mdi_cntrl);	readw(&bdp->scb->scb_status);	/* wait 20usec before checking status */	udelay(20);	/* poll for the mdi read to complete */	e100_retry = E100_CMD_WAIT;	while ((!((mdi_cntrl = readl(&bdp->scb->scb_mdi_cntrl)) & MDI_PHY_READY)) && (e100_retry)) {		udelay(20);		e100_retry--;	}	spin_unlock_bh(&bdp->mdi_access_lock);	if (mdi_cntrl & MDI_PHY_READY) {		/* return the lower word */		*data = (u16) mdi_cntrl;		return 0;	}	else {		printk(KERN_ERR "e100: MDI read timeout\n");		return 1;	}}static unsigned char __devinite100_phy_valid(struct e100_private *bdp, unsigned int phy_address){	u16 ctrl_reg, stat_reg;	/* Read the MDI control register */	e100_mdi_read(bdp, MII_BMCR, phy_address, &ctrl_reg);	/* Read the status register twice, bacause of sticky bits */	e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);	e100_mdi_read(bdp, MII_BMSR, phy_address, &stat_reg);	if ((ctrl_reg == 0xffff) || ((stat_reg == 0) && (ctrl_reg == 0)))		return false;	return true;}static void __devinite100_phy_address_detect(struct e100_private *bdp){	unsigned int addr;	unsigned char valid_phy_found = false;	if (IS_NC3133(bdp)) {		bdp->phy_addr = 0;		return;	}	if (e100_phy_valid(bdp, PHY_DEFAULT_ADDRESS)) {		bdp->phy_addr = PHY_DEFAULT_ADDRESS;		valid_phy_found = true;	} else {		for (addr = MIN_PHY_ADDR; addr <= MAX_PHY_ADDR; addr++) {			if (e100_phy_valid(bdp, addr)) {				bdp->phy_addr = addr;				valid_phy_found = true;				break;			}		}	}	if (!valid_phy_found) {		bdp->phy_addr = PHY_ADDRESS_503;	}}static void __devinite100_phy_id_detect(struct e100_private *bdp){	u16 low_id_reg, high_id_reg;	if (bdp->phy_addr == PHY_ADDRESS_503) {		bdp->PhyId = PHY_503;		return;	}	if (!(bdp->flags & IS_ICH)) {		if (bdp->rev_id >= D102_REV_ID) {			bdp->PhyId = PHY_82562ET;			return;		}	}	/* Read phy id from the MII register */	e100_mdi_read(bdp, MII_PHYSID1, bdp->phy_addr, &low_id_reg);	e100_mdi_read(bdp, MII_PHYSID2, bdp->phy_addr, &high_id_reg);	bdp->PhyId = ((unsigned int) low_id_reg |		      ((unsigned int) high_id_reg << 16));}static void __devinite100_phy_isolate(struct e100_private *bdp){	unsigned int phy_address;	u16 ctrl_reg;	/* Go over all phy addresses. Deisolate the selected one, and isolate	 * all the rest */	for (phy_address = 0; phy_address <= MAX_PHY_ADDR; phy_address++) {		if (phy_address != bdp->phy_addr) {			e100_mdi_write(bdp, MII_BMCR, phy_address,				       BMCR_ISOLATE);		} else {			e100_mdi_read(bdp, MII_BMCR, bdp->phy_addr, &ctrl_reg);			ctrl_reg &= ~BMCR_ISOLATE;			e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr, ctrl_reg);		}		udelay(100);	}}static unsigned char __devinite100_phy_specific_setup(struct e100_private *bdp){	u16 misc_reg;	if (bdp->phy_addr == PHY_ADDRESS_503) {		switch (bdp->params.e100_speed_duplex) {		case E100_AUTONEG:			/* The adapter can't autoneg. so set to 10/HALF */			printk(KERN_INFO			       "e100: 503 serial component detected which "			       "cannot autonegotiate\n");			printk(KERN_INFO			       "e100: speed/duplex forced to "			       "10Mbps / Half duplex\n");			bdp->params.e100_speed_duplex = E100_SPEED_10_HALF;			break;		case E100_SPEED_100_HALF:		case E100_SPEED_100_FULL:			printk(KERN_ERR			       "e100: 503 serial component detected "			       "which does not support 100Mbps\n");			printk(KERN_ERR			       "e100: Change the forced speed/duplex "			       "to a supported setting\n");			return false;		}		return true;	}	if (IS_NC3133(bdp)) {		u16 int_reg;		/* enable 100BASE fiber interface */		e100_mdi_write(bdp, MDI_NC3133_CONFIG_REG, bdp->phy_addr,			       MDI_NC3133_100FX_ENABLE);		if ((bdp->params.e100_speed_duplex != E100_AUTONEG) &&		    (bdp->params.e100_speed_duplex != E100_SPEED_100_FULL)) {			/* just inform user about 100 full */			printk(KERN_ERR "e100: NC3133 NIC can only run "			       "at 100Mbps full duplex\n");		}		bdp->params.e100_speed_duplex = E100_SPEED_100_FULL;		/* enable interrupts */		e100_mdi_read(bdp, MDI_NC3133_INT_ENABLE_REG,			      bdp->phy_addr, &int_reg);		int_reg |= MDI_NC3133_INT_ENABLE;		e100_mdi_write(bdp, MDI_NC3133_INT_ENABLE_REG,			       bdp->phy_addr, int_reg);	}	/* Handle the National TX */	if ((bdp->PhyId & PHY_MODEL_REV_ID_MASK) == PHY_NSC_TX) {		e100_mdi_read(bdp, NSC_CONG_CONTROL_REG,			      bdp->phy_addr, &misc_reg);		misc_reg |= NSC_TX_CONG_TXREADY;		/* disable the congestion control bit in the National Phy */		misc_reg &= ~NSC_TX_CONG_ENABLE;		e100_mdi_write(bdp, NSC_CONG_CONTROL_REG,			       bdp->phy_addr, misc_reg);	}	return true;}/*  * Procedure:	e100_phy_fix_squelch * * Description: *	Help find link on certain rare scenarios. *	NOTE: This routine must be called once per watchdog, *	      and *after* setting the current link state. * * Arguments: *	bdp - Ptr to this card's e100_bdconfig structure * * Returns: *	NOTHING */static voide100_phy_fix_squelch(struct e100_private *bdp){	if ((bdp->PhyId != PHY_82555_TX) || (bdp->flags & DF_SPEED_FORCED))		return;	if (netif_carrier_ok(bdp->device)) {		switch (bdp->PhyState) {		case 0:			break;		case 1:			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,				       bdp->phy_addr, 0x0000);			break;		case 2:			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,				       bdp->phy_addr, 0x3000);			break;		}		bdp->PhyState = 0;		bdp->PhyDelay = 0;	} else if (!bdp->PhyDelay--) {		switch (bdp->PhyState) {		case 0:			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,				       bdp->phy_addr, EXTENDED_SQUELCH_BIT);			bdp->PhyState = 1;			break;		case 1:			e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,				       bdp->phy_addr, 0x0000);			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,				       bdp->phy_addr, 0x2010);			bdp->PhyState = 2;			break;		case 2:			e100_mdi_write(bdp, PHY_82555_MDI_EQUALIZER_CSR,				       bdp->phy_addr, 0x3000);			bdp->PhyState = 0;			break;		}		e100_mdi_write(bdp, MII_BMCR, bdp->phy_addr,			       BMCR_ANENABLE | BMCR_ANRESTART);		bdp->PhyDelay = 3;	}}/*  * Procedure:	e100_fix_polarity * * Description: *	Fix for 82555 auto-polarity toggle problem. With a short cable  *	connecting an 82555 with an 840A link partner, if the medium is noisy, *	the 82555 sometime thinks that the polarity might be wrong and so  *	toggles polarity. This happens repeatedly and results in a high bit  *	error rate. *	NOTE: This happens only at 10 Mbps * * Arguments: *	bdp - Ptr to this card's e100_bdconfig structure * * Returns: *	NOTHING */static void __devinite100_fix_polarity(struct e100_private *bdp){	u16 status;	u16 errors;	u16 misc_reg;	int speed;	if ((bdp->PhyId != PHY_82555_TX) && (bdp->PhyId != PHY_82562ET) &&	    (bdp->PhyId != PHY_82562EM))		return;	/* If the user wants auto-polarity disabled, do only that and nothing *	 * else. * e100_autopolarity == 0 means disable --- we do just the	 * disabling * e100_autopolarity == 1 means enable  --- we do nothing at	 * all * e100_autopolarity >= 2 means we do the workaround code. */	/* Change for 82558 enhancement */	switch (E100_AUTOPOLARITY) {	case 0:		e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,			      bdp->phy_addr, &misc_reg);		e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,			       (u16) (misc_reg | DISABLE_AUTO_POLARITY));		break;	case 1:		e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,			      bdp->phy_addr, &misc_reg);		e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL, bdp->phy_addr,			       (u16) (misc_reg & ~DISABLE_AUTO_POLARITY));		break;	case 2:		/* we do this only if link is up */		if (!netif_carrier_ok(bdp->device)) {			break;		}		e100_mdi_read(bdp, PHY_82555_CSR, bdp->phy_addr, &status);		speed = (status & PHY_82555_SPEED_BIT) ? 100 : 10;		/* we need to do this only if speed is 10 */		if (speed != 10) {			break;		}		/* see if we have any end of frame errors */		e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,			      bdp->phy_addr, &errors);		/* if non-zero, wait for 100 ms before reading again */		if (errors) {			udelay(200);			e100_mdi_read(bdp, PHY_82555_EOF_COUNTER,				      bdp->phy_addr, &errors);			/* if non-zero again, we disable polarity */			if (errors) {				e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,					      bdp->phy_addr, &misc_reg);				e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,					       bdp->phy_addr,					       (u16) (misc_reg |						      DISABLE_AUTO_POLARITY));			}		}		if (!errors) {			/* it is safe to read the polarity now */			e100_mdi_read(bdp, PHY_82555_CSR,				      bdp->phy_addr, &status);			/* if polarity is normal, disable polarity */			if (!(status & PHY_82555_POLARITY_BIT)) {				e100_mdi_read(bdp, PHY_82555_SPECIAL_CONTROL,					      bdp->phy_addr, &misc_reg);				e100_mdi_write(bdp, PHY_82555_SPECIAL_CONTROL,					       bdp->phy_addr,					       (u16) (misc_reg |						      DISABLE_AUTO_POLARITY));			}		}		break;	default:		break;	}}/*  * Procedure:	e100_find_speed_duplex * * Description: This routine will figure out what line speed and duplex mode *		the PHY is currently using. * * Arguments: *	bdp - Ptr to this card's e100_bdconfig structure * * Returns: *	NOTHING */static voide100_find_speed_duplex(struct e100_private *bdp){	unsigned int PhyId;	u16 stat_reg, misc_reg;	u16 ad_reg, lp_ad_reg;	PhyId = bdp->PhyId & PHY_MODEL_REV_ID_MASK;	/* First we should check to see if we have link */	/* If we don't have a link no reason to print a speed and duplex */	if (!e100_update_link_state(bdp)) {		bdp->cur_line_speed = 0;		bdp->cur_dplx_mode = 0;		return;	}	/* On the 82559 and later controllers, speed/duplex is part of the *	 * SCB. So, we save an mdi_read and get these from the SCB. * */	if (bdp->rev_id >= D101MA_REV_ID) {		/* Read speed */		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_1)			bdp->cur_line_speed = 100;		else			bdp->cur_line_speed = 10;		/* Read duplex */		if (readb(&bdp->scb->scb_ext.d101m_scb.scb_gen_stat) & BIT_2)			bdp->cur_dplx_mode = FULL_DUPLEX;		else			bdp->cur_dplx_mode = HALF_DUPLEX;		return;	}	/* If this is a Phy 100, then read bits 1 and 0 of extended register 0,	 * to get the current speed and duplex settings. */	if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) ||	    (PhyId == PHY_82555_TX)) {		/* Read Phy 100 extended register 0 */		e100_mdi_read(bdp, EXTENDED_REG_0, bdp->phy_addr, &misc_reg);		/* Get current speed setting */		if (misc_reg & PHY_100_ER0_SPEED_INDIC)			bdp->cur_line_speed = 100;		else			bdp->cur_line_speed = 10;		/* Get current duplex setting -- FDX enabled if bit is set */		if (misc_reg & PHY_100_ER0_FDX_INDIC)			bdp->cur_dplx_mode = FULL_DUPLEX;		else			bdp->cur_dplx_mode = HALF_DUPLEX;		return;	}	/* See if link partner is capable of Auto-Negotiation (bit 0, reg 6) */	e100_mdi_read(bdp, MII_EXPANSION, bdp->phy_addr, &misc_reg);	/* See if Auto-Negotiation was complete (bit 5, reg 1) */	e100_mdi_read(bdp, MII_BMSR, bdp->phy_addr, &stat_reg);	/* If a True NWAY connection was made, then we can detect speed/dplx	 * by ANDing our adapter's advertised abilities with our link partner's	 * advertised ablilities, and then assuming that the highest common	 * denominator was chosed by NWAY. */	if ((misc_reg & EXPANSION_NWAY) && (stat_reg & BMSR_ANEGCOMPLETE)) {		/* Read our advertisement register */		e100_mdi_read(bdp, MII_ADVERTISE, bdp->phy_addr, &ad_reg);		/* Read our link partner's advertisement register */		e100_mdi_read(bdp, MII_LPA, bdp->phy_addr, &lp_ad_reg);		/* AND the two advertisement registers together, and get rid		 * of any extraneous bits. */		ad_reg &= (lp_ad_reg & NWAY_LP_ABILITY);		/* Get speed setting */

⌨️ 快捷键说明

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