x86: prevent stale state of c1e_mask across CPU offline/online

Impact: hang which happens across CPU offline/online on AMD C1E systems.

When a CPU goes offline then the corresponding bit in the broadcast
mask is cleared. For AMD C1E enabled CPUs we do not reenable the
broadcast when the CPU comes online again as we do not clear the
corresponding bit in the c1e_mask, which keeps track which CPUs
have been switched to broadcast already. So on those !$@#& machines
we never switch back to broadcasting after a CPU offline/online cycle.

Clear the bit when the CPU plays dead.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Thomas Gleixner 2008-09-22 18:54:29 +02:00
Родитель 6441402b1f
Коммит 4faac97d44
4 изменённых файлов: 13 добавлений и 3 удалений

Просмотреть файл

@ -246,6 +246,14 @@ static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c)
return 1; return 1;
} }
static cpumask_t c1e_mask = CPU_MASK_NONE;
static int c1e_detected;
void c1e_remove_cpu(int cpu)
{
cpu_clear(cpu, c1e_mask);
}
/* /*
* C1E aware idle routine. We check for C1E active in the interrupt * C1E aware idle routine. We check for C1E active in the interrupt
* pending message MSR. If we detect C1E, then we handle it the same * pending message MSR. If we detect C1E, then we handle it the same
@ -253,9 +261,6 @@ static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c)
*/ */
static void c1e_idle(void) static void c1e_idle(void)
{ {
static cpumask_t c1e_mask = CPU_MASK_NONE;
static int c1e_detected;
if (need_resched()) if (need_resched())
return; return;

Просмотреть файл

@ -88,6 +88,7 @@ static void cpu_exit_clear(void)
cpu_clear(cpu, cpu_callin_map); cpu_clear(cpu, cpu_callin_map);
numa_remove_cpu(cpu); numa_remove_cpu(cpu);
c1e_remove_cpu(cpu);
} }
/* We don't actually take CPU down, just spin without interrupts. */ /* We don't actually take CPU down, just spin without interrupts. */

Просмотреть файл

@ -93,6 +93,8 @@ DECLARE_PER_CPU(int, cpu_state);
static inline void play_dead(void) static inline void play_dead(void)
{ {
idle_task_exit(); idle_task_exit();
c1e_remove_cpu(raw_smp_processor_id());
mb(); mb();
/* Ack it */ /* Ack it */
__get_cpu_var(cpu_state) = CPU_DEAD; __get_cpu_var(cpu_state) = CPU_DEAD;

Просмотреть файл

@ -10,4 +10,6 @@ void idle_notifier_register(struct notifier_block *n);
void enter_idle(void); void enter_idle(void);
void exit_idle(void); void exit_idle(void);
void c1e_remove_cpu(int cpu);
#endif #endif