162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2020, Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/vmalloc.h> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include "ice.h" 762306a36Sopenharmony_ci#include "ice_lib.h" 862306a36Sopenharmony_ci#include "ice_devlink.h" 962306a36Sopenharmony_ci#include "ice_eswitch.h" 1062306a36Sopenharmony_ci#include "ice_fw_update.h" 1162306a36Sopenharmony_ci#include "ice_dcb_lib.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic int ice_active_port_option = -1; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* context for devlink info version reporting */ 1662306a36Sopenharmony_cistruct ice_info_ctx { 1762306a36Sopenharmony_ci char buf[128]; 1862306a36Sopenharmony_ci struct ice_orom_info pending_orom; 1962306a36Sopenharmony_ci struct ice_nvm_info pending_nvm; 2062306a36Sopenharmony_ci struct ice_netlist_info pending_netlist; 2162306a36Sopenharmony_ci struct ice_hw_dev_caps dev_caps; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* The following functions are used to format specific strings for various 2562306a36Sopenharmony_ci * devlink info versions. The ctx parameter is used to provide the storage 2662306a36Sopenharmony_ci * buffer, as well as any ancillary information calculated when the info 2762306a36Sopenharmony_ci * request was made. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * If a version does not exist, for example when attempting to get the 3062306a36Sopenharmony_ci * inactive version of flash when there is no pending update, the function 3162306a36Sopenharmony_ci * should leave the buffer in the ctx structure empty. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void ice_info_get_dsn(struct ice_pf *pf, struct ice_info_ctx *ctx) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci u8 dsn[8]; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci /* Copy the DSN into an array in Big Endian format */ 3962306a36Sopenharmony_ci put_unaligned_be64(pci_get_dsn(pf->pdev), dsn); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%8phD", dsn); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic void ice_info_pba(struct ice_pf *pf, struct ice_info_ctx *ctx) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 4762306a36Sopenharmony_ci int status; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci status = ice_read_pba_string(hw, (u8 *)ctx->buf, sizeof(ctx->buf)); 5062306a36Sopenharmony_ci if (status) 5162306a36Sopenharmony_ci /* We failed to locate the PBA, so just skip this entry */ 5262306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Failed to read Product Board Assembly string, status %d\n", 5362306a36Sopenharmony_ci status); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void ice_info_fw_mgmt(struct ice_pf *pf, struct ice_info_ctx *ctx) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", 6162306a36Sopenharmony_ci hw->fw_maj_ver, hw->fw_min_ver, hw->fw_patch); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void ice_info_fw_api(struct ice_pf *pf, struct ice_info_ctx *ctx) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", hw->api_maj_ver, 6962306a36Sopenharmony_ci hw->api_min_ver, hw->api_patch); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void ice_info_fw_build(struct ice_pf *pf, struct ice_info_ctx *ctx) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", hw->fw_build); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void ice_info_orom_ver(struct ice_pf *pf, struct ice_info_ctx *ctx) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct ice_orom_info *orom = &pf->hw.flash.orom; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", 8462306a36Sopenharmony_ci orom->major, orom->build, orom->patch); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void 8862306a36Sopenharmony_ciice_info_pending_orom_ver(struct ice_pf __always_unused *pf, 8962306a36Sopenharmony_ci struct ice_info_ctx *ctx) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct ice_orom_info *orom = &ctx->pending_orom; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (ctx->dev_caps.common_cap.nvm_update_pending_orom) 9462306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u", 9562306a36Sopenharmony_ci orom->major, orom->build, orom->patch); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void ice_info_nvm_ver(struct ice_pf *pf, struct ice_info_ctx *ctx) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct ice_nvm_info *nvm = &pf->hw.flash.nvm; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", nvm->major, nvm->minor); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void 10662306a36Sopenharmony_ciice_info_pending_nvm_ver(struct ice_pf __always_unused *pf, 10762306a36Sopenharmony_ci struct ice_info_ctx *ctx) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct ice_nvm_info *nvm = &ctx->pending_nvm; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (ctx->dev_caps.common_cap.nvm_update_pending_nvm) 11262306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%x.%02x", 11362306a36Sopenharmony_ci nvm->major, nvm->minor); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic void ice_info_eetrack(struct ice_pf *pf, struct ice_info_ctx *ctx) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct ice_nvm_info *nvm = &pf->hw.flash.nvm; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm->eetrack); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic void 12462306a36Sopenharmony_ciice_info_pending_eetrack(struct ice_pf *pf, struct ice_info_ctx *ctx) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct ice_nvm_info *nvm = &ctx->pending_nvm; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (ctx->dev_caps.common_cap.nvm_update_pending_nvm) 12962306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", nvm->eetrack); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic void ice_info_ddp_pkg_name(struct ice_pf *pf, struct ice_info_ctx *ctx) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%s", hw->active_pkg_name); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic void 14062306a36Sopenharmony_ciice_info_ddp_pkg_version(struct ice_pf *pf, struct ice_info_ctx *ctx) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct ice_pkg_ver *pkg = &pf->hw.active_pkg_ver; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%u.%u.%u.%u", 14562306a36Sopenharmony_ci pkg->major, pkg->minor, pkg->update, pkg->draft); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void 14962306a36Sopenharmony_ciice_info_ddp_pkg_bundle_id(struct ice_pf *pf, struct ice_info_ctx *ctx) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", pf->hw.active_track_id); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic void ice_info_netlist_ver(struct ice_pf *pf, struct ice_info_ctx *ctx) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct ice_netlist_info *netlist = &pf->hw.flash.netlist; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* The netlist version fields are BCD formatted */ 15962306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x", 16062306a36Sopenharmony_ci netlist->major, netlist->minor, 16162306a36Sopenharmony_ci netlist->type >> 16, netlist->type & 0xFFFF, 16262306a36Sopenharmony_ci netlist->rev, netlist->cust_ver); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void ice_info_netlist_build(struct ice_pf *pf, struct ice_info_ctx *ctx) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct ice_netlist_info *netlist = &pf->hw.flash.netlist; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void 17362306a36Sopenharmony_ciice_info_pending_netlist_ver(struct ice_pf __always_unused *pf, 17462306a36Sopenharmony_ci struct ice_info_ctx *ctx) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct ice_netlist_info *netlist = &ctx->pending_netlist; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* The netlist version fields are BCD formatted */ 17962306a36Sopenharmony_ci if (ctx->dev_caps.common_cap.nvm_update_pending_netlist) 18062306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "%x.%x.%x-%x.%x.%x", 18162306a36Sopenharmony_ci netlist->major, netlist->minor, 18262306a36Sopenharmony_ci netlist->type >> 16, netlist->type & 0xFFFF, 18362306a36Sopenharmony_ci netlist->rev, netlist->cust_ver); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic void 18762306a36Sopenharmony_ciice_info_pending_netlist_build(struct ice_pf __always_unused *pf, 18862306a36Sopenharmony_ci struct ice_info_ctx *ctx) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci struct ice_netlist_info *netlist = &ctx->pending_netlist; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (ctx->dev_caps.common_cap.nvm_update_pending_netlist) 19362306a36Sopenharmony_ci snprintf(ctx->buf, sizeof(ctx->buf), "0x%08x", netlist->hash); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#define fixed(key, getter) { ICE_VERSION_FIXED, key, getter, NULL } 19762306a36Sopenharmony_ci#define running(key, getter) { ICE_VERSION_RUNNING, key, getter, NULL } 19862306a36Sopenharmony_ci#define stored(key, getter, fallback) { ICE_VERSION_STORED, key, getter, fallback } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* The combined() macro inserts both the running entry as well as a stored 20162306a36Sopenharmony_ci * entry. The running entry will always report the version from the active 20262306a36Sopenharmony_ci * handler. The stored entry will first try the pending handler, and fallback 20362306a36Sopenharmony_ci * to the active handler if the pending function does not report a version. 20462306a36Sopenharmony_ci * The pending handler should check the status of a pending update for the 20562306a36Sopenharmony_ci * relevant flash component. It should only fill in the buffer in the case 20662306a36Sopenharmony_ci * where a valid pending version is available. This ensures that the related 20762306a36Sopenharmony_ci * stored and running versions remain in sync, and that stored versions are 20862306a36Sopenharmony_ci * correctly reported as expected. 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci#define combined(key, active, pending) \ 21162306a36Sopenharmony_ci running(key, active), \ 21262306a36Sopenharmony_ci stored(key, pending, active) 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cienum ice_version_type { 21562306a36Sopenharmony_ci ICE_VERSION_FIXED, 21662306a36Sopenharmony_ci ICE_VERSION_RUNNING, 21762306a36Sopenharmony_ci ICE_VERSION_STORED, 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic const struct ice_devlink_version { 22162306a36Sopenharmony_ci enum ice_version_type type; 22262306a36Sopenharmony_ci const char *key; 22362306a36Sopenharmony_ci void (*getter)(struct ice_pf *pf, struct ice_info_ctx *ctx); 22462306a36Sopenharmony_ci void (*fallback)(struct ice_pf *pf, struct ice_info_ctx *ctx); 22562306a36Sopenharmony_ci} ice_devlink_versions[] = { 22662306a36Sopenharmony_ci fixed(DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, ice_info_pba), 22762306a36Sopenharmony_ci running(DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, ice_info_fw_mgmt), 22862306a36Sopenharmony_ci running("fw.mgmt.api", ice_info_fw_api), 22962306a36Sopenharmony_ci running("fw.mgmt.build", ice_info_fw_build), 23062306a36Sopenharmony_ci combined(DEVLINK_INFO_VERSION_GENERIC_FW_UNDI, ice_info_orom_ver, ice_info_pending_orom_ver), 23162306a36Sopenharmony_ci combined("fw.psid.api", ice_info_nvm_ver, ice_info_pending_nvm_ver), 23262306a36Sopenharmony_ci combined(DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID, ice_info_eetrack, ice_info_pending_eetrack), 23362306a36Sopenharmony_ci running("fw.app.name", ice_info_ddp_pkg_name), 23462306a36Sopenharmony_ci running(DEVLINK_INFO_VERSION_GENERIC_FW_APP, ice_info_ddp_pkg_version), 23562306a36Sopenharmony_ci running("fw.app.bundle_id", ice_info_ddp_pkg_bundle_id), 23662306a36Sopenharmony_ci combined("fw.netlist", ice_info_netlist_ver, ice_info_pending_netlist_ver), 23762306a36Sopenharmony_ci combined("fw.netlist.build", ice_info_netlist_build, ice_info_pending_netlist_build), 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/** 24162306a36Sopenharmony_ci * ice_devlink_info_get - .info_get devlink handler 24262306a36Sopenharmony_ci * @devlink: devlink instance structure 24362306a36Sopenharmony_ci * @req: the devlink info request 24462306a36Sopenharmony_ci * @extack: extended netdev ack structure 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * Callback for the devlink .info_get operation. Reports information about the 24762306a36Sopenharmony_ci * device. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * Return: zero on success or an error code on failure. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_cistatic int ice_devlink_info_get(struct devlink *devlink, 25262306a36Sopenharmony_ci struct devlink_info_req *req, 25362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 25662306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 25762306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 25862306a36Sopenharmony_ci struct ice_info_ctx *ctx; 25962306a36Sopenharmony_ci size_t i; 26062306a36Sopenharmony_ci int err; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci err = ice_wait_for_reset(pf, 10 * HZ); 26362306a36Sopenharmony_ci if (err) { 26462306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device is busy resetting"); 26562306a36Sopenharmony_ci return err; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 26962306a36Sopenharmony_ci if (!ctx) 27062306a36Sopenharmony_ci return -ENOMEM; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* discover capabilities first */ 27362306a36Sopenharmony_ci err = ice_discover_dev_caps(hw, &ctx->dev_caps); 27462306a36Sopenharmony_ci if (err) { 27562306a36Sopenharmony_ci dev_dbg(dev, "Failed to discover device capabilities, status %d aq_err %s\n", 27662306a36Sopenharmony_ci err, ice_aq_str(hw->adminq.sq_last_status)); 27762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unable to discover device capabilities"); 27862306a36Sopenharmony_ci goto out_free_ctx; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (ctx->dev_caps.common_cap.nvm_update_pending_orom) { 28262306a36Sopenharmony_ci err = ice_get_inactive_orom_ver(hw, &ctx->pending_orom); 28362306a36Sopenharmony_ci if (err) { 28462306a36Sopenharmony_ci dev_dbg(dev, "Unable to read inactive Option ROM version data, status %d aq_err %s\n", 28562306a36Sopenharmony_ci err, ice_aq_str(hw->adminq.sq_last_status)); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* disable display of pending Option ROM */ 28862306a36Sopenharmony_ci ctx->dev_caps.common_cap.nvm_update_pending_orom = false; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (ctx->dev_caps.common_cap.nvm_update_pending_nvm) { 29362306a36Sopenharmony_ci err = ice_get_inactive_nvm_ver(hw, &ctx->pending_nvm); 29462306a36Sopenharmony_ci if (err) { 29562306a36Sopenharmony_ci dev_dbg(dev, "Unable to read inactive NVM version data, status %d aq_err %s\n", 29662306a36Sopenharmony_ci err, ice_aq_str(hw->adminq.sq_last_status)); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* disable display of pending Option ROM */ 29962306a36Sopenharmony_ci ctx->dev_caps.common_cap.nvm_update_pending_nvm = false; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (ctx->dev_caps.common_cap.nvm_update_pending_netlist) { 30462306a36Sopenharmony_ci err = ice_get_inactive_netlist_ver(hw, &ctx->pending_netlist); 30562306a36Sopenharmony_ci if (err) { 30662306a36Sopenharmony_ci dev_dbg(dev, "Unable to read inactive Netlist version data, status %d aq_err %s\n", 30762306a36Sopenharmony_ci err, ice_aq_str(hw->adminq.sq_last_status)); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* disable display of pending Option ROM */ 31062306a36Sopenharmony_ci ctx->dev_caps.common_cap.nvm_update_pending_netlist = false; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci ice_info_get_dsn(pf, ctx); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci err = devlink_info_serial_number_put(req, ctx->buf); 31762306a36Sopenharmony_ci if (err) { 31862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unable to set serial number"); 31962306a36Sopenharmony_ci goto out_free_ctx; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ice_devlink_versions); i++) { 32362306a36Sopenharmony_ci enum ice_version_type type = ice_devlink_versions[i].type; 32462306a36Sopenharmony_ci const char *key = ice_devlink_versions[i].key; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci memset(ctx->buf, 0, sizeof(ctx->buf)); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ice_devlink_versions[i].getter(pf, ctx); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* If the default getter doesn't report a version, use the 33162306a36Sopenharmony_ci * fallback function. This is primarily useful in the case of 33262306a36Sopenharmony_ci * "stored" versions that want to report the same value as the 33362306a36Sopenharmony_ci * running version in the normal case of no pending update. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci if (ctx->buf[0] == '\0' && ice_devlink_versions[i].fallback) 33662306a36Sopenharmony_ci ice_devlink_versions[i].fallback(pf, ctx); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Do not report missing versions */ 33962306a36Sopenharmony_ci if (ctx->buf[0] == '\0') 34062306a36Sopenharmony_ci continue; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci switch (type) { 34362306a36Sopenharmony_ci case ICE_VERSION_FIXED: 34462306a36Sopenharmony_ci err = devlink_info_version_fixed_put(req, key, ctx->buf); 34562306a36Sopenharmony_ci if (err) { 34662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unable to set fixed version"); 34762306a36Sopenharmony_ci goto out_free_ctx; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci case ICE_VERSION_RUNNING: 35162306a36Sopenharmony_ci err = devlink_info_version_running_put(req, key, ctx->buf); 35262306a36Sopenharmony_ci if (err) { 35362306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unable to set running version"); 35462306a36Sopenharmony_ci goto out_free_ctx; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci case ICE_VERSION_STORED: 35862306a36Sopenharmony_ci err = devlink_info_version_stored_put(req, key, ctx->buf); 35962306a36Sopenharmony_ci if (err) { 36062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unable to set stored version"); 36162306a36Sopenharmony_ci goto out_free_ctx; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ciout_free_ctx: 36862306a36Sopenharmony_ci kfree(ctx); 36962306a36Sopenharmony_ci return err; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci/** 37362306a36Sopenharmony_ci * ice_devlink_reload_empr_start - Start EMP reset to activate new firmware 37462306a36Sopenharmony_ci * @pf: pointer to the pf instance 37562306a36Sopenharmony_ci * @extack: netlink extended ACK structure 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * Allow user to activate new Embedded Management Processor firmware by 37862306a36Sopenharmony_ci * issuing device specific EMP reset. Called in response to 37962306a36Sopenharmony_ci * a DEVLINK_CMD_RELOAD with the DEVLINK_RELOAD_ACTION_FW_ACTIVATE. 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * Note that teardown and rebuild of the driver state happens automatically as 38262306a36Sopenharmony_ci * part of an interrupt and watchdog task. This is because all physical 38362306a36Sopenharmony_ci * functions on the device must be able to reset when an EMP reset occurs from 38462306a36Sopenharmony_ci * any source. 38562306a36Sopenharmony_ci */ 38662306a36Sopenharmony_cistatic int 38762306a36Sopenharmony_ciice_devlink_reload_empr_start(struct ice_pf *pf, 38862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 39162306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 39262306a36Sopenharmony_ci u8 pending; 39362306a36Sopenharmony_ci int err; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci err = ice_get_pending_updates(pf, &pending, extack); 39662306a36Sopenharmony_ci if (err) 39762306a36Sopenharmony_ci return err; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* pending is a bitmask of which flash banks have a pending update, 40062306a36Sopenharmony_ci * including the main NVM bank, the Option ROM bank, and the netlist 40162306a36Sopenharmony_ci * bank. If any of these bits are set, then there is a pending update 40262306a36Sopenharmony_ci * waiting to be activated. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci if (!pending) { 40562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "No pending firmware update"); 40662306a36Sopenharmony_ci return -ECANCELED; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (pf->fw_emp_reset_disabled) { 41062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "EMP reset is not available. To activate firmware, a reboot or power cycle is needed"); 41162306a36Sopenharmony_ci return -ECANCELED; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci dev_dbg(dev, "Issuing device EMP reset to activate firmware\n"); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci err = ice_aq_nvm_update_empr(hw); 41762306a36Sopenharmony_ci if (err) { 41862306a36Sopenharmony_ci dev_err(dev, "Failed to trigger EMP device reset to reload firmware, err %d aq_err %s\n", 41962306a36Sopenharmony_ci err, ice_aq_str(hw->adminq.sq_last_status)); 42062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to trigger EMP device reset to reload firmware"); 42162306a36Sopenharmony_ci return err; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci/** 42862306a36Sopenharmony_ci * ice_devlink_reload_down - prepare for reload 42962306a36Sopenharmony_ci * @devlink: pointer to the devlink instance to reload 43062306a36Sopenharmony_ci * @netns_change: if true, the network namespace is changing 43162306a36Sopenharmony_ci * @action: the action to perform 43262306a36Sopenharmony_ci * @limit: limits on what reload should do, such as not resetting 43362306a36Sopenharmony_ci * @extack: netlink extended ACK structure 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_cistatic int 43662306a36Sopenharmony_ciice_devlink_reload_down(struct devlink *devlink, bool netns_change, 43762306a36Sopenharmony_ci enum devlink_reload_action action, 43862306a36Sopenharmony_ci enum devlink_reload_limit limit, 43962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci switch (action) { 44462306a36Sopenharmony_ci case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: 44562306a36Sopenharmony_ci if (ice_is_eswitch_mode_switchdev(pf)) { 44662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 44762306a36Sopenharmony_ci "Go to legacy mode before doing reinit\n"); 44862306a36Sopenharmony_ci return -EOPNOTSUPP; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci if (ice_is_adq_active(pf)) { 45162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 45262306a36Sopenharmony_ci "Turn off ADQ before doing reinit\n"); 45362306a36Sopenharmony_ci return -EOPNOTSUPP; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci if (ice_has_vfs(pf)) { 45662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, 45762306a36Sopenharmony_ci "Remove all VFs before doing reinit\n"); 45862306a36Sopenharmony_ci return -EOPNOTSUPP; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci ice_unload(pf); 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: 46362306a36Sopenharmony_ci return ice_devlink_reload_empr_start(pf, extack); 46462306a36Sopenharmony_ci default: 46562306a36Sopenharmony_ci WARN_ON(1); 46662306a36Sopenharmony_ci return -EOPNOTSUPP; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/** 47162306a36Sopenharmony_ci * ice_devlink_reload_empr_finish - Wait for EMP reset to finish 47262306a36Sopenharmony_ci * @pf: pointer to the pf instance 47362306a36Sopenharmony_ci * @extack: netlink extended ACK structure 47462306a36Sopenharmony_ci * 47562306a36Sopenharmony_ci * Wait for driver to finish rebuilding after EMP reset is completed. This 47662306a36Sopenharmony_ci * includes time to wait for both the actual device reset as well as the time 47762306a36Sopenharmony_ci * for the driver's rebuild to complete. 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_cistatic int 48062306a36Sopenharmony_ciice_devlink_reload_empr_finish(struct ice_pf *pf, 48162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci int err; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci err = ice_wait_for_reset(pf, 60 * HZ); 48662306a36Sopenharmony_ci if (err) { 48762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Device still resetting after 1 minute"); 48862306a36Sopenharmony_ci return err; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci/** 49562306a36Sopenharmony_ci * ice_devlink_port_opt_speed_str - convert speed to a string 49662306a36Sopenharmony_ci * @speed: speed value 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_cistatic const char *ice_devlink_port_opt_speed_str(u8 speed) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci switch (speed & ICE_AQC_PORT_OPT_MAX_LANE_M) { 50162306a36Sopenharmony_ci case ICE_AQC_PORT_OPT_MAX_LANE_100M: 50262306a36Sopenharmony_ci return "0.1"; 50362306a36Sopenharmony_ci case ICE_AQC_PORT_OPT_MAX_LANE_1G: 50462306a36Sopenharmony_ci return "1"; 50562306a36Sopenharmony_ci case ICE_AQC_PORT_OPT_MAX_LANE_2500M: 50662306a36Sopenharmony_ci return "2.5"; 50762306a36Sopenharmony_ci case ICE_AQC_PORT_OPT_MAX_LANE_5G: 50862306a36Sopenharmony_ci return "5"; 50962306a36Sopenharmony_ci case ICE_AQC_PORT_OPT_MAX_LANE_10G: 51062306a36Sopenharmony_ci return "10"; 51162306a36Sopenharmony_ci case ICE_AQC_PORT_OPT_MAX_LANE_25G: 51262306a36Sopenharmony_ci return "25"; 51362306a36Sopenharmony_ci case ICE_AQC_PORT_OPT_MAX_LANE_50G: 51462306a36Sopenharmony_ci return "50"; 51562306a36Sopenharmony_ci case ICE_AQC_PORT_OPT_MAX_LANE_100G: 51662306a36Sopenharmony_ci return "100"; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci return "-"; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci#define ICE_PORT_OPT_DESC_LEN 50 52362306a36Sopenharmony_ci/** 52462306a36Sopenharmony_ci * ice_devlink_port_options_print - Print available port split options 52562306a36Sopenharmony_ci * @pf: the PF to print split port options 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * Prints a table with available port split options and max port speeds 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_cistatic void ice_devlink_port_options_print(struct ice_pf *pf) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci u8 i, j, options_count, cnt, speed, pending_idx, active_idx; 53262306a36Sopenharmony_ci struct ice_aqc_get_port_options_elem *options, *opt; 53362306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 53462306a36Sopenharmony_ci bool active_valid, pending_valid; 53562306a36Sopenharmony_ci char desc[ICE_PORT_OPT_DESC_LEN]; 53662306a36Sopenharmony_ci const char *str; 53762306a36Sopenharmony_ci int status; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci options = kcalloc(ICE_AQC_PORT_OPT_MAX * ICE_MAX_PORT_PER_PCI_DEV, 54062306a36Sopenharmony_ci sizeof(*options), GFP_KERNEL); 54162306a36Sopenharmony_ci if (!options) 54262306a36Sopenharmony_ci return; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci for (i = 0; i < ICE_MAX_PORT_PER_PCI_DEV; i++) { 54562306a36Sopenharmony_ci opt = options + i * ICE_AQC_PORT_OPT_MAX; 54662306a36Sopenharmony_ci options_count = ICE_AQC_PORT_OPT_MAX; 54762306a36Sopenharmony_ci active_valid = 0; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci status = ice_aq_get_port_options(&pf->hw, opt, &options_count, 55062306a36Sopenharmony_ci i, true, &active_idx, 55162306a36Sopenharmony_ci &active_valid, &pending_idx, 55262306a36Sopenharmony_ci &pending_valid); 55362306a36Sopenharmony_ci if (status) { 55462306a36Sopenharmony_ci dev_dbg(dev, "Couldn't read port option for port %d, err %d\n", 55562306a36Sopenharmony_ci i, status); 55662306a36Sopenharmony_ci goto err; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci dev_dbg(dev, "Available port split options and max port speeds (Gbps):\n"); 56162306a36Sopenharmony_ci dev_dbg(dev, "Status Split Quad 0 Quad 1\n"); 56262306a36Sopenharmony_ci dev_dbg(dev, " count L0 L1 L2 L3 L4 L5 L6 L7\n"); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci for (i = 0; i < options_count; i++) { 56562306a36Sopenharmony_ci cnt = 0; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (i == ice_active_port_option) 56862306a36Sopenharmony_ci str = "Active"; 56962306a36Sopenharmony_ci else if ((i == pending_idx) && pending_valid) 57062306a36Sopenharmony_ci str = "Pending"; 57162306a36Sopenharmony_ci else 57262306a36Sopenharmony_ci str = ""; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt, 57562306a36Sopenharmony_ci "%-8s", str); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt, 57862306a36Sopenharmony_ci "%-6u", options[i].pmd); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci for (j = 0; j < ICE_MAX_PORT_PER_PCI_DEV; ++j) { 58162306a36Sopenharmony_ci speed = options[i + j * ICE_AQC_PORT_OPT_MAX].max_lane_speed; 58262306a36Sopenharmony_ci str = ice_devlink_port_opt_speed_str(speed); 58362306a36Sopenharmony_ci cnt += snprintf(&desc[cnt], ICE_PORT_OPT_DESC_LEN - cnt, 58462306a36Sopenharmony_ci "%3s ", str); 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci dev_dbg(dev, "%s\n", desc); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cierr: 59162306a36Sopenharmony_ci kfree(options); 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/** 59562306a36Sopenharmony_ci * ice_devlink_aq_set_port_option - Send set port option admin queue command 59662306a36Sopenharmony_ci * @pf: the PF to print split port options 59762306a36Sopenharmony_ci * @option_idx: selected port option 59862306a36Sopenharmony_ci * @extack: extended netdev ack structure 59962306a36Sopenharmony_ci * 60062306a36Sopenharmony_ci * Sends set port option admin queue command with selected port option and 60162306a36Sopenharmony_ci * calls NVM write activate. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_cistatic int 60462306a36Sopenharmony_ciice_devlink_aq_set_port_option(struct ice_pf *pf, u8 option_idx, 60562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 60862306a36Sopenharmony_ci int status; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci status = ice_aq_set_port_option(&pf->hw, 0, true, option_idx); 61162306a36Sopenharmony_ci if (status) { 61262306a36Sopenharmony_ci dev_dbg(dev, "ice_aq_set_port_option, err %d aq_err %d\n", 61362306a36Sopenharmony_ci status, pf->hw.adminq.sq_last_status); 61462306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port split request failed"); 61562306a36Sopenharmony_ci return -EIO; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci status = ice_acquire_nvm(&pf->hw, ICE_RES_WRITE); 61962306a36Sopenharmony_ci if (status) { 62062306a36Sopenharmony_ci dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n", 62162306a36Sopenharmony_ci status, pf->hw.adminq.sq_last_status); 62262306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore"); 62362306a36Sopenharmony_ci return -EIO; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci status = ice_nvm_write_activate(&pf->hw, ICE_AQC_NVM_ACTIV_REQ_EMPR, NULL); 62762306a36Sopenharmony_ci if (status) { 62862306a36Sopenharmony_ci dev_dbg(dev, "ice_nvm_write_activate failed, err %d aq_err %d\n", 62962306a36Sopenharmony_ci status, pf->hw.adminq.sq_last_status); 63062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port split request failed to save data"); 63162306a36Sopenharmony_ci ice_release_nvm(&pf->hw); 63262306a36Sopenharmony_ci return -EIO; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ice_release_nvm(&pf->hw); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Reboot required to finish port split"); 63862306a36Sopenharmony_ci return 0; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/** 64262306a36Sopenharmony_ci * ice_devlink_port_split - .port_split devlink handler 64362306a36Sopenharmony_ci * @devlink: devlink instance structure 64462306a36Sopenharmony_ci * @port: devlink port structure 64562306a36Sopenharmony_ci * @count: number of ports to split to 64662306a36Sopenharmony_ci * @extack: extended netdev ack structure 64762306a36Sopenharmony_ci * 64862306a36Sopenharmony_ci * Callback for the devlink .port_split operation. 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci * Unfortunately, the devlink expression of available options is limited 65162306a36Sopenharmony_ci * to just a number, so search for an FW port option which supports 65262306a36Sopenharmony_ci * the specified number. As there could be multiple FW port options with 65362306a36Sopenharmony_ci * the same port split count, allow switching between them. When the same 65462306a36Sopenharmony_ci * port split count request is issued again, switch to the next FW port 65562306a36Sopenharmony_ci * option with the same port split count. 65662306a36Sopenharmony_ci * 65762306a36Sopenharmony_ci * Return: zero on success or an error code on failure. 65862306a36Sopenharmony_ci */ 65962306a36Sopenharmony_cistatic int 66062306a36Sopenharmony_ciice_devlink_port_split(struct devlink *devlink, struct devlink_port *port, 66162306a36Sopenharmony_ci unsigned int count, struct netlink_ext_ack *extack) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct ice_aqc_get_port_options_elem options[ICE_AQC_PORT_OPT_MAX]; 66462306a36Sopenharmony_ci u8 i, j, active_idx, pending_idx, new_option; 66562306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 66662306a36Sopenharmony_ci u8 option_count = ICE_AQC_PORT_OPT_MAX; 66762306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 66862306a36Sopenharmony_ci bool active_valid, pending_valid; 66962306a36Sopenharmony_ci int status; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci status = ice_aq_get_port_options(&pf->hw, options, &option_count, 67262306a36Sopenharmony_ci 0, true, &active_idx, &active_valid, 67362306a36Sopenharmony_ci &pending_idx, &pending_valid); 67462306a36Sopenharmony_ci if (status) { 67562306a36Sopenharmony_ci dev_dbg(dev, "Couldn't read port split options, err = %d\n", 67662306a36Sopenharmony_ci status); 67762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to get available port split options"); 67862306a36Sopenharmony_ci return -EIO; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci new_option = ICE_AQC_PORT_OPT_MAX; 68262306a36Sopenharmony_ci active_idx = pending_valid ? pending_idx : active_idx; 68362306a36Sopenharmony_ci for (i = 1; i <= option_count; i++) { 68462306a36Sopenharmony_ci /* In order to allow switching between FW port options with 68562306a36Sopenharmony_ci * the same port split count, search for a new option starting 68662306a36Sopenharmony_ci * from the active/pending option (with array wrap around). 68762306a36Sopenharmony_ci */ 68862306a36Sopenharmony_ci j = (active_idx + i) % option_count; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (count == options[j].pmd) { 69162306a36Sopenharmony_ci new_option = j; 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (new_option == active_idx) { 69762306a36Sopenharmony_ci dev_dbg(dev, "request to split: count: %u is already set and there are no other options\n", 69862306a36Sopenharmony_ci count); 69962306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Requested split count is already set"); 70062306a36Sopenharmony_ci ice_devlink_port_options_print(pf); 70162306a36Sopenharmony_ci return -EINVAL; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (new_option == ICE_AQC_PORT_OPT_MAX) { 70562306a36Sopenharmony_ci dev_dbg(dev, "request to split: count: %u not found\n", count); 70662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Port split requested unsupported port config"); 70762306a36Sopenharmony_ci ice_devlink_port_options_print(pf); 70862306a36Sopenharmony_ci return -EINVAL; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci status = ice_devlink_aq_set_port_option(pf, new_option, extack); 71262306a36Sopenharmony_ci if (status) 71362306a36Sopenharmony_ci return status; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci ice_devlink_port_options_print(pf); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci/** 72162306a36Sopenharmony_ci * ice_devlink_port_unsplit - .port_unsplit devlink handler 72262306a36Sopenharmony_ci * @devlink: devlink instance structure 72362306a36Sopenharmony_ci * @port: devlink port structure 72462306a36Sopenharmony_ci * @extack: extended netdev ack structure 72562306a36Sopenharmony_ci * 72662306a36Sopenharmony_ci * Callback for the devlink .port_unsplit operation. 72762306a36Sopenharmony_ci * Calls ice_devlink_port_split with split count set to 1. 72862306a36Sopenharmony_ci * There could be no FW option available with split count 1. 72962306a36Sopenharmony_ci * 73062306a36Sopenharmony_ci * Return: zero on success or an error code on failure. 73162306a36Sopenharmony_ci */ 73262306a36Sopenharmony_cistatic int 73362306a36Sopenharmony_ciice_devlink_port_unsplit(struct devlink *devlink, struct devlink_port *port, 73462306a36Sopenharmony_ci struct netlink_ext_ack *extack) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci return ice_devlink_port_split(devlink, port, 1, extack); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci/** 74062306a36Sopenharmony_ci * ice_tear_down_devlink_rate_tree - removes devlink-rate exported tree 74162306a36Sopenharmony_ci * @pf: pf struct 74262306a36Sopenharmony_ci * 74362306a36Sopenharmony_ci * This function tears down tree exported during VF's creation. 74462306a36Sopenharmony_ci */ 74562306a36Sopenharmony_civoid ice_tear_down_devlink_rate_tree(struct ice_pf *pf) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct devlink *devlink; 74862306a36Sopenharmony_ci struct ice_vf *vf; 74962306a36Sopenharmony_ci unsigned int bkt; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci devlink = priv_to_devlink(pf); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci devl_lock(devlink); 75462306a36Sopenharmony_ci mutex_lock(&pf->vfs.table_lock); 75562306a36Sopenharmony_ci ice_for_each_vf(pf, bkt, vf) { 75662306a36Sopenharmony_ci if (vf->devlink_port.devlink_rate) 75762306a36Sopenharmony_ci devl_rate_leaf_destroy(&vf->devlink_port); 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci mutex_unlock(&pf->vfs.table_lock); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci devl_rate_nodes_destroy(devlink); 76262306a36Sopenharmony_ci devl_unlock(devlink); 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci/** 76662306a36Sopenharmony_ci * ice_enable_custom_tx - try to enable custom Tx feature 76762306a36Sopenharmony_ci * @pf: pf struct 76862306a36Sopenharmony_ci * 76962306a36Sopenharmony_ci * This function tries to enable custom Tx feature, 77062306a36Sopenharmony_ci * it's not possible to enable it, if DCB or ADQ is active. 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_cistatic bool ice_enable_custom_tx(struct ice_pf *pf) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct ice_port_info *pi = ice_get_main_vsi(pf)->port_info; 77562306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (pi->is_custom_tx_enabled) 77862306a36Sopenharmony_ci /* already enabled, return true */ 77962306a36Sopenharmony_ci return true; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (ice_is_adq_active(pf)) { 78262306a36Sopenharmony_ci dev_err(dev, "ADQ active, can't modify Tx scheduler tree\n"); 78362306a36Sopenharmony_ci return false; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (ice_is_dcb_active(pf)) { 78762306a36Sopenharmony_ci dev_err(dev, "DCB active, can't modify Tx scheduler tree\n"); 78862306a36Sopenharmony_ci return false; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci pi->is_custom_tx_enabled = true; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci return true; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci/** 79762306a36Sopenharmony_ci * ice_traverse_tx_tree - traverse Tx scheduler tree 79862306a36Sopenharmony_ci * @devlink: devlink struct 79962306a36Sopenharmony_ci * @node: current node, used for recursion 80062306a36Sopenharmony_ci * @tc_node: tc_node struct, that is treated as a root 80162306a36Sopenharmony_ci * @pf: pf struct 80262306a36Sopenharmony_ci * 80362306a36Sopenharmony_ci * This function traverses Tx scheduler tree and exports 80462306a36Sopenharmony_ci * entire structure to the devlink-rate. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_cistatic void ice_traverse_tx_tree(struct devlink *devlink, struct ice_sched_node *node, 80762306a36Sopenharmony_ci struct ice_sched_node *tc_node, struct ice_pf *pf) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct devlink_rate *rate_node = NULL; 81062306a36Sopenharmony_ci struct ice_vf *vf; 81162306a36Sopenharmony_ci int i; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (node->parent == tc_node) { 81462306a36Sopenharmony_ci /* create root node */ 81562306a36Sopenharmony_ci rate_node = devl_rate_node_create(devlink, node, node->name, NULL); 81662306a36Sopenharmony_ci } else if (node->vsi_handle && 81762306a36Sopenharmony_ci pf->vsi[node->vsi_handle]->vf) { 81862306a36Sopenharmony_ci vf = pf->vsi[node->vsi_handle]->vf; 81962306a36Sopenharmony_ci if (!vf->devlink_port.devlink_rate) 82062306a36Sopenharmony_ci /* leaf nodes doesn't have children 82162306a36Sopenharmony_ci * so we don't set rate_node 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci devl_rate_leaf_create(&vf->devlink_port, node, 82462306a36Sopenharmony_ci node->parent->rate_node); 82562306a36Sopenharmony_ci } else if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF && 82662306a36Sopenharmony_ci node->parent->rate_node) { 82762306a36Sopenharmony_ci rate_node = devl_rate_node_create(devlink, node, node->name, 82862306a36Sopenharmony_ci node->parent->rate_node); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (rate_node && !IS_ERR(rate_node)) 83262306a36Sopenharmony_ci node->rate_node = rate_node; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci for (i = 0; i < node->num_children; i++) 83562306a36Sopenharmony_ci ice_traverse_tx_tree(devlink, node->children[i], tc_node, pf); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci/** 83962306a36Sopenharmony_ci * ice_devlink_rate_init_tx_topology - export Tx scheduler tree to devlink rate 84062306a36Sopenharmony_ci * @devlink: devlink struct 84162306a36Sopenharmony_ci * @vsi: main vsi struct 84262306a36Sopenharmony_ci * 84362306a36Sopenharmony_ci * This function finds a root node, then calls ice_traverse_tx tree, which 84462306a36Sopenharmony_ci * traverses the tree and exports it's contents to devlink rate. 84562306a36Sopenharmony_ci */ 84662306a36Sopenharmony_ciint ice_devlink_rate_init_tx_topology(struct devlink *devlink, struct ice_vsi *vsi) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct ice_port_info *pi = vsi->port_info; 84962306a36Sopenharmony_ci struct ice_sched_node *tc_node; 85062306a36Sopenharmony_ci struct ice_pf *pf = vsi->back; 85162306a36Sopenharmony_ci int i; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci tc_node = pi->root->children[0]; 85462306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 85562306a36Sopenharmony_ci devl_lock(devlink); 85662306a36Sopenharmony_ci for (i = 0; i < tc_node->num_children; i++) 85762306a36Sopenharmony_ci ice_traverse_tx_tree(devlink, tc_node->children[i], tc_node, pf); 85862306a36Sopenharmony_ci devl_unlock(devlink); 85962306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return 0; 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci/** 86562306a36Sopenharmony_ci * ice_set_object_tx_share - sets node scheduling parameter 86662306a36Sopenharmony_ci * @pi: devlink struct instance 86762306a36Sopenharmony_ci * @node: node struct instance 86862306a36Sopenharmony_ci * @bw: bandwidth in bytes per second 86962306a36Sopenharmony_ci * @extack: extended netdev ack structure 87062306a36Sopenharmony_ci * 87162306a36Sopenharmony_ci * This function sets ICE_MIN_BW scheduling BW limit. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_cistatic int ice_set_object_tx_share(struct ice_port_info *pi, struct ice_sched_node *node, 87462306a36Sopenharmony_ci u64 bw, struct netlink_ext_ack *extack) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci int status; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 87962306a36Sopenharmony_ci /* converts bytes per second to kilo bits per second */ 88062306a36Sopenharmony_ci node->tx_share = div_u64(bw, 125); 88162306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt(pi, node, ICE_MIN_BW, node->tx_share); 88262306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (status) 88562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can't set scheduling node tx_share"); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return status; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci/** 89162306a36Sopenharmony_ci * ice_set_object_tx_max - sets node scheduling parameter 89262306a36Sopenharmony_ci * @pi: devlink struct instance 89362306a36Sopenharmony_ci * @node: node struct instance 89462306a36Sopenharmony_ci * @bw: bandwidth in bytes per second 89562306a36Sopenharmony_ci * @extack: extended netdev ack structure 89662306a36Sopenharmony_ci * 89762306a36Sopenharmony_ci * This function sets ICE_MAX_BW scheduling BW limit. 89862306a36Sopenharmony_ci */ 89962306a36Sopenharmony_cistatic int ice_set_object_tx_max(struct ice_port_info *pi, struct ice_sched_node *node, 90062306a36Sopenharmony_ci u64 bw, struct netlink_ext_ack *extack) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci int status; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 90562306a36Sopenharmony_ci /* converts bytes per second value to kilo bits per second */ 90662306a36Sopenharmony_ci node->tx_max = div_u64(bw, 125); 90762306a36Sopenharmony_ci status = ice_sched_set_node_bw_lmt(pi, node, ICE_MAX_BW, node->tx_max); 90862306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci if (status) 91162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can't set scheduling node tx_max"); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci return status; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci/** 91762306a36Sopenharmony_ci * ice_set_object_tx_priority - sets node scheduling parameter 91862306a36Sopenharmony_ci * @pi: devlink struct instance 91962306a36Sopenharmony_ci * @node: node struct instance 92062306a36Sopenharmony_ci * @priority: value representing priority for strict priority arbitration 92162306a36Sopenharmony_ci * @extack: extended netdev ack structure 92262306a36Sopenharmony_ci * 92362306a36Sopenharmony_ci * This function sets priority of node among siblings. 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_cistatic int ice_set_object_tx_priority(struct ice_port_info *pi, struct ice_sched_node *node, 92662306a36Sopenharmony_ci u32 priority, struct netlink_ext_ack *extack) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci int status; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (priority >= 8) { 93162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Priority should be less than 8"); 93262306a36Sopenharmony_ci return -EINVAL; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 93662306a36Sopenharmony_ci node->tx_priority = priority; 93762306a36Sopenharmony_ci status = ice_sched_set_node_priority(pi, node, node->tx_priority); 93862306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci if (status) 94162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can't set scheduling node tx_priority"); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci return status; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci/** 94762306a36Sopenharmony_ci * ice_set_object_tx_weight - sets node scheduling parameter 94862306a36Sopenharmony_ci * @pi: devlink struct instance 94962306a36Sopenharmony_ci * @node: node struct instance 95062306a36Sopenharmony_ci * @weight: value represeting relative weight for WFQ arbitration 95162306a36Sopenharmony_ci * @extack: extended netdev ack structure 95262306a36Sopenharmony_ci * 95362306a36Sopenharmony_ci * This function sets node weight for WFQ algorithm. 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_cistatic int ice_set_object_tx_weight(struct ice_port_info *pi, struct ice_sched_node *node, 95662306a36Sopenharmony_ci u32 weight, struct netlink_ext_ack *extack) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci int status; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (weight > 200 || weight < 1) { 96162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Weight must be between 1 and 200"); 96262306a36Sopenharmony_ci return -EINVAL; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 96662306a36Sopenharmony_ci node->tx_weight = weight; 96762306a36Sopenharmony_ci status = ice_sched_set_node_weight(pi, node, node->tx_weight); 96862306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (status) 97162306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can't set scheduling node tx_weight"); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci return status; 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci/** 97762306a36Sopenharmony_ci * ice_get_pi_from_dev_rate - get port info from devlink_rate 97862306a36Sopenharmony_ci * @rate_node: devlink struct instance 97962306a36Sopenharmony_ci * 98062306a36Sopenharmony_ci * This function returns corresponding port_info struct of devlink_rate 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_cistatic struct ice_port_info *ice_get_pi_from_dev_rate(struct devlink_rate *rate_node) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(rate_node->devlink); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci return ice_get_main_vsi(pf)->port_info; 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_cistatic int ice_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv, 99062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci struct ice_sched_node *node; 99362306a36Sopenharmony_ci struct ice_port_info *pi; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci pi = ice_get_pi_from_dev_rate(rate_node); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_node->devlink))) 99862306a36Sopenharmony_ci return -EBUSY; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci /* preallocate memory for ice_sched_node */ 100162306a36Sopenharmony_ci node = devm_kzalloc(ice_hw_to_dev(pi->hw), sizeof(*node), GFP_KERNEL); 100262306a36Sopenharmony_ci *priv = node; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci return 0; 100562306a36Sopenharmony_ci} 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_cistatic int ice_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv, 100862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci struct ice_sched_node *node, *tc_node; 101162306a36Sopenharmony_ci struct ice_port_info *pi; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci pi = ice_get_pi_from_dev_rate(rate_node); 101462306a36Sopenharmony_ci tc_node = pi->root->children[0]; 101562306a36Sopenharmony_ci node = priv; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (!rate_node->parent || !node || tc_node == node || !extack) 101862306a36Sopenharmony_ci return 0; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_node->devlink))) 102162306a36Sopenharmony_ci return -EBUSY; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* can't allow to delete a node with children */ 102462306a36Sopenharmony_ci if (node->num_children) 102562306a36Sopenharmony_ci return -EINVAL; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 102862306a36Sopenharmony_ci ice_free_sched_node(pi, node); 102962306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci return 0; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic int ice_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void *priv, 103562306a36Sopenharmony_ci u64 tx_max, struct netlink_ext_ack *extack) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci struct ice_sched_node *node = priv; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_leaf->devlink))) 104062306a36Sopenharmony_ci return -EBUSY; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (!node) 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci return ice_set_object_tx_max(ice_get_pi_from_dev_rate(rate_leaf), 104662306a36Sopenharmony_ci node, tx_max, extack); 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic int ice_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void *priv, 105062306a36Sopenharmony_ci u64 tx_share, struct netlink_ext_ack *extack) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct ice_sched_node *node = priv; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_leaf->devlink))) 105562306a36Sopenharmony_ci return -EBUSY; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (!node) 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci return ice_set_object_tx_share(ice_get_pi_from_dev_rate(rate_leaf), node, 106162306a36Sopenharmony_ci tx_share, extack); 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic int ice_devlink_rate_leaf_tx_priority_set(struct devlink_rate *rate_leaf, void *priv, 106562306a36Sopenharmony_ci u32 tx_priority, struct netlink_ext_ack *extack) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci struct ice_sched_node *node = priv; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_leaf->devlink))) 107062306a36Sopenharmony_ci return -EBUSY; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (!node) 107362306a36Sopenharmony_ci return 0; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return ice_set_object_tx_priority(ice_get_pi_from_dev_rate(rate_leaf), node, 107662306a36Sopenharmony_ci tx_priority, extack); 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic int ice_devlink_rate_leaf_tx_weight_set(struct devlink_rate *rate_leaf, void *priv, 108062306a36Sopenharmony_ci u32 tx_weight, struct netlink_ext_ack *extack) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci struct ice_sched_node *node = priv; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_leaf->devlink))) 108562306a36Sopenharmony_ci return -EBUSY; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (!node) 108862306a36Sopenharmony_ci return 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci return ice_set_object_tx_weight(ice_get_pi_from_dev_rate(rate_leaf), node, 109162306a36Sopenharmony_ci tx_weight, extack); 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistatic int ice_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *priv, 109562306a36Sopenharmony_ci u64 tx_max, struct netlink_ext_ack *extack) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci struct ice_sched_node *node = priv; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_node->devlink))) 110062306a36Sopenharmony_ci return -EBUSY; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci if (!node) 110362306a36Sopenharmony_ci return 0; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci return ice_set_object_tx_max(ice_get_pi_from_dev_rate(rate_node), 110662306a36Sopenharmony_ci node, tx_max, extack); 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_cistatic int ice_devlink_rate_node_tx_share_set(struct devlink_rate *rate_node, void *priv, 111062306a36Sopenharmony_ci u64 tx_share, struct netlink_ext_ack *extack) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci struct ice_sched_node *node = priv; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_node->devlink))) 111562306a36Sopenharmony_ci return -EBUSY; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if (!node) 111862306a36Sopenharmony_ci return 0; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci return ice_set_object_tx_share(ice_get_pi_from_dev_rate(rate_node), 112162306a36Sopenharmony_ci node, tx_share, extack); 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic int ice_devlink_rate_node_tx_priority_set(struct devlink_rate *rate_node, void *priv, 112562306a36Sopenharmony_ci u32 tx_priority, struct netlink_ext_ack *extack) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci struct ice_sched_node *node = priv; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_node->devlink))) 113062306a36Sopenharmony_ci return -EBUSY; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (!node) 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return ice_set_object_tx_priority(ice_get_pi_from_dev_rate(rate_node), 113662306a36Sopenharmony_ci node, tx_priority, extack); 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic int ice_devlink_rate_node_tx_weight_set(struct devlink_rate *rate_node, void *priv, 114062306a36Sopenharmony_ci u32 tx_weight, struct netlink_ext_ack *extack) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci struct ice_sched_node *node = priv; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(rate_node->devlink))) 114562306a36Sopenharmony_ci return -EBUSY; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (!node) 114862306a36Sopenharmony_ci return 0; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci return ice_set_object_tx_weight(ice_get_pi_from_dev_rate(rate_node), 115162306a36Sopenharmony_ci node, tx_weight, extack); 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic int ice_devlink_set_parent(struct devlink_rate *devlink_rate, 115562306a36Sopenharmony_ci struct devlink_rate *parent, 115662306a36Sopenharmony_ci void *priv, void *parent_priv, 115762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 115862306a36Sopenharmony_ci{ 115962306a36Sopenharmony_ci struct ice_port_info *pi = ice_get_pi_from_dev_rate(devlink_rate); 116062306a36Sopenharmony_ci struct ice_sched_node *tc_node, *node, *parent_node; 116162306a36Sopenharmony_ci u16 num_nodes_added; 116262306a36Sopenharmony_ci u32 first_node_teid; 116362306a36Sopenharmony_ci u32 node_teid; 116462306a36Sopenharmony_ci int status; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci tc_node = pi->root->children[0]; 116762306a36Sopenharmony_ci node = priv; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci if (!extack) 117062306a36Sopenharmony_ci return 0; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (!ice_enable_custom_tx(devlink_priv(devlink_rate->devlink))) 117362306a36Sopenharmony_ci return -EBUSY; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (!parent) { 117662306a36Sopenharmony_ci if (!node || tc_node == node || node->num_children) 117762306a36Sopenharmony_ci return -EINVAL; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 118062306a36Sopenharmony_ci ice_free_sched_node(pi, node); 118162306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci return 0; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci parent_node = parent_priv; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci /* if the node doesn't exist, create it */ 118962306a36Sopenharmony_ci if (!node->parent) { 119062306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 119162306a36Sopenharmony_ci status = ice_sched_add_elems(pi, tc_node, parent_node, 119262306a36Sopenharmony_ci parent_node->tx_sched_layer + 1, 119362306a36Sopenharmony_ci 1, &num_nodes_added, &first_node_teid, 119462306a36Sopenharmony_ci &node); 119562306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (status) { 119862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can't add a new node"); 119962306a36Sopenharmony_ci return status; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (devlink_rate->tx_share) 120362306a36Sopenharmony_ci ice_set_object_tx_share(pi, node, devlink_rate->tx_share, extack); 120462306a36Sopenharmony_ci if (devlink_rate->tx_max) 120562306a36Sopenharmony_ci ice_set_object_tx_max(pi, node, devlink_rate->tx_max, extack); 120662306a36Sopenharmony_ci if (devlink_rate->tx_priority) 120762306a36Sopenharmony_ci ice_set_object_tx_priority(pi, node, devlink_rate->tx_priority, extack); 120862306a36Sopenharmony_ci if (devlink_rate->tx_weight) 120962306a36Sopenharmony_ci ice_set_object_tx_weight(pi, node, devlink_rate->tx_weight, extack); 121062306a36Sopenharmony_ci } else { 121162306a36Sopenharmony_ci node_teid = le32_to_cpu(node->info.node_teid); 121262306a36Sopenharmony_ci mutex_lock(&pi->sched_lock); 121362306a36Sopenharmony_ci status = ice_sched_move_nodes(pi, parent_node, 1, &node_teid); 121462306a36Sopenharmony_ci mutex_unlock(&pi->sched_lock); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (status) 121762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Can't move existing node to a new parent"); 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci return status; 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci/** 122462306a36Sopenharmony_ci * ice_devlink_reload_up - do reload up after reinit 122562306a36Sopenharmony_ci * @devlink: pointer to the devlink instance reloading 122662306a36Sopenharmony_ci * @action: the action requested 122762306a36Sopenharmony_ci * @limit: limits imposed by userspace, such as not resetting 122862306a36Sopenharmony_ci * @actions_performed: on return, indicate what actions actually performed 122962306a36Sopenharmony_ci * @extack: netlink extended ACK structure 123062306a36Sopenharmony_ci */ 123162306a36Sopenharmony_cistatic int 123262306a36Sopenharmony_ciice_devlink_reload_up(struct devlink *devlink, 123362306a36Sopenharmony_ci enum devlink_reload_action action, 123462306a36Sopenharmony_ci enum devlink_reload_limit limit, 123562306a36Sopenharmony_ci u32 *actions_performed, 123662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci switch (action) { 124162306a36Sopenharmony_ci case DEVLINK_RELOAD_ACTION_DRIVER_REINIT: 124262306a36Sopenharmony_ci *actions_performed = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT); 124362306a36Sopenharmony_ci return ice_load(pf); 124462306a36Sopenharmony_ci case DEVLINK_RELOAD_ACTION_FW_ACTIVATE: 124562306a36Sopenharmony_ci *actions_performed = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE); 124662306a36Sopenharmony_ci return ice_devlink_reload_empr_finish(pf, extack); 124762306a36Sopenharmony_ci default: 124862306a36Sopenharmony_ci WARN_ON(1); 124962306a36Sopenharmony_ci return -EOPNOTSUPP; 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci} 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cistatic const struct devlink_ops ice_devlink_ops = { 125462306a36Sopenharmony_ci .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, 125562306a36Sopenharmony_ci .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) | 125662306a36Sopenharmony_ci BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), 125762306a36Sopenharmony_ci .reload_down = ice_devlink_reload_down, 125862306a36Sopenharmony_ci .reload_up = ice_devlink_reload_up, 125962306a36Sopenharmony_ci .eswitch_mode_get = ice_eswitch_mode_get, 126062306a36Sopenharmony_ci .eswitch_mode_set = ice_eswitch_mode_set, 126162306a36Sopenharmony_ci .info_get = ice_devlink_info_get, 126262306a36Sopenharmony_ci .flash_update = ice_devlink_flash_update, 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci .rate_node_new = ice_devlink_rate_node_new, 126562306a36Sopenharmony_ci .rate_node_del = ice_devlink_rate_node_del, 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci .rate_leaf_tx_max_set = ice_devlink_rate_leaf_tx_max_set, 126862306a36Sopenharmony_ci .rate_leaf_tx_share_set = ice_devlink_rate_leaf_tx_share_set, 126962306a36Sopenharmony_ci .rate_leaf_tx_priority_set = ice_devlink_rate_leaf_tx_priority_set, 127062306a36Sopenharmony_ci .rate_leaf_tx_weight_set = ice_devlink_rate_leaf_tx_weight_set, 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci .rate_node_tx_max_set = ice_devlink_rate_node_tx_max_set, 127362306a36Sopenharmony_ci .rate_node_tx_share_set = ice_devlink_rate_node_tx_share_set, 127462306a36Sopenharmony_ci .rate_node_tx_priority_set = ice_devlink_rate_node_tx_priority_set, 127562306a36Sopenharmony_ci .rate_node_tx_weight_set = ice_devlink_rate_node_tx_weight_set, 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci .rate_leaf_parent_set = ice_devlink_set_parent, 127862306a36Sopenharmony_ci .rate_node_parent_set = ice_devlink_set_parent, 127962306a36Sopenharmony_ci}; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_cistatic int 128262306a36Sopenharmony_ciice_devlink_enable_roce_get(struct devlink *devlink, u32 id, 128362306a36Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci ctx->val.vbool = pf->rdma_mode & IIDC_RDMA_PROTOCOL_ROCEV2 ? true : false; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci return 0; 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic int 129362306a36Sopenharmony_ciice_devlink_enable_roce_set(struct devlink *devlink, u32 id, 129462306a36Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 129562306a36Sopenharmony_ci{ 129662306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 129762306a36Sopenharmony_ci bool roce_ena = ctx->val.vbool; 129862306a36Sopenharmony_ci int ret; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci if (!roce_ena) { 130162306a36Sopenharmony_ci ice_unplug_aux_dev(pf); 130262306a36Sopenharmony_ci pf->rdma_mode &= ~IIDC_RDMA_PROTOCOL_ROCEV2; 130362306a36Sopenharmony_ci return 0; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci pf->rdma_mode |= IIDC_RDMA_PROTOCOL_ROCEV2; 130762306a36Sopenharmony_ci ret = ice_plug_aux_dev(pf); 130862306a36Sopenharmony_ci if (ret) 130962306a36Sopenharmony_ci pf->rdma_mode &= ~IIDC_RDMA_PROTOCOL_ROCEV2; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci return ret; 131262306a36Sopenharmony_ci} 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_cistatic int 131562306a36Sopenharmony_ciice_devlink_enable_roce_validate(struct devlink *devlink, u32 id, 131662306a36Sopenharmony_ci union devlink_param_value val, 131762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) 132262306a36Sopenharmony_ci return -EOPNOTSUPP; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci if (pf->rdma_mode & IIDC_RDMA_PROTOCOL_IWARP) { 132562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "iWARP is currently enabled. This device cannot enable iWARP and RoCEv2 simultaneously"); 132662306a36Sopenharmony_ci return -EOPNOTSUPP; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci return 0; 133062306a36Sopenharmony_ci} 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cistatic int 133362306a36Sopenharmony_ciice_devlink_enable_iw_get(struct devlink *devlink, u32 id, 133462306a36Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci ctx->val.vbool = pf->rdma_mode & IIDC_RDMA_PROTOCOL_IWARP; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci return 0; 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_cistatic int 134462306a36Sopenharmony_ciice_devlink_enable_iw_set(struct devlink *devlink, u32 id, 134562306a36Sopenharmony_ci struct devlink_param_gset_ctx *ctx) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 134862306a36Sopenharmony_ci bool iw_ena = ctx->val.vbool; 134962306a36Sopenharmony_ci int ret; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci if (!iw_ena) { 135262306a36Sopenharmony_ci ice_unplug_aux_dev(pf); 135362306a36Sopenharmony_ci pf->rdma_mode &= ~IIDC_RDMA_PROTOCOL_IWARP; 135462306a36Sopenharmony_ci return 0; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci pf->rdma_mode |= IIDC_RDMA_PROTOCOL_IWARP; 135862306a36Sopenharmony_ci ret = ice_plug_aux_dev(pf); 135962306a36Sopenharmony_ci if (ret) 136062306a36Sopenharmony_ci pf->rdma_mode &= ~IIDC_RDMA_PROTOCOL_IWARP; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci return ret; 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic int 136662306a36Sopenharmony_ciice_devlink_enable_iw_validate(struct devlink *devlink, u32 id, 136762306a36Sopenharmony_ci union devlink_param_value val, 136862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci if (!test_bit(ICE_FLAG_RDMA_ENA, pf->flags)) 137362306a36Sopenharmony_ci return -EOPNOTSUPP; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci if (pf->rdma_mode & IIDC_RDMA_PROTOCOL_ROCEV2) { 137662306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "RoCEv2 is currently enabled. This device cannot enable iWARP and RoCEv2 simultaneously"); 137762306a36Sopenharmony_ci return -EOPNOTSUPP; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci return 0; 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic const struct devlink_param ice_devlink_params[] = { 138462306a36Sopenharmony_ci DEVLINK_PARAM_GENERIC(ENABLE_ROCE, BIT(DEVLINK_PARAM_CMODE_RUNTIME), 138562306a36Sopenharmony_ci ice_devlink_enable_roce_get, 138662306a36Sopenharmony_ci ice_devlink_enable_roce_set, 138762306a36Sopenharmony_ci ice_devlink_enable_roce_validate), 138862306a36Sopenharmony_ci DEVLINK_PARAM_GENERIC(ENABLE_IWARP, BIT(DEVLINK_PARAM_CMODE_RUNTIME), 138962306a36Sopenharmony_ci ice_devlink_enable_iw_get, 139062306a36Sopenharmony_ci ice_devlink_enable_iw_set, 139162306a36Sopenharmony_ci ice_devlink_enable_iw_validate), 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci}; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_cistatic void ice_devlink_free(void *devlink_ptr) 139662306a36Sopenharmony_ci{ 139762306a36Sopenharmony_ci devlink_free((struct devlink *)devlink_ptr); 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci/** 140162306a36Sopenharmony_ci * ice_allocate_pf - Allocate devlink and return PF structure pointer 140262306a36Sopenharmony_ci * @dev: the device to allocate for 140362306a36Sopenharmony_ci * 140462306a36Sopenharmony_ci * Allocate a devlink instance for this device and return the private area as 140562306a36Sopenharmony_ci * the PF structure. The devlink memory is kept track of through devres by 140662306a36Sopenharmony_ci * adding an action to remove it when unwinding. 140762306a36Sopenharmony_ci */ 140862306a36Sopenharmony_cistruct ice_pf *ice_allocate_pf(struct device *dev) 140962306a36Sopenharmony_ci{ 141062306a36Sopenharmony_ci struct devlink *devlink; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf), dev); 141362306a36Sopenharmony_ci if (!devlink) 141462306a36Sopenharmony_ci return NULL; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* Add an action to teardown the devlink when unwinding the driver */ 141762306a36Sopenharmony_ci if (devm_add_action_or_reset(dev, ice_devlink_free, devlink)) 141862306a36Sopenharmony_ci return NULL; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci return devlink_priv(devlink); 142162306a36Sopenharmony_ci} 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci/** 142462306a36Sopenharmony_ci * ice_devlink_register - Register devlink interface for this PF 142562306a36Sopenharmony_ci * @pf: the PF to register the devlink for. 142662306a36Sopenharmony_ci * 142762306a36Sopenharmony_ci * Register the devlink instance associated with this physical function. 142862306a36Sopenharmony_ci * 142962306a36Sopenharmony_ci * Return: zero on success or an error code on failure. 143062306a36Sopenharmony_ci */ 143162306a36Sopenharmony_civoid ice_devlink_register(struct ice_pf *pf) 143262306a36Sopenharmony_ci{ 143362306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(pf); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci devlink_register(devlink); 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci/** 143962306a36Sopenharmony_ci * ice_devlink_unregister - Unregister devlink resources for this PF. 144062306a36Sopenharmony_ci * @pf: the PF structure to cleanup 144162306a36Sopenharmony_ci * 144262306a36Sopenharmony_ci * Releases resources used by devlink and cleans up associated memory. 144362306a36Sopenharmony_ci */ 144462306a36Sopenharmony_civoid ice_devlink_unregister(struct ice_pf *pf) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci devlink_unregister(priv_to_devlink(pf)); 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci/** 145062306a36Sopenharmony_ci * ice_devlink_set_switch_id - Set unique switch id based on pci dsn 145162306a36Sopenharmony_ci * @pf: the PF to create a devlink port for 145262306a36Sopenharmony_ci * @ppid: struct with switch id information 145362306a36Sopenharmony_ci */ 145462306a36Sopenharmony_cistatic void 145562306a36Sopenharmony_ciice_devlink_set_switch_id(struct ice_pf *pf, struct netdev_phys_item_id *ppid) 145662306a36Sopenharmony_ci{ 145762306a36Sopenharmony_ci struct pci_dev *pdev = pf->pdev; 145862306a36Sopenharmony_ci u64 id; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci id = pci_get_dsn(pdev); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci ppid->id_len = sizeof(id); 146362306a36Sopenharmony_ci put_unaligned_be64(id, &ppid->id); 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ciint ice_devlink_register_params(struct ice_pf *pf) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(pf); 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci return devlink_params_register(devlink, ice_devlink_params, 147162306a36Sopenharmony_ci ARRAY_SIZE(ice_devlink_params)); 147262306a36Sopenharmony_ci} 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_civoid ice_devlink_unregister_params(struct ice_pf *pf) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci devlink_params_unregister(priv_to_devlink(pf), ice_devlink_params, 147762306a36Sopenharmony_ci ARRAY_SIZE(ice_devlink_params)); 147862306a36Sopenharmony_ci} 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci/** 148162306a36Sopenharmony_ci * ice_devlink_set_port_split_options - Set port split options 148262306a36Sopenharmony_ci * @pf: the PF to set port split options 148362306a36Sopenharmony_ci * @attrs: devlink attributes 148462306a36Sopenharmony_ci * 148562306a36Sopenharmony_ci * Sets devlink port split options based on available FW port options 148662306a36Sopenharmony_ci */ 148762306a36Sopenharmony_cistatic void 148862306a36Sopenharmony_ciice_devlink_set_port_split_options(struct ice_pf *pf, 148962306a36Sopenharmony_ci struct devlink_port_attrs *attrs) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci struct ice_aqc_get_port_options_elem options[ICE_AQC_PORT_OPT_MAX]; 149262306a36Sopenharmony_ci u8 i, active_idx, pending_idx, option_count = ICE_AQC_PORT_OPT_MAX; 149362306a36Sopenharmony_ci bool active_valid, pending_valid; 149462306a36Sopenharmony_ci int status; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci status = ice_aq_get_port_options(&pf->hw, options, &option_count, 149762306a36Sopenharmony_ci 0, true, &active_idx, &active_valid, 149862306a36Sopenharmony_ci &pending_idx, &pending_valid); 149962306a36Sopenharmony_ci if (status) { 150062306a36Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Couldn't read port split options, err = %d\n", 150162306a36Sopenharmony_ci status); 150262306a36Sopenharmony_ci return; 150362306a36Sopenharmony_ci } 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci /* find the biggest available port split count */ 150662306a36Sopenharmony_ci for (i = 0; i < option_count; i++) 150762306a36Sopenharmony_ci attrs->lanes = max_t(int, attrs->lanes, options[i].pmd); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci attrs->splittable = attrs->lanes ? 1 : 0; 151062306a36Sopenharmony_ci ice_active_port_option = active_idx; 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic const struct devlink_port_ops ice_devlink_port_ops = { 151462306a36Sopenharmony_ci .port_split = ice_devlink_port_split, 151562306a36Sopenharmony_ci .port_unsplit = ice_devlink_port_unsplit, 151662306a36Sopenharmony_ci}; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci/** 151962306a36Sopenharmony_ci * ice_devlink_create_pf_port - Create a devlink port for this PF 152062306a36Sopenharmony_ci * @pf: the PF to create a devlink port for 152162306a36Sopenharmony_ci * 152262306a36Sopenharmony_ci * Create and register a devlink_port for this PF. 152362306a36Sopenharmony_ci * 152462306a36Sopenharmony_ci * Return: zero on success or an error code on failure. 152562306a36Sopenharmony_ci */ 152662306a36Sopenharmony_ciint ice_devlink_create_pf_port(struct ice_pf *pf) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci struct devlink_port_attrs attrs = {}; 152962306a36Sopenharmony_ci struct devlink_port *devlink_port; 153062306a36Sopenharmony_ci struct devlink *devlink; 153162306a36Sopenharmony_ci struct ice_vsi *vsi; 153262306a36Sopenharmony_ci struct device *dev; 153362306a36Sopenharmony_ci int err; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci devlink_port = &pf->devlink_port; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci vsi = ice_get_main_vsi(pf); 154062306a36Sopenharmony_ci if (!vsi) 154162306a36Sopenharmony_ci return -EIO; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 154462306a36Sopenharmony_ci attrs.phys.port_number = pf->hw.bus.func; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci /* As FW supports only port split options for whole device, 154762306a36Sopenharmony_ci * set port split options only for first PF. 154862306a36Sopenharmony_ci */ 154962306a36Sopenharmony_ci if (pf->hw.pf_id == 0) 155062306a36Sopenharmony_ci ice_devlink_set_port_split_options(pf, &attrs); 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci ice_devlink_set_switch_id(pf, &attrs.switch_id); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci devlink_port_attrs_set(devlink_port, &attrs); 155562306a36Sopenharmony_ci devlink = priv_to_devlink(pf); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci err = devlink_port_register_with_ops(devlink, devlink_port, vsi->idx, 155862306a36Sopenharmony_ci &ice_devlink_port_ops); 155962306a36Sopenharmony_ci if (err) { 156062306a36Sopenharmony_ci dev_err(dev, "Failed to create devlink port for PF %d, error %d\n", 156162306a36Sopenharmony_ci pf->hw.pf_id, err); 156262306a36Sopenharmony_ci return err; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci return 0; 156662306a36Sopenharmony_ci} 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci/** 156962306a36Sopenharmony_ci * ice_devlink_destroy_pf_port - Destroy the devlink_port for this PF 157062306a36Sopenharmony_ci * @pf: the PF to cleanup 157162306a36Sopenharmony_ci * 157262306a36Sopenharmony_ci * Unregisters the devlink_port structure associated with this PF. 157362306a36Sopenharmony_ci */ 157462306a36Sopenharmony_civoid ice_devlink_destroy_pf_port(struct ice_pf *pf) 157562306a36Sopenharmony_ci{ 157662306a36Sopenharmony_ci devlink_port_unregister(&pf->devlink_port); 157762306a36Sopenharmony_ci} 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci/** 158062306a36Sopenharmony_ci * ice_devlink_create_vf_port - Create a devlink port for this VF 158162306a36Sopenharmony_ci * @vf: the VF to create a port for 158262306a36Sopenharmony_ci * 158362306a36Sopenharmony_ci * Create and register a devlink_port for this VF. 158462306a36Sopenharmony_ci * 158562306a36Sopenharmony_ci * Return: zero on success or an error code on failure. 158662306a36Sopenharmony_ci */ 158762306a36Sopenharmony_ciint ice_devlink_create_vf_port(struct ice_vf *vf) 158862306a36Sopenharmony_ci{ 158962306a36Sopenharmony_ci struct devlink_port_attrs attrs = {}; 159062306a36Sopenharmony_ci struct devlink_port *devlink_port; 159162306a36Sopenharmony_ci struct devlink *devlink; 159262306a36Sopenharmony_ci struct ice_vsi *vsi; 159362306a36Sopenharmony_ci struct device *dev; 159462306a36Sopenharmony_ci struct ice_pf *pf; 159562306a36Sopenharmony_ci int err; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci pf = vf->pf; 159862306a36Sopenharmony_ci dev = ice_pf_to_dev(pf); 159962306a36Sopenharmony_ci devlink_port = &vf->devlink_port; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci vsi = ice_get_vf_vsi(vf); 160262306a36Sopenharmony_ci if (!vsi) 160362306a36Sopenharmony_ci return -EINVAL; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci attrs.flavour = DEVLINK_PORT_FLAVOUR_PCI_VF; 160662306a36Sopenharmony_ci attrs.pci_vf.pf = pf->hw.bus.func; 160762306a36Sopenharmony_ci attrs.pci_vf.vf = vf->vf_id; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci ice_devlink_set_switch_id(pf, &attrs.switch_id); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci devlink_port_attrs_set(devlink_port, &attrs); 161262306a36Sopenharmony_ci devlink = priv_to_devlink(pf); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci err = devlink_port_register(devlink, devlink_port, vsi->idx); 161562306a36Sopenharmony_ci if (err) { 161662306a36Sopenharmony_ci dev_err(dev, "Failed to create devlink port for VF %d, error %d\n", 161762306a36Sopenharmony_ci vf->vf_id, err); 161862306a36Sopenharmony_ci return err; 161962306a36Sopenharmony_ci } 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return 0; 162262306a36Sopenharmony_ci} 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci/** 162562306a36Sopenharmony_ci * ice_devlink_destroy_vf_port - Destroy the devlink_port for this VF 162662306a36Sopenharmony_ci * @vf: the VF to cleanup 162762306a36Sopenharmony_ci * 162862306a36Sopenharmony_ci * Unregisters the devlink_port structure associated with this VF. 162962306a36Sopenharmony_ci */ 163062306a36Sopenharmony_civoid ice_devlink_destroy_vf_port(struct ice_vf *vf) 163162306a36Sopenharmony_ci{ 163262306a36Sopenharmony_ci devl_rate_leaf_destroy(&vf->devlink_port); 163362306a36Sopenharmony_ci devlink_port_unregister(&vf->devlink_port); 163462306a36Sopenharmony_ci} 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci#define ICE_DEVLINK_READ_BLK_SIZE (1024 * 1024) 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_cistatic const struct devlink_region_ops ice_nvm_region_ops; 163962306a36Sopenharmony_cistatic const struct devlink_region_ops ice_sram_region_ops; 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci/** 164262306a36Sopenharmony_ci * ice_devlink_nvm_snapshot - Capture a snapshot of the NVM flash contents 164362306a36Sopenharmony_ci * @devlink: the devlink instance 164462306a36Sopenharmony_ci * @ops: the devlink region to snapshot 164562306a36Sopenharmony_ci * @extack: extended ACK response structure 164662306a36Sopenharmony_ci * @data: on exit points to snapshot data buffer 164762306a36Sopenharmony_ci * 164862306a36Sopenharmony_ci * This function is called in response to a DEVLINK_CMD_REGION_NEW for either 164962306a36Sopenharmony_ci * the nvm-flash or shadow-ram region. 165062306a36Sopenharmony_ci * 165162306a36Sopenharmony_ci * It captures a snapshot of the NVM or Shadow RAM flash contents. This 165262306a36Sopenharmony_ci * snapshot can then later be viewed via the DEVLINK_CMD_REGION_READ netlink 165362306a36Sopenharmony_ci * interface. 165462306a36Sopenharmony_ci * 165562306a36Sopenharmony_ci * @returns zero on success, and updates the data pointer. Returns a non-zero 165662306a36Sopenharmony_ci * error code on failure. 165762306a36Sopenharmony_ci */ 165862306a36Sopenharmony_cistatic int ice_devlink_nvm_snapshot(struct devlink *devlink, 165962306a36Sopenharmony_ci const struct devlink_region_ops *ops, 166062306a36Sopenharmony_ci struct netlink_ext_ack *extack, u8 **data) 166162306a36Sopenharmony_ci{ 166262306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 166362306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 166462306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 166562306a36Sopenharmony_ci bool read_shadow_ram; 166662306a36Sopenharmony_ci u8 *nvm_data, *tmp, i; 166762306a36Sopenharmony_ci u32 nvm_size, left; 166862306a36Sopenharmony_ci s8 num_blks; 166962306a36Sopenharmony_ci int status; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci if (ops == &ice_nvm_region_ops) { 167262306a36Sopenharmony_ci read_shadow_ram = false; 167362306a36Sopenharmony_ci nvm_size = hw->flash.flash_size; 167462306a36Sopenharmony_ci } else if (ops == &ice_sram_region_ops) { 167562306a36Sopenharmony_ci read_shadow_ram = true; 167662306a36Sopenharmony_ci nvm_size = hw->flash.sr_words * 2u; 167762306a36Sopenharmony_ci } else { 167862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unexpected region in snapshot function"); 167962306a36Sopenharmony_ci return -EOPNOTSUPP; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci nvm_data = vzalloc(nvm_size); 168362306a36Sopenharmony_ci if (!nvm_data) 168462306a36Sopenharmony_ci return -ENOMEM; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci num_blks = DIV_ROUND_UP(nvm_size, ICE_DEVLINK_READ_BLK_SIZE); 168762306a36Sopenharmony_ci tmp = nvm_data; 168862306a36Sopenharmony_ci left = nvm_size; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci /* Some systems take longer to read the NVM than others which causes the 169162306a36Sopenharmony_ci * FW to reclaim the NVM lock before the entire NVM has been read. Fix 169262306a36Sopenharmony_ci * this by breaking the reads of the NVM into smaller chunks that will 169362306a36Sopenharmony_ci * probably not take as long. This has some overhead since we are 169462306a36Sopenharmony_ci * increasing the number of AQ commands, but it should always work 169562306a36Sopenharmony_ci */ 169662306a36Sopenharmony_ci for (i = 0; i < num_blks; i++) { 169762306a36Sopenharmony_ci u32 read_sz = min_t(u32, ICE_DEVLINK_READ_BLK_SIZE, left); 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci status = ice_acquire_nvm(hw, ICE_RES_READ); 170062306a36Sopenharmony_ci if (status) { 170162306a36Sopenharmony_ci dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n", 170262306a36Sopenharmony_ci status, hw->adminq.sq_last_status); 170362306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore"); 170462306a36Sopenharmony_ci vfree(nvm_data); 170562306a36Sopenharmony_ci return -EIO; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci status = ice_read_flat_nvm(hw, i * ICE_DEVLINK_READ_BLK_SIZE, 170962306a36Sopenharmony_ci &read_sz, tmp, read_shadow_ram); 171062306a36Sopenharmony_ci if (status) { 171162306a36Sopenharmony_ci dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n", 171262306a36Sopenharmony_ci read_sz, status, hw->adminq.sq_last_status); 171362306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents"); 171462306a36Sopenharmony_ci ice_release_nvm(hw); 171562306a36Sopenharmony_ci vfree(nvm_data); 171662306a36Sopenharmony_ci return -EIO; 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci ice_release_nvm(hw); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci tmp += read_sz; 172162306a36Sopenharmony_ci left -= read_sz; 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci *data = nvm_data; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci return 0; 172762306a36Sopenharmony_ci} 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci/** 173062306a36Sopenharmony_ci * ice_devlink_nvm_read - Read a portion of NVM flash contents 173162306a36Sopenharmony_ci * @devlink: the devlink instance 173262306a36Sopenharmony_ci * @ops: the devlink region to snapshot 173362306a36Sopenharmony_ci * @extack: extended ACK response structure 173462306a36Sopenharmony_ci * @offset: the offset to start at 173562306a36Sopenharmony_ci * @size: the amount to read 173662306a36Sopenharmony_ci * @data: the data buffer to read into 173762306a36Sopenharmony_ci * 173862306a36Sopenharmony_ci * This function is called in response to DEVLINK_CMD_REGION_READ to directly 173962306a36Sopenharmony_ci * read a section of the NVM contents. 174062306a36Sopenharmony_ci * 174162306a36Sopenharmony_ci * It reads from either the nvm-flash or shadow-ram region contents. 174262306a36Sopenharmony_ci * 174362306a36Sopenharmony_ci * @returns zero on success, and updates the data pointer. Returns a non-zero 174462306a36Sopenharmony_ci * error code on failure. 174562306a36Sopenharmony_ci */ 174662306a36Sopenharmony_cistatic int ice_devlink_nvm_read(struct devlink *devlink, 174762306a36Sopenharmony_ci const struct devlink_region_ops *ops, 174862306a36Sopenharmony_ci struct netlink_ext_ack *extack, 174962306a36Sopenharmony_ci u64 offset, u32 size, u8 *data) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 175262306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 175362306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 175462306a36Sopenharmony_ci bool read_shadow_ram; 175562306a36Sopenharmony_ci u64 nvm_size; 175662306a36Sopenharmony_ci int status; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (ops == &ice_nvm_region_ops) { 175962306a36Sopenharmony_ci read_shadow_ram = false; 176062306a36Sopenharmony_ci nvm_size = hw->flash.flash_size; 176162306a36Sopenharmony_ci } else if (ops == &ice_sram_region_ops) { 176262306a36Sopenharmony_ci read_shadow_ram = true; 176362306a36Sopenharmony_ci nvm_size = hw->flash.sr_words * 2u; 176462306a36Sopenharmony_ci } else { 176562306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Unexpected region in snapshot function"); 176662306a36Sopenharmony_ci return -EOPNOTSUPP; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci if (offset + size >= nvm_size) { 177062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Cannot read beyond the region size"); 177162306a36Sopenharmony_ci return -ERANGE; 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci status = ice_acquire_nvm(hw, ICE_RES_READ); 177562306a36Sopenharmony_ci if (status) { 177662306a36Sopenharmony_ci dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n", 177762306a36Sopenharmony_ci status, hw->adminq.sq_last_status); 177862306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore"); 177962306a36Sopenharmony_ci return -EIO; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci status = ice_read_flat_nvm(hw, (u32)offset, &size, data, 178362306a36Sopenharmony_ci read_shadow_ram); 178462306a36Sopenharmony_ci if (status) { 178562306a36Sopenharmony_ci dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n", 178662306a36Sopenharmony_ci size, status, hw->adminq.sq_last_status); 178762306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents"); 178862306a36Sopenharmony_ci ice_release_nvm(hw); 178962306a36Sopenharmony_ci return -EIO; 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci ice_release_nvm(hw); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci return 0; 179462306a36Sopenharmony_ci} 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci/** 179762306a36Sopenharmony_ci * ice_devlink_devcaps_snapshot - Capture snapshot of device capabilities 179862306a36Sopenharmony_ci * @devlink: the devlink instance 179962306a36Sopenharmony_ci * @ops: the devlink region being snapshotted 180062306a36Sopenharmony_ci * @extack: extended ACK response structure 180162306a36Sopenharmony_ci * @data: on exit points to snapshot data buffer 180262306a36Sopenharmony_ci * 180362306a36Sopenharmony_ci * This function is called in response to the DEVLINK_CMD_REGION_TRIGGER for 180462306a36Sopenharmony_ci * the device-caps devlink region. It captures a snapshot of the device 180562306a36Sopenharmony_ci * capabilities reported by firmware. 180662306a36Sopenharmony_ci * 180762306a36Sopenharmony_ci * @returns zero on success, and updates the data pointer. Returns a non-zero 180862306a36Sopenharmony_ci * error code on failure. 180962306a36Sopenharmony_ci */ 181062306a36Sopenharmony_cistatic int 181162306a36Sopenharmony_ciice_devlink_devcaps_snapshot(struct devlink *devlink, 181262306a36Sopenharmony_ci const struct devlink_region_ops *ops, 181362306a36Sopenharmony_ci struct netlink_ext_ack *extack, u8 **data) 181462306a36Sopenharmony_ci{ 181562306a36Sopenharmony_ci struct ice_pf *pf = devlink_priv(devlink); 181662306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 181762306a36Sopenharmony_ci struct ice_hw *hw = &pf->hw; 181862306a36Sopenharmony_ci void *devcaps; 181962306a36Sopenharmony_ci int status; 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci devcaps = vzalloc(ICE_AQ_MAX_BUF_LEN); 182262306a36Sopenharmony_ci if (!devcaps) 182362306a36Sopenharmony_ci return -ENOMEM; 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci status = ice_aq_list_caps(hw, devcaps, ICE_AQ_MAX_BUF_LEN, NULL, 182662306a36Sopenharmony_ci ice_aqc_opc_list_dev_caps, NULL); 182762306a36Sopenharmony_ci if (status) { 182862306a36Sopenharmony_ci dev_dbg(dev, "ice_aq_list_caps: failed to read device capabilities, err %d aq_err %d\n", 182962306a36Sopenharmony_ci status, hw->adminq.sq_last_status); 183062306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to read device capabilities"); 183162306a36Sopenharmony_ci vfree(devcaps); 183262306a36Sopenharmony_ci return status; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci *data = (u8 *)devcaps; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci return 0; 183862306a36Sopenharmony_ci} 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_cistatic const struct devlink_region_ops ice_nvm_region_ops = { 184162306a36Sopenharmony_ci .name = "nvm-flash", 184262306a36Sopenharmony_ci .destructor = vfree, 184362306a36Sopenharmony_ci .snapshot = ice_devlink_nvm_snapshot, 184462306a36Sopenharmony_ci .read = ice_devlink_nvm_read, 184562306a36Sopenharmony_ci}; 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_cistatic const struct devlink_region_ops ice_sram_region_ops = { 184862306a36Sopenharmony_ci .name = "shadow-ram", 184962306a36Sopenharmony_ci .destructor = vfree, 185062306a36Sopenharmony_ci .snapshot = ice_devlink_nvm_snapshot, 185162306a36Sopenharmony_ci .read = ice_devlink_nvm_read, 185262306a36Sopenharmony_ci}; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_cistatic const struct devlink_region_ops ice_devcaps_region_ops = { 185562306a36Sopenharmony_ci .name = "device-caps", 185662306a36Sopenharmony_ci .destructor = vfree, 185762306a36Sopenharmony_ci .snapshot = ice_devlink_devcaps_snapshot, 185862306a36Sopenharmony_ci}; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci/** 186162306a36Sopenharmony_ci * ice_devlink_init_regions - Initialize devlink regions 186262306a36Sopenharmony_ci * @pf: the PF device structure 186362306a36Sopenharmony_ci * 186462306a36Sopenharmony_ci * Create devlink regions used to enable access to dump the contents of the 186562306a36Sopenharmony_ci * flash memory on the device. 186662306a36Sopenharmony_ci */ 186762306a36Sopenharmony_civoid ice_devlink_init_regions(struct ice_pf *pf) 186862306a36Sopenharmony_ci{ 186962306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(pf); 187062306a36Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 187162306a36Sopenharmony_ci u64 nvm_size, sram_size; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci nvm_size = pf->hw.flash.flash_size; 187462306a36Sopenharmony_ci pf->nvm_region = devlink_region_create(devlink, &ice_nvm_region_ops, 1, 187562306a36Sopenharmony_ci nvm_size); 187662306a36Sopenharmony_ci if (IS_ERR(pf->nvm_region)) { 187762306a36Sopenharmony_ci dev_err(dev, "failed to create NVM devlink region, err %ld\n", 187862306a36Sopenharmony_ci PTR_ERR(pf->nvm_region)); 187962306a36Sopenharmony_ci pf->nvm_region = NULL; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci sram_size = pf->hw.flash.sr_words * 2u; 188362306a36Sopenharmony_ci pf->sram_region = devlink_region_create(devlink, &ice_sram_region_ops, 188462306a36Sopenharmony_ci 1, sram_size); 188562306a36Sopenharmony_ci if (IS_ERR(pf->sram_region)) { 188662306a36Sopenharmony_ci dev_err(dev, "failed to create shadow-ram devlink region, err %ld\n", 188762306a36Sopenharmony_ci PTR_ERR(pf->sram_region)); 188862306a36Sopenharmony_ci pf->sram_region = NULL; 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci pf->devcaps_region = devlink_region_create(devlink, 189262306a36Sopenharmony_ci &ice_devcaps_region_ops, 10, 189362306a36Sopenharmony_ci ICE_AQ_MAX_BUF_LEN); 189462306a36Sopenharmony_ci if (IS_ERR(pf->devcaps_region)) { 189562306a36Sopenharmony_ci dev_err(dev, "failed to create device-caps devlink region, err %ld\n", 189662306a36Sopenharmony_ci PTR_ERR(pf->devcaps_region)); 189762306a36Sopenharmony_ci pf->devcaps_region = NULL; 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci} 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci/** 190262306a36Sopenharmony_ci * ice_devlink_destroy_regions - Destroy devlink regions 190362306a36Sopenharmony_ci * @pf: the PF device structure 190462306a36Sopenharmony_ci * 190562306a36Sopenharmony_ci * Remove previously created regions for this PF. 190662306a36Sopenharmony_ci */ 190762306a36Sopenharmony_civoid ice_devlink_destroy_regions(struct ice_pf *pf) 190862306a36Sopenharmony_ci{ 190962306a36Sopenharmony_ci if (pf->nvm_region) 191062306a36Sopenharmony_ci devlink_region_destroy(pf->nvm_region); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci if (pf->sram_region) 191362306a36Sopenharmony_ci devlink_region_destroy(pf->sram_region); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci if (pf->devcaps_region) 191662306a36Sopenharmony_ci devlink_region_destroy(pf->devcaps_region); 191762306a36Sopenharmony_ci} 1918