habanalabs/gaudi: skip iATU if F/W security is enabled
authorOfir Bitton <obitton@habana.ai>
Wed, 10 Mar 2021 13:08:44 +0000 (15:08 +0200)
committerOded Gabbay <ogabbay@kernel.org>
Fri, 9 Apr 2021 11:09:25 +0000 (14:09 +0300)
As part of the securing GAUDI, the F/W will configure the PCI iATU
regions. If the driver identifies a secured PCI ID, it will know to
skip iATU configuration in a very early stage.

Signed-off-by: Ofir Bitton <obitton@habana.ai>
Reviewed-by: Oded Gabbay <ogabbay@kernel.org>
Signed-off-by: Oded Gabbay <ogabbay@kernel.org>
drivers/misc/habanalabs/common/habanalabs.h
drivers/misc/habanalabs/common/pci/pci.c
drivers/misc/habanalabs/gaudi/gaudi.c
drivers/misc/habanalabs/goya/goya.c

index c1b46126c5222d426f233d935d5aeb5e126b50c3..44e89da30b4a70040488c2d838755b62275aa44f 100644 (file)
@@ -445,6 +445,7 @@ struct hl_mmu_properties {
  * @dram_supports_virtual_memory: is there an MMU towards the DRAM
  * @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.
  */
 struct asic_fixed_properties {
        struct hw_queue_properties      *hw_queues_props;
@@ -508,6 +509,7 @@ struct asic_fixed_properties {
        u8                              dram_supports_virtual_memory;
        u8                              hard_reset_done_by_fw;
        u8                              num_functional_hbms;
+       u8                              iatu_done_by_fw;
 };
 
 /**
@@ -2400,6 +2402,7 @@ int hl_fw_read_preboot_status(struct hl_device *hdev, u32 cpu_boot_status_reg,
 
 int hl_pci_bars_map(struct hl_device *hdev, const char * const name[3],
                        bool is_wc[3]);
+int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data);
 int hl_pci_iatu_write(struct hl_device *hdev, u32 addr, u32 data);
 int hl_pci_set_inbound_region(struct hl_device *hdev, u8 region,
                struct hl_inbound_pci_region *pci_region);
index b799f9258fb014e5a46f36539c8ded2e9aa40825..e941b7eef346d4d6620db0e510fc45a649adfeb6 100644 (file)
@@ -85,6 +85,58 @@ static void hl_pci_bars_unmap(struct hl_device *hdev)
        pci_release_regions(pdev);
 }
 
+int hl_pci_elbi_read(struct hl_device *hdev, u64 addr, u32 *data)
+{
+       struct pci_dev *pdev = hdev->pdev;
+       ktime_t timeout;
+       u64 msec;
+       u32 val;
+
+       if (hdev->pldm)
+               msec = HL_PLDM_PCI_ELBI_TIMEOUT_MSEC;
+       else
+               msec = HL_PCI_ELBI_TIMEOUT_MSEC;
+
+       /* Clear previous status */
+       pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, 0);
+
+       pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_ADDR, (u32) addr);
+       pci_write_config_dword(pdev, mmPCI_CONFIG_ELBI_CTRL, 0);
+
+       timeout = ktime_add_ms(ktime_get(), msec);
+       for (;;) {
+               pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS, &val);
+               if (val & PCI_CONFIG_ELBI_STS_MASK)
+                       break;
+               if (ktime_compare(ktime_get(), timeout) > 0) {
+                       pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_STS,
+                                               &val);
+                       break;
+               }
+
+               usleep_range(300, 500);
+       }
+
+       if ((val & PCI_CONFIG_ELBI_STS_MASK) == PCI_CONFIG_ELBI_STS_DONE) {
+               pci_read_config_dword(pdev, mmPCI_CONFIG_ELBI_DATA, data);
+
+               return 0;
+       }
+
+       if (val & PCI_CONFIG_ELBI_STS_ERR) {
+               dev_err(hdev->dev, "Error reading from ELBI\n");
+               return -EIO;
+       }
+
+       if (!(val & PCI_CONFIG_ELBI_STS_MASK)) {
+               dev_err(hdev->dev, "ELBI read didn't finish in time\n");
+               return -EIO;
+       }
+
+       dev_err(hdev->dev, "ELBI read has undefined bits in status\n");
+       return -EIO;
+}
+
 /**
  * hl_pci_elbi_write() - Write through the ELBI interface.
  * @hdev: Pointer to hl_device structure.
index 841748392e496dc2b441276abc82bbe55dbf3afa..8730b691ec612c111118e1a3252d26f073ad8b3f 100644 (file)
@@ -629,6 +629,11 @@ static int gaudi_init_iatu(struct hl_device *hdev)
        struct hl_outbound_pci_region outbound_region;
        int rc;
 
+       if (hdev->asic_prop.iatu_done_by_fw) {
+               hdev->asic_funcs->set_dma_mask_from_fw(hdev);
+               return 0;
+       }
+
        /* Inbound Region 0 - Bar 0 - Point to SRAM + CFG */
        inbound_region.mode = PCI_BAR_MATCH_MODE;
        inbound_region.bar = SRAM_BAR_ID;
@@ -673,6 +678,7 @@ static int gaudi_early_init(struct hl_device *hdev)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
        struct pci_dev *pdev = hdev->pdev;
+       u32 fw_boot_status;
        int rc;
 
        rc = gaudi_get_fixed_properties(hdev);
@@ -706,6 +712,23 @@ static int gaudi_early_init(struct hl_device *hdev)
 
        prop->dram_pci_bar_size = pci_resource_len(pdev, HBM_BAR_ID);
 
+       /* If FW security is enabled at this point it means no access to ELBI */
+       if (!hdev->asic_prop.fw_security_disabled) {
+               hdev->asic_prop.iatu_done_by_fw = true;
+               goto pci_init;
+       }
+
+       rc = hl_pci_elbi_read(hdev, CFG_BASE + mmCPU_BOOT_DEV_STS0,
+                               &fw_boot_status);
+       if (rc)
+               goto free_queue_props;
+
+       /* Check whether FW is configuring iATU */
+       if ((fw_boot_status & CPU_BOOT_DEV_STS0_ENABLED) &&
+                       (fw_boot_status & CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN))
+               hdev->asic_prop.iatu_done_by_fw = true;
+
+pci_init:
        rc = hl_pci_init(hdev);
        if (rc)
                goto free_queue_props;
index 44dd4d8d88225cbb4d214205296a7e8d0aaafea8..e27338f4aad2f68afebc1d736ea2014d7e5231e7 100644 (file)
@@ -555,6 +555,11 @@ static int goya_init_iatu(struct hl_device *hdev)
        struct hl_outbound_pci_region outbound_region;
        int rc;
 
+       if (hdev->asic_prop.iatu_done_by_fw) {
+               hdev->asic_funcs->set_dma_mask_from_fw(hdev);
+               return 0;
+       }
+
        /* Inbound Region 0 - Bar 0 - Point to SRAM and CFG */
        inbound_region.mode = PCI_BAR_MATCH_MODE;
        inbound_region.bar = SRAM_CFG_BAR_ID;
@@ -602,7 +607,7 @@ static int goya_early_init(struct hl_device *hdev)
 {
        struct asic_fixed_properties *prop = &hdev->asic_prop;
        struct pci_dev *pdev = hdev->pdev;
-       u32 val;
+       u32 fw_boot_status, val;
        int rc;
 
        rc = goya_get_fixed_properties(hdev);
@@ -636,6 +641,23 @@ static int goya_early_init(struct hl_device *hdev)
 
        prop->dram_pci_bar_size = pci_resource_len(pdev, DDR_BAR_ID);
 
+       /* If FW security is enabled at this point it means no access to ELBI */
+       if (!hdev->asic_prop.fw_security_disabled) {
+               hdev->asic_prop.iatu_done_by_fw = true;
+               goto pci_init;
+       }
+
+       rc = hl_pci_elbi_read(hdev, CFG_BASE + mmCPU_BOOT_DEV_STS0,
+                               &fw_boot_status);
+       if (rc)
+               goto free_queue_props;
+
+       /* Check whether FW is configuring iATU */
+       if ((fw_boot_status & CPU_BOOT_DEV_STS0_ENABLED) &&
+                       (fw_boot_status & CPU_BOOT_DEV_STS0_FW_IATU_CONF_EN))
+               hdev->asic_prop.iatu_done_by_fw = true;
+
+pci_init:
        rc = hl_pci_init(hdev);
        if (rc)
                goto free_queue_props;