diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2014-09-12 05:50:21 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2014-09-12 05:50:21 -0400 |
commit | c2eb6b6139183af632a5be8f7c33006d7b03702d (patch) | |
tree | 5d63e31481edd059c0174acff23e73d4ec3abbea | |
parent | e3672649faae400e8a598938766a63f395a27ae6 (diff) | |
parent | 18910ab0d916b1a87016d69efd027714a80521dd (diff) |
Merge arm64 CPU suspend branch
* cpuidle:
arm64: add PSCI CPU_SUSPEND based cpu_suspend support
arm64: kernel: introduce cpu_init_idle CPU operation
arm64: kernel: refactor the CPU suspend API for retention states
Documentation: arm: define DT idle states bindings
-rw-r--r-- | Documentation/devicetree/bindings/arm/cpus.txt | 8 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/arm/idle-states.txt | 679 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/arm/psci.txt | 14 | ||||
-rw-r--r-- | arch/arm64/include/asm/cpu_ops.h | 3 | ||||
-rw-r--r-- | arch/arm64/include/asm/cpuidle.h | 13 | ||||
-rw-r--r-- | arch/arm64/include/asm/suspend.h | 1 | ||||
-rw-r--r-- | arch/arm64/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/arm64/kernel/cpuidle.c | 31 | ||||
-rw-r--r-- | arch/arm64/kernel/psci.c | 104 | ||||
-rw-r--r-- | arch/arm64/kernel/sleep.S | 47 | ||||
-rw-r--r-- | arch/arm64/kernel/suspend.c | 48 |
11 files changed, 916 insertions, 33 deletions
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index 298e2f6b33c6..6fd0f15e899a 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt | |||
@@ -219,6 +219,12 @@ nodes to be present and contain the properties described below. | |||
219 | Value type: <phandle> | 219 | Value type: <phandle> |
220 | Definition: Specifies the ACC[2] node associated with this CPU. | 220 | Definition: Specifies the ACC[2] node associated with this CPU. |
221 | 221 | ||
222 | - cpu-idle-states | ||
223 | Usage: Optional | ||
224 | Value type: <prop-encoded-array> | ||
225 | Definition: | ||
226 | # List of phandles to idle state nodes supported | ||
227 | by this cpu [3]. | ||
222 | 228 | ||
223 | Example 1 (dual-cluster big.LITTLE system 32-bit): | 229 | Example 1 (dual-cluster big.LITTLE system 32-bit): |
224 | 230 | ||
@@ -415,3 +421,5 @@ cpus { | |||
415 | -- | 421 | -- |
416 | [1] arm/msm/qcom,saw2.txt | 422 | [1] arm/msm/qcom,saw2.txt |
417 | [2] arm/msm/qcom,kpss-acc.txt | 423 | [2] arm/msm/qcom,kpss-acc.txt |
424 | [3] ARM Linux kernel documentation - idle states bindings | ||
425 | Documentation/devicetree/bindings/arm/idle-states.txt | ||
diff --git a/Documentation/devicetree/bindings/arm/idle-states.txt b/Documentation/devicetree/bindings/arm/idle-states.txt new file mode 100644 index 000000000000..37375c7f3ccc --- /dev/null +++ b/Documentation/devicetree/bindings/arm/idle-states.txt | |||
@@ -0,0 +1,679 @@ | |||
1 | ========================================== | ||
2 | ARM idle states binding description | ||
3 | ========================================== | ||
4 | |||
5 | ========================================== | ||
6 | 1 - Introduction | ||
7 | ========================================== | ||
8 | |||
9 | ARM systems contain HW capable of managing power consumption dynamically, | ||
10 | where cores can be put in different low-power states (ranging from simple | ||
11 | wfi to power gating) according to OS PM policies. The CPU states representing | ||
12 | the range of dynamic idle states that a processor can enter at run-time, can be | ||
13 | specified through device tree bindings representing the parameters required | ||
14 | to enter/exit specific idle states on a given processor. | ||
15 | |||
16 | According to the Server Base System Architecture document (SBSA, [3]), the | ||
17 | power states an ARM CPU can be put into are identified by the following list: | ||
18 | |||
19 | - Running | ||
20 | - Idle_standby | ||
21 | - Idle_retention | ||
22 | - Sleep | ||
23 | - Off | ||
24 | |||
25 | The power states described in the SBSA document define the basic CPU states on | ||
26 | top of which ARM platforms implement power management schemes that allow an OS | ||
27 | PM implementation to put the processor in different idle states (which include | ||
28 | states listed above; "off" state is not an idle state since it does not have | ||
29 | wake-up capabilities, hence it is not considered in this document). | ||
30 | |||
31 | Idle state parameters (eg entry latency) are platform specific and need to be | ||
32 | characterized with bindings that provide the required information to OS PM | ||
33 | code so that it can build the required tables and use them at runtime. | ||
34 | |||
35 | The device tree binding definition for ARM idle states is the subject of this | ||
36 | document. | ||
37 | |||
38 | =========================================== | ||
39 | 2 - idle-states definitions | ||
40 | =========================================== | ||
41 | |||
42 | Idle states are characterized for a specific system through a set of | ||
43 | timing and energy related properties, that underline the HW behaviour | ||
44 | triggered upon idle states entry and exit. | ||
45 | |||
46 | The following diagram depicts the CPU execution phases and related timing | ||
47 | properties required to enter and exit an idle state: | ||
48 | |||
49 | ..__[EXEC]__|__[PREP]__|__[ENTRY]__|__[IDLE]__|__[EXIT]__|__[EXEC]__.. | ||
50 | | | | | | | ||
51 | |||
52 | |<------ entry ------->| | ||
53 | | latency | | ||
54 | |<- exit ->| | ||
55 | | latency | | ||
56 | |<-------- min-residency -------->| | ||
57 | |<------- wakeup-latency ------->| | ||
58 | |||
59 | Diagram 1: CPU idle state execution phases | ||
60 | |||
61 | EXEC: Normal CPU execution. | ||
62 | |||
63 | PREP: Preparation phase before committing the hardware to idle mode | ||
64 | like cache flushing. This is abortable on pending wake-up | ||
65 | event conditions. The abort latency is assumed to be negligible | ||
66 | (i.e. less than the ENTRY + EXIT duration). If aborted, CPU | ||
67 | goes back to EXEC. This phase is optional. If not abortable, | ||
68 | this should be included in the ENTRY phase instead. | ||
69 | |||
70 | ENTRY: The hardware is committed to idle mode. This period must run | ||
71 | to completion up to IDLE before anything else can happen. | ||
72 | |||
73 | IDLE: This is the actual energy-saving idle period. This may last | ||
74 | between 0 and infinite time, until a wake-up event occurs. | ||
75 | |||
76 | EXIT: Period during which the CPU is brought back to operational | ||
77 | mode (EXEC). | ||
78 | |||
79 | entry-latency: Worst case latency required to enter the idle state. The | ||
80 | exit-latency may be guaranteed only after entry-latency has passed. | ||
81 | |||
82 | min-residency: Minimum period, including preparation and entry, for a given | ||
83 | idle state to be worthwhile energywise. | ||
84 | |||
85 | wakeup-latency: Maximum delay between the signaling of a wake-up event and the | ||
86 | CPU being able to execute normal code again. If not specified, this is assumed | ||
87 | to be entry-latency + exit-latency. | ||
88 | |||
89 | These timing parameters can be used by an OS in different circumstances. | ||
90 | |||
91 | An idle CPU requires the expected min-residency time to select the most | ||
92 | appropriate idle state based on the expected expiry time of the next IRQ | ||
93 | (ie wake-up) that causes the CPU to return to the EXEC phase. | ||
94 | |||
95 | An operating system scheduler may need to compute the shortest wake-up delay | ||
96 | for CPUs in the system by detecting how long will it take to get a CPU out | ||
97 | of an idle state, eg: | ||
98 | |||
99 | wakeup-delay = exit-latency + max(entry-latency - (now - entry-timestamp), 0) | ||
100 | |||
101 | In other words, the scheduler can make its scheduling decision by selecting | ||
102 | (eg waking-up) the CPU with the shortest wake-up latency. | ||
103 | The wake-up latency must take into account the entry latency if that period | ||
104 | has not expired. The abortable nature of the PREP period can be ignored | ||
105 | if it cannot be relied upon (e.g. the PREP deadline may occur much sooner than | ||
106 | the worst case since it depends on the CPU operating conditions, ie caches | ||
107 | state). | ||
108 | |||
109 | An OS has to reliably probe the wakeup-latency since some devices can enforce | ||
110 | latency constraints guarantees to work properly, so the OS has to detect the | ||
111 | worst case wake-up latency it can incur if a CPU is allowed to enter an | ||
112 | idle state, and possibly to prevent that to guarantee reliable device | ||
113 | functioning. | ||
114 | |||
115 | The min-residency time parameter deserves further explanation since it is | ||
116 | expressed in time units but must factor in energy consumption coefficients. | ||
117 | |||
118 | The energy consumption of a cpu when it enters a power state can be roughly | ||
119 | characterised by the following graph: | ||
120 | |||
121 | | | ||
122 | | | ||
123 | | | ||
124 | e | | ||
125 | n | /--- | ||
126 | e | /------ | ||
127 | r | /------ | ||
128 | g | /----- | ||
129 | y | /------ | ||
130 | | ---- | ||
131 | | /| | ||
132 | | / | | ||
133 | | / | | ||
134 | | / | | ||
135 | | / | | ||
136 | | / | | ||
137 | |/ | | ||
138 | -----|-------+---------------------------------- | ||
139 | 0| 1 time(ms) | ||
140 | |||
141 | Graph 1: Energy vs time example | ||
142 | |||
143 | The graph is split in two parts delimited by time 1ms on the X-axis. | ||
144 | The graph curve with X-axis values = { x | 0 < x < 1ms } has a steep slope | ||
145 | and denotes the energy costs incurred whilst entering and leaving the idle | ||
146 | state. | ||
147 | The graph curve in the area delimited by X-axis values = {x | x > 1ms } has | ||
148 | shallower slope and essentially represents the energy consumption of the idle | ||
149 | state. | ||
150 | |||
151 | min-residency is defined for a given idle state as the minimum expected | ||
152 | residency time for a state (inclusive of preparation and entry) after | ||
153 | which choosing that state become the most energy efficient option. A good | ||
154 | way to visualise this, is by taking the same graph above and comparing some | ||
155 | states energy consumptions plots. | ||
156 | |||
157 | For sake of simplicity, let's consider a system with two idle states IDLE1, | ||
158 | and IDLE2: | ||
159 | |||
160 | | | ||
161 | | | ||
162 | | | ||
163 | | /-- IDLE1 | ||
164 | e | /--- | ||
165 | n | /---- | ||
166 | e | /--- | ||
167 | r | /-----/--------- IDLE2 | ||
168 | g | /-------/--------- | ||
169 | y | ------------ /---| | ||
170 | | / /---- | | ||
171 | | / /--- | | ||
172 | | / /---- | | ||
173 | | / /--- | | ||
174 | | --- | | ||
175 | | / | | ||
176 | | / | | ||
177 | |/ | time | ||
178 | ---/----------------------------+------------------------ | ||
179 | |IDLE1-energy < IDLE2-energy | IDLE2-energy < IDLE1-energy | ||
180 | | | ||
181 | IDLE2-min-residency | ||
182 | |||
183 | Graph 2: idle states min-residency example | ||
184 | |||
185 | In graph 2 above, that takes into account idle states entry/exit energy | ||
186 | costs, it is clear that if the idle state residency time (ie time till next | ||
187 | wake-up IRQ) is less than IDLE2-min-residency, IDLE1 is the better idle state | ||
188 | choice energywise. | ||
189 | |||
190 | This is mainly down to the fact that IDLE1 entry/exit energy costs are lower | ||
191 | than IDLE2. | ||
192 | |||
193 | However, the lower power consumption (ie shallower energy curve slope) of idle | ||
194 | state IDLE2 implies that after a suitable time, IDLE2 becomes more energy | ||
195 | efficient. | ||
196 | |||
197 | The time at which IDLE2 becomes more energy efficient than IDLE1 (and other | ||
198 | shallower states in a system with multiple idle states) is defined | ||
199 | IDLE2-min-residency and corresponds to the time when energy consumption of | ||
200 | IDLE1 and IDLE2 states breaks even. | ||
201 | |||
202 | The definitions provided in this section underpin the idle states | ||
203 | properties specification that is the subject of the following sections. | ||
204 | |||
205 | =========================================== | ||
206 | 3 - idle-states node | ||
207 | =========================================== | ||
208 | |||
209 | ARM processor idle states are defined within the idle-states node, which is | ||
210 | a direct child of the cpus node [1] and provides a container where the | ||
211 | processor idle states, defined as device tree nodes, are listed. | ||
212 | |||
213 | - idle-states node | ||
214 | |||
215 | Usage: Optional - On ARM systems, it is a container of processor idle | ||
216 | states nodes. If the system does not provide CPU | ||
217 | power management capabilities or the processor just | ||
218 | supports idle_standby an idle-states node is not | ||
219 | required. | ||
220 | |||
221 | Description: idle-states node is a container node, where its | ||
222 | subnodes describe the CPU idle states. | ||
223 | |||
224 | Node name must be "idle-states". | ||
225 | |||
226 | The idle-states node's parent node must be the cpus node. | ||
227 | |||
228 | The idle-states node's child nodes can be: | ||
229 | |||
230 | - one or more state nodes | ||
231 | |||
232 | Any other configuration is considered invalid. | ||
233 | |||
234 | An idle-states node defines the following properties: | ||
235 | |||
236 | - entry-method | ||
237 | Value type: <stringlist> | ||
238 | Usage and definition depend on ARM architecture version. | ||
239 | # On ARM v8 64-bit this property is required and must | ||
240 | be one of: | ||
241 | - "psci" (see bindings in [2]) | ||
242 | # On ARM 32-bit systems this property is optional | ||
243 | |||
244 | The nodes describing the idle states (state) can only be defined within the | ||
245 | idle-states node, any other configuration is considered invalid and therefore | ||
246 | must be ignored. | ||
247 | |||
248 | =========================================== | ||
249 | 4 - state node | ||
250 | =========================================== | ||
251 | |||
252 | A state node represents an idle state description and must be defined as | ||
253 | follows: | ||
254 | |||
255 | - state node | ||
256 | |||
257 | Description: must be child of the idle-states node | ||
258 | |||
259 | The state node name shall follow standard device tree naming | ||
260 | rules ([5], 2.2.1 "Node names"), in particular state nodes which | ||
261 | are siblings within a single common parent must be given a unique name. | ||
262 | |||
263 | The idle state entered by executing the wfi instruction (idle_standby | ||
264 | SBSA,[3][4]) is considered standard on all ARM platforms and therefore | ||
265 | must not be listed. | ||
266 | |||
267 | With the definitions provided above, the following list represents | ||
268 | the valid properties for a state node: | ||
269 | |||
270 | - compatible | ||
271 | Usage: Required | ||
272 | Value type: <stringlist> | ||
273 | Definition: Must be "arm,idle-state". | ||
274 | |||
275 | - local-timer-stop | ||
276 | Usage: See definition | ||
277 | Value type: <none> | ||
278 | Definition: if present the CPU local timer control logic is | ||
279 | lost on state entry, otherwise it is retained. | ||
280 | |||
281 | - entry-latency-us | ||
282 | Usage: Required | ||
283 | Value type: <prop-encoded-array> | ||
284 | Definition: u32 value representing worst case latency in | ||
285 | microseconds required to enter the idle state. | ||
286 | The exit-latency-us duration may be guaranteed | ||
287 | only after entry-latency-us has passed. | ||
288 | |||
289 | - exit-latency-us | ||
290 | Usage: Required | ||
291 | Value type: <prop-encoded-array> | ||
292 | Definition: u32 value representing worst case latency | ||
293 | in microseconds required to exit the idle state. | ||
294 | |||
295 | - min-residency-us | ||
296 | Usage: Required | ||
297 | Value type: <prop-encoded-array> | ||
298 | Definition: u32 value representing minimum residency duration | ||
299 | in microseconds, inclusive of preparation and | ||
300 | entry, for this idle state to be considered | ||
301 | worthwhile energy wise (refer to section 2 of | ||
302 | this document for a complete description). | ||
303 | |||
304 | - wakeup-latency-us: | ||
305 | Usage: Optional | ||
306 | Value type: <prop-encoded-array> | ||
307 | Definition: u32 value representing maximum delay between the | ||
308 | signaling of a wake-up event and the CPU being | ||
309 | able to execute normal code again. If omitted, | ||
310 | this is assumed to be equal to: | ||
311 | |||
312 | entry-latency-us + exit-latency-us | ||
313 | |||
314 | It is important to supply this value on systems | ||
315 | where the duration of PREP phase (see diagram 1, | ||
316 | section 2) is non-neglibigle. | ||
317 | In such systems entry-latency-us + exit-latency-us | ||
318 | will exceed wakeup-latency-us by this duration. | ||
319 | |||
320 | In addition to the properties listed above, a state node may require | ||
321 | additional properties specifics to the entry-method defined in the | ||
322 | idle-states node, please refer to the entry-method bindings | ||
323 | documentation for properties definitions. | ||
324 | |||
325 | =========================================== | ||
326 | 4 - Examples | ||
327 | =========================================== | ||
328 | |||
329 | Example 1 (ARM 64-bit, 16-cpu system, PSCI enable-method): | ||
330 | |||
331 | cpus { | ||
332 | #size-cells = <0>; | ||
333 | #address-cells = <2>; | ||
334 | |||
335 | CPU0: cpu@0 { | ||
336 | device_type = "cpu"; | ||
337 | compatible = "arm,cortex-a57"; | ||
338 | reg = <0x0 0x0>; | ||
339 | enable-method = "psci"; | ||
340 | cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 | ||
341 | &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; | ||
342 | }; | ||
343 | |||
344 | CPU1: cpu@1 { | ||
345 | device_type = "cpu"; | ||
346 | compatible = "arm,cortex-a57"; | ||
347 | reg = <0x0 0x1>; | ||
348 | enable-method = "psci"; | ||
349 | cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 | ||
350 | &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; | ||
351 | }; | ||
352 | |||
353 | CPU2: cpu@100 { | ||
354 | device_type = "cpu"; | ||
355 | compatible = "arm,cortex-a57"; | ||
356 | reg = <0x0 0x100>; | ||
357 | enable-method = "psci"; | ||
358 | cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 | ||
359 | &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; | ||
360 | }; | ||
361 | |||
362 | CPU3: cpu@101 { | ||
363 | device_type = "cpu"; | ||
364 | compatible = "arm,cortex-a57"; | ||
365 | reg = <0x0 0x101>; | ||
366 | enable-method = "psci"; | ||
367 | cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 | ||
368 | &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; | ||
369 | }; | ||
370 | |||
371 | CPU4: cpu@10000 { | ||
372 | device_type = "cpu"; | ||
373 | compatible = "arm,cortex-a57"; | ||
374 | reg = <0x0 0x10000>; | ||
375 | enable-method = "psci"; | ||
376 | cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 | ||
377 | &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; | ||
378 | }; | ||
379 | |||
380 | CPU5: cpu@10001 { | ||
381 | device_type = "cpu"; | ||
382 | compatible = "arm,cortex-a57"; | ||
383 | reg = <0x0 0x10001>; | ||
384 | enable-method = "psci"; | ||
385 | cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 | ||
386 | &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; | ||
387 | }; | ||
388 | |||
389 | CPU6: cpu@10100 { | ||
390 | device_type = "cpu"; | ||
391 | compatible = "arm,cortex-a57"; | ||
392 | reg = <0x0 0x10100>; | ||
393 | enable-method = "psci"; | ||
394 | cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 | ||
395 | &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; | ||
396 | }; | ||
397 | |||
398 | CPU7: cpu@10101 { | ||
399 | device_type = "cpu"; | ||
400 | compatible = "arm,cortex-a57"; | ||
401 | reg = <0x0 0x10101>; | ||
402 | enable-method = "psci"; | ||
403 | cpu-idle-states = <&CPU_RETENTION_0_0 &CPU_SLEEP_0_0 | ||
404 | &CLUSTER_RETENTION_0 &CLUSTER_SLEEP_0>; | ||
405 | }; | ||
406 | |||
407 | CPU8: cpu@100000000 { | ||
408 | device_type = "cpu"; | ||
409 | compatible = "arm,cortex-a53"; | ||
410 | reg = <0x1 0x0>; | ||
411 | enable-method = "psci"; | ||
412 | cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 | ||
413 | &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; | ||
414 | }; | ||
415 | |||
416 | CPU9: cpu@100000001 { | ||
417 | device_type = "cpu"; | ||
418 | compatible = "arm,cortex-a53"; | ||
419 | reg = <0x1 0x1>; | ||
420 | enable-method = "psci"; | ||
421 | cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 | ||
422 | &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; | ||
423 | }; | ||
424 | |||
425 | CPU10: cpu@100000100 { | ||
426 | device_type = "cpu"; | ||
427 | compatible = "arm,cortex-a53"; | ||
428 | reg = <0x1 0x100>; | ||
429 | enable-method = "psci"; | ||
430 | cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 | ||
431 | &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; | ||
432 | }; | ||
433 | |||
434 | CPU11: cpu@100000101 { | ||
435 | device_type = "cpu"; | ||
436 | compatible = "arm,cortex-a53"; | ||
437 | reg = <0x1 0x101>; | ||
438 | enable-method = "psci"; | ||
439 | cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 | ||
440 | &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; | ||
441 | }; | ||
442 | |||
443 | CPU12: cpu@100010000 { | ||
444 | device_type = "cpu"; | ||
445 | compatible = "arm,cortex-a53"; | ||
446 | reg = <0x1 0x10000>; | ||
447 | enable-method = "psci"; | ||
448 | cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 | ||
449 | &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; | ||
450 | }; | ||
451 | |||
452 | CPU13: cpu@100010001 { | ||
453 | device_type = "cpu"; | ||
454 | compatible = "arm,cortex-a53"; | ||
455 | reg = <0x1 0x10001>; | ||
456 | enable-method = "psci"; | ||
457 | cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 | ||
458 | &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; | ||
459 | }; | ||
460 | |||
461 | CPU14: cpu@100010100 { | ||
462 | device_type = "cpu"; | ||
463 | compatible = "arm,cortex-a53"; | ||
464 | reg = <0x1 0x10100>; | ||
465 | enable-method = "psci"; | ||
466 | cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 | ||
467 | &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; | ||
468 | }; | ||
469 | |||
470 | CPU15: cpu@100010101 { | ||
471 | device_type = "cpu"; | ||
472 | compatible = "arm,cortex-a53"; | ||
473 | reg = <0x1 0x10101>; | ||
474 | enable-method = "psci"; | ||
475 | cpu-idle-states = <&CPU_RETENTION_1_0 &CPU_SLEEP_1_0 | ||
476 | &CLUSTER_RETENTION_1 &CLUSTER_SLEEP_1>; | ||
477 | }; | ||
478 | |||
479 | idle-states { | ||
480 | entry-method = "arm,psci"; | ||
481 | |||
482 | CPU_RETENTION_0_0: cpu-retention-0-0 { | ||
483 | compatible = "arm,idle-state"; | ||
484 | arm,psci-suspend-param = <0x0010000>; | ||
485 | entry-latency-us = <20>; | ||
486 | exit-latency-us = <40>; | ||
487 | min-residency-us = <80>; | ||
488 | }; | ||
489 | |||
490 | CLUSTER_RETENTION_0: cluster-retention-0 { | ||
491 | compatible = "arm,idle-state"; | ||
492 | local-timer-stop; | ||
493 | arm,psci-suspend-param = <0x1010000>; | ||
494 | entry-latency-us = <50>; | ||
495 | exit-latency-us = <100>; | ||
496 | min-residency-us = <250>; | ||
497 | wakeup-latency-us = <130>; | ||
498 | }; | ||
499 | |||
500 | CPU_SLEEP_0_0: cpu-sleep-0-0 { | ||
501 | compatible = "arm,idle-state"; | ||
502 | local-timer-stop; | ||
503 | arm,psci-suspend-param = <0x0010000>; | ||
504 | entry-latency-us = <250>; | ||
505 | exit-latency-us = <500>; | ||
506 | min-residency-us = <950>; | ||
507 | }; | ||
508 | |||
509 | CLUSTER_SLEEP_0: cluster-sleep-0 { | ||
510 | compatible = "arm,idle-state"; | ||
511 | local-timer-stop; | ||
512 | arm,psci-suspend-param = <0x1010000>; | ||
513 | entry-latency-us = <600>; | ||
514 | exit-latency-us = <1100>; | ||
515 | min-residency-us = <2700>; | ||
516 | wakeup-latency-us = <1500>; | ||
517 | }; | ||
518 | |||
519 | CPU_RETENTION_1_0: cpu-retention-1-0 { | ||
520 | compatible = "arm,idle-state"; | ||
521 | arm,psci-suspend-param = <0x0010000>; | ||
522 | entry-latency-us = <20>; | ||
523 | exit-latency-us = <40>; | ||
524 | min-residency-us = <90>; | ||
525 | }; | ||
526 | |||
527 | CLUSTER_RETENTION_1: cluster-retention-1 { | ||
528 | compatible = "arm,idle-state"; | ||
529 | local-timer-stop; | ||
530 | arm,psci-suspend-param = <0x1010000>; | ||
531 | entry-latency-us = <50>; | ||
532 | exit-latency-us = <100>; | ||
533 | min-residency-us = <270>; | ||
534 | wakeup-latency-us = <100>; | ||
535 | }; | ||
536 | |||
537 | CPU_SLEEP_1_0: cpu-sleep-1-0 { | ||
538 | compatible = "arm,idle-state"; | ||
539 | local-timer-stop; | ||
540 | arm,psci-suspend-param = <0x0010000>; | ||
541 | entry-latency-us = <70>; | ||
542 | exit-latency-us = <100>; | ||
543 | min-residency-us = <300>; | ||
544 | wakeup-latency-us = <150>; | ||
545 | }; | ||
546 | |||
547 | CLUSTER_SLEEP_1: cluster-sleep-1 { | ||
548 | compatible = "arm,idle-state"; | ||
549 | local-timer-stop; | ||
550 | arm,psci-suspend-param = <0x1010000>; | ||
551 | entry-latency-us = <500>; | ||
552 | exit-latency-us = <1200>; | ||
553 | min-residency-us = <3500>; | ||
554 | wakeup-latency-us = <1300>; | ||
555 | }; | ||
556 | }; | ||
557 | |||
558 | }; | ||
559 | |||
560 | Example 2 (ARM 32-bit, 8-cpu system, two clusters): | ||
561 | |||
562 | cpus { | ||
563 | #size-cells = <0>; | ||
564 | #address-cells = <1>; | ||
565 | |||
566 | CPU0: cpu@0 { | ||
567 | device_type = "cpu"; | ||
568 | compatible = "arm,cortex-a15"; | ||
569 | reg = <0x0>; | ||
570 | cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>; | ||
571 | }; | ||
572 | |||
573 | CPU1: cpu@1 { | ||
574 | device_type = "cpu"; | ||
575 | compatible = "arm,cortex-a15"; | ||
576 | reg = <0x1>; | ||
577 | cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>; | ||
578 | }; | ||
579 | |||
580 | CPU2: cpu@2 { | ||
581 | device_type = "cpu"; | ||
582 | compatible = "arm,cortex-a15"; | ||
583 | reg = <0x2>; | ||
584 | cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>; | ||
585 | }; | ||
586 | |||
587 | CPU3: cpu@3 { | ||
588 | device_type = "cpu"; | ||
589 | compatible = "arm,cortex-a15"; | ||
590 | reg = <0x3>; | ||
591 | cpu-idle-states = <&CPU_SLEEP_0_0 &CLUSTER_SLEEP_0>; | ||
592 | }; | ||
593 | |||
594 | CPU4: cpu@100 { | ||
595 | device_type = "cpu"; | ||
596 | compatible = "arm,cortex-a7"; | ||
597 | reg = <0x100>; | ||
598 | cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>; | ||
599 | }; | ||
600 | |||
601 | CPU5: cpu@101 { | ||
602 | device_type = "cpu"; | ||
603 | compatible = "arm,cortex-a7"; | ||
604 | reg = <0x101>; | ||
605 | cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>; | ||
606 | }; | ||
607 | |||
608 | CPU6: cpu@102 { | ||
609 | device_type = "cpu"; | ||
610 | compatible = "arm,cortex-a7"; | ||
611 | reg = <0x102>; | ||
612 | cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>; | ||
613 | }; | ||
614 | |||
615 | CPU7: cpu@103 { | ||
616 | device_type = "cpu"; | ||
617 | compatible = "arm,cortex-a7"; | ||
618 | reg = <0x103>; | ||
619 | cpu-idle-states = <&CPU_SLEEP_1_0 &CLUSTER_SLEEP_1>; | ||
620 | }; | ||
621 | |||
622 | idle-states { | ||
623 | CPU_SLEEP_0_0: cpu-sleep-0-0 { | ||
624 | compatible = "arm,idle-state"; | ||
625 | local-timer-stop; | ||
626 | entry-latency-us = <200>; | ||
627 | exit-latency-us = <100>; | ||
628 | min-residency-us = <400>; | ||
629 | wakeup-latency-us = <250>; | ||
630 | }; | ||
631 | |||
632 | CLUSTER_SLEEP_0: cluster-sleep-0 { | ||
633 | compatible = "arm,idle-state"; | ||
634 | local-timer-stop; | ||
635 | entry-latency-us = <500>; | ||
636 | exit-latency-us = <1500>; | ||
637 | min-residency-us = <2500>; | ||
638 | wakeup-latency-us = <1700>; | ||
639 | }; | ||
640 | |||
641 | CPU_SLEEP_1_0: cpu-sleep-1-0 { | ||
642 | compatible = "arm,idle-state"; | ||
643 | local-timer-stop; | ||
644 | entry-latency-us = <300>; | ||
645 | exit-latency-us = <500>; | ||
646 | min-residency-us = <900>; | ||
647 | wakeup-latency-us = <600>; | ||
648 | }; | ||
649 | |||
650 | CLUSTER_SLEEP_1: cluster-sleep-1 { | ||
651 | compatible = "arm,idle-state"; | ||
652 | local-timer-stop; | ||
653 | entry-latency-us = <800>; | ||
654 | exit-latency-us = <2000>; | ||
655 | min-residency-us = <6500>; | ||
656 | wakeup-latency-us = <2300>; | ||
657 | }; | ||
658 | }; | ||
659 | |||
660 | }; | ||
661 | |||
662 | =========================================== | ||
663 | 5 - References | ||
664 | =========================================== | ||
665 | |||
666 | [1] ARM Linux Kernel documentation - CPUs bindings | ||
667 | Documentation/devicetree/bindings/arm/cpus.txt | ||
668 | |||
669 | [2] ARM Linux Kernel documentation - PSCI bindings | ||
670 | Documentation/devicetree/bindings/arm/psci.txt | ||
671 | |||
672 | [3] ARM Server Base System Architecture (SBSA) | ||
673 | http://infocenter.arm.com/help/index.jsp | ||
674 | |||
675 | [4] ARM Architecture Reference Manuals | ||
676 | http://infocenter.arm.com/help/index.jsp | ||
677 | |||
678 | [5] ePAPR standard | ||
679 | https://www.power.org/documentation/epapr-version-1-1/ | ||
diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt index b4a58f39223c..5aa40ede0e99 100644 --- a/Documentation/devicetree/bindings/arm/psci.txt +++ b/Documentation/devicetree/bindings/arm/psci.txt | |||
@@ -50,6 +50,16 @@ Main node optional properties: | |||
50 | 50 | ||
51 | - migrate : Function ID for MIGRATE operation | 51 | - migrate : Function ID for MIGRATE operation |
52 | 52 | ||
53 | Device tree nodes that require usage of PSCI CPU_SUSPEND function (ie idle | ||
54 | state nodes, as per bindings in [1]) must specify the following properties: | ||
55 | |||
56 | - arm,psci-suspend-param | ||
57 | Usage: Required for state nodes[1] if the corresponding | ||
58 | idle-states node entry-method property is set | ||
59 | to "psci". | ||
60 | Value type: <u32> | ||
61 | Definition: power_state parameter to pass to the PSCI | ||
62 | suspend call. | ||
53 | 63 | ||
54 | Example: | 64 | Example: |
55 | 65 | ||
@@ -64,7 +74,6 @@ Case 1: PSCI v0.1 only. | |||
64 | migrate = <0x95c10003>; | 74 | migrate = <0x95c10003>; |
65 | }; | 75 | }; |
66 | 76 | ||
67 | |||
68 | Case 2: PSCI v0.2 only | 77 | Case 2: PSCI v0.2 only |
69 | 78 | ||
70 | psci { | 79 | psci { |
@@ -88,3 +97,6 @@ Case 3: PSCI v0.2 and PSCI v0.1. | |||
88 | 97 | ||
89 | ... | 98 | ... |
90 | }; | 99 | }; |
100 | |||
101 | [1] Kernel documentation - ARM idle states bindings | ||
102 | Documentation/devicetree/bindings/arm/idle-states.txt | ||
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index d7b4b38a8e86..47dfa31ad71a 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h | |||
@@ -28,6 +28,8 @@ struct device_node; | |||
28 | * enable-method property. | 28 | * enable-method property. |
29 | * @cpu_init: Reads any data necessary for a specific enable-method from the | 29 | * @cpu_init: Reads any data necessary for a specific enable-method from the |
30 | * devicetree, for a given cpu node and proposed logical id. | 30 | * devicetree, for a given cpu node and proposed logical id. |
31 | * @cpu_init_idle: Reads any data necessary to initialize CPU idle states from | ||
32 | * devicetree, for a given cpu node and proposed logical id. | ||
31 | * @cpu_prepare: Early one-time preparation step for a cpu. If there is a | 33 | * @cpu_prepare: Early one-time preparation step for a cpu. If there is a |
32 | * mechanism for doing so, tests whether it is possible to boot | 34 | * mechanism for doing so, tests whether it is possible to boot |
33 | * the given CPU. | 35 | * the given CPU. |
@@ -47,6 +49,7 @@ struct device_node; | |||
47 | struct cpu_operations { | 49 | struct cpu_operations { |
48 | const char *name; | 50 | const char *name; |
49 | int (*cpu_init)(struct device_node *, unsigned int); | 51 | int (*cpu_init)(struct device_node *, unsigned int); |
52 | int (*cpu_init_idle)(struct device_node *, unsigned int); | ||
50 | int (*cpu_prepare)(unsigned int); | 53 | int (*cpu_prepare)(unsigned int); |
51 | int (*cpu_boot)(unsigned int); | 54 | int (*cpu_boot)(unsigned int); |
52 | void (*cpu_postboot)(void); | 55 | void (*cpu_postboot)(void); |
diff --git a/arch/arm64/include/asm/cpuidle.h b/arch/arm64/include/asm/cpuidle.h new file mode 100644 index 000000000000..b52a9932e2b1 --- /dev/null +++ b/arch/arm64/include/asm/cpuidle.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef __ASM_CPUIDLE_H | ||
2 | #define __ASM_CPUIDLE_H | ||
3 | |||
4 | #ifdef CONFIG_CPU_IDLE | ||
5 | extern int cpu_init_idle(unsigned int cpu); | ||
6 | #else | ||
7 | static inline int cpu_init_idle(unsigned int cpu) | ||
8 | { | ||
9 | return -EOPNOTSUPP; | ||
10 | } | ||
11 | #endif | ||
12 | |||
13 | #endif | ||
diff --git a/arch/arm64/include/asm/suspend.h b/arch/arm64/include/asm/suspend.h index e9c149c042e0..456d67c1f0fa 100644 --- a/arch/arm64/include/asm/suspend.h +++ b/arch/arm64/include/asm/suspend.h | |||
@@ -21,6 +21,7 @@ struct sleep_save_sp { | |||
21 | phys_addr_t save_ptr_stash_phys; | 21 | phys_addr_t save_ptr_stash_phys; |
22 | }; | 22 | }; |
23 | 23 | ||
24 | extern int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long)); | ||
24 | extern void cpu_resume(void); | 25 | extern void cpu_resume(void); |
25 | extern int cpu_suspend(unsigned long); | 26 | extern int cpu_suspend(unsigned long); |
26 | 27 | ||
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index df7ef8768fc2..6e9538c2d28a 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile | |||
@@ -26,6 +26,7 @@ arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o | |||
26 | arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | 26 | arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o |
27 | arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o | 27 | arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o |
28 | arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o | 28 | arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o |
29 | arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o | ||
29 | arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o | 30 | arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o |
30 | arm64-obj-$(CONFIG_KGDB) += kgdb.o | 31 | arm64-obj-$(CONFIG_KGDB) += kgdb.o |
31 | arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o | 32 | arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o |
diff --git a/arch/arm64/kernel/cpuidle.c b/arch/arm64/kernel/cpuidle.c new file mode 100644 index 000000000000..19d17f51db37 --- /dev/null +++ b/arch/arm64/kernel/cpuidle.c | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * ARM64 CPU idle arch support | ||
3 | * | ||
4 | * Copyright (C) 2014 ARM Ltd. | ||
5 | * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/of.h> | ||
13 | #include <linux/of_device.h> | ||
14 | |||
15 | #include <asm/cpuidle.h> | ||
16 | #include <asm/cpu_ops.h> | ||
17 | |||
18 | int cpu_init_idle(unsigned int cpu) | ||
19 | { | ||
20 | int ret = -EOPNOTSUPP; | ||
21 | struct device_node *cpu_node = of_cpu_device_node_get(cpu); | ||
22 | |||
23 | if (!cpu_node) | ||
24 | return -ENODEV; | ||
25 | |||
26 | if (cpu_ops[cpu] && cpu_ops[cpu]->cpu_init_idle) | ||
27 | ret = cpu_ops[cpu]->cpu_init_idle(cpu_node, cpu); | ||
28 | |||
29 | of_node_put(cpu_node); | ||
30 | return ret; | ||
31 | } | ||
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 553954771a67..866c1c821860 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/reboot.h> | 21 | #include <linux/reboot.h> |
22 | #include <linux/pm.h> | 22 | #include <linux/pm.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/slab.h> | ||
24 | #include <uapi/linux/psci.h> | 25 | #include <uapi/linux/psci.h> |
25 | 26 | ||
26 | #include <asm/compiler.h> | 27 | #include <asm/compiler.h> |
@@ -28,6 +29,7 @@ | |||
28 | #include <asm/errno.h> | 29 | #include <asm/errno.h> |
29 | #include <asm/psci.h> | 30 | #include <asm/psci.h> |
30 | #include <asm/smp_plat.h> | 31 | #include <asm/smp_plat.h> |
32 | #include <asm/suspend.h> | ||
31 | #include <asm/system_misc.h> | 33 | #include <asm/system_misc.h> |
32 | 34 | ||
33 | #define PSCI_POWER_STATE_TYPE_STANDBY 0 | 35 | #define PSCI_POWER_STATE_TYPE_STANDBY 0 |
@@ -65,6 +67,8 @@ enum psci_function { | |||
65 | PSCI_FN_MAX, | 67 | PSCI_FN_MAX, |
66 | }; | 68 | }; |
67 | 69 | ||
70 | static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state); | ||
71 | |||
68 | static u32 psci_function_id[PSCI_FN_MAX]; | 72 | static u32 psci_function_id[PSCI_FN_MAX]; |
69 | 73 | ||
70 | static int psci_to_linux_errno(int errno) | 74 | static int psci_to_linux_errno(int errno) |
@@ -93,6 +97,18 @@ static u32 psci_power_state_pack(struct psci_power_state state) | |||
93 | & PSCI_0_2_POWER_STATE_AFFL_MASK); | 97 | & PSCI_0_2_POWER_STATE_AFFL_MASK); |
94 | } | 98 | } |
95 | 99 | ||
100 | static void psci_power_state_unpack(u32 power_state, | ||
101 | struct psci_power_state *state) | ||
102 | { | ||
103 | state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >> | ||
104 | PSCI_0_2_POWER_STATE_ID_SHIFT; | ||
105 | state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >> | ||
106 | PSCI_0_2_POWER_STATE_TYPE_SHIFT; | ||
107 | state->affinity_level = | ||
108 | (power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >> | ||
109 | PSCI_0_2_POWER_STATE_AFFL_SHIFT; | ||
110 | } | ||
111 | |||
96 | /* | 112 | /* |
97 | * The following two functions are invoked via the invoke_psci_fn pointer | 113 | * The following two functions are invoked via the invoke_psci_fn pointer |
98 | * and will not be inlined, allowing us to piggyback on the AAPCS. | 114 | * and will not be inlined, allowing us to piggyback on the AAPCS. |
@@ -199,6 +215,63 @@ static int psci_migrate_info_type(void) | |||
199 | return err; | 215 | return err; |
200 | } | 216 | } |
201 | 217 | ||
218 | static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node, | ||
219 | unsigned int cpu) | ||
220 | { | ||
221 | int i, ret, count = 0; | ||
222 | struct psci_power_state *psci_states; | ||
223 | struct device_node *state_node; | ||
224 | |||
225 | /* | ||
226 | * If the PSCI cpu_suspend function hook has not been initialized | ||
227 | * idle states must not be enabled, so bail out | ||
228 | */ | ||
229 | if (!psci_ops.cpu_suspend) | ||
230 | return -EOPNOTSUPP; | ||
231 | |||
232 | /* Count idle states */ | ||
233 | while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states", | ||
234 | count))) { | ||
235 | count++; | ||
236 | of_node_put(state_node); | ||
237 | } | ||
238 | |||
239 | if (!count) | ||
240 | return -ENODEV; | ||
241 | |||
242 | psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL); | ||
243 | if (!psci_states) | ||
244 | return -ENOMEM; | ||
245 | |||
246 | for (i = 0; i < count; i++) { | ||
247 | u32 psci_power_state; | ||
248 | |||
249 | state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); | ||
250 | |||
251 | ret = of_property_read_u32(state_node, | ||
252 | "arm,psci-suspend-param", | ||
253 | &psci_power_state); | ||
254 | if (ret) { | ||
255 | pr_warn(" * %s missing arm,psci-suspend-param property\n", | ||
256 | state_node->full_name); | ||
257 | of_node_put(state_node); | ||
258 | goto free_mem; | ||
259 | } | ||
260 | |||
261 | of_node_put(state_node); | ||
262 | pr_debug("psci-power-state %#x index %d\n", psci_power_state, | ||
263 | i); | ||
264 | psci_power_state_unpack(psci_power_state, &psci_states[i]); | ||
265 | } | ||
266 | /* Idle states parsed correctly, initialize per-cpu pointer */ | ||
267 | per_cpu(psci_power_state, cpu) = psci_states; | ||
268 | return 0; | ||
269 | |||
270 | free_mem: | ||
271 | kfree(psci_states); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
202 | static int get_set_conduit_method(struct device_node *np) | 275 | static int get_set_conduit_method(struct device_node *np) |
203 | { | 276 | { |
204 | const char *method; | 277 | const char *method; |
@@ -436,8 +509,39 @@ static int cpu_psci_cpu_kill(unsigned int cpu) | |||
436 | #endif | 509 | #endif |
437 | #endif | 510 | #endif |
438 | 511 | ||
512 | static int psci_suspend_finisher(unsigned long index) | ||
513 | { | ||
514 | struct psci_power_state *state = __get_cpu_var(psci_power_state); | ||
515 | |||
516 | return psci_ops.cpu_suspend(state[index - 1], | ||
517 | virt_to_phys(cpu_resume)); | ||
518 | } | ||
519 | |||
520 | static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) | ||
521 | { | ||
522 | int ret; | ||
523 | struct psci_power_state *state = __get_cpu_var(psci_power_state); | ||
524 | /* | ||
525 | * idle state index 0 corresponds to wfi, should never be called | ||
526 | * from the cpu_suspend operations | ||
527 | */ | ||
528 | if (WARN_ON_ONCE(!index)) | ||
529 | return -EINVAL; | ||
530 | |||
531 | if (state->type == PSCI_POWER_STATE_TYPE_STANDBY) | ||
532 | ret = psci_ops.cpu_suspend(state[index - 1], 0); | ||
533 | else | ||
534 | ret = __cpu_suspend(index, psci_suspend_finisher); | ||
535 | |||
536 | return ret; | ||
537 | } | ||
538 | |||
439 | const struct cpu_operations cpu_psci_ops = { | 539 | const struct cpu_operations cpu_psci_ops = { |
440 | .name = "psci", | 540 | .name = "psci", |
541 | #ifdef CONFIG_CPU_IDLE | ||
542 | .cpu_init_idle = cpu_psci_cpu_init_idle, | ||
543 | .cpu_suspend = cpu_psci_cpu_suspend, | ||
544 | #endif | ||
441 | #ifdef CONFIG_SMP | 545 | #ifdef CONFIG_SMP |
442 | .cpu_init = cpu_psci_cpu_init, | 546 | .cpu_init = cpu_psci_cpu_init, |
443 | .cpu_prepare = cpu_psci_cpu_prepare, | 547 | .cpu_prepare = cpu_psci_cpu_prepare, |
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index b1925729c692..a564b440416a 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S | |||
@@ -49,28 +49,39 @@ | |||
49 | orr \dst, \dst, \mask // dst|=(aff3>>rs3) | 49 | orr \dst, \dst, \mask // dst|=(aff3>>rs3) |
50 | .endm | 50 | .endm |
51 | /* | 51 | /* |
52 | * Save CPU state for a suspend. This saves callee registers, and allocates | 52 | * Save CPU state for a suspend and execute the suspend finisher. |
53 | * space on the kernel stack to save the CPU specific registers + some | 53 | * On success it will return 0 through cpu_resume - ie through a CPU |
54 | * other data for resume. | 54 | * soft/hard reboot from the reset vector. |
55 | * On failure it returns the suspend finisher return value or force | ||
56 | * -EOPNOTSUPP if the finisher erroneously returns 0 (the suspend finisher | ||
57 | * is not allowed to return, if it does this must be considered failure). | ||
58 | * It saves callee registers, and allocates space on the kernel stack | ||
59 | * to save the CPU specific registers + some other data for resume. | ||
55 | * | 60 | * |
56 | * x0 = suspend finisher argument | 61 | * x0 = suspend finisher argument |
62 | * x1 = suspend finisher function pointer | ||
57 | */ | 63 | */ |
58 | ENTRY(__cpu_suspend) | 64 | ENTRY(__cpu_suspend_enter) |
59 | stp x29, lr, [sp, #-96]! | 65 | stp x29, lr, [sp, #-96]! |
60 | stp x19, x20, [sp,#16] | 66 | stp x19, x20, [sp,#16] |
61 | stp x21, x22, [sp,#32] | 67 | stp x21, x22, [sp,#32] |
62 | stp x23, x24, [sp,#48] | 68 | stp x23, x24, [sp,#48] |
63 | stp x25, x26, [sp,#64] | 69 | stp x25, x26, [sp,#64] |
64 | stp x27, x28, [sp,#80] | 70 | stp x27, x28, [sp,#80] |
71 | /* | ||
72 | * Stash suspend finisher and its argument in x20 and x19 | ||
73 | */ | ||
74 | mov x19, x0 | ||
75 | mov x20, x1 | ||
65 | mov x2, sp | 76 | mov x2, sp |
66 | sub sp, sp, #CPU_SUSPEND_SZ // allocate cpu_suspend_ctx | 77 | sub sp, sp, #CPU_SUSPEND_SZ // allocate cpu_suspend_ctx |
67 | mov x1, sp | 78 | mov x0, sp |
68 | /* | 79 | /* |
69 | * x1 now points to struct cpu_suspend_ctx allocated on the stack | 80 | * x0 now points to struct cpu_suspend_ctx allocated on the stack |
70 | */ | 81 | */ |
71 | str x2, [x1, #CPU_CTX_SP] | 82 | str x2, [x0, #CPU_CTX_SP] |
72 | ldr x2, =sleep_save_sp | 83 | ldr x1, =sleep_save_sp |
73 | ldr x2, [x2, #SLEEP_SAVE_SP_VIRT] | 84 | ldr x1, [x1, #SLEEP_SAVE_SP_VIRT] |
74 | #ifdef CONFIG_SMP | 85 | #ifdef CONFIG_SMP |
75 | mrs x7, mpidr_el1 | 86 | mrs x7, mpidr_el1 |
76 | ldr x9, =mpidr_hash | 87 | ldr x9, =mpidr_hash |
@@ -82,11 +93,21 @@ ENTRY(__cpu_suspend) | |||
82 | ldp w3, w4, [x9, #MPIDR_HASH_SHIFTS] | 93 | ldp w3, w4, [x9, #MPIDR_HASH_SHIFTS] |
83 | ldp w5, w6, [x9, #(MPIDR_HASH_SHIFTS + 8)] | 94 | ldp w5, w6, [x9, #(MPIDR_HASH_SHIFTS + 8)] |
84 | compute_mpidr_hash x8, x3, x4, x5, x6, x7, x10 | 95 | compute_mpidr_hash x8, x3, x4, x5, x6, x7, x10 |
85 | add x2, x2, x8, lsl #3 | 96 | add x1, x1, x8, lsl #3 |
86 | #endif | 97 | #endif |
87 | bl __cpu_suspend_finisher | 98 | bl __cpu_suspend_save |
99 | /* | ||
100 | * Grab suspend finisher in x20 and its argument in x19 | ||
101 | */ | ||
102 | mov x0, x19 | ||
103 | mov x1, x20 | ||
104 | /* | ||
105 | * We are ready for power down, fire off the suspend finisher | ||
106 | * in x1, with argument in x0 | ||
107 | */ | ||
108 | blr x1 | ||
88 | /* | 109 | /* |
89 | * Never gets here, unless suspend fails. | 110 | * Never gets here, unless suspend finisher fails. |
90 | * Successful cpu_suspend should return from cpu_resume, returning | 111 | * Successful cpu_suspend should return from cpu_resume, returning |
91 | * through this code path is considered an error | 112 | * through this code path is considered an error |
92 | * If the return value is set to 0 force x0 = -EOPNOTSUPP | 113 | * If the return value is set to 0 force x0 = -EOPNOTSUPP |
@@ -103,7 +124,7 @@ ENTRY(__cpu_suspend) | |||
103 | ldp x27, x28, [sp, #80] | 124 | ldp x27, x28, [sp, #80] |
104 | ldp x29, lr, [sp], #96 | 125 | ldp x29, lr, [sp], #96 |
105 | ret | 126 | ret |
106 | ENDPROC(__cpu_suspend) | 127 | ENDPROC(__cpu_suspend_enter) |
107 | .ltorg | 128 | .ltorg |
108 | 129 | ||
109 | /* | 130 | /* |
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c index 55a99b9a97e0..13ad4dbb1615 100644 --- a/arch/arm64/kernel/suspend.c +++ b/arch/arm64/kernel/suspend.c | |||
@@ -9,22 +9,19 @@ | |||
9 | #include <asm/suspend.h> | 9 | #include <asm/suspend.h> |
10 | #include <asm/tlbflush.h> | 10 | #include <asm/tlbflush.h> |
11 | 11 | ||
12 | extern int __cpu_suspend(unsigned long); | 12 | extern int __cpu_suspend_enter(unsigned long arg, int (*fn)(unsigned long)); |
13 | /* | 13 | /* |
14 | * This is called by __cpu_suspend() to save the state, and do whatever | 14 | * This is called by __cpu_suspend_enter() to save the state, and do whatever |
15 | * flushing is required to ensure that when the CPU goes to sleep we have | 15 | * flushing is required to ensure that when the CPU goes to sleep we have |
16 | * the necessary data available when the caches are not searched. | 16 | * the necessary data available when the caches are not searched. |
17 | * | 17 | * |
18 | * @arg: Argument to pass to suspend operations | 18 | * ptr: CPU context virtual address |
19 | * @ptr: CPU context virtual address | 19 | * save_ptr: address of the location where the context physical address |
20 | * @save_ptr: address of the location where the context physical address | 20 | * must be saved |
21 | * must be saved | ||
22 | */ | 21 | */ |
23 | int __cpu_suspend_finisher(unsigned long arg, struct cpu_suspend_ctx *ptr, | 22 | void notrace __cpu_suspend_save(struct cpu_suspend_ctx *ptr, |
24 | phys_addr_t *save_ptr) | 23 | phys_addr_t *save_ptr) |
25 | { | 24 | { |
26 | int cpu = smp_processor_id(); | ||
27 | |||
28 | *save_ptr = virt_to_phys(ptr); | 25 | *save_ptr = virt_to_phys(ptr); |
29 | 26 | ||
30 | cpu_do_suspend(ptr); | 27 | cpu_do_suspend(ptr); |
@@ -35,8 +32,6 @@ int __cpu_suspend_finisher(unsigned long arg, struct cpu_suspend_ctx *ptr, | |||
35 | */ | 32 | */ |
36 | __flush_dcache_area(ptr, sizeof(*ptr)); | 33 | __flush_dcache_area(ptr, sizeof(*ptr)); |
37 | __flush_dcache_area(save_ptr, sizeof(*save_ptr)); | 34 | __flush_dcache_area(save_ptr, sizeof(*save_ptr)); |
38 | |||
39 | return cpu_ops[cpu]->cpu_suspend(arg); | ||
40 | } | 35 | } |
41 | 36 | ||
42 | /* | 37 | /* |
@@ -56,15 +51,15 @@ void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *)) | |||
56 | } | 51 | } |
57 | 52 | ||
58 | /** | 53 | /** |
59 | * cpu_suspend | 54 | * cpu_suspend() - function to enter a low-power state |
55 | * @arg: argument to pass to CPU suspend operations | ||
60 | * | 56 | * |
61 | * @arg: argument to pass to the finisher function | 57 | * Return: 0 on success, -EOPNOTSUPP if CPU suspend hook not initialized, CPU |
58 | * operations back-end error code otherwise. | ||
62 | */ | 59 | */ |
63 | int cpu_suspend(unsigned long arg) | 60 | int cpu_suspend(unsigned long arg) |
64 | { | 61 | { |
65 | struct mm_struct *mm = current->active_mm; | 62 | int cpu = smp_processor_id(); |
66 | int ret, cpu = smp_processor_id(); | ||
67 | unsigned long flags; | ||
68 | 63 | ||
69 | /* | 64 | /* |
70 | * If cpu_ops have not been registered or suspend | 65 | * If cpu_ops have not been registered or suspend |
@@ -72,6 +67,21 @@ int cpu_suspend(unsigned long arg) | |||
72 | */ | 67 | */ |
73 | if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_suspend) | 68 | if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_suspend) |
74 | return -EOPNOTSUPP; | 69 | return -EOPNOTSUPP; |
70 | return cpu_ops[cpu]->cpu_suspend(arg); | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * __cpu_suspend | ||
75 | * | ||
76 | * arg: argument to pass to the finisher function | ||
77 | * fn: finisher function pointer | ||
78 | * | ||
79 | */ | ||
80 | int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long)) | ||
81 | { | ||
82 | struct mm_struct *mm = current->active_mm; | ||
83 | int ret; | ||
84 | unsigned long flags; | ||
75 | 85 | ||
76 | /* | 86 | /* |
77 | * From this point debug exceptions are disabled to prevent | 87 | * From this point debug exceptions are disabled to prevent |
@@ -86,7 +96,7 @@ int cpu_suspend(unsigned long arg) | |||
86 | * page tables, so that the thread address space is properly | 96 | * page tables, so that the thread address space is properly |
87 | * set-up on function return. | 97 | * set-up on function return. |
88 | */ | 98 | */ |
89 | ret = __cpu_suspend(arg); | 99 | ret = __cpu_suspend_enter(arg, fn); |
90 | if (ret == 0) { | 100 | if (ret == 0) { |
91 | cpu_switch_mm(mm->pgd, mm); | 101 | cpu_switch_mm(mm->pgd, mm); |
92 | flush_tlb_all(); | 102 | flush_tlb_all(); |
@@ -95,7 +105,7 @@ int cpu_suspend(unsigned long arg) | |||
95 | * Restore per-cpu offset before any kernel | 105 | * Restore per-cpu offset before any kernel |
96 | * subsystem relying on it has a chance to run. | 106 | * subsystem relying on it has a chance to run. |
97 | */ | 107 | */ |
98 | set_my_cpu_offset(per_cpu_offset(cpu)); | 108 | set_my_cpu_offset(per_cpu_offset(smp_processor_id())); |
99 | 109 | ||
100 | /* | 110 | /* |
101 | * Restore HW breakpoint registers to sane values | 111 | * Restore HW breakpoint registers to sane values |