static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) { netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n"); /* Disable auto-negotiation */ xgbe_disable_an(pdata); /* Validate/Set specified speed */ switch (pdata->phy.speed) { case SPEED_10000: xgbe_set_mode(pdata, XGBE_MODE_KR); break; case SPEED_2500: case SPEED_1000: xgbe_set_mode(pdata, XGBE_MODE_KX); break; default: return -EINVAL; } /* Validate duplex mode */ if (pdata->phy.duplex != DUPLEX_FULL) return -EINVAL; return 0; }
static int xgbe_phy_config_fixed(struct xgbe_prv_data *pdata) { enum xgbe_mode mode; netif_dbg(pdata, link, pdata->netdev, "fixed PHY configuration\n"); /* Disable auto-negotiation */ xgbe_an_disable(pdata); /* Set specified mode for specified speed */ mode = pdata->phy_if.phy_impl.get_mode(pdata, pdata->phy.speed); switch (mode) { case XGBE_MODE_KX_1000: case XGBE_MODE_KX_2500: case XGBE_MODE_KR: case XGBE_MODE_SGMII_100: case XGBE_MODE_SGMII_1000: case XGBE_MODE_X: case XGBE_MODE_SFI: break; case XGBE_MODE_UNKNOWN: default: return -EINVAL; } /* Validate duplex mode */ if (pdata->phy.duplex != DUPLEX_FULL) return -EINVAL; xgbe_set_mode(pdata, mode); return 0; }
static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) { set_bit(XGBE_LINK_INIT, &pdata->dev_state); pdata->link_check = jiffies; if (pdata->phy.autoneg != AUTONEG_ENABLE) return xgbe_phy_config_fixed(pdata); netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n"); /* Disable auto-negotiation interrupt */ disable_irq(pdata->an_irq); /* Start auto-negotiation in a supported mode */ if (pdata->phy.advertising & ADVERTISED_10000baseKR_Full) { xgbe_set_mode(pdata, XGBE_MODE_KR); } else if ((pdata->phy.advertising & ADVERTISED_1000baseKX_Full) || (pdata->phy.advertising & ADVERTISED_2500baseX_Full)) { xgbe_set_mode(pdata, XGBE_MODE_KX); } else { enable_irq(pdata->an_irq); return -EINVAL; } /* Disable and stop any in progress auto-negotiation */ xgbe_disable_an(pdata); /* Clear any auto-negotitation interrupts */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); pdata->an_result = XGBE_AN_READY; pdata->an_state = XGBE_AN_READY; pdata->kr_state = XGBE_RX_BPA; pdata->kx_state = XGBE_RX_BPA; /* Re-enable auto-negotiation interrupt */ enable_irq(pdata->an_irq); /* Set up advertisement registers based on current settings */ xgbe_an_init(pdata); /* Enable and start auto-negotiation */ xgbe_restart_an(pdata); return 0; }
static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) { enum xgbe_mode mode; pdata->phy.lp_advertising = 0; if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect) mode = xgbe_cur_mode(pdata); else mode = xgbe_phy_status_aneg(pdata); switch (mode) { case XGBE_MODE_SGMII_100: pdata->phy.speed = SPEED_100; break; case XGBE_MODE_X: case XGBE_MODE_KX_1000: case XGBE_MODE_SGMII_1000: pdata->phy.speed = SPEED_1000; break; case XGBE_MODE_KX_2500: pdata->phy.speed = SPEED_2500; break; case XGBE_MODE_KR: case XGBE_MODE_SFI: pdata->phy.speed = SPEED_10000; break; case XGBE_MODE_UNKNOWN: default: pdata->phy.speed = SPEED_UNKNOWN; } pdata->phy.duplex = DUPLEX_FULL; xgbe_set_mode(pdata, mode); }
static int __xgbe_phy_config_aneg(struct xgbe_prv_data *pdata) { int ret; set_bit(XGBE_LINK_INIT, &pdata->dev_state); pdata->link_check = jiffies; ret = pdata->phy_if.phy_impl.an_config(pdata); if (ret) return ret; if (pdata->phy.autoneg != AUTONEG_ENABLE) { ret = xgbe_phy_config_fixed(pdata); if (ret || !pdata->kr_redrv) return ret; netif_dbg(pdata, link, pdata->netdev, "AN redriver support\n"); } else { netif_dbg(pdata, link, pdata->netdev, "AN PHY configuration\n"); } /* Disable auto-negotiation interrupt */ disable_irq(pdata->an_irq); /* Start auto-negotiation in a supported mode */ if (xgbe_use_mode(pdata, XGBE_MODE_KR)) { xgbe_set_mode(pdata, XGBE_MODE_KR); } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_2500)) { xgbe_set_mode(pdata, XGBE_MODE_KX_2500); } else if (xgbe_use_mode(pdata, XGBE_MODE_KX_1000)) { xgbe_set_mode(pdata, XGBE_MODE_KX_1000); } else if (xgbe_use_mode(pdata, XGBE_MODE_SFI)) { xgbe_set_mode(pdata, XGBE_MODE_SFI); } else if (xgbe_use_mode(pdata, XGBE_MODE_X)) { xgbe_set_mode(pdata, XGBE_MODE_X); } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_1000)) { xgbe_set_mode(pdata, XGBE_MODE_SGMII_1000); } else if (xgbe_use_mode(pdata, XGBE_MODE_SGMII_100)) { xgbe_set_mode(pdata, XGBE_MODE_SGMII_100); } else { enable_irq(pdata->an_irq); return -EINVAL; } /* Disable and stop any in progress auto-negotiation */ xgbe_an_disable_all(pdata); /* Clear any auto-negotitation interrupts */ xgbe_an_clear_interrupts_all(pdata); pdata->an_result = XGBE_AN_READY; pdata->an_state = XGBE_AN_READY; pdata->kr_state = XGBE_RX_BPA; pdata->kx_state = XGBE_RX_BPA; /* Re-enable auto-negotiation interrupt */ enable_irq(pdata->an_irq); xgbe_an_init(pdata); xgbe_an_restart(pdata); return 0; }
static void xgbe_phy_status_aneg(struct xgbe_prv_data *pdata) { unsigned int ad_reg, lp_reg; pdata->phy.lp_advertising = 0; if ((pdata->phy.autoneg != AUTONEG_ENABLE) || pdata->parallel_detect) return xgbe_phy_status_force(pdata); pdata->phy.lp_advertising |= ADVERTISED_Autoneg; pdata->phy.lp_advertising |= ADVERTISED_Backplane; /* Compare Advertisement and Link Partner register 1 */ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA); if (lp_reg & 0x400) pdata->phy.lp_advertising |= ADVERTISED_Pause; if (lp_reg & 0x800) pdata->phy.lp_advertising |= ADVERTISED_Asym_Pause; if (pdata->phy.pause_autoneg) { /* Set flow control based on auto-negotiation result */ pdata->phy.tx_pause = 0; pdata->phy.rx_pause = 0; if (ad_reg & lp_reg & 0x400) { pdata->phy.tx_pause = 1; pdata->phy.rx_pause = 1; } else if (ad_reg & lp_reg & 0x800) { if (ad_reg & 0x400) pdata->phy.rx_pause = 1; else if (lp_reg & 0x400) pdata->phy.tx_pause = 1; } } /* Compare Advertisement and Link Partner register 2 */ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 1); if (lp_reg & 0x80) pdata->phy.lp_advertising |= ADVERTISED_10000baseKR_Full; if (lp_reg & 0x20) { switch (pdata->speed_set) { case XGBE_SPEEDSET_1000_10000: pdata->phy.lp_advertising |= ADVERTISED_1000baseKX_Full; break; case XGBE_SPEEDSET_2500_10000: pdata->phy.lp_advertising |= ADVERTISED_2500baseX_Full; break; } } ad_reg &= lp_reg; if (ad_reg & 0x80) { pdata->phy.speed = SPEED_10000; xgbe_set_mode(pdata, XGBE_MODE_KR); } else if (ad_reg & 0x20) { 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; } xgbe_set_mode(pdata, XGBE_MODE_KX); } else { pdata->phy.speed = SPEED_UNKNOWN; } /* Compare Advertisement and Link Partner register 3 */ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPA + 2); if (lp_reg & 0xc000) pdata->phy.lp_advertising |= ADVERTISED_10000baseR_FEC; pdata->phy.duplex = DUPLEX_FULL; }