* [patch] x86: Rendezvous all the cpu's for MTRR/PAT init
@ 2009-08-19 0:30 Suresh Siddha
2009-08-19 1:01 ` Andrew Morton
0 siblings, 1 reply; 6+ messages in thread
From: Suresh Siddha @ 2009-08-19 0:30 UTC (permalink / raw)
To: mingo, hpa, tglx; +Cc: venkatesh.pallipadi, linux-kernel
Please consider applying this patch after the clockevents bugfix posted
yesterday http://marc.info/?l=linux-kernel&m=125054497316006&w=2
thanks,
suresh
---
From: Suresh Siddha <suresh.b.siddha@intel.com>
Subject: x86: Rendezvous all the cpu's for MTRR/PAT init
SDM Vol 3a section titled "MTRR considerations in MP systems" specifies
the need for synchronizing the logical cpu's while initializing/updating
MTRR.
Currently Linux kernel does the synchronization of all cpu's only when
a single MTRR register is programmed/updated. During an AP online
(during boot/cpu-online/resume) where we initialize all the MTRR/PAT registers,
we don't follow this synchronization algorithm.
This can lead to scenarios where during a dynamic cpu online, that logical cpu
is initializing MTRR/PAT with cache disabled (cr0.cd=1) etc while other logical
HT sibling continue to run (also with cache disabled because of cr0.cd=1
on its sibling).
Starting from Westmere, VMX transitions with cr0.cd=1 don't work properly
(because of some VMX performance optimizations) and the above scenario
(with one logical cpu doing VMX activity and another logical cpu coming online)
can result in system crash.
Fix the MTRR initialization by doing rendezvous of all the cpus. During
boot and resume, we delay the MTRR/PAT init for APs till all the
logical cpu's come online and the rendezvous process at the end of AP's bringup,
will initialize the MTRR/PAT for all AP's.
For dynamic single cpu online, we synchronize all the logical cpus and
do the MTRR/PAT init on the AP that is coming online.
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
---
Index: tip/arch/x86/include/asm/mtrr.h
===================================================================
--- tip.orig/arch/x86/include/asm/mtrr.h
+++ tip/arch/x86/include/asm/mtrr.h
@@ -121,8 +121,12 @@ extern int mtrr_del_page(int reg, unsign
extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi);
extern void mtrr_ap_init(void);
extern void mtrr_bp_init(void);
+extern void set_mtrr_aps_delayed_init(void);
+extern void mtrr_aps_init(void);
+extern void mtrr_bp_restore(void);
extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
extern int amd_special_default_mtrr(void);
+extern u32 mtrr_aps_delayed_init;
# else
static inline u8 mtrr_type_lookup(u64 addr, u64 end)
{
@@ -161,6 +165,9 @@ static inline void mtrr_centaur_report_m
#define mtrr_ap_init() do {} while (0)
#define mtrr_bp_init() do {} while (0)
+#define set_mtrr_aps_delayed_init() do {} while (0)
+#define mtrr_aps_init() do {} while (0)
+#define mtrr_bp_restore() do {} while (0)
# endif
#ifdef CONFIG_COMPAT
Index: tip/arch/x86/kernel/cpu/common.c
===================================================================
--- tip.orig/arch/x86/kernel/cpu/common.c
+++ tip/arch/x86/kernel/cpu/common.c
@@ -880,7 +880,12 @@ void __cpuinit identify_secondary_cpu(st
#ifdef CONFIG_X86_32
enable_sep_cpu();
#endif
+ /*
+ * mtrr_ap_init() uses smp_call_function. Enable interrupts.
+ */
+ local_irq_enable();
mtrr_ap_init();
+ local_irq_disable();
}
struct msr_range {
Index: tip/arch/x86/kernel/cpu/mtrr/main.c
===================================================================
--- tip.orig/arch/x86/kernel/cpu/mtrr/main.c
+++ tip/arch/x86/kernel/cpu/mtrr/main.c
@@ -58,6 +58,7 @@ unsigned int mtrr_usage_table[MTRR_MAX_V
static DEFINE_MUTEX(mtrr_mutex);
u64 size_or_mask, size_and_mask;
+u32 mtrr_aps_delayed_init;
static struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM];
@@ -163,7 +164,10 @@ static void ipi_handler(void *info)
if (data->smp_reg != ~0U) {
mtrr_if->set(data->smp_reg, data->smp_base,
data->smp_size, data->smp_type);
- } else {
+ } else if (mtrr_aps_delayed_init) {
+ /*
+ * Initialize the MTRRs inaddition to the synchronisation.
+ */
mtrr_if->set_all();
}
@@ -265,6 +269,8 @@ set_mtrr(unsigned int reg, unsigned long
*/
if (reg != ~0U)
mtrr_if->set(reg, base, size, type);
+ else if (!mtrr_aps_delayed_init)
+ mtrr_if->set_all();
/* Wait for the others */
while (atomic_read(&data.count))
@@ -721,9 +727,7 @@ void __init mtrr_bp_init(void)
void mtrr_ap_init(void)
{
- unsigned long flags;
-
- if (!mtrr_if || !use_intel())
+ if (!use_intel() || mtrr_aps_delayed_init)
return;
/*
* Ideally we should hold mtrr_mutex here to avoid mtrr entries
@@ -738,11 +742,7 @@ void mtrr_ap_init(void)
* 2. cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug
* lock to prevent mtrr entry changes
*/
- local_irq_save(flags);
-
- mtrr_if->set_all();
-
- local_irq_restore(flags);
+ set_mtrr(~0U, 0, 0, 0);
}
/**
@@ -753,6 +753,42 @@ void mtrr_save_state(void)
smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1);
}
+void set_mtrr_aps_delayed_init(void)
+{
+ if (!use_intel())
+ return;
+
+ mtrr_aps_delayed_init = 1;
+}
+
+/*
+ * MTRR initialization for all AP's
+ */
+void mtrr_aps_init(void)
+{
+ if (!use_intel())
+ return;
+
+ /*
+ * Ideally we should hold mtrr_mutex here to avoid mtrr entries changed,
+ * but this routine will be called in cpu boot time, holding the lock
+ * breaks it. This routine is called in two cases: 1.very earily time
+ * of software resume, when there absolutely isn't mtrr entry changes;
+ * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
+ * prevent mtrr entry changes
+ */
+ set_mtrr(~0U, 0, 0, 0);
+ mtrr_aps_delayed_init = 0;
+}
+
+void mtrr_bp_restore(void)
+{
+ if (!use_intel())
+ return;
+
+ mtrr_if->set_all();
+}
+
static int __init mtrr_init_finialize(void)
{
if (!mtrr_if)
Index: tip/arch/x86/kernel/smpboot.c
===================================================================
--- tip.orig/arch/x86/kernel/smpboot.c
+++ tip/arch/x86/kernel/smpboot.c
@@ -1118,9 +1118,22 @@ void __init native_smp_prepare_cpus(unsi
if (is_uv_system())
uv_system_init();
+
+ set_mtrr_aps_delayed_init();
out:
preempt_enable();
}
+
+void arch_enable_nonboot_cpus_begin(void)
+{
+ set_mtrr_aps_delayed_init();
+}
+
+void arch_enable_nonboot_cpus_end(void)
+{
+ mtrr_aps_init();
+}
+
/*
* Early setup to make printk work.
*/
@@ -1142,6 +1155,7 @@ void __init native_smp_cpus_done(unsigne
setup_ioapic_dest();
#endif
check_nmi_watchdog();
+ mtrr_aps_init();
}
static int __initdata setup_possible_cpus = -1;
Index: tip/arch/x86/power/cpu.c
===================================================================
--- tip.orig/arch/x86/power/cpu.c
+++ tip/arch/x86/power/cpu.c
@@ -224,7 +224,7 @@ static void __restore_processor_state(st
fix_processor_context();
do_fpu_end();
- mtrr_ap_init();
+ mtrr_bp_restore();
#ifdef CONFIG_X86_OLD_MCE
mcheck_init(&boot_cpu_data);
Index: tip/kernel/cpu.c
===================================================================
--- tip.orig/kernel/cpu.c
+++ tip/kernel/cpu.c
@@ -413,6 +413,14 @@ int disable_nonboot_cpus(void)
return error;
}
+void __attribute__((weak)) arch_enable_nonboot_cpus_begin(void)
+{
+}
+
+void __attribute__((weak)) arch_enable_nonboot_cpus_end(void)
+{
+}
+
void __ref enable_nonboot_cpus(void)
{
int cpu, error;
@@ -424,6 +432,9 @@ void __ref enable_nonboot_cpus(void)
goto out;
printk("Enabling non-boot CPUs ...\n");
+
+ arch_enable_nonboot_cpus_begin();
+
for_each_cpu(cpu, frozen_cpus) {
error = _cpu_up(cpu, 1);
if (!error) {
@@ -432,6 +443,9 @@ void __ref enable_nonboot_cpus(void)
}
printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
}
+
+ arch_enable_nonboot_cpus_end();
+
cpumask_clear(frozen_cpus);
out:
cpu_maps_update_done();
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] x86: Rendezvous all the cpu's for MTRR/PAT init
2009-08-19 0:30 [patch] x86: Rendezvous all the cpu's for MTRR/PAT init Suresh Siddha
@ 2009-08-19 1:01 ` Andrew Morton
2009-08-19 6:20 ` Suresh Siddha
0 siblings, 1 reply; 6+ messages in thread
From: Andrew Morton @ 2009-08-19 1:01 UTC (permalink / raw)
To: Suresh Siddha; +Cc: mingo, hpa, tglx, venkatesh.pallipadi, linux-kernel
On Tue, 18 Aug 2009 17:30:35 -0700 Suresh Siddha <suresh.b.siddha@intel.com> wrote:
> Please consider applying this patch after the clockevents bugfix posted
> yesterday http://marc.info/?l=linux-kernel&m=125054497316006&w=2
>
> thanks,
> suresh
> ---
>
> From: Suresh Siddha <suresh.b.siddha@intel.com>
> Subject: x86: Rendezvous all the cpu's for MTRR/PAT init
>
> SDM Vol 3a section titled "MTRR considerations in MP systems" specifies
> the need for synchronizing the logical cpu's while initializing/updating
> MTRR.
>
> Currently Linux kernel does the synchronization of all cpu's only when
> a single MTRR register is programmed/updated. During an AP online
> (during boot/cpu-online/resume) where we initialize all the MTRR/PAT registers,
> we don't follow this synchronization algorithm.
>
> This can lead to scenarios where during a dynamic cpu online, that logical cpu
> is initializing MTRR/PAT with cache disabled (cr0.cd=1) etc while other logical
> HT sibling continue to run (also with cache disabled because of cr0.cd=1
> on its sibling).
>
> Starting from Westmere, VMX transitions with cr0.cd=1 don't work properly
> (because of some VMX performance optimizations) and the above scenario
> (with one logical cpu doing VMX activity and another logical cpu coming online)
> can result in system crash.
>
> Fix the MTRR initialization by doing rendezvous of all the cpus. During
> boot and resume, we delay the MTRR/PAT init for APs till all the
> logical cpu's come online and the rendezvous process at the end of AP's bringup,
> will initialize the MTRR/PAT for all AP's.
>
> For dynamic single cpu online, we synchronize all the logical cpus and
> do the MTRR/PAT init on the AP that is coming online.
>
> ...
>
> @@ -880,7 +880,12 @@ void __cpuinit identify_secondary_cpu(st
> #ifdef CONFIG_X86_32
> enable_sep_cpu();
> #endif
> + /*
> + * mtrr_ap_init() uses smp_call_function. Enable interrupts.
> + */
> + local_irq_enable();
> mtrr_ap_init();
> + local_irq_disable();
> }
Ick.
It's quite unobvious (to me) that this function is reliably called with
local interrupts disabled.
If it _is_ reliably called with interrupts disabled then why is it safe
to randomly reenable them here? Why not just stop disabling interrupts
at the top level?
>
> ...
>
> +void mtrr_aps_init(void)
> +{
> + if (!use_intel())
> + return;
> +
> + /*
> + * Ideally we should hold mtrr_mutex here to avoid mtrr entries changed,
> + * but this routine will be called in cpu boot time, holding the lock
> + * breaks it. This routine is called in two cases: 1.very earily time
> + * of software resume, when there absolutely isn't mtrr entry changes;
> + * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
> + * prevent mtrr entry changes
> + */
That's a tantalising little comment. What does "breaks it" mean? How
can reviewers and later code-readers possibly suggest alternative fixes
to this breakage if they aren't told what it is?
> + set_mtrr(~0U, 0, 0, 0);
> + mtrr_aps_delayed_init = 0;
> +}
> +
> +void mtrr_bp_restore(void)
> +{
> + if (!use_intel())
> + return;
> +
> + mtrr_if->set_all();
> +}
> +
>
> ...
>
> --- tip.orig/kernel/cpu.c
> +++ tip/kernel/cpu.c
> @@ -413,6 +413,14 @@ int disable_nonboot_cpus(void)
> return error;
> }
>
> +void __attribute__((weak)) arch_enable_nonboot_cpus_begin(void)
> +{
> +}
> +
> +void __attribute__((weak)) arch_enable_nonboot_cpus_end(void)
> +{
> +}
Please use __weak.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] x86: Rendezvous all the cpu's for MTRR/PAT init
2009-08-19 1:01 ` Andrew Morton
@ 2009-08-19 6:20 ` Suresh Siddha
2009-08-19 6:59 ` Shaohua Li
2009-08-19 7:50 ` Nick Piggin
0 siblings, 2 replies; 6+ messages in thread
From: Suresh Siddha @ 2009-08-19 6:20 UTC (permalink / raw)
To: Andrew Morton
Cc: Shaohua Li, Nick Piggin, mingo@elte.hu, hpa@zytor.com,
tglx@linutronix.de, Pallipadi, Venkatesh,
linux-kernel@vger.kernel.org
On Tue, 2009-08-18 at 18:01 -0700, Andrew Morton wrote:
> On Tue, 18 Aug 2009 17:30:35 -0700 Suresh Siddha <suresh.b.siddha@intel.com> wrote:
> > @@ -880,7 +880,12 @@ void __cpuinit identify_secondary_cpu(st
> > #ifdef CONFIG_X86_32
> > enable_sep_cpu();
> > #endif
> > + /*
> > + * mtrr_ap_init() uses smp_call_function. Enable interrupts.
> > + */
> > + local_irq_enable();
> > mtrr_ap_init();
> > + local_irq_disable();
> > }
>
> Ick.
oops. thought it will miss the radar of the sharp eyes. I was wrong :(
>
> It's quite unobvious (to me) that this function is reliably called with
> local interrupts disabled.
>
> If it _is_ reliably called with interrupts disabled then why is it safe
> to randomly reenable them here? Why not just stop disabling interrupts
> at the top level?
identify_secondary_cpu() always get called on APs. And APs have
interrupts disabled at this point. I did this
local_irq_enable()/disable() safely and thought I can getaway because
just before calling this, in smpboot.c in smp_callin() we do this:
local_irq_enable();
calibrate_delay();
local_irq_disable();
So having local_irq_enable()/disable() around mtrr_ap_init() is safe.
To make it clean I can move the smp_store_cpu_info() call before
local_irq_disable() in smp_callin(). But that needs more changes (for
xen etc). So thinking more, I think it is safe to do smp_call_function()
with interrupts disabled as the caller is currently not in the
cpu_online_mask.
i.e., no one else sends smp_call_function interrupt to this AP who is
doing smp_call_function() with interrupts disabled and as such there
won't be any deadlocks typically associated with calling
smp_call_function() with interrupts disabled. Copied Nick to confirm or
correct my understanding.
New patch appended removes this irq enable/disable sequence around
mtrr_ap_init() and add's a cpu_online() check in smp_call_function
warn-on's.
> > +void mtrr_aps_init(void)
> > +{
> > + if (!use_intel())
> > + return;
> > +
> > + /*
> > + * Ideally we should hold mtrr_mutex here to avoid mtrr entries changed,
> > + * but this routine will be called in cpu boot time, holding the lock
> > + * breaks it. This routine is called in two cases: 1.very earily time
> > + * of software resume, when there absolutely isn't mtrr entry changes;
> > + * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
> > + * prevent mtrr entry changes
> > + */
>
> That's a tantalising little comment. What does "breaks it" mean? How
> can reviewers and later code-readers possibly suggest alternative fixes
> to this breakage if they aren't told what it is?
This is a cut and paste comment coming from the previous code. Shaohua
added this comment originally and I think this is the case he is trying
to avoid.
cpu - A modifying/adding a MTRR register
cpu - B is coming online
if cpu - A doesn't take the cpu hotplug lock, then potentially what can
happen is that cpu B will update its mtrr's with old state and now A can
change the state and before B comes completely online, A can do send the
MTRR update to all cpu's except B.
So Shaohua's code is taking cpu hotplug lock before A updates MTRR's so
that B's MTRRs are always is in sync with rest of the cpu's in the
system. Only the mtrr_mutex is not enough.
Nevertheless as far as this patch is concerned mtrr_aps_init() gets
called during early boot/resume time and as such we never hit this
condition. So I removed this comment in the new patch appended.
Shaohua if you agree with my explanation we can have a separate patch to
make the original comment more meaningful.
> >
> > +void __attribute__((weak)) arch_enable_nonboot_cpus_begin(void)
> > +{
> > +}
> > +
> > +void __attribute__((weak)) arch_enable_nonboot_cpus_end(void)
> > +{
> > +}
>
> Please use __weak.
Oops. Fixed.
New patch appended. I can split the smp.c warn_on() changes into another
patch, if needed. But for distribution pickups, I thought single patch
might be easy.
thanks,
suresh
---
From: Suresh Siddha <suresh.b.siddha@intel.com>
Subject: x86: Rendezvous all the cpu's for MTRR/PAT init
SDM Vol 3a section titled "MTRR considerations in MP systems" specifies
the need for synchronizing the logical cpu's while initializing/updating
MTRR.
Currently Linux kernel does the synchronization of all cpu's only when
a single MTRR register is programmed/updated. During an AP online
(during boot/cpu-online/resume) where we initialize all the MTRR/PAT registers,
we don't follow this synchronization algorithm.
This can lead to scenarios where during a dynamic cpu online, that logical cpu
is initializing MTRR/PAT with cache disabled (cr0.cd=1) etc while other logical
HT sibling continue to run (also with cache disabled because of cr0.cd=1
on its sibling).
Starting from Westmere, VMX transitions with cr0.cd=1 don't work properly
(because of some VMX performance optimizations) and the above scenario
(with one logical cpu doing VMX activity and another logical cpu coming online)
can result in system crash.
Fix the MTRR initialization by doing rendezvous of all the cpus. During
boot and resume, we delay the MTRR/PAT init for APs till all the
logical cpu's come online and the rendezvous process at the end of AP's bringup,
will initialize the MTRR/PAT for all AP's.
For dynamic single cpu online, we synchronize all the logical cpus and
do the MTRR/PAT init on the AP that is coming online.
Also fix the warn_on's in smp_call_function() to check for online cpu,
as it is safe for a cpu that is still not online to call smp_call_function()
with interrupts disabled.
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
---
Index: tip/arch/x86/include/asm/mtrr.h
===================================================================
--- tip.orig/arch/x86/include/asm/mtrr.h
+++ tip/arch/x86/include/asm/mtrr.h
@@ -121,8 +121,12 @@ extern int mtrr_del_page(int reg, unsign
extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi);
extern void mtrr_ap_init(void);
extern void mtrr_bp_init(void);
+extern void set_mtrr_aps_delayed_init(void);
+extern void mtrr_aps_init(void);
+extern void mtrr_bp_restore(void);
extern int mtrr_trim_uncached_memory(unsigned long end_pfn);
extern int amd_special_default_mtrr(void);
+extern u32 mtrr_aps_delayed_init;
# else
static inline u8 mtrr_type_lookup(u64 addr, u64 end)
{
@@ -161,6 +165,9 @@ static inline void mtrr_centaur_report_m
#define mtrr_ap_init() do {} while (0)
#define mtrr_bp_init() do {} while (0)
+#define set_mtrr_aps_delayed_init() do {} while (0)
+#define mtrr_aps_init() do {} while (0)
+#define mtrr_bp_restore() do {} while (0)
# endif
#ifdef CONFIG_COMPAT
Index: tip/arch/x86/kernel/cpu/mtrr/main.c
===================================================================
--- tip.orig/arch/x86/kernel/cpu/mtrr/main.c
+++ tip/arch/x86/kernel/cpu/mtrr/main.c
@@ -58,6 +58,7 @@ unsigned int mtrr_usage_table[MTRR_MAX_V
static DEFINE_MUTEX(mtrr_mutex);
u64 size_or_mask, size_and_mask;
+u32 mtrr_aps_delayed_init;
static struct mtrr_ops *mtrr_ops[X86_VENDOR_NUM];
@@ -163,7 +164,10 @@ static void ipi_handler(void *info)
if (data->smp_reg != ~0U) {
mtrr_if->set(data->smp_reg, data->smp_base,
data->smp_size, data->smp_type);
- } else {
+ } else if (mtrr_aps_delayed_init) {
+ /*
+ * Initialize the MTRRs inaddition to the synchronisation.
+ */
mtrr_if->set_all();
}
@@ -265,6 +269,8 @@ set_mtrr(unsigned int reg, unsigned long
*/
if (reg != ~0U)
mtrr_if->set(reg, base, size, type);
+ else if (!mtrr_aps_delayed_init)
+ mtrr_if->set_all();
/* Wait for the others */
while (atomic_read(&data.count))
@@ -721,9 +727,7 @@ void __init mtrr_bp_init(void)
void mtrr_ap_init(void)
{
- unsigned long flags;
-
- if (!mtrr_if || !use_intel())
+ if (!use_intel() || mtrr_aps_delayed_init)
return;
/*
* Ideally we should hold mtrr_mutex here to avoid mtrr entries
@@ -738,11 +742,7 @@ void mtrr_ap_init(void)
* 2. cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug
* lock to prevent mtrr entry changes
*/
- local_irq_save(flags);
-
- mtrr_if->set_all();
-
- local_irq_restore(flags);
+ set_mtrr(~0U, 0, 0, 0);
}
/**
@@ -753,6 +753,34 @@ void mtrr_save_state(void)
smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1);
}
+void set_mtrr_aps_delayed_init(void)
+{
+ if (!use_intel())
+ return;
+
+ mtrr_aps_delayed_init = 1;
+}
+
+/*
+ * MTRR initialization for all AP's
+ */
+void mtrr_aps_init(void)
+{
+ if (!use_intel())
+ return;
+
+ set_mtrr(~0U, 0, 0, 0);
+ mtrr_aps_delayed_init = 0;
+}
+
+void mtrr_bp_restore(void)
+{
+ if (!use_intel())
+ return;
+
+ mtrr_if->set_all();
+}
+
static int __init mtrr_init_finialize(void)
{
if (!mtrr_if)
Index: tip/arch/x86/kernel/smpboot.c
===================================================================
--- tip.orig/arch/x86/kernel/smpboot.c
+++ tip/arch/x86/kernel/smpboot.c
@@ -1118,9 +1118,22 @@ void __init native_smp_prepare_cpus(unsi
if (is_uv_system())
uv_system_init();
+
+ set_mtrr_aps_delayed_init();
out:
preempt_enable();
}
+
+void arch_enable_nonboot_cpus_begin(void)
+{
+ set_mtrr_aps_delayed_init();
+}
+
+void arch_enable_nonboot_cpus_end(void)
+{
+ mtrr_aps_init();
+}
+
/*
* Early setup to make printk work.
*/
@@ -1142,6 +1155,7 @@ void __init native_smp_cpus_done(unsigne
setup_ioapic_dest();
#endif
check_nmi_watchdog();
+ mtrr_aps_init();
}
static int __initdata setup_possible_cpus = -1;
Index: tip/arch/x86/power/cpu.c
===================================================================
--- tip.orig/arch/x86/power/cpu.c
+++ tip/arch/x86/power/cpu.c
@@ -224,7 +224,7 @@ static void __restore_processor_state(st
fix_processor_context();
do_fpu_end();
- mtrr_ap_init();
+ mtrr_bp_restore();
#ifdef CONFIG_X86_OLD_MCE
mcheck_init(&boot_cpu_data);
Index: tip/kernel/cpu.c
===================================================================
--- tip.orig/kernel/cpu.c
+++ tip/kernel/cpu.c
@@ -413,6 +413,14 @@ int disable_nonboot_cpus(void)
return error;
}
+void __weak arch_enable_nonboot_cpus_begin(void)
+{
+}
+
+void __weak arch_enable_nonboot_cpus_end(void)
+{
+}
+
void __ref enable_nonboot_cpus(void)
{
int cpu, error;
@@ -424,6 +432,9 @@ void __ref enable_nonboot_cpus(void)
goto out;
printk("Enabling non-boot CPUs ...\n");
+
+ arch_enable_nonboot_cpus_begin();
+
for_each_cpu(cpu, frozen_cpus) {
error = _cpu_up(cpu, 1);
if (!error) {
@@ -432,6 +443,9 @@ void __ref enable_nonboot_cpus(void)
}
printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
}
+
+ arch_enable_nonboot_cpus_end();
+
cpumask_clear(frozen_cpus);
out:
cpu_maps_update_done();
Index: tip/kernel/smp.c
===================================================================
--- tip.orig/kernel/smp.c
+++ tip/kernel/smp.c
@@ -286,7 +286,8 @@ int smp_call_function_single(int cpu, vo
this_cpu = get_cpu();
/* Can deadlock when called with interrupts disabled */
- WARN_ON_ONCE(irqs_disabled() && !oops_in_progress);
+ WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
+ && !oops_in_progress);
if (cpu == this_cpu) {
local_irq_save(flags);
@@ -330,7 +331,8 @@ void __smp_call_function_single(int cpu,
csd_lock(data);
/* Can deadlock when called with interrupts disabled */
- WARN_ON_ONCE(wait && irqs_disabled() && !oops_in_progress);
+ WARN_ON_ONCE(cpu_online(smp_processor_id()) && wait && irqs_disabled()
+ && !oops_in_progress);
generic_exec_single(cpu, data, wait);
}
@@ -366,7 +368,8 @@ void smp_call_function_many(const struct
int cpu, next_cpu, this_cpu = smp_processor_id();
/* Can deadlock when called with interrupts disabled */
- WARN_ON_ONCE(irqs_disabled() && !oops_in_progress);
+ WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled()
+ && !oops_in_progress);
/* So, what's a CPU they want? Ignoring this one. */
cpu = cpumask_first_and(mask, cpu_online_mask);
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] x86: Rendezvous all the cpu's for MTRR/PAT init
2009-08-19 6:20 ` Suresh Siddha
@ 2009-08-19 6:59 ` Shaohua Li
2009-08-19 7:50 ` Nick Piggin
1 sibling, 0 replies; 6+ messages in thread
From: Shaohua Li @ 2009-08-19 6:59 UTC (permalink / raw)
To: Siddha, Suresh B
Cc: Andrew Morton, Nick Piggin, mingo@elte.hu, hpa@zytor.com,
tglx@linutronix.de, Pallipadi, Venkatesh,
linux-kernel@vger.kernel.org
On Wed, Aug 19, 2009 at 02:20:57PM +0800, Siddha, Suresh B wrote:
> On Tue, 2009-08-18 at 18:01 -0700, Andrew Morton wrote:
> > On Tue, 18 Aug 2009 17:30:35 -0700 Suresh Siddha <suresh.b.siddha@intel.com> wrote:
> > > + /*
> > > + * Ideally we should hold mtrr_mutex here to avoid mtrr entries changed,
> > > + * but this routine will be called in cpu boot time, holding the lock
> > > + * breaks it. This routine is called in two cases: 1.very earily time
> > > + * of software resume, when there absolutely isn't mtrr entry changes;
> > > + * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
> > > + * prevent mtrr entry changes
> > > + */
> >
> > That's a tantalising little comment. What does "breaks it" mean? How
> > can reviewers and later code-readers possibly suggest alternative fixes
> > to this breakage if they aren't told what it is?
>
> This is a cut and paste comment coming from the previous code. Shaohua
> added this comment originally and I think this is the case he is trying
> to avoid.
>
> cpu - A modifying/adding a MTRR register
>
> cpu - B is coming online
>
> if cpu - A doesn't take the cpu hotplug lock, then potentially what can
> happen is that cpu B will update its mtrr's with old state and now A can
> change the state and before B comes completely online, A can do send the
> MTRR update to all cpu's except B.
>
> So Shaohua's code is taking cpu hotplug lock before A updates MTRR's so
> that B's MTRRs are always is in sync with rest of the cpu's in the
> system. Only the mtrr_mutex is not enough.
>
> Nevertheless as far as this patch is concerned mtrr_aps_init() gets
> called during early boot/resume time and as such we never hit this
> condition. So I removed this comment in the new patch appended.
>
> Shaohua if you agree with my explanation we can have a separate patch to
> make the original comment more meaningful.
Yes, your explanation is correct.
Thanks,
Shaohua
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] x86: Rendezvous all the cpu's for MTRR/PAT init
2009-08-19 6:20 ` Suresh Siddha
2009-08-19 6:59 ` Shaohua Li
@ 2009-08-19 7:50 ` Nick Piggin
2009-08-19 13:10 ` Ingo Molnar
1 sibling, 1 reply; 6+ messages in thread
From: Nick Piggin @ 2009-08-19 7:50 UTC (permalink / raw)
To: Suresh Siddha
Cc: Andrew Morton, Shaohua Li, mingo@elte.hu, hpa@zytor.com,
tglx@linutronix.de, Pallipadi, Venkatesh,
linux-kernel@vger.kernel.org
On Tue, Aug 18, 2009 at 11:20:57PM -0700, Suresh B wrote:
> To make it clean I can move the smp_store_cpu_info() call before
> local_irq_disable() in smp_callin(). But that needs more changes (for
> xen etc). So thinking more, I think it is safe to do smp_call_function()
> with interrupts disabled as the caller is currently not in the
> cpu_online_mask.
>
> i.e., no one else sends smp_call_function interrupt to this AP who is
> doing smp_call_function() with interrupts disabled and as such there
> won't be any deadlocks typically associated with calling
> smp_call_function() with interrupts disabled. Copied Nick to confirm or
> correct my understanding.
>
> New patch appended removes this irq enable/disable sequence around
> mtrr_ap_init() and add's a cpu_online() check in smp_call_function
> warn-on's.
Yes this seems like a fine idea to me. Maybe also add a
WARN_ON(cpu_online) in the interrupt-side as well just to
make it clear.
If you split the patch out with its own changelog and give
a comment for the special case, then you can add an
Acked-by: Nick Piggin <npiggin@suse.de>
Although until you get acks from all arch maintainers, the
functionality would have to only be used on a per-arch basis
but that's probably OK as it's a pretty tricky thing for
generic code to be doing :)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [patch] x86: Rendezvous all the cpu's for MTRR/PAT init
2009-08-19 7:50 ` Nick Piggin
@ 2009-08-19 13:10 ` Ingo Molnar
0 siblings, 0 replies; 6+ messages in thread
From: Ingo Molnar @ 2009-08-19 13:10 UTC (permalink / raw)
To: Nick Piggin
Cc: Suresh Siddha, Andrew Morton, Shaohua Li, hpa@zytor.com,
tglx@linutronix.de, Pallipadi, Venkatesh,
linux-kernel@vger.kernel.org
* Nick Piggin <npiggin@suse.de> wrote:
> On Tue, Aug 18, 2009 at 11:20:57PM -0700, Suresh B wrote:
> > To make it clean I can move the smp_store_cpu_info() call before
> > local_irq_disable() in smp_callin(). But that needs more changes (for
> > xen etc). So thinking more, I think it is safe to do smp_call_function()
> > with interrupts disabled as the caller is currently not in the
> > cpu_online_mask.
> >
> > i.e., no one else sends smp_call_function interrupt to this AP who is
> > doing smp_call_function() with interrupts disabled and as such there
> > won't be any deadlocks typically associated with calling
> > smp_call_function() with interrupts disabled. Copied Nick to confirm or
> > correct my understanding.
> >
> > New patch appended removes this irq enable/disable sequence around
> > mtrr_ap_init() and add's a cpu_online() check in smp_call_function
> > warn-on's.
>
> Yes this seems like a fine idea to me. Maybe also add a
> WARN_ON(cpu_online) in the interrupt-side as well just to
> make it clear.
>
> If you split the patch out with its own changelog and give
> a comment for the special case, then you can add an
> Acked-by: Nick Piggin <npiggin@suse.de>
>
> Although until you get acks from all arch maintainers, the
> functionality would have to only be used on a per-arch basis but
> that's probably OK as it's a pretty tricky thing for generic code
> to be doing :)
Also, Suresh, please generate patches with diffstat included so
that the arch impact can be deducted at a glance.
Ingo
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-08-19 13:10 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-19 0:30 [patch] x86: Rendezvous all the cpu's for MTRR/PAT init Suresh Siddha
2009-08-19 1:01 ` Andrew Morton
2009-08-19 6:20 ` Suresh Siddha
2009-08-19 6:59 ` Shaohua Li
2009-08-19 7:50 ` Nick Piggin
2009-08-19 13:10 ` Ingo Molnar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox