summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTuan Phan <tphan@apm.com>2014-08-20 19:50:23 -0700
committerDaniel Silverstone <daniel.silverstone@codethink.co.uk>2015-01-27 09:54:59 +0000
commit3f733eb9deca9311645bf6f80f25fbc111abbd10 (patch)
tree2560492c625efa8ae6ee75d7c0c6a734a752d5f0
parent1572e6825565af3c3ea2230f1d52f20bd0e23b8b (diff)
downloadlinux-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.c20
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");
}