On 12/2/13, Prarit Bhargava <pra...@redhat.com> wrote:
> Bugzilla: 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.  fixup_irqs() goes through the IRR and retriggers
> the IRQs left in the APIC IRR.  After this, the vector for the irq is set
> to -1.  There is a possibility here, however, that the CPU does handle an
> irq in the IRR and then calls the vector.
>

The patch does not seem to root-cause the problem. It seems to hide
the real problem.

It is not possible that a device-triggered irq can arrive to this cpu
again after fixup_irqs() fills its vector_irq[vector] to -1, because
we've done the following:

1. We disabled interrupt on this cpu in stop_machine().
2. We called irq_set_affinity() to exclude this cpu as a target for the irq.
3. We checked APIC_IRR and re-triggered any pending irqs to other cpus.

So the root cause of this spruious irq isn't found yet. I notice that
there's a mdelay(1) in fixup_irqs() which claims to be able to avoid
spurious irqs, but with no reasoning there.

The only way this irq can come again is through IPI. One possibility
is that cpu_online_mask() isn't protected by a spin lock, so if there
are other cpus being offlined simultaneously, then they may read wrong
cpu_online_mask due to contention, thus re-triggering pending irqs to
this offlined cpu. So the mdelay(1) can wait for that IPI to come and
we can catch it by checking APIC_IRR...But mdelay(1) may not be long
enough so you still see the spurious event and ended up with this
patch. I didn't do any test, just trying some thought experiments.

So why isn't cpu_online_mask() protected by a spin lock?

Thanks
Rui

> When this happens, do_IRQ() spits out a warning like
>
> kernel: [  612.014573] do_IRQ: 56.134 No irq handler for vector (irq -1)
>
> I added a debug printk to output which CPU & vector was retriggered and
> discovered that that we are getting bogus events.  This patchset resolves
> this by adding definitions for VECTOR_UNDEFINED(-1) and
> VECTOR_RETRIGGERED(-2) and modifying the code to use them.
>
> Signed-off-by: Prarit Bhargava <pra...@redhat.com>
> Cc: Thomas Gleixner <t...@linutronix.de>
> Cc: Ingo Molnar <mi...@redhat.com>
> Cc: "H. Peter Anvin" <h...@zytor.com>
> Cc: x...@kernel.org
> Cc: Michel Lespinasse <wal...@google.com>
> Cc: Andi Kleen <a...@linux.intel.com>
> Cc: Seiji Aguchi <seiji.agu...@hds.com>
> Cc: Yang Zhang <yang.z.zh...@intel.com>
> Cc: Paul Gortmaker <paul.gortma...@windriver.com>
> Cc: janet.mor...@intel.com
> Cc: tony.l...@intel.com
> ---
>  arch/x86/include/asm/hw_irq.h  |    2 ++
>  arch/x86/kernel/apic/io_apic.c |   13 +++++++------
>  arch/x86/kernel/irq.c          |   17 +++++++++++------
>  arch/x86/kernel/irqinit.c      |    4 ++--
>  4 files changed, 22 insertions(+), 14 deletions(-)
>
> diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
> index 92b3bae..22c425e 100644
> --- a/arch/x86/include/asm/hw_irq.h
> +++ b/arch/x86/include/asm/hw_irq.h
> @@ -188,6 +188,8 @@ extern __visible void smp_invalidate_interrupt(struct
> pt_regs *);
>
>  extern void (*__initconst
> interrupt[NR_VECTORS-FIRST_EXTERNAL_VECTOR])(void);
>
> +#define VECTOR_UNDEFINED     -1
> +#define VECTOR_RETRIGGERED   -2
>  typedef int vector_irq_t[NR_VECTORS];
>  DECLARE_PER_CPU(vector_irq_t, vector_irq);
>  extern 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 e63a5bd..6e1541c 100644
> --- a/arch/x86/kernel/apic/io_apic.c
> +++ b/arch/x86/kernel/apic/io_apic.c
> @@ -1143,7 +1143,8 @@ next:
>                       goto next;
>
>               for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
> -                     if (per_cpu(vector_irq, new_cpu)[vector] != -1)
> +                     if (per_cpu(vector_irq, new_cpu)[vector] >
> +                                                           VECTOR_UNDEFINED)
>                               goto next;
>               /* Found one! */
>               current_vector = vector;
> @@ -1183,7 +1184,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg
> *cfg)
>
>       vector = cfg->vector;
>       for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
> -             per_cpu(vector_irq, cpu)[vector] = -1;
> +             per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
>
>       cfg->vector = 0;
>       cpumask_clear(cfg->domain);
> @@ -1195,7 +1196,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg
> *cfg)
>                                                               vector++) {
>                       if (per_cpu(vector_irq, cpu)[vector] != irq)
>                               continue;
> -                     per_cpu(vector_irq, cpu)[vector] = -1;
> +                     per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
>                       break;
>               }
>       }
> @@ -1228,12 +1229,12 @@ void __setup_vector_irq(int cpu)
>       /* Mark the free vectors */
>       for (vector = 0; vector < NR_VECTORS; ++vector) {
>               irq = per_cpu(vector_irq, cpu)[vector];
> -             if (irq < 0)
> +             if (irq <= VECTOR_UNDEFINED)
>                       continue;
>
>               cfg = irq_cfg(irq);
>               if (!cpumask_test_cpu(cpu, cfg->domain))
> -                     per_cpu(vector_irq, cpu)[vector] = -1;
> +                     per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
>       }
>       raw_spin_unlock(&vector_lock);
>  }
> @@ -2208,7 +2209,7 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
>               struct irq_cfg *cfg;
>               irq = __this_cpu_read(vector_irq[vector]);
>
> -             if (irq == -1)
> +             if (irq <= VECTOR_UNDEFINED)
>                       continue;
>
>               desc = irq_to_desc(irq);
> diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
> index 22d0687..030f0e2 100644
> --- a/arch/x86/kernel/irq.c
> +++ b/arch/x86/kernel/irq.c
> @@ -193,9 +193,10 @@ __visible unsigned int __irq_entry do_IRQ(struct
> pt_regs *regs)
>       if (!handle_irq(irq, regs)) {
>               ack_APIC_irq();
>
> -             if (printk_ratelimit())
> -                     pr_emerg("%s: %d.%d No irq handler for vector (irq 
> %d)\n",
> -                             __func__, smp_processor_id(), vector, irq);
> +             if (irq != VECTOR_RETRIGGERED)
> +                     pr_emerg_ratelimited("%s: %d.%d No irq handler for 
> vector (irq %d)\n",
> +                                          __func__, smp_processor_id(),
> +                                          vector, irq);
>       }
>
>       irq_exit();
> @@ -344,7 +345,7 @@ void fixup_irqs(void)
>       for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
>               unsigned int irr;
>
> -             if (__this_cpu_read(vector_irq[vector]) < 0)
> +             if (__this_cpu_read(vector_irq[vector]) <= VECTOR_UNDEFINED)
>                       continue;
>
>               irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
> @@ -355,11 +356,15 @@ void fixup_irqs(void)
>                       data = irq_desc_get_irq_data(desc);
>                       chip = irq_data_get_irq_chip(data);
>                       raw_spin_lock(&desc->lock);
> -                     if (chip->irq_retrigger)
> +                     if (chip->irq_retrigger) {
>                               chip->irq_retrigger(data);
> +                             __this_cpu_write(vector_irq[vector],
> +                                              VECTOR_RETRIGGERED);
> +                     }
>                       raw_spin_unlock(&desc->lock);
>               }
> -             __this_cpu_write(vector_irq[vector], -1);
> +             if (__this_cpu_read(vector_irq[vector]) != VECTOR_RETRIGGERED)
> +                     __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
>       }
>  }
>  #endif
> diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
> index a2a1fbc..7f50156 100644
> --- a/arch/x86/kernel/irqinit.c
> +++ b/arch/x86/kernel/irqinit.c
> @@ -52,7 +52,7 @@ static struct irqaction irq2 = {
>  };
>
>  DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
> -     [0 ... NR_VECTORS - 1] = -1,
> +     [0 ... NR_VECTORS - 1] = VECTOR_UNDEFINED,
>  };
>
>  int vector_used_by_percpu_irq(unsigned int vector)
> @@ -60,7 +60,7 @@ int vector_used_by_percpu_irq(unsigned int vector)
>       int cpu;
>
>       for_each_online_cpu(cpu) {
> -             if (per_cpu(vector_irq, cpu)[vector] != -1)
> +             if (per_cpu(vector_irq, cpu)[vector] > VECTOR_UNDEFINED)
>                       return 1;
>       }
>
> --
> 1.7.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to