diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-10-14 15:11:21 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-10-14 15:11:21 -0400 |
| commit | 2b34218e893a0ff39f6f46517cb5df2f990db8c0 (patch) | |
| tree | cff6b92ae5935927f91609ee800dea3f66bc27b8 /kernel | |
| parent | a515d05e96eed14550cbeca08cb9e38dc95b5922 (diff) | |
| parent | e43b3b58548051f8809391eb7bec7a27ed3003ea (diff) | |
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq fixes from Ingo Molnar:
"A CPU hotplug related fix, plus two related sanity checks"
* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
genirq/cpuhotplug: Enforce affinity setting on startup of managed irqs
genirq/cpuhotplug: Add sanity check for effective affinity mask
genirq: Warn when effective affinity is not updated
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/irq/chip.c | 2 | ||||
| -rw-r--r-- | kernel/irq/cpuhotplug.c | 28 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 17 |
3 files changed, 45 insertions, 2 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 6fc89fd93824..5a2ef92c2782 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -265,8 +265,8 @@ int irq_startup(struct irq_desc *desc, bool resend, bool force) | |||
| 265 | irq_setup_affinity(desc); | 265 | irq_setup_affinity(desc); |
| 266 | break; | 266 | break; |
| 267 | case IRQ_STARTUP_MANAGED: | 267 | case IRQ_STARTUP_MANAGED: |
| 268 | irq_do_set_affinity(d, aff, false); | ||
| 268 | ret = __irq_startup(desc); | 269 | ret = __irq_startup(desc); |
| 269 | irq_set_affinity_locked(d, aff, false); | ||
| 270 | break; | 270 | break; |
| 271 | case IRQ_STARTUP_ABORT: | 271 | case IRQ_STARTUP_ABORT: |
| 272 | return 0; | 272 | return 0; |
diff --git a/kernel/irq/cpuhotplug.c b/kernel/irq/cpuhotplug.c index 638eb9c83d9f..9eb09aef0313 100644 --- a/kernel/irq/cpuhotplug.c +++ b/kernel/irq/cpuhotplug.c | |||
| @@ -18,8 +18,34 @@ | |||
| 18 | static inline bool irq_needs_fixup(struct irq_data *d) | 18 | static inline bool irq_needs_fixup(struct irq_data *d) |
| 19 | { | 19 | { |
| 20 | const struct cpumask *m = irq_data_get_effective_affinity_mask(d); | 20 | const struct cpumask *m = irq_data_get_effective_affinity_mask(d); |
| 21 | unsigned int cpu = smp_processor_id(); | ||
| 21 | 22 | ||
| 22 | return cpumask_test_cpu(smp_processor_id(), m); | 23 | #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK |
| 24 | /* | ||
| 25 | * The cpumask_empty() check is a workaround for interrupt chips, | ||
| 26 | * which do not implement effective affinity, but the architecture has | ||
| 27 | * enabled the config switch. Use the general affinity mask instead. | ||
| 28 | */ | ||
| 29 | if (cpumask_empty(m)) | ||
| 30 | m = irq_data_get_affinity_mask(d); | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Sanity check. If the mask is not empty when excluding the outgoing | ||
| 34 | * CPU then it must contain at least one online CPU. The outgoing CPU | ||
| 35 | * has been removed from the online mask already. | ||
| 36 | */ | ||
| 37 | if (cpumask_any_but(m, cpu) < nr_cpu_ids && | ||
| 38 | cpumask_any_and(m, cpu_online_mask) >= nr_cpu_ids) { | ||
| 39 | /* | ||
| 40 | * If this happens then there was a missed IRQ fixup at some | ||
| 41 | * point. Warn about it and enforce fixup. | ||
| 42 | */ | ||
| 43 | pr_warn("Eff. affinity %*pbl of IRQ %u contains only offline CPUs after offlining CPU %u\n", | ||
| 44 | cpumask_pr_args(m), d->irq, cpu); | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | #endif | ||
| 48 | return cpumask_test_cpu(cpu, m); | ||
| 23 | } | 49 | } |
| 24 | 50 | ||
| 25 | static bool migrate_one_irq(struct irq_desc *desc) | 51 | static bool migrate_one_irq(struct irq_desc *desc) |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index d00132b5c325..4bff6a10ae8e 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -168,6 +168,19 @@ void irq_set_thread_affinity(struct irq_desc *desc) | |||
| 168 | set_bit(IRQTF_AFFINITY, &action->thread_flags); | 168 | set_bit(IRQTF_AFFINITY, &action->thread_flags); |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | static void irq_validate_effective_affinity(struct irq_data *data) | ||
| 172 | { | ||
| 173 | #ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK | ||
| 174 | const struct cpumask *m = irq_data_get_effective_affinity_mask(data); | ||
| 175 | struct irq_chip *chip = irq_data_get_irq_chip(data); | ||
| 176 | |||
| 177 | if (!cpumask_empty(m)) | ||
| 178 | return; | ||
| 179 | pr_warn_once("irq_chip %s did not update eff. affinity mask of irq %u\n", | ||
| 180 | chip->name, data->irq); | ||
| 181 | #endif | ||
| 182 | } | ||
| 183 | |||
| 171 | int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, | 184 | int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, |
| 172 | bool force) | 185 | bool force) |
| 173 | { | 186 | { |
| @@ -175,12 +188,16 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, | |||
| 175 | struct irq_chip *chip = irq_data_get_irq_chip(data); | 188 | struct irq_chip *chip = irq_data_get_irq_chip(data); |
| 176 | int ret; | 189 | int ret; |
| 177 | 190 | ||
| 191 | if (!chip || !chip->irq_set_affinity) | ||
| 192 | return -EINVAL; | ||
| 193 | |||
| 178 | ret = chip->irq_set_affinity(data, mask, force); | 194 | ret = chip->irq_set_affinity(data, mask, force); |
| 179 | switch (ret) { | 195 | switch (ret) { |
| 180 | case IRQ_SET_MASK_OK: | 196 | case IRQ_SET_MASK_OK: |
| 181 | case IRQ_SET_MASK_OK_DONE: | 197 | case IRQ_SET_MASK_OK_DONE: |
| 182 | cpumask_copy(desc->irq_common_data.affinity, mask); | 198 | cpumask_copy(desc->irq_common_data.affinity, mask); |
| 183 | case IRQ_SET_MASK_OK_NOCOPY: | 199 | case IRQ_SET_MASK_OK_NOCOPY: |
| 200 | irq_validate_effective_affinity(data); | ||
| 184 | irq_set_thread_affinity(desc); | 201 | irq_set_thread_affinity(desc); |
| 185 | ret = 0; | 202 | ret = 0; |
| 186 | } | 203 | } |
