summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/amd/pds_core/core.c2
-rw-r--r--drivers/net/ethernet/amd/pds_core/devlink.c145
2 files changed, 142 insertions, 5 deletions
diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c
index d13b727dee42..51d21328c73d 100644
--- a/drivers/net/ethernet/amd/pds_core/core.c
+++ b/drivers/net/ethernet/amd/pds_core/core.c
@@ -596,6 +596,8 @@ void pdsc_fw_up(struct pdsc *pdsc)
return;
}
+ pdsc_fw_components_invalidate(pdsc);
+
err = pdsc_setup(pdsc, PDSC_SETUP_RECOVERY);
if (err)
goto err_out;
diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c
index 3b763ee1715e..63fe45e91f71 100644
--- a/drivers/net/ethernet/amd/pds_core/devlink.c
+++ b/drivers/net/ethernet/amd/pds_core/devlink.c
@@ -93,14 +93,120 @@ int pdsc_dl_flash_update(struct devlink *dl,
return pdsc_firmware_update(pdsc, params, extack);
}
+static int pdsc_dl_report_component(struct devlink_info_req *req,
+ struct pds_core_fw_component_info *info)
+{
+ enum devlink_info_version_type ver_type;
+ u16 flags = le16_to_cpu(info->flags);
+ char *ver = info->version;
+ const char *name;
+ char buf[32];
+
+ /* Main firmware is reported as generic "fw" */
+ if (info->component_type == PDS_CORE_FW_TYPE_MAIN) {
+ if (info->slot_id == PDS_CORE_FW_SLOT_GOLD)
+ snprintf(buf, sizeof(buf), "fw.gold");
+ else
+ snprintf(buf, sizeof(buf), "fw");
+ } else {
+ name = pdsc_fw_type_to_name(info->component_type);
+ if (!name)
+ return 0;
+
+ if (info->slot_id == PDS_CORE_FW_SLOT_GOLD)
+ snprintf(buf, sizeof(buf), "fw.%s.gold", name);
+ else
+ snprintf(buf, sizeof(buf), "fw.%s", name);
+ }
+
+ ver_type = DEVLINK_INFO_VERSION_TYPE_NONE;
+ if (flags & PDS_CORE_FW_COMPONENT_INFO_F_UPDATE_BY_NAME)
+ ver_type = DEVLINK_INFO_VERSION_TYPE_COMPONENT;
+
+ if (flags & PDS_CORE_FW_COMPONENT_INFO_F_FIXED) {
+ int err;
+
+ err = devlink_info_version_fixed_put(req, buf, ver);
+ if (err)
+ return err;
+ }
+
+ if (flags & PDS_CORE_FW_COMPONENT_INFO_F_RUNNING) {
+ int err;
+
+ err = devlink_info_version_running_put_ext(req, buf,
+ ver, ver_type);
+ if (err)
+ return err;
+ }
+
+ if (flags & PDS_CORE_FW_COMPONENT_INFO_F_STARTUP) {
+ int err;
+
+ err = devlink_info_version_stored_put_ext(req, buf,
+ ver, ver_type);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int pdsc_dl_report_fw_ver(struct devlink_info_req *req, char *fw_ver)
+{
+ return devlink_info_version_running_put(req,
+ DEVLINK_INFO_VERSION_GENERIC_FW,
+ fw_ver);
+}
+
+static int pdsc_dl_component_info_get(struct devlink *dl,
+ struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
+{
+ struct pdsc *pdsc = devlink_priv(dl);
+ u8 num_components;
+ int err;
+ int i;
+
+ /* Pairs with WRITE_ONCE in pdsc_fw_components_invalidate().
+ * Use READ_ONCE to get a consistent snapshot of num_components.
+ * pdsc_fw_components_invalidate() can zero it concurrently during
+ * firmware recovery; using the local copy avoids iterating zero
+ * times when we already decided the cache was valid.
+ */
+ num_components = READ_ONCE(pdsc->fw_components.num_components);
+ if (!num_components) {
+ err = pdsc_get_component_info(pdsc);
+ if (err)
+ return pdsc_dl_report_fw_ver(req,
+ pdsc->dev_info.fw_version);
+ num_components = READ_ONCE(pdsc->fw_components.num_components);
+ if (!num_components)
+ return pdsc_dl_report_fw_ver(req,
+ pdsc->dev_info.fw_version);
+ }
+
+ num_components = min_t(u16, num_components,
+ le16_to_cpu(pdsc->dev_ident.max_fw_slots));
+ for (i = 0; i < num_components; i++) {
+ err = pdsc_dl_report_component(req,
+ &pdsc->fw_components.info[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static char *fw_slotnames[] = {
"fw.goldfw",
"fw.mainfwa",
"fw.mainfwb",
};
-int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
- struct netlink_ext_ack *extack)
+static int pdsc_dl_fw_list_info_get(struct devlink *dl,
+ struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
{
union pds_core_dev_cmd cmd = {
.fw_control.opcode = PDS_CORE_CMD_FW_CONTROL,
@@ -134,12 +240,41 @@ int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
return err;
}
- err = devlink_info_version_running_put(req,
- DEVLINK_INFO_VERSION_GENERIC_FW,
- pdsc->dev_info.fw_version);
+ return 0;
+}
+
+static int pdsc_dl_info_get_v1(struct devlink *dl,
+ struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
+{
+ struct pdsc *pdsc = devlink_priv(dl);
+ int err;
+
+ err = pdsc_dl_fw_list_info_get(dl, req, extack);
if (err)
return err;
+ /* Version 1: report fw from dev_info (running only) */
+ return pdsc_dl_report_fw_ver(req, pdsc->dev_info.fw_version);
+}
+
+int pdsc_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
+{
+ struct pdsc *pdsc = devlink_priv(dl);
+ char buf[32];
+ int err;
+
+ if (pdsc->dev_ident.version >= PDS_CORE_IDENTITY_VERSION_2) {
+ err = pdsc_dl_component_info_get(dl, req, extack);
+ if (err)
+ return err;
+ } else {
+ err = pdsc_dl_info_get_v1(dl, req, extack);
+ if (err)
+ return err;
+ }
+
snprintf(buf, sizeof(buf), "0x%x", pdsc->dev_info.asic_type);
err = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,