static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) { int rc = 0, rc2, i, ctrl_reg, res_reg; /* Initialise cable diagnostic results to unknown failure */ for (i = 1; i < 9; ++i) results[i] = -1; /* Run cable diagnostics; wait up to 5 seconds for them to complete. * A cable fault is not a self-test failure, but a timeout is. */ ctrl_reg = ((1 << CDIAG_CTRL_IMMED_LBN) | (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN)); if (flags & ETH_TEST_FL_OFFLINE) { /* Break the link in order to run full diagnostics. We * must reset the PHY to resume normal service. */ ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN); } efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG, ctrl_reg); i = 0; while (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_CTRL_REG) & (1 << CDIAG_CTRL_IN_PROG_LBN)) { if (++i == 50) { rc = -ETIMEDOUT; goto out; } msleep(100); } res_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_RES_REG); for (i = 0; i < 4; i++) { int pair_res = (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) & ((1 << CDIAG_RES_WIDTH) - 1); int len_reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_CDIAG_LEN_REG + i); if (pair_res == CDIAG_RES_OK) results[1 + i] = 1; else if (pair_res == CDIAG_RES_INVALID) results[1 + i] = -1; else results[1 + i] = -pair_res; if (pair_res != CDIAG_RES_INVALID && pair_res != CDIAG_RES_OPEN && len_reg != 0xffff) results[5 + i] = len_reg; } out: if (flags & ETH_TEST_FL_OFFLINE) { /* Reset, running the BIST and then resuming normal service. */ rc2 = tenxpress_special_reset(efx); results[0] = rc2 ? -1 : 1; if (!rc) rc = rc2; efx_mdio_an_reconfigure(efx); } return rc; }
static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) { int rc = 0; int devad = __ffs(efx->mdio.mmds); u16 physid1, physid2; if (efx->phy_type == PHY_TYPE_NONE) return 0; mutex_lock(&efx->mac_lock); tests->mdio = -1; physid1 = efx_mdio_read(efx, devad, MDIO_DEVID1); physid2 = efx_mdio_read(efx, devad, MDIO_DEVID2); if ((physid1 == 0x0000) || (physid1 == 0xffff) || (physid2 == 0x0000) || (physid2 == 0xffff)) { EFX_ERR(efx, "no MDIO PHY present with ID %d\n", efx->mdio.prtad); rc = -EINVAL; goto out; } if (EFX_IS10G(efx)) { rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0); if (rc) goto out; } out: mutex_unlock(&efx->mac_lock); tests->mdio = rc ? -1 : 1; return rc; }
static void txc_reset_logic_mmd(struct efx_nic *efx, int mmd) { int val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); int tries = 50; val |= (1 << TXC_GLCMD_LMTSWRST_LBN); efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, val); while (tries--) { val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN))) break; udelay(1); } if (!tries) EFX_INFO(efx, TXCNAME " Logic reset timed out!\n"); }
static int tenxpress_special_reset(struct efx_nic *efx) { int rc, reg; falcon_stop_nic_stats(efx); 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) goto out; rc = tenxpress_init(efx); if (rc < 0) goto out; mdelay(10); out: falcon_start_nic_stats(efx); return rc; }
/* Poll for link state changes */ static bool tenxpress_phy_poll(struct efx_nic *efx) { struct efx_link_state old_state = efx->link_state; if (efx->phy_type == PHY_TYPE_SFX7101) { efx->link_state.up = sfx7101_link_ok(efx); efx->link_state.speed = 10000; efx->link_state.fd = true; efx->link_state.fc = efx_mdio_get_pause(efx); sfx7101_check_bad_lp(efx, efx->link_state.up); } else { struct ethtool_cmd ecmd; /* Check the LASI alarm first */ if (efx->loopback_mode == LOOPBACK_NONE && !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) & MDIO_PMA_LASI_LSALARM)) return false; tenxpress_get_settings(efx, &ecmd); efx->link_state.up = sft9001_link_ok(efx, &ecmd); efx->link_state.speed = ecmd.speed; efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL); efx->link_state.fc = efx_mdio_get_pause(efx); } return !efx_link_state_equal(&efx->link_state, &old_state); }
/* Perform a "special software reset" on the PHY. The caller is * responsible for saving and restoring the PHY hardware registers * properly, and masking/unmasking LASI */ static int tenxpress_special_reset(struct efx_nic *efx) { int rc, reg; /* The XGMAC clock is driven from the SFX7101 312MHz clock, so * a special software reset can glitch the XGMAC sufficiently for stats * requests to fail. */ falcon_stop_nic_stats(efx); /* Initiate reset */ 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); /* Wait for the blocks to come out of reset */ rc = efx_mdio_wait_reset_mmds(efx, TENXPRESS_REQUIRED_DEVS); if (rc < 0) goto out; /* Try and reconfigure the device */ rc = tenxpress_init(efx); if (rc < 0) goto out; /* Wait for the XGXS state machine to churn */ mdelay(10); out: falcon_start_nic_stats(efx); return rc; }
static int tenxpress_init(struct efx_nic *efx) { int reg; if (efx->phy_type == PHY_TYPE_SFX7101) { /* Enable 312.5 MHz clock */ efx_mdio_write(efx, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, 1 << CLK312_EN_LBN); } else { /* Enable 312.5 MHz clock and GMII */ reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | (1 << PMA_PMD_EXT_CLK_OUT_LBN) | (1 << PMA_PMD_EXT_CLK312_LBN) | (1 << PMA_PMD_EXT_ROBUST_LBN)); efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG, reg); efx_mdio_set_flag(efx, MDIO_MMD_C22EXT, GPHY_XCONTROL_REG, 1 << GPHY_ISOLATE_LBN, false); } /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */ if (efx->phy_type == PHY_TYPE_SFX7101) { efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG, 1 << PMA_PMA_LED_ACTIVITY_LBN, true); efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, SFX7101_PMA_PMD_LED_DEFAULT); } return 0; }
/* Initialisation entry point for this PHY driver */ static int txc43128_phy_init(struct efx_nic *efx) { u32 devid; int rc; devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); EFX_INFO(efx, ""TXCNAME ": PHY ID reg %x (OUI %06x model %02x " "revision %x)\n", devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), efx_mdio_id_rev(devid)); EFX_INFO(efx, ""TXCNAME ": Silicon ID %x\n", efx_mdio_read(efx, MDIO_MMD_PHYXS, TXC_GLRGS_SLID) & TXC_GLRGS_SLID_MASK); rc = txc_reset_phy(efx); if (rc < 0) return rc; rc = txc_bist(efx); if (rc < 0) return rc; txc_apply_defaults(efx); return 0; }
static void tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { u32 adv = 0, lpa = 0; int reg; reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL); if (reg & MDIO_AN_10GBT_CTRL_ADV10G) adv |= ADVERTISED_10000baseT_Full; reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); if (reg & MDIO_AN_10GBT_STAT_LP10G) lpa |= ADVERTISED_10000baseT_Full; mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); if (LOOPBACK_EXTERNAL(efx)) ethtool_cmd_speed_set(ecmd, SPEED_10000); }
static ssize_t show_phy_short_reach(struct device *dev, struct device_attribute *attr, char *buf) { struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); int reg; reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR); return sprintf(buf, "%d\n", !!(reg & MDIO_PMA_10GBT_TXPWR_SHORT)); }
static void tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { u32 adv = 0, lpa = 0; int reg; if (efx->phy_type != PHY_TYPE_SFX7101) { reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_CTRL); if (reg & (1 << C22EXT_MSTSLV_CTRL_ADV_1000_FD_LBN)) adv |= ADVERTISED_1000baseT_Full; reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_MSTSLV_STATUS); if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_HD_LBN)) lpa |= ADVERTISED_1000baseT_Half; if (reg & (1 << C22EXT_MSTSLV_STATUS_LP_1000_FD_LBN)) lpa |= ADVERTISED_1000baseT_Full; } reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL); if (reg & MDIO_AN_10GBT_CTRL_ADV10G) adv |= ADVERTISED_10000baseT_Full; reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); if (reg & MDIO_AN_10GBT_STAT_LP10G) lpa |= ADVERTISED_10000baseT_Full; mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); if (efx->phy_type != PHY_TYPE_SFX7101) { ecmd->supported |= (SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full); if (ecmd->speed != SPEED_10000) { ecmd->eth_tp_mdix = (efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XSTATUS_REG) & (1 << PMA_PMD_XSTAT_MDIX_LBN)) ? ETH_TP_MDI_X : ETH_TP_MDI; } } /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ if (efx->loopback_mode == LOOPBACK_GPHY) ecmd->speed = SPEED_1000; else if (LOOPBACK_EXTERNAL(efx)) ecmd->speed = SPEED_10000; }
static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) { struct tenxpress_phy_data *pd = efx->phy_data; bool bad_lp; int reg; if (link_ok) { bad_lp = false; } else { /* Check that AN has started but not completed. */ reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1); if (!(reg & MDIO_AN_STAT1_LPABLE)) return; /* LP status is unknown */ bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE); if (bad_lp) pd->bad_lp_tries++; } /* Nothing to do if all is well and was previously so. */ if (!pd->bad_lp_tries) return; /* Use the RX (red) LED as an error indicator once we've seen AN * failure several times in a row, and also log a message. */ if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) { reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG); reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN); if (!bad_lp) { reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN; } else { reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN; netif_err(efx, link, efx->net_dev, "appears to be plugged into a port" " that is not 10GBASE-T capable. The PHY" " supports 10GBASE-T ONLY, so no link can" " be established\n"); } efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg); pd->bad_lp_tries = bad_lp; } }
/* Set the lane power down state in the analog control registers */ static void txc_analog_lane_power(struct efx_nic *efx, int mmd) { int txpd = (1 << TXC_ATXCTL_TXPD3_LBN) | (1 << TXC_ATXCTL_TXPD2_LBN) | (1 << TXC_ATXCTL_TXPD1_LBN) | (1 << TXC_ATXCTL_TXPD0_LBN); int rxpd = (1 << TXC_ARXCTL_RXPD3_LBN) | (1 << TXC_ARXCTL_RXPD2_LBN) | (1 << TXC_ARXCTL_RXPD1_LBN) | (1 << TXC_ARXCTL_RXPD0_LBN); int txctl = efx_mdio_read(efx, mmd, TXC_ALRGS_ATXCTL); int rxctl = efx_mdio_read(efx, mmd, TXC_ALRGS_ARXCTL); if (!(efx->phy_mode & PHY_MODE_LOW_POWER)) { txctl &= ~txpd; rxctl &= ~rxpd; } else { txctl |= txpd; rxctl |= rxpd; } efx_mdio_write(efx, mmd, TXC_ALRGS_ATXCTL, txctl); efx_mdio_write(efx, mmd, TXC_ALRGS_ARXCTL, rxctl); }
static void tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { u32 adv = 0, lpa = 0; int reg; reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL); if (reg & MDIO_AN_10GBT_CTRL_ADV10G) adv |= ADVERTISED_10000baseT_Full; reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); if (reg & MDIO_AN_10GBT_STAT_LP10G) lpa |= ADVERTISED_10000baseT_Full; mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); /* In loopback, the PHY automatically brings up the correct interface, * but doesn't advertise the correct speed. So override it */ if (LOOPBACK_EXTERNAL(efx)) ethtool_cmd_speed_set(ecmd, SPEED_10000); }
static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) { struct tenxpress_phy_data *pd = efx->phy_data; bool bad_lp; int reg; if (link_ok) { bad_lp = false; } else { reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_STAT1); if (!(reg & MDIO_AN_STAT1_LPABLE)) return; bad_lp = !(reg & MDIO_AN_STAT1_COMPLETE); if (bad_lp) pd->bad_lp_tries++; } if (!pd->bad_lp_tries) return; if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) { reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG); reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN); if (!bad_lp) { reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN; } else { reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN; netif_err(efx, link, efx->net_dev, "appears to be plugged into a port" " that is not 10GBASE-T capable. The PHY" " supports 10GBASE-T ONLY, so no link can" " be established\n"); } efx_mdio_write(efx, MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG, reg); pd->bad_lp_tries = bad_lp; } }
/* Set the lane power down state in the global registers */ static void txc_glrgs_lane_power(struct efx_nic *efx, int mmd) { int pd = (1 << TXC_GLCMD_L01PD_LBN) | (1 << TXC_GLCMD_L23PD_LBN); int ctl = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD); if (!(efx->phy_mode & PHY_MODE_LOW_POWER)) ctl &= ~pd; else ctl |= pd; efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, ctl); }
int sft9001_wait_boot(struct efx_nic *efx) { unsigned long timeout = jiffies + HZ + 1; int boot_stat; for (;;) { boot_stat = efx_mdio_read(efx, MDIO_MMD_PCS, PCS_BOOT_STATUS_REG); if (boot_stat >= 0) { EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat); switch (boot_stat & ((1 << PCS_BOOT_FATAL_ERROR_LBN) | (3 << PCS_BOOT_PROGRESS_LBN) | (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) | (1 << PCS_BOOT_CODE_STARTED_LBN))) { case ((1 << PCS_BOOT_FATAL_ERROR_LBN) | (PCS_BOOT_PROGRESS_CHECKSUM << PCS_BOOT_PROGRESS_LBN)): case ((1 << PCS_BOOT_FATAL_ERROR_LBN) | (PCS_BOOT_PROGRESS_INIT << PCS_BOOT_PROGRESS_LBN) | (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)): return -EINVAL; case ((PCS_BOOT_PROGRESS_WAIT_MDIO << PCS_BOOT_PROGRESS_LBN) | (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)): return (efx->phy_mode & PHY_MODE_SPECIAL) ? 0 : -EIO; case ((PCS_BOOT_PROGRESS_JUMP << PCS_BOOT_PROGRESS_LBN) | (1 << PCS_BOOT_CODE_STARTED_LBN)): case ((PCS_BOOT_PROGRESS_JUMP << PCS_BOOT_PROGRESS_LBN) | (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) | (1 << PCS_BOOT_CODE_STARTED_LBN)): return (efx->phy_mode & PHY_MODE_SPECIAL) ? -EIO : 0; default: if (boot_stat & (1 << PCS_BOOT_FATAL_ERROR_LBN)) return -EIO; break; } } if (time_after_eq(jiffies, timeout)) return -ETIMEDOUT; msleep(50); } }
static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) { u32 reg; if (efx_phy_mode_disabled(efx->phy_mode)) return false; else if (efx->loopback_mode == LOOPBACK_GPHY) return true; else if (efx->loopback_mode) return efx_mdio_links_ok(efx, MDIO_DEVS_PMAPMD | MDIO_DEVS_PHYXS); /* We must use the same definition of link state as LASI, * otherwise we can miss a link state transition */ if (ecmd->speed == 10000) { reg = efx_mdio_read(efx, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1); return reg & MDIO_PCS_10GBRT_STAT1_BLKLK; } else { reg = efx_mdio_read(efx, MDIO_MMD_C22EXT, C22EXT_STATUS_REG); return reg & (1 << C22EXT_STATUS_LINK_LBN); } }
/* Push the non-configurable defaults into the PHY. This must be * done after every full reset */ static void txc_apply_defaults(struct efx_nic *efx) { int mctrl; /* Turn amplitude down and preemphasis off on the host side * (PHY<->MAC) as this is believed less likely to upset Falcon * and no adverse effects have been noted. It probably also * saves a picowatt or two */ /* Turn off preemphasis */ efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0, TXC_ATXPRE_NONE); efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1, TXC_ATXPRE_NONE); /* Turn down the amplitude */ efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP0, TXC_ATXAMP_0820_BOTH); efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP1, TXC_ATXAMP_0820_BOTH); /* Set the line side amplitude and preemphasis to the databook * defaults as an erratum causes them to be 0 on at least some * PHY rev.s */ efx_mdio_write(efx, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE0, TXC_ATXPRE_DEFAULT); efx_mdio_write(efx, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE1, TXC_ATXPRE_DEFAULT); efx_mdio_write(efx, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP0, TXC_ATXAMP_DEFAULT); efx_mdio_write(efx, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP1, TXC_ATXAMP_DEFAULT); /* Set up the LEDs */ mctrl = efx_mdio_read(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL); /* Set the Green and Red LEDs to their default modes */ mctrl &= ~((1 << TXC_MCTL_TXLED_LBN) | (1 << TXC_MCTL_RXLED_LBN)); efx_mdio_write(efx, MDIO_MMD_PHYXS, TXC_MRGS_CTL, mctrl); /* Databook recommends doing this after configuration changes */ txc_reset_logic(efx); falcon_board(efx)->type->init_phy(efx); }
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; }
/* Run a single BIST on one MMD*/ static int txc_bist_one(struct efx_nic *efx, int mmd, int test) { int ctrl, bctl; int lane; int rc = 0; EFX_INFO(efx, "" TXCNAME ": running BIST on %s MMD\n", efx_mdio_mmd_name(mmd)); /* Set PMA to test into loopback using Mt Diablo reg as per app note */ ctrl = efx_mdio_read(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL); ctrl |= (1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN); efx_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl); /* The BIST app. note lists these as 3 distinct steps. */ /* Set the BIST type */ bctl = (test << TXC_BIST_CTRL_TYPE_LBN); efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl); /* Set the BSTEN bit in the BIST Control register to enable */ bctl |= (1 << TXC_BIST_CTRL_ENAB_LBN); efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl); /* Set the BSTRT bit in the BIST Control register */ efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl | (1 << TXC_BIST_CTRL_STRT_LBN)); /* Wait. */ udelay(TXC_BIST_DURATION); /* Set the BSTOP bit in the BIST Control register */ bctl |= (1 << TXC_BIST_CTRL_STOP_LBN); efx_mdio_write(efx, mmd, TXC_BIST_CTL, bctl); /* The STOP bit should go off when things have stopped */ while (bctl & (1 << TXC_BIST_CTRL_STOP_LBN)) bctl = efx_mdio_read(efx, mmd, TXC_BIST_CTL); /* Check all the error counts are 0 and all the frame counts are non-zero */ for (lane = 0; lane < 4; lane++) { int count = efx_mdio_read(efx, mmd, TXC_BIST_RX0ERRCNT + lane); if (count != 0) { EFX_ERR(efx, ""TXCNAME": BIST error. " "Lane %d had %d errs\n", lane, count); rc = -EIO; } count = efx_mdio_read(efx, mmd, TXC_BIST_RX0FRMCNT + lane); if (count == 0) { EFX_ERR(efx, ""TXCNAME": BIST error. " "Lane %d got 0 frames\n", lane); rc = -EIO; } } if (rc == 0) EFX_INFO(efx, ""TXCNAME": BIST pass\n"); /* Disable BIST */ efx_mdio_write(efx, mmd, TXC_BIST_CTL, 0); /* Turn off loopback */ ctrl &= ~(1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN); efx_mdio_write(efx, MDIO_MMD_PCS, TXC_MTDIABLO_CTRL, ctrl); return rc; }