aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCatalin Marinas <catalin.marinas@arm.com>2014-09-12 05:50:21 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2014-09-12 05:50:21 -0400
commitc2eb6b6139183af632a5be8f7c33006d7b03702d (patch)
tree5d63e31481edd059c0174acff23e73d4ec3abbea
parente3672649faae400e8a598938766a63f395a27ae6 (diff)
parent18910ab0d916b1a87016d69efd027714a80521dd (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.txt8
-rw-r--r--Documentation/devicetree/bindings/arm/idle-states.txt679
-rw-r--r--Documentation/devicetree/bindings/arm/psci.txt14
-rw-r--r--arch/arm64/include/asm/cpu_ops.h3
-rw-r--r--arch/arm64/include/asm/cpuidle.h13
-rw-r--r--arch/arm64/include/asm/suspend.h1
-rw-r--r--arch/arm64/kernel/Makefile1
-rw-r--r--arch/arm64/kernel/cpuidle.c31
-rw-r--r--arch/arm64/kernel/psci.c104
-rw-r--r--arch/arm64/kernel/sleep.S47
-rw-r--r--arch/arm64/kernel/suspend.c48
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
223Example 1 (dual-cluster big.LITTLE system 32-bit): 229Example 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==========================================
2ARM idle states binding description
3==========================================
4
5==========================================
61 - Introduction
7==========================================
8
9ARM systems contain HW capable of managing power consumption dynamically,
10where cores can be put in different low-power states (ranging from simple
11wfi to power gating) according to OS PM policies. The CPU states representing
12the range of dynamic idle states that a processor can enter at run-time, can be
13specified through device tree bindings representing the parameters required
14to enter/exit specific idle states on a given processor.
15
16According to the Server Base System Architecture document (SBSA, [3]), the
17power 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
25The power states described in the SBSA document define the basic CPU states on
26top of which ARM platforms implement power management schemes that allow an OS
27PM implementation to put the processor in different idle states (which include
28states listed above; "off" state is not an idle state since it does not have
29wake-up capabilities, hence it is not considered in this document).
30
31Idle state parameters (eg entry latency) are platform specific and need to be
32characterized with bindings that provide the required information to OS PM
33code so that it can build the required tables and use them at runtime.
34
35The device tree binding definition for ARM idle states is the subject of this
36document.
37
38===========================================
392 - idle-states definitions
40===========================================
41
42Idle states are characterized for a specific system through a set of
43timing and energy related properties, that underline the HW behaviour
44triggered upon idle states entry and exit.
45
46The following diagram depicts the CPU execution phases and related timing
47properties 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
61EXEC: Normal CPU execution.
62
63PREP: 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
70ENTRY: The hardware is committed to idle mode. This period must run
71 to completion up to IDLE before anything else can happen.
72
73IDLE: This is the actual energy-saving idle period. This may last
74 between 0 and infinite time, until a wake-up event occurs.
75
76EXIT: Period during which the CPU is brought back to operational
77 mode (EXEC).
78
79entry-latency: Worst case latency required to enter the idle state. The
80exit-latency may be guaranteed only after entry-latency has passed.
81
82min-residency: Minimum period, including preparation and entry, for a given
83idle state to be worthwhile energywise.
84
85wakeup-latency: Maximum delay between the signaling of a wake-up event and the
86CPU being able to execute normal code again. If not specified, this is assumed
87to be entry-latency + exit-latency.
88
89These timing parameters can be used by an OS in different circumstances.
90
91An idle CPU requires the expected min-residency time to select the most
92appropriate 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
95An operating system scheduler may need to compute the shortest wake-up delay
96for CPUs in the system by detecting how long will it take to get a CPU out
97of an idle state, eg:
98
99wakeup-delay = exit-latency + max(entry-latency - (now - entry-timestamp), 0)
100
101In other words, the scheduler can make its scheduling decision by selecting
102(eg waking-up) the CPU with the shortest wake-up latency.
103The wake-up latency must take into account the entry latency if that period
104has not expired. The abortable nature of the PREP period can be ignored
105if it cannot be relied upon (e.g. the PREP deadline may occur much sooner than
106the worst case since it depends on the CPU operating conditions, ie caches
107state).
108
109An OS has to reliably probe the wakeup-latency since some devices can enforce
110latency constraints guarantees to work properly, so the OS has to detect the
111worst case wake-up latency it can incur if a CPU is allowed to enter an
112idle state, and possibly to prevent that to guarantee reliable device
113functioning.
114
115The min-residency time parameter deserves further explanation since it is
116expressed in time units but must factor in energy consumption coefficients.
117
118The energy consumption of a cpu when it enters a power state can be roughly
119characterised 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
143The graph is split in two parts delimited by time 1ms on the X-axis.
144The graph curve with X-axis values = { x | 0 < x < 1ms } has a steep slope
145and denotes the energy costs incurred whilst entering and leaving the idle
146state.
147The graph curve in the area delimited by X-axis values = {x | x > 1ms } has
148shallower slope and essentially represents the energy consumption of the idle
149state.
150
151min-residency is defined for a given idle state as the minimum expected
152residency time for a state (inclusive of preparation and entry) after
153which choosing that state become the most energy efficient option. A good
154way to visualise this, is by taking the same graph above and comparing some
155states energy consumptions plots.
156
157For sake of simplicity, let's consider a system with two idle states IDLE1,
158and 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
185In graph 2 above, that takes into account idle states entry/exit energy
186costs, it is clear that if the idle state residency time (ie time till next
187wake-up IRQ) is less than IDLE2-min-residency, IDLE1 is the better idle state
188choice energywise.
189
190This is mainly down to the fact that IDLE1 entry/exit energy costs are lower
191than IDLE2.
192
193However, the lower power consumption (ie shallower energy curve slope) of idle
194state IDLE2 implies that after a suitable time, IDLE2 becomes more energy
195efficient.
196
197The time at which IDLE2 becomes more energy efficient than IDLE1 (and other
198shallower states in a system with multiple idle states) is defined
199IDLE2-min-residency and corresponds to the time when energy consumption of
200IDLE1 and IDLE2 states breaks even.
201
202The definitions provided in this section underpin the idle states
203properties specification that is the subject of the following sections.
204
205===========================================
2063 - idle-states node
207===========================================
208
209ARM processor idle states are defined within the idle-states node, which is
210a direct child of the cpus node [1] and provides a container where the
211processor 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
244The nodes describing the idle states (state) can only be defined within the
245idle-states node, any other configuration is considered invalid and therefore
246must be ignored.
247
248===========================================
2494 - state node
250===========================================
251
252A state node represents an idle state description and must be defined as
253follows:
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===========================================
3264 - Examples
327===========================================
328
329Example 1 (ARM 64-bit, 16-cpu system, PSCI enable-method):
330
331cpus {
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
560Example 2 (ARM 32-bit, 8-cpu system, two clusters):
561
562cpus {
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===========================================
6635 - 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
53Device tree nodes that require usage of PSCI CPU_SUSPEND function (ie idle
54state 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
54Example: 64Example:
55 65
@@ -64,7 +74,6 @@ Case 1: PSCI v0.1 only.
64 migrate = <0x95c10003>; 74 migrate = <0x95c10003>;
65 }; 75 };
66 76
67
68Case 2: PSCI v0.2 only 77Case 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;
47struct cpu_operations { 49struct 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
5extern int cpu_init_idle(unsigned int cpu);
6#else
7static 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
24extern int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long));
24extern void cpu_resume(void); 25extern void cpu_resume(void);
25extern int cpu_suspend(unsigned long); 26extern 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
26arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o 26arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
27arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o 27arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
28arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o 28arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
29arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
29arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o 30arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
30arm64-obj-$(CONFIG_KGDB) += kgdb.o 31arm64-obj-$(CONFIG_KGDB) += kgdb.o
31arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o 32arm64-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
18int 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
70static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state);
71
68static u32 psci_function_id[PSCI_FN_MAX]; 72static u32 psci_function_id[PSCI_FN_MAX];
69 73
70static int psci_to_linux_errno(int errno) 74static 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
100static 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
218static 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
270free_mem:
271 kfree(psci_states);
272 return ret;
273}
274
202static int get_set_conduit_method(struct device_node *np) 275static 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
512static 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
520static 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
439const struct cpu_operations cpu_psci_ops = { 539const 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 */
58ENTRY(__cpu_suspend) 64ENTRY(__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
106ENDPROC(__cpu_suspend) 127ENDPROC(__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
12extern int __cpu_suspend(unsigned long); 12extern 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 */
23int __cpu_suspend_finisher(unsigned long arg, struct cpu_suspend_ctx *ptr, 22void 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 */
63int cpu_suspend(unsigned long arg) 60int 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 */
80int __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