pstate.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. pstate.c
  5. Abstract:
  6. This module implements support for processor performance states.
  7. Author:
  8. Evan Green 9-Sep-2015
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include "pmp.h"
  17. //
  18. // ---------------------------------------------------------------- Definitions
  19. //
  20. //
  21. // ------------------------------------------------------ Data Type Definitions
  22. //
  23. /*++
  24. Structure Description:
  25. This structure defines the state necessary for computing the load for a
  26. given processor.
  27. Members:
  28. LastBusyCycles - Stores the last snap of the sum of the processor's
  29. non-idle cycles.
  30. CurrentState - Stores the performance state index this processor should
  31. operate in.
  32. DesiredState - Stores the performance state the system would like to
  33. switch this processor to.
  34. --*/
  35. typedef struct _PM_PROCESSOR_LOAD {
  36. ULONGLONG LastBusyCycles;
  37. ULONG CurrentState;
  38. ULONG DesiredState;
  39. } PM_PROCESSOR_LOAD, *PPM_PROCESSOR_LOAD;
  40. /*++
  41. Structure Description:
  42. This structure defines the kernel performance state interface.
  43. Members:
  44. Interface - Stores a pointer to the interface.
  45. TimerDpc - Stores a pointer to the DPC associated with the re-evaluation
  46. DPC.
  47. Timer - Stores a pointer to the timer used to periodically re-evaluate the
  48. current performance state.
  49. ChangeDpc - Stores a pointer to the DPC queued to actually change the
  50. performance state, if the performance state is per-processor.
  51. ChangeWorkItem - Stores a pointer to the work item used to actually change
  52. the performance state, if the performance state is global.
  53. ChangeRunning - Stores an atomic variable indicating whether or not the
  54. a change is already in progress.
  55. Load - Stores a pointer to an arry of processor load structures, one for
  56. each processor in the system.
  57. LastTimestamp - Stores the time counter value the last time this evaluation
  58. was performed.
  59. TimeCounterFrequency - Stores the frequency of the time counter.
  60. ProcessorCounter - Stores information about the processor counter.
  61. ConstantCycleFrequency - Stores a boolean indicating if the frequency of
  62. the processor cycle counter is constant across all p-states (TRUE) or
  63. varies according to the current p-state (FALSE).
  64. ProcessorCount - Stores the number of processors in the system, which
  65. equals the number of elements in the load array.
  66. CurrentState - Stores the current performance state index if the
  67. performance state is global across all processors.
  68. DesiredState - Stores the desired performance state index to switch to if
  69. the performance state is global across all processors.
  70. --*/
  71. typedef struct _PM_PSTATE_DATA {
  72. PPM_PERFORMANCE_STATE_INTERFACE Interface;
  73. PDPC TimerDpc;
  74. PKTIMER Timer;
  75. PDPC ChangeDpc;
  76. PWORK_ITEM ChangeWorkItem;
  77. BOOL ChangeRunning;
  78. PPM_PROCESSOR_LOAD Load;
  79. ULONGLONG LastTimestamp;
  80. ULONGLONG TimeCounterFrequency;
  81. HL_PROCESSOR_COUNTER_INFORMATION ProcessorCounter;
  82. BOOL ConstantCycleFrequency;
  83. ULONG ProcessorCount;
  84. KSPIN_LOCK Lock;
  85. ULONG CurrentState;
  86. ULONG DesiredState;
  87. } PM_PSTATE_DATA, *PPM_PSTATE_DATA;
  88. //
  89. // ----------------------------------------------- Internal Function Prototypes
  90. //
  91. KSTATUS
  92. PmpInitializePerformanceStates (
  93. PPM_PERFORMANCE_STATE_INTERFACE Interface
  94. );
  95. VOID
  96. PmpReevaluatePerformanceStateDpc (
  97. PDPC Dpc
  98. );
  99. VOID
  100. PmpChangePerformanceStateDpc (
  101. PDPC Dpc
  102. );
  103. VOID
  104. PmpChangePerformanceStateWorker (
  105. PVOID Parameter
  106. );
  107. RUNLEVEL
  108. PmpAcquirePerformanceStateLock (
  109. VOID
  110. );
  111. VOID
  112. PmpReleasePerformanceStateLock (
  113. RUNLEVEL OldRunLevel
  114. );
  115. //
  116. // -------------------------------------------------------------------- Globals
  117. //
  118. //
  119. // Set this debug boolean to disable future p-state changes.
  120. //
  121. BOOL PmDisablePstateChanges;
  122. //
  123. // Define the global pointer to the p-state data.
  124. //
  125. PPM_PSTATE_DATA PmPstateData;
  126. //
  127. // ------------------------------------------------------------------ Functions
  128. //
  129. KSTATUS
  130. PmpGetSetPerformanceStateHandlers (
  131. BOOL FromKernelMode,
  132. PVOID Data,
  133. PUINTN DataSize,
  134. BOOL Set
  135. )
  136. /*++
  137. Routine Description:
  138. This routine gets or sets the performance state handlers. In this case
  139. the data pointer is used directly (so the interface structure must not
  140. disappear after the call). This can only be set, can only be set once, and
  141. can only be set from kernel mode for obvious reasons.
  142. Arguments:
  143. FromKernelMode - Supplies a boolean indicating whether or not this request
  144. (and the buffer associated with it) originates from user mode (FALSE)
  145. or kernel mode (TRUE).
  146. Data - Supplies a pointer to the data buffer where the data is either
  147. returned for a get operation or given for a set operation.
  148. DataSize - Supplies a pointer that on input contains the size of the
  149. data buffer. On output, contains the required size of the data buffer.
  150. Set - Supplies a boolean indicating if this is a get operation (FALSE) or
  151. a set operation (TRUE).
  152. Return Value:
  153. STATUS_SUCCESS if the performance state information was initialized.
  154. STATUS_NOT_SUPPORTED for a get operation.
  155. STATUS_PERMISSION_DENIED if this is a user mode request.
  156. STATUS_DATA_LENGTH_MISMATCH if the data size is not the size of the
  157. PM_PERFORMANCE_STATE_INTERFACE structure.
  158. STATUS_TOO_LATE if performance state handlers have already been registered.
  159. Other errors if the performance state runtime could not be initialized.
  160. --*/
  161. {
  162. if (FromKernelMode == FALSE) {
  163. return STATUS_PERMISSION_DENIED;
  164. }
  165. if (Set == FALSE) {
  166. return STATUS_NOT_SUPPORTED;
  167. }
  168. if (*DataSize != sizeof(PM_PERFORMANCE_STATE_INTERFACE)) {
  169. *DataSize = sizeof(PM_PERFORMANCE_STATE_INTERFACE);
  170. return STATUS_DATA_LENGTH_MISMATCH;
  171. }
  172. if (PmPstateData != NULL) {
  173. return STATUS_TOO_LATE;
  174. }
  175. return PmpInitializePerformanceStates(Data);
  176. }
  177. //
  178. // --------------------------------------------------------- Internal Functions
  179. //
  180. KSTATUS
  181. PmpInitializePerformanceStates (
  182. PPM_PERFORMANCE_STATE_INTERFACE Interface
  183. )
  184. /*++
  185. Routine Description:
  186. This routine initializes performance state support in the kernel. It
  187. assumes a performance state interface has been registered.
  188. Arguments:
  189. Interface - Supplies a pointer to the interface.
  190. Return Value:
  191. Status code.
  192. --*/
  193. {
  194. UINTN AllocationSize;
  195. PPM_PSTATE_DATA Data;
  196. ULONG ProcessorCount;
  197. ULONG ProcessorIndex;
  198. KSTATUS Status;
  199. ASSERT(PmPstateData == NULL);
  200. ProcessorCount = KeGetActiveProcessorCount();
  201. AllocationSize = sizeof(PM_PSTATE_DATA) +
  202. (ProcessorCount * sizeof(PM_PROCESSOR_LOAD));
  203. Data = MmAllocateNonPagedPool(AllocationSize, PM_PSTATE_ALLOCATION_TAG);
  204. if (Data == NULL) {
  205. Status = STATUS_INSUFFICIENT_RESOURCES;
  206. goto InitializePerformanceStatesEnd;
  207. }
  208. RtlZeroMemory(Data, AllocationSize);
  209. KeInitializeSpinLock(&(Data->Lock));
  210. Data->Interface = Interface;
  211. Data->ProcessorCount = ProcessorCount;
  212. Data->TimeCounterFrequency = HlQueryTimeCounterFrequency();
  213. Status = HlGetProcessorCounterInformation(&(Data->ProcessorCounter));
  214. if (!KSUCCESS(Status)) {
  215. goto InitializePerformanceStatesEnd;
  216. }
  217. Data->Load = (PPM_PROCESSOR_LOAD)(Data + 1);
  218. Data->TimerDpc = KeCreateDpc(PmpReevaluatePerformanceStateDpc, NULL);
  219. Data->Timer = KeCreateTimer(PM_PSTATE_ALLOCATION_TAG);
  220. if ((Data->TimerDpc == NULL) || (Data->Timer == NULL)) {
  221. Status = STATUS_INSUFFICIENT_RESOURCES;
  222. goto InitializePerformanceStatesEnd;
  223. }
  224. if ((Interface->Flags & PM_PERFORMANCE_STATE_PER_PROCESSOR) != 0) {
  225. Data->ChangeDpc = KeCreateDpc(PmpChangePerformanceStateDpc, NULL);
  226. if (Data->ChangeDpc == NULL) {
  227. Status = STATUS_INSUFFICIENT_RESOURCES;
  228. goto InitializePerformanceStatesEnd;
  229. }
  230. } else {
  231. Data->ChangeWorkItem = KeCreateWorkItem(NULL,
  232. WorkPriorityNormal,
  233. PmpChangePerformanceStateWorker,
  234. NULL,
  235. PM_PSTATE_ALLOCATION_TAG);
  236. if (Data->ChangeWorkItem == NULL) {
  237. Status = STATUS_INSUFFICIENT_RESOURCES;
  238. goto InitializePerformanceStatesEnd;
  239. }
  240. }
  241. //
  242. // Remember whether or not the processor counter runs at the same rate
  243. // regardless of p-states.
  244. //
  245. if ((Data->ProcessorCounter.Features &
  246. TIMER_FEATURE_P_STATE_VARIANT) == 0) {
  247. Data->ConstantCycleFrequency = TRUE;
  248. }
  249. //
  250. // Initialize all the current states to be the fastest, which it's assumed
  251. // they start at.
  252. //
  253. for (ProcessorIndex = 0;
  254. ProcessorIndex < ProcessorCount;
  255. ProcessorIndex += 1) {
  256. Data->Load[ProcessorIndex].CurrentState = Interface->StateCount - 1;
  257. }
  258. Data->CurrentState = Interface->StateCount - 1;
  259. //
  260. // Queue the timer to get the party started.
  261. //
  262. Status = KeQueueTimer(Data->Timer,
  263. TimerQueueSoft,
  264. 0,
  265. Data->Interface->MinimumPeriod,
  266. 0,
  267. Data->TimerDpc);
  268. if (!KSUCCESS(Status)) {
  269. goto InitializePerformanceStatesEnd;
  270. }
  271. Status = STATUS_SUCCESS;
  272. InitializePerformanceStatesEnd:
  273. if (!KSUCCESS(Status)) {
  274. if (Data != NULL) {
  275. if (Data->Timer != NULL) {
  276. KeDestroyTimer(Data->Timer);
  277. }
  278. if (Data->TimerDpc != NULL) {
  279. KeDestroyDpc(Data->TimerDpc);
  280. }
  281. MmFreeNonPagedPool(Data);
  282. Data = NULL;
  283. }
  284. }
  285. PmPstateData = Data;
  286. return Status;
  287. }
  288. VOID
  289. PmpReevaluatePerformanceStateDpc (
  290. PDPC Dpc
  291. )
  292. /*++
  293. Routine Description:
  294. This routine is called from the periodic timer. It re-evaluates the current
  295. performance state.
  296. Arguments:
  297. Dpc - Supplies a pointer to the DPC that is running.
  298. Return Value:
  299. None.
  300. --*/
  301. {
  302. ULONGLONG BusyCycles;
  303. LONGLONG BusyDelta;
  304. ULONG CurrentLoad;
  305. ULONG CurrentState;
  306. ULONGLONG CurrentTime;
  307. ULONGLONG CycleCounterFrequency;
  308. PPM_PSTATE_DATA Data;
  309. ULONG DesiredIndex;
  310. ULONG FirstChangedProcessor;
  311. PPM_PROCESSOR_LOAD Load;
  312. ULONG MaxIndex;
  313. RUNLEVEL OldRunLevel;
  314. BOOL PerProcessor;
  315. PPROCESSOR_BLOCK ProcessorBlock;
  316. ULONG ProcessorIndex;
  317. BOOL QueueChangeDpc;
  318. KSTATUS Status;
  319. ULONGLONG TimeCounterFrequency;
  320. ULONGLONG TimeDelta;
  321. ULONGLONG TimeDeltaCycles;
  322. ULONG WeightSum;
  323. Data = PmPstateData;
  324. //
  325. // Do nothing if P-state changes are locked out via the debug boolean.
  326. //
  327. if (PmDisablePstateChanges != FALSE) {
  328. return;
  329. }
  330. OldRunLevel = PmpAcquirePerformanceStateLock();
  331. FirstChangedProcessor = Data->ProcessorCount;
  332. MaxIndex = 0;
  333. Load = Data->Load;
  334. PerProcessor = FALSE;
  335. if ((Data->Interface->Flags & PM_PERFORMANCE_STATE_PER_PROCESSOR) != 0) {
  336. PerProcessor = TRUE;
  337. }
  338. //
  339. // Update the time counter snap.
  340. //
  341. TimeCounterFrequency = Data->TimeCounterFrequency;
  342. CurrentTime = HlQueryTimeCounter();
  343. TimeDelta = CurrentTime - Data->LastTimestamp;
  344. Data->LastTimestamp = CurrentTime;
  345. //
  346. // Compute p-state data for all processors at once.
  347. //
  348. for (ProcessorIndex = 0;
  349. ProcessorIndex < Data->ProcessorCount;
  350. ProcessorIndex += 1) {
  351. ProcessorBlock = KeGetProcessorBlock(ProcessorIndex);
  352. //
  353. // Grab the current busy cycles. This can tear, but it just means the
  354. // calculations will be off this iteration and the next.
  355. //
  356. BusyCycles = ProcessorBlock->UserCycles +
  357. ProcessorBlock->KernelCycles +
  358. ProcessorBlock->InterruptCycles;
  359. BusyDelta = BusyCycles - Load->LastBusyCycles;
  360. Load->LastBusyCycles = BusyCycles;
  361. //
  362. // Assume a tear occurred if the numbers appear to go backwards.
  363. //
  364. if (BusyDelta < 0) {
  365. Load += 1;
  366. continue;
  367. }
  368. //
  369. // Convert the time counter ticks into cycles so they can be compared.
  370. // The frequency of the cycle counter depends on how it behaves. It
  371. // might either be constant no matter what the p-state is, or it might
  372. // depend on the current p-state.
  373. //
  374. if (Data->ConstantCycleFrequency != FALSE) {
  375. CycleCounterFrequency = Data->ProcessorCounter.Frequency;
  376. } else {
  377. if (PerProcessor != FALSE) {
  378. CurrentState = Load->CurrentState;
  379. } else {
  380. CurrentState = Data->CurrentState;
  381. }
  382. CycleCounterFrequency =
  383. Data->Interface->States[CurrentState].Frequency * 1000;
  384. //
  385. // Some cycle counters (like potentially the ARM cycle counter) run
  386. // at a divisor of their actual speed.
  387. //
  388. BusyDelta *= Data->ProcessorCounter.Multiplier;
  389. }
  390. //
  391. // If the time counter is the processor counter, don't bother with all
  392. // the math.
  393. //
  394. if (CycleCounterFrequency == TimeCounterFrequency) {
  395. TimeDeltaCycles = TimeDelta;
  396. //
  397. // Cancel the units: Tticks * Cticks/s * s/Tticks = Cticks.
  398. //
  399. } else {
  400. TimeDeltaCycles = (TimeDelta * CycleCounterFrequency) /
  401. TimeCounterFrequency;
  402. }
  403. //
  404. // Compute the load over the previous duration.
  405. //
  406. CurrentLoad = (BusyDelta << PM_PERFORMANCE_STATE_WEIGHT_SHIFT) /
  407. TimeDeltaCycles;
  408. //
  409. // Figure out what state that load corresponds to.
  410. //
  411. DesiredIndex = 0;
  412. WeightSum = 0;
  413. for (DesiredIndex = 0;
  414. DesiredIndex < Data->Interface->StateCount - 1;
  415. DesiredIndex += 1) {
  416. WeightSum += Data->Interface->States[DesiredIndex].Weight;
  417. if (WeightSum > CurrentLoad) {
  418. break;
  419. }
  420. }
  421. Load->DesiredState = DesiredIndex;
  422. if (DesiredIndex != Load->CurrentState) {
  423. if (FirstChangedProcessor == Data->ProcessorCount) {
  424. FirstChangedProcessor = ProcessorIndex;
  425. }
  426. }
  427. //
  428. // Keep track of the highest requested state.
  429. //
  430. if (DesiredIndex > MaxIndex) {
  431. MaxIndex = DesiredIndex;
  432. }
  433. //
  434. // If the state appears to have changed.
  435. //
  436. Load += 1;
  437. }
  438. QueueChangeDpc = FALSE;
  439. if (Data->ChangeRunning == FALSE) {
  440. if (PerProcessor != FALSE) {
  441. if (FirstChangedProcessor != Data->ProcessorCount) {
  442. Data->ChangeRunning = TRUE;
  443. QueueChangeDpc = TRUE;
  444. }
  445. } else {
  446. if (MaxIndex != Data->CurrentState) {
  447. Data->DesiredState = MaxIndex;
  448. Data->ChangeRunning = TRUE;
  449. Status = KeQueueWorkItem(Data->ChangeWorkItem);
  450. if (!KSUCCESS(Status)) {
  451. ASSERT(FALSE);
  452. Data->ChangeRunning = FALSE;
  453. }
  454. }
  455. }
  456. }
  457. PmpReleasePerformanceStateLock(OldRunLevel);
  458. //
  459. // Queue the change DPC if needed. Do this with the lock dropped since
  460. // queuing the DPC might immediately run it.
  461. //
  462. if (QueueChangeDpc != FALSE) {
  463. ASSERT(PerProcessor != FALSE);
  464. KeQueueDpcOnProcessor(Data->ChangeDpc, FirstChangedProcessor);
  465. }
  466. return;
  467. }
  468. VOID
  469. PmpChangePerformanceStateDpc (
  470. PDPC Dpc
  471. )
  472. /*++
  473. Routine Description:
  474. This routine is called to change the current performance state on a
  475. particular processor.
  476. Arguments:
  477. Dpc - Supplies a pointer to the DPC that is running.
  478. Return Value:
  479. None.
  480. --*/
  481. {
  482. ULONG CurrentProcessor;
  483. PPM_PSTATE_DATA Data;
  484. PPM_PROCESSOR_LOAD Load;
  485. RUNLEVEL OldRunLevel;
  486. ULONG Processor;
  487. KSTATUS Status;
  488. Data = PmPstateData;
  489. CurrentProcessor = KeGetCurrentProcessorNumber();
  490. OldRunLevel = PmpAcquirePerformanceStateLock();
  491. Load = &(Data->Load[CurrentProcessor]);
  492. if (Load->CurrentState != Load->DesiredState) {
  493. Status = Data->Interface->SetPerformanceState(Data->Interface,
  494. Load->DesiredState);
  495. if (!KSUCCESS(Status)) {
  496. RtlDebugPrint("Failed to set p-state on core %d: %x\n",
  497. CurrentProcessor,
  498. Status);
  499. } else {
  500. Load->CurrentState = Load->DesiredState;
  501. }
  502. }
  503. //
  504. // Queue the DPC now on the next processor that requires a change.
  505. //
  506. for (Processor = 0; Processor < Data->ProcessorCount; Processor += 1) {
  507. if (Processor == CurrentProcessor) {
  508. continue;
  509. }
  510. Load = &(Data->Load[CurrentProcessor]);
  511. if (Load->CurrentState != Load->DesiredState) {
  512. //
  513. // This DPC is not running on this processor, so it can be queued
  514. // without worrying about this thread calling into it.
  515. //
  516. KeQueueDpcOnProcessor(Data->ChangeDpc, Processor);
  517. break;
  518. }
  519. }
  520. //
  521. // If nothing was queued, then mark the DPC as no longer running.
  522. //
  523. if (Processor == Data->ProcessorCount) {
  524. Data->ChangeRunning = FALSE;
  525. }
  526. PmpReleasePerformanceStateLock(OldRunLevel);
  527. return;
  528. }
  529. VOID
  530. PmpChangePerformanceStateWorker (
  531. PVOID Parameter
  532. )
  533. /*++
  534. Routine Description:
  535. This routine is called to change the global performance state.
  536. Arguments:
  537. Parameter - Supplies an optional parameter passed in by the creator of the
  538. work item.
  539. Return Value:
  540. None.
  541. --*/
  542. {
  543. PPM_PSTATE_DATA Data;
  544. ULONG DesiredState;
  545. BOOL Loop;
  546. RUNLEVEL OldRunLevel;
  547. KSTATUS Status;
  548. Data = PmPstateData;
  549. //
  550. // Loop changing the performance state while this worker thread is behind
  551. // the times.
  552. //
  553. Loop = TRUE;
  554. do {
  555. //
  556. // Perform the change without acquiring the (dispatch level) lock.
  557. //
  558. DesiredState = Data->DesiredState;
  559. Status = Data->Interface->SetPerformanceState(Data->Interface,
  560. DesiredState);
  561. //
  562. // Now acquire the lock and reconcile. There's no need to worry about
  563. // two of these calls racing since the change running boolean (which is
  564. // synchronized) prevents that.
  565. //
  566. OldRunLevel = PmpAcquirePerformanceStateLock();
  567. if (!KSUCCESS(Status)) {
  568. RtlDebugPrint("Failed to set p-state on core %d: %x\n", -1, Status);
  569. } else {
  570. Data->CurrentState = DesiredState;
  571. }
  572. //
  573. // Stop looping if the state caught up, or a failure occurred.
  574. //
  575. if ((!KSUCCESS(Status)) || (Data->CurrentState == Data->DesiredState)) {
  576. Data->ChangeRunning = FALSE;
  577. Loop = FALSE;
  578. }
  579. PmpReleasePerformanceStateLock(OldRunLevel);
  580. } while (Loop != FALSE);
  581. return;
  582. }
  583. RUNLEVEL
  584. PmpAcquirePerformanceStateLock (
  585. VOID
  586. )
  587. /*++
  588. Routine Description:
  589. This routine acquires the global performance state lock and raises to
  590. dispatch level.
  591. Arguments:
  592. None.
  593. Return Value:
  594. Returns the original runlevel.
  595. --*/
  596. {
  597. RUNLEVEL OldRunLevel;
  598. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  599. KeAcquireSpinLock(&(PmPstateData->Lock));
  600. return OldRunLevel;
  601. }
  602. VOID
  603. PmpReleasePerformanceStateLock (
  604. RUNLEVEL OldRunLevel
  605. )
  606. /*++
  607. Routine Description:
  608. This routine releases the global performance state lock.
  609. Arguments:
  610. OldRunLevel - Supplies the previous runlevel to return to before the lock
  611. was acquired.
  612. Return Value:
  613. None.
  614. --*/
  615. {
  616. KeReleaseSpinLock(&(PmPstateData->Lock));
  617. KeLowerRunLevel(OldRunLevel);
  618. return;
  619. }