/* 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 void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { efx_oword_t reg; if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) return; /* We expect xgmii faults if the wireside link is up */ if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) return; /* We can only use this interrupt to signal the negative edge of * xaui_align [we have to poll the positive edge]. */ if (!efx->mac_up) return; /* Flush the ISR */ if (enable) falcon_read(efx, ®, XM_MGT_INT_REG_B0); EFX_POPULATE_OWORD_2(reg, XM_MSK_RMTFLT, !enable, XM_MSK_LCLFLT, !enable); falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); }
static void falcon_poll_xmac(struct efx_nic *efx) { if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up) return; falcon_mask_status_intr(efx, false); falcon_check_xaui_link_up(efx, 1); falcon_mask_status_intr(efx, true); }
void falcon_poll_xmac(struct efx_nic *efx) { if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || !efx->xmac_poll_required) return; efx->xmac_poll_required = !falcon_xmac_link_ok_retry(efx, 1); falcon_ack_status_intr(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_ack_status_intr(struct efx_nic *efx) { efx_oword_t reg; if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx)) return; /* We expect xgmii faults if the wireside link is down */ if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up) return; /* We can only use this interrupt to signal the negative edge of * xaui_align [we have to poll the positive edge]. */ if (efx->xmac_poll_required) return; efx_reado(efx, ®, FR_AB_XM_MGT_INT_MSK); }
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 void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { efx_oword_t reg; if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) return; if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) return; if (!efx->mac_up) return; if (enable) falcon_read(efx, ®, XM_MGT_INT_REG_B0); EFX_POPULATE_OWORD_2(reg, XM_MSK_RMTFLT, !enable, XM_MSK_LCLFLT, !enable); falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); }
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; }