📄 oemidle.c
字号:
/* Copyright ?2002 Intel Corp. */
/*++
Module Name: $Workfile: OEMIdle.c $
Abstract:
Intel XScale Microarchitecture OEM Idle routine
Notes:
--*/
#include <windows.h>
#include <math.h>
#include <stdlib.h>
#include <bldver.h>
#include <nkintr.h>
#include "bvd1.h"
#include "bvd1bd.h"
#include "timer.h"
#include "pmu.h"
#include "drv_glob.h"
extern CPUEnterIdle();
extern void SetCoreVoltage(DWORD dacValue);
extern XSC1ReadCLKCFG(void);
extern void XSC1EnterTurbo(void);
extern void XSC1ExitTurbo(void);
extern DWORD curridlehigh, curridlelow; // 64-bit idle time in ms
extern DWORD CurMSec;
extern BOOL bProfileTimerRunning;
extern BOOL fIntrTime;
extern void SetCoreFrequency(int LMult, int NMult, int run_mode_flag, int fastbus_mode_flag);
extern DWORD dwReschedTime;
static DWORD dwPartialCurMSec = 0; // Keep sub-millisecond leftover.
volatile ULARGE_INTEGER CurTicks = { 0, 0 };
//
// This routine is called by the kernel when there are no threads ready to
// run. The CPU should be put into a reduced power mode and halted. It is
// important to be able to resume execution quickly upon receiving an interrupt.
//
// Note: It is assumed that interrupts are off when OEMIdle is called.
//
void OEMIdle (DWORD dwIdleParam)
{
DWORD dwIdleMSec, dwIdleTick, dwTicksElapsed;
DWORD dwPrevMSec = CurMSec;
DWORD idletime;
DWORD dwCount;
div_t div_result;
static int sample_counter;
static int actual_idle_index;
static int actual_idle;
static int predict_total_idle;
static int IDLE_State;
static int IDLE_State_var;
static int idle_counter,prev_util;
static int systemalive, total_idletime;
static int idle_percentage;
unsigned long CLKCFGValue = 0;
int i =0, IDLE_FLAG=0;
int util = 0;
int TOUCH_FLAG = 0;
#ifdef USING_DVM
unsigned int InterestingInterrupts;
#endif
static int NUM_CONTINUE_TOUCH;
ULARGE_INTEGER currIdle =
{
curridlelow,
curridlehigh
};
volatile PDRIVER_GLOBALS v_pDriverGlobals = (volatile PDRIVER_GLOBALS)DRIVER_GLOBALS_U_VIRTUAL;
volatile XLLP_CLKMGR_T *v_pClkReg = (volatile XLLP_CLKMGR_T *)CLK_BASE_U_VIRTUAL;
volatile XLLP_OST_T *v_pOSTReg = (volatile XLLP_OST_T *)OST_BASE_U_VIRTUAL;
volatile XLLP_INTC_T *v_pICReg = (volatile XLLP_INTC_T *)INTC_BASE_U_VIRTUAL;
//
// Check to see if scheduler needs to run before
// entering "idle"
//
//
// Dougfir (Talisker) or later
//
//return;
//
// Calculate number MS until next scheduled event
//
if ((int) (dwIdleMSec = dwReschedTime - dwPrevMSec) <= 0)
{
//
// Already time to wake up - return to scheduler
//
return;
}
if (bPMURunning)
{
//
// If PMU is currently sampling, we can't enter idle mode,
// else the PMU counters will be turned off
//
return;
}
if (bProfileTimerRunning)
{
// system timer is running at CPU specific profiling value - just call CPUEnterIdle and return
CPUEnterIdle();
return;
}
#ifdef USING_DVM
CLKCFGValue = XSC1ReadCLKCFG();
if(IDLE_State == 1)
{
if( CLKCFGValue ==1 || CLKCFGValue ==3 )
{
XSC1ExitTurbo();
SetCoreVoltage(200);
}
}
else if ( IDLE_State == 0 && (dwIdleMSec * idle_percentage) > 2000)
{
if( CLKCFGValue ==1 || CLKCFGValue ==3 )
{
XSC1ExitTurbo();
SetCoreVoltage(200);
}
}
#endif
//
// Check if we're profiling, or doing interrupt latency timing
//
if (bProfileTimerRunning || fIntrTime)
{
// idle till end of tick
CPUEnterIdle();
// Update global idle time and return
currIdle.QuadPart += RESCHED_PERIOD;
curridlelow = currIdle.LowPart;
curridlehigh = currIdle.HighPart;
EdbgOutputDebugString("exit 4\r\n");
return;
}
//
// Calculate ticks that have elapsed since last timer firing
//
dwCount = PerfCountSinceTick();
//
// Add any partial Msec from last time
//
dwCount += dwPartialCurMSec;
//
// Calculate new Partial Msec
//
dwPartialCurMSec = dwCount % OEM_TICKS_1MS;
//
// Convert to MS and add to CurMsec
//
dwCount /= OEM_TICKS_1MS;
CurMSec += dwCount;
//
// Adjust idle with any Msecs that have elapsed
// (due to dwPartialCurMSec tracking) and...
//
// Only idle if there is more than a Msec to do so
if ((int) (dwIdleMSec -= CurMSec - dwPrevMSec) > 0)
{
//
// Adjust PreviousMsec to Current
//
//NKDbgPrintfW(TEXT("Will be enter idle state\r\n"));
dwPrevMSec = CurMSec;
//
// Check idle time to timer's max timeout value
//
if (dwIdleMSec > MAX_IDLE_TIME)
{
dwIdleMSec = MAX_IDLE_TIME;
}
dwIdleTick = dwIdleMSec * OEM_TICKS_1MS;
//
// Set match timer to length of time for idlemode
//
v_pOSTReg->osmr0 = v_pOSTReg->oscr0 + dwIdleTick;
//Clear and enable the M0 interrupt
TIMER_M0_INT_CLR(v_pOSTReg->ossr);
TIMER_M0_INT_EN(v_pOSTReg->oier);
// Set CPU to Idle to be awakened on any interrupt
//
// activetime = CurMSec - firstidle;
CPUEnterIdle();
INTERRUPTS_OFF();
#ifdef USING_DVM
if ( (v_pICReg->icmr & v_pICReg->icip) != 0x04000000)
{
IDLE_State_var +=0;
IDLE_FLAG = 0;
}
else
{
IDLE_State_var +=1;
IDLE_FLAG = 1;
}
#endif
//
// We've been interrupted from our idle time:
// * Update counters and idle time
// * Re-arm (&clear) system timer interval and return
//
//
// We're awake!
// The wake-up ISR (or any other ISR) has already run.
//
if (dwPrevMSec != CurMSec)
{
//
// We completed the full period we asked to sleep. Update the counters.
//
CurMSec += (dwIdleMSec - RESCHED_PERIOD); // Subtract resched period, because ISR also incremented.
CurTicks.QuadPart += (dwIdleMSec - RESCHED_PERIOD) * OEM_TICKS_1MS;
currIdle.QuadPart += dwIdleMSec;
}
else
{
//
// Some other interrupt woke us up before the
// full idle period was complete.
//
//
// Determine how much time has elapsed and update time variables.
//
// Note: If oscr went past the match point, the math still works since
// it accounts for the dwIdleTick time plus the time past the match.
//
dwTicksElapsed = dwIdleTick - ((DWORD)v_pOSTReg->osmr0 - (DWORD)v_pOSTReg->oscr0);
CurTicks.QuadPart += dwTicksElapsed;
currIdle.QuadPart += (dwTicksElapsed/OEM_TICKS_1MS);
//
// Calculate new Partial Msec
//
dwCount = dwPartialCurMSec;
dwCount += dwTicksElapsed;
dwPartialCurMSec = dwCount % OEM_TICKS_1MS;
//
// Convert to MS and add to CurMsec
//
div_result = div (dwCount, OEM_TICKS_1MS);
dwCount = div_result.quot;
CurMSec += dwCount;
}
//
// Update idle time variables
//
curridlelow = currIdle.LowPart;
curridlehigh = currIdle.HighPart;
idletime = dwTicksElapsed/OEM_TICKS_1MS;
v_pDriverGlobals->uninit_misc.idletime += (unsigned char)idletime;
//
// Restore timer increment to normal value
//
v_pOSTReg->osmr0 = v_pOSTReg->oscr0 + RESCHED_INCREMENT;
//Clear and enable the interrupt
TIMER_M0_INT_CLR(v_pOSTReg->ossr);
TIMER_M0_INT_EN(v_pOSTReg->oier);
//enable the interrupt for DVM
//
// Caller will turn interrupts back on
//
}
else
{
idletime = 0;
#ifdef USING_DVM
IDLE_State_var =IDLE_State_var + 1;
IDLE_FLAG = 1;
#endif
}
#ifdef USING_DVM
if(sample_counter <=5)
{
sample_counter++;
predict_total_idle += dwIdleMSec;
actual_idle += idletime;
}
if(sample_counter ==5)
{
idle_percentage = (100* actual_idle/ predict_total_idle);
sample_counter = 0;
actual_idle = 0;
predict_total_idle = 0;
if(IDLE_State_var >= 5)
IDLE_State = 1;
else
IDLE_State = 0;
IDLE_State_var = 0;
}
CLKCFGValue = XSC1ReadCLKCFG();
if(IDLE_State == 0)
{
if( CLKCFGValue ==0 || CLKCFGValue ==2 )
{
VM_SetVoltage(0);
XSC1EnterTurbo();
}
}
#endif
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -