* Ignore CRAT table during KFD initialization. By default, KFD uses the ACPI CRAT
  * table to get information about AMD APUs. This option can serve as a workaround on
  * systems with a broken CRAT table.
+ *
+ * Default is auto (according to asic type, iommu_v2, and crat table, to decide
+ * whehter use CRAT)
  */
 int ignore_crat;
 module_param(ignore_crat, int, 0444);
 MODULE_PARM_DESC(ignore_crat,
-       "Ignore CRAT table during KFD initialization (0 = use CRAT (default), 1 = ignore CRAT)");
+       "Ignore CRAT table during KFD initialization (0 = auto (default), 1 = ignore CRAT)");
 
 /**
  * DOC: halt_if_hws_hang (int)
 
                return true;
        }
 
-       if (dev->device_info->needs_iommu_device)
+       if (dev->use_iommu_v2)
                return false;
 
        amdgpu_amdkfd_get_local_mem_info(dev->kgd, &mem_info);
 
        return 0;
 }
 
+static bool kfd_ignore_crat(void)
+{
+       bool ret;
+
+       if (ignore_crat)
+               return true;
+
+#ifndef KFD_SUPPORT_IOMMU_V2
+       ret = true;
+#else
+       ret = false;
+#endif
+
+       return ret;
+}
+
 /*
  * kfd_create_crat_image_acpi - Allocates memory for CRAT image and
  * copies CRAT from ACPI (if available).
                return -EINVAL;
        }
 
-       if (ignore_crat) {
+       if (kfd_ignore_crat()) {
                pr_info("CRAT table disabled by module option\n");
                return -ENODATA;
        }
 
        .num_xgmi_sdma_engines = 0,
        .num_sdma_queues_per_engine = 2,
 };
+#endif
 
 static const struct kfd_device_info raven_device_info = {
        .asic_family = CHIP_RAVEN,
        .num_xgmi_sdma_engines = 0,
        .num_sdma_queues_per_engine = 2,
 };
-#endif
 
 static const struct kfd_device_info hawaii_device_info = {
        .asic_family = CHIP_HAWAII,
                goto gws_error;
        }
 
+       /* If CRAT is broken, won't set iommu enabled */
+       kfd_double_confirm_iommu_support(kfd);
+
        if (kfd_iommu_device_init(kfd)) {
                dev_err(kfd_device, "Error initializing iommuv2\n");
                goto device_iommu_error;
 
                                SH_MEM_ALIGNMENT_MODE_UNALIGNED <<
                                        SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT;
                if (amdgpu_noretry &&
-                   !dqm->dev->device_info->needs_iommu_device)
+                   !dqm->dev->use_iommu_v2)
                        qpd->sh_mem_config |=
                                1 << SH_MEM_CONFIG__RETRY_DISABLE__SHIFT;
 
 
        pdd->lds_base = MAKE_LDS_APP_BASE_VI();
        pdd->lds_limit = MAKE_LDS_APP_LIMIT(pdd->lds_base);
 
-       if (!pdd->dev->device_info->needs_iommu_device) {
+       if (!pdd->dev->use_iommu_v2) {
                /* dGPUs: SVM aperture starting at 0
                 * with small reserved space for kernel.
                 * Set them to CANONICAL addresses.
                                return -EINVAL;
                        }
 
-                       if (!dev->device_info->needs_iommu_device) {
+                       if (!dev->use_iommu_v2) {
                                /* dGPUs: the reserved space for kernel
                                 * before SVM
                                 */
 
        struct amd_iommu_device_info iommu_info;
        int err;
 
-       if (!kfd->device_info->needs_iommu_device)
+       if (!kfd->use_iommu_v2)
                return -ENODEV;
 
        iommu_info.flags = 0;
        unsigned int pasid_limit;
        int err;
 
-       if (!kfd->device_info->needs_iommu_device)
+       if (!kfd->use_iommu_v2)
                return 0;
 
        iommu_info.flags = 0;
        struct kfd_process *p = pdd->process;
        int err;
 
-       if (!dev->device_info->needs_iommu_device || pdd->bound == PDD_BOUND)
+       if (!dev->use_iommu_v2 || pdd->bound == PDD_BOUND)
                return 0;
 
        if (unlikely(pdd->bound == PDD_BOUND_SUSPENDED)) {
  */
 void kfd_iommu_suspend(struct kfd_dev *kfd)
 {
-       if (!kfd->device_info->needs_iommu_device)
+       if (!kfd->use_iommu_v2)
                return;
 
        kfd_unbind_processes_from_device(kfd);
        unsigned int pasid_limit;
        int err;
 
-       if (!kfd->device_info->needs_iommu_device)
+       if (!kfd->use_iommu_v2)
                return 0;
 
        pasid_limit = kfd_get_pasid_limit();
 
 
        bool pci_atomic_requested;
 
+       /* Use IOMMU v2 flag */
+       bool use_iommu_v2;
+
        /* SRAM ECC flag */
        atomic_t sram_ecc_flag;
 
 struct kfd_dev *kfd_device_by_kgd(const struct kgd_dev *kgd);
 int kfd_topology_enum_kfd_devices(uint8_t idx, struct kfd_dev **kdev);
 int kfd_numa_node_to_apic_id(int numa_node_id);
+void kfd_double_confirm_iommu_support(struct kfd_dev *gpu);
 
 /* Interrupts */
 int kfd_interrupt_init(struct kfd_dev *dev);
 
        sysfs_show_32bit_prop(buffer, offs, "cpu_cores_count",
                              dev->node_props.cpu_cores_count);
        sysfs_show_32bit_prop(buffer, offs, "simd_count",
-                             dev->node_props.simd_count);
+                             dev->gpu ? dev->node_props.simd_count : 0);
        sysfs_show_32bit_prop(buffer, offs, "mem_banks_count",
                              dev->node_props.mem_banks_count);
        sysfs_show_32bit_prop(buffer, offs, "caches_count",
                /* Discrete GPUs need their own topology device list
                 * entries. Don't assign them to CPU/APU nodes.
                 */
-               if (!gpu->device_info->needs_iommu_device &&
+               if (!gpu->use_iommu_v2 &&
                    dev->node_props.cpu_cores_count)
                        continue;
 
        * Overwrite ATS capability according to needs_iommu_device to fix
        * potential missing corresponding bit in CRAT of BIOS.
        */
-       if (dev->gpu->device_info->needs_iommu_device)
+       if (dev->gpu->use_iommu_v2)
                dev->node_props.capability |= HSA_CAP_ATS_PRESENT;
        else
                dev->node_props.capability &= ~HSA_CAP_ATS_PRESENT;
        return kfd_cpumask_to_apic_id(cpumask_of_node(numa_node_id));
 }
 
+void kfd_double_confirm_iommu_support(struct kfd_dev *gpu)
+{
+       struct kfd_topology_device *dev;
+
+       gpu->use_iommu_v2 = false;
+
+       if (!gpu->device_info->needs_iommu_device)
+               return;
+
+       down_read(&topology_lock);
+
+       /* Only use IOMMUv2 if there is an APU topology node with no GPU
+        * assigned yet. This GPU will be assigned to it.
+        */
+       list_for_each_entry(dev, &topology_device_list, list)
+               if (dev->node_props.cpu_cores_count &&
+                   dev->node_props.simd_count &&
+                   !dev->gpu)
+                       gpu->use_iommu_v2 = true;
+
+       up_read(&topology_lock);
+}
+
 #if defined(CONFIG_DEBUG_FS)
 
 int kfd_debugfs_hqds_by_device(struct seq_file *m, void *data)