hwsleep.c 17.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8

/******************************************************************************
 *
 * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
 *
 *****************************************************************************/

/*
9
 * Copyright (C) 2000 - 2011, Intel Corp.
L
Linus Torvalds 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
L
Len Brown 已提交
46 47
#include "accommon.h"
#include "actables.h"
48
#include <linux/tboot.h>
L
Linus Torvalds 已提交
49 50

#define _COMPONENT          ACPI_HARDWARE
L
Len Brown 已提交
51
ACPI_MODULE_NAME("hwsleep")
L
Linus Torvalds 已提交
52

R
Robert Moore 已提交
53
/*******************************************************************************
L
Linus Torvalds 已提交
54 55 56
 *
 * FUNCTION:    acpi_set_firmware_waking_vector
 *
57
 * PARAMETERS:  physical_address    - 32-bit physical address of ACPI real mode
L
Linus Torvalds 已提交
58 59 60 61
 *                                    entry point.
 *
 * RETURN:      Status
 *
62
 * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS
L
Linus Torvalds 已提交
63 64 65
 *
 ******************************************************************************/
acpi_status
66
acpi_set_firmware_waking_vector(u32 physical_address)
L
Linus Torvalds 已提交
67
{
B
Bob Moore 已提交
68
	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
L
Linus Torvalds 已提交
69

70

71 72 73 74 75 76 77 78
	/*
	 * According to the ACPI specification 2.0c and later, the 64-bit
	 * waking vector should be cleared and the 32-bit waking vector should
	 * be used, unless we want the wake-up code to be called by the BIOS in
	 * Protected Mode.  Some systems (for example HP dv5-1004nr) are known
	 * to fail to resume if the 64-bit vector is used.
	 */

79 80
	/* Set the 32-bit vector */

81
	acpi_gbl_FACS->firmware_waking_vector = physical_address;
82 83 84

	/* Clear the 64-bit vector if it exists */

85 86
	if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) {
		acpi_gbl_FACS->xfirmware_waking_vector = 0;
87
	}
L
Linus Torvalds 已提交
88

L
Len Brown 已提交
89
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
90 91
}

B
Bob Moore 已提交
92 93
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)

94
#if ACPI_MACHINE_WIDTH == 64
R
Robert Moore 已提交
95
/*******************************************************************************
L
Linus Torvalds 已提交
96
 *
97
 * FUNCTION:    acpi_set_firmware_waking_vector64
L
Linus Torvalds 已提交
98
 *
99 100
 * PARAMETERS:  physical_address    - 64-bit physical address of ACPI protected
 *                                    mode entry point.
L
Linus Torvalds 已提交
101
 *
102
 * RETURN:      Status
L
Linus Torvalds 已提交
103
 *
104
 * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if
105 106
 *              it exists in the table. This function is intended for use with
 *              64-bit host operating systems.
L
Linus Torvalds 已提交
107 108 109
 *
 ******************************************************************************/
acpi_status
110
acpi_set_firmware_waking_vector64(u64 physical_address)
L
Linus Torvalds 已提交
111
{
112
	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64);
L
Linus Torvalds 已提交
113 114


115 116
	/* Determine if the 64-bit vector actually exists */

117
	if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) {
118 119 120 121 122
		return_ACPI_STATUS(AE_NOT_EXIST);
	}

	/* Clear 32-bit vector, set the 64-bit X_ vector */

123 124
	acpi_gbl_FACS->firmware_waking_vector = 0;
	acpi_gbl_FACS->xfirmware_waking_vector = physical_address;
L
Linus Torvalds 已提交
125

L
Len Brown 已提交
126
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
127
}
B
Bob Moore 已提交
128

129
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64)
130
#endif
131

R
Robert Moore 已提交
132
/*******************************************************************************
L
Linus Torvalds 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145
 *
 * FUNCTION:    acpi_enter_sleep_state_prep
 *
 * PARAMETERS:  sleep_state         - Which sleep state to enter
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
 *              This function must execute with interrupts enabled.
 *              We break sleeping into 2 stages so that OSPM can handle
 *              various OS-specific tasks between the two steps.
 *
 ******************************************************************************/
L
Len Brown 已提交
146
acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
L
Linus Torvalds 已提交
147
{
L
Len Brown 已提交
148 149 150
	acpi_status status;
	struct acpi_object_list arg_list;
	union acpi_object arg;
L
Linus Torvalds 已提交
151

B
Bob Moore 已提交
152
	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
L
Linus Torvalds 已提交
153

154 155
	/* _PSW methods could be run here to enable wake-on keyboard, LAN, etc. */

L
Len Brown 已提交
156 157 158 159 160
	status = acpi_get_sleep_type_data(sleep_state,
					  &acpi_gbl_sleep_type_a,
					  &acpi_gbl_sleep_type_b);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
161 162 163 164 165 166 167 168 169 170
	}

	/* Setup parameter object */

	arg_list.count = 1;
	arg_list.pointer = &arg;

	arg.type = ACPI_TYPE_INTEGER;
	arg.integer.value = sleep_state;

171
	/* Run the _PTS method */
L
Linus Torvalds 已提交
172

L
Len Brown 已提交
173 174 175
	status = acpi_evaluate_object(NULL, METHOD_NAME__PTS, &arg_list, NULL);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
	}

	/* Setup the argument to _SST */

	switch (sleep_state) {
	case ACPI_STATE_S0:
		arg.integer.value = ACPI_SST_WORKING;
		break;

	case ACPI_STATE_S1:
	case ACPI_STATE_S2:
	case ACPI_STATE_S3:
		arg.integer.value = ACPI_SST_SLEEPING;
		break;

	case ACPI_STATE_S4:
		arg.integer.value = ACPI_SST_SLEEP_CONTEXT;
		break;

	default:
L
Len Brown 已提交
196
		arg.integer.value = ACPI_SST_INDICATOR_OFF;	/* Default is off */
L
Linus Torvalds 已提交
197 198 199
		break;
	}

200 201 202 203
	/*
	 * Set the system indicators to show the desired sleep state.
	 * _SST is an optional method (return no error if not found)
	 */
L
Len Brown 已提交
204 205
	status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
B
Bob Moore 已提交
206 207
		ACPI_EXCEPTION((AE_INFO, status,
				"While executing method _SST"));
L
Linus Torvalds 已提交
208 209
	}

210
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
211 212
}

B
Bob Moore 已提交
213 214
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)

215 216 217 218 219 220
static unsigned int gts, bfs;
module_param(gts, uint, 0644);
module_param(bfs, uint, 0644);
MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);

R
Robert Moore 已提交
221
/*******************************************************************************
L
Linus Torvalds 已提交
222 223 224 225 226 227 228 229 230 231 232
 *
 * FUNCTION:    acpi_enter_sleep_state
 *
 * PARAMETERS:  sleep_state         - Which sleep state to enter
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
 *
 ******************************************************************************/
L
Len Brown 已提交
233
acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
L
Linus Torvalds 已提交
234
{
235 236
	u32 pm1a_control;
	u32 pm1b_control;
L
Len Brown 已提交
237 238 239
	struct acpi_bit_register_info *sleep_type_reg_info;
	struct acpi_bit_register_info *sleep_enable_reg_info;
	u32 in_value;
240 241
	struct acpi_object_list arg_list;
	union acpi_object arg;
L
Len Brown 已提交
242
	acpi_status status;
L
Linus Torvalds 已提交
243

B
Bob Moore 已提交
244
	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
L
Linus Torvalds 已提交
245 246

	if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
L
Len Brown 已提交
247
	    (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
248
		ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
B
Bob Moore 已提交
249
			    acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
L
Len Brown 已提交
250
		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
L
Linus Torvalds 已提交
251 252
	}

L
Len Brown 已提交
253
	sleep_type_reg_info =
254
	    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
L
Len Brown 已提交
255 256
	sleep_enable_reg_info =
	    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
L
Linus Torvalds 已提交
257 258 259

	/* Clear wake status */

260 261
	status =
	    acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
L
Len Brown 已提交
262 263
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
264 265 266 267
	}

	/* Clear all fixed and general purpose status bits */

268
	status = acpi_hw_clear_acpi_status();
L
Len Brown 已提交
269 270
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
271 272 273
	}

	/*
P
Pavel Machek 已提交
274
	 * 1) Disable/Clear all GPEs
L
Linus Torvalds 已提交
275 276
	 * 2) Enable all wakeup GPEs
	 */
