aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/irq.c')
-rw-r--r--arch/arm/kernel/irq.c51
1 files changed, 30 insertions, 21 deletions
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 83bbad03fcc..0f928a131af 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -131,54 +131,63 @@ int __init arch_probe_nr_irqs(void)
131 131
132#ifdef CONFIG_HOTPLUG_CPU 132#ifdef CONFIG_HOTPLUG_CPU
133 133
134static bool migrate_one_irq(struct irq_data *d) 134static bool migrate_one_irq(struct irq_desc *desc)
135{ 135{
136 unsigned int cpu = cpumask_any_and(d->affinity, cpu_online_mask); 136 struct irq_data *d = irq_desc_get_irq_data(desc);
137 const struct cpumask *affinity = d->affinity;
138 struct irq_chip *c;
137 bool ret = false; 139 bool ret = false;
138 140
139 if (cpu >= nr_cpu_ids) { 141 /*
140 cpu = cpumask_any(cpu_online_mask); 142 * If this is a per-CPU interrupt, or the affinity does not
143 * include this CPU, then we have nothing to do.
144 */
145 if (irqd_is_per_cpu(d) || !cpumask_test_cpu(smp_processor_id(), affinity))
146 return false;
147
148 if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
149 affinity = cpu_online_mask;
141 ret = true; 150 ret = true;
142 } 151 }
143 152
144 pr_debug("IRQ%u: moving from cpu%u to cpu%u\n", d->irq, d->node, cpu); 153 c = irq_data_get_irq_chip(d);
145 154 if (c->irq_set_affinity)
146 d->chip->irq_set_affinity(d, cpumask_of(cpu), true); 155 c->irq_set_affinity(d, affinity, true);
156 else
157 pr_debug("IRQ%u: unable to set affinity\n", d->irq);
147 158
148 return ret; 159 return ret;
149} 160}
150 161
151/* 162/*
152 * The CPU has been marked offline. Migrate IRQs off this CPU. If 163 * The current CPU has been marked offline. Migrate IRQs off this CPU.
153 * the affinity settings do not allow other CPUs, force them onto any 164 * If the affinity settings do not allow other CPUs, force them onto any
154 * available CPU. 165 * available CPU.
166 *
167 * Note: we must iterate over all IRQs, whether they have an attached
168 * action structure or not, as we need to get chained interrupts too.
155 */ 169 */
156void migrate_irqs(void) 170void migrate_irqs(void)
157{ 171{
158 unsigned int i, cpu = smp_processor_id(); 172 unsigned int i;
159 struct irq_desc *desc; 173 struct irq_desc *desc;
160 unsigned long flags; 174 unsigned long flags;
161 175
162 local_irq_save(flags); 176 local_irq_save(flags);
163 177
164 for_each_irq_desc(i, desc) { 178 for_each_irq_desc(i, desc) {
165 struct irq_data *d = &desc->irq_data;
166 bool affinity_broken = false; 179 bool affinity_broken = false;
167 180
168 raw_spin_lock(&desc->lock); 181 if (!desc)
169 do { 182 continue;
170 if (desc->action == NULL)
171 break;
172
173 if (d->node != cpu)
174 break;
175 183
176 affinity_broken = migrate_one_irq(d); 184 raw_spin_lock(&desc->lock);
177 } while (0); 185 affinity_broken = migrate_one_irq(desc);
178 raw_spin_unlock(&desc->lock); 186 raw_spin_unlock(&desc->lock);
179 187
180 if (affinity_broken && printk_ratelimit()) 188 if (affinity_broken && printk_ratelimit())
181 pr_warning("IRQ%u no longer affine to CPU%u\n", i, cpu); 189 pr_warning("IRQ%u no longer affine to CPU%u\n", i,
190 smp_processor_id());
182 } 191 }
183 192
184 local_irq_restore(flags); 193 local_irq_restore(flags);