intelcst.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. intelcst.c
  5. Abstract:
  6. This module implements support for Intel processor C-States.
  7. Author:
  8. Evan Green 25-Sep-2015
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. //
  16. // This could be abstracted out into a driver. The only reason it's not is that
  17. // there are so few x86 manufacturers, and there's a small problem of
  18. // enumerating some device that would cause this driver to load. Anyway, try to
  19. // avoid including kernel internal headers here or using non-exported
  20. // functions, as the extraction of this code out into a driver may happen some
  21. // day.
  22. //
  23. #include <minoca/kernel/kernel.h>
  24. #include <minoca/kernel/x86.h>
  25. //
  26. // ---------------------------------------------------------------- Definitions
  27. //
  28. #define PM_INTEL_CSTATE_ALLOCATION_TAG 0x436C7449
  29. #define PM_INTEL_MAX_CSTATES 8
  30. #define PM_INTEL_CSTATE_MASK 0xFF
  31. #define PM_INTEL_CSTATE_SHIFT 4
  32. #define PM_INTEL_CSTATE_SUBSTATE_MASK 0x0F
  33. #define PM_INTEL_PENRYN_CSTATE_COUNT 4
  34. #define PM_INTEL_NEHALEM_CSTATE_COUNT 4
  35. #define PM_INTEL_SANDY_BRIDGE_CSTATE_COUNT 5
  36. #define PM_INTEL_BAY_TRAIL_CSTATE_COUNT 5
  37. #define PM_INTEL_IVY_BRIDGE_CSTATE_COUNT 5
  38. #define PM_INTEL_IVY_TOWN_CSTATE_COUNT 4
  39. #define PM_INTEL_HASWELL_CSTATE_COUNT 8
  40. #define PM_INTEL_ATOM_CSTATE_COUNT 4
  41. #define PM_INTEL_AVOTON_CSTATE_COUNT 2
  42. //
  43. // Define Intel C-state flags that go along with the states.
  44. //
  45. //
  46. // This flag is only ever set on the first state, and it indicates that
  47. // automatic C1E promotion should be disabled.
  48. //
  49. #define PM_INTEL_DISABLE_C1E_PROMOTION (1 << 8)
  50. //
  51. // ------------------------------------------------------ Data Type Definitions
  52. //
  53. /*++
  54. Structure Description:
  55. This structure defines a single CPU idle state that a processor can enter.
  56. Members:
  57. Interface - Stores the interface itself.
  58. States - Stores the array of enumerated C-states.
  59. StateCount - Stores the count of enumerated C-states.
  60. MwaitSubstates - Stores the MWAIT substates for each C-state.
  61. Model - Stores the processor model.
  62. --*/
  63. typedef struct _PM_INTEL_CSTATE_CONTEXT {
  64. PM_IDLE_STATE_INTERFACE Interface;
  65. PM_IDLE_STATE States[PM_INTEL_MAX_CSTATES];
  66. ULONG StateCount;
  67. ULONG MwaitSubstates;
  68. ULONG Model;
  69. } PM_INTEL_CSTATE_CONTEXT, *PPM_INTEL_CSTATE_CONTEXT;
  70. //
  71. // ----------------------------------------------- Internal Function Prototypes
  72. //
  73. KSTATUS
  74. PmpIntelInitializeCstates (
  75. PPM_IDLE_STATE_INTERFACE Interface,
  76. PPM_IDLE_PROCESSOR_STATE Processor
  77. );
  78. VOID
  79. PmpIntelEnterCstate (
  80. PPM_IDLE_PROCESSOR_STATE Processor,
  81. ULONG State
  82. );
  83. //
  84. // -------------------------------------------------------------------- Globals
  85. //
  86. //
  87. // Define the idle states for the various Intel processor generations. The
  88. // times are initialized in microseconds, and need to be converted to time
  89. // counter ticks before sending to the kernel.
  90. //
  91. PM_IDLE_STATE PmIntelPenrynCstates[PM_INTEL_PENRYN_CSTATE_COUNT] = {
  92. {
  93. "C1",
  94. 0,
  95. (PVOID)0x00,
  96. 1,
  97. 4
  98. },
  99. {
  100. "C2",
  101. 0,
  102. (PVOID)0x10,
  103. 20,
  104. 80
  105. },
  106. {
  107. "C4",
  108. 0,
  109. (PVOID)0x20,
  110. 100,
  111. 400
  112. },
  113. {
  114. "C6",
  115. 0,
  116. (PVOID)0x30,
  117. 150,
  118. 550
  119. },
  120. };
  121. PM_IDLE_STATE PmIntelNehalemCstates[PM_INTEL_NEHALEM_CSTATE_COUNT] = {
  122. {
  123. "C1",
  124. 0,
  125. (PVOID)(0x00 | PM_INTEL_DISABLE_C1E_PROMOTION),
  126. 3,
  127. 6
  128. },
  129. {
  130. "C1E",
  131. 0,
  132. (PVOID)0x01,
  133. 10,
  134. 20
  135. },
  136. {
  137. "C3",
  138. 0,
  139. (PVOID)0x10,
  140. 20,
  141. 80
  142. },
  143. {
  144. "C6",
  145. 0,
  146. (PVOID)0x20,
  147. 200,
  148. 800
  149. },
  150. };
  151. PM_IDLE_STATE PmIntelSandyBridgeCstates[PM_INTEL_SANDY_BRIDGE_CSTATE_COUNT] = {
  152. {
  153. "C1",
  154. 0,
  155. (PVOID)(0x00 | PM_INTEL_DISABLE_C1E_PROMOTION),
  156. 2,
  157. 2
  158. },
  159. {
  160. "C1E",
  161. 0,
  162. (PVOID)0x01,
  163. 10,
  164. 20
  165. },
  166. {
  167. "C3",
  168. 0,
  169. (PVOID)0x10,
  170. 80,
  171. 200
  172. },
  173. {
  174. "C6",
  175. 0,
  176. (PVOID)0x20,
  177. 100,
  178. 300
  179. },
  180. {
  181. "C7",
  182. 0,
  183. (PVOID)0x30,
  184. 110,
  185. 350
  186. },
  187. };
  188. PM_IDLE_STATE PmIntelBayTrailCstates[PM_INTEL_BAY_TRAIL_CSTATE_COUNT] = {
  189. {
  190. "C1",
  191. 0,
  192. (PVOID)(0x00 | PM_INTEL_DISABLE_C1E_PROMOTION),
  193. 1,
  194. 4
  195. },
  196. {
  197. "C6N",
  198. 0,
  199. (PVOID)0x58,
  200. 300,
  201. 300
  202. },
  203. {
  204. "C6S",
  205. 0,
  206. (PVOID)0x52,
  207. 500,
  208. 550
  209. },
  210. {
  211. "C7",
  212. 0,
  213. (PVOID)0x60,
  214. 1200,
  215. 4000
  216. },
  217. {
  218. "C7S",
  219. 0,
  220. (PVOID)0x64,
  221. 10000,
  222. 20000
  223. },
  224. };
  225. PM_IDLE_STATE PmIntelIvyBridgeCstates[PM_INTEL_IVY_BRIDGE_CSTATE_COUNT] = {
  226. {
  227. "C1",
  228. 0,
  229. (PVOID)(0x00 | PM_INTEL_DISABLE_C1E_PROMOTION),
  230. 1,
  231. 1
  232. },
  233. {
  234. "C1E",
  235. 0,
  236. (PVOID)0x01,
  237. 10,
  238. 20
  239. },
  240. {
  241. "C3",
  242. 0,
  243. (PVOID)0x10,
  244. 60,
  245. 150
  246. },
  247. {
  248. "C6",
  249. 0,
  250. (PVOID)0x20,
  251. 80,
  252. 300
  253. },
  254. {
  255. "C7",
  256. 0,
  257. (PVOID)0x30,
  258. 90,
  259. 350
  260. },
  261. };
  262. PM_IDLE_STATE PmIntelIvyTownCstates[PM_INTEL_IVY_TOWN_CSTATE_COUNT] = {
  263. {
  264. "C1",
  265. 0,
  266. (PVOID)(0x00 | PM_INTEL_DISABLE_C1E_PROMOTION),
  267. 1,
  268. 1
  269. },
  270. {
  271. "C1E",
  272. 0,
  273. (PVOID)0x01,
  274. 10,
  275. 120
  276. },
  277. {
  278. "C3",
  279. 0,
  280. (PVOID)0x10,
  281. 60,
  282. 150
  283. },
  284. {
  285. "C6",
  286. 0,
  287. (PVOID)0x20,
  288. 80,
  289. 300
  290. },
  291. };
  292. PM_IDLE_STATE PmIntelHaswellCstates[PM_INTEL_HASWELL_CSTATE_COUNT] = {
  293. {
  294. "C1",
  295. 0,
  296. (PVOID)(0x00 | PM_INTEL_DISABLE_C1E_PROMOTION),
  297. 1,
  298. 2
  299. },
  300. {
  301. "C1E",
  302. 0,
  303. (PVOID)0x01,
  304. 10,
  305. 20
  306. },
  307. {
  308. "C3",
  309. 0,
  310. (PVOID)0x10,
  311. 40,
  312. 100
  313. },
  314. {
  315. "C6",
  316. 0,
  317. (PVOID)0x20,
  318. 150,
  319. 400
  320. },
  321. {
  322. "C7s",
  323. 0,
  324. (PVOID)0x32,
  325. 160,
  326. 500
  327. },
  328. {
  329. "C8",
  330. 0,
  331. (PVOID)0x40,
  332. 300,
  333. 900
  334. },
  335. {
  336. "C9",
  337. 0,
  338. (PVOID)0x50,
  339. 600,
  340. 1800
  341. },
  342. {
  343. "C10",
  344. 0,
  345. (PVOID)0x60,
  346. 2600,
  347. 7700
  348. },
  349. };
  350. PM_IDLE_STATE PmIntelAtomCstates[PM_INTEL_ATOM_CSTATE_COUNT] = {
  351. {
  352. "C1",
  353. 0,
  354. (PVOID)0x00,
  355. 1,
  356. 4
  357. },
  358. {
  359. "C2",
  360. 0,
  361. (PVOID)0x10,
  362. 20,
  363. 80
  364. },
  365. {
  366. "C4",
  367. 0,
  368. (PVOID)0x30,
  369. 100,
  370. 400
  371. },
  372. {
  373. "C6",
  374. 0,
  375. (PVOID)0x52,
  376. 150,
  377. 550
  378. },
  379. };
  380. PM_IDLE_STATE PmIntelAvotonCstates[PM_INTEL_AVOTON_CSTATE_COUNT] = {
  381. {
  382. "C1",
  383. 0,
  384. (PVOID)0x00,
  385. 2,
  386. 2
  387. },
  388. {
  389. "C6",
  390. 0,
  391. (PVOID)0x51,
  392. 15,
  393. 45
  394. },
  395. };
  396. //
  397. // ------------------------------------------------------------------ Functions
  398. //
  399. VOID
  400. PmpIntelCstateDriverEntry (
  401. VOID
  402. )
  403. /*++
  404. Routine Description:
  405. This routine initializes support for Intel C-states. It will register
  406. itself as a processor idle state manager if it supports this processor.
  407. Arguments:
  408. None.
  409. Return Value:
  410. None.
  411. --*/
  412. {
  413. ULONG CState;
  414. ULONG CStateMask;
  415. PPM_INTEL_CSTATE_CONTEXT Data;
  416. UINTN DataSize;
  417. PPM_IDLE_STATE Destination;
  418. ULONG Eax;
  419. ULONG Ebx;
  420. ULONG Ecx;
  421. ULONG Edx;
  422. ULONG MaxLevel;
  423. ULONG Model;
  424. ULONG MwaitSubstates;
  425. RUNLEVEL OldRunLevel;
  426. PPROCESSOR_BLOCK ProcessorBlock;
  427. ULONG Shift;
  428. PPM_IDLE_STATE Source;
  429. ULONG StateCount;
  430. ULONG StateIndex;
  431. PPM_IDLE_STATE States;
  432. KSTATUS Status;
  433. ULONG Substates;
  434. Data = NULL;
  435. //
  436. // Get the vendor/family/model/stepping information out of the processor
  437. // block since it's all there. If this is extracted out to the driver, it
  438. // would need to do its own CPUIDing.
  439. //
  440. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  441. ProcessorBlock = KeGetCurrentProcessorBlock();
  442. if ((ProcessorBlock->CpuVersion.Vendor != X86_VENDOR_INTEL) ||
  443. (ProcessorBlock->CpuVersion.Family != 6)) {
  444. KeLowerRunLevel(OldRunLevel);
  445. goto IntelCstateDriverEntryEnd;
  446. }
  447. Model = ProcessorBlock->CpuVersion.Model;
  448. KeLowerRunLevel(OldRunLevel);
  449. //
  450. // Make sure the MWAIT leaf is available.
  451. //
  452. Ecx = 0;
  453. Eax = X86_CPUID_IDENTIFICATION;
  454. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  455. MaxLevel = Eax;
  456. if (MaxLevel < X86_CPUID_MWAIT) {
  457. goto IntelCstateDriverEntryEnd;
  458. }
  459. //
  460. // Make sure the monitor/mwait instructions are present.
  461. //
  462. Eax = X86_CPUID_BASIC_INFORMATION;
  463. Ecx = 0;
  464. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  465. if ((Ecx & X86_CPUID_BASIC_ECX_MONITOR) == 0) {
  466. goto IntelCstateDriverEntryEnd;
  467. }
  468. //
  469. // Check if mwait has extensions and can be broken out even with interrupts
  470. // disabled.
  471. //
  472. Eax = X86_CPUID_MWAIT;
  473. Ecx = 0;
  474. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  475. if (((Ecx & X86_CPUID_MWAIT_ECX_EXTENSIONS_SUPPORTED) == 0) ||
  476. ((Ecx & X86_CPUID_MWAIT_ECX_INTERRUPT_BREAK) == 0)) {
  477. goto IntelCstateDriverEntryEnd;
  478. }
  479. MwaitSubstates = Edx;
  480. switch (Model) {
  481. case 0x17:
  482. States = PmIntelPenrynCstates;
  483. StateCount = PM_INTEL_PENRYN_CSTATE_COUNT;
  484. break;
  485. //
  486. // Handle Penryn, Nehalem, Westmere models under the same group.
  487. //
  488. case 0x1A:
  489. case 0x1E:
  490. case 0x1F:
  491. case 0x25:
  492. case 0x2C:
  493. case 0x2E:
  494. case 0x2F:
  495. States = PmIntelNehalemCstates;
  496. StateCount = PM_INTEL_NEHALEM_CSTATE_COUNT;
  497. break;
  498. case 0x1C:
  499. case 0x26:
  500. case 0x36:
  501. States = PmIntelAtomCstates;
  502. StateCount = PM_INTEL_ATOM_CSTATE_COUNT;
  503. break;
  504. case 0x2A:
  505. case 0x2D:
  506. States = PmIntelSandyBridgeCstates;
  507. StateCount = PM_INTEL_SANDY_BRIDGE_CSTATE_COUNT;
  508. break;
  509. case 0x37:
  510. case 0x4C:
  511. States = PmIntelBayTrailCstates;
  512. StateCount = PM_INTEL_BAY_TRAIL_CSTATE_COUNT;
  513. break;
  514. case 0x3A:
  515. States = PmIntelIvyBridgeCstates;
  516. StateCount = PM_INTEL_IVY_BRIDGE_CSTATE_COUNT;
  517. break;
  518. case 0x3E:
  519. States = PmIntelIvyTownCstates;
  520. StateCount = PM_INTEL_IVY_TOWN_CSTATE_COUNT;
  521. break;
  522. //
  523. // Handle Haswell and Broadwell under the same group.
  524. //
  525. case 0x3C:
  526. case 0x3D:
  527. case 0x3F:
  528. case 0x45:
  529. case 0x46:
  530. case 0x47:
  531. case 0x4F:
  532. case 0x56:
  533. States = PmIntelHaswellCstates;
  534. StateCount = PM_INTEL_HASWELL_CSTATE_COUNT;
  535. break;
  536. case 0x4D:
  537. States = PmIntelAvotonCstates;
  538. StateCount = PM_INTEL_AVOTON_CSTATE_COUNT;
  539. break;
  540. default:
  541. RtlDebugPrint("Unknown Intel processor model 0x%x. "
  542. "Disabling C-states.\n",
  543. Model);
  544. goto IntelCstateDriverEntryEnd;
  545. }
  546. Data = MmAllocateNonPagedPool(sizeof(PM_INTEL_CSTATE_CONTEXT),
  547. PM_INTEL_CSTATE_ALLOCATION_TAG);
  548. if (Data == NULL) {
  549. goto IntelCstateDriverEntryEnd;
  550. }
  551. RtlZeroMemory(Data, sizeof(PM_INTEL_CSTATE_CONTEXT));
  552. //
  553. // Assuming that all CPUs are the same, go through and validate that each
  554. // C-state listed in the array is present in the processor.
  555. //
  556. CStateMask = 0;
  557. for (StateIndex = 0; StateIndex < StateCount; StateIndex += 1) {
  558. Source = States + StateIndex;
  559. //
  560. // Determine if the given state actually exists on the processor. Skip
  561. // any that don't.
  562. //
  563. CState = (((UINTN)Source->Context) & PM_INTEL_CSTATE_MASK) >>
  564. PM_INTEL_CSTATE_SHIFT;
  565. Shift = (CState + 1) * 4;
  566. Substates = (MwaitSubstates >> Shift) & PM_INTEL_CSTATE_SUBSTATE_MASK;
  567. CStateMask |= PM_INTEL_CSTATE_SUBSTATE_MASK << Shift;
  568. if (Substates == 0) {
  569. continue;
  570. }
  571. Destination = &(Data->States[Data->StateCount]);
  572. RtlCopyMemory(Destination, Source, sizeof(PM_IDLE_STATE));
  573. Destination->ExitLatency =
  574. KeConvertMicrosecondsToTimeTicks(Destination->ExitLatency);
  575. Destination->TargetResidency =
  576. KeConvertMicrosecondsToTimeTicks(Destination->TargetResidency);
  577. Data->StateCount += 1;
  578. }
  579. Data->MwaitSubstates = MwaitSubstates;
  580. Data->Model = Model;
  581. //
  582. // Notice if the CPU enumerated C-states that aren't in the hardcoded
  583. // arrays.
  584. //
  585. if ((MwaitSubstates & ~CStateMask) != 0) {
  586. RtlDebugPrint("Intel Model 0x%x had extra C-States: %08x.\n",
  587. Model,
  588. MwaitSubstates & ~CStateMask);
  589. }
  590. //
  591. // If it ended up not enumerating any C-states, don't register the driver.
  592. //
  593. if (Data->StateCount == 0) {
  594. RtlDebugPrint("Intel: No C-states\n");
  595. MmFreeNonPagedPool(Data);
  596. goto IntelCstateDriverEntryEnd;
  597. }
  598. Data->Interface.InitializeIdleStates = PmpIntelInitializeCstates;
  599. Data->Interface.EnterIdleState = PmpIntelEnterCstate;
  600. Data->Interface.Context = Data;
  601. DataSize = sizeof(PM_IDLE_STATE_INTERFACE);
  602. Status = KeGetSetSystemInformation(SystemInformationPm,
  603. PmInformationIdleStateHandlers,
  604. &(Data->Interface),
  605. &DataSize,
  606. TRUE);
  607. if (!KSUCCESS(Status)) {
  608. RtlDebugPrint("Intel: C-state registration failed: %x\n", Status);
  609. MmFreeNonPagedPool(Data);
  610. }
  611. IntelCstateDriverEntryEnd:
  612. return;
  613. }
  614. //
  615. // --------------------------------------------------------- Internal Functions
  616. //
  617. KSTATUS
  618. PmpIntelInitializeCstates (
  619. PPM_IDLE_STATE_INTERFACE Interface,
  620. PPM_IDLE_PROCESSOR_STATE Processor
  621. )
  622. /*++
  623. Routine Description:
  624. This routine prototype represents a function that is called to go set up
  625. idle state information on the current processor. It should set the states
  626. and state count in the given processor idle information structure. This
  627. routine is called once on every processor. It runs at dispatch level.
  628. Arguments:
  629. Interface - Supplies a pointer to the interface.
  630. Processor - Supplies a pointer to the context for this processor.
  631. Return Value:
  632. Status code.
  633. --*/
  634. {
  635. PPM_INTEL_CSTATE_CONTEXT Data;
  636. ULONG Eax;
  637. ULONG Ebx;
  638. ULONG Ecx;
  639. ULONG Edx;
  640. ULONG Flags;
  641. ULONGLONG PowerControl;
  642. PPROCESSOR_BLOCK ProcessorBlock;
  643. Data = Interface->Context;
  644. //
  645. // Fail if the processor type is not the same as the original one that
  646. // everything was initialized for.
  647. //
  648. ProcessorBlock = KeGetCurrentProcessorBlock();
  649. if ((ProcessorBlock->CpuVersion.Vendor != X86_VENDOR_INTEL) ||
  650. (ProcessorBlock->CpuVersion.Model != Data->Model)) {
  651. ASSERT(FALSE);
  652. return STATUS_UNEXPECTED_TYPE;
  653. }
  654. Eax = X86_CPUID_MWAIT;
  655. Ecx = 0;
  656. ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
  657. if (Edx != Data->MwaitSubstates) {
  658. ASSERT(FALSE);
  659. return STATUS_UNEXPECTED_TYPE;
  660. }
  661. Processor->States = Data->States;
  662. Processor->StateCount = Data->StateCount;
  663. if (Processor->StateCount != 0) {
  664. Flags = (UINTN)(Processor->States[0].Context);
  665. //
  666. // Disable automatic promotion of C1 to C1E by hardware if desired.
  667. //
  668. if ((Flags & PM_INTEL_DISABLE_C1E_PROMOTION) != 0) {
  669. PowerControl = ArReadMsr(X86_MSR_POWER_CONTROL);
  670. PowerControl &= ~X86_MSR_POWER_CONTROL_C1E_PROMOTION;
  671. ArWriteMsr(X86_MSR_POWER_CONTROL, PowerControl);
  672. }
  673. }
  674. return STATUS_SUCCESS;
  675. }
  676. VOID
  677. PmpIntelEnterCstate (
  678. PPM_IDLE_PROCESSOR_STATE Processor,
  679. ULONG State
  680. )
  681. /*++
  682. Routine Description:
  683. This routine goes to the given C-state on Intel processors.
  684. Arguments:
  685. Processor - Supplies a pointer to the information for the current processor.
  686. State - Supplies the new state index to change to.
  687. Return Value:
  688. None. It is assumed when this function returns that the idle state was
  689. entered and then exited.
  690. --*/
  691. {
  692. ULONG Eax;
  693. ULONG Ecx;
  694. Eax = (UINTN)(Processor->States[State].Context) & PM_INTEL_CSTATE_MASK;
  695. Ecx = 1;
  696. ArMonitor(&Eax, 0, 0);
  697. ArMwait(Eax, Ecx);
  698. return;
  699. }