277 278 279 280
	status = acpi_hw_disable_all_gpes();
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}
L
Linus Torvalds 已提交
281 282
	acpi_gbl_system_awake_and_running = FALSE;

L
Len Brown 已提交
283 284 285
	status = acpi_hw_enable_all_wakeup_gpes();
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
286 287
	}

288 289
	if (gts) {
		/* Execute the _GTS method */
290

291 292 293 294
		arg_list.count = 1;
		arg_list.pointer = &arg;
		arg.type = ACPI_TYPE_INTEGER;
		arg.integer.value = sleep_state;
295

296 297 298 299
		status = acpi_evaluate_object(NULL, METHOD_NAME__GTS, &arg_list, NULL);
		if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
			return_ACPI_STATUS(status);
		}
300 301
	}

L
Linus Torvalds 已提交
302 303
	/* Get current value of PM1A control */

304 305
	status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
				       &pm1a_control);
L
Len Brown 已提交
306 307
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
308
	}
L
Len Brown 已提交
309
	ACPI_DEBUG_PRINT((ACPI_DB_INIT,
310
			  "Entering sleep state [S%u]\n", sleep_state));
L
Linus Torvalds 已提交
311

312
	/* Clear the SLP_EN and SLP_TYP fields */
L
Linus Torvalds 已提交
313

314 315 316
	pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
			  sleep_enable_reg_info->access_bit_mask);
	pm1b_control = pm1a_control;
L
Linus Torvalds 已提交
317

318
	/* Insert the SLP_TYP bits */
L
Linus Torvalds 已提交
319

320
	pm1a_control |=
L
Len Brown 已提交
321
	    (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
322
	pm1b_control |=
L
Len Brown 已提交
323
	    (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
L
Linus Torvalds 已提交
324 325 326 327 328 329

	/*
	 * We split the writes of SLP_TYP and SLP_EN to workaround
	 * poorly implemented hardware.
	 */

330
	/* Write #1: write the SLP_TYP data to the PM1 Control registers */
L
Linus Torvalds 已提交
331

332
	status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
L
Len Brown 已提交
333 334
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
335 336
	}

337
	/* Insert the sleep enable (SLP_EN) bit */
L
Linus Torvalds 已提交
338

339 340
	pm1a_control |= sleep_enable_reg_info->access_bit_mask;
	pm1b_control |= sleep_enable_reg_info->access_bit_mask;
L
Linus Torvalds 已提交
341

342
	/* Flush caches, as per ACPI specification */
L
Linus Torvalds 已提交
343

L
Len Brown 已提交
344
	ACPI_FLUSH_CPU_CACHE();
L
Linus Torvalds 已提交
345

346 347
	tboot_sleep(sleep_state, pm1a_control, pm1b_control);

348
	/* Write #2: Write both SLP_TYP + SLP_EN */
L
Linus Torvalds 已提交
349

350
	status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);
L
Len Brown 已提交
351 352
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
353 354 355 356
	}

	if (sleep_state > ACPI_STATE_S3) {
		/*
R
Robert Moore 已提交
357 358
		 * We wanted to sleep > S3, but it didn't happen (by virtue of the
		 * fact that we are still executing!)
L
Linus Torvalds 已提交
359
		 *
R
Robert Moore 已提交
360 361
		 * Wait ten seconds, then try again. This is to get S4/S5 to work on
		 * all machines.
L
Linus Torvalds 已提交
362
		 *
363 364
		 * We wait so long to allow chipsets that poll this reg very slowly
		 * to still read the right value. Ideally, this block would go
L
Linus Torvalds 已提交
365 366
		 * away entirely.
		 */
L
Len Brown 已提交
367 368
		acpi_os_stall(10000000);

369
		status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
L
Len Brown 已提交
370 371 372 373
						sleep_enable_reg_info->
						access_bit_mask);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
374 375 376 377 378 379
		}
	}

	/* Wait until we enter sleep state */

	do {
380
		status = acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS,
381
						    &in_value);
L
Len Brown 已提交
382 383
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
384 385 386 387 388 389
		}

		/* Spin until we wake */

	} while (!in_value);

L
Len Brown 已提交
390
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
391 392
}

B
Bob Moore 已提交
393
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
L
Linus Torvalds 已提交
394

R
Robert Moore 已提交
395
/*******************************************************************************
L
Linus Torvalds 已提交
396 397 398 399 400 401 402 403 404 405 406
 *
 * FUNCTION:    acpi_enter_sleep_state_s4bios
 *
 * PARAMETERS:  None
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Perform a S4 bios request.
 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
 *
 ******************************************************************************/
L
Len Brown 已提交
407
acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
L
Linus Torvalds 已提交
408
{
L
Len Brown 已提交
409 410
	u32 in_value;
	acpi_status status;
L
Linus Torvalds 已提交
411

B
Bob Moore 已提交
412
	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
L
Linus Torvalds 已提交
413

414 415 416 417
	/* Clear the wake status bit (PM1) */

	status =
	    acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
L
Len Brown 已提交
418 419
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
420 421
	}

422
	status = acpi_hw_clear_acpi_status();
L
Len Brown 已提交
423 424
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
425 426 427 428 429 430
	}

	/*
	 * 1) Disable/Clear all GPEs
	 * 2) Enable all wakeup GPEs
	 */
L
Len Brown 已提交
431 432 433
	status = acpi_hw_disable_all_gpes();
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
434 435 436
	}
	acpi_gbl_system_awake_and_running = FALSE;

L
Len Brown 已提交
437 438 439
	status = acpi_hw_enable_all_wakeup_gpes();
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
440 441
	}

L
Len Brown 已提交
442
	ACPI_FLUSH_CPU_CACHE();
L
Linus Torvalds 已提交
443

B
Bob Moore 已提交
444
	status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
445
				    (u32) acpi_gbl_FADT.S4bios_request, 8);
L
Linus Torvalds 已提交
446 447 448

	do {
		acpi_os_stall(1000);
449 450
		status =
		    acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
L
Len Brown 已提交
451 452
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
453 454 455
		}
	} while (!in_value);

L
Len Brown 已提交
456
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
457 458
}

B
Bob Moore 已提交
459
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
L
Linus Torvalds 已提交
460

R
Robert Moore 已提交
461
/*******************************************************************************
L
Linus Torvalds 已提交
462
 *
463
 * FUNCTION:    acpi_leave_sleep_state_prep
L
Linus Torvalds 已提交
464
 *
465
 * PARAMETERS:  sleep_state         - Which sleep state we are exiting
L
Linus Torvalds 已提交
466 467 468
 *
 * RETURN:      Status
 *
469 470 471
 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
 *              sleep.
 *              Called with interrupts DISABLED.
L
Linus Torvalds 已提交
472 473
 *
 ******************************************************************************/
474
acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
L
Linus Torvalds 已提交
475
{
L
Len Brown 已提交
476 477 478 479 480
	struct acpi_object_list arg_list;
	union acpi_object arg;
	acpi_status status;
	struct acpi_bit_register_info *sleep_type_reg_info;
	struct acpi_bit_register_info *sleep_enable_reg_info;
481 482
	u32 pm1a_control;
	u32 pm1b_control;
L
Linus Torvalds 已提交
483

484
	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
L
Linus Torvalds 已提交
485 486 487 488 489 490

	/*
	 * Set SLP_TYPE and SLP_EN to state S0.
	 * This is unclear from the ACPI Spec, but it is required
	 * by some machines.
	 */
L
Len Brown 已提交
491 492 493 494 495
	status = acpi_get_sleep_type_data(ACPI_STATE_S0,
					  &acpi_gbl_sleep_type_a,
					  &acpi_gbl_sleep_type_b);
	if (ACPI_SUCCESS(status)) {
		sleep_type_reg_info =
496
		    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_TYPE);
L
Len Brown 已提交
497 498
		sleep_enable_reg_info =
		    acpi_hw_get_bit_register_info(ACPI_BITREG_SLEEP_ENABLE);
L
Linus Torvalds 已提交
499 500 501

		/* Get current value of PM1A control */

502
		status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
503
					       &pm1a_control);
L
Len Brown 已提交
504
		if (ACPI_SUCCESS(status)) {
B
Bob Moore 已提交
505

506
			/* Clear the SLP_EN and SLP_TYP fields */
L
Linus Torvalds 已提交
507

508 509 510 511
			pm1a_control &= ~(sleep_type_reg_info->access_bit_mask |
					  sleep_enable_reg_info->
					  access_bit_mask);
			pm1b_control = pm1a_control;
L
Linus Torvalds 已提交
512

513
			/* Insert the SLP_TYP bits */
L
Linus Torvalds 已提交
514

515 516 517 518
			pm1a_control |= (acpi_gbl_sleep_type_a <<
					 sleep_type_reg_info->bit_position);
			pm1b_control |= (acpi_gbl_sleep_type_b <<
					 sleep_type_reg_info->bit_position);
L
Linus Torvalds 已提交
519

520
			/* Write the control registers and ignore any errors */
L
Linus Torvalds 已提交
521

522 523
			(void)acpi_hw_write_pm1_control(pm1a_control,
							pm1b_control);
L
Linus Torvalds 已提交
524 525 526
		}
	}

527 528
	if (bfs) {
		/* Execute the _BFS method */
529

530 531 532 533
		arg_list.count = 1;
		arg_list.pointer = &arg;
		arg.type = ACPI_TYPE_INTEGER;
		arg.integer.value = sleep_state;
534

535 536 537 538
		status = acpi_evaluate_object(NULL, METHOD_NAME__BFS, &arg_list, NULL);
		if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
			ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
		}
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
	}
	return_ACPI_STATUS(status);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_leave_sleep_state
 *
 * PARAMETERS:  sleep_state         - Which sleep state we just exited
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
 *              Called with interrupts ENABLED.
 *
 ******************************************************************************/
acpi_status acpi_leave_sleep_state(u8 sleep_state)
{
	struct acpi_object_list arg_list;
	union acpi_object arg;
	acpi_status status;

	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);

L
Linus Torvalds 已提交
563 564 565 566 567 568 569 570 571 572 573 574 575
	/* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */

	acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;

	/* Setup parameter object */

	arg_list.count = 1;
	arg_list.pointer = &arg;
	arg.type = ACPI_TYPE_INTEGER;

	/* Ignore any errors from these methods */

	arg.integer.value = ACPI_SST_WAKING;
L
Len Brown 已提交
576 577
	status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
B
Bob Moore 已提交
578
		ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
L
Linus Torvalds 已提交
579 580 581
	}

	/*
582 583 584
	 * GPEs must be enabled before _WAK is called as GPEs
	 * might get fired there
	 *
L
Linus Torvalds 已提交
585 586 587 588
	 * Restore the GPEs:
	 * 1) Disable/Clear all GPEs
	 * 2) Enable all runtime GPEs
	 */
L
Len Brown 已提交
589 590 591
	status = acpi_hw_disable_all_gpes();
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
592
	}
L
Len Brown 已提交
593 594 595
	status = acpi_hw_enable_all_runtime_gpes();
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
596 597
	}

598
	arg.integer.value = sleep_state;
599 600 601 602 603 604
	status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
		ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK"));
	}
	/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */

M
Matthew Garrett 已提交
605 606 607 608 609
	/*
	 * Some BIOSes assume that WAK_STS will be cleared on resume and use
	 * it to determine whether the system is rebooting or resuming. Clear
	 * it for compatibility.
	 */
610
	acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, 1);
M
Matthew Garrett 已提交
611

612 613
	acpi_gbl_system_awake_and_running = TRUE;

L
Linus Torvalds 已提交
614 615
	/* Enable power button */

L
Len Brown 已提交
616
	(void)
617
	    acpi_write_bit_register(acpi_gbl_fixed_event_info
618 619
			      [ACPI_EVENT_POWER_BUTTON].
			      enable_register_id, ACPI_ENABLE_EVENT);
R
Robert Moore 已提交
620

L
Len Brown 已提交
621
	(void)
622
	    acpi_write_bit_register(acpi_gbl_fixed_event_info
623 624
			      [ACPI_EVENT_POWER_BUTTON].
			      status_register_id, ACPI_CLEAR_STATUS);
L
Linus Torvalds 已提交
625 626

	arg.integer.value = ACPI_SST_WORKING;
L
Len Brown 已提交
627 628
	status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
B
Bob Moore 已提交
629
		ACPI_EXCEPTION((AE_INFO, status, "During Method _SST"));
L
Linus Torvalds 已提交
630 631
	}

L
Len Brown 已提交
632
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
633
}
B
Bob Moore 已提交
634 635

ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)