hrev44860 adds 17 changesets to branch 'master' old head: 8a6451b9fdd949f67cdef090635ce610d1216cce new head: 5e520ef3995c81a6e1d4ba7ef094c18b4eeaeef3 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=5e520ef+^8a6451b ---------------------------------------------------------------------------- 2195811: idle: introduce cpuidle generic module This module will load the various lowlevel cpuidle modules' implementations during initialiation. If it finds one available module, it will change the global gCpuIdleFunc as its own better one. When idle, cpuidle module will select the best cstate and enter it by calling the lowlevel module's implementation. Signed-off-by: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 251f971: cpuidle: add intel native cpuidle module Currently, it only supports intel sandy bridge processors. Signed-off-by: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 32c4d58: driver: add cpuidle device driver Currently, it's only used to load generic cpuidle module. But in the future, we will add some features such as stats reporting etc. Signed-off-by: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 5ae9700: enable cpuidle module and device driver Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 66b0c86: cpuidle: rename CpuidleStats to CpuidleStat Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 76877c9: intel_cpuidle: apply strict cpu checking to see it's snb or not we need to check cpu vendor, family, and model Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] e467ba9: cpuidle: add stats reporting support Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 69f69b0: cpuidle: we should exit when cStateCount is less than 3 If only C0, C1 are available, it doesn't make any sense to enable cpuidle Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 57311e7: acpi: add ACPI_ALLOCATE_LOCAL_BUFFER to ACPI.h Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 71d9d37: cpuidle: move generic cpuidle to generic After this change, low level cpuidle drivers load the generic cpuidle module if they can support the underlying platform. change the intel cpuidle driver accordingly, now it's loaded by acpi bus manager during boot, although it doesn't depend on acpi Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 0a0af89: acpi: export read_bit_register and write_bit_register acpi cpuidle needs such acpi functions Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 0138a95: cpuidle: implement acpi cpuidle driver we prefer intel native cpuidle driver on newer intel platforms -- sandybridge or later. we'll fall back to acpi cpuidle driver for other platforms. Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] be9a02c: cpuidle: remove drivers/cpuidle Since generic cpuidle module is loaded by lowlevel cpuidle drivers which are loaded dynamically during boot, we don't need drivers/cpuidle any more Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 8073227: x86_cpuidle: use module_dependencies rather than get_module() Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 5554814: x86_cpuidle: coding style fix according to Jerome Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ] 553f1eb: Add disabled cpuidle driver and module to haikuImage. CPU idle still needs some polish, but it should work on newer cpus. [ Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ] 5e520ef: Merge branch 'cpu_idle' * cpu_idle: Add disabled cpuidle driver and module to haikuImage. x86_cpuidle: coding style fix according to Jerome x86_cpuidle: use module_dependencies rather than get_module() cpuidle: remove drivers/cpuidle cpuidle: implement acpi cpuidle driver acpi: export read_bit_register and write_bit_register cpuidle: move generic cpuidle to generic acpi: add ACPI_ALLOCATE_LOCAL_BUFFER to ACPI.h cpuidle: we should exit when cStateCount is less than 3 cpuidle: add stats reporting support intel_cpuidle: apply strict cpu checking to see it's snb or not cpuidle: rename CpuidleStats to CpuidleStat enable cpuidle module and device driver driver: add cpuidle device driver cpuidle: add intel native cpuidle module idle: introduce cpuidle generic module [ Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ] ---------------------------------------------------------------------------- 12 files changed, 939 insertions(+), 2 deletions(-) build/jam/HaikuImage | 3 +- headers/os/drivers/ACPI.h | 5 + headers/os/drivers/cpuidle.h | 57 ++ .../kernel/bus_managers/acpi/BusManager.cpp | 18 +- src/add-ons/kernel/drivers/power/Jamfile | 1 + .../kernel/drivers/power/x86_cpuidle/Jamfile | 10 + .../drivers/power/x86_cpuidle/acpi_cpuidle.cpp | 583 +++++++++++++++++++ .../drivers/power/x86_cpuidle/intel_cpuidle.cpp | 121 ++++ .../drivers/power/x86_cpuidle/x86_cpuidle.h | 30 + src/add-ons/kernel/generic/Jamfile | 1 + src/add-ons/kernel/generic/cpuidle/Jamfile | 7 + src/add-ons/kernel/generic/cpuidle/cpuidle.cpp | 105 ++++ ############################################################################ Commit: 2195811a847b0a573b017750eefda19abcf0a6ec URL: http://cgit.haiku-os.org/haiku/commit/?id=2195811 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Wed Jul 4 15:28:43 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:17 2012 UTC idle: introduce cpuidle generic module This module will load the various lowlevel cpuidle modules' implementations during initialiation. If it finds one available module, it will change the global gCpuIdleFunc as its own better one. When idle, cpuidle module will select the best cstate and enter it by calling the lowlevel module's implementation. Signed-off-by: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/cpuidle.h b/headers/os/drivers/cpuidle.h new file mode 100644 index 0000000..67d8f30 --- /dev/null +++ b/headers/os/drivers/cpuidle.h @@ -0,0 +1,51 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _CPUIDLE_MODULE_H +#define _CPUIDLE_MODULE_H + + +#include <module.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define CPUIDLE_CSTATE_MAX 8 +#define CSTATE_NAME_LENGTH 32 +#define B_CPUIDLE_MODULE_NAME "idle/generic/cpuidle/v1" + + +struct CpuidleStats { + uint64 usageCount; + bigtime_t usageTime; +}; + + +struct CpuidleInfo { + int32 cstateSleep; + CpuidleStats stats[CPUIDLE_CSTATE_MAX]; +}; + + +struct CpuidleCstate { + char name[CSTATE_NAME_LENGTH]; + int32 latency; + int32 (*EnterIdle)(int32 state, CpuidleCstate *cstate); + void *pData; +}; + + +struct CpuidleModuleInfo { + module_info info; + CpuidleCstate cStates[CPUIDLE_CSTATE_MAX]; + int32 cStateCount; +}; + + +#ifdef __cplusplus +} +#endif + +#endif // _CPUIDLE_MODULE_H diff --git a/src/add-ons/kernel/idle/Jamfile b/src/add-ons/kernel/idle/Jamfile new file mode 100644 index 0000000..27f0864 --- /dev/null +++ b/src/add-ons/kernel/idle/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src add-ons kernel idle ; + +SubInclude HAIKU_TOP src add-ons kernel idle generic ; diff --git a/src/add-ons/kernel/idle/generic/Jamfile b/src/add-ons/kernel/idle/generic/Jamfile new file mode 100644 index 0000000..f7ff039 --- /dev/null +++ b/src/add-ons/kernel/idle/generic/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src add-ons kernel idle generic ; + +UsePrivateKernelHeaders ; + +KernelAddon <module>cpuidle : + cpuidle.cpp + ; diff --git a/src/add-ons/kernel/idle/generic/cpuidle.cpp b/src/add-ons/kernel/idle/generic/cpuidle.cpp new file mode 100644 index 0000000..4338a16 --- /dev/null +++ b/src/add-ons/kernel/idle/generic/cpuidle.cpp @@ -0,0 +1,119 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yongcong Du <ycdu.vmcore@xxxxxxxxx> + */ + +#include <KernelExport.h> +#include <stdio.h> +#include <string.h> + +#include <smp.h> +#include <cpuidle.h> + + +static CpuidleInfo sPerCPU[B_MAX_CPU_COUNT]; +static CpuidleModuleInfo *sCpuidleModule; + +extern void (*gCpuIdleFunc)(void); + + +/* + * next cstate selection algorithm is based on NetBSD's + * it's simple, stupid + */ +static int32 +SelectCstate(CpuidleInfo *info) +{ + static const int32 csFactor = 3; + + for (int32 i = sCpuidleModule->cStateCount - 1; i > 0; i--) { + CpuidleCstate *cState = &sCpuidleModule->cStates[i]; + if (info->cstateSleep > cState->latency * csFactor) + return i; + } + + /* Choose C1 if there's no state found */ + return 1; +} + + +static inline void +EnterCstate(int32 state, CpuidleInfo *info) +{ + CpuidleCstate *cstate = &sCpuidleModule->cStates[state]; + bigtime_t now = system_time(); + if (cstate->EnterIdle(state, cstate) > 0) { + bigtime_t diff = system_time() - now; + info->cstateSleep = diff; + info->stats[state].usageCount++; + info->stats[state].usageTime += diff; + } else { + info->cstateSleep = 0; + } +} + + +static void +CpuCstateIdle(void) +{ + CpuidleInfo *info = &sPerCPU[smp_get_current_cpu()]; + int32 state = SelectCstate(info); + EnterCstate(state, info); +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + { + dprintf("generic cpuidle init\n"); + void *cookie = open_module_list("idle/cpuidles"); + if (cookie == NULL) + return B_ERROR; + + char name[B_FILE_NAME_LENGTH]; + size_t nameLength = sizeof(name); + + while (read_next_module_name(cookie, name, &nameLength) == B_OK) { + if (get_module(name, (module_info **)&sCpuidleModule) == B_OK) { + break; + } + } + + close_module_list(cookie); + if (sCpuidleModule->cStateCount < 2) { + dprintf("no enough available cstates, exiting...\n"); + put_module(sCpuidleModule->info.name); + return B_ERROR; + } else { + dprintf("using %s\n", sCpuidleModule->info.name); + gCpuIdleFunc = CpuCstateIdle; + return B_OK; + } + } + case B_MODULE_UNINIT: + dprintf("generic cpuidle uninit\n"); + put_module(sCpuidleModule->info.name); + return B_OK; + } + + return B_ERROR; +} + + +static module_info sModule = { + B_CPUIDLE_MODULE_NAME, + 0, + std_ops +}; + + +module_info *modules[] = { + (module_info *)&sModule, + NULL +}; ############################################################################ Commit: 251f971259714ef07cc4642f145bfb4ce552eb0e URL: http://cgit.haiku-os.org/haiku/commit/?id=251f971 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Wed Jul 4 16:09:35 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:17 2012 UTC cpuidle: add intel native cpuidle module Currently, it only supports intel sandy bridge processors. Signed-off-by: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/idle/Jamfile b/src/add-ons/kernel/idle/Jamfile index 27f0864..878fd5c 100644 --- a/src/add-ons/kernel/idle/Jamfile +++ b/src/add-ons/kernel/idle/Jamfile @@ -1,3 +1,4 @@ SubDir HAIKU_TOP src add-ons kernel idle ; +SubInclude HAIKU_TOP src add-ons kernel idle cpuidles ; SubInclude HAIKU_TOP src add-ons kernel idle generic ; diff --git a/src/add-ons/kernel/idle/cpuidles/Jamfile b/src/add-ons/kernel/idle/cpuidles/Jamfile new file mode 100644 index 0000000..03a6a3c --- /dev/null +++ b/src/add-ons/kernel/idle/cpuidles/Jamfile @@ -0,0 +1,3 @@ +SubDir HAIKU_TOP src add-ons kernel idle cpuidles ; + +SubInclude HAIKU_TOP src add-ons kernel idle cpuidles intel_cpuidle ; diff --git a/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/Jamfile b/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/Jamfile new file mode 100644 index 0000000..4b74f09 --- /dev/null +++ b/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src add-ons kernel idle cpuidles intel_cpuidle ; + +UsePrivateKernelHeaders ; + +KernelAddon intel_cpuidle : + intel_cpuidle.cpp + ; diff --git a/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp b/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp new file mode 100644 index 0000000..a2bba81 --- /dev/null +++ b/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp @@ -0,0 +1,148 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yongcong Du <ycdu.vmcore@xxxxxxxxx> + */ + +#include <KernelExport.h> +#include <stdio.h> + +#include <cpu.h> +#include <arch_system_info.h> +#include <cpuidle.h> + + +static status_t std_ops(int32 op, ...); + + +static inline void +x86_monitor(const void *addr, unsigned long ecx, unsigned long edx) +{ + asm volatile("monitor" + :: "a" (addr), "c" (ecx), "d"(edx)); +} + + +static inline void +x86_mwait(unsigned long eax, unsigned long ecx) +{ + asm volatile("mwait" + :: "a" (eax), "c" (ecx)); +} + + +static void *kMwaitEax[] = { + // C0, we never use it + (void *)0x00, + // MWAIT C1 + (void *)0x00, + // MWAIT C2 + (void *)0x10, + // MWAIT C3 + (void *)0x20, + // MWAIT C4 + (void *)0x30, + // MWAIT C5 + (void *)0x40, + // MWAIT C6, 0x2 is used to fully shrink L2 cache + (void *)0x52 +}; + + +static int32 +IntelCstateIdleEnter(int32 state, CpuidleCstate *cstate) +{ + cpu_ent *cpu = get_cpu_struct(); + if (cpu->invoke_scheduler) + return 0; + + x86_monitor((void *)&cpu->invoke_scheduler, 0, 0); + if (!cpu->invoke_scheduler) + x86_mwait((unsigned long)cstate->pData, 1); + + return state; +} + + +static CpuidleCstate kSnbcStates[CPUIDLE_CSTATE_MAX] = { + {}, + { + "C1-SNB", + 1, + IntelCstateIdleEnter, + }, + { + "C3-SNB", + 80, + IntelCstateIdleEnter, + }, + { + "C6-SNB", + 104, + IntelCstateIdleEnter, + }, + { + "C7-SNB", + 109, + IntelCstateIdleEnter, + }, +}; + + +static CpuidleModuleInfo sIntelidleModule = { + { + "idle/cpuidles/intel_cpuidle/v1", + 0, + std_ops + }, + +}; + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + { + cpuid_info cpuid; + get_current_cpuid(&cpuid, 5); + /* ecx[0] monitor/mwait extension supported + * ecx[1] support for treating interrupts as break-events for mwait + * edx number of sub-states + */ + if (!((cpuid.regs.ecx & 0x1) && (cpuid.regs.ecx & 0x2) && + cpuid.regs.edx)) { + return B_ERROR; + } + + sIntelidleModule.cStateCount = 1; + for (int32 i = 1; i < CPUIDLE_CSTATE_MAX; i++) { + int32 subStates = (cpuid.regs.edx >> ((i) * 4)) & 0xf; + // no sub-states means the state is not available + if (!subStates) + continue; + sIntelidleModule.cStates[sIntelidleModule.cStateCount] = + kSnbcStates[i]; + sIntelidleModule.cStates[sIntelidleModule.cStateCount].pData = + kMwaitEax[i]; + sIntelidleModule.cStateCount++; + } + dprintf("intel idle init\n"); + return B_OK; + } + case B_MODULE_UNINIT: + dprintf("intel idle uninit\n"); + return B_OK; + } + + return B_ERROR; +} + + +module_info *modules[] = { + (module_info *)&sIntelidleModule, + NULL +}; ############################################################################ Commit: 32c4d58bd3f0cc284c95103e8c970dda643e57f4 URL: http://cgit.haiku-os.org/haiku/commit/?id=32c4d58 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Wed Jul 4 16:11:53 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:18 2012 UTC driver: add cpuidle device driver Currently, it's only used to load generic cpuidle module. But in the future, we will add some features such as stats reporting etc. Signed-off-by: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/cpuidle/Jamfile b/src/add-ons/kernel/drivers/cpuidle/Jamfile new file mode 100644 index 0000000..50b9290 --- /dev/null +++ b/src/add-ons/kernel/drivers/cpuidle/Jamfile @@ -0,0 +1,5 @@ +SubDir HAIKU_TOP src add-ons kernel drivers cpuidle ; + +KernelAddon <driver>cpuidle : + cpuidle.cpp + ; diff --git a/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp b/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp new file mode 100644 index 0000000..9440358 --- /dev/null +++ b/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yongcong Du <ycdu.vmcore@xxxxxxxxx> + */ + +#include <Drivers.h> +#include <KernelExport.h> + +#include <cpuidle.h> + +#define DEVICE_NAME "cpuidle" + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +CpuidleModuleInfo *sCpuidleModule; + +static status_t +cpuidle_open(const char *name, uint32 flags, void **cookie) +{ + *cookie = NULL; + return B_OK; +} + + +static status_t +cpuidle_close(void *cookie) +{ + return B_OK; +} + + +static status_t +cpuidle_free(void *cookie) +{ + return B_OK; +} + + +static status_t +cpuidle_ioctl(void *cookie, uint32 op, void *buffer, size_t length) +{ + return B_OK; +} + + +static status_t +cpuidle_read(void *cookie, off_t pos, void *buffer, size_t *length) +{ + *length = 0; + return B_OK; +} + + +static status_t +cpuidle_write(void *cookie, off_t pos, const void *buffer, size_t *_length) +{ + return B_OK; +} + + +status_t +init_hardware(void) +{ + return B_OK; +} + + +const char ** +publish_devices(void) +{ + static const char *devices[] = { + DEVICE_NAME, + NULL + }; + + return devices; +} + + +device_hooks * +find_device(const char *name) +{ + static device_hooks hooks = { + &cpuidle_open, + &cpuidle_close, + &cpuidle_free, + &cpuidle_ioctl, + &cpuidle_read, + &cpuidle_write, + }; + + + return &hooks; +} + + +status_t +init_driver(void) +{ + status_t err; + + err = get_module(B_CPUIDLE_MODULE_NAME, (module_info **)&sCpuidleModule); + if (err != B_OK) { + dprintf("can't load "B_CPUIDLE_MODULE_NAME"\n"); + } + return B_OK; +} + + +void +uninit_driver(void) +{ + put_module(B_CPUIDLE_MODULE_NAME); +} ############################################################################ Commit: 5ae9700a12099acc5a2f68660ea795e3d2d31f83 URL: http://cgit.haiku-os.org/haiku/commit/?id=5ae9700 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Wed Jul 4 16:13:55 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:18 2012 UTC enable cpuidle module and device driver Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/Jamfile b/src/add-ons/kernel/Jamfile index 5a5b275..03f5786 100644 --- a/src/add-ons/kernel/Jamfile +++ b/src/add-ons/kernel/Jamfile @@ -8,6 +8,7 @@ SubInclude HAIKU_TOP src add-ons kernel debugger ; SubInclude HAIKU_TOP src add-ons kernel drivers ; SubInclude HAIKU_TOP src add-ons kernel file_cache ; SubInclude HAIKU_TOP src add-ons kernel file_systems ; +SubInclude HAIKU_TOP src add-ons kernel idle ; SubInclude HAIKU_TOP src add-ons kernel interrupt_controllers ; SubInclude HAIKU_TOP src add-ons kernel network ; SubInclude HAIKU_TOP src add-ons kernel media ; diff --git a/src/add-ons/kernel/drivers/Jamfile b/src/add-ons/kernel/drivers/Jamfile index ef7c7ee..f23cf48 100644 --- a/src/add-ons/kernel/drivers/Jamfile +++ b/src/add-ons/kernel/drivers/Jamfile @@ -4,6 +4,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers bluetooth ; SubInclude HAIKU_TOP src add-ons kernel drivers bus ; SubInclude HAIKU_TOP src add-ons kernel drivers audio ; SubInclude HAIKU_TOP src add-ons kernel drivers common ; +SubInclude HAIKU_TOP src add-ons kernel drivers cpuidle ; SubInclude HAIKU_TOP src add-ons kernel drivers disk ; SubInclude HAIKU_TOP src add-ons kernel drivers dvb ; SubInclude HAIKU_TOP src add-ons kernel drivers input ; ############################################################################ Commit: 66b0c86ae4a3f29e998114ec4a1a4824922e0d9a URL: http://cgit.haiku-os.org/haiku/commit/?id=66b0c86 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Sat Jul 7 11:41:27 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:18 2012 UTC cpuidle: rename CpuidleStats to CpuidleStat Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/cpuidle.h b/headers/os/drivers/cpuidle.h index 67d8f30..7234429 100644 --- a/headers/os/drivers/cpuidle.h +++ b/headers/os/drivers/cpuidle.h @@ -17,15 +17,15 @@ extern "C" { #define B_CPUIDLE_MODULE_NAME "idle/generic/cpuidle/v1" -struct CpuidleStats { +struct CpuidleStat { uint64 usageCount; bigtime_t usageTime; }; struct CpuidleInfo { - int32 cstateSleep; - CpuidleStats stats[CPUIDLE_CSTATE_MAX]; + int32 cstateSleep; + CpuidleStat stats[CPUIDLE_CSTATE_MAX]; }; ############################################################################ Commit: 76877c9a514e51a6f37ca40c8b09f2fcc32321ff URL: http://cgit.haiku-os.org/haiku/commit/?id=76877c9 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Sat Jul 7 11:42:14 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:18 2012 UTC intel_cpuidle: apply strict cpu checking to see it's snb or not we need to check cpu vendor, family, and model Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp b/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp index a2bba81..6265c73 100644 --- a/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp +++ b/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp @@ -66,7 +66,7 @@ IntelCstateIdleEnter(int32 state, CpuidleCstate *cstate) } -static CpuidleCstate kSnbcStates[CPUIDLE_CSTATE_MAX] = { +static CpuidleCstate sSnbcStates[CPUIDLE_CSTATE_MAX] = { {}, { "C1-SNB", @@ -107,6 +107,15 @@ std_ops(int32 op, ...) switch (op) { case B_MODULE_INIT: { + cpu_ent *cpu = get_cpu_struct(); + if (cpu->arch.vendor != VENDOR_INTEL || cpu->arch.family != 6) + return B_ERROR; + + // Calculated Model Value: M = (Extended Model << 4) + Model + uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model; + if (model != 0x2a && model != 0x2d) + return B_ERROR; + cpuid_info cpuid; get_current_cpuid(&cpuid, 5); /* ecx[0] monitor/mwait extension supported @@ -125,7 +134,7 @@ std_ops(int32 op, ...) if (!subStates) continue; sIntelidleModule.cStates[sIntelidleModule.cStateCount] = - kSnbcStates[i]; + sSnbcStates[i]; sIntelidleModule.cStates[sIntelidleModule.cStateCount].pData = kMwaitEax[i]; sIntelidleModule.cStateCount++; ############################################################################ Commit: e467ba95b017924b06f2f52a73ab5380d553543a URL: http://cgit.haiku-os.org/haiku/commit/?id=e467ba9 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Sat Jul 7 13:52:56 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:19 2012 UTC cpuidle: add stats reporting support Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/cpuidle.h b/headers/os/drivers/cpuidle.h index 7234429..ed79be9 100644 --- a/headers/os/drivers/cpuidle.h +++ b/headers/os/drivers/cpuidle.h @@ -44,6 +44,15 @@ struct CpuidleModuleInfo { }; +struct GenCpuidle { + module_info info; + int32 (*GetIdleStateCount)(void); + char * (*GetIdleStateName)(int32 state); + void (*GetIdleStateInfo)(int32 cpu, int32 state, + CpuidleStat *stat); +}; + + #ifdef __cplusplus } #endif diff --git a/src/add-ons/kernel/drivers/cpuidle/Jamfile b/src/add-ons/kernel/drivers/cpuidle/Jamfile index 50b9290..ce5f450 100644 --- a/src/add-ons/kernel/drivers/cpuidle/Jamfile +++ b/src/add-ons/kernel/drivers/cpuidle/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers cpuidle ; +UsePrivateKernelHeaders ; + KernelAddon <driver>cpuidle : cpuidle.cpp ; diff --git a/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp b/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp index 9440358..82110c9 100644 --- a/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp +++ b/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp @@ -6,6 +6,10 @@ * Yongcong Du <ycdu.vmcore@xxxxxxxxx> */ +#include <stdio.h> +#include <string.h> +#include <smp.h> + #include <Drivers.h> #include <KernelExport.h> @@ -15,7 +19,7 @@ int32 api_version = B_CUR_DRIVER_API_VERSION; -CpuidleModuleInfo *sCpuidleModule; +static GenCpuidle *sGenCpuidle; static status_t cpuidle_open(const char *name, uint32 flags, void **cookie) @@ -49,7 +53,36 @@ cpuidle_ioctl(void *cookie, uint32 op, void *buffer, size_t length) static status_t cpuidle_read(void *cookie, off_t pos, void *buffer, size_t *length) { - *length = 0; + if (pos != 0) { + *length = 0; + return B_OK; + } + char *str = (char *)buffer; + size_t max_len = *length; + int32 stateCount = sGenCpuidle->GetIdleStateCount(); + int32 bytes = snprintf(str, max_len, "C-STATE COUNT: %"B_PRId32"\n", stateCount); + max_len-= bytes; + str += bytes; + int32 cpu = smp_get_num_cpus(); + + for (int32 i = 0; i < cpu; i++) { + bytes = snprintf(str, max_len, "CPU%"B_PRId32"\n", i); + max_len-= bytes; + str += bytes; + for (int32 j = 1; j < stateCount; j++) { + CpuidleStat stat; + bytes = snprintf(str, max_len, "%s\n", sGenCpuidle->GetIdleStateName(j)); + max_len-= bytes; + str += bytes; + sGenCpuidle->GetIdleStateInfo(i, j, &stat); + bytes = snprintf(str, max_len, "%lld %lldus\n", + stat.usageCount, stat.usageTime); + max_len-= bytes; + str += bytes; + } + } + *length = strlen((char *)buffer); + return B_OK; } @@ -102,7 +135,7 @@ init_driver(void) { status_t err; - err = get_module(B_CPUIDLE_MODULE_NAME, (module_info **)&sCpuidleModule); + err = get_module(B_CPUIDLE_MODULE_NAME, (module_info **)&sGenCpuidle); if (err != B_OK) { dprintf("can't load "B_CPUIDLE_MODULE_NAME"\n"); } diff --git a/src/add-ons/kernel/idle/generic/cpuidle.cpp b/src/add-ons/kernel/idle/generic/cpuidle.cpp index 4338a16..041b729 100644 --- a/src/add-ons/kernel/idle/generic/cpuidle.cpp +++ b/src/add-ons/kernel/idle/generic/cpuidle.cpp @@ -106,10 +106,37 @@ std_ops(int32 op, ...) } -static module_info sModule = { - B_CPUIDLE_MODULE_NAME, - 0, - std_ops +static char * +GetIdleStateName(int32 state) +{ + return sCpuidleModule->cStates[state].name; +} + + +static int32 +GetIdleStateCount(void) +{ + return sCpuidleModule->cStateCount; +} + + +static void +GetIdleStateInfo(int32 cpu, int32 state, CpuidleStat *stat) +{ + memcpy(stat, &sPerCPU[cpu].stats[state], sizeof(CpuidleStat)); +} + + +static GenCpuidle sModule = { + { + B_CPUIDLE_MODULE_NAME, + 0, + std_ops + }, + + GetIdleStateCount, + GetIdleStateName, + GetIdleStateInfo }; ############################################################################ Commit: 69f69b003afc34ed153ac3463e7844f77c29dce2 URL: http://cgit.haiku-os.org/haiku/commit/?id=69f69b0 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Thu Jul 5 02:42:55 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:19 2012 UTC cpuidle: we should exit when cStateCount is less than 3 If only C0, C1 are available, it doesn't make any sense to enable cpuidle Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/idle/generic/cpuidle.cpp b/src/add-ons/kernel/idle/generic/cpuidle.cpp index 041b729..0ce9851 100644 --- a/src/add-ons/kernel/idle/generic/cpuidle.cpp +++ b/src/add-ons/kernel/idle/generic/cpuidle.cpp @@ -86,7 +86,7 @@ std_ops(int32 op, ...) } close_module_list(cookie); - if (sCpuidleModule->cStateCount < 2) { + if (sCpuidleModule->cStateCount < 3) { dprintf("no enough available cstates, exiting...\n"); put_module(sCpuidleModule->info.name); return B_ERROR; ############################################################################ Commit: 57311e7bb7302866bdcbb28aea336152c7ae873d URL: http://cgit.haiku-os.org/haiku/commit/?id=57311e7 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Sat Aug 4 14:12:45 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:19 2012 UTC acpi: add ACPI_ALLOCATE_LOCAL_BUFFER to ACPI.h Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/ACPI.h b/headers/os/drivers/ACPI.h index 221c649..aeea707 100644 --- a/headers/os/drivers/ACPI.h +++ b/headers/os/drivers/ACPI.h @@ -133,6 +133,7 @@ typedef struct acpi_data { enum { ACPI_ALLOCATE_BUFFER = -1, + ACPI_ALLOCATE_LOCAL_BUFFER = -2, }; ############################################################################ Commit: 71d9d375b82be4c5c336831042bc7401b9ed0e07 URL: http://cgit.haiku-os.org/haiku/commit/?id=71d9d37 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Sat Aug 4 14:12:40 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:19 2012 UTC cpuidle: move generic cpuidle to generic After this change, low level cpuidle drivers load the generic cpuidle module if they can support the underlying platform. change the intel cpuidle driver accordingly, now it's loaded by acpi bus manager during boot, although it doesn't depend on acpi Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/cpuidle.h b/headers/os/drivers/cpuidle.h index ed79be9..7649cda 100644 --- a/headers/os/drivers/cpuidle.h +++ b/headers/os/drivers/cpuidle.h @@ -14,7 +14,7 @@ extern "C" { #define CPUIDLE_CSTATE_MAX 8 #define CSTATE_NAME_LENGTH 32 -#define B_CPUIDLE_MODULE_NAME "idle/generic/cpuidle/v1" +#define B_CPUIDLE_MODULE_NAME "generic/cpuidle/v1" struct CpuidleStat { @@ -28,28 +28,25 @@ struct CpuidleInfo { CpuidleStat stats[CPUIDLE_CSTATE_MAX]; }; +struct CpuidleDevice; struct CpuidleCstate { char name[CSTATE_NAME_LENGTH]; int32 latency; - int32 (*EnterIdle)(int32 state, CpuidleCstate *cstate); + int32 (*EnterIdle)(int32 state, CpuidleDevice *device); void *pData; }; -struct CpuidleModuleInfo { - module_info info; +struct CpuidleDevice { CpuidleCstate cStates[CPUIDLE_CSTATE_MAX]; int32 cStateCount; }; -struct GenCpuidle { +struct CpuidleModuleInfo { module_info info; - int32 (*GetIdleStateCount)(void); - char * (*GetIdleStateName)(int32 state); - void (*GetIdleStateInfo)(int32 cpu, int32 state, - CpuidleStat *stat); + status_t (*AddDevice)(CpuidleDevice *device); }; diff --git a/src/add-ons/kernel/Jamfile b/src/add-ons/kernel/Jamfile index 03f5786..5a5b275 100644 --- a/src/add-ons/kernel/Jamfile +++ b/src/add-ons/kernel/Jamfile @@ -8,7 +8,6 @@ SubInclude HAIKU_TOP src add-ons kernel debugger ; SubInclude HAIKU_TOP src add-ons kernel drivers ; SubInclude HAIKU_TOP src add-ons kernel file_cache ; SubInclude HAIKU_TOP src add-ons kernel file_systems ; -SubInclude HAIKU_TOP src add-ons kernel idle ; SubInclude HAIKU_TOP src add-ons kernel interrupt_controllers ; SubInclude HAIKU_TOP src add-ons kernel network ; SubInclude HAIKU_TOP src add-ons kernel media ; diff --git a/src/add-ons/kernel/drivers/power/Jamfile b/src/add-ons/kernel/drivers/power/Jamfile index 56d9143..45feced 100644 --- a/src/add-ons/kernel/drivers/power/Jamfile +++ b/src/add-ons/kernel/drivers/power/Jamfile @@ -5,3 +5,4 @@ SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_button ; SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_lid ; SubInclude HAIKU_TOP src add-ons kernel drivers power acpi_thermal ; SubInclude HAIKU_TOP src add-ons kernel drivers power enhanced_speedstep ; +SubInclude HAIKU_TOP src add-ons kernel drivers power x86_cpuidle ; diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/Jamfile b/src/add-ons/kernel/drivers/power/x86_cpuidle/Jamfile new file mode 100644 index 0000000..5161250 --- /dev/null +++ b/src/add-ons/kernel/drivers/power/x86_cpuidle/Jamfile @@ -0,0 +1,10 @@ +SubDir HAIKU_TOP src add-ons kernel drivers power x86_cpuidle ; + +UsePrivateKernelHeaders ; + +KernelAddon x86_cpuidle : + acpi_cpuidle.cpp + intel_cpuidle.cpp + ; + +Depends x86_cpuidle : acpi ; diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp b/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp new file mode 100644 index 0000000..8064d50 --- /dev/null +++ b/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp @@ -0,0 +1,181 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * + * Distributed under the terms of the MIT License. + * + * Authors: + * Yongcong Du <ycdu.vmcore@xxxxxxxxx> + */ + +#include <KernelExport.h> +#include <Drivers.h> +#include <Errors.h> +#include <smp.h> +#include <cpu.h> +#include <arch_system_info.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <ACPI.h> + +#include "x86_cpuidle.h" + +#define ACPI_CPUIDLE_MODULE_NAME "drivers/power/x86_cpuidle/acpi/driver_v1" + +struct acpi_cpuidle_driver_info { + device_node *node; + acpi_device_module_info *acpi; + acpi_device acpi_cookie; +}; + +static device_manager_info *sDeviceManager; +static acpi_cpuidle_driver_info *acpi_processor[B_MAX_CPU_COUNT]; + + +static status_t +acpi_cpuidle_init(void) +{ + dprintf("acpi_cpuidle_init\n"); + + return B_ERROR; +} + + +static status_t +acpi_processor_init(acpi_cpuidle_driver_info *device) +{ + status_t status = B_ERROR; + + acpi_data buffer; + buffer.pointer = NULL; + buffer.length = ACPI_ALLOCATE_BUFFER; + dprintf("get acpi processor @%p\n", device->acpi_cookie); + status = device->acpi->evaluate_method(device->acpi_cookie, NULL, NULL, + &buffer); + if (status != B_OK) { + dprintf("failed to get processor obj\n"); + return B_IO_ERROR; + } + acpi_object_type *object = (acpi_object_type *)buffer.pointer; + dprintf("acpi cpu%"B_PRId32": P_BLK at %#x/%lu\n", + object->data.processor.cpu_id, + object->data.processor.pblk_address, + object->data.processor.pblk_length); + int32 cpuid = object->data.processor.cpu_id; + free(buffer.pointer); + if (cpuid > smp_get_num_cpus()) + return B_ERROR; + + if (smp_get_num_cpus() == 1) + cpuid = 1; + + acpi_processor[cpuid-1] = device; + + if (cpuid == 1) { + if (intel_cpuidle_init() != B_OK) + return acpi_cpuidle_init(); + } + + return B_OK; +} + + +static float +acpi_cpuidle_support(device_node *parent) +{ + const char *bus; + uint32 device_type; + + dprintf("acpi_cpuidle_support\n"); + // make sure parent is really the ACPI bus manager + if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) + return -1; + + if (strcmp(bus, "acpi")) + return 0.0; + + // check whether it's really a cpu Device + if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &device_type, false) != B_OK + || device_type != ACPI_TYPE_PROCESSOR) { + return 0.0; + } + + return 0.6; +} + + +static status_t +acpi_cpuidle_register_device(device_node *node) +{ + device_attr attrs[] = { + { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "ACPI CPU IDLE" }}, + { NULL } + }; + + dprintf("acpi_cpuidle_register_device\n"); + return sDeviceManager->register_node(node, ACPI_CPUIDLE_MODULE_NAME, attrs, + NULL, NULL); +} + + +static status_t +acpi_cpuidle_init_driver(device_node *node, void **driverCookie) +{ + dprintf("acpi_cpuidle_init_driver\n"); + acpi_cpuidle_driver_info *device; + device = (acpi_cpuidle_driver_info *)calloc(1, sizeof(*device)); + if (device == NULL) + return B_NO_MEMORY; + + *driverCookie = device; + + device->node = node; + + device_node *parent; + parent = sDeviceManager->get_parent_node(node); + sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi, + (void **)&device->acpi_cookie); + sDeviceManager->put_node(parent); + + return acpi_processor_init(device); +} + + +static void +acpi_cpuidle_uninit_driver(void *driverCookie) +{ + dprintf("acpi_cpuidle_uninit_driver"); + acpi_cpuidle_driver_info *device = (acpi_cpuidle_driver_info *)driverCookie; + free(device); +} + + +module_dependency module_dependencies[] = { + { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, + {} +}; + + +static driver_module_info sAcpiidleModule = { + { + ACPI_CPUIDLE_MODULE_NAME, + 0, + NULL + }, + + acpi_cpuidle_support, + acpi_cpuidle_register_device, + acpi_cpuidle_init_driver, + acpi_cpuidle_uninit_driver, + NULL, + NULL, // rescan + NULL, // removed +}; + + +module_info *modules[] = { + (module_info *)&sAcpiidleModule, + NULL +}; diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp b/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp new file mode 100644 index 0000000..1032a5d --- /dev/null +++ b/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yongcong Du <ycdu.vmcore@xxxxxxxxx> + */ + +#include <KernelExport.h> +#include <cpu.h> +#include <arch_system_info.h> + +#include <stdio.h> + +#include <cpuidle.h> + +#include "x86_cpuidle.h" + +static CpuidleModuleInfo *sIdle; +static CpuidleDevice sIntelDevice; + +static void *kMwaitEax[] = { + // C0, we never use it + (void *)0x00, + // MWAIT C1 + (void *)0x00, + // MWAIT C2 + (void *)0x10, + // MWAIT C3 + (void *)0x20, + // MWAIT C4 + (void *)0x30, + // MWAIT C5 + (void *)0x40, + // MWAIT C6, 0x2 is used to fully shrink L2 cache + (void *)0x52 +}; + + +static int32 +IntelCstateIdleEnter(int32 state, CpuidleDevice *device) +{ + cpu_ent *cpu = get_cpu_struct(); + if (cpu->invoke_scheduler) + return 0; + + CpuidleCstate *cState = &device->cStates[state]; + x86_monitor((void *)&cpu->invoke_scheduler, 0, 0); + if (!cpu->invoke_scheduler) + x86_mwait((unsigned long)cState->pData, 1); + + return state; +} + + +static CpuidleCstate sSnbcStates[CPUIDLE_CSTATE_MAX] = { + {}, + { + "C1-SNB", + 1, + IntelCstateIdleEnter, + }, + { + "C3-SNB", + 80, + IntelCstateIdleEnter, + }, + { + "C6-SNB", + 104, + IntelCstateIdleEnter, + }, + { + "C7-SNB", + 109, + IntelCstateIdleEnter, + }, +}; + + +status_t +intel_cpuidle_init(void) +{ + dprintf("intel idle init\n"); + if (get_module(B_CPUIDLE_MODULE_NAME, (module_info**)&sIdle) != B_OK) + return B_ERROR; + cpu_ent *cpu = get_cpu_struct(); + if (cpu->arch.vendor != VENDOR_INTEL || cpu->arch.family != 6) + return B_ERROR; + + // Calculated Model Value: M = (Extended Model << 4) + Model + uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model; + if (model != 0x2a && model != 0x2d) + return B_ERROR; + + cpuid_info cpuid; + get_current_cpuid(&cpuid, 5); + /* ecx[0] monitor/mwait extension supported + * ecx[1] support for treating interrupts as break-events for mwait + * edx number of sub-states + */ + if (!((cpuid.regs.ecx & 0x1) && (cpuid.regs.ecx & 0x2) && + cpuid.regs.edx)) { + return B_ERROR; + } + + sIntelDevice.cStateCount = 1; + for (int32 i = 1; i < CPUIDLE_CSTATE_MAX; i++) { + int32 subStates = (cpuid.regs.edx >> ((i) * 4)) & 0xf; + // no sub-states means the state is not available + if (!subStates) + continue; + sIntelDevice.cStates[sIntelDevice.cStateCount] = + sSnbcStates[i]; + sIntelDevice.cStates[sIntelDevice.cStateCount].pData = + kMwaitEax[i]; + sIntelDevice.cStateCount++; + } + status_t status = sIdle->AddDevice(&sIntelDevice); + if (status == B_OK) + dprintf("using intel idle\n"); + else + put_module(B_CPUIDLE_MODULE_NAME); + return status; +} diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/x86_cpuidle.h b/src/add-ons/kernel/drivers/power/x86_cpuidle/x86_cpuidle.h new file mode 100644 index 0000000..b524ef1 --- /dev/null +++ b/src/add-ons/kernel/drivers/power/x86_cpuidle/x86_cpuidle.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ + +#ifdef __cplusplus +extern "C" { +#endif +static inline void +x86_monitor(const void *addr, unsigned long ecx, unsigned long edx) +{ + asm volatile("monitor" + :: "a" (addr), "c" (ecx), "d"(edx)); +} + +static inline void +x86_mwait(unsigned long eax, unsigned long ecx) +{ + asm volatile("mwait" + :: "a" (eax), "c" (ecx)); +} + +status_t intel_cpuidle_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/add-ons/kernel/generic/Jamfile b/src/add-ons/kernel/generic/Jamfile index a2a6bfc..719061b 100644 --- a/src/add-ons/kernel/generic/Jamfile +++ b/src/add-ons/kernel/generic/Jamfile @@ -2,6 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel generic ; SubInclude HAIKU_TOP src add-ons kernel generic ata_adapter ; SubInclude HAIKU_TOP src add-ons kernel generic atomizer ; +SubInclude HAIKU_TOP src add-ons kernel generic cpuidle ; SubInclude HAIKU_TOP src add-ons kernel generic dpc ; SubInclude HAIKU_TOP src add-ons kernel generic ide_adapter ; SubInclude HAIKU_TOP src add-ons kernel generic locked_pool ; diff --git a/src/add-ons/kernel/generic/cpuidle/Jamfile b/src/add-ons/kernel/generic/cpuidle/Jamfile new file mode 100644 index 0000000..bb7cdd2 --- /dev/null +++ b/src/add-ons/kernel/generic/cpuidle/Jamfile @@ -0,0 +1,7 @@ +SubDir HAIKU_TOP src add-ons kernel generic cpuidle ; + +UsePrivateKernelHeaders ; + +KernelAddon cpuidle : + cpuidle.cpp + ; diff --git a/src/add-ons/kernel/generic/cpuidle/cpuidle.cpp b/src/add-ons/kernel/generic/cpuidle/cpuidle.cpp new file mode 100644 index 0000000..cc17be8 --- /dev/null +++ b/src/add-ons/kernel/generic/cpuidle/cpuidle.cpp @@ -0,0 +1,105 @@ +/* + * Copyright 2012, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Yongcong Du <ycdu.vmcore@xxxxxxxxx> + */ + +#include <KernelExport.h> +#include <stdio.h> +#include <string.h> + +#include <smp.h> +#include <cpuidle.h> + + +static CpuidleInfo sPerCPU[B_MAX_CPU_COUNT]; +static CpuidleDevice *sDevice; +extern void (*gCpuIdleFunc)(void); + + +/* + * next cstate selection algorithm is based on NetBSD's + * it's simple, stupid + */ +static int32 +SelectCstate(CpuidleInfo *info) +{ + static const int32 csFactor = 3; + + for (int32 i = sDevice->cStateCount - 1; i > 0; i--) { + CpuidleCstate *cState = &sDevice->cStates[i]; + if (info->cstateSleep > cState->latency * csFactor) + return i; + } + + /* Choose C1 if there's no state found */ + return 1; +} + + +static inline void +EnterCstate(int32 state, CpuidleInfo *info) +{ + CpuidleCstate *cstate = &sDevice->cStates[state]; + bigtime_t now = system_time(); + int32 finalState = cstate->EnterIdle(state, sDevice); + if (finalState > 0) { + bigtime_t diff = system_time() - now; + info->cstateSleep = diff; + info->stats[finalState].usageCount++; + info->stats[finalState].usageTime += diff; + } else { + info->cstateSleep = 0; + } +} + + +static void +CpuCstateIdle(void) +{ + CpuidleInfo *info = &sPerCPU[smp_get_current_cpu()]; + int32 state = SelectCstate(info); + EnterCstate(state, info); +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return B_OK; + case B_MODULE_UNINIT: + return B_OK; + } + + return B_ERROR; +} + + +status_t AddDevice(CpuidleDevice *device) +{ + sDevice = device; + memory_write_barrier(); + gCpuIdleFunc = CpuCstateIdle; + return B_OK; +} + + +static CpuidleModuleInfo sCpuidleModule = { + { + B_CPUIDLE_MODULE_NAME, + 0, + std_ops + }, + + AddDevice, +}; + + +module_info *modules[] = { + (module_info *)&sCpuidleModule, + NULL +}; diff --git a/src/add-ons/kernel/idle/Jamfile b/src/add-ons/kernel/idle/Jamfile deleted file mode 100644 index 878fd5c..0000000 --- a/src/add-ons/kernel/idle/Jamfile +++ /dev/null @@ -1,4 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel idle ; - -SubInclude HAIKU_TOP src add-ons kernel idle cpuidles ; -SubInclude HAIKU_TOP src add-ons kernel idle generic ; diff --git a/src/add-ons/kernel/idle/cpuidles/Jamfile b/src/add-ons/kernel/idle/cpuidles/Jamfile deleted file mode 100644 index 03a6a3c..0000000 --- a/src/add-ons/kernel/idle/cpuidles/Jamfile +++ /dev/null @@ -1,3 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel idle cpuidles ; - -SubInclude HAIKU_TOP src add-ons kernel idle cpuidles intel_cpuidle ; diff --git a/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/Jamfile b/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/Jamfile deleted file mode 100644 index 4b74f09..0000000 --- a/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel idle cpuidles intel_cpuidle ; - -UsePrivateKernelHeaders ; - -KernelAddon intel_cpuidle : - intel_cpuidle.cpp - ; diff --git a/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp b/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp deleted file mode 100644 index 6265c73..0000000 --- a/src/add-ons/kernel/idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2012, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Yongcong Du <ycdu.vmcore@xxxxxxxxx> - */ - -#include <KernelExport.h> -#include <stdio.h> - -#include <cpu.h> -#include <arch_system_info.h> -#include <cpuidle.h> - - -static status_t std_ops(int32 op, ...); - - -static inline void -x86_monitor(const void *addr, unsigned long ecx, unsigned long edx) -{ - asm volatile("monitor" - :: "a" (addr), "c" (ecx), "d"(edx)); -} - - -static inline void -x86_mwait(unsigned long eax, unsigned long ecx) -{ - asm volatile("mwait" - :: "a" (eax), "c" (ecx)); -} - - -static void *kMwaitEax[] = { - // C0, we never use it - (void *)0x00, - // MWAIT C1 - (void *)0x00, - // MWAIT C2 - (void *)0x10, - // MWAIT C3 - (void *)0x20, - // MWAIT C4 - (void *)0x30, - // MWAIT C5 - (void *)0x40, - // MWAIT C6, 0x2 is used to fully shrink L2 cache - (void *)0x52 -}; - - -static int32 -IntelCstateIdleEnter(int32 state, CpuidleCstate *cstate) -{ - cpu_ent *cpu = get_cpu_struct(); - if (cpu->invoke_scheduler) - return 0; - - x86_monitor((void *)&cpu->invoke_scheduler, 0, 0); - if (!cpu->invoke_scheduler) - x86_mwait((unsigned long)cstate->pData, 1); - - return state; -} - - -static CpuidleCstate sSnbcStates[CPUIDLE_CSTATE_MAX] = { - {}, - { - "C1-SNB", - 1, - IntelCstateIdleEnter, - }, - { - "C3-SNB", - 80, - IntelCstateIdleEnter, - }, - { - "C6-SNB", - 104, - IntelCstateIdleEnter, - }, - { - "C7-SNB", - 109, - IntelCstateIdleEnter, - }, -}; - - -static CpuidleModuleInfo sIntelidleModule = { - { - "idle/cpuidles/intel_cpuidle/v1", - 0, - std_ops - }, - -}; - - -static status_t -std_ops(int32 op, ...) -{ - switch (op) { - case B_MODULE_INIT: - { - cpu_ent *cpu = get_cpu_struct(); - if (cpu->arch.vendor != VENDOR_INTEL || cpu->arch.family != 6) - return B_ERROR; - - // Calculated Model Value: M = (Extended Model << 4) + Model - uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model; - if (model != 0x2a && model != 0x2d) - return B_ERROR; - - cpuid_info cpuid; - get_current_cpuid(&cpuid, 5); - /* ecx[0] monitor/mwait extension supported - * ecx[1] support for treating interrupts as break-events for mwait - * edx number of sub-states - */ - if (!((cpuid.regs.ecx & 0x1) && (cpuid.regs.ecx & 0x2) && - cpuid.regs.edx)) { - return B_ERROR; - } - - sIntelidleModule.cStateCount = 1; - for (int32 i = 1; i < CPUIDLE_CSTATE_MAX; i++) { - int32 subStates = (cpuid.regs.edx >> ((i) * 4)) & 0xf; - // no sub-states means the state is not available - if (!subStates) - continue; - sIntelidleModule.cStates[sIntelidleModule.cStateCount] = - sSnbcStates[i]; - sIntelidleModule.cStates[sIntelidleModule.cStateCount].pData = - kMwaitEax[i]; - sIntelidleModule.cStateCount++; - } - dprintf("intel idle init\n"); - return B_OK; - } - case B_MODULE_UNINIT: - dprintf("intel idle uninit\n"); - return B_OK; - } - - return B_ERROR; -} - - -module_info *modules[] = { - (module_info *)&sIntelidleModule, - NULL -}; diff --git a/src/add-ons/kernel/idle/generic/Jamfile b/src/add-ons/kernel/idle/generic/Jamfile deleted file mode 100644 index f7ff039..0000000 --- a/src/add-ons/kernel/idle/generic/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel idle generic ; - -UsePrivateKernelHeaders ; - -KernelAddon <module>cpuidle : - cpuidle.cpp - ; diff --git a/src/add-ons/kernel/idle/generic/cpuidle.cpp b/src/add-ons/kernel/idle/generic/cpuidle.cpp deleted file mode 100644 index 0ce9851..0000000 --- a/src/add-ons/kernel/idle/generic/cpuidle.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2012, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Yongcong Du <ycdu.vmcore@xxxxxxxxx> - */ - -#include <KernelExport.h> -#include <stdio.h> -#include <string.h> - -#include <smp.h> -#include <cpuidle.h> - - -static CpuidleInfo sPerCPU[B_MAX_CPU_COUNT]; -static CpuidleModuleInfo *sCpuidleModule; - -extern void (*gCpuIdleFunc)(void); - - -/* - * next cstate selection algorithm is based on NetBSD's - * it's simple, stupid - */ -static int32 -SelectCstate(CpuidleInfo *info) -{ - static const int32 csFactor = 3; - - for (int32 i = sCpuidleModule->cStateCount - 1; i > 0; i--) { - CpuidleCstate *cState = &sCpuidleModule->cStates[i]; - if (info->cstateSleep > cState->latency * csFactor) - return i; - } - - /* Choose C1 if there's no state found */ - return 1; -} - - -static inline void -EnterCstate(int32 state, CpuidleInfo *info) -{ - CpuidleCstate *cstate = &sCpuidleModule->cStates[state]; - bigtime_t now = system_time(); - if (cstate->EnterIdle(state, cstate) > 0) { - bigtime_t diff = system_time() - now; - info->cstateSleep = diff; - info->stats[state].usageCount++; - info->stats[state].usageTime += diff; - } else { - info->cstateSleep = 0; - } -} - - -static void -CpuCstateIdle(void) -{ - CpuidleInfo *info = &sPerCPU[smp_get_current_cpu()]; - int32 state = SelectCstate(info); - EnterCstate(state, info); -} - - -static status_t -std_ops(int32 op, ...) -{ - switch (op) { - case B_MODULE_INIT: - { - dprintf("generic cpuidle init\n"); - void *cookie = open_module_list("idle/cpuidles"); - if (cookie == NULL) - return B_ERROR; - - char name[B_FILE_NAME_LENGTH]; - size_t nameLength = sizeof(name); - - while (read_next_module_name(cookie, name, &nameLength) == B_OK) { - if (get_module(name, (module_info **)&sCpuidleModule) == B_OK) { - break; - } - } - - close_module_list(cookie); - if (sCpuidleModule->cStateCount < 3) { - dprintf("no enough available cstates, exiting...\n"); - put_module(sCpuidleModule->info.name); - return B_ERROR; - } else { - dprintf("using %s\n", sCpuidleModule->info.name); - gCpuIdleFunc = CpuCstateIdle; - return B_OK; - } - } - case B_MODULE_UNINIT: - dprintf("generic cpuidle uninit\n"); - put_module(sCpuidleModule->info.name); - return B_OK; - } - - return B_ERROR; -} - - -static char * -GetIdleStateName(int32 state) -{ - return sCpuidleModule->cStates[state].name; -} - - -static int32 -GetIdleStateCount(void) -{ - return sCpuidleModule->cStateCount; -} - - -static void -GetIdleStateInfo(int32 cpu, int32 state, CpuidleStat *stat) -{ - memcpy(stat, &sPerCPU[cpu].stats[state], sizeof(CpuidleStat)); -} - - -static GenCpuidle sModule = { - { - B_CPUIDLE_MODULE_NAME, - 0, - std_ops - }, - - GetIdleStateCount, - GetIdleStateName, - GetIdleStateInfo -}; - - -module_info *modules[] = { - (module_info *)&sModule, - NULL -}; ############################################################################ Commit: 0a0af8957e4ad48168cb26dba4a058f7eb0e4892 URL: http://cgit.haiku-os.org/haiku/commit/?id=0a0af89 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Fri Aug 17 11:23:53 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:20 2012 UTC acpi: export read_bit_register and write_bit_register acpi cpuidle needs such acpi functions Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/headers/os/drivers/ACPI.h b/headers/os/drivers/ACPI.h index aeea707..66ce0d0 100644 --- a/headers/os/drivers/ACPI.h +++ b/headers/os/drivers/ACPI.h @@ -262,6 +262,10 @@ struct acpi_module_info { /* Table Access */ status_t (*get_table)(const char *signature, uint32 instance, void **tableHeader); + + /* Register Access */ + status_t (*read_bit_register)(uint32 regid, uint32 *val); + status_t (*write_bit_register)(uint32 regid, uint32 val); }; diff --git a/src/add-ons/kernel/bus_managers/acpi/BusManager.cpp b/src/add-ons/kernel/bus_managers/acpi/BusManager.cpp index 692898b..ea63dba 100644 --- a/src/add-ons/kernel/bus_managers/acpi/BusManager.cpp +++ b/src/add-ons/kernel/bus_managers/acpi/BusManager.cpp @@ -715,6 +715,20 @@ get_table(const char* signature, uint32 instance, void** tableHeader) } +status_t +read_bit_register(uint32 regid, uint32 *val) +{ + return AcpiReadBitRegister(regid, (UINT32 *)val); +} + + +status_t +write_bit_register(uint32 regid, uint32 val) +{ + return AcpiWriteBitRegister(regid, val); +} + + struct acpi_module_info gACPIModule = { { B_ACPI_MODULE_NAME, @@ -759,5 +773,7 @@ struct acpi_module_info gACPIModule = { prepare_sleep_state, enter_sleep_state, reboot, - get_table + get_table, + read_bit_register, + write_bit_register }; ############################################################################ Commit: 0138a95ebac947f56c39ff2a148d3380ad5db1cc URL: http://cgit.haiku-os.org/haiku/commit/?id=0138a95 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Sun Aug 19 11:30:23 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:20 2012 UTC cpuidle: implement acpi cpuidle driver we prefer intel native cpuidle driver on newer intel platforms -- sandybridge or later. we'll fall back to acpi cpuidle driver for other platforms. Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp b/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp index 8064d50..fb4095c 100644 --- a/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp +++ b/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp @@ -19,27 +19,433 @@ #include <string.h> #include <ACPI.h> +#include <cpuidle.h> #include "x86_cpuidle.h" +#define ACPI_PDC_REVID 0x1 +#define ACPI_OSC_QUERY (1 << 0) + +#define ACPI_PDC_P_FFH (1 << 0) +#define ACPI_PDC_C_C1_HALT (1 << 1) +#define ACPI_PDC_T_FFH (1 << 2) +#define ACPI_PDC_SMP_C1PT (1 << 3) +#define ACPI_PDC_SMP_C2C3 (1 << 4) +#define ACPI_PDC_SMP_P_SW (1 << 5) +#define ACPI_PDC_SMP_C_SW (1 << 6) +#define ACPI_PDC_SMP_T_SW (1 << 7) +#define ACPI_PDC_C_C1_FFH (1 << 8) +#define ACPI_PDC_C_C2C3_FFH (1 << 9) +#define ACPI_PDC_P_HWCOORD (1 << 11) + +// Bus Master check required +#define ACPI_PDC_GAS_BM (1 << 1) + +#define ACPI_CSTATE_HALT 0x1 +#define ACPI_CSTATE_SYSIO 0x2 +#define ACPI_CSTATE_FFH 0x3 + +// Bus Master Check +#define ACPI_FLAG_C_BM (1 << 0) +// Bus master arbitration +#define ACPI_FLAG_C_ARB (1 << 1) + +// Copied from acpica's actypes.h, where's the best place to put? +#define ACPI_BITREG_BUS_MASTER_STATUS 0x01 +#define ACPI_BITREG_BUS_MASTER_RLD 0x0F +#define ACPI_BITREG_ARB_DISABLE 0x13 + +#define ACPI_STATE_C0 (uint8) 0 +#define ACPI_STATE_C1 (uint8) 1 +#define ACPI_STATE_C2 (uint8) 2 +#define ACPI_STATE_C3 (uint8) 3 +#define ACPI_C_STATES_MAX ACPI_STATE_C3 +#define ACPI_C_STATE_COUNT 4 + + #define ACPI_CPUIDLE_MODULE_NAME "drivers/power/x86_cpuidle/acpi/driver_v1" +struct acpicpu_reg { + uint8 reg_desc; + uint16 reg_reslen; + uint8 reg_spaceid; + uint8 reg_bitwidth; + uint8 reg_bitoffset; + uint8 reg_accesssize; + uint64 reg_addr; +} __attribute__((packed)); + struct acpi_cpuidle_driver_info { device_node *node; acpi_device_module_info *acpi; acpi_device acpi_cookie; + uint32 flags; +}; + +struct acpi_cstate_info { + uint32 address; + uint8 skip_bm_sts; + uint8 method; + uint8 type; }; static device_manager_info *sDeviceManager; static acpi_cpuidle_driver_info *acpi_processor[B_MAX_CPU_COUNT]; +static CpuidleModuleInfo *sIdle; +static CpuidleDevice sAcpiDevice; +static acpi_module_info *sAcpi; + + +static status_t +acpi_eval_pdc(acpi_cpuidle_driver_info *device) +{ + acpi_objects arg; + acpi_object_type obj; + uint32 cap[3]; + + arg.count = 1; + arg.pointer = &obj; + cap[0] = 1; + cap[1] = 1; + cap[2] = ACPI_PDC_C_C1_HALT | ACPI_PDC_SMP_C1PT | ACPI_PDC_SMP_C2C3; + cap[2] |= ACPI_PDC_SMP_P_SW | ACPI_PDC_SMP_C_SW | ACPI_PDC_SMP_T_SW; + cap[2] |= ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH; + cap[2] |= ACPI_PDC_SMP_T_SW | ACPI_PDC_P_FFH | ACPI_PDC_P_HWCOORD | ACPI_PDC_T_FFH; + obj.object_type = ACPI_TYPE_BUFFER; + obj.data.buffer.length = sizeof(cap); + obj.data.buffer.buffer = cap; + status_t status = device->acpi->evaluate_method(device->acpi_cookie, "_PDC", &arg, NULL); + return status; +} + + +static status_t +acpi_eval_osc(acpi_cpuidle_driver_info *device) +{ + // guid for intel platform + dprintf("%s@%p\n", __func__, device->acpi_cookie); + static uint8 uuid[] = { + 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47, + 0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53 + }; + uint32 cap[2]; + cap[0] = 0; + cap[1] = ACPI_PDC_C_C1_HALT | ACPI_PDC_SMP_C1PT | ACPI_PDC_SMP_C2C3; + cap[1] |= ACPI_PDC_SMP_P_SW | ACPI_PDC_SMP_C_SW | ACPI_PDC_SMP_T_SW; + cap[1] |= ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH; + cap[1] |= ACPI_PDC_SMP_T_SW | ACPI_PDC_P_FFH | ACPI_PDC_P_HWCOORD | ACPI_PDC_T_FFH; + + acpi_objects arg; + acpi_object_type obj[4]; + + arg.count = 4; + arg.pointer = obj; + + obj[0].object_type = ACPI_TYPE_BUFFER; + obj[0].data.buffer.length = sizeof(uuid); + obj[0].data.buffer.buffer = uuid; + obj[1].object_type = ACPI_TYPE_INTEGER; + obj[1].data.integer = ACPI_PDC_REVID; + obj[2].object_type = ACPI_TYPE_INTEGER; + obj[2].data.integer = sizeof(cap)/sizeof(cap[0]); + obj[3].object_type = ACPI_TYPE_BUFFER; + obj[3].data.buffer.length = sizeof(cap); + obj[3].data.buffer.buffer = (void *)cap; + + acpi_data buf; + buf.pointer = NULL; + buf.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status_t status = device->acpi->evaluate_method(device->acpi_cookie, "_OSC", &arg, &buf); + if (status != B_OK) + return status; + acpi_object_type *osc = (acpi_object_type *)buf.pointer; + if (osc->object_type != ACPI_TYPE_BUFFER) + return B_BAD_TYPE; + if (osc->data.buffer.length != sizeof(cap)) + return B_BUFFER_OVERFLOW; + return status; +} + + +static inline bool +acpi_cstate_bm_check(void) +{ + uint32 val; + sAcpi->read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &val); + if (!val) + return false; + sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1); + + return true; +} + + +static inline void +acpi_cstate_ffh_enter(CpuidleCstate *cState) +{ + cpu_ent *cpu = get_cpu_struct(); + if (cpu->invoke_scheduler) + return; + + x86_monitor((void *)&cpu->invoke_scheduler, 0, 0); + if (!cpu->invoke_scheduler) + x86_mwait((unsigned long)cState->pData, 1); +} + + +static inline void +acpi_cstate_halt(void) +{ + cpu_ent *cpu = get_cpu_struct(); + if (cpu->invoke_scheduler) + return; + asm("hlt"); +} + + +static void +acpi_cstate_enter(CpuidleCstate *cState) +{ + acpi_cstate_info *ci = (acpi_cstate_info *)cState->pData; + if (ci->method == ACPI_CSTATE_FFH) + acpi_cstate_ffh_enter(cState); + else if (ci->method == ACPI_CSTATE_SYSIO) + in8(ci->address); + else + acpi_cstate_halt(); +} + + +static int32 +acpi_cstate_idle(int32 state, CpuidleDevice *device) +{ + CpuidleCstate *cState = &device->cStates[state]; + acpi_cstate_info *ci = (acpi_cstate_info *)cState->pData; + if (!ci->skip_bm_sts) { + // we fall back to C1 if there's bus master activity + if (acpi_cstate_bm_check()) + state = 1; + } + if (ci->type != ACPI_STATE_C3) + acpi_cstate_enter(cState); + + // set BM_RLD for Bus Master to activity to wake the system from C3 + // With Newer chipsets BM_RLD is a NOP Since DMA is automatically handled + // during C3 State + acpi_cpuidle_driver_info *pi = acpi_processor[smp_get_current_cpu()]; + if (pi->flags & ACPI_FLAG_C_BM) + sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 1); + + // disable bus master arbitration during C3 + if (pi->flags & ACPI_FLAG_C_ARB) + sAcpi->write_bit_register(ACPI_BITREG_ARB_DISABLE, 1); + + acpi_cstate_enter(cState); + + // clear BM_RLD and re-enable the arbiter + if (pi->flags & ACPI_FLAG_C_BM) + sAcpi->write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0); + + if (pi->flags & ACPI_FLAG_C_ARB) + sAcpi->write_bit_register(ACPI_BITREG_ARB_DISABLE, 0); + + return state; +} + + +static status_t +acpi_cstate_add(acpi_object_type *object, CpuidleCstate *cState) +{ + acpi_cstate_info *ci = (acpi_cstate_info *)malloc(sizeof(acpi_cstate_info)); + if (!ci) + return B_NO_MEMORY; + + if (object->object_type != ACPI_TYPE_PACKAGE) { + dprintf("invalid _CST object\n"); + return B_ERROR; + } + + if (object->data.package.count != 4) { + dprintf("invalid _CST number\n"); + return B_ERROR; + } + + // type + acpi_object_type * pointer = &object->data.package.objects[1]; + if (pointer->object_type != ACPI_TYPE_INTEGER) { + dprintf("invalid _CST elem type\n"); + return B_ERROR; + } + uint32 n = pointer->data.integer; + if (n < 1 || n > 3) { + dprintf("invalid _CST elem value\n"); + return B_ERROR; + } + ci->type = n; + dprintf("C%" B_PRId32 "\n", n); + snprintf(cState->name, sizeof(cState->name), "C%"B_PRId32, n); + + // Latency + pointer = &object->data.package.objects[2]; + if (pointer->object_type != ACPI_TYPE_INTEGER) { + dprintf("invalid _CST elem type\n"); + return B_ERROR; + } + n = pointer->data.integer; + cState->latency = n; + dprintf("Latency: %" B_PRId32 "\n", n); + + // power + pointer = &object->data.package.objects[3]; + if (pointer->object_type != ACPI_TYPE_INTEGER) { + dprintf("invalid _CST elem type\n"); + return B_ERROR; + } + n = pointer->data.integer; + dprintf("power: %" B_PRId32 "\n", n); + + // register + pointer = &object->data.package.objects[0]; + if (pointer->object_type != ACPI_TYPE_BUFFER) { + dprintf("invalid _CST elem type\n"); + return B_ERROR; + } + if (pointer->data.buffer.length < 15) { + dprintf("invalid _CST elem length\n"); + return B_ERROR; + } + + struct acpicpu_reg *reg = (struct acpicpu_reg *)pointer->data.buffer.buffer; + switch (reg->reg_spaceid) { + case ACPI_ADR_SPACE_SYSTEM_IO: + dprintf("IO method\n"); + if (reg->reg_addr == 0) { + dprintf("illegal address\n"); + return B_ERROR; + } + if (reg->reg_bitwidth != 8) { + dprintf("invalid source length\n"); + return B_ERROR; + } + ci->address = reg->reg_addr; + ci->method = ACPI_CSTATE_SYSIO; + break; + case ACPI_ADR_SPACE_FIXED_HARDWARE: + { + dprintf("FFH method\n"); + ci->method = ACPI_CSTATE_FFH; + ci->address = reg->reg_addr; + + // skip checking BM_STS if ACPI_PDC_GAS_BM is cleared + cpu_ent *cpu = get_cpu_struct(); + if ((cpu->arch.vendor == VENDOR_INTEL) && + !(reg->reg_accesssize & ACPI_PDC_GAS_BM)) + ci->skip_bm_sts = 1; + break; + } + default: + dprintf("invalid spaceid %" B_PRId8 "\n", reg->reg_spaceid); + break; + } + cState->pData = ci; + cState->EnterIdle = acpi_cstate_idle; + + return B_OK; +} + + +static void +acpi_cstate_quirks(acpi_cpuidle_driver_info *device) +{ + cpu_ent *cpu = get_cpu_struct(); + // Calculated Model Value: M = (Extended Model << 4) + Model + uint32 model = (cpu->arch.extended_model << 4) + cpu->arch.model; + + // On all recent Intel platforms, ARB_DIS is not necessary + if (cpu->arch.vendor != VENDOR_INTEL) + return; + if (cpu->arch.family > 0xf || (cpu->arch.family == 6 && model >= 0xf)) + device->flags &= ~ACPI_FLAG_C_ARB; +} + + +static status_t +acpi_cpuidle_setup(acpi_cpuidle_driver_info *device) +{ + // _PDC is deprecated in the ACPI 3.0, we will try _OSC firstly + // and fall back to _PDC if _OSC fail + status_t status = acpi_eval_osc(device); + if (status != B_OK) + status = acpi_eval_pdc(device); + if (status != B_OK) { + dprintf("faile to eval _OSC and _PDC\n"); + return status; + } + + acpi_data buffer; + buffer.pointer = NULL; + buffer.length = ACPI_ALLOCATE_BUFFER; + + dprintf("evaluate _CST @%p\n", device->acpi_cookie); + status = device->acpi->evaluate_method(device->acpi_cookie, "_CST", NULL, + &buffer); + if (status != B_OK) { + dprintf("failed to get _CST\n"); + return B_IO_ERROR; + } + + acpi_object_type *object = (acpi_object_type *)buffer.pointer; + if (object->object_type != ACPI_TYPE_PACKAGE) + dprintf("invalid _CST type\n"); + if (object->data.package.count < 2) + dprintf("invalid _CST count\n"); + + acpi_object_type *pointer = object->data.package.objects; + if (pointer[0].object_type != ACPI_TYPE_INTEGER) + dprintf("invalid _CST type 2\n"); + uint32 n = pointer[0].data.integer; + if (n != object->data.package.count - 1) + dprintf("invalid _CST count 2\n"); + if (n > 8) + dprintf("_CST has too many states\n"); + dprintf("cpuidle found %" B_PRId32 " cstates\n", n); + uint32 count = 1; + for (uint32 i = 1; i <= n; i++) { + pointer = &object->data.package.objects[i]; + if (acpi_cstate_add(pointer, &sAcpiDevice.cStates[count]) == B_OK) + ++count; + } + sAcpiDevice.cStateCount = count; + free(buffer.pointer); + + // TODO we assume BM is a must and ARB_DIS is always available + device->flags |= ACPI_FLAG_C_ARB | ACPI_FLAG_C_BM; + + acpi_cstate_quirks(device); + + return B_OK; +} static status_t acpi_cpuidle_init(void) { dprintf("acpi_cpuidle_init\n"); + if (get_module(B_CPUIDLE_MODULE_NAME, (module_info**)&sIdle) != B_OK) + return B_ERROR; + if (get_module(B_ACPI_MODULE_NAME, (module_info**)&sAcpi) != B_OK) + return B_ERROR; + + for (int32 i = 0; i < smp_get_num_cpus(); i++) + if (acpi_cpuidle_setup(acpi_processor[i]) != B_OK) + return B_ERROR; - return B_ERROR; + status_t status = sIdle->AddDevice(&sAcpiDevice); + if (status == B_OK) + dprintf("using acpi idle\n"); + else + put_module(B_CPUIDLE_MODULE_NAME); + return status; } @@ -147,6 +553,9 @@ static void acpi_cpuidle_uninit_driver(void *driverCookie) { dprintf("acpi_cpuidle_uninit_driver"); + put_module(B_CPUIDLE_MODULE_NAME); + if (sAcpi) + put_module(B_ACPI_MODULE_NAME); acpi_cpuidle_driver_info *device = (acpi_cpuidle_driver_info *)driverCookie; free(device); } ############################################################################ Commit: be9a02c0db1f0b7b0a75d2d5099371992195bb01 URL: http://cgit.haiku-os.org/haiku/commit/?id=be9a02c Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Wed Aug 22 10:55:23 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:20 2012 UTC cpuidle: remove drivers/cpuidle Since generic cpuidle module is loaded by lowlevel cpuidle drivers which are loaded dynamically during boot, we don't need drivers/cpuidle any more Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/Jamfile b/src/add-ons/kernel/drivers/Jamfile index f23cf48..ef7c7ee 100644 --- a/src/add-ons/kernel/drivers/Jamfile +++ b/src/add-ons/kernel/drivers/Jamfile @@ -4,7 +4,6 @@ SubInclude HAIKU_TOP src add-ons kernel drivers bluetooth ; SubInclude HAIKU_TOP src add-ons kernel drivers bus ; SubInclude HAIKU_TOP src add-ons kernel drivers audio ; SubInclude HAIKU_TOP src add-ons kernel drivers common ; -SubInclude HAIKU_TOP src add-ons kernel drivers cpuidle ; SubInclude HAIKU_TOP src add-ons kernel drivers disk ; SubInclude HAIKU_TOP src add-ons kernel drivers dvb ; SubInclude HAIKU_TOP src add-ons kernel drivers input ; diff --git a/src/add-ons/kernel/drivers/cpuidle/Jamfile b/src/add-ons/kernel/drivers/cpuidle/Jamfile deleted file mode 100644 index ce5f450..0000000 --- a/src/add-ons/kernel/drivers/cpuidle/Jamfile +++ /dev/null @@ -1,7 +0,0 @@ -SubDir HAIKU_TOP src add-ons kernel drivers cpuidle ; - -UsePrivateKernelHeaders ; - -KernelAddon <driver>cpuidle : - cpuidle.cpp - ; diff --git a/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp b/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp deleted file mode 100644 index 82110c9..0000000 --- a/src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2012, Haiku, Inc. All Rights Reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Yongcong Du <ycdu.vmcore@xxxxxxxxx> - */ - -#include <stdio.h> -#include <string.h> -#include <smp.h> - -#include <Drivers.h> -#include <KernelExport.h> - -#include <cpuidle.h> - -#define DEVICE_NAME "cpuidle" - -int32 api_version = B_CUR_DRIVER_API_VERSION; - -static GenCpuidle *sGenCpuidle; - -static status_t -cpuidle_open(const char *name, uint32 flags, void **cookie) -{ - *cookie = NULL; - return B_OK; -} - - -static status_t -cpuidle_close(void *cookie) -{ - return B_OK; -} - - -static status_t -cpuidle_free(void *cookie) -{ - return B_OK; -} - - -static status_t -cpuidle_ioctl(void *cookie, uint32 op, void *buffer, size_t length) -{ - return B_OK; -} - - -static status_t -cpuidle_read(void *cookie, off_t pos, void *buffer, size_t *length) -{ - if (pos != 0) { - *length = 0; - return B_OK; - } - char *str = (char *)buffer; - size_t max_len = *length; - int32 stateCount = sGenCpuidle->GetIdleStateCount(); - int32 bytes = snprintf(str, max_len, "C-STATE COUNT: %"B_PRId32"\n", stateCount); - max_len-= bytes; - str += bytes; - int32 cpu = smp_get_num_cpus(); - - for (int32 i = 0; i < cpu; i++) { - bytes = snprintf(str, max_len, "CPU%"B_PRId32"\n", i); - max_len-= bytes; - str += bytes; - for (int32 j = 1; j < stateCount; j++) { - CpuidleStat stat; - bytes = snprintf(str, max_len, "%s\n", sGenCpuidle->GetIdleStateName(j)); - max_len-= bytes; - str += bytes; - sGenCpuidle->GetIdleStateInfo(i, j, &stat); - bytes = snprintf(str, max_len, "%lld %lldus\n", - stat.usageCount, stat.usageTime); - max_len-= bytes; - str += bytes; - } - } - *length = strlen((char *)buffer); - - return B_OK; -} - - -static status_t -cpuidle_write(void *cookie, off_t pos, const void *buffer, size_t *_length) -{ - return B_OK; -} - - -status_t -init_hardware(void) -{ - return B_OK; -} - - -const char ** -publish_devices(void) -{ - static const char *devices[] = { - DEVICE_NAME, - NULL - }; - - return devices; -} - - -device_hooks * -find_device(const char *name) -{ - static device_hooks hooks = { - &cpuidle_open, - &cpuidle_close, - &cpuidle_free, - &cpuidle_ioctl, - &cpuidle_read, - &cpuidle_write, - }; - - - return &hooks; -} - - -status_t -init_driver(void) -{ - status_t err; - - err = get_module(B_CPUIDLE_MODULE_NAME, (module_info **)&sGenCpuidle); - if (err != B_OK) { - dprintf("can't load "B_CPUIDLE_MODULE_NAME"\n"); - } - return B_OK; -} - - -void -uninit_driver(void) -{ - put_module(B_CPUIDLE_MODULE_NAME); -} ############################################################################ Commit: 8073227c1d0deeb4fc7aece63b893e401f815442 URL: http://cgit.haiku-os.org/haiku/commit/?id=8073227 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Thu Aug 23 19:50:11 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:20 2012 UTC x86_cpuidle: use module_dependencies rather than get_module() Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp b/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp index fb4095c..dbce64c 100644 --- a/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp +++ b/src/add-ons/kernel/drivers/power/x86_cpuidle/acpi_cpuidle.cpp @@ -89,11 +89,11 @@ struct acpi_cstate_info { uint8 type; }; -static device_manager_info *sDeviceManager; static acpi_cpuidle_driver_info *acpi_processor[B_MAX_CPU_COUNT]; -static CpuidleModuleInfo *sIdle; static CpuidleDevice sAcpiDevice; +static device_manager_info *sDeviceManager; static acpi_module_info *sAcpi; +CpuidleModuleInfo *gIdle; static status_t @@ -431,20 +431,14 @@ static status_t acpi_cpuidle_init(void) { dprintf("acpi_cpuidle_init\n"); - if (get_module(B_CPUIDLE_MODULE_NAME, (module_info**)&sIdle) != B_OK) - return B_ERROR; - if (get_module(B_ACPI_MODULE_NAME, (module_info**)&sAcpi) != B_OK) - return B_ERROR; for (int32 i = 0; i < smp_get_num_cpus(); i++) if (acpi_cpuidle_setup(acpi_processor[i]) != B_OK) return B_ERROR; - status_t status = sIdle->AddDevice(&sAcpiDevice); + status_t status = gIdle->AddDevice(&sAcpiDevice); if (status == B_OK) dprintf("using acpi idle\n"); - else - put_module(B_CPUIDLE_MODULE_NAME); return status; } @@ -553,9 +547,6 @@ static void acpi_cpuidle_uninit_driver(void *driverCookie) { dprintf("acpi_cpuidle_uninit_driver"); - put_module(B_CPUIDLE_MODULE_NAME); - if (sAcpi) - put_module(B_ACPI_MODULE_NAME); acpi_cpuidle_driver_info *device = (acpi_cpuidle_driver_info *)driverCookie; free(device); } @@ -563,6 +554,8 @@ acpi_cpuidle_uninit_driver(void *driverCookie) module_dependency module_dependencies[] = { { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, + { B_ACPI_MODULE_NAME, (module_info **)&sAcpi}, + { B_CPUIDLE_MODULE_NAME, (module_info **)&gIdle }, {} }; diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp b/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp index 1032a5d..069fbc1 100644 --- a/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp +++ b/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp @@ -16,7 +16,6 @@ #include "x86_cpuidle.h" -static CpuidleModuleInfo *sIdle; static CpuidleDevice sIntelDevice; static void *kMwaitEax[] = { @@ -82,8 +81,6 @@ status_t intel_cpuidle_init(void) { dprintf("intel idle init\n"); - if (get_module(B_CPUIDLE_MODULE_NAME, (module_info**)&sIdle) != B_OK) - return B_ERROR; cpu_ent *cpu = get_cpu_struct(); if (cpu->arch.vendor != VENDOR_INTEL || cpu->arch.family != 6) return B_ERROR; @@ -116,10 +113,8 @@ intel_cpuidle_init(void) kMwaitEax[i]; sIntelDevice.cStateCount++; } - status_t status = sIdle->AddDevice(&sIntelDevice); + status_t status = gIdle->AddDevice(&sIntelDevice); if (status == B_OK) dprintf("using intel idle\n"); - else - put_module(B_CPUIDLE_MODULE_NAME); return status; } diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/x86_cpuidle.h b/src/add-ons/kernel/drivers/power/x86_cpuidle/x86_cpuidle.h index b524ef1..4b6285c 100644 --- a/src/add-ons/kernel/drivers/power/x86_cpuidle/x86_cpuidle.h +++ b/src/add-ons/kernel/drivers/power/x86_cpuidle/x86_cpuidle.h @@ -6,6 +6,9 @@ #ifdef __cplusplus extern "C" { #endif + +extern CpuidleModuleInfo *gIdle; + static inline void x86_monitor(const void *addr, unsigned long ecx, unsigned long edx) { ############################################################################ Commit: 5554814b12e0d7bce167a422b661b70fafb77cc9 URL: http://cgit.haiku-os.org/haiku/commit/?id=5554814 Author: Yongcong Du <ycdu.vmcore@xxxxxxxxx> Date: Thu Aug 23 20:01:58 2012 UTC Committer: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Commit-Date: Sun Nov 18 16:39:21 2012 UTC x86_cpuidle: coding style fix according to Jerome Signed-off-by: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp b/src/add-ons/kernel/drivers/power/x86_cpuidle/intel_cpuidle.cpp index 069fbc1..7f6fbd6 100644 [ *** diff truncated: 14 lines dropped *** ] ############################################################################ Commit: 553f1ebfc1f6e0cb1cc001ea35cb2b2be77bf366 URL: http://cgit.haiku-os.org/haiku/commit/?id=553f1eb Author: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Date: Sat Sep 8 18:55:06 2012 UTC Add disabled cpuidle driver and module to haikuImage. CPU idle still needs some polish, but it should work on newer cpus. ---------------------------------------------------------------------------- ############################################################################ Revision: hrev44860 Commit: 5e520ef3995c81a6e1d4ba7ef094c18b4eeaeef3 URL: http://cgit.haiku-os.org/haiku/commit/?id=5e520ef Author: Fredrik Holmqvist <fredrik.holmqvist@xxxxxxxxx> Date: Sun Nov 18 16:42:43 2012 UTC Merge branch 'cpu_idle' * cpu_idle: Add disabled cpuidle driver and module to haikuImage. x86_cpuidle: coding style fix according to Jerome x86_cpuidle: use module_dependencies rather than get_module() cpuidle: remove drivers/cpuidle cpuidle: implement acpi cpuidle driver acpi: export read_bit_register and write_bit_register cpuidle: move generic cpuidle to generic acpi: add ACPI_ALLOCATE_LOCAL_BUFFER to ACPI.h cpuidle: we should exit when cStateCount is less than 3 cpuidle: add stats reporting support intel_cpuidle: apply strict cpu checking to see it's snb or not cpuidle: rename CpuidleStats to CpuidleStat enable cpuidle module and device driver driver: add cpuidle device driver cpuidle: add intel native cpuidle module idle: introduce cpuidle generic module ----------------------------------------------------------------------------