diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-04 11:47:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-04 11:47:12 -0400 |
commit | b05d59dfceaea72565b1648af929b037b0f96d7f (patch) | |
tree | bbe92714be468ed8783bce6ac2c305c0aedf8eb5 /arch/arm64 | |
parent | daf342af2f7856fd2f5c66b9fb39a8f24986ca53 (diff) | |
parent | 820b3fcdeb80d30410f4427d2cbf9161c35fdeef (diff) |
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm into next
Pull KVM updates from Paolo Bonzini:
"At over 200 commits, covering almost all supported architectures, this
was a pretty active cycle for KVM. Changes include:
- a lot of s390 changes: optimizations, support for migration, GDB
support and more
- ARM changes are pretty small: support for the PSCI 0.2 hypercall
interface on both the guest and the host (the latter acked by
Catalin)
- initial POWER8 and little-endian host support
- support for running u-boot on embedded POWER targets
- pretty large changes to MIPS too, completing the userspace
interface and improving the handling of virtualized timer hardware
- for x86, a larger set of changes is scheduled for 3.17. Still, we
have a few emulator bugfixes and support for running nested
fully-virtualized Xen guests (para-virtualized Xen guests have
always worked). And some optimizations too.
The only missing architecture here is ia64. It's not a coincidence
that support for KVM on ia64 is scheduled for removal in 3.17"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (203 commits)
KVM: add missing cleanup_srcu_struct
KVM: PPC: Book3S PR: Rework SLB switching code
KVM: PPC: Book3S PR: Use SLB entry 0
KVM: PPC: Book3S HV: Fix machine check delivery to guest
KVM: PPC: Book3S HV: Work around POWER8 performance monitor bugs
KVM: PPC: Book3S HV: Make sure we don't miss dirty pages
KVM: PPC: Book3S HV: Fix dirty map for hugepages
KVM: PPC: Book3S HV: Put huge-page HPTEs in rmap chain for base address
KVM: PPC: Book3S HV: Fix check for running inside guest in global_invalidates()
KVM: PPC: Book3S: Move KVM_REG_PPC_WORT to an unused register number
KVM: PPC: Book3S: Add ONE_REG register names that were missed
KVM: PPC: Add CAP to indicate hcall fixes
KVM: PPC: MPIC: Reset IRQ source private members
KVM: PPC: Graciously fail broken LE hypercalls
PPC: ePAPR: Fix hypercall on LE guest
KVM: PPC: BOOK3S: Remove open coded make_dsisr in alignment handler
KVM: PPC: BOOK3S: Always use the saved DAR value
PPC: KVM: Make NX bit available with magic page
KVM: PPC: Disable NX for old magic page using guests
KVM: PPC: BOOK3S: HV: Add mixed page-size support for guest
...
Diffstat (limited to 'arch/arm64')
-rw-r--r-- | arch/arm64/include/asm/cpu_ops.h | 2 | ||||
-rw-r--r-- | arch/arm64/include/asm/cputype.h | 1 | ||||
-rw-r--r-- | arch/arm64/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/arm64/include/asm/kvm_psci.h | 6 | ||||
-rw-r--r-- | arch/arm64/include/asm/psci.h | 2 | ||||
-rw-r--r-- | arch/arm64/include/uapi/asm/kvm.h | 13 | ||||
-rw-r--r-- | arch/arm64/kernel/psci.c | 231 | ||||
-rw-r--r-- | arch/arm64/kernel/smp.c | 22 | ||||
-rw-r--r-- | arch/arm64/kvm/guest.c | 2 | ||||
-rw-r--r-- | arch/arm64/kvm/handle_exit.c | 10 | ||||
-rw-r--r-- | arch/arm64/kvm/sys_regs_generic_v8.c | 2 |
11 files changed, 245 insertions, 48 deletions
diff --git a/arch/arm64/include/asm/cpu_ops.h b/arch/arm64/include/asm/cpu_ops.h index 152413076503..d7b4b38a8e86 100644 --- a/arch/arm64/include/asm/cpu_ops.h +++ b/arch/arm64/include/asm/cpu_ops.h | |||
@@ -39,6 +39,7 @@ struct device_node; | |||
39 | * from the cpu to be killed. | 39 | * from the cpu to be killed. |
40 | * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the | 40 | * @cpu_die: Makes a cpu leave the kernel. Must not fail. Called from the |
41 | * cpu being killed. | 41 | * cpu being killed. |
42 | * @cpu_kill: Ensures a cpu has left the kernel. Called from another cpu. | ||
42 | * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing | 43 | * @cpu_suspend: Suspends a cpu and saves the required context. May fail owing |
43 | * to wrong parameters or error conditions. Called from the | 44 | * to wrong parameters or error conditions. Called from the |
44 | * CPU being suspended. Must be called with IRQs disabled. | 45 | * CPU being suspended. Must be called with IRQs disabled. |
@@ -52,6 +53,7 @@ struct cpu_operations { | |||
52 | #ifdef CONFIG_HOTPLUG_CPU | 53 | #ifdef CONFIG_HOTPLUG_CPU |
53 | int (*cpu_disable)(unsigned int cpu); | 54 | int (*cpu_disable)(unsigned int cpu); |
54 | void (*cpu_die)(unsigned int cpu); | 55 | void (*cpu_die)(unsigned int cpu); |
56 | int (*cpu_kill)(unsigned int cpu); | ||
55 | #endif | 57 | #endif |
56 | #ifdef CONFIG_ARM64_CPU_SUSPEND | 58 | #ifdef CONFIG_ARM64_CPU_SUSPEND |
57 | int (*cpu_suspend)(unsigned long); | 59 | int (*cpu_suspend)(unsigned long); |
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index c404fb0df3a6..27f54a7cc81b 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h | |||
@@ -41,6 +41,7 @@ | |||
41 | 41 | ||
42 | #define ARM_CPU_PART_AEM_V8 0xD0F0 | 42 | #define ARM_CPU_PART_AEM_V8 0xD0F0 |
43 | #define ARM_CPU_PART_FOUNDATION 0xD000 | 43 | #define ARM_CPU_PART_FOUNDATION 0xD000 |
44 | #define ARM_CPU_PART_CORTEX_A53 0xD030 | ||
44 | #define ARM_CPU_PART_CORTEX_A57 0xD070 | 45 | #define ARM_CPU_PART_CORTEX_A57 0xD070 |
45 | 46 | ||
46 | #define APM_CPU_PART_POTENZA 0x0000 | 47 | #define APM_CPU_PART_POTENZA 0x0000 |
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 0a1d69751562..92242ce06309 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <kvm/arm_vgic.h> | 39 | #include <kvm/arm_vgic.h> |
40 | #include <kvm/arm_arch_timer.h> | 40 | #include <kvm/arm_arch_timer.h> |
41 | 41 | ||
42 | #define KVM_VCPU_MAX_FEATURES 2 | 42 | #define KVM_VCPU_MAX_FEATURES 3 |
43 | 43 | ||
44 | struct kvm_vcpu; | 44 | struct kvm_vcpu; |
45 | int kvm_target_cpu(void); | 45 | int kvm_target_cpu(void); |
diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h index e301a4816355..bc39e557c56c 100644 --- a/arch/arm64/include/asm/kvm_psci.h +++ b/arch/arm64/include/asm/kvm_psci.h | |||
@@ -18,6 +18,10 @@ | |||
18 | #ifndef __ARM64_KVM_PSCI_H__ | 18 | #ifndef __ARM64_KVM_PSCI_H__ |
19 | #define __ARM64_KVM_PSCI_H__ | 19 | #define __ARM64_KVM_PSCI_H__ |
20 | 20 | ||
21 | bool kvm_psci_call(struct kvm_vcpu *vcpu); | 21 | #define KVM_ARM_PSCI_0_1 1 |
22 | #define KVM_ARM_PSCI_0_2 2 | ||
23 | |||
24 | int kvm_psci_version(struct kvm_vcpu *vcpu); | ||
25 | int kvm_psci_call(struct kvm_vcpu *vcpu); | ||
22 | 26 | ||
23 | #endif /* __ARM64_KVM_PSCI_H__ */ | 27 | #endif /* __ARM64_KVM_PSCI_H__ */ |
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h index d15ab8b46336..e5312ea0ec1a 100644 --- a/arch/arm64/include/asm/psci.h +++ b/arch/arm64/include/asm/psci.h | |||
@@ -14,6 +14,6 @@ | |||
14 | #ifndef __ASM_PSCI_H | 14 | #ifndef __ASM_PSCI_H |
15 | #define __ASM_PSCI_H | 15 | #define __ASM_PSCI_H |
16 | 16 | ||
17 | void psci_init(void); | 17 | int psci_init(void); |
18 | 18 | ||
19 | #endif /* __ASM_PSCI_H */ | 19 | #endif /* __ASM_PSCI_H */ |
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index eaf54a30bedc..e633ff8cdec8 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h | |||
@@ -31,6 +31,7 @@ | |||
31 | #define KVM_NR_SPSR 5 | 31 | #define KVM_NR_SPSR 5 |
32 | 32 | ||
33 | #ifndef __ASSEMBLY__ | 33 | #ifndef __ASSEMBLY__ |
34 | #include <linux/psci.h> | ||
34 | #include <asm/types.h> | 35 | #include <asm/types.h> |
35 | #include <asm/ptrace.h> | 36 | #include <asm/ptrace.h> |
36 | 37 | ||
@@ -56,8 +57,9 @@ struct kvm_regs { | |||
56 | #define KVM_ARM_TARGET_FOUNDATION_V8 1 | 57 | #define KVM_ARM_TARGET_FOUNDATION_V8 1 |
57 | #define KVM_ARM_TARGET_CORTEX_A57 2 | 58 | #define KVM_ARM_TARGET_CORTEX_A57 2 |
58 | #define KVM_ARM_TARGET_XGENE_POTENZA 3 | 59 | #define KVM_ARM_TARGET_XGENE_POTENZA 3 |
60 | #define KVM_ARM_TARGET_CORTEX_A53 4 | ||
59 | 61 | ||
60 | #define KVM_ARM_NUM_TARGETS 4 | 62 | #define KVM_ARM_NUM_TARGETS 5 |
61 | 63 | ||
62 | /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ | 64 | /* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */ |
63 | #define KVM_ARM_DEVICE_TYPE_SHIFT 0 | 65 | #define KVM_ARM_DEVICE_TYPE_SHIFT 0 |
@@ -77,6 +79,7 @@ struct kvm_regs { | |||
77 | 79 | ||
78 | #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ | 80 | #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ |
79 | #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ | 81 | #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ |
82 | #define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */ | ||
80 | 83 | ||
81 | struct kvm_vcpu_init { | 84 | struct kvm_vcpu_init { |
82 | __u32 target; | 85 | __u32 target; |
@@ -186,10 +189,10 @@ struct kvm_arch_memory_slot { | |||
186 | #define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) | 189 | #define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2) |
187 | #define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) | 190 | #define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3) |
188 | 191 | ||
189 | #define KVM_PSCI_RET_SUCCESS 0 | 192 | #define KVM_PSCI_RET_SUCCESS PSCI_RET_SUCCESS |
190 | #define KVM_PSCI_RET_NI ((unsigned long)-1) | 193 | #define KVM_PSCI_RET_NI PSCI_RET_NOT_SUPPORTED |
191 | #define KVM_PSCI_RET_INVAL ((unsigned long)-2) | 194 | #define KVM_PSCI_RET_INVAL PSCI_RET_INVALID_PARAMS |
192 | #define KVM_PSCI_RET_DENIED ((unsigned long)-3) | 195 | #define KVM_PSCI_RET_DENIED PSCI_RET_DENIED |
193 | 196 | ||
194 | #endif | 197 | #endif |
195 | 198 | ||
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index ea4828a4aa96..9e9798f91172 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c | |||
@@ -18,12 +18,17 @@ | |||
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/smp.h> | 20 | #include <linux/smp.h> |
21 | #include <linux/reboot.h> | ||
22 | #include <linux/pm.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <uapi/linux/psci.h> | ||
21 | 25 | ||
22 | #include <asm/compiler.h> | 26 | #include <asm/compiler.h> |
23 | #include <asm/cpu_ops.h> | 27 | #include <asm/cpu_ops.h> |
24 | #include <asm/errno.h> | 28 | #include <asm/errno.h> |
25 | #include <asm/psci.h> | 29 | #include <asm/psci.h> |
26 | #include <asm/smp_plat.h> | 30 | #include <asm/smp_plat.h> |
31 | #include <asm/system_misc.h> | ||
27 | 32 | ||
28 | #define PSCI_POWER_STATE_TYPE_STANDBY 0 | 33 | #define PSCI_POWER_STATE_TYPE_STANDBY 0 |
29 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 | 34 | #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 |
@@ -40,58 +45,52 @@ struct psci_operations { | |||
40 | int (*cpu_off)(struct psci_power_state state); | 45 | int (*cpu_off)(struct psci_power_state state); |
41 | int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); | 46 | int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); |
42 | int (*migrate)(unsigned long cpuid); | 47 | int (*migrate)(unsigned long cpuid); |
48 | int (*affinity_info)(unsigned long target_affinity, | ||
49 | unsigned long lowest_affinity_level); | ||
50 | int (*migrate_info_type)(void); | ||
43 | }; | 51 | }; |
44 | 52 | ||
45 | static struct psci_operations psci_ops; | 53 | static struct psci_operations psci_ops; |
46 | 54 | ||
47 | static int (*invoke_psci_fn)(u64, u64, u64, u64); | 55 | static int (*invoke_psci_fn)(u64, u64, u64, u64); |
56 | typedef int (*psci_initcall_t)(const struct device_node *); | ||
48 | 57 | ||
49 | enum psci_function { | 58 | enum psci_function { |
50 | PSCI_FN_CPU_SUSPEND, | 59 | PSCI_FN_CPU_SUSPEND, |
51 | PSCI_FN_CPU_ON, | 60 | PSCI_FN_CPU_ON, |
52 | PSCI_FN_CPU_OFF, | 61 | PSCI_FN_CPU_OFF, |
53 | PSCI_FN_MIGRATE, | 62 | PSCI_FN_MIGRATE, |
63 | PSCI_FN_AFFINITY_INFO, | ||
64 | PSCI_FN_MIGRATE_INFO_TYPE, | ||
54 | PSCI_FN_MAX, | 65 | PSCI_FN_MAX, |
55 | }; | 66 | }; |
56 | 67 | ||
57 | static u32 psci_function_id[PSCI_FN_MAX]; | 68 | static u32 psci_function_id[PSCI_FN_MAX]; |
58 | 69 | ||
59 | #define PSCI_RET_SUCCESS 0 | ||
60 | #define PSCI_RET_EOPNOTSUPP -1 | ||
61 | #define PSCI_RET_EINVAL -2 | ||
62 | #define PSCI_RET_EPERM -3 | ||
63 | |||
64 | static int psci_to_linux_errno(int errno) | 70 | static int psci_to_linux_errno(int errno) |
65 | { | 71 | { |
66 | switch (errno) { | 72 | switch (errno) { |
67 | case PSCI_RET_SUCCESS: | 73 | case PSCI_RET_SUCCESS: |
68 | return 0; | 74 | return 0; |
69 | case PSCI_RET_EOPNOTSUPP: | 75 | case PSCI_RET_NOT_SUPPORTED: |
70 | return -EOPNOTSUPP; | 76 | return -EOPNOTSUPP; |
71 | case PSCI_RET_EINVAL: | 77 | case PSCI_RET_INVALID_PARAMS: |
72 | return -EINVAL; | 78 | return -EINVAL; |
73 | case PSCI_RET_EPERM: | 79 | case PSCI_RET_DENIED: |
74 | return -EPERM; | 80 | return -EPERM; |
75 | }; | 81 | }; |
76 | 82 | ||
77 | return -EINVAL; | 83 | return -EINVAL; |
78 | } | 84 | } |
79 | 85 | ||
80 | #define PSCI_POWER_STATE_ID_MASK 0xffff | ||
81 | #define PSCI_POWER_STATE_ID_SHIFT 0 | ||
82 | #define PSCI_POWER_STATE_TYPE_MASK 0x1 | ||
83 | #define PSCI_POWER_STATE_TYPE_SHIFT 16 | ||
84 | #define PSCI_POWER_STATE_AFFL_MASK 0x3 | ||
85 | #define PSCI_POWER_STATE_AFFL_SHIFT 24 | ||
86 | |||
87 | static u32 psci_power_state_pack(struct psci_power_state state) | 86 | static u32 psci_power_state_pack(struct psci_power_state state) |
88 | { | 87 | { |
89 | return ((state.id & PSCI_POWER_STATE_ID_MASK) | 88 | return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT) |
90 | << PSCI_POWER_STATE_ID_SHIFT) | | 89 | & PSCI_0_2_POWER_STATE_ID_MASK) | |
91 | ((state.type & PSCI_POWER_STATE_TYPE_MASK) | 90 | ((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT) |
92 | << PSCI_POWER_STATE_TYPE_SHIFT) | | 91 | & PSCI_0_2_POWER_STATE_TYPE_MASK) | |
93 | ((state.affinity_level & PSCI_POWER_STATE_AFFL_MASK) | 92 | ((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT) |
94 | << PSCI_POWER_STATE_AFFL_SHIFT); | 93 | & PSCI_0_2_POWER_STATE_AFFL_MASK); |
95 | } | 94 | } |
96 | 95 | ||
97 | /* | 96 | /* |
@@ -128,6 +127,14 @@ static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, | |||
128 | return function_id; | 127 | return function_id; |
129 | } | 128 | } |
130 | 129 | ||
130 | static int psci_get_version(void) | ||
131 | { | ||
132 | int err; | ||
133 | |||
134 | err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); | ||
135 | return err; | ||
136 | } | ||
137 | |||
131 | static int psci_cpu_suspend(struct psci_power_state state, | 138 | static int psci_cpu_suspend(struct psci_power_state state, |
132 | unsigned long entry_point) | 139 | unsigned long entry_point) |
133 | { | 140 | { |
@@ -171,26 +178,36 @@ static int psci_migrate(unsigned long cpuid) | |||
171 | return psci_to_linux_errno(err); | 178 | return psci_to_linux_errno(err); |
172 | } | 179 | } |
173 | 180 | ||
174 | static const struct of_device_id psci_of_match[] __initconst = { | 181 | static int psci_affinity_info(unsigned long target_affinity, |
175 | { .compatible = "arm,psci", }, | 182 | unsigned long lowest_affinity_level) |
176 | {}, | 183 | { |
177 | }; | 184 | int err; |
185 | u32 fn; | ||
186 | |||
187 | fn = psci_function_id[PSCI_FN_AFFINITY_INFO]; | ||
188 | err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0); | ||
189 | return err; | ||
190 | } | ||
178 | 191 | ||
179 | void __init psci_init(void) | 192 | static int psci_migrate_info_type(void) |
180 | { | 193 | { |
181 | struct device_node *np; | 194 | int err; |
182 | const char *method; | 195 | u32 fn; |
183 | u32 id; | ||
184 | 196 | ||
185 | np = of_find_matching_node(NULL, psci_of_match); | 197 | fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE]; |
186 | if (!np) | 198 | err = invoke_psci_fn(fn, 0, 0, 0); |
187 | return; | 199 | return err; |
200 | } | ||
188 | 201 | ||
189 | pr_info("probing function IDs from device-tree\n"); | 202 | static int get_set_conduit_method(struct device_node *np) |
203 | { | ||
204 | const char *method; | ||
205 | |||
206 | pr_info("probing for conduit method from DT.\n"); | ||
190 | 207 | ||
191 | if (of_property_read_string(np, "method", &method)) { | 208 | if (of_property_read_string(np, "method", &method)) { |
192 | pr_warning("missing \"method\" property\n"); | 209 | pr_warn("missing \"method\" property\n"); |
193 | goto out_put_node; | 210 | return -ENXIO; |
194 | } | 211 | } |
195 | 212 | ||
196 | if (!strcmp("hvc", method)) { | 213 | if (!strcmp("hvc", method)) { |
@@ -198,10 +215,99 @@ void __init psci_init(void) | |||
198 | } else if (!strcmp("smc", method)) { | 215 | } else if (!strcmp("smc", method)) { |
199 | invoke_psci_fn = __invoke_psci_fn_smc; | 216 | invoke_psci_fn = __invoke_psci_fn_smc; |
200 | } else { | 217 | } else { |
201 | pr_warning("invalid \"method\" property: %s\n", method); | 218 | pr_warn("invalid \"method\" property: %s\n", method); |
219 | return -EINVAL; | ||
220 | } | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) | ||
225 | { | ||
226 | invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); | ||
227 | } | ||
228 | |||
229 | static void psci_sys_poweroff(void) | ||
230 | { | ||
231 | invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * PSCI Function IDs for v0.2+ are well defined so use | ||
236 | * standard values. | ||
237 | */ | ||
238 | static int psci_0_2_init(struct device_node *np) | ||
239 | { | ||
240 | int err, ver; | ||
241 | |||
242 | err = get_set_conduit_method(np); | ||
243 | |||
244 | if (err) | ||
245 | goto out_put_node; | ||
246 | |||
247 | ver = psci_get_version(); | ||
248 | |||
249 | if (ver == PSCI_RET_NOT_SUPPORTED) { | ||
250 | /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */ | ||
251 | pr_err("PSCI firmware does not comply with the v0.2 spec.\n"); | ||
252 | err = -EOPNOTSUPP; | ||
202 | goto out_put_node; | 253 | goto out_put_node; |
254 | } else { | ||
255 | pr_info("PSCIv%d.%d detected in firmware.\n", | ||
256 | PSCI_VERSION_MAJOR(ver), | ||
257 | PSCI_VERSION_MINOR(ver)); | ||
258 | |||
259 | if (PSCI_VERSION_MAJOR(ver) == 0 && | ||
260 | PSCI_VERSION_MINOR(ver) < 2) { | ||
261 | err = -EINVAL; | ||
262 | pr_err("Conflicting PSCI version detected.\n"); | ||
263 | goto out_put_node; | ||
264 | } | ||
203 | } | 265 | } |
204 | 266 | ||
267 | pr_info("Using standard PSCI v0.2 function IDs\n"); | ||
268 | psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; | ||
269 | psci_ops.cpu_suspend = psci_cpu_suspend; | ||
270 | |||
271 | psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; | ||
272 | psci_ops.cpu_off = psci_cpu_off; | ||
273 | |||
274 | psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON; | ||
275 | psci_ops.cpu_on = psci_cpu_on; | ||
276 | |||
277 | psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; | ||
278 | psci_ops.migrate = psci_migrate; | ||
279 | |||
280 | psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO; | ||
281 | psci_ops.affinity_info = psci_affinity_info; | ||
282 | |||
283 | psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = | ||
284 | PSCI_0_2_FN_MIGRATE_INFO_TYPE; | ||
285 | psci_ops.migrate_info_type = psci_migrate_info_type; | ||
286 | |||
287 | arm_pm_restart = psci_sys_reset; | ||
288 | |||
289 | pm_power_off = psci_sys_poweroff; | ||
290 | |||
291 | out_put_node: | ||
292 | of_node_put(np); | ||
293 | return err; | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * PSCI < v0.2 get PSCI Function IDs via DT. | ||
298 | */ | ||
299 | static int psci_0_1_init(struct device_node *np) | ||
300 | { | ||
301 | u32 id; | ||
302 | int err; | ||
303 | |||
304 | err = get_set_conduit_method(np); | ||
305 | |||
306 | if (err) | ||
307 | goto out_put_node; | ||
308 | |||
309 | pr_info("Using PSCI v0.1 Function IDs from DT\n"); | ||
310 | |||
205 | if (!of_property_read_u32(np, "cpu_suspend", &id)) { | 311 | if (!of_property_read_u32(np, "cpu_suspend", &id)) { |
206 | psci_function_id[PSCI_FN_CPU_SUSPEND] = id; | 312 | psci_function_id[PSCI_FN_CPU_SUSPEND] = id; |
207 | psci_ops.cpu_suspend = psci_cpu_suspend; | 313 | psci_ops.cpu_suspend = psci_cpu_suspend; |
@@ -224,7 +330,28 @@ void __init psci_init(void) | |||
224 | 330 | ||
225 | out_put_node: | 331 | out_put_node: |
226 | of_node_put(np); | 332 | of_node_put(np); |
227 | return; | 333 | return err; |
334 | } | ||
335 | |||
336 | static const struct of_device_id psci_of_match[] __initconst = { | ||
337 | { .compatible = "arm,psci", .data = psci_0_1_init}, | ||
338 | { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, | ||
339 | {}, | ||
340 | }; | ||
341 | |||
342 | int __init psci_init(void) | ||
343 | { | ||
344 | struct device_node *np; | ||
345 | const struct of_device_id *matched_np; | ||
346 | psci_initcall_t init_fn; | ||
347 | |||
348 | np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); | ||
349 | |||
350 | if (!np) | ||
351 | return -ENODEV; | ||
352 | |||
353 | init_fn = (psci_initcall_t)matched_np->data; | ||
354 | return init_fn(np); | ||
228 | } | 355 | } |
229 | 356 | ||
230 | #ifdef CONFIG_SMP | 357 | #ifdef CONFIG_SMP |
@@ -277,6 +404,35 @@ static void cpu_psci_cpu_die(unsigned int cpu) | |||
277 | 404 | ||
278 | pr_crit("unable to power off CPU%u (%d)\n", cpu, ret); | 405 | pr_crit("unable to power off CPU%u (%d)\n", cpu, ret); |
279 | } | 406 | } |
407 | |||
408 | static int cpu_psci_cpu_kill(unsigned int cpu) | ||
409 | { | ||
410 | int err, i; | ||
411 | |||
412 | if (!psci_ops.affinity_info) | ||
413 | return 1; | ||
414 | /* | ||
415 | * cpu_kill could race with cpu_die and we can | ||
416 | * potentially end up declaring this cpu undead | ||
417 | * while it is dying. So, try again a few times. | ||
418 | */ | ||
419 | |||
420 | for (i = 0; i < 10; i++) { | ||
421 | err = psci_ops.affinity_info(cpu_logical_map(cpu), 0); | ||
422 | if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) { | ||
423 | pr_info("CPU%d killed.\n", cpu); | ||
424 | return 1; | ||
425 | } | ||
426 | |||
427 | msleep(10); | ||
428 | pr_info("Retrying again to check for CPU kill\n"); | ||
429 | } | ||
430 | |||
431 | pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n", | ||
432 | cpu, err); | ||
433 | /* Make op_cpu_kill() fail. */ | ||
434 | return 0; | ||
435 | } | ||
280 | #endif | 436 | #endif |
281 | 437 | ||
282 | const struct cpu_operations cpu_psci_ops = { | 438 | const struct cpu_operations cpu_psci_ops = { |
@@ -287,6 +443,7 @@ const struct cpu_operations cpu_psci_ops = { | |||
287 | #ifdef CONFIG_HOTPLUG_CPU | 443 | #ifdef CONFIG_HOTPLUG_CPU |
288 | .cpu_disable = cpu_psci_cpu_disable, | 444 | .cpu_disable = cpu_psci_cpu_disable, |
289 | .cpu_die = cpu_psci_cpu_die, | 445 | .cpu_die = cpu_psci_cpu_die, |
446 | .cpu_kill = cpu_psci_cpu_kill, | ||
290 | #endif | 447 | #endif |
291 | }; | 448 | }; |
292 | 449 | ||
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index f0a141dd5655..c3cb160edc69 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c | |||
@@ -228,6 +228,19 @@ int __cpu_disable(void) | |||
228 | return 0; | 228 | return 0; |
229 | } | 229 | } |
230 | 230 | ||
231 | static int op_cpu_kill(unsigned int cpu) | ||
232 | { | ||
233 | /* | ||
234 | * If we have no means of synchronising with the dying CPU, then assume | ||
235 | * that it is really dead. We can only wait for an arbitrary length of | ||
236 | * time and hope that it's dead, so let's skip the wait and just hope. | ||
237 | */ | ||
238 | if (!cpu_ops[cpu]->cpu_kill) | ||
239 | return 1; | ||
240 | |||
241 | return cpu_ops[cpu]->cpu_kill(cpu); | ||
242 | } | ||
243 | |||
231 | static DECLARE_COMPLETION(cpu_died); | 244 | static DECLARE_COMPLETION(cpu_died); |
232 | 245 | ||
233 | /* | 246 | /* |
@@ -241,6 +254,15 @@ void __cpu_die(unsigned int cpu) | |||
241 | return; | 254 | return; |
242 | } | 255 | } |
243 | pr_notice("CPU%u: shutdown\n", cpu); | 256 | pr_notice("CPU%u: shutdown\n", cpu); |
257 | |||
258 | /* | ||
259 | * Now that the dying CPU is beyond the point of no return w.r.t. | ||
260 | * in-kernel synchronisation, try to get the firwmare to help us to | ||
261 | * verify that it has really left the kernel before we consider | ||
262 | * clobbering anything it might still be using. | ||
263 | */ | ||
264 | if (!op_cpu_kill(cpu)) | ||
265 | pr_warn("CPU%d may not have shut down cleanly\n", cpu); | ||
244 | } | 266 | } |
245 | 267 | ||
246 | /* | 268 | /* |
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 08745578d54d..60b5c31f3c10 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c | |||
@@ -214,6 +214,8 @@ int __attribute_const__ kvm_target_cpu(void) | |||
214 | return KVM_ARM_TARGET_AEM_V8; | 214 | return KVM_ARM_TARGET_AEM_V8; |
215 | case ARM_CPU_PART_FOUNDATION: | 215 | case ARM_CPU_PART_FOUNDATION: |
216 | return KVM_ARM_TARGET_FOUNDATION_V8; | 216 | return KVM_ARM_TARGET_FOUNDATION_V8; |
217 | case ARM_CPU_PART_CORTEX_A53: | ||
218 | return KVM_ARM_TARGET_CORTEX_A53; | ||
217 | case ARM_CPU_PART_CORTEX_A57: | 219 | case ARM_CPU_PART_CORTEX_A57: |
218 | return KVM_ARM_TARGET_CORTEX_A57; | 220 | return KVM_ARM_TARGET_CORTEX_A57; |
219 | }; | 221 | }; |
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 7bc41eab4c64..182415e1a952 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c | |||
@@ -30,11 +30,15 @@ typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *); | |||
30 | 30 | ||
31 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) | 31 | static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) |
32 | { | 32 | { |
33 | if (kvm_psci_call(vcpu)) | 33 | int ret; |
34 | |||
35 | ret = kvm_psci_call(vcpu); | ||
36 | if (ret < 0) { | ||
37 | kvm_inject_undefined(vcpu); | ||
34 | return 1; | 38 | return 1; |
39 | } | ||
35 | 40 | ||
36 | kvm_inject_undefined(vcpu); | 41 | return ret; |
37 | return 1; | ||
38 | } | 42 | } |
39 | 43 | ||
40 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) | 44 | static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) |
diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c index 8fe6f76b0edc..475fd2929310 100644 --- a/arch/arm64/kvm/sys_regs_generic_v8.c +++ b/arch/arm64/kvm/sys_regs_generic_v8.c | |||
@@ -88,6 +88,8 @@ static int __init sys_reg_genericv8_init(void) | |||
88 | &genericv8_target_table); | 88 | &genericv8_target_table); |
89 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_FOUNDATION_V8, | 89 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_FOUNDATION_V8, |
90 | &genericv8_target_table); | 90 | &genericv8_target_table); |
91 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A53, | ||
92 | &genericv8_target_table); | ||
91 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A57, | 93 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A57, |
92 | &genericv8_target_table); | 94 | &genericv8_target_table); |
93 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_XGENE_POTENZA, | 95 | kvm_register_target_sys_reg_table(KVM_ARM_TARGET_XGENE_POTENZA, |