/***************************************************************************** * * ip_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) */ void ip_phyCheckStatusChange(int ethUnit) { int phyUnit; UINT16 phyHwStatus; ipPhyInfo_t *lastStatus; int linkCount = 0; int lostLinks = 0; int gainedLinks = 0; UINT32 phyBase; UINT32 phyAddr; for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); lastStatus = &ipPhyInfo[phyUnit]; phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS); if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */ /* See if we've lost link */ if (phyHwStatus & IP_STATUS_LINK_PASS) { linkCount++; } else { lostLinks++; #ifdef COBRA_TODO mv_flushATUDB(phyUnit); #endif DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d down\n", ethUnit, phyUnit)); lastStatus->isPhyAlive = FALSE; } } else { /* last known link status was DEAD */ /* Check for AutoNegotiation complete */ if (IP_AUTONEG_DONE(phyHwStatus)) { gainedLinks++; linkCount++; DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d up\n", ethUnit, phyUnit)); lastStatus->isPhyAlive = TRUE; } } } if (linkCount == 0) { if (lostLinks) { /* We just lost the last link for this MAC */ ae_unitLinkLost(ethUnit); } } else { if (gainedLinks == linkCount) { /* We just gained our first link(s) for this MAC */ ae_unitLinkGained(ethUnit); } } }
BOOL ip_phySpeed(int ethUnit) { int phyUnit; uint16_t phyHwStatus; uint32_t phyBase; uint32_t phyAddr; for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (ip_phyIsLinkAlive(phyUnit)) { phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, IP_LINK_PARTNER_ABILITY); if (phyHwStatus & IP_LINK_100BASETX) { return AG7100_PHY_SPEED_100TX; } } } return AG7100_PHY_SPEED_10T; }
/****************************************************************************** * * ip_phyIsSpeed100 - Determines the speed of phy ports associated with the * specified device. * * RETURNS: * TRUE --> at least one associated PHY at 100 Mbit * FALSE --> all 10Mbit, or no links */ BOOL ip_phyIsSpeed100(int ethUnit) { int phyUnit; UINT16 phyHwStatus; UINT32 phyBase; UINT32 phyAddr; for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (ip_phyIsLinkAlive(phyUnit)) { phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, IP_LINK_PARTNER_ABILITY); if (phyHwStatus & IP_LINK_100BASETX) { return TRUE; } } } return FALSE; }
/****************************************************************************** * * ip_phyIsDuplexFull - Determines whether the phy ports associated with the * specified device are FULL or HALF duplex. * * RETURNS: * 1 --> FULL * 0 --> HALF */ int ip_phyIsFullDuplex(int ethUnit) { int phyUnit; uint32_t phyBase; uint32_t phyAddr; uint16_t phyHwStatus; for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (ip_phyIsLinkAlive(phyUnit)) { phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, IP_LINK_PARTNER_ABILITY); printk("ipPhy.c: phyHwStatus 0x%x\n",phyHwStatus); if ((phyHwStatus & IP_LINK_100BASETX_FULL_DUPLEX) || (phyHwStatus & IP_LINK_10BASETX_FULL_DUPLEX)) { return TRUE; } } return -1; } return FALSE; }
/***************************************************************************** * * ip_phySet - Modify the value of a PHY register (debug only). */ void ip_phySet(int phyUnit, UINT32 regnum, UINT32 value) { UINT32 phyBase; UINT32 phyAddr; if (ip_validPhyId(phyUnit)) { phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyRegWrite(phyBase, phyAddr, regnum, value); } }
/***************************************************************************** * * ip_phySet - Modify the value of a PHY register (debug only). */ void ip_phySet(int phyUnit, uint32_t regnum, uint32_t value) { uint32_t phyBase; uint32_t phyAddr; if (ip_validPhyId(phyUnit)) { phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phy_reg_write(phyBase, phyAddr, regnum, value); } }
/****************************************************************************** * * ip_phyIsLinkAlive - test to see if the specified link is alive * * RETURNS: * TRUE --> link is alive * FALSE --> link is down */ BOOL ip_phyIsLinkAlive(int phyUnit) { UINT16 phyHwStatus; UINT32 phyBase; UINT32 phyAddr; phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS); if (phyHwStatus & IP_STATUS_LINK_PASS) { return TRUE; } else { return FALSE; } }
/****************************************************************************** * * ip_phyIsLinkAlive - test to see if the specified link is alive * * RETURNS: * TRUE --> link is alive * FALSE --> link is down */ BOOL ip_phyIsLinkAlive(int phyUnit) { uint16_t phyHwStatus; uint32_t phyBase; uint32_t phyAddr; phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phy_reg_read(phyBase, phyAddr, IP_PHY_STATUS); if (phyHwStatus & IP_STATUS_LINK_PASS) { return TRUE; } else { return FALSE; } }
void vlan_init(int portmask) { int phyUnit; unsigned int phyBase; unsigned int phyReg; unsigned int phyAddr; int i; int numports = 5; for (i = 0; i < numports - 1; i++) // last one will be wan port { ipPhyInfo[i].VLANTableSetting = IP_LAN_PORT_VLAN; } ipPhyInfo[i++].VLANTableSetting = IP_WAN_PORT_VLAN; ipPhyInfo[i].VLANTableSetting = IP_LAN_PORT_VLAN; ipPhyInfo[i].isEnetPort = FALSE; ipPhyInfo[i].isPhyAlive = TRUE; ipPhyInfo[i++].phyAddr = 0x0; numports = i; fprintf(stderr, "Reset ICPLUS Phy\n"); for (phyUnit = 0; phyUnit < numports; phyUnit++) { if (((1 << phyUnit) & portmask)) { phyAddr = IP_PHYADDR(phyUnit); setPhy(phyAddr, IP_PHY_CONTROL, IP_CTRL_SOFTWARE_RESET); } } sleep(1); fprintf(stderr, "Start Autonegotiation\n"); for (phyUnit = 0; phyUnit < numports; phyUnit++) { if (((1 << phyUnit) & portmask)) { phyAddr = IP_PHYADDR(phyUnit); setPhy(phyAddr, IP_AUTONEG_ADVERT, IP_ADVERTISE_ALL); setPhy(phyAddr, IP_PHY_CONTROL, IP_CTRL_AUTONEGOTIATION_ENABLE | IP_CTRL_START_AUTONEGOTIATION); } } int timeout = 5; for (phyUnit = 0; (phyUnit < numports); phyUnit++) { if (((1 << phyUnit) & portmask)) { for (;;) { phyAddr = IP_PHYADDR(phyUnit); int phyHwStatus = getPhy(phyAddr, IP_PHY_STATUS); if (IP_AUTONEG_DONE(phyHwStatus)) { fprintf(stderr, "Port %d, Neg Success\n", phyUnit); break; } if (timeout == 0) { fprintf(stderr, "Port %d, Negogiation timeout\n", phyUnit); break; } if (--timeout == 0) { fprintf(stderr, "Port %d, Negogiation timeout\n", phyUnit); break; } usleep(150); } } } fprintf(stderr, "Setup VLANS\n"); /* * setPhy(29,24,0); setPhy(29,25,0); setPhy(29,26,0); setPhy(29,27,0); * setPhy(29,28,2); setPhy(29,30,0); setPhy(29,23,0x07c2); * setPhy(30,1,0x002f); setPhy(30,2,0x0030); setPhy(30,9,0x1089); */ unsigned int phy1Reg = 0; unsigned int phy2Reg = 0; unsigned int phy23Reg = 0; unsigned int phy9Reg = 0; for (phyUnit = 0; phyUnit < numports; phyUnit++) { if (((1 << phyUnit) & portmask)) { setPhy(IP_GLOBAL_PHY29_ADDR, IP_GLOBAL_PHY29_24_REG + ((phyUnit == 5) ? (phyUnit + 1) : phyUnit), IP_VLAN_TABLE_SETTING(phyUnit)); fprintf(stderr, "write register %d, addr %d with %X\n", IP_GLOBAL_PHY29_ADDR, IP_GLOBAL_PHY29_24_REG + ((phyUnit == 5) ? (phyUnit + 1) : phyUnit), IP_VLAN_TABLE_SETTING(phyUnit)); if (IP_IS_ENET_PORT(phyUnit)) { if (IP_IS_WAN_PORT(phyUnit)) { phy2Reg |= ((1 << phyUnit) << IP_VLAN2_OUTPUT_PORT_MASK_S); } else { phy1Reg |= ((1 << phyUnit) << IP_VLAN0_OUTPUT_PORT_MASK_S); } phy23Reg = phy23Reg | ((1 << phyUnit) << IP_PORTX_REMOVE_TAG_S); phy23Reg = phy23Reg & ~((1 << phyUnit) << IP_PORTX_ADD_TAG_S); } else { phy1Reg |= ((1 << phyUnit) << IP_VLAN0_OUTPUT_PORT_MASK_S); phy2Reg |= ((1 << phyUnit) << IP_VLAN2_OUTPUT_PORT_MASK_S); phy23Reg = phy23Reg | (1 << IP_PORT5_ADD_TAG_S); phy23Reg = phy23Reg & ~(1 << IP_PORT5_REMOVE_TAG_S); } } } phy9Reg = 0; //getPhy(IP_GLOBAL_PHY30_ADDR,IP_GLOBAL_PHY30_9_REG); phy9Reg = phy9Reg | TAG_VLAN_ENABLE; phy9Reg = phy9Reg & ~VID_INDX_SEL_M; phy9Reg = phy9Reg | 1; //1 vlan group used for lan phy9Reg = phy9Reg | 1 << 3; //enable smart mac phy9Reg = phy9Reg | 1 << 12; //port 4 is a wan port (required for smart mac) fprintf(stderr, "write register %d, addr %d with %X\n", IP_GLOBAL_PHY29_ADDR, IP_GLOBAL_PHY29_23_REG, phy23Reg); fprintf(stderr, "write register %d, addr %d with %X\n", IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG, phy1Reg); fprintf(stderr, "write register %d, addr %d with %X\n", IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_2_REG, phy2Reg); fprintf(stderr, "write register %d, addr %d with %X\n", IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG, phy9Reg); setPhy(IP_GLOBAL_PHY29_ADDR, IP_GLOBAL_PHY29_23_REG, phy23Reg); setPhy(IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG, phy1Reg); setPhy(IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_2_REG, phy2Reg); setPhy(IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG, phy9Reg); // // echo "echo \"WRITE 29 23 07c2\" > ".$mii_dev."\n"; // // echo "echo \"WRITE 29 24 0\" > ".$mii_dev."\n"; /* PORT0 Default VLAN ID */ // echo "echo \"WRITE 29 25 0\" > ".$mii_dev."\n"; /* PORT1 Default VLAN ID */ // echo "echo \"WRITE 29 26 0\" > ".$mii_dev."\n"; /* PORT2 Default VLAN ID */ // echo "echo \"WRITE 29 27 0\" > ".$mii_dev."\n"; /* PORT3 Default VLAN ID */ // echo "echo \"WRITE 29 28 2\" > ".$mii_dev."\n"; /* PORT4 Default VLAN ID */ // echo "echo \"WRITE 29 30 0\" > ".$mii_dev."\n"; /* PORT5 Default VLAN ID (CPU) */ // echo "echo \"WRITE 29 23 07c2\" > ".$mii_dev."\n"; // echo "echo \"WRITE 30 1 002f\" > ".$mii_dev."\n"; /* Port 5,3,2,1,0 = VLAN 0 */ // echo "echo \"WRITE 30 2 0030\" > ".$mii_dev."\n"; /* Port 5,4 = VLAN 2 */ // echo "echo \"WRITE 30 9 1089\" > ".$mii_dev."\n"; eval("vconfig", "set_name_type", "VLAN_PLUS_VID_NO_PAD"); eval("vconfig", "add", "eth0", "0"); eval("vconfig", "add", "eth0", "2"); struct ifreq ifr; int s; if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))) { char eabuf[32]; strncpy(ifr.ifr_name, "eth0", IFNAMSIZ); ioctl(s, SIOCGIFHWADDR, &ifr); char macaddr[32]; strcpy(macaddr, ether_etoa((unsigned char *)ifr.ifr_hwaddr.sa_data, eabuf)); nvram_set("et0macaddr", macaddr); // MAC_ADD (macaddr); ether_atoe(macaddr, (unsigned char *)ifr.ifr_hwaddr.sa_data); strncpy(ifr.ifr_name, "vlan2", IFNAMSIZ); ioctl(s, SIOCSIFHWADDR, &ifr); close(s); } eval("ifconfig", "vlan0", "promisc"); eval("ifconfig", "vlan2", "promisc"); }
/****************************************************************************** * * ip_phySetup - reset and setup the PHY switch. * * Resets each PHY port. * * RETURNS: * TRUE --> at least 1 PHY with LINK * FALSE --> no LINKs on this ethernet unit */ BOOL ip_phySetup(int ethUnit) { int phyUnit; UINT16 phyHwStatus; UINT16 timeout; int liveLinks = 0; UINT32 phyBase = 0; BOOL foundPhy = FALSE; UINT32 phyAddr; /* Reset PHYs*/ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyRegWrite(phyBase, phyAddr, IP_PHY_CONTROL, IP_CTRL_SOFTWARE_RESET); } /* * After the phy is reset, it takes a little while before * it can respond properly. */ sysMsDelay(300); /* Verify that the switch is what we think it is, and that it's ready */ ip_verifyReady(ethUnit); /* See if there's any configuration data for this enet */ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (IP_ETHUNIT(phyUnit) != ethUnit) { continue; } phyBase = IP_PHYBASE(phyUnit); foundPhy = TRUE; break; } if (!foundPhy) { return FALSE; /* No PHY's configured for this ethUnit */ } #ifdef COBRA_TODO /* Initialize global switch settings */ /* Initialize the aging time */ /* Set the learning properties */ #endif /* start auto negogiation on each phy */ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyRegWrite(phyBase, phyAddr, IP_AUTONEG_ADVERT, IP_ADVERTISE_ALL); phyRegWrite(phyBase, phyAddr, IP_PHY_CONTROL, IP_CTRL_AUTONEGOTIATION_ENABLE | IP_CTRL_START_AUTONEGOTIATION); } /* * Wait up to .75 seconds for ALL associated PHYs to finish * autonegotiation. The only way we get out of here sooner is * if ALL PHYs are connected AND finish autonegotiation. */ timeout=5; for (phyUnit=0; (phyUnit < IP_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } for (;;) { phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS); if (IP_AUTONEG_DONE(phyHwStatus)) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Neg Success\n", phyUnit)); break; } if (timeout == 0) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit)); break; } if (--timeout == 0) { DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Port %d, Negogiation timeout\n", phyUnit)); break; } sysMsDelay(150); } } /* * 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 < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } if (ip_phyIsLinkAlive(phyUnit)) { liveLinks++; IP_IS_PHY_ALIVE(phyUnit) = TRUE; } else { IP_IS_PHY_ALIVE(phyUnit) = FALSE; } DRV_PRINT(DRV_DEBUG_PHYSETUP, ("eth%d: Phy Status=%4.4x\n", ethUnit, phyRegRead(IP_PHYBASE(phyUnit), IP_PHYADDR(phyUnit), IP_PHY_STATUS))); } ip_VLANInit(ethUnit); return (liveLinks > 0); }
/***************************************************************************** * * ip_phyShow - Dump the state of a PHY. * There are two sets of registers for each phy port: * "phy registers" and * "switch port registers" * We dump 'em all, plus the switch global registers. */ void ip_phyShow(int phyUnit) { int i; UINT16 value; UINT32 phyBase; UINT32 phyAddr; if (!ip_validPhyId(phyUnit)) { return; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); printf("PHY state for PHY%d (enet%d, phyBase 0x%8x, phyAddr 0x%x)\n", phyUnit, IP_ETHUNIT(phyUnit), IP_PHYBASE(phyUnit), IP_PHYADDR(phyUnit)); printf("PHY Registers:\n"); for (i=0; i < ipPhyNumRegs; i++) { value = phyRegRead(phyBase, phyAddr, ipPhyRegisterTable[i].regNum); printf("Reg %02d (0x%02x) %s = 0x%08x\n", ipPhyRegisterTable[i].regNum, ipPhyRegisterTable[i].regNum, ipPhyRegisterTable[i].regIdString, value); } phyBase = IP_GLOBALREGBASE; printf("Switch Global Registers:\n"); printf("Phy29 Registers:\n"); for (i=0; i < ipPhy29GlobalNumRegs; i++) { value = phyRegRead(phyBase, IP_GLOBAL_PHY29_ADDR, ipPhy29GlobalRegisterTable[i].regNum); printf("Reg %02d (0x%02x) %s = 0x%08x\n", ipPhy29GlobalRegisterTable[i].regNum, ipPhy29GlobalRegisterTable[i].regNum, ipPhy29GlobalRegisterTable[i].regIdString, value); } printf("Phy30 Registers:\n"); for (i=0; i < ipPhy30GlobalNumRegs; i++) { value = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR, ipPhy30GlobalRegisterTable[i].regNum); printf("Reg %02d (0x%02x) %s = 0x%08x\n", ipPhy30GlobalRegisterTable[i].regNum, ipPhy30GlobalRegisterTable[i].regNum, ipPhy30GlobalRegisterTable[i].regIdString, value); } printf("Phy31 Registers:\n"); for (i=0; i < ipPhy31GlobalNumRegs; i++) { value = phyRegRead(phyBase, IP_GLOBAL_PHY31_ADDR, ipPhy31GlobalRegisterTable[i].regNum); printf("Reg %02d (0x%02x) %s = 0x%08x\n", ipPhy31GlobalRegisterTable[i].regNum, ipPhy31GlobalRegisterTable[i].regNum, ipPhy31GlobalRegisterTable[i].regIdString, value); } }
LOCAL void ip_verifyReady(int ethUnit) { int phyUnit; UINT32 phyBase = 0; UINT32 phyAddr; UINT16 phyID1; UINT16 phyID2; /* * The first read to the Phy port registers always fails and * returns 0. So get things started with a bogus read. */ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyID1 = phyRegRead(phyBase, phyAddr, IP_PHY_ID1); /* returns 0 */ break; } for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) { if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) { continue; } /*******************/ /* Verify phy port */ /*******************/ phyBase = IP_PHYBASE(phyUnit); phyAddr = IP_PHYADDR(phyUnit); phyID1 = phyRegRead(phyBase, phyAddr, IP_PHY_ID1); if (phyID1 != IP_PHY_ID1_EXPECTATION) { DRV_PRINT(DRV_DEBUG_PHYERROR, ("Invalid PHY ID1 for enet%d port%d. Expected 0x%04x, read 0x%04x\n", ethUnit, phyUnit, IP_PHY_ID1_EXPECTATION, phyID1)); return; } phyID2 = phyRegRead(phyBase, phyAddr, IP_PHY_ID2); if ((phyID2 & IP_OUI_LSB_MASK) != IP_OUI_LSB_EXPECTATION) { DRV_PRINT(DRV_DEBUG_PHYERROR, ("Invalid PHY ID2 for enet%d port %d. Expected 0x%04x, read 0x%04x\n", ethUnit, phyUnit, IP_OUI_LSB_EXPECTATION, phyID2)); return; } DRV_PRINT(DRV_DEBUG_PHYSETUP, ("Found PHY enet%d port%d: model 0x%x revision 0x%x\n", ethUnit, phyUnit, (phyID2 & IP_MODEL_NUM_MASK) >> IP_MODEL_NUM_SHIFT, (phyID2 & IP_REV_NUM_MASK) >> IP_REV_NUM_SHIFT)); } }