diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2015-06-05 06:21:23 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2015-06-05 06:21:23 -0400 |
commit | addc8120a784181cc6410973948eee94ea16f2bd (patch) | |
tree | de84cba276c224bcc4c1070a58a4f19625960723 | |
parent | eb7c11ee3c5ce6c45ac28a5015a8e60ed458b412 (diff) | |
parent | c5a1330573c1748179898f4799f130e416ce4738 (diff) |
Merge branch 'arm64/psci-rework' of git://git.kernel.org/pub/scm/linux/kernel/git/mark/linux
* 'arm64/psci-rework' of git://git.kernel.org/pub/scm/linux/kernel/git/mark/linux:
arm64: psci: remove ACPI coupling
arm64: psci: kill psci_power_state
arm64: psci: account for Trusted OS instances
arm64: psci: support unsigned return values
arm64: psci: remove unnecessary id indirection
arm64: smp: consistently use error codes
arm64: smp_plat: add get_logical_index
arm/arm64: kvm: add missing PSCI include
Conflicts:
arch/arm64/kernel/smp.c
-rw-r--r-- | arch/arm/kvm/psci.c | 2 | ||||
-rw-r--r-- | arch/arm64/include/asm/acpi.h | 15 | ||||
-rw-r--r-- | arch/arm64/include/asm/psci.h | 12 | ||||
-rw-r--r-- | arch/arm64/include/asm/smp_plat.h | 16 | ||||
-rw-r--r-- | arch/arm64/kernel/acpi.c | 11 | ||||
-rw-r--r-- | arch/arm64/kernel/psci.c | 231 | ||||
-rw-r--r-- | arch/arm64/kernel/smp.c | 10 |
7 files changed, 175 insertions, 122 deletions
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 02fa8eff6ae1..7e9398c6b387 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <asm/kvm_psci.h> | 24 | #include <asm/kvm_psci.h> |
25 | #include <asm/kvm_host.h> | 25 | #include <asm/kvm_host.h> |
26 | 26 | ||
27 | #include <uapi/linux/psci.h> | ||
28 | |||
27 | /* | 29 | /* |
28 | * This is an implementation of the Power State Coordination Interface | 30 | * This is an implementation of the Power State Coordination Interface |
29 | * as described in ARM document number ARM DEN 0022A. | 31 | * as described in ARM document number ARM DEN 0022A. |
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index 1240b867d4a2..39248d3adf5d 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/irqchip/arm-gic-acpi.h> | 16 | #include <linux/irqchip/arm-gic-acpi.h> |
17 | 17 | ||
18 | #include <asm/cputype.h> | 18 | #include <asm/cputype.h> |
19 | #include <asm/psci.h> | ||
19 | #include <asm/smp_plat.h> | 20 | #include <asm/smp_plat.h> |
20 | 21 | ||
21 | /* Basic configuration for ACPI */ | 22 | /* Basic configuration for ACPI */ |
@@ -39,18 +40,6 @@ extern int acpi_disabled; | |||
39 | extern int acpi_noirq; | 40 | extern int acpi_noirq; |
40 | extern int acpi_pci_disabled; | 41 | extern int acpi_pci_disabled; |
41 | 42 | ||
42 | /* 1 to indicate PSCI 0.2+ is implemented */ | ||
43 | static inline bool acpi_psci_present(void) | ||
44 | { | ||
45 | return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT; | ||
46 | } | ||
47 | |||
48 | /* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */ | ||
49 | static inline bool acpi_psci_use_hvc(void) | ||
50 | { | ||
51 | return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC; | ||
52 | } | ||
53 | |||
54 | static inline void disable_acpi(void) | 43 | static inline void disable_acpi(void) |
55 | { | 44 | { |
56 | acpi_disabled = 1; | 45 | acpi_disabled = 1; |
@@ -88,8 +77,6 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { } | |||
88 | void __init acpi_init_cpus(void); | 77 | void __init acpi_init_cpus(void); |
89 | 78 | ||
90 | #else | 79 | #else |
91 | static inline bool acpi_psci_present(void) { return false; } | ||
92 | static inline bool acpi_psci_use_hvc(void) { return false; } | ||
93 | static inline void acpi_init_cpus(void) { } | 80 | static inline void acpi_init_cpus(void) { } |
94 | #endif /* CONFIG_ACPI */ | 81 | #endif /* CONFIG_ACPI */ |
95 | 82 | ||
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h index 2454bc59c916..49d7e1aaebdc 100644 --- a/arch/arm64/include/asm/psci.h +++ b/arch/arm64/include/asm/psci.h | |||
@@ -14,7 +14,15 @@ | |||
14 | #ifndef __ASM_PSCI_H | 14 | #ifndef __ASM_PSCI_H |
15 | #define __ASM_PSCI_H | 15 | #define __ASM_PSCI_H |
16 | 16 | ||
17 | int psci_dt_init(void); | 17 | int __init psci_dt_init(void); |
18 | int psci_acpi_init(void); | 18 | |
19 | #ifdef CONFIG_ACPI | ||
20 | int __init psci_acpi_init(void); | ||
21 | bool __init acpi_psci_present(void); | ||
22 | bool __init acpi_psci_use_hvc(void); | ||
23 | #else | ||
24 | static inline int psci_acpi_init(void) { return 0; } | ||
25 | static inline bool acpi_psci_present(void) { return false; } | ||
26 | #endif | ||
19 | 27 | ||
20 | #endif /* __ASM_PSCI_H */ | 28 | #endif /* __ASM_PSCI_H */ |
diff --git a/arch/arm64/include/asm/smp_plat.h b/arch/arm64/include/asm/smp_plat.h index 8dcd61e32176..7abf7570c00f 100644 --- a/arch/arm64/include/asm/smp_plat.h +++ b/arch/arm64/include/asm/smp_plat.h | |||
@@ -19,6 +19,8 @@ | |||
19 | #ifndef __ASM_SMP_PLAT_H | 19 | #ifndef __ASM_SMP_PLAT_H |
20 | #define __ASM_SMP_PLAT_H | 20 | #define __ASM_SMP_PLAT_H |
21 | 21 | ||
22 | #include <linux/cpumask.h> | ||
23 | |||
22 | #include <asm/types.h> | 24 | #include <asm/types.h> |
23 | 25 | ||
24 | struct mpidr_hash { | 26 | struct mpidr_hash { |
@@ -39,6 +41,20 @@ static inline u32 mpidr_hash_size(void) | |||
39 | */ | 41 | */ |
40 | extern u64 __cpu_logical_map[NR_CPUS]; | 42 | extern u64 __cpu_logical_map[NR_CPUS]; |
41 | #define cpu_logical_map(cpu) __cpu_logical_map[cpu] | 43 | #define cpu_logical_map(cpu) __cpu_logical_map[cpu] |
44 | /* | ||
45 | * Retrieve logical cpu index corresponding to a given MPIDR.Aff* | ||
46 | * - mpidr: MPIDR.Aff* bits to be used for the look-up | ||
47 | * | ||
48 | * Returns the cpu logical index or -EINVAL on look-up error | ||
49 | */ | ||
50 | static inline int get_logical_index(u64 mpidr) | ||
51 | { | ||
52 | int cpu; | ||
53 | for (cpu = 0; cpu < nr_cpu_ids; cpu++) | ||
54 | if (cpu_logical_map(cpu) == mpidr) | ||
55 | return cpu; | ||
56 | return -EINVAL; | ||
57 | } | ||
42 | 58 | ||
43 | void __init do_post_cpus_up_work(void); | 59 | void __init do_post_cpus_up_work(void); |
44 | 60 | ||
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 732f57b8731b..19de7537e7d3 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c | |||
@@ -89,6 +89,17 @@ void __init __acpi_unmap_table(char *map, unsigned long size) | |||
89 | early_memunmap(map, size); | 89 | early_memunmap(map, size); |
90 | } | 90 | } |
91 | 91 | ||
92 | bool __init acpi_psci_present(void) | ||
93 | { | ||
94 | return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT; | ||
95 | } | ||
96 | |||
97 | /* Whether HVC must be used instead of SMC as the PSCI conduit */ | ||
98 | bool __init acpi_psci_use_hvc(void) | ||
99 | { | ||
100 | return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC; | ||
101 | } | ||
102 | |||
92 | /* | 103 | /* |
93 | * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity | 104 | * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity |
94 | * checks on it | 105 | * checks on it |
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index efe3480a97a9..cba05d9bcbc6 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c | |||
@@ -15,7 +15,6 @@ | |||
15 | 15 | ||
16 | #define pr_fmt(fmt) "psci: " fmt | 16 | #define pr_fmt(fmt) "psci: " fmt |
17 | 17 | ||
18 | #include <linux/acpi.h> | ||
19 | #include <linux/init.h> | 18 | #include <linux/init.h> |
20 | #include <linux/of.h> | 19 | #include <linux/of.h> |
21 | #include <linux/smp.h> | 20 | #include <linux/smp.h> |
@@ -25,8 +24,8 @@ | |||
25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
26 | #include <uapi/linux/psci.h> | 25 | #include <uapi/linux/psci.h> |
27 | 26 | ||
28 | #include <asm/acpi.h> | ||
29 | #include <asm/compiler.h> | 27 | #include <asm/compiler.h> |
28 | #include <asm/cputype.h> | ||
30 | #include <asm/cpu_ops.h> | 29 | #include <asm/cpu_ops.h> |
31 | #include <asm/errno.h> | 30 | #include <asm/errno.h> |
32 | #include <asm/psci.h> | 31 | #include <asm/psci.h> |
@@ -37,16 +36,36 @@ | |||
37 | #define PSCI_POWER_STATE_TYPE_STANDBY 0 | 36 | #define PSCI_POWER_STATE_TYPE_STANDBY 0 |
38 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 | 37 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 |
39 | 38 | ||
40 | struct psci_power_state { | 39 | static bool psci_power_state_loses_context(u32 state) |
41 | u16 id; | 40 | { |
42 | u8 type; | 41 | return state & PSCI_0_2_POWER_STATE_TYPE_MASK; |
43 | u8 affinity_level; | 42 | } |
44 | }; | 43 | |
44 | static bool psci_power_state_is_valid(u32 state) | ||
45 | { | ||
46 | const u32 valid_mask = PSCI_0_2_POWER_STATE_ID_MASK | | ||
47 | PSCI_0_2_POWER_STATE_TYPE_MASK | | ||
48 | PSCI_0_2_POWER_STATE_AFFL_MASK; | ||
49 | |||
50 | return !(state & ~valid_mask); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF | ||
55 | * calls to its resident CPU, so we must avoid issuing those. We never migrate | ||
56 | * a Trusted OS even if it claims to be capable of migration -- doing so will | ||
57 | * require cooperation with a Trusted OS driver. | ||
58 | */ | ||
59 | static int resident_cpu = -1; | ||
60 | |||
61 | static bool psci_tos_resident_on(int cpu) | ||
62 | { | ||
63 | return cpu == resident_cpu; | ||
64 | } | ||
45 | 65 | ||
46 | struct psci_operations { | 66 | struct psci_operations { |
47 | int (*cpu_suspend)(struct psci_power_state state, | 67 | int (*cpu_suspend)(u32 state, unsigned long entry_point); |
48 | unsigned long entry_point); | 68 | int (*cpu_off)(u32 state); |
49 | int (*cpu_off)(struct psci_power_state state); | ||
50 | int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); | 69 | int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); |
51 | int (*migrate)(unsigned long cpuid); | 70 | int (*migrate)(unsigned long cpuid); |
52 | int (*affinity_info)(unsigned long target_affinity, | 71 | int (*affinity_info)(unsigned long target_affinity, |
@@ -56,23 +75,21 @@ struct psci_operations { | |||
56 | 75 | ||
57 | static struct psci_operations psci_ops; | 76 | static struct psci_operations psci_ops; |
58 | 77 | ||
59 | static int (*invoke_psci_fn)(u64, u64, u64, u64); | 78 | typedef unsigned long (psci_fn)(unsigned long, unsigned long, |
60 | typedef int (*psci_initcall_t)(const struct device_node *); | 79 | unsigned long, unsigned long); |
61 | 80 | asmlinkage psci_fn __invoke_psci_fn_hvc; | |
62 | asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64); | 81 | asmlinkage psci_fn __invoke_psci_fn_smc; |
63 | asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64); | 82 | static psci_fn *invoke_psci_fn; |
64 | 83 | ||
65 | enum psci_function { | 84 | enum psci_function { |
66 | PSCI_FN_CPU_SUSPEND, | 85 | PSCI_FN_CPU_SUSPEND, |
67 | PSCI_FN_CPU_ON, | 86 | PSCI_FN_CPU_ON, |
68 | PSCI_FN_CPU_OFF, | 87 | PSCI_FN_CPU_OFF, |
69 | PSCI_FN_MIGRATE, | 88 | PSCI_FN_MIGRATE, |
70 | PSCI_FN_AFFINITY_INFO, | ||
71 | PSCI_FN_MIGRATE_INFO_TYPE, | ||
72 | PSCI_FN_MAX, | 89 | PSCI_FN_MAX, |
73 | }; | 90 | }; |
74 | 91 | ||
75 | static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state); | 92 | static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); |
76 | 93 | ||
77 | static u32 psci_function_id[PSCI_FN_MAX]; | 94 | static u32 psci_function_id[PSCI_FN_MAX]; |
78 | 95 | ||
@@ -92,56 +109,28 @@ static int psci_to_linux_errno(int errno) | |||
92 | return -EINVAL; | 109 | return -EINVAL; |
93 | } | 110 | } |
94 | 111 | ||
95 | static u32 psci_power_state_pack(struct psci_power_state state) | 112 | static u32 psci_get_version(void) |
96 | { | ||
97 | return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT) | ||
98 | & PSCI_0_2_POWER_STATE_ID_MASK) | | ||
99 | ((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT) | ||
100 | & PSCI_0_2_POWER_STATE_TYPE_MASK) | | ||
101 | ((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | ||
102 | & PSCI_0_2_POWER_STATE_AFFL_MASK); | ||
103 | } | ||
104 | |||
105 | static void psci_power_state_unpack(u32 power_state, | ||
106 | struct psci_power_state *state) | ||
107 | { | 113 | { |
108 | state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >> | 114 | return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); |
109 | PSCI_0_2_POWER_STATE_ID_SHIFT; | ||
110 | state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >> | ||
111 | PSCI_0_2_POWER_STATE_TYPE_SHIFT; | ||
112 | state->affinity_level = | ||
113 | (power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >> | ||
114 | PSCI_0_2_POWER_STATE_AFFL_SHIFT; | ||
115 | } | 115 | } |
116 | 116 | ||
117 | static int psci_get_version(void) | 117 | static int psci_cpu_suspend(u32 state, unsigned long entry_point) |
118 | { | 118 | { |
119 | int err; | 119 | int err; |
120 | 120 | u32 fn; | |
121 | err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); | ||
122 | return err; | ||
123 | } | ||
124 | |||
125 | static int psci_cpu_suspend(struct psci_power_state state, | ||
126 | unsigned long entry_point) | ||
127 | { | ||
128 | int err; | ||
129 | u32 fn, power_state; | ||
130 | 121 | ||
131 | fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; | 122 | fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; |
132 | power_state = psci_power_state_pack(state); | 123 | err = invoke_psci_fn(fn, state, entry_point, 0); |
133 | err = invoke_psci_fn(fn, power_state, entry_point, 0); | ||
134 | return psci_to_linux_errno(err); | 124 | return psci_to_linux_errno(err); |
135 | } | 125 | } |
136 | 126 | ||
137 | static int psci_cpu_off(struct psci_power_state state) | 127 | static int psci_cpu_off(u32 state) |
138 | { | 128 | { |
139 | int err; | 129 | int err; |
140 | u32 fn, power_state; | 130 | u32 fn; |
141 | 131 | ||
142 | fn = psci_function_id[PSCI_FN_CPU_OFF]; | 132 | fn = psci_function_id[PSCI_FN_CPU_OFF]; |
143 | power_state = psci_power_state_pack(state); | 133 | err = invoke_psci_fn(fn, state, 0, 0); |
144 | err = invoke_psci_fn(fn, power_state, 0, 0); | ||
145 | return psci_to_linux_errno(err); | 134 | return psci_to_linux_errno(err); |
146 | } | 135 | } |
147 | 136 | ||
@@ -168,28 +157,24 @@ static int psci_migrate(unsigned long cpuid) | |||
168 | static int psci_affinity_info(unsigned long target_affinity, | 157 | static int psci_affinity_info(unsigned long target_affinity, |
169 | unsigned long lowest_affinity_level) | 158 | unsigned long lowest_affinity_level) |
170 | { | 159 | { |
171 | int err; | 160 | return invoke_psci_fn(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, |
172 | u32 fn; | 161 | lowest_affinity_level, 0); |
173 | |||
174 | fn = psci_function_id[PSCI_FN_AFFINITY_INFO]; | ||
175 | err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0); | ||
176 | return err; | ||
177 | } | 162 | } |
178 | 163 | ||
179 | static int psci_migrate_info_type(void) | 164 | static int psci_migrate_info_type(void) |
180 | { | 165 | { |
181 | int err; | 166 | return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0); |
182 | u32 fn; | 167 | } |
183 | 168 | ||
184 | fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE]; | 169 | static unsigned long psci_migrate_info_up_cpu(void) |
185 | err = invoke_psci_fn(fn, 0, 0, 0); | 170 | { |
186 | return err; | 171 | return invoke_psci_fn(PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, 0, 0, 0); |
187 | } | 172 | } |
188 | 173 | ||
189 | static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu) | 174 | static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu) |
190 | { | 175 | { |
191 | int i, ret, count = 0; | 176 | int i, ret, count = 0; |
192 | struct psci_power_state *psci_states; | 177 | u32 *psci_states; |
193 | struct device_node *state_node, *cpu_node; | 178 | struct device_node *state_node, *cpu_node; |
194 | 179 | ||
195 | cpu_node = of_get_cpu_node(cpu, NULL); | 180 | cpu_node = of_get_cpu_node(cpu, NULL); |
@@ -218,13 +203,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu) | |||
218 | return -ENOMEM; | 203 | return -ENOMEM; |
219 | 204 | ||
220 | for (i = 0; i < count; i++) { | 205 | for (i = 0; i < count; i++) { |
221 | u32 psci_power_state; | 206 | u32 state; |
222 | 207 | ||
223 | state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); | 208 | state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); |
224 | 209 | ||
225 | ret = of_property_read_u32(state_node, | 210 | ret = of_property_read_u32(state_node, |
226 | "arm,psci-suspend-param", | 211 | "arm,psci-suspend-param", |
227 | &psci_power_state); | 212 | &state); |
228 | if (ret) { | 213 | if (ret) { |
229 | pr_warn(" * %s missing arm,psci-suspend-param property\n", | 214 | pr_warn(" * %s missing arm,psci-suspend-param property\n", |
230 | state_node->full_name); | 215 | state_node->full_name); |
@@ -233,9 +218,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu) | |||
233 | } | 218 | } |
234 | 219 | ||
235 | of_node_put(state_node); | 220 | of_node_put(state_node); |
236 | pr_debug("psci-power-state %#x index %d\n", psci_power_state, | 221 | pr_debug("psci-power-state %#x index %d\n", state, i); |
237 | i); | 222 | if (!psci_power_state_is_valid(state)) { |
238 | psci_power_state_unpack(psci_power_state, &psci_states[i]); | 223 | pr_warn("Invalid PSCI power state %#x\n", state); |
224 | ret = -EINVAL; | ||
225 | goto free_mem; | ||
226 | } | ||
227 | psci_states[i] = state; | ||
239 | } | 228 | } |
240 | /* Idle states parsed correctly, initialize per-cpu pointer */ | 229 | /* Idle states parsed correctly, initialize per-cpu pointer */ |
241 | per_cpu(psci_power_state, cpu) = psci_states; | 230 | per_cpu(psci_power_state, cpu) = psci_states; |
@@ -278,6 +267,46 @@ static void psci_sys_poweroff(void) | |||
278 | invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); | 267 | invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); |
279 | } | 268 | } |
280 | 269 | ||
270 | /* | ||
271 | * Detect the presence of a resident Trusted OS which may cause CPU_OFF to | ||
272 | * return DENIED (which would be fatal). | ||
273 | */ | ||
274 | static void __init psci_init_migrate(void) | ||
275 | { | ||
276 | unsigned long cpuid; | ||
277 | int type, cpu; | ||
278 | |||
279 | type = psci_ops.migrate_info_type(); | ||
280 | |||
281 | if (type == PSCI_0_2_TOS_MP) { | ||
282 | pr_info("Trusted OS migration not required\n"); | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | if (type == PSCI_RET_NOT_SUPPORTED) { | ||
287 | pr_info("MIGRATE_INFO_TYPE not supported.\n"); | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | if (type != PSCI_0_2_TOS_UP_MIGRATE && | ||
292 | type != PSCI_0_2_TOS_UP_NO_MIGRATE) { | ||
293 | pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type); | ||
294 | return; | ||
295 | } | ||
296 | |||
297 | cpuid = psci_migrate_info_up_cpu(); | ||
298 | if (cpuid & ~MPIDR_HWID_BITMASK) { | ||
299 | pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n", | ||
300 | cpuid); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | cpu = get_logical_index(cpuid); | ||
305 | resident_cpu = cpu >= 0 ? cpu : -1; | ||
306 | |||
307 | pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); | ||
308 | } | ||
309 | |||
281 | static void __init psci_0_2_set_functions(void) | 310 | static void __init psci_0_2_set_functions(void) |
282 | { | 311 | { |
283 | pr_info("Using standard PSCI v0.2 function IDs\n"); | 312 | pr_info("Using standard PSCI v0.2 function IDs\n"); |
@@ -293,11 +322,8 @@ static void __init psci_0_2_set_functions(void) | |||
293 | psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; | 322 | psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; |
294 | psci_ops.migrate = psci_migrate; | 323 | psci_ops.migrate = psci_migrate; |
295 | 324 | ||
296 | psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO; | ||
297 | psci_ops.affinity_info = psci_affinity_info; | 325 | psci_ops.affinity_info = psci_affinity_info; |
298 | 326 | ||
299 | psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = | ||
300 | PSCI_0_2_FN_MIGRATE_INFO_TYPE; | ||
301 | psci_ops.migrate_info_type = psci_migrate_info_type; | 327 | psci_ops.migrate_info_type = psci_migrate_info_type; |
302 | 328 | ||
303 | arm_pm_restart = psci_sys_reset; | 329 | arm_pm_restart = psci_sys_reset; |
@@ -310,32 +336,26 @@ static void __init psci_0_2_set_functions(void) | |||
310 | */ | 336 | */ |
311 | static int __init psci_probe(void) | 337 | static int __init psci_probe(void) |
312 | { | 338 | { |
313 | int ver = psci_get_version(); | 339 | u32 ver = psci_get_version(); |
314 | 340 | ||
315 | if (ver == PSCI_RET_NOT_SUPPORTED) { | 341 | pr_info("PSCIv%d.%d detected in firmware.\n", |
316 | /* | 342 | PSCI_VERSION_MAJOR(ver), |
317 | * PSCI versions >=0.2 mandates implementation of | 343 | PSCI_VERSION_MINOR(ver)); |
318 | * PSCI_VERSION. | 344 | |
319 | */ | 345 | if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { |
320 | pr_err("PSCI firmware does not comply with the v0.2 spec.\n"); | 346 | pr_err("Conflicting PSCI version detected.\n"); |
321 | return -EOPNOTSUPP; | 347 | return -EINVAL; |
322 | } else { | ||
323 | pr_info("PSCIv%d.%d detected in firmware.\n", | ||
324 | PSCI_VERSION_MAJOR(ver), | ||
325 | PSCI_VERSION_MINOR(ver)); | ||
326 | |||
327 | if (PSCI_VERSION_MAJOR(ver) == 0 && | ||
328 | PSCI_VERSION_MINOR(ver) < 2) { | ||
329 | pr_err("Conflicting PSCI version detected.\n"); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | } | 348 | } |
333 | 349 | ||
334 | psci_0_2_set_functions(); | 350 | psci_0_2_set_functions(); |
335 | 351 | ||
352 | psci_init_migrate(); | ||
353 | |||
336 | return 0; | 354 | return 0; |
337 | } | 355 | } |
338 | 356 | ||
357 | typedef int (*psci_initcall_t)(const struct device_node *); | ||
358 | |||
339 | /* | 359 | /* |
340 | * PSCI init function for PSCI versions >=0.2 | 360 | * PSCI init function for PSCI versions >=0.2 |
341 | * | 361 | * |
@@ -424,6 +444,7 @@ int __init psci_dt_init(void) | |||
424 | return init_fn(np); | 444 | return init_fn(np); |
425 | } | 445 | } |
426 | 446 | ||
447 | #ifdef CONFIG_ACPI | ||
427 | /* | 448 | /* |
428 | * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's | 449 | * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's |
429 | * explicitly clarified in SBBR | 450 | * explicitly clarified in SBBR |
@@ -444,6 +465,7 @@ int __init psci_acpi_init(void) | |||
444 | 465 | ||
445 | return psci_probe(); | 466 | return psci_probe(); |
446 | } | 467 | } |
468 | #endif | ||
447 | 469 | ||
448 | #ifdef CONFIG_SMP | 470 | #ifdef CONFIG_SMP |
449 | 471 | ||
@@ -477,6 +499,11 @@ static int cpu_psci_cpu_disable(unsigned int cpu) | |||
477 | /* Fail early if we don't have CPU_OFF support */ | 499 | /* Fail early if we don't have CPU_OFF support */ |
478 | if (!psci_ops.cpu_off) | 500 | if (!psci_ops.cpu_off) |
479 | return -EOPNOTSUPP; | 501 | return -EOPNOTSUPP; |
502 | |||
503 | /* Trusted OS will deny CPU_OFF */ | ||
504 | if (psci_tos_resident_on(cpu)) | ||
505 | return -EPERM; | ||
506 | |||
480 | return 0; | 507 | return 0; |
481 | } | 508 | } |
482 | 509 | ||
@@ -487,9 +514,8 @@ static void cpu_psci_cpu_die(unsigned int cpu) | |||
487 | * There are no known implementations of PSCI actually using the | 514 | * There are no known implementations of PSCI actually using the |
488 | * power state field, pass a sensible default for now. | 515 | * power state field, pass a sensible default for now. |
489 | */ | 516 | */ |
490 | struct psci_power_state state = { | 517 | u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN << |
491 | .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, | 518 | PSCI_0_2_POWER_STATE_TYPE_SHIFT; |
492 | }; | ||
493 | 519 | ||
494 | ret = psci_ops.cpu_off(state); | 520 | ret = psci_ops.cpu_off(state); |
495 | 521 | ||
@@ -501,7 +527,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu) | |||
501 | int err, i; | 527 | int err, i; |
502 | 528 | ||
503 | if (!psci_ops.affinity_info) | 529 | if (!psci_ops.affinity_info) |
504 | return 1; | 530 | return 0; |
505 | /* | 531 | /* |
506 | * cpu_kill could race with cpu_die and we can | 532 | * cpu_kill could race with cpu_die and we can |
507 | * potentially end up declaring this cpu undead | 533 | * potentially end up declaring this cpu undead |
@@ -512,7 +538,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu) | |||
512 | err = psci_ops.affinity_info(cpu_logical_map(cpu), 0); | 538 | err = psci_ops.affinity_info(cpu_logical_map(cpu), 0); |
513 | if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) { | 539 | if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) { |
514 | pr_info("CPU%d killed.\n", cpu); | 540 | pr_info("CPU%d killed.\n", cpu); |
515 | return 1; | 541 | return 0; |
516 | } | 542 | } |
517 | 543 | ||
518 | msleep(10); | 544 | msleep(10); |
@@ -521,15 +547,14 @@ static int cpu_psci_cpu_kill(unsigned int cpu) | |||
521 | 547 | ||
522 | pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n", | 548 | pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n", |
523 | cpu, err); | 549 | cpu, err); |
524 | /* Make op_cpu_kill() fail. */ | 550 | return -ETIMEDOUT; |
525 | return 0; | ||
526 | } | 551 | } |
527 | #endif | 552 | #endif |
528 | #endif | 553 | #endif |
529 | 554 | ||
530 | static int psci_suspend_finisher(unsigned long index) | 555 | static int psci_suspend_finisher(unsigned long index) |
531 | { | 556 | { |
532 | struct psci_power_state *state = __this_cpu_read(psci_power_state); | 557 | u32 *state = __this_cpu_read(psci_power_state); |
533 | 558 | ||
534 | return psci_ops.cpu_suspend(state[index - 1], | 559 | return psci_ops.cpu_suspend(state[index - 1], |
535 | virt_to_phys(cpu_resume)); | 560 | virt_to_phys(cpu_resume)); |
@@ -538,7 +563,7 @@ static int psci_suspend_finisher(unsigned long index) | |||
538 | static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) | 563 | static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) |
539 | { | 564 | { |
540 | int ret; | 565 | int ret; |
541 | struct psci_power_state *state = __this_cpu_read(psci_power_state); | 566 | u32 *state = __this_cpu_read(psci_power_state); |
542 | /* | 567 | /* |
543 | * idle state index 0 corresponds to wfi, should never be called | 568 | * idle state index 0 corresponds to wfi, should never be called |
544 | * from the cpu_suspend operations | 569 | * from the cpu_suspend operations |
@@ -546,7 +571,7 @@ static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index) | |||
546 | if (WARN_ON_ONCE(!index)) | 571 | if (WARN_ON_ONCE(!index)) |
547 | return -EINVAL; | 572 | return -EINVAL; |
548 | 573 | ||
549 | if (state[index - 1].type == PSCI_POWER_STATE_TYPE_STANDBY) | 574 | if (!psci_power_state_loses_context(state[index - 1])) |
550 | ret = psci_ops.cpu_suspend(state[index - 1], 0); | 575 | ret = psci_ops.cpu_suspend(state[index - 1], 0); |
551 | else | 576 | else |
552 | ret = __cpu_suspend(index, psci_suspend_finisher); | 577 | ret = __cpu_suspend(index, psci_suspend_finisher); |
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index 65f1a7f72697..4b2121bd7f9c 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c | |||
@@ -249,7 +249,7 @@ static int op_cpu_kill(unsigned int cpu) | |||
249 | * time and hope that it's dead, so let's skip the wait and just hope. | 249 | * time and hope that it's dead, so let's skip the wait and just hope. |
250 | */ | 250 | */ |
251 | if (!cpu_ops[cpu]->cpu_kill) | 251 | if (!cpu_ops[cpu]->cpu_kill) |
252 | return 1; | 252 | return 0; |
253 | 253 | ||
254 | return cpu_ops[cpu]->cpu_kill(cpu); | 254 | return cpu_ops[cpu]->cpu_kill(cpu); |
255 | } | 255 | } |
@@ -260,6 +260,8 @@ static int op_cpu_kill(unsigned int cpu) | |||
260 | */ | 260 | */ |
261 | void __cpu_die(unsigned int cpu) | 261 | void __cpu_die(unsigned int cpu) |
262 | { | 262 | { |
263 | int err; | ||
264 | |||
263 | if (!cpu_wait_death(cpu, 5)) { | 265 | if (!cpu_wait_death(cpu, 5)) { |
264 | pr_crit("CPU%u: cpu didn't die\n", cpu); | 266 | pr_crit("CPU%u: cpu didn't die\n", cpu); |
265 | return; | 267 | return; |
@@ -272,8 +274,10 @@ void __cpu_die(unsigned int cpu) | |||
272 | * verify that it has really left the kernel before we consider | 274 | * verify that it has really left the kernel before we consider |
273 | * clobbering anything it might still be using. | 275 | * clobbering anything it might still be using. |
274 | */ | 276 | */ |
275 | if (!op_cpu_kill(cpu)) | 277 | err = op_cpu_kill(cpu); |
276 | pr_warn("CPU%d may not have shut down cleanly\n", cpu); | 278 | if (err) |
279 | pr_warn("CPU%d may not have shut down cleanly: %d\n", | ||
280 | cpu, err); | ||
277 | } | 281 | } |
278 | 282 | ||
279 | /* | 283 | /* |