···1414#include <linux/smp.h>1515#include <linux/percpu.h>1616#include <linux/hrtimer.h>1717+#include <linux/kref.h>1818+#include <linux/workqueue.h>17191820#include <asm/atomic.h>1921#include <asm/ptrace.h>···242240extern int irq_select_affinity(unsigned int irq);243241244242extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m);243243+244244+/**245245+ * struct irq_affinity_notify - context for notification of IRQ affinity changes246246+ * @irq: Interrupt to which notification applies247247+ * @kref: Reference count, for internal use248248+ * @work: Work item, for internal use249249+ * @notify: Function to be called on change. This will be250250+ * called in process context.251251+ * @release: Function to be called on release. This will be252252+ * called in process context. Once registered, the253253+ * structure must only be freed when this function is254254+ * called or later.255255+ */256256+struct irq_affinity_notify {257257+ unsigned int irq;258258+ struct kref kref;259259+ struct work_struct work;260260+ void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask);261261+ void (*release)(struct kref *ref);262262+};263263+264264+extern int265265+irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify);266266+267267+static inline void irq_run_affinity_notifiers(void)268268+{269269+ flush_scheduled_work();270270+}271271+245272#else /* CONFIG_SMP */246273247274static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m)···286255static inline int irq_select_affinity(unsigned int irq) { return 0; }287256288257static inline int irq_set_affinity_hint(unsigned int irq,289289- const struct cpumask *m)258258+ const struct cpumask *m)290259{291260 return -EINVAL;292261}
+3
include/linux/irqdesc.h
···88 * For now it's included from <linux/irq.h>99 */10101111+struct irq_affinity_notify;1112struct proc_dir_entry;1213struct timer_rand_state;1314/**···2524 * @last_unhandled: aging timer for unhandled count2625 * @irqs_unhandled: stats field for spurious unhandled interrupts2726 * @lock: locking for SMP2727+ * @affinity_notify: context for notification of affinity changes2828 * @pending_mask: pending rebalanced interrupts2929 * @threads_active: number of irqaction threads currently running3030 * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers···7270 raw_spinlock_t lock;7371#ifdef CONFIG_SMP7472 const struct cpumask *affinity_hint;7373+ struct irq_affinity_notify *affinity_notify;7574#ifdef CONFIG_GENERIC_PENDING_IRQ7675 cpumask_var_t pending_mask;7776#endif
+82
kernel/irq/manage.c
···134134 irq_set_thread_affinity(desc);135135 }136136#endif137137+ if (desc->affinity_notify) {138138+ kref_get(&desc->affinity_notify->kref);139139+ schedule_work(&desc->affinity_notify->work);140140+ }137141 desc->status |= IRQ_AFFINITY_SET;138142 raw_spin_unlock_irqrestore(&desc->lock, flags);139143 return 0;···158154 return 0;159155}160156EXPORT_SYMBOL_GPL(irq_set_affinity_hint);157157+158158+static void irq_affinity_notify(struct work_struct *work)159159+{160160+ struct irq_affinity_notify *notify =161161+ container_of(work, struct irq_affinity_notify, work);162162+ struct irq_desc *desc = irq_to_desc(notify->irq);163163+ cpumask_var_t cpumask;164164+ unsigned long flags;165165+166166+ if (!desc)167167+ goto out;168168+169169+ if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))170170+ goto out;171171+172172+ raw_spin_lock_irqsave(&desc->lock, flags);173173+#ifdef CONFIG_GENERIC_PENDING_IRQ174174+ if (desc->status & IRQ_MOVE_PENDING)175175+ cpumask_copy(cpumask, desc->pending_mask);176176+ else177177+#endif178178+ cpumask_copy(cpumask, desc->affinity);179179+ raw_spin_unlock_irqrestore(&desc->lock, flags);180180+181181+ notify->notify(notify, cpumask);182182+183183+ free_cpumask_var(cpumask);184184+out:185185+ kref_put(¬ify->kref, notify->release);186186+}187187+188188+/**189189+ * irq_set_affinity_notifier - control notification of IRQ affinity changes190190+ * @irq: Interrupt for which to enable/disable notification191191+ * @notify: Context for notification, or %NULL to disable192192+ * notification. Function pointers must be initialised;193193+ * the other fields will be initialised by this function.194194+ *195195+ * Must be called in process context. Notification may only be enabled196196+ * after the IRQ is allocated and must be disabled before the IRQ is197197+ * freed using free_irq().198198+ */199199+int200200+irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)201201+{202202+ struct irq_desc *desc = irq_to_desc(irq);203203+ struct irq_affinity_notify *old_notify;204204+ unsigned long flags;205205+206206+ /* The release function is promised process context */207207+ might_sleep();208208+209209+ if (!desc)210210+ return -EINVAL;211211+212212+ /* Complete initialisation of *notify */213213+ if (notify) {214214+ notify->irq = irq;215215+ kref_init(¬ify->kref);216216+ INIT_WORK(¬ify->work, irq_affinity_notify);217217+ }218218+219219+ raw_spin_lock_irqsave(&desc->lock, flags);220220+ old_notify = desc->affinity_notify;221221+ desc->affinity_notify = notify;222222+ raw_spin_unlock_irqrestore(&desc->lock, flags);223223+224224+ if (old_notify)225225+ kref_put(&old_notify->kref, old_notify->release);226226+227227+ return 0;228228+}229229+EXPORT_SYMBOL_GPL(irq_set_affinity_notifier);161230162231#ifndef CONFIG_AUTO_IRQ_AFFINITY163232/*···1080100310811004 if (!desc)10821005 return;10061006+10071007+#ifdef CONFIG_SMP10081008+ if (WARN_ON(desc->affinity_notify))10091009+ desc->affinity_notify = NULL;10101010+#endif1083101110841012 chip_bus_lock(desc);10851013 kfree(__free_irq(irq, dev_id));