/** * cvm_oct_phy_setup_device - setup the PHY * * @dev: Device to setup * * Returns Zero on success, negative on failure */ int cvm_oct_phy_setup_device(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); int phy_addr = cvmx_helper_board_get_mii_address(priv->port); if (phy_addr != -1) { char phy_id[20]; if (phy_addr & 0x100) snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "1", phy_addr & 0xff); else snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "0", phy_addr); priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0, PHY_INTERFACE_MODE_GMII); if (IS_ERR(priv->phydev)) { priv->phydev = NULL; return -1; } priv->last_link = 0; phy_start_aneg(priv->phydev); } return 0; }
/** * Setup the MDIO device structures * * @param dev Device to setup * * @return Zero on success, negative on failure */ int cvm_oct_mdio_setup_device(struct ifnet *ifp) { cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; priv->phy_id = cvmx_helper_board_get_mii_address(priv->port); priv->phy_device = NULL; priv->mdio_read = NULL; priv->mdio_write = NULL; return 0; }
int cvm_oct_mdio_setup_device(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); int phy_id = cvmx_helper_board_get_mii_address(priv->port); if (phy_id != -1) { priv->mii_info.dev = dev; priv->mii_info.phy_id = phy_id; priv->mii_info.phy_id_mask = 0xff; priv->mii_info.supports_gmii = 1; priv->mii_info.reg_num_mask = 0x1f; priv->mii_info.mdio_read = cvm_oct_mdio_read; priv->mii_info.mdio_write = cvm_oct_mdio_write; } else { priv->mii_info.mdio_read = cvm_oct_mdio_dummy_read; priv->mii_info.mdio_write = cvm_oct_mdio_dummy_write; } return 0; }
/** * This function is the board specific method of determining an * ethernet ports link speed. Most Octeon boards have Marvell PHYs * and are handled by the fall through case. This function must be * updated for boards that don't have the normal Marvell PHYs. * * This function must be modified for every new Octeon board. * Internally it uses switch statements based on the cvmx_sysinfo * data to determine board types and revisions. It relies on the * fact that every Octeon board receives a unique board type * enumeration from the bootloader. * * @ipd_port: IPD input port associated with the port we want to get link * status for. * * Returns The ports link status. If the link isn't fully resolved, this must * return zero. */ cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port) { cvmx_helper_link_info_t result; int phy_addr; int is_broadcom_phy = 0; /* Give the user a chance to override the processing of this function */ if (cvmx_override_board_link_get) return cvmx_override_board_link_get(ipd_port); /* Unless we fix it later, all links are defaulted to down */ result.u64 = 0; /* * This switch statement should handle all ports that either don't use * Marvell PHYS, or don't support in-band status. */ switch (cvmx_sysinfo_get()->board_type) { case CVMX_BOARD_TYPE_SIM: /* The simulator gives you a simulated 1Gbps full duplex link */ result.s.link_up = 1; result.s.full_duplex = 1; result.s.speed = 1000; return result; case CVMX_BOARD_TYPE_EBH3100: case CVMX_BOARD_TYPE_CN3010_EVB_HS5: case CVMX_BOARD_TYPE_CN3005_EVB_HS5: case CVMX_BOARD_TYPE_CN3020_EVB_HS5: /* Port 1 on these boards is always Gigabit */ if (ipd_port == 1) { result.s.link_up = 1; result.s.full_duplex = 1; result.s.speed = 1000; return result; } /* Fall through to the generic code below */ break; case CVMX_BOARD_TYPE_CUST_NB5: /* Port 1 on these boards is always Gigabit */ if (ipd_port == 1) { result.s.link_up = 1; result.s.full_duplex = 1; result.s.speed = 1000; return result; } else /* The other port uses a broadcom PHY */ is_broadcom_phy = 1; break; case CVMX_BOARD_TYPE_BBGW_REF: /* Port 1 on these boards is always Gigabit */ if (ipd_port == 2) { /* Port 2 is not hooked up */ result.u64 = 0; return result; } else { /* Ports 0 and 1 connect to the switch */ result.s.link_up = 1; result.s.full_duplex = 1; result.s.speed = 1000; return result; } break; } phy_addr = cvmx_helper_board_get_mii_address(ipd_port); if (phy_addr != -1) { if (is_broadcom_phy) { /* * Below we are going to read SMI/MDIO * register 0x19 which works on Broadcom * parts */ int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0x19); switch ((phy_status >> 8) & 0x7) { case 0: result.u64 = 0; break; case 1: result.s.link_up = 1; result.s.full_duplex = 0; result.s.speed = 10; break; case 2: result.s.link_up = 1; result.s.full_duplex = 1; result.s.speed = 10; break; case 3: result.s.link_up = 1; result.s.full_duplex = 0; result.s.speed = 100; break; case 4: result.s.link_up = 1; result.s.full_duplex = 1; result.s.speed = 100; break; case 5: result.s.link_up = 1; result.s.full_duplex = 1; result.s.speed = 100; break; case 6: result.s.link_up = 1; result.s.full_duplex = 0; result.s.speed = 1000; break; case 7: result.s.link_up = 1; result.s.full_duplex = 1; result.s.speed = 1000; break; } } else { /* * This code assumes we are using a Marvell * Gigabit PHY. All the speed information can * be read from register 17 in one * go. Somebody using a different PHY will * need to handle it above in the board * specific area. */ int phy_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17); /* * If the resolve bit 11 isn't set, see if * autoneg is turned off (bit 12, reg 0). The * resolve bit doesn't get set properly when * autoneg is off, so force it. */ if ((phy_status & (1 << 11)) == 0) { int auto_status = cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 0); if ((auto_status & (1 << 12)) == 0) phy_status |= 1 << 11; } /* * Only return a link if the PHY has finished * auto negotiation and set the resolved bit * (bit 11) */ if (phy_status & (1 << 11)) { result.s.link_up = 1; result.s.full_duplex = ((phy_status >> 13) & 1); switch ((phy_status >> 14) & 3) { case 0: /* 10 Mbps */ result.s.speed = 10; break; case 1: /* 100 Mbps */ result.s.speed = 100; break; case 2: /* 1 Gbps */ result.s.speed = 1000; break; case 3: /* Illegal */ result.u64 = 0; break; } }