genirq/msi: Add pointers for per device irq domains
authorThomas Gleixner <tglx@linutronix.de>
Thu, 24 Nov 2022 23:24:22 +0000 (00:24 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 5 Dec 2022 18:20:59 +0000 (19:20 +0100)
With the upcoming per device MSI interrupt domain support it is necessary
to store the domain pointers per device.

Instead of delegating that storage to device drivers or subsystems add a
domain pointer to the msi_dev_domain array in struct msi_device_data.

This pointer is also used to take care of tearing down the irq domains when
msi_device_data is cleaned up via devres.

The interfaces into the MSI core will be changed from irqdomain pointer
based interfaces to domain id based interfaces to support multiple MSI
domains on a single device (e.g. PCI/MSI[-X] and PCI/IMS.

Once the per device domain support is complete the irq domain pointer in
struct device::msi.domain will not longer contain a pointer to the "global"
MSI domain. It will contain a pointer to the MSI parent domain instead.

It would be a horrible maze of conditionals to evaluate all over the place
which domain pointer should be used, i.e. the "global" one in
device::msi::domain or one from the internal pointer array.

To avoid this evaluate in msi_setup_device_data() whether the irq domain
which is associated to a device is a "global" or a parent MSI domain. If it
is global then copy the pointer into the first entry of the msi_dev_domain
array.

This allows to convert interfaces and implementation to domain ids while
keeping everything existing working.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20221124230313.923860399@linutronix.de
include/linux/msi.h
kernel/irq/msi.c

index f7b9c41a4f54bf16c4063c02ceaa0c3ac9ab2472..fdbc80d81e260398a5a3c66cea2df977d43a947c 100644 (file)
@@ -77,6 +77,7 @@ struct msi_desc;
 struct pci_dev;
 struct platform_msi_priv_data;
 struct device_attribute;
+struct irq_domain;
 
 void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 #ifdef CONFIG_GENERIC_MSI_IRQ
@@ -177,9 +178,11 @@ enum msi_desc_filter {
 /**
  * struct msi_dev_domain - The internals of MSI domain info per device
  * @store:             Xarray for storing MSI descriptor pointers
+ * @irqdomain:         Pointer to a per device interrupt domain
  */
 struct msi_dev_domain {
        struct xarray           store;
+       struct irq_domain       *domain;
 };
 
 /**
index c2bc94ee5c3e1976095559f33235b56cdb8f924c..de65acc5cfb04440e238e85153060085316b8f7c 100644 (file)
@@ -220,6 +220,15 @@ int msi_setup_device_data(struct device *dev)
        for (i = 0; i < MSI_MAX_DEVICE_IRQDOMAINS; i++)
                xa_init(&md->__domains[i].store);
 
+       /*
+        * If @dev::msi::domain is set and is a global MSI domain, copy the
+        * pointer into the domain array so all code can operate on domain
+        * ids. The NULL pointer check is required to keep the legacy
+        * architecture specific PCI/MSI support working.
+        */
+       if (dev->msi.domain && !irq_domain_is_msi_parent(dev->msi.domain))
+               md->__domains[MSI_DEFAULT_DOMAIN].domain = dev->msi.domain;
+
        mutex_init(&md->mutex);
        dev->msi.data = md;
        devres_add(dev, md);