From da7cdc41aa3813f6bb1c87ced178f60185dac692 Mon Sep 17 00:00:00 2001 From: Yi Liu Date: Thu, 12 Sep 2024 01:38:46 -0700 Subject: [PATCH] vfio: Synthesize vPASID capability to VM If user wants to expose PASID capability in vIOMMU, then VFIO would also report the PASID cap for this device if the underlying hardware supports it as well. As a start, this chooses to put the vPASID cap in the last 8 bytes of the vconfig space. This is a choice in the good hope of no conflict with any existing cap or hidden registers. For the devices that has hidden registers, user should figure out a proper offset for the vPASID cap. This may require an option for user to config it. Here we leave it as a future extension. There are more discussions on the mechanism of finding the proper offset. https://lore.kernel.org/kvm/BN9PR11MB5276318969A212AD0649C7BE8CBE2@BN9PR11MB5276.namprd11.prod.outlook.com/ Signed-off-by: Yi Liu --- hw/pci/pcie.c | 12 ++++++++++++ hw/vfio/pci.c | 28 ++++++++++++++++++++++++++++ include/hw/pci/pcie.h | 4 ++++ 3 files changed, 44 insertions(+) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 04fbd794a8..a5b4e54bd7 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -1123,3 +1123,15 @@ void pcie_acs_reset(PCIDevice *dev) pci_set_word(dev->config + dev->exp.acs_cap + PCI_ACS_CTRL, 0); } } + +void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint16_t caps) +{ + pcie_add_capability(dev, PCI_EXT_CAP_ID_PASID, 1, + offset, PCI_EXT_CAP_PASID_SIZEOF); + + dev->exp.pasid_cap = offset; + + pci_set_word(dev->config + offset + PCI_PASID_CAP, caps); + + pci_set_word(dev->wmask + dev->exp.pasid_cap + PCI_PASID_CTRL, 0x7); +} diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index f585f285f4..293deb8737 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include CONFIG_DEVICES /* CONFIG_IOMMUFD */ #include +#include #include #include "hw/hw.h" @@ -2348,6 +2349,33 @@ static void vfio_add_ext_cap(VFIOPCIDevice *vdev) } + { + HostIOMMUDeviceCaps *caps = &vdev->vbasedev.hiod->caps; + + /* + * TODO: Add option for enabling pasid at a safe offset, this adds the + * pasid capability in the end of the PCIE config space. + */ + if (caps->max_pasid_log2 && pci_device_get_pasid_cap(&vdev->pdev)) { + uint16_t pasid_caps = (caps->max_pasid_log2 << 8) & PCI_PASID_CAP_WIDTH; + + if (caps->hw_caps & IOMMU_HW_CAP_PCI_PASID_EXEC) { + pasid_caps |= PCI_PASID_CAP_EXEC; + } + + if (caps->hw_caps & IOMMU_HW_CAP_PCI_PASID_PRIV) { + pasid_caps |= PCI_PASID_CAP_PRIV; + } + + pcie_pasid_init(pdev, + PCIE_CONFIG_SPACE_SIZE - PCI_EXT_CAP_PASID_SIZEOF, + pasid_caps); + + /* PASID capability is fully emulated by QEMU */ + memset(vdev->emulated_config_bits + pdev->exp.pasid_cap, 0xff, 8); + } + } + /* 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); diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index 11f5a91bbb..41ee27f023 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -79,6 +79,9 @@ struct PCIExpressDevice { uint16_t sriov_cap; PCIESriovPF sriov_pf; PCIESriovVF sriov_vf; + + /* Offset of PASID capability in config space */ + uint16_t pasid_cap; }; #define COMPAT_PROP_PCP "power_controller_present" @@ -147,4 +150,5 @@ void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); +void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint16_t caps); #endif /* QEMU_PCIE_H */ -- 2.41.0.windows.1