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; }
int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, loff_t offset, const u8 *buffer, size_t length) { u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX)]; int rc; MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type); MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset); MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length); memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length); BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4), NULL, 0, NULL); if (rc) goto fail; return 0; fail: netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; }
void efx_mcdi_print_fwver(struct efx_nic *efx, char *buf, size_t len) { u8 outbuf[ALIGN(MC_CMD_GET_VERSION_V1_OUT_LEN, 4)]; size_t outlength; const __le16 *ver_words; int rc; BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0, outbuf, sizeof(outbuf), &outlength); if (rc) goto fail; if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) { rc = -EIO; goto fail; } ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION); snprintf(buf, len, "%u.%u.%u.%u", le16_to_cpu(ver_words[0]), le16_to_cpu(ver_words[1]), le16_to_cpu(ver_words[2]), le16_to_cpu(ver_words[3])); return; fail: netif_err(efx, probe, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); buf[0] = 0; }
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; }
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_ef10_vport_del_vf_mac(struct efx_nic *efx, unsigned int port_id, u8 *mac) { MCDI_DECLARE_BUF(inbuf, MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN); MCDI_DECLARE_BUF_ERR(outbuf); size_t outlen; int rc; MCDI_SET_DWORD(inbuf, VPORT_DEL_MAC_ADDRESS_IN_VPORT_ID, port_id); ether_addr_copy(MCDI_PTR(inbuf, VPORT_DEL_MAC_ADDRESS_IN_MACADDR), mac); rc = efx_mcdi_rpc(efx, MC_CMD_VPORT_DEL_MAC_ADDRESS, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); return rc; }
int efx_mcdi_set_mac(struct efx_nic *efx) { u32 fcntl; MCDI_DECLARE_BUF(cmdbytes, MC_CMD_SET_MAC_IN_LEN); BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0); /* This has no effect on EF10 */ ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR), efx->net_dev->dev_addr); MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, EFX_MAX_FRAME_LEN(efx->net_dev->mtu)); MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0); /* Set simple MAC filter for Siena */ MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_REJECT, SET_MAC_IN_REJECT_UNCST, efx->unicast_filter); MCDI_POPULATE_DWORD_1(cmdbytes, SET_MAC_IN_FLAGS, SET_MAC_IN_FLAG_INCLUDE_FCS, !!(efx->net_dev->features & NETIF_F_RXFCS)); switch (efx->wanted_fc) { case EFX_FC_RX | EFX_FC_TX: fcntl = MC_CMD_FCNTL_BIDIR; break; case EFX_FC_RX: fcntl = MC_CMD_FCNTL_RESPOND; break; default: fcntl = MC_CMD_FCNTL_OFF; break; } if (efx->wanted_fc & EFX_FC_AUTO) fcntl = MC_CMD_FCNTL_AUTO; if (efx->fc_disable) fcntl = MC_CMD_FCNTL_OFF; MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl); return efx_mcdi_rpc(efx, MC_CMD_SET_MAC, cmdbytes, sizeof(cmdbytes), NULL, 0, NULL); }
int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, u32 dma_len, int enable, int clear) { u8 inbuf[MC_CMD_MAC_STATS_IN_LEN]; int rc; efx_dword_t *cmd_ptr; int period = enable ? 1000 : 0; u32 addr_hi; u32 addr_lo; BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_DMA_LEN != 0); addr_lo = ((u64)dma_addr) >> 0; addr_hi = ((u64)dma_addr) >> 32; MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_LO, addr_lo); MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_HI, addr_hi); cmd_ptr = (efx_dword_t *)MCDI_PTR(inbuf, MAC_STATS_IN_CMD); EFX_POPULATE_DWORD_7(*cmd_ptr, MC_CMD_MAC_STATS_IN_DMA, !!enable, MC_CMD_MAC_STATS_IN_CLEAR, clear, MC_CMD_MAC_STATS_IN_PERIODIC_CHANGE, 1, MC_CMD_MAC_STATS_IN_PERIODIC_ENABLE, !!enable, MC_CMD_MAC_STATS_IN_PERIODIC_CLEAR, 0, MC_CMD_MAC_STATS_IN_PERIODIC_NOEVENT, 1, MC_CMD_MAC_STATS_IN_PERIOD_MS, period); MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len); rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf), NULL, 0, NULL); if (rc) goto fail; return 0; fail: netif_err(efx, hw, efx->net_dev, "%s: %s failed rc=%d\n", __func__, enable ? "enable" : "disable", rc); return rc; }
static int siena_mac_reconfigure(struct efx_nic *efx) { MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_MCAST_HASH_IN_LEN); int rc; BUILD_BUG_ON(MC_CMD_SET_MCAST_HASH_IN_LEN != MC_CMD_SET_MCAST_HASH_IN_HASH0_OFST + sizeof(efx->multicast_hash)); efx_farch_filter_sync_rx_mode(efx); WARN_ON(!mutex_is_locked(&efx->mac_lock)); rc = efx_mcdi_set_mac(efx); if (rc != 0) return rc; memcpy(MCDI_PTR(inbuf, SET_MCAST_HASH_IN_HASH0), efx->multicast_hash.byte, sizeof(efx->multicast_hash)); return efx_mcdi_rpc(efx, MC_CMD_SET_MCAST_HASH, inbuf, sizeof(inbuf), NULL, 0, NULL); }
/** 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; }
int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, loff_t offset, u8 *buffer, size_t length) { u8 inbuf[MC_CMD_NVRAM_READ_IN_LEN]; u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX)]; size_t outlen; int rc; MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type); MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset); MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length); rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); if (rc) goto fail; memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length); return 0; fail: netif_err(efx, hw, 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; 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; }