qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC v2 0/6] Introduce IOMMU Option For PCI Root Bus
@ 2021-03-24 13:16 Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 1/6] hw/pci/pci_host: Add iommu property for pci host Wang Xingang
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Wang Xingang @ 2021-03-24 13:16 UTC (permalink / raw)
  To: qemu-devel, qemu-arm, eric.auger
  Cc: xieyingtai, peter.maydell, cenjiahui, ehabkost, mst,
	richard.henderson, shannon.zhaosl, pbonzini, imammedo,
	wangxingang5

From: Xingang Wang <wangxingang5@huawei.com>

These patches add support for configure iommu on/off for pci root bus,
including primary bus and pxb root bus. At present, All root bus
will go through iommu when iommu is configured, which is not flexible.

So this add option to enable/disable iommu for primary bus and pxb
root bus.  When iommu is enabled for the root bus, devices attached to it
will go through iommu. When iommu is disabled for the root bus, devices
will not go through iommu accordingly.

The option example for iommu configuration is like the following:

primary root bus option:
arm: -machine virt iommu=smmuv3,primary_bus_iommu=false(or true)
x86: -machine q35,primary_bus_iommu=false(or true)

pxb root bus:
-device pxb-pcie,bus_nr=0x10,id=pci.10,bus=pcie.0,addr=0x3.0x1,iommu=false 

History:

v1 -> v2:
- Fix some issues
- Took into account Eric's comments, and remove the PCI_BUS_IOMMU flag,
  replace it with a property in PCIHostState.
- Add support for x86 iommu option

Xingang Wang (6):
  hw/pci/pci_host: Add iommu property for pci host
  hw/pci: Add iommu option for pci root bus
  hw/pci: Add pci_root_bus_max_bus
  hw/arm/virt-acpi-build: Add explicit idmap info in IORT table
  hw/i386/acpi-build: Add explicit scope in DMAR table
  hw/i386/acpi-build: Add iommu filter in IVRS table

 hw/arm/virt-acpi-build.c            | 103 ++++++++++++++++++++++------
 hw/arm/virt.c                       |  25 +++++++
 hw/i386/acpi-build.c                |  70 ++++++++++++++++++-
 hw/i386/pc.c                        |  19 +++++
 hw/pci-bridge/pci_expander_bridge.c |   3 +
 hw/pci-host/q35.c                   |   1 +
 hw/pci/pci.c                        |  52 +++++++++++++-
 hw/pci/pci_host.c                   |   2 +
 include/hw/arm/virt.h               |   1 +
 include/hw/i386/pc.h                |   1 +
 include/hw/pci/pci.h                |   2 +
 include/hw/pci/pci_host.h           |   1 +
 12 files changed, 254 insertions(+), 26 deletions(-)

-- 
2.19.1



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH RFC v2 1/6] hw/pci/pci_host: Add iommu property for pci host
  2021-03-24 13:16 [PATCH RFC v2 0/6] Introduce IOMMU Option For PCI Root Bus Wang Xingang
@ 2021-03-24 13:16 ` Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 2/6] hw/pci: Add iommu option for pci root bus Wang Xingang
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Wang Xingang @ 2021-03-24 13:16 UTC (permalink / raw)
  To: qemu-devel, qemu-arm, eric.auger
  Cc: xieyingtai, peter.maydell, cenjiahui, ehabkost, mst,
	richard.henderson, shannon.zhaosl, pbonzini, imammedo,
	wangxingang5

From: Xingang Wang <wangxingang5@huawei.com>

The pci host iommu property is useful to check whether
the iommu is enabled on the pci root bus.

Signed-off-by: Xingang Wang <wangxingang5@huawei.com>
Signed-off-by: Jiahui Cen <cenjiahui@huawei.com>
---
 hw/pci/pci.c              | 18 +++++++++++++++++-
 hw/pci/pci_host.c         |  2 ++
 include/hw/pci/pci.h      |  1 +
 include/hw/pci/pci_host.h |  1 +
 4 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 0eadcdbc9e..b82f39af10 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -416,6 +416,22 @@ const char *pci_root_bus_path(PCIDevice *dev)
     return rootbus->qbus.name;
 }
 
+bool pci_root_bus_has_iommu(PCIBus *bus)
+{
+    PCIBus *rootbus = bus;
+    PCIHostState *host_bridge;
+
+    if (!pci_bus_is_root(bus)) {
+        rootbus = pci_device_root_bus(bus->parent_dev);
+    }
+
+    host_bridge = PCI_HOST_BRIDGE(rootbus->qbus.parent);
+
+    assert(host_bridge->bus == rootbus);
+
+    return host_bridge->iommu;
+}
+
 static void pci_root_bus_init(PCIBus *bus, DeviceState *parent,
                               MemoryRegion *address_space_mem,
                               MemoryRegion *address_space_io,
@@ -2715,7 +2731,7 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev)
 
         iommu_bus = parent_bus;
     }
-    if (iommu_bus && iommu_bus->iommu_fn) {
+    if (pci_root_bus_has_iommu(bus) && iommu_bus && iommu_bus->iommu_fn) {
         return iommu_bus->iommu_fn(bus, iommu_bus->iommu_opaque, devfn);
     }
     return &address_space_memory;
diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c
index 8ca5fadcbd..92ce213b18 100644
--- a/hw/pci/pci_host.c
+++ b/hw/pci/pci_host.c
@@ -222,6 +222,8 @@ const VMStateDescription vmstate_pcihost = {
 static Property pci_host_properties_common[] = {
     DEFINE_PROP_BOOL("x-config-reg-migration-enabled", PCIHostState,
                      mig_enabled, true),
+    DEFINE_PROP_BOOL("pci-host-iommu-enabled", PCIHostState,
+                     iommu, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 1bc231480f..300332bc2c 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -479,6 +479,7 @@ void pci_for_each_bus(PCIBus *bus,
 
 PCIBus *pci_device_root_bus(const PCIDevice *d);
 const char *pci_root_bus_path(PCIDevice *dev);
+bool pci_root_bus_has_iommu(PCIBus *bus);
 PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn);
 int pci_qdev_find_device(const char *id, PCIDevice **pdev);
 void pci_bus_get_w64_range(PCIBus *bus, Range *range);
diff --git a/include/hw/pci/pci_host.h b/include/hw/pci/pci_host.h
index 52e038c019..64128e3a19 100644
--- a/include/hw/pci/pci_host.h
+++ b/include/hw/pci/pci_host.h
@@ -43,6 +43,7 @@ struct PCIHostState {
     uint32_t config_reg;
     bool mig_enabled;
     PCIBus *bus;
+    bool iommu;
 
     QLIST_ENTRY(PCIHostState) next;
 };
-- 
2.19.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC v2 2/6] hw/pci: Add iommu option for pci root bus
  2021-03-24 13:16 [PATCH RFC v2 0/6] Introduce IOMMU Option For PCI Root Bus Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 1/6] hw/pci/pci_host: Add iommu property for pci host Wang Xingang
@ 2021-03-24 13:16 ` Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 3/6] hw/pci: Add pci_root_bus_max_bus Wang Xingang
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Wang Xingang @ 2021-03-24 13:16 UTC (permalink / raw)
  To: qemu-devel, qemu-arm, eric.auger
  Cc: xieyingtai, peter.maydell, cenjiahui, ehabkost, mst,
	richard.henderson, shannon.zhaosl, pbonzini, imammedo,
	wangxingang5

From: Xingang Wang <wangxingang5@huawei.com>

This add iommu option for pci root bus, including primary bus
and pxb root bus. The option is valid only if there is a virtual
iommu device.

Signed-off-by: Xingang Wang <wangxingang5@huawei.com>
Signed-off-by: Jiahui Cen <cenjiahui@huawei.com>
---
 hw/arm/virt.c                       | 25 +++++++++++++++++++++++++
 hw/i386/pc.c                        | 19 +++++++++++++++++++
 hw/pci-bridge/pci_expander_bridge.c |  3 +++
 hw/pci-host/q35.c                   |  1 +
 include/hw/arm/virt.h               |  1 +
 include/hw/i386/pc.h                |  1 +
 6 files changed, 50 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index aa2bbd14e0..446b3b867f 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1366,6 +1366,7 @@ static void create_pcie(VirtMachineState *vms)
     }
 
     pci = PCI_HOST_BRIDGE(dev);
+    pci->iommu = vms->primary_bus_iommu;
     vms->bus = pci->bus;
     if (vms->bus) {
         for (i = 0; i < nb_nics; i++) {
@@ -2319,6 +2320,20 @@ static void virt_set_iommu(Object *obj, const char *value, Error **errp)
     }
 }
 
+static bool virt_get_primary_bus_iommu(Object *obj, Error **errp)
+{
+    VirtMachineState *vms = VIRT_MACHINE(obj);
+
+    return vms->primary_bus_iommu;
+}
+
+static void virt_set_primary_bus_iommu(Object *obj, bool value, Error **errp)
+{
+    VirtMachineState *vms = VIRT_MACHINE(obj);
+
+    vms->primary_bus_iommu = value;
+}
+
 static CpuInstanceProperties
 virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
 {
@@ -2652,6 +2667,13 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
                                           "Set the IOMMU type. "
                                           "Valid values are none and smmuv3");
 
+    object_class_property_add_bool(oc, "primary_bus_iommu",
+                                  virt_get_primary_bus_iommu,
+                                  virt_set_primary_bus_iommu);
+    object_class_property_set_description(oc, "primary_bus_iommu",
+                                          "Set on/off to enable/disable "
+                                          "iommu for primary bus");
+
     object_class_property_add_bool(oc, "ras", virt_get_ras,
                                    virt_set_ras);
     object_class_property_set_description(oc, "ras",
@@ -2719,6 +2741,9 @@ static void virt_instance_init(Object *obj)
     /* Default disallows iommu instantiation */
     vms->iommu = VIRT_IOMMU_NONE;
 
+    /* The primary bus is attached to iommu by default */
+    vms->primary_bus_iommu = true;
+
     /* Default disallows RAS instantiation */
     vms->ras = false;
 
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 410db9ef96..3426cd9c3f 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1531,6 +1531,21 @@ static void pc_machine_set_hpet(Object *obj, bool value, Error **errp)
     pcms->hpet_enabled = value;
 }
 
+static bool pc_machine_get_primary_bus_iommu(Object *obj, Error **errp)
+{
+    PCMachineState *pcms = PC_MACHINE(obj);
+
+    return pcms->primary_bus_iommu;
+}
+
+static void pc_machine_set_primary_bus_iommu(Object *obj, bool value,
+                                             Error **errp)
+{
+    PCMachineState *pcms = PC_MACHINE(obj);
+
+    pcms->primary_bus_iommu = value;
+}
+
 static void pc_machine_get_max_ram_below_4g(Object *obj, Visitor *v,
                                             const char *name, void *opaque,
                                             Error **errp)
@@ -1675,6 +1690,7 @@ static void pc_machine_initfn(Object *obj)
 #ifdef CONFIG_HPET
     pcms->hpet_enabled = true;
 #endif
+    pcms->primary_bus_iommu = true;
 
     pc_system_flash_create(pcms);
     pcms->pcspk = isa_new(TYPE_PC_SPEAKER);
@@ -1799,6 +1815,9 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
     object_class_property_add_bool(oc, "hpet",
         pc_machine_get_hpet, pc_machine_set_hpet);
 
+    object_class_property_add_bool(oc, "primary_bus_iommu",
+        pc_machine_get_primary_bus_iommu, pc_machine_set_primary_bus_iommu);
+
     object_class_property_add(oc, PC_MACHINE_MAX_FW_SIZE, "size",
         pc_machine_get_max_fw_size, pc_machine_set_max_fw_size,
         NULL, NULL);
diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c
index aedded1064..f1a0eadc03 100644
--- a/hw/pci-bridge/pci_expander_bridge.c
+++ b/hw/pci-bridge/pci_expander_bridge.c
@@ -57,6 +57,7 @@ struct PXBDev {
 
     uint8_t bus_nr;
     uint16_t numa_node;
+    bool iommu;
 };
 
 static PXBDev *convert_to_pxb(PCIDevice *dev)
@@ -255,6 +256,7 @@ static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp)
     bus->map_irq = pxb_map_irq_fn;
 
     PCI_HOST_BRIDGE(ds)->bus = bus;
+    PCI_HOST_BRIDGE(ds)->iommu = pxb->iommu;
 
     pxb_register_bus(dev, bus, &local_err);
     if (local_err) {
@@ -301,6 +303,7 @@ static Property pxb_dev_properties[] = {
     /* Note: 0 is not a legal PXB bus number. */
     DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
     DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED),
+    DEFINE_PROP_BOOL("iommu", PXBDev, iommu, true),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 2eb729dff5..3b23fd0975 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -64,6 +64,7 @@ static void q35_host_realize(DeviceState *dev, Error **errp)
                                 s->mch.address_space_io,
                                 0, TYPE_PCIE_BUS);
     PC_MACHINE(qdev_get_machine())->bus = pci->bus;
+    pci->iommu = PC_MACHINE(qdev_get_machine())->primary_bus_iommu;
     qdev_realize(DEVICE(&s->mch), BUS(pci->bus), &error_fatal);
 }
 
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 921416f918..1fbb19710f 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -147,6 +147,7 @@ struct VirtMachineState {
     OnOffAuto acpi;
     VirtGICType gic_version;
     VirtIOMMUType iommu;
+    bool primary_bus_iommu;
     VirtMSIControllerType msi_controller;
     uint16_t virtio_iommu_bdf;
     struct arm_boot_info bootinfo;
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index d4c3d73c11..61137b3bd8 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -45,6 +45,7 @@ typedef struct PCMachineState {
     bool sata_enabled;
     bool pit_enabled;
     bool hpet_enabled;
+    bool primary_bus_iommu;
     uint64_t max_fw_size;
     char *oem_id;
     char *oem_table_id;
-- 
2.19.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC v2 3/6] hw/pci: Add pci_root_bus_max_bus
  2021-03-24 13:16 [PATCH RFC v2 0/6] Introduce IOMMU Option For PCI Root Bus Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 1/6] hw/pci/pci_host: Add iommu property for pci host Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 2/6] hw/pci: Add iommu option for pci root bus Wang Xingang
@ 2021-03-24 13:16 ` Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 4/6] hw/arm/virt-acpi-build: Add explicit idmap info in IORT table Wang Xingang
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Wang Xingang @ 2021-03-24 13:16 UTC (permalink / raw)
  To: qemu-devel, qemu-arm, eric.auger
  Cc: xieyingtai, peter.maydell, cenjiahui, ehabkost, mst,
	richard.henderson, shannon.zhaosl, pbonzini, imammedo,
	wangxingang5

From: Xingang Wang <wangxingang5@huawei.com>

This helps to find max bus number of a root bus.

Signed-off-by: Xingang Wang <wangxingang5@huawei.com>
Signed-off-by: Jiahui Cen <cenjiahui@huawei.com>
---
 hw/pci/pci.c         | 34 ++++++++++++++++++++++++++++++++++
 include/hw/pci/pci.h |  1 +
 2 files changed, 35 insertions(+)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index b82f39af10..ca26ab7750 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -537,6 +537,40 @@ int pci_bus_num(PCIBus *s)
     return PCI_BUS_GET_CLASS(s)->bus_num(s);
 }
 
+int pci_root_bus_max_bus(PCIBus *bus)
+{
+    PCIHostState *host;
+    PCIDevice *dev;
+    int max_bus = 0;
+    int type, devfn;
+    uint8_t subordinate;
+
+    if (!pci_bus_is_root(bus)) {
+        return 0;
+    }
+
+    host = PCI_HOST_BRIDGE(BUS(bus)->parent);
+    max_bus = pci_bus_num(host->bus);
+
+    for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
+        dev = host->bus->devices[devfn];
+
+        if (!dev) {
+            continue;
+        }
+
+        type = dev->config[PCI_HEADER_TYPE] & ~PCI_HEADER_TYPE_MULTI_FUNCTION;
+        if (type == PCI_HEADER_TYPE_BRIDGE) {
+            subordinate = dev->config[PCI_SUBORDINATE_BUS];
+            if (subordinate > max_bus) {
+                max_bus = subordinate;
+            }
+        }
+    }
+
+    return max_bus;
+}
+
 int pci_bus_numa_node(PCIBus *bus)
 {
     return PCI_BUS_GET_CLASS(bus)->numa_node(bus);
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index 300332bc2c..96adf0220a 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -449,6 +449,7 @@ static inline PCIBus *pci_get_bus(const PCIDevice *dev)
     return PCI_BUS(qdev_get_parent_bus(DEVICE(dev)));
 }
 int pci_bus_num(PCIBus *s);
+int pci_root_bus_max_bus(PCIBus *bus);
 static inline int pci_dev_bus_num(const PCIDevice *dev)
 {
     return pci_bus_num(pci_get_bus(dev));
-- 
2.19.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC v2 4/6] hw/arm/virt-acpi-build: Add explicit idmap info in IORT table
  2021-03-24 13:16 [PATCH RFC v2 0/6] Introduce IOMMU Option For PCI Root Bus Wang Xingang
                   ` (2 preceding siblings ...)
  2021-03-24 13:16 ` [PATCH RFC v2 3/6] hw/pci: Add pci_root_bus_max_bus Wang Xingang
@ 2021-03-24 13:16 ` Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 5/6] hw/i386/acpi-build: Add explicit scope in DMAR table Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 6/6] hw/i386/acpi-build: Add iommu filter in IVRS table Wang Xingang
  5 siblings, 0 replies; 7+ messages in thread
From: Wang Xingang @ 2021-03-24 13:16 UTC (permalink / raw)
  To: qemu-devel, qemu-arm, eric.auger
  Cc: xieyingtai, peter.maydell, cenjiahui, ehabkost, mst,
	richard.henderson, shannon.zhaosl, pbonzini, imammedo,
	wangxingang5

From: Xingang Wang <wangxingang5@huawei.com>

The idmap of smmuv3 and root complex covers the whole RID space for now,
this patch add explicit idmap info according to root bus number range.
This add smmuv3 idmap for certain bus which has enabled the iommu property.

Signed-off-by: Xingang Wang <wangxingang5@huawei.com>
Signed-off-by: Jiahui Cen <cenjiahui@huawei.com>
---
 hw/arm/virt-acpi-build.c | 103 ++++++++++++++++++++++++++++++---------
 1 file changed, 81 insertions(+), 22 deletions(-)

diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index f9c9df916c..e4a1ac3678 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -44,6 +44,7 @@
 #include "hw/acpi/tpm.h"
 #include "hw/pci/pcie_host.h"
 #include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
 #include "hw/pci-host/gpex.h"
 #include "hw/arm/virt.h"
 #include "hw/mem/nvdimm.h"
@@ -237,6 +238,41 @@ static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms)
     aml_append(scope, dev);
 }
 
+typedef
+struct AcpiIortMapping {
+    AcpiIortIdMapping idmap;
+    bool iommu;
+} AcpiIortMapping;
+
+/* For all PCI host bridges, walk and insert DMAR scope */
+static int
+iort_host_bridges(Object *obj, void *opaque)
+{
+    GArray *map_blob = opaque;
+    AcpiIortMapping map;
+    AcpiIortIdMapping *idmap = &map.idmap;
+    int bus_num, max_bus;
+
+    if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
+        PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
+
+        if (bus) {
+            bus_num = pci_bus_num(bus);
+            max_bus = pci_root_bus_max_bus(bus);
+
+            idmap->input_base = cpu_to_le32(bus_num << 8);
+            idmap->id_count = cpu_to_le32((max_bus - bus_num + 1) << 8);
+            idmap->output_base = cpu_to_le32(bus_num << 8);
+            idmap->flags = cpu_to_le32(0);
+
+            map.iommu = pci_root_bus_has_iommu(bus);
+            g_array_append_val(map_blob, map);
+        }
+    }
+
+    return 0;
+}
+
 static void
 build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 {
@@ -247,6 +283,21 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
     AcpiIortSmmu3 *smmu;
     size_t node_size, iort_node_offset, iort_length, smmu_offset = 0;
     AcpiIortRC *rc;
+    int smmu_mapping_count;
+    GArray *map_blob = g_array_new(false, true, sizeof(AcpiIortMapping));
+    AcpiIortMapping *map;
+
+    /* pci_for_each_bus(vms->bus, insert_map, map_blob); */
+    object_child_foreach_recursive(object_get_root(),
+                                   iort_host_bridges, map_blob);
+
+    smmu_mapping_count = 0;
+    for (int i = 0; i < map_blob->len; i++) {
+        map = &g_array_index(map_blob, AcpiIortMapping, i);
+        if (map->iommu) {
+            smmu_mapping_count++;
+        }
+    }
 
     iort = acpi_data_push(table_data, sizeof(*iort));
 
@@ -280,13 +331,13 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 
         /* SMMUv3 node */
         smmu_offset = iort_node_offset + node_size;
-        node_size = sizeof(*smmu) + sizeof(*idmap);
+        node_size = sizeof(*smmu) + sizeof(*idmap) * smmu_mapping_count;
         iort_length += node_size;
         smmu = acpi_data_push(table_data, node_size);
 
         smmu->type = ACPI_IORT_NODE_SMMU_V3;
         smmu->length = cpu_to_le16(node_size);
-        smmu->mapping_count = cpu_to_le32(1);
+        smmu->mapping_count = cpu_to_le32(smmu_mapping_count);
         smmu->mapping_offset = cpu_to_le32(sizeof(*smmu));
         smmu->base_address = cpu_to_le64(vms->memmap[VIRT_SMMU].base);
         smmu->flags = cpu_to_le32(ACPI_IORT_SMMU_V3_COHACC_OVERRIDE);
@@ -295,23 +346,28 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
         smmu->gerr_gsiv = cpu_to_le32(irq + 2);
         smmu->sync_gsiv = cpu_to_le32(irq + 3);
 
-        /* Identity RID mapping covering the whole input RID range */
-        idmap = &smmu->id_mapping_array[0];
-        idmap->input_base = 0;
-        idmap->id_count = cpu_to_le32(0xFFFF);
-        idmap->output_base = 0;
-        /* output IORT node is the ITS group node (the first node) */
-        idmap->output_reference = cpu_to_le32(iort_node_offset);
+        for (int i = 0, j = 0; i < map_blob->len; i++) {
+            map = &g_array_index(map_blob, AcpiIortMapping, i);
+
+            if (!map->iommu) {
+                continue;
+            }
+
+            idmap = &smmu->id_mapping_array[j++];
+            *idmap = map->idmap;
+            /* output IORT node is the ITS group node (the first node) */
+            idmap->output_reference = cpu_to_le32(iort_node_offset);
+        }
     }
 
     /* Root Complex Node */
-    node_size = sizeof(*rc) + sizeof(*idmap);
+    node_size = sizeof(*rc) + sizeof(*idmap) * map_blob->len;
     iort_length += node_size;
     rc = acpi_data_push(table_data, node_size);
 
     rc->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX;
     rc->length = cpu_to_le16(node_size);
-    rc->mapping_count = cpu_to_le32(1);
+    rc->mapping_count = cpu_to_le32(map_blob->len);
     rc->mapping_offset = cpu_to_le32(sizeof(*rc));
 
     /* fully coherent device */
@@ -319,20 +375,23 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
     rc->memory_properties.memory_flags = 0x3; /* CCA = CPM = DCAS = 1 */
     rc->pci_segment_number = 0; /* MCFG pci_segment */
 
-    /* Identity RID mapping covering the whole input RID range */
-    idmap = &rc->id_mapping_array[0];
-    idmap->input_base = 0;
-    idmap->id_count = cpu_to_le32(0xFFFF);
-    idmap->output_base = 0;
+    for (int i = 0; i < map_blob->len; i++) {
+        map = &g_array_index(map_blob, AcpiIortMapping, i);
+        idmap = &rc->id_mapping_array[i];
 
-    if (vms->iommu == VIRT_IOMMU_SMMUV3) {
-        /* output IORT node is the smmuv3 node */
-        idmap->output_reference = cpu_to_le32(smmu_offset);
-    } else {
-        /* output IORT node is the ITS group node (the first node) */
-        idmap->output_reference = cpu_to_le32(iort_node_offset);
+        *idmap = map->idmap;
+
+        if (vms->iommu == VIRT_IOMMU_SMMUV3 && map->iommu) {
+            /* output IORT node is the smmuv3 node */
+            idmap->output_reference = cpu_to_le32(smmu_offset);
+        } else {
+            /* output IORT node is the ITS group node (the first node) */
+            idmap->output_reference = cpu_to_le32(iort_node_offset);
+        }
     }
 
+    g_array_free(map_blob, true);
+
     /*
      * Update the pointer address in case table_data->data moves during above
      * acpi_data_push operations.
-- 
2.19.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC v2 5/6] hw/i386/acpi-build: Add explicit scope in DMAR table
  2021-03-24 13:16 [PATCH RFC v2 0/6] Introduce IOMMU Option For PCI Root Bus Wang Xingang
                   ` (3 preceding siblings ...)
  2021-03-24 13:16 ` [PATCH RFC v2 4/6] hw/arm/virt-acpi-build: Add explicit idmap info in IORT table Wang Xingang
@ 2021-03-24 13:16 ` Wang Xingang
  2021-03-24 13:16 ` [PATCH RFC v2 6/6] hw/i386/acpi-build: Add iommu filter in IVRS table Wang Xingang
  5 siblings, 0 replies; 7+ messages in thread
From: Wang Xingang @ 2021-03-24 13:16 UTC (permalink / raw)
  To: qemu-devel, qemu-arm, eric.auger
  Cc: xieyingtai, peter.maydell, cenjiahui, ehabkost, mst,
	richard.henderson, shannon.zhaosl, pbonzini, imammedo,
	wangxingang5

From: Xingang Wang <wangxingang5@huawei.com>

In DMAR table, the drhd is set to cover all pci devices when intel_iommu
is on. This patch add explicit scope data, including only the pci devices
that go through iommu.

Signed-off-by: Xingang Wang <wangxingang5@huawei.com>
Signed-off-by: Jiahui Cen <cenjiahui@huawei.com>
---
 hw/i386/acpi-build.c | 68 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 2 deletions(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 442b4629a9..7729c96489 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -1878,6 +1878,56 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
                  pcms->oem_table_id);
 }
 
+/*
+ * Insert DMAR scope for PCI bridges and endpoint devcie
+ */
+static void
+insert_scope(PCIBus *bus, PCIDevice *dev, void *opaque)
+{
+    GArray *scope_blob = opaque;
+    AcpiDmarDeviceScope *scope = NULL;
+
+    if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
+        /* Dmar Scope Type: 0x02 for PCI Bridge */
+        build_append_int_noprefix(scope_blob, 0x02, 1);
+    } else {
+        /* Dmar Scope Type: 0x01 for PCI Endpoint Device */
+        build_append_int_noprefix(scope_blob, 0x01, 1);
+    }
+
+    /* length */
+    build_append_int_noprefix(scope_blob,
+                              sizeof(*scope) + sizeof(scope->path[0]), 1);
+    /* reserved */
+    build_append_int_noprefix(scope_blob, 0, 2);
+    /* enumeration_id */
+    build_append_int_noprefix(scope_blob, 0, 1);
+    /* bus */
+    build_append_int_noprefix(scope_blob, pci_bus_num(bus), 1);
+    /* device */
+    build_append_int_noprefix(scope_blob, PCI_SLOT(dev->devfn), 1);
+    /* function */
+    build_append_int_noprefix(scope_blob, PCI_FUNC(dev->devfn), 1);
+}
+
+/* For all PCI host bridges, walk and insert DMAR scope */
+static int
+dmar_host_bridges(Object *obj, void *opaque)
+{
+    GArray *scope_blob = opaque;
+
+    if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
+        PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
+
+        if (bus && pci_root_bus_has_iommu(bus)) {
+            pci_for_each_device(bus, pci_bus_num(bus), insert_scope,
+                                scope_blob);
+        }
+    }
+
+    return 0;
+}
+
 /*
  * VT-d spec 8.1 DMA Remapping Reporting Structure
  * (version Oct. 2014 or later)
@@ -1897,6 +1947,15 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id,
     /* Root complex IOAPIC use one path[0] only */
     size_t ioapic_scope_size = sizeof(*scope) + sizeof(scope->path[0]);
     IntelIOMMUState *intel_iommu = INTEL_IOMMU_DEVICE(iommu);
+    GArray *scope_blob = g_array_new(false, true, 1);
+
+    /*
+     * A PCI bus walk, for each PCI host bridge.
+     * Insert scope for each PCI bridge and endpoint device which
+     * is attached to a bus with iommu enabled.
+     */
+    object_child_foreach_recursive(object_get_root(),
+                                   dmar_host_bridges, scope_blob);
 
     assert(iommu);
     if (x86_iommu_ir_supported(iommu)) {
@@ -1910,8 +1969,9 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id,
     /* DMAR Remapping Hardware Unit Definition structure */
     drhd = acpi_data_push(table_data, sizeof(*drhd) + ioapic_scope_size);
     drhd->type = cpu_to_le16(ACPI_DMAR_TYPE_HARDWARE_UNIT);
-    drhd->length = cpu_to_le16(sizeof(*drhd) + ioapic_scope_size);
-    drhd->flags = ACPI_DMAR_INCLUDE_PCI_ALL;
+    drhd->length =
+        cpu_to_le16(sizeof(*drhd) + ioapic_scope_size + scope_blob->len);
+    drhd->flags = 0;            /* Don't include all pci device */
     drhd->pci_segment = cpu_to_le16(0);
     drhd->address = cpu_to_le64(Q35_HOST_BRIDGE_IOMMU_ADDR);
 
@@ -1925,6 +1985,10 @@ build_dmar_q35(GArray *table_data, BIOSLinker *linker, const char *oem_id,
     scope->path[0].device = PCI_SLOT(Q35_PSEUDO_DEVFN_IOAPIC);
     scope->path[0].function = PCI_FUNC(Q35_PSEUDO_DEVFN_IOAPIC);
 
+    /* Add scope found above */
+    g_array_append_vals(table_data, scope_blob->data, scope_blob->len);
+    g_array_free(scope_blob, true);
+
     if (iommu->dt_supported) {
         atsr = acpi_data_push(table_data, sizeof(*atsr));
         atsr->type = cpu_to_le16(ACPI_DMAR_TYPE_ATSR);
-- 
2.19.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH RFC v2 6/6] hw/i386/acpi-build: Add iommu filter in IVRS table
  2021-03-24 13:16 [PATCH RFC v2 0/6] Introduce IOMMU Option For PCI Root Bus Wang Xingang
                   ` (4 preceding siblings ...)
  2021-03-24 13:16 ` [PATCH RFC v2 5/6] hw/i386/acpi-build: Add explicit scope in DMAR table Wang Xingang
@ 2021-03-24 13:16 ` Wang Xingang
  5 siblings, 0 replies; 7+ messages in thread
From: Wang Xingang @ 2021-03-24 13:16 UTC (permalink / raw)
  To: qemu-devel, qemu-arm, eric.auger
  Cc: xieyingtai, peter.maydell, cenjiahui, ehabkost, mst,
	richard.henderson, shannon.zhaosl, pbonzini, imammedo,
	wangxingang5

From: Xingang Wang <wangxingang5@huawei.com>

When building amd IVRS table, only devices attached to root bus with
IOMMU flag should be scanned.

Signed-off-by: Xingang Wang <wangxingang5@huawei.com>
Signed-off-by: Jiahui Cen <cenjiahui@huawei.com>
---
 hw/i386/acpi-build.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 7729c96489..4e6b30d53a 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2119,7 +2119,7 @@ ivrs_host_bridges(Object *obj, void *opaque)
     if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
         PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
 
-        if (bus) {
+        if (bus && pci_root_bus_has_iommu(bus)) {
             pci_for_each_device(bus, pci_bus_num(bus), insert_ivhd, ivhd_blob);
         }
     }
-- 
2.19.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-03-24 13:23 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-24 13:16 [PATCH RFC v2 0/6] Introduce IOMMU Option For PCI Root Bus Wang Xingang
2021-03-24 13:16 ` [PATCH RFC v2 1/6] hw/pci/pci_host: Add iommu property for pci host Wang Xingang
2021-03-24 13:16 ` [PATCH RFC v2 2/6] hw/pci: Add iommu option for pci root bus Wang Xingang
2021-03-24 13:16 ` [PATCH RFC v2 3/6] hw/pci: Add pci_root_bus_max_bus Wang Xingang
2021-03-24 13:16 ` [PATCH RFC v2 4/6] hw/arm/virt-acpi-build: Add explicit idmap info in IORT table Wang Xingang
2021-03-24 13:16 ` [PATCH RFC v2 5/6] hw/i386/acpi-build: Add explicit scope in DMAR table Wang Xingang
2021-03-24 13:16 ` [PATCH RFC v2 6/6] hw/i386/acpi-build: Add iommu filter in IVRS table Wang Xingang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).