📄 miilib.c
字号:
/* miiLib.c - Media Independent Interface library */ /* Copyright 1989-2000 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01h,10jun00,dat restored funcBindP.h01g,06may00,jgn SPR 31705, fixed wdog use, fixed link status change monitoring, added more debug messages01f,05jan00,stv removed private/funcBindP.h (SPR# 29875).01e,28oct99,cn added miiLibInit (), miiLibUnInit (), miiPhyUnInit (), miiPhyBusScan (), miiPhyMonitorStart (), miiPhyMonitor (). Also updated documentation.01d,28sep99,cn changed miiProbe to better detect PHYs.01c,13sep99,cn fixed SPR# 28305. Also added show routines.01b,16jun99,cn implemented changes after code review.01a,16mar99,cn written from motFecEnd.c, 01c.*//*DESCRIPTIONThis module implements a Media Independent Interface (MII) library. The MII is an inexpensive and easy-to-implement interconnection betweenthe Carrier Sense Multiple Access with Collision Detection (CSMA/CD)media access controllers and the Physical Layer Entities (PHYs).The purpose of this library is to provide Ethernet drivers in VxWorkswith a standardized, MII-compliant, easy-to-use interface to various PHYs.In other words, using the services of this library, network driverswill be able to scan the existing PHYs, run diagnostics, electricallyisolate a subset of them, negotiate their technology abilities with otherlink-partners on the network, and ultimately initialize and configure aspecific PHY in a proper, MII-compliant fashion.In order to initialize and configure a PHY, its MII management interface has to be used. This is made up of two lines: management data clock (MDC) and management data input/output (MDIO). The former provides the timing reference for transfer of information on the MDIO signal. The latter is used to transfer control and status information between the PHY and the MAC controller. For this transfer to be successful, the information itselfhas to be encoded into a frame format, and both the MDIO and MDC signals haveto comply with certain requirements as described in the 802.3u IEEE Standard.Since no assumption can be made as to the specific MAC-to-MIIinterface, this library expects the driver's writer to provide it with specialized read and write routines to access that interface. See EXTERNAL SUPPORT REQUIREMENTS below.EXTERNAL INTERFACEThe external routines provided by this library are miiPhyInit (), miiPhyUnInit (), miiLibInit (), miiLibUnInit (), miiPhyOptFuncSet ()..CS STATUS miiLibInit (void);.CE.CS STATUS miiLibUnInit (void);.CEmiiPhyInit () should be called with the address of a PHY_INFO sructureas only parameter..CS STATUS miiPhyInit (PHY_INFO * pPhyInfo);.CEmiiPhyUnInit () should be called with the address of a PHY_INFO sructureas only parameter. .CS STATUS miiPhyUnInit (PHY_INFO * pPhyInfo);.CEThe routine miiPhyOptFuncSet () should have a valid function pointeras only parameter..CS void miiPhyOptFuncSet (FUNCPTR optRegsFunc);.CEEXTERNAL SUPPORT REQUIREMENTS.IP phyReadRtn ().CS STATUS phyReadRtn (DRV_CTRL * pDrvCtrl, UINT8 phyAddr, UINT8 phyReg, UINT16 * value);.CEThis routine is expected to perform any driver-specific functions requiredto read a 16-bit word from the <phyReg> register of the MII-compliant PHYwhose address is specified by <phyAddr>. Reading is performed through theMII management interface..IP phyWriteRtn ().CS STATUS phyWriteRtn (DRV_CTRL * pDrvCtrl, UINT8 phyAddr, UINT8 phyReg, UINT16 value);.CEThis routine is expected to perform any driver-specific functions requiredto write a 16-bit word to the <phyReg> register of the MII-compliant PHYwhose address is specified by <phyAddr>. Writing is performed through theMII management interface..IP phyDelayRtn ().CS STATUS phyDelayRtn (UINT32 phyDelayParm);.CEThis routine is expected to cause a limited delay to the calling task,no matter whether this is an active delay, or an inactive one.miiPhyInit () calls this routine on several occasions throughoutthe code with <phyDelayParm> as parameter. This represents the granularity of the delay itself, whereas the field <phyMaxDelay> in PHY_INFO is themaximum allowed delay, in <phyDelayParm> units.The user should be aware that some of these events may take as long as2-3 seconds to be completed, and he should therefore tune this routineand the parameter <phyMaxDelay> accordingly.If the related field <phyDelayRtn> in the PHY_INFO structure is initialized to NULL, no delay is performed..IP phyLinkDownRtn ().CS STATUS phyLinkDownRtn (DRV_CTRL *);.CEThis routine is expected to take any action necessary to re-initialize themedia interface, including possibly stopping and restarting the driver itself.It is called when a link down event is detected for any active PHY, with thepointer to the relevant driver control structure as only parameter..LPSEE ALSO: .I "IEEE 802.3u Standard"INTERNALThis library contains conditional compilation switch MII_DBG.If defined, adds debug output routines. Output is furtherselectable at run-time via the miiDbg global variable.*/#include "vxWorks.h"#include "errnoLib.h"#include "stdio.h"#include "stdlib.h"#include "iosLib.h"#include "net/mbuf.h"#include "logLib.h"#include "netLib.h"#include "end.h"#include "sysLib.h"#include "taskLib.h"#include "wdLib.h"#include "lstLib.h"#include "miiLib.h"#include "private/funcBindP.h" /* for logMsg *//* defines *//* Driver debug control */#undef MII_DBG /* Driver debug control */#ifdef MII_DBG#define MII_DBG_ANY 0xffffUINT32 miiDbg = 0x0;PHY_INFO * phyInfoDbg = NULL;#define MII_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \ do { \ if ((miiDbg & FLG) && (_func_logMsg != NULL)) \ _func_logMsg ((X0), (int)(X1), (int)(X2),(int)(X3), \ (int)(X4),(int)(X5),(int)(X6)); \ } while (0)#else /* MII_DBG */#define MII_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)#endif /* MII_DBG */ #define MII_PHY_CHECK_CABLE \ do { \ if (_func_logMsg != NULL) \ _func_logMsg ("miiPhyInit check cable connection \n", \ 0, 0, 0, 0, 0, 0); \ } while (0)/* * the table below is used to translate user settings * into MII-standard values for the control register. */ LOCAL UINT16 miiDefLookupTbl [] = { MII_CR_NORM_EN, MII_CR_FDX, MII_CR_100, (MII_CR_100 | MII_CR_FDX), MII_CR_100, MII_CR_RESTART | MII_CR_AUTO_EN }; #define MII_FROM_ANSR_TO_ANAR(statReg, adsReg) \ { \ phyStat &= MII_SR_ABIL_MASK; \ phyStat >>= 6; \ phyAds = phyStat + (phyAds & 0x7000) + (phyAds & MII_ADS_SEL_MASK); \ }#define MII_SEM_TAKE(tmout) \ semTake (miiMutex, (int) (tmout))#define MII_SEM_GIVE() \ semGive (miiMutex)/* globals *//* locals */LOCAL SEM_ID miiMutex; /* mutex semaphore */LOCAL LIST miiList; /* all PHYs in the system */LOCAL BOOL miiLibInitialized = FALSE; /* have we been initialized? */LOCAL WDOG_ID miiWd = NULL; /* monitor watchdog ID */LOCAL FUNCPTR pPhyOptRegsRtn = NULL;/* forward function declarations */LOCAL STATUS miiDiag (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiPhyIsolate (PHY_INFO * pPhyInfo, UINT8 isoPhyAddr);LOCAL STATUS miiPhyPwrDown (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiPhyBestModeSet (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiPhyDefModeSet (PHY_INFO * pPhyInfo);LOCAL STATUS miiAutoNegotiate (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiAutoNegStart (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiModeForce (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiDefForce (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiAnCheck (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiPhyUpdate (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiFlagsHandle (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiProbe (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiAbilFlagSet (PHY_INFO * pPhyInfo, UINT8 phyAddr);LOCAL STATUS miiLibInit (void);LOCAL STATUS miiPhyMonitor (void);LOCAL STATUS miiPhyListAdd (PHY_INFO * pPhyInfo);LOCAL STATUS miiPhyBusScan (PHY_INFO * pPhyInfo);LOCAL STATUS miiPhyLinkSet (PHY_INFO * pPhyInfo);LOCAL STATUS miiPhyMonitorStart (void);/**************************************************************************** miiPhyInit - initialize and configure the PHY devices** This routine scans, initializes and configures the PHY device described* in <phyInfo>. Space for <phyInfo> is to be provided by the calling* task.** This routine is called from the driver's Start routine to* perform media inialization and configuration. To access the PHY* device through the MII-management interface, it uses the read and* write routines which are provided by the driver itself* in the fields phyReadRtn(), phyWriteRtn() of the phyInfo structure.* Before it attempts to use this routine, the driver has to properly * initialize some of the fields in the <phyInfo> structure, and optionally* fill in others, as below:* .CS** /@ fill in mandatory fields in phyInfo @/* * pDrvCtrl->phyInfo->pDrvCtrl = (void *) pDrvCtrl;* pDrvCtrl->phyInfo->phyWriteRtn = (FUNCPTR) xxxMiiWrite;* pDrvCtrl->phyInfo->phyReadRtn = (FUNCPTR) xxxMiiRead;* * /@ fill in some optional fields in phyInfo @/* * pDrvCtrl->phyInfo->phyFlags = 0;* pDrvCtrl->phyInfo->phyAddr = (UINT8) MII_PHY_DEF_ADDR;* pDrvCtrl->phyInfo->phyDefMode = (UINT8) PHY_10BASE_T;* pDrvCtrl->phyInfo->phyAnOrderTbl = (MII_AN_ORDER_TBL *)* &xxxPhyAnOrderTbl;* * /@ * @ fill in some more optional fields in phyInfo: the delay stuff* @ we want this routine to use our xxxDelay () routine, with* @ the constant one as an argument, and the max delay we may* @ tolerate is the constant MII_PHY_DEF_DELAY, in xxxDelay units* @/* * pDrvCtrl->phyInfo->phyDelayRtn = (FUNCPTR) xxxDelay;* pDrvCtrl->phyInfo->phyMaxDelay = MII_PHY_DEF_DELAY;* pDrvCtrl->phyInfo->phyDelayParm = 1;** /@ * @ fill in some more optional fields in phyInfo: the PHY's callback* @ to handle "link down" events. This routine is invoked whenever * @ the link status in the PHY being used is detected to be low.* @/* * pDrvCtrl->phyInfo->phyStatChngRtn = (FUNCPTR) xxxRestart;** .CE** Some of the above fields may be overwritten by this routine, since * for instance, the logical address of the PHY actually used may differ* from the user's initial setting. Likewise, the specific PHY being* initialized, may not support all the technology abilities the user* has allowed for its operations.* * This routine first scans for all possible PHY addresses in the range 0-31,* checking for an MII-compliant PHY, and attempts at running some diagnostics * on it. If none is found, ERROR is returned.** Typically PHYs are scanned from address 0, but if the user specifies* an alternative start PHY address via the parameter phyAddr in the * phyInfo structure, PHYs are scanned in order starting * with the specified PHY address. In addition, if the flag <MII_ALL_BUS_SCAN> * is set, this routine will scan the whole bus even if a valid PHY has * already been found, and stores bus topology information. If the flags * <MII_PHY_ISO>, <MII_PHY_PWR_DOWN> are set, all of the PHYs found but the* first will be respectively electrically isolated from the MII interface* and/or put in low-power mode. These two flags are meaningless in a * configuration where only one PHY is present.** The phyAddr parameter is very important from a performance point of view.* Since the MII management interface, through which the PHY is configured,* is a very slow one, providing an incorrect or invalid address in this* field may result in a particularly long boot process.** If the flag <MII_ALL_BUS_SCAN> is not set, this routine will * assume that the first PHY found is the only one.** This routine then attempts to bring the link up.* This routine offers two strategies to select a PHY and establish a* valid link. The default strategy is to use the standard 802.3 style * auto-negotiation, where both link partners negotiate all their * technology abilities at the same time, and the highest common * denominator ability is chosen. Before the auto-negotiation* is started, the next-page exchange mechanism is disabled.** The user can prevent the PHY from negotiating certain abilities via * userFlags -- <MII_PHY_FD>, <MII_PHY_100>, <MII_PHY_HD>, and <MII_PHY_10>. * When <MII_PHY_FD> is not specified, full duplex will not be * negotiated; when <MII_PHY_HD> is not specified half duplex * will not be negotiated, when <MII_PHY_100> is not specified, * 100Mbps ability will not be negotiated; when <MII_PHY_10> is not * specified, 10Mbps ability will not be negotiated.** When <MII_PHY_TBL> is set in the user flags, the BSP specific * table whose address may be provided in the <phyAnOrderTbl>* field of the <phyInfo> structure, is used to obtain the list, and * the order of technology abilities to be negotiated.* The entries in this table are ordered such that entry 0 is the* highest priority, entry 1 in next and so on. Entries in this table * may be repeated, and multiple technology abilities can* be OR'd to create a single entry. If a PHY cannot support a* ability in an entry, that entry is ignored. ** If no PHY provides a valid link, and if <MII_PHY_DEF_SET> is set in the* phyFlags field of the PHY_INFO structure, the first PHY that supports * the default abilities defined in the <phyDefMode> of the phyInfo structure * will be selected, regardless of the link status.** In addition, this routine adds an entry in a linked list of PHY devices* for each active PHY it found. If the flag <MII_PHY_MONITOR> is set, the * link status for the relevant PHY is continually monitored for a link down * event. If such event is detected, and if the <phyLinkDownRtn> in the PHY_INFO * structure is a valid function pointer, then the routine it points at is * executed in the context of the netTask (). The macro MII_MONITOR_DELAY may * be used to define the period in seconds with which the link status is * checked. Its default value is 5.** RETURNS: OK or ERROR if the PHY could not be initialised,**/STATUS miiPhyInit ( PHY_INFO * pPhyInfo /* pointer to PHY_INFO structure */ ) { int retVal; /* convenient holder for return value */ /* sanity checks */ if (pPhyInfo == NULL || (pPhyInfo->phyReadRtn == NULL) || (pPhyInfo->phyWriteRtn == NULL) || (pPhyInfo->pDrvCtrl == NULL)) { MII_LOG (MII_DBG_ANY, ("miiPhyInit... missing params \n"), 0, 0, 0, 0, 0, 0); return (ERROR); }/* initialize the library @@@ */ if (miiLibInit () == ERROR) return (ERROR);#ifdef MII_DBG phyInfoDbg = pPhyInfo;#endif /* MII_DBG */ /* scan the whole bus */ if (miiPhyBusScan (pPhyInfo) == ERROR) return (ERROR); /* set the mode for a PHY, return in case of success or fatal error */ retVal = miiPhyLinkSet (pPhyInfo); if (retVal == OK) return (OK); if (errno != S_miiLib_PHY_LINK_DOWN) return (ERROR); /* if we're here, none of the PHYs could be initialized */ MII_PHY_CHECK_CABLE; if (!(MII_PHY_DEF_SET)) return (ERROR); /* set the default mode for a PHY, do not check the link */ return (miiPhyDefModeSet (pPhyInfo)); } /**************************************************************************** miiPhyUnInit - uninitialize a PHY** This routine uninitializes the PHY specified in <pPhyInfo>. It brings it* in low-power mode, and electrically isolate it from the MII management * interface to which it is attached. In addition, it frees resources * previously allocated.** RETURNS: OK, ERROR in case of fatal errors.**/STATUS miiPhyUnInit ( PHY_INFO * pPhyInfo /* pointer to PHY_INFO structure */ ) { if (pPhyInfo == NULL) return (ERROR); MII_LOG (MII_DBG_ANY, ("miiPhyUnInit \n"), 0, 0, 0, 0, 0, 0); /* this counts also for isolate */ if (miiProbe (pPhyInfo, pPhyInfo->phyAddr) == ERROR) return (ERROR); if (miiPhyPwrDown (pPhyInfo, pPhyInfo->phyAddr) == ERROR) return (ERROR); MII_PHY_FLAGS_CLEAR (MII_PHY_INIT); /* protect it from other MII routines */ MII_SEM_TAKE (WAIT_FOREVER); lstDelete (&miiList, (NODE *) pPhyInfo->pMiiPhyNode); /* we're done, release the mutex */ MII_SEM_GIVE (); /* free memory */ free ((char *) pPhyInfo->pMiiPhyNode); free ((char *) pPhyInfo->miiPhyPresent); pPhyInfo->pMiiPhyNode = NULL; /* stop the monitor if necessary */ if (miiList.count == 0) return (wdCancel (miiWd)); return (OK); }/**************************************************************************** miiProbe - probe the PHY device** This routine probes the PHY device by reading its control register.* It also checks the PHY can be successfully electrically isolated from its* MII interface.** RETURNS: OK, ERROR in case of fatal errors.** ERRNO: S_miiLib_PHY_NULL**/LOCAL STATUS miiProbe ( PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */ UINT8 phyAddr /* the PHY being read */ ) { UINT8 regAddr; /* the PHY's register being read */ UINT16 data; /* data to be written to the PHY's reg */ int retVal; /* convenient holder for return value */ MII_LOG (MII_DBG_ANY, "miiProbe for addr %#x starts\n",phyAddr,0,0,0,0,0); regAddr = MII_CTRL_REG; MII_READ (phyAddr, regAddr, &data, retVal); if (retVal == ERROR) return (ERROR); /* check the reserved bits, and the ability to isolate the PHY */ MII_LOG (MII_DBG_ANY, "miiProbe checking addr %#x\n",phyAddr,0,0,0,0,0); if (((data & MII_CR_RES_MASK) > 0x0) || ((miiPhyIsolate (pPhyInfo, phyAddr) != OK))) { errnoSet (S_miiLib_PHY_NULL); return (ERROR); } MII_LOG (MII_DBG_ANY, ("miiProbe... ends\n"), 0, 0, 0, 0, 0, 0); return (OK); }/********************************************************************************* miiDiag - run some diagnostics** This routine runs some diagnostics on the PHY whose address is * specified in the parameter <phyAddr>.** RETURNS: OK or ERROR.*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -