📄 miilib.c
字号:
}/********************************************************************************* 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 */ 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -