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