1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Name: hwesleep.c - ACPI Hardware Sleep/Wake Support functions for the |
5 | * extended FADT-V5 sleep registers. |
6 | * |
7 | * Copyright (C) 2000 - 2023, Intel Corp. |
8 | * |
9 | *****************************************************************************/ |
10 | |
11 | #include <acpi/acpi.h> |
12 | #include "accommon.h" |
13 | |
14 | #define _COMPONENT ACPI_HARDWARE |
15 | ACPI_MODULE_NAME("hwesleep" ) |
16 | |
17 | /******************************************************************************* |
18 | * |
19 | * FUNCTION: acpi_hw_execute_sleep_method |
20 | * |
21 | * PARAMETERS: method_pathname - Pathname of method to execute |
22 | * integer_argument - Argument to pass to the method |
23 | * |
24 | * RETURN: None |
25 | * |
26 | * DESCRIPTION: Execute a sleep/wake related method with one integer argument |
27 | * and no return value. |
28 | * |
29 | ******************************************************************************/ |
30 | void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument) |
31 | { |
32 | struct acpi_object_list arg_list; |
33 | union acpi_object arg; |
34 | acpi_status status; |
35 | |
36 | ACPI_FUNCTION_TRACE(hw_execute_sleep_method); |
37 | |
38 | /* One argument, integer_argument; No return value expected */ |
39 | |
40 | arg_list.count = 1; |
41 | arg_list.pointer = &arg; |
42 | arg.type = ACPI_TYPE_INTEGER; |
43 | arg.integer.value = (u64)integer_argument; |
44 | |
45 | status = acpi_evaluate_object(NULL, pathname: method_pathname, parameter_objects: &arg_list, NULL); |
46 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { |
47 | ACPI_EXCEPTION((AE_INFO, status, "While executing method %s" , |
48 | method_pathname)); |
49 | } |
50 | |
51 | return_VOID; |
52 | } |
53 | |
54 | /******************************************************************************* |
55 | * |
56 | * FUNCTION: acpi_hw_extended_sleep |
57 | * |
58 | * PARAMETERS: sleep_state - Which sleep state to enter |
59 | * |
60 | * RETURN: Status |
61 | * |
62 | * DESCRIPTION: Enter a system sleep state via the extended FADT sleep |
63 | * registers (V5 FADT). |
64 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED |
65 | * |
66 | ******************************************************************************/ |
67 | |
68 | acpi_status acpi_hw_extended_sleep(u8 sleep_state) |
69 | { |
70 | acpi_status status; |
71 | u8 sleep_control; |
72 | u64 sleep_status; |
73 | |
74 | ACPI_FUNCTION_TRACE(hw_extended_sleep); |
75 | |
76 | /* Extended sleep registers must be valid */ |
77 | |
78 | if (!acpi_gbl_FADT.sleep_control.address || |
79 | !acpi_gbl_FADT.sleep_status.address) { |
80 | return_ACPI_STATUS(AE_NOT_EXIST); |
81 | } |
82 | |
83 | /* Clear wake status (WAK_STS) */ |
84 | |
85 | status = acpi_write(value: (u64)ACPI_X_WAKE_STATUS, |
86 | reg: &acpi_gbl_FADT.sleep_status); |
87 | if (ACPI_FAILURE(status)) { |
88 | return_ACPI_STATUS(status); |
89 | } |
90 | |
91 | acpi_gbl_system_awake_and_running = FALSE; |
92 | |
93 | /* |
94 | * Set the SLP_TYP and SLP_EN bits. |
95 | * |
96 | * Note: We only use the first value returned by the \_Sx method |
97 | * (acpi_gbl_sleep_type_a) - As per ACPI specification. |
98 | */ |
99 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, |
100 | "Entering sleep state [S%u]\n" , sleep_state)); |
101 | |
102 | sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & |
103 | ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE; |
104 | |
105 | /* Flush caches, as per ACPI specification */ |
106 | |
107 | if (sleep_state < ACPI_STATE_S4) { |
108 | ACPI_FLUSH_CPU_CACHE(); |
109 | } |
110 | |
111 | status = acpi_os_enter_sleep(sleep_state, rega_value: sleep_control, regb_value: 0); |
112 | if (status == AE_CTRL_TERMINATE) { |
113 | return_ACPI_STATUS(AE_OK); |
114 | } |
115 | if (ACPI_FAILURE(status)) { |
116 | return_ACPI_STATUS(status); |
117 | } |
118 | |
119 | status = acpi_write(value: (u64)sleep_control, reg: &acpi_gbl_FADT.sleep_control); |
120 | if (ACPI_FAILURE(status)) { |
121 | return_ACPI_STATUS(status); |
122 | } |
123 | |
124 | /* Wait for transition back to Working State */ |
125 | |
126 | do { |
127 | status = acpi_read(value: &sleep_status, reg: &acpi_gbl_FADT.sleep_status); |
128 | if (ACPI_FAILURE(status)) { |
129 | return_ACPI_STATUS(status); |
130 | } |
131 | |
132 | } while (!(((u8)sleep_status) & ACPI_X_WAKE_STATUS)); |
133 | |
134 | return_ACPI_STATUS(AE_OK); |
135 | } |
136 | |
137 | /******************************************************************************* |
138 | * |
139 | * FUNCTION: acpi_hw_extended_wake_prep |
140 | * |
141 | * PARAMETERS: sleep_state - Which sleep state we just exited |
142 | * |
143 | * RETURN: Status |
144 | * |
145 | * DESCRIPTION: Perform first part of OS-independent ACPI cleanup after |
146 | * a sleep. Called with interrupts ENABLED. |
147 | * |
148 | ******************************************************************************/ |
149 | |
150 | acpi_status acpi_hw_extended_wake_prep(u8 sleep_state) |
151 | { |
152 | u8 sleep_type_value; |
153 | |
154 | ACPI_FUNCTION_TRACE(hw_extended_wake_prep); |
155 | |
156 | if (acpi_gbl_sleep_type_a_s0 != ACPI_SLEEP_TYPE_INVALID) { |
157 | sleep_type_value = |
158 | ((acpi_gbl_sleep_type_a_s0 << ACPI_X_SLEEP_TYPE_POSITION) & |
159 | ACPI_X_SLEEP_TYPE_MASK); |
160 | |
161 | (void)acpi_write(value: (u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE), |
162 | reg: &acpi_gbl_FADT.sleep_control); |
163 | } |
164 | |
165 | return_ACPI_STATUS(AE_OK); |
166 | } |
167 | |
168 | /******************************************************************************* |
169 | * |
170 | * FUNCTION: acpi_hw_extended_wake |
171 | * |
172 | * PARAMETERS: sleep_state - Which sleep state we just exited |
173 | * |
174 | * RETURN: Status |
175 | * |
176 | * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep |
177 | * Called with interrupts ENABLED. |
178 | * |
179 | ******************************************************************************/ |
180 | |
181 | acpi_status acpi_hw_extended_wake(u8 sleep_state) |
182 | { |
183 | ACPI_FUNCTION_TRACE(hw_extended_wake); |
184 | |
185 | /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */ |
186 | |
187 | acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID; |
188 | |
189 | /* Execute the wake methods */ |
190 | |
191 | acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WAKING); |
192 | acpi_hw_execute_sleep_method(METHOD_PATHNAME__WAK, integer_argument: sleep_state); |
193 | |
194 | /* |
195 | * Some BIOS code assumes that WAK_STS will be cleared on resume |
196 | * and use it to determine whether the system is rebooting or |
197 | * resuming. Clear WAK_STS for compatibility. |
198 | */ |
199 | (void)acpi_write(value: (u64)ACPI_X_WAKE_STATUS, reg: &acpi_gbl_FADT.sleep_status); |
200 | acpi_gbl_system_awake_and_running = TRUE; |
201 | |
202 | acpi_hw_execute_sleep_method(METHOD_PATHNAME__SST, ACPI_SST_WORKING); |
203 | return_ACPI_STATUS(AE_OK); |
204 | } |
205 | |