115 lines
4.0 KiB
Diff
115 lines
4.0 KiB
Diff
|
|
From da7cdc41aa3813f6bb1c87ced178f60185dac692 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Yi Liu <yi.l.liu@intel.com>
|
||
|
|
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 <yi.l.liu@intel.com>
|
||
|
|
---
|
||
|
|
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 <linux/vfio.h>
|
||
|
|
+#include <linux/iommufd.h>
|
||
|
|
#include <sys/ioctl.h>
|
||
|
|
|
||
|
|
#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
|
||
|
|
|