habanalabs: prepare preboot stage to dynamic f/w load
authorOhad Sharabi <osharabi@habana.ai>
Thu, 25 Mar 2021 08:06:26 +0000 (10:06 +0200)
committerOded Gabbay <ogabbay@kernel.org>
Fri, 18 Jun 2021 12:23:38 +0000 (15:23 +0300)
Start the skeleton for the dynamic F/W load by marking current preboot
code path as legacy.

Signed-off-by: Ohad Sharabi <osharabi@habana.ai>
Reviewed-by: Oded Gabbay <ogabbay@kernel.org>
Signed-off-by: Oded Gabbay <ogabbay@kernel.org>
drivers/misc/habanalabs/common/firmware_if.c
drivers/misc/habanalabs/common/habanalabs.h

index 0713b2c12d54f4fded7b38bf79538c02e1f0fe1e..a45aea4730cfe48c36499e39d00fe6e6df79ddf1 100644 (file)
@@ -809,21 +809,15 @@ static void detect_cpu_boot_status(struct hl_device *hdev, u32 status)
        }
 }
 
-int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
-               u32 cpu_security_boot_status_reg, u32 boot_err0_reg,
-               u32 timeout)
+static int hl_fw_read_preboot_caps(struct hl_device *hdev,
+                                       u32 cpu_boot_status_reg,
+                                       u32 cpu_boot_caps_reg,
+                                       u32 boot_err0_reg, u32 timeout)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
-       u32 status, security_status;
+       u32 status;
        int rc;
 
-       /* pldm was added for cases in which we use preboot on pldm and want
-        * to load boot fit, but we can't wait for preboot because it runs
-        * very slowly
-        */
-       if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU) || hdev->pldm)
-               return 0;
-
        /* Need to check two possible scenarios:
         *
         * CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT - for newer firmwares where
@@ -846,7 +840,7 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
                timeout);
 
        if (rc) {
-               dev_err(hdev->dev, "Failed to read preboot version\n");
+               dev_err(hdev->dev, "CPU boot ready status timeout\n");
                detect_cpu_boot_status(hdev, status);
 
                /* If we read all FF, then something is totally wrong, no point
@@ -854,15 +848,39 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
                 */
                if (status != -1)
                        fw_read_errors(hdev, boot_err0_reg,
-                                       cpu_security_boot_status_reg);
+                                       cpu_boot_status_reg);
                return -EIO;
        }
 
+       prop->fw_preboot_caps_map = RREG32(cpu_boot_caps_reg);
+
+       /*
+        * For now- force dynamic_fw_load to false as LKD does not yet
+        * implements all necessary parts of it.
+        * TODO: once dynamic load is ready set to:
+        * prop->dynamic_fw_load = !!(prop->fw_preboot_caps_map &
+        *                                CPU_BOOT_DEV_STS0_FW_LD_COM_EN)
+        */
+       prop->dynamic_fw_load = 0;
+
+       dev_dbg(hdev->dev, "Attempting %s FW load\n",
+                       prop->dynamic_fw_load ? "dynamic" : "legacy");
+       return 0;
+}
+
+static int hl_fw_read_preboot_status_legacy(struct hl_device *hdev,
+               u32 cpu_boot_status_reg, u32 cpu_security_boot_status_reg,
+               u32 boot_err0_reg, u32 timeout)
+{
+       struct asic_fixed_properties *prop = &hdev->asic_prop;
+       u32 security_status;
+       int rc;
+
        rc = hdev->asic_funcs->read_device_fw_version(hdev, FW_COMP_PREBOOT);
        if (rc)
                return rc;
 
-       security_status = RREG32(cpu_security_boot_status_reg);
+       security_status = prop->fw_preboot_caps_map;
 
        /* We read security status multiple times during boot:
         * 1. preboot - a. Check whether the security status bits are valid
@@ -904,6 +922,38 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
        return 0;
 }
 
+int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
+               u32 cpu_boot_caps_reg, u32 boot_err0_reg,
+               u32 timeout)
+{
+       int rc;
+
+       /* pldm was added for cases in which we use preboot on pldm and want
+        * to load boot fit, but we can't wait for preboot because it runs
+        * very slowly
+        */
+       if (!(hdev->fw_components & FW_TYPE_PREBOOT_CPU) || hdev->pldm)
+               return 0;
+
+       /*
+        * In order to determine boot method (static VS dymanic) we need to
+        * read the boot caps register
+        */
+       rc = hl_fw_read_preboot_caps(hdev, cpu_boot_status_reg,
+                               cpu_boot_caps_reg, boot_err0_reg,
+                               timeout);
+       if (rc)
+               return rc;
+
+       if (!hdev->asic_prop.dynamic_fw_load)
+               return hl_fw_read_preboot_status_legacy(hdev, cpu_boot_status_reg,
+                               cpu_boot_caps_reg, boot_err0_reg,
+                               timeout);
+
+       dev_err(hdev->dev, "Dynamic FW load is not supported\n");
+       return -EINVAL;
+}
+
 int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
                        u32 msg_to_cpu_reg, u32 cpu_msg_status_reg,
                        u32 cpu_security_boot_status_reg, u32 boot_err0_reg,
index 6579f8767abdaccc6edee903449a44541b789815..72726de6575ca91acc3d383bde03734d7bbf96ec 100644 (file)
@@ -420,6 +420,9 @@ struct hl_mmu_properties {
  * @cb_pool_cb_size: size of each CB in the CB pool.
  * @max_pending_cs: maximum of concurrent pending command submissions
  * @max_queues: maximum amount of queues in the system
+ * @fw_preboot_caps_map: bitmap representation of preboot cpu capabilities
+ *                              reported by FW, bit description can be found in
+ *                              CPU_BOOT_DEV_STS*
  * @fw_boot_cpu_security_map: bitmap representation of boot cpu security status
  *                            reported by FW, bit description can be found in
  *                            CPU_BOOT_DEV_STS*
@@ -446,6 +449,7 @@ struct hl_mmu_properties {
  * @hard_reset_done_by_fw: true if firmware is handling hard reset flow
  * @num_functional_hbms: number of functional HBMs in each DCORE.
  * @iatu_done_by_fw: true if iATU configuration is being done by FW.
+ * @dynamic_fw_load: is dynamic FW load is supported.
  */
 struct asic_fixed_properties {
        struct hw_queue_properties      *hw_queues_props;
@@ -491,6 +495,7 @@ struct asic_fixed_properties {
        u32                             cb_pool_cb_size;
        u32                             max_pending_cs;
        u32                             max_queues;
+       u32                             fw_preboot_caps_map;
        u32                             fw_boot_cpu_security_map;
        u32                             fw_app_security_map;
        u16                             collective_first_sob;
@@ -510,6 +515,7 @@ struct asic_fixed_properties {
        u8                              hard_reset_done_by_fw;
        u8                              num_functional_hbms;
        u8                              iatu_done_by_fw;
+       u8                              dynamic_fw_load;
 };
 
 /**
@@ -2404,7 +2410,7 @@ int hl_fw_init_cpu(struct hl_device *hdev, u32 cpu_boot_status_reg,
                        u32 cpu_security_boot_status_reg, u32 boot_err0_reg,
                        bool skip_bmc, u32 cpu_timeout, u32 boot_fit_timeout);
 int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
-               u32 cpu_security_boot_status_reg, u32 boot_err0_reg,
+               u32 cpu_boot_caps_reg, u32 boot_err0_reg,
                u32 timeout);
 
 int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3],