[OEM-B] [PATCH 1/7] PCI/DPC: Clear interrupt status in interrupt handler top half
Kai-Heng Feng
kai.heng.feng at canonical.com
Tue Nov 26 08:51:43 UTC 2019
From: Oza Pawandeep <poza at codeaurora.org>
BugLink: https://bugs.launchpad.net/bugs/1853991
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 at codeaurora.org>
[bhelgaas: changelog]
Signed-off-by: Bjorn Helgaas <helgaas at kernel.org>
Reviewed-by: Keith Busch <keith.busch at intel.com>
(backported from commit 56abbf8ad73c89d0a4c3c84b1449ceaaabd1b8c7)
Signed-off-by: Kai-Heng Feng <kai.heng.feng at canonical.com>
---
drivers/pci/pcie/dpc.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c
index de937ea6d138..0292d7387454 100644
--- a/drivers/pci/pcie/dpc.c
+++ b/drivers/pci/pcie/dpc.c
@@ -126,7 +126,7 @@ static void interrupt_event_handler(struct work_struct *work)
}
pci_write_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS,
- PCI_EXP_DPC_STATUS_TRIGGER | PCI_EXP_DPC_STATUS_INTERRUPT);
+ PCI_EXP_DPC_STATUS_TRIGGER);
}
static void dpc_rp_pio_print_tlp_header(struct device *dev,
@@ -241,7 +241,7 @@ static irqreturn_t dpc_irq(int irq, void *context)
struct dpc_dev *dpc = (struct dpc_dev *)context;
struct pci_dev *pdev = dpc->dev->port;
struct device *dev = &dpc->dev->device;
- u16 status, source;
+ u16 cap = dpc->cap_pos, status, source;
pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_STATUS, &status);
pci_read_config_word(pdev, dpc->cap_pos + PCI_EXP_DPC_SOURCE_ID,
@@ -267,6 +267,9 @@ static irqreturn_t dpc_irq(int irq, void *context)
if (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;
--
2.17.1
More information about the kernel-team
mailing list