On 7/25/2026 4:01 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.
> 
> Fixes: d29a09ca6842 ("hw/i386: Introduce AMD IOMMU")
> Signed-off-by: Dongli Zhang <[email protected]>
> ---
> v1->v2:
>   - Add Fixes tag.
>   - Rename amdvi_as_devid() to amdvi_get_as_devid().
>   - Introduce amdvi_get_devid().
>   - Rebase to call amdvi_get_devid() at amdvi_find_as_by_devid().
> 
>  hw/i386/amd_iommu.c | 24 ++++++++++++++++++------
>  1 file changed, 18 insertions(+), 6 deletions(-)
> 
> diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c
> index a5682747ac..2fd680c4ff 100644
> --- a/hw/i386/amd_iommu.c
> +++ b/hw/i386/amd_iommu.c
> @@ -65,6 +65,16 @@ typedef struct AMDVIIOTLBEntry {
>      uint64_t page_mask;         /* physical page size  */
>  } AMDVIIOTLBEntry;
>  
> +static uint16_t amdvi_get_devid(PCIBus *bus, uint8_t devfn)
> +{
> +    return PCI_BUILD_BDF(pci_bus_num(bus), devfn);
> +}
> +
> +static uint16_t amdvi_get_as_devid(AMDVIAddressSpace *as)
> +{
> +    return amdvi_get_devid(as->bus, as->devfn);
> +}
> +
>  /*
>   * 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
> @@ -459,7 +469,7 @@ static gboolean amdvi_find_as_by_devid(gpointer key, 
> gpointer value,
>      const AMDVIAsKey *as = key;
>      const uint16_t *devidp = user_data;
>  
> -    return *devidp == PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn);
> +    return *devidp == amdvi_get_devid(as->bus, as->devfn);
>  }
>  
>  static AMDVIAddressSpace *amdvi_get_as_by_devid(AMDVIState *s, uint16_t 
> devid)
> @@ -664,7 +674,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_get_as_devid(as);
>      AMDVIState *s = as->iommu_state;
>  
>      if (!amdvi_get_dte(s, devid, dte)) {
> @@ -763,6 +773,7 @@ static int fetch_pte(AMDVIAddressSpace *as, hwaddr 
> address, uint64_t dte,
>      uint8_t pt_level, next_pt_level;
>      IOMMUAccessFlags perms;
>      int ret;
> +    uint16_t devid = amdvi_get_as_devid(as);
>  
>      *page_size = 0;
>  
> @@ -780,7 +791,7 @@ static int fetch_pte(AMDVIAddressSpace *as, hwaddr 
> address, uint64_t dte,
>       * Pointer and indexing the top level table using the IOVA from the 
> request.
>       */
>      pte_addr = NEXT_PTE_ADDR(dte, pt_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) {
>          /*
> @@ -836,7 +847,7 @@ static int fetch_pte(AMDVIAddressSpace *as, hwaddr 
> address, uint64_t dte,
>          *page_size = PTE_LEVEL_PAGE_SIZE(pt_level);
>  
>          pte_addr = NEXT_PTE_ADDR(*pte, pt_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) {
>              /* Failure to read PTE. Page walk skips a page_size chunk */
> @@ -1897,6 +1908,7 @@ static void amdvi_page_walk(AMDVIAddressSpace *as, 
> uint64_t *dte,
>      uint8_t mode;
>      uint64_t pte;
>      int fetch_ret;
> +    uint16_t devid = amdvi_get_as_devid(as);
>  
>      /* make sure the DTE has TV = 1 */
>      if (!(dte[0] & AMDVI_DEV_TRANSLATION_VALID)) {
> @@ -1930,7 +1942,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;
>      }
> @@ -1957,7 +1969,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_get_as_devid(as);
>      AMDVIIOTLBEntry *iotlb_entry = amdvi_iotlb_lookup(s, addr, devid);
>      uint64_t entry[4];
>      int dte_ret;

Reviewed-by: Sairaj Kodilkar <[email protected]>

Thanks
Sairaj

Reply via email to