diff --git a/headers/os/drivers/cpuidle.h b/headers/os/drivers/cpuidle.h index ed79be9622..7649cdadab 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 03f57867b9..5a5b275cb3 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 56d91431ba..45feced8e9 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 0000000000..51612506a6 --- /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 0000000000..8064d506e0 --- /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 + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#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 0000000000..1032a5d5e2 --- /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 + */ + +#include +#include +#include + +#include + +#include + +#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 0000000000..b524ef19cc --- /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 a2a6bfc1fa..719061b0dc 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 0000000000..bb7cdd2746 --- /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 0000000000..cc17be8fac --- /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 + */ + +#include +#include +#include + +#include +#include + + +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 878fd5cc5e..0000000000 --- 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 03a6a3c860..0000000000 --- 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 4b74f09e92..0000000000 --- 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 6265c7326a..0000000000 --- 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 - */ - -#include -#include - -#include -#include -#include - - -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 f7ff039052..0000000000 --- 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 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 0ce9851132..0000000000 --- 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 - */ - -#include -#include -#include - -#include -#include - - -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 -};