Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6595 serge 1
/******************************************************************************
2
 *
3
 * Name: hwxfsleep.c - ACPI Hardware Sleep/Wake External Interfaces
4
 *
5
 *****************************************************************************/
6
 
7
/*
8
 * Copyright (C) 2000 - 2015, Intel Corp.
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions, and the following disclaimer,
16
 *    without modification.
17
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18
 *    substantially similar to the "NO WARRANTY" disclaimer below
19
 *    ("Disclaimer") and any redistribution must be conditioned upon
20
 *    including a substantially similar Disclaimer requirement for further
21
 *    binary redistribution.
22
 * 3. Neither the names of the above-listed copyright holders nor the names
23
 *    of any contributors may be used to endorse or promote products derived
24
 *    from this software without specific prior written permission.
25
 *
26
 * Alternatively, this software may be distributed under the terms of the
27
 * GNU General Public License ("GPL") version 2 as published by the Free
28
 * Software Foundation.
29
 *
30
 * NO WARRANTY
31
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41
 * POSSIBILITY OF SUCH DAMAGES.
42
 */
43
 
44
#define EXPORT_ACPI_INTERFACES
45
 
46
#include 
47
#include "accommon.h"
48
 
49
#define _COMPONENT          ACPI_HARDWARE
50
ACPI_MODULE_NAME("hwxfsleep")
51
 
52
/* Local prototypes */
53
#if (!ACPI_REDUCED_HARDWARE)
54
static acpi_status
55
acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs,
56
				    acpi_physical_address physical_address,
57
				    acpi_physical_address physical_address64);
58
#endif
59
 
60
static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id);
61
 
62
/*
63
 * Dispatch table used to efficiently branch to the various sleep
64
 * functions.
65
 */
66
#define ACPI_SLEEP_FUNCTION_ID         0
67
#define ACPI_WAKE_PREP_FUNCTION_ID     1
68
#define ACPI_WAKE_FUNCTION_ID          2
69
 
70
/* Legacy functions are optional, based upon ACPI_REDUCED_HARDWARE */
71
 
72
static struct acpi_sleep_functions acpi_sleep_dispatch[] = {
73
	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_sleep),
74
	 acpi_hw_extended_sleep},
75
	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake_prep),
76
	 acpi_hw_extended_wake_prep},
77
	{ACPI_HW_OPTIONAL_FUNCTION(acpi_hw_legacy_wake), acpi_hw_extended_wake}
78
};
79
 
80
/*
81
 * These functions are removed for the ACPI_REDUCED_HARDWARE case:
82
 *      acpi_set_firmware_waking_vectors
83
 *      acpi_set_firmware_waking_vector
84
 *      acpi_set_firmware_waking_vector64
85
 *      acpi_enter_sleep_state_s4bios
86
 */
87
 
88
#if (!ACPI_REDUCED_HARDWARE)
89
/*******************************************************************************
90
 *
91
 * FUNCTION:    acpi_hw_set_firmware_waking_vectors
92
 *
93
 * PARAMETERS:  facs                - Pointer to FACS table
94
 *              physical_address    - 32-bit physical address of ACPI real mode
95
 *                                    entry point.
96
 *              physical_address64  - 64-bit physical address of ACPI protected
97
 *                                    mode entry point.
98
 *
99
 * RETURN:      Status
100
 *
101
 * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
102
 *
103
 ******************************************************************************/
104
 
105
static acpi_status
106
acpi_hw_set_firmware_waking_vectors(struct acpi_table_facs *facs,
107
				    acpi_physical_address physical_address,
108
				    acpi_physical_address physical_address64)
109
{
110
	ACPI_FUNCTION_TRACE(acpi_hw_set_firmware_waking_vectors);
111
 
112
 
113
	/*
114
	 * According to the ACPI specification 2.0c and later, the 64-bit
115
	 * waking vector should be cleared and the 32-bit waking vector should
116
	 * be used, unless we want the wake-up code to be called by the BIOS in
117
	 * Protected Mode.  Some systems (for example HP dv5-1004nr) are known
118
	 * to fail to resume if the 64-bit vector is used.
119
	 */
120
 
121
	/* Set the 32-bit vector */
122
 
123
	facs->firmware_waking_vector = (u32)physical_address;
124
 
125
	if (facs->length > 32) {
126
		if (facs->version >= 1) {
127
 
128
			/* Set the 64-bit vector */
129
 
130
			facs->xfirmware_waking_vector = physical_address64;
131
		} else {
132
			/* Clear the 64-bit vector if it exists */
133
 
134
			facs->xfirmware_waking_vector = 0;
135
		}
136
	}
137
 
138
	return_ACPI_STATUS(AE_OK);
139
}
140
 
141
/*******************************************************************************
142
 *
143
 * FUNCTION:    acpi_set_firmware_waking_vectors
144
 *
145
 * PARAMETERS:  physical_address    - 32-bit physical address of ACPI real mode
146
 *                                    entry point.
147
 *              physical_address64  - 64-bit physical address of ACPI protected
148
 *                                    mode entry point.
149
 *
150
 * RETURN:      Status
151
 *
152
 * DESCRIPTION: Sets the firmware_waking_vector fields of the FACS
153
 *
154
 ******************************************************************************/
155
 
156
acpi_status
157
acpi_set_firmware_waking_vectors(acpi_physical_address physical_address,
158
				 acpi_physical_address physical_address64)
159
{
160
 
161
	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors);
162
 
163
	if (acpi_gbl_FACS) {
164
		(void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_FACS,
165
							  physical_address,
166
							  physical_address64);
167
	}
168
 
169
	return_ACPI_STATUS(AE_OK);
170
}
171
 
172
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vectors)
173
 
174
/*******************************************************************************
175
 *
176
 * FUNCTION:    acpi_set_firmware_waking_vector
177
 *
178
 * PARAMETERS:  physical_address    - 32-bit physical address of ACPI real mode
179
 *                                    entry point.
180
 *
181
 * RETURN:      Status
182
 *
183
 * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS
184
 *
185
 ******************************************************************************/
186
acpi_status acpi_set_firmware_waking_vector(u32 physical_address)
187
{
188
	acpi_status status;
189
 
190
	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
191
 
192
	status = acpi_set_firmware_waking_vectors((acpi_physical_address)
193
						  physical_address, 0);
194
 
195
	return_ACPI_STATUS(status);
196
}
197
 
198
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
199
 
200
#if ACPI_MACHINE_WIDTH == 64
201
/*******************************************************************************
202
 *
203
 * FUNCTION:    acpi_set_firmware_waking_vector64
204
 *
205
 * PARAMETERS:  physical_address    - 64-bit physical address of ACPI protected
206
 *                                    mode entry point.
207
 *
208
 * RETURN:      Status
209
 *
210
 * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if
211
 *              it exists in the table. This function is intended for use with
212
 *              64-bit host operating systems.
213
 *
214
 ******************************************************************************/
215
acpi_status acpi_set_firmware_waking_vector64(u64 physical_address)
216
{
217
	acpi_status status;
218
 
219
	ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64);
220
 
221
	status = acpi_set_firmware_waking_vectors(0,
222
						  (acpi_physical_address)
223
						  physical_address);
224
 
225
	return_ACPI_STATUS(status);
226
}
227
 
228
ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64)
229
#endif
230
/*******************************************************************************
231
 *
232
 * FUNCTION:    acpi_enter_sleep_state_s4bios
233
 *
234
 * PARAMETERS:  None
235
 *
236
 * RETURN:      Status
237
 *
238
 * DESCRIPTION: Perform a S4 bios request.
239
 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
240
 *
241
 ******************************************************************************/
242
acpi_status acpi_enter_sleep_state_s4bios(void)
243
{
244
	u32 in_value;
245
	acpi_status status;
246
 
247
	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
248
 
249
	/* Clear the wake status bit (PM1) */
250
 
251
	status =
252
	    acpi_write_bit_register(ACPI_BITREG_WAKE_STATUS, ACPI_CLEAR_STATUS);
253
	if (ACPI_FAILURE(status)) {
254
		return_ACPI_STATUS(status);
255
	}
256
 
257
	status = acpi_hw_clear_acpi_status();
258
	if (ACPI_FAILURE(status)) {
259
		return_ACPI_STATUS(status);
260
	}
261
 
262
	/*
263
	 * 1) Disable/Clear all GPEs
264
	 * 2) Enable all wakeup GPEs
265
	 */
266
	status = acpi_hw_disable_all_gpes();
267
	if (ACPI_FAILURE(status)) {
268
		return_ACPI_STATUS(status);
269
	}
270
	acpi_gbl_system_awake_and_running = FALSE;
271
 
272
	status = acpi_hw_enable_all_wakeup_gpes();
273
	if (ACPI_FAILURE(status)) {
274
		return_ACPI_STATUS(status);
275
	}
276
 
277
	ACPI_FLUSH_CPU_CACHE();
278
 
279
	status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
280
				    (u32)acpi_gbl_FADT.s4_bios_request, 8);
281
 
282
	do {
283
		acpi_os_stall(ACPI_USEC_PER_MSEC);
284
		status =
285
		    acpi_read_bit_register(ACPI_BITREG_WAKE_STATUS, &in_value);
286
		if (ACPI_FAILURE(status)) {
287
			return_ACPI_STATUS(status);
288
		}
289
	} while (!in_value);
290
 
291
	return_ACPI_STATUS(AE_OK);
292
}
293
 
294
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
295
#endif				/* !ACPI_REDUCED_HARDWARE */
296
/*******************************************************************************
297
 *
298
 * FUNCTION:    acpi_hw_sleep_dispatch
299
 *
300
 * PARAMETERS:  sleep_state         - Which sleep state to enter/exit
301
 *              function_id         - Sleep, wake_prep, or Wake
302
 *
303
 * RETURN:      Status from the invoked sleep handling function.
304
 *
305
 * DESCRIPTION: Dispatch a sleep/wake request to the appropriate handling
306
 *              function.
307
 *
308
 ******************************************************************************/
309
static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id)
310
{
311
	acpi_status status;
312
	struct acpi_sleep_functions *sleep_functions =
313
	    &acpi_sleep_dispatch[function_id];
314
 
315
#if (!ACPI_REDUCED_HARDWARE)
316
	/*
317
	 * If the Hardware Reduced flag is set (from the FADT), we must
318
	 * use the extended sleep registers (FADT). Note: As per the ACPI
319
	 * specification, these extended registers are to be used for HW-reduced
320
	 * platforms only. They are not general-purpose replacements for the
321
	 * legacy PM register sleep support.
322
	 */
323
	if (acpi_gbl_reduced_hardware) {
324
		status = sleep_functions->extended_function(sleep_state);
325
	} else {
326
		/* Legacy sleep */
327
 
328
		status = sleep_functions->legacy_function(sleep_state);
329
	}
330
 
331
	return (status);
332
 
333
#else
334
	/*
335
	 * For the case where reduced-hardware-only code is being generated,
336
	 * we know that only the extended sleep registers are available
337
	 */
338
	status = sleep_functions->extended_function(sleep_state);
339
	return (status);
340
 
341
#endif				/* !ACPI_REDUCED_HARDWARE */
342
}
343
 
344
/*******************************************************************************
345
 *
346
 * FUNCTION:    acpi_enter_sleep_state_prep
347
 *
348
 * PARAMETERS:  sleep_state         - Which sleep state to enter
349
 *
350
 * RETURN:      Status
351
 *
352
 * DESCRIPTION: Prepare to enter a system sleep state.
353
 *              This function must execute with interrupts enabled.
354
 *              We break sleeping into 2 stages so that OSPM can handle
355
 *              various OS-specific tasks between the two steps.
356
 *
357
 ******************************************************************************/
358
 
359
acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
360
{
361
	acpi_status status;
362
	struct acpi_object_list arg_list;
363
	union acpi_object arg;
364
	u32 sst_value;
365
 
366
	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_prep);
367
 
368
	status = acpi_get_sleep_type_data(sleep_state,
369
					  &acpi_gbl_sleep_type_a,
370
					  &acpi_gbl_sleep_type_b);
371
	if (ACPI_FAILURE(status)) {
372
		return_ACPI_STATUS(status);
373
	}
374
 
375
	/* Execute the _PTS method (Prepare To Sleep) */
376
 
377
	arg_list.count = 1;
378
	arg_list.pointer = &arg;
379
	arg.type = ACPI_TYPE_INTEGER;
380
	arg.integer.value = sleep_state;
381
 
382
	status =
383
	    acpi_evaluate_object(NULL, METHOD_PATHNAME__PTS, &arg_list, NULL);
384
	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
385
		return_ACPI_STATUS(status);
386
	}
387
 
388
	/* Setup the argument to the _SST method (System STatus) */
389
 
390
	switch (sleep_state) {
391
	case ACPI_STATE_S0:
392
 
393
		sst_value = ACPI_SST_WORKING;
394
		break;
395
 
396
	case ACPI_STATE_S1:
397
	case ACPI_STATE_S2:
398
	case ACPI_STATE_S3:
399
 
400
		sst_value = ACPI_SST_SLEEPING;
401
		break;
402
 
403
	case ACPI_STATE_S4:
404
 
405
		sst_value = ACPI_SST_SLEEP_CONTEXT;
406
		break;
407
 
408
	default:
409
 
410
		sst_value = ACPI_SST_INDICATOR_OFF;	/* Default is off */
411
		break;
412
	}
413
 
414
	/*
415
	 * Set the system indicators to show the desired sleep state.
416
	 * _SST is an optional method (return no error if not found)
417
	 */
418
	acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, sst_value);
419
	return_ACPI_STATUS(AE_OK);
420
}
421
 
422
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
423
 
424
/*******************************************************************************
425
 *
426
 * FUNCTION:    acpi_enter_sleep_state
427
 *
428
 * PARAMETERS:  sleep_state         - Which sleep state to enter
429
 *
430
 * RETURN:      Status
431
 *
432
 * DESCRIPTION: Enter a system sleep state
433
 *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
434
 *
435
 ******************************************************************************/
436
acpi_status acpi_enter_sleep_state(u8 sleep_state)
437
{
438
	acpi_status status;
439
 
440
	ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
441
 
442
	if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
443
	    (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
444
		ACPI_ERROR((AE_INFO, "Sleep values out of range: A=0x%X B=0x%X",
445
			    acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
446
		return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
447
	}
448
 
449
	status = acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID);
450
	return_ACPI_STATUS(status);
451
}
452
 
453
ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
454
 
455
/*******************************************************************************
456
 *
457
 * FUNCTION:    acpi_leave_sleep_state_prep
458
 *
459
 * PARAMETERS:  sleep_state         - Which sleep state we are exiting
460
 *
461
 * RETURN:      Status
462
 *
463
 * DESCRIPTION: Perform the first state of OS-independent ACPI cleanup after a
464
 *              sleep. Called with interrupts DISABLED.
465
 *              We break wake/resume into 2 stages so that OSPM can handle
466
 *              various OS-specific tasks between the two steps.
467
 *
468
 ******************************************************************************/
469
acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
470
{
471
	acpi_status status;
472
 
473
	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
474
 
475
	status =
476
	    acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_PREP_FUNCTION_ID);
477
	return_ACPI_STATUS(status);
478
}
479
 
480
ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state_prep)
481
 
482
/*******************************************************************************
483
 *
484
 * FUNCTION:    acpi_leave_sleep_state
485
 *
486
 * PARAMETERS:  sleep_state         - Which sleep state we are exiting
487
 *
488
 * RETURN:      Status
489
 *
490
 * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
491
 *              Called with interrupts ENABLED.
492
 *
493
 ******************************************************************************/
494
acpi_status acpi_leave_sleep_state(u8 sleep_state)
495
{
496
	acpi_status status;
497
 
498
	ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
499
 
500
	status = acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_FUNCTION_ID);
501
	return_ACPI_STATUS(status);
502
}
503
 
504
ACPI_EXPORT_SYMBOL(acpi_leave_sleep_state)