diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2010-09-20 16:04:45 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2010-09-20 18:51:59 -0400 |
commit | ce5f68246bf2385d6174856708d0b746dc378f20 (patch) | |
tree | ba2436cd462a72222a995a6ba887f66232f50843 /arch/x86/kernel/smpboot.c | |
parent | a68e5c94f7d3dd64fef34dd5d97e365cae4bb42a (diff) |
x86, hotplug: In the MWAIT case of play_dead, CLFLUSH the cache line
When we're using MWAIT for play_dead, explicitly CLFLUSH the cache
line before executing MONITOR. This is a potential workaround for the
Xeon 7400 erratum AAI65 after having a spurious wakeup and returning
around the loop. "Potential" here because it is not certain that that
erratum could actually trigger; however, the CLFLUSH should be
harmless.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Acked-by: Venkatesh Pallipadi <venki@google.com>
Cc: Asit Mallick <asit.k.mallick@intel.com>
Cc: Arjan van de Ven <arjan@linux.kernel.org>
Cc: Len Brown <lenb@kernel.org>
Diffstat (limited to 'arch/x86/kernel/smpboot.c')
-rw-r--r-- | arch/x86/kernel/smpboot.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 55c80ffb8719..fdccfe9dc63d 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -1394,9 +1394,12 @@ static inline void mwait_play_dead(void) | |||
1394 | unsigned int highest_cstate = 0; | 1394 | unsigned int highest_cstate = 0; |
1395 | unsigned int highest_subcstate = 0; | 1395 | unsigned int highest_subcstate = 0; |
1396 | int i; | 1396 | int i; |
1397 | void *mwait_ptr; | ||
1397 | 1398 | ||
1398 | if (!cpu_has(¤t_cpu_data, X86_FEATURE_MWAIT)) | 1399 | if (!cpu_has(¤t_cpu_data, X86_FEATURE_MWAIT)) |
1399 | return; | 1400 | return; |
1401 | if (!cpu_has(¤t_cpu_data, X86_FEATURE_CLFLSH)) | ||
1402 | return; | ||
1400 | if (current_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) | 1403 | if (current_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) |
1401 | return; | 1404 | return; |
1402 | 1405 | ||
@@ -1422,10 +1425,25 @@ static inline void mwait_play_dead(void) | |||
1422 | (highest_subcstate - 1); | 1425 | (highest_subcstate - 1); |
1423 | } | 1426 | } |
1424 | 1427 | ||
1428 | /* | ||
1429 | * This should be a memory location in a cache line which is | ||
1430 | * unlikely to be touched by other processors. The actual | ||
1431 | * content is immaterial as it is not actually modified in any way. | ||
1432 | */ | ||
1433 | mwait_ptr = ¤t_thread_info()->flags; | ||
1434 | |||
1425 | wbinvd(); | 1435 | wbinvd(); |
1426 | 1436 | ||
1427 | while (1) { | 1437 | while (1) { |
1428 | __monitor(¤t_thread_info()->flags, 0, 0); | 1438 | /* |
1439 | * The CLFLUSH is a workaround for erratum AAI65 for | ||
1440 | * the Xeon 7400 series. It's not clear it is actually | ||
1441 | * needed, but it should be harmless in either case. | ||
1442 | * The WBINVD is insufficient due to the spurious-wakeup | ||
1443 | * case where we return around the loop. | ||
1444 | */ | ||
1445 | clflush(mwait_ptr); | ||
1446 | __monitor(mwait_ptr, 0, 0); | ||
1429 | mb(); | 1447 | mb(); |
1430 | __mwait(eax, 0); | 1448 | __mwait(eax, 0); |
1431 | } | 1449 | } |