📄 miilib.c
字号:
regAddr = MII_AN_ADS_REG;
MII_WRITE (phyAddr, regAddr, phyAds, retVal);
if (retVal != OK)
return (ERROR);
MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyAds=0x%x\n"),
phyAds, 0, 0, 0, 0, 0);
/* set MSC register accordingly */
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
regAddr = MII_MASSLA_CTRL_REG;
MII_WRITE (phyAddr, regAddr, phyMstSlaCtrl, retVal);
if (retVal != OK)
return (ERROR);
}
/*
* start the auto-negotiation process: return
* only in case of fatal error.
*/
retVal = miiAutoNegStart (pPhyInfo, phyAddr);
/*
* in case of fatal error, we return immediately; otherwise,
* we try to recover from the failure, if we're not using
* the standard auto-negotiation process.
*/
if (retVal == ERROR)
{
if (errno != S_miiLib_PHY_AN_FAIL)
return (ERROR);
else
{
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_TBL)))
return (ERROR);
else
{
/* let's try the next entry in the table */
errno = 0;
continue;
}
}
}
/* check the negotiation was successful */
if (miiAnCheck (pPhyInfo, phyAddr) == OK)
return (OK);
/*
* we are here if the negotiation went wong:
* if the auto-negotiation order table was not
* used, we return ERROR, as all the PHY abilities
* were negotiated at once.
*/
if (!(MII_PHY_FLAGS_ARE_SET (MII_PHY_TBL)))
return (ERROR);
}
return (OK);
}
/*******************************************************************************
*
* miiAutoNegStart - start the auto-negotiation process
*
* This routine starts the auto-negotiation process for the PHY whose
* address is specified in the parameter <phyAddr>.
*
* RETURNS: OK or ERROR.
*
* ERRNO: S_miiLib_PHY_AN_FAIL
*
*/
LOCAL STATUS miiAutoNegStart
(
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 phyStatus; /* holder for the PHY status */
UINT16 ix = 0; /* a counter */
int retVal; /* convenient holder for return value */
regAddr = MII_STAT_REG;
MII_READ (phyAddr, regAddr, &phyStatus, retVal);
if (retVal != OK)
return (ERROR);
MII_LOG (MII_DBG_ANY, ("miiAutoNegStart phy=0x%x reg=0x%x status=0x%x\n"),
phyAddr, regAddr, phyStatus, 0, 0, 0);
/* check the PHY has this ability */
if ((phyStatus & MII_SR_AUTO_SEL) != MII_SR_AUTO_SEL)
{
MII_LOG (MII_DBG_ANY, ("miiAutoNegStart phy not
auto neg capable\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
/* restart the auto-negotiation process */
regAddr = MII_CTRL_REG;
data = (MII_CR_RESTART | MII_CR_AUTO_EN);
MII_WRITE (phyAddr, regAddr, data, retVal);
if (retVal != OK)
return (ERROR);
/* save status info */
pPhyInfo->miiRegs.phyCtrl = data;
/* let's check the PHY status for completion */
regAddr = MII_STAT_REG;
/* spin until it is done */
do
{
MII_SYS_DELAY (pPhyInfo->phyDelayParm);
if (ix++ == pPhyInfo->phyMaxDelay)
break;
MII_READ (phyAddr, regAddr, &phyStatus, retVal);
if (retVal != OK)
return (ERROR);
} while ((phyStatus & MII_SR_AUTO_NEG) != MII_SR_AUTO_NEG);
MII_LOG (MII_DBG_ANY, ("miiAutoNegStart auto neg attempts=%d \n"),
ix, 0, 0, 0, 0, 0);
if (ix >= pPhyInfo->phyMaxDelay)
{
MII_LOG (MII_DBG_ANY, ("miiAutoNegStart auto neg fail\n"),
0, 0, 0, 0, 0, 0);
errnoSet (S_miiLib_PHY_AN_FAIL);
return (ERROR);
}
else
{
MII_LOG (MII_DBG_ANY, ("miiAutoNegStart auto neg done phyStat=0x%x\n"),
phyStatus, 0, 0, 0, 0, 0);
}
return (OK);
}
/*******************************************************************************
*
* miiBasicCheck - run a basic check on the PHY status register
*
* This routine runs a basic check on the PHY status register to
* ensure a valid link has been established and no faults have been
* detected.
*
* RETURNS: OK or ERROR.
*
*/
LOCAL STATUS miiBasicCheck
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* address of a PHY */
)
{
UINT8 regAddr; /* PHY register */
UINT16 phyStatus; /* holder for the PHY status */
UINT16 ix = 0; /* a counter */
int retVal; /* convenient holder for return value */
/* let's check the PHY status for completion */
regAddr = MII_STAT_REG;
/* spin until it is done */
do
{
MII_SYS_DELAY (sysClkRateGet());
ix += sysClkRateGet();
if (ix >= pPhyInfo->phyMaxDelay)
break;
MII_READ (phyAddr, regAddr, &phyStatus, retVal);
if (retVal != OK)
return (ERROR);
} while ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS);
if (ix >= pPhyInfo->phyMaxDelay)
{
MII_LOG (MII_DBG_ANY, ("miiBasicCheck fail\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
MII_LOG (MII_DBG_ANY, ("miiBasicCheck Link up! status=0x%x\n"),
phyStatus, 0, 0, 0, 0, 0);
/* check for remote fault condition, read twice */
MII_READ (phyAddr, regAddr, &phyStatus, retVal);
if (retVal != OK)
return (ERROR);
MII_READ (phyAddr, regAddr, &phyStatus, retVal);
if (retVal != OK)
return (ERROR);
if ((phyStatus & MII_SR_REMOTE_FAULT) == MII_SR_REMOTE_FAULT)
{
MII_LOG (MII_DBG_ANY, ("miiBasicCheck remote fault\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
/* store the current registers values */
pPhyInfo->miiRegs.phyStatus = phyStatus;
return (OK);
}
/*******************************************************************************
*
* miiFlagsHandle - handle some flags
*
* This routine sets some fields in the PHY_INFO structure according to the
* values of the related flags.
*
* RETURNS: OK, always.
*/
LOCAL STATUS miiFlagsHandle
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* address of a PHY */
)
{
/* check speed ... */
if (MII_PHY_FLAGS_ARE_SET (MII_PHY_1000T_FD) ||
MII_PHY_FLAGS_ARE_SET (MII_PHY_1000T_HD))
pPhyInfo->phySpeed = MII_1000MBS;
else if (MII_PHY_FLAGS_ARE_SET (MII_PHY_100))
pPhyInfo->phySpeed = MII_100MBS;
else
pPhyInfo->phySpeed = MII_10MBS;
if (MII_PHY_FLAGS_ARE_SET (MII_PHY_FD))
{
bcopy (MII_FDX_STR, (char *) pPhyInfo->phyMode, MII_FDX_LEN);
}
else
{
bcopy (MII_HDX_STR, (char *) pPhyInfo->phyMode, MII_HDX_LEN);
}
MII_LOG (MII_DBG_ANY, ("miiFlagsHandle speed=%d mode=%s\n"),
pPhyInfo->phySpeed,
(char *) pPhyInfo->phyMode, 0, 0, 0, 0);
return (OK);
}
/*******************************************************************************
*
* miiPhyUpdate - update the phyInfo structure to the latest PHY status
*
* This routine updates the phyInfo structure to the latest PHY status.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS miiPhyUpdate
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* address of a PHY */
)
{
UINT16 phyStatus; /* holder for the PHY status */
UINT16 phyAds; /* PHY advertisement register value */
UINT16 phyPrtn; /* PHY partner ability register value */
UINT16 phyExp; /* PHY expansion register value */
UINT16 phyMstSlaCtrl; /* PHY Master-slave Control value */
UINT16 phyMstSlaStat; /* PHY Master-slave Status value */
UINT16 negAbility; /* abilities after negotiation */
int retVal; /* convenient holder for return value */
MII_READ (phyAddr, MII_STAT_REG, &phyStatus, retVal);
if (retVal == ERROR)
return (ERROR);
/* does the PHY support the extended registers set? */
if (!(phyStatus & MII_SR_EXT_CAP))
return (OK);
MII_READ (phyAddr, MII_AN_ADS_REG, &phyAds, retVal);
if (retVal == ERROR)
return (ERROR);
MII_READ (phyAddr, MII_AN_PRTN_REG, &phyPrtn, retVal);
if (retVal == ERROR)
return (ERROR);
MII_READ (phyAddr, MII_AN_EXP_REG, &phyExp, retVal);
if (retVal == ERROR)
return (ERROR);
/* flow control configuration */
/* MII defines symmetric PAUSE ability */
if ((!(phyAds & MII_ANAR_PAUSE)) || (!(phyPrtn & MII_TECH_PAUSE)))
pPhyInfo->phyFlags &= ~(MII_PHY_TX_FLOW_CTRL | MII_PHY_RX_FLOW_CTRL);
else
pPhyInfo->phyFlags |= (MII_PHY_TX_FLOW_CTRL | MII_PHY_RX_FLOW_CTRL);
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
/* GMII also defines asymmetric PAUSE ability */
/* Advertises transmitter but no receiver */
if (((phyAds & MII_ANAR_PAUSE_MASK) == MII_ANAR_ASM_PAUSE) &&
((phyPrtn & MII_TECH_PAUSE_MASK) == MII_TECH_PAUSE_MASK))
{
pPhyInfo->phyFlags |= MII_PHY_TX_FLOW_CTRL;
}
/* Advertises receiver but no transmitter */
else if (((phyAds & MII_ANAR_PAUSE_MASK) == MII_ANAR_PAUSE_MASK) &&
((phyPrtn & MII_TECH_PAUSE_MASK) == MII_TECH_ASM_PAUSE))
{
pPhyInfo->phyFlags |= MII_PHY_RX_FLOW_CTRL;
}
/* no flow control */
else if ((!(phyAds & MII_ANAR_PAUSE)) || (!(phyPrtn & MII_TECH_PAUSE)))
{
pPhyInfo->phyFlags &= ~(MII_PHY_TX_FLOW_CTRL |
MII_PHY_RX_FLOW_CTRL);
}
/* TX and RX flow control */
else
{
pPhyInfo->phyFlags |= (MII_PHY_TX_FLOW_CTRL | MII_PHY_RX_FLOW_CTRL);
}
}
/* find out the max common abilities */
if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE)
{
/* search for 1000T capbility */
/* get MASTER-SLAVE control register */
MII_READ (phyAddr, MII_MASSLA_CTRL_REG, &phyMstSlaCtrl, retVal);
if (retVal == ERROR)
return (ERROR);
/* get MASTER-SLAVE status register */
MII_READ (phyAddr, MII_MASSLA_STAT_REG, &phyMstSlaStat, retVal);
if (retVal == ERROR)
return (ERROR);
MII_READ (phyAddr, MII_MASSLA_STAT_REG, &phyMstSlaStat, retVal);
if (retVal == ERROR)
return (ERROR);
if ((phyMstSlaStat & MII_MASSLA_STAT_LP1000T_FD) &&
(phyMstSlaCtrl & MII_MASSLA_CTRL_1000T_FD))
{
/* 1000T FD supported */
MII_PHY_FLAGS_SET (MII_PHY_FD);
goto exitPhyUpdate;
}
else if ((phyMstSlaStat & MII_MASSLA_STAT_LP1000T_HD) &&
(phyMstSlaCtrl & MII_MASSLA_CTRL_1000T_HD))
{
/* 1000T HD supported */
MII_PHY_FLAGS_SET (MII_PHY_HD);
MII_PHY_FLAGS_CLEAR (MII_PHY_1000T_FD);
goto exitPhyUpdate;
}
else
{
/* 1000T not supported, go check other abilities */
MII_PHY_FLAGS_CLEAR (MII_PHY_1000T_FD);
MII_PHY_FLAGS_CLEAR (MII_PHY_1000T_HD);
}
}
negAbility = phyPrtn & phyAds & MII_ADS_TECH_MASK;
MII_LOG (MII_DBG_ANY, ("miiPhyUpdate phyAds=0x%x
phyPrtn=0x%x common=0x%x phyExp=0x%x\n"),
phyAds,
phyPrtn,
negAbility,
phyExp, 0, 0);
if (negAbility & MII_TECH_100BASE_TX_FD)
{
}
else if ((negAbility & MII_TECH_100BASE_TX) ||
(negAbility & MII_TECH_100BASE_T4))
{
MII_PHY_FLAGS_CLEAR (MII_PHY_FD);
}
else if (negAbility & MII_TECH_10BASE_FD)
{
MII_PHY_FLAGS_CLEAR (MII_PHY_100);
}
else if (negAbility & MII_TECH_10BASE_T)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -