[haiku-commits] BRANCH yongcong-github.master - src/add-ons/kernel/idle/cpuidles/intel_cpuidle src/add-ons/kernel/idle/generic src/add-ons/kernel/drivers/cpuidle headers/os/drivers src/add-ons/kernel/idle

  • From: yongcong-github.master <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 4 Jul 2012 18:49:09 +0200 (CEST)

added 4 changesets to branch 'refs/remotes/yongcong-github/master'
old head: 550a5b94b16e6e576bed1e59f81aa9cd30c49a94
new head: b73729cf392c399d6999c6d70ff78c46b8daf6c0

----------------------------------------------------------------------------

e29b134: 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>

6717e5b: cpuidle: add intel native cpuidle module
  
  Currently, it only supports intel sandy bridge processors.
  
  Signed-off-by: Yongcong Du <ycdu.vmcore@xxxxxxxxx>

7b31651: 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>

b73729c: enable cpuidle module and device driver

                                     [ Yongcong Du <ycdu.vmcore@xxxxxxxxx> ]

----------------------------------------------------------------------------

11 files changed, 463 insertions(+)
headers/os/drivers/cpuidle.h                       |   51 ++++++
src/add-ons/kernel/Jamfile                         |    1 +
src/add-ons/kernel/drivers/Jamfile                 |    1 +
src/add-ons/kernel/drivers/cpuidle/Jamfile         |    5 +
src/add-ons/kernel/drivers/cpuidle/cpuidle.cpp     |  117 ++++++++++++
src/add-ons/kernel/idle/Jamfile                    |    4 +
src/add-ons/kernel/idle/cpuidles/Jamfile           |    3 +
.../kernel/idle/cpuidles/intel_cpuidle/Jamfile     |    7 +
.../idle/cpuidles/intel_cpuidle/intel_cpuidle.cpp  |  148 ++++++++++++++++
src/add-ons/kernel/idle/generic/Jamfile            |    7 +
src/add-ons/kernel/idle/generic/cpuidle.cpp        |  119 +++++++++++++

############################################################################

Commit:      e29b13495af9f1da2fc1ca09490f774ef5675c24

Author:      Yongcong Du <ycdu.vmcore@xxxxxxxxx>
Date:        Wed Jul  4 15:28:43 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>

----------------------------------------------------------------------------

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:      6717e5bc180dca45ceca63ea1e94d8c43aa18001

Author:      Yongcong Du <ycdu.vmcore@xxxxxxxxx>
Date:        Wed Jul  4 16:09:35 2012 UTC

cpuidle: add intel native cpuidle module

Currently, it only supports intel sandy bridge processors.

Signed-off-by: Yongcong Du <ycdu.vmcore@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:      7b3165100e3dbb0a1fbd6fc4c0ba6571257ed805

Author:      Yongcong Du <ycdu.vmcore@xxxxxxxxx>
Date:        Wed Jul  4 16:11:53 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>

----------------------------------------------------------------------------

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:      b73729cf392c399d6999c6d70ff78c46b8daf6c0

Author:      Yongcong Du <ycdu.vmcore@xxxxxxxxx>
Date:        Wed Jul  4 16:13:55 2012 UTC

enable cpuidle module and device driver

----------------------------------------------------------------------------

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 ;


Other related posts: