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_reset(struct xgbe_prv_data *pdata) { unsigned int count, reg; reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); reg |= MDIO_CTRL1_RESET; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); count = 50; do { msleep(20); reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); } while ((reg & MDIO_CTRL1_RESET) && --count); if (reg & MDIO_CTRL1_RESET) return -ETIMEDOUT; /* Disable auto-negotiation for now */ xgbe_disable_an(pdata); /* Clear auto-negotiation interrupts */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); return 0; }
static enum xgbe_an xgbe_an_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_disable_an(pdata); xgbe_switch_mode(pdata); xgbe_restart_an(pdata); return XGBE_AN_INCOMPAT_LINK; }
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_stop(struct xgbe_prv_data *pdata) { netif_dbg(pdata, link, pdata->netdev, "stopping PHY\n"); /* Disable auto-negotiation */ xgbe_disable_an(pdata); /* Disable auto-negotiation interrupts */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); devm_free_irq(pdata->dev, pdata->an_irq, pdata); pdata->phy.link = 0; netif_carrier_off(pdata->netdev); xgbe_phy_adjust_link(pdata); }