]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI/MSI: Add startup/shutdown for per device domains
authorInochi Amaoto <inochiama@gmail.com>
Wed, 13 Aug 2025 23:28:32 +0000 (07:28 +0800)
committerThomas Gleixner <tglx@linutronix.de>
Sat, 23 Aug 2025 19:21:13 +0000 (21:21 +0200)
As the RISC-V PLIC cannot apply affinity settings without invoking
irq_enable(), it will make the interrupt unavailble when used as an
underlying interrupt chip for the MSI controller.

Implement the irq_startup() and irq_shutdown() callbacks for the PCI MSI
and MSI-X templates.

For chips that specify MSI_FLAG_PCI_MSI_STARTUP_PARENT, the parent startup
and shutdown functions are invoked. That allows the interrupt on the parent
chip to be enabled if the interrupt has not been enabled during
allocation. This is necessary for MSI controllers which use PLIC as
underlying parent interrupt chip.

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Chen Wang <unicorn_wang@outlook.com> # Pioneerbox
Reviewed-by: Chen Wang <unicorn_wang@outlook.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://lore.kernel.org/all/20250813232835.43458-3-inochiama@gmail.com
drivers/pci/msi/irqdomain.c
include/linux/msi.h

index 0938ef7ebabf2d46400d412fb2feb446996f13ed..e0a800f918e81242f371a9ac806188806218df28 100644 (file)
@@ -148,6 +148,23 @@ static void pci_device_domain_set_desc(msi_alloc_info_t *arg, struct msi_desc *d
        arg->hwirq = desc->msi_index;
 }
 
+static void cond_shutdown_parent(struct irq_data *data)
+{
+       struct msi_domain_info *info = data->domain->host_data;
+
+       if (unlikely(info->flags & MSI_FLAG_PCI_MSI_STARTUP_PARENT))
+               irq_chip_shutdown_parent(data);
+}
+
+static unsigned int cond_startup_parent(struct irq_data *data)
+{
+       struct msi_domain_info *info = data->domain->host_data;
+
+       if (unlikely(info->flags & MSI_FLAG_PCI_MSI_STARTUP_PARENT))
+               return irq_chip_startup_parent(data);
+       return 0;
+}
+
 static __always_inline void cond_mask_parent(struct irq_data *data)
 {
        struct msi_domain_info *info = data->domain->host_data;
@@ -164,6 +181,23 @@ static __always_inline void cond_unmask_parent(struct irq_data *data)
                irq_chip_unmask_parent(data);
 }
 
+static void pci_irq_shutdown_msi(struct irq_data *data)
+{
+       struct msi_desc *desc = irq_data_get_msi_desc(data);
+
+       pci_msi_mask(desc, BIT(data->irq - desc->irq));
+       cond_shutdown_parent(data);
+}
+
+static unsigned int pci_irq_startup_msi(struct irq_data *data)
+{
+       struct msi_desc *desc = irq_data_get_msi_desc(data);
+       unsigned int ret = cond_startup_parent(data);
+
+       pci_msi_unmask(desc, BIT(data->irq - desc->irq));
+       return ret;
+}
+
 static void pci_irq_mask_msi(struct irq_data *data)
 {
        struct msi_desc *desc = irq_data_get_msi_desc(data);
@@ -194,6 +228,8 @@ static void pci_irq_unmask_msi(struct irq_data *data)
 static const struct msi_domain_template pci_msi_template = {
        .chip = {
                .name                   = "PCI-MSI",
+               .irq_startup            = pci_irq_startup_msi,
+               .irq_shutdown           = pci_irq_shutdown_msi,
                .irq_mask               = pci_irq_mask_msi,
                .irq_unmask             = pci_irq_unmask_msi,
                .irq_write_msi_msg      = pci_msi_domain_write_msg,
@@ -210,6 +246,20 @@ static const struct msi_domain_template pci_msi_template = {
        },
 };
 
+static void pci_irq_shutdown_msix(struct irq_data *data)
+{
+       pci_msix_mask(irq_data_get_msi_desc(data));
+       cond_shutdown_parent(data);
+}
+
+static unsigned int pci_irq_startup_msix(struct irq_data *data)
+{
+       unsigned int ret = cond_startup_parent(data);
+
+       pci_msix_unmask(irq_data_get_msi_desc(data));
+       return ret;
+}
+
 static void pci_irq_mask_msix(struct irq_data *data)
 {
        pci_msix_mask(irq_data_get_msi_desc(data));
@@ -234,6 +284,8 @@ EXPORT_SYMBOL_GPL(pci_msix_prepare_desc);
 static const struct msi_domain_template pci_msix_template = {
        .chip = {
                .name                   = "PCI-MSIX",
+               .irq_startup            = pci_irq_startup_msix,
+               .irq_shutdown           = pci_irq_shutdown_msix,
                .irq_mask               = pci_irq_mask_msix,
                .irq_unmask             = pci_irq_unmask_msix,
                .irq_write_msi_msg      = pci_msi_domain_write_msg,
index e5e86a8529fb6f75c2c30fcbbe009119b185d3a5..3111ba95fbde49afba1f90bf6f784462eab52f18 100644 (file)
@@ -568,6 +568,8 @@ enum {
        MSI_FLAG_PARENT_PM_DEV          = (1 << 8),
        /* Support for parent mask/unmask */
        MSI_FLAG_PCI_MSI_MASK_PARENT    = (1 << 9),
+       /* Support for parent startup/shutdown */
+       MSI_FLAG_PCI_MSI_STARTUP_PARENT = (1 << 10),
 
        /* Mask for the generic functionality */
        MSI_GENERIC_FLAGS_MASK          = GENMASK(15, 0),