Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 413cb66b authored by Marc Zyngier's avatar Marc Zyngier Committed by Greg Kroah-Hartman
Browse files

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: 8c934095 ("PCI: dwc: Clear MSI interrupt status after it is handled,
not before")
Fixes: 7c5925af ("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: default avatarTrent Piepho <tpiepho@impinj.com>
Tested-by: default avatarNiklas Cassel <niklas.cassel@linaro.org>
Tested-by: default avatarGustavo Pimentel <gustavo.pimentel@synopsys.com>
Tested-by: default avatarStanimir Varbanov <svarbanov@mm-sol.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
[lorenzo.pieralisi@arm.com: updated commit log]
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e89ec9b9
Loading
Loading
Loading
Loading
+12 −3
Original line number Original line Diff line number Diff line
@@ -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);
	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 = {
static struct irq_chip dw_msi_irq_chip = {
	.name = "PCI-MSI",
	.name = "PCI-MSI",
	.irq_ack = dwc_irq_ack,
	.irq_enable = pci_msi_unmask_irq,
	.irq_enable = pci_msi_unmask_irq,
	.irq_disable = pci_msi_mask_irq,
	.irq_disable = pci_msi_mask_irq,
	.irq_mask = 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) {
					    pos)) != 32) {
			irq = irq_find_mapping(pp->irq_domain, i * 32 + pos);
			irq = irq_find_mapping(pp->irq_domain, i * 32 + pos);
			generic_handle_irq(irq);
			generic_handle_irq(irq);
			dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12,
					    4, 1 << pos);
			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,
static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
			   irq_hw_number_t hwirq)
			   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);
	irq_set_chip_data(irq, domain->host_data);


	return 0;
	return 0;