@samitouri / QOSamiQemu / commits / ca7bac51e0

hw/riscv/riscv-iommu: Avoid caching PCI device IDs

PCI bus numbers may still be unassigned when QEMU initializes a PCI device's bus-master address space. For devices behind bridges, pci_bus_num() can return 0 at that point because the guest has not yet programmed the bridge Secondary Bus Number register. The RISC-V IOMMU currently stores a fixed device_id in RISCVIOMMUSpace when the address space is created. If the guest later enumerates the device on a non-zero bus, DMA translation still uses the stale device_id and may look up the wrong device context in the DDT. Store the stable PCIBus pointer and devfn in RISCVIOMMUSpace instead, and compute the device_id from the current bus number when it is needed. This keeps DMA translation and ATS invalidation in sync with guest PCI bus enumeration. Signed-off-by: Chengbo Gao <gaochengbo@bosc.ac.cn> Reviewed-by: Daniel Henrique Barboza <daniel.barboza@oss.qualcomm.com> Message-ID: <20260514020637.2819308-1-gaochengbo@bosc.ac.cn> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>

Chengbo Gao committed May 14, 2026 at 10:06 UTC ca7bac51e04fa1ad384963577fabd3a58355ae23
1 file changed +25 -15
hw/riscv/riscv-iommu.c
+25 -15
@@ -49,7 +49,8 @@ struct RISCVIOMMUSpace {
49 IOMMUMemoryRegion iova_mr; /* IOVA memory region for attached device */
50 AddressSpace iova_as; /* IOVA address space for attached device */
51 RISCVIOMMUState *iommu; /* Managing IOMMU device state */
52 - uint32_t devid; /* Requester identifier, AKA device_id */
52 + PCIBus *bus; /* PCI bus of the requester */
53 + uint8_t devfn; /* Requester identifier, AKA device_id */
54 bool notifier; /* IOMMU unmap notifier enabled */
55 QLIST_ENTRY(RISCVIOMMUSpace) list;
56 };
@@ -74,6 +75,15 @@ struct RISCVIOMMUEntry {
75 /* IOMMU index for transactions without process_id specified. */
76 #define RISCV_IOMMU_NOPROCID 0
77
78 +static uint32_t riscv_iommu_space_devid(RISCVIOMMUSpace *as)
79 +{
80 + uint32_t devid = PCI_BUILD_BDF(pci_bus_num(as->bus), as->devfn);
81 +
82 + /* FIXME: PCIe bus remapping for attached endpoints. */
83 + devid |= as->iommu->bus << 8;
84 + return devid;
85 +}
86 +
87 static uint8_t riscv_iommu_get_icvec_vector(uint32_t icvec, uint32_t vec_type)
88 {
89 switch (vec_type) {
@@ -1379,15 +1389,13 @@ static void riscv_iommu_ctx_put(RISCVIOMMUState *s, void *ref)
1389 }
1390
1391 /* Find or allocate address space for a given device */
1382 -static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid)
1392 +static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, PCIBus *bus,
1393 + int devfn)
1394 {
1395 RISCVIOMMUSpace *as;
1396
1386 - /* FIXME: PCIe bus remapping for attached endpoints. */
1387 - devid |= s->bus << 8;
1388 -
1397 QLIST_FOREACH(as, &s->spaces, list) {
1390 - if (as->devid == devid) {
1398 + if (as->bus == bus && as->devfn == devfn) {
1399 break;
1400 }
1401 }
@@ -1397,10 +1405,11 @@ static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid)
1405 as = g_new0(RISCVIOMMUSpace, 1);
1406
1407 as->iommu = s;
1400 - as->devid = devid;
1408 + as->bus = bus;
1409 + as->devfn = devfn;
1410
1411 snprintf(name, sizeof(name), "riscv-iommu-%04x:%02x.%d-iova",
1403 - PCI_BUS_NUM(as->devid), PCI_SLOT(as->devid), PCI_FUNC(as->devid));
1412 + pci_bus_num(bus), PCI_SLOT(devfn), PCI_FUNC(devfn));
1413
1414 /* IOVA address space, untranslated addresses */
1415 memory_region_init_iommu(&as->iova_mr, sizeof(as->iova_mr),
@@ -1410,8 +1419,8 @@ static AddressSpace *riscv_iommu_space(RISCVIOMMUState *s, uint32_t devid)
1419
1420 QLIST_INSERT_HEAD(&s->spaces, as, list);
1421
1413 - trace_riscv_iommu_new(s->parent_obj.id, PCI_BUS_NUM(as->devid),
1414 - PCI_SLOT(as->devid), PCI_FUNC(as->devid));
1422 + trace_riscv_iommu_new(s->parent_obj.id, pci_bus_num(bus),
1423 + PCI_SLOT(devfn), PCI_FUNC(devfn));
1424 }
1425 return &as->iova_as;
1426 }
@@ -1732,7 +1741,7 @@ static void riscv_iommu_ats(RISCVIOMMUState *s,
1741 pid = get_field(cmd->dword0, RISCV_IOMMU_CMD_ATS_PID);
1742
1743 QLIST_FOREACH(as, &s->spaces, list) {
1735 - if (as->devid == devid) {
1744 + if (riscv_iommu_space_devid(as) == devid) {
1745 break;
1746 }
1747 }
@@ -2745,8 +2754,9 @@ static IOMMUTLBEntry riscv_iommu_memory_region_translate(
2754 .addr_mask = ~0ULL,
2755 .perm = flag,
2756 };
2757 + uint32_t devid = riscv_iommu_space_devid(as);
2758
2749 - ctx = riscv_iommu_ctx(as->iommu, as->devid, iommu_idx, &ref);
2759 + ctx = riscv_iommu_ctx(as->iommu, devid, iommu_idx, &ref);
2760 if (ctx == NULL) {
2761 /* Translation disabled or invalid. */
2762 iotlb.addr_mask = 0;
@@ -2758,8 +2768,8 @@ static IOMMUTLBEntry riscv_iommu_memory_region_translate(
2768 }
2769
2770 /* Trace all dma translations with original access flags. */
2761 - trace_riscv_iommu_dma(as->iommu->parent_obj.id, PCI_BUS_NUM(as->devid),
2762 - PCI_SLOT(as->devid), PCI_FUNC(as->devid), iommu_idx,
2771 + trace_riscv_iommu_dma(as->iommu->parent_obj.id, PCI_BUS_NUM(devid),
2772 + PCI_SLOT(devid), PCI_FUNC(devid), iommu_idx,
2773 IOMMU_FLAG_STR[flag & IOMMU_RW], iotlb.iova,
2774 iotlb.translated_addr);
2775
@@ -2807,7 +2817,7 @@ static AddressSpace *riscv_iommu_find_as(PCIBus *bus, void *opaque, int devfn)
2817
2818 /* Find first matching IOMMU */
2819 while (s != NULL && as == NULL) {
2810 - as = riscv_iommu_space(s, PCI_BUILD_BDF(pci_bus_num(bus), devfn));
2820 + as = riscv_iommu_space(s, bus, devfn);
2821 s = s->iommus.le_next;
2822 }
2823