Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'irq/numa' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

+117 -1
+32 -1
include/linux/interrupt.h
··· 14 14 #include <linux/smp.h> 15 15 #include <linux/percpu.h> 16 16 #include <linux/hrtimer.h> 17 + #include <linux/kref.h> 18 + #include <linux/workqueue.h> 17 19 18 20 #include <asm/atomic.h> 19 21 #include <asm/ptrace.h> ··· 242 240 extern int irq_select_affinity(unsigned int irq); 243 241 244 242 extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); 243 + 244 + /** 245 + * struct irq_affinity_notify - context for notification of IRQ affinity changes 246 + * @irq: Interrupt to which notification applies 247 + * @kref: Reference count, for internal use 248 + * @work: Work item, for internal use 249 + * @notify: Function to be called on change. This will be 250 + * called in process context. 251 + * @release: Function to be called on release. This will be 252 + * called in process context. Once registered, the 253 + * structure must only be freed when this function is 254 + * called or later. 255 + */ 256 + struct irq_affinity_notify { 257 + unsigned int irq; 258 + struct kref kref; 259 + struct work_struct work; 260 + void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask); 261 + void (*release)(struct kref *ref); 262 + }; 263 + 264 + extern int 265 + irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); 266 + 267 + static inline void irq_run_affinity_notifiers(void) 268 + { 269 + flush_scheduled_work(); 270 + } 271 + 245 272 #else /* CONFIG_SMP */ 246 273 247 274 static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m) ··· 286 255 static inline int irq_select_affinity(unsigned int irq) { return 0; } 287 256 288 257 static inline int irq_set_affinity_hint(unsigned int irq, 289 - const struct cpumask *m) 258 + const struct cpumask *m) 290 259 { 291 260 return -EINVAL; 292 261 }
+3
include/linux/irqdesc.h
··· 8 8 * For now it's included from <linux/irq.h> 9 9 */ 10 10 11 + struct irq_affinity_notify; 11 12 struct proc_dir_entry; 12 13 struct timer_rand_state; 13 14 /** ··· 25 24 * @last_unhandled: aging timer for unhandled count 26 25 * @irqs_unhandled: stats field for spurious unhandled interrupts 27 26 * @lock: locking for SMP 27 + * @affinity_notify: context for notification of affinity changes 28 28 * @pending_mask: pending rebalanced interrupts 29 29 * @threads_active: number of irqaction threads currently running 30 30 * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers ··· 72 70 raw_spinlock_t lock; 73 71 #ifdef CONFIG_SMP 74 72 const struct cpumask *affinity_hint; 73 + struct irq_affinity_notify *affinity_notify; 75 74 #ifdef CONFIG_GENERIC_PENDING_IRQ 76 75 cpumask_var_t pending_mask; 77 76 #endif
+82
kernel/irq/manage.c
··· 134 134 irq_set_thread_affinity(desc); 135 135 } 136 136 #endif 137 + if (desc->affinity_notify) { 138 + kref_get(&desc->affinity_notify->kref); 139 + schedule_work(&desc->affinity_notify->work); 140 + } 137 141 desc->status |= IRQ_AFFINITY_SET; 138 142 raw_spin_unlock_irqrestore(&desc->lock, flags); 139 143 return 0; ··· 158 154 return 0; 159 155 } 160 156 EXPORT_SYMBOL_GPL(irq_set_affinity_hint); 157 + 158 + static void irq_affinity_notify(struct work_struct *work) 159 + { 160 + struct irq_affinity_notify *notify = 161 + container_of(work, struct irq_affinity_notify, work); 162 + struct irq_desc *desc = irq_to_desc(notify->irq); 163 + cpumask_var_t cpumask; 164 + unsigned long flags; 165 + 166 + if (!desc) 167 + goto out; 168 + 169 + if (!alloc_cpumask_var(&cpumask, GFP_KERNEL)) 170 + goto out; 171 + 172 + raw_spin_lock_irqsave(&desc->lock, flags); 173 + #ifdef CONFIG_GENERIC_PENDING_IRQ 174 + if (desc->status & IRQ_MOVE_PENDING) 175 + cpumask_copy(cpumask, desc->pending_mask); 176 + else 177 + #endif 178 + cpumask_copy(cpumask, desc->affinity); 179 + raw_spin_unlock_irqrestore(&desc->lock, flags); 180 + 181 + notify->notify(notify, cpumask); 182 + 183 + free_cpumask_var(cpumask); 184 + out: 185 + kref_put(&notify->kref, notify->release); 186 + } 187 + 188 + /** 189 + * irq_set_affinity_notifier - control notification of IRQ affinity changes 190 + * @irq: Interrupt for which to enable/disable notification 191 + * @notify: Context for notification, or %NULL to disable 192 + * notification. Function pointers must be initialised; 193 + * the other fields will be initialised by this function. 194 + * 195 + * Must be called in process context. Notification may only be enabled 196 + * after the IRQ is allocated and must be disabled before the IRQ is 197 + * freed using free_irq(). 198 + */ 199 + int 200 + irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) 201 + { 202 + struct irq_desc *desc = irq_to_desc(irq); 203 + struct irq_affinity_notify *old_notify; 204 + unsigned long flags; 205 + 206 + /* The release function is promised process context */ 207 + might_sleep(); 208 + 209 + if (!desc) 210 + return -EINVAL; 211 + 212 + /* Complete initialisation of *notify */ 213 + if (notify) { 214 + notify->irq = irq; 215 + kref_init(&notify->kref); 216 + INIT_WORK(&notify->work, irq_affinity_notify); 217 + } 218 + 219 + raw_spin_lock_irqsave(&desc->lock, flags); 220 + old_notify = desc->affinity_notify; 221 + desc->affinity_notify = notify; 222 + raw_spin_unlock_irqrestore(&desc->lock, flags); 223 + 224 + if (old_notify) 225 + kref_put(&old_notify->kref, old_notify->release); 226 + 227 + return 0; 228 + } 229 + EXPORT_SYMBOL_GPL(irq_set_affinity_notifier); 161 230 162 231 #ifndef CONFIG_AUTO_IRQ_AFFINITY 163 232 /* ··· 1080 1003 1081 1004 if (!desc) 1082 1005 return; 1006 + 1007 + #ifdef CONFIG_SMP 1008 + if (WARN_ON(desc->affinity_notify)) 1009 + desc->affinity_notify = NULL; 1010 + #endif 1083 1011 1084 1012 chip_bus_lock(desc); 1085 1013 kfree(__free_irq(irq, dev_id));