aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Westerberg2016-10-03 05:17:08 -0500
committerGreg Kroah-Hartman2016-10-16 10:36:15 -0500
commiteba90a4c76b91db06c307035c06b20dbcb5fa487 (patch)
tree5dab5e1ff3fbb350dfa210248aca39af7716e764
parent09634475c76af9841dbd209f66cc34cc50877176 (diff)
downloadgraphics-kernel-feature-tree-eba90a4c76b91db06c307035c06b20dbcb5fa487.tar.gz
graphics-kernel-feature-tree-eba90a4c76b91db06c307035c06b20dbcb5fa487.tar.xz
graphics-kernel-feature-tree-eba90a4c76b91db06c307035c06b20dbcb5fa487.zip
x86/irq: Prevent force migration of irqs which are not in the vector domain
commit db91aa793ff984ac048e199ea1c54202543952fe upstream. When a CPU is about to be offlined we call fixup_irqs() that resets IRQ affinities related to the CPU in question. The same thing is also done when the system is suspended to S-states like S3 (mem). For each IRQ we try to complete any on-going move regardless whether the IRQ is actually part of x86_vector_domain. For each IRQ descriptor we fetch its chip_data, assume it is of type struct apic_chip_data and manipulate it by clearing old_domain mask etc. For irq_chips that are not part of the x86_vector_domain, like those created by various GPIO drivers, will find their chip_data being changed unexpectly. Below is an example where GPIO chip owned by pinctrl-sunrisepoint.c gets corrupted after resume: # cat /sys/kernel/debug/gpio gpiochip0: GPIOs 360-511, parent: platform/INT344B:00, INT344B:00: gpio-511 ( |sysfs ) in hi # rtcwake -s10 -mmem <10 seconds passes> # cat /sys/kernel/debug/gpio gpiochip0: GPIOs 360-511, parent: platform/INT344B:00, INT344B:00: gpio-511 ( |sysfs ) in ? Note '?' in the output. It means the struct gpio_chip ->get function is NULL whereas before suspend it was there. Fix this by first checking that the IRQ belongs to x86_vector_domain before we try to use the chip_data as struct apic_chip_data. Reported-and-tested-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Link: http://lkml.kernel.org/r/20161003101708.34795-1-mika.westerberg@linux.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--arch/x86/kernel/apic/vector.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index df6b4eeac0bd..0988e204f1e3 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -659,11 +659,28 @@ void irq_complete_move(struct irq_cfg *cfg)
659 */ 659 */
660void irq_force_complete_move(struct irq_desc *desc) 660void irq_force_complete_move(struct irq_desc *desc)
661{ 661{
662 struct irq_data *irqdata = irq_desc_get_irq_data(desc); 662 struct irq_data *irqdata;
663 struct apic_chip_data *data = apic_chip_data(irqdata); 663 struct apic_chip_data *data;
664 struct irq_cfg *cfg = data ? &data->cfg : NULL; 664 struct irq_cfg *cfg;
665 unsigned int cpu; 665 unsigned int cpu;
666 666
667 /*
668 * The function is called for all descriptors regardless of which
669 * irqdomain they belong to. For example if an IRQ is provided by
670 * an irq_chip as part of a GPIO driver, the chip data for that
671 * descriptor is specific to the irq_chip in question.
672 *
673 * Check first that the chip_data is what we expect
674 * (apic_chip_data) before touching it any further.
675 */
676 irqdata = irq_domain_get_irq_data(x86_vector_domain,
677 irq_desc_get_irq(desc));
678 if (!irqdata)
679 return;
680
681 data = apic_chip_data(irqdata);
682 cfg = data ? &data->cfg : NULL;
683
667 if (!cfg) 684 if (!cfg)
668 return; 685 return;
669 686