RackMac3_1_CPUBUniFanCtrlLoop.cpp [plain text]
#include "IOPlatformPluginDefs.h"
#include "IOPlatformPluginSymbols.h"
#include "RackMac3_1_PlatformPlugin.h"
#include "IOPlatformSensor.h"
#include "RackMac3_1_CPUBUniFanCtrlLoop.h"
#define super IOPlatformPIDCtrlLoop
OSDefineMetaClassAndStructors(RackMac3_1_CPUBUniFanCtrlLoop, IOPlatformPIDCtrlLoop)
extern const OSSymbol * gRM31DIMMFanCtrlLoopTarget;
bool RackMac3_1_CPUBUniFanCtrlLoop::init( void )
{
if (!super::init()) return(false);
secondOutputControl = NULL;
thirdOutputControl = NULL;
return(true);
}
void RackMac3_1_CPUBUniFanCtrlLoop::free( void )
{
if (secondOutputControl) { secondOutputControl->release(); secondOutputControl = NULL; }
if (thirdOutputControl) { thirdOutputControl->release(); thirdOutputControl = NULL; }
super::free();
}
IOReturn RackMac3_1_CPUBUniFanCtrlLoop::initPlatformCtrlLoop( const OSDictionary *dict)
{
IOReturn status;
const OSArray * array;
status = super::initPlatformCtrlLoop(dict);
if ((array = OSDynamicCast(OSArray, dict->getObject(kIOPPluginThermalControlIDsKey))) == NULL ||
(secondOutputControl = platformPlugin->lookupControlByID( OSDynamicCast(OSNumber, array->getObject(1)) )) == NULL)
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::initPlatformCtrlLoop no second control ID!!\n");
return(kIOReturnError);
}
secondOutputControl->retain();
addControl( secondOutputControl );
if ((array = OSDynamicCast(OSArray, dict->getObject(kIOPPluginThermalControlIDsKey))) == NULL ||
(thirdOutputControl = platformPlugin->lookupControlByID( OSDynamicCast(OSNumber, array->getObject(2)) )) == NULL)
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::initPlatformCtrlLoop no third control ID!!\n");
return(kIOReturnError);
}
thirdOutputControl->retain();
addControl( thirdOutputControl );
return(status);
}
bool RackMac3_1_CPUBUniFanCtrlLoop::updateMetaState( void )
{
const OSArray * metaStateArray;
const OSDictionary * metaStateDict;
const OSNumber * newMetaState;
if ((metaStateArray = OSDynamicCast(OSArray, infoDict->getObject(gIOPPluginThermalMetaStatesKey))) == NULL)
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::updateMetaState no meta state array\n");
return(false);
}
if (platformPlugin->envArrayCondIsTrue(gIOPPluginEnvInternalOvertemp))
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::updateMetaState Entering Overtemp Mode\n");
if ((metaStateDict = OSDynamicCast(OSDictionary, metaStateArray->getObject(1))) != NULL &&
(cacheMetaState( metaStateDict ) == true))
{
setMetaState( gIOPPluginOne );
return(true);
}
else
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::updateMetaState Overtemp Mode Failed!\n");
}
}
if ((metaStateDict = OSDynamicCast(OSDictionary, infoDict->getObject(gIOPPluginForceCtrlLoopMetaStateKey))) != NULL)
{
if (cacheMetaState( metaStateDict ) == true)
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::updateMetaState using forced meta state\n");
newMetaState = OSNumber::withNumber( 0xFFFFFFFF, 32 );
setMetaState( newMetaState );
newMetaState->release();
return(true);
}
else
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::updateMetaState forced meta state is invalid, removing...\n");
infoDict->removeObject(gIOPPluginForceCtrlLoopMetaStateKey);
}
}
if ((metaStateDict = OSDynamicCast(OSDictionary, metaStateArray->getObject(0))) != NULL && (cacheMetaState( metaStateDict ) == true))
{
setMetaState( gIOPPluginZero );
return(true);
}
else
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::updateMetaState no valid meta states!\n");
return(false);
}
}
bool RackMac3_1_CPUBUniFanCtrlLoop::cacheMetaState( const OSDictionary * metaState )
{
const OSNumber * numInterval, * numOverride;
const OSNumber * numOutputMin, * numOutputMax;
UInt32 tempInterval;
if ((numInterval = OSDynamicCast(OSNumber, metaState->getObject("interval"))) != NULL)
{
tempInterval = numInterval->unsigned32BitValue();
if ((tempInterval == 0) || (tempInterval > 300))
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::cacheMetaState meta state interval is out of bounds\n");
goto failNoInterval;
}
}
else
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::cacheMetaState meta state interval is absent\n");
goto failNoInterval;
}
if ((numOverride = OSDynamicCast(OSNumber, metaState->getObject(kIOPPIDCtrlLoopOutputOverrideKey))) != NULL)
{
overrideActive = true;
outputOverride = numOverride;
outputOverride->retain();
}
else
{
if ((numOutputMin = OSDynamicCast(OSNumber, metaState->getObject(kIOPPIDCtrlLoopOutputMinKey))) == NULL)
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::cacheMetaState meta state has no output-min\n");
goto failFullSet;
}
if ((numOutputMax = OSDynamicCast(OSNumber, metaState->getObject(kIOPPIDCtrlLoopOutputMaxKey))) == NULL)
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::cacheMetaState meta state has no output-max\n");
goto failFullSet;
}
overrideActive = false;
if (outputOverride) { outputOverride->release(); outputOverride = NULL; }
outputMin = numOutputMin->unsigned32BitValue();
outputMax = numOutputMax->unsigned32BitValue();
}
intervalSec = tempInterval;
clock_interval_to_absolutetime_interval(intervalSec, NSEC_PER_SEC, &interval);
return(true);
failFullSet:
failNoInterval:
return(false);
}
ControlValue RackMac3_1_CPUBUniFanCtrlLoop::calculateNewTarget( void ) const
{
UInt32 newOutputMin;
ControlValue newTarget;
const OSNumber * newDIMMFanCtrlLoopTarget;
if (overrideActive)
{
CTRLLOOP_DLOG("*** PID *** Override Active\n");
newTarget = outputOverride->unsigned32BitValue();
}
else
{
newTarget = outputMin;
newOutputMin = outputMin;
newDIMMFanCtrlLoopTarget = OSDynamicCast(OSNumber, platformPlugin->getEnv(gRM31DIMMFanCtrlLoopTarget));
if(newDIMMFanCtrlLoopTarget)
{
newOutputMin = newDIMMFanCtrlLoopTarget->unsigned32BitValue();
if(newOutputMin < outputMin)
newOutputMin = outputMin;
}
if (newTarget < newOutputMin)
newTarget = newOutputMin;
else if (newTarget > outputMax)
newTarget = outputMax;
}
return(newTarget);
}
void RackMac3_1_CPUBUniFanCtrlLoop::deadlinePassed( void )
{
bool deadlineAbsolute;
ControlValue newTarget;
deadlineAbsolute = (ctrlloopState == kIOPCtrlLoopFirstAdjustment);
timerCallbackActive = true;
if (ctrlloopState == kIOPCtrlLoopNotReady)
return;
newTarget = calculateNewTarget();
sendNewTarget( newTarget );
if (deadlineAbsolute)
{
AbsoluteTime adjustedInterval;
const OSNumber * id = getCtrlLoopID();
clock_interval_to_absolutetime_interval(100 * id->unsigned32BitValue(), NSEC_PER_USEC, &adjustedInterval);
ADD_ABSOLUTETIME( &adjustedInterval, &interval );
clock_absolutetime_interval_to_deadline(adjustedInterval, &deadline);
}
else
{
ADD_ABSOLUTETIME(&deadline, &interval);
}
timerCallbackActive = false;
}
void RackMac3_1_CPUBUniFanCtrlLoop::sendNewTarget( ControlValue newTarget )
{
if (ctrlloopState == kIOPCtrlLoopFirstAdjustment ||
ctrlloopState == kIOPCtrlLoopDidWake ||
newTarget != outputControl->getTargetValue() )
{
if (outputControl->sendTargetValue( newTarget ))
{
outputControl->setTargetValue(newTarget);
ctrlloopState = kIOPCtrlLoopAllRegistered;
}
else
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::sendNewTarget failed to send target value to first control\n");
}
if (secondOutputControl->sendTargetValue( newTarget ))
{
secondOutputControl->setTargetValue(newTarget);
ctrlloopState = kIOPCtrlLoopAllRegistered;
}
else
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::sendNewTarget failed to send target value to second control\n");
}
if (thirdOutputControl->sendTargetValue( newTarget ))
{
thirdOutputControl->setTargetValue(newTarget);
ctrlloopState = kIOPCtrlLoopAllRegistered;
}
else
{
CTRLLOOP_DLOG("RackMac3_1_CPUBUniFanCtrlLoop::sendNewTarget failed to send target value to third control\n");
}
}
}
void RackMac3_1_CPUBUniFanCtrlLoop::sensorRegistered( IOPlatformSensor * aSensor )
{
if( (outputControl->isRegistered() == kOSBooleanTrue) &&
(secondOutputControl->isRegistered() == kOSBooleanTrue) &&
(thirdOutputControl->isRegistered() == kOSBooleanTrue) )
{
ctrlloopState = kIOPCtrlLoopFirstAdjustment;
deadlinePassed();
}
}
void RackMac3_1_CPUBUniFanCtrlLoop::controlRegistered( IOPlatformControl * aControl )
{
if( (outputControl->isRegistered() == kOSBooleanTrue) &&
(secondOutputControl->isRegistered() == kOSBooleanTrue) &&
(thirdOutputControl->isRegistered() == kOSBooleanTrue) )
{
ctrlloopState = kIOPCtrlLoopFirstAdjustment;
deadlinePassed();
}
}