📄 miilib.c
字号:
}
}
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 */
/* 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);
/* 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;
/*
* 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))
{
/* check we're not at the end of the user table */
if (pPhyInfo->phyAnOrderTbl == NULL)
{
MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate no auto-neg table\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
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;
MII_LOG (MII_DBG_ANY, ("miiAutoNegotiate phyAds=0x%x\n"),
phyAds, 0, 0, 0, 0, 0);
}
/* set the ANAR accordingly */
regAddr = MII_AN_ADS_REG;
MII_WRITE (phyAddr, regAddr, phyAds, 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 read 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 */
int retVal; /* convenient holder for return value */
/* let's check the PHY status */
regAddr = MII_STAT_REG;
MII_READ (phyAddr, regAddr, &phyStatus, retVal);
if (retVal != OK)
return (ERROR);
if ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
{
MII_LOG (MII_DBG_ANY, ("miiBasicCheck first time
phy stat=0x%x\n"),
phyStatus, 0, 0, 0, 0, 0);
/* wait for a while */
MII_SYS_DELAY (pPhyInfo->phyDelayParm);
/* we need to read it twice, as this's a latched function */
MII_READ (phyAddr, regAddr, &phyStatus, retVal);
if (retVal != OK)
return (ERROR);
if ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS)
{
MII_LOG (MII_DBG_ANY, ("miiBasicCheck phy stat=0x%x\n"),
phyStatus, 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 */
)
{
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);
}
/*******************************************************************************
* miiAnCheck - check the auto-negotiation process result
*
* This routine checks the auto-negotiation process has completed
* successfully and no faults have been detected by any of the PHYs
* engaged in the process.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS miiAnCheck
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* address of a PHY */
)
{
UINT8 regAddr; /* PHY register */
UINT16 phyAds; /* PHY advertisement register value */
UINT16 phyPrtn; /* PHY partner ability register value */
UINT16 phyExp; /* PHY expansion register value */
UINT16 negAbility; /* abilities after negotiation */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -