mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 08:43:55 -06:00
pci: Add a PCI-level API for PRI
A device can send a PRI request to the IOMMU using pci_pri_request_page. The PRI response is sent back using the notifier managed with pci_pri_register_notifier and pci_pri_unregister_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-12-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
e9b457500a
commit
f0f37daf8e
2 changed files with 196 additions and 0 deletions
66
hw/pci/pci.c
66
hw/pci/pci.c
|
@ -2987,6 +2987,72 @@ void pci_device_unset_iommu_device(PCIDevice *dev)
|
|||
}
|
||||
}
|
||||
|
||||
int pci_pri_request_page(PCIDevice *dev, uint32_t pasid, bool priv_req,
|
||||
bool exec_req, hwaddr addr, bool lpig,
|
||||
uint16_t prgi, bool is_read, bool is_write)
|
||||
{
|
||||
PCIBus *bus;
|
||||
PCIBus *iommu_bus;
|
||||
int devfn;
|
||||
|
||||
if (!dev->is_master ||
|
||||
((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev))) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if (!pcie_pri_enabled(dev)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
|
||||
if (iommu_bus && iommu_bus->iommu_ops->pri_request_page) {
|
||||
return iommu_bus->iommu_ops->pri_request_page(bus,
|
||||
iommu_bus->iommu_opaque,
|
||||
devfn, pasid, priv_req,
|
||||
exec_req, addr, lpig, prgi,
|
||||
is_read, is_write);
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int pci_pri_register_notifier(PCIDevice *dev, uint32_t pasid,
|
||||
IOMMUPRINotifier *notifier)
|
||||
{
|
||||
PCIBus *bus;
|
||||
PCIBus *iommu_bus;
|
||||
int devfn;
|
||||
|
||||
if (!dev->is_master ||
|
||||
((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->pri_register_notifier) {
|
||||
iommu_bus->iommu_ops->pri_register_notifier(bus,
|
||||
iommu_bus->iommu_opaque,
|
||||
devfn, pasid, notifier);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void pci_pri_unregister_notifier(PCIDevice *dev, uint32_t pasid)
|
||||
{
|
||||
PCIBus *bus;
|
||||
PCIBus *iommu_bus;
|
||||
int devfn;
|
||||
|
||||
pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn);
|
||||
if (iommu_bus && iommu_bus->iommu_ops->pri_unregister_notifier) {
|
||||
iommu_bus->iommu_ops->pri_unregister_notifier(bus,
|
||||
iommu_bus->iommu_opaque,
|
||||
devfn, pasid);
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t pci_ats_request_translation(PCIDevice *dev, uint32_t pasid,
|
||||
bool priv_req, bool exec_req,
|
||||
hwaddr addr, size_t length,
|
||||
|
|
|
@ -375,6 +375,28 @@ void pci_bus_get_w64_range(PCIBus *bus, Range *range);
|
|||
|
||||
void pci_device_deassert_intx(PCIDevice *dev);
|
||||
|
||||
/* Page Request Interface */
|
||||
typedef enum {
|
||||
IOMMU_PRI_RESP_SUCCESS,
|
||||
IOMMU_PRI_RESP_INVALID_REQUEST,
|
||||
IOMMU_PRI_RESP_FAILURE,
|
||||
} IOMMUPRIResponseCode;
|
||||
|
||||
typedef struct IOMMUPRIResponse {
|
||||
IOMMUPRIResponseCode response_code;
|
||||
uint16_t prgi;
|
||||
} IOMMUPRIResponse;
|
||||
|
||||
struct IOMMUPRINotifier;
|
||||
|
||||
typedef void (*IOMMUPRINotify)(struct IOMMUPRINotifier *notifier,
|
||||
IOMMUPRIResponse *response);
|
||||
|
||||
typedef struct IOMMUPRINotifier {
|
||||
IOMMUPRINotify notify;
|
||||
} IOMMUPRINotifier;
|
||||
|
||||
#define PCI_PRI_PRGI_MASK 0x1ffU
|
||||
|
||||
/**
|
||||
* struct PCIIOMMUOps: callbacks structure for specific IOMMU handlers
|
||||
|
@ -536,6 +558,72 @@ typedef struct PCIIOMMUOps {
|
|||
IOMMUTLBEntry *result,
|
||||
size_t result_length,
|
||||
uint32_t *err_count);
|
||||
/**
|
||||
* @pri_register_notifier: setup the PRI completion callback.
|
||||
*
|
||||
* Callback required if devices are allowed to use the page request
|
||||
* interface.
|
||||
*
|
||||
* @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 track.
|
||||
*
|
||||
* @notifier: the notifier to register.
|
||||
*/
|
||||
void (*pri_register_notifier)(PCIBus *bus, void *opaque, int devfn,
|
||||
uint32_t pasid, IOMMUPRINotifier *notifier);
|
||||
/**
|
||||
* @pri_unregister_notifier: remove the PRI completion callback.
|
||||
*
|
||||
* Callback required if devices are allowed to use the page request
|
||||
* interface.
|
||||
*
|
||||
* @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 tracking.
|
||||
*/
|
||||
void (*pri_unregister_notifier)(PCIBus *bus, void *opaque, int devfn,
|
||||
uint32_t pasid);
|
||||
/**
|
||||
* @pri_request_page: issue a PRI request.
|
||||
*
|
||||
* Callback required if devices are allowed to use the page request
|
||||
* interface.
|
||||
*
|
||||
* @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: untranslated address of the requested page.
|
||||
*
|
||||
* @lpig: last page in group.
|
||||
*
|
||||
* @prgi: page request group index.
|
||||
*
|
||||
* @is_read: request read access.
|
||||
*
|
||||
* @is_write: request write access.
|
||||
*/
|
||||
int (*pri_request_page)(PCIBus *bus, void *opaque, int devfn,
|
||||
uint32_t pasid, bool priv_req, bool exec_req,
|
||||
hwaddr addr, bool lpig, uint16_t prgi, bool is_read,
|
||||
bool is_write);
|
||||
} PCIIOMMUOps;
|
||||
|
||||
AddressSpace *pci_device_iommu_address_space(PCIDevice *dev);
|
||||
|
@ -595,6 +683,48 @@ ssize_t pci_ats_request_translation(PCIDevice *dev, uint32_t pasid,
|
|||
size_t result_length,
|
||||
uint32_t *err_count);
|
||||
|
||||
/**
|
||||
* pci_pri_request_page: perform a PRI request.
|
||||
*
|
||||
* Returns 0 if the PRI request has been sent to the guest OS,
|
||||
* an error code otherwise.
|
||||
*
|
||||
* @dev: the PRI-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: untranslated address of the requested page.
|
||||
* @lpig: last page in group.
|
||||
* @prgi: page request group index.
|
||||
* @is_read: request read access.
|
||||
* @is_write: request write access.
|
||||
*/
|
||||
int pci_pri_request_page(PCIDevice *dev, uint32_t pasid, bool priv_req,
|
||||
bool exec_req, hwaddr addr, bool lpig,
|
||||
uint16_t prgi, bool is_read, bool is_write);
|
||||
|
||||
/**
|
||||
* pci_pri_register_notifier: register the PRI callback for a given address
|
||||
* space.
|
||||
*
|
||||
* Returns 0 on success, an error code otherwise.
|
||||
*
|
||||
* @dev: the PRI-capable PCI device.
|
||||
* @pasid: the pasid of the address space to track.
|
||||
* @notifier: the notifier to register.
|
||||
*/
|
||||
int pci_pri_register_notifier(PCIDevice *dev, uint32_t pasid,
|
||||
IOMMUPRINotifier *notifier);
|
||||
|
||||
/**
|
||||
* pci_pri_unregister_notifier: remove the PRI callback from a given address
|
||||
* space.
|
||||
*
|
||||
* @dev: the PRI-capable PCI device.
|
||||
* @pasid: the pasid of the address space to stop tracking.
|
||||
*/
|
||||
void pci_pri_unregister_notifier(PCIDevice *dev, uint32_t pasid);
|
||||
|
||||
/**
|
||||
* pci_iommu_register_iotlb_notifier: register a notifier for changes to
|
||||
* IOMMU translation entries in a specific address space.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue