Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'psci/for-rmk' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux into devel-stable

+500 -735
+9
MAINTAINERS
··· 8066 8066 F: include/linux/power_supply.h 8067 8067 F: drivers/power/ 8068 8068 8069 + POWER STATE COORDINATION INTERFACE (PSCI) 8070 + M: Mark Rutland <mark.rutland@arm.com> 8071 + M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> 8072 + L: linux-arm-kernel@lists.infradead.org 8073 + S: Maintained 8074 + F: drivers/firmware/psci.c 8075 + F: include/linux/psci.h 8076 + F: include/uapi/linux/psci.h 8077 + 8069 8078 PNP SUPPORT 8070 8079 M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> 8071 8080 S: Maintained
+1
arch/arm/Kconfig
··· 1496 1496 config ARM_PSCI 1497 1497 bool "Support for the ARM Power State Coordination Interface (PSCI)" 1498 1498 depends on CPU_V7 1499 + select ARM_PSCI_FW 1499 1500 help 1500 1501 Say Y here if you want Linux to communicate with system firmware 1501 1502 implementing the PSCI specification for CPU-centric power
-23
arch/arm/include/asm/psci.h
··· 14 14 #ifndef __ASM_ARM_PSCI_H 15 15 #define __ASM_ARM_PSCI_H 16 16 17 - #define PSCI_POWER_STATE_TYPE_STANDBY 0 18 - #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 19 - 20 - struct psci_power_state { 21 - u16 id; 22 - u8 type; 23 - u8 affinity_level; 24 - }; 25 - 26 - struct psci_operations { 27 - int (*cpu_suspend)(struct psci_power_state state, 28 - unsigned long entry_point); 29 - int (*cpu_off)(struct psci_power_state state); 30 - int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); 31 - int (*migrate)(unsigned long cpuid); 32 - int (*affinity_info)(unsigned long target_affinity, 33 - unsigned long lowest_affinity_level); 34 - int (*migrate_info_type)(void); 35 - }; 36 - 37 - extern struct psci_operations psci_ops; 38 17 extern struct smp_operations psci_smp_ops; 39 18 40 19 #ifdef CONFIG_ARM_PSCI 41 - int psci_init(void); 42 20 bool psci_smp_available(void); 43 21 #else 44 - static inline int psci_init(void) { return 0; } 45 22 static inline bool psci_smp_available(void) { return false; } 46 23 #endif 47 24
+1 -1
arch/arm/kernel/Makefile
··· 88 88 89 89 obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o 90 90 ifeq ($(CONFIG_ARM_PSCI),y) 91 - obj-y += psci.o psci-call.o 91 + obj-y += psci-call.o 92 92 obj-$(CONFIG_SMP) += psci_smp.o 93 93 endif 94 94
-299
arch/arm/kernel/psci.c
··· 1 - /* 2 - * This program is free software; you can redistribute it and/or modify 3 - * it under the terms of the GNU General Public License version 2 as 4 - * published by the Free Software Foundation. 5 - * 6 - * This program is distributed in the hope that it will be useful, 7 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 - * GNU General Public License for more details. 10 - * 11 - * Copyright (C) 2012 ARM Limited 12 - * 13 - * Author: Will Deacon <will.deacon@arm.com> 14 - */ 15 - 16 - #define pr_fmt(fmt) "psci: " fmt 17 - 18 - #include <linux/init.h> 19 - #include <linux/of.h> 20 - #include <linux/reboot.h> 21 - #include <linux/pm.h> 22 - #include <uapi/linux/psci.h> 23 - 24 - #include <asm/compiler.h> 25 - #include <asm/errno.h> 26 - #include <asm/psci.h> 27 - #include <asm/system_misc.h> 28 - 29 - struct psci_operations psci_ops; 30 - 31 - static int (*invoke_psci_fn)(u32, u32, u32, u32); 32 - typedef int (*psci_initcall_t)(const struct device_node *); 33 - 34 - asmlinkage int __invoke_psci_fn_hvc(u32, u32, u32, u32); 35 - asmlinkage int __invoke_psci_fn_smc(u32, u32, u32, u32); 36 - 37 - enum psci_function { 38 - PSCI_FN_CPU_SUSPEND, 39 - PSCI_FN_CPU_ON, 40 - PSCI_FN_CPU_OFF, 41 - PSCI_FN_MIGRATE, 42 - PSCI_FN_AFFINITY_INFO, 43 - PSCI_FN_MIGRATE_INFO_TYPE, 44 - PSCI_FN_MAX, 45 - }; 46 - 47 - static u32 psci_function_id[PSCI_FN_MAX]; 48 - 49 - static int psci_to_linux_errno(int errno) 50 - { 51 - switch (errno) { 52 - case PSCI_RET_SUCCESS: 53 - return 0; 54 - case PSCI_RET_NOT_SUPPORTED: 55 - return -EOPNOTSUPP; 56 - case PSCI_RET_INVALID_PARAMS: 57 - return -EINVAL; 58 - case PSCI_RET_DENIED: 59 - return -EPERM; 60 - }; 61 - 62 - return -EINVAL; 63 - } 64 - 65 - static u32 psci_power_state_pack(struct psci_power_state state) 66 - { 67 - return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT) 68 - & PSCI_0_2_POWER_STATE_ID_MASK) | 69 - ((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT) 70 - & PSCI_0_2_POWER_STATE_TYPE_MASK) | 71 - ((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT) 72 - & PSCI_0_2_POWER_STATE_AFFL_MASK); 73 - } 74 - 75 - static int psci_get_version(void) 76 - { 77 - int err; 78 - 79 - err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); 80 - return err; 81 - } 82 - 83 - static int psci_cpu_suspend(struct psci_power_state state, 84 - unsigned long entry_point) 85 - { 86 - int err; 87 - u32 fn, power_state; 88 - 89 - fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; 90 - power_state = psci_power_state_pack(state); 91 - err = invoke_psci_fn(fn, power_state, entry_point, 0); 92 - return psci_to_linux_errno(err); 93 - } 94 - 95 - static int psci_cpu_off(struct psci_power_state state) 96 - { 97 - int err; 98 - u32 fn, power_state; 99 - 100 - fn = psci_function_id[PSCI_FN_CPU_OFF]; 101 - power_state = psci_power_state_pack(state); 102 - err = invoke_psci_fn(fn, power_state, 0, 0); 103 - return psci_to_linux_errno(err); 104 - } 105 - 106 - static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) 107 - { 108 - int err; 109 - u32 fn; 110 - 111 - fn = psci_function_id[PSCI_FN_CPU_ON]; 112 - err = invoke_psci_fn(fn, cpuid, entry_point, 0); 113 - return psci_to_linux_errno(err); 114 - } 115 - 116 - static int psci_migrate(unsigned long cpuid) 117 - { 118 - int err; 119 - u32 fn; 120 - 121 - fn = psci_function_id[PSCI_FN_MIGRATE]; 122 - err = invoke_psci_fn(fn, cpuid, 0, 0); 123 - return psci_to_linux_errno(err); 124 - } 125 - 126 - static int psci_affinity_info(unsigned long target_affinity, 127 - unsigned long lowest_affinity_level) 128 - { 129 - int err; 130 - u32 fn; 131 - 132 - fn = psci_function_id[PSCI_FN_AFFINITY_INFO]; 133 - err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0); 134 - return err; 135 - } 136 - 137 - static int psci_migrate_info_type(void) 138 - { 139 - int err; 140 - u32 fn; 141 - 142 - fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE]; 143 - err = invoke_psci_fn(fn, 0, 0, 0); 144 - return err; 145 - } 146 - 147 - static int get_set_conduit_method(struct device_node *np) 148 - { 149 - const char *method; 150 - 151 - pr_info("probing for conduit method from DT.\n"); 152 - 153 - if (of_property_read_string(np, "method", &method)) { 154 - pr_warn("missing \"method\" property\n"); 155 - return -ENXIO; 156 - } 157 - 158 - if (!strcmp("hvc", method)) { 159 - invoke_psci_fn = __invoke_psci_fn_hvc; 160 - } else if (!strcmp("smc", method)) { 161 - invoke_psci_fn = __invoke_psci_fn_smc; 162 - } else { 163 - pr_warn("invalid \"method\" property: %s\n", method); 164 - return -EINVAL; 165 - } 166 - return 0; 167 - } 168 - 169 - static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) 170 - { 171 - invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); 172 - } 173 - 174 - static void psci_sys_poweroff(void) 175 - { 176 - invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); 177 - } 178 - 179 - /* 180 - * PSCI Function IDs for v0.2+ are well defined so use 181 - * standard values. 182 - */ 183 - static int psci_0_2_init(struct device_node *np) 184 - { 185 - int err, ver; 186 - 187 - err = get_set_conduit_method(np); 188 - 189 - if (err) 190 - goto out_put_node; 191 - 192 - ver = psci_get_version(); 193 - 194 - if (ver == PSCI_RET_NOT_SUPPORTED) { 195 - /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */ 196 - pr_err("PSCI firmware does not comply with the v0.2 spec.\n"); 197 - err = -EOPNOTSUPP; 198 - goto out_put_node; 199 - } else { 200 - pr_info("PSCIv%d.%d detected in firmware.\n", 201 - PSCI_VERSION_MAJOR(ver), 202 - PSCI_VERSION_MINOR(ver)); 203 - 204 - if (PSCI_VERSION_MAJOR(ver) == 0 && 205 - PSCI_VERSION_MINOR(ver) < 2) { 206 - err = -EINVAL; 207 - pr_err("Conflicting PSCI version detected.\n"); 208 - goto out_put_node; 209 - } 210 - } 211 - 212 - pr_info("Using standard PSCI v0.2 function IDs\n"); 213 - psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_CPU_SUSPEND; 214 - psci_ops.cpu_suspend = psci_cpu_suspend; 215 - 216 - psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; 217 - psci_ops.cpu_off = psci_cpu_off; 218 - 219 - psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_CPU_ON; 220 - psci_ops.cpu_on = psci_cpu_on; 221 - 222 - psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_MIGRATE; 223 - psci_ops.migrate = psci_migrate; 224 - 225 - psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN_AFFINITY_INFO; 226 - psci_ops.affinity_info = psci_affinity_info; 227 - 228 - psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = 229 - PSCI_0_2_FN_MIGRATE_INFO_TYPE; 230 - psci_ops.migrate_info_type = psci_migrate_info_type; 231 - 232 - arm_pm_restart = psci_sys_reset; 233 - 234 - pm_power_off = psci_sys_poweroff; 235 - 236 - out_put_node: 237 - of_node_put(np); 238 - return err; 239 - } 240 - 241 - /* 242 - * PSCI < v0.2 get PSCI Function IDs via DT. 243 - */ 244 - static int psci_0_1_init(struct device_node *np) 245 - { 246 - u32 id; 247 - int err; 248 - 249 - err = get_set_conduit_method(np); 250 - 251 - if (err) 252 - goto out_put_node; 253 - 254 - pr_info("Using PSCI v0.1 Function IDs from DT\n"); 255 - 256 - if (!of_property_read_u32(np, "cpu_suspend", &id)) { 257 - psci_function_id[PSCI_FN_CPU_SUSPEND] = id; 258 - psci_ops.cpu_suspend = psci_cpu_suspend; 259 - } 260 - 261 - if (!of_property_read_u32(np, "cpu_off", &id)) { 262 - psci_function_id[PSCI_FN_CPU_OFF] = id; 263 - psci_ops.cpu_off = psci_cpu_off; 264 - } 265 - 266 - if (!of_property_read_u32(np, "cpu_on", &id)) { 267 - psci_function_id[PSCI_FN_CPU_ON] = id; 268 - psci_ops.cpu_on = psci_cpu_on; 269 - } 270 - 271 - if (!of_property_read_u32(np, "migrate", &id)) { 272 - psci_function_id[PSCI_FN_MIGRATE] = id; 273 - psci_ops.migrate = psci_migrate; 274 - } 275 - 276 - out_put_node: 277 - of_node_put(np); 278 - return err; 279 - } 280 - 281 - static const struct of_device_id psci_of_match[] __initconst = { 282 - { .compatible = "arm,psci", .data = psci_0_1_init}, 283 - { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, 284 - {}, 285 - }; 286 - 287 - int __init psci_init(void) 288 - { 289 - struct device_node *np; 290 - const struct of_device_id *matched_np; 291 - psci_initcall_t init_fn; 292 - 293 - np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); 294 - if (!np) 295 - return -ENODEV; 296 - 297 - init_fn = (psci_initcall_t)matched_np->data; 298 - return init_fn(np); 299 - }
+23 -8
arch/arm/kernel/psci_smp.c
··· 17 17 #include <linux/smp.h> 18 18 #include <linux/of.h> 19 19 #include <linux/delay.h> 20 + #include <linux/psci.h> 21 + 20 22 #include <uapi/linux/psci.h> 21 23 22 24 #include <asm/psci.h> ··· 53 51 { 54 52 if (psci_ops.cpu_on) 55 53 return psci_ops.cpu_on(cpu_logical_map(cpu), 56 - __pa(secondary_startup)); 54 + virt_to_idmap(&secondary_startup)); 57 55 return -ENODEV; 58 56 } 59 57 60 58 #ifdef CONFIG_HOTPLUG_CPU 59 + int psci_cpu_disable(unsigned int cpu) 60 + { 61 + /* Fail early if we don't have CPU_OFF support */ 62 + if (!psci_ops.cpu_off) 63 + return -EOPNOTSUPP; 64 + 65 + /* Trusted OS will deny CPU_OFF */ 66 + if (psci_tos_resident_on(cpu)) 67 + return -EPERM; 68 + 69 + return 0; 70 + } 71 + 61 72 void __ref psci_cpu_die(unsigned int cpu) 62 73 { 63 - const struct psci_power_state ps = { 64 - .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, 65 - }; 74 + u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN << 75 + PSCI_0_2_POWER_STATE_TYPE_SHIFT; 66 76 67 - if (psci_ops.cpu_off) 68 - psci_ops.cpu_off(ps); 77 + if (psci_ops.cpu_off) 78 + psci_ops.cpu_off(state); 69 79 70 - /* We should never return */ 71 - panic("psci: cpu %d failed to shutdown\n", cpu); 80 + /* We should never return */ 81 + panic("psci: cpu %d failed to shutdown\n", cpu); 72 82 } 73 83 74 84 int __ref psci_cpu_kill(unsigned int cpu) ··· 123 109 struct smp_operations __initdata psci_smp_ops = { 124 110 .smp_boot_secondary = psci_boot_secondary, 125 111 #ifdef CONFIG_HOTPLUG_CPU 112 + .cpu_disable = psci_cpu_disable, 126 113 .cpu_die = psci_cpu_die, 127 114 .cpu_kill = psci_cpu_kill, 128 115 #endif
+2 -1
arch/arm/kernel/setup.c
··· 31 31 #include <linux/bug.h> 32 32 #include <linux/compiler.h> 33 33 #include <linux/sort.h> 34 + #include <linux/psci.h> 34 35 35 36 #include <asm/unified.h> 36 37 #include <asm/cp15.h> ··· 973 972 unflatten_device_tree(); 974 973 975 974 arm_dt_init_cpu_maps(); 976 - psci_init(); 975 + psci_dt_init(); 977 976 xen_early_init(); 978 977 #ifdef CONFIG_SMP 979 978 if (is_smp()) {
+1 -1
arch/arm/mach-highbank/highbank.c
··· 28 28 #include <linux/reboot.h> 29 29 #include <linux/amba/bus.h> 30 30 #include <linux/platform_device.h> 31 + #include <linux/psci.h> 31 32 32 - #include <asm/psci.h> 33 33 #include <asm/hardware/cache-l2x0.h> 34 34 #include <asm/mach/arch.h> 35 35 #include <asm/mach/map.h>
+9 -7
arch/arm/mach-highbank/pm.c
··· 16 16 17 17 #include <linux/cpu_pm.h> 18 18 #include <linux/init.h> 19 + #include <linux/psci.h> 19 20 #include <linux/suspend.h> 20 21 21 22 #include <asm/suspend.h> 22 - #include <asm/psci.h> 23 + 24 + #include <uapi/linux/psci.h> 25 + 26 + #define HIGHBANK_SUSPEND_PARAM \ 27 + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ 28 + (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ 29 + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) 23 30 24 31 static int highbank_suspend_finish(unsigned long val) 25 32 { 26 - const struct psci_power_state ps = { 27 - .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, 28 - .affinity_level = 1, 29 - }; 30 - 31 - return psci_ops.cpu_suspend(ps, __pa(cpu_resume)); 33 + return psci_ops.cpu_suspend(HIGHBANK_SUSPEND_PARAM, __pa(cpu_resume)); 32 34 } 33 35 34 36 static int highbank_pm_enter(suspend_state_t state)
+1
arch/arm64/Kconfig
··· 20 20 select ARM_GIC_V2M if PCI_MSI 21 21 select ARM_GIC_V3 22 22 select ARM_GIC_V3_ITS if PCI_MSI 23 + select ARM_PSCI_FW 23 24 select BUILDTIME_EXTABLE_SORT 24 25 select CLONE_BACKWARDS 25 26 select COMMON_CLK
+2 -2
arch/arm64/include/asm/acpi.h
··· 12 12 #ifndef _ASM_ACPI_H 13 13 #define _ASM_ACPI_H 14 14 15 - #include <linux/mm.h> 16 15 #include <linux/irqchip/arm-gic-acpi.h> 16 + #include <linux/mm.h> 17 + #include <linux/psci.h> 17 18 18 19 #include <asm/cputype.h> 19 - #include <asm/psci.h> 20 20 #include <asm/smp_plat.h> 21 21 22 22 /* Macros for consistency checks of the GICC subtable of MADT */
-28
arch/arm64/include/asm/psci.h
··· 1 - /* 2 - * This program is free software; you can redistribute it and/or modify 3 - * it under the terms of the GNU General Public License version 2 as 4 - * published by the Free Software Foundation. 5 - * 6 - * This program is distributed in the hope that it will be useful, 7 - * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 - * GNU General Public License for more details. 10 - * 11 - * Copyright (C) 2013 ARM Limited 12 - */ 13 - 14 - #ifndef __ASM_PSCI_H 15 - #define __ASM_PSCI_H 16 - 17 - int __init psci_dt_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 27 - 28 - #endif /* __ASM_PSCI_H */
+2 -359
arch/arm64/kernel/psci.c
··· 18 18 #include <linux/init.h> 19 19 #include <linux/of.h> 20 20 #include <linux/smp.h> 21 - #include <linux/reboot.h> 22 - #include <linux/pm.h> 23 21 #include <linux/delay.h> 22 + #include <linux/psci.h> 24 23 #include <linux/slab.h> 24 + 25 25 #include <uapi/linux/psci.h> 26 26 27 27 #include <asm/compiler.h> 28 - #include <asm/cputype.h> 29 28 #include <asm/cpu_ops.h> 30 29 #include <asm/errno.h> 31 - #include <asm/psci.h> 32 30 #include <asm/smp_plat.h> 33 31 #include <asm/suspend.h> 34 - #include <asm/system_misc.h> 35 - 36 - #define PSCI_POWER_STATE_TYPE_STANDBY 0 37 - #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 38 32 39 33 static bool psci_power_state_loses_context(u32 state) 40 34 { ··· 44 50 return !(state & ~valid_mask); 45 51 } 46 52 47 - /* 48 - * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF 49 - * calls to its resident CPU, so we must avoid issuing those. We never migrate 50 - * a Trusted OS even if it claims to be capable of migration -- doing so will 51 - * require cooperation with a Trusted OS driver. 52 - */ 53 - static int resident_cpu = -1; 54 - 55 - struct psci_operations { 56 - int (*cpu_suspend)(u32 state, unsigned long entry_point); 57 - int (*cpu_off)(u32 state); 58 - int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); 59 - int (*migrate)(unsigned long cpuid); 60 - int (*affinity_info)(unsigned long target_affinity, 61 - unsigned long lowest_affinity_level); 62 - int (*migrate_info_type)(void); 63 - }; 64 - 65 - static struct psci_operations psci_ops; 66 - 67 - typedef unsigned long (psci_fn)(unsigned long, unsigned long, 68 - unsigned long, unsigned long); 69 - asmlinkage psci_fn __invoke_psci_fn_hvc; 70 - asmlinkage psci_fn __invoke_psci_fn_smc; 71 - static psci_fn *invoke_psci_fn; 72 - 73 - enum psci_function { 74 - PSCI_FN_CPU_SUSPEND, 75 - PSCI_FN_CPU_ON, 76 - PSCI_FN_CPU_OFF, 77 - PSCI_FN_MIGRATE, 78 - PSCI_FN_MAX, 79 - }; 80 - 81 53 static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); 82 - 83 - static u32 psci_function_id[PSCI_FN_MAX]; 84 - 85 - static int psci_to_linux_errno(int errno) 86 - { 87 - switch (errno) { 88 - case PSCI_RET_SUCCESS: 89 - return 0; 90 - case PSCI_RET_NOT_SUPPORTED: 91 - return -EOPNOTSUPP; 92 - case PSCI_RET_INVALID_PARAMS: 93 - return -EINVAL; 94 - case PSCI_RET_DENIED: 95 - return -EPERM; 96 - }; 97 - 98 - return -EINVAL; 99 - } 100 - 101 - static u32 psci_get_version(void) 102 - { 103 - return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); 104 - } 105 - 106 - static int psci_cpu_suspend(u32 state, unsigned long entry_point) 107 - { 108 - int err; 109 - u32 fn; 110 - 111 - fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; 112 - err = invoke_psci_fn(fn, state, entry_point, 0); 113 - return psci_to_linux_errno(err); 114 - } 115 - 116 - static int psci_cpu_off(u32 state) 117 - { 118 - int err; 119 - u32 fn; 120 - 121 - fn = psci_function_id[PSCI_FN_CPU_OFF]; 122 - err = invoke_psci_fn(fn, state, 0, 0); 123 - return psci_to_linux_errno(err); 124 - } 125 - 126 - static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) 127 - { 128 - int err; 129 - u32 fn; 130 - 131 - fn = psci_function_id[PSCI_FN_CPU_ON]; 132 - err = invoke_psci_fn(fn, cpuid, entry_point, 0); 133 - return psci_to_linux_errno(err); 134 - } 135 - 136 - static int psci_migrate(unsigned long cpuid) 137 - { 138 - int err; 139 - u32 fn; 140 - 141 - fn = psci_function_id[PSCI_FN_MIGRATE]; 142 - err = invoke_psci_fn(fn, cpuid, 0, 0); 143 - return psci_to_linux_errno(err); 144 - } 145 - 146 - static int psci_affinity_info(unsigned long target_affinity, 147 - unsigned long lowest_affinity_level) 148 - { 149 - return invoke_psci_fn(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, 150 - lowest_affinity_level, 0); 151 - } 152 - 153 - static int psci_migrate_info_type(void) 154 - { 155 - return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0); 156 - } 157 - 158 - static unsigned long psci_migrate_info_up_cpu(void) 159 - { 160 - return invoke_psci_fn(PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU, 0, 0, 0); 161 - } 162 54 163 55 static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu) 164 56 { ··· 110 230 return ret; 111 231 } 112 232 113 - static int get_set_conduit_method(struct device_node *np) 114 - { 115 - const char *method; 116 - 117 - pr_info("probing for conduit method from DT.\n"); 118 - 119 - if (of_property_read_string(np, "method", &method)) { 120 - pr_warn("missing \"method\" property\n"); 121 - return -ENXIO; 122 - } 123 - 124 - if (!strcmp("hvc", method)) { 125 - invoke_psci_fn = __invoke_psci_fn_hvc; 126 - } else if (!strcmp("smc", method)) { 127 - invoke_psci_fn = __invoke_psci_fn_smc; 128 - } else { 129 - pr_warn("invalid \"method\" property: %s\n", method); 130 - return -EINVAL; 131 - } 132 - return 0; 133 - } 134 - 135 - static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) 136 - { 137 - invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); 138 - } 139 - 140 - static void psci_sys_poweroff(void) 141 - { 142 - invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); 143 - } 144 - 145 - /* 146 - * Detect the presence of a resident Trusted OS which may cause CPU_OFF to 147 - * return DENIED (which would be fatal). 148 - */ 149 - static void __init psci_init_migrate(void) 150 - { 151 - unsigned long cpuid; 152 - int type, cpu; 153 - 154 - type = psci_ops.migrate_info_type(); 155 - 156 - if (type == PSCI_0_2_TOS_MP) { 157 - pr_info("Trusted OS migration not required\n"); 158 - return; 159 - } 160 - 161 - if (type == PSCI_RET_NOT_SUPPORTED) { 162 - pr_info("MIGRATE_INFO_TYPE not supported.\n"); 163 - return; 164 - } 165 - 166 - if (type != PSCI_0_2_TOS_UP_MIGRATE && 167 - type != PSCI_0_2_TOS_UP_NO_MIGRATE) { 168 - pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type); 169 - return; 170 - } 171 - 172 - cpuid = psci_migrate_info_up_cpu(); 173 - if (cpuid & ~MPIDR_HWID_BITMASK) { 174 - pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n", 175 - cpuid); 176 - return; 177 - } 178 - 179 - cpu = get_logical_index(cpuid); 180 - resident_cpu = cpu >= 0 ? cpu : -1; 181 - 182 - pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); 183 - } 184 - 185 - static void __init psci_0_2_set_functions(void) 186 - { 187 - pr_info("Using standard PSCI v0.2 function IDs\n"); 188 - psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND; 189 - psci_ops.cpu_suspend = psci_cpu_suspend; 190 - 191 - psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; 192 - psci_ops.cpu_off = psci_cpu_off; 193 - 194 - psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON; 195 - psci_ops.cpu_on = psci_cpu_on; 196 - 197 - psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE; 198 - psci_ops.migrate = psci_migrate; 199 - 200 - psci_ops.affinity_info = psci_affinity_info; 201 - 202 - psci_ops.migrate_info_type = psci_migrate_info_type; 203 - 204 - arm_pm_restart = psci_sys_reset; 205 - 206 - pm_power_off = psci_sys_poweroff; 207 - } 208 - 209 - /* 210 - * Probe function for PSCI firmware versions >= 0.2 211 - */ 212 - static int __init psci_probe(void) 213 - { 214 - u32 ver = psci_get_version(); 215 - 216 - pr_info("PSCIv%d.%d detected in firmware.\n", 217 - PSCI_VERSION_MAJOR(ver), 218 - PSCI_VERSION_MINOR(ver)); 219 - 220 - if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { 221 - pr_err("Conflicting PSCI version detected.\n"); 222 - return -EINVAL; 223 - } 224 - 225 - psci_0_2_set_functions(); 226 - 227 - psci_init_migrate(); 228 - 229 - return 0; 230 - } 231 - 232 - typedef int (*psci_initcall_t)(const struct device_node *); 233 - 234 - /* 235 - * PSCI init function for PSCI versions >=0.2 236 - * 237 - * Probe based on PSCI PSCI_VERSION function 238 - */ 239 - static int __init psci_0_2_init(struct device_node *np) 240 - { 241 - int err; 242 - 243 - err = get_set_conduit_method(np); 244 - 245 - if (err) 246 - goto out_put_node; 247 - /* 248 - * Starting with v0.2, the PSCI specification introduced a call 249 - * (PSCI_VERSION) that allows probing the firmware version, so 250 - * that PSCI function IDs and version specific initialization 251 - * can be carried out according to the specific version reported 252 - * by firmware 253 - */ 254 - err = psci_probe(); 255 - 256 - out_put_node: 257 - of_node_put(np); 258 - return err; 259 - } 260 - 261 - /* 262 - * PSCI < v0.2 get PSCI Function IDs via DT. 263 - */ 264 - static int __init psci_0_1_init(struct device_node *np) 265 - { 266 - u32 id; 267 - int err; 268 - 269 - err = get_set_conduit_method(np); 270 - 271 - if (err) 272 - goto out_put_node; 273 - 274 - pr_info("Using PSCI v0.1 Function IDs from DT\n"); 275 - 276 - if (!of_property_read_u32(np, "cpu_suspend", &id)) { 277 - psci_function_id[PSCI_FN_CPU_SUSPEND] = id; 278 - psci_ops.cpu_suspend = psci_cpu_suspend; 279 - } 280 - 281 - if (!of_property_read_u32(np, "cpu_off", &id)) { 282 - psci_function_id[PSCI_FN_CPU_OFF] = id; 283 - psci_ops.cpu_off = psci_cpu_off; 284 - } 285 - 286 - if (!of_property_read_u32(np, "cpu_on", &id)) { 287 - psci_function_id[PSCI_FN_CPU_ON] = id; 288 - psci_ops.cpu_on = psci_cpu_on; 289 - } 290 - 291 - if (!of_property_read_u32(np, "migrate", &id)) { 292 - psci_function_id[PSCI_FN_MIGRATE] = id; 293 - psci_ops.migrate = psci_migrate; 294 - } 295 - 296 - out_put_node: 297 - of_node_put(np); 298 - return err; 299 - } 300 - 301 - static const struct of_device_id psci_of_match[] __initconst = { 302 - { .compatible = "arm,psci", .data = psci_0_1_init}, 303 - { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, 304 - {}, 305 - }; 306 - 307 - int __init psci_dt_init(void) 308 - { 309 - struct device_node *np; 310 - const struct of_device_id *matched_np; 311 - psci_initcall_t init_fn; 312 - 313 - np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); 314 - 315 - if (!np) 316 - return -ENODEV; 317 - 318 - init_fn = (psci_initcall_t)matched_np->data; 319 - return init_fn(np); 320 - } 321 - 322 - #ifdef CONFIG_ACPI 323 - /* 324 - * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's 325 - * explicitly clarified in SBBR 326 - */ 327 - int __init psci_acpi_init(void) 328 - { 329 - if (!acpi_psci_present()) { 330 - pr_info("is not implemented in ACPI.\n"); 331 - return -EOPNOTSUPP; 332 - } 333 - 334 - pr_info("probing for conduit method from ACPI.\n"); 335 - 336 - if (acpi_psci_use_hvc()) 337 - invoke_psci_fn = __invoke_psci_fn_hvc; 338 - else 339 - invoke_psci_fn = __invoke_psci_fn_smc; 340 - 341 - return psci_probe(); 342 - } 343 - #endif 344 - 345 233 #ifdef CONFIG_SMP 346 234 347 235 static int __init cpu_psci_cpu_init(unsigned int cpu) ··· 137 489 } 138 490 139 491 #ifdef CONFIG_HOTPLUG_CPU 140 - static bool psci_tos_resident_on(int cpu) 141 - { 142 - return cpu == resident_cpu; 143 - } 144 - 145 492 static int cpu_psci_cpu_disable(unsigned int cpu) 146 493 { 147 494 /* Fail early if we don't have CPU_OFF support */
+1 -1
arch/arm64/kernel/setup.c
··· 46 46 #include <linux/of_platform.h> 47 47 #include <linux/efi.h> 48 48 #include <linux/personality.h> 49 + #include <linux/psci.h> 49 50 50 51 #include <asm/acpi.h> 51 52 #include <asm/fixmap.h> ··· 62 61 #include <asm/tlbflush.h> 63 62 #include <asm/traps.h> 64 63 #include <asm/memblock.h> 65 - #include <asm/psci.h> 66 64 #include <asm/efi.h> 67 65 #include <asm/virt.h> 68 66 #include <asm/xen/hypervisor.h>
+10 -5
drivers/cpuidle/cpuidle-calxeda.c
··· 25 25 #include <linux/init.h> 26 26 #include <linux/mm.h> 27 27 #include <linux/platform_device.h> 28 + #include <linux/psci.h> 29 + 28 30 #include <asm/cpuidle.h> 29 31 #include <asm/suspend.h> 30 - #include <asm/psci.h> 32 + 33 + #include <uapi/linux/psci.h> 34 + 35 + #define CALXEDA_IDLE_PARAM \ 36 + ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \ 37 + (0 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \ 38 + (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT)) 31 39 32 40 static int calxeda_idle_finish(unsigned long val) 33 41 { 34 - const struct psci_power_state ps = { 35 - .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, 36 - }; 37 - return psci_ops.cpu_suspend(ps, __pa(cpu_resume)); 42 + return psci_ops.cpu_suspend(CALXEDA_IDLE_PARAM, __pa(cpu_resume)); 38 43 } 39 44 40 45 static int calxeda_pwrdown_idle(struct cpuidle_device *dev,
+3
drivers/firmware/Kconfig
··· 5 5 6 6 menu "Firmware Drivers" 7 7 8 + config ARM_PSCI_FW 9 + bool 10 + 8 11 config EDD 9 12 tristate "BIOS Enhanced Disk Drive calls determine boot disk" 10 13 depends on X86
+1
drivers/firmware/Makefile
··· 1 1 # 2 2 # Makefile for the linux kernel. 3 3 # 4 + obj-$(CONFIG_ARM_PSCI_FW) += psci.o 4 5 obj-$(CONFIG_DMI) += dmi_scan.o 5 6 obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o 6 7 obj-$(CONFIG_EDD) += edd.o
+382
drivers/firmware/psci.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License version 2 as 4 + * published by the Free Software Foundation. 5 + * 6 + * This program is distributed in the hope that it will be useful, 7 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 + * GNU General Public License for more details. 10 + * 11 + * Copyright (C) 2015 ARM Limited 12 + */ 13 + 14 + #define pr_fmt(fmt) "psci: " fmt 15 + 16 + #include <linux/errno.h> 17 + #include <linux/linkage.h> 18 + #include <linux/of.h> 19 + #include <linux/pm.h> 20 + #include <linux/printk.h> 21 + #include <linux/psci.h> 22 + #include <linux/reboot.h> 23 + 24 + #include <uapi/linux/psci.h> 25 + 26 + #include <asm/cputype.h> 27 + #include <asm/system_misc.h> 28 + #include <asm/smp_plat.h> 29 + 30 + /* 31 + * While a 64-bit OS can make calls with SMC32 calling conventions, for some 32 + * calls it is necessary to use SMC64 to pass or return 64-bit values. For such 33 + * calls PSCI_0_2_FN_NATIVE(x) will choose the appropriate (native-width) 34 + * function ID. 35 + */ 36 + #ifdef CONFIG_64BIT 37 + #define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN64_##name 38 + #else 39 + #define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN_##name 40 + #endif 41 + 42 + /* 43 + * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF 44 + * calls to its resident CPU, so we must avoid issuing those. We never migrate 45 + * a Trusted OS even if it claims to be capable of migration -- doing so will 46 + * require cooperation with a Trusted OS driver. 47 + */ 48 + static int resident_cpu = -1; 49 + 50 + bool psci_tos_resident_on(int cpu) 51 + { 52 + return cpu == resident_cpu; 53 + } 54 + 55 + struct psci_operations psci_ops; 56 + 57 + typedef unsigned long (psci_fn)(unsigned long, unsigned long, 58 + unsigned long, unsigned long); 59 + asmlinkage psci_fn __invoke_psci_fn_hvc; 60 + asmlinkage psci_fn __invoke_psci_fn_smc; 61 + static psci_fn *invoke_psci_fn; 62 + 63 + enum psci_function { 64 + PSCI_FN_CPU_SUSPEND, 65 + PSCI_FN_CPU_ON, 66 + PSCI_FN_CPU_OFF, 67 + PSCI_FN_MIGRATE, 68 + PSCI_FN_MAX, 69 + }; 70 + 71 + static u32 psci_function_id[PSCI_FN_MAX]; 72 + 73 + static int psci_to_linux_errno(int errno) 74 + { 75 + switch (errno) { 76 + case PSCI_RET_SUCCESS: 77 + return 0; 78 + case PSCI_RET_NOT_SUPPORTED: 79 + return -EOPNOTSUPP; 80 + case PSCI_RET_INVALID_PARAMS: 81 + return -EINVAL; 82 + case PSCI_RET_DENIED: 83 + return -EPERM; 84 + }; 85 + 86 + return -EINVAL; 87 + } 88 + 89 + static u32 psci_get_version(void) 90 + { 91 + return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); 92 + } 93 + 94 + static int psci_cpu_suspend(u32 state, unsigned long entry_point) 95 + { 96 + int err; 97 + u32 fn; 98 + 99 + fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; 100 + err = invoke_psci_fn(fn, state, entry_point, 0); 101 + return psci_to_linux_errno(err); 102 + } 103 + 104 + static int psci_cpu_off(u32 state) 105 + { 106 + int err; 107 + u32 fn; 108 + 109 + fn = psci_function_id[PSCI_FN_CPU_OFF]; 110 + err = invoke_psci_fn(fn, state, 0, 0); 111 + return psci_to_linux_errno(err); 112 + } 113 + 114 + static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) 115 + { 116 + int err; 117 + u32 fn; 118 + 119 + fn = psci_function_id[PSCI_FN_CPU_ON]; 120 + err = invoke_psci_fn(fn, cpuid, entry_point, 0); 121 + return psci_to_linux_errno(err); 122 + } 123 + 124 + static int psci_migrate(unsigned long cpuid) 125 + { 126 + int err; 127 + u32 fn; 128 + 129 + fn = psci_function_id[PSCI_FN_MIGRATE]; 130 + err = invoke_psci_fn(fn, cpuid, 0, 0); 131 + return psci_to_linux_errno(err); 132 + } 133 + 134 + static int psci_affinity_info(unsigned long target_affinity, 135 + unsigned long lowest_affinity_level) 136 + { 137 + return invoke_psci_fn(PSCI_0_2_FN_NATIVE(AFFINITY_INFO), 138 + target_affinity, lowest_affinity_level, 0); 139 + } 140 + 141 + static int psci_migrate_info_type(void) 142 + { 143 + return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0); 144 + } 145 + 146 + static unsigned long psci_migrate_info_up_cpu(void) 147 + { 148 + return invoke_psci_fn(PSCI_0_2_FN_NATIVE(MIGRATE_INFO_UP_CPU), 149 + 0, 0, 0); 150 + } 151 + 152 + static int get_set_conduit_method(struct device_node *np) 153 + { 154 + const char *method; 155 + 156 + pr_info("probing for conduit method from DT.\n"); 157 + 158 + if (of_property_read_string(np, "method", &method)) { 159 + pr_warn("missing \"method\" property\n"); 160 + return -ENXIO; 161 + } 162 + 163 + if (!strcmp("hvc", method)) { 164 + invoke_psci_fn = __invoke_psci_fn_hvc; 165 + } else if (!strcmp("smc", method)) { 166 + invoke_psci_fn = __invoke_psci_fn_smc; 167 + } else { 168 + pr_warn("invalid \"method\" property: %s\n", method); 169 + return -EINVAL; 170 + } 171 + return 0; 172 + } 173 + 174 + static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) 175 + { 176 + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); 177 + } 178 + 179 + static void psci_sys_poweroff(void) 180 + { 181 + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); 182 + } 183 + 184 + /* 185 + * Detect the presence of a resident Trusted OS which may cause CPU_OFF to 186 + * return DENIED (which would be fatal). 187 + */ 188 + static void __init psci_init_migrate(void) 189 + { 190 + unsigned long cpuid; 191 + int type, cpu = -1; 192 + 193 + type = psci_ops.migrate_info_type(); 194 + 195 + if (type == PSCI_0_2_TOS_MP) { 196 + pr_info("Trusted OS migration not required\n"); 197 + return; 198 + } 199 + 200 + if (type == PSCI_RET_NOT_SUPPORTED) { 201 + pr_info("MIGRATE_INFO_TYPE not supported.\n"); 202 + return; 203 + } 204 + 205 + if (type != PSCI_0_2_TOS_UP_MIGRATE && 206 + type != PSCI_0_2_TOS_UP_NO_MIGRATE) { 207 + pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type); 208 + return; 209 + } 210 + 211 + cpuid = psci_migrate_info_up_cpu(); 212 + if (cpuid & ~MPIDR_HWID_BITMASK) { 213 + pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n", 214 + cpuid); 215 + return; 216 + } 217 + 218 + cpu = get_logical_index(cpuid); 219 + resident_cpu = cpu >= 0 ? cpu : -1; 220 + 221 + pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); 222 + } 223 + 224 + static void __init psci_0_2_set_functions(void) 225 + { 226 + pr_info("Using standard PSCI v0.2 function IDs\n"); 227 + psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_NATIVE(CPU_SUSPEND); 228 + psci_ops.cpu_suspend = psci_cpu_suspend; 229 + 230 + psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; 231 + psci_ops.cpu_off = psci_cpu_off; 232 + 233 + psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_NATIVE(CPU_ON); 234 + psci_ops.cpu_on = psci_cpu_on; 235 + 236 + psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_NATIVE(MIGRATE); 237 + psci_ops.migrate = psci_migrate; 238 + 239 + psci_ops.affinity_info = psci_affinity_info; 240 + 241 + psci_ops.migrate_info_type = psci_migrate_info_type; 242 + 243 + arm_pm_restart = psci_sys_reset; 244 + 245 + pm_power_off = psci_sys_poweroff; 246 + } 247 + 248 + /* 249 + * Probe function for PSCI firmware versions >= 0.2 250 + */ 251 + static int __init psci_probe(void) 252 + { 253 + u32 ver = psci_get_version(); 254 + 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 && PSCI_VERSION_MINOR(ver) < 2) { 260 + pr_err("Conflicting PSCI version detected.\n"); 261 + return -EINVAL; 262 + } 263 + 264 + psci_0_2_set_functions(); 265 + 266 + psci_init_migrate(); 267 + 268 + return 0; 269 + } 270 + 271 + typedef int (*psci_initcall_t)(const struct device_node *); 272 + 273 + /* 274 + * PSCI init function for PSCI versions >=0.2 275 + * 276 + * Probe based on PSCI PSCI_VERSION function 277 + */ 278 + static int __init psci_0_2_init(struct device_node *np) 279 + { 280 + int err; 281 + 282 + err = get_set_conduit_method(np); 283 + 284 + if (err) 285 + goto out_put_node; 286 + /* 287 + * Starting with v0.2, the PSCI specification introduced a call 288 + * (PSCI_VERSION) that allows probing the firmware version, so 289 + * that PSCI function IDs and version specific initialization 290 + * can be carried out according to the specific version reported 291 + * by firmware 292 + */ 293 + err = psci_probe(); 294 + 295 + out_put_node: 296 + of_node_put(np); 297 + return err; 298 + } 299 + 300 + /* 301 + * PSCI < v0.2 get PSCI Function IDs via DT. 302 + */ 303 + static int __init psci_0_1_init(struct device_node *np) 304 + { 305 + u32 id; 306 + int err; 307 + 308 + err = get_set_conduit_method(np); 309 + 310 + if (err) 311 + goto out_put_node; 312 + 313 + pr_info("Using PSCI v0.1 Function IDs from DT\n"); 314 + 315 + if (!of_property_read_u32(np, "cpu_suspend", &id)) { 316 + psci_function_id[PSCI_FN_CPU_SUSPEND] = id; 317 + psci_ops.cpu_suspend = psci_cpu_suspend; 318 + } 319 + 320 + if (!of_property_read_u32(np, "cpu_off", &id)) { 321 + psci_function_id[PSCI_FN_CPU_OFF] = id; 322 + psci_ops.cpu_off = psci_cpu_off; 323 + } 324 + 325 + if (!of_property_read_u32(np, "cpu_on", &id)) { 326 + psci_function_id[PSCI_FN_CPU_ON] = id; 327 + psci_ops.cpu_on = psci_cpu_on; 328 + } 329 + 330 + if (!of_property_read_u32(np, "migrate", &id)) { 331 + psci_function_id[PSCI_FN_MIGRATE] = id; 332 + psci_ops.migrate = psci_migrate; 333 + } 334 + 335 + out_put_node: 336 + of_node_put(np); 337 + return err; 338 + } 339 + 340 + static const struct of_device_id psci_of_match[] __initconst = { 341 + { .compatible = "arm,psci", .data = psci_0_1_init}, 342 + { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, 343 + {}, 344 + }; 345 + 346 + int __init psci_dt_init(void) 347 + { 348 + struct device_node *np; 349 + const struct of_device_id *matched_np; 350 + psci_initcall_t init_fn; 351 + 352 + np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); 353 + 354 + if (!np) 355 + return -ENODEV; 356 + 357 + init_fn = (psci_initcall_t)matched_np->data; 358 + return init_fn(np); 359 + } 360 + 361 + #ifdef CONFIG_ACPI 362 + /* 363 + * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's 364 + * explicitly clarified in SBBR 365 + */ 366 + int __init psci_acpi_init(void) 367 + { 368 + if (!acpi_psci_present()) { 369 + pr_info("is not implemented in ACPI.\n"); 370 + return -EOPNOTSUPP; 371 + } 372 + 373 + pr_info("probing for conduit method from ACPI.\n"); 374 + 375 + if (acpi_psci_use_hvc()) 376 + invoke_psci_fn = __invoke_psci_fn_hvc; 377 + else 378 + invoke_psci_fn = __invoke_psci_fn_smc; 379 + 380 + return psci_probe(); 381 + } 382 + #endif
+52
include/linux/psci.h
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License version 2 as 4 + * published by the Free Software Foundation. 5 + * 6 + * This program is distributed in the hope that it will be useful, 7 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 8 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 + * GNU General Public License for more details. 10 + * 11 + * Copyright (C) 2015 ARM Limited 12 + */ 13 + 14 + #ifndef __LINUX_PSCI_H 15 + #define __LINUX_PSCI_H 16 + 17 + #include <linux/init.h> 18 + #include <linux/types.h> 19 + 20 + #define PSCI_POWER_STATE_TYPE_STANDBY 0 21 + #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 22 + 23 + bool psci_tos_resident_on(int cpu); 24 + 25 + struct psci_operations { 26 + int (*cpu_suspend)(u32 state, unsigned long entry_point); 27 + int (*cpu_off)(u32 state); 28 + int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); 29 + int (*migrate)(unsigned long cpuid); 30 + int (*affinity_info)(unsigned long target_affinity, 31 + unsigned long lowest_affinity_level); 32 + int (*migrate_info_type)(void); 33 + }; 34 + 35 + extern struct psci_operations psci_ops; 36 + 37 + #if defined(CONFIG_ARM_PSCI_FW) 38 + int __init psci_dt_init(void); 39 + #else 40 + static inline int psci_dt_init(void) { return 0; } 41 + #endif 42 + 43 + #if defined(CONFIG_ARM_PSCI_FW) && defined(CONFIG_ACPI) 44 + int __init psci_acpi_init(void); 45 + bool __init acpi_psci_present(void); 46 + bool __init acpi_psci_use_hvc(void); 47 + #else 48 + static inline int psci_acpi_init(void) { return 0; } 49 + static inline bool acpi_psci_present(void) { return false; } 50 + #endif 51 + 52 + #endif /* __LINUX_PSCI_H */