📄 miilib.c
字号:
/* * 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)) { 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; 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); /* * 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 (pPhyInfo->phyDelayParm); 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 */ ) { 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 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); /* find out the max common abilities */ 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 */ pPhyInfo->miiRegs.phyStatus = phyStatus; pPhyInfo->miiRegs.phyAds = phyAds; pPhyInfo->miiRegs.phyPrtn = phyPrtn; pPhyInfo->miiRegs.phyExp = phyExp; /* 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.** 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 phyPrtn; /* PHY partner ability register value */ UINT16 phyExp; /* PHY expansion register value */ int retVal; /* convenient holder for return value */ /* run a check on the status bits of basic registers only */ retVal = miiBasicCheck (pPhyInfo, phyAddr); if (retVal != OK) return (retVal); /* we know the auto-negotiation process has finished */ regAddr = MII_AN_EXP_REG; MII_READ (phyAddr, regAddr, &phyExp, retVal); if (retVal != OK) return (ERROR); /* check for faults detected by the parallel function */ if ((phyExp & MII_EXP_FAULT) == MII_EXP_FAULT) { MII_LOG (MII_DBG_ANY, ("miiAnCheck: fault expStat=0x%x\n"), phyExp, 0, 0, 0, 0, 0); /* * Don't fail here as some PHY devices don't support this register, * but seem to return 0xffff when it is read (jgn - 5/8/00) */ /* return (ERROR); */ } /* check for remote faults */ regAddr = MII_AN_PRTN_REG; MII_READ (phyAddr, regAddr, &phyPrtn, retVal); if (retVal != OK) return (ERROR); if ((phyPrtn & MII_BP_FAULT) == MII_BP_FAULT) { MII_LOG (MII_DBG_ANY, ("miiAnCheck partner stat=0x%x\n"), phyPrtn, 0, 0, 0, 0, 0); return (ERROR); } if (miiPhyUpdate (pPhyInfo, phyAddr) == ERROR) { MII_LOG (MII_DBG_ANY, "miiPhyUpdate error\n",0,0,0,0,0,0); return (ERROR); } MII_LOG (MII_DBG_ANY, ("miiAnCheck OK\n"), 0, 0, 0, 0, 0, 0); return (OK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -