Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue

Tony Nguyen says:

====================
100GbE Intel Wired LAN Driver Updates 2021-02-05

This series contains updates to ice driver only.

Jake adds adds reporting of timeout length during devlink flash and
implements support to report devlink info regarding the version of
firmware that is stored (downloaded) to the device, but is not yet active.
ice_devlink_info_get will report "stored" versions when there is no
pending flash update. Version info includes the UNDI Option ROM, the
Netlist module, and the fw.bundle_id.

Gustavo A. R. Silva replaces a one-element array to flexible-array
member.

Bruce utilizes flex_array_size() helper and removes dead code on a check
for a condition that can't occur.

v2:
* removed security revision implementation, and re-ordered patches to
account for this removal
* squashed patches implementing ice_read_flash_module to avoid patches
refactoring the implementation of a previous patch in the series
* modify ice_devlink_info_get to always report "stored" versions instead
of only reporting them when a pending flash update is ready.

* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  ice: remove dead code
  ice: use flex_array_size where possible
  ice: Replace one-element array with flexible-array member
  ice: display stored UNDI firmware version via devlink info
  ice: display stored netlist versions via devlink info
  ice: display some stored NVM versions via devlink info
  ice: introduce function for reading from flash modules
  ice: cache NVM module bank information
  ice: introduce context struct for info report
  ice: create flash_info structure and separate NVM version
  ice: report timeout length for erasing during devlink flash
====================

Link: https://lore.kernel.org/r/20210206044101.636242-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2021-02-06 16:10:19 -08:00
commit badc6ac321
12 changed files with 915 additions and 251 deletions

View file

@ -166,7 +166,7 @@ struct ice_tc_cfg {
struct ice_res_tracker {
u16 num_entries;
u16 end;
u16 list[1];
u16 list[];
};
struct ice_qs_cfg {

View file

@ -1334,33 +1334,6 @@ struct ice_aqc_nvm_checksum {
u8 rsvd2[12];
};
/* The result of netlist NVM read comes in a TLV format. The actual data
* (netlist header) starts from word offset 1 (byte 2). The FW strips
* out the type field from the TLV header so all the netlist fields
* should adjust their offset value by 1 word (2 bytes) in order to map
* their correct location.
*/
#define ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID 0x11B
#define ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN_OFFSET 1
#define ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN 2 /* In bytes */
#define ICE_AQC_NVM_NETLIST_NODE_COUNT_OFFSET 2
#define ICE_AQC_NVM_NETLIST_NODE_COUNT_LEN 2 /* In bytes */
#define ICE_AQC_NVM_NETLIST_NODE_COUNT_M ICE_M(0x3FF, 0)
#define ICE_AQC_NVM_NETLIST_ID_BLK_START_OFFSET 5
#define ICE_AQC_NVM_NETLIST_ID_BLK_LEN 0x30 /* In words */
/* netlist ID block field offsets (word offsets) */
#define ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_LOW 2
#define ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_HIGH 3
#define ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_LOW 4
#define ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_HIGH 5
#define ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_LOW 6
#define ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_HIGH 7
#define ICE_AQC_NVM_NETLIST_ID_BLK_REV_LOW 8
#define ICE_AQC_NVM_NETLIST_ID_BLK_REV_HIGH 9
#define ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH 0xA
#define ICE_AQC_NVM_NETLIST_ID_BLK_CUST_VER 0x2F
/* Used for NVM Set Package Data command - 0x070A */
struct ice_aqc_nvm_pkg_data {
u8 reserved[3];

View file

@ -1653,7 +1653,7 @@ ice_aq_alloc_free_res(struct ice_hw *hw, u16 num_entries,
if (!buf)
return ICE_ERR_PARAM;
if (buf_size < (num_entries * sizeof(buf->elem[0])))
if (buf_size < flex_array_size(buf, elem, num_entries))
return ICE_ERR_PARAM;
ice_fill_dflt_direct_cmd_desc(&desc, opc);

View file

@ -6,132 +6,226 @@
#include "ice_devlink.h"
#include "ice_fw_update.h"
static void ice_info_get_dsn(struct ice_pf *pf, char *buf, size_t len)
/* context for devlink info version reporting */
struct ice_info_ctx {
char buf[128];
struct ice_orom_info pending_orom;
struct ice_nvm_info pending_nvm;
struct ice_netlist_info pending_netlist;
struct ice_hw_dev_caps dev_caps;
};
/* The following functions are used to format specific strings for various
* devlink info versions. The ctx parameter is used to provide the storage
* buffer, as well as any ancillary information calculated when the info
* request was made.
*
* If a version does not exist, for example when attempting to get the
* inactive version of flash when there is no pending update, the function
* should leave the buffer in the ctx structure empty and return 0.
*/
static void ice_info_get_dsn(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
u8 dsn[8];
/* Copy the DSN into an array in Big Endian format */
put_unaligned_be64(pci_get_dsn(pf->pdev), dsn);
snprintf(buf, len, "%8phD", dsn);
snprintf(ctx->buf, sizeof(ctx->buf), "%8phD", dsn);
}
static int ice_info_pba(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_pba(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_hw *hw = &pf->hw;
enum ice_status status;
status = ice_read_pba_string(hw, (u8 *)buf, len);
status = ice_read_pba_string(hw, (u8 *)ctx->buf, sizeof(ctx->buf));
if (status)
return -EIO;
return 0;
}
static int ice_info_fw_mgmt(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_fw_mgmt(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_hw *hw = &pf->hw;
snprintf(buf, len, "%u.%u.%u", hw->fw_maj_ver, hw->fw_min_ver,
snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", hw->fw_maj_ver, hw->fw_min_ver,
hw->fw_patch);
return 0;
}
static int ice_info_fw_api(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_fw_api(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_hw *hw = &pf->hw;
snprintf(buf, len, "%u.%u", hw->api_maj_ver, hw->api_min_ver);
snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u", hw->api_maj_ver, hw->api_min_ver);
return 0;
}
static int ice_info_fw_build(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_fw_build(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_hw *hw = &pf->hw;
snprintf(buf, len, "0x%08x", hw->fw_build);
snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", hw->fw_build);
return 0;
}
static int ice_info_orom_ver(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_orom_ver(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_orom_info *orom = &pf->hw.nvm.orom;
struct ice_orom_info *orom = &pf->hw.flash.orom;
snprintf(buf, len, "%u.%u.%u", orom->major, orom->build, orom->patch);
snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", orom->major, orom->build, orom->patch);
return 0;
}
static int ice_info_nvm_ver(struct ice_pf *pf, char *buf, size_t len)
static int
ice_info_pending_orom_ver(struct ice_pf __always_unused *pf, struct ice_info_ctx *ctx)
{
struct ice_nvm_info *nvm = &pf->hw.nvm;
struct ice_orom_info *orom = &ctx->pending_orom;
snprintf(buf, len, "%x.%02x", nvm->major_ver, nvm->minor_ver);
if (ctx->dev_caps.common_cap.nvm_update_pending_orom)
snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u",
orom->major, orom->build, orom->patch);
return 0;
}
static int ice_info_eetrack(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_nvm_ver(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_nvm_info *nvm = &pf->hw.nvm;
struct ice_nvm_info *nvm = &pf->hw.flash.nvm;
snprintf(buf, len, "0x%08x", nvm->eetrack);
snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", nvm->major, nvm->minor);
return 0;
}
static int ice_info_ddp_pkg_name(struct ice_pf *pf, char *buf, size_t len)
static int
ice_info_pending_nvm_ver(struct ice_pf __always_unused *pf, struct ice_info_ctx *ctx)
{
struct ice_nvm_info *nvm = &ctx->pending_nvm;
if (ctx->dev_caps.common_cap.nvm_update_pending_nvm)
snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", nvm->major, nvm->minor);
return 0;
}
static int ice_info_eetrack(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_nvm_info *nvm = &pf->hw.flash.nvm;
snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm->eetrack);
return 0;
}
static int
ice_info_pending_eetrack(struct ice_pf __always_unused *pf, struct ice_info_ctx *ctx)
{
struct ice_nvm_info *nvm = &ctx->pending_nvm;
if (ctx->dev_caps.common_cap.nvm_update_pending_nvm)
snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm->eetrack);
return 0;
}
static int ice_info_ddp_pkg_name(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_hw *hw = &pf->hw;
snprintf(buf, len, "%s", hw->active_pkg_name);
snprintf(ctx->buf, sizeof(ctx->buf), "%s", hw->active_pkg_name);
return 0;
}
static int ice_info_ddp_pkg_version(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_ddp_pkg_version(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_pkg_ver *pkg = &pf->hw.active_pkg_ver;
snprintf(buf, len, "%u.%u.%u.%u", pkg->major, pkg->minor, pkg->update,
snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u.%u", pkg->major, pkg->minor, pkg->update,
pkg->draft);
return 0;
}
static int ice_info_ddp_pkg_bundle_id(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_ddp_pkg_bundle_id(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
snprintf(buf, len, "0x%08x", pf->hw.active_track_id);
snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", pf->hw.active_track_id);
return 0;
}
static int ice_info_netlist_ver(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_netlist_ver(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_netlist_ver_info *netlist = &pf->hw.netlist_ver;
struct ice_netlist_info *netlist = &pf->hw.flash.netlist;
/* The netlist version fields are BCD formatted */
snprintf(buf, len, "%x.%x.%x-%x.%x.%x", netlist->major, netlist->minor,
snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x", netlist->major, netlist->minor,
netlist->type >> 16, netlist->type & 0xFFFF, netlist->rev,
netlist->cust_ver);
return 0;
}
static int ice_info_netlist_build(struct ice_pf *pf, char *buf, size_t len)
static int ice_info_netlist_build(struct ice_pf *pf, struct ice_info_ctx *ctx)
{
struct ice_netlist_ver_info *netlist = &pf->hw.netlist_ver;
struct ice_netlist_info *netlist = &pf->hw.flash.netlist;
snprintf(buf, len, "0x%08x", netlist->hash);
snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash);
return 0;
}
#define fixed(key, getter) { ICE_VERSION_FIXED, key, getter }
#define running(key, getter) { ICE_VERSION_RUNNING, key, getter }
static int
ice_info_pending_netlist_ver(struct ice_pf __always_unused *pf, struct ice_info_ctx *ctx)
{
struct ice_netlist_info *netlist = &ctx->pending_netlist;
/* The netlist version fields are BCD formatted */
if (ctx->dev_caps.common_cap.nvm_update_pending_netlist)
snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x",
netlist->major, netlist->minor,
netlist->type >> 16, netlist->type & 0xFFFF, netlist->rev,
netlist->cust_ver);
return 0;
}
static int
ice_info_pending_netlist_build(struct ice_pf __always_unused *pf, struct ice_info_ctx *ctx)
{
struct ice_netlist_info *netlist = &ctx->pending_netlist;
if (ctx->dev_caps.common_cap.nvm_update_pending_netlist)
snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash);
return 0;
}
#define fixed(key, getter) { ICE_VERSION_FIXED, key, getter, NULL }
#define running(key, getter) { ICE_VERSION_RUNNING, key, getter, NULL }
#define stored(key, getter, fallback) { ICE_VERSION_STORED, key, getter, fallback }
/* The combined() macro inserts both the running entry as well as a stored
* entry. The running entry will always report the version from the active
* handler. The stored entry will first try the pending handler, and fallback
* to the active handler if the pending function does not report a version.
* The pending handler should check the status of a pending update for the
* relevant flash component. It should only fill in the buffer in the case
* where a valid pending version is available. This ensures that the related
* stored and running versions remain in sync, and that stored versions are
* correctly reported as expected.
*/
#define combined(key, active, pending) \
running(key, active), \
stored(key, pending, active)
enum ice_version_type {
ICE_VERSION_FIXED,
@ -142,20 +236,21 @@ enum ice_version_type {
static const struct ice_devlink_version {
enum ice_version_type type;
const char *key;
int (*getter)(struct ice_pf *pf, char *buf, size_t len);
int (*getter)(struct ice_pf *pf, struct ice_info_ctx *ctx);
int (*fallback)(struct ice_pf *pf, struct ice_info_ctx *ctx);
} ice_devlink_versions[] = {
fixed(DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, ice_info_pba),
running(DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, ice_info_fw_mgmt),
running("fw.mgmt.api", ice_info_fw_api),
running("fw.mgmt.build", ice_info_fw_build),
running(DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, ice_info_orom_ver),
running("fw.psid.api", ice_info_nvm_ver),
running(DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, ice_info_eetrack),
combined(DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, ice_info_orom_ver, ice_info_pending_orom_ver),
combined("fw.psid.api", ice_info_nvm_ver, ice_info_pending_nvm_ver),
combined(DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, ice_info_eetrack, ice_info_pending_eetrack),
running("fw.app.name", ice_info_ddp_pkg_name),
running(DEVLINK_INFO_VERSION_GENERIC_FW_APP, ice_info_ddp_pkg_version),
running("fw.app.bundle_id", ice_info_ddp_pkg_bundle_id),
running("fw.netlist", ice_info_netlist_ver),
running("fw.netlist.build", ice_info_netlist_build),
combined("fw.netlist", ice_info_netlist_ver, ice_info_pending_netlist_ver),
combined("fw.netlist.build", ice_info_netlist_build, ice_info_pending_netlist_build),
};
/**
@ -174,60 +269,128 @@ static int ice_devlink_info_get(struct devlink *devlink,
struct netlink_ext_ack *extack)
{
struct ice_pf *pf = devlink_priv(devlink);
char buf[100];
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
struct ice_info_ctx *ctx;
enum ice_status status;
size_t i;
int err;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
/* discover capabilities first */
status = ice_discover_dev_caps(hw, &ctx->dev_caps);
if (status) {
err = -EIO;
goto out_free_ctx;
}
if (ctx->dev_caps.common_cap.nvm_update_pending_orom) {
status = ice_get_inactive_orom_ver(hw, &ctx->pending_orom);
if (status) {
dev_dbg(dev, "Unable to read inactive Option ROM version data, status %s aq_err %s\n",
ice_stat_str(status), ice_aq_str(hw->adminq.sq_last_status));
/* disable display of pending Option ROM */
ctx->dev_caps.common_cap.nvm_update_pending_orom = false;
}
}
if (ctx->dev_caps.common_cap.nvm_update_pending_nvm) {
status = ice_get_inactive_nvm_ver(hw, &ctx->pending_nvm);
if (status) {
dev_dbg(dev, "Unable to read inactive NVM version data, status %s aq_err %s\n",
ice_stat_str(status), ice_aq_str(hw->adminq.sq_last_status));
/* disable display of pending Option ROM */
ctx->dev_caps.common_cap.nvm_update_pending_nvm = false;
}
}
if (ctx->dev_caps.common_cap.nvm_update_pending_netlist) {
status = ice_get_inactive_netlist_ver(hw, &ctx->pending_netlist);
if (status) {
dev_dbg(dev, "Unable to read inactive Netlist version data, status %s aq_err %s\n",
ice_stat_str(status), ice_aq_str(hw->adminq.sq_last_status));
/* disable display of pending Option ROM */
ctx->dev_caps.common_cap.nvm_update_pending_netlist = false;
}
}
err = devlink_info_driver_name_put(req, KBUILD_MODNAME);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to set driver name");
return err;
goto out_free_ctx;
}
ice_info_get_dsn(pf, buf, sizeof(buf));
ice_info_get_dsn(pf, ctx);
err = devlink_info_serial_number_put(req, buf);
err = devlink_info_serial_number_put(req, ctx->buf);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to set serial number");
return err;
goto out_free_ctx;
}
for (i = 0; i < ARRAY_SIZE(ice_devlink_versions); i++) {
enum ice_version_type type = ice_devlink_versions[i].type;
const char *key = ice_devlink_versions[i].key;
err = ice_devlink_versions[i].getter(pf, buf, sizeof(buf));
memset(ctx->buf, 0, sizeof(ctx->buf));
err = ice_devlink_versions[i].getter(pf, ctx);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to obtain version info");
return err;
goto out_free_ctx;
}
/* If the default getter doesn't report a version, use the
* fallback function. This is primarily useful in the case of
* "stored" versions that want to report the same value as the
* running version in the normal case of no pending update.
*/
if (ctx->buf[0] == '\0' && ice_devlink_versions[i].fallback) {
err = ice_devlink_versions[i].fallback(pf, ctx);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to obtain version info");
goto out_free_ctx;
}
}
/* Do not report missing versions */
if (ctx->buf[0] == '\0')
continue;
switch (type) {
case ICE_VERSION_FIXED:
err = devlink_info_version_fixed_put(req, key, buf);
err = devlink_info_version_fixed_put(req, key, ctx->buf);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to set fixed version");
return err;
goto out_free_ctx;
}
break;
case ICE_VERSION_RUNNING:
err = devlink_info_version_running_put(req, key, buf);
err = devlink_info_version_running_put(req, key, ctx->buf);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to set running version");
return err;
goto out_free_ctx;
}
break;
case ICE_VERSION_STORED:
err = devlink_info_version_stored_put(req, key, buf);
err = devlink_info_version_stored_put(req, key, ctx->buf);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "Unable to set stored version");
return err;
goto out_free_ctx;
}
break;
}
}
return 0;
out_free_ctx:
kfree(ctx);
return err;
}
/**
@ -433,7 +596,7 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
void *nvm_data;
u32 nvm_size;
nvm_size = hw->nvm.flash_size;
nvm_size = hw->flash.flash_size;
nvm_data = vzalloc(nvm_size);
if (!nvm_data)
return -ENOMEM;
@ -533,7 +696,7 @@ void ice_devlink_init_regions(struct ice_pf *pf)
struct device *dev = ice_pf_to_dev(pf);
u64 nvm_size;
nvm_size = pf->hw.nvm.flash_size;
nvm_size = pf->hw.flash.flash_size;
pf->nvm_region = devlink_region_create(devlink, &ice_nvm_region_ops, 1,
nvm_size);
if (IS_ERR(pf->nvm_region)) {

View file

@ -179,8 +179,8 @@ ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
struct ice_orom_info *orom;
struct ice_nvm_info *nvm;
nvm = &hw->nvm;
orom = &nvm->orom;
nvm = &hw->flash.nvm;
orom = &hw->flash.orom;
strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
@ -188,7 +188,7 @@ ice_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
* determined) which contains more pertinent information.
*/
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
"%x.%02x 0x%x %d.%d.%d", nvm->major_ver, nvm->minor_ver,
"%x.%02x 0x%x %d.%d.%d", nvm->major, nvm->minor,
nvm->eetrack, orom->major, orom->build, orom->patch);
strscpy(drvinfo->bus_info, pci_name(pf->pdev),
@ -250,7 +250,7 @@ static int ice_get_eeprom_len(struct net_device *netdev)
struct ice_netdev_priv *np = netdev_priv(netdev);
struct ice_pf *pf = np->vsi->back;
return (int)pf->hw.nvm.flash_size;
return (int)pf->hw.flash.flash_size;
}
static int

View file

@ -1525,7 +1525,7 @@ ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count)
bld->reserved_section_table_entries += count;
data_end = le16_to_cpu(buf->data_end) +
(count * sizeof(buf->section_entry[0]));
flex_array_size(buf, section_entry, count);
buf->data_end = cpu_to_le16(data_end);
return 0;

View file

@ -417,6 +417,11 @@ ice_write_nvm_module(struct ice_pf *pf, u16 module, const char *component,
return err;
}
/* Length in seconds to wait before timing out when erasing a flash module.
* Yes, erasing really can take minutes to complete.
*/
#define ICE_FW_ERASE_TIMEOUT 300
/**
* ice_erase_nvm_module - Erase an NVM module and await firmware completion
* @pf: the PF data structure
@ -449,7 +454,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
devlink = priv_to_devlink(pf);
devlink_flash_update_status_notify(devlink, "Erasing", component, 0, 0);
devlink_flash_update_timeout_notify(devlink, "Erasing", component, ICE_FW_ERASE_TIMEOUT);
status = ice_aq_erase_nvm(hw, module, NULL);
if (status) {
@ -461,8 +466,7 @@ ice_erase_nvm_module(struct ice_pf *pf, u16 module, const char *component,
goto out_notify_devlink;
}
/* Yes, this really can take minutes to complete */
err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_erase, 300 * HZ, &event);
err = ice_aq_wait_for_event(pf, ice_aqc_opc_nvm_erase, ICE_FW_ERASE_TIMEOUT * HZ, &event);
if (err) {
dev_err(dev, "Timed out waiting for firmware to respond with erase completion for %s (module 0x%02x), err %d\n",
component, module, err);

View file

@ -785,15 +785,9 @@ static void ice_set_dflt_mib(struct ice_pf *pf)
u8 mib_type, *buf, *lldpmib = NULL;
u16 len, typelen, offset = 0;
struct ice_lldp_org_tlv *tlv;
struct ice_hw *hw;
struct ice_hw *hw = &pf->hw;
u32 ouisubtype;
if (!pf) {
dev_dbg(dev, "%s NULL pf pointer\n", __func__);
return;
}
hw = &pf->hw;
mib_type = SET_LOCAL_MIB_TYPE_LOCAL_MIB;
lldpmib = kzalloc(ICE_LLDPDU_SIZE, GFP_KERNEL);
if (!lldpmib) {
@ -3495,9 +3489,9 @@ static int ice_init_interrupt_scheme(struct ice_pf *pf)
return vectors;
/* set up vector assignment tracking */
pf->irq_tracker =
devm_kzalloc(ice_pf_to_dev(pf), sizeof(*pf->irq_tracker) +
(sizeof(u16) * vectors), GFP_KERNEL);
pf->irq_tracker = devm_kzalloc(ice_pf_to_dev(pf),
struct_size(pf->irq_tracker, list, vectors),
GFP_KERNEL);
if (!pf->irq_tracker) {
ice_dis_msix(pf);
return -ENOMEM;
@ -6250,6 +6244,8 @@ const char *ice_stat_str(enum ice_status stat_err)
return "ICE_ERR_OUT_OF_RANGE";
case ICE_ERR_ALREADY_EXISTS:
return "ICE_ERR_ALREADY_EXISTS";
case ICE_ERR_NVM:
return "ICE_ERR_NVM";
case ICE_ERR_NVM_CHECKSUM:
return "ICE_ERR_NVM_CHECKSUM";
case ICE_ERR_BUF_TOO_SHORT:

View file

@ -72,7 +72,7 @@ ice_read_flat_nvm(struct ice_hw *hw, u32 offset, u32 *length, u8 *data,
*length = 0;
/* Verify the length of the read if this is for the Shadow RAM */
if (read_shadow_ram && ((offset + inlen) > (hw->nvm.sr_words * 2u))) {
if (read_shadow_ram && ((offset + inlen) > (hw->flash.sr_words * 2u))) {
ice_debug(hw, ICE_DBG_NVM, "NVM error: requested offset is beyond Shadow RAM limit\n");
return ICE_ERR_PARAM;
}
@ -213,7 +213,7 @@ ice_read_sr_word_aq(struct ice_hw *hw, u16 offset, u16 *data)
enum ice_status
ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access)
{
if (hw->nvm.blank_nvm_mode)
if (hw->flash.blank_nvm_mode)
return 0;
return ice_acquire_res(hw, ICE_NVM_RES_ID, access, ICE_NVM_TIMEOUT);
@ -227,12 +227,185 @@ ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access)
*/
void ice_release_nvm(struct ice_hw *hw)
{
if (hw->nvm.blank_nvm_mode)
if (hw->flash.blank_nvm_mode)
return;
ice_release_res(hw, ICE_NVM_RES_ID);
}
/**
* ice_get_flash_bank_offset - Get offset into requested flash bank
* @hw: pointer to the HW structure
* @bank: whether to read from the active or inactive flash bank
* @module: the module to read from
*
* Based on the module, lookup the module offset from the beginning of the
* flash.
*
* Returns the flash offset. Note that a value of zero is invalid and must be
* treated as an error.
*/
static u32 ice_get_flash_bank_offset(struct ice_hw *hw, enum ice_bank_select bank, u16 module)
{
struct ice_bank_info *banks = &hw->flash.banks;
enum ice_flash_bank active_bank;
bool second_bank_active;
u32 offset, size;
switch (module) {
case ICE_SR_1ST_NVM_BANK_PTR:
offset = banks->nvm_ptr;
size = banks->nvm_size;
active_bank = banks->nvm_bank;
break;
case ICE_SR_1ST_OROM_BANK_PTR:
offset = banks->orom_ptr;
size = banks->orom_size;
active_bank = banks->orom_bank;
break;
case ICE_SR_NETLIST_BANK_PTR:
offset = banks->netlist_ptr;
size = banks->netlist_size;
active_bank = banks->netlist_bank;
break;
default:
ice_debug(hw, ICE_DBG_NVM, "Unexpected value for flash module: 0x%04x\n", module);
return 0;
}
switch (active_bank) {
case ICE_1ST_FLASH_BANK:
second_bank_active = false;
break;
case ICE_2ND_FLASH_BANK:
second_bank_active = true;
break;
default:
ice_debug(hw, ICE_DBG_NVM, "Unexpected value for active flash bank: %u\n",
active_bank);
return 0;
}
/* The second flash bank is stored immediately following the first
* bank. Based on whether the 1st or 2nd bank is active, and whether
* we want the active or inactive bank, calculate the desired offset.
*/
switch (bank) {
case ICE_ACTIVE_FLASH_BANK:
return offset + (second_bank_active ? size : 0);
case ICE_INACTIVE_FLASH_BANK:
return offset + (second_bank_active ? 0 : size);
}
ice_debug(hw, ICE_DBG_NVM, "Unexpected value for flash bank selection: %u\n", bank);
return 0;
}
/**
* ice_read_flash_module - Read a word from one of the main NVM modules
* @hw: pointer to the HW structure
* @bank: which bank of the module to read
* @module: the module to read
* @offset: the offset into the module in bytes
* @data: storage for the word read from the flash
* @length: bytes of data to read
*
* Read data from the specified flash module. The bank parameter indicates
* whether or not to read from the active bank or the inactive bank of that
* module.
*
* The word will be read using flat NVM access, and relies on the
* hw->flash.banks data being setup by ice_determine_active_flash_banks()
* during initialization.
*/
static enum ice_status
ice_read_flash_module(struct ice_hw *hw, enum ice_bank_select bank, u16 module,
u32 offset, u8 *data, u32 length)
{
enum ice_status status;
u32 start;
start = ice_get_flash_bank_offset(hw, bank, module);
if (!start) {
ice_debug(hw, ICE_DBG_NVM, "Unable to calculate flash bank offset for module 0x%04x\n",
module);
return ICE_ERR_PARAM;
}
status = ice_acquire_nvm(hw, ICE_RES_READ);
if (status)
return status;
status = ice_read_flat_nvm(hw, start + offset, &length, data, false);
ice_release_nvm(hw);
return status;
}
/**
* ice_read_nvm_module - Read from the active main NVM module
* @hw: pointer to the HW structure
* @bank: whether to read from active or inactive NVM module
* @offset: offset into the NVM module to read, in words
* @data: storage for returned word value
*
* Read the specified word from the active NVM module. This includes the CSS
* header at the start of the NVM module.
*/
static enum ice_status
ice_read_nvm_module(struct ice_hw *hw, enum ice_bank_select bank, u32 offset, u16 *data)
{
enum ice_status status;
__le16 data_local;
status = ice_read_flash_module(hw, bank, ICE_SR_1ST_NVM_BANK_PTR, offset * sizeof(u16),
(__force u8 *)&data_local, sizeof(u16));
if (!status)
*data = le16_to_cpu(data_local);
return status;
}
/**
* ice_read_nvm_sr_copy - Read a word from the Shadow RAM copy in the NVM bank
* @hw: pointer to the HW structure
* @bank: whether to read from the active or inactive NVM module
* @offset: offset into the Shadow RAM copy to read, in words
* @data: storage for returned word value
*
* Read the specified word from the copy of the Shadow RAM found in the
* specified NVM module.
*/
static enum ice_status
ice_read_nvm_sr_copy(struct ice_hw *hw, enum ice_bank_select bank, u32 offset, u16 *data)
{
return ice_read_nvm_module(hw, bank, ICE_NVM_SR_COPY_WORD_OFFSET + offset, data);
}
/**
* ice_read_netlist_module - Read data from the netlist module area
* @hw: pointer to the HW structure
* @bank: whether to read from the active or inactive module
* @offset: offset into the netlist to read from
* @data: storage for returned word value
*
* Read a word from the specified netlist bank.
*/
static enum ice_status
ice_read_netlist_module(struct ice_hw *hw, enum ice_bank_select bank, u32 offset, u16 *data)
{
enum ice_status status;
__le16 data_local;
status = ice_read_flash_module(hw, bank, ICE_SR_NETLIST_BANK_PTR, offset * sizeof(u16),
(__force u8 *)&data_local, sizeof(u16));
if (!status)
*data = le16_to_cpu(data_local);
return status;
}
/**
* ice_read_sr_word - Reads Shadow RAM word and acquire NVM if necessary
* @hw: pointer to the HW structure
@ -380,138 +553,246 @@ ice_read_pba_string(struct ice_hw *hw, u8 *pba_num, u32 pba_num_size)
}
/**
* ice_get_orom_ver_info - Read Option ROM version information
* ice_get_nvm_ver_info - Read NVM version information
* @hw: pointer to the HW struct
* @bank: whether to read from the active or inactive flash bank
* @nvm: pointer to NVM info structure
*
* Read the Combo Image version data from the Boot Configuration TLV and fill
* in the option ROM version data.
* Read the NVM EETRACK ID and map version of the main NVM image bank, filling
* in the NVM info structure.
*/
static enum ice_status ice_get_orom_ver_info(struct ice_hw *hw)
static enum ice_status
ice_get_nvm_ver_info(struct ice_hw *hw, enum ice_bank_select bank, struct ice_nvm_info *nvm)
{
u16 combo_hi, combo_lo, boot_cfg_tlv, boot_cfg_tlv_len;
struct ice_orom_info *orom = &hw->nvm.orom;
u16 eetrack_lo, eetrack_hi, ver;
enum ice_status status;
u32 combo_ver;
status = ice_get_pfa_module_tlv(hw, &boot_cfg_tlv, &boot_cfg_tlv_len,
ICE_SR_BOOT_CFG_PTR);
status = ice_read_nvm_sr_copy(hw, bank, ICE_SR_NVM_DEV_STARTER_VER, &ver);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read Boot Configuration Block TLV.\n");
ice_debug(hw, ICE_DBG_NVM, "Failed to read DEV starter version.\n");
return status;
}
/* Boot Configuration Block must have length at least 2 words
* (Combo Image Version High and Combo Image Version Low)
*/
if (boot_cfg_tlv_len < 2) {
ice_debug(hw, ICE_DBG_INIT, "Invalid Boot Configuration Block TLV size.\n");
return ICE_ERR_INVAL_SIZE;
}
nvm->major = (ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT;
nvm->minor = (ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT;
status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OROM_VER_OFF),
&combo_hi);
status = ice_read_nvm_sr_copy(hw, bank, ICE_SR_NVM_EETRACK_LO, &eetrack_lo);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read OROM_VER hi.\n");
ice_debug(hw, ICE_DBG_NVM, "Failed to read EETRACK lo.\n");
return status;
}
status = ice_read_nvm_sr_copy(hw, bank, ICE_SR_NVM_EETRACK_HI, &eetrack_hi);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read EETRACK hi.\n");
return status;
}
status = ice_read_sr_word(hw, (boot_cfg_tlv + ICE_NVM_OROM_VER_OFF + 1),
&combo_lo);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read OROM_VER lo.\n");
return status;
}
combo_ver = ((u32)combo_hi << 16) | combo_lo;
orom->major = (u8)((combo_ver & ICE_OROM_VER_MASK) >>
ICE_OROM_VER_SHIFT);
orom->patch = (u8)(combo_ver & ICE_OROM_VER_PATCH_MASK);
orom->build = (u16)((combo_ver & ICE_OROM_VER_BUILD_MASK) >>
ICE_OROM_VER_BUILD_SHIFT);
nvm->eetrack = (eetrack_hi << 16) | eetrack_lo;
return 0;
}
/**
* ice_get_netlist_ver_info
* @hw: pointer to the HW struct
* ice_get_inactive_nvm_ver - Read Option ROM version from the inactive bank
* @hw: pointer to the HW structure
* @nvm: storage for Option ROM version information
*
* Get the netlist version information
* Reads the NVM EETRACK ID, Map version, and security revision of the
* inactive NVM bank. Used to access version data for a pending update that
* has not yet been activated.
*/
static enum ice_status ice_get_netlist_ver_info(struct ice_hw *hw)
enum ice_status ice_get_inactive_nvm_ver(struct ice_hw *hw, struct ice_nvm_info *nvm)
{
struct ice_netlist_ver_info *ver = &hw->netlist_ver;
enum ice_status ret;
u32 id_blk_start;
__le16 raw_data;
u16 data, i;
u16 *buff;
return ice_get_nvm_ver_info(hw, ICE_INACTIVE_FLASH_BANK, nvm);
}
ret = ice_acquire_nvm(hw, ICE_RES_READ);
if (ret)
return ret;
buff = kcalloc(ICE_AQC_NVM_NETLIST_ID_BLK_LEN, sizeof(*buff),
GFP_KERNEL);
if (!buff) {
ret = ICE_ERR_NO_MEMORY;
goto exit_no_mem;
/**
* ice_get_orom_civd_data - Get the combo version information from Option ROM
* @hw: pointer to the HW struct
* @bank: whether to read from the active or inactive flash module
* @civd: storage for the Option ROM CIVD data.
*
* Searches through the Option ROM flash contents to locate the CIVD data for
* the image.
*/
static enum ice_status
ice_get_orom_civd_data(struct ice_hw *hw, enum ice_bank_select bank,
struct ice_orom_civd_info *civd)
{
struct ice_orom_civd_info tmp;
enum ice_status status;
u32 offset;
/* The CIVD section is located in the Option ROM aligned to 512 bytes.
* The first 4 bytes must contain the ASCII characters "$CIV".
* A simple modulo 256 sum of all of the bytes of the structure must
* equal 0.
*/
for (offset = 0; (offset + 512) <= hw->flash.banks.orom_size; offset += 512) {
u8 sum = 0, i;
status = ice_read_flash_module(hw, bank, ICE_SR_1ST_OROM_BANK_PTR,
offset, (u8 *)&tmp, sizeof(tmp));
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Unable to read Option ROM CIVD data\n");
return status;
}
/* Skip forward until we find a matching signature */
if (memcmp("$CIV", tmp.signature, sizeof(tmp.signature)) != 0)
continue;
/* Verify that the simple checksum is zero */
for (i = 0; i < sizeof(tmp); i++)
sum += ((u8 *)&tmp)[i];
if (sum) {
ice_debug(hw, ICE_DBG_NVM, "Found CIVD data with invalid checksum of %u\n",
sum);
return ICE_ERR_NVM;
}
*civd = tmp;
return 0;
}
/* read module length */
ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID,
ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN_OFFSET * 2,
ICE_AQC_NVM_LINK_TOPO_NETLIST_LEN, &raw_data,
false, false, NULL);
if (ret)
return ICE_ERR_NVM;
}
/**
* ice_get_orom_ver_info - Read Option ROM version information
* @hw: pointer to the HW struct
* @bank: whether to read from the active or inactive flash module
* @orom: pointer to Option ROM info structure
*
* Read Option ROM version and security revision from the Option ROM flash
* section.
*/
static enum ice_status
ice_get_orom_ver_info(struct ice_hw *hw, enum ice_bank_select bank, struct ice_orom_info *orom)
{
struct ice_orom_civd_info civd;
enum ice_status status;
u32 combo_ver;
status = ice_get_orom_civd_data(hw, bank, &civd);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to locate valid Option ROM CIVD data\n");
return status;
}
combo_ver = le32_to_cpu(civd.combo_ver);
orom->major = (u8)((combo_ver & ICE_OROM_VER_MASK) >> ICE_OROM_VER_SHIFT);
orom->patch = (u8)(combo_ver & ICE_OROM_VER_PATCH_MASK);
orom->build = (u16)((combo_ver & ICE_OROM_VER_BUILD_MASK) >> ICE_OROM_VER_BUILD_SHIFT);
return 0;
}
/**
* ice_get_inactive_orom_ver - Read Option ROM version from the inactive bank
* @hw: pointer to the HW structure
* @orom: storage for Option ROM version information
*
* Reads the Option ROM version and security revision data for the inactive
* section of flash. Used to access version data for a pending update that has
* not yet been activated.
*/
enum ice_status ice_get_inactive_orom_ver(struct ice_hw *hw, struct ice_orom_info *orom)
{
return ice_get_orom_ver_info(hw, ICE_INACTIVE_FLASH_BANK, orom);
}
/**
* ice_get_netlist_info
* @hw: pointer to the HW struct
* @bank: whether to read from the active or inactive flash bank
* @netlist: pointer to netlist version info structure
*
* Get the netlist version information from the requested bank. Reads the Link
* Topology section to find the Netlist ID block and extract the relevant
* information into the netlist version structure.
*/
static enum ice_status
ice_get_netlist_info(struct ice_hw *hw, enum ice_bank_select bank,
struct ice_netlist_info *netlist)
{
u16 module_id, length, node_count, i;
enum ice_status status;
u16 *id_blk;
status = ice_read_netlist_module(hw, bank, ICE_NETLIST_TYPE_OFFSET, &module_id);
if (status)
return status;
if (module_id != ICE_NETLIST_LINK_TOPO_MOD_ID) {
ice_debug(hw, ICE_DBG_NVM, "Expected netlist module_id ID of 0x%04x, but got 0x%04x\n",
ICE_NETLIST_LINK_TOPO_MOD_ID, module_id);
return ICE_ERR_NVM;
}
status = ice_read_netlist_module(hw, bank, ICE_LINK_TOPO_MODULE_LEN, &length);
if (status)
return status;
/* sanity check that we have at least enough words to store the netlist ID block */
if (length < ICE_NETLIST_ID_BLK_SIZE) {
ice_debug(hw, ICE_DBG_NVM, "Netlist Link Topology module too small. Expected at least %u words, but got %u words.\n",
ICE_NETLIST_ID_BLK_SIZE, length);
return ICE_ERR_NVM;
}
status = ice_read_netlist_module(hw, bank, ICE_LINK_TOPO_NODE_COUNT, &node_count);
if (status)
return status;
node_count &= ICE_LINK_TOPO_NODE_COUNT_M;
id_blk = kcalloc(ICE_NETLIST_ID_BLK_SIZE, sizeof(*id_blk), GFP_KERNEL);
if (!id_blk)
return ICE_ERR_NO_MEMORY;
/* Read out the entire Netlist ID Block at once. */
status = ice_read_flash_module(hw, bank, ICE_SR_NETLIST_BANK_PTR,
ICE_NETLIST_ID_BLK_OFFSET(node_count) * sizeof(u16),
(u8 *)id_blk, ICE_NETLIST_ID_BLK_SIZE * sizeof(u16));
if (status)
goto exit_error;
data = le16_to_cpu(raw_data);
/* exit if length is = 0 */
if (!data)
goto exit_error;
for (i = 0; i < ICE_NETLIST_ID_BLK_SIZE; i++)
id_blk[i] = le16_to_cpu(((__force __le16 *)id_blk)[i]);
/* read node count */
ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID,
ICE_AQC_NVM_NETLIST_NODE_COUNT_OFFSET * 2,
ICE_AQC_NVM_NETLIST_NODE_COUNT_LEN, &raw_data,
false, false, NULL);
if (ret)
goto exit_error;
data = le16_to_cpu(raw_data) & ICE_AQC_NVM_NETLIST_NODE_COUNT_M;
/* netlist ID block starts from offset 4 + node count * 2 */
id_blk_start = ICE_AQC_NVM_NETLIST_ID_BLK_START_OFFSET + data * 2;
/* read the entire netlist ID block */
ret = ice_aq_read_nvm(hw, ICE_AQC_NVM_LINK_TOPO_NETLIST_MOD_ID,
id_blk_start * 2,
ICE_AQC_NVM_NETLIST_ID_BLK_LEN * 2, buff, false,
false, NULL);
if (ret)
goto exit_error;
for (i = 0; i < ICE_AQC_NVM_NETLIST_ID_BLK_LEN; i++)
buff[i] = le16_to_cpu(((__force __le16 *)buff)[i]);
ver->major = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_HIGH] << 16) |
buff[ICE_AQC_NVM_NETLIST_ID_BLK_MAJOR_VER_LOW];
ver->minor = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_HIGH] << 16) |
buff[ICE_AQC_NVM_NETLIST_ID_BLK_MINOR_VER_LOW];
ver->type = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_HIGH] << 16) |
buff[ICE_AQC_NVM_NETLIST_ID_BLK_TYPE_LOW];
ver->rev = (buff[ICE_AQC_NVM_NETLIST_ID_BLK_REV_HIGH] << 16) |
buff[ICE_AQC_NVM_NETLIST_ID_BLK_REV_LOW];
ver->cust_ver = buff[ICE_AQC_NVM_NETLIST_ID_BLK_CUST_VER];
netlist->major = id_blk[ICE_NETLIST_ID_BLK_MAJOR_VER_HIGH] << 16 |
id_blk[ICE_NETLIST_ID_BLK_MAJOR_VER_LOW];
netlist->minor = id_blk[ICE_NETLIST_ID_BLK_MINOR_VER_HIGH] << 16 |
id_blk[ICE_NETLIST_ID_BLK_MINOR_VER_LOW];
netlist->type = id_blk[ICE_NETLIST_ID_BLK_TYPE_HIGH] << 16 |
id_blk[ICE_NETLIST_ID_BLK_TYPE_LOW];
netlist->rev = id_blk[ICE_NETLIST_ID_BLK_REV_HIGH] << 16 |
id_blk[ICE_NETLIST_ID_BLK_REV_LOW];
netlist->cust_ver = id_blk[ICE_NETLIST_ID_BLK_CUST_VER];
/* Read the left most 4 bytes of SHA */
ver->hash = buff[ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH + 15] << 16 |
buff[ICE_AQC_NVM_NETLIST_ID_BLK_SHA_HASH + 14];
netlist->hash = id_blk[ICE_NETLIST_ID_BLK_SHA_HASH_WORD(15)] << 16 |
id_blk[ICE_NETLIST_ID_BLK_SHA_HASH_WORD(14)];
exit_error:
kfree(buff);
exit_no_mem:
ice_release_nvm(hw);
return ret;
kfree(id_blk);
return status;
}
/**
* ice_get_inactive_netlist_ver
* @hw: pointer to the HW struct
* @netlist: pointer to netlist version info structure
*
* Read the netlist version data from the inactive netlist bank. Used to
* extract version data of a pending flash update in order to display the
* version data.
*/
enum ice_status ice_get_inactive_netlist_ver(struct ice_hw *hw, struct ice_netlist_info *netlist)
{
return ice_get_netlist_info(hw, ICE_INACTIVE_FLASH_BANK, netlist);
}
/**
@ -555,7 +836,7 @@ static enum ice_status ice_discover_flash_size(struct ice_hw *hw)
ice_debug(hw, ICE_DBG_NVM, "Predicted flash size is %u bytes\n", max_size);
hw->nvm.flash_size = max_size;
hw->flash.flash_size = max_size;
err_read_flat_nvm:
ice_release_nvm(hw);
@ -563,6 +844,151 @@ static enum ice_status ice_discover_flash_size(struct ice_hw *hw)
return status;
}
/**
* ice_read_sr_pointer - Read the value of a Shadow RAM pointer word
* @hw: pointer to the HW structure
* @offset: the word offset of the Shadow RAM word to read
* @pointer: pointer value read from Shadow RAM
*
* Read the given Shadow RAM word, and convert it to a pointer value specified
* in bytes. This function assumes the specified offset is a valid pointer
* word.
*
* Each pointer word specifies whether it is stored in word size or 4KB
* sector size by using the highest bit. The reported pointer value will be in
* bytes, intended for flat NVM reads.
*/
static enum ice_status
ice_read_sr_pointer(struct ice_hw *hw, u16 offset, u32 *pointer)
{
enum ice_status status;
u16 value;
status = ice_read_sr_word(hw, offset, &value);
if (status)
return status;
/* Determine if the pointer is in 4KB or word units */
if (value & ICE_SR_NVM_PTR_4KB_UNITS)
*pointer = (value & ~ICE_SR_NVM_PTR_4KB_UNITS) * 4 * 1024;
else
*pointer = value * 2;
return 0;
}
/**
* ice_read_sr_area_size - Read an area size from a Shadow RAM word
* @hw: pointer to the HW structure
* @offset: the word offset of the Shadow RAM to read
* @size: size value read from the Shadow RAM
*
* Read the given Shadow RAM word, and convert it to an area size value
* specified in bytes. This function assumes the specified offset is a valid
* area size word.
*
* Each area size word is specified in 4KB sector units. This function reports
* the size in bytes, intended for flat NVM reads.
*/
static enum ice_status
ice_read_sr_area_size(struct ice_hw *hw, u16 offset, u32 *size)
{
enum ice_status status;
u16 value;
status = ice_read_sr_word(hw, offset, &value);
if (status)
return status;
/* Area sizes are always specified in 4KB units */
*size = value * 4 * 1024;
return 0;
}
/**
* ice_determine_active_flash_banks - Discover active bank for each module
* @hw: pointer to the HW struct
*
* Read the Shadow RAM control word and determine which banks are active for
* the NVM, OROM, and Netlist modules. Also read and calculate the associated
* pointer and size. These values are then cached into the ice_flash_info
* structure for later use in order to calculate the correct offset to read
* from the active module.
*/
static enum ice_status
ice_determine_active_flash_banks(struct ice_hw *hw)
{
struct ice_bank_info *banks = &hw->flash.banks;
enum ice_status status;
u16 ctrl_word;
status = ice_read_sr_word(hw, ICE_SR_NVM_CTRL_WORD, &ctrl_word);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read the Shadow RAM control word\n");
return status;
}
/* Check that the control word indicates validity */
if ((ctrl_word & ICE_SR_CTRL_WORD_1_M) >> ICE_SR_CTRL_WORD_1_S != ICE_SR_CTRL_WORD_VALID) {
ice_debug(hw, ICE_DBG_NVM, "Shadow RAM control word is invalid\n");
return ICE_ERR_CFG;
}
if (!(ctrl_word & ICE_SR_CTRL_WORD_NVM_BANK))
banks->nvm_bank = ICE_1ST_FLASH_BANK;
else
banks->nvm_bank = ICE_2ND_FLASH_BANK;
if (!(ctrl_word & ICE_SR_CTRL_WORD_OROM_BANK))
banks->orom_bank = ICE_1ST_FLASH_BANK;
else
banks->orom_bank = ICE_2ND_FLASH_BANK;
if (!(ctrl_word & ICE_SR_CTRL_WORD_NETLIST_BANK))
banks->netlist_bank = ICE_1ST_FLASH_BANK;
else
banks->netlist_bank = ICE_2ND_FLASH_BANK;
status = ice_read_sr_pointer(hw, ICE_SR_1ST_NVM_BANK_PTR, &banks->nvm_ptr);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read NVM bank pointer\n");
return status;
}
status = ice_read_sr_area_size(hw, ICE_SR_NVM_BANK_SIZE, &banks->nvm_size);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read NVM bank area size\n");
return status;
}
status = ice_read_sr_pointer(hw, ICE_SR_1ST_OROM_BANK_PTR, &banks->orom_ptr);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read OROM bank pointer\n");
return status;
}
status = ice_read_sr_area_size(hw, ICE_SR_OROM_BANK_SIZE, &banks->orom_size);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read OROM bank area size\n");
return status;
}
status = ice_read_sr_pointer(hw, ICE_SR_NETLIST_BANK_PTR, &banks->netlist_ptr);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read Netlist bank pointer\n");
return status;
}
status = ice_read_sr_area_size(hw, ICE_SR_NETLIST_BANK_SIZE, &banks->netlist_size);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "Failed to read Netlist bank area size\n");
return status;
}
return 0;
}
/**
* ice_init_nvm - initializes NVM setting
* @hw: pointer to the HW struct
@ -572,8 +998,7 @@ static enum ice_status ice_discover_flash_size(struct ice_hw *hw)
*/
enum ice_status ice_init_nvm(struct ice_hw *hw)
{
struct ice_nvm_info *nvm = &hw->nvm;
u16 eetrack_lo, eetrack_hi, ver;
struct ice_flash_info *flash = &hw->flash;
enum ice_status status;
u32 fla, gens_stat;
u8 sr_size;
@ -585,54 +1010,43 @@ enum ice_status ice_init_nvm(struct ice_hw *hw)
sr_size = (gens_stat & GLNVM_GENS_SR_SIZE_M) >> GLNVM_GENS_SR_SIZE_S;
/* Switching to words (sr_size contains power of 2) */
nvm->sr_words = BIT(sr_size) * ICE_SR_WORDS_IN_1KB;
flash->sr_words = BIT(sr_size) * ICE_SR_WORDS_IN_1KB;
/* Check if we are in the normal or blank NVM programming mode */
fla = rd32(hw, GLNVM_FLA);
if (fla & GLNVM_FLA_LOCKED_M) { /* Normal programming mode */
nvm->blank_nvm_mode = false;
flash->blank_nvm_mode = false;
} else {
/* Blank programming mode */
nvm->blank_nvm_mode = true;
flash->blank_nvm_mode = true;
ice_debug(hw, ICE_DBG_NVM, "NVM init error: unsupported blank mode.\n");
return ICE_ERR_NVM_BLANK_MODE;
}
status = ice_read_sr_word(hw, ICE_SR_NVM_DEV_STARTER_VER, &ver);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read DEV starter version.\n");
return status;
}
nvm->major_ver = (ver & ICE_NVM_VER_HI_MASK) >> ICE_NVM_VER_HI_SHIFT;
nvm->minor_ver = (ver & ICE_NVM_VER_LO_MASK) >> ICE_NVM_VER_LO_SHIFT;
status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_LO, &eetrack_lo);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK lo.\n");
return status;
}
status = ice_read_sr_word(hw, ICE_SR_NVM_EETRACK_HI, &eetrack_hi);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read EETRACK hi.\n");
return status;
}
nvm->eetrack = (eetrack_hi << 16) | eetrack_lo;
status = ice_discover_flash_size(hw);
if (status) {
ice_debug(hw, ICE_DBG_NVM, "NVM init error: failed to discover flash size.\n");
return status;
}
status = ice_get_orom_ver_info(hw);
status = ice_determine_active_flash_banks(hw);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read Option ROM info.\n");
ice_debug(hw, ICE_DBG_NVM, "Failed to determine active flash banks.\n");
return status;
}
status = ice_get_nvm_ver_info(hw, ICE_ACTIVE_FLASH_BANK, &flash->nvm);
if (status) {
ice_debug(hw, ICE_DBG_INIT, "Failed to read NVM info.\n");
return status;
}
status = ice_get_orom_ver_info(hw, ICE_ACTIVE_FLASH_BANK, &flash->orom);
if (status)
ice_debug(hw, ICE_DBG_INIT, "Failed to read Option ROM info.\n");
/* read the netlist version information */
status = ice_get_netlist_ver_info(hw);
status = ice_get_netlist_info(hw, ICE_ACTIVE_FLASH_BANK, &flash->netlist);
if (status)
ice_debug(hw, ICE_DBG_INIT, "Failed to read netlist info.\n");

View file

@ -4,6 +4,14 @@
#ifndef _ICE_NVM_H_
#define _ICE_NVM_H_
struct ice_orom_civd_info {
u8 signature[4]; /* Must match ASCII '$CIV' characters */
u8 checksum; /* Simple modulo 256 sum of all structure bytes must equal 0 */
__le32 combo_ver; /* Combo Image Version number */
u8 combo_name_len; /* Length of the unicode combo image version string, max of 32 */
__le16 combo_name[32]; /* Unicode string representing the Combo Image version */
} __packed;
enum ice_status
ice_acquire_nvm(struct ice_hw *hw, enum ice_aq_res_access_type access);
void ice_release_nvm(struct ice_hw *hw);
@ -14,6 +22,12 @@ enum ice_status
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
u16 module_type);
enum ice_status
ice_get_inactive_orom_ver(struct ice_hw *hw, struct ice_orom_info *orom);
enum ice_status
ice_get_inactive_nvm_ver(struct ice_hw *hw, struct ice_nvm_info *nvm);
enum ice_status
ice_get_inactive_netlist_ver(struct ice_hw *hw, struct ice_netlist_info *netlist);
enum ice_status
ice_read_pba_string(struct ice_hw *hw, u8 *pba_num, u32 pba_num_size);
enum ice_status ice_init_nvm(struct ice_hw *hw);
enum ice_status ice_read_sr_word(struct ice_hw *hw, u16 offset, u16 *data);

