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 void xgbe_phy_status(struct xgbe_prv_data *pdata) { unsigned int reg, link_aneg; if (test_bit(XGBE_LINK_ERR, &pdata->dev_state)) { if (test_and_clear_bit(XGBE_LINK, &pdata->dev_state)) netif_carrier_off(pdata->netdev); pdata->phy.link = 0; goto adjust_link; } link_aneg = (pdata->phy.autoneg == AUTONEG_ENABLE); /* Get the link status. Link status is latched low, so read * once to clear and then read again to get current state */ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1); pdata->phy.link = (reg & MDIO_STAT1_LSTATUS) ? 1 : 0; if (pdata->phy.link) { if (link_aneg && !xgbe_phy_aneg_done(pdata)) { xgbe_check_link_timeout(pdata); return; } xgbe_phy_status_aneg(pdata); if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) clear_bit(XGBE_LINK_INIT, &pdata->dev_state); if (!test_bit(XGBE_LINK, &pdata->dev_state)) { set_bit(XGBE_LINK, &pdata->dev_state); netif_carrier_on(pdata->netdev); } } else { if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) { xgbe_check_link_timeout(pdata); if (link_aneg) return; } xgbe_phy_status_aneg(pdata); if (test_bit(XGBE_LINK, &pdata->dev_state)) { clear_bit(XGBE_LINK, &pdata->dev_state); netif_carrier_off(pdata->netdev); } } adjust_link: xgbe_phy_adjust_link(pdata); }
static void axgbe_an37_disable_interrupts(struct axgbe_port *pdata) { int reg; reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); reg &= ~AXGBE_AN_CL37_INT_MASK; XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL); reg &= ~AXGBE_PCS_CL37_BP; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg); }
static void xgbe_an37_enable_interrupts(struct xgbe_prv_data *pdata) { int reg; reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL); reg |= XGBE_PCS_CL37_BP; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_PCS_DIG_CTRL, reg); reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); reg |= XGBE_AN_CL37_INT_MASK; XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); }
static enum xgbe_an xgbe_an73_rx_xnp(struct xgbe_prv_data *pdata, enum xgbe_rx *state) { unsigned int ad_reg, lp_reg; /* Check Extended Next Page support */ ad_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_XNP); lp_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_LPX); 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); }
static void xgbe_an73_init(struct xgbe_prv_data *pdata) { unsigned int advertising, reg; advertising = pdata->phy_if.phy_impl.an_advertising(pdata); /* Set up Advertisement register 3 first */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2); if (advertising & ADVERTISED_10000baseR_FEC) reg |= 0xc000; else reg &= ~0xc000; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, reg); /* Set up Advertisement register 2 next */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1); if (advertising & ADVERTISED_10000baseKR_Full) reg |= 0x80; else reg &= ~0x80; if ((advertising & ADVERTISED_1000baseKX_Full) || (advertising & ADVERTISED_2500baseX_Full)) reg |= 0x20; else reg &= ~0x20; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, reg); /* Set up Advertisement register 1 last */ reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE); if (advertising & ADVERTISED_Pause) reg |= 0x400; else reg &= ~0x400; if (advertising & ADVERTISED_Asym_Pause) reg |= 0x800; else reg &= ~0x800; /* We don't intend to perform XNP */ reg &= ~XGBE_XNP_NP_EXCHANGE; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); netif_dbg(pdata, link, pdata->netdev, "CL73 AN initialized\n"); }
static irqreturn_t xgbe_an_isr(int irq, void *data) { struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n"); /* Disable AN interrupts */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0); /* Save the interrupt(s) that fired */ pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); if (pdata->an_int) { /* Clear the interrupt(s) that fired and process them */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int); queue_work(pdata->an_workqueue, &pdata->an_irq_work); } else { /* Enable AN interrupts */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_INT_MASK); } return IRQ_HANDLED; }
static void xgbe_gmii_mode(struct xgbe_prv_data *pdata) { unsigned int reg; /* Disable KR training */ xgbe_an_disable_kr_training(pdata); /* Set MAC to 1G speed */ pdata->hw_if.set_gmii_speed(pdata); /* Set PCS to KX/1G speed */ reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); reg &= ~MDIO_PCS_CTRL2_TYPE; reg |= MDIO_PCS_CTRL2_10GBX; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL2, reg); reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); reg &= ~MDIO_CTRL1_SPEEDSEL; reg |= MDIO_CTRL1_SPEED1G; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); xgbe_pcs_power_cycle(pdata); /* Set SerDes to 1G speed */ xgbe_serdes_start_ratechange(pdata); XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, DATARATE, XGBE_SPEED_1000_RATE); XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, WORDMODE, XGBE_SPEED_1000_WORD); XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, PLLSEL, XGBE_SPEED_1000_PLL); XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, CDR_RATE, pdata->serdes_cdr_rate[XGBE_SPEED_1000]); XSIR1_IOWRITE_BITS(pdata, SIR1_SPEED, TXAMP, pdata->serdes_tx_amp[XGBE_SPEED_1000]); XRXTX_IOWRITE_BITS(pdata, RXTX_REG20, BLWC_ENA, pdata->serdes_blwc[XGBE_SPEED_1000]); XRXTX_IOWRITE_BITS(pdata, RXTX_REG114, PQ_REG, pdata->serdes_pq_skew[XGBE_SPEED_1000]); XRXTX_IOWRITE_BITS(pdata, RXTX_REG129, RXDFE_CONFIG, pdata->serdes_dfe_tap_cfg[XGBE_SPEED_1000]); XRXTX_IOWRITE(pdata, RXTX_REG22, pdata->serdes_dfe_tap_ena[XGBE_SPEED_1000]); xgbe_serdes_complete_ratechange(pdata); netif_dbg(pdata, link, pdata->netdev, "1GbE KX mode set\n"); }
static void xgbe_an37_clear_interrupts(struct xgbe_prv_data *pdata) { int reg; reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT); reg &= ~XGBE_AN_CL37_INT_MASK; XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg); }
static void xgbe_an37_init(struct xgbe_prv_data *pdata) { unsigned int advertising, reg; advertising = pdata->phy_if.phy_impl.an_advertising(pdata); /* Set up Advertisement register */ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE); if (advertising & ADVERTISED_Pause) reg |= 0x100; else reg &= ~0x100; if (advertising & ADVERTISED_Asym_Pause) reg |= 0x80; else reg &= ~0x80; /* Full duplex, but not half */ reg |= XGBE_AN_CL37_FD_MASK; reg &= ~XGBE_AN_CL37_HD_MASK; XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_ADVERTISE, reg); /* Set up the Control register */ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL); reg &= ~XGBE_AN_CL37_TX_CONFIG_MASK; reg &= ~XGBE_AN_CL37_PCS_MODE_MASK; switch (pdata->an_mode) { case XGBE_AN_MODE_CL37: reg |= XGBE_AN_CL37_PCS_MODE_BASEX; break; case XGBE_AN_MODE_CL37_SGMII: reg |= XGBE_AN_CL37_PCS_MODE_SGMII; break; default: break; } XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_CTRL, reg); netif_dbg(pdata, link, pdata->netdev, "CL37 AN (%s) initialized\n", (pdata->an_mode == XGBE_AN_MODE_CL37) ? "BaseX" : "SGMII"); }
static void xgbe_an73_disable_kr_training(struct xgbe_prv_data *pdata) { unsigned int reg; reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); reg &= ~XGBE_KR_TRAINING_ENABLE; XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); }
static void xgbe_phy_init(struct xgbe_prv_data *pdata) { mutex_init(&pdata->an_mutex); INIT_WORK(&pdata->an_irq_work, xgbe_an_irq_work); INIT_WORK(&pdata->an_work, xgbe_an_state_machine); pdata->mdio_mmd = MDIO_MMD_PCS; /* Initialize supported features */ pdata->phy.supported = SUPPORTED_Autoneg; pdata->phy.supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; pdata->phy.supported |= SUPPORTED_Backplane; pdata->phy.supported |= SUPPORTED_10000baseKR_Full; switch (pdata->speed_set) { case XGBE_SPEEDSET_1000_10000: pdata->phy.supported |= SUPPORTED_1000baseKX_Full; break; case XGBE_SPEEDSET_2500_10000: pdata->phy.supported |= SUPPORTED_2500baseX_Full; break; } pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECABLE); pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE); if (pdata->fec_ability & MDIO_PMA_10GBR_FECABLE_ABLE) pdata->phy.supported |= SUPPORTED_10000baseR_FEC; pdata->phy.advertising = pdata->phy.supported; pdata->phy.address = 0; pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN; pdata->phy.link = 0; pdata->phy.pause_autoneg = pdata->pause_autoneg; pdata->phy.tx_pause = pdata->tx_pause; pdata->phy.rx_pause = pdata->rx_pause; /* Fix up Flow Control advertising */ pdata->phy.advertising &= ~ADVERTISED_Pause; pdata->phy.advertising &= ~ADVERTISED_Asym_Pause; if (pdata->rx_pause) { pdata->phy.advertising |= ADVERTISED_Pause; pdata->phy.advertising |= ADVERTISED_Asym_Pause; } if (pdata->tx_pause) pdata->phy.advertising ^= ADVERTISED_Asym_Pause; if (netif_msg_drv(pdata)) xgbe_dump_phy_registers(pdata); }
static void axgbe_an73_enable_kr_training(struct axgbe_port *pdata) { unsigned int reg; reg = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL); reg |= AXGBE_KR_TRAINING_ENABLE; XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); }
static int xgbe_phy_init(struct xgbe_prv_data *pdata) { int ret; mutex_init(&pdata->an_mutex); INIT_WORK(&pdata->an_irq_work, xgbe_an_irq_work); INIT_WORK(&pdata->an_work, xgbe_an_state_machine); pdata->mdio_mmd = MDIO_MMD_PCS; /* Check for FEC support */ pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECABLE); pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE); /* Setup the phy (including supported features) */ ret = pdata->phy_if.phy_impl.init(pdata); if (ret) return ret; pdata->phy.advertising = pdata->phy.supported; pdata->phy.address = 0; if (pdata->phy.advertising & ADVERTISED_Autoneg) { pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN; } else { pdata->phy.autoneg = AUTONEG_DISABLE; pdata->phy.speed = xgbe_phy_best_advertised_speed(pdata); pdata->phy.duplex = DUPLEX_FULL; } pdata->phy.link = 0; pdata->phy.pause_autoneg = pdata->pause_autoneg; pdata->phy.tx_pause = pdata->tx_pause; pdata->phy.rx_pause = pdata->rx_pause; /* Fix up Flow Control advertising */ pdata->phy.advertising &= ~ADVERTISED_Pause; pdata->phy.advertising &= ~ADVERTISED_Asym_Pause; if (pdata->rx_pause) { pdata->phy.advertising |= ADVERTISED_Pause; pdata->phy.advertising |= ADVERTISED_Asym_Pause; } if (pdata->tx_pause) pdata->phy.advertising ^= ADVERTISED_Asym_Pause; if (netif_msg_drv(pdata)) xgbe_dump_phy_registers(pdata); return 0; }
static ssize_t xpcs_reg_value_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { struct xgbe_prv_data *pdata = filp->private_data; unsigned int value; value = XMDIO_READ(pdata, pdata->debugfs_xpcs_mmd, pdata->debugfs_xpcs_reg); return xgbe_common_read(buffer, count, ppos, value); }
static void xgbe_cur_mode(struct xgbe_prv_data *pdata, enum xgbe_mode *mode) { unsigned int reg; reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL2); if ((reg & MDIO_PCS_CTRL2_TYPE) == MDIO_PCS_CTRL2_10GBR) *mode = XGBE_MODE_KR; else *mode = XGBE_MODE_KX; }
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 void xgbe_pcs_power_cycle(struct xgbe_prv_data *pdata) { unsigned int reg; reg = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); reg |= MDIO_CTRL1_LPOWER; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); usleep_range(75, 100); reg &= ~MDIO_CTRL1_LPOWER; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, reg); }
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); }
static int axgbe_phy_init(struct axgbe_port *pdata) { int ret; pdata->mdio_mmd = MDIO_MMD_PCS; /* Check for FEC support */ pdata->fec_ability = XMDIO_READ(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FECABLE); pdata->fec_ability &= (MDIO_PMA_10GBR_FECABLE_ABLE | MDIO_PMA_10GBR_FECABLE_ERRABLE); /* Setup the phy (including supported features) */ ret = pdata->phy_if.phy_impl.init(pdata); if (ret) return ret; pdata->phy.advertising = pdata->phy.supported; pdata->phy.address = 0; if (pdata->phy.advertising & ADVERTISED_Autoneg) { pdata->phy.autoneg = AUTONEG_ENABLE; pdata->phy.speed = SPEED_UNKNOWN; pdata->phy.duplex = DUPLEX_UNKNOWN; } else { pdata->phy.autoneg = AUTONEG_DISABLE; pdata->phy.speed = axgbe_phy_best_advertised_speed(pdata); pdata->phy.duplex = DUPLEX_FULL; } pdata->phy.link = 0; pdata->phy.pause_autoneg = pdata->pause_autoneg; pdata->phy.tx_pause = pdata->tx_pause; pdata->phy.rx_pause = pdata->rx_pause; /* Fix up Flow Control advertising */ pdata->phy.advertising &= ~ADVERTISED_Pause; pdata->phy.advertising &= ~ADVERTISED_Asym_Pause; if (pdata->rx_pause) { pdata->phy.advertising |= ADVERTISED_Pause; pdata->phy.advertising |= ADVERTISED_Asym_Pause; } if (pdata->tx_pause) pdata->phy.advertising ^= ADVERTISED_Asym_Pause; return 0; }
static int xgbe_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct xgbe_prv_data *pdata = pci_get_drvdata(pdev); struct net_device *netdev = pdata->netdev; int ret = 0; if (netif_running(netdev)) ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT); pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl); return ret; }
static void xgbe_set_an(struct xgbe_prv_data *pdata, bool enable, bool restart) { unsigned int reg; reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1); reg &= ~MDIO_AN_CTRL1_ENABLE; if (enable) reg |= MDIO_AN_CTRL1_ENABLE; if (restart) reg |= MDIO_AN_CTRL1_RESTART; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_CTRL1, reg); }
static void axgbe_an37_set(struct axgbe_port *pdata, bool enable, bool restart) { unsigned int reg; reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_CTRL1); reg &= ~MDIO_VEND2_CTRL1_AN_ENABLE; if (enable) reg |= MDIO_VEND2_CTRL1_AN_ENABLE; if (restart) reg |= MDIO_VEND2_CTRL1_AN_RESTART; XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg); }
static void xgbe_an73_isr(struct xgbe_prv_data *pdata) { /* Disable AN interrupts */ xgbe_an73_disable_interrupts(pdata); /* Save the interrupt(s) that fired */ pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); if (pdata->an_int) { /* Clear the interrupt(s) that fired and process them */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int); queue_work(pdata->an_workqueue, &pdata->an_irq_work); } else { /* Enable AN interrupts */ xgbe_an73_enable_interrupts(pdata); } }
static int xgbe_suspend(struct device *dev) { struct net_device *netdev = dev_get_drvdata(dev); struct xgbe_prv_data *pdata = netdev_priv(netdev); int ret = 0; DBGPR("-->xgbe_suspend\n"); if (netif_running(netdev)) ret = xgbe_powerdown(netdev, XGMAC_DRIVER_CONTEXT); pdata->lpm_ctrl = XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1); pdata->lpm_ctrl |= MDIO_CTRL1_LPOWER; XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl); DBGPR("<--xgbe_suspend\n"); return ret; }
static void axgbe_an73_isr(struct axgbe_port *pdata) { /* Disable AN interrupts */ axgbe_an73_disable_interrupts(pdata); /* Save the interrupt(s) that fired */ pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); if (pdata->an_int) { /* Clear the interrupt(s) that fired and process them */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int); pthread_mutex_lock(&pdata->an_mutex); axgbe_an73_state_machine(pdata); pthread_mutex_unlock(&pdata->an_mutex); } else { /* Enable AN interrupts */ axgbe_an73_enable_interrupts(pdata); } }
static void xgbe_an37_isr(struct xgbe_prv_data *pdata) { unsigned int reg; /* Disable AN interrupts */ xgbe_an37_disable_interrupts(pdata); /* Save the interrupt(s) that fired */ reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT); pdata->an_int = reg & XGBE_AN_CL37_INT_MASK; pdata->an_status = reg & ~XGBE_AN_CL37_INT_MASK; if (pdata->an_int) { /* Clear the interrupt(s) that fired and process them */ reg &= ~XGBE_AN_CL37_INT_MASK; XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_VEND2_AN_STAT, reg); queue_work(pdata->an_workqueue, &pdata->an_irq_work); } else { /* Enable AN interrupts */ xgbe_an37_enable_interrupts(pdata); } }
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; }
static void xgbe_an_state_machine(struct work_struct *work) { struct xgbe_prv_data *pdata = container_of(work, struct xgbe_prv_data, an_work); enum xgbe_an cur_state = pdata->an_state; unsigned int int_reg, int_mask; mutex_lock(&pdata->an_mutex); /* Read the interrupt */ int_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); if (!int_reg) goto out; next_int: if (int_reg & XGBE_AN_PG_RCV) { pdata->an_state = XGBE_AN_PAGE_RECEIVED; int_mask = XGBE_AN_PG_RCV; } else if (int_reg & XGBE_AN_INC_LINK) { pdata->an_state = XGBE_AN_INCOMPAT_LINK; int_mask = XGBE_AN_INC_LINK; } else if (int_reg & XGBE_AN_INT_CMPLT) { pdata->an_state = XGBE_AN_COMPLETE; int_mask = XGBE_AN_INT_CMPLT; } else { pdata->an_state = XGBE_AN_ERROR; int_mask = 0; } /* Clear the interrupt to be processed */ int_reg &= ~int_mask; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, int_reg); pdata->an_result = pdata->an_state; again: netif_dbg(pdata, link, pdata->netdev, "AN %s\n", xgbe_state_as_string(pdata->an_state)); cur_state = pdata->an_state; switch (pdata->an_state) { case XGBE_AN_READY: pdata->an_supported = 0; break; case XGBE_AN_PAGE_RECEIVED: pdata->an_state = xgbe_an_page_received(pdata); pdata->an_supported++; break; case XGBE_AN_INCOMPAT_LINK: pdata->an_supported = 0; pdata->parallel_detect = 0; pdata->an_state = xgbe_an_incompat_link(pdata); break; case XGBE_AN_COMPLETE: pdata->parallel_detect = pdata->an_supported ? 0 : 1; netif_dbg(pdata, link, pdata->netdev, "%s successful\n", pdata->an_supported ? "Auto negotiation" : "Parallel detection"); break; case XGBE_AN_NO_LINK: break; default: pdata->an_state = XGBE_AN_ERROR; } if (pdata->an_state == XGBE_AN_NO_LINK) { int_reg = 0; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); } else if (pdata->an_state == XGBE_AN_ERROR) { netdev_err(pdata->netdev, "error during auto-negotiation, state=%u\n", cur_state); int_reg = 0; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); } if (pdata->an_state >= XGBE_AN_COMPLETE) { pdata->an_result = pdata->an_state; pdata->an_state = XGBE_AN_READY; pdata->kr_state = XGBE_RX_BPA; pdata->kx_state = XGBE_RX_BPA; pdata->an_start = 0; netif_dbg(pdata, link, pdata->netdev, "AN result: %s\n", xgbe_state_as_string(pdata->an_result)); } if (cur_state != pdata->an_state) goto again; if (int_reg) goto next_int; out: enable_irq(pdata->an_irq); mutex_unlock(&pdata->an_mutex); }
static void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata) { struct device *dev = pdata->dev; dev_dbg(dev, "\n************* PHY Reg dump **********************\n"); dev_dbg(dev, "PCS Control Reg (%#06x) = %#06x\n", MDIO_CTRL1, XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_CTRL1)); dev_dbg(dev, "PCS Status Reg (%#06x) = %#06x\n", MDIO_STAT1, XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_STAT1)); dev_dbg(dev, "Phy Id (PHYS ID 1 %#06x)= %#06x\n", MDIO_DEVID1, XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID1)); dev_dbg(dev, "Phy Id (PHYS ID 2 %#06x)= %#06x\n", MDIO_DEVID2, XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVID2)); dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS1, XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS1)); dev_dbg(dev, "Devices in Package (%#06x)= %#06x\n", MDIO_DEVS2, XMDIO_READ(pdata, MDIO_MMD_PCS, MDIO_DEVS2)); dev_dbg(dev, "Auto-Neg Control Reg (%#06x) = %#06x\n", MDIO_CTRL1, XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_CTRL1)); dev_dbg(dev, "Auto-Neg Status Reg (%#06x) = %#06x\n", MDIO_STAT1, XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_STAT1)); dev_dbg(dev, "Auto-Neg Ad Reg 1 (%#06x) = %#06x\n", MDIO_AN_ADVERTISE, XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE)); dev_dbg(dev, "Auto-Neg Ad Reg 2 (%#06x) = %#06x\n", MDIO_AN_ADVERTISE + 1, XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1)); dev_dbg(dev, "Auto-Neg Ad Reg 3 (%#06x) = %#06x\n", MDIO_AN_ADVERTISE + 2, XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2)); dev_dbg(dev, "Auto-Neg Completion Reg (%#06x) = %#06x\n", MDIO_AN_COMP_STAT, XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_COMP_STAT)); dev_dbg(dev, "\n*************************************************\n"); }