[PATCH v5 7/7] PCI/MSI: re-enable conditional parent mask/unmask with sw moderation
Luigi Rizzo <[email protected]>
| Newsgroups | org.kernel.vger.linux-pci,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Recent commits removed masking of interrupts at the PCIe level when the masking is also done at the parent (e.g. on ARM with GIC). This optimization saves the PCIe write, and especially the expensive readback, but causes the device to still send MSI interrupts that are ignored. As a result, it very harmful on platforms (many, for multiple architectures) that are unable to deal with too many MSI interrupts, and defeats GSIM (CONFIG_IRQ_SW_MODERATION), which is esplicitely designed to address this problem, but depends on masking interrupts at the PCIe level. Revert to the old behavior when GSIM (CONFIG_IRQ_SW_MODERATION) is compiled in. Signed-off-by: Luigi Rizzo <[email protected]> --- drivers/irqchip/irq-msi-lib.c | 8 ++++++++ drivers/pci/msi/irqdomain.c | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/drivers/irqchip/irq-msi-lib.c b/drivers/irqchip/irq-msi-lib.c index 45e0ed3134ce1..453a5d5a2c106 100644 --- a/drivers/irqchip/irq-msi-lib.c +++ b/drivers/irqchip/irq-msi-lib.c @@ -116,6 +116,14 @@ bool msi_lib_init_dev_msi_info(struct device *dev, struct irq_domain *domain, if (!chip->irq_set_affinity && !(info->flags & MSI_FLAG_NO_AFFINITY)) chip->irq_set_affinity = msi_domain_set_affinity; + /* + * The problem addressed by software moderation depends on actually + * masking at the PCI level. irq_mask() can be optimized separately + * for the common cases outside the move/teardown paths. + */ + if (IS_ENABLED(CONFIG_IRQ_SW_MODERATION)) + return true; + /* * If the parent domain insists on being in charge of masking, obey * blindly. The interrupt is un-masked at the PCI level on startup diff --git a/drivers/pci/msi/irqdomain.c b/drivers/pci/msi/irqdomain.c index 6e65f0f44112e..44b022fee7f1a 100644 --- a/drivers/pci/msi/irqdomain.c +++ b/drivers/pci/msi/irqdomain.c @@ -80,6 +80,22 @@ static unsigned int cond_startup_parent(struct irq_data *data) return 0; } +static __always_inline void cond_mask_parent(struct irq_data *data) +{ + struct msi_domain_info *info = data->domain->host_data; + + if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT)) + irq_chip_mask_parent(data); +} + +static __always_inline void cond_unmask_parent(struct irq_data *data) +{ + struct msi_domain_info *info = data->domain->host_data; + + if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT)) + 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); @@ -102,12 +118,14 @@ static void pci_irq_mask_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_mask_parent(data); } static void pci_irq_unmask_msi(struct irq_data *data) { struct msi_desc *desc = irq_data_get_msi_desc(data); + cond_unmask_parent(data); pci_msi_unmask(desc, BIT(data->irq - desc->irq)); } @@ -160,10 +178,12 @@ static unsigned int pci_irq_startup_msix(struct irq_data *data) static void pci_irq_mask_msix(struct irq_data *data) { pci_msix_mask(irq_data_get_msi_desc(data)); + cond_mask_parent(data); } static void pci_irq_unmask_msix(struct irq_data *data) { + cond_unmask_parent(data); pci_msix_unmask(irq_data_get_msi_desc(data)); } -- 2.55.0.737.g08866a6d13-goog