-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[AMD][Zen] kernel cpuidle and cpufreq integration #115
Comments
Skylake Idle Statesstatic IDLE_STATE SKL_IdleState[] = {
{
.Name = "C1",
.Desc = "SKL-C1",
.flags = 0x00 << 24,
.Latency = 2,
.Residency = 2
},
{
.Name = "C1E",
.Desc = "SKL-C1E",
.flags = 0x01 << 24,
.Latency = 10,
.Residency = 20
},
{
.Name = "C3",
.Desc = "SKL-C3",
.flags = (0x10 << 24) | 0x10000,
.Latency = 70,
.Residency = 100
},
{
.Name = "C6",
.Desc = "SKL-C6",
.flags = (0x20 << 24) | 0x10000,
.Latency = 85,
.Residency = 200
},
{
.Name = "C7",
.Desc = "SKL-C7",
.flags = (0x33 << 24) | 0x10000,
.Latency = 124,
.Residency = 800
},
{
.Name = "C8",
.Desc = "SKL-C8",
.flags = (0x40 << 24) | 0x10000,
.Latency = 200,
.Residency = 800
},
{
.Name = "C9",
.Desc = "SKL-C9",
.flags = (0x50 << 24) | 0x10000,
.Latency = 480,
.Residency = 5000
},
{
.Name = "C10",
.Desc = "SKL-C10",
.flags = (0x60 << 24) | 0x10000,
.Latency = 890,
.Residency = 5000
},
{NULL}
};
[Skylake_S] = { /* 39*/
.Signature = _Skylake_S,
.Query = Query_Broadwell,
.Update = PerCore_Skylake_Query,
.Start = Start_Skylake,
.Stop = Stop_Skylake,
.Exit = NULL,
.Timer = InitTimer_Skylake,
.BaseClock = BaseClock_Skylake,
.ClockMod = ClockMod_Skylake_HWP,
.TurboClock = Intel_Turbo_Config8C,
.thermalFormula = THERMAL_FORMULA_INTEL,
.voltageFormula = VOLTAGE_FORMULA_INTEL_SNB,
.powerFormula = POWER_FORMULA_INTEL,
.PCI_ids = PCI_Skylake_ids,
.Uncore = {
.Start = Start_Uncore_Skylake,
.Stop = Stop_Uncore_Skylake,
.ClockMod = NULL
},
.Specific = Void_Specific,
.IdleState = SKL_IdleState,
.Architecture = Arch_Skylake_S
},
|
SandyBridge Idle Statesstatic IDLE_STATE SNB_IdleState[] = {
{
.Name = "C1",
.Desc = "SNB-C1",
.flags = 0x00 << 24,
.Latency = 2,
.Residency = 2
},
{
.Name = "C1E",
.Desc = "SNB-C1E",
.flags = 0x01 << 24,
.Latency = 10,
.Residency = 20
},
{
.Name = "C3",
.Desc = "SNB-C3",
.flags = (0x10 << 24) | 0x10000,
.Latency = 80,
.Residency = 211
},
{
.Name = "C6",
.Desc = "SNB-C6",
.flags = (0x20 << 24) | 0x10000,
.Latency = 104,
.Residency = 345
},
{
.Name = "C7",
.Desc = "SNB-C7",
.flags = (0x30 << 24) | 0x10000,
.Latency = 109,
.Residency = 345
},
{NULL}
};
[SandyBridge] = { /* 26*/
.Signature = _SandyBridge,
.Query = Query_SandyBridge,
.Update = PerCore_SandyBridge_Query,
.Start = Start_SandyBridge,
.Stop = Stop_SandyBridge,
.Exit = NULL,
.Timer = InitTimer_SandyBridge,
.BaseClock = BaseClock_SandyBridge,
.ClockMod = ClockMod_SandyBridge_PPC,
.TurboClock = Intel_Turbo_Config8C,
.thermalFormula = THERMAL_FORMULA_INTEL,
.voltageFormula = VOLTAGE_FORMULA_INTEL_SNB,
.powerFormula = POWER_FORMULA_INTEL,
.PCI_ids = PCI_SandyBridge_ids,
.Uncore = {
.Start = Start_Uncore_SandyBridge,
.Stop = Stop_Uncore_SandyBridge,
.ClockMod = NULL
},
.Specific = Void_Specific,
.IdleState = SNB_IdleState,
.Architecture = Arch_SandyBridge
}, |
Code change to add and fix the C-States description. From the Intel SDM:
|
Code is stable, |
Kernel ability to cap the C-StatesReferring to the last commit: Line 8481 in f753304
Found a proper way to cap the idle states (instead of altering the indexes count):
The kernel mechanism of disablement appears to be in descending order (starting from the right side of the array). For example, with the plan below, to limit to a Cn state, the superior idle state indexes must all be disabled.
According to the kernel documentation , the Line 7925 in f753304
|
static int CoreFreqK_IdleDriver_Init(void)
{
int rc = -EPERM;
#if defined(CONFIG_CPU_IDLE) && LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
if (Arch[Proc->ArchID].SystemDriver != NULL)
{
IDLE_STATE *pIdleState = Arch[Proc->ArchID].SystemDriver->IdleState;
if ((pIdleState != NULL) && Proc->Features.Std.ECX.MONITOR)
{
if((CoreFreqK.IdleDevice = alloc_percpu(struct cpuidle_device)) == NULL)
rc = -ENOMEM;
else {
unsigned int subState[] = {
Proc->Features.MWait.EDX.SubCstate_MWAIT0, /* C0 */
Proc->Features.MWait.EDX.SubCstate_MWAIT1, /* C1 */
Proc->Features.MWait.EDX.SubCstate_MWAIT1, /* C1E */
Proc->Features.MWait.EDX.SubCstate_MWAIT2, /* C3 */
Proc->Features.MWait.EDX.SubCstate_MWAIT3, /* C6 */
Proc->Features.MWait.EDX.SubCstate_MWAIT4, /* C7 */
Proc->Features.MWait.EDX.SubCstate_MWAIT5, /* C8 */
Proc->Features.MWait.EDX.SubCstate_MWAIT6, /* C9 */
Proc->Features.MWait.EDX.SubCstate_MWAIT7 /* C10 */
};
const unsigned int subStateCount = sizeof(subState)
/ sizeof(subState[0]);
/* Kernel polling loop */
cpuidle_poll_state_init(&CoreFreqK.IdleDriver);
CoreFreqK.IdleDriver.state_count = 1;
/* Idle States */
while (pIdleState->Name != NULL)
{
if ((CoreFreqK.IdleDriver.state_count < subStateCount)
&& (subState[CoreFreqK.IdleDriver.state_count] > 0))
{
StrCopy(CoreFreqK.IdleDriver.states[
CoreFreqK.IdleDriver.state_count
].name, pIdleState->Name, CPUIDLE_NAME_LEN);
StrCopy(CoreFreqK.IdleDriver.states[
CoreFreqK.IdleDriver.state_count
].desc, pIdleState->Desc, CPUIDLE_NAME_LEN);
CoreFreqK.IdleDriver.states[
CoreFreqK.IdleDriver.state_count
].flags = pIdleState->flags;
CoreFreqK.IdleDriver.states[
CoreFreqK.IdleDriver.state_count
].exit_latency = pIdleState->Latency;
CoreFreqK.IdleDriver.states[
CoreFreqK.IdleDriver.state_count
].target_residency = pIdleState->Residency;
CoreFreqK.IdleDriver.states[
CoreFreqK.IdleDriver.state_count
].enter = CoreFreqK_IdleHandler;
CoreFreqK.IdleDriver.states[
CoreFreqK.IdleDriver.state_count
].enter_s2idle = CoreFreqK_S2IdleHandler;
CoreFreqK.IdleDriver.state_count++;
}
pIdleState++;
}
if ((rc = cpuidle_register_driver(&CoreFreqK.IdleDriver)) == 0) {
struct cpuidle_device *device;
unsigned int cpu;
for (cpu = 0; cpu < Proc->CPU.Count; cpu++) {
if (!BITVAL(KPublic->Core[cpu]->OffLine, HW)) {
device = per_cpu_ptr(CoreFreqK.IdleDevice, cpu);
device->cpu = cpu;
if ((rc = cpuidle_register_device(device)) == 0)
continue;
cpuidle_unregister_driver(&CoreFreqK.IdleDriver);
break;
}
}
}
}
}
}
#endif /* CONFIG_CPU_IDLE */
return(rc);
} |
Version 1.63.2Register the sub-drivers prior querying the platform information, such as the Turbo state, through the Line 9423 in 52b47d1
...
/* Set the uArch's name with the first found codename */
StrCopy(Proc->Architecture,
Arch[Proc->ArchID].Architecture[0].CodeName,
CODENAME_LEN);
/* Copy various SMBIOS data [version 3.2] */
SMBIOS_Collect();
/* Register the Idle & Frequency sub-drivers */
if (Register_CPU_Idle == 1) {
Proc->Registration.Driver.cpuidle = \
CoreFreqK_IdleDriver_Init() == 0;
}
if (Register_CPU_Freq == 1) {
Proc->Registration.Driver.cpufreq = \
CoreFreqK_FreqDriver_Init() == 0;
}
/* Initialize the CoreFreq controller */
Controller_Init();
MatchPeerForDefaultService(&Proc->Service,
iArg.localProcessor);
printk(KERN_INFO "CoreFreq(%u:%d):" \
" Processor [%2X%1X_%1X%1X]" \
" Architecture [%s] %3s [%u/%u]\n",
Proc->Service.Core, Proc->Service.Thread,
Proc->Features.Std.EAX.ExtFamily,
Proc->Features.Std.EAX.Family,
Proc->Features.Std.EAX.ExtModel,
Proc->Features.Std.EAX.Model,
Proc->Architecture,
Proc->Features.HTT_Enable ? "SMT" : "CPU",
Proc->CPU.OnLine,
Proc->CPU.Count);
/*TODO: CleanUp
if (Register_CPU_Idle == 1) {
Proc->Registration.Driver.cpuidle = \
CoreFreqK_IdleDriver_Init() == 0;
}
if (Register_CPU_Freq == 1) {
Proc->Registration.Driver.cpufreq = \
CoreFreqK_FreqDriver_Init() == 0;
}
*/
Controller_Start(0);
... |
Above change verified ok |
Although AMD is not covered yet, C-States limit and Frequency target can be controlled on most Intel architectures. |
Version 1.81.1PrerequisitesThis version has been tested with
Bellow my boot command line parameters:
Build
Registering the CoreFreq sub-drivers-- Two ways --[A] When loading the CoreFreq kernel module
[B] From the UI in the
|
Version 1.51
This version implements a C-States handler.
Build
Code can be compiled with the feature directive of level 2
Prerequisites
idle
initialized tohalt
Here's my boot command line:
(probably too many drivers blacklisted, but I need control over the hardware)
Start
corefreqk-idle
becomes the new idle driverStop
Issue: The Kernel may refuse to unload the CoreFreq driver.
(I believe that as soon as an idle handler is instantiated it has to stay resident)
However, you can force the removal:
Screenshots
Tuning
CoreFreq/corefreqk.h
Line 2299 in 124d9e5
Thanks
The text was updated successfully, but these errors were encountered: