📄 miilib.c
字号:
/* * 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 */ int maxDelay; /* maximum delay tick or count */ int delayUnit; /* delay unit/tick per call phyDelayRtn */ int delayCount; /* delay number/tick */ /* let's check the PHY status for completion */ regAddr = MII_STAT_REG; /* * the old algorithm assumes the delay routine is taskDelay(), which * is not appropriate. However, for backward compatibility reason, * the old algorithm is still kept if the delay function is taskDelay(). */ if (pPhyInfo->phyDelayRtn == (FUNCPTR) taskDelay) { maxDelay = pPhyInfo->phyMaxDelay * pPhyInfo->phyDelayParm; delayUnit = sysClkRateGet (); delayCount = delayUnit; } else { maxDelay = pPhyInfo->phyMaxDelay; delayUnit = pPhyInfo->phyDelayParm; delayCount = 1; } /* spin until it is done */ do { MII_SYS_DELAY (delayUnit); ix += delayCount; if (ix >= maxDelay) { MII_LOG (MII_DBG_ANY, ("miiBasicCheck fail\n"), 0, 0, 0, 0, 0, 0); return (ERROR); } MII_READ (phyAddr, regAddr, &phyStatus, retVal); if (retVal != OK) return (ERROR); } while ((phyStatus & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS); 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) { MII_PHY_FLAGS_CLEAR (MII_PHY_FD); MII_PHY_FLAGS_CLEAR (MII_PHY_100); } else { MII_LOG (MII_DBG_ANY, ("miiPhyUpdate fail!\n"), 0, 0, 0, 0, 0, 0); return (ERROR); } /* store the current registers values */exitPhyUpdate: pPhyInfo->miiRegs.phyStatus = phyStatus; pPhyInfo->miiRegs.phyAds = phyAds; pPhyInfo->miiRegs.phyPrtn = phyPrtn; pPhyInfo->miiRegs.phyExp = phyExp; if (pPhyInfo->phyFlags & MII_PHY_GMII_TYPE) { pPhyInfo->miiGRegs.phyMSStatus = phyMstSlaStat; pPhyInfo->miiGRegs.phyMSCtrl = phyMstSlaCtrl; } /* handle some flags */ if (miiFlagsHandle (pPhyInfo, phyAddr) != OK) return (ERROR); 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.** NOTE: * In case the cable is pulled out and reconnect to the same/different * hub/switch again. PHY probably starts a new auto-negotiation process and * get different negotiation results. User should call this routine to check * link status and update phyFlags. pPhyInfo should include a valid * PHY bus number (phyAddr), and include the phyFlags that was used last time
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -