Re: [PATCH 4/8] acpi_build: Use IOMMU pci device to build IOMMU device ID

"Michael S. Tsirkin" <[email protected]> Fri, 31 Jul 2026 20:01:34 -0400
Newsgroups org.nongnu.qemu-devel
Message-ID <[email protected]>
On Fri, Jul 31, 2026 at 05:47:18PM -0400, Alejandro Jimenez wrote:
> 
> On 7/31/26 8:32 AM, Sairaj Kodilkar wrote:
> > On 7/31/2026 3: 20 PM, Michael S. Tsirkin wrote: > On Mon, May 11, 2026 at
> > 06: 09: 33PM +0530, Sairaj Kodilkar wrote: >> Currently, build_amd_iommu()
> > uses "addr" property to build the device ID for >> IOMMU device and
> > advertise it
> > 
> > 
> > On 7/31/2026 3:20 PM, Michael S. Tsirkin wrote:
> >> On Mon, May 11, 2026 at 06:09:33PM +0530, Sairaj Kodilkar wrote:
> >>> Currently, build_amd_iommu() uses "addr" property to build the device ID for
> >>> IOMMU device and advertise it throught IVRS. But this property does not encode
> >>> IOMMU bus. This will be a problem if IOMMU is attached to different bus.
> >>> Hence use iommu pci device which provides bus, to build the IOMMU device ID.
> >>>
> >>> Signed-off-by: Sairaj Kodilkar <[email protected]>
> >>> Reviewed-by: Vasant Hegde <[email protected]>
> >> 
> >> But is this called after firmware has enumerated the pci bus?
> >> And I guess OS better not change that bus number eh?
> 
> The above line sounds fairly threatening :) so I dug a bit more into the
> details.
> Short story: I tested placing the IOMMU behind a PCI bridge, which the
> implementation currently allows, and the guest can (easily) change the bus
> number. That changes the IOMMU BDF, so the DeviceID encoded in IVRS becomes
> incorrect.
> 
> The spec doesn't forbid the above scenario, but "strongly recommends":
> 
> • An IOMMU should be a root-complex device (i.e., appear directly on the
> bus at the top of the PCI tree hierarchy).
> • Some system software may prohibit an IOMMU from appearing under a
> PCI-to-PCI bridge.
> 
> (from Section 4.5 Software and Platform Firmware Implementation Issues)
> 
> While I don't know if that is the case in all HW implementations, my
> Genoa/Zen4 system does follow the recommended topology i.e. it exposes all
> of its 8 IOMMU functions directly on a PCI root bus, with no bridges.
> 
> So I think a reasonable choice is to enforce that an AMDVI-PCI device must
> always be directly attached to a PCI root bus. There is precedent for this
> in the virtio-iommu implementation already, the code change would be
> basically the same in amdvi_pci_realize(), see:
> 
> e72cfabf4ef2 ("hw/virtio/virtio-iommu-pci: Enforce the device is plugged on
> the root bus")
> 
> MST: does this address your concern?

Indeed, it is.

> Sairaj: Am I missing anything, perhaps from your unpublished patches, that
> makes this approach non-viable?
> 
> Thank you,
> Alejandro
> 
> > 
> > Hi Michael
> > 
> > Yes, the ACPI function is called two times -- during qemu initialization
> > and firmware writes. During first call, bus numbers are 0 and during
> > second call, IVRS is created with bus number. This second IVRS
> > overwrites the first one.
> > 
> > Thanks
> > Sairaj
> > 
> >>> ---
> >>>  hw/i386/acpi-build.c | 12 ++++++------
> >>>  1 file changed, 6 insertions(+), 6 deletions(-)
> >>>
> >>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> >>> index e4ad01eec037..718e3f546b18 100644
> >>> --- a/hw/i386/acpi-build.c
> >>> +++ b/hw/i386/acpi-build.c
> >>> @@ -1752,10 +1752,13 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
> >>>                  const char *oem_table_id)
> >>>  {
> >>>      AMDVIState *s = AMD_IOMMU_DEVICE(x86_iommu_get_default());
> >>> +    PCIDevice *iommu_dev = &(s->pci->dev);
> >>>      GArray *ivhd_blob = g_array_new(false, true, 1);
> >>>      AcpiTable table = { .sig = "IVRS", .rev = 1, .oem_id = oem_id,
> >>>                          .oem_table_id = oem_table_id };
> >>>      uint64_t feature_report;
> >>> +    int iommu_bus = pci_bus_num(pci_get_bus(iommu_dev));
> >>> +    uint16_t iommu_devid = PCI_BUILD_BDF(iommu_bus, iommu_dev->devfn);
> >>>  
> >>>      acpi_table_begin(&table, table_data);
> >>>      /* IVinfo - IO virtualization information common to all
> >>> @@ -1816,9 +1819,7 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
> >>>      /* IVHD length */
> >>>      build_append_int_noprefix(table_data, ivhd_blob->len + 24, 2);
> >>>      /* DeviceID */
> >>> -    build_append_int_noprefix(table_data,
> >>> -                              object_property_get_int(OBJECT(s->pci), "addr",
> >>> -                                                      &error_abort), 2);
> >>> +    build_append_int_noprefix(table_data, iommu_devid, 2);
> >>>      /* Capability offset */
> >>>      build_append_int_noprefix(table_data, s->pci->capab_offset, 2);
> >>>      /* IOMMU base address */
> >>> @@ -1850,10 +1851,9 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id,
> >>>  
> >>>      /* IVHD length */
> >>>      build_append_int_noprefix(table_data, ivhd_blob->len + 40, 2);
> >>> +
> >>>      /* DeviceID */
> >>> -    build_append_int_noprefix(table_data,
> >>> -                              object_property_get_int(OBJECT(s->pci), "addr",
> >>> -                                                      &error_abort), 2);
> >>> +    build_append_int_noprefix(table_data, iommu_devid, 2);
> >>>      /* Capability offset */
> >>>      build_append_int_noprefix(table_data, s->pci->capab_offset, 2);
> >>>      /* IOMMU base address */
> >>> -- 
> >>> 2.34.1
> >> 
> >