📄 miilib.c
字号:
/* miiLib.c - Media Independent Interface library */
/* Copyright 1989-1999 Wind River Systems, Inc. */
#include "copyright_wrs.h"
/*
modification history
--------------------
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.
EXTERNAL INTERFACE
The only external routines are miiPhyInit () and miiPhyOptFuncSet ().
miiPhyInit () should be called with the address of a PHY_INFO sructure
as only parameter.
.CS
STATUS miiPhyInit (PHY_INFO * pPhyInfo);
.CE
The routine miiPhyOptFuncSet () should have a valid function pointer
as only parameter.
.CS
void miiPhyOptFuncSet (FUNCPTR optRegsFunc);
.CE
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 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.
.LP
SEE ALSO:
.I "IEEE 802.3u Standard"
INTERNAL
This library contains conditional compilation switch MII_END_DEBUG.
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 "private/funcBindP.h"
#include "logLib.h"
#include "lstLib.h"
#include "miiLib.h"
#include "end.h"
/* 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) \
{ \
if (miiDbg & FLG) \
if (_func_logMsg != NULL) \
_func_logMsg ((X0), (X1), (X2), (X3), (X4), (X5), (X6)); \
}
#else /* MII_DBG */
#define MII_LOG(FLG, X0, X1, X2, X3, X4, X5, X6)
#endif /* MII_DBG */
#define MII_PHY_CHECK_CABLE \
if (_func_logMsg != NULL) \
_func_logMsg ("miiPhyInit check cable connection \n", \
0, 0, 0, 0, 0, 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
};
/* library flags */
#define MII_PHY_FLAGS_SET(setBits) \
(pPhyInfo->phyFlags |= (setBits))
#define MII_PHY_FLAGS_ARE_SET(setBits) \
(pPhyInfo->phyFlags & (setBits))
#define MII_PHY_FLAGS_GET(setBits) \
(pPhyInfo->phyFlags)
#define MII_PHY_FLAGS_CLEAR(clearBits) \
(pPhyInfo->phyFlags &= ~(clearBits))
#define MII_FROM_ANSR_TO_ANAR(statReg, adsReg) \
{ \
phyStat &= MII_SR_ABIL_MASK; \
phyStat >>= 6; \
phyAds = phyStat + (phyAds & 0x7000) + (phyAds & MII_ADS_SEL_MASK); \
}
/* globals */
/* locals */
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 miiPhyFeatureSet (PHY_INFO * pPhyInfo);
LOCAL STATUS miiPhyPwrDown (PHY_INFO * pPhyInfo, UINT8 phyAddr);
LOCAL STATUS miiPhyBestModeSet (PHY_INFO * pPhyInfo);
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 miiFlagsHandle (PHY_INFO * pPhyInfo, UINT8 phyAddr);
LOCAL STATUS miiProbe (PHY_INFO * pPhyInfo, UINT8 phyAddr);
LOCAL STATUS miiAbilFlagSet (PHY_INFO * pPhyInfo, UINT8 phyAddr);
/**************************************************************************
*
* 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;
*
* .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.
*
* Before it attempts to bring the link up, this routine checks the
* phyFlags field in the phyInfo structure for PHY devices that need to be
* electrically isolated by the MII interface. All the valid PHYs found are
* electrically isolated.
*
* The routine then scans for all possible PHY addresses in the range 0-31,
* checking for an MII-compliant PHY, and attempts to establish a
* valid link for 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, all (32) PHYs are scanned in order starting
* with the specified PHY address, until a valid link is established.
*
* 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 is to 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 PHYs are scanned again in the
* same order, and the first PHY that supports the default abilities
* defined in the <phyDefMode> of the phyInfo structure will be selected,
* regardless of the link status.
*
* 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);
}
#ifdef MII_DBG
phyInfoDbg = pPhyInfo;
#endif /* MII_DBG */
/*
* set some features for all the PHYs (power down mode,
* electrical isolation, etc.)
*/
if (miiPhyFeatureSet (pPhyInfo) == ERROR)
return (ERROR);
/* set the mode for a PHY, return in case of success or fatal error */
retVal = miiPhyBestModeSet (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));
}
/**************************************************************************
*
* miiProbe - probe the PHY device
*
* This routine probes the PHY device by reading its control register.
*
* 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 */
regAddr = MII_CTRL_REG;
MII_READ (phyAddr, regAddr, &data, retVal);
if (retVal == ERROR)
return (ERROR);
if (((data & MII_CR_DEF_0_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.
*/
LOCAL STATUS miiDiag
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* address of a PHY */
)
{
UINT16 data; /* data to be written to the control reg */
UINT8 regAddr; /* PHY register */
UINT16 ix = 0; /* a counter */
int retVal; /* convenient holder for return value */
/* reset the PHY */
regAddr = MII_CTRL_REG;
data = MII_CR_RESET;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -