diff options
author | Tuan Phan <tphan@apm.com> | 2014-08-20 19:50:23 -0700 |
---|---|---|
committer | Daniel Silverstone <daniel.silverstone@codethink.co.uk> | 2015-01-27 09:54:59 +0000 |
commit | 3f733eb9deca9311645bf6f80f25fbc111abbd10 (patch) | |
tree | 2560492c625efa8ae6ee75d7c0c6a734a752d5f0 | |
parent | 1572e6825565af3c3ea2230f1d52f20bd0e23b8b (diff) | |
download | linux-3f733eb9deca9311645bf6f80f25fbc111abbd10.tar.gz |
UBUNTU: SAUCE: (no-up) pci-xgene-msi: fixed deadlock in irq_set_affinity
BugLink: http://bugs.launchpad.net/bugs/1359514
Issue: CPU affinity is changed while irqbalance is running.
+ Problem explanation:
- Old code
+ Call xgene_msi_cascade function (CPU x)
+ raw_spin_lock(&desc->lock); (CPU x)
+ Goto generic_handle_irq (CPU x)
+ The CPU x doesn't have a chance to exit the xgene_msi_cascade function to unlock desc->lock before Linux scheduce and call xgene_msi_set_affinity (irqbalance is caller) in the same CPU x
+ In irq_set_affinity, call raw_spin_lock_irqsave(&desc->lock, flags) which cause deadlock to CPU x because it disables preempt
- New code
+ Use chained_irq_enter and exit as the standard way to cascade interrupt functions.
Signed-off-by: Tuan Phan <tphan@apm.com>
Signed-off-by: Phong Vo <pvo@apm.com>
Signed-off-by: dann frazier <dann.frazier@canonical.com>
(fix for non-upstream driver)
Signed-off-by: Craig Magina <craig.magina@canonical.com>
-rw-r--r-- | drivers/pci/host/pci-xgene-msi.c | 20 |
1 files changed, 4 insertions, 16 deletions
diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c index f21c4590d4cc..9722d57af994 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/host/pci-xgene-msi.c @@ -25,6 +25,7 @@ #include <linux/platform_device.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> #include <linux/bootmem.h> #include <linux/msi.h> @@ -306,7 +307,6 @@ exit: static void xgene_msi_cascade(unsigned int irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); - struct irq_data *idata = irq_desc_get_irq_data(desc); struct xgene_msi_cascade_data *cascade_data; struct xgene_msi *msi_data; unsigned int cascade_irq; @@ -317,22 +317,18 @@ static void xgene_msi_cascade(unsigned int irq, struct irq_desc *desc) u32 msi_intr_reg; pr_debug("\nENTER %s, irq=%u\n", __func__, irq); + + chained_irq_enter(chip, desc); cascade_data = irq_get_handler_data(irq); msi_data = cascade_data->msi_data; pr_debug("xgene_msi : 0x%p, irq = %u\n", msi_data, irq); - raw_spin_lock(&desc->lock); - if (unlikely(irqd_irq_inprogress(idata))) - goto unlock; - msi_intr_reg = cascade_data->index; pr_debug("msi_intr_reg : %d\n", msi_intr_reg); if (msi_intr_reg >= NR_MSI_REG) cascade_irq = 0; - irqd_set_chained_irq_inprogress(idata); - switch (msi_data->feature & XGENE_PIC_IP_MASK) { case XGENE_PIC_IP_GIC: msi_intr_reg_value = xgene_msi_intr_read(msi_data->msi_regs, @@ -361,16 +357,8 @@ static void xgene_msi_cascade(unsigned int irq, struct irq_desc *desc) msi_intr_reg_value &= ~(1 << msir_index); pr_debug("msi_intr_reg_value : 0x%08x\n", msi_intr_reg_value); } - irqd_clr_chained_irq_inprogress(idata); - - switch (msi_data->feature & XGENE_PIC_IP_MASK) { - case XGENE_PIC_IP_GIC: - chip->irq_eoi(idata); - break; - } -unlock: - raw_spin_unlock(&desc->lock); + chained_irq_exit(chip, desc); pr_debug("EXIT\n"); } |