windows-nt/Source/XPSP1/NT/base/hals/halacpi/amd64/pmtimer.c
2020-09-26 16:20:57 +08:00

237 lines
4.3 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
pmtimer.c
Abstract:
This module implements the code for ACPI-related timer
functions.
Author:
Jake Oshins (jakeo) March 28, 1997
Environment:
Kernel mode only.
Revision History:
Split from pmclock.asm due to PIIX4 bugs.
Forrest Foltz (forrestf) 23-Oct-2000
Ported from pmtimer.asm to pmtimer.c
--*/
#include <halp.h>
#include <ntacpi.h>
//
// HalpCurrentTime is the value of the hardware timer. It is updated at
// every timer tick.
//
volatile ULONG64 HalpCurrentTime;
//
// HalpHardwareTimeRollover represents the maximum count + 1 of the
// hardware timer.
//
// The hardware is either 24- or 32-bits. HalpHardwareTimeRollover will
// therefore have a vale of either 0x1000000 or 0x100000000.
//
// ACPI generates an interrupt whenever the MSb of the hardware timer
// changes.
//
ULONG64 HalpHardwareTimeRollover;
ULONG64 HalpTimeBias;
//
// HalpCurrentTimePort is the port number of the 32-bit hardware timer.
//
ULONG HalpCurrentTimePort;
#if DBG
UCHAR TimerPerf[4096];
ULONG TimerPerfIndex = 0;
#endif
#define MSBMASK24 0x00800000
#define MSBMASK32 0x80000000
ULONG TimerInfo[] = {
0,
0,
0,
0,
MSBMASK24,
0,
0,
0,
2,
2 };
ULONG64
HalpQueryPerformanceCounter (
VOID
)
{
ULONG64 currentTime;
ULONG hardwareTime;
ULONG lastHardwareTime;
//
// Get a local copy of HalpCurrentTime and the value of the hardware
// timer, in that order.
//
currentTime = HalpCurrentTime;
hardwareTime = READ_PORT_ULONG(UlongToPtr(HalpCurrentTimePort));
//
// Extract the hardware portion of the currentTime.
//
lastHardwareTime = (ULONG)(currentTime & (HalpHardwareTimeRollover - 1));
//
// Replace the lastHardwareTime component of currentTime with the
// current hardware time.
//
currentTime ^= lastHardwareTime;
currentTime |= hardwareTime;
//
// Check and compensate for hardware timer rollover
//
if (lastHardwareTime > hardwareTime) {
currentTime += HalpHardwareTimeRollover;
}
return currentTime;
}
LARGE_INTEGER
HalpAcpiTimerQueryPerfCount (
OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
)
/*++
Routine Description:
This routine returns current 64-bit performance counter and,
optionally, the Performance Frequency.
N.B. The performace counter returned by this routine is
not necessary the value when this routine is just entered.
The value returned is actually the counter value at any point
between the routine is entered and is exited.
Arguments:
PerformanceFrequency - optionally, supplies the address of a variable
variable to receive the performance counter frequency.
Return Value:
Current value of the performance counter will be returned.
--*/
{
LARGE_INTEGER time;
if (PerformanceFrequency != NULL) {
PerformanceFrequency->QuadPart = PM_TMR_FREQ;
}
time.QuadPart = HalpQueryPerformanceCounter() + HalpTimeBias;
return time;
}
VOID
HalAcpiTimerCarry (
VOID
)
/*++
Routine Description:
This routine is called to service the PM timer carry interrupt
N.B. This function is called at interrupt time and assumes the
caller clears the interrupt
Arguments:
None
Return Value:
None
--*/
{
ULONG hardwareTime;
ULONG64 currentTime;
ULONG64 halfRollover;
currentTime = HalpCurrentTime;
hardwareTime = READ_PORT_ULONG(UlongToPtr(HalpCurrentTimePort));
//
// ACPI generates an interrupt whenever the MSb of the hardware timer
// changes. Each interrupt represents, therefore, half a rollover.
//
halfRollover = HalpHardwareTimeRollover / 2;
currentTime += halfRollover;
//
// Make sure the MSb of the hardware matches the software MSb. Breaking
// into the debugger might have gotten these out of sync.
//
currentTime += halfRollover & (currentTime ^ hardwareTime);
//
// Finally, store the new current time back into the global
//
HalpCurrentTime = currentTime;
}
#if 0
VOID
HalaAcpiTimerInit(
IN ULONG TimerPort,
IN BOOLEAN TimerValExt
)
{
HalpCurrentTimePort = TimerPort;
if (TimerValExt) {
HalpHardwareTimeRollover = 0x100000000;
} else {
HalpHardwareTimeRollover = 0x1000000;
}
}
#endif