📄 pwrmg.c
字号:
/* Copyright ?2000-2001 Intel Corp. */
/*++
Module Name: OEMIdle.c
Abstract:
Intel XScale Microarchitecture OEM Idle routine
for Platform Build 3.0 based systems
Notes:
--*/
#include <windows.h>
#include <bldver.h>
#include <nkintr.h>
#include "xsc1.h"
#include "XSC1bd.h"
#include "timerxsc1.h"
#include "pmu.h"
#include "drv_glob.h"
extern CPUEnterIdle();
extern void usWaitHal(unsigned usVal);
DWORD curridlehigh, curridlelow; // 64-bit idle time in ms
DWORD CurMSec;
BOOL bProfileTimerRunning;
DWORD DiffMSec;
DWORD dwPartialDiffMSec;
DWORD ticksleft, dwSleepMin;
static DWORD dwPartialCurMSec = 0; // Keep sub-millisecond leftover.
volatile ULARGE_INTEGER CurTicks = { 0, 0 };
extern void CheckIdaIdleExit(void);
//
// 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 dwDiffMSecPrev = DiffMSec;
DWORD dwCount, dwTemp;
ULARGE_INTEGER currIdle =
{
curridlelow,
curridlehigh
};
volatile OST_REGS *v_pOSTReg = (volatile OST_REGS *)OST_BASE_U_VIRTUAL;
#ifdef PLAT_LUBBOCK
volatile BLR_REGS *v_pBLReg = (volatile BLR_REGS *) FPGA_REGS_BASE_U_VIRTUAL;
volatile GPIO_REGS *v_pGPIOReg = (volatile GPIO_REGS *)GPIO_BASE_U_VIRTUAL;
#endif
//RETAILMSG(0,(TEXT("+OEMIdle\r\n")));
//
// Check to see if scheduler needs to run before
// entering "idle"
//
//
// if ticksleft, there are threads on the sleep queue waiting to run
// Sleep timer expiring (dwSleepMin) and sleep queue needs to be checked
//
if ((ticksleft) || ((dwSleepMin) && (DiffMSec >= dwSleepMin)))
{
//
// 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();
CheckIdaIdleExit(); // IDAE bit testing.
return;
}
//
// If no minimum sleep time specified
// or interrupt latency timing (fIntrTime - not currently supported),
//
if (dwSleepMin == 0)
{
// idle till end of tick
CPUEnterIdle();
CheckIdaIdleExit(); // IDAE bit testing.
// Update global idle time and return
currIdle.QuadPart += RESCHED_PERIOD;
curridlelow = currIdle.LowPart;
curridlehigh = currIdle.HighPart;
return;
}
//
// Calculate the idle period
// Time since scheduler was run (DiffMSec) from time until next
// thread is ready to run (dwSleepMin)
//
dwIdleMSec = dwSleepMin - dwDiffMSecPrev;
//
// Since OEMIdle( ) is being called in the middle of a normal reschedule
// period, CurMSec, dwPartialCurMSec, dwPartialDiffMSec and CurTicks need
// to be updated accordingly.
//
//
//
// Calculate ticks that have elapsed since last timer firing
//
dwCount = PerfCountSinceTick();
dwTemp = dwCount;
//
// Adjust dwPartialDiffMSec and DiffMSec
// and dwPartialCurMSec and CurMSec
//
// Add any partial MSec from last time
//
dwCount += dwPartialCurMSec;
dwTemp += dwPartialDiffMSec;
//
// Calculate new Partial Msec, DiffMsec
//
dwPartialCurMSec = dwCount % OEM_TICKS_1MS;
dwPartialDiffMSec = dwTemp % OEM_TICKS_1MS;
//
// Convert to MS and add to CurMsec, DiffMsec
//
dwCount /= OEM_TICKS_1MS;
CurMSec += dwCount;
dwTemp /= OEM_TICKS_1MS;
DiffMSec += dwTemp;
dwDiffMSecPrev = DiffMSec;
//
// 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
//
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;
//
// Settimer to length of time for idlemode
//
v_pOSTReg->osmr0 = v_pOSTReg->oscr + 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
//
CPUEnterIdle();
CheckIdaIdleExit(); // IDAE bit testing.
INTERRUPTS_OFF();
//
// 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.
DiffMSec += (dwIdleMSec - RESCHED_PERIOD);
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->oscr);
currIdle.QuadPart += dwTicksElapsed;
//
// Calculate new Partial Msec
//
dwCount = dwPartialCurMSec;
dwCount += dwTicksElapsed;
dwPartialCurMSec = dwCount % OEM_TICKS_1MS;
dwTemp = dwPartialDiffMSec;
dwTemp += dwTicksElapsed;
dwPartialDiffMSec = dwTemp % OEM_TICKS_1MS;
//
// Convert to MS and add to CurMsec
//
dwCount /= OEM_TICKS_1MS;
CurMSec += dwCount;
dwTemp /= OEM_TICKS_1MS;
DiffMSec += dwTemp;
}
//
// Update global idle time variables
//
curridlelow = currIdle.LowPart;
curridlehigh = currIdle.HighPart;
//
// Restore timer increment to normal value
//
v_pOSTReg->osmr0 = v_pOSTReg->oscr + RESCHED_INCREMENT;
//
// Clear any interrupt on Match 0
//
TIMER_M0_INT_CLR(v_pOSTReg->ossr);
TIMER_M0_INT_EN(v_pOSTReg->oier);
//
// Caller will turn interrupts back on
//
}
return;
}
void OEMPowerOff (void)
{
RETAILMSG(0,(TEXT("+OEMPowerOff\r\n")));
RETAILMSG(0,(TEXT("-OEMPowerOn\r\n")));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -