[RFC PATCH v2 1/1] platform-msi: Add platform check for subdevice irq domain

From: Lu Baolu
Date: Tue Jan 05 2021 - 21:38:25 EST


The pci_subdevice_msi_create_irq_domain() should fail if the underlying
platform is not able to support IMS (Interrupt Message Storage). Otherwise,
the isolation of interrupt is not guaranteed.

For x86, IMS is only supported on bare metal for now. We could enable it
in the virtualization environments in the future if interrupt HYPERCALL
domain is supported or the hardware has the capability of interrupt
isolation for subdevices.

Suggested-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Link: https://lore.kernel.org/linux-pci/87pn4nk7nn.fsf@xxxxxxxxxxxxxxxxxxxxxxx/
Link: https://lore.kernel.org/linux-pci/877dqrnzr3.fsf@xxxxxxxxxxxxxxxxxxxxxxx/
Link: https://lore.kernel.org/linux-pci/877dqqmc2h.fsf@xxxxxxxxxxxxxxxxxxxxxxx/
Signed-off-by: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx>
---
arch/x86/pci/common.c | 47 +++++++++++++++++++++++++++++++++++++
drivers/base/platform-msi.c | 8 +++++++
include/linux/msi.h | 1 +
3 files changed, 56 insertions(+)


Background:
Learnt from the discussions in this thread:

https://lore.kernel.org/linux-pci/160408357912.912050.17005584526266191420.stgit@xxxxxxxxxxxxxxxxxxxxxxxxxx/

The device IMS (Interrupt Message Storage) should not be enabled in any
virtualization environments unless there is a HYPERCALL domain which
makes the changes in the message store managed by the hypervisor.

As the initial step, we allow the IMS to be enabled only if we are
running on the bare metal. It's easy to enable IMS in the virtualization
environments if above preconditions are met in the future.

We ever thought about moving on_bare_metal() to a generic file so that
it could be well maintained and used. But we need some suggestions about
where to put it. Your comments are very appreciated.

This patch is only for comments purpose. Please don't merge it. We will
include it in the Intel IMS implementation later once we reach a
consensus.

Change log:
v1->v2:
- v1:
https://lore.kernel.org/linux-pci/20201210004624.345282-1-baolu.lu@xxxxxxxxxxxxxxx/
- Rename probably_on_bare_metal() with on_bare_metal();
- Some vendors might use the same name for both bare metal and virtual
environment. Before we add vendor specific code to distinguish
between them, let's return false in on_bare_metal(). This won't
introduce any regression. The only impact is that the coming new
platform msi feature won't be supported until the vendor specific code
is provided.

Best regards,
baolu

diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 3507f456fcd0..963e0401f2b2 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -724,3 +724,50 @@ struct pci_dev *pci_real_dma_dev(struct pci_dev *dev)
return dev;
}
#endif
+
+/*
+ * We want to figure out which context we are running in. But the hardware
+ * does not introduce a reliable way (instruction, CPUID leaf, MSR, whatever)
+ * which can be manipulated by the VMM to let the OS figure out where it runs.
+ * So we go with the below probably on_bare_metal() function as a replacement
+ * for definitely on_bare_metal() to go forward only for the very simple reason
+ * that this is the only option we have.
+ *
+ * People might use the same vendor name for both bare metal and virtual
+ * environment. We can remove those names once we have vendor specific code to
+ * distinguish between them.
+ */
+static const char * const vmm_vendor_name[] = {
+ "QEMU", "Bochs", "KVM", "Xen", "VMware", "VMW", "VMware Inc.",
+ "innotek GmbH", "Oracle Corporation", "Parallels", "BHYVE",
+ "Microsoft Corporation", "Amazon EC2"
+};
+
+static bool on_bare_metal(void)
+{
+ int i;
+
+ if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(vmm_vendor_name); i++)
+ if (dmi_match(DMI_SYS_VENDOR, vmm_vendor_name[i]))
+ return false;
+
+ pr_info("System running on bare metal, report to bugzilla.kernel.org if not the case.");
+
+ return true;
+}
+
+bool arch_support_pci_device_ims(struct pci_dev *pdev)
+{
+ /*
+ * When we are running in a VMM context, the device IMS could only be
+ * enabled when the underlying hardware supports interrupt isolation
+ * of the subdevice, or any mechanism (trap, hypercall) is added so
+ * that changes in the interrupt message store could be managed by the
+ * VMM. For now, we only support the device IMS when we are running on
+ * the bare metal.
+ */
+ return on_bare_metal();
+}
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index 8432a1bf4e28..88e5fe4dae67 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -512,6 +512,11 @@ struct irq_domain *device_msi_create_irq_domain(struct fwnode_handle *fn,
#ifdef CONFIG_PCI
#include <linux/pci.h>

+bool __weak arch_support_pci_device_ims(struct pci_dev *pdev)
+{
+ return false;
+}
+
/**
* pci_subdevice_msi_create_irq_domain - Create an irq domain for subdevices
* @pdev: Pointer to PCI device for which the subdevice domain is created
@@ -523,6 +528,9 @@ struct irq_domain *pci_subdevice_msi_create_irq_domain(struct pci_dev *pdev,
struct irq_domain *domain, *pdev_msi;
struct fwnode_handle *fn;

+ if (!arch_support_pci_device_ims(pdev))
+ return NULL;
+
/*
* Retrieve the MSI domain of the underlying PCI device's MSI
* domain. The PCI device domain's parent domain is also the parent
diff --git a/include/linux/msi.h b/include/linux/msi.h
index f319d7c6a4ef..6fda81c4b859 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -478,6 +478,7 @@ struct irq_domain *device_msi_create_irq_domain(struct fwnode_handle *fn,
struct irq_domain *parent);

# ifdef CONFIG_PCI
+bool arch_support_pci_device_ims(struct pci_dev *pdev);
struct irq_domain *pci_subdevice_msi_create_irq_domain(struct pci_dev *pdev,
struct msi_domain_info *info);
# endif
--
2.25.1