On 3/27/26 10:52, Zhenzhong Duan wrote:
Propagate guest's PRQ response to host by writing to fault_fd.
Create a new VTDPRQEntry to cache cookie for each fault group,
this cookie is used to mark the fault group on host side.

Signed-off-by: Zhenzhong Duan <[email protected]>
---
  hw/i386/intel_iommu_accel.h   | 14 ++++++++
  include/hw/i386/intel_iommu.h |  6 ++++
  hw/i386/intel_iommu.c         |  4 +++
  hw/i386/intel_iommu_accel.c   | 65 +++++++++++++++++++++++++++++++++++
  hw/i386/trace-events          |  1 +
  5 files changed, 90 insertions(+)

diff --git a/hw/i386/intel_iommu_accel.h b/hw/i386/intel_iommu_accel.h
index 10e6ee5722..b46c7126f7 100644
--- a/hw/i386/intel_iommu_accel.h
+++ b/hw/i386/intel_iommu_accel.h
@@ -19,6 +19,9 @@ typedef struct VTDAccelPASIDCacheEntry {
      uint32_t fs_hwpt_id;
      uint32_t fault_id;
      int fault_fd;
+    QLIST_HEAD(, VTDPRQEntry) vtd_prq_list;
+    IOMMUPRINotifier pri_notifier_entry;
+    IOMMUPRINotifier *pri_notifier;
      QLIST_ENTRY(VTDAccelPASIDCacheEntry) next;
  } VTDAccelPASIDCacheEntry;
@@ -31,6 +34,9 @@ void vtd_flush_host_piotlb_all_accel(IntelIOMMUState *s, uint16_t domain_id,
                                       uint64_t npages, bool ih);
  void vtd_pasid_cache_sync_accel(IntelIOMMUState *s, VTDPASIDCacheInfo 
*pc_info);
  void vtd_pasid_cache_reset_accel(IntelIOMMUState *s);
+bool vtd_propagate_page_group_response_accel(IntelIOMMUState *s,
+                                             uint16_t rid, uint32_t pasid,
+                                             IOMMUPRIResponse *response);
  void vtd_iommu_ops_update_accel(PCIIOMMUOps *ops);
  #else
  static inline bool vtd_check_hiod_accel(IntelIOMMUState *s,
@@ -69,6 +75,14 @@ static inline void 
vtd_pasid_cache_reset_accel(IntelIOMMUState *s)
  {
  }
+static inline
+bool vtd_propagate_page_group_response_accel(IntelIOMMUState *s,
+                                             uint16_t rid, uint32_t pasid,
+                                             IOMMUPRIResponse *response)
+{
+    return false;
+}
+
  static inline void vtd_iommu_ops_update_accel(PCIIOMMUOps *ops)
  {
  }
diff --git a/include/hw/i386/intel_iommu.h b/include/hw/i386/intel_iommu.h
index 1842ba5840..5d44eac0ed 100644
--- a/include/hw/i386/intel_iommu.h
+++ b/include/hw/i386/intel_iommu.h
@@ -100,6 +100,12 @@ typedef struct VTDPASIDCacheEntry {
      bool valid;
  } VTDPASIDCacheEntry;
+typedef struct VTDPRQEntry {
+    uint32_t grpid;
+    uint32_t cookie;
+    QLIST_ENTRY(VTDPRQEntry) next;
+} VTDPRQEntry;
+
  struct VTDAddressSpace {
      PCIBus *bus;
      uint8_t devfn;
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index 96b4102ab9..d670a0377b 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -3390,6 +3390,10 @@ static bool 
vtd_process_page_group_response_desc(IntelIOMMUState *s,
          response.response_code = IOMMU_PRI_RESP_FAILURE;
      }
+ if (vtd_propagate_page_group_response_accel(s, rid, pasid, &response)) {
+        return true;
+    }
+
      if (vtd_dev_as->pri_notifier) {
          vtd_dev_as->pri_notifier->notify(vtd_dev_as->pri_notifier, &response);
      }
diff --git a/hw/i386/intel_iommu_accel.c b/hw/i386/intel_iommu_accel.c
index 0fce62ff75..44af534c55 100644
--- a/hw/i386/intel_iommu_accel.c
+++ b/hw/i386/intel_iommu_accel.c
@@ -102,6 +102,30 @@ VTDHostIOMMUDevice *vtd_find_hiod_iommufd(VTDAddressSpace 
*as)
      return NULL;
  }
+bool vtd_propagate_page_group_response_accel(IntelIOMMUState *s,
+                                             uint16_t rid, uint32_t pasid,
+                                             IOMMUPRIResponse *response)

s/vtd_propagate_page_group_response_accel/vtd_accel_propagate_page_group_response/

+{
+    VTDAddressSpace *vtd_as = vtd_get_as_by_sid(s, rid);
+    VTDAccelPASIDCacheEntry *vtd_pce;
+    VTDHostIOMMUDevice *vtd_hiod = vtd_find_hiod_iommufd(vtd_as);
+
+    if (!vtd_hiod) {
+        return false;
+    }
+
+    QLIST_FOREACH(vtd_pce, &vtd_hiod->pasid_cache_list, next) {
+        if (vtd_pce->pasid == pasid) {
+            if (vtd_pce->pri_notifier) {
+                vtd_pce->pri_notifier->notify(vtd_pce->pri_notifier, response);

is the notify mechanism really needed? You already have vtd_pce here which is the main input that needed by vtd_prq_response_notify().
You might call vtd_prq_response_notify() directly here since it's
internal helper?

+            }
+            return true;
+        }
+    }
+
+    return false;
+}
+
  static void vtd_prq_report_fault(VTDAccelPASIDCacheEntry *vtd_pce,
                                   struct iommu_hwpt_pgfault *fault, int cnt)
  {
@@ -117,6 +141,13 @@ static void vtd_prq_report_fault(VTDAccelPASIDCacheEntry 
*vtd_pce,
                                      fault->addr, last_page, fault->grpid,
                                      fault->perm & IOMMU_PGFAULT_PERM_READ,
                                      fault->perm & IOMMU_PGFAULT_PERM_WRITE);
+        if (last_page) {
+            VTDPRQEntry *prqe = g_malloc0(sizeof(*prqe));
+
+            prqe->grpid = fault->grpid;
+            prqe->cookie = fault->cookie;
+            QLIST_INSERT_HEAD(&vtd_pce->vtd_prq_list, prqe, next);
+        }
      }
  }
@@ -150,6 +181,36 @@ static void vtd_prq_read_fault(void *opaque)
      vtd_prq_report_fault(vtd_pce, fault, bytes / sizeof(fault[0]));
  }
+static void vtd_prq_response_notify(struct IOMMUPRINotifier *notifier,
+                                    IOMMUPRIResponse *response)
+{
+    VTDAccelPASIDCacheEntry *vtd_pce =
+        container_of(notifier, VTDAccelPASIDCacheEntry, pri_notifier_entry);
+    uint32_t id = vtd_pce->fault_id, fd = vtd_pce->fault_fd;
+    struct iommu_hwpt_page_response resp;
+    VTDPRQEntry *prqe, *tmp;
+    ssize_t bytes;
+
+    QLIST_FOREACH_SAFE(prqe, &vtd_pce->vtd_prq_list, next, tmp) {
+        if (prqe->grpid != response->prgi) {
+            continue;
+        }
+
+        resp.cookie = prqe->cookie;
+        resp.code = response->response_code;
+        bytes = write(fd, &resp, sizeof(resp));
+        trace_vtd_prq_response_notify(id, fd, resp.cookie, resp.code, bytes);
+        if (bytes < 0) {
+            error_report_once("FAULTQ(id %u): write failed "
+                              "[cookie 0x%x code 0x%x] (%m)",
+                              id, resp.cookie, resp.code);
+        }
+
+        QLIST_REMOVE(prqe, next);
+        g_free(prqe);
+    }
+}
+
  static void vtd_destroy_fs_faultq(VTDHostIOMMUDevice *vtd_hiod,
                                    uint32_t fault_id, uint32_t fault_fd)
  {
@@ -213,6 +274,7 @@ static void vtd_destroy_old_fs_faultq(VTDHostIOMMUDevice 
*vtd_hiod,
          return;
      }
+ vtd_pce->pri_notifier = NULL;
      qemu_set_fd_handler(vtd_pce->fault_fd, NULL, NULL, NULL);
      vtd_destroy_fs_faultq(vtd_hiod, vtd_pce->fault_id, vtd_pce->fault_fd);
      vtd_pce->fault_id = 0;
@@ -228,6 +290,8 @@ static void vtd_setup_fs_faultq(VTDAccelPASIDCacheEntry 
*vtd_pce,
vtd_pce->fault_id = fault_id;
      vtd_pce->fault_fd = fault_fd;
+    vtd_pce->pri_notifier_entry.notify = vtd_prq_response_notify;
+    vtd_pce->pri_notifier = &vtd_pce->pri_notifier_entry;
      qemu_set_fd_handler(fault_fd, vtd_prq_read_fault, NULL, vtd_pce);
  }
@@ -492,6 +556,7 @@ static void vtd_accel_fill_pc(VTDHostIOMMUDevice *vtd_hiod, uint32_t pasid,
      vtd_pce->vtd_hiod = vtd_hiod;
      vtd_pce->pasid = pasid;
      vtd_pce->pasid_entry = *pe;
+    QLIST_INIT(&vtd_pce->vtd_prq_list);
      QLIST_INSERT_HEAD(&vtd_hiod->pasid_cache_list, vtd_pce, next);
if (!vtd_device_attach_iommufd(vtd_pce, &local_err)) {
diff --git a/hw/i386/trace-events b/hw/i386/trace-events
index bf139338f7..52dab0b508 100644
--- a/hw/i386/trace-events
+++ b/hw/i386/trace-events
@@ -78,6 +78,7 @@ vtd_device_attach_hwpt(uint32_t dev_id, uint32_t pasid, 
uint32_t hwpt_id, int re
  vtd_device_detach_hwpt(uint32_t dev_id, uint32_t pasid, int ret) "dev_id %d pasid 
%d ret: %d"
  vtd_device_reattach_def_hwpt(uint32_t dev_id, uint32_t pasid, uint32_t hwpt_id, int 
ret) "dev_id %d pasid %d hwpt_id %d, ret: %d"
  vtd_prq_read_fault(uint32_t fault_id, uint32_t fault_fd, ssize_t bytes) "fault_id 
%d fault_fd %d ret: %zd"
+vtd_prq_response_notify(uint32_t fault_id, uint32_t fault_fd, uint32_t cookie, uint32_t 
code, ssize_t bytes) "fault_id %d fault_fd %d cookie %d code %d ret: %zd"
# amd_iommu.c
  amdvi_evntlog_fail(uint64_t addr, uint32_t head) "error: fail to write at addr 
0x%"PRIx64" +  offset 0x%"PRIx32


Reply via email to