mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 00:33:55 -06:00
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>
This commit is contained in:
parent
a849ff5d6f
commit
e9b457500a
2 changed files with 207 additions and 0 deletions
81
hw/pci/pci.c
81
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)
|
||||
{
|
||||
|
|
|
@ -462,6 +462,80 @@ typedef struct PCIIOMMUOps {
|
|||
void (*init_iotlb_notifier)(PCIBus *bus, void *opaque, int devfn,
|
||||
IOMMUNotifier *n, IOMMUNotify fn,
|
||||
void *user_opaque);
|
||||
/**
|
||||
* @register_iotlb_notifier: setup an IOTLB invalidation notifier.
|
||||
*
|
||||
* Callback required if devices are allowed to cache translations.
|
||||
*
|
||||
* @bus: the #PCIBus of the PCI device.
|
||||
*
|
||||
* @opaque: the data passed to pci_setup_iommu().
|
||||
*
|
||||
* @devfn: device and function number of the PCI device.
|
||||
*
|
||||
* @pasid: the pasid of the address space to watch.
|
||||
*
|
||||
* @n: the notifier to register.
|
||||
*/
|
||||
void (*register_iotlb_notifier)(PCIBus *bus, void *opaque, int devfn,
|
||||
uint32_t pasid, IOMMUNotifier *n);
|
||||
/**
|
||||
* @unregister_iotlb_notifier: remove an IOTLB invalidation notifier.
|
||||
*
|
||||
* Callback required if devices are allowed to cache translations.
|
||||
*
|
||||
* @bus: the #PCIBus of the PCI device.
|
||||
*
|
||||
* @opaque: the data passed to pci_setup_iommu().
|
||||
*
|
||||
* @devfn: device and function number of the PCI device.
|
||||
*
|
||||
* @pasid: the pasid of the address space to stop watching.
|
||||
*
|
||||
* @n: the notifier to unregister.
|
||||
*/
|
||||
void (*unregister_iotlb_notifier)(PCIBus *bus, void *opaque, int devfn,
|
||||
uint32_t pasid, IOMMUNotifier *n);
|
||||
/**
|
||||
* @ats_request_translation: issue an ATS request.
|
||||
*
|
||||
* Callback required if devices are allowed to use the address
|
||||
* translation service.
|
||||
*
|
||||
* @bus: the #PCIBus of the PCI device.
|
||||
*
|
||||
* @opaque: the data passed to pci_setup_iommu().
|
||||
*
|
||||
* @devfn: device and function number of the PCI device.
|
||||
*
|
||||
* @pasid: the pasid of the address space to use for the request.
|
||||
*
|
||||
* @priv_req: privileged mode bit (PASID TLP).
|
||||
*
|
||||
* @exec_req: execute request bit (PASID TLP).
|
||||
*
|
||||
* @addr: start address of the memory range to be translated.
|
||||
*
|
||||
* @length: length of the memory range in bytes.
|
||||
*
|
||||
* @no_write: request a read-only translation (if supported).
|
||||
*
|
||||
* @result: buffer in which the TLB entries will be stored.
|
||||
*
|
||||
* @result_length: result buffer length.
|
||||
*
|
||||
* @err_count: number of untranslated subregions.
|
||||
*
|
||||
* Returns: the number of translations stored in the result buffer, or
|
||||
* -ENOMEM if the buffer is not large enough.
|
||||
*/
|
||||
ssize_t (*ats_request_translation)(PCIBus *bus, void *opaque, int devfn,
|
||||
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);
|
||||
} PCIIOMMUOps;
|
||||
|
||||
AddressSpace *pci_device_iommu_address_space(PCIDevice *dev);
|
||||
|
@ -495,6 +569,58 @@ int pci_iommu_get_iotlb_info(PCIDevice *dev, uint8_t *addr_width,
|
|||
int pci_iommu_init_iotlb_notifier(PCIDevice *dev, IOMMUNotifier *n,
|
||||
IOMMUNotify fn, void *opaque);
|
||||
|
||||
/**
|
||||
* pci_ats_request_translation: perform an ATS request.
|
||||
*
|
||||
* Returns the number of translations stored in @result in case of success,
|
||||
* a negative error code otherwise.
|
||||
* -ENOMEM is returned when the result buffer is not large enough to store
|
||||
* all the translations.
|
||||
*
|
||||
* @dev: the ATS-capable PCI device.
|
||||
* @pasid: the pasid of the address space in which the translation will be done.
|
||||
* @priv_req: privileged mode bit (PASID TLP).
|
||||
* @exec_req: execute request bit (PASID TLP).
|
||||
* @addr: start address of the memory range to be translated.
|
||||
* @length: length of the memory range in bytes.
|
||||
* @no_write: request a read-only translation (if supported).
|
||||
* @result: buffer in which the TLB entries will be stored.
|
||||
* @result_length: result buffer length.
|
||||
* @err_count: number of untranslated subregions.
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* pci_iommu_register_iotlb_notifier: register a notifier for changes to
|
||||
* IOMMU translation entries in a specific address space.
|
||||
*
|
||||
* Returns 0 on success, or a negative errno otherwise.
|
||||
*
|
||||
* @dev: the device that wants to get notified.
|
||||
* @pasid: the pasid of the address space to track.
|
||||
* @n: the notifier to register.
|
||||
*/
|
||||
int pci_iommu_register_iotlb_notifier(PCIDevice *dev, uint32_t pasid,
|
||||
IOMMUNotifier *n);
|
||||
|
||||
/**
|
||||
* pci_iommu_unregister_iotlb_notifier: unregister a notifier that has been
|
||||
* registerd with pci_iommu_register_iotlb_notifier.
|
||||
*
|
||||
* Returns 0 on success, or a negative errno otherwise.
|
||||
*
|
||||
* @dev: the device that wants to stop notifications.
|
||||
* @pasid: the pasid of the address space to stop tracking.
|
||||
* @n: the notifier to unregister.
|
||||
*/
|
||||
int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid,
|
||||
IOMMUNotifier *n);
|
||||
|
||||
/**
|
||||
* pci_setup_iommu: Initialize specific IOMMU handlers for a PCIBus
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue