diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2018-11-13 17:57:32 -0500 |
---|---|---|
committer | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2018-12-11 05:37:13 -0500 |
commit | 830920e065e90db318a0da98bf13a02b641eae7f (patch) | |
tree | e86e65c8c848e45a72f75bd863a4bb7b253b3c0c /drivers/pci/controller/dwc/pcie-designware-host.c | |
parent | 651022382c7f8da46cb4872a545ee1da6d097d2a (diff) |
PCI: dwc: Use interrupt masking instead of disabling
The dwc driver is showing an interesting level of brokeness, as it
insists on using the enable/disable set of registers to mask/unmask
MSIs, meaning that an MSIs being generated while the interrupt is in
that "disabled" state will simply be lost.
Let's move to the mask/unmask set of registers, which offers the
expected semantics.
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/
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.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 29a05759a294..0f81b7169147 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c | |||
@@ -168,8 +168,8 @@ static void dw_pci_bottom_mask(struct irq_data *data) | |||
168 | bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL; | 168 | bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL; |
169 | 169 | ||
170 | pp->irq_status[ctrl] &= ~(1 << bit); | 170 | pp->irq_status[ctrl] &= ~(1 << bit); |
171 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, | 171 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, |
172 | pp->irq_status[ctrl]); | 172 | ~pp->irq_status[ctrl]); |
173 | } | 173 | } |
174 | 174 | ||
175 | raw_spin_unlock_irqrestore(&pp->lock, flags); | 175 | raw_spin_unlock_irqrestore(&pp->lock, flags); |
@@ -191,8 +191,8 @@ static void dw_pci_bottom_unmask(struct irq_data *data) | |||
191 | bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL; | 191 | bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL; |
192 | 192 | ||
193 | pp->irq_status[ctrl] |= 1 << bit; | 193 | pp->irq_status[ctrl] |= 1 << bit; |
194 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, | 194 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4, |
195 | pp->irq_status[ctrl]); | 195 | ~pp->irq_status[ctrl]); |
196 | } | 196 | } |
197 | 197 | ||
198 | raw_spin_unlock_irqrestore(&pp->lock, flags); | 198 | raw_spin_unlock_irqrestore(&pp->lock, flags); |
@@ -658,10 +658,15 @@ void dw_pcie_setup_rc(struct pcie_port *pp) | |||
658 | num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; | 658 | num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL; |
659 | 659 | ||
660 | /* Initialize IRQ Status array */ | 660 | /* Initialize IRQ Status array */ |
661 | for (ctrl = 0; ctrl < num_ctrls; ctrl++) | 661 | for (ctrl = 0; ctrl < num_ctrls; ctrl++) { |
662 | dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + | 662 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + |
663 | (ctrl * MSI_REG_CTRL_BLOCK_SIZE), | 663 | (ctrl * MSI_REG_CTRL_BLOCK_SIZE), |
664 | 4, &pp->irq_status[ctrl]); | 664 | 4, ~0); |
665 | dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + | ||
666 | (ctrl * MSI_REG_CTRL_BLOCK_SIZE), | ||
667 | 4, ~0); | ||
668 | pp->irq_status[ctrl] = 0; | ||
669 | } | ||
665 | 670 | ||
666 | /* Setup RC BARs */ | 671 | /* Setup RC BARs */ |
667 | dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004); | 672 | dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004); |