On 6/10/2026 2:13 AM, Dongli Zhang wrote:
AMDVIAddressSpace->devfn only contains the PCI device/function number.
AMD-Vi event log entries require the full DeviceID, including the PCI
bus number.

When reporting IO page faults for devices behind a pcie-root-port, QEMU
logs the fault against the wrong requester. For example, a fault from
01:00.0 is reported as 00:00.0 because only devfn is passed to
amdvi_page_fault().

[root@vm ~]# lspci
... ...
01:00.0 Ethernet controller: Red Hat, Inc. Virtio 1.0 network device (rev 01)

[   58.154050] pci 0000:00:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT 
domain=0x0000 address=0xc0000000 flags=0x000a]
[   58.156968] pci 0000:00:00.0: AMD-Vi: Event logged [IO_PAGE_FAULT 
domain=0x0000 address=0xc0000000 flags=0x000a]

Use the full BDF consistently for AMD-Vi address spaces and pass it to
page fault and page-table access error reporting.

Signed-off-by: Dongli Zhang <[email protected]>
---
  hw/i386/amd_iommu.c | 15 +++++++++++----
  1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
index 997d02eab5..ca9d79bb51 100644
--- a/hw/i386/amd_iommu.c
+++ b/hw/i386/amd_iommu.c
@@ -87,6 +87,11 @@ typedef struct AMDVIIOTLBEntry {
      uint64_t page_mask;         /* physical page size  */
  } AMDVIIOTLBEntry;
+static uint16_t amdvi_as_devid(AMDVIAddressSpace *as)
+{
+    return PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn);
+}
+

A better function name can be 'amdvi_get_as_devid'

  /*
   * These 'fault' reasons have an overloaded meaning since they are not only
   * intended for describing reasons that generate an IO_PAGE_FAULT as per the 
AMD
@@ -613,7 +618,7 @@ static inline uint64_t amdvi_get_pte_entry(AMDVIState *s, 
uint64_t pte_addr,
static int amdvi_as_to_dte(AMDVIAddressSpace *as, uint64_t *dte)
  {
-    uint16_t devid = PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn);
+    uint16_t devid = amdvi_as_devid(as);
      AMDVIState *s = as->iommu_state;
if (!amdvi_get_dte(s, devid, dte)) {
@@ -664,6 +669,7 @@ static uint64_t fetch_pte(AMDVIAddressSpace *as, hwaddr 
address, uint64_t dte,
  {
      IOMMUAccessFlags perms = amdvi_get_perms(dte);
+ uint16_t devid = amdvi_as_devid(as);
      uint8_t level, mode;
      uint64_t pte_addr;
@@ -719,7 +725,7 @@ static uint64_t fetch_pte(AMDVIAddressSpace *as, hwaddr address, uint64_t dte,
           * and walk down to the lower level.
           */
          pte_addr = NEXT_PTE_ADDR(*pte, level, address);
-        *pte = amdvi_get_pte_entry(as->iommu_state, pte_addr, as->devfn);
+        *pte = amdvi_get_pte_entry(as->iommu_state, pte_addr, devid);
if (*pte == (uint64_t)-1) {
              /*
@@ -1763,6 +1769,7 @@ static void amdvi_page_walk(AMDVIAddressSpace *as, 
uint64_t *dte,
      uint8_t mode;
      uint64_t pte;
      int fetch_ret;
+    uint16_t devid = amdvi_as_devid(as);
/* make sure the DTE has TV = 1 */
      if (!(dte[0] & AMDVI_DEV_TRANSLATION_VALID)) {
@@ -1796,7 +1803,7 @@ static void amdvi_page_walk(AMDVIAddressSpace *as, 
uint64_t *dte,
      if (fetch_ret < 0 || !IOMMU_PTE_PRESENT(pte) ||
          perms != (perms & amdvi_get_perms(pte))) {
- amdvi_page_fault(as->iommu_state, as->devfn, addr, perms);
+        amdvi_page_fault(as->iommu_state, devid, addr, perms);
          trace_amdvi_page_fault(addr);
          return;
      }
@@ -1823,7 +1830,7 @@ static void amdvi_do_translate(AMDVIAddressSpace *as, 
hwaddr addr,
                                 bool is_write, IOMMUTLBEntry *ret)
  {
      AMDVIState *s = as->iommu_state;
-    uint16_t devid = PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn);
+    uint16_t devid = amdvi_as_devid(as);
      AMDVIIOTLBEntry *iotlb_entry = amdvi_iotlb_lookup(s, addr, devid);
      uint64_t entry[4];
      int dte_ret;

Update the function amdvi_find_as_by_devid as well to use amdvi_as_devid. Thanks Sairaj

Reply via email to