static bool efx_mcdi_phy_poll(struct efx_nic *efx) { struct efx_link_state old_state = efx->link_state; u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; int rc; WARN_ON(!mutex_is_locked(&efx->mac_lock)); BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), NULL); if (rc) { netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); efx->link_state.up = false; } else { efx_mcdi_phy_decode_link( efx, &efx->link_state, MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); } return !efx_link_state_equal(&efx->link_state, &old_state); }
static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev) { u32 flags, fcntl, speed, lpa; speed = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_SPEED); EFX_BUG_ON_PARANOID(speed >= ARRAY_SIZE(efx_mcdi_event_link_speed)); speed = efx_mcdi_event_link_speed[speed]; flags = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LINK_FLAGS); fcntl = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_FCNTL); lpa = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LP_CAP); /* efx->link_state is only modified by efx_mcdi_phy_get_link(), * which is only run after flushing the event queues. Therefore, it * is safe to modify the link state outside of the mac_lock here. */ efx_mcdi_phy_decode_link(efx, &efx->link_state, speed, flags, fcntl); efx_mcdi_phy_check_fcntl(efx, lpa); efx_link_status_changed(efx); }
static bool efx_mcdi_phy_poll(struct efx_nic *efx) { struct efx_link_state old_state = efx->link_state; MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); int rc; WARN_ON(!mutex_is_locked(&efx->mac_lock)); BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), NULL); if (rc) efx->link_state.up = false; else efx_mcdi_phy_decode_link( efx, &efx->link_state, MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); return !efx_link_state_equal(&efx->link_state, &old_state); }
static int efx_mcdi_phy_probe(struct efx_nic *efx) { struct efx_mcdi_phy_data *phy_data; u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; u32 caps; int rc; /* Initialise and populate phy_data */ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); if (phy_data == NULL) return -ENOMEM; rc = efx_mcdi_get_phy_cfg(efx, phy_data); if (rc != 0) goto fail; /* Read initial link advertisement */ BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), NULL); if (rc) goto fail; /* Fill out nic state */ efx->phy_data = phy_data; efx->phy_type = phy_data->type; efx->mdio_bus = phy_data->channel; efx->mdio.prtad = phy_data->port; efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); efx->mdio.mode_support = 0; if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) efx->mdio.mode_support |= MDIO_SUPPORTS_C22; if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) efx->link_advertising = mcdi_to_ethtool_cap(phy_data->media, caps); else phy_data->forced_cap = caps; /* Assert that we can map efx -> mcdi loopback modes */ BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC); BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII); BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS); BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI); BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII); BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII); BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR); BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI); BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR); BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR); BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR); BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR); BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY); BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS); BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS); BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD); BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT); BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS); BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS); BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR); BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR); BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS); BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS); BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR); BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS); rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes); if (rc != 0) goto fail; /* The MC indicates that LOOPBACK_NONE is a valid loopback mode, * but by convention we don't */ efx->loopback_modes &= ~(1 << LOOPBACK_NONE); /* Set the initial link mode */ efx_mcdi_phy_decode_link( efx, &efx->link_state, MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); /* Default to Autonegotiated flow control if the PHY supports it */ efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) efx->wanted_fc |= EFX_FC_AUTO; efx_link_set_wanted_fc(efx, efx->wanted_fc); return 0; fail: kfree(phy_data); return rc; }
static int efx_mcdi_phy_probe(struct efx_nic *efx) { struct efx_mcdi_phy_data *phy_data; u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; u32 caps; int rc; phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); if (phy_data == NULL) return -ENOMEM; rc = efx_mcdi_get_phy_cfg(efx, phy_data); if (rc != 0) goto fail; BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), NULL); if (rc) goto fail; efx->phy_data = phy_data; efx->phy_type = phy_data->type; efx->mdio_bus = phy_data->channel; efx->mdio.prtad = phy_data->port; efx->mdio.mmds = phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); efx->mdio.mode_support = 0; if (phy_data->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) efx->mdio.mode_support |= MDIO_SUPPORTS_C22; if (phy_data->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) efx->link_advertising = mcdi_to_ethtool_cap(phy_data->media, caps); else phy_data->forced_cap = caps; BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC); BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII); BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS); BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI); BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII); BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII); BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR); BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI); BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR); BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR); BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR); BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR); BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY); BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS); BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS); BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD); BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT); BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS); BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS); BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR); BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR); BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS); BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS); BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR); BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS); rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes); if (rc != 0) goto fail; efx->loopback_modes &= ~(1 << LOOPBACK_NONE); efx_mcdi_phy_decode_link( efx, &efx->link_state, MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) efx->wanted_fc |= EFX_FC_AUTO; efx_link_set_wanted_fc(efx, efx->wanted_fc); return 0; fail: kfree(phy_data); return rc; }