int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, unsigned int prtad, unsigned int devad, u16 addr, u16 *value_out, u32 *status_out) { u8 inbuf[MC_CMD_MDIO_READ_IN_LEN]; u8 outbuf[MC_CMD_MDIO_READ_OUT_LEN]; size_t outlen; int rc; MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, bus); MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad); MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad); MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr); rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; *value_out = (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE); *status_out = MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS); return 0; fail: netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, size_t *size_out, size_t *erase_size_out, bool *protected_out) { u8 inbuf[MC_CMD_NVRAM_INFO_IN_LEN]; u8 outbuf[MC_CMD_NVRAM_INFO_OUT_LEN]; size_t outlen; int rc; MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type); rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) { rc = -EIO; goto fail; } *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE); *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE); *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) & (1 << MC_CMD_NVRAM_PROTECTED_LBN)); return 0; fail: netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
static int efx_mcdi_mdio_read(struct net_device *net_dev, int prtad, int devad, u16 addr) { struct efx_nic *efx = netdev_priv(net_dev); MCDI_DECLARE_BUF(inbuf, MC_CMD_MDIO_READ_IN_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_MDIO_READ_OUT_LEN); size_t outlen; int rc; MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, efx->mdio_bus); MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad); MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad); MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr); rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) return rc; if (MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS) != MC_CMD_MDIO_STATUS_GOOD) return -EIO; return (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE); }
static int efx_sriov_cmd(struct efx_nic *efx, bool enable, unsigned *vi_scale_out, unsigned *vf_total_out) { u8 inbuf[MC_CMD_SRIOV_IN_LEN]; u8 outbuf[MC_CMD_SRIOV_OUT_LEN]; unsigned vi_scale, vf_total; size_t outlen; int rc; MCDI_SET_DWORD(inbuf, SRIOV_IN_ENABLE, enable ? 1 : 0); MCDI_SET_DWORD(inbuf, SRIOV_IN_VI_BASE, EFX_VI_BASE); MCDI_SET_DWORD(inbuf, SRIOV_IN_VF_COUNT, efx->vf_count); rc = efx_mcdi_rpc(efx, MC_CMD_SRIOV, inbuf, MC_CMD_SRIOV_IN_LEN, outbuf, MC_CMD_SRIOV_OUT_LEN, &outlen); if (rc) return rc; if (outlen < MC_CMD_SRIOV_OUT_LEN) return -EIO; vf_total = MCDI_DWORD(outbuf, SRIOV_OUT_VF_TOTAL); vi_scale = MCDI_DWORD(outbuf, SRIOV_OUT_VI_SCALE); if (vi_scale > EFX_VI_SCALE_MAX) return -EOPNOTSUPP; if (vi_scale_out) *vi_scale_out = vi_scale; if (vf_total_out) *vf_total_out = vf_total; return 0; }
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 int efx_mcdi_read_assertion(struct efx_nic *efx) { u8 inbuf[MC_CMD_GET_ASSERTS_IN_LEN]; u8 outbuf[MC_CMD_GET_ASSERTS_OUT_LEN]; unsigned int flags, index, ofst; const char *reason; size_t outlen; int retry; int rc; /* Attempt to read any stored assertion state before we reboot * the mcfw out of the assertion handler. Retry twice, once * because a boot-time assertion might cause this command to fail * with EINTR. And once again because GET_ASSERTS can race with * MC_CMD_REBOOT running on the other port. */ retry = 2; do { MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1); rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS, inbuf, MC_CMD_GET_ASSERTS_IN_LEN, outbuf, sizeof(outbuf), &outlen); } while ((rc == -EINTR || rc == -EIO) && retry-- > 0); if (rc) return rc; if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN) return -EIO; /* Print out any recorded assertion state */ flags = MCDI_DWORD(outbuf, GET_ASSERTS_OUT_GLOBAL_FLAGS); if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) return 0; reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) ? "system-level assertion" : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) ? "thread-level assertion" : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) ? "watchdog reset" : "unknown assertion"; netif_err(efx, hw, efx->net_dev, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason, MCDI_DWORD(outbuf, GET_ASSERTS_OUT_SAVED_PC_OFFS), MCDI_DWORD(outbuf, GET_ASSERTS_OUT_THREAD_OFFS)); /* Print out the registers */ ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; for (index = 1; index < 32; index++) { netif_err(efx, hw, efx->net_dev, "R%.2d (?): 0x%.8x\n", index, MCDI_DWORD2(outbuf, ofst)); ofst += sizeof(efx_dword_t); } return 0; }
static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, const u8 *mac, int *id_out) { u8 inbuf[MC_CMD_WOL_FILTER_SET_IN_LEN]; u8 outbuf[MC_CMD_WOL_FILTER_SET_OUT_LEN]; size_t outlen; int rc; MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type); MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE, MC_CMD_FILTER_MODE_SIMPLE); memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN); rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) { rc = -EIO; goto fail; } *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID); return 0; fail: *id_out = -1; netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
static void efx_mcdi_phy_get_link_ksettings(struct efx_nic *efx, struct ethtool_link_ksettings *cmd) { struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); int rc; u32 supported, advertising, lp_advertising; supported = mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); advertising = efx->link_advertising; cmd->base.speed = efx->link_state.speed; cmd->base.duplex = efx->link_state.fd; cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media); cmd->base.phy_address = phy_cfg->port; cmd->base.autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg); cmd->base.mdio_support = (efx->mdio.mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, supported); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, advertising); 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) return; lp_advertising = mcdi_to_ethtool_cap(phy_cfg->media, MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP)); ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, lp_advertising); }
int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out) { u8 outbuf[MC_CMD_NVRAM_TYPES_OUT_LEN]; size_t outlen; int rc; BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0, outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) { rc = -EIO; goto fail; } *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES); return 0; fail: netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out) { u8 outbuf[MC_CMD_WOL_FILTER_GET_OUT_LEN]; size_t outlen; int rc; rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0, outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) { rc = -EIO; goto fail; } *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID); return 0; fail: *id_out = -1; netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; int rc; ecmd->supported = mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); ecmd->advertising = efx->link_advertising; ecmd->speed = efx->link_state.speed; ecmd->duplex = efx->link_state.fd; ecmd->port = mcdi_to_ethtool_media(phy_cfg->media); ecmd->phy_address = phy_cfg->port; ecmd->transceiver = XCVR_INTERNAL; ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg); ecmd->mdio_support = (efx->mdio.mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); 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); return; } ecmd->lp_advertising = mcdi_to_ethtool_cap(phy_cfg->media, MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP)); }
int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, bool *was_attached) { u8 inbuf[MC_CMD_DRV_ATTACH_IN_LEN]; u8 outbuf[MC_CMD_DRV_ATTACH_OUT_LEN]; size_t outlen; int rc; MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE, driver_operating ? 1 : 0); MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1); rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) { rc = -EIO; goto fail; } if (was_attached != NULL) *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE); return 0; fail: netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode, int *results) { unsigned int retry, i, count = 0; size_t outlen; u32 status; MCDI_DECLARE_BUF(inbuf, MC_CMD_START_BIST_IN_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_POLL_BIST_OUT_SFT9001_LEN); u8 *ptr; int rc; BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0); MCDI_SET_DWORD(inbuf, START_BIST_IN_TYPE, bist_mode); rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, inbuf, MC_CMD_START_BIST_IN_LEN, NULL, 0, NULL); if (rc) goto out; /* Wait up to 10s for BIST to finish */ for (retry = 0; retry < 100; ++retry) { BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0, outbuf, sizeof(outbuf), &outlen); if (rc) goto out; status = MCDI_DWORD(outbuf, POLL_BIST_OUT_RESULT); if (status != MC_CMD_POLL_BIST_RUNNING) goto finished; msleep(100); } rc = -ETIMEDOUT; goto out; finished: results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1; /* SFT9001 specific cable diagnostics output */ if (efx->phy_type == PHY_TYPE_SFT9001B && (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT || bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) { ptr = MCDI_PTR(outbuf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A); if (status == MC_CMD_POLL_BIST_PASSED && outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) { for (i = 0; i < 8; i++) { results[count + i] = EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i], EFX_DWORD_0); } } count += 8; } rc = count; out: return rc; }
static int efx_mcdi_phy_get_module_eeprom(struct efx_nic *efx, struct ethtool_eeprom *ee, u8 *data) { MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX); MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN); size_t outlen; int rc; unsigned int payload_len; unsigned int space_remaining = ee->len; unsigned int page; unsigned int page_off; unsigned int to_copy; u8 *user_data = data; BUILD_BUG_ON(SFP_PAGE_SIZE * SFP_NUM_PAGES != ETH_MODULE_SFF_8079_LEN); page_off = ee->offset % SFP_PAGE_SIZE; page = ee->offset / SFP_PAGE_SIZE; while (space_remaining && (page < SFP_NUM_PAGES)) { MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page); rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_MEDIA_INFO, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) return rc; if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST + SFP_PAGE_SIZE)) return -EIO; payload_len = MCDI_DWORD(outbuf, GET_PHY_MEDIA_INFO_OUT_DATALEN); if (payload_len != SFP_PAGE_SIZE) return -EIO; /* Copy as much as we can into data */ payload_len -= page_off; to_copy = (space_remaining < payload_len) ? space_remaining : payload_len; memcpy(user_data, MCDI_PTR(outbuf, GET_PHY_MEDIA_INFO_OUT_DATA) + page_off, to_copy); space_remaining -= to_copy; user_data += to_copy; page_off = 0; page++; } return 0; }
/* Get physical port number (EF10 only; on Siena it is same as PF number) */ int efx_mcdi_port_get_number(struct efx_nic *efx) { MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN); int rc; rc = efx_mcdi_rpc(efx, MC_CMD_GET_PORT_ASSIGNMENT, NULL, 0, outbuf, sizeof(outbuf), NULL); if (rc) return rc; return MCDI_DWORD(outbuf, GET_PORT_ASSIGNMENT_OUT_PORT); }
int efx_aoe_update_keys(struct efx_nic *efx, struct efx_update_license *key_stats) { int rc; MCDI_DECLARE_BUF(inbuf, MC_CMD_FC_IN_LICENSE_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_FC_OUT_LICENSE_LEN); if (!efx->aoe_data) return -ENOSYS; /* 1. Request the FC to update the license keys */ MCDI_SET_DWORD(inbuf, FC_IN_CMD, MC_CMD_FC_OP_LICENSE); MCDI_SET_DWORD(inbuf, FC_IN_LICENSE_OP, MC_CMD_FC_IN_LICENSE_UPDATE_LICENSE); rc = efx_mcdi_rpc(efx, MC_CMD_FC, inbuf, sizeof(inbuf), NULL, 0, NULL); if (rc) return rc; /* 2. Obtain stats about the keys and return to the called */ MCDI_SET_DWORD(inbuf, FC_IN_LICENSE_OP, MC_CMD_FC_IN_LICENSE_GET_KEY_STATS); rc = efx_mcdi_rpc(efx, MC_CMD_FC, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), NULL); if (rc) return rc; key_stats->valid_keys = MCDI_DWORD(outbuf, FC_OUT_LICENSE_VALID_KEYS); key_stats->invalid_keys = MCDI_DWORD(outbuf, FC_OUT_LICENSE_INVALID_KEYS); key_stats->blacklisted_keys = MCDI_DWORD(outbuf, FC_OUT_LICENSE_BLACKLISTED_KEYS); return 0; }
int efx_ef10_sriov_get_vf_config(struct efx_nic *efx, int vf_i, struct ifla_vf_info *ivf) { #ifdef EFX_HAVE_VF_LINK_STATE MCDI_DECLARE_BUF(inbuf, MC_CMD_LINK_STATE_MODE_IN_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_LINK_STATE_MODE_OUT_LEN); #endif struct efx_ef10_nic_data *nic_data = efx->nic_data; struct ef10_vf *vf; #ifdef EFX_HAVE_VF_LINK_STATE size_t outlen; int rc; #endif if (vf_i >= efx->vf_count) return -EINVAL; if (nic_data->vf == NULL) return -EOPNOTSUPP; vf = nic_data->vf + vf_i; ivf->vf = vf_i; #if !defined(EFX_USE_KCOMPAT) || defined(EFX_HAVE_VF_INFO_MIN_TX_RATE) ivf->min_tx_rate = 0; ivf->max_tx_rate = 0; #else ivf->tx_rate = 0; #endif ether_addr_copy(ivf->mac, vf->mac); ivf->vlan = (vf->vlan == EFX_EF10_NO_VLAN) ? 0 : vf->vlan; ivf->qos = 0; #ifdef EFX_HAVE_VF_LINK_STATE MCDI_POPULATE_DWORD_2(inbuf, LINK_STATE_MODE_IN_FUNCTION, LINK_STATE_MODE_IN_FUNCTION_PF, nic_data->pf_index, LINK_STATE_MODE_IN_FUNCTION_VF, vf_i); MCDI_SET_DWORD(inbuf, LINK_STATE_MODE_IN_NEW_MODE, MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE); rc = efx_mcdi_rpc(efx, MC_CMD_LINK_STATE_MODE, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) return rc; if (outlen < MC_CMD_LINK_STATE_MODE_OUT_LEN) return -EIO; ivf->linkstate = MCDI_DWORD(outbuf, LINK_STATE_MODE_OUT_OLD_MODE); #endif return 0; }
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); }
bool efx_mcdi_mac_check_fault(struct efx_nic *efx) { MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); size_t outlength; int rc; BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), &outlength); if (rc) return true; return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0; }
static int efx_ef10_sriov_vf_max(struct efx_nic *efx) { MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_SRIOV_CFG_OUT_LEN); size_t outlen; int rc; int vf_max; BUILD_BUG_ON(MC_CMD_GET_SRIOV_CFG_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_SRIOV_CFG, NULL, 0, outbuf, sizeof(outbuf), &outlen); if (rc) vf_max = 0; else vf_max = MCDI_DWORD(outbuf, GET_SRIOV_CFG_OUT_VF_MAX); return vf_max; }
bool efx_mcdi_mac_check_fault(struct efx_nic *efx) { u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; size_t outlength; int rc; BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), &outlength); if (rc) { netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return true; } return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0; }
static int efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg) { u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN]; size_t outlen; int rc; BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0); BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name)); rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0, outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) { rc = -EIO; goto fail; } cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS); cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE); cfg->supported_cap = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP); cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL); cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT); cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK); memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME), sizeof(cfg->name)); cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE); cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK); memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION), sizeof(cfg->revision)); return 0; fail: netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
static int efx_mcdi_phy_test_alive(struct efx_nic *efx) { u8 outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN]; size_t outlen; int rc; BUILD_BUG_ON(MC_CMD_GET_PHY_STATE_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_STATE, NULL, 0, outbuf, sizeof(outbuf), &outlen); if (rc) return rc; if (outlen < MC_CMD_GET_PHY_STATE_OUT_LEN) return -EIO; if (MCDI_DWORD(outbuf, GET_PHY_STATE_STATE) != MC_CMD_PHY_STATE_OK) return -EINVAL; return 0; }
static int efx_mcdi_get_mac_faults(struct efx_nic *efx, u32 *faults) { u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; size_t outlength; int rc; BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), &outlength); if (rc) goto fail; *faults = MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT); return 0; fail: netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type) { u8 inbuf[MC_CMD_NVRAM_TEST_IN_LEN]; u8 outbuf[MC_CMD_NVRAM_TEST_OUT_LEN]; int rc; MCDI_SET_DWORD(inbuf, NVRAM_TEST_IN_TYPE, type); rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TEST, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), NULL); if (rc) return rc; switch (MCDI_DWORD(outbuf, NVRAM_TEST_OUT_RESULT)) { case MC_CMD_NVRAM_TEST_PASS: case MC_CMD_NVRAM_TEST_NOTSUPP: return 0; default: return -EIO; } }
/** efx_mcdi_phy_get_module_eeprom_page() - Get a single page of module eeprom * @efx: NIC context * @page: EEPROM page number * @data: Destination data pointer * @offset: Offset in page to copy from in to data * @space: Space available in data * * Return: * >=0 - amount of data copied * <0 - error */ static int efx_mcdi_phy_get_module_eeprom_page(struct efx_nic *efx, unsigned int page, u8 *data, ssize_t offset, ssize_t space) { MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_PHY_MEDIA_INFO_OUT_LENMAX); MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN); size_t outlen; unsigned int payload_len; unsigned int to_copy; int rc; if (offset > SFP_PAGE_SIZE) return -EINVAL; to_copy = min(space, SFP_PAGE_SIZE - offset); MCDI_SET_DWORD(inbuf, GET_PHY_MEDIA_INFO_IN_PAGE, page); rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_PHY_MEDIA_INFO, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) return rc; if (outlen < (MC_CMD_GET_PHY_MEDIA_INFO_OUT_DATA_OFST + SFP_PAGE_SIZE)) return -EIO; payload_len = MCDI_DWORD(outbuf, GET_PHY_MEDIA_INFO_OUT_DATALEN); if (payload_len != SFP_PAGE_SIZE) return -EIO; memcpy(data, MCDI_PTR(outbuf, GET_PHY_MEDIA_INFO_OUT_DATA) + offset, to_copy); return to_copy; }
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; }
static int efx_mcdi_bist(struct efx_nic *efx, unsigned int bist_mode, int *results) { unsigned int retry, i, count = 0; size_t outlen; u32 status; u8 *buf, *ptr; int rc; buf = kzalloc(0x100, GFP_KERNEL); if (buf == NULL) return -ENOMEM; BUILD_BUG_ON(MC_CMD_START_BIST_OUT_LEN != 0); MCDI_SET_DWORD(buf, START_BIST_IN_TYPE, bist_mode); rc = efx_mcdi_rpc(efx, MC_CMD_START_BIST, buf, MC_CMD_START_BIST_IN_LEN, NULL, 0, NULL); if (rc) goto out; for (retry = 0; retry < 100; ++retry) { BUILD_BUG_ON(MC_CMD_POLL_BIST_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0, buf, 0x100, &outlen); if (rc) goto out; status = MCDI_DWORD(buf, POLL_BIST_OUT_RESULT); if (status != MC_CMD_POLL_BIST_RUNNING) goto finished; msleep(100); } rc = -ETIMEDOUT; goto out; finished: results[count++] = (status == MC_CMD_POLL_BIST_PASSED) ? 1 : -1; if (efx->phy_type == PHY_TYPE_SFT9001B && (bist_mode == MC_CMD_PHY_BIST_CABLE_SHORT || bist_mode == MC_CMD_PHY_BIST_CABLE_LONG)) { ptr = MCDI_PTR(buf, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A); if (status == MC_CMD_POLL_BIST_PASSED && outlen >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN) { for (i = 0; i < 8; i++) { results[count + i] = EFX_DWORD_FIELD(((efx_dword_t *)ptr)[i], EFX_DWORD_0); } } count += 8; } rc = count; out: kfree(buf); 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; /* 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; }