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.

856 lines
17 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. amdk7.c
  5. Abstract:
  6. This module implements code specific to the AMDK7 processor
  7. Author:
  8. Todd Carpenter (1/30/01) - create file
  9. Environment:
  10. Kernel mode
  11. Notes:
  12. DeviceInst = "ACPI\AuthenticAMD_-_x86_Family_6_Model_6"
  13. ServiceName = "amdk7"
  14. Revision History:
  15. --*/
  16. #include "..\lib\processor.h"
  17. #include "amdk7.h"
  18. #if DBG
  19. PUCHAR DebugName = "AmdK7.sys";
  20. #endif
  21. PFDO_DATA DeviceExtensions[MAX_SUPPORTED_PROCESSORS];
  22. UCHAR DevExtIndex;
  23. ULONG AmdK7HackFlags;
  24. extern GLOBALS Globals;
  25. #ifdef ALLOC_PRAGMA
  26. #pragma alloc_text (PAGE, InitializeDriver)
  27. #pragma alloc_text (PAGE, GetProcessorBrandString)
  28. #pragma alloc_text (PAGE, InitializeAcpi2PStates)
  29. #pragma alloc_text (PAGE, InitializeAcpi2Cstates)
  30. #pragma alloc_text (PAGE, MergePerformanceStates)
  31. #endif
  32. NTSTATUS
  33. InitializeDriver(
  34. PUNICODE_STRING ServiceKeyRegPath
  35. )
  36. /*++
  37. Routine Description:
  38. Arguments:
  39. Return Value:
  40. --*/
  41. {
  42. //
  43. // Get AmdK7 Hack Flags
  44. //
  45. GetRegistryDwordValue((PWCHAR) AMDK7_PARAMETERS_KEY,
  46. L"HackFlags",
  47. &AmdK7HackFlags);
  48. return STATUS_SUCCESS;
  49. }
  50. NTSTATUS
  51. FASTCALL
  52. SetPerfLevel(
  53. IN UCHAR Throttle
  54. )
  55. /*++
  56. Routine Description:
  57. Arguments:
  58. Return Value:
  59. --*/
  60. {
  61. PFDO_DATA DeviceExtension;
  62. ULONG apicId;
  63. ULONG index = 0;
  64. DebugEnter();
  65. //
  66. // Get APIC Id and retrieve Device Extension index
  67. //
  68. if (!Globals.SingleProcessorProfile) {
  69. apicId = GetApicId();
  70. index = Globals.ProcInfo.ApicIdToDevExtIndex[apicId];
  71. }
  72. //
  73. // Get the DeviceExtension.
  74. //
  75. DeviceExtension = DeviceExtensions[index];
  76. //
  77. // This driver only supports FFH addresses, but SetPerfLevelGeneric
  78. // only finds the correct state, it will then call Acpi2PerfStateTransition
  79. //
  80. return SetPerfLevelGeneric(Throttle, DeviceExtension);
  81. }
  82. NTSTATUS
  83. FASTCALL
  84. SetThrottleLevel(
  85. IN UCHAR Throttle
  86. )
  87. /*++
  88. Routine Description:
  89. Arguments:
  90. Return Value:
  91. --*/
  92. {
  93. PFDO_DATA DeviceExtension;
  94. ULONG apicId;
  95. ULONG index = 0;
  96. DebugEnter();
  97. //
  98. // Get APIC Id and retrieve Device Extension index
  99. //
  100. if (!Globals.SingleProcessorProfile) {
  101. apicId = GetApicId();
  102. index = Globals.ProcInfo.ApicIdToDevExtIndex[apicId];
  103. }
  104. //
  105. // Get the DeviceExtension.
  106. //
  107. DeviceExtension = DeviceExtensions[index];
  108. //
  109. // This driver supports Acpi 1.0b style of throttling, use
  110. // generic function
  111. //
  112. return SetThrottleLevelGeneric(Throttle, DeviceExtension);
  113. }
  114. NTSTATUS
  115. GetProcessorBrandString (
  116. PUCHAR BrandString,
  117. PULONG Size
  118. )
  119. /*++
  120. Routine Description:
  121. Arguments:
  122. Return Value:
  123. --*/
  124. {
  125. //
  126. // This processor supports the CpuId based brand string
  127. //
  128. return GetCPUIDProcessorBrandString(BrandString, Size);
  129. }
  130. NTSTATUS
  131. InitializeAcpi2PStates(
  132. IN PFDO_DATA DevExt
  133. )
  134. /*++
  135. Routine Description:
  136. Arguments:
  137. Return Value:
  138. --*/
  139. {
  140. NTSTATUS status;
  141. status = InitializeAcpi2PStatesGeneric(DevExt);
  142. if (NT_SUCCESS(status)) {
  143. if ((DevExt->PctPackage.Control.AddressSpaceID != AcpiGenericSpaceFixedFunction) ||
  144. (DevExt->PctPackage.Status.AddressSpaceID != AcpiGenericSpaceFixedFunction)) {
  145. DebugPrint((WARN, "ONLY Acpi 2.0 FFH addresses are supported\n"));
  146. DebugPrint((WARN, "NOT using Acpi 2.0 Performance States\n"));
  147. //
  148. // Undo what InitializeAcpi2PStatesGeneric() did
  149. //
  150. if (DevExt->PssPackage) {
  151. ExFreePool(DevExt->PssPackage);
  152. DevExt->PssPackage = NULL;
  153. }
  154. return STATUS_NOT_SUPPORTED;
  155. }
  156. //
  157. // Walk through _PSS states to calculate latency values
  158. //
  159. ValidatePssLatencyValues(DevExt);
  160. //
  161. // Need to merge this new data with our perfstates
  162. //
  163. MergePerformanceStates(DevExt);
  164. }
  165. return status;
  166. }
  167. NTSTATUS
  168. InitializeAcpi2Cstates(
  169. PFDO_DATA DevExt
  170. )
  171. /*++
  172. Routine Description:
  173. This function looks to see if there is an ACPI 2.0 _CST object in the
  174. namespace, and, if there is, it replaces the functions found by
  175. InitializeAcpi1Cstates.
  176. Further note: This function leaves the filling in of throttling functions
  177. to the InitializePerformanceStates functions.
  178. Arguments:
  179. DeviceExtension
  180. Return Value:
  181. A NTSTATUS code to indicate the result of the initialization.
  182. --*/
  183. {
  184. ULONG apicId;
  185. ULONG index = 0;
  186. DebugEnter();
  187. //
  188. // Record the address of this processor's DeviceExtension, as the
  189. // throttling API doesn't give it to us.
  190. //
  191. if (!Globals.SingleProcessorProfile) {
  192. //
  193. // save the index into the DeviceExtension[] for later retrieval based
  194. // on APIC Id.
  195. //
  196. apicId = Globals.ProcInfo.ProcIdToApicId[DevExt->ProcObjInfo.PhysicalID];
  197. Globals.ProcInfo.ApicIdToDevExtIndex[apicId] = DevExtIndex;
  198. index = DevExtIndex++;
  199. }
  200. //
  201. // save Device Extension pointer
  202. //
  203. DeviceExtensions[index] = DevExt;
  204. //
  205. // This processor driver only supports I/O Space based Cstates.
  206. // InitializeAcpi2IoSpaceCstates() will fail if it finds Cstates with
  207. // non AcpiGenericSpaceIO type addresses.
  208. //
  209. return InitializeAcpi2IoSpaceCstates(DevExt);
  210. }
  211. NTSTATUS
  212. MergePerformanceStates(
  213. IN PFDO_DATA DeviceExtension
  214. )
  215. /*++
  216. Routine Description:
  217. This routine looks at the performance states stored in the device extension.
  218. Arguments:
  219. DeviceExtension
  220. Return Value:
  221. A NTSTATUS code to indicate the result of the initialization.
  222. NOTE:
  223. - The caller must hold PerfStateLock.
  224. - This is called during START_DEVICE, and after recieving a Notify(0x80)
  225. on the processor.
  226. --*/
  227. {
  228. NTSTATUS status;
  229. NTSTATUS findStatus;
  230. ULONG pssState = 0xdeadbeef;
  231. DebugEnter();
  232. //
  233. // This function just merges available _PSS and stop clock throttle states
  234. //
  235. status = MergePerformanceStatesGeneric(DeviceExtension);
  236. //
  237. // With amdk7.sys, the order of transition execution differs if going from a
  238. // higher state to a lower state when compared to going from a lower state to
  239. // a higher state... Therefore, it is important that we set the current state
  240. // before registering new performance states with the kernel.
  241. //
  242. // NOTE: MergePerformanceStatesGeneric() will invalidate CurrentPerfState,
  243. // so it must be set here.
  244. //
  245. if (NT_SUCCESS(status)) {
  246. findStatus = FindCurrentPssPerfState(DeviceExtension->PssPackage, &pssState);
  247. if (NT_SUCCESS(findStatus)) {
  248. DebugAssert(pssState < DeviceExtension->PssPackage->NumPStates);
  249. DeviceExtension->CurrentPerfState = pssState;
  250. }
  251. }
  252. return status;
  253. }
  254. NTSTATUS
  255. Acpi2PerfStateTransition(
  256. IN PFDO_DATA DeviceExtension,
  257. IN ULONG NewState
  258. )
  259. /*++
  260. Routine Description:
  261. This routine changes the performance state of the processor
  262. based on ACPI 2.0 performance state objects.
  263. Arguments:
  264. State - Index into _PSS object
  265. Return Value:
  266. none
  267. --*/
  268. {
  269. NTSTATUS status = STATUS_SUCCESS;
  270. ULONG transitionStatus;
  271. ULONG pssControl;
  272. ULONG64 fidControl;
  273. ULONG64 vidControl;
  274. ULONG64 fidVidStatus;
  275. DebugEnter();
  276. DebugAssert(DeviceExtension->PssPackage)
  277. DebugAssert(NewState >= DeviceExtension->PpcResult);
  278. DebugAssert(NewState < DeviceExtension->PssPackage->NumPStates);
  279. DebugAssert(DeviceExtension->PssPackage->State[NewState].Control);
  280. if (DeviceExtension->PctPackage.Control.AddressSpaceID != AcpiGenericSpaceFixedFunction) {
  281. DebugAssert(!"Acpi2PerfStateTransition ONLY understands FFH addresses");
  282. status = STATUS_UNSUCCESSFUL;
  283. goto Acpi2PerfStateTransitionExit;
  284. }
  285. if (NewState == DeviceExtension->CurrentPssState) {
  286. DebugPrint((WARN, "Acpi2PerfStateTransition() CurrentState == TargetState, exiting...\n"));
  287. goto Acpi2PerfStateTransitionExit;
  288. }
  289. //
  290. // Transitioning the Mobile Athlon Processor requires two steps:
  291. //
  292. // If transitioning from a higher state to a lower state, then:
  293. // 1) core frequency transition
  294. // 2) core voltage transition
  295. //
  296. // If transitioning from a lower state to a higher state, then:
  297. // 1) core voltage transition
  298. // 2) core frequency transition
  299. //
  300. //
  301. // Get Frequency and Voltage value to write to MSR
  302. //
  303. pssControl = DeviceExtension->PssPackage->State[NewState].Control;
  304. fidControl = ConvertPssControlToFidVidControl(pssControl, TRUE);
  305. vidControl = ConvertPssControlToFidVidControl(pssControl, FALSE);
  306. if (NewState > DeviceExtension->CurrentPssState) {
  307. //
  308. // High -> Low
  309. //
  310. DebugPrint((TRACE, "Perf Transition: state %u -> state %u\n", DeviceExtension->CurrentPssState, NewState));
  311. DebugPrint((TRACE, "FidControl = 0x%I64x, VidControl = 0x%I64x\n", fidControl, vidControl));
  312. AmdK7FidVidTransition(fidControl);
  313. AmdK7FidVidTransition(vidControl);
  314. } else {
  315. //
  316. // Low -> High
  317. //
  318. DebugPrint((TRACE, "Perf Transition: state %u -> state %u\n", DeviceExtension->CurrentPssState, NewState));
  319. DebugPrint((TRACE, "VidControl = 0x%I64x, FidControl = 0x%I64x\n", vidControl, fidControl));
  320. AmdK7FidVidTransition(vidControl);
  321. AmdK7FidVidTransition(fidControl);
  322. }
  323. //
  324. // check status
  325. //
  326. fidVidStatus = ReadMSR(AMDK7_FID_VID_STATUS_MSR);
  327. transitionStatus = ConvertFidVidStatusToPssStatus(fidVidStatus);
  328. if (transitionStatus == DeviceExtension->PssPackage->State[NewState].Status) {
  329. DeviceExtension->CurrentPssState = NewState;
  330. } else {
  331. DebugPrint((ERROR, "ERROR! Expected 0x%x status value, recieved 0x%x\n",
  332. DeviceExtension->PssPackage->State[NewState].Status,
  333. transitionStatus));
  334. DebugPrint((ERROR, "_PSS[%u]->Status:\n", NewState));
  335. DumpPssStatus(DeviceExtension->PssPackage->State[NewState].Status);
  336. DebugPrint((ERROR, "FidVidStatus MSR:\n", fidVidStatus));
  337. DumpFidVidStatus(fidVidStatus);
  338. status = STATUS_UNSUCCESSFUL;
  339. }
  340. Acpi2PerfStateTransitionExit:
  341. DebugExitStatus(status);
  342. return status;
  343. }
  344. NTSTATUS
  345. ProcessResumeFromSleepState(
  346. SYSTEM_POWER_STATE PreviousState,
  347. PFDO_DATA DeviceExtension
  348. )
  349. /*++
  350. Routine Description:
  351. Arguments:
  352. Return Value:
  353. --*/
  354. {
  355. DebugEnter();
  356. //
  357. // if we are resuming from Hibernate, and this is an Acpi 2.0 system,
  358. // we must re-claim perf state and cstate control from the bios.
  359. //
  360. if (PreviousState == PowerSystemHibernate) {
  361. if (DeviceExtension->PssPackage) {
  362. AssumeProcessorPerformanceControl();
  363. }
  364. if (DeviceExtension->CstPresent) {
  365. AssumeCStateControl();
  366. }
  367. }
  368. //
  369. // restore previous state
  370. //
  371. return RestoreToSavedPerformanceState(DeviceExtension);
  372. }
  373. NTSTATUS
  374. ProcessSuspendToSleepState(
  375. SYSTEM_POWER_STATE TargetState,
  376. PFDO_DATA DeviceExtension
  377. )
  378. /*++
  379. Routine Description:
  380. Arguments:
  381. Return Value:
  382. --*/
  383. {
  384. DebugEnter();
  385. //
  386. // save previous state, transition to lowest non-throttled perf state
  387. //
  388. return SaveCurrentStateGoToLowVolts(DeviceExtension);
  389. }
  390. ULONG64
  391. ConvertPssControlToFidVidControl(
  392. ULONG PssControlValue,
  393. BOOLEAN Fid
  394. )
  395. /*++
  396. Routine Description:
  397. Arguments:
  398. Return Value:
  399. NOTES:
  400. _PSS Control field:
  401. Bit Name
  402. ---- ----
  403. 4:0 FID
  404. 9:5 VID
  405. 29:10 SGTC
  406. 31:30 Reserved
  407. FidVidCtl:
  408. Bit Name Function
  409. ---- ---- --------
  410. 4:0 FID[4:0] New 5-bit FID to transition to
  411. 7:5 reserved
  412. 12:8 VID[4:0] New 5-bit VID to transition to
  413. 15:13 reserved
  414. 16 FIDC FID Control bit
  415. 17 VIDC VID Control bit
  416. 19:18 reserved
  417. 20 FidChgRatio Fid Change Ratio (always set to 1)
  418. 31:21 reserved
  419. 51:32 SGTC[19:0] Stop-Grant Timeout Count (write only)
  420. 63:52 reserved
  421. --*/
  422. {
  423. FID_VID_CONTROL fidVidControl = {0};
  424. PSS_CONTROL pssControl;
  425. //DebugEnter();
  426. DebugAssert(PssControlValue);
  427. pssControl.AsDWord = PssControlValue;
  428. fidVidControl.Fid = pssControl.Fid;
  429. fidVidControl.Vid = pssControl.Vid;
  430. fidVidControl.FidChngRatio = 1;
  431. //
  432. // The timeout needed for the Frequency Transion (FID) is exactly half that
  433. // needed by the Voltage Transion (VID). We do this because of the latency
  434. // savings
  435. //
  436. if (Fid) {
  437. fidVidControl.SGTC = pssControl.SGTC / 2;
  438. fidVidControl.FidControl = 1;
  439. } else {
  440. fidVidControl.SGTC = pssControl.SGTC;
  441. fidVidControl.VidControl = 1;
  442. }
  443. return fidVidControl.AsQWord;
  444. }
  445. ULONG
  446. ConvertFidVidStatusToPssStatus(
  447. ULONG64 FidVidStatusValue
  448. )
  449. /*++
  450. Routine Description:
  451. Arguments:
  452. Return Value:
  453. NOTES:
  454. FidVidStatus:
  455. Bit Name Function
  456. ---- ---- --------
  457. 4:0 CFID[4:0] Current 5-bit FID
  458. 7:5 reserved
  459. 12:8 SFID[4:0] Startup 5-bit FID
  460. 15:13 reserved
  461. 20:16 MFID[4:0] Maximum 5-bit FID
  462. 31:21 reserved
  463. 36:32 CVID[4:0] Current 5-bit VID
  464. 39:37 reserved
  465. 44:40 SVID[4:0] Startup 5-bit VID
  466. 47:45 reserved
  467. 52:48 MVID[4:0] Maximum 5-bit VID
  468. 63:53 reserved
  469. _PSS Status Field:
  470. Bit Name
  471. ---- ----
  472. 4:0 FID current frequency
  473. 9:5 VID current voltage
  474. 31:10 reserved
  475. --*/
  476. {
  477. PSS_STATUS pssStatus;
  478. FID_VID_STATUS fidVidStatus;
  479. //DebugEnter();
  480. DebugAssert(FidVidStatusValue);
  481. fidVidStatus.AsQWord = FidVidStatusValue;
  482. pssStatus.Fid = fidVidStatus.CFid;
  483. pssStatus.Vid = fidVidStatus.CVid;
  484. pssStatus.Reserved = 0;
  485. return pssStatus.AsDWord;
  486. }
  487. NTSTATUS
  488. FindCurrentPssPerfState(
  489. PACPI_PSS_PACKAGE PssPackage,
  490. PULONG PssState
  491. )
  492. /*++
  493. Routine Description:
  494. Arguments:
  495. Return Value:
  496. --*/
  497. {
  498. NTSTATUS status = STATUS_UNSUCCESSFUL;
  499. ULONG x;
  500. ULONG transitionStatus;
  501. ULONG64 fidVidStatus;
  502. DebugEnter();
  503. DebugAssert(PssPackage);
  504. DebugAssert(PssState);
  505. fidVidStatus = ReadMSR(AMDK7_FID_VID_STATUS_MSR);
  506. transitionStatus = ConvertFidVidStatusToPssStatus(fidVidStatus);
  507. for (x=0; x < PssPackage->NumPStates; x++) {
  508. if (transitionStatus == PssPackage->State[x].Status) {
  509. status = STATUS_SUCCESS;
  510. *PssState = x;
  511. break;
  512. }
  513. }
  514. DebugExitStatus(status);
  515. return status;
  516. }
  517. #if DBG
  518. VOID
  519. DumpFidVidStatus(
  520. IN ULONG64 FidVidStatus
  521. )
  522. {
  523. FID_VID_STATUS status;
  524. status.AsQWord = FidVidStatus;
  525. DebugPrint((MAXTRACE, " CFid: 0x%x\n", status.CFid));
  526. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved1));
  527. DebugPrint((MAXTRACE, " SFid: 0x%x\n", status.SFid));
  528. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved2));
  529. DebugPrint((MAXTRACE, " MFid: 0x%x\n", status.MFid));
  530. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved3));
  531. DebugPrint((MAXTRACE, " CVid: 0x%x\n", status.CVid));
  532. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved4));
  533. DebugPrint((MAXTRACE, " SVid: 0x%x\n", status.SVid));
  534. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved5));
  535. DebugPrint((MAXTRACE, " MVid: 0x%x\n", status.MVid));
  536. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved6));
  537. DebugPrint((MAXTRACE, "\n"));
  538. }
  539. VOID
  540. DumpFidVidControl(
  541. IN ULONG64 FidVidControl
  542. )
  543. {
  544. FID_VID_CONTROL control;
  545. control.AsQWord = FidVidControl;
  546. DebugPrint((MAXTRACE, " Fid: 0x%x\n", control.Fid));
  547. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved1));
  548. DebugPrint((MAXTRACE, " Vid: 0x%x\n", control.Vid));
  549. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved2));
  550. DebugPrint((MAXTRACE, " FidControl: 0x%x\n", control.FidControl));
  551. DebugPrint((MAXTRACE, " VidControl: 0x%x\n", control.VidControl));
  552. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved3));
  553. DebugPrint((MAXTRACE, " FidChngRatio: 0x%x\n", control.FidChngRatio));
  554. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved4));
  555. DebugPrint((MAXTRACE, " SGTC: 0x%x\n", control.SGTC));
  556. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved5));
  557. DebugPrint((MAXTRACE, "\n"));
  558. }
  559. VOID
  560. DumpPssStatus(
  561. IN ULONG PssStatus
  562. )
  563. {
  564. PSS_STATUS status;
  565. status.AsDWord = PssStatus;
  566. DebugPrint((MAXTRACE, " Fid: 0x%x\n", status.Fid));
  567. DebugPrint((MAXTRACE, " Vid: 0x%x\n", status.Vid));
  568. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved));
  569. DebugPrint((MAXTRACE, "\n"));
  570. }
  571. VOID
  572. DumpPssControl(
  573. IN ULONG PssControl
  574. )
  575. {
  576. PSS_CONTROL control;
  577. control.AsDWord = PssControl;
  578. DebugPrint((MAXTRACE, " Fid: 0x%x\n", control.Fid));
  579. DebugPrint((MAXTRACE, " Vid: 0x%x\n", control.Vid));
  580. DebugPrint((MAXTRACE, " SGTC: 0x%x\n", control.SGTC));
  581. DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved));
  582. DebugPrint((MAXTRACE, "\n"));
  583. }
  584. #endif