aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPrarit Bhargava <prarit@redhat.com>2014-01-05 11:10:52 -0500
committerIngo Molnar <mingo@kernel.org>2014-01-12 07:13:02 -0500
commit9345005f4eed805308193658d12e4e7e9c261e74 (patch)
tree8dce273d90c66709baaef7ce91fc8710de78de2f
parent228fdc083b017eaf90e578fa86fb1ecfd5ffae87 (diff)
x86/irq: Fix do_IRQ() interrupt warning for cpu hotplug retriggered irqs
During heavy CPU-hotplug operations the following spurious kernel warnings can trigger: do_IRQ: No ... irq handler for vector (irq -1) [ See: https://bugzilla.kernel.org/show_bug.cgi?id=64831 ] When downing a cpu it is possible that there are unhandled irqs left in the APIC IRR register. The following code path shows how the problem can occur: 1. CPU 5 is to go down. 2. cpu_disable() on CPU 5 executes with interrupt flag cleared by local_irq_save() via stop_machine(). 3. IRQ 12 asserts on CPU 5, setting IRR but not ISR because interrupt flag is cleared (CPU unabled to handle the irq) 4. IRQs are migrated off of CPU 5, and the vectors' irqs are set to -1. 5. stop_machine() finishes cpu_disable() 6. cpu_die() for CPU 5 executes in normal context. 7. CPU 5 attempts to handle IRQ 12 because the IRR is set for IRQ 12. The code attempts to find the vector's IRQ and cannot because it has been set to -1. 8. do_IRQ() warning displays warning about CPU 5 IRQ 12. I added a debug printk to output which CPU & vector was retriggered and discovered that that we are getting bogus events. I see a 100% correlation between this debug printk in fixup_irqs() and the do_IRQ() warning. This patchset resolves this by adding definitions for VECTOR_UNDEFINED(-1) and VECTOR_RETRIGGERED(-2) and modifying the code to use them. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=64831 Signed-off-by: Prarit Bhargava <prarit@redhat.com> Reviewed-by: Rui Wang <rui.y.wang@intel.com> Cc: Michel Lespinasse <walken@google.com> Cc: Seiji Aguchi <seiji.aguchi@hds.com> Cc: Yang Zhang <yang.z.zhang@Intel.com> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: janet.morgan@Intel.com Cc: tony.luck@Intel.com Cc: ruiv.wang@gmail.com Link: http://lkml.kernel.org/r/1388938252-16627-1-git-send-email-prarit@redhat.com [ Cleaned up the code a bit. ] Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/hw_irq.h3
-rw-r--r--arch/x86/kernel/apic/io_apic.c18
-rw-r--r--arch/x86/kernel/irq.c19
-rw-r--r--arch/x86/kernel/irqinit.c4
4 files changed, 27 insertions, 17 deletions
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index cba45d99ac1a..67d69b8e2d20 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -191,6 +191,9 @@ extern void (*__initconst interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void);
191#define trace_interrupt interrupt 191#define trace_interrupt interrupt
192#endif 192#endif
193 193
194#define VECTOR_UNDEFINED -1
195#define VECTOR_RETRIGGERED -2
196
194typedef int vector_irq_t[NR_VECTORS]; 197typedef int vector_irq_t[NR_VECTORS];
195DECLARE_PER_CPU(vector_irq_t, vector_irq); 198DECLARE_PER_CPU(vector_irq_t, vector_irq);
196extern void setup_vector_irq(int cpu); 199extern void setup_vector_irq(int cpu);
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index e63a5bd2a78f..6df0b660753b 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1142,9 +1142,10 @@ next:
1142 if (test_bit(vector, used_vectors)) 1142 if (test_bit(vector, used_vectors))
1143 goto next; 1143 goto next;
1144 1144
1145 for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) 1145 for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) {
1146 if (per_cpu(vector_irq, new_cpu)[vector] != -1) 1146 if (per_cpu(vector_irq, new_cpu)[vector] > VECTOR_UNDEFINED)
1147 goto next; 1147 goto next;
1148 }
1148 /* Found one! */ 1149 /* Found one! */
1149 current_vector = vector; 1150 current_vector = vector;
1150 current_offset = offset; 1151 current_offset = offset;
@@ -1183,7 +1184,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
1183 1184
1184 vector = cfg->vector; 1185 vector = cfg->vector;
1185 for_each_cpu_and(cpu, cfg->domain, cpu_online_mask) 1186 for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
1186 per_cpu(vector_irq, cpu)[vector] = -1; 1187 per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
1187 1188
1188 cfg->vector = 0; 1189 cfg->vector = 0;
1189 cpumask_clear(cfg->domain); 1190 cpumask_clear(cfg->domain);
@@ -1191,11 +1192,10 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
1191 if (likely(!cfg->move_in_progress)) 1192 if (likely(!cfg->move_in_progress))
1192 return; 1193 return;
1193 for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) { 1194 for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
1194 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; 1195 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
1195 vector++) {
1196 if (per_cpu(vector_irq, cpu)[vector] != irq) 1196 if (per_cpu(vector_irq, cpu)[vector] != irq)
1197 continue; 1197 continue;
1198 per_cpu(vector_irq, cpu)[vector] = -1; 1198 per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
1199 break; 1199 break;
1200 } 1200 }
1201 } 1201 }
@@ -1228,12 +1228,12 @@ void __setup_vector_irq(int cpu)
1228 /* Mark the free vectors */ 1228 /* Mark the free vectors */
1229 for (vector = 0; vector < NR_VECTORS; ++vector) { 1229 for (vector = 0; vector < NR_VECTORS; ++vector) {
1230 irq = per_cpu(vector_irq, cpu)[vector]; 1230 irq = per_cpu(vector_irq, cpu)[vector];
1231 if (irq < 0) 1231 if (irq <= VECTOR_UNDEFINED)
1232 continue; 1232 continue;
1233 1233
1234 cfg = irq_cfg(irq); 1234 cfg = irq_cfg(irq);
1235 if (!cpumask_test_cpu(cpu, cfg->domain)) 1235 if (!cpumask_test_cpu(cpu, cfg->domain))
1236 per_cpu(vector_irq, cpu)[vector] = -1; 1236 per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
1237 } 1237 }
1238 raw_spin_unlock(&vector_lock); 1238 raw_spin_unlock(&vector_lock);
1239} 1239}
@@ -2208,7 +2208,7 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
2208 struct irq_cfg *cfg; 2208 struct irq_cfg *cfg;
2209 irq = __this_cpu_read(vector_irq[vector]); 2209 irq = __this_cpu_read(vector_irq[vector]);
2210 2210
2211 if (irq == -1) 2211 if (irq <= VECTOR_UNDEFINED)
2212 continue; 2212 continue;
2213 2213
2214 desc = irq_to_desc(irq); 2214 desc = irq_to_desc(irq);
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 22d0687e7fda..884d875c1434 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -193,9 +193,13 @@ __visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
193 if (!handle_irq(irq, regs)) { 193 if (!handle_irq(irq, regs)) {
194 ack_APIC_irq(); 194 ack_APIC_irq();
195 195
196 if (printk_ratelimit()) 196 if (irq != VECTOR_RETRIGGERED) {
197 pr_emerg("%s: %d.%d No irq handler for vector (irq %d)\n", 197 pr_emerg_ratelimited("%s: %d.%d No irq handler for vector (irq %d)\n",
198 __func__, smp_processor_id(), vector, irq); 198 __func__, smp_processor_id(),
199 vector, irq);
200 } else {
201 __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
202 }
199 } 203 }
200 204
201 irq_exit(); 205 irq_exit();
@@ -344,7 +348,7 @@ void fixup_irqs(void)
344 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { 348 for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
345 unsigned int irr; 349 unsigned int irr;
346 350
347 if (__this_cpu_read(vector_irq[vector]) < 0) 351 if (__this_cpu_read(vector_irq[vector]) <= VECTOR_UNDEFINED)
348 continue; 352 continue;
349 353
350 irr = apic_read(APIC_IRR + (vector / 32 * 0x10)); 354 irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
@@ -355,11 +359,14 @@ void fixup_irqs(void)
355 data = irq_desc_get_irq_data(desc); 359 data = irq_desc_get_irq_data(desc);
356 chip = irq_data_get_irq_chip(data); 360 chip = irq_data_get_irq_chip(data);
357 raw_spin_lock(&desc->lock); 361 raw_spin_lock(&desc->lock);
358 if (chip->irq_retrigger) 362 if (chip->irq_retrigger) {
359 chip->irq_retrigger(data); 363 chip->irq_retrigger(data);
364 __this_cpu_write(vector_irq[vector], VECTOR_RETRIGGERED);
365 }
360 raw_spin_unlock(&desc->lock); 366 raw_spin_unlock(&desc->lock);
361 } 367 }
362 __this_cpu_write(vector_irq[vector], -1); 368 if (__this_cpu_read(vector_irq[vector]) != VECTOR_RETRIGGERED)
369 __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
363 } 370 }
364} 371}
365#endif 372#endif
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index a2a1fbc594ff..7f50156542fb 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -52,7 +52,7 @@ static struct irqaction irq2 = {
52}; 52};
53 53
54DEFINE_PER_CPU(vector_irq_t, vector_irq) = { 54DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
55 [0 ... NR_VECTORS - 1] = -1, 55 [0 ... NR_VECTORS - 1] = VECTOR_UNDEFINED,
56}; 56};
57 57
58int vector_used_by_percpu_irq(unsigned int vector) 58int vector_used_by_percpu_irq(unsigned int vector)
@@ -60,7 +60,7 @@ int vector_used_by_percpu_irq(unsigned int vector)
60 int cpu; 60 int cpu;
61 61
62 for_each_online_cpu(cpu) { 62 for_each_online_cpu(cpu) {
63 if (per_cpu(vector_irq, cpu)[vector] != -1) 63 if (per_cpu(vector_irq, cpu)[vector] > VECTOR_UNDEFINED)
64 return 1; 64 return 1;
65 } 65 }
66 66