1 /* 2 * Generic cpu hotunplug interrupt migration code copied from the 3 * arch/arm implementation 4 * 5 * Copyright (C) Russell King 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 #include <linux/interrupt.h> 12 #include <linux/ratelimit.h> 13 #include <linux/irq.h> 14 15 #include "internals.h" 16 17 static bool migrate_one_irq(struct irq_desc *desc) 18 { 19 struct irq_data *d = irq_desc_get_irq_data(desc); 20 const struct cpumask *affinity = d->common->affinity; 21 struct irq_chip *c; 22 bool ret = false; 23 24 /* 25 * If this is a per-CPU interrupt, or the affinity does not 26 * include this CPU, then we have nothing to do. 27 */ 28 if (irqd_is_per_cpu(d) || 29 !cpumask_test_cpu(smp_processor_id(), affinity)) 30 return false; 31 32 if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) { 33 affinity = cpu_online_mask; 34 ret = true; 35 } 36 37 c = irq_data_get_irq_chip(d); 38 if (!c->irq_set_affinity) { 39 pr_debug("IRQ%u: unable to set affinity\n", d->irq); 40 } else { 41 int r = irq_do_set_affinity(d, affinity, false); 42 if (r) 43 pr_warn_ratelimited("IRQ%u: set affinity failed(%d).\n", 44 d->irq, r); 45 } 46 47 return ret; 48 } 49 50 /** 51 * irq_migrate_all_off_this_cpu - Migrate irqs away from offline cpu 52 * 53 * The current CPU has been marked offline. Migrate IRQs off this CPU. 54 * If the affinity settings do not allow other CPUs, force them onto any 55 * available CPU. 56 * 57 * Note: we must iterate over all IRQs, whether they have an attached 58 * action structure or not, as we need to get chained interrupts too. 59 */ 60 void irq_migrate_all_off_this_cpu(void) 61 { 62 unsigned int irq; 63 struct irq_desc *desc; 64 unsigned long flags; 65 66 local_irq_save(flags); 67 68 for_each_active_irq(irq) { 69 bool affinity_broken; 70 71 desc = irq_to_desc(irq); 72 raw_spin_lock(&desc->lock); 73 affinity_broken = migrate_one_irq(desc); 74 raw_spin_unlock(&desc->lock); 75 76 if (affinity_broken) 77 pr_warn_ratelimited("IRQ%u no longer affine to CPU%u\n", 78 irq, smp_processor_id()); 79 } 80 81 local_irq_restore(flags); 82 } 83