static int tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; return 0; } phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); if (loop_reset || phy_mode_change) { tenxpress_special_reset(efx); falcon_reset_xaui(efx); } tenxpress_low_power(efx); efx_mdio_transmit_disable(efx); efx_mdio_phy_reconfigure(efx); tenxpress_ext_loopback(efx); efx_mdio_an_reconfigure(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; return 0; }
int falcon_init_xmac(struct efx_nic *efx) { int rc; /* Initialize the PHY first so the clock is around */ rc = efx->phy_op->init(efx); if (rc) goto fail1; rc = falcon_reset_xaui(efx); if (rc) goto fail2; /* Wait again. Give the PHY and MAC time to come back */ schedule_timeout_uninterruptible(HZ / 10); rc = falcon_reset_xmac(efx); if (rc) goto fail2; falcon_mask_status_intr(efx, true); return 0; fail2: efx->phy_op->fini(efx); fail1: return rc; }
static int tenxpress_phy_init(struct efx_nic *efx) { int rc; falcon_board(efx)->type->init_phy(efx); if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) return rc; rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) return rc; } rc = tenxpress_init(efx); if (rc < 0) return rc; /* Reinitialise flow control settings */ efx_link_set_wanted_fc(efx, efx->wanted_fc); efx_mdio_an_reconfigure(efx); schedule_timeout_uninterruptible(HZ / 5); /* 200ms */ /* Let XGXS and SerDes out of reset */ falcon_reset_xaui(efx); return 0; }
/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails * to come back up. Bash it until it comes back up */ static bool falcon_check_xaui_link_up(struct efx_nic *efx) { int max_tries, tries; tries = EFX_WORKAROUND_5147(efx) ? 5 : 1; max_tries = tries; if ((efx->loopback_mode == LOOPBACK_NETWORK) || (efx->phy_type == PHY_TYPE_NONE) || efx_phy_mode_disabled(efx->phy_mode)) return false; while (tries) { if (falcon_xaui_link_ok(efx)) return true; EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n", __func__, tries); falcon_reset_xaui(efx); udelay(200); tries--; } EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n", max_tries); return false; }
static int txc43128_phy_reconfigure(struct efx_nic *efx) { struct txc43128_data *phy_data = efx->phy_data; enum efx_phy_mode mode_change = efx->phy_mode ^ phy_data->phy_mode; bool loop_change = LOOPBACK_CHANGED(phy_data, efx, TXC_LOOPBACKS); if (efx->phy_mode & mode_change & PHY_MODE_TX_DISABLED) { txc_reset_phy(efx); txc_apply_defaults(efx); falcon_reset_xaui(efx); mode_change &= ~PHY_MODE_TX_DISABLED; } efx_mdio_transmit_disable(efx); efx_mdio_phy_reconfigure(efx); if (mode_change & PHY_MODE_LOW_POWER) txc_set_power(efx); /* The data sheet claims this is required after every reconfiguration * (note at end of 7.1), but we mustn't do it when nothing changes as * it glitches the link, and reconfigure gets called on link change, * so we get an IRQ storm on link up. */ if (loop_change || mode_change) txc_reset_logic(efx); phy_data->phy_mode = efx->phy_mode; phy_data->loopback_mode = efx->loopback_mode; return 0; }
static int tenxpress_phy_init(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data; int rc = 0; phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); if (!phy_data) return -ENOMEM; efx->phy_data = phy_data; phy_data->phy_mode = efx->phy_mode; if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { if (efx->phy_type == PHY_TYPE_SFT9001A) { int reg; reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= (1 << PMA_PMD_EXT_SSR_LBN); mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); mdelay(200); } rc = mdio_clause45_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) goto fail; rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); if (rc < 0) goto fail; } rc = tenxpress_init(efx); if (rc < 0) goto fail; mdio_clause45_set_pause(efx); if (efx->phy_type == PHY_TYPE_SFT9001B) { rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_short_reach); if (rc) goto fail; } schedule_timeout_uninterruptible(HZ / 5); /* 200ms */ /* Let XGXS and SerDes out of reset */ falcon_reset_xaui(efx); return 0; fail: kfree(efx->phy_data); efx->phy_data = NULL; return rc; }
static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; struct ethtool_cmd ecmd; bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; return; } tenxpress_low_power(efx); phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); if (loop_reset || phy_mode_change) { int rc; efx->phy_op->get_settings(efx, &ecmd); if (loop_reset || phy_mode_change) { tenxpress_special_reset(efx); /* Reset XAUI if we were in 10G, and are staying * in 10G. If we're moving into and out of 10G * then xaui will be reset anyway */ if (EFX_IS10G(efx)) falcon_reset_xaui(efx); } rc = efx->phy_op->set_settings(efx, &ecmd); WARN_ON(rc); } mdio_clause45_transmit_disable(efx); mdio_clause45_phy_reconfigure(efx); tenxpress_ext_loopback(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; if (efx->phy_type == PHY_TYPE_SFX7101) { efx->link_speed = 10000; efx->link_fd = true; efx->link_up = sfx7101_link_ok(efx); } else { efx->phy_op->get_settings(efx, &ecmd); efx->link_speed = ecmd.speed; efx->link_fd = ecmd.duplex == DUPLEX_FULL; efx->link_up = sft9001_link_ok(efx, &ecmd); } efx->link_fc = mdio_clause45_get_pause(efx); }
static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) { efx_oword_t reg; bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS); bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI); bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII); /* XGXS block is flaky and will need to be reset if moving * into our out of XGMII, XGXS or XAUI loopbacks. */ if (EFX_WORKAROUND_5147(efx)) { bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback; bool reset_xgxs; efx_reado(efx, ®, FR_AB_XX_CORE_STAT); old_xgxs_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN); old_xgmii_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN); efx_reado(efx, ®, FR_AB_XX_SD_CTL); old_xaui_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_LPBKA); /* The PHY driver may have turned XAUI off */ reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || (xaui_loopback != old_xaui_loopback) || (xgmii_loopback != old_xgmii_loopback)); if (reset_xgxs) falcon_reset_xaui(efx); } efx_reado(efx, ®, FR_AB_XX_CORE_STAT); EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG, (xgxs_loopback || xaui_loopback) ? FFE_AB_XX_FORCE_SIG_ALL_LANES : 0); EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback); EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback); efx_writeo(efx, ®, FR_AB_XX_CORE_STAT); efx_reado(efx, ®, FR_AB_XX_SD_CTL); EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback); EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback); EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback); EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback); efx_writeo(efx, ®, FR_AB_XX_SD_CTL); }
static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries) { efx->mac_up = falcon_xaui_link_ok(efx); if ((efx->loopback_mode == LOOPBACK_NETWORK) || efx_phy_mode_disabled(efx->phy_mode)) return; while (!efx->mac_up && tries) { EFX_LOG(efx, "bashing xaui\n"); falcon_reset_xaui(efx); udelay(200); efx->mac_up = falcon_xaui_link_ok(efx); --tries; } }
static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) { efx_oword_t reg; bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS); bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI); bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII); if (EFX_WORKAROUND_5147(efx)) { bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback; bool reset_xgxs; falcon_read(efx, ®, XX_CORE_STAT_REG); old_xgxs_loopback = EFX_OWORD_FIELD(reg, XX_XGXS_LB_EN); old_xgmii_loopback = EFX_OWORD_FIELD(reg, XX_XGMII_LB_EN); falcon_read(efx, ®, XX_SD_CTL_REG); old_xaui_loopback = EFX_OWORD_FIELD(reg, XX_LPBKA); reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) || (xaui_loopback != old_xaui_loopback) || (xgmii_loopback != old_xgmii_loopback)); if (reset_xgxs) falcon_reset_xaui(efx); } falcon_read(efx, ®, XX_CORE_STAT_REG); EFX_SET_OWORD_FIELD(reg, XX_FORCE_SIG, (xgxs_loopback || xaui_loopback) ? XX_FORCE_SIG_DECODE_FORCED : 0); EFX_SET_OWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback); EFX_SET_OWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback); falcon_write(efx, ®, XX_CORE_STAT_REG); falcon_read(efx, ®, XX_SD_CTL_REG); EFX_SET_OWORD_FIELD(reg, XX_LPBKD, xaui_loopback); EFX_SET_OWORD_FIELD(reg, XX_LPBKC, xaui_loopback); EFX_SET_OWORD_FIELD(reg, XX_LPBKB, xaui_loopback); EFX_SET_OWORD_FIELD(reg, XX_LPBKA, xaui_loopback); falcon_write(efx, ®, XX_SD_CTL_REG); }
static int tenxpress_phy_init(struct efx_nic *efx) { int rc; falcon_board(efx)->type->init_phy(efx); if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { if (efx->phy_type == PHY_TYPE_SFT9001A) { int reg; reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= (1 << PMA_PMD_EXT_SSR_LBN); efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); mdelay(200); } rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) return rc; rc = efx_mdio_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); if (rc < 0) return rc; } rc = tenxpress_init(efx); if (rc < 0) return rc; /* Reinitialise flow control settings */ efx_link_set_wanted_fc(efx, efx->wanted_fc); efx_mdio_an_reconfigure(efx); schedule_timeout_uninterruptible(HZ / 5); /* 200ms */ /* Let XGXS and SerDes out of reset */ falcon_reset_xaui(efx); return 0; }
int falcon_check_xmac(struct efx_nic *efx) { bool xaui_link_ok; int rc; if ((efx->loopback_mode == LOOPBACK_NETWORK) || efx_phy_mode_disabled(efx->phy_mode)) return 0; falcon_mask_status_intr(efx, false); xaui_link_ok = falcon_xaui_link_ok(efx); if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok) falcon_reset_xaui(efx); /* Call the PHY check_hw routine */ rc = efx->phy_op->check_hw(efx); /* Unmask interrupt if everything was (and still is) ok */ if (xaui_link_ok && efx->link_up) falcon_mask_status_intr(efx, true); return rc; }
/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */ static bool falcon_xmac_link_ok_retry(struct efx_nic *efx, int tries) { bool mac_up = falcon_xmac_link_ok(efx); if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || efx_phy_mode_disabled(efx->phy_mode)) /* XAUI link is expected to be down */ return mac_up; falcon_stop_nic_stats(efx); while (!mac_up && tries) { EFX_LOG(efx, "bashing xaui\n"); falcon_reset_xaui(efx); udelay(200); mac_up = falcon_xmac_link_ok(efx); --tries; } falcon_start_nic_stats(efx); return mac_up; }
static int tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; return 0; } phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); if (loop_reset || phy_mode_change) { tenxpress_special_reset(efx); /* Reset XAUI if we were in 10G, and are staying * in 10G. If we're moving into and out of 10G * then xaui will be reset anyway */ if (EFX_IS10G(efx)) falcon_reset_xaui(efx); } tenxpress_low_power(efx); efx_mdio_transmit_disable(efx); efx_mdio_phy_reconfigure(efx); tenxpress_ext_loopback(efx); efx_mdio_an_reconfigure(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; return 0; }