Skip to content
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

Restores lost states after wakeup from sleep #70

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 30 additions & 29 deletions AMDRyzenCPUPowerManagement/AMDRyzenCPUPowerManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,20 @@ bool AMDRyzenCPUPowerManagement::init(OSDictionary *dictionary){
IOLog("AMDCPUSupport v%s, init\n", xStringify(MODULE_VERSION));

IOLog("AMDCPUSupport::enter dlinking..\n");

pmRyzen_symtable_ready = 0;

retry:
find_mach_header_addr(getKernelVersion() >= KernelVersion::BigSur);
pmRyzen_symtable._wrmsr_carefully = lookup_symbol("_wrmsr_carefully");

if(!pmRyzen_symtable._wrmsr_carefully){
kextloadAlerts++;
IOSleep(2);
goto retry;
}


pmRyzen_symtable._KUNCUserNotificationDisplayAlert = lookup_symbol("_KUNCUserNotificationDisplayAlert");
pmRyzen_symtable._cpu_to_processor = lookup_symbol("_cpu_to_processor");
pmRyzen_symtable._tscFreq = lookup_symbol("_tscFreq");
Expand Down Expand Up @@ -145,7 +145,7 @@ void AMDRyzenCPUPowerManagement::startWorkLoop() {

//Read PStateDef generated by EFI.
if(pmRyzen_cpu_is_master(cpu_num))
provider->dumpPstate();
provider->dumpPstate(nullptr);


if(!pmRyzen_cpu_primary_in_core(cpu_num)) return;
Expand Down Expand Up @@ -320,11 +320,11 @@ bool AMDRyzenCPUPowerManagement::start(IOService *provider){
IOLog("AMDCPUSupport::start no PCI support found, failing...\n");
return false;
}

// while (!pmRyzen_symtable_ready) {
// IOSleep(200);
// }

void *safe_wrmsr = pmRyzen_symtable._wrmsr_carefully;
if(!safe_wrmsr){
IOLog("AMDCPUSupport::start WARN: Can't find _wrmsr_carefully, proceeding with unsafe wrmsr\n");
Expand Down Expand Up @@ -390,12 +390,17 @@ IOReturn AMDRyzenCPUPowerManagement::setPowerState(unsigned long powerStateOrdin
if (0 == powerStateOrdinal) {
// Going to sleep
IOLog("AMDCPUSupport::setPowerState preparing for sleep\n");
wentToSleep = true;
sleepState.sleep = true;
sleepState.cpb = getCPBState();
//dumpPstate(sleepState.pstate);

stopWorkLoop();
} else if (1 == powerStateOrdinal && wentToSleep) {
} else if (1 == powerStateOrdinal && sleepState.sleep) {
// Waking up
IOLog("AMDCPUSupport::setPowerState preparing for wakeup\n");
wentToSleep = false;
sleepState.sleep = false;
setCPBState(sleepState.cpb);
//writePstate(sleepState.pstate);
startWorkLoop();
}

Expand Down Expand Up @@ -510,18 +515,20 @@ void AMDRyzenCPUPowerManagement::calculateEffectiveFrequency(uint8_t physical){
//If an overflow of either the MPERF or APERF register occurs between read of last MPERF and
//read of last APERF, the effective frequency calculated in is invalid.
if(APERF <= lastAPERF || MPERF <= lastMPERF) {
// IOLog("AMDCPUSupport::calculateEffectiveFrequency: frequency is invalid!!!");
IOLog("AMDCPUSupport::calculateEffectiveFrequency: frequency is invalid for %u", physical);
lastAPERF_PerCore[physical] = APERF;
lastMPERF_PerCore[physical] = MPERF;
return;
}

float freqP0 = PStateDefClock_perCore[0];

uint64_t deltaAPERF = APERF - lastAPERF;
float effFreq = ((float)deltaAPERF / (float)(MPERF - lastMPERF)) * freqP0;

effFreq_perCore[physical] = effFreq;


uint64_t deltaMPERF = MPERF - lastMPERF;
if (deltaMPERF != 0) {
float effFreq = ((float)deltaAPERF / (float)(deltaMPERF)) * freqP0;
effFreq_perCore[physical] = effFreq;
}
}

void AMDRyzenCPUPowerManagement::updateInstructionDelta(uint8_t cpu_num){
Expand Down Expand Up @@ -633,9 +640,8 @@ void AMDRyzenCPUPowerManagement::updatePackageEnergy(){
pwrLastTSC = rdtsc64();
}

void AMDRyzenCPUPowerManagement::dumpPstate(){
void AMDRyzenCPUPowerManagement::dumpPstate(uint64_t buf[8]){

uint8_t len = 0;
for (uint32_t i = 0; i < kMSR_PSTATE_LEN; i++) {
uint64_t msr_value_buf = 0;
bool err = !read_msr(kMSR_PSTATE_0 + i, &msr_value_buf);
Expand All @@ -654,17 +660,12 @@ void AMDRyzenCPUPowerManagement::dumpPstate(){
PStateDef_perCore[i] = msr_value_buf;
PStateDefClock_perCore[i] = clock;

if(msr_value_buf & ((uint64_t)1 << 63)) len++;
// IOLog("a: %llu", msr_value_buf);
}

PStateEnabledLen = max(PStateEnabledLen, len);
if(buf != nullptr) buf[i] = msr_value_buf;
};
}

void AMDRyzenCPUPowerManagement::writePstate(const uint64_t *buf){

PStateEnabledLen = 0;

//A bit hacky but at least works for now.
void* args[] = {this, (void*)buf};

Expand All @@ -687,7 +688,7 @@ void AMDRyzenCPUPowerManagement::writePstate(const uint64_t *buf){


if(!pmRyzen_cpu_is_master(cpu_number())) return;
provider->dumpPstate();
provider->dumpPstate(nullptr);

}, nullptr, args);

Expand Down Expand Up @@ -725,7 +726,7 @@ EXPORT extern "C" kern_return_t amdryzencpupm_kern_start(kmod_info_t *, void *)
// This works better and increases boot speed in some cases.
PE_parse_boot_argn("liludelay", &ADDPR(debugPrintDelay), sizeof(ADDPR(debugPrintDelay)));
ADDPR(debugEnabled) = checkKernelArgument("-amdpdbg");

// IOLog("AMDCPUSupport::enter dlinking..\n");
//
// pmRyzen_symtable_ready = 0;
Expand All @@ -741,7 +742,7 @@ EXPORT extern "C" kern_return_t amdryzencpupm_kern_start(kmod_info_t *, void *)
// pmRyzen_symtable._i386_cpu_IPI = lookup_symbol("_i386_cpu_IPI");
// pmRyzen_symtable_ready = 1;
// IOLog("AMDCPUSupport::enter link finished.\n");

return KERN_SUCCESS;
}

Expand Down
12 changes: 9 additions & 3 deletions AMDRyzenCPUPowerManagement/AMDRyzenCPUPowerManagement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ typedef struct tctl_offset {
int offset;
} TempOffset;

typedef struct sleep_state {
bool sleep;
bool cpb;
uint64_t pstate[8];
} SleepState;


static IOPMPowerState powerStates[kNrOfPowerStates] = {
{1, kIOPMPowerOff, kIOPMPowerOff, kIOPMPowerOff, 0, 0, 0, 0, 0, 0, 0, 0},
Expand Down Expand Up @@ -159,7 +165,7 @@ class AMDRyzenCPUPowerManagement : public IOService {

void registerRequest();

void dumpPstate();
void dumpPstate(uint64_t buf[8]);
void writePstate(const uint64_t *buf);

bool initSuperIO(uint16_t* chipIntel);
Expand Down Expand Up @@ -209,7 +215,6 @@ class AMDRyzenCPUPowerManagement : public IOService {
uint8_t PStateCur_perCore[CPUInfo::MaxCpus];
uint8_t PStateCtl = 0;
uint64_t PStateDef_perCore[8];
uint8_t PStateEnabledLen = 0;
float PStateDefClock_perCore[8];
bool cpbSupported;

Expand Down Expand Up @@ -260,7 +265,8 @@ class AMDRyzenCPUPowerManagement : public IOService {
KernelPatcher *liluKernelPatcher;

bool getPCIService();
bool wentToSleep;

SleepState sleepState;

void startWorkLoop();
void stopWorkLoop();
Expand Down