diff options
| author | CLEMENT MATHIEU--DRIF <clement.mathieu--drif@eviden.com> | 2025-05-20 07:19:03 +0000 |
|---|---|---|
| committer | Michael S. Tsirkin <mst@redhat.com> | 2025-06-01 06:38:53 -0400 |
| commit | e9b457500adb023229a08ece3a8d7f5866dd360e (patch) | |
| tree | 5d1d0d09234102d7c3193498ddb93bfbc14c3c53 /hw/pci/pci.c | |
| parent | a849ff5d6fa9d263beaecd6421fff8e21d2591c8 (diff) | |
| download | focaccia-qemu-e9b457500adb023229a08ece3a8d7f5866dd360e.tar.gz focaccia-qemu-e9b457500adb023229a08ece3a8d7f5866dd360e.zip | |
pci: Add a pci-level API for ATS
Devices implementing ATS can send translation requests using pci_ats_request_translation. The invalidation events are sent back to the device using the iommu notifier managed with pci_iommu_register_iotlb_notifier / pci_iommu_unregister_iotlb_notifier. Signed-off-by: Clement Mathieu--Drif <clement.mathieu--drif@eviden.com> Co-authored-by: Ethan Milon <ethan.milon@eviden.com> Message-Id: <20250520071823.764266-11-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/pci/pci.c')
| -rw-r--r-- | hw/pci/pci.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/hw/pci/pci.c b/hw/pci/pci.c index dfa5a0259e..0c63cb4bbe 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2987,6 +2987,87 @@ void pci_device_unset_iommu_device(PCIDevice *dev) } } +ssize_t pci_ats_request_translation(PCIDevice *dev, uint32_t pasid, + bool priv_req, bool exec_req, + hwaddr addr, size_t length, + bool no_write, IOMMUTLBEntry *result, + size_t result_length, + uint32_t *err_count) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + if (!dev->is_master || + ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev))) { + return -EPERM; + } + + if (result_length == 0) { + return -ENOSPC; + } + + if (!pcie_ats_enabled(dev)) { + return -EPERM; + } + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->ats_request_translation) { + return iommu_bus->iommu_ops->ats_request_translation(bus, + iommu_bus->iommu_opaque, + devfn, pasid, priv_req, + exec_req, addr, length, + no_write, result, + result_length, err_count); + } + + return -ENODEV; +} + +int pci_iommu_register_iotlb_notifier(PCIDevice *dev, uint32_t pasid, + IOMMUNotifier *n) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + if ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev)) { + return -EPERM; + } + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->register_iotlb_notifier) { + iommu_bus->iommu_ops->register_iotlb_notifier(bus, + iommu_bus->iommu_opaque, devfn, + pasid, n); + return 0; + } + + return -ENODEV; +} + +int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid, + IOMMUNotifier *n) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + if ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev)) { + return -EPERM; + } + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->unregister_iotlb_notifier) { + iommu_bus->iommu_ops->unregister_iotlb_notifier(bus, + iommu_bus->iommu_opaque, + devfn, pasid, n); + return 0; + } + + return -ENODEV; +} + int pci_iommu_get_iotlb_info(PCIDevice *dev, uint8_t *addr_width, uint32_t *min_page_size) { |