View file

@ -29,6 +29,7 @@ enum ice_status {
ICE_ERR_HW_TABLE = -19,
ICE_ERR_FW_DDP_MISMATCH = -20,
ICE_ERR_NVM = -50,
ICE_ERR_NVM_CHECKSUM = -51,
ICE_ERR_BUF_TOO_SHORT = -52,
ICE_ERR_NVM_BLANK_MODE = -53,

View file

@ -313,14 +313,62 @@ struct ice_orom_info {
u16 build; /* Build version of OROM */
};
/* NVM Information */
/* NVM version information */
struct ice_nvm_info {
u32 eetrack;
u8 major;
u8 minor;
};
/* netlist version information */
struct ice_netlist_info {
u32 major; /* major high/low */
u32 minor; /* minor high/low */
u32 type; /* type high/low */
u32 rev; /* revision high/low */
u32 hash; /* SHA-1 hash word */
u16 cust_ver; /* customer version */
};
/* Enumeration of possible flash banks for the NVM, OROM, and Netlist modules
* of the flash image.
*/
enum ice_flash_bank {
ICE_INVALID_FLASH_BANK,
ICE_1ST_FLASH_BANK,
ICE_2ND_FLASH_BANK,
};
/* Enumeration of which flash bank is desired to read from, either the active
* bank or the inactive bank. Used to abstract 1st and 2nd bank notion from
* code which just wants to read the active or inactive flash bank.
*/
enum ice_bank_select {
ICE_ACTIVE_FLASH_BANK,
ICE_INACTIVE_FLASH_BANK,
};
/* information for accessing NVM, OROM, and Netlist flash banks */
struct ice_bank_info {
u32 nvm_ptr; /* Pointer to 1st NVM bank */
u32 nvm_size; /* Size of NVM bank */
u32 orom_ptr; /* Pointer to 1st OROM bank */
u32 orom_size; /* Size of OROM bank */
u32 netlist_ptr; /* Pointer to 1st Netlist bank */
u32 netlist_size; /* Size of Netlist bank */
enum ice_flash_bank nvm_bank; /* Active NVM bank */
enum ice_flash_bank orom_bank; /* Active OROM bank */
enum ice_flash_bank netlist_bank; /* Active Netlist bank */
};
/* Flash Chip Information */
struct ice_flash_info {
struct ice_orom_info orom; /* Option ROM version info */
u32 eetrack; /* NVM data version */
struct ice_nvm_info nvm; /* NVM version information */
struct ice_netlist_info netlist;/* Netlist version info */
struct ice_bank_info banks; /* Flash Bank information */
u16 sr_words; /* Shadow RAM size in words */
u32 flash_size; /* Size of available flash in bytes */
u8 major_ver; /* major version of NVM package */
u8 minor_ver; /* minor version of dev starter */
u8 blank_nvm_mode; /* is NVM empty (no FW present) */
};
@ -348,16 +396,6 @@ struct ice_link_default_override_tlv {
#define ICE_NVM_VER_LEN 32
/* netlist version information */
struct ice_netlist_ver_info {
u32 major; /* major high/low */
u32 minor; /* minor high/low */
u32 type; /* type high/low */
u32 rev; /* revision high/low */
u32 hash; /* SHA-1 hash word */
u16 cust_ver; /* customer version */
};
/* Max number of port to queue branches w.r.t topology */
#define ICE_MAX_TRAFFIC_CLASS 8
#define ICE_TXSCHED_MAX_BRANCHES ICE_MAX_TRAFFIC_CLASS
@ -605,10 +643,9 @@ struct ice_hw {
u8 evb_veb; /* true for VEB, false for VEPA */
u8 reset_ongoing; /* true if HW is in reset, false otherwise */
struct ice_bus_info bus;
struct ice_nvm_info nvm;
struct ice_flash_info flash;
struct ice_hw_dev_caps dev_caps; /* device capabilities */
struct ice_hw_func_caps func_caps; /* function capabilities */
struct ice_netlist_ver_info netlist_ver; /* netlist version info */
struct ice_switch_info *switch_info; /* switch filter lists */
@ -765,6 +802,7 @@ struct ice_hw_port_stats {
};
/* Checksum and Shadow RAM pointers */
#define ICE_SR_NVM_CTRL_WORD 0x00
#define ICE_SR_BOOT_CFG_PTR 0x132
#define ICE_SR_NVM_WOL_CFG 0x19
#define ICE_NVM_OROM_VER_OFF 0x02
@ -784,10 +822,71 @@ struct ice_hw_port_stats {
#define ICE_OROM_VER_MASK (0xff << ICE_OROM_VER_SHIFT)
#define ICE_SR_PFA_PTR 0x40
#define ICE_SR_1ST_NVM_BANK_PTR 0x42
#define ICE_SR_NVM_BANK_SIZE 0x43
#define ICE_SR_1ST_OROM_BANK_PTR 0x44
#define ICE_SR_OROM_BANK_SIZE 0x45
#define ICE_SR_NETLIST_BANK_PTR 0x46
#define ICE_SR_NETLIST_BANK_SIZE 0x47
#define ICE_SR_SECTOR_SIZE_IN_WORDS 0x800
/* CSS Header words */
#define ICE_NVM_CSS_SREV_L 0x14
#define ICE_NVM_CSS_SREV_H 0x15
/* Length of CSS header section in words */
#define ICE_CSS_HEADER_LENGTH 330
/* Offset of Shadow RAM copy in the NVM bank area. */
#define ICE_NVM_SR_COPY_WORD_OFFSET roundup(ICE_CSS_HEADER_LENGTH, 32)
/* Size in bytes of Option ROM trailer */
#define ICE_NVM_OROM_TRAILER_LENGTH (2 * ICE_CSS_HEADER_LENGTH)
/* The Link Topology Netlist section is stored as a series of words. It is
* stored in the NVM as a TLV, with the first two words containing the type
* and length.
*/
#define ICE_NETLIST_LINK_TOPO_MOD_ID 0x011B
#define ICE_NETLIST_TYPE_OFFSET 0x0000
#define ICE_NETLIST_LEN_OFFSET 0x0001
/* The Link Topology section follows the TLV header. When reading the netlist
* using ice_read_netlist_module, we need to account for the 2-word TLV
* header.
*/
#define ICE_NETLIST_LINK_TOPO_OFFSET(n) ((n) + 2)
#define ICE_LINK_TOPO_MODULE_LEN ICE_NETLIST_LINK_TOPO_OFFSET(0x0000)
#define ICE_LINK_TOPO_NODE_COUNT ICE_NETLIST_LINK_TOPO_OFFSET(0x0001)
#define ICE_LINK_TOPO_NODE_COUNT_M ICE_M(0x3FF, 0)
/* The Netlist ID Block is located after all of the Link Topology nodes. */
#define ICE_NETLIST_ID_BLK_SIZE 0x30
#define ICE_NETLIST_ID_BLK_OFFSET(n) ICE_NETLIST_LINK_TOPO_OFFSET(0x0004 + 2 * (n))
/* netlist ID block field offsets (word offsets) */
#define ICE_NETLIST_ID_BLK_MAJOR_VER_LOW 0x02
#define ICE_NETLIST_ID_BLK_MAJOR_VER_HIGH 0x03
#define ICE_NETLIST_ID_BLK_MINOR_VER_LOW 0x04
#define ICE_NETLIST_ID_BLK_MINOR_VER_HIGH 0x05
#define ICE_NETLIST_ID_BLK_TYPE_LOW 0x06
#define ICE_NETLIST_ID_BLK_TYPE_HIGH 0x07
#define ICE_NETLIST_ID_BLK_REV_LOW 0x08
#define ICE_NETLIST_ID_BLK_REV_HIGH 0x09
#define ICE_NETLIST_ID_BLK_SHA_HASH_WORD(n) (0x0A + (n))
#define ICE_NETLIST_ID_BLK_CUST_VER 0x2F
/* Auxiliary field, mask, and shift definition for Shadow RAM and NVM Flash */
#define ICE_SR_CTRL_WORD_1_S 0x06
#define ICE_SR_CTRL_WORD_1_M (0x03 << ICE_SR_CTRL_WORD_1_S)
#define ICE_SR_CTRL_WORD_VALID 0x1
#define ICE_SR_CTRL_WORD_OROM_BANK BIT(3)
#define ICE_SR_CTRL_WORD_NETLIST_BANK BIT(4)
#define ICE_SR_CTRL_WORD_NVM_BANK BIT(5)
#define ICE_SR_NVM_PTR_4KB_UNITS BIT(15)
/* Link override related */
#define ICE_SR_PFA_LINK_OVERRIDE_WORDS 10
#define ICE_SR_PFA_LINK_OVERRIDE_PHY_WORDS 4