kernel: Add cpufreq module for Intel P-states
Since Sandy Bridge managing P-states on Intel processors is much easier and more powerful than when using previous versions of EIST.
This commit is contained in:
@@ -52,6 +52,7 @@ AddFilesToPackage add-ons kernel generic
|
||||
AddFilesToPackage add-ons kernel partitioning_systems
|
||||
: amiga_rdb apple efi_gpt intel session ;
|
||||
AddFilesToPackage add-ons kernel interrupt_controllers : openpic@ppc ;
|
||||
AddFilesToPackage add-ons kernel power cpufreq : intel_pstates@x86,x86_64 ;
|
||||
|
||||
if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 {
|
||||
AddFilesToPackage add-ons kernel cpu : generic_x86 ;
|
||||
|
||||
@@ -51,6 +51,7 @@ AddFilesToPackage add-ons kernel generic
|
||||
AddFilesToPackage add-ons kernel partitioning_systems
|
||||
: amiga_rdb apple efi_gpt intel session ;
|
||||
AddFilesToPackage add-ons kernel interrupt_controllers : openpic@ppc ;
|
||||
AddFilesToPackage add-ons kernel power cpufreq : intel_pstates@x86,x86_64 ;
|
||||
|
||||
if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 {
|
||||
AddFilesToPackage add-ons kernel cpu : generic_x86 ;
|
||||
|
||||
@@ -31,10 +31,16 @@
|
||||
#define IA32_MSR_TSC 0x10
|
||||
#define IA32_MSR_APIC_BASE 0x1b
|
||||
|
||||
#define IA32_MSR_PLATFORM_INFO 0xce
|
||||
#define IA32_MSR_MPERF 0xe7
|
||||
#define IA32_MSR_APERF 0xe8
|
||||
#define IA32_MSR_MTRR_CAPABILITIES 0xfe
|
||||
#define IA32_MSR_SYSENTER_CS 0x174
|
||||
#define IA32_MSR_SYSENTER_ESP 0x175
|
||||
#define IA32_MSR_SYSENTER_EIP 0x176
|
||||
#define IA32_MSR_PERF_STATUS 0x198
|
||||
#define IA32_MSR_PERF_CTL 0x199
|
||||
#define IA32_MSR_TURBO_RATIO_LIMIT 0x1ad
|
||||
#define IA32_MSR_ENERGY_PERF_BIAS 0x1b0
|
||||
#define IA32_MSR_MTRR_DEFAULT_TYPE 0x2ff
|
||||
#define IA32_MSR_MTRR_PHYSICAL_BASE_0 0x200
|
||||
|
||||
@@ -14,3 +14,4 @@ SubInclude HAIKU_TOP src add-ons kernel media ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel partitioning_systems ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel generic ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel bluetooth ;
|
||||
SubInclude HAIKU_TOP src add-ons kernel power ;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel power ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel power cpufreq ;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel power cpufreq ;
|
||||
|
||||
SubInclude HAIKU_TOP src add-ons kernel power cpufreq intel_pstates ;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
SubDir HAIKU_TOP src add-ons kernel power cpufreq intel_pstates ;
|
||||
|
||||
UsePrivateKernelHeaders ;
|
||||
|
||||
KernelAddon intel_pstates :
|
||||
intel_pstates.cpp
|
||||
;
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2013, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Paweł Dziepak, <[email protected]>
|
||||
*/
|
||||
|
||||
|
||||
#include <cpufreq.h>
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include <arch_cpu.h>
|
||||
#include <cpu.h>
|
||||
#include <smp.h>
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
|
||||
#define INTEL_PSTATES_MODULE_NAME CPUFREQ_MODULES_PREFIX "/intel_pstates/v1"
|
||||
|
||||
|
||||
const int kMinimalInterval = 50000;
|
||||
|
||||
static uint16 sMinPState;
|
||||
static uint16 sMaxPState;
|
||||
static uint16 sBoostPState;
|
||||
|
||||
|
||||
struct CPUEntry {
|
||||
CPUEntry();
|
||||
|
||||
uint16 fCurrentPState;
|
||||
|
||||
bigtime_t fLastUpdate;
|
||||
};
|
||||
static CPUEntry* sCPUEntries;
|
||||
|
||||
|
||||
CPUEntry::CPUEntry()
|
||||
:
|
||||
fCurrentPState(sMinPState - 1),
|
||||
fLastUpdate(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
measure_pstate(CPUEntry* entry)
|
||||
{
|
||||
InterruptsLocker locker;
|
||||
|
||||
uint64 mperf = x86_read_msr(IA32_MSR_MPERF);
|
||||
uint64 aperf = x86_read_msr(IA32_MSR_APERF);
|
||||
|
||||
x86_write_msr(IA32_MSR_MPERF, 0);
|
||||
x86_write_msr(IA32_MSR_APERF, 0);
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
if (mperf == 0)
|
||||
return sMinPState;
|
||||
|
||||
int oldPState = sMaxPState * aperf / mperf;
|
||||
oldPState = min_c(max_c(oldPState, sMinPState), sBoostPState);
|
||||
|
||||
return oldPState;
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
set_pstate(uint16 pstate)
|
||||
{
|
||||
CPUEntry* entry = &sCPUEntries[smp_get_current_cpu()];
|
||||
pstate = min_c(max_c(sMinPState, pstate), sBoostPState);
|
||||
|
||||
if (entry->fCurrentPState != pstate) {
|
||||
entry->fLastUpdate = system_time();
|
||||
entry->fCurrentPState = pstate;
|
||||
|
||||
x86_write_msr(IA32_MSR_PERF_CTL, pstate << 8);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
increase_performance(int delta, bool allowBoost)
|
||||
{
|
||||
CPUEntry* entry = &sCPUEntries[smp_get_current_cpu()];
|
||||
|
||||
if (system_time() - entry->fLastUpdate < kMinimalInterval)
|
||||
return B_OK;
|
||||
|
||||
int pState = measure_pstate(entry);
|
||||
pState += (sBoostPState - pState) * delta / kCPUPerformanceScaleMax;
|
||||
|
||||
if (!allowBoost)
|
||||
pState = min_c(pState, sMaxPState);
|
||||
|
||||
set_pstate(pState);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
decrease_performance(int delta)
|
||||
{
|
||||
CPUEntry* entry = &sCPUEntries[smp_get_current_cpu()];
|
||||
|
||||
if (system_time() - entry->fLastUpdate < kMinimalInterval)
|
||||
return B_OK;
|
||||
|
||||
int pState = measure_pstate(entry);
|
||||
pState -= (pState - sMinPState) * delta / kCPUPerformanceScaleMax;
|
||||
|
||||
set_pstate(pState);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
is_cpu_model_supported(cpu_ent* cpu)
|
||||
{
|
||||
uint8 model = cpu->arch.model + (cpu->arch.extended_model << 4);
|
||||
|
||||
if (cpu->arch.vendor != VENDOR_INTEL)
|
||||
return false;
|
||||
|
||||
if (cpu->arch.family != 6)
|
||||
return false;
|
||||
|
||||
const uint8 kSupportedFamily6Models[] = {
|
||||
0x2a, 0x2d, 0x2e, 0x3a, 0x3c, 0x3e, 0x3f, 0x45, 0x46,
|
||||
};
|
||||
const int kSupportedFamily6ModelsCount
|
||||
= sizeof(kSupportedFamily6Models) / sizeof(uint8);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < kSupportedFamily6ModelsCount; i++) {
|
||||
if (model == kSupportedFamily6Models[i])
|
||||
break;
|
||||
}
|
||||
|
||||
return i != kSupportedFamily6ModelsCount;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_normal_pstate(void* /* dummy */, int cpu)
|
||||
{
|
||||
measure_pstate(&sCPUEntries[cpu]);
|
||||
set_pstate(sMaxPState);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
init_pstates()
|
||||
{
|
||||
if (!x86_check_feature(IA32_FEATURE_MSR, FEATURE_COMMON))
|
||||
return B_ERROR;
|
||||
|
||||
if (!x86_check_feature(IA32_FEATURE_APERFMPERF, FEATURE_6_ECX))
|
||||
return B_ERROR;
|
||||
|
||||
int32 cpuCount = smp_get_num_cpus();
|
||||
for (int32 i = 0; i < cpuCount; i++) {
|
||||
if (!is_cpu_model_supported(&gCPU[i]))
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
sMinPState = (x86_read_msr(IA32_MSR_PLATFORM_INFO) >> 40) & 0xff;
|
||||
sMaxPState = (x86_read_msr(IA32_MSR_PLATFORM_INFO) >> 8) & 0xff;
|
||||
sBoostPState
|
||||
= max_c(x86_read_msr(IA32_MSR_TURBO_RATIO_LIMIT) & 0xff, sMaxPState);
|
||||
|
||||
dprintf("using Intel P-States: min %" B_PRIu16 ", max %" B_PRIu16
|
||||
", boost %" B_PRIu16 "\n", sMinPState, sMaxPState, sBoostPState);
|
||||
|
||||
if (sMaxPState <= sMinPState || sMaxPState == 0) {
|
||||
dprintf("unexpected or invalid Intel P-States limits, aborting\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
sCPUEntries = new(std::nothrow) CPUEntry[cpuCount];
|
||||
if (sCPUEntries == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
call_all_cpus_sync(set_normal_pstate, NULL);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
uninit_pstates()
|
||||
{
|
||||
call_all_cpus_sync(set_normal_pstate, NULL);
|
||||
delete[] sCPUEntries;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
std_ops(int32 op, ...)
|
||||
{
|
||||
switch (op) {
|
||||
case B_MODULE_INIT:
|
||||
return init_pstates();
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
uninit_pstates();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static cpufreq_module_info sIntelPStates = {
|
||||
{
|
||||
INTEL_PSTATES_MODULE_NAME,
|
||||
0,
|
||||
std_ops,
|
||||
},
|
||||
|
||||
increase_performance,
|
||||
decrease_performance,
|
||||
};
|
||||
|
||||
|
||||
module_info* modules[] = {
|
||||
(module_info*)&sIntelPStates,
|
||||
NULL
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user