>-----Original Message-----
>From: Shameer Kolothum <[email protected]>
>Subject: [PATCH v7 35/36] hw/vfio/pci: Synthesize PASID capability for
>vfio-pci devices
>
>Add support for synthesizing a PCIe PASID extended capability for
>vfio-pci devices when PASID is enabled via a vIOMMU and supported by
>the host IOMMU backend.
>
>PASID capability parameters are retrieved via IOMMUFD APIs and the
>capability is inserted into the PCIe extended capability list using
>the insertion helper. A new x-vpasid-cap-offset property allows
>explicit control over the placement; by default the capability is
>placed at the end of the PCIe extended configuration space.
>
>If the kernel does not expose PASID information or insertion fails,
>the device continues without PASID support.
>
>Signed-off-by: Shameer Kolothum <[email protected]>
>---
> hw/vfio/pci.c | 84
>+++++++++++++++++++++++++++++++++++++++++
> hw/vfio/pci.h | 1 +
> include/hw/core/iommu.h | 1 +
> 3 files changed, 86 insertions(+)
>
>diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
>index c734472721..96990576ac 100644
>--- a/hw/vfio/pci.c
>+++ b/hw/vfio/pci.c
>@@ -24,6 +24,7 @@
> #include <sys/ioctl.h>
>
> #include "hw/core/hw-error.h"
>+#include "hw/core/iommu.h"
> #include "hw/pci/msi.h"
> #include "hw/pci/msix.h"
> #include "hw/pci/pci_bridge.h"
>@@ -2498,9 +2499,71 @@ static int vfio_setup_rebar_ecap(VFIOPCIDevice
>*vdev, uint16_t pos)
> return 0;
> }
>
>+/*
>+ * Try to retrieve PASID capability information via IOMMUFD APIs and,
>+ * if supported, synthesize a PASID PCIe extended capability for the
>+ * VFIO device.
>+ *
>+ * Use user-specified PASID capability offset if provided, otherwise
>+ * place it at the end of the PCIe extended configuration space.
>+ */
>+static void vfio_pci_synthesize_pasid_cap(VFIOPCIDevice *vdev)
>+{
>+ HostIOMMUDevice *hiod = vdev->vbasedev.hiod;
>+ HostIOMMUDeviceClass *hiodc;
>+ PasidInfo pasid_info;
>+ PCIDevice *pdev = PCI_DEVICE(vdev);
>+ uint16_t pasid_offset;
>+
>+ if (vdev->vbasedev.mdev) {
>+ return;
>+ }
I'm not sure if checking hiod directly is more accurate, vdev->vbasedev.mdev
can be false
for mdev device if fd passing is used.
Thanks
Zhenzhong
>+
>+ hiodc = HOST_IOMMU_DEVICE_GET_CLASS(hiod);
>+ if (!hiodc || !hiodc->get_pasid_info ||
>+ !hiodc->get_pasid_info(hiod, &pasid_info) ||
>+ !(pci_device_get_viommu_flags(pdev) &
>VIOMMU_FLAG_PASID_SUPPORTED)) {
>+ return;
>+ }
>+
>+ /*
>+ * Check if user has specified an offset to place PASID CAP,
>+ * else select the last offset as default
>+ */
>+ if (vdev->vpasid_cap_offset) {
>+ if (!QEMU_IS_ALIGNED(vdev->vpasid_cap_offset,
>PCI_EXT_CAP_ALIGN) ||
>+ vdev->vpasid_cap_offset < PCI_CONFIG_SPACE_SIZE ||
>+ vdev->vpasid_cap_offset + PCI_EXT_CAP_PASID_SIZEOF >
>+ PCIE_CONFIG_SPACE_SIZE) {
>+ error_report("vfio: invalid x-vpasid-cap-offset 0x%x, skipping
>PASID",
>+ vdev->vpasid_cap_offset);
>+ return;
>+ }
>+ pasid_offset = vdev->vpasid_cap_offset;
>+ } else {
>+ pasid_offset = PCIE_CONFIG_SPACE_SIZE -
>PCI_EXT_CAP_PASID_SIZEOF;
>+ warn_report("vfio: PASID capability offset(x-vpasid-cap-offset) not
>specified, "
>+ "placing at the default offset 0x%x",
>+ pasid_offset);
>+ }
>+
>+ if (!pcie_insert_capability(pdev, PCI_EXT_CAP_ID_PASID,
>PCI_PASID_VER,
>+ pasid_offset,
>PCI_EXT_CAP_PASID_SIZEOF)) {
>+ error_report("vfio: Placing PASID capability at offset 0x%x failed",
>+ pasid_offset);
>+ }
>+ pcie_pasid_common_init(pdev, pasid_offset,
>pasid_info.max_pasid_log2,
>+ pasid_info.exec_perm,
>pasid_info.priv_mod);
>+
>+ /* PASID capability is fully emulated by QEMU */
>+ memset(vdev->emulated_config_bits + pdev->exp.pasid_cap, 0xff,
>+ PCI_EXT_CAP_PASID_SIZEOF);
>+}
>+
> static void vfio_add_ext_cap(VFIOPCIDevice *vdev)
> {
> PCIDevice *pdev = PCI_DEVICE(vdev);
>+ bool pasid_cap_added = false;
> uint32_t header;
> uint16_t cap_id, next, size;
> uint8_t cap_ver;
>@@ -2578,12 +2641,24 @@ static void vfio_add_ext_cap(VFIOPCIDevice
>*vdev)
> pcie_add_capability(pdev, cap_id, cap_ver, next, size);
> }
> break;
>+ /*
>+ * VFIO kernel does not expose the PASID CAP today. We may
>synthesize
>+ * one later through IOMMUFD APIs. If VFIO ever starts exposing
>it,
>+ * record its presence here so we do not create a duplicate CAP.
>+ */
>+ case PCI_EXT_CAP_ID_PASID:
>+ pasid_cap_added = true;
>+ /* fallthrough */
> default:
> pcie_add_capability(pdev, cap_id, cap_ver, next, size);
> }
>
> }
>
>+ if (!pasid_cap_added) {
>+ vfio_pci_synthesize_pasid_cap(vdev);
>+ }
>+
> /* Cleanup chain head ID if necessary */
> if (pci_get_word(pdev->config + PCI_CONFIG_SPACE_SIZE) == 0xFFFF) {
> pci_set_word(pdev->config + PCI_CONFIG_SPACE_SIZE, 0);
>@@ -3756,6 +3831,8 @@ static const Property vfio_pci_properties[] = {
> TYPE_IOMMUFD_BACKEND, IOMMUFDBackend
>*),
> #endif
> DEFINE_PROP_BOOL("skip-vsc-check", VFIOPCIDevice, skip_vsc_check,
>true),
>+ DEFINE_PROP_UINT16("x-vpasid-cap-offset", VFIOPCIDevice,
>+ vpasid_cap_offset, 0),
> };
>
> #ifdef CONFIG_IOMMUFD
>@@ -3913,6 +3990,13 @@ static void vfio_pci_class_init(ObjectClass *klass,
>const void *data)
> "destination when doing
>live "
> "migration of device
>state via "
> "multifd channels");
>+ object_class_property_set_description(klass, /* 11.0 */
>+ "x-vpasid-cap-offset",
>+ "PCIe extended
>configuration space offset at which to place a "
>+ "synthetic PASID
>extended capability when PASID is enabled via "
>+ "a vIOMMU. A value of 0
>(default) places the capability at the "
>+ "end of the extended
>configuration space. The offset must be "
>+ "4-byte aligned and
>within the PCIe extended configuration space");
> }
>
> static const TypeInfo vfio_pci_info = {
>diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h
>index 0f78cf9cdb..d6495d7f29 100644
>--- a/hw/vfio/pci.h
>+++ b/hw/vfio/pci.h
>@@ -187,6 +187,7 @@ struct VFIOPCIDevice {
> bool defer_kvm_irq_routing;
> bool clear_parent_atomics_on_exit;
> bool skip_vsc_check;
>+ uint16_t vpasid_cap_offset;
> VFIODisplay *dpy;
> Notifier irqchip_change_notifier;
> VFIOPCICPR cpr;
>diff --git a/include/hw/core/iommu.h b/include/hw/core/iommu.h
>index 9b8bb94fc2..9635770bee 100644
>--- a/include/hw/core/iommu.h
>+++ b/include/hw/core/iommu.h
>@@ -20,6 +20,7 @@
> enum viommu_flags {
> /* vIOMMU needs nesting parent HWPT to create nested HWPT */
> VIOMMU_FLAG_WANT_NESTING_PARENT = BIT_ULL(0),
>+ VIOMMU_FLAG_PASID_SUPPORTED = BIT_ULL(1),
> };
>
> #endif /* HW_IOMMU_H */
>--
>2.43.0