1/* 2 * Copyright 2012, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Yongcong Du <ycdu.vmcore@gmail.com> 7 */ 8 9#include <KernelExport.h> 10#include <stdio.h> 11#include <string.h> 12 13#include <smp.h> 14#include <cpuidle.h> 15 16 17static CpuidleInfo sPerCPU[B_MAX_CPU_COUNT]; 18static CpuidleDevice *sDevice; 19extern void (*gCpuIdleFunc)(void); 20 21 22/* 23 * next cstate selection algorithm is based on NetBSD's 24 * it's simple, stupid 25 */ 26static int32 27SelectCstate(CpuidleInfo *info) 28{ 29 static const int32 csFactor = 3; 30 31 for (int32 i = sDevice->cStateCount - 1; i > 0; i--) { 32 CpuidleCstate *cState = &sDevice->cStates[i]; 33 if (info->cstateSleep > cState->latency * csFactor) 34 return i; 35 } 36 37 /* Choose C1 if there's no state found */ 38 return 1; 39} 40 41 42static inline void 43EnterCstate(int32 state, CpuidleInfo *info) 44{ 45 CpuidleCstate *cstate = &sDevice->cStates[state]; 46 bigtime_t now = system_time(); 47 int32 finalState = cstate->EnterIdle(state, sDevice); 48 if (finalState > 0) { 49 bigtime_t diff = system_time() - now; 50 info->cstateSleep = diff; 51 info->stats[finalState].usageCount++; 52 info->stats[finalState].usageTime += diff; 53 } else { 54 info->cstateSleep = 0; 55 } 56} 57 58 59static void 60CpuCstateIdle(void) 61{ 62 CpuidleInfo *info = &sPerCPU[smp_get_current_cpu()]; 63 int32 state = SelectCstate(info); 64 EnterCstate(state, info); 65} 66 67 68static status_t 69std_ops(int32 op, ...) 70{ 71 switch (op) { 72 case B_MODULE_INIT: 73 return B_OK; 74 case B_MODULE_UNINIT: 75 return B_OK; 76 } 77 78 return B_ERROR; 79} 80 81 82status_t AddDevice(CpuidleDevice *device) 83{ 84 sDevice = device; 85 memory_write_barrier(); 86 gCpuIdleFunc = CpuCstateIdle; 87 return B_OK; 88} 89 90 91static CpuidleModuleInfo sCpuidleModule = { 92 { 93 B_CPUIDLE_MODULE_NAME, 94 0, 95 std_ops 96 }, 97 98 AddDevice, 99}; 100 101 102module_info *modules[] = { 103 (module_info *)&sCpuidleModule, 104 NULL 105}; 106