PCI: dwc: Move interrupt acking into the proper callback
authorMarc Zyngier <marc.zyngier@arm.com>
Tue, 13 Nov 2018 22:57:34 +0000 (22:57 +0000)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tue, 11 Dec 2018 10:37:58 +0000 (10:37 +0000)
The write to the status register is really an ACK for the HW,
and should be treated as such by the driver. Let's move it to the
irq_ack() callback, which will prevent people from moving it around
in order to paper over other bugs.

Fixes: 8c934095fa2f ("PCI: dwc: Clear MSI interrupt status after it is handled,
not before")
Fixes: 7c5925afbc58 ("PCI: dwc: Move MSI IRQs allocation to IRQ domains
hierarchical API")
Link: https://lore.kernel.org/linux-pci/20181113225734.8026-1-marc.zyngier@arm.com/
Reported-by: Trent Piepho <tpiepho@impinj.com>
Tested-by: Niklas Cassel <niklas.cassel@linaro.org>
Tested-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
Tested-by: Stanimir Varbanov <svarbanov@mm-sol.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
[lorenzo.pieralisi@arm.com: updated commit log]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: stable@vger.kernel.org
drivers/pci/controller/dwc/pcie-designware-host.c

index 610a5e0..0fa9e8f 100644 (file)
@@ -99,9 +99,6 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
                                               (i * MAX_MSI_IRQS_PER_CTRL) +
                                               pos);
                        generic_handle_irq(irq);
-                       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS +
-                                               (i * MSI_REG_CTRL_BLOCK_SIZE),
-                                           4, 1 << pos);
                        pos++;
                }
        }
@@ -200,14 +197,18 @@ static void dw_pci_bottom_unmask(struct irq_data *data)
 
 static void dw_pci_bottom_ack(struct irq_data *d)
 {
-       struct msi_desc *msi = irq_data_get_msi_desc(d);
-       struct pcie_port *pp;
+       struct pcie_port *pp  = irq_data_get_irq_chip_data(d);
+       unsigned int res, bit, ctrl;
        unsigned long flags;
 
-       pp = msi_desc_to_pci_sysdata(msi);
+       ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
+       res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+       bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
 
        raw_spin_lock_irqsave(&pp->lock, flags);
 
+       dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, 1 << bit);
+
        if (pp->ops->msi_irq_ack)
                pp->ops->msi_irq_ack(d->hwirq, pp);