📄 miilib.c
字号:
)
{
/*
* start the auto-negotiation process,
* unless the user dictated the contrary.
*/
if (pPhyInfo->phyFlags & MII_PHY_AUTO)
if (miiAutoNegotiate (pPhyInfo, phyAddr) == OK)
{
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
pPhyInfo->phyLinkMethod = MII_PHY_LINK_AUTO;
}
goto miiPhyOk;
}
/*
* the auto-negotiation process did not succeed
* in establishing a valid link: try to do it
* manually, enabling as many high priority abilities
* as possible.
*/
if (miiModeForce (pPhyInfo, phyAddr) == OK)
{
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
pPhyInfo->phyLinkMethod = MII_PHY_LINK_FORCE;
}
goto miiPhyOk;
}
return (ERROR);
miiPhyOk:
/* store this PHY and return */
pPhyInfo->phyAddr = phyAddr;
MII_PHY_FLAGS_SET (MII_PHY_INIT);
return (OK);
}
/*******************************************************************************
*
* miiPhyLinkSet - set the link for a PHY
*
* This routine sets the link for the PHY pointed to by <pPhyInfo>. To do
* so, it calls miiPhyBestModeSet (). Upon success it returns OK.
* Otherwise, it checks whether other PHYs are on the bus, and attempts at
* establishing a link for them starting from the first and scanning the
* whole range. In case of failure, ERROR is returned.
*
* SEE ALSO: miiPhyBestModeSet ().
*
* RETURNS: OK or ERROR.
*
* ERRNO: S_miiLib_PHY_LINK_DOWN
*
*/
LOCAL STATUS miiPhyLinkSet
(
PHY_INFO * pPhyInfo /* pointer to PHY_INFO structure */
)
{
UINT16 ix; /* a counter */
UINT8 phyAddr; /* address of a PHY */
UINT32 phyFlags; /* default PHY's flags */
/* store the default phy's flags */
phyFlags = pPhyInfo->phyFlags;
for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
{
phyAddr = (ix + pPhyInfo->phyAddr) % MII_MAX_PHY_NUM;
MII_LOG (MII_DBG_ANY, ("miiPhyLinkSet phyAddr=0x%x \n"),
phyAddr, 0, 0, 0, 0, 0);
if (* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr) == FALSE)
continue;
/* add this PHY to the linked list */
if (miiPhyListAdd (pPhyInfo) == ERROR)
return (ERROR);
MII_LOG (MII_DBG_ANY, ("miiPhyLinkSet phyAddr=0x%x pres=0x%x \n"),
phyAddr,
(* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr)),
0, 0, 0, 0);
/* find out the PHY's abilities and set flags accordingly */
if (miiAbilFlagSet (pPhyInfo, phyAddr) != OK)
return (ERROR);
/* we need this phyAddr before we call pPhyOptRegsRtn */
pPhyInfo->phyAddr = phyAddr;
/*
* check with the BSP if we need to do something else before
* we try and establish the link
*/
if (pPhyInfo->pPhyOptRegsRtn != NULL)
(* pPhyInfo->pPhyOptRegsRtn) (pPhyInfo);
else
if (pPhyOptRegsRtn != NULL)
(* pPhyOptRegsRtn) (pPhyInfo);
/* initialize phyLinkMethod */
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
pPhyInfo->phyLinkMethod = MII_PHY_LINK_UNKNOWN;
}
/* establist the link */
if (miiPhyBestModeSet (pPhyInfo, phyAddr) == OK)
{
return (OK);
}
/* restore the default flags, miiAbilFlagSet may have changed them */
pPhyInfo->phyFlags = phyFlags;
}
/* set errno, since we did not establish a valid link */
errnoSet (S_miiLib_PHY_LINK_DOWN);
return (ERROR);
}
/*******************************************************************************
*
* miiPhyDefModeSet - set the default operating mode for a PHY
*
* This routine sets the default operating mode for a PHY looking at the
* parameters in <pPhyInfo>. It calls miiDefForce () for each PHY found.
*
* SEE ALSO: miiDefForce ().
*
* RETURNS: OK or ERROR.
*
*/
LOCAL STATUS miiPhyDefModeSet
(
PHY_INFO * pPhyInfo /* pointer to PHY_INFO structure */
)
{
UINT16 ix; /* a counter */
int retVal; /* holder for return value */
UINT8 phyAddr; /* address of a PHY */
/* try to establish a default operating mode, do not check the link! */
for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
{
phyAddr = (ix + pPhyInfo->phyAddr) % MII_MAX_PHY_NUM;
/* check the PHY is there */
if (* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr) == FALSE)
continue;
/*
* Force default parameters: field phyDefMode in the PHY info
* structure. Return OK even if the link is not up.
*/
retVal = miiDefForce (pPhyInfo, phyAddr);
if (retVal == OK)
{
/* store this PHY and return */
pPhyInfo->phyAddr = phyAddr;
MII_PHY_FLAGS_SET (MII_PHY_INIT);
return (OK);
}
/* if the PHY does not have the default abilities... */
if (errno == S_miiLib_PHY_NO_ABLE)
{
if (ix == (MII_MAX_PHY_NUM - 1))
return (ERROR);
errno = 0;
continue;
}
}
return (ERROR);
}
/*******************************************************************************
*
* miiAutoNegotiate - run the auto-negotiation process
*
* This routine runs the auto-negotiation process for the PHY whose
* address is specified in the parameter <phyAddr>, without enabling the
* next page function. It also calls miiAnCheck() to ensure
* a valid link has been established.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS miiAutoNegotiate
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* address of a PHY */
)
{
UINT8 regAddr; /* PHY register */
UINT16 phyAds; /* holder for the PHY ads register value */
UINT16 status; /* PHY auto-negotiation status */
UINT16 ix; /* a counter */
int retVal; /* holder for return value */
UINT16 phyStat; /* PHY auto-negotiation status */
UINT16 phyMstSlaCtrl; /* PHY Mater-slave Control */
UINT16 phyExtStat; /* PHY extented status */
/* save phyFlags for phyAutoNegotiateFlags */
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
pPhyInfo->phyAutoNegotiateFlags = pPhyInfo->phyFlags;
}
/* Read ANER to clear status from previous operations */
regAddr = MII_AN_EXP_REG;
MII_READ (phyAddr, regAddr, &status, retVal);
if (retVal != OK)
return (ERROR);
/*
* copy the abilities in ANSR to ANAR. This is necessary because
* according to the 802.3 standard, the technology ability
* field in ANAR "is set based on the value in the MII status
* register or equivalent". What does "equivalent" mean?
*/
regAddr = MII_AN_ADS_REG;
MII_READ (phyAddr, regAddr, &phyAds, retVal);
if (retVal != OK)
return (ERROR);
MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyAds=0x%x expStat=0x%x \n"),
phyAds, status, 0, 0, 0, 0);
regAddr = MII_STAT_REG;
MII_READ (phyAddr, regAddr, &phyStat, retVal);
if (retVal != OK)
return (ERROR);
MII_FROM_ANSR_TO_ANAR (phyStat, phyAds);
/* also disable the next page function */
phyAds &= (~MII_NP_NP);
MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate write to ANAR=0x%x\n"),
phyAds, 0, 0, 0, 0, 0);
/* configure flow control */
/* MII defines symmetric PAUSE ability */
if ((MII_PHY_FLAGS_ARE_SET (MII_PHY_TX_FLOW_CTRL)) &&
(MII_PHY_FLAGS_ARE_SET (MII_PHY_RX_FLOW_CTRL)))
phyAds |= MII_ANAR_PAUSE;
else
phyAds &= ~MII_ANAR_PAUSE;
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
/* GMII also defines asymmetric PAUSE ability */
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_TX_FLOW_CTRL)) &&
!(MII_PHY_FLAGS_ARE_SET (MII_PHY_RX_FLOW_CTRL)))
{
/* not flow control */
phyAds &= ~MII_ANAR_ASM_PAUSE;
phyAds &= ~MII_ANAR_PAUSE;
}
else if ((MII_PHY_FLAGS_ARE_SET (MII_PHY_TX_FLOW_CTRL)) &&
!(MII_PHY_FLAGS_ARE_SET (MII_PHY_RX_FLOW_CTRL)))
{
/* TX flow control */
phyAds |= MII_ANAR_ASM_PAUSE;
phyAds &= ~MII_ANAR_PAUSE;
}
else
{
/* RX flow control */
phyAds |= MII_ANAR_ASM_PAUSE;
phyAds |= MII_ANAR_PAUSE;
}
}
/* write ANAR */
regAddr = MII_AN_ADS_REG;
MII_WRITE (phyAddr, regAddr, phyAds, retVal);
if (retVal != OK)
return (ERROR);
/* store the current registers values */
pPhyInfo->miiRegs.phyAds = phyAds;
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
/* get Master-Slave Control (MSC) Register */
regAddr = MII_MASSLA_CTRL_REG;
MII_READ (phyAddr, regAddr, &phyMstSlaCtrl, retVal);
if (retVal != OK)
return (ERROR);
/* get extended status register */
regAddr = MII_EXT_STAT_REG;
MII_READ (phyAddr, regAddr, &phyExtStat, retVal);
if (retVal != OK)
return (ERROR);
/* set MSC register value based on PHY ability on EXTS */
phyMstSlaCtrl = (phyExtStat & MII_EXT_STAT_1000T_HD) ?
(phyMstSlaCtrl | MII_MASSLA_CTRL_1000T_HD) :
(phyMstSlaCtrl & ~MII_MASSLA_CTRL_1000T_HD);
phyMstSlaCtrl = (phyExtStat & MII_EXT_STAT_1000T_FD) ?
(phyMstSlaCtrl | MII_MASSLA_CTRL_1000T_FD) :
(phyMstSlaCtrl & ~MII_MASSLA_CTRL_1000T_FD);
/* write MSC register value */
regAddr = MII_MASSLA_CTRL_REG;
MII_WRITE (phyAddr, regAddr, phyMstSlaCtrl, retVal);
if (retVal != OK)
return (ERROR);
/* store the current registers values */
pPhyInfo->miiGRegs.phyMSCtrl = phyMstSlaCtrl;
}
/*
* start the auto-negotiation process, possibly
* following the order the user dictated.
*/
for (ix = 0; ; ix++)
{
if (MII_PHY_FLAGS_ARE_SET (MII_PHY_TBL))
{
if (pPhyInfo->phyAnOrderTbl == NULL)
{
MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate no auto-neg table\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
/* check we're not at the end of the user table */
if (*((INT16*) pPhyInfo->phyAnOrderTbl + ix) == -1)
return (ERROR);
/* just negotiate one ability at a time */
phyAds &= ~MII_ADS_TECH_MASK;
/* translate user settings */
phyAds |= *((INT16*) pPhyInfo->phyAnOrderTbl + ix);
/* check the PHY has the desidered ability */
if (!(phyAds & pPhyInfo->miiRegs.phyAds))
continue;
}
else
{
/* check the PHY flags and possibly mask some abilities off */
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_FD)))
phyAds &= ~(MII_TECH_10BASE_FD | MII_TECH_100BASE_TX_FD);
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_HD)))
phyAds &= ~(MII_TECH_10BASE_T | MII_TECH_100BASE_TX
| MII_TECH_100BASE_T4);
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_100)))
phyAds &= ~(MII_TECH_100BASE_TX | MII_TECH_100BASE_TX_FD
| MII_TECH_100BASE_T4);
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_10)))
phyAds &= ~(MII_TECH_10BASE_T | MII_TECH_10BASE_FD);
/* store the current registers values */
pPhyInfo->miiRegs.phyAds = phyAds;
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
/* check phyFlags with 1000T FD mode */
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_1000T_FD)))
phyMstSlaCtrl &= ~MII_MASSLA_CTRL_1000T_FD;
/* check phyFlags with 1000T HD mode */
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_1000T_HD)))
phyMstSlaCtrl &= ~MII_MASSLA_CTRL_1000T_HD;
/* store the current registers values */
pPhyInfo->miiGRegs.phyMSCtrl = phyMstSlaCtrl;;
MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyMSCtrl=0x%x\n"),
phyMstSlaCtrl, 0, 0, 0, 0, 0);
}
MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyAds=0x%x\n"),
phyAds, 0, 0, 0, 0, 0);
}
/* set the ANAR accordingly */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -