diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/irq/manage.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0caa59f747dd..0587c5ceaed8 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -134,6 +134,10 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask) | |||
134 | irq_set_thread_affinity(desc); | 134 | irq_set_thread_affinity(desc); |
135 | } | 135 | } |
136 | #endif | 136 | #endif |
137 | if (desc->affinity_notify) { | ||
138 | kref_get(&desc->affinity_notify->kref); | ||
139 | schedule_work(&desc->affinity_notify->work); | ||
140 | } | ||
137 | desc->status |= IRQ_AFFINITY_SET; | 141 | desc->status |= IRQ_AFFINITY_SET; |
138 | raw_spin_unlock_irqrestore(&desc->lock, flags); | 142 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
139 | return 0; | 143 | return 0; |
@@ -155,6 +159,79 @@ int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) | |||
155 | } | 159 | } |
156 | EXPORT_SYMBOL_GPL(irq_set_affinity_hint); | 160 | EXPORT_SYMBOL_GPL(irq_set_affinity_hint); |
157 | 161 | ||
162 | static void irq_affinity_notify(struct work_struct *work) | ||
163 | { | ||
164 | struct irq_affinity_notify *notify = | ||
165 | container_of(work, struct irq_affinity_notify, work); | ||
166 | struct irq_desc *desc = irq_to_desc(notify->irq); | ||
167 | cpumask_var_t cpumask; | ||
168 | unsigned long flags; | ||
169 | |||
170 | if (!desc) | ||
171 | goto out; | ||
172 | |||
173 | if (!alloc_cpumask_var(&cpumask, GFP_KERNEL)) | ||
174 | goto out; | ||
175 | |||
176 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
177 | #ifdef CONFIG_GENERIC_PENDING_IRQ | ||
178 | if (desc->status & IRQ_MOVE_PENDING) | ||
179 | cpumask_copy(cpumask, desc->pending_mask); | ||
180 | else | ||
181 | #endif | ||
182 | cpumask_copy(cpumask, desc->affinity); | ||
183 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
184 | |||
185 | notify->notify(notify, cpumask); | ||
186 | |||
187 | free_cpumask_var(cpumask); | ||
188 | out: | ||
189 | kref_put(¬ify->kref, notify->release); | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * irq_set_affinity_notifier - control notification of IRQ affinity changes | ||
194 | * @irq: Interrupt for which to enable/disable notification | ||
195 | * @notify: Context for notification, or %NULL to disable | ||
196 | * notification. Function pointers must be initialised; | ||
197 | * the other fields will be initialised by this function. | ||
198 | * | ||
199 | * Must be called in process context. Notification may only be enabled | ||
200 | * after the IRQ is allocated and must be disabled before the IRQ is | ||
201 | * freed using free_irq(). | ||
202 | */ | ||
203 | int | ||
204 | irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) | ||
205 | { | ||
206 | struct irq_desc *desc = irq_to_desc(irq); | ||
207 | struct irq_affinity_notify *old_notify; | ||
208 | unsigned long flags; | ||
209 | |||
210 | /* The release function is promised process context */ | ||
211 | might_sleep(); | ||
212 | |||
213 | if (!desc) | ||
214 | return -EINVAL; | ||
215 | |||
216 | /* Complete initialisation of *notify */ | ||
217 | if (notify) { | ||
218 | notify->irq = irq; | ||
219 | kref_init(¬ify->kref); | ||
220 | INIT_WORK(¬ify->work, irq_affinity_notify); | ||
221 | } | ||
222 | |||
223 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
224 | old_notify = desc->affinity_notify; | ||
225 | desc->affinity_notify = notify; | ||
226 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
227 | |||
228 | if (old_notify) | ||
229 | kref_put(&old_notify->kref, old_notify->release); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | EXPORT_SYMBOL_GPL(irq_set_affinity_notifier); | ||
234 | |||
158 | #ifndef CONFIG_AUTO_IRQ_AFFINITY | 235 | #ifndef CONFIG_AUTO_IRQ_AFFINITY |
159 | /* | 236 | /* |
160 | * Generic version of the affinity autoselector. | 237 | * Generic version of the affinity autoselector. |
@@ -1004,6 +1081,11 @@ void free_irq(unsigned int irq, void *dev_id) | |||
1004 | if (!desc) | 1081 | if (!desc) |
1005 | return; | 1082 | return; |
1006 | 1083 | ||
1084 | #ifdef CONFIG_SMP | ||
1085 | if (WARN_ON(desc->affinity_notify)) | ||
1086 | desc->affinity_notify = NULL; | ||
1087 | #endif | ||
1088 | |||
1007 | chip_bus_lock(desc); | 1089 | chip_bus_lock(desc); |
1008 | kfree(__free_irq(irq, dev_id)); | 1090 | kfree(__free_irq(irq, dev_id)); |
1009 | chip_bus_sync_unlock(desc); | 1091 | chip_bus_sync_unlock(desc); |