📄 mvphy.c
字号:
* RETURNS:* TRUE --> at least 1 PHY with LINK* FALSE --> no LINKs on this ethernet unit*/BOOLmv_phySetup(int ethUnit, UINT32 phyBase){ int phyUnit; int liveLinks = 0; BOOL foundPhy = FALSE; UINT32 phyAddr; UINT16 atuControl; /* * Allow platform-specific code to determine the default Ethernet MAC * at run-time. If phyEthMacDefault returns a negative value, use the * static mvPhyInfo table "as is". But if phyEthMacDefault returns a * non-negative value, use it as the default ethernet unit. */ { int ethMacDefault = phyEthMacDefault(); if (ethMacDefault >= 0) { for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { MV_ETHUNIT(phyUnit)=ethMacDefault; } } } /* * See if there's any configuration data for this enet, * and set up phyBase in table. */ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { if (MV_ETHUNIT(phyUnit) != ethUnit) { continue; } MV_PHYBASE(phyUnit) = phyBase; MV_PRINT(MV_DEBUG_PHYSETUP,("phyBase =%x unit = %d\n",phyBase, phyUnit )); foundPhy = TRUE; } if (!foundPhy) { return FALSE; /* No PHY's configured for this ethUnit */ } /* Verify that the switch is what we think it is, and that it's ready */ mv_verifyReady(ethUnit); /* Initialize global switch settings */ atuControl = MV_ATUCTRL_AGE_TIME_DEFAULT << MV_ATUCTRL_AGE_TIME_SHIFT; atuControl |= MV_ATUCTRL_ATU_SIZE_DEFAULT << MV_ATUCTRL_ATU_SIZE_SHIFT; phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_CONTROL, atuControl); /* Reset PHYs and start autonegoation on each. */ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { if (MV_ETHUNIT(phyUnit) != ethUnit) { continue; } phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); phyRegWrite(phyBase, phyAddr, MV_PHY_CONTROL, MV_CTRL_SOFTWARE_RESET | MV_CTRL_AUTONEGOTIATION_ENABLE); }#if 0 /* Don't wait -- we'll detect shortly after the link comes up */{ int timeout; UINT16 phyHwStatus; /* * Wait 5 seconds for ALL associated PHYs to finish autonegotiation. */ timeout=50; for (phyUnit=0; (phyUnit < MV_PHY_MAX) && (timeout > 0); phyUnit++) { if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } for (;;) { phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); if (MV_AUTONEG_DONE(phyHwStatus)) { break; } if (--timeout == 0) { break; } sysMsDelay(100); } }}#endif /* * All PHYs have had adequate time to autonegotiate. * Now initialize software status. * * It's possible that some ports may take a bit longer * to autonegotiate; but we can't wait forever. They'll * get noticed by mv_phyCheckStatusChange during regular * polling activities. */ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (mv_phyIsLinkAlive(phyUnit)) { liveLinks++; MV_IS_PHY_ALIVE(phyUnit) = TRUE; } else { MV_IS_PHY_ALIVE(phyUnit) = FALSE; } MV_PRINT(MV_DEBUG_PHYSETUP, ("ethmac%d: Phy Status=%4.4x\n", ethUnit, phyRegRead(MV_PHYBASE(phyUnit), MV_PHYADDR(phyUnit), MV_PHY_SPECIFIC_STATUS))); } mv_VLANInit(ethUnit); mv_enableConfiguredPorts(ethUnit); return (liveLinks > 0);}/******************************************************************************** mv_phyIsDuplexFull - Determines whether the phy ports associated with the* specified device are FULL or HALF duplex.** RETURNS:* 1 --> at least one associated PHY in FULL DUPLEX* 0 --> all half duplex* -1 --> No links*/intmv_phyIsFullDuplex(int ethUnit){ int phyUnit; UINT32 phyBase; UINT32 phyAddr; UINT16 phyHwStatus; int oneIsReady=0; for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (mv_phyIsLinkAlive(phyUnit)) { oneIsReady = 1; phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); if (phyHwStatus & MV_STATUS_RESOLVED_DUPLEX_FULL) {// printf("full duplex mode\n"); return 1; } } } if (oneIsReady) {// printf("half duplex mode\n"); return 0; } else return -1;}/******************************************************************************** mv_phyIsSpeed100 - Determines the speed of a phy port** RETURNS:* TRUE --> PHY operating at 100 Mbit* FALSE --> link down, or not operating at 100 Mbit*/BOOLmv_phyIsSpeed100(int phyUnit){ UINT16 phyHwStatus; UINT32 phyBase; UINT32 phyAddr; if (MV_IS_ENET_PORT(phyUnit)) { if (mv_phyIsLinkAlive(phyUnit)) { phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); if (phyHwStatus & MV_STATUS_RESOLVED_SPEED_100) { return TRUE; } } } return FALSE;}BOOLmv_phyIsFullDuplex_ext(int phyUnit){ UINT16 phyHwStatus; UINT32 phyBase; UINT32 phyAddr; if (MV_IS_ENET_PORT(phyUnit)) { if (mv_phyIsLinkAlive(phyUnit)) { phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); if (phyHwStatus & MV_STATUS_RESOLVED_DUPLEX_FULL) { return TRUE; } } } return FALSE;}#ifdef CONFIG_VENETDEV_ATH/******************************************************************************** mv_phyDetermineSource - Examine a received frame's Egress Trailer* to determine whether it came from a LAN or WAN port.** RETURNS:* Sets *pFromLAN: 1-->LAN, 0-->WAN* Modifies *pLen to remove PHY trailer from frame*/#define IFLAN 1#define IFWAN 0voidmv_phyDetermineSource(char *data, int len, int *pFromLAN){ unsigned char *phyTrailer; unsigned char incomingPort; #ifdef HEADER_MODE incomingPort = data[1];#else phyTrailer = &data[len - MV_PHY_TRAILER_SIZE];// ASSERT(phyTrailer[0] == MV_EGRESS_TRAILER_VALID); incomingPort = phyTrailer[1];#endif if (MV_IS_LAN_PORT(incomingPort)) { *pFromLAN = IFLAN; } else {// ASSERT(MV_IS_WAN_PORT(incomingPort)); *pFromLAN = IFWAN; } }/******************************************************************************** mv_phySetDestinationPort - Set the Ingress Trailer to force the* frame to be sent to LAN or WAN, as specified.**/voidmv_phySetDestinationPort(char *data, int len, int from){ char *phyTrailer;#ifdef HEADER_MODE char *phyHeader; phyHeader = &data[0]; if (from == IFLAN) { /* LAN ports: Use default settings, as per mvPhyInfo */ phyHeader[0] = 0x00; phyHeader[1] = 0x0f; } else { /* WAN port: Direct to WAN port */ phyHeader[0] = 0x10; phyHeader[1] = 1 << MV_WAN_PORT; } #else phyTrailer = &data[len - MV_PHY_TRAILER_SIZE]; if (from == IFLAN) { /* LAN ports: Use default settings, as per mvPhyInfo */ phyTrailer[0] = 0x00;//MV_INGRESS_TRAILER_OVERRIDE; phyTrailer[1] = 0x0f;//0x00; } else { /* WAN port: Direct to WAN port */ phyTrailer[0] = MV_INGRESS_TRAILER_OVERRIDE; phyTrailer[1] = 1 << MV_WAN_PORT; } phyTrailer[2] = 0x00; phyTrailer[3] = 0x00;#endif }#endif/******************************************************************************* Validate that the specified PHY unit number is a valid PHY ID.* Print a message if it is invalid.* RETURNS* TRUE --> valid* FALSE --> invalid*/LOCAL BOOLmv_validPhyId(int phyUnit){ if ((phyUnit >= MV_ID_MIN) && (phyUnit <= MV_ID_MAX)) { return TRUE; } else { PRINTF("PHY unit number must be in the range [%d..%d]\n", MV_ID_MIN, MV_ID_MAX); return FALSE; } }/******************************************************************************* mv_waitWhileATUBusy - spins until the ATU completes* its previous operation.*/LOCAL voidmv_waitWhileATUBusy(UINT32 phyBase){ BOOL isBusy; UINT16 ATUOperation; do { ATUOperation = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION); isBusy = (ATUOperation & MV_ATU_BUSY_MASK) == MV_ATU_IS_BUSY; } while(isBusy);}/******************************************************************************* mv_flushATUDB - flushes ALL entries in the Address Translation Unit* DataBase associated with phyUnit. [Since we use a single DB for* all PHYs, this flushes the entire shared DataBase.]** The current implementation flushes even more than absolutely needed --* it flushes all entries for all phyUnits on the same ethernet as the* specified phyUnit.** It is called only when a link failure is detected on a port that was* previously working. In other words, when the cable is unplugged.*/voidmv_flushATUDB(int phyUnit){ UINT32 phyBase; if (!mv_validPhyId(phyUnit)) { PRINTF("Invalid port number: %d\n", phyUnit); return; } phyBase = MV_PHYBASE(phyUnit); /* Wait for previous operation (if any) to complete */ mv_waitWhileATUBusy(phyBase); /* Tell hardware to flush all entries */ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION, MV_ATU_OP_FLUSH_ALL | MV_ATU_IS_BUSY); mv_waitWhileATUBusy(phyBase);} /******************************************************************************* mv_phyCheckStatusChange -- checks for significant changes in PHY state.** A "significant change" is:* dropped link (e.g. ethernet cable unplugged) OR* autonegotiation completed + link (e.g. ethernet cable plugged in)*/voidmv_phyCheckStatusChange(int ethUnit){ int phyUnit; UINT16 phyHwStatus; mvPhyInfo_t *lastStatus; int linkCount = 0; int lostLinks = 0; int gainedLinks = 0; UINT32 phyBase; UINT32 phyAddr; for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) { if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = MV_PHYBASE(phyUnit); phyAddr = MV_PHYADDR(phyUnit); lastStatus = &mvPhyInfo[phyUnit]; phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS); if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */ /* See if we've lost link */ if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) { linkCount++; } else { lostLinks++; mv_flushATUDB(phyUnit); MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d down\n", ethUnit, phyUnit)); lastStatus->isPhyAlive = FALSE; } } else { /* last known link status was DEAD */ /* Check for AutoNegotiation complete */ if (MV_AUTONEG_DONE(phyHwStatus)) { gainedLinks++; linkCount++; MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d up\n",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -