mirror of
https://github.com/torvalds/linux.git
synced 2024-12-30 14:52:05 +00:00
Merge branch 'x86-idle-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-idle-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: x86, hotplug: In the MWAIT case of play_dead, CLFLUSH the cache line x86, hotplug: Move WBINVD back outside the play_dead loop x86, hotplug: Use mwait to offline a processor, fix the legacy case x86, mwait: Move mwait constants to a common header file
This commit is contained in:
commit
2a8b67fb72
15
arch/x86/include/asm/mwait.h
Normal file
15
arch/x86/include/asm/mwait.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef _ASM_X86_MWAIT_H
|
||||||
|
#define _ASM_X86_MWAIT_H
|
||||||
|
|
||||||
|
#define MWAIT_SUBSTATE_MASK 0xf
|
||||||
|
#define MWAIT_CSTATE_MASK 0xf
|
||||||
|
#define MWAIT_SUBSTATE_SIZE 4
|
||||||
|
#define MWAIT_MAX_NUM_CSTATES 8
|
||||||
|
|
||||||
|
#define CPUID_MWAIT_LEAF 5
|
||||||
|
#define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1
|
||||||
|
#define CPUID5_ECX_INTERRUPT_BREAK 0x2
|
||||||
|
|
||||||
|
#define MWAIT_ECX_INTERRUPT_BREAK 0x1
|
||||||
|
|
||||||
|
#endif /* _ASM_X86_MWAIT_H */
|
@ -766,29 +766,6 @@ extern unsigned long idle_halt;
|
|||||||
extern unsigned long idle_nomwait;
|
extern unsigned long idle_nomwait;
|
||||||
extern bool c1e_detected;
|
extern bool c1e_detected;
|
||||||
|
|
||||||
/*
|
|
||||||
* on systems with caches, caches must be flashed as the absolute
|
|
||||||
* last instruction before going into a suspended halt. Otherwise,
|
|
||||||
* dirty data can linger in the cache and become stale on resume,
|
|
||||||
* leading to strange errors.
|
|
||||||
*
|
|
||||||
* perform a variety of operations to guarantee that the compiler
|
|
||||||
* will not reorder instructions. wbinvd itself is serializing
|
|
||||||
* so the processor will not reorder.
|
|
||||||
*
|
|
||||||
* Systems without cache can just go into halt.
|
|
||||||
*/
|
|
||||||
static inline void wbinvd_halt(void)
|
|
||||||
{
|
|
||||||
mb();
|
|
||||||
/* check for clflush to determine if wbinvd is legal */
|
|
||||||
if (cpu_has_clflush)
|
|
||||||
asm volatile("cli; wbinvd; 1: hlt; jmp 1b" : : : "memory");
|
|
||||||
else
|
|
||||||
while (1)
|
|
||||||
halt();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void enable_sep_cpu(void);
|
extern void enable_sep_cpu(void);
|
||||||
extern int sysenter_setup(void);
|
extern int sysenter_setup(void);
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <acpi/processor.h>
|
#include <acpi/processor.h>
|
||||||
#include <asm/acpi.h>
|
#include <asm/acpi.h>
|
||||||
|
#include <asm/mwait.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize bm_flags based on the CPU cache properties
|
* Initialize bm_flags based on the CPU cache properties
|
||||||
@ -65,16 +66,6 @@ static struct cstate_entry __percpu *cpu_cstate_entry; /* per CPU ptr */
|
|||||||
|
|
||||||
static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
|
static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
|
||||||
|
|
||||||
#define MWAIT_SUBSTATE_MASK (0xf)
|
|
||||||
#define MWAIT_CSTATE_MASK (0xf)
|
|
||||||
#define MWAIT_SUBSTATE_SIZE (4)
|
|
||||||
|
|
||||||
#define CPUID_MWAIT_LEAF (5)
|
|
||||||
#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
|
|
||||||
#define CPUID5_ECX_INTERRUPT_BREAK (0x2)
|
|
||||||
|
|
||||||
#define MWAIT_ECX_INTERRUPT_BREAK (0x1)
|
|
||||||
|
|
||||||
#define NATIVE_CSTATE_BEYOND_HALT (2)
|
#define NATIVE_CSTATE_BEYOND_HALT (2)
|
||||||
|
|
||||||
static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
|
static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
#include <asm/mtrr.h>
|
#include <asm/mtrr.h>
|
||||||
|
#include <asm/mwait.h>
|
||||||
#include <asm/vmi.h>
|
#include <asm/vmi.h>
|
||||||
#include <asm/apic.h>
|
#include <asm/apic.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
@ -1395,11 +1396,88 @@ void play_dead_common(void)
|
|||||||
local_irq_disable();
|
local_irq_disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to flush the caches before going to sleep, lest we have
|
||||||
|
* dirty data in our caches when we come back up.
|
||||||
|
*/
|
||||||
|
static inline void mwait_play_dead(void)
|
||||||
|
{
|
||||||
|
unsigned int eax, ebx, ecx, edx;
|
||||||
|
unsigned int highest_cstate = 0;
|
||||||
|
unsigned int highest_subcstate = 0;
|
||||||
|
int i;
|
||||||
|
void *mwait_ptr;
|
||||||
|
|
||||||
|
if (!cpu_has(¤t_cpu_data, X86_FEATURE_MWAIT))
|
||||||
|
return;
|
||||||
|
if (!cpu_has(¤t_cpu_data, X86_FEATURE_CLFLSH))
|
||||||
|
return;
|
||||||
|
if (current_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
|
||||||
|
return;
|
||||||
|
|
||||||
|
eax = CPUID_MWAIT_LEAF;
|
||||||
|
ecx = 0;
|
||||||
|
native_cpuid(&eax, &ebx, &ecx, &edx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* eax will be 0 if EDX enumeration is not valid.
|
||||||
|
* Initialized below to cstate, sub_cstate value when EDX is valid.
|
||||||
|
*/
|
||||||
|
if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED)) {
|
||||||
|
eax = 0;
|
||||||
|
} else {
|
||||||
|
edx >>= MWAIT_SUBSTATE_SIZE;
|
||||||
|
for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
|
||||||
|
if (edx & MWAIT_SUBSTATE_MASK) {
|
||||||
|
highest_cstate = i;
|
||||||
|
highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
|
||||||
|
(highest_subcstate - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This should be a memory location in a cache line which is
|
||||||
|
* unlikely to be touched by other processors. The actual
|
||||||
|
* content is immaterial as it is not actually modified in any way.
|
||||||
|
*/
|
||||||
|
mwait_ptr = ¤t_thread_info()->flags;
|
||||||
|
|
||||||
|
wbinvd();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/*
|
||||||
|
* The CLFLUSH is a workaround for erratum AAI65 for
|
||||||
|
* the Xeon 7400 series. It's not clear it is actually
|
||||||
|
* needed, but it should be harmless in either case.
|
||||||
|
* The WBINVD is insufficient due to the spurious-wakeup
|
||||||
|
* case where we return around the loop.
|
||||||
|
*/
|
||||||
|
clflush(mwait_ptr);
|
||||||
|
__monitor(mwait_ptr, 0, 0);
|
||||||
|
mb();
|
||||||
|
__mwait(eax, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hlt_play_dead(void)
|
||||||
|
{
|
||||||
|
if (current_cpu_data.x86 >= 4)
|
||||||
|
wbinvd();
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
native_halt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void native_play_dead(void)
|
void native_play_dead(void)
|
||||||
{
|
{
|
||||||
play_dead_common();
|
play_dead_common();
|
||||||
tboot_shutdown(TB_SHUTDOWN_WFS);
|
tboot_shutdown(TB_SHUTDOWN_WFS);
|
||||||
wbinvd_halt();
|
|
||||||
|
mwait_play_dead(); /* Only returns on failure */
|
||||||
|
hlt_play_dead();
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* ... !CONFIG_HOTPLUG_CPU */
|
#else /* ... !CONFIG_HOTPLUG_CPU */
|
||||||
|
@ -30,18 +30,13 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <acpi/acpi_bus.h>
|
#include <acpi/acpi_bus.h>
|
||||||
#include <acpi/acpi_drivers.h>
|
#include <acpi/acpi_drivers.h>
|
||||||
|
#include <asm/mwait.h>
|
||||||
|
|
||||||
#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"
|
#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"
|
||||||
#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
|
#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
|
||||||
#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
|
#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
|
||||||
static DEFINE_MUTEX(isolated_cpus_lock);
|
static DEFINE_MUTEX(isolated_cpus_lock);
|
||||||
|
|
||||||
#define MWAIT_SUBSTATE_MASK (0xf)
|
|
||||||
#define MWAIT_CSTATE_MASK (0xf)
|
|
||||||
#define MWAIT_SUBSTATE_SIZE (4)
|
|
||||||
#define CPUID_MWAIT_LEAF (5)
|
|
||||||
#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
|
|
||||||
#define CPUID5_ECX_INTERRUPT_BREAK (0x2)
|
|
||||||
static unsigned long power_saving_mwait_eax;
|
static unsigned long power_saving_mwait_eax;
|
||||||
|
|
||||||
static unsigned char tsc_detected_unstable;
|
static unsigned char tsc_detected_unstable;
|
||||||
|
@ -59,18 +59,11 @@
|
|||||||
#include <linux/hrtimer.h> /* ktime_get_real() */
|
#include <linux/hrtimer.h> /* ktime_get_real() */
|
||||||
#include <trace/events/power.h>
|
#include <trace/events/power.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <asm/mwait.h>
|
||||||
|
|
||||||
#define INTEL_IDLE_VERSION "0.4"
|
#define INTEL_IDLE_VERSION "0.4"
|
||||||
#define PREFIX "intel_idle: "
|
#define PREFIX "intel_idle: "
|
||||||
|
|
||||||
#define MWAIT_SUBSTATE_MASK (0xf)
|
|
||||||
#define MWAIT_CSTATE_MASK (0xf)
|
|
||||||
#define MWAIT_SUBSTATE_SIZE (4)
|
|
||||||
#define MWAIT_MAX_NUM_CSTATES 8
|
|
||||||
#define CPUID_MWAIT_LEAF (5)
|
|
||||||
#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
|
|
||||||
#define CPUID5_ECX_INTERRUPT_BREAK (0x2)
|
|
||||||
|
|
||||||
static struct cpuidle_driver intel_idle_driver = {
|
static struct cpuidle_driver intel_idle_driver = {
|
||||||
.name = "intel_idle",
|
.name = "intel_idle",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
Loading…
Reference in New Issue
Block a user