aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2018-11-13 22:57:34 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-01-26 09:37:07 +0100
commit413cb66bbb700adb356b7eb47cc7c843fe20a364 (patch)
tree2aa30df58e625cb9222249f9fdc05506f923c5d1
parente89ec9b92f9b75b44e1ff9f52dab48bd01834ed6 (diff)
download96b-common-413cb66bbb700adb356b7eb47cc7c843fe20a364.tar.gz
PCI: dwc: Move interrupt acking into the proper callback
commit 3f7bb2ec20ce07c02b2002349d256c91a463fcc5 upstream. 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 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/pci/dwc/pcie-designware-host.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/pci/dwc/pcie-designware-host.c b/drivers/pci/dwc/pcie-designware-host.c
index bc3e2d8d0cce..58b38c54a7cf 100644
--- a/drivers/pci/dwc/pcie-designware-host.c
+++ b/drivers/pci/dwc/pcie-designware-host.c
@@ -45,8 +45,19 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
return dw_pcie_write(pci->dbi_base + where, size, val);
}
+static void dwc_irq_ack(struct irq_data *d)
+{
+ struct msi_desc *msi = irq_data_get_msi_desc(d);
+ struct pcie_port *pp = msi_desc_to_pci_sysdata(msi);
+ int pos = d->hwirq % 32;
+ int i = d->hwirq / 32;
+
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, BIT(pos));
+}
+
static struct irq_chip dw_msi_irq_chip = {
.name = "PCI-MSI",
+ .irq_ack = dwc_irq_ack,
.irq_enable = pci_msi_unmask_irq,
.irq_disable = pci_msi_mask_irq,
.irq_mask = pci_msi_mask_irq,
@@ -72,8 +83,6 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
pos)) != 32) {
irq = irq_find_mapping(pp->irq_domain, i * 32 + pos);
generic_handle_irq(irq);
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12,
- 4, 1 << pos);
pos++;
}
}
@@ -263,7 +272,7 @@ static struct msi_controller dw_pcie_msi_chip = {
static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq)
{
- irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
+ irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_edge_irq);
irq_set_chip_data(irq, domain->host_data);
return 0;