Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61791244 authored by Russell King's avatar Russell King
Browse files

ARM: irq migration: ensure migration is handled safely



Ensure appropriate locks are taken to ensure that IRQ migration off
the current CPU is race-free.  We may have a concurrent set_affinity
via procfs running on another CPU in parallel with the IRQ migration,
resulting in unpredictable results.

Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 1dbfa187
Loading
Loading
Loading
Loading
+31 −19
Original line number Diff line number Diff line
@@ -179,14 +179,21 @@ int __init arch_probe_nr_irqs(void)

#ifdef CONFIG_HOTPLUG_CPU

static void route_irq(struct irq_desc *desc, unsigned int irq, unsigned int cpu)
static bool migrate_one_irq(struct irq_data *d)
{
	pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", irq, desc->irq_data.node, cpu);
	unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask);
	bool ret = false;

	raw_spin_lock_irq(&desc->lock);
	desc->irq_data.chip->irq_set_affinity(&desc->irq_data,
					      cpumask_of(cpu), true);
	raw_spin_unlock_irq(&desc->lock);
	if (cpu >= nr_cpu_ids) {
		cpu = cpumask_any(cpu_online_mask);
		ret = true;
	}

	pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu);

	d->chip->irq_set_affinity(d, cpumask_of(cpu), true);

	return ret;
}

/*
@@ -198,25 +205,30 @@ void migrate_irqs(void)
{
	unsigned int i, cpu = smp_processor_id();
	struct irq_desc *desc;
	unsigned long flags;

	local_irq_save(flags);

	for_each_irq_desc(i, desc) {
		struct irq_data *d = &desc->irq_data;
		bool affinity_broken = false;

		if (d->node == cpu) {
			unsigned int newcpu = cpumask_any_and(d->affinity,
							      cpu_online_mask);
			if (newcpu >= nr_cpu_ids) {
				if (printk_ratelimit())
					printk(KERN_INFO "IRQ%u no longer affine to CPU%u\n",
					       i, cpu);
		raw_spin_lock(&desc->lock);
		do {
			if (desc->action == NULL)
				break;

				cpumask_setall(d->affinity);
				newcpu = cpumask_any_and(d->affinity,
							 cpu_online_mask);
			}
			if (d->node != cpu)
				break;

			route_irq(desc, i, newcpu);
		}
			affinity_broken = migrate_one_irq(d);
		} while (0);
		raw_spin_unlock(&desc->lock);

		if (affinity_broken && printk_ratelimit())
			pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu);
	}

	local_irq_restore(flags);
}
#endif /* CONFIG_HOTPLUG_CPU */