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

788 lines
19 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. pmsleep.c
  5. Abstract:
  6. This file provides the code that changes the system from
  7. the ACPI S0 (running) state to any one of the sleep states.
  8. Author:
  9. Jake Oshins (jakeo) Feb. 11, 1997
  10. Revision History:
  11. Todd Kjos (HP) (v-tkjos) 1-Jun-1998: Initial port to IA64
  12. --*/
  13. #include "halp.h"
  14. #include "acpitabl.h"
  15. #include "xxacpi.h"
  16. #include "ixsleep.h"
  17. #include "kddll.h"
  18. //
  19. // Internal functions
  20. //
  21. VOID
  22. HalpLockedIncrementUlong(
  23. PULONG SyncVariable
  24. );
  25. VOID
  26. HalpReboot (
  27. VOID
  28. );
  29. NTSTATUS
  30. HaliAcpiFakeSleep(
  31. IN PVOID Context,
  32. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  33. IN PVOID SystemContext,
  34. IN LONG NumberProcessors,
  35. IN volatile PLONG Number
  36. );
  37. NTSTATUS
  38. HaliAcpiSleep(
  39. IN PVOID Context,
  40. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  41. IN PVOID SystemContext,
  42. IN LONG NumberProcessors,
  43. IN volatile PLONG Number
  44. );
  45. VOID
  46. HalpSetClockBeforeSleep(
  47. VOID
  48. );
  49. VOID
  50. HalpSetClockAfterSleep(
  51. VOID
  52. );
  53. BOOLEAN
  54. HalpWakeupTimeElapsed(
  55. VOID
  56. );
  57. VOID
  58. HalpReenableAcpi(
  59. VOID
  60. );
  61. VOID
  62. HalpSetInterruptControllerWakeupState(
  63. ULONG Context
  64. );
  65. typedef struct _ERESOURCE {
  66. LIST_ENTRY SystemResourcesList;
  67. PVOID OwnerTable;
  68. SHORT ActiveCount;
  69. USHORT Flag;
  70. PKSEMAPHORE SharedWaiters;
  71. PKEVENT ExclusiveWaiters;
  72. LIST_ENTRY OwnerThreads[2];
  73. ULONG ContentionCount;
  74. USHORT NumberOfSharedWaiters;
  75. USHORT NumberOfExclusiveWaiters;
  76. union {
  77. PVOID Address;
  78. ULONG CreatorBackTraceIndex;
  79. };
  80. KSPIN_LOCK SpinLock;
  81. } ERESOURCE, *PERESOURCE;
  82. #ifdef ALLOC_PRAGMA
  83. #pragma alloc_text(PAGELK, HaliAcpiSleep)
  84. #pragma alloc_text(PAGELK, HaliAcpiFakeSleep)
  85. #pragma alloc_text(PAGELK, HalpAcpiPreSleep)
  86. #pragma alloc_text(PAGELK, HalpAcpiPostSleep)
  87. #pragma alloc_text(PAGELK, HalpWakeupTimeElapsed)
  88. #pragma alloc_text(PAGELK, HalpReenableAcpi)
  89. #pragma alloc_text(PAGELK, HaliSetWakeEnable)
  90. #pragma alloc_text(PAGELK, HaliSetWakeAlarm)
  91. #endif
  92. HAL_WAKEUP_STATE HalpWakeupState;
  93. ULONG Barrier;
  94. volatile ULONG HalpSleepSync;
  95. PKPROCESSOR_STATE HalpHiberProcState;
  96. #if DBG
  97. BOOLEAN HalpFailSleep = FALSE;
  98. #endif
  99. #define PM1_TMR_EN 0x0001
  100. #define PM1_RTC_EN 0x0400
  101. #define WAK_STS 0x8000
  102. #define HAL_PRIMARY_PROCESSOR 0
  103. //
  104. // For re-enabling the debugger's com port.
  105. //
  106. extern PUCHAR KdComPortInUse;
  107. VOID
  108. HalpAcpiFlushCache(
  109. )
  110. {
  111. HalSweepDcache();
  112. HalSweepIcache();
  113. }
  114. VOID
  115. HalpSaveProcessorStateAndWait(
  116. IN PKPROCESSOR_STATE ProcessorState,
  117. IN volatile PULONG Count
  118. )
  119. /*++
  120. Rountine description:
  121. This function saves the volatile, non-volatile and special register
  122. state of the current processor.
  123. N.B. floating point state is NOT captured.
  124. Arguments:
  125. ProcessorState - Address of processor state record to fill in.
  126. pBarrier - Address of a value to use as a lock.
  127. Return Value:
  128. None. This function does not return.
  129. --*/
  130. {
  131. #if 0
  132. //
  133. // Fill in ProcessorState
  134. //
  135. KeSaveStateForHibernate(ProcessorState);
  136. //
  137. // Save return address, not caller's return address.
  138. //
  139. ProcessorState->ContextFrame.StIIP = HalpGetReturnAddress();
  140. #endif
  141. //
  142. // Flush the cache, as the processor may be about to power off.
  143. //
  144. //
  145. HalpAcpiFlushCache();
  146. //
  147. // Singal that this processor has saved its state.
  148. //
  149. HalpLockedIncrementUlong(Count);
  150. //
  151. // Wait for the hibernation file to be written.
  152. // Processor 0 will zero Barrier when it is
  153. // finished.
  154. //
  155. // N.B. We can't return from this function
  156. // before the hibernation file is finished
  157. // because we would be tearing down the very same
  158. // stack that we will be jumping onto when the
  159. // processor resumes. But after the hibernation
  160. // file is written, it doesn't matter, because
  161. // the stack will be restored from disk.
  162. //
  163. while (*Count != 0);
  164. }
  165. BOOLEAN
  166. HalpAcpiPreSleep(
  167. SLEEP_STATE_CONTEXT Context
  168. )
  169. /*++
  170. Routine Description:
  171. Arguments:
  172. none
  173. Return Value:
  174. status
  175. --*/
  176. {
  177. USHORT pmTimer;
  178. GEN_ADDR pm1a;
  179. GEN_ADDR pm1b;
  180. pm1a = HalpFixedAcpiDescTable.x_pm1a_evt_blk;
  181. pm1a.Address.QuadPart += (HalpFixedAcpiDescTable.x_pm1a_evt_blk.BitWidth / 2 / 8); // 2 because we want to cut it in half, 8 because we want to convert bits to bytes
  182. pm1a.BitWidth = HalpFixedAcpiDescTable.x_pm1a_evt_blk.BitWidth / 2;
  183. pm1b = HalpFixedAcpiDescTable.x_pm1b_evt_blk;
  184. pm1b.Address.QuadPart += (HalpFixedAcpiDescTable.x_pm1b_evt_blk.BitWidth / 2 / 8);
  185. pm1b.BitWidth = HalpFixedAcpiDescTable.x_pm1b_evt_blk.BitWidth / 2;
  186. HalpSleepContext.AsULONG = Context.AsULONG;
  187. #if DBG
  188. if (HalpFailSleep) {
  189. return FALSE;
  190. }
  191. #endif
  192. //
  193. // If we should have woken up already, don't sleep.
  194. //
  195. if (HalpWakeupTimeElapsed()) {
  196. return FALSE;
  197. }
  198. //
  199. // If an RTC alarm is set, then enable it and disable
  200. // periodic interrupts (for profiling.)
  201. //
  202. HalpSetClockBeforeSleep();
  203. //
  204. // Check to see if we need to disable all wakeup events.
  205. //
  206. if (!HalpWakeupState.GeneralWakeupEnable) {
  207. AcpiEnableDisableGPEvents(FALSE);
  208. } else {
  209. //
  210. // Only call this before going to sleep --- waking up should
  211. // reset the GPEs to the 'proper' value
  212. //
  213. AcpiGpeEnableWakeEvents();
  214. }
  215. if (Context.bits.Flags & SLEEP_STATE_SAVE_MOTHERBOARD) {
  216. HalpSaveDmaControllerState();
  217. HalpSaveTimerState();
  218. }
  219. //
  220. // We need to make sure that the PM timer is disabled from
  221. // this point onward. We also need to make that the
  222. // RTC Enable is only enabled if the RTC shold wake up the compiler
  223. //
  224. pmTimer = (USHORT)HalpReadGenAddr(&pm1a);
  225. if (HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address.QuadPart) {
  226. pmTimer |= (USHORT)HalpReadGenAddr(&pm1b);
  227. }
  228. //
  229. // Clear the timer enable bit.
  230. //
  231. pmTimer &= ~PM1_TMR_EN;
  232. //
  233. // Check to see if we the machine supports RTC wake in Fixed Feature
  234. // space. Some machines implement RTC support via control methods.
  235. //
  236. if (!(HalpFixedAcpiDescTable.flags & RTC_WAKE_GENERIC) ) {
  237. //
  238. // Check to see f we need to disable/enable the RTC alarm
  239. //
  240. if (!HalpWakeupState.RtcWakeupEnable) {
  241. pmTimer &= ~PM1_RTC_EN;
  242. } else {
  243. pmTimer |= PM1_RTC_EN;
  244. }
  245. }
  246. //
  247. // Write it back into the hardware.
  248. //
  249. HalpWriteGenAddr(&pm1a, pmTimer);
  250. if (HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address.QuadPart) {
  251. HalpWriteGenAddr(&pm1b, pmTimer);
  252. }
  253. return TRUE;
  254. }
  255. BOOLEAN
  256. HalpAcpiPostSleep(
  257. ULONG Context
  258. )
  259. {
  260. USHORT pmTimer;
  261. GEN_ADDR pm1a;
  262. GEN_ADDR pm1b;
  263. pm1a = HalpFixedAcpiDescTable.x_pm1a_evt_blk;
  264. pm1a.Address.QuadPart += (HalpFixedAcpiDescTable.pm1_evt_len / 2);
  265. pm1b = HalpFixedAcpiDescTable.x_pm1b_evt_blk;
  266. pm1b.Address.QuadPart += (HalpFixedAcpiDescTable.pm1_evt_len / 2);
  267. //
  268. // Read te currently set PM1 Enable bits.
  269. //
  270. pmTimer = (USHORT)HalpReadGenAddr(&pm1a);
  271. if (HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address.QuadPart) {
  272. pmTimer |= (USHORT)HalpReadGenAddr(&pm1b);
  273. }
  274. //
  275. // Set the timer enable bit. Clear the RTC enable bit.
  276. //
  277. pmTimer &= ~PM1_RTC_EN;
  278. //
  279. // Write it back the new PM1 Enable bits
  280. //
  281. HalpWriteGenAddr(&pm1a, pmTimer);
  282. if (HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address.QuadPart) {
  283. HalpWriteGenAddr(&pm1b, pmTimer);
  284. }
  285. //
  286. // Unset the RTC alarm and re-enable periodic interrupts.
  287. //
  288. HalpSetClockAfterSleep();
  289. HalpWakeupState.RtcWakeupEnable = FALSE;
  290. *((PULONG)HalpWakeVector) = 0;
  291. HalpSetInterruptControllerWakeupState(Context);
  292. if (HalpSleepContext.bits.Flags & SLEEP_STATE_SAVE_MOTHERBOARD) {
  293. //
  294. // If Kd was in use, then invalidate it. It will re-sync itself.
  295. //
  296. if (KdComPortInUse) {
  297. KdRestore(TRUE);
  298. }
  299. HalpRestoreDmaControllerState();
  300. HalpRestoreTimerState();
  301. }
  302. //
  303. // Enable all GPEs, not just the wake ones
  304. //
  305. AcpiEnableDisableGPEvents(TRUE);
  306. return TRUE;
  307. }
  308. BOOLEAN
  309. HalpWakeupTimeElapsed(
  310. VOID
  311. )
  312. {
  313. LARGE_INTEGER wakeupTime, currentTime;
  314. TIME_FIELDS currentTimeFields;
  315. //
  316. // Check to see if a wakeup timer has already expired.
  317. //
  318. if (HalpWakeupState.RtcWakeupEnable) {
  319. HalQueryRealTimeClock(&currentTimeFields);
  320. RtlTimeFieldsToTime(&currentTimeFields,
  321. &currentTime);
  322. RtlTimeFieldsToTime(&HalpWakeupState.RtcWakeupTime,
  323. &wakeupTime);
  324. if (wakeupTime.QuadPart < currentTime.QuadPart) {
  325. return TRUE;
  326. }
  327. }
  328. return FALSE;
  329. }
  330. NTSTATUS
  331. HaliSetWakeAlarm (
  332. IN ULONGLONG WakeSystemTime,
  333. IN PTIME_FIELDS WakeTimeFields OPTIONAL
  334. )
  335. /*++
  336. Routine Description:
  337. This routine sets the real-time clock's alarm to go
  338. off at a specified time in the future and programs
  339. the ACPI chipset so that this wakes the computer.
  340. Arguments:
  341. WakeSystemTime - amount of time that passes before we wake
  342. WakeTimeFields - time to wake broken down into TIME_FIELDS
  343. Return Value:
  344. status
  345. --*/
  346. {
  347. if (WakeSystemTime == 0) {
  348. HalpWakeupState.RtcWakeupEnable = FALSE;
  349. return STATUS_SUCCESS;
  350. }
  351. ASSERT( WakeTimeFields );
  352. HalpWakeupState.RtcWakeupEnable = TRUE;
  353. HalpWakeupState.RtcWakeupTime = *WakeTimeFields;
  354. return HalpSetWakeAlarm(WakeSystemTime,
  355. WakeTimeFields);
  356. }
  357. VOID
  358. HaliSetWakeEnable(
  359. IN BOOLEAN Enable
  360. )
  361. /*++
  362. Routine Description:
  363. This routine is called to set the policy for waking up.
  364. As we go to sleep, the global HalpWakeupState will be
  365. read and the hardware set accordingly.
  366. Arguments:
  367. Enable - true or false
  368. Return Value:
  369. --*/
  370. {
  371. if (Enable) {
  372. HalpWakeupState.GeneralWakeupEnable = TRUE;
  373. } else {
  374. HalpWakeupState.GeneralWakeupEnable = FALSE;
  375. HalpWakeupState.RtcWakeupEnable = FALSE;
  376. }
  377. }
  378. VOID
  379. HalpReenableAcpi(
  380. VOID
  381. )
  382. /*++
  383. Routine Description:
  384. This calls into the ACPI driver to switch back into ACPI mode,
  385. presumably after S4 and sets the ACPI registers that the HAL
  386. controls.
  387. Arguments:
  388. Return Value:
  389. --*/
  390. {
  391. // TEMPTEMP?
  392. HalpInitializeClock();
  393. AcpiInitEnableAcpi(TRUE);
  394. AcpiEnableDisableGPEvents(TRUE);
  395. }
  396. /*++
  397. Routine Description:
  398. This is a stub to allow us to perform device powerdown
  399. testing on IA64 machines before they actually support
  400. real sleep states.
  401. Arguments:
  402. <standard sleep handler args>
  403. Return Value:
  404. STATUS_NOT_SUPPORTED
  405. --*/
  406. NTSTATUS
  407. HaliAcpiFakeSleep(
  408. IN PVOID Context,
  409. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  410. IN PVOID SystemContext,
  411. IN LONG NumberProcessors,
  412. IN volatile PLONG Number
  413. )
  414. {
  415. return STATUS_NOT_SUPPORTED;
  416. }
  417. NTSTATUS
  418. HaliAcpiSleep(
  419. IN PVOID Context,
  420. IN PENTER_STATE_SYSTEM_HANDLER SystemHandler OPTIONAL,
  421. IN PVOID SystemContext,
  422. IN LONG NumberProcessors,
  423. IN volatile PLONG Number
  424. )
  425. /*++
  426. Routine Description:
  427. At some point in time this function will be called to put PCs into a sleep
  428. state. It saves motherboard state and then bails out. For now this function
  429. is only called to implement S5 on Itanium.
  430. Arguments:
  431. --*/
  432. {
  433. NTSTATUS Status = STATUS_SUCCESS;
  434. KIRQL OldIrql;
  435. SLEEP_STATE_CONTEXT SleepContext;
  436. USHORT SlpTypA, SlpTypB, Pm1Control;
  437. PKPROCESSOR_STATE CurrentProcessorState;
  438. GEN_ADDR Pm1bEvt;
  439. PKPRCB Prcb;
  440. //
  441. // initial setup.
  442. //
  443. HalpDisableInterrupts();
  444. KeRaiseIrql(HIGH_LEVEL, &OldIrql);
  445. SleepContext.AsULONG = (ULONG) (((ULONGLONG) Context) & 0xffffffff);
  446. SlpTypA = (USHORT)HalpReadGenAddr(&HalpFixedAcpiDescTable.x_pm1a_ctrl_blk);
  447. if (HalpFixedAcpiDescTable.x_pm1b_ctrl_blk.Address.QuadPart) {
  448. SlpTypB = (USHORT)HalpReadGenAddr(&HalpFixedAcpiDescTable.x_pm1b_ctrl_blk);
  449. }
  450. //
  451. // If it is not processor 0, then goto wait loop.
  452. //
  453. Prcb = PCR->Prcb;
  454. if (Prcb->Number != 0) {
  455. //
  456. // Get processor number, get size of proc state and generate an index
  457. // into HalpHiberProcState.
  458. //
  459. CurrentProcessorState = HalpHiberProcState + Prcb->Number;
  460. HalpSaveProcessorStateAndWait(CurrentProcessorState,
  461. (PULONG) &HalpSleepSync);
  462. //
  463. // Wait for next phase
  464. //
  465. while (HalpSleepSync != 0); // wait for barrier to move
  466. } else { // processor 0
  467. Barrier = 0;
  468. //
  469. // Make sure the other processors have saved their
  470. // state and begun to spin.
  471. //
  472. HalpLockedIncrementUlong((PULONG) &HalpSleepSync);
  473. while (NumberProcessors != (LONG) HalpSleepSync);
  474. //
  475. // Take care of chores (RTC, interrupt controller, etc.)
  476. //
  477. //
  478. // The hal has all of it's state saved into ram and is ready
  479. // for the power down. If there's a system state handler give
  480. // it a shot
  481. //
  482. if (SystemHandler) {
  483. Status = (*SystemHandler)(SystemContext);
  484. if (!NT_SUCCESS(Status)) {
  485. HalpReenableAcpi();
  486. //
  487. // Restore the SLP_TYP registers. (So that embedded controllers
  488. // and BIOSes can be sure that we think the machine is awake.)
  489. //
  490. HalpWriteGenAddr (&HalpFixedAcpiDescTable.x_pm1a_ctrl_blk, SlpTypA);
  491. if (HalpFixedAcpiDescTable.x_pm1b_ctrl_blk.Address.QuadPart) {
  492. HalpWriteGenAddr(&HalpFixedAcpiDescTable.x_pm1b_ctrl_blk, SlpTypB);
  493. }
  494. HalpAcpiPostSleep(SleepContext.AsULONG);
  495. }
  496. } else {
  497. if (HalpAcpiPreSleep(SleepContext)) {
  498. //
  499. // If we will not be losing processor state, go to sleep.
  500. //
  501. if ((SleepContext.bits.Flags & SLEEP_STATE_FIRMWARE_RESTART) == 0) {
  502. //
  503. // Reset WAK_STS
  504. //
  505. HalpWriteGenAddr(&HalpFixedAcpiDescTable.x_pm1a_evt_blk, (USHORT) WAK_STS);
  506. if (HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address.QuadPart) {
  507. HalpWriteGenAddr(&HalpFixedAcpiDescTable.x_pm1b_evt_blk, (USHORT) WAK_STS);
  508. }
  509. //
  510. // Flush the caches if necessary
  511. //
  512. if (SleepContext.bits.Flags & SLEEP_STATE_FLUSH_CACHE) {
  513. HalpAcpiFlushCache();
  514. }
  515. //
  516. // Issue SLP commands to PM1a_CNT and PM1b_CNT
  517. //
  518. //
  519. // nibble 0 is 1a sleep type, put it in position and enable sleep.
  520. // preserve some bits in Pm1aCnt.
  521. //
  522. Pm1Control = (USHORT)HalpReadGenAddr(&HalpFixedAcpiDescTable.x_pm1a_ctrl_blk);
  523. Pm1Control = (USHORT) ((Pm1Control & CTL_PRESERVE) |
  524. (SleepContext.bits.Pm1aVal << SLP_TYP_SHIFT) | SLP_EN);
  525. HalpWriteGenAddr (&HalpFixedAcpiDescTable.x_pm1a_ctrl_blk, Pm1Control);
  526. //
  527. // nibble 1 is 1b sleep type, put it in position and enable sleep
  528. // preserve some bits in Pm1bCnt.
  529. //
  530. if (HalpFixedAcpiDescTable.x_pm1b_ctrl_blk.Address.QuadPart) {
  531. Pm1Control = (USHORT)HalpReadGenAddr(&HalpFixedAcpiDescTable.x_pm1b_ctrl_blk);
  532. Pm1Control = (USHORT) ((Pm1Control & CTL_PRESERVE) |
  533. (SleepContext.bits.Pm1bVal << SLP_TYP_SHIFT) | SLP_EN);
  534. HalpWriteGenAddr(&HalpFixedAcpiDescTable.x_pm1b_ctrl_blk, Pm1Control);
  535. }
  536. if (SleepContext.bits.Flags & SLEEP_STATE_OFF) {
  537. //
  538. // We are trying to do Shutdown Power Off. Some OEM's
  539. // chipsets don't actually implement the ACPI registers
  540. // fully. So we are going to do a HalReturnToFirmware
  541. // if the system doesn't power off in 30 seconds.
  542. //
  543. KeStallExecutionProcessor(30 * 1000 * 1000);
  544. HalReturnToFirmware(HalPowerDownRoutine);
  545. }
  546. //
  547. // Wait for sleep to be over
  548. //
  549. if (HalpFixedAcpiDescTable.x_pm1b_evt_blk.Address.QuadPart) {
  550. Pm1bEvt = HalpFixedAcpiDescTable.x_pm1b_evt_blk;
  551. } else {
  552. Pm1bEvt = HalpFixedAcpiDescTable.x_pm1a_evt_blk;
  553. }
  554. while ( ((HalpReadGenAddr(&HalpFixedAcpiDescTable.x_pm1a_evt_blk) & WAK_STS) == 0) &&
  555. ((HalpReadGenAddr(&Pm1bEvt) & WAK_STS) == 0) );
  556. } else {
  557. CurrentProcessorState = HalpHiberProcState + Prcb->Number;
  558. // HalpSetupStateForResume(CurrentProcessorState);
  559. }
  560. } // HalpAcpiPreSleep() == 0
  561. } // SystemHandler == 0
  562. //
  563. // Notify other processor of completion
  564. //
  565. HalpSleepSync = 0;
  566. } // processor 0
  567. //
  568. // Restore each processor's APIC state.
  569. //
  570. // HalpPostSleepMP<NumberProc, Barrier>;
  571. //
  572. // Restore caller's IRQL.
  573. //
  574. KeLowerIrql(OldIrql);
  575. //
  576. // Exit.
  577. //
  578. // HalpSleepSync = 0;
  579. return(Status);
  580. }