hwsleep.c revision 1.1.1.2.4.2 1
2 /******************************************************************************
3 *
4 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000 - 2011, Intel Corp.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions, and the following disclaimer,
17 * without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 * substantially similar to the "NO WARRANTY" disclaimer below
20 * ("Disclaimer") and any redistribution must be conditioned upon
21 * including a substantially similar Disclaimer requirement for further
22 * binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 * of any contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
30 *
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
43 */
44
45 #include "acpi.h"
46 #include "accommon.h"
47
48 #define _COMPONENT ACPI_HARDWARE
49 ACPI_MODULE_NAME ("hwsleep")
50
51
52 /*******************************************************************************
53 *
54 * FUNCTION: AcpiSetFirmwareWakingVector
55 *
56 * PARAMETERS: PhysicalAddress - 32-bit physical address of ACPI real mode
57 * entry point.
58 *
59 * RETURN: Status
60 *
61 * DESCRIPTION: Sets the 32-bit FirmwareWakingVector field of the FACS
62 *
63 ******************************************************************************/
64
65 ACPI_STATUS
66 AcpiSetFirmwareWakingVector (
67 UINT32 PhysicalAddress)
68 {
69 ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector);
70
71
72 /* Set the 32-bit vector */
73
74 AcpiGbl_FACS->FirmwareWakingVector = PhysicalAddress;
75
76 /* Clear the 64-bit vector if it exists */
77
78 if ((AcpiGbl_FACS->Length > 32) && (AcpiGbl_FACS->Version >= 1))
79 {
80 AcpiGbl_FACS->XFirmwareWakingVector = 0;
81 }
82
83 return_ACPI_STATUS (AE_OK);
84 }
85
86 ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector)
87
88
89 #if ACPI_MACHINE_WIDTH == 64
90 /*******************************************************************************
91 *
92 * FUNCTION: AcpiSetFirmwareWakingVector64
93 *
94 * PARAMETERS: PhysicalAddress - 64-bit physical address of ACPI protected
95 * mode entry point.
96 *
97 * RETURN: Status
98 *
99 * DESCRIPTION: Sets the 64-bit X_FirmwareWakingVector field of the FACS, if
100 * it exists in the table. This function is intended for use with
101 * 64-bit host operating systems.
102 *
103 ******************************************************************************/
104
105 ACPI_STATUS
106 AcpiSetFirmwareWakingVector64 (
107 UINT64 PhysicalAddress)
108 {
109 ACPI_FUNCTION_TRACE (AcpiSetFirmwareWakingVector64);
110
111
112 /* Determine if the 64-bit vector actually exists */
113
114 if ((AcpiGbl_FACS->Length <= 32) || (AcpiGbl_FACS->Version < 1))
115 {
116 return_ACPI_STATUS (AE_NOT_EXIST);
117 }
118
119 /* Clear 32-bit vector, set the 64-bit X_ vector */
120
121 AcpiGbl_FACS->FirmwareWakingVector = 0;
122 AcpiGbl_FACS->XFirmwareWakingVector = PhysicalAddress;
123 return_ACPI_STATUS (AE_OK);
124 }
125
126 ACPI_EXPORT_SYMBOL (AcpiSetFirmwareWakingVector64)
127 #endif
128
129 /*******************************************************************************
130 *
131 * FUNCTION: AcpiEnterSleepStatePrep
132 *
133 * PARAMETERS: SleepState - Which sleep state to enter
134 *
135 * RETURN: Status
136 *
137 * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
138 * This function must execute with interrupts enabled.
139 * We break sleeping into 2 stages so that OSPM can handle
140 * various OS-specific tasks between the two steps.
141 *
142 ******************************************************************************/
143
144 ACPI_STATUS
145 AcpiEnterSleepStatePrep (
146 UINT8 SleepState)
147 {
148 ACPI_STATUS Status;
149 ACPI_OBJECT_LIST ArgList;
150 ACPI_OBJECT Arg;
151
152
153 ACPI_FUNCTION_TRACE (AcpiEnterSleepStatePrep);
154
155
156 /* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */
157
158 Status = AcpiGetSleepTypeData (SleepState,
159 &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
160 if (ACPI_FAILURE (Status))
161 {
162 return_ACPI_STATUS (Status);
163 }
164
165 /* Execute the _PTS method (Prepare To Sleep) */
166
167 ArgList.Count = 1;
168 ArgList.Pointer = &Arg;
169 Arg.Type = ACPI_TYPE_INTEGER;
170 Arg.Integer.Value = SleepState;
171
172 Status = AcpiEvaluateObject (NULL, METHOD_NAME__PTS, &ArgList, NULL);
173 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
174 {
175 return_ACPI_STATUS (Status);
176 }
177
178 /* Setup the argument to the _SST method (System STatus) */
179
180 switch (SleepState)
181 {
182 case ACPI_STATE_S0:
183 Arg.Integer.Value = ACPI_SST_WORKING;
184 break;
185
186 case ACPI_STATE_S1:
187 case ACPI_STATE_S2:
188 case ACPI_STATE_S3:
189 Arg.Integer.Value = ACPI_SST_SLEEPING;
190 break;
191
192 case ACPI_STATE_S4:
193 Arg.Integer.Value = ACPI_SST_SLEEP_CONTEXT;
194 break;
195
196 default:
197 Arg.Integer.Value = ACPI_SST_INDICATOR_OFF; /* Default is off */
198 break;
199 }
200
201 /*
202 * Set the system indicators to show the desired sleep state.
203 * _SST is an optional method (return no error if not found)
204 */
205 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
206 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
207 {
208 ACPI_EXCEPTION ((AE_INFO, Status, "While executing method _SST"));
209 }
210
211 return_ACPI_STATUS (AE_OK);
212 }
213
214 ACPI_EXPORT_SYMBOL (AcpiEnterSleepStatePrep)
215
216
217 /*******************************************************************************
218 *
219 * FUNCTION: AcpiEnterSleepState
220 *
221 * PARAMETERS: SleepState - Which sleep state to enter
222 *
223 * RETURN: Status
224 *
225 * DESCRIPTION: Enter a system sleep state
226 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
227 *
228 ******************************************************************************/
229
230 ACPI_STATUS
231 AcpiEnterSleepState (
232 UINT8 SleepState)
233 {
234 UINT32 Pm1aControl;
235 UINT32 Pm1bControl;
236 ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo;
237 ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo;
238 UINT32 InValue;
239 ACPI_OBJECT_LIST ArgList;
240 ACPI_OBJECT Arg;
241 ACPI_STATUS Status;
242
243
244 ACPI_FUNCTION_TRACE (AcpiEnterSleepState);
245
246
247 if ((AcpiGbl_SleepTypeA > ACPI_SLEEP_TYPE_MAX) ||
248 (AcpiGbl_SleepTypeB > ACPI_SLEEP_TYPE_MAX))
249 {
250 ACPI_ERROR ((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
251 AcpiGbl_SleepTypeA, AcpiGbl_SleepTypeB));
252 return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
253 }
254
255 SleepTypeRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
256 SleepEnableRegInfo = AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
257
258 /* Clear wake status */
259
260 Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
261 if (ACPI_FAILURE (Status))
262 {
263 return_ACPI_STATUS (Status);
264 }
265
266 /* Clear all fixed and general purpose status bits */
267
268 Status = AcpiHwClearAcpiStatus ();
269 if (ACPI_FAILURE (Status))
270 {
271 return_ACPI_STATUS (Status);
272 }
273
274 if (SleepState != ACPI_STATE_S5)
275 {
276 /*
277 * Disable BM arbitration. This feature is contained within an
278 * optional register (PM2 Control), so ignore a BAD_ADDRESS
279 * exception.
280 */
281 Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 1);
282 if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS))
283 {
284 return_ACPI_STATUS (Status);
285 }
286 }
287
288 /*
289 * 1) Disable/Clear all GPEs
290 * 2) Enable all wakeup GPEs
291 */
292 Status = AcpiHwDisableAllGpes ();
293 if (ACPI_FAILURE (Status))
294 {
295 return_ACPI_STATUS (Status);
296 }
297 AcpiGbl_SystemAwakeAndRunning = FALSE;
298
299 Status = AcpiHwEnableAllWakeupGpes ();
300 if (ACPI_FAILURE (Status))
301 {
302 return_ACPI_STATUS (Status);
303 }
304
305 /* Execute the _GTS method (Going To Sleep) */
306
307 ArgList.Count = 1;
308 ArgList.Pointer = &Arg;
309 Arg.Type = ACPI_TYPE_INTEGER;
310 Arg.Integer.Value = SleepState;
311
312 Status = AcpiEvaluateObject (NULL, METHOD_NAME__GTS, &ArgList, NULL);
313 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
314 {
315 return_ACPI_STATUS (Status);
316 }
317
318 /* Get current value of PM1A control */
319
320 Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
321 &Pm1aControl);
322 if (ACPI_FAILURE (Status))
323 {
324 return_ACPI_STATUS (Status);
325 }
326 ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
327 "Entering sleep state [S%u]\n", SleepState));
328
329 /* Clear the SLP_EN and SLP_TYP fields */
330
331 Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask |
332 SleepEnableRegInfo->AccessBitMask);
333 Pm1bControl = Pm1aControl;
334
335 /* Insert the SLP_TYP bits */
336
337 Pm1aControl |= (AcpiGbl_SleepTypeA << SleepTypeRegInfo->BitPosition);
338 Pm1bControl |= (AcpiGbl_SleepTypeB << SleepTypeRegInfo->BitPosition);
339
340 /*
341 * We split the writes of SLP_TYP and SLP_EN to workaround
342 * poorly implemented hardware.
343 */
344
345 /* Write #1: write the SLP_TYP data to the PM1 Control registers */
346
347 Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
348 if (ACPI_FAILURE (Status))
349 {
350 return_ACPI_STATUS (Status);
351 }
352
353 /* Insert the sleep enable (SLP_EN) bit */
354
355 Pm1aControl |= SleepEnableRegInfo->AccessBitMask;
356 Pm1bControl |= SleepEnableRegInfo->AccessBitMask;
357
358 /* Flush caches, as per ACPI specification */
359
360 ACPI_FLUSH_CPU_CACHE ();
361
362 /* Write #2: Write both SLP_TYP + SLP_EN */
363
364 Status = AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
365 if (ACPI_FAILURE (Status))
366 {
367 return_ACPI_STATUS (Status);
368 }
369
370 if (SleepState > ACPI_STATE_S3)
371 {
372 /*
373 * We wanted to sleep > S3, but it didn't happen (by virtue of the
374 * fact that we are still executing!)
375 *
376 * Wait ten seconds, then try again. This is to get S4/S5 to work on
377 * all machines.
378 *
379 * We wait so long to allow chipsets that poll this reg very slowly
380 * to still read the right value. Ideally, this block would go
381 * away entirely.
382 */
383 AcpiOsStall (10000000);
384
385 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_CONTROL,
386 SleepEnableRegInfo->AccessBitMask);
387 if (ACPI_FAILURE (Status))
388 {
389 return_ACPI_STATUS (Status);
390 }
391 }
392
393 /* Wait until we enter sleep state */
394
395 do
396 {
397 Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
398 if (ACPI_FAILURE (Status))
399 {
400 return_ACPI_STATUS (Status);
401 }
402
403 /* Spin until we wake */
404
405 } while (!InValue);
406
407 return_ACPI_STATUS (AE_OK);
408 }
409
410 ACPI_EXPORT_SYMBOL (AcpiEnterSleepState)
411
412
413 /*******************************************************************************
414 *
415 * FUNCTION: AcpiEnterSleepStateS4bios
416 *
417 * PARAMETERS: None
418 *
419 * RETURN: Status
420 *
421 * DESCRIPTION: Perform a S4 bios request.
422 * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
423 *
424 ******************************************************************************/
425
426 ACPI_STATUS
427 AcpiEnterSleepStateS4bios (
428 void)
429 {
430 UINT32 InValue;
431 ACPI_STATUS Status;
432
433
434 ACPI_FUNCTION_TRACE (AcpiEnterSleepStateS4bios);
435
436
437 /* Clear the wake status bit (PM1) */
438
439 Status = AcpiWriteBitRegister (ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
440 if (ACPI_FAILURE (Status))
441 {
442 return_ACPI_STATUS (Status);
443 }
444
445 Status = AcpiHwClearAcpiStatus ();
446 if (ACPI_FAILURE (Status))
447 {
448 return_ACPI_STATUS (Status);
449 }
450
451 /*
452 * 1) Disable/Clear all GPEs
453 * 2) Enable all wakeup GPEs
454 */
455 Status = AcpiHwDisableAllGpes ();
456 if (ACPI_FAILURE (Status))
457 {
458 return_ACPI_STATUS (Status);
459 }
460 AcpiGbl_SystemAwakeAndRunning = FALSE;
461
462 Status = AcpiHwEnableAllWakeupGpes ();
463 if (ACPI_FAILURE (Status))
464 {
465 return_ACPI_STATUS (Status);
466 }
467
468 ACPI_FLUSH_CPU_CACHE ();
469
470 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand,
471 (UINT32) AcpiGbl_FADT.S4BiosRequest, 8);
472
473 do {
474 AcpiOsStall(1000);
475 Status = AcpiReadBitRegister (ACPI_BITREG_WAKE_STATUS, &InValue);
476 if (ACPI_FAILURE (Status))
477 {
478 return_ACPI_STATUS (Status);
479 }
480 } while (!InValue);
481
482 return_ACPI_STATUS (AE_OK);
483 }
484
485 ACPI_EXPORT_SYMBOL (AcpiEnterSleepStateS4bios)
486
487
488 /*******************************************************************************
489 *
490 * FUNCTION: AcpiLeaveSleepState
491 *
492 * PARAMETERS: SleepState - Which sleep state we just exited
493 *
494 * RETURN: Status
495 *
496 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
497 * Called with interrupts ENABLED.
498 *
499 ******************************************************************************/
500
501 ACPI_STATUS
502 AcpiLeaveSleepState (
503 UINT8 SleepState)
504 {
505 ACPI_OBJECT_LIST ArgList;
506 ACPI_OBJECT Arg;
507 ACPI_STATUS Status;
508 ACPI_BIT_REGISTER_INFO *SleepTypeRegInfo;
509 ACPI_BIT_REGISTER_INFO *SleepEnableRegInfo;
510 UINT32 Pm1aControl;
511 UINT32 Pm1bControl;
512
513
514 ACPI_FUNCTION_TRACE (AcpiLeaveSleepState);
515
516
517 /*
518 * Set SLP_TYPE and SLP_EN to state S0.
519 * This is unclear from the ACPI Spec, but it is required
520 * by some machines.
521 */
522 Status = AcpiGetSleepTypeData (ACPI_STATE_S0,
523 &AcpiGbl_SleepTypeA, &AcpiGbl_SleepTypeB);
524 if (ACPI_SUCCESS (Status))
525 {
526 SleepTypeRegInfo =
527 AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_TYPE);
528 SleepEnableRegInfo =
529 AcpiHwGetBitRegisterInfo (ACPI_BITREG_SLEEP_ENABLE);
530
531 /* Get current value of PM1A control */
532
533 Status = AcpiHwRegisterRead (ACPI_REGISTER_PM1_CONTROL,
534 &Pm1aControl);
535 if (ACPI_SUCCESS (Status))
536 {
537 /* Clear the SLP_EN and SLP_TYP fields */
538
539 Pm1aControl &= ~(SleepTypeRegInfo->AccessBitMask |
540 SleepEnableRegInfo->AccessBitMask);
541 Pm1bControl = Pm1aControl;
542
543 /* Insert the SLP_TYP bits */
544
545 Pm1aControl |= (AcpiGbl_SleepTypeA <<
546 SleepTypeRegInfo->BitPosition);
547 Pm1bControl |= (AcpiGbl_SleepTypeB <<
548 SleepTypeRegInfo->BitPosition);
549
550 /* Write the control registers and ignore any errors */
551
552 (void) AcpiHwWritePm1Control (Pm1aControl, Pm1bControl);
553 }
554 }
555
556 /* Ensure EnterSleepStatePrep -> EnterSleepState ordering */
557
558 AcpiGbl_SleepTypeA = ACPI_SLEEP_TYPE_INVALID;
559
560 /* Setup parameter object */
561
562 ArgList.Count = 1;
563 ArgList.Pointer = &Arg;
564 Arg.Type = ACPI_TYPE_INTEGER;
565
566 /* Ignore any errors from these methods */
567
568 Arg.Integer.Value = ACPI_SST_WAKING;
569 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
570 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
571 {
572 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST"));
573 }
574
575 Arg.Integer.Value = SleepState;
576 Status = AcpiEvaluateObject (NULL, METHOD_NAME__BFS, &ArgList, NULL);
577 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
578 {
579 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _BFS"));
580 }
581
582 Status = AcpiEvaluateObject (NULL, METHOD_NAME__WAK, &ArgList, NULL);
583 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
584 {
585 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _WAK"));
586 }
587 /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
588
589 /*
590 * Restore the GPEs:
591 * 1) Disable/Clear all GPEs
592 * 2) Enable all runtime GPEs
593 */
594 Status = AcpiHwDisableAllGpes ();
595 if (ACPI_FAILURE (Status))
596 {
597 return_ACPI_STATUS (Status);
598 }
599 AcpiGbl_SystemAwakeAndRunning = TRUE;
600
601 Status = AcpiHwEnableAllRuntimeGpes ();
602 if (ACPI_FAILURE (Status))
603 {
604 return_ACPI_STATUS (Status);
605 }
606
607 /* Enable power button */
608
609 (void) AcpiWriteBitRegister(
610 AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].EnableRegisterId,
611 ACPI_ENABLE_EVENT);
612
613 (void) AcpiWriteBitRegister(
614 AcpiGbl_FixedEventInfo[ACPI_EVENT_POWER_BUTTON].StatusRegisterId,
615 ACPI_CLEAR_STATUS);
616
617 /*
618 * Enable BM arbitration. This feature is contained within an
619 * optional register (PM2 Control), so ignore a BAD_ADDRESS
620 * exception.
621 */
622 Status = AcpiWriteBitRegister (ACPI_BITREG_ARB_DISABLE, 0);
623 if (ACPI_FAILURE (Status) && (Status != AE_BAD_ADDRESS))
624 {
625 return_ACPI_STATUS (Status);
626 }
627
628 Arg.Integer.Value = ACPI_SST_WORKING;
629 Status = AcpiEvaluateObject (NULL, METHOD_NAME__SST, &ArgList, NULL);
630 if (ACPI_FAILURE (Status) && Status != AE_NOT_FOUND)
631 {
632 ACPI_EXCEPTION ((AE_INFO, Status, "During Method _SST"));
633 }
634
635 return_ACPI_STATUS (Status);
636 }
637
638 ACPI_EXPORT_SYMBOL (AcpiLeaveSleepState)
639
640