#define VTD_PE_GET_SS_LEVEL(pe) \
(2 + (((pe)->val[0] >> 2) & VTD_SM_PASID_ENTRY_AW))
-/*
- * PCI bus number (or SID) is not reliable since the device is usaully
- * initialized before guest can configure the PCI bridge
- * (SECONDARY_BUS_NUMBER).
- */
-struct vtd_as_key {
- PCIBus *bus;
- uint8_t devfn;
- uint32_t pasid;
-};
-
/* bus/devfn is PCI device's real BDF not the aliased one */
struct vtd_hiod_key {
PCIBus *bus;
/* Return whether the device is using IOMMU translation. */
static bool vtd_switch_address_space(VTDAddressSpace *as)
{
+ IntelIOMMUState *s;
bool use_iommu, pt;
assert(as);
- use_iommu = as->iommu_state->dmar_enabled && !vtd_as_pt_enabled(as);
- pt = as->iommu_state->dmar_enabled && vtd_as_pt_enabled(as);
+ s = as->iommu_state;
+ use_iommu = s->dmar_enabled && !vtd_as_pt_enabled(as);
+ pt = s->dmar_enabled && vtd_as_pt_enabled(as);
+
+ /*
+ * When guest enables scalable mode and sets up first stage page table,
+ * we stick to system MR for IOMMUFD backed host device. Then its
+ * default hwpt contains GPA->HPA mappings which is used directly if
+ * PGTT=PT and used as nesting parent if PGTT=FST. Otherwise fall back
+ * to original processing.
+ */
+ if (s->root_scalable && s->fsts && vtd_find_hiod_iommufd(as)) {
+ use_iommu = false;
+ }
trace_vtd_switch_address_space(pci_bus_num(as->bus),
VTD_PCI_SLOT(as->devfn),
"host IOMMU is incompatible with guest first stage translation");
return false;
}
+
+VTDHostIOMMUDevice *vtd_find_hiod_iommufd(VTDAddressSpace *as)
+{
+ IntelIOMMUState *s = as->iommu_state;
+ struct vtd_as_key key = {
+ .bus = as->bus,
+ .devfn = as->devfn,
+ };
+ VTDHostIOMMUDevice *vtd_hiod = g_hash_table_lookup(s->vtd_host_iommu_dev,
+ &key);
+
+ if (vtd_hiod && vtd_hiod->hiod &&
+ object_dynamic_cast(OBJECT(vtd_hiod->hiod),
+ TYPE_HOST_IOMMU_DEVICE_IOMMUFD)) {
+ return vtd_hiod;
+ }
+ return NULL;
+}
#ifdef CONFIG_VTD_ACCEL
bool vtd_check_hiod_accel(IntelIOMMUState *s, VTDHostIOMMUDevice *vtd_hiod,
Error **errp);
+VTDHostIOMMUDevice *vtd_find_hiod_iommufd(VTDAddressSpace *as);
#else
static inline bool vtd_check_hiod_accel(IntelIOMMUState *s,
VTDHostIOMMUDevice *vtd_hiod,
error_append_hint(errp, "CONFIG_VTD_ACCEL is not enabled");
return false;
}
+
+static inline VTDHostIOMMUDevice *vtd_find_hiod_iommufd(VTDAddressSpace *as)
+{
+ return NULL;
+}
#endif
#endif