Pull ia64-mutex-primitives into release branch
[pandora-kernel.git] / drivers / acpi / hardware / hwsleep.c
1
2 /******************************************************************************
3  *
4  * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
5  *
6  *****************************************************************************/
7
8 /*
9  * Copyright (C) 2000 - 2006, R. Byron Moore
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 <linux/module.h>
46 #include <acpi/acpi.h>
47
48 #define _COMPONENT          ACPI_HARDWARE
49 ACPI_MODULE_NAME("hwsleep")
50
51 /*******************************************************************************
52  *
53  * FUNCTION:    acpi_set_firmware_waking_vector
54  *
55  * PARAMETERS:  physical_address    - Physical address of ACPI real mode
56  *                                    entry point.
57  *
58  * RETURN:      Status
59  *
60  * DESCRIPTION: Access function for the firmware_waking_vector field in FACS
61  *
62  ******************************************************************************/
63 acpi_status
64 acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
65 {
66
67         ACPI_FUNCTION_TRACE("acpi_set_firmware_waking_vector");
68
69         /* Set the vector */
70
71         if (acpi_gbl_common_fACS.vector_width == 32) {
72                 *(ACPI_CAST_PTR
73                   (u32, acpi_gbl_common_fACS.firmware_waking_vector))
74                     = (u32) physical_address;
75         } else {
76                 *acpi_gbl_common_fACS.firmware_waking_vector = physical_address;
77         }
78
79         return_ACPI_STATUS(AE_OK);
80 }
81
82 /*******************************************************************************
83  *
84  * FUNCTION:    acpi_get_firmware_waking_vector
85  *
86  * PARAMETERS:  *physical_address   - Where the contents of
87  *                                    the firmware_waking_vector field of
88  *                                    the FACS will be returned.
89  *
90  * RETURN:      Status, vector
91  *
92  * DESCRIPTION: Access function for the firmware_waking_vector field in FACS
93  *
94  ******************************************************************************/
95
96 #ifdef ACPI_FUTURE_USAGE
97 acpi_status
98 acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
99 {
100
101         ACPI_FUNCTION_TRACE("acpi_get_firmware_waking_vector");
102
103         if (!physical_address) {
104                 return_ACPI_STATUS(AE_BAD_PARAMETER);
105         }
106
107         /* Get the vector */
108
109         if (acpi_gbl_common_fACS.vector_width == 32) {
110                 *physical_address = (acpi_physical_address)
111                     *
112                     (ACPI_CAST_PTR
113                      (u32, acpi_gbl_common_fACS.firmware_waking_vector));
114         } else {
115                 *physical_address =
116                     *acpi_gbl_common_fACS.firmware_waking_vector;
117         }
118
119         return_ACPI_STATUS(AE_OK);
120 }
121 #endif
122
123 /*******************************************************************************
124  *
125  * FUNCTION:    acpi_enter_sleep_state_prep
126  *
127  * PARAMETERS:  sleep_state         - Which sleep state to enter
128  *
129  * RETURN:      Status
130  *
131  * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
132  *              This function must execute with interrupts enabled.
133  *              We break sleeping into 2 stages so that OSPM can handle
134  *              various OS-specific tasks between the two steps.
135  *
136  ******************************************************************************/
137
138 acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
139 {
140         acpi_status status;
141         struct acpi_object_list arg_list;
142         union acpi_object arg;
143
144         ACPI_FUNCTION_TRACE("acpi_enter_sleep_state_prep");
145
146         /*
147          * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
148          */
149         status = acpi_get_sleep_type_data(sleep_state,
150                                           &acpi_gbl_sleep_type_a,
151                                           &acpi_gbl_sleep_type_b);
152         if (ACPI_FAILURE(status)) {
153                 return_ACPI_STATUS(status);
154         }
155
156         /* Setup parameter object */
157
158         arg_list.count = 1;
159         arg_list.pointer = &arg;
160
161         arg.type = ACPI_TYPE_INTEGER;
162         arg.integer.value = sleep_state;
163
164         /* Run the _PTS and _GTS methods */
165
166         status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL);
167         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
168                 return_ACPI_STATUS(status);
169         }
170
171         status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
172         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
173                 return_ACPI_STATUS(status);
174         }
175
176         /* Setup the argument to _SST */
177
178         switch (sleep_state) {
179         case ACPI_STATE_S0:
180                 arg.integer.value = ACPI_SST_WORKING;
181                 break;
182
183         case ACPI_STATE_S1:
184         case ACPI_STATE_S2:
185         case ACPI_STATE_S3:
186                 arg.integer.value = ACPI_SST_SLEEPING;
187                 break;
188
189         case ACPI_STATE_S4:
190                 arg.integer.value = ACPI_SST_SLEEP_CONTEXT;
191                 break;
192
193         default:
194                 arg.integer.value = ACPI_SST_INDICATOR_OFF;     /* Default is off */
195                 break;
196         }
197
198         /* Set the system indicators to show the desired sleep state. */
199
200         status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
201         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
202                 ACPI_EXCEPTION((AE_INFO, status,
203                                 "While executing method _SST"));
204         }
205
206         return_ACPI_STATUS(AE_OK);
207 }
208
209 /*******************************************************************************
210  *
211  * FUNCTION:    acpi_enter_sleep_state
212  *
213  * PARAMETERS:  sleep_state         - Which sleep state to enter
214  *
215  * RETURN:      Status
216  *
217  * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
218  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
219  *
220  ******************************************************************************/
221
222 acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
223 {
224         u32 PM1Acontrol;
225         u32 PM1Bcontrol;
226         struct acpi_bit_register_info *sleep_type_reg_info;
227         struct acpi_bit_register_info *sleep_enable_reg_info;
228         u32 in_value;
229         acpi_status status;
230
231         ACPI_FUNCTION_TRACE("acpi_enter_sleep_state");
232
233         if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
234             (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
235                 ACPI_ERROR((AE_INFO, "Sleep values out of range: A=%X B=%X",
236                             acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
237                 return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
238         }
239
240         sleep_type_reg_info =
241             acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE_A);
242         sleep_enable_reg_info =
243             acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
244
245         /* Clear wake status */
246
247         status =
248             acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
249         if (ACPI_FAILURE(status)) {
250                 return_ACPI_STATUS(status);
251         }
252
253         /* Clear all fixed and general purpose status bits */
254
255         status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
256         if (ACPI_FAILURE(status)) {
257                 return_ACPI_STATUS(status);
258         }
259
260         /*
261          * 1) Disable/Clear all GPEs
262          * 2) Enable all wakeup GPEs
263          */
264         status = acpi_hw_disable_all_gpes();
265         if (ACPI_FAILURE(status)) {
266                 return_ACPI_STATUS(status);
267         }
268         acpi_gbl_system_awake_and_running = FALSE;
269
270         status = acpi_hw_enable_all_wakeup_gpes();
271         if (ACPI_FAILURE(status)) {
272                 return_ACPI_STATUS(status);
273         }
274
275         /* Get current value of PM1A control */
276
277         status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
278                                        ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
279         if (ACPI_FAILURE(status)) {
280                 return_ACPI_STATUS(status);
281         }
282         ACPI_DEBUG_PRINT((ACPI_DB_INIT,
283                           "Entering sleep state [S%d]\n", sleep_state));
284
285         /* Clear SLP_EN and SLP_TYP fields */
286
287         PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
288                          sleep_enable_reg_info->access_bit_mask);
289         PM1Bcontrol = PM1Acontrol;
290
291         /* Insert SLP_TYP bits */
292
293         PM1Acontrol |=
294             (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
295         PM1Bcontrol |=
296             (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
297
298         /*
299          * We split the writes of SLP_TYP and SLP_EN to workaround
300          * poorly implemented hardware.
301          */
302
303         /* Write #1: fill in SLP_TYP data */
304
305         status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
306                                         ACPI_REGISTER_PM1A_CONTROL,
307                                         PM1Acontrol);
308         if (ACPI_FAILURE(status)) {
309                 return_ACPI_STATUS(status);
310         }
311
312         status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
313                                         ACPI_REGISTER_PM1B_CONTROL,
314                                         PM1Bcontrol);
315         if (ACPI_FAILURE(status)) {
316                 return_ACPI_STATUS(status);
317         }
318
319         /* Insert SLP_ENABLE bit */
320
321         PM1Acontrol |= sleep_enable_reg_info->access_bit_mask;
322         PM1Bcontrol |= sleep_enable_reg_info->access_bit_mask;
323
324         /* Write #2: SLP_TYP + SLP_EN */
325
326         ACPI_FLUSH_CPU_CACHE();
327
328         status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
329                                         ACPI_REGISTER_PM1A_CONTROL,
330                                         PM1Acontrol);
331         if (ACPI_FAILURE(status)) {
332                 return_ACPI_STATUS(status);
333         }
334
335         status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
336                                         ACPI_REGISTER_PM1B_CONTROL,
337                                         PM1Bcontrol);
338         if (ACPI_FAILURE(status)) {
339                 return_ACPI_STATUS(status);
340         }
341
342         if (sleep_state > ACPI_STATE_S3) {
343                 /*
344                  * We wanted to sleep > S3, but it didn't happen (by virtue of the
345                  * fact that we are still executing!)
346                  *
347                  * Wait ten seconds, then try again. This is to get S4/S5 to work on
348                  * all machines.
349                  *
350                  * We wait so long to allow chipsets that poll this reg very slowly to
351                  * still read the right value. Ideally, this block would go
352                  * away entirely.
353                  */
354                 acpi_os_stall(10000000);
355
356                 status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
357                                                 ACPI_REGISTER_PM1_CONTROL,
358                                                 sleep_enable_reg_info->
359                                                 access_bit_mask);
360                 if (ACPI_FAILURE(status)) {
361                         return_ACPI_STATUS(status);
362                 }
363         }
364
365         /* Wait until we enter sleep state */
366
367         do {
368                 status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
369                                            ACPI_MTX_DO_NOT_LOCK);
370                 if (ACPI_FAILURE(status)) {
371                         return_ACPI_STATUS(status);
372                 }
373
374                 /* Spin until we wake */
375
376         } while (!in_value);
377
378         return_ACPI_STATUS(AE_OK);
379 }
380
381 EXPORT_SYMBOL(acpi_enter_sleep_state);
382
383 /*******************************************************************************
384  *
385  * FUNCTION:    acpi_enter_sleep_state_s4bios
386  *
387  * PARAMETERS:  None
388  *
389  * RETURN:      Status
390  *
391  * DESCRIPTION: Perform a S4 bios request.
392  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
393  *
394  ******************************************************************************/
395
396 acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
397 {
398         u32 in_value;
399         acpi_status status;
400
401         ACPI_FUNCTION_TRACE("acpi_enter_sleep_state_s4bios");
402
403         status =
404             acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
405         if (ACPI_FAILURE(status)) {
406                 return_ACPI_STATUS(status);
407         }
408
409         status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
410         if (ACPI_FAILURE(status)) {
411                 return_ACPI_STATUS(status);
412         }
413
414         /*
415          * 1) Disable/Clear all GPEs
416          * 2) Enable all wakeup GPEs
417          */
418         status = acpi_hw_disable_all_gpes();
419         if (ACPI_FAILURE(status)) {
420                 return_ACPI_STATUS(status);
421         }
422         acpi_gbl_system_awake_and_running = FALSE;
423
424         status = acpi_hw_enable_all_wakeup_gpes();
425         if (ACPI_FAILURE(status)) {
426                 return_ACPI_STATUS(status);
427         }
428
429         ACPI_FLUSH_CPU_CACHE();
430
431         status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
432                                     (u32) acpi_gbl_FADT->S4bios_req, 8);
433
434         do {
435                 acpi_os_stall(1000);
436                 status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
437                                            ACPI_MTX_DO_NOT_LOCK);
438                 if (ACPI_FAILURE(status)) {
439                         return_ACPI_STATUS(status);
440                 }
441         } while (!in_value);
442
443         return_ACPI_STATUS(AE_OK);
444 }
445
446 EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios);
447
448 /*******************************************************************************
449  *
450  * FUNCTION:    acpi_leave_sleep_state
451  *
452  * PARAMETERS:  sleep_state         - Which sleep state we just exited
453  *
454  * RETURN:      Status
455  *
456  * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
457  *              Called with interrupts ENABLED.
458  *
459  ******************************************************************************/
460
461 acpi_status acpi_leave_sleep_state(u8 sleep_state)
462 {
463         struct acpi_object_list arg_list;
464         union acpi_object arg;
465         acpi_status status;
466         struct acpi_bit_register_info *sleep_type_reg_info;
467         struct acpi_bit_register_info *sleep_enable_reg_info;
468         u32 PM1Acontrol;
469         u32 PM1Bcontrol;
470
471         ACPI_FUNCTION_TRACE("acpi_leave_sleep_state");
472
473         /*
474          * Set SLP_TYPE and SLP_EN to state S0.
475          * This is unclear from the ACPI Spec, but it is required
476          * by some machines.
477          */
478         status = acpi_get_sleep_type_data(ACPI_STATE_S0,
479                                           &acpi_gbl_sleep_type_a,
480                                           &acpi_gbl_sleep_type_b);
481         if (ACPI_SUCCESS(status)) {
482                 sleep_type_reg_info =
483                     acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE_A);
484                 sleep_enable_reg_info =
485                     acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
486
487                 /* Get current value of PM1A control */
488
489                 status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
490                                                ACPI_REGISTER_PM1_CONTROL,
491                                                &PM1Acontrol);
492                 if (ACPI_SUCCESS(status)) {
493                         /* Clear SLP_EN and SLP_TYP fields */
494
495                         PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
496                                          sleep_enable_reg_info->
497                                          access_bit_mask);
498                         PM1Bcontrol = PM1Acontrol;
499
500                         /* Insert SLP_TYP bits */
501
502                         PM1Acontrol |=
503                             (acpi_gbl_sleep_type_a << sleep_type_reg_info->
504                              bit_position);
505                         PM1Bcontrol |=
506                             (acpi_gbl_sleep_type_b << sleep_type_reg_info->
507                              bit_position);
508
509                         /* Just ignore any errors */
510
511                         (void)acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
512                                                      ACPI_REGISTER_PM1A_CONTROL,
513                                                      PM1Acontrol);
514                         (void)acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
515                                                      ACPI_REGISTER_PM1B_CONTROL,
516                                                      PM1Bcontrol);
517                 }
518         }
519
520         /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
521
522         acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
523
524         /* Setup parameter object */
525
526         arg_list.count = 1;
527         arg_list.pointer = &arg;
528         arg.type = ACPI_TYPE_INTEGER;
529
530         /* Ignore any errors from these methods */
531
532         arg.integer.value = ACPI_SST_WAKING;
533         status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
534         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
535                 ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
536         }
537
538         arg.integer.value = sleep_state;
539         status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
540         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
541                 ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
542         }
543
544         status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
545         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
546                 ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK"));
547         }
548         /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
549
550         /*
551          * Restore the GPEs:
552          * 1) Disable/Clear all GPEs
553          * 2) Enable all runtime GPEs
554          */
555         status = acpi_hw_disable_all_gpes();
556         if (ACPI_FAILURE(status)) {
557                 return_ACPI_STATUS(status);
558         }
559         acpi_gbl_system_awake_and_running = TRUE;
560
561         status = acpi_hw_enable_all_runtime_gpes();
562         if (ACPI_FAILURE(status)) {
563                 return_ACPI_STATUS(status);
564         }
565
566         /* Enable power button */
567
568         (void)
569             acpi_set_register(acpi_gbl_fixed_event_info
570                               [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1,
571                               ACPI_MTX_DO_NOT_LOCK);
572
573         (void)
574             acpi_set_register(acpi_gbl_fixed_event_info
575                               [ACPI_EVENT_POWER_BUTTON].status_register_id, 1,
576                               ACPI_MTX_DO_NOT_LOCK);
577
578         arg.integer.value = ACPI_SST_WORKING;
579         status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
580         if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
581                 ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
582         }
583
584         return_ACPI_STATUS(status);
585 }