static enum xgbe_an xgbe_an73_incompat_link(struct xgbe_prv_data *pdata) { /* Be sure we aren't looping trying to negotiate */ if (xgbe_in_kr_mode(pdata)) { pdata->kr_state = XGBE_RX_ERROR; if (!(pdata->phy.advertising & ADVERTISED_1000baseKX_Full) && !(pdata->phy.advertising & ADVERTISED_2500baseX_Full)) return XGBE_AN_NO_LINK; if (pdata->kx_state != XGBE_RX_BPA) return XGBE_AN_NO_LINK; } else { pdata->kx_state = XGBE_RX_ERROR; if (!(pdata->phy.advertising & ADVERTISED_10000baseKR_Full)) return XGBE_AN_NO_LINK; if (pdata->kr_state != XGBE_RX_BPA) return XGBE_AN_NO_LINK; } xgbe_an73_disable(pdata); xgbe_switch_mode(pdata); xgbe_an73_restart(pdata); return XGBE_AN_INCOMPAT_LINK; }
static void xgbe_switch_mode(struct xgbe_prv_data *pdata) { /* If we are in KR switch to KX, and vice-versa */ if (xgbe_in_kr_mode(pdata)) { if (pdata->speed_set == XGBE_SPEEDSET_1000_10000) xgbe_gmii_mode(pdata); else xgbe_gmii_2500_mode(pdata); } else { xgbe_xgmii_mode(pdata); } }
static void xgbe_phy_status_force(struct xgbe_prv_data *pdata) { if (xgbe_in_kr_mode(pdata)) { pdata->phy.speed = SPEED_10000; } else { switch (pdata->speed_set) { case XGBE_SPEEDSET_1000_10000: pdata->phy.speed = SPEED_1000; break; case XGBE_SPEEDSET_2500_10000: pdata->phy.speed = SPEED_2500; break; } } pdata->phy.duplex = DUPLEX_FULL; }
static enum xgbe_an xgbe_an73_page_received(struct xgbe_prv_data *pdata) { enum xgbe_rx *state; unsigned long an_timeout; enum xgbe_an ret; if (!pdata->an_start) { pdata->an_start = jiffies; } else { an_timeout = pdata->an_start + msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); if (time_after(jiffies, an_timeout)) { /* Auto-negotiation timed out, reset state */ pdata->kr_state = XGBE_RX_BPA; pdata->kx_state = XGBE_RX_BPA; pdata->an_start = jiffies; netif_dbg(pdata, link, pdata->netdev, "CL73 AN timed out, resetting state\n"); } } state = xgbe_in_kr_mode(pdata) ? &pdata->kr_state : &pdata->kx_state; switch (*state) { case XGBE_RX_BPA: ret = xgbe_an73_rx_bpa(pdata, state); break; case XGBE_RX_XNP: ret = xgbe_an73_rx_xnp(pdata, state); break; default: ret = XGBE_AN_ERROR; } return ret; }
static enum xgbe_an xgbe_an73_tx_training(struct xgbe_prv_data *pdata, enum xgbe_rx *state) { unsigned int ad_reg, lp_reg, reg; *state = XGBE_RX_COMPLETE; /* If we're not in KR mode then we're done */ if (!xgbe_in_kr_mode(pdata)) return XGBE_AN_PAGE_RECEIVED; /* Enable/Disable FEC */ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL); reg &= ~(MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE); if ((ad_reg & 0xc000) && (lp_reg & 0xc000)) reg |= pdata->fec_ability; XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECCTRL, reg); /* Start KR training */ reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); if (reg & XGBE_KR_TRAINING_ENABLE) { if (pdata->phy_if.phy_impl.kr_training_pre) pdata->phy_if.phy_impl.kr_training_pre(pdata); reg |= XGBE_KR_TRAINING_START; XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); if (pdata->phy_if.phy_impl.kr_training_post) pdata->phy_if.phy_impl.kr_training_post(pdata); netif_dbg(pdata, link, pdata->netdev, "KR training initiated\n"); } return XGBE_AN_PAGE_RECEIVED; }
static enum xgbe_an xgbe_an73_rx_bpa(struct xgbe_prv_data *pdata, enum xgbe_rx *state) { unsigned int link_support; unsigned int reg, ad_reg, lp_reg; /* Read Base Ability register 2 first */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); /* Check for a supported mode, otherwise restart in a different one */ link_support = xgbe_in_kr_mode(pdata) ? 0x80 : 0x20; if (!(reg & link_support)) return XGBE_AN_INCOMPAT_LINK; /* Check Extended Next Page support */ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); return ((ad_reg & XGBE_XNP_NP_EXCHANGE) || (lp_reg & XGBE_XNP_NP_EXCHANGE)) ? xgbe_an73_tx_xnp(pdata, state) : xgbe_an73_tx_training(pdata, state); }