Skip to content

Commit

Permalink
x86: Force irq complete move during cpu offline
Browse files Browse the repository at this point in the history
When a cpu goes offline, fixup_irqs() try to move irq's
currently destined to the offline cpu to a new cpu. But this
attempt will fail if the irq is recently moved to this cpu and
the irq still hasn't arrived at this cpu (for non intr-remapping
platforms this is when we free the vector allocation at the
previous destination) that is about to go offline.

This will endup with the interrupt subsystem still pointing the
irq to the offline cpu, causing that irq to not work any more.

Fix this by forcing the irq to complete its move (its been a
long time we moved the irq to this cpu which we are offlining
now) and then move this irq to a new cpu before this cpu goes
offline.

Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Acked-by: Gary Hade <garyhade@us.ibm.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
LKML-Reference: <20091026230001.848830905@sbs-t61.sc.intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Suresh Siddha authored and Ingo Molnar committed Nov 2, 2009
1 parent 23359a8 commit a5e74b8
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 3 deletions.
1 change: 1 addition & 0 deletions arch/x86/include/asm/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ static inline int irq_canonicalize(int irq)
#ifdef CONFIG_HOTPLUG_CPU
#include <linux/cpumask.h>
extern void fixup_irqs(void);
extern void irq_force_complete_move(int);
#endif

extern void (*generic_interrupt_extension)(void);
Expand Down
18 changes: 15 additions & 3 deletions arch/x86/kernel/apic/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -2450,21 +2450,33 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
irq_exit();
}

static void irq_complete_move(struct irq_desc **descp)
static void __irq_complete_move(struct irq_desc **descp, unsigned vector)
{
struct irq_desc *desc = *descp;
struct irq_cfg *cfg = desc->chip_data;
unsigned vector, me;
unsigned me;

if (likely(!cfg->move_in_progress))
return;

vector = ~get_irq_regs()->orig_ax;
me = smp_processor_id();

if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
send_cleanup_vector(cfg);
}

static void irq_complete_move(struct irq_desc **descp)
{
__irq_complete_move(descp, ~get_irq_regs()->orig_ax);
}

void irq_force_complete_move(int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irq_cfg *cfg = desc->chip_data;

__irq_complete_move(&desc, cfg->vector);
}
#else
static inline void irq_complete_move(struct irq_desc **descp) {}
#endif
Expand Down
7 changes: 7 additions & 0 deletions arch/x86/kernel/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,13 @@ void fixup_irqs(void)
continue;
}

/*
* Complete the irq move. This cpu is going down and for
* non intr-remapping case, we can't wait till this interrupt
* arrives at this cpu before completing the irq move.
*/
irq_force_complete_move(irq);

if (cpumask_any_and(affinity, cpu_online_mask) >= nr_cpu_ids) {
break_affinity = 1;
affinity = cpu_all_mask;
Expand Down

0 comments on commit a5e74b8

Please sign in to comment.