2 #include <pexpert/pexpert.h>
5 #define super IOService
7 #include "IntelEnhancedSpeedStep.h"
11 OSDefineMetaClassAndStructors(net_mercurysquad_driver_IntelEnhancedSpeedStep, IOService)
12 OSDefineMetaClassAndStructors(AutoThrottler, OSObject)
14 /**********************************************************************************/
15 /* sysctl interface for compatibility with Niall Douglas' ACPICPUThrottle.kext */
17 static int iess_handle_curfreq SYSCTL_HANDLER_ARGS
22 int pstate, wantedFreq;
23 err = SYSCTL_IN(req, &wantedFreq, sizeof(int));
26 if (wantedFreq < 16 && wantedFreq < NumberOfPStates) // pstate specified directly
28 else // freq in MHz is given, find closest pstate
29 pstate = FindClosestPState(wantedFreq);
31 dbg("Throttling to PState %d\n", pstate);
32 throttleAllCPUs(&PStates[pstate]);
34 } else { // just reading
35 int MHz = PStates[FindClosestPState(getCurrentFrequency())].AcpiFreq;
36 err = SYSCTL_OUT(req, &MHz, sizeof(int));
42 static int iess_handle_curvolt SYSCTL_HANDLER_ARGS
46 // New voltage being set
48 err = SYSCTL_IN(req, &wantedvolt, sizeof(int));
50 int pstate = FindClosestPState(getCurrentFrequency());
51 int origvolt = VID_to_mV(PStates[pstate].OriginalVoltage);
52 if (wantedvolt > origvolt+100) {
53 wantedvolt = origvolt;
54 warn("Will not set voltage more than 100 mV higher than factory spec %d mV\n", origvolt);
56 dbg("Changing voltage of current PState %d to %d mV\n", pstate, wantedvolt);
57 PStates[pstate].Voltage = mV_to_VID(wantedvolt);
58 throttleAllCPUs(&PStates[pstate]);
60 } else { // just reading
61 int volt = getCurrentVoltage();
62 err = SYSCTL_OUT(req, &volt, sizeof(int));
68 static int iess_handle_ctl SYSCTL_HANDLER_ARGS
73 warn("Use of kern.cputhrottle_ctl is only for debugging."
74 "Use wisely - no validation is done!\n");
76 err = SYSCTL_IN(req, &ctl, sizeof(int));
78 dbg("Manual stepping to %xh\n", ctl);
80 PState p; p.Frequency = FID(ctl); p.Voltage = VID(ctl);
84 int ctl = rdmsr64(INTEL_MSR_PERF_STS);
85 ctl &= 0xffff; // only last 32 bits
86 err = SYSCTL_OUT(req, &ctl, sizeof(int));
91 static int iess_handle_auto SYSCTL_HANDLER_ARGS
97 err = SYSCTL_IN(req, &whetherOn, sizeof(int));
100 Throttler = new AutoThrottler;
101 if (!Throttler) return kIOReturnError;
103 // If setup was not done yet, do so.
104 if (Throttler->setupDone == false) {
105 if (Throttler->setup((OSObject*) Throttler) == false) {
106 warn("Auto-throttler could not be setup.\n");
107 return kIOReturnError;
110 dbg("Setting autothrottle to %d\n", whetherOn);
111 Throttler->setEnabled(whetherOn != 0);
114 if (!Throttler) return kIOReturnError;
115 int sts = Throttler->getEnabled() ? 1 : 0;
116 err = SYSCTL_OUT(req, &sts, sizeof(int));
121 static int iess_handle_usage SYSCTL_HANDLER_ARGS
124 if (!req->newptr) { // reading
125 int curpos = 0; uint64_t pc;
126 if (totalTimerEvents == 0) return kIOReturnError;
127 for (int i = NumberOfPStates - 1; i >= 0; i--) {
128 pc = (100 * 100 * PStates[i].TimesChosen) / totalTimerEvents;
129 sprintf((frequencyUsage + curpos), "%u.%u%% ", pc / 100, pc % 100);
132 else if (pc / 100 < 100)
137 curpos -= 1; // when it's xx.x% and not xx.xx%
139 frequencyUsage[curpos] = '\0';
140 err = SYSCTL_OUT(req, frequencyUsage, curpos + 1);
145 static int iess_handle_avgfreq SYSCTL_HANDLER_ARGS
148 if (!req->newptr) { // reading
149 if (totalTimerEvents == 0) return kIOReturnError;
150 uint64_t sum = 0; int avg = 0;
151 for (int i = NumberOfPStates - 1; i >= 0; i--) {
152 sum += PStates[i].TimesChosen * FID_to_MHz(PStates[i].Frequency);
154 avg = sum / totalTimerEvents;
155 err = SYSCTL_OUT(req, &avg, sizeof(avg));
160 SYSCTL_PROC (_kern, OID_AUTO, cputhrottle_auto, CTLTYPE_INT | CTLFLAG_RW, 0, 0, &iess_handle_auto, "I", "Auto-throttle status");
161 SYSCTL_PROC (_kern, OID_AUTO, cputhrottle_curfreq, CTLTYPE_INT | CTLFLAG_RW, 0, 0, &iess_handle_curfreq, "I", "Current CPU frequency");
162 SYSCTL_PROC (_kern, OID_AUTO, cputhrottle_curvolt, CTLTYPE_INT | CTLFLAG_RW, 0, 0, &iess_handle_curvolt, "I", "Current CPU voltage");
163 SYSCTL_PROC (_kern, OID_AUTO, cputhrottle_ctl, CTLTYPE_INT | CTLFLAG_RW, 0, 0, &iess_handle_ctl, "I", "Current MSR status");
164 SYSCTL_STRING(_kern, OID_AUTO, cputhrottle_freqs, CTLFLAG_RD, frequencyList, 0, "CPU frequencies supported");
165 SYSCTL_PROC (_kern, OID_AUTO, cputhrottle_usage, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, &iess_handle_usage,"A", "CPU frequency usage pattern");
166 SYSCTL_STRING(_kern, OID_AUTO, cputhrottle_factoryvolts,CTLFLAG_RD, originalVoltages, 0, "Factory default voltages for each frequency");
167 SYSCTL_QUAD (_kern, OID_AUTO, cputhrottle_totalthrottles, CTLFLAG_RD, &totalThrottles, "Total number of frequency throttles made");
168 SYSCTL_PROC (_kern, OID_AUTO, cputhrottle_avgfreq, CTLTYPE_INT | CTLFLAG_RD, 0, 0, &iess_handle_avgfreq, "I", "Weighted average frequency in MHz at which this computer stays");
169 /******* Helper functions for sysctl interface *********/
171 /* Return null terminated list of frequencies */
172 char* getFreqList() {
173 // Makes a list of space separated frequencies supported by the CPU
174 // Each frequency can occupy 4 digits, plus a space
175 char* freqs = new char[5 * NumberOfPStates];
177 for (int i = NumberOfPStates-1; i >= 0; i--) {
178 sprintf((freqs + c), "%d ", PStates[i].AcpiFreq);
179 // Advance by 5 places if freq was of 4 digits
180 if (PStates[i].AcpiFreq >= 1000)
182 else // otherwise 4 places
185 // Set last char (which would be a space) to null
190 /* Return null terminated list of voltages */
191 char* getVoltageList(bool originals) {
192 char* volts = new char[5 * NumberOfPStates];
193 int c = 0, svolt = 0;
194 for (int i = NumberOfPStates-1; i >= 0; i--) {
195 svolt = originals ? VID_to_mV(PStates[i].OriginalVoltage) : VID_to_mV(PStates[i].Voltage);
196 sprintf((volts + c), "%d ", svolt);
197 // Advance by 5 places if voltage was of 4 digits
200 else // otherwise 4 places
203 // Set last char (which would be a space) to null
208 int FindClosestPState(int wantedFreq) {
211 int bestdiff = abs(PStates[0].AcpiFreq - wantedFreq);
213 // now iterate over others and find the best
214 for (int i = 1; i < NumberOfPStates; i++) {
215 if (abs(PStates[i].AcpiFreq - wantedFreq) < bestdiff) {
217 bestdiff = abs(PStates[i].AcpiFreq - wantedFreq);
225 /***************************************************************************************************/
227 bool net_mercurysquad_driver_IntelEnhancedSpeedStep::init(OSDictionary* dict) {
228 bool res = super::init(dict);
229 info("Initializing version 1.5.0 (C) Prashant Vaibhav <mercurysquad@yahoo.com>\n");
230 /* Allocate our spinlock for later use */
231 Lock = IOSimpleLockAlloc();
232 /* Check for a patched kernel which properly implements rtc_clock_stepped() */
233 uint64_t magic = -1; // means autodetect
235 OSBoolean* debugMsgs = (OSBoolean*) dict->getObject("DebugMessages");
237 DebugOn = debugMsgs->getValue();
241 OSNumber* kernelFeatures = (OSNumber*) dict->getObject("KernelFeatures");
242 if (kernelFeatures != 0)
243 magic = kernelFeatures->unsigned8BitValue();
245 if (magic == 255) nanoseconds_to_absolutetime(~(0), &magic); //255uint = -1 int
250 } else if (magic == 2) {
253 } else if (magic == 3) {
254 RtcFixKernel = false;
257 RtcFixKernel = false;
261 checkForNby2Ratio(); // check and store in global variable before loading pstate override
262 if (getFSB() == false)
266 OSArray* overrideTable = (OSArray*) dict->getObject("PStateTable");
267 if (overrideTable != 0 && !PE_parse_boot_arg("-autopstates", &bootarg))
268 loadPStateOverride(overrideTable);
270 OSNumber* defaultState = (OSNumber*) dict->getObject("DefaultPState");
271 if (defaultState != 0)
272 DefaultPState = defaultState->unsigned8BitValue();
274 DefaultPState = -1; // indicate no default state
276 OSNumber* maxLatency = (OSNumber*) dict->getObject("Latency");
278 MaxLatency = maxLatency->unsigned32BitValue();
282 Throttler = new AutoThrottler;
284 dbg("Throttler instantiated.\n");
285 OSNumber* targetload = (OSNumber*) dict->getObject("TargetCPULoad");
287 Throttler->targetCPULoad = (targetload->unsigned16BitValue()) * 10;
289 Throttler->targetCPULoad = 300;
293 frequencyUsage[0] = '\0';
295 /* Return whatever the superclass returned */
299 void net_mercurysquad_driver_IntelEnhancedSpeedStep::free(void) {
300 dbg("Freeing driver resources\n");
301 /* Deallocate the previously allocated spinlock */
302 IOSimpleLockFree(Lock);
306 IOService* net_mercurysquad_driver_IntelEnhancedSpeedStep::probe(IOService* provider, SInt32* score) {
307 IOService* res = super::probe(provider, score);
308 dbg("Probing for Intel processor...\n");
310 /* Make preliminary check */
311 if ( (strcmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL) == 0) // Check it's actually Intel
312 && ( cpuid_info()->cpuid_features & CPUID_FEATURE_EST) ) { // Check it supports EST
314 dbg("Supported Intel processor found on your system\n");
317 warn("No Intel processor found, or your processor does not support SpeedStep."
318 "Kext will not load\n");
322 if (!isConstantTSC()) {
325 dbg("Your processor doesn't support constant_tsc, but you have a kernel which can compensate for it.\n");
327 warn("Your processor doesn't support constant_tsc and your kernel doesn't "
328 "know how to compensate - Expect timing issues or switch to a kernel with RTC fix.\n");
331 Below1Ghz = true; // blindly, because we're not gonna recalibrate the clock so no fear of panic
337 bool net_mercurysquad_driver_IntelEnhancedSpeedStep::start(IOService *provider) {
338 bool res = super::start(provider);
339 if (!res) return false;
343 /* Create PState tables */
344 if (!createPStateTable(PStates, &NumberOfPStates))
347 // Set the frequency list for sysctl
348 strcpy(frequencyList, getFreqList());
349 strcpy(originalVoltages, getVoltageList(true));
351 sysctl_register_oid(&sysctl__kern_cputhrottle_curfreq);
352 sysctl_register_oid(&sysctl__kern_cputhrottle_curvolt);
353 sysctl_register_oid(&sysctl__kern_cputhrottle_freqs);
354 sysctl_register_oid(&sysctl__kern_cputhrottle_usage);
355 sysctl_register_oid(&sysctl__kern_cputhrottle_avgfreq);
356 sysctl_register_oid(&sysctl__kern_cputhrottle_factoryvolts);
357 sysctl_register_oid(&sysctl__kern_cputhrottle_totalthrottles);
358 sysctl_register_oid(&sysctl__kern_cputhrottle_ctl);
360 if (DefaultPState != -1 && DefaultPState < NumberOfPStates) // If a default Pstate was specified in info.plist
362 dbg("Throttling to default PState %d as specified in Info.plist\n", DefaultPState);
363 throttleAllCPUs(&PStates[DefaultPState]); // then throttle to that value
366 // Now turn on our auto-throttler
367 if (Throttler->setup((OSObject*) Throttler) == false)
368 warn("Auto-throttler could not be setup, start it manually later.\n");
370 Throttler->setEnabled(true);
375 void net_mercurysquad_driver_IntelEnhancedSpeedStep::stop(IOService *provider) {
376 dbg("Shutting down\n");
378 Throttler->destruct();
379 Throttler->release();
382 sysctl_unregister_oid(&sysctl__kern_cputhrottle_curfreq);
383 sysctl_unregister_oid(&sysctl__kern_cputhrottle_freqs);
384 sysctl_unregister_oid(&sysctl__kern_cputhrottle_curvolt);
385 sysctl_unregister_oid(&sysctl__kern_cputhrottle_avgfreq);
386 sysctl_unregister_oid(&sysctl__kern_cputhrottle_factoryvolts);
387 sysctl_unregister_oid(&sysctl__kern_cputhrottle_ctl);
388 sysctl_unregister_oid(&sysctl__kern_cputhrottle_usage);
389 sysctl_unregister_oid(&sysctl__kern_cputhrottle_totalthrottles);
391 super::stop(provider);
394 bool isConstantTSC() {
395 /* Check for constant_tsc by getting family, model, stepping */
396 /* Ref http://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits
397 * And http://www.intel.com/assets/pdf/appnote/241618.pdf
399 uint8_t cpumodel = (cpuid_info()->cpuid_extmodel << 4) + cpuid_info()->cpuid_model;
400 uint8_t cpufamily = cpuid_info()->cpuid_family;
401 dbg("Processor Family %d, Model %d\n", cpufamily, cpumodel);
402 if ((cpufamily == 0x6 && cpumodel < 14) // 13 is pentium M, 14+ is core and above
403 || ( cpufamily == 0xf && cpumodel < 3)) // 0xF is pentium 4, less than model 3 dont support constant tsc
404 // Ref - http://www.tomshardware.com/forum/128629-28-intel
410 void checkForPenryn() {
411 uint8_t cpumodel = (cpuid_info()->cpuid_extmodel << 4) + cpuid_info()->cpuid_model;
412 Is45nmPenryn = (cpuid_info()->cpuid_family == 6) && (cpumodel >= 0x17);
414 dbg("On your processor, voltages can be changed in 12.5 mV steps\n");
416 dbg("On your processor, voltages can be changed in 16 mV steps\n");
419 void checkForNby2Ratio() {
421 sts = rdmsr64(INTEL_MSR_PERF_STS);
422 Nby2Ratio = (sts & (1ULL << 46)); // bit 46 is set
425 uint16_t getCurrentVoltage() {
426 // Apple recommends not to return cached value, but to read it from the processor
427 uint64_t msr = rdmsr64(INTEL_MSR_PERF_STS);
428 return VID_to_mV(VID(msr));
431 uint16_t getCurrentFrequency() {
432 uint64_t msr = rdmsr64(INTEL_MSR_PERF_STS);
433 return FID_to_MHz(FID(msr));
436 uint16_t VID_to_mV(uint8_t VID) {
438 return (((int)VID * 125) + 7125) / 10; // to avoid using float
440 return (((int)VID * 16) + 700);
443 uint8_t mV_to_VID(uint16_t mv) {
445 return ((mv * 10) - 7125) / 125;
447 return (mv - 700) / 16;
450 inline uint16_t FID_to_MHz(uint8_t x) {
451 bool nby2 = x & 0x80;
452 uint8_t realfid = x & 0x7f; // removes the bit from 0x80
455 return realfid * (FSB / 1000000ULL);
458 static inline uint32_t FID_to_Hz(uint8_t x) {
459 bool nby2 = x & 0x80;
460 uint8_t realfid = x & 0x7f;
463 return realfid * FSB;
466 inline uint8_t MHz_to_FID(uint16_t x) {
467 uint8_t realfid = x / (FSB / 1000000ULL);
468 if (Nby2Ratio && x < 1000) // FIXME: use n/2 for only <1ghz frequencies?
469 realfid = (realfid*2) | 0x80;
473 void loadPStateOverride(OSArray* dict) {
474 /* Here we load the override pstate table from the given array */
475 NumberOfPStates = dict->getCount();
476 for (int i = 0; i < NumberOfPStates; i++) {
477 OSArray* onePstate = (OSArray*) dict->getObject(i);
478 PStates[i].AcpiFreq = ((OSNumber*) onePstate->getObject(0))->unsigned16BitValue();
479 PStates[i].Frequency = MHz_to_FID(PStates[i].AcpiFreq); // this accounts for N/2 automatically
480 PStates[i].OriginalVoltage = mV_to_VID(((OSNumber*) onePstate->getObject(1))->unsigned16BitValue());
481 PStates[i].Voltage = PStates[i].OriginalVoltage;
482 PStates[i].TimesChosen = 0;
483 dbg("P-State %d: %d MHz at %d mV\n", i, PStates[i].AcpiFreq, VID_to_mV(PStates[i].OriginalVoltage));
485 info("Loaded %d PStates from Info.plist\n", NumberOfPStates);
490 IORegistryEntry* efi = IORegistryEntry::fromPath("/efi/platform", IORegistryEntry::getPlane("IODeviceTree"));
492 warn("EFI registry entry not found!\n");
495 OSData* fsb = (OSData*) efi->getProperty("FSBFrequency");
497 warn("FSB frequency entry not found!\n");
500 bcopy(fsb->getBytesNoCopy(), &FSB, 8);
501 dbg("FSB = %d MHz\n", FSB/1000000ULL);
502 efi = 0; fsb = 0; // in dono ka kaam khatam
506 bool createPStateTable(PState* pS, unsigned int* numStates) {
507 checkForPenryn(); // early on, so we can display proper mV values
509 /* If the PState table was specified manually, we dont do the rest. Otherwise autodetect */
510 if (NumberOfPStates != 0) {
511 dbg("PState table was already created. No autodetection will be performed\n");
515 /* Find CPUs in the IODeviceTree plane */
516 IORegistryEntry* ioreg = IORegistryEntry::fromPath("/cpus", IORegistryEntry::getPlane("IODeviceTree"));
518 warn("Holy moly we cannot find your CPU!\n");
522 /* Get the first CPU - we assume all CPUs share the same P-State */
523 IOACPIPlatformDevice* cpu = (IOACPIPlatformDevice*) ioreg->getChildEntry(IORegistryEntry::getPlane("IODeviceTree"));
525 warn("Um you don't seem to have a CPU o.O\n");
530 dbg("Using data from %s\n", cpu->getName());
532 /* Now try to find the performance state table */
533 OSObject* PSS; uint32_t bootarg;
534 cpu->evaluateObject("_PSS", &PSS);
535 if(PSS == 0 || PE_parse_boot_arg("-autopstates", &bootarg)) {
536 warn("Auto-creating a PState table.\n");
537 int maxFID = MHz_to_FID(getCurrentFrequency());
538 int maxVID = mV_to_VID(getCurrentVoltage());
539 int minVID = mV_to_VID(984); // For now we'll use hardcoded minvolt, later use table
540 int minFID = 6; // No LFM right now
541 NumberOfPStates = 1 + ((maxFID - minFID) / 2);
542 for (int i = 1; i < NumberOfPStates; i++) {
543 PStates[i].Frequency = minFID + (2*(NumberOfPStates - i - 1));
544 PStates[i].AcpiFreq = FID_to_MHz(PStates[i].Frequency);
545 PStates[i].OriginalVoltage = maxVID - (i*((maxVID - minVID) / NumberOfPStates));
546 PStates[i].Voltage = PStates[i].OriginalVoltage;
547 PStates[i].Latency = 110;
548 PStates[i].TimesChosen = 0;
551 PStates[0].Frequency = maxFID;
552 PStates[0].AcpiFreq = FID_to_MHz(maxFID);
553 PStates[0].OriginalVoltage = maxVID;
554 PStates[0].Voltage = PStates[0].OriginalVoltage;
555 PStates[0].Latency = 110;
556 PStates[0].TimesChosen = 0;
557 MaxLatency = PStates[0].Latency;
558 info("Using %d PStates (auto-created, may not be optimal).\n", NumberOfPStates);
563 OSArray* PSSArray = (OSArray*) PSS;
564 NumberOfPStates = PSSArray->getCount();
565 dbg("Found %d P-States\n", NumberOfPStates);
566 OSArray* onestate; uint16_t ctl, acpifreq; uint32_t power, latency;
569 while (c < PSSArray->getCount()) {
570 onestate = ( OSArray* )(PSSArray->getObject(c));
571 ctl = ((OSNumber*) onestate->getObject(4))->unsigned32BitValue();
572 acpifreq = ((OSNumber*) onestate->getObject(0))->unsigned32BitValue();
573 power = ((OSNumber*) onestate->getObject(1))->unsigned32BitValue();
574 latency = ((OSNumber*) onestate->getObject(2))->unsigned32BitValue();
577 if (acpifreq - (10 * (acpifreq / 10)) == 1) {
578 // most likely spurious, so skip it
579 warn("** Spurious P-State %d: %d MHz at %d mV, consuming %d W, latency %d usec\n", i, acpifreq, VID_to_mV(ctl), power / 1000, latency);
584 if (acpifreq < 1000 && !Below1Ghz) {
585 warn("%d MHz disabled because your processor or kernel doesn't support it.\n");
590 PStates[i].AcpiFreq = acpifreq; // cosmetic only
591 PStates[i].Frequency = FID(ctl);
592 PStates[i].OriginalVoltage = VID(ctl);
593 PStates[i].Voltage = PStates[i].OriginalVoltage; // initially same
594 PStates[i].Latency = latency;
595 PStates[i].TimesChosen = 0;
597 if (latency > MaxLatency) MaxLatency = latency;
599 dbg("P-State %d: %d MHz at %d mV, consuming %d W, latency %d usec\n",
600 i, PStates[i].AcpiFreq, VID_to_mV(PStates[i].OriginalVoltage),
601 power / 1000, latency);
605 info("Using %d PStates.\n", NumberOfPStates);
607 ioreg = 0; cpu = 0; PSS = 0; onestate = 0;
611 /**************************************************************************************************/
612 /* Throttling functions */
614 void throttleAllCPUs(PState* p) {
615 dbg("Starting throttle with CTL 0x%x\n", CTL(p->Frequency, p->Voltage));
616 IOSimpleLockLock(Lock);
618 mp_rendezvous(disableInterrupts, throttleCPU, enableInterrupts, p);
619 IODelay(p->Latency); // maybe wait longer?
623 IOSimpleLockUnlock(Lock);
624 dbg("Throttle done.\n");
627 void throttleCPU(void *t) {
630 uint32_t newfreq, oldfreq;
632 bcopy(t,&p,sizeof(PState)); // get the ctl we want
634 msr = rdmsr64(INTEL_MSR_PERF_STS); // read current MSR
636 // For clock recalibration
637 oldfreq = FID_to_Hz(FID(msr));
638 // blank out last 32 bits and put our ctl there
639 msr = (msr & 0xffffffffffff0000ULL) | CTL(p.Frequency, p.Voltage);
640 newfreq = FID_to_Hz(FID(msr)); // after setting ctl in msr
642 if (RtcFixKernel && !ConstantTSC) {
643 rtc_clock_stepping(newfreq, oldfreq);
646 wrmsr64(INTEL_MSR_PERF_CTL, msr); // and write it to the processor
648 if (RtcFixKernel && !ConstantTSC)
649 rtc_clock_stepped(newfreq, oldfreq);
652 void disableInterrupts(__unused void *t) {
653 InterruptsEnabled = ml_set_interrupts_enabled(false);
656 void enableInterrupts(__unused void *t) {
657 ml_set_interrupts_enabled(InterruptsEnabled);
663 /**********************************************************************************************************/
666 static int iess_handle_targetload SYSCTL_HANDLER_ARGS
672 err = SYSCTL_IN(req, &target, sizeof(int));
674 if (!Throttler) return kIOReturnError;
675 if (target > 95) return kIOReturnError;
676 dbg("Setting autothrottle target to %d\n", target*10);
677 Throttler->targetCPULoad = target * 10;
680 if (!Throttler) return kIOReturnError;
681 int target = Throttler->targetCPULoad / 10;
682 err = SYSCTL_OUT(req, &target, sizeof(int));
687 SYSCTL_PROC (_kern, OID_AUTO, cputhrottle_targetload, CTLTYPE_INT | CTLFLAG_RW, 0, 0, &iess_handle_targetload, "I", "Auto-throttle target CPU load");
689 bool AutoThrottler::setup(OSObject* owner) {
690 if (setupDone) return true;
692 workLoop = IOWorkLoop::workLoop();
693 if (workLoop == 0) return false;
695 perfTimer = IOTimerEventSource::timerEventSource(owner, (IOTimerEventSource::Action) &perfTimerWrapper);
696 if (perfTimer == 0) return false;
698 /* from Superhai (modified by mercurysquad) */
699 cpu_count = 0; OSDictionary* service;
700 mach_timespec_t serviceTimeout = { 60, 0 }; // in seconds
701 totalTimerEvents = 0;
703 IOService* firstCPU = IOService::waitForService(IOService::serviceMatching("IOCPU"), &serviceTimeout);
706 warn("IOKit CPUs not found. Auto-throttle may not work.\n");
709 // we got first cpu, so the others should also be available by now. get them
710 service = IOService::serviceMatching("IOCPU");
713 OSIterator* iterator = IOService::getMatchingServices(service);
716 warn("IOKit CPU iterator couldn't be created. Auto-throttle may not work.\n");
721 while (cpu = OSDynamicCast(IOCPU, iterator->getNextObject()))
723 dbg("Got I/O Kit CPU %d (%d) named %s", cpu_count, cpu->getCPUNumber(), cpu->getCPUName()->getCStringNoCopy());
724 mach_cpu[cpu_count] = cpu->getMachProcessor();
725 if (cpu_count++ > max_cpus) break;
727 selfHost = host_priv_self();
728 if (workLoop->addEventSource(perfTimer) != kIOReturnSuccess) return false;
729 currentPState = NumberOfPStates - 1;
730 perfTimer->setTimeoutMS(throttleQuantum * (1 + currentPState));
731 clock_get_uptime(&lastTime);
732 if (!targetCPULoad) targetCPULoad = defaultTargetLoad; // % x10
733 sysctl_register_oid(&sysctl__kern_cputhrottle_targetload);
734 sysctl_register_oid(&sysctl__kern_cputhrottle_auto);
740 void AutoThrottler::stop() {
742 perfTimer->cancelTimeout();
743 perfTimer->disable();
744 // Settle time in case we were just stepping
746 if (workLoop) workLoop->removeEventSource(perfTimer); // Remove our event sources
747 dbg("Autothrottler stopped.\n");
751 void AutoThrottler::setEnabled(bool _enabled) {
756 perfTimer->cancelTimeout();
757 perfTimer->disable();
762 bool AutoThrottler::getEnabled() {
766 void AutoThrottler::destruct() {
767 if (enabled) enabled = false;
768 if (setupDone) stop();
769 sysctl_unregister_oid(&sysctl__kern_cputhrottle_targetload);
770 sysctl_unregister_oid(&sysctl__kern_cputhrottle_auto);
772 perfTimer->release();
783 void AutoThrottler::GetCPUTicks(long* idle, long* total) {
784 mach_msg_type_number_t cpu_count_type;
785 unsigned int cpu_maxload = 0;
786 /* Superhai method */
787 unsigned int temp_ticks = 0;
788 for (int i = 0; i < cpu_count; i++)
790 cpu_count_type = PROCESSOR_CPU_LOAD_INFO_COUNT;
792 kern_return_t kret = processor_info(mach_cpu[i], PROCESSOR_CPU_LOAD_INFO, &selfHost,
793 (processor_info_t) &cpu_load[i], &cpu_count_type);
794 if (kret != KERN_SUCCESS)
796 dbg("Error when reading cpu load on cpu %d (%x)", i, kret);
799 cpu_load_temp[i] = cpu_load[i];
800 for (int t = 0; t < CPU_STATE_MAX; t++)
802 (cpu_load_temp[i].cpu_ticks[t]) -= (cpu_load_last[i].cpu_ticks[t]);
803 total_ticks[i] += (cpu_load_temp[i].cpu_ticks[t]);
805 load_ticks[i] = total_ticks[i] - cpu_load_temp[i].cpu_ticks[CPU_STATE_IDLE];
806 if ((load_ticks[i]) > temp_ticks)
808 temp_ticks = load_ticks[i];
811 cpu_load_last[i] = cpu_load[i];
814 *total = total_ticks[cpu_maxload];
815 *idle = *total - load_ticks[cpu_maxload];
817 dbg("Autothrottle: CPU load %d /10 pc\n", (1000 * (*total - *idle)) / *total);
822 bool perfTimerWrapper(OSObject* owner, IOTimerEventSource* src, int count) {
823 register AutoThrottler* objDriver = (AutoThrottler*) owner;
824 return (objDriver->perfTimerEvent(src, count));
828 bool AutoThrottler::perfTimerEvent(IOTimerEventSource* src, int count) {
829 uint32_t wantspeed,wantstep;
830 long idle, used, total;
832 if (!enabled || !setupDone) return false;
835 PStates[currentPState].TimesChosen++;
838 GetCPUTicks(&idle, &total);
840 // Used = % used x 10
841 used = ((total - idle) * 1000) / total;
843 // If used > 95% we can't really guess how much is needed, so step to highest speed
845 wantspeed = PStates[0].AcpiFreq;
846 else // Otherwise wantspeed is the ideal frequency to maintain idle % target
847 wantspeed = (PStates[currentPState].AcpiFreq * (used + 1)) / targetCPULoad;
849 wantstep = FindClosestPState(wantspeed);
851 if (wantstep == currentPState) goto check_soon;
853 currentPState = wantstep; // Assume we got the one we wanted
854 throttleAllCPUs(&PStates[currentPState]);
856 perfTimer->setTimeoutMS(throttleQuantum * (NumberOfPStates - wantstep)); // Make the delay until the next check proportional to the speed we picked
860 perfTimer->setTimeoutMS(throttleQuantum);