habanalabs: print firmware versions
authorOded Gabbay <ogabbay@kernel.org>
Wed, 9 Jun 2021 07:04:35 +0000 (10:04 +0300)
committerOded Gabbay <ogabbay@kernel.org>
Fri, 18 Jun 2021 12:23:42 +0000 (15:23 +0300)
Firmware in habanalabs devices is composed of several components.
During device initialization, we read these versions from the device.
Print them during device initialization to allow better visibility in
automated systems.

Signed-off-by: Oded Gabbay <ogabbay@kernel.org>
drivers/misc/habanalabs/common/firmware_if.c

index 2bb2a41..14e7042 100644 (file)
 #include <linux/firmware.h>
 #include <linux/crc32.h>
 #include <linux/slab.h>
+#include <linux/ctype.h>
 
 #define FW_FILE_MAX_SIZE               0x1400000 /* maximum size of 20MB */
 
 #define FW_CPU_STATUS_POLL_INTERVAL_USEC       10000
 
+static char *extract_fw_ver_from_str(const char *fw_str)
+{
+       char *str, *fw_ver, *whitespace;
+
+       fw_ver = kmalloc(16, GFP_KERNEL);
+       if (!fw_ver)
+               return NULL;
+
+       str = strnstr(fw_str, "fw-", VERSION_MAX_LEN);
+       if (!str)
+               goto free_fw_ver;
+
+       /* Skip the fw- part */
+       str += 3;
+
+       /* Copy until the next whitespace */
+       whitespace =  strnstr(str, " ", 15);
+       if (!whitespace)
+               goto free_fw_ver;
+
+       strscpy(fw_ver, str, whitespace - str + 1);
+
+       return fw_ver;
+
+free_fw_ver:
+       kfree(fw_ver);
+       return NULL;
+}
+
 static int hl_request_fw(struct hl_device *hdev,
                                const struct firmware **firmware_p,
                                const char *fw_name)
@@ -573,8 +603,9 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev,
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
        struct cpucp_packet pkt = {};
-       void *cpucp_info_cpu_addr;
        dma_addr_t cpucp_info_dma_addr;
+       void *cpucp_info_cpu_addr;
+       char *kernel_ver;
        u64 result;
        int rc;
 
@@ -621,6 +652,12 @@ int hl_fw_cpucp_info_get(struct hl_device *hdev,
                goto out;
        }
 
+       kernel_ver = extract_fw_ver_from_str(prop->cpucp_info.kernel_version);
+       if (kernel_ver) {
+               dev_info(hdev->dev, "Linux version %s", kernel_ver);
+               kfree(kernel_ver);
+       }
+
        /* assume EQ code doesn't need to check eqe index */
        hdev->event_queue.check_eqe_index = false;
 
@@ -1066,24 +1103,26 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev,
 static int hl_fw_static_read_device_fw_version(struct hl_device *hdev,
                                        enum hl_fw_component fwc)
 {
+       struct asic_fixed_properties *prop = &hdev->asic_prop;
        struct fw_load_mgr *fw_loader = &hdev->fw_loader;
        struct static_fw_load_mgr *static_loader;
-       const char *name;
+       char *dest, *boot_ver, *preboot_ver;
        u32 ver_off, limit;
-       char *dest;
+       const char *name;
+       char btl_ver[32];
 
        static_loader = &hdev->fw_loader.static_loader;
 
        switch (fwc) {
        case FW_COMP_BOOT_FIT:
                ver_off = RREG32(static_loader->boot_fit_version_offset_reg);
-               dest = hdev->asic_prop.uboot_ver;
+               dest = prop->uboot_ver;
                name = "Boot-fit";
                limit = static_loader->boot_fit_version_max_off;
                break;
        case FW_COMP_PREBOOT:
                ver_off = RREG32(static_loader->preboot_version_offset_reg);
-               dest = hdev->asic_prop.preboot_ver;
+               dest = prop->preboot_ver;
                name = "Preboot";
                limit = static_loader->preboot_version_max_off;
                break;
@@ -1105,6 +1144,30 @@ static int hl_fw_static_read_device_fw_version(struct hl_device *hdev,
                return -EIO;
        }
 
+       if (fwc == FW_COMP_BOOT_FIT) {
+               boot_ver = extract_fw_ver_from_str(prop->uboot_ver);
+               if (boot_ver) {
+                       dev_info(hdev->dev, "boot-fit version %s\n", boot_ver);
+                       kfree(boot_ver);
+               }
+       } else if (fwc == FW_COMP_PREBOOT) {
+               preboot_ver = strnstr(prop->preboot_ver, "Preboot",
+                                               VERSION_MAX_LEN);
+               if (preboot_ver && preboot_ver != prop->preboot_ver) {
+                       strscpy(btl_ver, prop->preboot_ver,
+                               min((int) (preboot_ver - prop->preboot_ver),
+                                                                       31));
+                       dev_info(hdev->dev, "%s\n", btl_ver);
+               }
+
+               preboot_ver = extract_fw_ver_from_str(prop->preboot_ver);
+               if (preboot_ver) {
+                       dev_info(hdev->dev, "preboot version %s\n",
+                                                               preboot_ver);
+                       kfree(preboot_ver);
+               }
+       }
+
        return 0;
 }
 
@@ -1691,21 +1754,43 @@ static void hl_fw_dynamic_read_device_fw_version(struct hl_device *hdev,
                                        enum hl_fw_component fwc,
                                        const char *fw_version)
 {
-       char *dest;
+       struct asic_fixed_properties *prop = &hdev->asic_prop;
+       char *preboot_ver, *boot_ver;
+       char btl_ver[32];
 
        switch (fwc) {
        case FW_COMP_BOOT_FIT:
-               dest = hdev->asic_prop.uboot_ver;
+               strscpy(prop->uboot_ver, fw_version, VERSION_MAX_LEN);
+               boot_ver = extract_fw_ver_from_str(prop->uboot_ver);
+               if (boot_ver) {
+                       dev_info(hdev->dev, "boot-fit version %s\n", boot_ver);
+                       kfree(boot_ver);
+               }
+
                break;
        case FW_COMP_PREBOOT:
-               dest = hdev->asic_prop.preboot_ver;
+               strscpy(prop->preboot_ver, fw_version, VERSION_MAX_LEN);
+               preboot_ver = strnstr(prop->preboot_ver, "Preboot",
+                                               VERSION_MAX_LEN);
+               if (preboot_ver && preboot_ver != prop->preboot_ver) {
+                       strscpy(btl_ver, prop->preboot_ver,
+                               min((int) (preboot_ver - prop->preboot_ver),
+                                                                       31));
+                       dev_info(hdev->dev, "%s\n", btl_ver);
+               }
+
+               preboot_ver = extract_fw_ver_from_str(prop->preboot_ver);
+               if (preboot_ver) {
+                       dev_info(hdev->dev, "preboot version %s\n",
+                                                               preboot_ver);
+                       kfree(preboot_ver);
+               }
+
                break;
        default:
                dev_warn(hdev->dev, "Undefined FW component: %d\n", fwc);
                return;
        }
-
-       strscpy(dest, fw_version, VERSION_MAX_LEN);
 }
 
 /**