Commit 01f8fa4f01d8362358eb90e412bd7ae18a3ec1ad
genirq: Allow forcing cpu affinity of interrupts
The current implementation of irq_set_affinity() refuses rightfully to route an interrupt to an offline cpu. But there is a special case, where this is actually desired. Some of the ARM SoCs have per cpu timers which require setting the affinity during cpu startup where the cpu is not yet in the online mask. If we can't do that, then the local timer interrupt for the about to become online cpu is routed to some random online cpu. The developers of the affected machines tried to work around that issue, but that results in a massive mess in that timer code. We have a yet unused argument in the set_affinity callbacks of the irq chips, which I added back then for a similar reason. It was never required so it got not used. But I'm happy that I never removed it. That allows us to implement a sane handling of the above scenario. So the affected SoC drivers can add the required force handling to their interrupt chip, switch the timer code to irq_force_affinity() and things just work. This does not affect any existing user of irq_set_affinity(). Tagged for stable to allow a simple fix of the affected SoC clock event drivers. Reported-and-tested-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Marek Szyprowski <m.szyprowski@samsung.com> Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Cc: Tomasz Figa <t.figa@samsung.com>, Cc: Daniel Lezcano <daniel.lezcano@linaro.org>, Cc: Kukjin Kim <kgene.kim@samsung.com> Cc: linux-arm-kernel@lists.infradead.org, Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20140416143315.717251504@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Showing 4 changed files with 43 additions and 14 deletions Side-by-side Diff
... | ... | @@ -635,7 +635,7 @@ |
635 | 635 | cpumask_clear(&new_affinity); |
636 | 636 | cpumask_set_cpu(cpumask_first(cpu_online_mask), &new_affinity); |
637 | 637 | } |
638 | - __irq_set_affinity_locked(data, &new_affinity); | |
638 | + irq_set_affinity_locked(data, &new_affinity, false); | |
639 | 639 | } |
640 | 640 | |
641 | 641 | static int octeon_irq_ciu_set_affinity(struct irq_data *data, |
... | ... | @@ -203,7 +203,40 @@ |
203 | 203 | |
204 | 204 | extern cpumask_var_t irq_default_affinity; |
205 | 205 | |
206 | -extern int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask); | |
206 | +/* Internal implementation. Use the helpers below */ | |
207 | +extern int __irq_set_affinity(unsigned int irq, const struct cpumask *cpumask, | |
208 | + bool force); | |
209 | + | |
210 | +/** | |
211 | + * irq_set_affinity - Set the irq affinity of a given irq | |
212 | + * @irq: Interrupt to set affinity | |
213 | + * @mask: cpumask | |
214 | + * | |
215 | + * Fails if cpumask does not contain an online CPU | |
216 | + */ | |
217 | +static inline int | |
218 | +irq_set_affinity(unsigned int irq, const struct cpumask *cpumask) | |
219 | +{ | |
220 | + return __irq_set_affinity(irq, cpumask, false); | |
221 | +} | |
222 | + | |
223 | +/** | |
224 | + * irq_force_affinity - Force the irq affinity of a given irq | |
225 | + * @irq: Interrupt to set affinity | |
226 | + * @mask: cpumask | |
227 | + * | |
228 | + * Same as irq_set_affinity, but without checking the mask against | |
229 | + * online cpus. | |
230 | + * | |
231 | + * Solely for low level cpu hotplug code, where we need to make per | |
232 | + * cpu interrupts affine before the cpu becomes online. | |
233 | + */ | |
234 | +static inline int | |
235 | +irq_force_affinity(unsigned int irq, const struct cpumask *cpumask) | |
236 | +{ | |
237 | + return __irq_set_affinity(irq, cpumask, true); | |
238 | +} | |
239 | + | |
207 | 240 | extern int irq_can_set_affinity(unsigned int irq); |
208 | 241 | extern int irq_select_affinity(unsigned int irq); |
209 | 242 |
... | ... | @@ -394,7 +394,8 @@ |
394 | 394 | |
395 | 395 | extern void irq_cpu_online(void); |
396 | 396 | extern void irq_cpu_offline(void); |
397 | -extern int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *cpumask); | |
397 | +extern int irq_set_affinity_locked(struct irq_data *data, | |
398 | + const struct cpumask *cpumask, bool force); | |
398 | 399 | |
399 | 400 | #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ) |
400 | 401 | void irq_move_irq(struct irq_data *data); |
... | ... | @@ -180,7 +180,7 @@ |
180 | 180 | struct irq_chip *chip = irq_data_get_irq_chip(data); |
181 | 181 | int ret; |
182 | 182 | |
183 | - ret = chip->irq_set_affinity(data, mask, false); | |
183 | + ret = chip->irq_set_affinity(data, mask, force); | |
184 | 184 | switch (ret) { |
185 | 185 | case IRQ_SET_MASK_OK: |
186 | 186 | cpumask_copy(data->affinity, mask); |
... | ... | @@ -192,7 +192,8 @@ |
192 | 192 | return ret; |
193 | 193 | } |
194 | 194 | |
195 | -int __irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask) | |
195 | +int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask, | |
196 | + bool force) | |
196 | 197 | { |
197 | 198 | struct irq_chip *chip = irq_data_get_irq_chip(data); |
198 | 199 | struct irq_desc *desc = irq_data_to_desc(data); |
... | ... | @@ -202,7 +203,7 @@ |
202 | 203 | return -EINVAL; |
203 | 204 | |
204 | 205 | if (irq_can_move_pcntxt(data)) { |
205 | - ret = irq_do_set_affinity(data, mask, false); | |
206 | + ret = irq_do_set_affinity(data, mask, force); | |
206 | 207 | } else { |
207 | 208 | irqd_set_move_pending(data); |
208 | 209 | irq_copy_pending(desc, mask); |
... | ... | @@ -217,13 +218,7 @@ |
217 | 218 | return ret; |
218 | 219 | } |
219 | 220 | |
220 | -/** | |
221 | - * irq_set_affinity - Set the irq affinity of a given irq | |
222 | - * @irq: Interrupt to set affinity | |
223 | - * @mask: cpumask | |
224 | - * | |
225 | - */ | |
226 | -int irq_set_affinity(unsigned int irq, const struct cpumask *mask) | |
221 | +int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force) | |
227 | 222 | { |
228 | 223 | struct irq_desc *desc = irq_to_desc(irq); |
229 | 224 | unsigned long flags; |
... | ... | @@ -233,7 +228,7 @@ |
233 | 228 | return -EINVAL; |
234 | 229 | |
235 | 230 | raw_spin_lock_irqsave(&desc->lock, flags); |
236 | - ret = __irq_set_affinity_locked(irq_desc_get_irq_data(desc), mask); | |
231 | + ret = irq_set_affinity_locked(irq_desc_get_irq_data(desc), mask, force); | |
237 | 232 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
238 | 233 | return ret; |
239 | 234 | } |
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit 8f1410
-
mentioned in commit bae362
-
mentioned in commit 3e32c2
-
mentioned in commit 8f1410
-
mentioned in commit bae362
-
mentioned in commit 3e32c2
-
mentioned in commit 4d9feb
-
mentioned in commit 7c2fbe
-
mentioned in commit 4d9feb
-
mentioned in commit 7c2fbe
-
mentioned in commit 8f1410
-
mentioned in commit bae362
-
mentioned in commit 3e32c2
-
mentioned in commit 4d9feb
-
mentioned in commit 7c2fbe
-
mentioned in commit 8f1410
-
mentioned in commit bae362
-
mentioned in commit 3e32c2
-
mentioned in commit 4d9feb
-
mentioned in commit 8f1410
-
mentioned in commit 7c2fbe
-
mentioned in commit bae362
-
mentioned in commit 3e32c2
-
mentioned in commit 4d9feb
-
mentioned in commit 7c2fbe
-
mentioned in commit 4c88d7
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit 4c88d7
-
mentioned in commit 601c94
-
mentioned in commit a04080
-
mentioned in commit 3d8afe
-
mentioned in commit a04080
-
mentioned in commit 3d8afe