aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/controller/dwc/pcie-designware-host.c
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2018-11-13 22:57:34 +0000
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2018-12-11 10:37:58 +0000
commit3f7bb2ec20ce07c02b2002349d256c91a463fcc5 (patch)
tree6ac71be7712de7854c078116debcefb34fbcd6aa /drivers/pci/controller/dwc/pcie-designware-host.c
parentPCI: dwc: Take lock when ACKing an interrupt (diff)
downloadlinux-dev-3f7bb2ec20ce07c02b2002349d256c91a463fcc5.tar.xz
linux-dev-3f7bb2ec20ce07c02b2002349d256c91a463fcc5.zip
PCI: dwc: Move interrupt acking into the proper callback
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
Diffstat (limited to 'drivers/pci/controller/dwc/pcie-designware-host.c')
-rw-r--r--drivers/pci/controller/dwc/pcie-designware-host.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 610a5e018d27..0fa9e8fdce66 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -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);