summaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/dpc.c
diff options
context:
space:
mode:
authorOza Pawandeep <poza@codeaurora.org>2018-05-16 15:59:35 -0500
committerBjorn Helgaas <helgaas@kernel.org>2018-05-16 15:59:35 -0500
commit56abbf8ad73c89d0a4c3c84b1449ceaaabd1b8c7 (patch)
tree114cc4fd08d62d13bc157fbdf7bb96c8d56a8471 /drivers/pci/pcie/dpc.c
parent60cc43fc888428bb2f18f08997432d426a243338 (diff)
downloadlinux-56abbf8ad73c89d0a4c3c84b1449ceaaabd1b8c7.tar.bz2
PCI/DPC: Clear interrupt status in interrupt handler top half
The generic IRQ handling code ensures that an interrupt handler runs with its interrupt masked or disabled. If the interrupt is level-triggered, the interrupt handler must tell its device to stop asserting the interrupt before returning. If it doesn't, we will immediately take the interrupt again when the handler returns and the generic code unmasks the interrupt. The driver doesn't know whether its interrupt is edge- or level-triggered, so it must clear its interrupt source directly in its interrupt handler. Previously we cleared the DPC interrupt status in the bottom half, i.e., in deferred work, which can cause an interrupt storm if the DPC interrupt happens to be level-triggered, e.g., if we're using INTx instead of MSI. Clear the DPC interrupt status bit in the interrupt handler, not in the deferred work. Signed-off-by: Oza Pawandeep <poza@codeaurora.org> [bhelgaas: changelog] Signed-off-by: Bjorn Helgaas <helgaas@kernel.org> Reviewed-by: Keith Busch <keith.busch@intel.com>
Diffstat (limited to 'drivers/pci/pcie/dpc.c')
-rw-r--r--drivers/pci/pcie/dpc.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index 8c57d607e603..74562dbacbf1 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -113,7 +113,7 @@ static void dpc_work(struct work_struct *work)
}
pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
- PCI_EXP_DPC_STATUS_TRIGGER | PCI_EXP_DPC_STATUS_INTERRUPT);
+ PCI_EXP_DPC_STATUS_TRIGGER);
pci_read_config_word(pdev, cap + PCI_EXP_DPC_CTL, &ctl);
pci_write_config_word(pdev, cap + PCI_EXP_DPC_CTL,
@@ -223,6 +223,9 @@ static irqreturn_t dpc_irq(int irq, void *context)
if (dpc->rp_extensions && reason == 3 && ext_reason == 0)
dpc_process_rp_pio_error(dpc);
+ pci_write_config_word(pdev, cap + PCI_EXP_DPC_STATUS,
+ PCI_EXP_DPC_STATUS_INTERRUPT);
+
schedule_work(&dpc->work);
return IRQ_HANDLED;