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
|
AddFilesToPackage add-ons kernel partitioning_systems
|
||||||
: amiga_rdb apple efi_gpt intel session ;
|
: amiga_rdb apple efi_gpt intel session ;
|
||||||
AddFilesToPackage add-ons kernel interrupt_controllers : openpic@ppc ;
|
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 {
|
if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 {
|
||||||
AddFilesToPackage add-ons kernel cpu : generic_x86 ;
|
AddFilesToPackage add-ons kernel cpu : generic_x86 ;
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ AddFilesToPackage add-ons kernel generic
|
|||||||
AddFilesToPackage add-ons kernel partitioning_systems
|
AddFilesToPackage add-ons kernel partitioning_systems
|
||||||
: amiga_rdb apple efi_gpt intel session ;
|
: amiga_rdb apple efi_gpt intel session ;
|
||||||
AddFilesToPackage add-ons kernel interrupt_controllers : openpic@ppc ;
|
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 {
|
if $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 {
|
||||||
AddFilesToPackage add-ons kernel cpu : generic_x86 ;
|
AddFilesToPackage add-ons kernel cpu : generic_x86 ;
|
||||||
|
|||||||
@@ -31,10 +31,16 @@
|
|||||||
#define IA32_MSR_TSC 0x10
|
#define IA32_MSR_TSC 0x10
|
||||||
#define IA32_MSR_APIC_BASE 0x1b
|
#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_MTRR_CAPABILITIES 0xfe
|
||||||
#define IA32_MSR_SYSENTER_CS 0x174
|
#define IA32_MSR_SYSENTER_CS 0x174
|
||||||
#define IA32_MSR_SYSENTER_ESP 0x175
|
#define IA32_MSR_SYSENTER_ESP 0x175
|
||||||
#define IA32_MSR_SYSENTER_EIP 0x176
|
#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_ENERGY_PERF_BIAS 0x1b0
|
||||||
#define IA32_MSR_MTRR_DEFAULT_TYPE 0x2ff
|
#define IA32_MSR_MTRR_DEFAULT_TYPE 0x2ff
|
||||||
#define IA32_MSR_MTRR_PHYSICAL_BASE_0 0x200
|
#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 partitioning_systems ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel generic ;
|
SubInclude HAIKU_TOP src add-ons kernel generic ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel bluetooth ;
|
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