📄 miilib.c
字号:
/* miiLib.c - Media Independent Interface library */
/* Copyright 1989-2002 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
01r,27may05,fhc MII_PHY_CHECK_CABLE now log the problematic phy
01q,25apr05,fhc comment out MII_CR_ISOLATE related things in miiDiag and
miiPhyIsoalte for RTL8201BL, which doesn't support it.
01p,13may02,rcs set the phyAddr before calling pPhyOptRegsRtn also created
miiPhyOptFuncMultiSet() to facilitate multiple types of devices
spr# 76711
01o,14jun01,rcs protected calls to new PHY_INFO fields with test for
MII_PHY_GMII_TYPE (SPR# 68502)
01n,23feb01,jln add basic GMII support for 1000T auto-negotiation capability,
restored call to miiLibInit (). (SPR# 68502)
01m,12dec00,rcs removed global variables miiValue and miiFunc[]
01l,12dec00,rcs fix coding error (SPR# 62972)
01k,25oct00,ham doc: cleanup for vxWorks AE 1.0.
01j,19sep00,rcs in miiBasicCheck() changed MII_SYS_DELAY argument
and ix increment to sysClkRateGet(). (SPR# 33991)
01i,10jun00,dat restored funcBindP.h
01h,06may00,jgn SPR 31705, fixed wdog use, fixed link status change monitoring,
added more debug messages
01g,05jan00,stv removed private/funcBindP.h (SPR# 29875).
01f,23nov99,cn removed call to miiLibInit (), to make miiLib a component
(SPR #29542).
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.
*/
/*
DESCRIPTION
This module implements a Media Independent Interface (MII) library.
The MII is an inexpensive and easy-to-implement interconnection between
the 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 VxWorks
with a standardized, MII-compliant, easy-to-use interface to various PHYs.
In other words, using the services of this library, network drivers
will be able to scan the existing PHYs, run diagnostics, electrically
isolate a subset of them, negotiate their technology abilities with other
link-partners on the network, and ultimately initialize and configure a
specific 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 itself
has to be encoded into a frame format, and both the MDIO and MDC signals have
to comply with certain requirements as described in the 802.3u IEEE Standard.
Since no assumption can be made as to the specific MAC-to-MII
interface, 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.
miiPhyUnInit (), miiLibInit (), miiLibUnInit (), miiPhyOptFuncSet ().
STATUS miiLibInit (void);
.CE
.CS
STATUS miiLibUnInit (void);
EXTERNAL SUPPORT REQUIREMENTS
.IP phyReadRtn ()
.CS
STATUS phyReadRtn (DRV_CTRL * pDrvCtrl, UINT8 phyAddr,
UINT8 phyReg, UINT16 * value);
.CE
This routine is expected to perform any driver-specific functions required
to read a 16-bit word from the <phyReg> register of the MII-compliant PHY
whose address is specified by <phyAddr>. Reading is performed through the
MII management interface.
.IP phyWriteRtn ()
.CS
STATUS phyWriteRtn (DRV_CTRL * pDrvCtrl, UINT8 phyAddr,
UINT8 phyReg, UINT16 value);
.CE
This routine is expected to perform any driver-specific functions required
to write a 16-bit word to the <phyReg> register of the MII-compliant PHY
whose address is specified by <phyAddr>. Writing is performed through the
MII management interface.
.IP phyDelayRtn ()
.CS
STATUS phyDelayRtn (UINT32 phyDelayParm);
.CE
This 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 throughout
the code with <phyDelayParm> as parameter. This represents the granularity
of the delay itself, whereas the field <phyMaxDelay> in PHY_INFO is the
maximum allowed delay, in <phyDelayParm> units. The minimum elapsed time
(<phyMaxDelay> * <phyDelayParm>) must be 5 seconds.
The user should be aware that some of these events may take as long as
2-3 seconds to be completed, and he should therefore tune this routine
and 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 *);
.CE
This routine is expected to take any action necessary to re-initialize the
media interface, including possibly stopping and restarting the driver itself.
It is called when a link down event is detected for any active PHY, with the
pointer to the relevant driver control structure as only parameter.
.LP
To use this feature, include the following component:
INCLUDE_MIILIB
SEE ALSO:
.I "IEEE 802.3.2000 Standard"
INTERNAL
This library contains conditional compilation switch MII_DBG.
If defined, adds debug output routines. Output is further
selectable 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 0xffff
UINT32 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(phyAddr) \
do { \
if (_func_logMsg != NULL) \
_func_logMsg ("miiPhyInit: check cable connection(PHY=%#x)\n",\
phyAddr, 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 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 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.
*
* If GMII interface is used, users can specify it through userFlags --
* <MII_PHY_GMII_TYPE>.
*
* 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>.
* as well as <MII_PHY_1000T_HD> and <MII_PHY_1000T_FD> if GMII is used.
* 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.
* Also, if GMII is used, when <MII_PHY_1000T_HD> is not specified,
* 1000T with half duplex mode will not be negotiated. Same thing
* applied to 1000T with full duplex mode via <MII_PHY_1000T_FD>.
* Flow control ability can also be negotiated via user flags --
* <MII_PHY_TX_FLOW_CTRL> and <MII_PHY_RX_FLOW_CTRL>. For symmetric
* PAUSE ability (MII), user can set/clean both flags together. For
* asymmetric PAUSE ability (GMII), user can seperate transmit and receive
* flow control ability. However, user should be aware that flow control
* ability is meaningful only if full duplex mode is used.
*
* 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 parameter 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);
}
/* Ensure that pPhyInfo->phyMaxDelay is minimum 5 seconds */
if (pPhyInfo->phyMaxDelay < (sysClkRateGet() * 5))
{
/* Set max delay porportionally */
pPhyInfo->phyMaxDelay = sysClkRateGet() * 5;
}
/* initialize the MII 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(pPhyInfo->phyAddr);
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_DEF_SET)))
return (ERROR);
/* set the default mode for a PHY, do not check the link */
return (miiPhyDefModeSet (pPhyInfo));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -