windows-nt/Source/XPSP1/NT/base/ntos/po/podata.c

636 lines
19 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
podata.c
Abstract:
This module contains the global read/write data for the I/O system.
Author:
N. Yoshiyama [IBM Corp] 07-April-1994 ( Depends on Microsoft's design )
Revision History:
--*/
#include "pop.h"
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("PAGECONST")
#endif // ALLOC_DATA_PRAGMA
#include "initguid.h" // define PO guids
#include "poclass.h"
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg()
#endif // ALLOC_DATA_PRAGMA
//
// Define the global data for the Power Management.
//
//
// Power Locks
//
//
// Protects the IRP serial list.
//
KSPIN_LOCK PopIrpSerialLock;
//
// Protects all Dope structures and dependents,
// including all Notify and Idle operations.
//
KSPIN_LOCK PopDopeGlobalLock;
//
// Must be held during creation or
// destruction of power notify channel
// structures.
ERESOURCE PopNotifyLock;
//
// PoPowerSequence - The current power sequence value. Forever counts
// up each time the machine is resumed from a suspend or hibernate
//
ULONG PoPowerSequence;
//
// PopInvalidNotifyBlockCount is the number of power notify blocks which
// have been invalidated but not fully closed up and freed. Should be 0
// most of the time. Non-0 indicates callers have failed to clean up
// in response to an Invalidate notify.
//
ULONG PopInvalidNotifyBlockCount;
//
// Irp serializtion and Inrush serialization - pocall.c and related
//
LIST_ENTRY PopIrpSerialList;
ULONG PopIrpSerialListLength;
BOOLEAN PopInrushPending;
PIRP PopInrushIrpPointer;
LONG PopInrushIrpReferenceCount;
//
// PopSystemIrpDisptachWorker control, etc
//
KSPIN_LOCK PopWorkerLock;
ULONG PopCallSystemState;
//
// For debugging, a list of all the outstanding PoRequestPowerIrps
//
LIST_ENTRY PopRequestedIrps;
//
// Idle detection service - see idle.c
//
// When adding to, removing from, or scanning the IdleDetectList, code
// must be at DPC_LEVEL and must hold the PopGlobalDopeLock
//
LIST_ENTRY PopIdleDetectList;
//
// A timer & defered procedure call to process idle scans
//
KTIMER PopIdleScanTimer;
KDPC PopIdleScanDpc;
LARGE_INTEGER PopIdleScanTime;
//
// Two scan modes, performance, conservation...
//
BOOLEAN PopIdleDetectionMode = PO_IDLE_PERFORMANCE;
//
// This value holds all Power Management Simulation Flags
//
ULONG PopSimulate = POP_ENABLE_HIBER_PERF;
//
// These defines are only used to initialize these global variables,
// so it makes sense to pair them all up. The global variables are
// all used for idle state transition calculations
//
//
// When throttling down an idle processor, keep it at least 30% active
//
#define IDLE_DEFAULT_MIN_THROTTLE 30
ULONG PopIdleDefaultMinThrottle = IDLE_DEFAULT_MIN_THROTTLE;
//
// When a processor is throttled down, queue a timer to verify that a
// processor does not go significantly "busy" and never returns to
// the idle loop for a throttle adjustment
// N.B idle values are in microseconds
//
#define IDLE_THROTTLE_CHECK_RATE 30000 // 30ms
ULONG PopIdleThrottleCheckRate = IDLE_THROTTLE_CHECK_RATE;
//
// If the throttle check timer noticies a processor has not returned
// to the idle loop for at least 100ms, then abort it's throttle
//
#define IDLE_THROTTLE_CHECK_TIMEOUT 100000 // 100ms
ULONG PopIdleThrottleCheckTimeout = IDLE_THROTTLE_CHECK_TIMEOUT;
//
// To promote from Idle 0 the processor must be more then 90% idle over
// the last 10 seconds
//
#define IDLE_FROM_0_DELAY 10000000 // 10 seconds
#define IDLE_FROM_0_IDLE_PERCENT 90 // > 90% to promote from idle 0
ULONG PopIdleFrom0Delay = IDLE_FROM_0_DELAY;
ULONG PopIdleFrom0IdlePercent = IDLE_FROM_0_IDLE_PERCENT;
//
// First idle handler checks no more then every 100ms
// idle below 20%
//
#define IDLE_0_TIME_CHECK 500000 // 500ms
ULONG PopIdle0TimeCheck = IDLE_0_TIME_CHECK;
//
// When in other idle state check every 100ms
//
#define IDLE_TIME_CHECK 100000 // 100ms
ULONG PopIdleTimeCheck = IDLE_TIME_CHECK;
//
// To demote to Idle 0 the processor must be less then 80% idle in a 100ms window
//
#define IDLE_TO_0_PERCENT 80
ULONG PopIdleTo0Percent = IDLE_TO_0_PERCENT;
//
// The default demotion occurs at less then 50% idle for 100ms
// N.B. The implementation assumes that IDLE_DEFAULT_DEMOTE_TIME divides
// into IDLE_DEFAULT_PROMOTE_TIME evenly
//
#define IDLE_DEFAULT_DEMOTE_PERCENT 50
#define IDLE_DEFAULT_DEMOTE_TIME 100000
ULONG PopIdleDefaultDemotePercent = IDLE_DEFAULT_DEMOTE_PERCENT;
ULONG PopIdleDefaultDemoteTime = IDLE_DEFAULT_DEMOTE_TIME;
//
// The default promotion occurs at more then 70% idle for 500ms
//
#define IDLE_DEFAULT_PROMOTE_TIME 500000 // 500ms
#define IDLE_DEFAULT_PROMOTE_PERCENT 70
ULONG PopIdleDefaultPromotePercent = IDLE_DEFAULT_PROMOTE_PERCENT;
ULONG PopIdleDefaultPromoteTime = IDLE_DEFAULT_PROMOTE_TIME;
//
// We define special extra global variables to handle promotion to/from
// C1. The reason that we do this is so that we can more finely tune these
// values.
//
ULONG PopIdleDefaultDemoteToC1Percent = IDLE_DEFAULT_DEMOTE_PERCENT;
ULONG PopIdleDefaultDemoteToC1Time = IDLE_DEFAULT_DEMOTE_TIME;
ULONG PopIdleDefaultPromoteFromC1Percent = IDLE_DEFAULT_PROMOTE_PERCENT;
ULONG PopIdleDefaultPromoteFromC1Time = IDLE_DEFAULT_PROMOTE_TIME;
//
// We convert PopIdleFrom0Delay (which is in ms) over to KeTimeIncrement
// intervals. This is the number of ticks needed for processor to be idle before
// we consider a promotion out of the Idle0 state
//
ULONG PopIdle0PromoteTicks;
//
// We convert PopIdleFrom0Delay and PopIdleFrom0IdlePercent percent into
// KeTimeIncrement inverals. This is the number of ticks allowed to acculate the
// the PromoteTicks time
//
ULONG PopIdle0PromoteLimit;
//
// These global variables and definitions all relate to CPU throttle management
//
//
// A value that defines the period of time, in microseconds (us) between
// intervals to check the processor busyness for the purposes of processor
// throttling by the idle thread. Note that we need to convert this value
// to KeTimeIncrement intervals. We store the converted number in
// PopPerfTimeTicks
//
#define PROC_PERF_TIME_DELTA 50000 // 50ms
ULONG PopPerfTimeDelta = PROC_PERF_TIME_DELTA;
ULONG PopPerfTimeTicks = 0;
//
// A value that defines the period of time, in microseconds (us) between
// intervals to check the processor busyness for the purposes of processor
// throttling by a DPC routine. Note that we need to convert this value
// to KeTimeIncrement intervals. We store the converted number in
// PopPerfCriticalTimeTicks.
//
#define PROC_PERF_CRITICAL_TIME_DELTA 300000 // 300ms
ULONG PopPerfCriticalTimeDelta = PROC_PERF_CRITICAL_TIME_DELTA;
ULONG PopPerfCriticalTimeTicks = 0;
//
// A percentage value that is added to the current CPU busyness percentage
// to determine if the processor is too busy for the current performance
// state and must be promoted. The closer the value is to zero, the harder it
// is for the processor to promote itself during times of extreme workloads
//
#define PROC_PERF_CRITICAL_FREQUENCY_DELTA 0 // 0%
ULONG PopPerfCriticalFrequencyDelta = PROC_PERF_CRITICAL_FREQUENCY_DELTA;
//
// A percentage value where lower means that the overall IncreaseLevel will
// actually be higher (and thus promotions won't occur as frequently) that
// indicates what percentage of the delta betwene the current state and the
// state to promote to should be used to set the promote level. A suggested
// value would be 20%
//
#define PROC_PERF_INCREASE_PERC_MOD 20 // 20%
ULONG PopPerfIncreasePercentModifier = PROC_PERF_INCREASE_PERC_MOD;
//
// A percentage value where lower means that the overall IncreaseLevel will
// actually be higher (and thus promotions won't occur as frequently) that
// indicates how many extra percentage points to remove from the promote level.
// It should be noted that if this value is particularly high, confusion migh
// result due to overlapping windows. A suggested value would be 1%
//
#define PROC_PERF_INCREASE_ABS_MOD 1 // 1%
ULONG PopPerfIncreaseAbsoluteModifier = PROC_PERF_INCREASE_ABS_MOD;
//
// A percentage value where higher means that the overall DecreaseLevel will
// actually be lower (and thus demotions won't occur as frequently) that
// indicates what percentage of the delta between the current state and the
// state to demote to should be used to set the demote level. A suggested
// value is 30%
//
#define PROC_PERF_DECREASE_PERC_MOD 30 // 50%
ULONG PopPerfDecreasePercentModifier = PROC_PERF_DECREASE_PERC_MOD;
//
// A percentage value where higher means that the overall DecreaseLevel will
// actually be lower (and thus demotions won't occur as frequently) that
// indicates how many extra percentage points to subtract from the demote
// level. It should be noted that if the value is particularly high, then it
// might not be possible to demote from this state. A suggested value would be
// 1%
//
#define PROC_PERF_DECREASE_ABS_MOD 1 // 1%
ULONG PopPerfDecreaseAbsoluteModifier = PROC_PERF_DECREASE_ABS_MOD;
//
// A value that defines the period of time, in microseconds (us) that must
// have occured before a throttle increase can be considered. This value is
// used as the basis for calculating the promotion time for each throttle
// step
//
#define PROC_PERF_INCREASE_TIME 10000 // 10 ms
#define PROC_PERF_INCREASE_MINIMUM_TIME 150000 // 150 ms
ULONG PopPerfIncreaseTimeValue = PROC_PERF_INCREASE_TIME;
ULONG PopPerfIncreaseMinimumTime = PROC_PERF_INCREASE_MINIMUM_TIME;
//
// A value that defines the period of time, in microseconds (us) that must
// have occured before a throttle decrease can be considered. This value is
// used as the basis for calculating the demotion time for each throttle
// step
//
#define PROC_PERF_DECREASE_TIME 10000 // 10 ms
#define PROC_PERF_DECREASE_MINIMUM_TIME 500000 // 500 ms
ULONG PopPerfDecreaseTimeValue = PROC_PERF_DECREASE_TIME;
ULONG PopPerfDecreaseMinimumTime = PROC_PERF_DECREASE_MINIMUM_TIME;
//
// A percentage value that represents at what point of battery capacity we
// will start forcing down the throttle when we are in Degraded Throttling
// mode. For example, a value of 50% means that we will start throttling
// down the CPU when the battery reaches 50%
//
#define PROC_PERF_DEGRADE_MIN_CAP 50 // 50%
ULONG PopPerfDegradeThrottleMinCapacity = PROC_PERF_DEGRADE_MIN_CAP;
//
// A percentage value that represents the lowest frequency we can force the
// throttle down to when we are in the Degraded Throttling mode. For example,
// a value of 30% means that we will never force the CPU below 30%
//
#define PROC_PERF_DEGRADE_MIN_FREQ 30 // 30%
ULONG PopPerfDegradeThrottleMinFrequency = PROC_PERF_DEGRADE_MIN_FREQ;
//
// A percentage value that represents the maximum amount of time that was
// spent in C3 for the last quanta before the idle loop will deside that
// it should optimize power for C3 usage. A sample value would be 50%
//
#define PROC_PERF_MAX_C3_FREQUENCY 50 // 50%
ULONG PopPerfMaxC3Frequency = PROC_PERF_MAX_C3_FREQUENCY;
#if DBG
//
// PoDebug - Debug level
//
ULONG PoDebug = PO_ERROR;
#endif
//
// PopPolicyLock - Protects policy data structures
//
ERESOURCE PopPolicyLock;
//
// PopWorkerSpinLock - Protects worker dispatch data
// PopWorkerPending - A set bit for each worker cataogry which is pending
// PopWorkerStatus - A clear bit for each worker catagory being serived
//
KSPIN_LOCK PopWorkerSpinLock;
ULONG PopWorkerPending;
ULONG PopWorkerStatus;
//
// PopNotifyEvents - PO_NOTIFY_xxx events which have fired.
//
ULONG PopNotifyEvents;
//
// PopVolumeLock - protects PopVolumeDevices from insertion. (removal is
// protected by the policy lock
//
FAST_MUTEX PopVolumeLock;
FAST_MUTEX PopRequestWakeLock;
//
// PopVolumeDevices - a list of off device objects which have had a VPBs attached
//
LIST_ENTRY PopVolumeDevices = {0};
//
// PopRequestWakeLock - synchronizes NtRequest/CancelDeviceWakeup
//
//
// PopPolicyWorker - Work queue item to get another worker thread
//
WORK_QUEUE_ITEM PopPolicyWorker;
//
// PopIdle - Pointer to Array of idle handlers.
//
PPOP_IDLE_HANDLER PopIdle;
//
// PopIdleHandlerLookAsideList - List to allocate storage from for idle
// handlers.
//
NPAGED_LOOKASIDE_LIST PopIdleHandlerLookAsideList;
//
// PopAttribute - Book keeping
//
POP_STATE_ATTRIBUTE PopAttributes[POP_NUMBER_ATTRIBUTES] = {
0, PopSystemRequiredSet, FALSE, 0,
0, PopDisplayRequired, TRUE, 0, // 0, PopSetNotificationWork, TRUE, PO_NOTIFY_DISPLAY_REQUIRED,
0, PopUserPresentSet, FALSE, 0,
0, PopAttribNop, FALSE, 0,
0, PopSetNotificationWork, TRUE, PO_NOTIFY_CAPABILITIES
};
//
// PopFullWake - Flag to indicate the system has transistioned from
// a quite wake to a full wake
//
ULONG PopFullWake;
//
// PoHiberInProgress - True when in the critical hibernation section
//
BOOLEAN PoHiberInProgress;
//
// PopShutdownCleanly - Controls whether clean shutdown sequence should
// be used.
//
ULONG PopShutdownCleanly = 0;
//
// PopDispatchPolicyIrps - Used to prevent policy irps from dispatching
// until the base drivers are loaded
//
BOOLEAN PopDispatchPolicyIrps;
//
// PopSystemIdleTimer - Timer used to get idle system detection worker
//
KTIMER PoSystemIdleTimer;
//
// PopSIdle - tracks the idle state of the system
//
POP_SYSTEM_IDLE PopSIdle;
//
// PopPolicyLockThread - Conains the current owning thread of the
// policy mutex.
//
PKTHREAD PopPolicyLockThread = NULL;
//
// PopAcPolicy - current power policy being implemented while on AC
// PopDcPolicy - current power policy being implemented while not on AC
// PopPolicy - current active policy
//
SYSTEM_POWER_POLICY PopAcPolicy = {0};
SYSTEM_POWER_POLICY PopDcPolicy = {0};
PSYSTEM_POWER_POLICY PopPolicy = NULL;
//
// PopAcProcessorPolicy - current processor power policy being implemented on AC
// PopDcProcessorPolicy - current processor power policy being implemented on DC
// PopProcessorPolicy - current active policy
//
PROCESSOR_POWER_POLICY PopAcProcessorPolicy = {0};
PROCESSOR_POWER_POLICY PopDcProcessorPolicy = {0};
PPROCESSOR_POWER_POLICY PopProcessorPolicy = NULL;
//
// PopAction - Current power action being taken
//
POP_POWER_ACTION PopAction = {0};
//
// Spinlock that protects the thermal zones
//
KSPIN_LOCK PopThermalLock;
//
// PopSwitches - list of button and lid devices currently opened
//
LIST_ENTRY PopSwitches = {0};
//
// User-present work item
//
WORK_QUEUE_ITEM PopUserPresentWorkItem = {0};
//
// Performance counter frequency used by throttle.c
//
LARGE_INTEGER PopPerfCounterFrequency;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#pragma const_seg("PAGECONST")
#endif
//
// Notify worker dispatch
//
const POP_NOTIFY_WORK PopNotifyWork[PO_NUMBER_NOTIFY] = {
PopDispatchCallback, PO_CB_BUTTON_COLLISION,
PopDispatchFullWake, 0,
PopDispatchCallback, PO_CB_SYSTEM_POWER_POLICY,
PopDispatchAcDcCallback, 0,
PopDispatchPolicyCallout, 0,
PopDispatchDisplayRequired, 0,
PopDispatchCallout, PsW32SystemPowerState,
PopDispatchEventCodes, 0,
PopDispatchCallout, PsW32CapabilitiesChanged,
PopDispatchSetStateFailure, 0,
PopDispatchCallback, PO_CB_PROCESSOR_POWER_POLICY,
PopDispatchProcessorPolicyCallout, 0
};
//
// PopAcRegName
// PopDcRegName - registry location under current control set to store
// and retrieve current policy settings from
//
const WCHAR PopRegKey[] = L"Control\\Session Manager\\Power";
const WCHAR PopAcRegName[] = L"AcPolicy";
const WCHAR PopDcRegName[] = L"DcPolicy";
const WCHAR PopUndockPolicyRegName[] = L"UndockPowerPolicy";
const WCHAR PopAdminRegName[] = L"PolicyOverrides";
const WCHAR PopHeuristicsRegName[] = L"Heuristics";
const WCHAR PopCompositeBatteryName[] = L"\\Device\\CompositeBattery";
const WCHAR PopSimulateRegKey[] = L"Control\\Session Manager";
const WCHAR PopSimulateRegName[] = L"PowerPolicySimulate";
const WCHAR PopHiberFileName[] = L"\\hiberfil.sys";
const WCHAR PopDebugHiberFileName[] = L"\\hiberfil.dbg";
const WCHAR PopDumpStackPrefix[] = L"hiber_";
const WCHAR PopApmActiveFlag[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ApmActive";
const WCHAR PopApmFlag[] = L"Active";
const WCHAR PopAcProcessorRegName[] = L"AcProcessorPolicy";
const WCHAR PopDcProcessorRegName[] = L"DcProcessorPolicy";
//
// PopAdminPolcy - Administrator overrides to apply to the current policy
//
ADMINISTRATOR_POWER_POLICY PopAdminPolicy = {0};
//
// PopCapabilities - Misc information on how the systems actual functions
//
SYSTEM_POWER_CAPABILITIES PopCapabilities; // nonpaged
//
// PopEventCallout - callout to USER for power events
//
PKWIN32_POWEREVENT_CALLOUT PopEventCallout; // nonpaged
//
// PopStateCallout - callout to USER for power state changes
//
PKWIN32_POWERSTATE_CALLOUT PopStateCallout = NULL;
//
// PopThermal - list of thermal zones currently opened
//
LIST_ENTRY PopThermal; // nonpaged
//
// PopCoolingMode - system is in active or passive cooling mode
//
ULONG PopCoolingMode = 0;
//
// PopCB - composite battery
//
POP_COMPOSITE_BATTERY PopCB; // nonpaged
//
// PopPolicyIrpQueue - Policy irps which have completed are put onto
// this queue for processingby the worker thread
//
LIST_ENTRY PopPolicyIrpQueue; // nonpaged
//
// PopEventCode - Queued event codes
//
ULONG PopEventCode[POP_MAX_EVENT_CODES] = {0};
//
// PopWorkerTypes - Worker functions for each policy worker type
//
const POP_WORKER_TYPES PopWorkerTypes[] = {
PopPolicyWorkerMain,
PopPolicyWorkerActionPromote,
PopPolicyWorkerAction,
PopPolicyWorkerNotify,
PopPolicySystemIdle,
PopPolicyTimeChange
};
//
// PopActionWaiters - Queue of synchronous action requests
//
LIST_ENTRY PopActionWaiters = {0};
//
// PopHeuristics - Presistant settings are heuristics which are not part
// of the saved policy structures
//
POP_HEURISTICS PopHeuristics = {0};
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg()
#pragma data_seg()
#endif
//
// PopPowerStateHandler - Handlers for the various supported power states
//
POWER_STATE_HANDLER PopPowerStateHandlers[PowerStateMaximum] = {0};
//
// PopPowerStateNotifyHandler - Handler to be notify before and after invoking
// PopPowerStateHandlers
//
POWER_STATE_NOTIFY_HANDLER PopPowerStateNotifyHandler = {0};
//
// PopHiberFile - information on the hibernation file
// PopHiberFileDebug - a second hibernation file for debugging
//
POP_HIBER_FILE PopHiberFile = { NULL };
POP_HIBER_FILE PopHiberFileDebug = { NULL };