diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-12-12 21:50:08 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-12-12 21:58:17 -0800 |
commit | 177dfcd80f28f8fbc3e22c2d8b24d21cb86f1d97 (patch) | |
tree | a6e5e9949f388d48ac20c4efbb2811762ac5f9d4 /drivers/net/sfc/falcon_xmac.c | |
parent | 356eebb2b3af24cc701823f1e025f04eef333239 (diff) |
sfc: Add support for sub-10G speeds
The SFC4000 has a separate MAC for use at sub-10G speeds. Introduce
an efx_mac_operations structure with implementations for the two MACs.
Switch between the MACs as necessary.
PHY settings are independent of the MAC, so add get_settings() and
set_settings() to efx_phy_operations. Also add macs field to indicate
which MACs the PHY is connected to.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc/falcon_xmac.c')
-rw-r--r-- | drivers/net/sfc/falcon_xmac.c | 222 |
1 files changed, 31 insertions, 191 deletions
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 4a54d0933e7..2206eada346 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -25,24 +25,6 @@ * MAC operations * *************************************************************************/ -static int falcon_reset_xmac(struct efx_nic *efx) -{ - efx_oword_t reg; - int count; - - EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1); - falcon_write(efx, ®, XM_GLB_CFG_REG); - - for (count = 0; count < 10000; count++) { /* wait upto 100ms */ - falcon_read(efx, ®, XM_GLB_CFG_REG); - if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0) - return 0; - udelay(10); - } - - EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); - return -ETIMEDOUT; -} /* Configure the XAUI driver that is an output from Falcon */ static void falcon_setup_xaui(struct efx_nic *efx) @@ -98,31 +80,20 @@ int falcon_reset_xaui(struct efx_nic *efx) return -ETIMEDOUT; } -static bool falcon_xgmii_status(struct efx_nic *efx) +static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { efx_oword_t reg; - if (falcon_rev(efx) < FALCON_REV_B0) - return true; - - /* The ISR latches, so clear it and re-read */ - falcon_read(efx, ®, XM_MGT_INT_REG_B0); - falcon_read(efx, ®, XM_MGT_INT_REG_B0); - - if (EFX_OWORD_FIELD(reg, XM_LCLFLT) || - EFX_OWORD_FIELD(reg, XM_RMTFLT)) { - EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg)); - return false; - } - - return true; -} + if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + return; -static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) -{ - efx_oword_t reg; + /* We expect xgmii faults if the wireside link is up */ + if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) + return; - if ((falcon_rev(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + /* 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 */ @@ -135,35 +106,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); } -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; -} - +/* Get status of XAUI link */ bool falcon_xaui_link_ok(struct efx_nic *efx) { efx_oword_t reg; @@ -187,18 +130,10 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); falcon_write(efx, ®, XX_CORE_STAT_REG); - /* If the link is up, then check the phy side of the xaui link - * (error conditions from the wire side propoagate back through - * the phy to the xaui side). */ - if (efx->link_up && link_ok) { + /* If the link is up, then check the phy side of the xaui link */ + if (efx->link_up && link_ok) if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) link_ok = mdio_clause45_phyxgxs_lane_sync(efx); - } - - /* If the PHY and XAUI links are up, then check the mac's xgmii - * fault state */ - if (efx->link_up && link_ok) - link_ok = falcon_xgmii_status(efx); return link_ok; } @@ -310,70 +245,39 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) /* 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) +static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries) { - int max_tries, tries; - tries = EFX_WORKAROUND_5147(efx) ? 5 : 1; - max_tries = tries; + efx->mac_up = falcon_xaui_link_ok(efx); 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; + /* XAUI link is expected to be down */ + return; - EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n", - __func__, tries); + while (!efx->mac_up && tries) { + EFX_LOG(efx, "bashing xaui\n"); 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; + efx->mac_up = falcon_xaui_link_ok(efx); + --tries; + } } -void falcon_reconfigure_xmac(struct efx_nic *efx) +static void falcon_reconfigure_xmac(struct efx_nic *efx) { - bool xaui_link_ok; - falcon_mask_status_intr(efx, false); - falcon_deconfigure_mac_wrapper(efx); - - /* Reconfigure the PHY, disabling transmit in mac level loopback. */ - if (LOOPBACK_INTERNAL(efx)) - efx->phy_mode |= PHY_MODE_TX_DISABLED; - else - efx->phy_mode &= ~PHY_MODE_TX_DISABLED; - efx->phy_op->reconfigure(efx); - falcon_reconfigure_xgxs_core(efx); falcon_reconfigure_xmac_core(efx); falcon_reconfigure_mac_wrapper(efx); - /* Ensure XAUI link is up */ - xaui_link_ok = falcon_check_xaui_link_up(efx); - - if (xaui_link_ok && efx->link_up) - falcon_mask_status_intr(efx, true); -} - -void falcon_fini_xmac(struct efx_nic *efx) -{ - /* Isolate the MAC - PHY */ - falcon_deconfigure_mac_wrapper(efx); - - /* Potentially power down the PHY */ - efx->phy_op->fini(efx); + falcon_check_xaui_link_up(efx, 5); + falcon_mask_status_intr(efx, true); } -void falcon_update_stats_xmac(struct efx_nic *efx) +static void falcon_update_stats_xmac(struct efx_nic *efx) { struct efx_mac_stats *mac_stats = &efx->mac_stats; int rc; @@ -438,7 +342,7 @@ void falcon_update_stats_xmac(struct efx_nic *efx) mac_stats->rx_control * 64); } -int falcon_check_xmac(struct efx_nic *efx) +static int falcon_check_xmac(struct efx_nic *efx) { bool xaui_link_ok; int rc; @@ -463,72 +367,8 @@ int falcon_check_xmac(struct efx_nic *efx) return rc; } -/* Simulate a PHY event */ -void falcon_xmac_sim_phy_event(struct efx_nic *efx) -{ - efx_qword_t phy_event; - - EFX_POPULATE_QWORD_2(phy_event, - EV_CODE, GLOBAL_EV_DECODE, - XG_PHY_INTR, 1); - falcon_generate_event(&efx->channel[0], &phy_event); -} - -int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -{ - mdio_clause45_get_settings(efx, ecmd); - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = efx->mii.phy_id; - ecmd->autoneg = AUTONEG_DISABLE; - ecmd->duplex = DUPLEX_FULL; - return 0; -} - -int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -{ - if (ecmd->transceiver != XCVR_INTERNAL) - return -EINVAL; - if (ecmd->autoneg != AUTONEG_DISABLE) - return -EINVAL; - if (ecmd->duplex != DUPLEX_FULL) - return -EINVAL; - - return mdio_clause45_set_settings(efx, ecmd); -} - - -int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control) -{ - bool reset; - - if (flow_control & EFX_FC_AUTO) { - EFX_LOG(efx, "10G does not support flow control " - "autonegotiation\n"); - return -EINVAL; - } - - if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX)) - return -EINVAL; - - /* TX flow control may automatically turn itself off if the - * link partner (intermittently) stops responding to pause - * frames. There isn't any indication that this has happened, - * so the best we do is leave it up to the user to spot this - * and fix it be cycling transmit flow control on this end. */ - reset = ((flow_control & EFX_FC_TX) && - !(efx->flow_control & EFX_FC_TX)); - if (EFX_WORKAROUND_11482(efx) && reset) { - if (falcon_rev(efx) >= FALCON_REV_B0) { - /* Recover by resetting the EM block */ - if (efx->link_up) - falcon_drain_tx_fifo(efx); - } else { - /* Schedule a reset to recover */ - efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); - } - } - - efx->flow_control = flow_control; - - return 0; -} +struct efx_mac_operations falcon_xmac_operations = { + .reconfigure = falcon_reconfigure_xmac, + .update_stats = falcon_update_stats_xmac, + .check_hw = falcon_check_xmac, +}; |