Source code of Windows XP (NT5)
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.

4112 lines
91 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. method.c
  5. Abstract:
  6. This module implements code to find and evaluate
  7. ACPI objects.
  8. Author:
  9. Jake Oshins (3/18/00) - create file
  10. Environment:
  11. Kernel mode
  12. Notes:
  13. Revision History:
  14. --*/
  15. #include "processor.h"
  16. #include "acpiioct.h"
  17. #include "ntacpi.h"
  18. #include <wdmguid.h>
  19. #include "apic.inc"
  20. #include "..\eventmsg.h"
  21. #define rgzMultiFunctionAdapter L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"
  22. #define rgzAcpiConfigurationData L"Configuration Data"
  23. #define rgzAcpiIdentifier L"Identifier"
  24. #define rgzBIOSIdentifier L"ACPI BIOS"
  25. const WCHAR CCSEnumRegKey[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum";
  26. const WCHAR FriendlyNameRegKey[] = L"FriendlyName";
  27. const WCHAR EnumKeyName[] = L"Enum";
  28. extern FADT HalpFixedAcpiDescTable;
  29. extern ULONG HalpThrottleScale;
  30. extern WMI_EVENT PStateEvent;
  31. extern WMI_EVENT NewPStatesEvent;
  32. extern WMI_EVENT NewCStatesEvent;
  33. // toddcar 4/24/01 ISSUE
  34. // when we support CStates and Throttle States on MP machines
  35. // these values need to be in the device extension.
  36. //
  37. GEN_ADDR PCntAddress;
  38. GEN_ADDR C2Address;
  39. GEN_ADDR C3Address;
  40. //
  41. // Well known virtual address of local processor apic
  42. //
  43. #define LOCALAPIC 0xfffe0000
  44. #define pLocalApic ((ULONG volatile *) UlongToPtr(LOCALAPIC))
  45. NTSTATUS
  46. AcpiParseGenRegDesc(
  47. IN PUCHAR Buffer,
  48. OUT PGEN_ADDR *GenericAddress
  49. );
  50. NTSTATUS
  51. AcpiFindRsdt (
  52. OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
  53. );
  54. VOID
  55. AcpiNotify80CallbackWorker(
  56. IN PDEVICE_OBJECT DeviceObject,
  57. IN PVOID Context
  58. );
  59. VOID
  60. AcpiNotify81CallbackWorker(
  61. IN PDEVICE_OBJECT DeviceObject,
  62. IN PVOID Context
  63. );
  64. #if DBG
  65. VOID
  66. DumpCStates(
  67. PACPI_CST_PACKAGE CStates
  68. );
  69. #else
  70. #define DumpCStates(_x_)
  71. #endif
  72. #ifdef ALLOC_PRAGMA
  73. #pragma alloc_text (PAGE, AcpiEvaluateCst)
  74. #pragma alloc_text (PAGE, AcpiEvaluateMethod)
  75. #pragma alloc_text (PAGE, AcpiEvaluatePct)
  76. #pragma alloc_text (PAGE, AcpiEvaluatePpc)
  77. #pragma alloc_text (PAGE, AcpiEvaluateProcessorObject)
  78. #pragma alloc_text (PAGE, AcpiEvaluatePss)
  79. #pragma alloc_text (PAGE, AcpiEvaluatePtc)
  80. #pragma alloc_text (PAGE, AcpiFindRsdt)
  81. #pragma alloc_text (PAGE, AcpiNotify80CallbackWorker)
  82. #pragma alloc_text (PAGE, AcpiParseGenRegDesc)
  83. #pragma alloc_text (PAGE, AcquireAcpiInterfaces)
  84. #pragma alloc_text (PAGE, GetRegistryValue)
  85. #pragma alloc_text (PAGE, GetAcpiTable)
  86. #pragma alloc_text (PAGE, InitializeAcpi2PStatesGeneric)
  87. #pragma alloc_text (PAGE, ReleaseAcpiInterfaces)
  88. #pragma alloc_text (PAGE, InitializeAcpi2IoSpaceCstates)
  89. #endif
  90. NTSTATUS
  91. AcpiEvaluateMethod (
  92. IN PFDO_DATA DeviceExtension,
  93. IN PCHAR MethodName,
  94. IN PVOID InputBuffer OPTIONAL,
  95. OUT PVOID *OutputBuffer
  96. )
  97. /*
  98. Routine Description:
  99. This routine sends an IRP to ACPI to evaluate a method.
  100. Arguments:
  101. MethodName - String identifying the method
  102. InputBuffer - Arguments for the method. If specified, the
  103. method name must match MethodName
  104. OutputBuffer- Return value(s) from method
  105. Return Value:
  106. NTSTATUS
  107. --*/
  108. #define CONTROL_METHOD_BUFFER_SIZE 0x1024
  109. {
  110. ACPI_EVAL_INPUT_BUFFER inputBuffer;
  111. NTSTATUS status;
  112. PIRP irp = NULL;
  113. KEVENT irpCompleted;
  114. IO_STATUS_BLOCK statusBlock;
  115. ULONG inputBufLen;
  116. DebugEnter();
  117. PAGED_CODE();
  118. if (!InputBuffer) {
  119. //
  120. // The caller didn't specify an input buffer. So
  121. // build one without any arguments out of the MethodName.
  122. //
  123. ASSERT(strlen(MethodName) <= 4);
  124. if (strlen(MethodName) > 4) {
  125. return STATUS_INVALID_PARAMETER_1;
  126. }
  127. inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
  128. strncpy(inputBuffer.MethodName, MethodName, sizeof(inputBuffer.MethodName));
  129. InputBuffer = &inputBuffer;
  130. }
  131. //
  132. // Figure out how big the input buffer is.
  133. //
  134. switch(((PACPI_EVAL_INPUT_BUFFER)InputBuffer)->Signature) {
  135. case ACPI_EVAL_INPUT_BUFFER_SIGNATURE:
  136. inputBufLen = sizeof(ACPI_EVAL_INPUT_BUFFER);
  137. break;
  138. case ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE:
  139. inputBufLen = sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER);
  140. break;
  141. case ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING_SIGNATURE:
  142. inputBufLen = sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING) +
  143. ((PACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING)InputBuffer)->StringLength - 1;
  144. break;
  145. case ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE:
  146. inputBufLen = ((PACPI_EVAL_INPUT_BUFFER_COMPLEX)InputBuffer)->Size;
  147. break;
  148. default:
  149. return STATUS_INVALID_PARAMETER_2;
  150. }
  151. KeInitializeEvent(&irpCompleted, NotificationEvent, FALSE);
  152. //
  153. // Allocate 1K for the output buffer. That should handle
  154. // everything that is necessary for ACPI 2.0 processor objects.
  155. //
  156. *OutputBuffer = ExAllocatePoolWithTag(PagedPool,
  157. CONTROL_METHOD_BUFFER_SIZE,
  158. PROCESSOR_POOL_TAG);
  159. if (!*OutputBuffer) {
  160. return STATUS_INSUFFICIENT_RESOURCES;
  161. }
  162. //
  163. // Build the IRP.
  164. //
  165. irp = IoBuildDeviceIoControlRequest(IOCTL_ACPI_EVAL_METHOD,
  166. DeviceExtension->NextLowerDriver,
  167. InputBuffer,
  168. inputBufLen,
  169. *OutputBuffer,
  170. CONTROL_METHOD_BUFFER_SIZE,
  171. FALSE,
  172. &irpCompleted,
  173. &statusBlock);
  174. if (!irp) {
  175. ExFreePool(*OutputBuffer);
  176. return STATUS_INSUFFICIENT_RESOURCES;
  177. }
  178. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  179. irp->IoStatus.Information = 0;
  180. status = IoCallDriver(DeviceExtension->NextLowerDriver, irp);
  181. if (status == STATUS_PENDING) {
  182. KeWaitForSingleObject(&irpCompleted,
  183. Executive,
  184. KernelMode,
  185. FALSE,
  186. NULL);
  187. status = statusBlock.Status;
  188. }
  189. if (!NT_SUCCESS(status)) {
  190. ExFreePool(*OutputBuffer);
  191. }
  192. return status;
  193. }
  194. NTSTATUS
  195. AcpiEvaluateProcessorObject (
  196. IN PFDO_DATA DeviceExtension,
  197. OUT PVOID *OutputBuffer
  198. )
  199. /*
  200. Routine Description:
  201. This routine sends an IRP to ACPI to evaluate a processor object.
  202. Arguments:
  203. OutputBuffer- Return value(s) from object
  204. Return Value:
  205. NTSTATUS
  206. --*/
  207. {
  208. NTSTATUS status;
  209. PIRP irp = NULL;
  210. KEVENT irpCompleted;
  211. IO_STATUS_BLOCK statusBlock;
  212. ULONG inputBufLen;
  213. DebugEnter();
  214. PAGED_CODE();
  215. KeInitializeEvent(&irpCompleted, NotificationEvent, FALSE);
  216. //
  217. // Allocate 1K for the output buffer. That should handle
  218. // everything that is necessary for ACPI 2.0 processor objects.
  219. //
  220. *OutputBuffer = ExAllocatePoolWithTag(PagedPool,
  221. sizeof(PROCESSOR_OBJECT_INFO),
  222. PROCESSOR_POOL_TAG);
  223. if (!*OutputBuffer) {
  224. return STATUS_INSUFFICIENT_RESOURCES;
  225. }
  226. //
  227. // Build the IRP.
  228. //
  229. irp = IoBuildDeviceIoControlRequest(IOCTL_GET_PROCESSOR_OBJ_INFO,
  230. DeviceExtension->NextLowerDriver,
  231. NULL,
  232. 0,
  233. *OutputBuffer,
  234. sizeof(PROCESSOR_OBJECT_INFO),
  235. FALSE,
  236. &irpCompleted,
  237. &statusBlock);
  238. if (!irp) {
  239. ExFreePool(*OutputBuffer);
  240. return STATUS_INSUFFICIENT_RESOURCES;
  241. }
  242. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  243. irp->IoStatus.Information = 0;
  244. status = IoCallDriver(DeviceExtension->NextLowerDriver, irp);
  245. if (status == STATUS_PENDING) {
  246. KeWaitForSingleObject(&irpCompleted,
  247. Executive,
  248. KernelMode,
  249. FALSE,
  250. NULL);
  251. status = statusBlock.Status;
  252. }
  253. if (!NT_SUCCESS(status)) {
  254. ExFreePool(*OutputBuffer);
  255. }
  256. return status;
  257. }
  258. NTSTATUS
  259. AcpiParseGenRegDesc(
  260. IN PUCHAR Buffer,
  261. OUT PGEN_ADDR *GenericAddress
  262. )
  263. /*++
  264. Routine Description:
  265. Arguments:
  266. Return Value:
  267. --*/
  268. {
  269. DebugEnter();
  270. PAGED_CODE();
  271. if ((Buffer[0] != 0x82) ||
  272. ((Buffer[1] != 0x0b) && (Buffer[1] != 0x0c)) ||
  273. (Buffer[2] != 0)) {
  274. //
  275. // The buffer is not a Generic Register Descriptor.
  276. //
  277. DebugPrint((WARN, "ACPI BIOS error: _PTC object was not a Generic Register Descriptor\n"));
  278. return STATUS_NOT_FOUND;
  279. }
  280. //
  281. // The thing passes the sanity test.
  282. //
  283. *GenericAddress = ExAllocatePoolWithTag(PagedPool,
  284. sizeof(GEN_ADDR),
  285. PROCESSOR_POOL_TAG);
  286. if (!*GenericAddress) {
  287. return STATUS_INSUFFICIENT_RESOURCES;
  288. }
  289. //
  290. // toddcar - 10/31/2000 - TEMP
  291. // Need to remove this code once new Acpi2.0 bios's change to
  292. // reflect new register descriptor type. Defined in Acpi 2.0 errata 1.1
  293. //
  294. if (Buffer[1] == 0x0b) {
  295. (*GenericAddress)->AddressSpaceID = Buffer[3];
  296. (*GenericAddress)->BitWidth = Buffer[4];
  297. (*GenericAddress)->BitOffset = Buffer[5];
  298. (*GenericAddress)->Reserved = 0;
  299. RtlCopyMemory(&(*GenericAddress)->Address.QuadPart,
  300. &(Buffer[6]),
  301. sizeof(PHYSICAL_ADDRESS));
  302. } else {
  303. RtlCopyMemory(*GenericAddress,
  304. &(Buffer[3]),
  305. sizeof(GEN_ADDR));
  306. }
  307. return STATUS_SUCCESS;
  308. }
  309. NTSTATUS
  310. AcpiEvaluatePtc(
  311. IN PFDO_DATA DeviceExtension,
  312. OUT PGEN_ADDR *Address
  313. )
  314. /*++
  315. Routine Description:
  316. Arguments:
  317. Return Value:
  318. --*/
  319. {
  320. PACPI_EVAL_OUTPUT_BUFFER ptcBuffer;
  321. NTSTATUS status;
  322. DebugEnter();
  323. PAGED_CODE();
  324. status = AcpiEvaluateMethod(DeviceExtension,
  325. "_PTC",
  326. NULL,
  327. &ptcBuffer);
  328. if (!NT_SUCCESS(status)) {
  329. return status;
  330. }
  331. ASSERT(ptcBuffer->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
  332. //
  333. // Sanity check the output buffer. (ACPI BIOSes can often be
  334. // wrong.
  335. //
  336. if (ptcBuffer->Count != 1) {
  337. DebugPrint((WARN, "ACPI BIOS error: _PTC object returned multiple objects\n"));
  338. status = STATUS_NOT_FOUND;
  339. goto AcpiEvaluatePtcExit;
  340. }
  341. if (ptcBuffer->Argument[0].Type != ACPI_METHOD_ARGUMENT_BUFFER) {
  342. DebugPrint((WARN, "ACPI BIOS error: _PTC object didn't return a buffer\n"));
  343. status = STATUS_ACPI_INVALID_ARGTYPE;
  344. goto AcpiEvaluatePtcExit;
  345. }
  346. if (ptcBuffer->Argument[0].DataLength != sizeof(GEN_ADDR) + 2) {
  347. //
  348. // The buffer is not the right size.
  349. //
  350. DebugPrint((WARN, "ACPI BIOS error: _PTC object returned a buffer of the wrong size\n"));
  351. status = STATUS_ACPI_INVALID_ARGTYPE;
  352. goto AcpiEvaluatePtcExit;
  353. }
  354. status = AcpiParseGenRegDesc(ptcBuffer->Argument[0].Data,
  355. Address);
  356. AcpiEvaluatePtcExit:
  357. ExFreePool(ptcBuffer);
  358. return status;
  359. }
  360. NTSTATUS
  361. AcpiEvaluateCst(
  362. IN PFDO_DATA DeviceExtension,
  363. OUT PACPI_CST_PACKAGE *CStates
  364. )
  365. /*
  366. Routine Description:
  367. This routine finds and evaluates the _CST object in an ACPI 2.0
  368. namespace. It returns the information in non-paged pool, as
  369. C-states must be entered and exited at DISPATCH_LEVEL.
  370. Arguments:
  371. DeviceExtension - FDO_DATA
  372. CStates - pointer to be filled in with return data
  373. Return Value:
  374. NTSTATUS
  375. --*/
  376. {
  377. PACPI_EVAL_OUTPUT_BUFFER output;
  378. PACPI_METHOD_ARGUMENT arg, subArg;
  379. NTSTATUS status;
  380. ULONG cstateCount = 0;
  381. ULONG subElement;
  382. ULONG size;
  383. ULONG totalCStates;
  384. DebugEnter();
  385. PAGED_CODE();
  386. DebugAssert(CStates);
  387. *CStates = NULL;
  388. status = AcpiEvaluateMethod(DeviceExtension,
  389. "_CST",
  390. NULL,
  391. &output);
  392. if (!NT_SUCCESS(status)) {
  393. return status;
  394. }
  395. DebugAssert(output->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
  396. //
  397. // Parse the output buffer, figuring out what we got. See chapter
  398. // 8.3.2 of the ACPI 2.0 spec for details.
  399. //
  400. if (output->Count == 0) {
  401. //
  402. // There was nothing in the object.
  403. //
  404. status = STATUS_ACPI_INVALID_ARGTYPE;
  405. goto AcpiEvaluateCstExit;
  406. }
  407. //
  408. // The first object should be an integer that lists the number of
  409. // C-states.
  410. //
  411. if (output->Argument[0].Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  412. //
  413. // The first element in the _CST package wasn't an
  414. // integer.
  415. //
  416. status = STATUS_ACPI_INVALID_ARGTYPE;
  417. goto AcpiEvaluateCstExit;
  418. }
  419. ASSERT(output->Argument[0].DataLength == sizeof(ULONG));
  420. totalCStates = output->Argument[0].Argument;
  421. size = ((totalCStates - 1) * sizeof(ACPI_CST_DESCRIPTOR)) +
  422. sizeof(ACPI_CST_PACKAGE);
  423. *CStates = ExAllocatePoolWithTag(NonPagedPool,
  424. size,
  425. PROCESSOR_POOL_TAG);
  426. if (!*CStates) {
  427. status = STATUS_INSUFFICIENT_RESOURCES;
  428. goto AcpiEvaluateCstExit;
  429. }
  430. RtlZeroMemory(*CStates, size);
  431. (*CStates)->NumCStates = (UCHAR) totalCStates;
  432. //
  433. // Get second data element, should be a package
  434. //
  435. arg = &output->Argument[1];
  436. while ((PUCHAR)arg < ((PUCHAR)output + output->Length)) {
  437. //
  438. // Crack the packages.
  439. //
  440. if (arg->Type == ACPI_METHOD_ARGUMENT_PACKAGE) {
  441. subArg = (PACPI_METHOD_ARGUMENT)(arg->Data);
  442. subElement = 0;
  443. // toddcar - 1/21/2001 - ISSUE
  444. // Currently there is no way to know if one our _CST
  445. // packages contained too few elements.
  446. //
  447. while ((PUCHAR)subArg < ((PUCHAR)(arg->Data) + arg->DataLength)) {
  448. //
  449. // In Chapter 8.3.2 of ACPI 2.0, these packages are
  450. // defined as having four elements each:
  451. //
  452. // C State_Register - Generic Register Descriptor
  453. // C State_Type - byte
  454. // Latency - word
  455. // Power_Consumption - dword
  456. //
  457. switch (subElement) {
  458. case 0:
  459. //
  460. // Looking at the buffer
  461. //
  462. ASSERT(subArg->Type == ACPI_METHOD_ARGUMENT_BUFFER);
  463. ASSERT(subArg->DataLength >= sizeof(ACPI_GENERIC_REGISTER_DESC));
  464. if ((subArg->DataLength < sizeof(ACPI_GENERIC_REGISTER_DESC)) ||
  465. (subArg->Type != ACPI_METHOD_ARGUMENT_BUFFER)) {
  466. DebugAssert(!"ACPI Bios Error: _CST Package[0] must be type Generic Register Descriptor");
  467. status = STATUS_ACPI_INVALID_ARGTYPE;
  468. goto AcpiEvaluateCstExit;
  469. }
  470. RtlCopyMemory(&(*CStates)->State[cstateCount].Register,
  471. &(subArg->Data[3]),
  472. sizeof(GEN_ADDR));
  473. break;
  474. case 1:
  475. if (subArg->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  476. DebugAssert(!"ACPI Bios Error: _CST Package item [1] must be type INTEGER");
  477. status = STATUS_ACPI_INVALID_ARGTYPE;
  478. goto AcpiEvaluateCstExit;
  479. }
  480. ASSERT(!(subArg->Argument & 0xffffff00));
  481. (*CStates)->State[cstateCount].StateType = (UCHAR)subArg->Argument;
  482. break;
  483. case 2:
  484. if (subArg->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  485. DebugAssert(!"ACPI Bios Error: _CST Package item[2] must be type INTEGER");
  486. status = STATUS_ACPI_INVALID_ARGTYPE;
  487. goto AcpiEvaluateCstExit;
  488. }
  489. ASSERT(!(subArg->Argument & 0xffff0000));
  490. (*CStates)->State[cstateCount].Latency = (USHORT)subArg->Argument;
  491. break;
  492. case 3:
  493. if (subArg->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  494. DebugAssert(!"ACPI Bios Error: _CST Package item[3] must be type INTEGER");
  495. status = STATUS_ACPI_INVALID_ARGTYPE;
  496. goto AcpiEvaluateCstExit;
  497. }
  498. (*CStates)->State[cstateCount].PowerConsumption = subArg->Argument;
  499. break;
  500. default:
  501. //
  502. // There were more than four elements in the package.
  503. //
  504. ASSERT(FALSE);
  505. status = STATUS_ACPI_INVALID_ARGTYPE;
  506. goto AcpiEvaluateCstExit;
  507. }
  508. subArg = ACPI_METHOD_NEXT_ARGUMENT(subArg);
  509. subElement++;
  510. }
  511. } else {
  512. //
  513. // There was an object that wasn't a package.
  514. //
  515. DebugAssert(!"ACPI Bios Error: _CST[2..n] must be type PACKAGE");
  516. status = STATUS_ACPI_INVALID_ARGTYPE;
  517. goto AcpiEvaluateCstExit;
  518. }
  519. arg = ACPI_METHOD_NEXT_ARGUMENT(arg);
  520. cstateCount++;
  521. }
  522. ASSERT(cstateCount == (output->Count - 1));
  523. DumpCStates(*CStates);
  524. AcpiEvaluateCstExit:
  525. if (!NT_SUCCESS(status) && (*CStates != NULL)) {
  526. ExFreePool(*CStates);
  527. *CStates = NULL;
  528. }
  529. ExFreePool(output);
  530. DebugExitStatus(status);
  531. return status;
  532. }
  533. NTSTATUS
  534. AcpiEvaluatePct(
  535. IN PFDO_DATA DeviceExtension,
  536. OUT PACPI_PCT_PACKAGE *Address
  537. )
  538. /*++
  539. Routine Description:
  540. Arguments:
  541. Return Value:
  542. --*/
  543. {
  544. PACPI_EVAL_OUTPUT_BUFFER pctBuffer;
  545. PACPI_METHOD_ARGUMENT arg;
  546. PGEN_ADDR genAddr;
  547. NTSTATUS status;
  548. ULONG pass = 0;
  549. DebugEnter();
  550. PAGED_CODE();
  551. ASSERT(Address);
  552. *Address = 0;
  553. status = AcpiEvaluateMethod(DeviceExtension,
  554. "_PCT",
  555. NULL,
  556. &pctBuffer);
  557. if (!NT_SUCCESS(status)) {
  558. return status;
  559. }
  560. ASSERT(pctBuffer->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
  561. //
  562. // Sanity check the output buffer. (ACPI BIOSes can often be
  563. // wrong.
  564. //
  565. if (pctBuffer->Count != 2) {
  566. DebugPrint((WARN, "ACPI BIOS error: _PCT object didn't return two objects\n"));
  567. status = STATUS_NOT_FOUND;
  568. goto AcpiEvaluatePctExit;
  569. }
  570. *Address = ExAllocatePoolWithTag(NonPagedPool,
  571. sizeof(ACPI_PCT_PACKAGE),
  572. PROCESSOR_POOL_TAG);
  573. if (!*Address) {
  574. status = STATUS_INSUFFICIENT_RESOURCES;
  575. goto AcpiEvaluatePctExit;
  576. }
  577. RtlZeroMemory(*Address, sizeof(ACPI_PCT_PACKAGE));
  578. //
  579. // Traverse the package, parsing the elements.
  580. //
  581. arg = (PACPI_METHOD_ARGUMENT)pctBuffer->Argument;
  582. while ((PUCHAR)arg < (PUCHAR)pctBuffer + pctBuffer->Length) {
  583. if (arg->Type != ACPI_METHOD_ARGUMENT_BUFFER) {
  584. DebugPrint((WARN, "ACPI BIOS error: _PCT object didn't return a buffer\n"));
  585. status = STATUS_ACPI_INVALID_ARGTYPE;
  586. goto AcpiEvaluatePctExit;
  587. }
  588. if (arg->DataLength < sizeof(GEN_ADDR) + 2) {
  589. //
  590. // The buffer is not the right size.
  591. //
  592. DebugPrint((WARN, "ACPI BIOS error: _PCT object returned a buffer of the wrong size\n"));
  593. status = STATUS_ACPI_INVALID_ARGTYPE;
  594. goto AcpiEvaluatePctExit;
  595. }
  596. if (pass > 1) {
  597. //
  598. // Too many things in the package.
  599. //
  600. status = STATUS_ACPI_INVALID_ARGTYPE;
  601. goto AcpiEvaluatePctExit;
  602. }
  603. //
  604. // Both package elements should contain generic addresses. So parse one.
  605. //
  606. status = AcpiParseGenRegDesc(arg->Data,
  607. &genAddr);
  608. if (!NT_SUCCESS(status)) {
  609. goto AcpiEvaluatePctExit;
  610. }
  611. switch (pass) {
  612. case 0:
  613. //
  614. // The first object in a _PCT should be the Perf Control Register
  615. //
  616. RtlCopyMemory(&((*Address)->Control), genAddr, sizeof(*genAddr));
  617. break;
  618. case 1:
  619. //
  620. // The second object in a _PCT should be the Perf Status Register
  621. //
  622. RtlCopyMemory(&((*Address)->Status), genAddr, sizeof(*genAddr));
  623. }
  624. ExFreePool(genAddr);
  625. arg = ACPI_METHOD_NEXT_ARGUMENT(arg);
  626. pass++;
  627. }
  628. AcpiEvaluatePctExit:
  629. if (!NT_SUCCESS(status)) {
  630. if (*Address) {
  631. ExFreePool(*Address);
  632. *Address = NULL;
  633. }
  634. }
  635. ExFreePool(pctBuffer);
  636. return status;
  637. }
  638. NTSTATUS
  639. AcpiEvaluatePss(
  640. IN PFDO_DATA DeviceExtension,
  641. OUT PACPI_PSS_PACKAGE *Address
  642. )
  643. /*++
  644. Routine Description:
  645. Arguments:
  646. Return Value:
  647. --*/
  648. {
  649. PACPI_EVAL_OUTPUT_BUFFER pssBuffer;
  650. PACPI_METHOD_ARGUMENT arg, subArg;
  651. NTSTATUS status;
  652. ULONG subElem, pState = 0;
  653. static UCHAR fieldOffsets[] = {
  654. FIELD_OFFSET(ACPI_PSS_DESCRIPTOR, CoreFrequency),
  655. FIELD_OFFSET(ACPI_PSS_DESCRIPTOR, Power),
  656. FIELD_OFFSET(ACPI_PSS_DESCRIPTOR, Latency),
  657. FIELD_OFFSET(ACPI_PSS_DESCRIPTOR, BmLatency),
  658. FIELD_OFFSET(ACPI_PSS_DESCRIPTOR, Control),
  659. FIELD_OFFSET(ACPI_PSS_DESCRIPTOR, Status)
  660. };
  661. DebugEnter();
  662. PAGED_CODE();
  663. ASSERT(Address);
  664. *Address = 0;
  665. status = AcpiEvaluateMethod(DeviceExtension,
  666. "_PSS",
  667. NULL,
  668. &pssBuffer);
  669. if (!NT_SUCCESS(status)) {
  670. return status;
  671. }
  672. ASSERT(pssBuffer->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
  673. //
  674. // The _PSS object is a package of packages. So the number
  675. // of objects in the _PCT method will be the number of
  676. // sub-packages. The amount of memory we need is calculated
  677. // from that.
  678. //
  679. *Address = ExAllocatePoolWithTag(NonPagedPool,
  680. sizeof(ACPI_PSS_PACKAGE) +
  681. (sizeof(ACPI_PSS_DESCRIPTOR) * (pssBuffer->Count - 1)),
  682. PROCESSOR_POOL_TAG);
  683. if (!*Address) {
  684. status = STATUS_INSUFFICIENT_RESOURCES;
  685. goto AcpiEvaluatePssExit;
  686. }
  687. (*Address)->NumPStates = (UCHAR)pssBuffer->Count;
  688. //
  689. // Traverse the package, parsing the elements.
  690. //
  691. arg = (PACPI_METHOD_ARGUMENT)pssBuffer->Argument;
  692. while ((PUCHAR)arg < (PUCHAR)pssBuffer + pssBuffer->Length) {
  693. //
  694. // Each element in a _PSS should be a package.
  695. //
  696. if (arg->Type != ACPI_METHOD_ARGUMENT_PACKAGE) {
  697. status = STATUS_ACPI_INVALID_ARGTYPE;
  698. goto AcpiEvaluatePssExit;
  699. }
  700. //
  701. // Traverse the inner package.
  702. //
  703. subElem = 0;
  704. subArg = (PACPI_METHOD_ARGUMENT)arg->Data;
  705. while ((PUCHAR)subArg < ((PUCHAR)arg) + arg->DataLength) {
  706. //
  707. // All the elements in the inner packages of
  708. // a _PSS object should be integers.
  709. //
  710. if (subArg->Type != ACPI_METHOD_ARGUMENT_INTEGER) {
  711. status = STATUS_ACPI_INVALID_ARGTYPE;
  712. goto AcpiEvaluatePssExit;
  713. }
  714. if (subElem > 5) {
  715. //
  716. // There are too many elements in this package.
  717. //
  718. status = STATUS_ACPI_INVALID_ARGTYPE;
  719. goto AcpiEvaluatePssExit;
  720. }
  721. //
  722. // The next step is to fill in the proper field in the P-State
  723. // table. Do this by indexing across pState and subElem.
  724. //
  725. *(PULONG)(((PUCHAR)&(*Address)->State[pState]) + fieldOffsets[subElem]) =
  726. subArg->Argument;
  727. subArg = ACPI_METHOD_NEXT_ARGUMENT(subArg);
  728. subElem++;
  729. }
  730. arg = ACPI_METHOD_NEXT_ARGUMENT(arg);
  731. pState++;
  732. }
  733. ASSERT(pState == (*Address)->NumPStates);
  734. status = STATUS_SUCCESS;
  735. AcpiEvaluatePssExit:
  736. if (!NT_SUCCESS(status)) {
  737. if (*Address) ExFreePool(*Address);
  738. }
  739. ExFreePool(pssBuffer);
  740. return status;
  741. }
  742. NTSTATUS
  743. AcpiEvaluatePpc(
  744. IN PFDO_DATA DeviceExtension,
  745. OUT ULONG *AvailablePerformanceStates
  746. )
  747. /*++
  748. Routine Description:
  749. Arguments:
  750. Return Value:
  751. --*/
  752. {
  753. PACPI_EVAL_OUTPUT_BUFFER ppcBuffer;
  754. NTSTATUS status;
  755. DebugEnter();
  756. PAGED_CODE();
  757. ASSERT(AvailablePerformanceStates);
  758. *AvailablePerformanceStates = 0;
  759. status = AcpiEvaluateMethod(DeviceExtension,
  760. "_PPC",
  761. NULL,
  762. &ppcBuffer);
  763. if (!NT_SUCCESS(status)) {
  764. return status;
  765. }
  766. ASSERT(ppcBuffer->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE);
  767. //
  768. // The _PPC object is an integer.
  769. //
  770. ASSERT(ppcBuffer->Count == 1);
  771. ASSERT(ppcBuffer->Argument[0].Type == ACPI_METHOD_ARGUMENT_INTEGER);
  772. *AvailablePerformanceStates = ppcBuffer->Argument[0].Argument;
  773. ExFreePool(ppcBuffer);
  774. return status;
  775. }
  776. NTSTATUS
  777. InitializeAcpi2PStatesGeneric(
  778. IN PFDO_DATA DeviceExtension
  779. )
  780. /*++
  781. Routine Description:
  782. This routine evaluates _PSS and _PCT, then
  783. builds the performance state array.
  784. Note: The caller must hold PerfStateLock.
  785. Arguments:
  786. DeviceExtension
  787. Return Value:
  788. A NTSTATUS code to indicate the result of the initialization.
  789. --*/
  790. {
  791. NTSTATUS status;
  792. PACPI_PCT_PACKAGE pctPackage = NULL;
  793. DebugEnter();
  794. PAGED_CODE();
  795. //
  796. // We automatically fail to use the Acpi 2.0 interface
  797. //
  798. if (Globals.HackFlags & DISABLE_ACPI20_INTERFACE_FLAG) {
  799. DebugPrint((ERROR, " Acpi 2.0 Interface Disabled\n"));
  800. return STATUS_NOT_FOUND;
  801. }
  802. //
  803. // Fill in the DeviceExtension with _PSS and _PCT.
  804. //
  805. status = AcpiEvaluatePss(DeviceExtension, &DeviceExtension->PssPackage);
  806. if (!NT_SUCCESS(status)) {
  807. goto InitializeAcpiPerformanceStatesExit;
  808. }
  809. status = AcpiEvaluatePct(DeviceExtension, &pctPackage);
  810. if (!NT_SUCCESS(status)) {
  811. goto InitializeAcpiPerformanceStatesExit;
  812. }
  813. RtlCopyMemory(&(DeviceExtension->PctPackage),
  814. pctPackage,
  815. sizeof(ACPI_PCT_PACKAGE));
  816. //
  817. // The _PCT object may have pointed to registers in Memory space.
  818. // If so, we need virtual addresses for these physical addresses.
  819. //
  820. if (DeviceExtension->PctPackage.Control.AddressSpaceID == AcpiGenericSpaceMemory) {
  821. DeviceExtension->PctPackage.Control.Address.QuadPart = (ULONG_PTR)
  822. MmMapIoSpace(DeviceExtension->PctPackage.Control.Address,
  823. DeviceExtension->PctPackage.Control.BitWidth / 8,
  824. MmNonCached);
  825. if (!DeviceExtension->PctPackage.Control.Address.QuadPart) {
  826. status = STATUS_INVALID_PARAMETER;
  827. goto InitializeAcpiPerformanceStatesExit;
  828. }
  829. }
  830. if (DeviceExtension->PctPackage.Status.AddressSpaceID == AcpiGenericSpaceMemory) {
  831. DeviceExtension->PctPackage.Status.Address.QuadPart = (ULONG_PTR)
  832. MmMapIoSpace(DeviceExtension->PctPackage.Status.Address,
  833. DeviceExtension->PctPackage.Status.BitWidth / 8,
  834. MmNonCached);
  835. if (!DeviceExtension->PctPackage.Status.Address.QuadPart) {
  836. status = STATUS_INVALID_PARAMETER;
  837. goto InitializeAcpiPerformanceStatesExit;
  838. }
  839. }
  840. //
  841. // Merge these states in with other available states.
  842. //
  843. status = MergePerformanceStates(DeviceExtension);
  844. //
  845. // Notify the bios we are taking control
  846. //
  847. if (NT_SUCCESS(status)) {
  848. AssumeProcessorPerformanceControl();
  849. }
  850. InitializeAcpiPerformanceStatesExit:
  851. if (!NT_SUCCESS(status)) {
  852. //
  853. // Something went wrong. Blow away the mess.
  854. //
  855. if (DeviceExtension->PssPackage) {
  856. ExFreePool(DeviceExtension->PssPackage);
  857. DeviceExtension->PssPackage = NULL;
  858. }
  859. }
  860. if (pctPackage) {
  861. ExFreePool(pctPackage);
  862. }
  863. DebugExitStatus(status);
  864. return status;
  865. }
  866. NTSTATUS
  867. AcpiFindRsdt (
  868. OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
  869. )
  870. /*++
  871. Routine Description:
  872. This function looks into the registry to find the ACPI RSDT,
  873. which was stored there by ntdetect.com.
  874. Arguments:
  875. RsdtPtr - Pointer to a buffer that contains the ACPI
  876. Root System Description Pointer Structure.
  877. The caller is responsible for freeing this
  878. buffer. Note: This is returned in non-paged
  879. pool.
  880. Return Value:
  881. A NTSTATUS code to indicate the result of the initialization.
  882. --*/
  883. {
  884. UNICODE_STRING unicodeString, unicodeValueName, biosId;
  885. OBJECT_ATTRIBUTES objectAttributes;
  886. HANDLE hMFunc, hBus;
  887. WCHAR wbuffer[10];
  888. ULONG i, length;
  889. PWSTR p;
  890. PKEY_VALUE_PARTIAL_INFORMATION valueInfo;
  891. NTSTATUS status;
  892. BOOLEAN same;
  893. PCM_PARTIAL_RESOURCE_LIST prl;
  894. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  895. PACPI_BIOS_MULTI_NODE multiNode;
  896. ULONG multiNodeSize;
  897. PLEGACY_GEYSERVILLE_INT15 int15Info;
  898. DebugEnter();
  899. PAGED_CODE();
  900. //
  901. // Look in the registry for the "ACPI BIOS bus" data
  902. //
  903. RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter);
  904. InitializeObjectAttributes (&objectAttributes,
  905. &unicodeString,
  906. OBJ_CASE_INSENSITIVE,
  907. NULL, // handle
  908. NULL);
  909. status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes);
  910. if (!NT_SUCCESS(status)) {
  911. DebugPrint((ERROR, "AcpiBios:Can not open MultifunctionAdapter registry key.\n"));
  912. return status;
  913. }
  914. unicodeString.Buffer = wbuffer;
  915. unicodeString.MaximumLength = sizeof(wbuffer);
  916. RtlInitUnicodeString(&biosId, rgzBIOSIdentifier);
  917. for (i = 0; TRUE; i++) {
  918. RtlIntegerToUnicodeString (i, 10, &unicodeString);
  919. InitializeObjectAttributes (&objectAttributes,
  920. &unicodeString,
  921. OBJ_CASE_INSENSITIVE,
  922. hMFunc,
  923. NULL);
  924. status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes);
  925. if (!NT_SUCCESS(status)) {
  926. //
  927. // Out of Multifunction adapter entries...
  928. //
  929. DebugPrint((ERROR, "AcpiBios: ACPI BIOS MultifunctionAdapter registry key not found.\n"));
  930. ZwClose (hMFunc);
  931. return STATUS_UNSUCCESSFUL;
  932. }
  933. //
  934. // Check the Indentifier to see if this is an ACPI BIOS entry
  935. //
  936. status = GetRegistryValue (hBus, rgzAcpiIdentifier, &valueInfo);
  937. if (!NT_SUCCESS (status)) {
  938. ZwClose (hBus);
  939. continue;
  940. }
  941. p = (PWSTR) ((PUCHAR) valueInfo->Data);
  942. unicodeValueName.Buffer = p;
  943. unicodeValueName.MaximumLength = (USHORT)valueInfo->DataLength;
  944. length = valueInfo->DataLength;
  945. //
  946. // Determine the real length of the ID string
  947. //
  948. while (length) {
  949. if (p[length / sizeof(WCHAR) - 1] == UNICODE_NULL) {
  950. length -= 2;
  951. } else {
  952. break;
  953. }
  954. }
  955. unicodeValueName.Length = (USHORT)length;
  956. same = RtlEqualUnicodeString(&biosId, &unicodeValueName, TRUE);
  957. ExFreePool(valueInfo);
  958. if (!same) {
  959. ZwClose (hBus);
  960. continue;
  961. }
  962. status = GetRegistryValue(hBus, rgzAcpiConfigurationData, &valueInfo);
  963. ZwClose (hBus);
  964. if (!NT_SUCCESS(status)) {
  965. continue ;
  966. }
  967. prl = (PCM_PARTIAL_RESOURCE_LIST)(valueInfo->Data);
  968. prd = &prl->PartialDescriptors[0];
  969. multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST));
  970. break;
  971. }
  972. multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) +
  973. ((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY)) +
  974. sizeof(LEGACY_GEYSERVILLE_INT15);
  975. *AcpiMulti = (PACPI_BIOS_MULTI_NODE) ExAllocatePoolWithTag(NonPagedPool,
  976. multiNodeSize,
  977. PROCESSOR_POOL_TAG);
  978. if (*AcpiMulti == NULL) {
  979. ExFreePool(valueInfo);
  980. return STATUS_INSUFFICIENT_RESOURCES;
  981. }
  982. RtlZeroMemory(*AcpiMulti, multiNodeSize);
  983. RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize - sizeof(LEGACY_GEYSERVILLE_INT15));
  984. //
  985. // Geyserville BIOS information is appended to the E820 entries. Unfortunately,
  986. // there is no way to know if it is there. So wrap the code in a try/except.
  987. //
  988. try {
  989. int15Info = (PLEGACY_GEYSERVILLE_INT15)&(multiNode->E820Entry[multiNode->Count]);
  990. if (int15Info->Signature == 'GS') {
  991. //
  992. // This BIOS supports Geyserville.
  993. //
  994. RtlCopyMemory(((PUCHAR)*AcpiMulti + multiNodeSize - sizeof(LEGACY_GEYSERVILLE_INT15)),
  995. int15Info,
  996. sizeof(LEGACY_GEYSERVILLE_INT15));
  997. }
  998. } except (EXCEPTION_EXECUTE_HANDLER) {
  999. *((PUSHORT)((PUCHAR)*AcpiMulti + multiNodeSize - sizeof(LEGACY_GEYSERVILLE_INT15))) = 0;
  1000. }
  1001. ExFreePool(valueInfo);
  1002. return STATUS_SUCCESS;
  1003. }
  1004. NTSTATUS
  1005. GetRegistryValue(
  1006. IN HANDLE KeyHandle,
  1007. IN PWSTR ValueName,
  1008. OUT PKEY_VALUE_PARTIAL_INFORMATION *Information
  1009. )
  1010. /*++
  1011. Routine Description:
  1012. This routine is invoked to retrieve the data for a registry key's value.
  1013. This is done by querying the value of the key with a zero-length buffer
  1014. to determine the size of the value, and then allocating a buffer and
  1015. actually querying the value into the buffer.
  1016. It is the responsibility of the caller to free the buffer.
  1017. Arguments:
  1018. KeyHandle - Supplies the key handle whose value is to be queried
  1019. ValueName - Supplies the null-terminated Unicode name of the value.
  1020. Information - Returns a pointer to the allocated data buffer.
  1021. Return Value:
  1022. The function value is the final status of the query operation.
  1023. --*/
  1024. {
  1025. UNICODE_STRING unicodeString;
  1026. NTSTATUS status;
  1027. PKEY_VALUE_PARTIAL_INFORMATION infoBuffer;
  1028. ULONG keyValueLength;
  1029. //DebugEnter();
  1030. PAGED_CODE();
  1031. RtlInitUnicodeString(&unicodeString, ValueName);
  1032. //
  1033. // Figure out how big the data value is so that a buffer of the
  1034. // appropriate size can be allocated.
  1035. //
  1036. status = ZwQueryValueKey(KeyHandle,
  1037. &unicodeString,
  1038. KeyValuePartialInformation,
  1039. (PVOID) NULL,
  1040. 0,
  1041. &keyValueLength);
  1042. if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) {
  1043. return status;
  1044. }
  1045. //
  1046. // Allocate a buffer large enough to contain the entire key data value.
  1047. //
  1048. infoBuffer = ExAllocatePoolWithTag(PagedPool,
  1049. keyValueLength,
  1050. PROCESSOR_POOL_TAG);
  1051. if (!infoBuffer) {
  1052. return STATUS_INSUFFICIENT_RESOURCES;
  1053. }
  1054. //
  1055. // Query the data for the key value.
  1056. //
  1057. status = ZwQueryValueKey(KeyHandle,
  1058. &unicodeString,
  1059. KeyValuePartialInformation,
  1060. infoBuffer,
  1061. keyValueLength,
  1062. &keyValueLength);
  1063. if (!NT_SUCCESS(status)) {
  1064. ExFreePool(infoBuffer);
  1065. return status;
  1066. }
  1067. //
  1068. // Everything worked, so simply return the address of the allocated
  1069. // buffer to the caller, who is now responsible for freeing it.
  1070. //
  1071. *Information = infoBuffer;
  1072. return STATUS_SUCCESS;
  1073. }
  1074. PVOID
  1075. GetAcpiTable(
  1076. IN ULONG Signature
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. This routine will retrieve any table referenced in the ACPI
  1081. RSDT.
  1082. Arguments:
  1083. Signature - Target table signature
  1084. Return Value:
  1085. pointer to a copy of the table, or NULL if not found
  1086. --*/
  1087. {
  1088. PACPI_BIOS_MULTI_NODE multiNode;
  1089. NTSTATUS status;
  1090. ULONG entry, rsdtEntries;
  1091. PDESCRIPTION_HEADER header;
  1092. PHYSICAL_ADDRESS physicalAddr;
  1093. PRSDT rsdt;
  1094. PVOID table = NULL;
  1095. DebugEnter();
  1096. PAGED_CODE();
  1097. status = AcpiFindRsdt(&multiNode);
  1098. if (!NT_SUCCESS(status)) {
  1099. return NULL;
  1100. }
  1101. rsdt = MmMapIoSpace(multiNode->RsdtAddress,
  1102. sizeof(RSDT) + (100 * sizeof(PHYSICAL_ADDRESS)),
  1103. MmCached);
  1104. ExFreePool(multiNode);
  1105. if (!rsdt) {
  1106. return NULL;
  1107. }
  1108. //
  1109. // Do a sanity check on the RSDT.
  1110. //
  1111. if ((rsdt->Header.Signature != RSDT_SIGNATURE) &&
  1112. (rsdt->Header.Signature != XSDT_SIGNATURE)) {
  1113. goto GetAcpiTableEnd;
  1114. }
  1115. //
  1116. // Calculate the number of entries in the RSDT.
  1117. //
  1118. rsdtEntries = rsdt->Header.Signature == XSDT_SIGNATURE ?
  1119. NumTableEntriesFromXSDTPointer(rsdt) :
  1120. NumTableEntriesFromRSDTPointer(rsdt);
  1121. //
  1122. // Look down the pointer in each entry to see if it points to
  1123. // the table we are looking for.
  1124. //
  1125. for (entry = 0; entry < rsdtEntries; entry++) {
  1126. //
  1127. // BUGBUG: should the highpart always be zero ? ie: what about PAE &
  1128. // WIN64 ? are other places in this module also susceptible to this ?
  1129. //
  1130. if (rsdt->Header.Signature == XSDT_SIGNATURE) {
  1131. physicalAddr = ((PXSDT)rsdt)->Tables[entry];
  1132. } else {
  1133. physicalAddr.HighPart = 0;
  1134. physicalAddr.LowPart = (ULONG)rsdt->Tables[entry];
  1135. }
  1136. header = MmMapIoSpace(physicalAddr,
  1137. PAGE_SIZE * 2,
  1138. MmCached);
  1139. if (!header) {
  1140. goto GetAcpiTableEnd;
  1141. }
  1142. if (header->Signature == Signature) {
  1143. break;
  1144. }
  1145. MmUnmapIoSpace(header, PAGE_SIZE * 2);
  1146. }
  1147. if (entry == rsdtEntries) {
  1148. goto GetAcpiTableEnd;
  1149. }
  1150. table = ExAllocatePoolWithTag(PagedPool,
  1151. header->Length,
  1152. PROCESSOR_POOL_TAG);
  1153. if (table) {
  1154. RtlCopyMemory(table, header, header->Length);
  1155. }
  1156. MmUnmapIoSpace(header, PAGE_SIZE * 2);
  1157. GetAcpiTableEnd:
  1158. MmUnmapIoSpace(rsdt,
  1159. sizeof(RSDT) + (100 * sizeof(PHYSICAL_ADDRESS)));
  1160. return table;
  1161. }
  1162. NTSTATUS
  1163. AcquireAcpiInterfaces(
  1164. PFDO_DATA DeviceExtension
  1165. )
  1166. /*++
  1167. Routine Description:
  1168. This routine sends an IRP to the ACPI driver to get the
  1169. funtion pointer table for the standard ACPI direct-call
  1170. interfaces.
  1171. Arguments:
  1172. DeviceExtension
  1173. Return Value:
  1174. NTSTATUS
  1175. --*/
  1176. {
  1177. KEVENT event;
  1178. NTSTATUS status, callbackStatus;
  1179. PIRP irp;
  1180. IO_STATUS_BLOCK ioStatusBlock;
  1181. PIO_STACK_LOCATION irpStack;
  1182. PACPI_INTERFACE_STANDARD acpiInterfaces = NULL;
  1183. DebugEnter();
  1184. PAGED_CODE();
  1185. ASSERT(DeviceExtension->DevicePnPState == NotStarted);
  1186. ASSERT(DeviceExtension->AcpiInterfaces == NULL);
  1187. KeInitializeEvent( &event, NotificationEvent, FALSE );
  1188. acpiInterfaces = ExAllocatePoolWithTag(PagedPool,
  1189. sizeof(ACPI_INTERFACE_STANDARD),
  1190. PROCESSOR_POOL_TAG);
  1191. if (!acpiInterfaces) {
  1192. return STATUS_INSUFFICIENT_RESOURCES;
  1193. }
  1194. irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  1195. DeviceExtension->NextLowerDriver,
  1196. NULL,
  1197. 0,
  1198. NULL,
  1199. &event,
  1200. &ioStatusBlock);
  1201. if (!irp) {
  1202. status = STATUS_INSUFFICIENT_RESOURCES;
  1203. goto AcquireAcpiInterfacesExit;
  1204. }
  1205. irpStack = IoGetNextIrpStackLocation(irp);
  1206. irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  1207. irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_ACPI_INTERFACE_STANDARD;
  1208. irpStack->Parameters.QueryInterface.Size = sizeof(ACPI_INTERFACE_STANDARD);
  1209. irpStack->Parameters.QueryInterface.Version = 1;
  1210. irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) acpiInterfaces;
  1211. irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1212. //
  1213. // Initialize the status to error in case the ACPI driver decides not to
  1214. // set it correctly.
  1215. //
  1216. irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
  1217. status = IoCallDriver( DeviceExtension->NextLowerDriver, irp );
  1218. if (!NT_SUCCESS(status)) {
  1219. goto AcquireAcpiInterfacesExit;
  1220. }
  1221. if (status == STATUS_PENDING) {
  1222. KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
  1223. status = ioStatusBlock.Status;
  1224. }
  1225. if (NT_SUCCESS(status)) {
  1226. DeviceExtension->AcpiInterfaces = acpiInterfaces;
  1227. //
  1228. // Reference the interface.
  1229. //
  1230. if (DeviceExtension->AcpiInterfaces->InterfaceReference) {
  1231. DeviceExtension->AcpiInterfaces->InterfaceReference(DeviceExtension->AcpiInterfaces->Context);
  1232. }
  1233. //
  1234. // Register for notification callbacks.
  1235. //
  1236. callbackStatus =
  1237. DeviceExtension->AcpiInterfaces->RegisterForDeviceNotifications(
  1238. DeviceExtension->UnderlyingPDO,
  1239. AcpiNotifyCallback,
  1240. DeviceExtension
  1241. );
  1242. if (!NT_SUCCESS(callbackStatus)) {
  1243. DebugAssert(!"AcpiInterfaces->RegisterForDeviceNotifications() Failed!");
  1244. if (DeviceExtension->AcpiInterfaces->InterfaceDereference) {
  1245. DeviceExtension->AcpiInterfaces->InterfaceDereference(DeviceExtension->AcpiInterfaces->Context);
  1246. }
  1247. DeviceExtension->AcpiInterfaces = NULL;
  1248. status = callbackStatus;
  1249. goto AcquireAcpiInterfacesExit;
  1250. }
  1251. }
  1252. AcquireAcpiInterfacesExit:
  1253. if (!NT_SUCCESS(status)) {
  1254. if (acpiInterfaces) {
  1255. ExFreePool(acpiInterfaces);
  1256. }
  1257. }
  1258. return status;
  1259. }
  1260. NTSTATUS
  1261. ReleaseAcpiInterfaces(
  1262. PFDO_DATA DeviceExtension
  1263. )
  1264. /*++
  1265. Routine Description:
  1266. This routine releases the ACPI interfaces.
  1267. Arguments:
  1268. DeviceExtension
  1269. Return Value:
  1270. NTSTATUS
  1271. --*/
  1272. {
  1273. DebugEnter();
  1274. PAGED_CODE();
  1275. ASSERT(DeviceExtension->DevicePnPState == Deleted);
  1276. ASSERT(DeviceExtension->AcpiInterfaces != NULL);
  1277. //
  1278. // Unregister for device notification.
  1279. //
  1280. DeviceExtension->AcpiInterfaces->UnregisterForDeviceNotifications(
  1281. DeviceExtension->UnderlyingPDO,
  1282. AcpiNotifyCallback
  1283. );
  1284. //
  1285. // Dereference the interface.
  1286. //
  1287. DeviceExtension->AcpiInterfaces->InterfaceDereference(DeviceExtension->AcpiInterfaces->Context);
  1288. DeviceExtension->AcpiInterfaces = NULL;
  1289. return STATUS_SUCCESS;
  1290. }
  1291. VOID
  1292. AcpiNotifyCallback(
  1293. PVOID Context,
  1294. ULONG NotifyCode
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. Arguments:
  1299. Return Value:
  1300. --*/
  1301. {
  1302. PFDO_DATA DeviceExtension = (PFDO_DATA)Context;
  1303. PIO_WORKITEM workItem;
  1304. DebugEnter();
  1305. if ((DeviceExtension->DevicePnPState != Started) ||
  1306. (DeviceExtension->LegacyInterface)) {
  1307. //
  1308. // Ignore notifications that come in while the device
  1309. // isn't started, or if we are using the legacy interface.
  1310. //
  1311. return;
  1312. }
  1313. //
  1314. // Allocate work item
  1315. //
  1316. workItem = IoAllocateWorkItem(DeviceExtension->Self);
  1317. if (!workItem) {
  1318. DebugPrint((ERROR, "IoAllocateWorkItem() Failed!\n"));
  1319. return; // STATUS_INSUFFICIENT_RESOURCES
  1320. }
  1321. switch (NotifyCode) {
  1322. case 0x80:
  1323. IoQueueWorkItem(workItem,
  1324. AcpiNotify80CallbackWorker,
  1325. DelayedWorkQueue,
  1326. workItem);
  1327. break;
  1328. case 0x81:
  1329. IoQueueWorkItem(workItem,
  1330. AcpiNotify81CallbackWorker,
  1331. DelayedWorkQueue,
  1332. workItem);
  1333. break;
  1334. default:
  1335. DebugPrint((ERROR, "Unrecognized Notify code (0x%x)\n", NotifyCode));
  1336. IoFreeWorkItem(workItem);
  1337. break;
  1338. }
  1339. return;
  1340. }
  1341. VOID
  1342. AcpiNotify80CallbackWorker(
  1343. IN PDEVICE_OBJECT DeviceObject,
  1344. IN PVOID Context
  1345. )
  1346. /*++
  1347. Routine Description:
  1348. Arguments:
  1349. DeviceObject -
  1350. Context - If we were called as part of a WorkItem, "Context" is a pointer
  1351. to the WorkItem, otherwise, this value is NULL
  1352. Return Value:
  1353. --*/
  1354. {
  1355. NTSTATUS status;
  1356. PFDO_DATA DeviceExtension = (PFDO_DATA) DeviceObject->DeviceExtension;
  1357. PPROCESSOR_PERFORMANCE_STATES oldPerfStates;
  1358. PROCESSOR_PERFORMANCE_STATES nullPerfStates = {NULL, 0, 0, 0, {0,0,0}};
  1359. DebugEnter();
  1360. PAGED_CODE();
  1361. //
  1362. // if called as WorkItem, free worker resources
  1363. //
  1364. if (Context) {
  1365. IoFreeWorkItem((PIO_WORKITEM) Context);
  1366. }
  1367. if (!DeviceExtension->PssPackage) {
  1368. //
  1369. // This machine has no _PSS package, so
  1370. // this notification shouldn't do anything.
  1371. //
  1372. return;
  1373. }
  1374. AcquireProcessorPerfStateLock(DeviceExtension);
  1375. //
  1376. // Register zero ACPI 2.0 performance states with the
  1377. // kernel so that no state gets invoked while we're
  1378. // screwing around with the DeviceExtension.
  1379. //
  1380. oldPerfStates = DeviceExtension->PerfStates;
  1381. DeviceExtension->PerfStates = &nullPerfStates;
  1382. status = RegisterStateHandlers(DeviceExtension);
  1383. //
  1384. // Need to put the orginal states back
  1385. //
  1386. DeviceExtension->PerfStates = oldPerfStates;
  1387. if (!NT_SUCCESS(status)) {
  1388. DebugAssert(!"RegisterStateHandlers(NULL PerfStates) Failed!");
  1389. goto AcpiNotify80CallbackWorkerExit;
  1390. }
  1391. //
  1392. // Calculate currently available states.
  1393. // NOTE: MergePerformanceStates will invalidate CurrentPerfState
  1394. //
  1395. status = MergePerformanceStates(DeviceExtension);
  1396. if (!NT_SUCCESS(status)) {
  1397. goto AcpiNotify80CallbackWorkerExit;
  1398. }
  1399. //
  1400. // Register new perf states with the kernel.
  1401. //
  1402. status = RegisterStateHandlers(DeviceExtension);
  1403. ASSERT(NT_SUCCESS(status));
  1404. AcpiNotify80CallbackWorkerExit:
  1405. if (!NT_SUCCESS(status)) {
  1406. //
  1407. // Something went wrong. Blow away the mess.
  1408. //
  1409. if (DeviceExtension->PerfStates) {
  1410. ExFreePool(DeviceExtension->PerfStates);
  1411. DeviceExtension->PerfStates = NULL;
  1412. DeviceExtension->CurrentPerfState = INVALID_PERF_STATE;
  1413. }
  1414. }
  1415. ReleaseProcessorPerfStateLock(DeviceExtension);
  1416. //
  1417. // Notify anyone who might be interested
  1418. //
  1419. ProcessorFireWmiEvent(DeviceExtension,
  1420. &NewPStatesEvent,
  1421. &DeviceExtension->PpcResult);
  1422. }
  1423. VOID
  1424. AcpiNotify81CallbackWorker(
  1425. IN PDEVICE_OBJECT DeviceObject,
  1426. IN PVOID Context
  1427. )
  1428. /*++
  1429. Routine Description:
  1430. Arguments:
  1431. Return Value:
  1432. --*/
  1433. {
  1434. NTSTATUS status;
  1435. PFDO_DATA DeviceExtension = (PFDO_DATA) DeviceObject->DeviceExtension;
  1436. PPROCESSOR_IDLE_STATES oldCStates;
  1437. PROCESSOR_IDLE_STATES nullCStates = {0,{0,0,{0,0,0,0,{0,0}},NULL}};
  1438. DebugEnter();
  1439. PAGED_CODE();
  1440. //
  1441. // Free worker resources
  1442. //
  1443. IoFreeWorkItem((PIO_WORKITEM) Context);
  1444. if (!DeviceExtension->CstPresent) {
  1445. //
  1446. // This machine has no _CST package, so
  1447. // this notification shouldn't do anything.
  1448. //
  1449. return;
  1450. }
  1451. AcquireProcessorPerfStateLock(DeviceExtension);
  1452. //
  1453. // Register zero ACPI 2.0 performance states with the
  1454. // kernel so that no state gets invoked while we're
  1455. // screwing around with the DeviceExtension.
  1456. //
  1457. oldCStates = DeviceExtension->CStates;
  1458. DeviceExtension->CStates = &nullCStates;
  1459. status = RegisterStateHandlers(DeviceExtension);
  1460. //
  1461. // restore previous CStates
  1462. //
  1463. DeviceExtension->CStates = oldCStates;
  1464. if (!NT_SUCCESS(status)) {
  1465. DebugAssert(!"RegisterStateHandlers(NULL CStates) Failed!");
  1466. goto AcpiNotify81CallbackWorkerExit;
  1467. }
  1468. //
  1469. // Calculate currently available Cstates.
  1470. //
  1471. status = InitializeAcpi2IoSpaceCstates(DeviceExtension);
  1472. if (!NT_SUCCESS(status)) {
  1473. goto AcpiNotify81CallbackWorkerExit;
  1474. }
  1475. //
  1476. // Register new perf states with the kernel.
  1477. //
  1478. status = RegisterStateHandlers(DeviceExtension);
  1479. ASSERT(NT_SUCCESS(status));
  1480. AcpiNotify81CallbackWorkerExit:
  1481. if (!NT_SUCCESS(status)) {
  1482. //
  1483. // Something went wrong. Blow away the mess.
  1484. //
  1485. if (DeviceExtension->CStates) {
  1486. ExFreePool(DeviceExtension->CStates);
  1487. DeviceExtension->CStates = NULL;
  1488. }
  1489. }
  1490. ReleaseProcessorPerfStateLock(DeviceExtension);
  1491. //
  1492. // Notify anyone who might be interested
  1493. //
  1494. ProcessorFireWmiEvent(DeviceExtension,
  1495. &NewCStatesEvent,
  1496. NULL);
  1497. }
  1498. NTSTATUS
  1499. Acpi2PerfStateTransitionGeneric(
  1500. IN PFDO_DATA DeviceExtension,
  1501. IN ULONG State
  1502. )
  1503. /*++
  1504. Routine Description:
  1505. This routine changes the performance state of the processor
  1506. based on ACPI 2.0 performance state objects.
  1507. NOTE: This function only understands I/O and Memory addresses,
  1508. not FFH addresses.
  1509. Arguments:
  1510. State - Index into _PSS
  1511. Return Value:
  1512. none
  1513. --*/
  1514. {
  1515. ULONG statusValue = 0;
  1516. NTSTATUS status = STATUS_SUCCESS;
  1517. DebugEnter();
  1518. DebugAssert(State >= DeviceExtension->PpcResult);
  1519. DebugAssert(State < DeviceExtension->PssPackage->NumPStates);
  1520. DebugAssert(DeviceExtension->PctPackage.Control.Address.QuadPart);
  1521. DebugAssert(DeviceExtension->PctPackage.Status.Address.QuadPart);
  1522. //
  1523. // Write Control value
  1524. //
  1525. WriteGenAddr(&DeviceExtension->PctPackage.Control,
  1526. DeviceExtension->PssPackage->State[State].Control);
  1527. //
  1528. // Get Status Value
  1529. //
  1530. statusValue = ReadGenAddr(&DeviceExtension->PctPackage.Status);
  1531. //
  1532. // Check to see if the status register matches what we expect.
  1533. //
  1534. if (statusValue != DeviceExtension->PssPackage->State[State].Status) {
  1535. DebugPrint((ERROR,
  1536. "Acpi2PerfStateTransitionGeneric: Transition failed! Expected 0x%x status value, recieved 0x%x\n",
  1537. DeviceExtension->PssPackage->State[State].Status,
  1538. statusValue));
  1539. status = STATUS_UNSUCCESSFUL;
  1540. }
  1541. DebugExitStatus(status);
  1542. return status;
  1543. }
  1544. NTSTATUS
  1545. AcpiPerfStateTransition (
  1546. IN PFDO_DATA DeviceExtension,
  1547. IN ULONG State
  1548. )
  1549. /*++
  1550. Routine Description:
  1551. Arguments:
  1552. State - Index into DeviceExtension->PerfStates
  1553. Return Value:
  1554. --*/
  1555. {
  1556. //
  1557. // Legacy drivers may use the PssPackage variable, so
  1558. // we first check for legacy, all legacy drivers have
  1559. // this flag set.
  1560. //
  1561. if (DeviceExtension->LegacyInterface) {
  1562. return AcpiLegacyPerfStateTransition(DeviceExtension, State);
  1563. } else if (DeviceExtension->PssPackage) {
  1564. //
  1565. // The State index passed in reflects an index in the current PerfStates
  1566. // registered with the kernel. Must convert it to an index into the _PSS.
  1567. //
  1568. return Acpi2PerfStateTransition(DeviceExtension,
  1569. State + DeviceExtension->PpcResult);
  1570. }
  1571. return STATUS_NOT_IMPLEMENTED;
  1572. }
  1573. NTSTATUS
  1574. InitializeAcpi2IoSpaceCstates(
  1575. IN PFDO_DATA DeviceExtension
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. This function looks to see if there is an ACPI 2.0 _CST object in the
  1580. namespace, and, if it is present and _does not_ contain CStates that
  1581. reference funtionly fixed hardware registers, it replaces the functions
  1582. found by InitializeAcpi1Cstates. This generic driver has no knowledge
  1583. of processor specific registers
  1584. Note: This is a little bit ridiculous, as the generic processor driver
  1585. can't possibly know how to use a C-state that it couldn't find via ACPI 1.0
  1586. means. Never-the-less, we should respect what we find in a _CST, if for no
  1587. other reason than that this code may be used as an example in a more complex
  1588. driver.
  1589. Further note: This function leaves the filling in of throttling functions
  1590. to the InitializePerformanceStates functions.
  1591. Arguments:
  1592. DeviceExtension
  1593. Return Value:
  1594. A NTSTATUS code to indicate the result of the initialization.
  1595. --*/
  1596. {
  1597. #define HIGHEST_SUPPORTED_CSTATE 3
  1598. PPROCESSOR_IDLE_STATES iStates;
  1599. PACPI_CST_PACKAGE cstData = NULL;
  1600. NTSTATUS status;
  1601. ULONG i;
  1602. UCHAR cState;
  1603. ULONG size;
  1604. DebugEnter();
  1605. PAGED_CODE();
  1606. //
  1607. // Find the _CST
  1608. //
  1609. status = AcpiEvaluateCst(DeviceExtension, &cstData);
  1610. if (!NT_SUCCESS(status)) {
  1611. goto InitializeAcpi2IoSpaceCstatesExit;
  1612. }
  1613. //
  1614. // The namespace contains a _CST package. So we should
  1615. // use it instead of ACPI 1.0 C-states.
  1616. //
  1617. if (DeviceExtension->CStates) {
  1618. //
  1619. // There were 1.0 C-states. Get rid of them.
  1620. //
  1621. ExFreePool(DeviceExtension->CStates);
  1622. DeviceExtension->CStates = NULL;
  1623. }
  1624. //
  1625. // Currently we only support 3 C States. We can't allocate based on
  1626. // the number of _CST cstates, as there may be more than we support
  1627. //
  1628. size = (sizeof(PROCESSOR_IDLE_STATE) *
  1629. (HIGHEST_SUPPORTED_CSTATE - 1)) +
  1630. sizeof(PROCESSOR_IDLE_STATES);
  1631. iStates = ExAllocatePoolWithTag(NonPagedPool,
  1632. size,
  1633. PROCESSOR_POOL_TAG);
  1634. if (!iStates) {
  1635. status = STATUS_INSUFFICIENT_RESOURCES;
  1636. goto InitializeAcpi2IoSpaceCstatesExit;
  1637. }
  1638. //
  1639. // Collect Acpi 2.0 CState info
  1640. //
  1641. DeviceExtension->CStates = iStates;
  1642. DeviceExtension->CstPresent = TRUE;
  1643. //
  1644. // We always support C1.
  1645. //
  1646. iStates->State[0].StateType = 1;
  1647. RtlZeroMemory(&(iStates->State[0].Register), sizeof(GEN_ADDR));
  1648. iStates->State[0].Latency = 0;
  1649. iStates->State[0].IdleHandler = AcpiC1Idle;
  1650. //
  1651. // We only support C2 & C3 on UP machines
  1652. //
  1653. if (!Globals.SingleProcessorProfile) {
  1654. goto InitializeAcpi2IoSpaceCstatesExit;
  1655. }
  1656. //
  1657. // Hunt through the _CST package looking for supported (and useful) states.
  1658. // NOTE: if the _CST contains multiple definitions for C2 or C3, we will
  1659. // use deepest state, ie the one that offers the greatest power savings.
  1660. //
  1661. //
  1662. // Start looking at C2
  1663. //
  1664. cState = 2;
  1665. for (i = 0; i < cstData->NumCStates; i++) {
  1666. if (cstData->State[i].StateType == cState) {
  1667. DebugPrint((INFO, "Found CState C%u\n", cState));
  1668. //
  1669. // Look ahead to see if another identicle C state with greater power
  1670. // savings exists.
  1671. //
  1672. while((i+1 < cstData->NumCStates) &&
  1673. (cstData->State[i+1].StateType == cState) &&
  1674. (cstData->State[i+1].PowerConsumption < cstData->State[i].PowerConsumption) &&
  1675. (cstData->State[i+1].Register.AddressSpaceID == AcpiGenericSpaceIO)) {
  1676. i++;
  1677. }
  1678. //
  1679. // We have found a state in the package that matches the one we're
  1680. // looking for. See if we think that it's usable. This function
  1681. // only knows how to use ACPI 1.0-compatible C-states. So anything
  1682. // that is not in I/O space is out of bounds.
  1683. //
  1684. if (cstData->State[i].Register.AddressSpaceID != AcpiGenericSpaceIO) {
  1685. DebugPrint((ERROR, "InitializeAcpi2IoSpaceCstates() only supports CStates in I/O space\n"));
  1686. continue;
  1687. }
  1688. iStates->State[cState - 1].StateType = cState;
  1689. iStates->State[cState - 1].Register = cstData->State[i].Register;
  1690. iStates->State[cState - 1].Latency = cstData->State[i].Latency;
  1691. switch (cState) {
  1692. case 2:
  1693. iStates->State[cState - 1].IdleHandler = Acpi2C2Idle;
  1694. C2Address = iStates->State[cState - 1].Register;
  1695. break;
  1696. case 3:
  1697. iStates->State[cState - 1].IdleHandler = Acpi2C3ArbdisIdle;
  1698. C3Address = iStates->State[cState - 1].Register;
  1699. break;
  1700. default:
  1701. DebugAssert(!"Found Unsupported CState")
  1702. break;
  1703. }
  1704. //
  1705. // Look for next state
  1706. //
  1707. cState++;
  1708. //
  1709. // if we found C3, then we are finished
  1710. //
  1711. if (cState > HIGHEST_SUPPORTED_CSTATE) {
  1712. break;
  1713. }
  1714. }
  1715. }
  1716. //
  1717. // "Count" represents the highest supported C State found,
  1718. // must be < MAX_IDLE_HANDLERS.
  1719. //
  1720. iStates->Count = cState - 1;
  1721. InitializeAcpi2IoSpaceCstatesExit:
  1722. if (cstData) {
  1723. ExFreePool(cstData);
  1724. }
  1725. DebugExitStatus(status);
  1726. return status;
  1727. }
  1728. VOID
  1729. AssumeProcessorPerformanceControl (
  1730. VOID
  1731. )
  1732. /*++
  1733. Routine Description:
  1734. Arguments:
  1735. Return Value:
  1736. --*/
  1737. {
  1738. DebugEnter();
  1739. DebugAssert(HalpFixedAcpiDescTable.smi_cmd_io_port);
  1740. //
  1741. // In Acpi 2.0, the FADT->pstate_control contains the magic value to write to
  1742. // the SMI Command port to turn off bios control of processor performance control
  1743. //
  1744. if (HalpFixedAcpiDescTable.pstate_control) {
  1745. WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR) HalpFixedAcpiDescTable.smi_cmd_io_port,
  1746. HalpFixedAcpiDescTable.pstate_control);
  1747. }
  1748. }
  1749. VOID
  1750. AssumeCStateControl (
  1751. VOID
  1752. )
  1753. /*++
  1754. Routine Description:
  1755. Arguments:
  1756. Return Value:
  1757. --*/
  1758. {
  1759. DebugEnter();
  1760. DebugAssert(HalpFixedAcpiDescTable.smi_cmd_io_port);
  1761. //
  1762. // In Acpi 2.0, the FADT->cstate_control contains the magic value to write to
  1763. // the SMI Command port to turn off bios control of Acpi 2.0 Cstates
  1764. //
  1765. if (HalpFixedAcpiDescTable.cstate_control) {
  1766. WRITE_PORT_UCHAR((PUCHAR)(ULONG_PTR) HalpFixedAcpiDescTable.smi_cmd_io_port,
  1767. HalpFixedAcpiDescTable.cstate_control);
  1768. }
  1769. }
  1770. NTSTATUS
  1771. GetRegistryDwordValue (
  1772. IN PWCHAR RegKey,
  1773. IN PWCHAR ValueName,
  1774. OUT PULONG RegData
  1775. )
  1776. /*++
  1777. Routine Description:
  1778. Arguments:
  1779. Return Value:
  1780. NTSTATUS
  1781. --*/
  1782. {
  1783. NTSTATUS ntStatus = STATUS_SUCCESS;
  1784. ULONG_PTR zero = 0;
  1785. RTL_QUERY_REGISTRY_TABLE paramTable[2] = {0}; // terminate with null table entry
  1786. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1787. paramTable[0].Name = ValueName;
  1788. paramTable[0].EntryContext = RegData;
  1789. paramTable[0].DefaultType = REG_DWORD;
  1790. paramTable[0].DefaultData = &zero;
  1791. paramTable[0].DefaultLength = sizeof(zero);
  1792. ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  1793. RegKey,
  1794. &paramTable[0],
  1795. NULL, // Context
  1796. NULL); // Environment
  1797. return ntStatus;
  1798. }
  1799. NTSTATUS
  1800. SetRegistryStringValue (
  1801. IN PWCHAR RegKey,
  1802. IN PWCHAR ValueName,
  1803. IN PWCHAR String
  1804. )
  1805. /*++
  1806. Routine Description:
  1807. Arguments:
  1808. Return Value:
  1809. NTSTATUS
  1810. --*/
  1811. {
  1812. return RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  1813. RegKey,
  1814. ValueName,
  1815. REG_SZ,
  1816. String,
  1817. (wcslen(String)+1) * sizeof(WCHAR));
  1818. }
  1819. NTSTATUS
  1820. GetRegistryStringValue (
  1821. IN PWCHAR RegKey,
  1822. IN PWCHAR ValueName,
  1823. OUT PUNICODE_STRING RegString
  1824. )
  1825. /*++
  1826. Routine Description:
  1827. Arguments:
  1828. Return Value:
  1829. NTSTATUS
  1830. --*/
  1831. {
  1832. NTSTATUS status;
  1833. ULONG_PTR zero = 0;
  1834. RTL_QUERY_REGISTRY_TABLE paramTable[2] = {0}; // terminate with null table entry
  1835. DebugEnter();
  1836. DebugAssert(RegString);
  1837. RtlZeroMemory(RegString, sizeof(UNICODE_STRING));
  1838. paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1839. paramTable[0].Name = ValueName;
  1840. paramTable[0].EntryContext = RegString;
  1841. paramTable[0].DefaultType = REG_SZ;
  1842. paramTable[0].DefaultData = &zero;
  1843. paramTable[0].DefaultLength = sizeof(zero);
  1844. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  1845. RegKey,
  1846. &paramTable[0],
  1847. NULL, // Context
  1848. NULL); // Environment
  1849. DebugExitStatus(status);
  1850. return status;
  1851. }
  1852. #ifdef _X86_
  1853. NTSTATUS
  1854. FASTCALL
  1855. SetPerfLevelGeneric(
  1856. IN UCHAR Throttle,
  1857. IN PFDO_DATA DeviceExtension
  1858. )
  1859. /*++
  1860. Routine Description:
  1861. Arguments:
  1862. Return Value:
  1863. --*/
  1864. {
  1865. ULONG newState, lowestPerfState;
  1866. ULONG throttleValue;
  1867. NTSTATUS status = STATUS_SUCCESS;
  1868. //DebugEnter();
  1869. DebugAssert(DeviceExtension);
  1870. DebugPrint((TRACE, "SetPerfLevelGeneric: Throttling to %u%%\n", Throttle));
  1871. //
  1872. // Save Throttle uncase we aren't able to Throttle
  1873. //
  1874. DeviceExtension->LastRequestedThrottle = Throttle;
  1875. //
  1876. // Run through the performance states looking for one
  1877. // that matches this throttling level.
  1878. //
  1879. for (newState = 0; newState < DeviceExtension->PerfStates->Count; newState++) {
  1880. if (DeviceExtension->PerfStates->State[newState].PercentFrequency <= Throttle) {
  1881. DebugPrint((TRACE, " Found Match! PerfState = %u, Freq %u%%\n",
  1882. newState,
  1883. DeviceExtension->PerfStates->State[newState].PercentFrequency));
  1884. break;
  1885. }
  1886. }
  1887. if (newState >= DeviceExtension->PerfStates->Count) {
  1888. DebugPrint((ERROR, "Couldn't find match for throttle request of %u%%\n", Throttle));
  1889. status = STATUS_UNSUCCESSFUL;
  1890. goto SetPerfLevelGenericExit;
  1891. }
  1892. if (newState == DeviceExtension->CurrentPerfState) {
  1893. //
  1894. // No work to do.
  1895. //
  1896. goto SetPerfLevelGenericExit;
  1897. }
  1898. //
  1899. // NOTE: The current state maybe invalid ie. 0xff, this happens notify(0x80).
  1900. //
  1901. lowestPerfState = DeviceExtension->LowestPerfState;
  1902. if (newState <= lowestPerfState) {
  1903. //
  1904. // If throttling is on, turn it off.
  1905. //
  1906. if (DeviceExtension->ThrottleValue) {
  1907. ProcessorThrottle((UCHAR)HalpThrottleScale);
  1908. DeviceExtension->ThrottleValue = 0;
  1909. }
  1910. status = AcpiPerfStateTransition(DeviceExtension, newState);
  1911. } else {
  1912. //
  1913. // Throttle states/percentages are build from the lowest Perf State, make
  1914. // sure we are currently in the lowest perf state.
  1915. //
  1916. if (DeviceExtension->CurrentPerfState != lowestPerfState) {
  1917. AcpiPerfStateTransition(DeviceExtension, lowestPerfState);
  1918. }
  1919. //
  1920. // this state is a throttle state, so throttle even if the Transition to
  1921. // low volts fails.
  1922. //
  1923. throttleValue = HalpThrottleScale - (newState - lowestPerfState);
  1924. DebugAssert(throttleValue);
  1925. DebugAssert(HalpThrottleScale != throttleValue);
  1926. ProcessorThrottle((UCHAR)throttleValue);
  1927. DeviceExtension->ThrottleValue = throttleValue;
  1928. status = STATUS_SUCCESS;
  1929. }
  1930. //
  1931. // Keep track of the state we just set.
  1932. //
  1933. DeviceExtension->LastTransitionResult = status;
  1934. if (NT_SUCCESS(status)) {
  1935. DeviceExtension->CurrentPerfState = newState;
  1936. }
  1937. //
  1938. // Notify any interested parties
  1939. //
  1940. if (PStateEvent.Enabled) {
  1941. PSTATE_EVENT data;
  1942. data.State = newState;
  1943. data.Status = status;
  1944. data.Latency = 0; // latency
  1945. data.Speed = DeviceExtension->PerfStates->State[newState].Frequency;
  1946. ProcessorFireWmiEvent(DeviceExtension, &PStateEvent, &data);
  1947. }
  1948. SetPerfLevelGenericExit:
  1949. return status;
  1950. }
  1951. NTSTATUS
  1952. FASTCALL
  1953. SetThrottleLevelGeneric (
  1954. IN UCHAR Throttle,
  1955. IN PFDO_DATA DeviceExtension
  1956. )
  1957. /*++
  1958. Routine Description:
  1959. Arguments:
  1960. Return Value:
  1961. --*/
  1962. {
  1963. UCHAR adjustedState;
  1964. UCHAR state;
  1965. UCHAR numAcpi2PerfStates;
  1966. DebugEnter();
  1967. DebugAssert(DeviceExtension);
  1968. DebugPrint((TRACE, " Throttling to %u%%\n", Throttle));
  1969. //
  1970. // Save Throttle in case we aren't able to Throttle
  1971. //
  1972. DeviceExtension->LastRequestedThrottle = Throttle;
  1973. //
  1974. // Run through the performance states looking for one
  1975. // that matches this throttling level.
  1976. //
  1977. for (state = 0; state < DeviceExtension->PerfStates->Count; state++) {
  1978. if (DeviceExtension->PerfStates->State[state].PercentFrequency <= Throttle) {
  1979. break;
  1980. }
  1981. }
  1982. //
  1983. // We didn't find a match, or HalpThrottleScale is incorrect.
  1984. // Either case is a problem.
  1985. //
  1986. if ((state >= DeviceExtension->PerfStates->Count) ||
  1987. (state >= HalpThrottleScale)) {
  1988. DebugAssert(!"SetThrottleLevel() Invalid state!");
  1989. return STATUS_UNSUCCESSFUL;
  1990. }
  1991. if (state == DeviceExtension->CurrentPerfState) {
  1992. return STATUS_SUCCESS;
  1993. }
  1994. //
  1995. // if state == 0, then we are turning stop throttling off.
  1996. //
  1997. ProcessorThrottle((UCHAR)HalpThrottleScale - state);
  1998. DeviceExtension->ThrottleValue = HalpThrottleScale - state;
  1999. DeviceExtension->CurrentPerfState = state;
  2000. //
  2001. // Notify any interested parties
  2002. //
  2003. if (PStateEvent.Enabled) {
  2004. PSTATE_EVENT data;
  2005. data.State = state;
  2006. data.Status = STATUS_SUCCESS;
  2007. data.Latency = 0; // latency
  2008. data.Speed = DeviceExtension->PerfStates->State[state].Frequency;
  2009. ProcessorFireWmiEvent(DeviceExtension, &PStateEvent, &data);
  2010. }
  2011. return STATUS_SUCCESS;
  2012. }
  2013. #endif
  2014. NTSTATUS
  2015. MergePerformanceStatesGeneric(
  2016. IN PFDO_DATA DeviceExtension
  2017. )
  2018. /*++
  2019. Routine Description:
  2020. This routine looks at the performance states in the device extension.
  2021. Note: The caller must hold PerfStateLock.
  2022. Arguments:
  2023. DeviceExtension
  2024. Return Value:
  2025. A NTSTATUS code to indicate the result of the initialization.
  2026. NOTE:
  2027. This is called during START_DEVICE, and after recieving a Notify(0x80)
  2028. on the processor.
  2029. --*/
  2030. {
  2031. NTSTATUS status = STATUS_SUCCESS;
  2032. ULONG oldBuffSize, newBuffSize, state;
  2033. ULONG availablePerfStates, numThrottlingStates;
  2034. ULONG lowestPerfState, lowestPerfStateFreq;
  2035. ULONG maxFreq, maxTransitionLatency = 0;
  2036. PPROCESSOR_PERFORMANCE_STATES newPerfStates;
  2037. DebugEnter();
  2038. PAGED_CODE();
  2039. //
  2040. // Find out how many performance states this machine currently supports
  2041. // by evaluating the ACPI 2.0 _PPC object.
  2042. //
  2043. if (DeviceExtension->PssPackage) {
  2044. status = BuildAvailablePerfStatesFromPss(DeviceExtension);
  2045. if (!NT_SUCCESS(status)) {
  2046. goto MergePerformanceStatesExit;
  2047. }
  2048. }
  2049. //
  2050. // We may have already found Acpi 2.0 or Legacy performance states
  2051. // we need to add those to any duty-cycle throttling states supported.
  2052. // So allocate a buffer big enough to hold them all.
  2053. //
  2054. DebugAssert(DeviceExtension->PerfStates);
  2055. availablePerfStates = DeviceExtension->PerfStates->Count;
  2056. oldBuffSize = sizeof(PROCESSOR_PERFORMANCE_STATES) +
  2057. (sizeof(PROCESSOR_PERFORMANCE_STATE) *
  2058. (availablePerfStates - 1));
  2059. //
  2060. // Calculate addition supported throttling states
  2061. //
  2062. numThrottlingStates = GetNumThrottleSettings(DeviceExtension);
  2063. availablePerfStates += numThrottlingStates;
  2064. newBuffSize = oldBuffSize +
  2065. (sizeof(PROCESSOR_PERFORMANCE_STATE) * numThrottlingStates);
  2066. newPerfStates = ExAllocatePoolWithTag(NonPagedPool,
  2067. newBuffSize,
  2068. PROCESSOR_POOL_TAG);
  2069. if (!newPerfStates) {
  2070. status = STATUS_INSUFFICIENT_RESOURCES;
  2071. goto MergePerformanceStatesExit;
  2072. }
  2073. RtlZeroMemory(newPerfStates, newBuffSize);
  2074. DebugAssert(newBuffSize >= oldBuffSize);
  2075. RtlCopyMemory(newPerfStates,
  2076. DeviceExtension->PerfStates,
  2077. oldBuffSize);
  2078. //
  2079. // Figure out which performance states to keep. At present,
  2080. // we believe that there is no advantage to throttling at any
  2081. // voltage other than the lowest. E.g. we will drop voltage until
  2082. // there is no more voltage to drop, throttling after that.
  2083. //
  2084. maxFreq = GetMaxProcFrequency(DeviceExtension);
  2085. //
  2086. // Now cycle through any throttling states, appending them if appropriate.
  2087. // PerfStates->Count - 1 is the lowest perf state. This state will be the one
  2088. // used to calculate frequency and power values from for throttling states.
  2089. //
  2090. lowestPerfState = DeviceExtension->PerfStates->Count - 1;
  2091. lowestPerfStateFreq = DeviceExtension->PerfStates->State[lowestPerfState].Frequency;
  2092. for (state = lowestPerfState + 1;
  2093. state < numThrottlingStates + lowestPerfState;
  2094. state++) {
  2095. //
  2096. // Frequency is some fraction of the lowest perf state frequency.
  2097. //
  2098. newPerfStates->State[state].Frequency = lowestPerfStateFreq *
  2099. (numThrottlingStates - (state - lowestPerfState)) / numThrottlingStates;
  2100. newPerfStates->State[state].PercentFrequency =
  2101. (UCHAR)PERCENT_TO_PERF_LEVEL((newPerfStates->State[state].Frequency * 100) / maxFreq);
  2102. DebugAssert(newPerfStates->State[state].PercentFrequency <= 100);
  2103. //
  2104. // Mark this state as a Throttling State
  2105. //
  2106. newPerfStates->State[state].Flags = PROCESSOR_STATE_TYPE_THROTTLE;
  2107. //
  2108. // Stop processing when we have found all states greater than 200mhz or
  2109. // 25% of max speed
  2110. //
  2111. #define LOWEST_USABLE_FREQUENCY 200
  2112. #define REQUIRED_THROTTLE_LEVEL 25
  2113. if ((newPerfStates->State[state].Frequency < LOWEST_USABLE_FREQUENCY) &&
  2114. (newPerfStates->State[state].PercentFrequency < REQUIRED_THROTTLE_LEVEL)) {
  2115. DebugPrint((INFO, "Droping all Perf States after state %u: Freq=%u Percent=%u\n",
  2116. state,
  2117. newPerfStates->State[state].Frequency,
  2118. newPerfStates->State[state].PercentFrequency));
  2119. break;
  2120. }
  2121. }
  2122. newPerfStates->Count = (UCHAR) state;
  2123. //
  2124. // Replace old perf states with new.
  2125. //
  2126. ExFreePool(DeviceExtension->PerfStates);
  2127. DeviceExtension->PerfStates = newPerfStates;
  2128. DeviceExtension->CurrentPerfState = INVALID_PERF_STATE;
  2129. DumpProcessorPerfStates(newPerfStates);
  2130. MergePerformanceStatesExit:
  2131. DebugExitStatus(status);
  2132. return status;
  2133. }
  2134. NTSTATUS
  2135. BuildAvailablePerfStatesFromPss (
  2136. PFDO_DATA DeviceExtension
  2137. )
  2138. /*++
  2139. Routine Description:
  2140. Arguments:
  2141. Return Value:
  2142. --*/
  2143. {
  2144. NTSTATUS status;
  2145. ULONG availablePerfStates, ppcResult, perfStatesSize;
  2146. ULONG maxFreq, maxTransitionLatency = 0, state;
  2147. DebugEnter();
  2148. DebugAssert(DeviceExtension->PssPackage);
  2149. //
  2150. // if this is a legacy system, simulate the _PPC method
  2151. //
  2152. if (DeviceExtension->LegacyInterface) {
  2153. status = STATUS_SUCCESS;
  2154. ppcResult = DeviceExtension->PpcResult;
  2155. } else {
  2156. status = AcpiEvaluatePpc(DeviceExtension, &ppcResult);
  2157. }
  2158. if (!NT_SUCCESS(status)) {
  2159. goto BuildAvailablePerfStatesFromPssExit;
  2160. }
  2161. if (ppcResult > (ULONG)(DeviceExtension->PssPackage->NumPStates - 1)) {
  2162. //
  2163. // Log Error
  2164. //
  2165. QueueEventLogWrite(DeviceExtension,
  2166. PROCESSOR_PCT_ERROR,
  2167. ppcResult);
  2168. //
  2169. // change ppcResult to valid value
  2170. //
  2171. ppcResult = DeviceExtension->PssPackage->NumPStates - 1;
  2172. }
  2173. DeviceExtension->PpcResult = ppcResult;
  2174. availablePerfStates = DeviceExtension->PssPackage->NumPStates - ppcResult;
  2175. DeviceExtension->LowestPerfState = availablePerfStates - 1;
  2176. DeviceExtension->CurrentPerfState = INVALID_PERF_STATE;
  2177. //
  2178. // if there were already PerfStates, they were probably acpi 1.0 type
  2179. // throttling, so we will blow them away, because they will be recreated
  2180. // in MergePerformanceStates()
  2181. //
  2182. if (DeviceExtension->PerfStates) {
  2183. ExFreePool(DeviceExtension->PerfStates);
  2184. }
  2185. perfStatesSize = sizeof(PROCESSOR_PERFORMANCE_STATES) +
  2186. (sizeof(PROCESSOR_PERFORMANCE_STATE) *
  2187. (availablePerfStates - 1));
  2188. DeviceExtension->PerfStates = ExAllocatePoolWithTag(PagedPool,
  2189. perfStatesSize,
  2190. PROCESSOR_POOL_TAG);
  2191. if (!DeviceExtension->PerfStates) {
  2192. status = STATUS_INSUFFICIENT_RESOURCES;
  2193. goto BuildAvailablePerfStatesFromPssExit;
  2194. }
  2195. RtlZeroMemory(DeviceExtension->PerfStates,
  2196. perfStatesSize);
  2197. maxFreq = GetMaxProcFrequency(DeviceExtension);
  2198. for (state = 0; state < availablePerfStates; state++) {
  2199. //
  2200. // Fill in the _PPC states, top down.
  2201. //
  2202. DeviceExtension->PerfStates->State[state].Frequency =
  2203. DeviceExtension->PssPackage->State[state + ppcResult].CoreFrequency;
  2204. DeviceExtension->PerfStates->State[state].PercentFrequency =
  2205. PERCENT_TO_PERF_LEVEL(
  2206. (DeviceExtension->PerfStates->State[state].Frequency * 100) / maxFreq);
  2207. //
  2208. // Mark this state as a Performance State
  2209. //
  2210. DeviceExtension->PerfStates->State[state].Flags = PROCESSOR_STATE_TYPE_PERFORMANCE;
  2211. maxTransitionLatency =
  2212. MAX(maxTransitionLatency,
  2213. DeviceExtension->PssPackage->State[state + ppcResult].Latency);
  2214. }
  2215. DeviceExtension->PerfStates->TransitionLatency = maxTransitionLatency;
  2216. DeviceExtension->PerfStates->TransitionFunction = SetPerfLevel;
  2217. DeviceExtension->PerfStates->Count = state;
  2218. BuildAvailablePerfStatesFromPssExit:
  2219. DebugExitStatus(status);
  2220. return status;
  2221. }
  2222. ULONG
  2223. GetMaxProcFrequency(
  2224. PFDO_DATA DeviceExtension
  2225. )
  2226. /*++
  2227. Routine Description:
  2228. Arguments:
  2229. Return Value:
  2230. --*/
  2231. {
  2232. NTSTATUS status;
  2233. ULONG frequency = 0;
  2234. static ULONG regSpeed = 0;
  2235. DebugEnter();
  2236. PAGED_CODE();
  2237. //
  2238. // First we check for Acpi 2.0 info, then NonAcpi info, and if we haven't
  2239. // yet gathered either of those, then we use the CPU speed from the registy.
  2240. //
  2241. if (DeviceExtension->PssPackage) {
  2242. frequency = DeviceExtension->PssPackage->State[0].CoreFrequency;
  2243. } else if (DeviceExtension->LegacyInterface) {
  2244. GetLegacyMaxProcFrequency(&frequency);
  2245. } else {
  2246. //
  2247. // Retrieve cpu speed from the registry.
  2248. //
  2249. if (!regSpeed) {
  2250. status = GetRegistryDwordValue(CPU0_REG_KEY,
  2251. L"~MHz",
  2252. &regSpeed);
  2253. }
  2254. frequency = regSpeed;
  2255. }
  2256. //
  2257. // We couldn't find the max speed, so we will have to guess.
  2258. //
  2259. if (!frequency) {
  2260. frequency = 650; // a reasonable guess?
  2261. }
  2262. DebugExitValue(frequency);
  2263. return frequency;
  2264. }
  2265. NTSTATUS
  2266. SaveCurrentStateGoToLowVolts(
  2267. IN PFDO_DATA DevExt
  2268. )
  2269. /*++
  2270. Routine Description:
  2271. Arguments:
  2272. Return Value:
  2273. --*/
  2274. {
  2275. ULONG targetState;
  2276. DebugEnter();
  2277. //
  2278. // Throttling should be off, and if we have perf states, then we
  2279. // should be at the lowest state.
  2280. //
  2281. if (DevExt->PerfStates && (DevExt->CurrentPerfState != INVALID_PERF_STATE)) {
  2282. AcquireProcessorPerfStateLock(DevExt);
  2283. //
  2284. // Save current throttle percentage
  2285. //
  2286. DebugAssert(DevExt->CurrentPerfState < DevExt->PerfStates->Count);
  2287. DevExt->SavedState = DevExt->PerfStates->State[DevExt->CurrentPerfState].PercentFrequency;
  2288. //
  2289. // Go to lowest Performance state
  2290. //
  2291. targetState = DevExt->LowestPerfState;
  2292. if (DevExt->PerfStates->TransitionFunction) {
  2293. DevExt->PerfStates->TransitionFunction(
  2294. (UCHAR)DevExt->PerfStates->State[targetState].PercentFrequency);
  2295. }
  2296. ReleaseProcessorPerfStateLock(DevExt);
  2297. }
  2298. return STATUS_SUCCESS;
  2299. }
  2300. NTSTATUS
  2301. RestoreToSavedPerformanceState(
  2302. IN PFDO_DATA DeviceExtension
  2303. )
  2304. /*++
  2305. Routine Description:
  2306. Arguments:
  2307. Return Value:
  2308. --*/
  2309. {
  2310. //
  2311. // BUG 615135: remove code that restores save processor performance state,
  2312. // as it causes the kernel to get out of sync.
  2313. //
  2314. return STATUS_SUCCESS;
  2315. }
  2316. NTSTATUS
  2317. SetProcessorPerformanceState(
  2318. IN ULONG TargetPerfState,
  2319. IN PFDO_DATA DeviceExtension
  2320. )
  2321. /*++
  2322. Routine Description:
  2323. Arguments:
  2324. Return Value:
  2325. --*/
  2326. {
  2327. NTSTATUS status;
  2328. DebugEnter();
  2329. DebugAssert(DeviceExtension);
  2330. DebugPrint((TRACE, "Transitioning to state 0x%x\n", TargetPerfState));
  2331. if (TargetPerfState < DeviceExtension->PerfStates->Count) {
  2332. DeviceExtension->PerfStates->TransitionFunction(
  2333. (UCHAR)DeviceExtension->PerfStates->State[TargetPerfState].PercentFrequency);
  2334. status = STATUS_SUCCESS;
  2335. } else {
  2336. //
  2337. // not a vaild state
  2338. //
  2339. DebugPrint((TRACE, "%u is not a valid Processor Performance State\n"));
  2340. status = STATUS_UNSUCCESSFUL;
  2341. }
  2342. return status;
  2343. }
  2344. NTSTATUS
  2345. QueueEventLogWrite(
  2346. IN PFDO_DATA DeviceExtension,
  2347. IN ULONG EventErrorCode,
  2348. IN ULONG EventValue
  2349. )
  2350. /*++
  2351. Routine Description:
  2352. Arguments:
  2353. Return Value:
  2354. --*/
  2355. {
  2356. PEVENT_LOG_CONTEXT context;
  2357. context = ExAllocatePoolWithTag(NonPagedPool,
  2358. sizeof(EVENT_LOG_CONTEXT),
  2359. PROCESSOR_POOL_TAG);
  2360. if (!context) {
  2361. return STATUS_INSUFFICIENT_RESOURCES;
  2362. }
  2363. context->EventErrorCode = EventErrorCode;
  2364. context->EventValue = EventValue;
  2365. context->WorkItem = IoAllocateWorkItem(DeviceExtension->Self);
  2366. if (context->WorkItem) {
  2367. //
  2368. // Log error to event log
  2369. //
  2370. IoQueueWorkItem(context->WorkItem,
  2371. ProcessEventLogEntry,
  2372. DelayedWorkQueue,
  2373. context);
  2374. return STATUS_SUCCESS;
  2375. } else {
  2376. DebugPrint((ERROR, "IoAllocateWorkItem() Failed!\n"));
  2377. ExFreePool(context);
  2378. return STATUS_INSUFFICIENT_RESOURCES;
  2379. }
  2380. }
  2381. VOID
  2382. ProcessEventLogEntry (
  2383. IN PDEVICE_OBJECT DeviceObject,
  2384. IN PVOID Context
  2385. )
  2386. /*++
  2387. Routine Description:
  2388. Arguments:
  2389. Return Value:
  2390. --*/
  2391. {
  2392. WCHAR eventLogValue[11];
  2393. UNICODE_STRING eventLogErrorString;
  2394. PEVENT_LOG_CONTEXT workItem = (PEVENT_LOG_CONTEXT) Context;
  2395. PVOID string = NULL;
  2396. ULONG stringCount = 0;
  2397. DebugEnter();
  2398. DebugAssert(Context);
  2399. PAGED_CODE();
  2400. //
  2401. // Free worker resources
  2402. //
  2403. IoFreeWorkItem(workItem->WorkItem);
  2404. switch (workItem->EventErrorCode) {
  2405. case PROCESSOR_PCT_ERROR:
  2406. case PROCESSOR_INIT_TRANSITION_FAILURE:
  2407. eventLogErrorString.Buffer = eventLogValue;
  2408. eventLogErrorString.MaximumLength = sizeof(eventLogValue);
  2409. RtlIntegerToUnicodeString(workItem->EventValue, 10, &eventLogErrorString);
  2410. string = &eventLogErrorString.Buffer;
  2411. stringCount = 1;
  2412. break;
  2413. case PROCESSOR_LEGACY_INTERFACE_FAILURE:
  2414. case PROCESSOR_INITIALIZATION_FAILURE:
  2415. case PROCESSOR_REINITIALIZATION_FAILURE:
  2416. //
  2417. // no strings
  2418. //
  2419. break;
  2420. default:
  2421. DebugPrint((ERROR, "ProcessEventLogEntry: Unknown EventErrorCode\n"));
  2422. goto ProcessEventLogEntryExit;
  2423. }
  2424. //
  2425. // Write Event
  2426. //
  2427. WriteEventLogEntry(DeviceObject,
  2428. workItem->EventErrorCode,
  2429. string,
  2430. stringCount,
  2431. NULL,
  2432. 0);
  2433. ProcessEventLogEntryExit:
  2434. ExFreePool(Context);
  2435. }
  2436. NTSTATUS
  2437. PowerStateHandlerNotificationRegistration (
  2438. IN PENTER_STATE_NOTIFY_HANDLER NotifyHandler,
  2439. IN PVOID Context,
  2440. IN BOOLEAN Register
  2441. )
  2442. /*++
  2443. Routine Description:
  2444. Arguments:
  2445. Return Value:
  2446. --*/
  2447. {
  2448. POWER_STATE_NOTIFY_HANDLER newHandler = {0};
  2449. NTSTATUS status;
  2450. DebugEnter();
  2451. if (Register) {
  2452. DebugAssert(NotifyHandler);
  2453. newHandler.Handler = NotifyHandler;
  2454. newHandler.Context = Context;
  2455. }
  2456. status = ZwPowerInformation(SystemPowerStateNotifyHandler,
  2457. &newHandler,
  2458. sizeof(POWER_STATE_NOTIFY_HANDLER),
  2459. NULL,
  2460. 0);
  2461. DebugExitStatus(status);
  2462. return status;
  2463. }
  2464. NTSTATUS
  2465. ProcessMultipleApicDescTable(
  2466. PPROCESSOR_INFO ProcInfo
  2467. )
  2468. /*++
  2469. Routine Description:
  2470. Arguments:
  2471. Return Value:
  2472. --*/
  2473. {
  2474. PMAPIC mapicTable = NULL;
  2475. PUCHAR apicTable;
  2476. PUCHAR mapicTableEnd;
  2477. UCHAR apicType;
  2478. UCHAR apicSize;
  2479. DebugEnter();
  2480. DebugAssert(ProcInfo);
  2481. DebugAssert(ProcInfo->TotalProcessors == 0);
  2482. //
  2483. // Get MAPIC table
  2484. //
  2485. mapicTable = GetAcpiTable(APIC_SIGNATURE);
  2486. if (!mapicTable) {
  2487. return STATUS_UNSUCCESSFUL;
  2488. }
  2489. //
  2490. // Start of MAPIC tables
  2491. //
  2492. apicTable = (PUCHAR) mapicTable->APICTables;
  2493. //
  2494. // Calculate end of MAPIC table.
  2495. //
  2496. mapicTableEnd = (PUCHAR) mapicTable + mapicTable->Header.Length;
  2497. //
  2498. // Walk through each APIC table
  2499. //
  2500. while ((apicTable + sizeof(PROCLOCALAPIC)) <= mapicTableEnd) {
  2501. //
  2502. // individual apic tables have common header
  2503. //
  2504. apicType = ((PAPICTABLE)apicTable)->Type;
  2505. apicSize = ((PAPICTABLE)apicTable)->Length;
  2506. //
  2507. // Sanity check
  2508. //
  2509. if (!apicSize) {
  2510. DebugPrint((ERROR, "ProcessMultipleApicDescTable() table size = 0\n"));
  2511. break;
  2512. }
  2513. if (apicType == PROCESSOR_LOCAL_APIC &&
  2514. apicSize == PROCESSOR_LOCAL_APIC_LENGTH) {
  2515. PPROCLOCALAPIC procLocalApic = (PPROCLOCALAPIC) apicTable;
  2516. // toddcar - 12/08/2000: TEMP
  2517. // Should implement better method to map between processorid and ApicId.
  2518. //
  2519. //
  2520. // save Processor ID to APIC ID mappings
  2521. //
  2522. ProcInfo->ProcIdToApicId[procLocalApic->ACPIProcessorID] = procLocalApic->APICID;
  2523. ProcInfo->TotalProcessors++;
  2524. DebugAssert(ProcInfo->TotalProcessors < MAX_PROCESSOR_VALUE);
  2525. if (procLocalApic->Flags & PLAF_ENABLED) {
  2526. ProcInfo->ActiveProcessors++;
  2527. }
  2528. }
  2529. apicTable += apicSize;
  2530. }
  2531. //
  2532. // Allocated by GetAcpiTable()
  2533. //
  2534. if (mapicTable) {
  2535. ExFreePool(mapicTable);
  2536. }
  2537. return STATUS_SUCCESS;
  2538. }
  2539. extern
  2540. _inline
  2541. ULONG
  2542. GetApicId(
  2543. VOID
  2544. )
  2545. {
  2546. //
  2547. // Well known virtual address of local processor apic
  2548. //
  2549. return ((pLocalApic[LU_ID_REGISTER] & APIC_ID_MASK) >> APIC_ID_SHIFT);
  2550. }
  2551. NTSTATUS
  2552. SetProcessorFriendlyName (
  2553. PFDO_DATA DeviceExtension
  2554. )
  2555. /*++
  2556. Routine Description:
  2557. Arguments:
  2558. Return Value:
  2559. --*/
  2560. {
  2561. NTSTATUS status = STATUS_UNSUCCESSFUL;
  2562. PWCHAR driverEnumKey;
  2563. PWCHAR instanceId;
  2564. PWCHAR deviceRegKey;
  2565. ULONG size;
  2566. PUCHAR cpuBrandString = NULL;
  2567. PUCHAR tmpBrandString = NULL;
  2568. ANSI_STRING ansiCpuString;
  2569. UNICODE_STRING unicodeCpuString;
  2570. UNICODE_STRING fullDeviceId;
  2571. DebugEnter();
  2572. //
  2573. // if we already have the Processor Brand String,
  2574. // we will use it.
  2575. //
  2576. if (!Globals.ProcessorBrandString) {
  2577. //
  2578. // Get size needed
  2579. //
  2580. status = GetProcessorBrandString(NULL, &size);
  2581. if (status == STATUS_NOT_SUPPORTED || !size) {
  2582. goto SetProcessorFriendlyNameExit;
  2583. }
  2584. //
  2585. // alloc some memory
  2586. //
  2587. cpuBrandString = ExAllocatePoolWithTag(PagedPool,
  2588. size,
  2589. PROCESSOR_POOL_TAG);
  2590. if (!cpuBrandString) {
  2591. status = STATUS_INSUFFICIENT_RESOURCES;
  2592. goto SetProcessorFriendlyNameExit;
  2593. }
  2594. //
  2595. // Get Brand String
  2596. //
  2597. status = GetProcessorBrandString(cpuBrandString, &size);
  2598. if (!NT_SUCCESS(status)) {
  2599. goto SetProcessorFriendlyNameExit;
  2600. }
  2601. //
  2602. // need to save orig pointer for the free
  2603. //
  2604. tmpBrandString = cpuBrandString;
  2605. //
  2606. // some Processors include leading spaces, removed them
  2607. //
  2608. while (tmpBrandString[0] == 0x20) {
  2609. tmpBrandString++;
  2610. }
  2611. //
  2612. // Convert ansi string to wide
  2613. //
  2614. RtlInitAnsiString(&ansiCpuString, tmpBrandString);
  2615. status = RtlAnsiStringToUnicodeString(&unicodeCpuString,
  2616. &ansiCpuString,
  2617. TRUE);
  2618. if (!NT_SUCCESS(status)) {
  2619. goto SetProcessorFriendlyNameExit;
  2620. }
  2621. Globals.ProcessorBrandString = unicodeCpuString.Buffer;
  2622. }
  2623. //
  2624. // construct registy path for current pocessor device
  2625. //
  2626. //
  2627. // Construct driver enum path...
  2628. // HKLM\Machine\System\CurrentControlSet\Services\P3+\+Enum
  2629. // 2 == "\" + NULL
  2630. //
  2631. size = Globals.RegistryPath.Length +
  2632. ((wcslen(EnumKeyName) + 2) * sizeof(WCHAR));
  2633. driverEnumKey = ExAllocatePoolWithTag(PagedPool, size, PROCESSOR_POOL_TAG);
  2634. if (!driverEnumKey) {
  2635. status = STATUS_INSUFFICIENT_RESOURCES;
  2636. goto SetProcessorFriendlyNameExit;
  2637. }
  2638. //
  2639. // construct enum registry path for current device
  2640. //
  2641. _snwprintf(driverEnumKey,
  2642. size,
  2643. L"%s\\%s",
  2644. Globals.RegistryPath.Buffer,
  2645. EnumKeyName);
  2646. //
  2647. // Get Instance Id string
  2648. //
  2649. status = GetInstanceId(DeviceExtension, &instanceId);
  2650. if (!NT_SUCCESS(status)) {
  2651. goto SetProcessorFriendlyNameExit;
  2652. }
  2653. //
  2654. // get Bus\DeviceId\InstanceId path from driver's enum key
  2655. //
  2656. GetRegistryStringValue(driverEnumKey,
  2657. instanceId,
  2658. &fullDeviceId);
  2659. ExFreePool(driverEnumKey);
  2660. ExFreePool(instanceId); // allocated inside GetInstanceId
  2661. //
  2662. // alloc enough memory for entire regkey path
  2663. // 2 == "\" + NULL
  2664. //
  2665. size = fullDeviceId.Length + ((wcslen(CCSEnumRegKey) + 2) * sizeof(WCHAR));
  2666. deviceRegKey = ExAllocatePoolWithTag(PagedPool, size, PROCESSOR_POOL_TAG);
  2667. if (!deviceRegKey) {
  2668. status = STATUS_INSUFFICIENT_RESOURCES;
  2669. goto SetProcessorFriendlyNameExit;
  2670. }
  2671. //
  2672. // construct enum registry path for current device
  2673. //
  2674. _snwprintf(deviceRegKey,
  2675. size,
  2676. L"%s\\%s",
  2677. CCSEnumRegKey,
  2678. fullDeviceId.Buffer);
  2679. //
  2680. // create "FriendlyName" regkey for processor device
  2681. //
  2682. status = SetRegistryStringValue(deviceRegKey,
  2683. (PWCHAR)FriendlyNameRegKey,
  2684. Globals.ProcessorBrandString);
  2685. ExFreePool(deviceRegKey);
  2686. ExFreePool(fullDeviceId.Buffer);
  2687. SetProcessorFriendlyNameExit:
  2688. if (cpuBrandString) {
  2689. ExFreePool(cpuBrandString);
  2690. }
  2691. DebugExitStatus(status);
  2692. return status;
  2693. }
  2694. NTSTATUS
  2695. GetHardwareId(
  2696. PFDO_DATA DeviceExtension
  2697. )
  2698. /*++
  2699. Routine Description:
  2700. Arguments:
  2701. Return Value:
  2702. --*/
  2703. {
  2704. NTSTATUS status;
  2705. KEVENT event;
  2706. PIRP irp;
  2707. IO_STATUS_BLOCK ioStatusBlock;
  2708. PIO_STACK_LOCATION irpStack;
  2709. DebugEnter();
  2710. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2711. irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  2712. DeviceExtension->NextLowerDriver,
  2713. NULL,
  2714. 0,
  2715. NULL,
  2716. &event,
  2717. &ioStatusBlock);
  2718. if (!irp) {
  2719. status = STATUS_INSUFFICIENT_RESOURCES;
  2720. goto GetHardwareIdExit;
  2721. }
  2722. irpStack = IoGetNextIrpStackLocation(irp);
  2723. irpStack->MinorFunction = IRP_MN_QUERY_ID;
  2724. irpStack->Parameters.QueryId.IdType = BusQueryDeviceID;
  2725. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  2726. status = IoCallDriver(DeviceExtension->NextLowerDriver, irp);
  2727. if (status == STATUS_PENDING) {
  2728. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2729. status = ioStatusBlock.Status;
  2730. }
  2731. if (NT_SUCCESS(status)) {
  2732. DebugPrint((ERROR, "DeviceId == %S\n", ioStatusBlock.Information));
  2733. }
  2734. GetHardwareIdExit:
  2735. DebugExitStatus(status);
  2736. return status;
  2737. }
  2738. NTSTATUS
  2739. GetInstanceId(
  2740. PFDO_DATA DeviceExtension,
  2741. PWCHAR *InstanceId
  2742. )
  2743. /*++
  2744. Routine Description:
  2745. Arguments:
  2746. Return Value:
  2747. --*/
  2748. {
  2749. NTSTATUS status;
  2750. KEVENT event;
  2751. PIRP irp;
  2752. ULONG idSize;
  2753. IO_STATUS_BLOCK ioStatusBlock;
  2754. PIO_STACK_LOCATION irpStack;
  2755. DebugEnter();
  2756. DebugAssert(InstanceId);
  2757. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2758. irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  2759. DeviceExtension->NextLowerDriver,
  2760. NULL,
  2761. 0,
  2762. NULL,
  2763. &event,
  2764. &ioStatusBlock);
  2765. if (!irp) {
  2766. status = STATUS_INSUFFICIENT_RESOURCES;
  2767. goto GetHardwareIdExit;
  2768. }
  2769. irpStack = IoGetNextIrpStackLocation(irp);
  2770. irpStack->MinorFunction = IRP_MN_QUERY_ID;
  2771. irpStack->Parameters.QueryId.IdType = BusQueryInstanceID;
  2772. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  2773. status = IoCallDriver(DeviceExtension->NextLowerDriver, irp);
  2774. if (status == STATUS_PENDING) {
  2775. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2776. status = ioStatusBlock.Status;
  2777. }
  2778. //
  2779. // remove leading white spaces
  2780. //
  2781. if (NT_SUCCESS(status)) {
  2782. PWCHAR idString = (PWCHAR)ioStatusBlock.Information;
  2783. //
  2784. // remove leading white space
  2785. //
  2786. while(idString[0] == 0x20) {
  2787. idString++;
  2788. }
  2789. idSize = (wcslen(idString) + 1) * sizeof(WCHAR);
  2790. *InstanceId = ExAllocatePoolWithTag(PagedPool, idSize, PROCESSOR_POOL_TAG);
  2791. if (!(*InstanceId)) {
  2792. status = STATUS_INSUFFICIENT_RESOURCES;
  2793. goto GetHardwareIdExit;
  2794. }
  2795. RtlCopyMemory(*InstanceId, idString, idSize);
  2796. //
  2797. // Free ID structure
  2798. //
  2799. ExFreePool((PWCHAR)ioStatusBlock.Information);
  2800. }
  2801. GetHardwareIdExit:
  2802. DebugExitStatus(status);
  2803. return status;
  2804. }
  2805. __inline
  2806. NTSTATUS
  2807. AcquireProcessorPerfStateLock (
  2808. IN PFDO_DATA DevExt
  2809. )
  2810. /*++
  2811. Routine Description:
  2812. Arguments:
  2813. Return Value:
  2814. --*/
  2815. {
  2816. return KeWaitForSingleObject(&DevExt->PerfStateLock,
  2817. Executive,
  2818. KernelMode,
  2819. FALSE,
  2820. NULL);
  2821. }
  2822. __inline
  2823. NTSTATUS
  2824. ReleaseProcessorPerfStateLock (
  2825. IN PFDO_DATA DevExt
  2826. )
  2827. /*++
  2828. Routine Description:
  2829. Arguments:
  2830. Return Value:
  2831. --*/
  2832. {
  2833. return KeSetEvent(&DevExt->PerfStateLock, IO_NO_INCREMENT, FALSE);
  2834. }
  2835. #if DBG
  2836. VOID
  2837. DumpCStates(
  2838. PACPI_CST_PACKAGE CStates
  2839. )
  2840. {
  2841. ULONG x;
  2842. PACPI_CST_DESCRIPTOR cState;
  2843. DebugAssert(CStates);
  2844. DebugPrint((TRACE, "\n"));
  2845. DebugPrint((TRACE, "_CST:\n"));
  2846. DebugPrint((TRACE, "Found %u C-states\n", CStates->NumCStates));
  2847. DebugPrint((TRACE, "\n"));
  2848. for (x=0; x < CStates->NumCStates; x++) {
  2849. cState = &CStates->State[x];
  2850. DebugPrint((TRACE, "State #%u:\n", x));
  2851. DebugPrint((TRACE, " Register:\n"));
  2852. DebugPrint((TRACE, " AddressSpaceID: 0x%x\n", cState->Register.AddressSpaceID));
  2853. DebugPrint((TRACE, " BitWidth: 0x%x\n", cState->Register.BitWidth));
  2854. DebugPrint((TRACE, " BitOffset: 0x%x\n", cState->Register.BitOffset));
  2855. DebugPrint((TRACE, " Reserved: 0x%x\n", cState->Register.Reserved));
  2856. DebugPrint((TRACE, " Address: 0x%I64x\n", cState->Register.Address));
  2857. DebugPrint((TRACE, "\n"));
  2858. DebugPrint((TRACE, " State Type: C%u\n", cState->StateType));
  2859. DebugPrint((TRACE, " Latency: %u us\n", cState->Latency));
  2860. DebugPrint((TRACE, " Power Consumption: %u mW\n", cState->PowerConsumption));
  2861. DebugPrint((TRACE, "\n"));
  2862. }
  2863. }
  2864. #endif