Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1750 lines
44 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. pidle.c
  5. Abstract:
  6. This module implements processor idle functionality
  7. Author:
  8. Ken Reneris (kenr) 17-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. #if DBG
  13. #define IDLE_DEBUG_TABLE_SIZE 400
  14. ULONGLONG ST[IDLE_DEBUG_TABLE_SIZE];
  15. ULONGLONG ET[IDLE_DEBUG_TABLE_SIZE];
  16. ULONGLONG TD[IDLE_DEBUG_TABLE_SIZE];
  17. #endif
  18. VOID
  19. PopPromoteFromIdle0 (
  20. IN PPROCESSOR_POWER_STATE PState,
  21. IN PKTHREAD Thread
  22. );
  23. VOID
  24. FASTCALL
  25. PopDemoteIdleness (
  26. IN PPROCESSOR_POWER_STATE PState,
  27. IN PPOP_IDLE_HANDLER IdleState
  28. );
  29. VOID
  30. FASTCALL
  31. PopPromoteIdleness (
  32. IN PPROCESSOR_POWER_STATE PState,
  33. IN PPOP_IDLE_HANDLER IdleState
  34. );
  35. VOID
  36. FASTCALL
  37. PopIdle0 (
  38. IN PPROCESSOR_POWER_STATE PState
  39. );
  40. VOID
  41. PopConvertUsToPerfCount (
  42. IN OUT PULONG UsTime
  43. );
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text(INIT, PoInitializePrcb)
  46. #pragma alloc_text(PAGE, PopInitProcessorStateHandlers)
  47. #pragma alloc_text(PAGE, PopInitProcessorStateHandlers2)
  48. #endif
  49. #if defined(i386) && !defined(NT_UP)
  50. PPROCESSOR_IDLE_FUNCTION PopIdle0Function = PopIdle0;
  51. VOID
  52. FASTCALL
  53. PopIdle0SMT (
  54. IN PPROCESSOR_POWER_STATE PState
  55. );
  56. //
  57. // PopIdle0Function is a pointer to Idle0 function.
  58. //
  59. #if 0
  60. VOID
  61. (FASTCALL *PopIdle0Function) (
  62. IN PPROCESSOR_POWER_STATE PState
  63. ) = PopIdle0;
  64. #endif
  65. #else
  66. #define PopIdle0Function PopIdle0
  67. #endif
  68. VOID
  69. FASTCALL
  70. PoInitializePrcb (
  71. PKPRCB Prcb
  72. )
  73. /*++
  74. Routine Description:
  75. Initialize PowerState structure within processor's Prcb
  76. before it enters the idle loop
  77. Arguments:
  78. Prcb Prcb for current processor which is initializing
  79. Return Value:
  80. None.
  81. --*/
  82. {
  83. //
  84. // Zero power state structure
  85. //
  86. RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
  87. //
  88. // Initialize to legacy function with promotion from it disabled
  89. //
  90. Prcb->PowerState.Idle0KernelTimeLimit = (ULONG) -1;
  91. Prcb->PowerState.IdleFunction = PopIdle0;
  92. Prcb->PowerState.CurrentThrottle = POP_PERF_SCALE;
  93. //
  94. // Initialize the adaptive throttling subcomponents
  95. //
  96. KeInitializeDpc(
  97. &(Prcb->PowerState.PerfDpc),
  98. PopPerfIdleDpc,
  99. Prcb
  100. );
  101. KeSetTargetProcessorDpc(
  102. &(Prcb->PowerState.PerfDpc),
  103. Prcb->Number
  104. );
  105. KeInitializeTimer(
  106. (PKTIMER) &(Prcb->PowerState.PerfTimer)
  107. );
  108. }
  109. VOID
  110. PopInitProcessorStateHandlers (
  111. IN PPROCESSOR_STATE_HANDLER InputBuffer
  112. )
  113. /*++
  114. Routine Description:
  115. Install processor state handlers. This routine simply translates the old-style
  116. PROCESSOR_STATE_HANDLER structure into a new-style PROCESSOR_STATE_HANDLER2
  117. structure and calls PopInitProcessorStateHandlers2
  118. Arguments:
  119. InputBuffer - Handlers
  120. Return Value:
  121. None.
  122. --*/
  123. {
  124. PPROCESSOR_STATE_HANDLER StateHandler1 = (PPROCESSOR_STATE_HANDLER)InputBuffer;
  125. PPROCESSOR_STATE_HANDLER2 StateHandler2;
  126. UCHAR PerfStates;
  127. ULONG i;
  128. UCHAR Frequency;
  129. //
  130. // Allocate a buffer large enough to hold the larger structure
  131. //
  132. if (StateHandler1->ThrottleScale > 1) {
  133. PerfStates = StateHandler1->ThrottleScale;
  134. } else {
  135. PerfStates = 0;
  136. }
  137. StateHandler2 = ExAllocatePoolWithTag(PagedPool,
  138. sizeof(PROCESSOR_STATE_HANDLER2) +
  139. sizeof(PROCESSOR_PERF_LEVEL) * (PerfStates-1),
  140. 'dHoP');
  141. if (!StateHandler2) {
  142. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  143. }
  144. StateHandler2->NumPerfStates = PerfStates;
  145. //
  146. // Fill in common information
  147. //
  148. StateHandler2->NumIdleHandlers = StateHandler1->NumIdleHandlers;
  149. for (i=0;i<MAX_IDLE_HANDLERS;i++) {
  150. StateHandler2->IdleHandler[i] = StateHandler1->IdleHandler[i];
  151. }
  152. //
  153. // Install our thunk that converts between the old and the new throttling
  154. // interfaces
  155. //
  156. PopRealSetThrottle = StateHandler1->SetThrottle;
  157. PopThunkThrottleScale = StateHandler1->ThrottleScale;
  158. StateHandler2->SetPerfLevel = PopThunkSetThrottle;
  159. StateHandler2->HardwareLatency = 0;
  160. //
  161. // Generate a perf level handler for each throttle step.
  162. //
  163. for (i=0; i<StateHandler2->NumPerfStates;i++) {
  164. Frequency = (UCHAR)((PerfStates-i)*POP_PERF_SCALE/PerfStates);
  165. StateHandler2->PerfLevel[i].PercentFrequency = Frequency;
  166. }
  167. //
  168. // We have built up our table, call off to PopInitProcessorStateHandlers2 for the rest
  169. // of the work. Note that this can raise an exception if there is an error.
  170. //
  171. try {
  172. PopInitProcessorStateHandlers2(StateHandler2);
  173. } finally {
  174. ExFreePool(StateHandler2);
  175. }
  176. }
  177. VOID
  178. PopInitProcessorStateHandlers2 (
  179. IN PPROCESSOR_STATE_HANDLER2 InputBuffer
  180. )
  181. /*++
  182. Routine Description:
  183. Install processor state handlers
  184. Arguments:
  185. InputBuffer - Handlers
  186. Return Value:
  187. None.
  188. --*/
  189. {
  190. PPROCESSOR_STATE_HANDLER2 processorHandler;
  191. ULONG last;
  192. ULONG i;
  193. ULONG j;
  194. ULONG max;
  195. POP_IDLE_HANDLER newIdle[MAX_IDLE_HANDLERS];
  196. POP_IDLE_HANDLER tempIdle[MAX_IDLE_HANDLERS];
  197. NTSTATUS status;
  198. processorHandler = (PPROCESSOR_STATE_HANDLER2) InputBuffer;
  199. //
  200. // Install processor throttle support if present
  201. //
  202. status = PopSetPerfLevels(processorHandler);
  203. if (!NT_SUCCESS(status)) {
  204. ExRaiseStatus(status);
  205. }
  206. //
  207. // If there aren't any idle handlers, then we must deregister the old
  208. // handlers (if any)
  209. //
  210. if ((KeNumberProcessors > 1 && processorHandler->NumIdleHandlers < 1) ||
  211. (KeNumberProcessors == 1 && processorHandler->NumIdleHandlers <= 1)) {
  212. //
  213. // Use NULL and 0 to indicate the number of elements...
  214. //
  215. PopIdleSwitchIdleHandlers( NULL, 0 );
  216. return;
  217. }
  218. //
  219. // Get ready to build a set of idle state handlers
  220. //
  221. RtlZeroMemory(newIdle, sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLERS );
  222. RtlZeroMemory(tempIdle, sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLERS );
  223. //
  224. // We don't support more than 3 handlers ...
  225. //
  226. max = processorHandler->NumIdleHandlers;
  227. if (max > MAX_IDLE_HANDLERS) {
  228. max = MAX_IDLE_HANDLERS;
  229. }
  230. //
  231. // Look at all the handlers provided to us...
  232. //
  233. for (last = i = 0; i < max; i++) {
  234. //
  235. // Ensure they were passed in ascending order
  236. //
  237. j = processorHandler->IdleHandler[i].HardwareLatency;
  238. ASSERT (j >= last && j <= 1000);
  239. last = j;
  240. //
  241. // Fill in some defaults
  242. //
  243. tempIdle[i].State = (UCHAR) i;
  244. tempIdle[i].IdleFunction= processorHandler->IdleHandler[i].Handler;
  245. tempIdle[i].Latency = j;
  246. //
  247. // Convert latency to perf rate scale
  248. //
  249. PopConvertUsToPerfCount(&tempIdle[i].Latency);
  250. }
  251. //
  252. // Apply policy to this set of states
  253. //
  254. status = PopIdleUpdateIdleHandler( newIdle, tempIdle, max );
  255. ASSERT( NT_SUCCESS( status ) );
  256. if (!NT_SUCCESS( status ) ) {
  257. return;
  258. }
  259. //
  260. // Initialize each processors idle info to start idle savings
  261. //
  262. PopIdleSwitchIdleHandlers( newIdle, max );
  263. }
  264. NTSTATUS
  265. PopIdleSwitchIdleHandler(
  266. IN PPOP_IDLE_HANDLER NewHandler,
  267. IN ULONG NumElements
  268. )
  269. /*++
  270. Routine Description:
  271. This routine is responsible for switching the idle handler on the
  272. current processor for the specified new one.
  273. N.B. This function is only callable at DISPATCH_LEVEL
  274. Arguments:
  275. NewHandler - Pointer to new handlers
  276. NumElements - Number of elements in the array
  277. Return Value:
  278. NTSTATUS
  279. --*/
  280. {
  281. PKPRCB prcb;
  282. PKTHREAD thread;
  283. PPROCESSOR_POWER_STATE pState;
  284. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  285. //
  286. // We need to know where the following data structures are
  287. //
  288. prcb = KeGetCurrentPrcb();
  289. pState = &(prcb->PowerState);
  290. thread = prcb->IdleThread;
  291. //
  292. // Update the current IdleHandler and IdleState to reflect what was
  293. // given to us
  294. //
  295. pState->IdleState = NewHandler;
  296. pState->IdleHandlers = NewHandler;
  297. pState->IdleHandlersCount = NumElements;
  298. if ( NewHandler) {
  299. //
  300. // Reset the timers to indicate that there is an idle handler
  301. // available
  302. //
  303. pState->Idle0KernelTimeLimit = thread->KernelTime + PopIdle0PromoteTicks;
  304. pState->Idle0LastTime = thread->KernelTime + thread->UserTime;
  305. pState->PromotionCheck = NewHandler[0].PromoteCount;
  306. } else {
  307. //
  308. // Setting these to Zero should indicate that there are no idle
  309. // handlers available
  310. //
  311. pState->Idle0KernelTimeLimit = (ULONG) -1;
  312. pState->Idle0LastTime = 0;
  313. pState->PromotionCheck = 0;
  314. pState->IdleFunction = PopIdle0Function;
  315. }
  316. #if defined(i386) && !defined(NT_UP)
  317. if (prcb->MultiThreadProcessorSet != prcb->SetMember) {
  318. //
  319. // This processor is a member of a simultaneous
  320. // multi threading processor set. Use the SMT
  321. // version of PopIdle0.
  322. //
  323. PopIdle0Function = PopIdle0SMT;
  324. pState->IdleFunction = PopIdle0SMT;
  325. }
  326. if (PopProcessorPolicy->DisableCStates) {
  327. //
  328. // PERF: We don't any throttling to operate on the machine
  329. //
  330. pState->IdleFunction = PopIdle0Function;
  331. RtlInterlockedSetBits( &(pState->Flags), PSTATE_DISABLE_CSTATES );
  332. } else {
  333. RtlInterlockedClearBits( &(pState->Flags), PSTATE_DISABLE_CSTATES );
  334. }
  335. #endif
  336. //
  337. // Success
  338. //
  339. return STATUS_SUCCESS;
  340. }
  341. NTSTATUS
  342. PopIdleSwitchIdleHandlers(
  343. IN PPOP_IDLE_HANDLER NewHandler,
  344. IN ULONG NumElements
  345. )
  346. /*++
  347. Routine Description:
  348. This routine is responsible for swapping each processor's idle handler
  349. routine for a new one....
  350. Arguments:
  351. NewHandler - Pointer to the array of new handlers
  352. NumElements - Number of elements in the array
  353. Return Value:
  354. STATUS_SUCCESS
  355. STATUS_INSUFICCIENT_RESOURCES
  356. --*/
  357. {
  358. KAFFINITY currentAffinity;
  359. KAFFINITY processors;
  360. KIRQL oldIrql;
  361. NTSTATUS status = STATUS_SUCCESS;
  362. PPOP_IDLE_HANDLER tempHandler = NULL;
  363. ASSERT( NumElements <= MAX_IDLE_HANDLER );
  364. if (NewHandler) {
  365. //
  366. // Step 1. Allocate a new set of handlers to hold the copy that we
  367. // will need to keep around
  368. //
  369. tempHandler = ExAllocateFromNPagedLookasideList(
  370. &PopIdleHandlerLookAsideList
  371. );
  372. if (tempHandler == NULL) {
  373. status = STATUS_INSUFFICIENT_RESOURCES;
  374. return status;
  375. }
  376. //
  377. // Step 2. Make sure that this new handler is in a consistent state,
  378. // and copy the buffer that was passed to us
  379. //
  380. RtlZeroMemory(
  381. tempHandler,
  382. sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLER
  383. );
  384. RtlCopyMemory(
  385. tempHandler,
  386. NewHandler,
  387. sizeof(POP_IDLE_HANDLER) * NumElements
  388. );
  389. } else {
  390. tempHandler = NULL;
  391. }
  392. //
  393. // Step 3. Iterate over the processors
  394. //
  395. currentAffinity = 1;
  396. processors = KeActiveProcessors;
  397. while (processors) {
  398. if (!(currentAffinity & processors)) {
  399. currentAffinity <<= 1;
  400. continue;
  401. }
  402. KeSetSystemAffinityThread( currentAffinity );
  403. processors &= ~currentAffinity;
  404. currentAffinity <<= 1;
  405. //
  406. // Step 4. Swap out old handler. Indicate that we want to free it
  407. //
  408. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  409. PopIdleSwitchIdleHandler( tempHandler, NumElements );
  410. KeLowerIrql(oldIrql);
  411. }
  412. //
  413. // Step 5. At this point, all of the processors should have been updated
  414. // and we are still running on the "last" processor in the machine. This
  415. // is a good point to update PopIdle to point to the new value. Note that
  416. // PopIdle isn't actually used for any else than storing a pointer to
  417. // the handler, but if there was something there already, then it should
  418. // be freed
  419. //
  420. if (PopIdle != NULL) {
  421. ExFreeToNPagedLookasideList(
  422. &PopIdleHandlerLookAsideList,
  423. PopIdle
  424. );
  425. }
  426. PopIdle = tempHandler;
  427. //
  428. // Step 6. At this point, its safe to return to the original processor
  429. // and to back to the previous IRQL...
  430. //
  431. KeRevertToUserAffinityThread();
  432. //
  433. // Done
  434. //
  435. return status;
  436. }
  437. NTSTATUS
  438. PopIdleUpdateIdleHandler(
  439. IN PPOP_IDLE_HANDLER NewHandler,
  440. IN PPOP_IDLE_HANDLER OldHandler,
  441. IN ULONG NumElements
  442. )
  443. /*++
  444. Routine Description:
  445. This routine takes the information stored in OldHandler (such as latency,
  446. and IdleFunction) and uses that to build the new idle handlers...
  447. Arguements:
  448. NewHandler - pointer to the new idle handlers
  449. OldHandler - pointer to the old idle handlers
  450. NumElements - number of elements in the old idle handlers
  451. Return Value:
  452. NTSTATUS
  453. --*/
  454. {
  455. NTSTATUS status;
  456. ULONG i;
  457. ULONG max;
  458. ULONG realMax;
  459. //
  460. // We don't support more than 3 handlers ...
  461. //
  462. realMax = max = NumElements;
  463. if (max > MAX_IDLE_HANDLERS) {
  464. realMax = max = MAX_IDLE_HANDLERS;
  465. }
  466. //
  467. // Cap the max based upon what the policy supports
  468. //
  469. if (max > PopProcessorPolicy->PolicyCount) {
  470. max = PopProcessorPolicy->PolicyCount;
  471. }
  472. //
  473. // Update the temp handler with the new policy
  474. //
  475. for (i = 0; i < max; i++) {
  476. NewHandler[i].State = (UCHAR) i;
  477. NewHandler[i].Latency = OldHandler[i].Latency;
  478. NewHandler[i].IdleFunction = OldHandler[i].IdleFunction;
  479. NewHandler[i].TimeCheck = PopProcessorPolicy->Policy[i].TimeCheck;
  480. NewHandler[i].PromoteLimit = PopProcessorPolicy->Policy[i].PromoteLimit;
  481. NewHandler[i].PromotePercent= PopProcessorPolicy->Policy[i].PromotePercent;
  482. NewHandler[i].DemoteLimit = PopProcessorPolicy->Policy[i].DemoteLimit;
  483. NewHandler[i].DemotePercent = PopProcessorPolicy->Policy[i].DemotePercent;
  484. //
  485. // Convert all the time units to the correct units
  486. //
  487. PopConvertUsToPerfCount(&NewHandler[i].TimeCheck);
  488. PopConvertUsToPerfCount(&NewHandler[i].DemoteLimit);
  489. PopConvertUsToPerfCount(&NewHandler[i].PromoteLimit);
  490. //
  491. // Fill in the table that allows for promotion / demotion
  492. //
  493. if (PopProcessorPolicy->Policy[i].AllowDemotion) {
  494. NewHandler[i].Demote = (UCHAR) i-1;
  495. } else {
  496. NewHandler[i].Demote = (UCHAR) i;
  497. }
  498. if (PopProcessorPolicy->Policy[i].AllowPromotion) {
  499. NewHandler[i].Promote = (UCHAR) i+1;
  500. } else {
  501. NewHandler[i].Promote = (UCHAR) i;
  502. }
  503. }
  504. //
  505. // Make sure that the boundary cases are well respected...
  506. //
  507. NewHandler[0].Demote = 0;
  508. NewHandler[(max-1)].Promote = (UCHAR) (max-1);
  509. //
  510. // We let PopVerifyHandler fill in all the details associated with
  511. // the fact that we don't want to allow demotion/promotion from these
  512. // states
  513. //
  514. NewHandler[0].DemotePercent = 0;
  515. NewHandler[(max-1)].PromotePercent = 0;
  516. //
  517. // Handle the states that we don't have a policy handler in place for
  518. //
  519. for (; i < realMax; i++) {
  520. //
  521. // The only pieces of data that we really need are the latency and the
  522. // idle handler function
  523. //
  524. NewHandler[i].State = (UCHAR) i;
  525. NewHandler[i].Latency = OldHandler[i].Latency;
  526. NewHandler[i].IdleFunction = OldHandler[i].IdleFunction;
  527. }
  528. //
  529. // Sanity check the new handler
  530. //
  531. status = PopIdleVerifyIdleHandlers( NewHandler, max );
  532. ASSERT( NT_SUCCESS( status ) );
  533. return status;
  534. }
  535. NTSTATUS
  536. PopIdleUpdateIdleHandlers(
  537. VOID
  538. )
  539. /*++
  540. Routine Description:
  541. This routine is called to update the idle handlers when the state of the
  542. machine warrants a possible change in policy
  543. Arguments:
  544. None
  545. Return Value:
  546. NTSTATUS
  547. --*/
  548. {
  549. BOOLEAN foundProcessor = FALSE;
  550. KAFFINITY currentAffinity;
  551. KAFFINITY processors;
  552. KIRQL oldIrql;
  553. NTSTATUS status = STATUS_SUCCESS;
  554. PKPRCB prcb;
  555. PPOP_IDLE_HANDLER tempHandler = NULL;
  556. PPROCESSOR_POWER_STATE pState;
  557. ULONG numElements = 0;
  558. //
  559. // Step 1. Allocate a new set of handlers to hold the copy that we
  560. // will need to keep around
  561. //
  562. tempHandler = ExAllocateFromNPagedLookasideList(
  563. &PopIdleHandlerLookAsideList
  564. );
  565. if (tempHandler == NULL) {
  566. return STATUS_INSUFFICIENT_RESOURCES;
  567. }
  568. RtlZeroMemory(
  569. tempHandler,
  570. sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLER
  571. );
  572. //
  573. // Step 2. Iterate over the processors
  574. //
  575. currentAffinity = 1;
  576. processors = KeActiveProcessors;
  577. while (processors) {
  578. if (!(currentAffinity & processors)) {
  579. currentAffinity <<= 1;
  580. continue;
  581. }
  582. KeSetSystemAffinityThread( currentAffinity );
  583. processors &= ~currentAffinity;
  584. currentAffinity <<= 1;
  585. //
  586. // Can't look at the processors without being at DPC level
  587. //
  588. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  589. //
  590. // We need to find a template to get the processor info from
  591. //
  592. if (!foundProcessor) {
  593. //
  594. // Step 3. If we haven't already found a processor so that we
  595. // create a new idle handler, then do so now. Note that it is
  596. // possible that this processor has no mask, in which case we
  597. // should clean up and return.
  598. //
  599. // N.B. That it is still safe to return at this point since
  600. // we haven't touch a single processor's data structures, so
  601. // we are in no danger of corrupting something...
  602. //
  603. prcb = KeGetCurrentPrcb();
  604. pState = &(prcb->PowerState);
  605. if (pState->IdleHandlers == NULL) {
  606. //
  607. // No idle handlers to update
  608. //
  609. ExFreeToNPagedLookasideList(
  610. &PopIdleHandlerLookAsideList,
  611. tempHandler
  612. );
  613. KeLowerIrql( oldIrql );
  614. KeRevertToUserAffinityThread();
  615. return STATUS_SUCCESS;
  616. }
  617. numElements = pState->IdleHandlersCount;
  618. //
  619. // Update the temp handler with the new policy
  620. //
  621. status = PopIdleUpdateIdleHandler(
  622. tempHandler,
  623. pState->IdleHandlers,
  624. numElements
  625. );
  626. ASSERT( NT_SUCCESS( status ) );
  627. if (!NT_SUCCESS( status ) ) {
  628. //
  629. // No idle handlers to update
  630. //
  631. ExFreeToNPagedLookasideList(
  632. &PopIdleHandlerLookAsideList,
  633. tempHandler
  634. );
  635. KeLowerIrql( oldIrql );
  636. KeRevertToUserAffinityThread();
  637. return status;
  638. }
  639. //
  640. // Remember that we have found the processor information
  641. //
  642. foundProcessor = TRUE;
  643. }
  644. //
  645. // Step 4. Swap out old handler. Indicate that we want to free it
  646. //
  647. PopIdleSwitchIdleHandler( tempHandler, numElements );
  648. //
  649. // Revert back to original irql
  650. //
  651. KeLowerIrql(oldIrql);
  652. }
  653. //
  654. // Step 5. At this point, all of the processors should have been updated
  655. // and we are still running on the "last" processor in the machine. This
  656. // is a good point to update PopIdle to point to the new value. Note that
  657. // PopIdle isn't actually used for any else than storing a pointer to
  658. // the handler, but if there was something there already, then it should
  659. // be freed
  660. //
  661. if (PopIdle != NULL) {
  662. ExFreeToNPagedLookasideList(
  663. &PopIdleHandlerLookAsideList,
  664. PopIdle
  665. );
  666. }
  667. PopIdle = tempHandler;
  668. //
  669. // Step 6. At this point, its safe to return to the original processor.
  670. //
  671. KeRevertToUserAffinityThread();
  672. //
  673. // Done
  674. //
  675. return status;
  676. }
  677. NTSTATUS
  678. PopIdleVerifyIdleHandlers(
  679. IN PPOP_IDLE_HANDLER NewHandler,
  680. IN ULONG NumElements
  681. )
  682. /*++
  683. Routine Description:
  684. This routine is called to sanity check a set of idle handlers. It will
  685. correct the errors (if it can) or return a failure code (if it cannot)
  686. Arguments:
  687. NewHandler - Array of Handlers
  688. NumElements - Number of Elements in the Array to actually verify. This
  689. may be smaller than the actual number of elements in the
  690. array
  691. Return Value:
  692. NTSTATUS
  693. --*/
  694. {
  695. ULONG i;
  696. //
  697. // Sanity Check
  698. //
  699. ASSERT( NewHandler != NULL );
  700. ASSERT( NumElements );
  701. //
  702. // Sanity check rules of multi-processors. We don't allow demotion from
  703. // Idle0 unless the machine is MP
  704. //
  705. if (KeNumberProcessors == 1 && NewHandler[0].DemotePercent != 0) {
  706. NewHandler[0].DemotePercent = 0;
  707. }
  708. //
  709. // first state.Demote must always be zero.
  710. //
  711. NewHandler[0].Demote = 0;
  712. //
  713. // Sanity check idle values. These numbers are stored in the policy
  714. // as MicroSeconds, we need to take the opportunity to convert them to
  715. // PerfCount units...
  716. //
  717. for (i = 0; i < NumElements; i++) {
  718. //
  719. // =============================
  720. // TimeCheck
  721. //
  722. // Time, in microseconds, that must expire before promotion or
  723. // demotion is considered.
  724. //
  725. // - Must be larger than DemoteLimit.
  726. // - If there's a DemotePercent, then we will use PromoteLimit
  727. // to move the process into a more active state. If that's the
  728. // case, then TimeCheck needs to be >= PromoteLimit.
  729. // =============================
  730. //
  731. if (NewHandler[i].TimeCheck < NewHandler[i].DemoteLimit) {
  732. NewHandler[i].TimeCheck = NewHandler[i].DemoteLimit;
  733. }
  734. if( (NewHandler[i].DemotePercent == 0) &&
  735. (NewHandler[i].TimeCheck < NewHandler[i].PromoteLimit) ) {
  736. NewHandler[i].TimeCheck = NewHandler[i].PromoteLimit;
  737. }
  738. //
  739. // =============================
  740. // DemotePercent and PromotePercent
  741. //
  742. // Value, expressed as a percentage, that scales the threshold at
  743. // which the power policy manager decreases/increases the performance
  744. // of the processor.
  745. //
  746. // - He needs to be <= 100
  747. // =============================
  748. //
  749. if( NewHandler[i].DemotePercent > 100 ) {
  750. NewHandler[i].DemotePercent = 100;
  751. }
  752. if( NewHandler[i].PromotePercent > 100 ) {
  753. NewHandler[i].PromotePercent = 100;
  754. }
  755. //
  756. // =============================
  757. // DemoteLimit
  758. //
  759. // Minimum amount of time, in microseconds, that must be spent in the
  760. // idle loop to avoid demotion.
  761. //
  762. // - This needs to be some percentage of TimeCheck. If the processor
  763. // is running slow, then we need to reduce TimeCheck by the same
  764. // percentage. In other words, 1000us in the idle loop on a 500MHz
  765. // processor is similar to 833us in the idle loop on a 600MHz processor.
  766. // NOTE: It's possible that DemotePercent is 0, in which case we want
  767. // to end up with DemoteLimit also set to zero.
  768. // =============================
  769. //
  770. NewHandler[i].DemoteLimit = (NewHandler[i].TimeCheck * NewHandler[i].DemotePercent) / 100;
  771. //
  772. // =============================
  773. // PromoteCount
  774. //
  775. // Number of TimeCheck intervals in PromoteLimit.
  776. //
  777. // - This makes no sense if TimeCheck is zero though. In that case,
  778. // PromoteCount and PromoteLimit should be disabled by setting
  779. // them to -1.
  780. // =============================
  781. //
  782. //
  783. // Compute promote count as # of time checks
  784. //
  785. if( NewHandler[i].TimeCheck ) {
  786. NewHandler[i].PromoteCount = NewHandler[i].PromoteLimit / NewHandler[i].TimeCheck;
  787. } else {
  788. //
  789. // Set PromotePercent to zero so that we'll fall into the 'else'
  790. // block below and nuke PomoteCount and PromoteLimit.
  791. NewHandler[i].PromotePercent = 0;
  792. }
  793. //
  794. // =============================
  795. // PromoteLimit
  796. //
  797. // Time, in microseconds, that must be exceeded to cause promotion to a deeper
  798. // idle state..
  799. //
  800. // - This needs to be scaled down by PromotePercent.
  801. //
  802. // NOTE: If PromotePercent is zero, then this is sort of non-sensical
  803. // and we're going to disable PromoteCount and PromoteLimit by
  804. // setting them to -1.
  805. // =============================
  806. //
  807. if (NewHandler[i].PromotePercent) {
  808. NewHandler[i].PromoteLimit = (NewHandler[i].PromoteLimit * NewHandler[i].PromotePercent) / 100;
  809. } else {
  810. NewHandler[i].PromoteCount = (ULONG) -1;
  811. NewHandler[i].PromoteLimit = (ULONG) -1;
  812. }
  813. }
  814. //
  815. // Sanity check the last state
  816. //
  817. i = NumElements - 1;
  818. NewHandler[i].Promote = (UCHAR) i;
  819. NewHandler[i].PromoteLimit = (ULONG) -1;
  820. NewHandler[i].PromotePercent = 0;
  821. //
  822. // We are happy with this policy...
  823. //
  824. return STATUS_SUCCESS;
  825. }
  826. VOID
  827. PopConvertUsToPerfCount (
  828. IN OUT PULONG UsTime
  829. )
  830. {
  831. LARGE_INTEGER li;
  832. LONGLONG temp;
  833. if (*UsTime) {
  834. //
  835. // Try to avoid Divide by Zero Errors...
  836. //
  837. temp = (US2SEC * MAXSECCHECK * 100L) / *UsTime;
  838. if (!temp) {
  839. *UsTime = (ULONG) -1;
  840. return;
  841. }
  842. //
  843. // Get scale of idle times
  844. //
  845. KeQueryPerformanceCounter (&li);
  846. li.QuadPart = (li.QuadPart*MAXSECCHECK*100L) / temp;
  847. ASSERT (li.HighPart == 0);
  848. *UsTime = li.LowPart;
  849. }
  850. }
  851. //
  852. // ----------------
  853. //
  854. VOID
  855. FASTCALL
  856. PopIdle0 (
  857. IN PPROCESSOR_POWER_STATE PState
  858. )
  859. /*++
  860. Routine Description:
  861. No idle optmiziations.
  862. N.B. This function is called with interrupts disabled from the idle loop
  863. Arguments:
  864. PState - Current processors power state structure
  865. Return Value:
  866. None.
  867. --*/
  868. {
  869. PKTHREAD Thread = KeGetCurrentThread();
  870. //
  871. // Performance Throttling Check
  872. //
  873. //
  874. // This piece of code really belongs in the functions that will eventually
  875. // call this one, PopIdle0 or PopProcessorIdle, to save a function call.
  876. //
  877. if ( (PState->Flags & PSTATE_ADAPTIVE_THROTTLE) &&
  878. !(PState->Flags & PSTATE_DISABLE_THROTTLE) ) {
  879. PopPerfIdle( PState );
  880. }
  881. //
  882. // If the idle thread's kernel time has exceeded the target idle time, then
  883. // check for possible promotion from Idle0
  884. //
  885. if (Thread->KernelTime > PState->Idle0KernelTimeLimit &&
  886. !(PState->Flags & PSTATE_DISABLE_CSTATES) ) {
  887. //
  888. // Must enable interrupts prior to calling PopPromoteFromIdle
  889. // to avoid spinning on system locks with interrupts disabled.
  890. //
  891. _enable();
  892. PopPromoteFromIdle0 (PState, Thread);
  893. return ;
  894. }
  895. #if defined(NT_UP)
  896. // use legacy function
  897. HalProcessorIdle ();
  898. #endif
  899. }
  900. #if defined(i386) && !defined(NT_UP)
  901. VOID
  902. FASTCALL
  903. PopIdle0SMT (
  904. IN PPROCESSOR_POWER_STATE PState
  905. )
  906. /*++
  907. Routine Description:
  908. No idle optmiziations.
  909. N.B. This function is called with interrupts disabled from the idle loop
  910. Arguments:
  911. PState - Current processors power state structure
  912. Return Value:
  913. None.
  914. --*/
  915. {
  916. PKTHREAD Thread = KeGetCurrentThread();
  917. PKPRCB Prcb = KeGetCurrentPrcb();
  918. //
  919. // Performance Throttling Check
  920. //
  921. //
  922. // This piece of code really belongs in the functions that will eventually
  923. // call this one, PopIdle0 or PopProcessorIdle, to save a function call.
  924. //
  925. if ( (PState->Flags & PSTATE_ADAPTIVE_THROTTLE) &&
  926. !(PState->Flags & PSTATE_DISABLE_THROTTLE) ) {
  927. PopPerfIdle( PState );
  928. }
  929. //
  930. // If this is a Simultaneous Multi Threading processor and other
  931. // processors in this set are NOT idle, promote this processor
  932. // immediately OR if the idle thread's kernel time has exceeded
  933. // the target idle time, then check for possible promotion from Idle0.
  934. //
  935. if ((KeIsSMTSetIdle(Prcb) == FALSE) ||
  936. (Thread->KernelTime > PState->Idle0KernelTimeLimit)) {
  937. //
  938. // Must enable interrupts prior to calling PopPromoteFromIdle
  939. // to avoid spinning on system locks with interrupts disabled.
  940. //
  941. _enable();
  942. PopPromoteFromIdle0 (PState, Thread);
  943. return ;
  944. }
  945. }
  946. #endif
  947. VOID
  948. FASTCALL
  949. PopProcessorIdle (
  950. IN PPROCESSOR_POWER_STATE PState
  951. )
  952. /*++
  953. Routine Description:
  954. For now this function is coded in C
  955. N.B. This function is called with interrupts disabled from the idle loop
  956. Arguments:
  957. PState - Current processors power state structure
  958. Return Value:
  959. None.
  960. --*/
  961. {
  962. PPOP_IDLE_HANDLER IdleState;
  963. LARGE_INTEGER Delta;
  964. ULONG IdleTime;
  965. BOOLEAN DemoteNow;
  966. IdleState = (PPOP_IDLE_HANDLER) PState->IdleState;
  967. //
  968. // Performance Throttling Check
  969. //
  970. //
  971. // This piece of code really belongs in the functions that will eventually
  972. // call this one, PopIdle0 or PopProcessorIdle, to save a function call.
  973. //
  974. if ( (PState->Flags & PSTATE_ADAPTIVE_THROTTLE) &&
  975. !(PState->Flags & PSTATE_DISABLE_THROTTLE) ) {
  976. PopPerfIdle( PState );
  977. }
  978. #if DBG
  979. if (!PState->LastCheck) {
  980. IdleState->IdleFunction (&PState->IdleTimes);
  981. PState->TotalIdleStateTime[IdleState->State] += (ULONG)(PState->IdleTimes.EndTime - PState->IdleTimes.StartTime);
  982. PState->TotalIdleTransitions[IdleState->State] += 1;
  983. PState->LastCheck = PState->IdleTimes.EndTime;
  984. PState->IdleTime1 = 0;
  985. PState->IdleTime2 = 0;
  986. PState->PromotionCheck = IdleState->PromoteCount;
  987. PState->DebugCount = 0;
  988. return ;
  989. }
  990. #endif
  991. //
  992. // Determine how long since last check
  993. //
  994. Delta.QuadPart = PState->IdleTimes.EndTime - PState->LastCheck;
  995. //
  996. // Accumulate last idle time
  997. //
  998. IdleTime = (ULONG) (PState->IdleTimes.EndTime - PState->IdleTimes.StartTime);
  999. if (IdleTime > IdleState->Latency) {
  1000. PState->IdleTime1 += IdleTime - IdleState->Latency;
  1001. }
  1002. #if DBG
  1003. PState->DebugDelta = Delta.QuadPart;
  1004. PState->DebugCount += 1;
  1005. if (PState->DebugCount < IDLE_DEBUG_TABLE_SIZE) {
  1006. ST[PState->DebugCount] = PState->IdleTimes.StartTime;
  1007. ET[PState->DebugCount] = PState->IdleTimes.EndTime;
  1008. TD[PState->DebugCount] = PState->IdleTimes.EndTime - PState->IdleTimes.StartTime;
  1009. }
  1010. #endif
  1011. //
  1012. // If over check interval, check fine grain idleness
  1013. //
  1014. if (Delta.HighPart || Delta.LowPart > IdleState->TimeCheck) {
  1015. PState->LastCheck = PState->IdleTimes.EndTime;
  1016. //
  1017. // Demote idleness?
  1018. //
  1019. if (PState->IdleTime1 < IdleState->DemoteLimit) {
  1020. #if defined(i386) && !defined(NT_UP)
  1021. //
  1022. // Don't demote if this is an SMT processor and any other
  1023. // member of the SMT set is not idle.
  1024. //
  1025. PKPRCB Prcb = KeGetCurrentPrcb();
  1026. if ((KeIsSMTSetIdle(Prcb) == FALSE) &&
  1027. (Prcb->SetMember != Prcb->MultiThreadProcessorSet)) {
  1028. PState->IdleTime1 = 0;
  1029. return;
  1030. }
  1031. #endif
  1032. PopDemoteIdleness (PState, IdleState);
  1033. #if DBG
  1034. PState->DebugCount = 0;
  1035. #endif
  1036. return ;
  1037. }
  1038. #if DBG
  1039. PState->DebugCount = 0;
  1040. #endif
  1041. //
  1042. // Clear demotion idle time check, and accumulate stat for promotion check
  1043. //
  1044. PState->IdleTime2 += PState->IdleTime1;
  1045. PState->IdleTime1 = 0;
  1046. //
  1047. // Time to check for promotion?
  1048. //
  1049. PState->PromotionCheck -= 1;
  1050. if (!PState->PromotionCheck) {
  1051. //
  1052. // Promote idleness?
  1053. //
  1054. if (PState->IdleTime2 > IdleState->PromoteLimit) {
  1055. PopPromoteIdleness (PState, IdleState);
  1056. return;
  1057. }
  1058. PState->PromotionCheck = IdleState->PromoteCount;
  1059. PState->IdleTime2 = 0;
  1060. }
  1061. }
  1062. //
  1063. // Call system specific power handler handler
  1064. //
  1065. DemoteNow = IdleState->IdleFunction (&PState->IdleTimes);
  1066. //
  1067. // If the handler returns TRUE, then the demote to less power savings state
  1068. //
  1069. if (DemoteNow) {
  1070. PopDemoteIdleness (PState, IdleState);
  1071. #if DBG
  1072. PState->DebugCount = 0;
  1073. #endif
  1074. } else {
  1075. PState->TotalIdleStateTime[IdleState->State] += PState->IdleTimes.EndTime - PState->IdleTimes.StartTime;
  1076. PState->TotalIdleTransitions[IdleState->State] += 1;
  1077. }
  1078. }
  1079. VOID
  1080. FASTCALL
  1081. PopDemoteIdleness (
  1082. IN PPROCESSOR_POWER_STATE PState,
  1083. IN PPOP_IDLE_HANDLER IdleState
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. Processor is not idle enough. Use a less agressive idle handler (or
  1088. increase processors throttle control).
  1089. Arguments:
  1090. PState - Current processors power state structure
  1091. IdleState - Current idle state for the current processor
  1092. Return Value:
  1093. None.
  1094. --*/
  1095. {
  1096. #if !defined(NT_UP)
  1097. PKPRCB Prcb;
  1098. PKTHREAD Thread;
  1099. #endif
  1100. PPOP_IDLE_HANDLER Idle;
  1101. //
  1102. // Clear idleness for next check
  1103. //
  1104. PState->IdleTime1 = 0;
  1105. PState->IdleTime2 = 0;
  1106. PERFINFO_POWER_IDLE_STATE_CHANGE( PState, -1 );
  1107. #if !defined(NT_UP)
  1108. //
  1109. // If this is a demotion to the non-blocking idle handler then
  1110. // clear this processors bit in the PoSleepingSummary
  1111. //
  1112. if ((PState->Flags & PSTATE_DISABLE_THROTTLE) ||
  1113. IdleState->Demote == PO_IDLE_COMPLETE_DEMOTION) {
  1114. Prcb = CONTAINING_RECORD (PState, KPRCB, PowerState);
  1115. InterlockedAndAffinity ((PLONG_PTR)&PoSleepingSummary, ~Prcb->SetMember);
  1116. Thread = Prcb->IdleThread;
  1117. PState->Idle0KernelTimeLimit = Thread->KernelTime + PopIdle0PromoteTicks;
  1118. PState->Idle0LastTime = Prcb->KernelTime + Prcb->UserTime;
  1119. PState->IdleFunction = PopIdle0Function;
  1120. return ;
  1121. }
  1122. #endif
  1123. //
  1124. // Demote to next idle state
  1125. //
  1126. Idle = PState->IdleHandlers;
  1127. PState->PromotionCheck = Idle[IdleState->Demote].PromoteCount;
  1128. PState->IdleState = (PVOID) &Idle[IdleState->Demote];
  1129. }
  1130. VOID
  1131. PopPromoteFromIdle0 (
  1132. IN PPROCESSOR_POWER_STATE PState,
  1133. IN PKTHREAD Thread
  1134. )
  1135. /*++
  1136. Routine Description:
  1137. Processor is using Idle0 and the required idle time has elasped.
  1138. Check idle precentage to see if a promotion out of Idle0 should occur.
  1139. Arguments:
  1140. PState - Current processors power state structure
  1141. Thread - Idle thread for the current processor
  1142. Return Value:
  1143. None.
  1144. --*/
  1145. {
  1146. ULONG etime;
  1147. PKPRCB Prcb;
  1148. PPOP_IDLE_HANDLER Idle;
  1149. //
  1150. // Compute elapsed system time
  1151. //
  1152. Prcb = CONTAINING_RECORD (PState, KPRCB, PowerState);
  1153. etime = Prcb->UserTime + Prcb->KernelTime - PState->Idle0LastTime;
  1154. Idle = PState->IdleHandlers;
  1155. //
  1156. // Has the processor been idle enough to promote?
  1157. //
  1158. if (etime < PopIdle0PromoteLimit) {
  1159. KEVENT DummyEvent;
  1160. //
  1161. // Promote to the first real idle handler
  1162. //
  1163. PERFINFO_POWER_IDLE_STATE_CHANGE( PState, 0 );
  1164. PState->IdleTime1 = 0;
  1165. PState->IdleTime2 = 0;
  1166. PState->PromotionCheck = Idle[0].PromoteCount;
  1167. PState->IdleState = Idle;
  1168. PState->IdleFunction = PopProcessorIdle;
  1169. PState->LastCheck = KeQueryPerformanceCounter(NULL).QuadPart;
  1170. PState->IdleTimes.StartTime = PState->LastCheck;
  1171. PState->IdleTimes.EndTime = PState->LastCheck;
  1172. InterlockedOrAffinity ((PLONG_PTR)&PoSleepingSummary, Prcb->SetMember);
  1173. //
  1174. // Once SleepingSummary is set, make sure no one is in the
  1175. // middle of a context switch by aquiring & releasing the
  1176. // dispatcher database lock
  1177. //
  1178. KeInitializeEvent(&DummyEvent, SynchronizationEvent, TRUE);
  1179. KeResetEvent (&DummyEvent);
  1180. return ;
  1181. }
  1182. //
  1183. // Set for next compare
  1184. //
  1185. PState->Idle0KernelTimeLimit = Thread->KernelTime + PopIdle0PromoteTicks;
  1186. PState->Idle0LastTime = Prcb->UserTime + Prcb->KernelTime;
  1187. }
  1188. VOID
  1189. FASTCALL
  1190. PopPromoteIdleness (
  1191. IN PPROCESSOR_POWER_STATE PState,
  1192. IN PPOP_IDLE_HANDLER IdleState
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. Processor is idle enough to be promoted to the next idle handler.
  1197. If the processor is already at its max idle handler, check to
  1198. see if the processors throttle control can be reduced. If any
  1199. processor is not running at it's best speed, a timer is used to
  1200. watch for some changes from idle to busy.
  1201. Arguments:
  1202. PState - Current processors power state structure
  1203. IdleState - Current idle state for the current processor
  1204. Return Value:
  1205. None.
  1206. --*/
  1207. {
  1208. PPOP_IDLE_HANDLER Idle;
  1209. //
  1210. // Clear idleness for next check
  1211. //
  1212. PState->IdleTime2 = 0;
  1213. PERFINFO_POWER_IDLE_STATE_CHANGE( PState, 1 );
  1214. //
  1215. // If already fully promoted, then nothing more to do.
  1216. //
  1217. if (IdleState->Promote == PO_IDLE_THROTTLE_PROMOTION) {
  1218. PState->PromotionCheck = IdleState->PromoteCount;
  1219. return;
  1220. }
  1221. //
  1222. // Promote to next idle state
  1223. //
  1224. Idle = PState->IdleHandlers;
  1225. PState->PromotionCheck = Idle[IdleState->Promote].PromoteCount;
  1226. PState->IdleState = (PVOID) &Idle[IdleState->Promote];
  1227. }
  1228. VOID
  1229. PopProcessorInformation (
  1230. OUT PPROCESSOR_POWER_INFORMATION ProcInfo,
  1231. IN ULONG ProcInfoLength,
  1232. OUT PULONG ReturnBufferLength
  1233. )
  1234. {
  1235. KAFFINITY Summary;
  1236. KAFFINITY Mask;
  1237. KIRQL OldIrql;
  1238. PPOP_IDLE_HANDLER IdleState;
  1239. PKPRCB Prcb;
  1240. PPROCESSOR_POWER_STATE PState;
  1241. PROCESSOR_POWER_INFORMATION TempInfo;
  1242. ULONG Processor;
  1243. ULONG MaxMhz;
  1244. ULONG BufferSize = 0;
  1245. ULONG MaxIdleState = 0;
  1246. ULONG i;
  1247. ULONG j;
  1248. //
  1249. // The best way to grab the state of the idle handlers is to raise to
  1250. // DISPATCH_LEVEL, grab the current PRCB and look at the handler there.
  1251. // The alternative is to find the last processor, switch to it, and then
  1252. // look at the PopIdle global. As an FYI, we cannot just arbitrarily
  1253. // look at it since the code that updates it might have already run past
  1254. // *this* processor...
  1255. //
  1256. KeRaiseIrql( DISPATCH_LEVEL, &OldIrql );
  1257. Prcb = KeGetCurrentPrcb();
  1258. PState = &(Prcb->PowerState);
  1259. IdleState = PState->IdleHandlers;
  1260. if (IdleState) {
  1261. for (i = 0, MaxIdleState = 1; ;) {
  1262. j = IdleState[i].Promote;
  1263. if (j == 0 || j == i || j == PO_IDLE_THROTTLE_PROMOTION) {
  1264. break;
  1265. }
  1266. i = j;
  1267. MaxIdleState += 1;
  1268. }
  1269. }
  1270. KeLowerIrql( OldIrql );
  1271. Summary = KeActiveProcessors;
  1272. Processor = 0;
  1273. Mask = 1;
  1274. while (Summary) {
  1275. if (!(Mask & Summary)) {
  1276. Mask <<= 1;
  1277. continue;
  1278. }
  1279. if (ProcInfoLength < BufferSize + sizeof(PROCESSOR_POWER_INFORMATION)) {
  1280. break;
  1281. }
  1282. //
  1283. // Run in the context of the target processor
  1284. //
  1285. KeSetSystemAffinityThread( Mask );
  1286. Summary &= ~Mask;
  1287. Mask <<= 1;
  1288. //
  1289. // Lets play safe
  1290. //
  1291. KeRaiseIrql( DISPATCH_LEVEL, &OldIrql );
  1292. //
  1293. // Get the current PState block...
  1294. //
  1295. Prcb = KeGetCurrentPrcb();
  1296. PState = &Prcb->PowerState;
  1297. MaxMhz = Prcb->MHz;
  1298. TempInfo.Number = Processor;
  1299. TempInfo.MaxMhz = MaxMhz;
  1300. TempInfo.CurrentMhz = (MaxMhz * PState->CurrentThrottle) / POP_PERF_SCALE;
  1301. TempInfo.MhzLimit = (MaxMhz * PState->ThermalThrottleLimit) / POP_PERF_SCALE;
  1302. //
  1303. // In theory, we could recalculate this number here, but I'm not sure
  1304. // that there is a benefit to doing that
  1305. //
  1306. TempInfo.MaxIdleState = MaxIdleState;
  1307. //
  1308. // Determine what the current Idle state is...
  1309. //
  1310. TempInfo.CurrentIdleState = 0;
  1311. if (PState->IdleFunction != PopIdle0Function) {
  1312. IdleState = PState->IdleState;
  1313. if (IdleState != NULL) {
  1314. TempInfo.CurrentIdleState = IdleState->State;
  1315. }
  1316. }
  1317. //
  1318. // At this point, we have captured the info that we need and can safely
  1319. // drop back to a lower irql
  1320. //
  1321. KeLowerIrql( OldIrql );
  1322. //
  1323. // Copy the temp structure we just created over...
  1324. //
  1325. RtlCopyMemory(ProcInfo, &TempInfo, sizeof(PROCESSOR_POWER_INFORMATION) );
  1326. ProcInfo += 1;
  1327. BufferSize += sizeof (PROCESSOR_POWER_INFORMATION);
  1328. //
  1329. // Next
  1330. //
  1331. Processor = Processor + 1;
  1332. }
  1333. KeRevertToUserAffinityThread();
  1334. *ReturnBufferLength = BufferSize;
  1335. }