arm/arm64: Unify PSCI client support
Subsystems (6)
Mark Rutland
maintainercover arm/arm64: Unify PSCI client support
This series unifies the 32-bit and 64-bit PSCI client code, moving the bulk of the FW invocation and probing out to a common locaiton in drivers/firmware. As part of this, the remaining edge cases for PSCI 0.2 (Trusted OSs rejecting CPU_OFF) are accounted for, maknig both 32-bit adn 64-bit clients more robust.
This results in a reasonable saving in terms of lines of code, and will allow for PSCI 1.0 support to be unified form the beginning, avoiding further duplication.
The series is based on v4.0-rc2.
Thanks,
Mark.
Mark Rutland (12):
arm/arm64: kvm: add missing PSCI include
arm64: smp_plat: add get_logical_index
arm64: smp: consistently use error codes
arm64: psci: remove unnecessary id indirection
arm64: psci: support unsigned return values
arm64: psci: account for Trusted OS instances
arm64: psci: kill psci_power_state
arm64: psci: remove ACPI coupling
arm64: psci: factor invocation code to drivers
drivers: psci: support native SMC{32,64} calls
ARM: migrate to common PSCI client code
MAINTAINERS: add PSCI entry
MAINTAINERS | 9 + arch/arm/Kconfig | 1 + arch/arm/include/asm/psci.h | 23 --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/psci.c | 299 ---------------------------- arch/arm/kernel/psci_smp.c | 29 ++- arch/arm/kernel/setup.c | 3 +- arch/arm/kvm/psci.c | 2 + arch/arm/mach-highbank/highbank.c | 2 +- arch/arm/mach-highbank/pm.c | 8 +- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/acpi.h | 14 -- arch/arm64/include/asm/psci.h | 20 -- arch/arm64/include/asm/smp_plat.h | 16 ++ arch/arm64/kernel/acpi.c | 11 ++ arch/arm64/kernel/psci.c | 398 ++++---------------------------------- arch/arm64/kernel/setup.c | 2 +- arch/arm64/kernel/smp.c | 10 +- drivers/cpuidle/cpuidle-calxeda.c | 7 +- drivers/firmware/Kconfig | 3 + drivers/firmware/Makefile | 1 + drivers/firmware/psci.c | 377 ++++++++++++++++++++++++++++++++++++ include/linux/psci.h | 48 +++++ 23 files changed, 541 insertions(+), 745 deletions(-) delete mode 100644 arch/arm/kernel/psci.c delete mode 100644 arch/arm64/include/asm/psci.h create mode 100644 drivers/firmware/psci.c create mode 100644 include/linux/psci.h
Signature · 1 line
1.9.1
Mark Rutland
maintainerPATCH 1/12 arm/arm64: kvm: add missing PSCI include
We make use of the PSCI function IDs, but don't explicitly include the header which defines them. Relying on transitive header includes is fragile and will be broken as headers are refactored.
This patch includes the relevant header file directly so as to avoid future breakage.
--- arch/arm/kvm/psci.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/kvm/psci.c +2 -0
@@ -24,6 +24,8 @@#include <asm/kvm_psci.h> #include <asm/kvm_host.h> +#include <uapi/linux/psci.h> +/* * This is an implementation of the Power State Coordination Interface * as described in ARM document number ARM DEN 0022A.
Signature · 1 line
1.9.1
PATCH 1/12 arm/arm64: kvm: add missing PSCI include
Quoted 10 lines · Mark Rutland
We make use of the PSCI function IDs, but don't explicitly include the header which defines them. Relying on transitive header includes is fragile and will be broken as headers are refactored.
This patch includes the relevant header file directly so as to avoid future breakage.
Signed-off-by Mark Rutland <[email protected]>Cc Christoffer Dall <[email protected]>Cc Marc Zyngier <[email protected]>
Mark Rutland
maintainerPATCH 2/12 arm64: smp_plat: add get_logical_index
In reply to Mark RutlandThe PSCI MIGRATE_INFO_UP_CPU call returns a physical ID, which we will need to map back to a Linux logical ID.
Implement a reusable get_logical_index to map from a physical ID to a logical ID.
--- arch/arm64/include/asm/smp_plat.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
arch/arm64/include/asm/smp_plat.h +16 -0
@@ -19,6 +19,8 @@#ifndef __ASM_SMP_PLAT_H#define __ASM_SMP_PLAT_H +#include <linux/cpumask.h> +#include <asm/types.h> struct mpidr_hash {
@@ -39,6 +41,20 @@ static inline u32 mpidr_hash_size(void)*/ extern u64 __cpu_logical_map[NR_CPUS ];#define cpu_logical_map (cpu) __cpu_logical_map[cpu] +/* +* Retrieve logical cpu index corresponding to a given MPIDR.Aff* +* - mpidr: MPIDR.Aff* bits to be used for the look-up +* +* Returns the cpu logical index or -EINVAL on look-up error +*/ +static inline int get_logical_index (u64 mpidr) +{ +int cpu; +for (cpu =0 ; cpu < nr_cpu_ids; cpu++) +if (cpu_logical_map (cpu) == mpidr) +return cpu; +return -EINVAL ; +}void __init do_post_cpus_up_work (void );
Signature · 1 line
1.9.1
Mark Rutland
maintainerPATCH 3/12 arm64: smp: consistently use error codes
In reply to Mark Rutlandcpu_kill currently returns one for success and zero for failure, which is unlike all the other cpu_operations, which return zero for success and an error code upon failure. This difference is unnecessarily confusing.
Make cpu_kill consistent with the other cpu_operations.
--- arch/arm64/kernel/psci.c | 7 +++---- arch/arm64/kernel/smp.c | 10 +++++++--- 2 files changed, 10 insertions(+), 7 deletions(-)
arch/arm64/kernel/psci.c +3 -4
@@ -498,7 +498,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu)int err, i;if (!psci_ops.affinity_info) -return 1 ; +return 0 ;/* * cpu_kill could race with cpu_die and we can * potentially end up declaring this cpu undead
@@ -509,7 +509,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu) err = psci_ops.affinity_info (cpu_logical_map (cpu),0 );if (err ==PSCI_0_2_AFFINITY_LEVEL_OFF ) {pr_info ("CPU%d killed.\n" , cpu); -return 1 ; +return 0 ; }msleep (10 );
@@ -518,8 +518,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu)pr_warn ("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n" , cpu, err); -/* Make op_cpu_kill() fail. */ -return 0 ; +return -ETIMEDOUT ; }#endif #endif
arch/arm64/kernel/smp.c +7 -3
@@ -248,7 +248,7 @@ static int op_cpu_kill(unsigned int cpu)* time and hope that it's dead, so let's skip the wait and just hope. */ if (!cpu_ops[cpu]->cpu_kill) -return 1 ; +return 0 ;return cpu_ops[cpu]->cpu_kill (cpu); }
@@ -261,6 +261,8 @@ static DECLARE_COMPLETION(cpu_died);*/ void __cpu_die (unsigned int cpu) { +int err; +if (!wait_for_completion_timeout (&cpu_died,msecs_to_jiffies (5000 ))) {pr_crit ("CPU%u: cpu didn't die\n" , cpu);return ;
@@ -273,8 +275,10 @@ void __cpu_die(unsigned int cpu)* verify that it has really left the kernel before we consider * clobbering anything it might still be using. */ -if (!op_cpu_kill (cpu)) -pr_warn ("CPU%d may not have shut down cleanly\n" , cpu); + err =op_cpu_kill (cpu); +if (err) +pr_warn ("CPU%d may not have shut down cleanly: %d\n" , + cpu, err); }/*
Signature · 1 line
1.9.1
Mark Rutland
maintainerPATCH 4/12 arm64: psci: remove unnecessary id indirection
In reply to Mark RutlandPSCI 0.1 did not define canonical IDs for CPU_ON, CPU_OFF, CPU_SUSPEND, or MIGRATE, and so these need to be provided when using firmware compliant to PSCI 0.1.
However, functions introduced in 0.2 or later have canonical IDs, and these cannot be provided via DT. There's no need to indirect the IDs via a table; they can be used directly at callsites (and already are for SYSTEM_OFF and SYSTEM_RESET).
This patch removes the unnecessary function ID indirection for AFFINITY_INFO and MIGRATE_INFO_TYPE.
--- arch/arm64/kernel/psci.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-)
arch/arm64/kernel/psci.c +3 -17
@@ -67,8 +67,6 @@ enum psci_function {PSCI_FN_CPU_ON ,PSCI_FN_CPU_OFF ,PSCI_FN_MIGRATE , -PSCI_FN_AFFINITY_INFO , -PSCI_FN_MIGRATE_INFO_TYPE , PSCI_FN_MAX, };
@@ -168,22 +166,13 @@ static int psci_migrate(unsigned long cpuid)static int psci_affinity_info (unsigned long target_affinity,unsigned long lowest_affinity_level) { -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_AFFINITY_INFO ]; - err =invoke_psci_fn (fn, target_affinity, lowest_affinity_level,0 ); -return err; +return invoke_psci_fn (PSCI_0_2_FN64_AFFINITY_INFO , target_affinity, + lowest_affinity_level,0 ); }static int psci_migrate_info_type (void ) { -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE ]; - err =invoke_psci_fn (fn,0 ,0 ,0 ); -return err; +return invoke_psci_fn (PSCI_0_2_FN_MIGRATE_INFO_TYPE ,0 ,0 ,0 ); } static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node,
@@ -290,11 +279,8 @@ static void __init psci_0_2_set_functions(void) psci_function_id[PSCI_FN_MIGRATE ] =PSCI_0_2_FN64_MIGRATE ; psci_ops.migrate = psci_migrate; - psci_function_id[PSCI_FN_AFFINITY_INFO ] =PSCI_0_2_FN64_AFFINITY_INFO ; psci_ops.affinity_info = psci_affinity_info; - psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE ] = -PSCI_0_2_FN_MIGRATE_INFO_TYPE ; psci_ops.migrate_info_type = psci_migrate_info_type; arm_pm_restart = psci_sys_reset;
Signature · 1 line
1.9.1
Mark Rutland
maintainerPATCH 5/12 arm64: psci: support unsigned return values
In reply to Mark RutlandPSCI_VERSION and MIGRATE_INFO_TYPE_UP_CPU return unsigned values, with the latter returning a 64-bit value. However, the PSCI invocation functions have prototypes returning int.
This patch upgrades the invocation functions to return unsigned long, with a new typedef to keep things legible. As PSCI_VERSION cannot return a negative value, the erroneous check against PSCI_RET_NOT_SUPPORTED is also removed. The unrelated psci_initcall_t typedef is moved closer to its first user, to avoid confusion with the invocation functions.
In preparation for sharing the code with ARM, unsigned long is used in preference of u64. In the SMC32 calling convention, the relevant fields will be 32 bits wide.
--- arch/arm64/kernel/psci.c | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-)
arch/arm64/kernel/psci.c +16 -27
@@ -56,11 +56,11 @@ struct psci_operations {static struct psci_operations psci_ops; -static int (*invoke_psci_fn)(u64 ,u64 ,u64 ,u64 ); -typedef int (*psci_initcall_t )(const struct device_node *); - -asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64); -asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64); +typedef unsigned long (psci_fn )(unsigned long ,unsigned long , +unsigned long ,unsigned long ); +asmlinkage psci_fn __invoke_psci_fn_hvc; +asmlinkage psci_fn __invoke_psci_fn_smc; +static psci_fn *invoke_psci_fn;enum psci_function {PSCI_FN_CPU_SUSPEND ,
@@ -112,12 +112,9 @@ static void psci_power_state_unpack(u32 power_state,PSCI_0_2_POWER_STATE_AFFL_SHIFT ; } -static int psci_get_version (void ) +static u32 psci_get_version (void ) { -int err; - - err =invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); -return err; +return invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); } static int psci_cpu_suspend(struct psci_power_state state,
@@ -295,23 +292,13 @@ static int __init psci_probe(void) {int ver =psci_get_version (); -if (ver ==PSCI_RET_NOT_SUPPORTED ) { -/* -* PSCI versions >=0.2 mandates implementation of -* PSCI_VERSION. -*/ -pr_err ("PSCI firmware does not comply with the v0.2 spec.\n" ); -return -EOPNOTSUPP ; - }else { -pr_info ("PSCIv%d.%d detected in firmware.\n" , -PSCI_VERSION_MAJOR (ver), -PSCI_VERSION_MINOR (ver)); - -if (PSCI_VERSION_MAJOR (ver) ==0 && -PSCI_VERSION_MINOR (ver) <2 ) { -pr_err ("Conflicting PSCI version detected.\n" ); -return -EINVAL ; - } +pr_info ("PSCIv%d.%d detected in firmware.\n" , +PSCI_VERSION_MAJOR (ver), +PSCI_VERSION_MINOR (ver)); + +if (PSCI_VERSION_MAJOR (ver) ==0 &&PSCI_VERSION_MINOR (ver) <2 ) { +pr_err ("Conflicting PSCI version detected.\n" ); +return -EINVAL ; }psci_0_2_set_functions ();
@@ -319,6 +306,8 @@ static int __init psci_probe(void)return 0 ; } +typedef int (*psci_initcall_t )(const struct device_node *); +/* * PSCI init function for PSCI versions >=0.2 *
Signature · 1 line
1.9.1
PATCH 5/12 arm64: psci: support unsigned return values
On Fri, May 08, 2015 at 12:36:37PM +0100, Mark Rutland wrote:
[...]
Quoted 12 lines
arch/arm64/kernel/psci.c +2
-5-static int psci_get_version (void ) +static u32 psci_get_version (void ) { -int err; - - err =invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); -return err; +return invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); } static int psci_cpu_suspend(struct psci_power_state state,
arch/arm64/kernel/psci.c static int __init psci_probe(void) · line 293
Quoted 2 lines
arch/arm64/kernel/psci.c +0
-0@@ -295,23 +292,13 @@ static int __init psci_probe(void) {int ver =psci_get_version ();
Is there a reason to keep ver as an int ?
Other than that the patch looks fine.
Lorenzo
Mark Rutland
maintainerPATCH 5/12 arm64: psci: support unsigned return values
Quoted 14 lines · Lorenzo Pieralisi
On Fri, May 08, 2015 at 12:36:37PM +0100, Mark Rutland wrote:
[...]
Quoted 10 lines
arch/arm64/kernel/psci.c +2
-5-static int psci_get_version (void ) +static u32 psci_get_version (void ) { -int err; - - err =invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); -return err; +return invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); }
Quoted 6 lines
arch/arm64/kernel/psci.c static int __init psci_probe(void) · line 293
Quoted 4 lines
static int psci_cpu_suspend(struct
psci_power_statestate,arch/arm64/kernel/psci.c +0
-0@@ -295,23 +292,13 @@ static int __init psci_probe(void) {int ver =psci_get_version ();Is there a reason to keep ver as an int ?
No, I just missed it when propagating the type changes. It should be corrected to a u32 as well.
Quoted 1 line
Other than that the patch looks fine.
Great!
Mark.
Mark Rutland
maintainerPATCH 6/12 arm64: psci: account for Trusted OS instances
In reply to Mark RutlandSoftware resident in the secure world (a "Trusted OS") may cause CPU_OFF calls for the CPU it is resident on to be denied. Such a denial would be fatal for the kernel, and so we must detect when this can happen before the point of no return.
This patch implements Trusted OS detection for PSCI 0.2+ systems, using MIGRATE_INFO_TYPE and MIGRATE_INFO_UP_CPU. When a trusted OS is detected as resident on a particular CPU, attempts to hot unplug that CPU will be denied early, before they can prove fatal.
Trusted OS migration is not implemented by this patch. Implementation of migratable UP trusted OSs seems unlikely, and the right policy for migration is unclear (and will likely differ across implementations). As such, it is likely that migration will require cooperation with Trusted OS drivers.
PSCI implementations prior to 0.1 do not provide the facility to detect the presence of a Trusted OS, nor the CPU any such OS is resident on, so without additional information it is not possible to handle Trusted OSs with PSCI 0.1.
--- arch/arm64/kernel/psci.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
arch/arm64/kernel/psci.c +61 -0
@@ -43,6 +43,19 @@ struct psci_power_state {u8 affinity_level; }; +/* +* The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF +* calls to its resident CPU, so we must avoid issuing those. We never migrate +* a Trusted OS even if it claims to be capable of migration -- doing so will +* require cooperation with a Trusted OS driver. +*/ +static int resident_cpu =-1 ; + +static bool psci_tos_resident_on (int cpu) +{ +return cpu == resident_cpu; +} +struct psci_operations {int (*cpu_suspend)(struct psci_power_state state,unsigned long entry_point);
@@ -52,6 +65,7 @@ struct psci_operations {int (*affinity_info)(unsigned long target_affinity,unsigned long lowest_affinity_level);int (*migrate_info_type)(void ); +unsigned long (*migrate_info_up_cpu)(void ); };static struct psci_operations psci_ops;
@@ -172,6 +186,11 @@ static int psci_migrate_info_type(void)return invoke_psci_fn (PSCI_0_2_FN_MIGRATE_INFO_TYPE ,0 ,0 ,0 ); } +static unsigned long psci_migrate_info_up_cpu (void ) +{ +return invoke_psci_fn (PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU ,0 ,0 ,0 ); +} +static int __maybe_unused cpu_psci_cpu_init_idle (struct device_node *cpu_node,unsigned int cpu) {
@@ -261,6 +280,40 @@ static void psci_sys_poweroff(void)invoke_psci_fn (PSCI_0_2_FN_SYSTEM_OFF ,0 ,0 ,0 ); } +/* +* Detect the presence of a resident Trusted OS which may cause CPU_OFF to +* return DENIED (which would be fatal). +*/ +static void __init psci_init_migrate (void ) +{ +unsigned long cpuid; +int type, cpu =-1 ; + + type = psci_ops.migrate_info_type (); + +if (type ==PSCI_0_2_TOS_MP ) { +pr_info ("Trusted OS migration not required\n" ); +return ; + } + +if (type ==PSCI_RET_NOT_SUPPORTED ) { +pr_info ("MIGRATE_INFO_TYPE not supported.\n" ); +return ; + } + +if (type !=PSCI_0_2_TOS_UP_MIGRATE && + type !=PSCI_0_2_TOS_UP_NO_MIGRATE ) { +pr_err ("MIGRATE_INFO_TYPE returned unknown type (%d)\n" , type); +return ; + } + + cpuid = psci_ops.migrate_info_up_cpu (); + cpu =get_logical_index (cpuid); + resident_cpu = cpu >=0 ? cpu :-1 ; + +pr_info ("Trusted OS resident on physical CPU 0x%lx\n" , cpuid); +} +static void __init psci_0_2_set_functions (void ) {pr_info ("Using standard PSCI v0.2 function IDs\n" );
@@ -279,6 +332,7 @@ static void __init psci_0_2_set_functions(void) psci_ops.affinity_info = psci_affinity_info; psci_ops.migrate_info_type = psci_migrate_info_type; + psci_ops.migrate_info_up_cpu = psci_migrate_info_up_cpu; arm_pm_restart = psci_sys_reset;
@@ -303,6 +357,8 @@ static int __init psci_probe(void)psci_0_2_set_functions (); +psci_init_migrate (); +return 0 ; }
@@ -449,6 +505,11 @@ static int cpu_psci_cpu_disable(unsigned int cpu)/* Fail early if we don't have CPU_OFF support */ if (!psci_ops.cpu_off)return -EOPNOTSUPP ; + +/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu)) +return -EPERM ; +return 0 ; }
Signature · 1 line
1.9.1
PATCH 6/12 arm64: psci: account for Trusted OS instances
Quoted 54 lines · Mark Rutland
Software resident in the secure world (a "Trusted OS") may cause
CPU_OFFcalls for the CPU it is resident on to be denied. Such a denial would be fatal for the kernel, and so we must detect when this can happen before the point of no return.This patch implements Trusted OS detection for PSCI 0.2+ systems, using
MIGRATE_INFO_TYPEandMIGRATE_INFO_UP_CPU. When a trusted OS is detected as resident on a particular CPU, attempts to hot unplug that CPU will be denied early, before they can prove fatal.Trusted OS migration is not implemented by this patch. Implementation of migratable UP trusted OSs seems unlikely, and the right policy for migration is unclear (and will likely differ across implementations). As such, it is likely that migration will require cooperation with Trusted OS drivers.
PSCI implementations prior to 0.1 do not provide the facility to detect the presence of a Trusted OS, nor the CPU any such OS is resident on, so without additional information it is not possible to handle Trusted OSs with PSCI 0.1.
Signed-off-by Mark Rutland <[email protected]>Cc Catalin Marinas <[email protected]>Cc Lorenzo Pieralisi <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm64/kernel/psci.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)arch/arm64/kernel/psci.c +13
-0@@ -43,6 +43,19 @@ struct psci_power_state {u8 affinity_level; }; +/* +* The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF +* calls to its resident CPU, so we must avoid issuing those. We never migrate +* a Trusted OS even if it claims to be capable of migration -- doing so will +* require cooperation with a Trusted OS driver. +*/ +static int resident_cpu =-1 ; + +static bool psci_tos_resident_on (int cpu) +{ +return cpu == resident_cpu; +} +struct psci_operations {int (*cpu_suspend)(struct psci_power_state state,unsigned long entry_point);
arch/arm64/kernel/psci.c struct psci_operations { · line 68
Quoted 4 lines
arch/arm64/kernel/psci.c +1
-0@@ -52,6 +65,7 @@ struct psci_operations {int (*affinity_info)(unsigned long target_affinity,unsigned long lowest_affinity_level);int (*migrate_info_type)(void ); +unsigned long (*migrate_info_up_cpu)(void );
Do we really need to keep a pointer in the ops for this function ? I think we can just call it once for all at boot and be done with that.
Actually the same comment applies to migrate_info_type.
arch/arm64/kernel/psci.c static int psci_migrate_info_type(void) · line 192
Quoted 11 lines
arch/arm64/kernel/psci.c +4
-0};static struct psci_operations psci_ops;@@ -172,6 +186,11 @@ static int psci_migrate_info_type(void)return invoke_psci_fn (PSCI_0_2_FN_MIGRATE_INFO_TYPE ,0 ,0 ,0 ); } +static unsigned long psci_migrate_info_up_cpu (void ) +{ +return invoke_psci_fn (PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU ,0 ,0 ,0 ); +}
See above, why can't we just invoke the function at probe time (we do not support migration hence I do not see why we want to keep the function after boot, it will never be called IIUC) ?
Quoted 5 lines
arch/arm64/kernel/psci.c +0
-0static int __maybe_unused cpu_psci_cpu_init_idle (struct device_node *cpu_node,unsigned int cpu) {@@ -261,6 +280,40 @@ static void psci_sys_poweroff(void)invoke_psci_fn (PSCI_0_2_FN_SYSTEM_OFF ,0 ,0 ,0 );
arch/arm64/kernel/psci.c static void psci_sys_poweroff(void) · line 290
Quoted 10 lines
arch/arm64/kernel/psci.c +8
-0} +/* +* Detect the presence of a resident Trusted OS which may cause CPU_OFF to +* return DENIED (which would be fatal). +*/ +static void __init psci_init_migrate (void ) +{ +unsigned long cpuid; +int type, cpu =-1 ;
Nit: cpu variable initialization is useless.
Apart from these minor comments patch is fine.
Lorenzo
Mark Rutland
maintainerPATCH 6/12 arm64: psci: account for Trusted OS instances
Quoted 63 lines · Lorenzo Pieralisi
Quoted 54 lines · Mark Rutland
Software resident in the secure world (a "Trusted OS") may cause
CPU_OFFcalls for the CPU it is resident on to be denied. Such a denial would be fatal for the kernel, and so we must detect when this can happen before the point of no return.This patch implements Trusted OS detection for PSCI 0.2+ systems, using
MIGRATE_INFO_TYPEandMIGRATE_INFO_UP_CPU. When a trusted OS is detected as resident on a particular CPU, attempts to hot unplug that CPU will be denied early, before they can prove fatal.Trusted OS migration is not implemented by this patch. Implementation of migratable UP trusted OSs seems unlikely, and the right policy for migration is unclear (and will likely differ across implementations). As such, it is likely that migration will require cooperation with Trusted OS drivers.
PSCI implementations prior to 0.1 do not provide the facility to detect the presence of a Trusted OS, nor the CPU any such OS is resident on, so without additional information it is not possible to handle Trusted OSs with PSCI 0.1.
Signed-off-by Mark Rutland <[email protected]>Cc Catalin Marinas <[email protected]>Cc Lorenzo Pieralisi <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm64/kernel/psci.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)arch/arm64/kernel/psci.c +13
-0@@ -43,6 +43,19 @@ struct psci_power_state {u8 affinity_level; }; +/* +* The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF +* calls to its resident CPU, so we must avoid issuing those. We never migrate +* a Trusted OS even if it claims to be capable of migration -- doing so will +* require cooperation with a Trusted OS driver. +*/ +static int resident_cpu =-1 ; + +static bool psci_tos_resident_on (int cpu) +{ +return cpu == resident_cpu; +} +struct psci_operations {int (*cpu_suspend)(struct psci_power_state state,unsigned long entry_point);arch/arm64/kernel/psci.c struct psci_operations { · line 68
Quoted 4 lines
arch/arm64/kernel/psci.c +1
-0@@ -52,6 +65,7 @@ struct psci_operations {int (*affinity_info)(unsigned long target_affinity,unsigned long lowest_affinity_level);int (*migrate_info_type)(void ); +unsigned long (*migrate_info_up_cpu)(void );Do we really need to keep a pointer in the ops for this function ? I think we can just call it once for all at boot and be done with that.
Quoted 1 line
Actually the same comment applies to
migrate_info_type.
Sure, I can drop migrate_info_up_cpu. I'll take a look at migrate_info_type.
Quoted 8 lines
Quoted 8 lines
arch/arm64/kernel/psci.c +0
-0};static struct psci_operations psci_ops;@@ -172,6 +186,11 @@ static int psci_migrate_info_type(void)return invoke_psci_fn (PSCI_0_2_FN_MIGRATE_INFO_TYPE ,0 ,0 ,0 ); }
Quoted 8 lines
arch/arm64/kernel/psci.c static int psci_migrate_info_type(void) · line 192
Quoted 4 lines
arch/arm64/kernel/psci.c +4
-0+static unsigned long psci_migrate_info_up_cpu (void ) +{ +return invoke_psci_fn (PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU ,0 ,0 ,0 ); +}See above, why can't we just invoke the function at probe time (we do not support migration hence I do not see why we want to keep the function after boot, it will never be called IIUC) ?
True, I can't see why we'd query this again.
Quoted 18 lines
Quoted 5 lines
arch/arm64/kernel/psci.c +0
-0static int __maybe_unused cpu_psci_cpu_init_idle (struct device_node *cpu_node,unsigned int cpu) {@@ -261,6 +280,40 @@ static void psci_sys_poweroff(void)invoke_psci_fn (PSCI_0_2_FN_SYSTEM_OFF ,0 ,0 ,0 );arch/arm64/kernel/psci.c static void psci_sys_poweroff(void) · line 290
Quoted 10 lines
arch/arm64/kernel/psci.c +8
-0} +/* +* Detect the presence of a resident Trusted OS which may cause CPU_OFF to +* return DENIED (which would be fatal). +*/ +static void __init psci_init_migrate (void ) +{ +unsigned long cpuid; +int type, cpu =-1 ;Nit: cpu variable initialization is useless.
Quoted 1 line
Apart from these minor comments patch is fine.
Thanks, I'll fix these up and push out a v2 shortly.
Thanks,
Mark.
PATCH 6/12 arm64: psci: account for Trusted OS instances
In reply to Mark RutlandQuoted 105 lines · Mark Rutland
Software resident in the secure world (a "Trusted OS") may cause
CPU_OFFcalls for the CPU it is resident on to be denied. Such a denial would be fatal for the kernel, and so we must detect when this can happen before the point of no return.This patch implements Trusted OS detection for PSCI 0.2+ systems, using
MIGRATE_INFO_TYPEandMIGRATE_INFO_UP_CPU. When a trusted OS is detected as resident on a particular CPU, attempts to hot unplug that CPU will be denied early, before they can prove fatal.Trusted OS migration is not implemented by this patch. Implementation of migratable UP trusted OSs seems unlikely, and the right policy for migration is unclear (and will likely differ across implementations). As such, it is likely that migration will require cooperation with Trusted OS drivers.
PSCI implementations prior to 0.1 do not provide the facility to detect the presence of a Trusted OS, nor the CPU any such OS is resident on, so without additional information it is not possible to handle Trusted OSs with PSCI 0.1.
Signed-off-by Mark Rutland <[email protected]>Cc Catalin Marinas <[email protected]>Cc Lorenzo Pieralisi <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm64/kernel/psci.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)arch/arm64/kernel/psci.c +47
-0@@ -43,6 +43,19 @@ struct psci_power_state {u8 affinity_level; }; +/* +* The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF +* calls to its resident CPU, so we must avoid issuing those. We never migrate +* a Trusted OS even if it claims to be capable of migration -- doing so will +* require cooperation with a Trusted OS driver. +*/ +static int resident_cpu =-1 ; + +static bool psci_tos_resident_on (int cpu) +{ +return cpu == resident_cpu; +} +struct psci_operations {int (*cpu_suspend)(struct psci_power_state state,unsigned long entry_point);@@ -52,6 +65,7 @@ struct psci_operations {int (*affinity_info)(unsigned long target_affinity,unsigned long lowest_affinity_level);int (*migrate_info_type)(void ); +unsigned long (*migrate_info_up_cpu)(void ); };static struct psci_operations psci_ops;@@ -172,6 +186,11 @@ static int psci_migrate_info_type(void)return invoke_psci_fn (PSCI_0_2_FN_MIGRATE_INFO_TYPE ,0 ,0 ,0 ); } +static unsigned long psci_migrate_info_up_cpu (void ) +{ +return invoke_psci_fn (PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU ,0 ,0 ,0 ); +} +static int __maybe_unused cpu_psci_cpu_init_idle (struct device_node *cpu_node,unsigned int cpu) {@@ -261,6 +280,40 @@ static void psci_sys_poweroff(void)invoke_psci_fn (PSCI_0_2_FN_SYSTEM_OFF ,0 ,0 ,0 ); } +/* +* Detect the presence of a resident Trusted OS which may cause CPU_OFF to +* return DENIED (which would be fatal). +*/ +static void __init psci_init_migrate (void ) +{ +unsigned long cpuid; +int type, cpu =-1 ; + + type = psci_ops.migrate_info_type (); + +if (type ==PSCI_0_2_TOS_MP ) { +pr_info ("Trusted OS migration not required\n" ); +return ; + } + +if (type ==PSCI_RET_NOT_SUPPORTED ) { +pr_info ("MIGRATE_INFO_TYPE not supported.\n" ); +return ; + } + +if (type !=PSCI_0_2_TOS_UP_MIGRATE && + type !=PSCI_0_2_TOS_UP_NO_MIGRATE ) { +pr_err ("MIGRATE_INFO_TYPE returned unknown type (%d)\n" , type); +return ; + } + + cpuid = psci_ops.migrate_info_up_cpu ();
[..]
Quoted 27 lines
arch/arm64/kernel/psci.c +9
-0+ cpu =get_logical_index (cpuid); + resident_cpu = cpu >=0 ? cpu :-1 ; + +pr_info ("Trusted OS resident on physical CPU 0x%lx\n" , cpuid); +} +static void __init psci_0_2_set_functions (void ) {pr_info ("Using standard PSCI v0.2 function IDs\n" );@@ -279,6 +332,7 @@ static void __init psci_0_2_set_functions(void) psci_ops.affinity_info = psci_affinity_info; psci_ops.migrate_info_type = psci_migrate_info_type; + psci_ops.migrate_info_up_cpu = psci_migrate_info_up_cpu; arm_pm_restart = psci_sys_reset;@@ -303,6 +357,8 @@ static int __init psci_probe(void)psci_0_2_set_functions (); +psci_init_migrate (); +return 0 ; }
arch/arm64/kernel/psci.c static int cpu_psci_cpu_disable(unsigned int cpu) · line 510
Quoted 6 lines
arch/arm64/kernel/psci.c +3
-0@@ -449,6 +505,11 @@ static int cpu_psci_cpu_disable(unsigned int cpu)/* Fail early if we don't have CPU_OFF support */ if (!psci_ops.cpu_off)return -EOPNOTSUPP ; + +/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu))
IIUC, you're denying CPU_OFF even if MIGRATE_INFO_TYPE = 2. Is that correct?
Mark Rutland
maintainerPATCH 6/12 arm64: psci: account for Trusted OS instances
Quoted 50 lines · Ashwin Chaugule
Quoted 49 lines · Mark Rutland
Software resident in the secure world (a "Trusted OS") may cause
CPU_OFFcalls for the CPU it is resident on to be denied. Such a denial would be fatal for the kernel, and so we must detect when this can happen before the point of no return.This patch implements Trusted OS detection for PSCI 0.2+ systems, using
MIGRATE_INFO_TYPEandMIGRATE_INFO_UP_CPU. When a trusted OS is detected as resident on a particular CPU, attempts to hot unplug that CPU will be denied early, before they can prove fatal.Trusted OS migration is not implemented by this patch. Implementation of migratable UP trusted OSs seems unlikely, and the right policy for migration is unclear (and will likely differ across implementations). As such, it is likely that migration will require cooperation with Trusted OS drivers.
PSCI implementations prior to 0.1 do not provide the facility to detect the presence of a Trusted OS, nor the CPU any such OS is resident on, so without additional information it is not possible to handle Trusted OSs with PSCI 0.1.
Signed-off-by Mark Rutland <[email protected]>Cc Catalin Marinas <[email protected]>Cc Lorenzo Pieralisi <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm64/kernel/psci.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)arch/arm64/kernel/psci.c +12
-0@@ -43,6 +43,19 @@ struct psci_power_state {u8 affinity_level; }; +/* +* The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF +* calls to its resident CPU, so we must avoid issuing those. We never migrate +* a Trusted OS even if it claims to be capable of migration -- doing so will +* require cooperation with a Trusted OS driver. +*/ +static int resident_cpu =-1 ; + +static bool psci_tos_resident_on (int cpu) +{ +return cpu == resident_cpu; +}
[...]
Quoted 36 lines
Quoted 28 lines
arch/arm64/kernel/psci.c +28
-0+/* +* Detect the presence of a resident Trusted OS which may cause CPU_OFF to +* return DENIED (which would be fatal). +*/ +static void __init psci_init_migrate (void ) +{ +unsigned long cpuid; +int type, cpu =-1 ; + + type = psci_ops.migrate_info_type (); + +if (type ==PSCI_0_2_TOS_MP ) { +pr_info ("Trusted OS migration not required\n" ); +return ; + } + +if (type ==PSCI_RET_NOT_SUPPORTED ) { +pr_info ("MIGRATE_INFO_TYPE not supported.\n" ); +return ; + } + +if (type !=PSCI_0_2_TOS_UP_MIGRATE && + type !=PSCI_0_2_TOS_UP_NO_MIGRATE ) { +pr_err ("MIGRATE_INFO_TYPE returned unknown type (%d)\n" , type); +return ; + } + + cpuid = psci_ops.migrate_info_up_cpu ();[..]
Quoted 5 lines
arch/arm64/kernel/psci.c +5
-0+ cpu =get_logical_index (cpuid); + resident_cpu = cpu >=0 ? cpu :-1 ; + +pr_info ("Trusted OS resident on physical CPU 0x%lx\n" , cpuid); +}
[...]
Quoted 10 lines
arch/arm64/kernel/psci.c static int cpu_psci_cpu_disable(unsigned int cpu) · line 510
Quoted 7 lines
arch/arm64/kernel/psci.c +3
-0@@ -449,6 +505,11 @@ static int cpu_psci_cpu_disable(unsigned int cpu)/* Fail early if we don't have CPU_OFF support */ if (!psci_ops.cpu_off)return -EOPNOTSUPP ; + +/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu))IIUC, you're denying
CPU_OFFeven ifMIGRATE_INFO_TYPE= 2. Is that correct?
Yes, though only for the CPU the TOS is resident on.
It's not clear what the right policy is w.r.t. migration, and it's probably going to depend on the TOS and workload. It's also not clear whether there are migrateable UP TOS instances out there.
So for the moment this just ensures we won't accidentally bring the system down in the presence of a UP TOS (migrateable or otherwise).
Thanks.
Mark.
Mark Rutland
maintainerPATCH 7/12 arm64: psci: kill psci_power_state
In reply to Mark RutlandA PSCI 1.0 implementation may choose to use the new extended StateID format, the presence of which may be queried via the PSCI_FEATURES call. The layout of this new StateID format is incompatible with the existing format, and so to handle both we must abstract attempts to parse the fields.
In preparation for PSCI 1.0 support, this patch introduces psci_power_state_loses_context and psci_power_state_is_valid functions to query information from a PSCI power state, which is no longer decomposed (and hence the pack/unpack functions are removed). As it is no longer decomposed, it is now passed round as an opaque u32 token.
--- arch/arm64/kernel/psci.c | 89 ++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 52 deletions(-)
arch/arm64/kernel/psci.c +37 -52
@@ -37,11 +37,19 @@#define PSCI_POWER_STATE_TYPE_STANDBY 0#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 -struct psci_power_state { -u16 id; -u8 type; -u8 affinity_level; -}; +static bool psci_power_state_loses_context (u32 state) +{ +return !!(state &PSCI_0_2_POWER_STATE_TYPE_MASK ); +} + +static bool psci_power_state_is_valid (u32 state) +{ +const u32 valid_mask =PSCI_0_2_POWER_STATE_ID_MASK | +PSCI_0_2_POWER_STATE_TYPE_MASK | +PSCI_0_2_POWER_STATE_AFFL_MASK ; + +return !(state & ~valid_mask); +}/* * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF
@@ -57,9 +65,8 @@ static bool psci_tos_resident_on(int cpu) }struct psci_operations { -int (*cpu_suspend)(struct psci_power_state state, -unsigned long entry_point); -int (*cpu_off)(struct psci_power_state state); +int (*cpu_suspend)(u32 state,unsigned long entry_point); +int (*cpu_off)(u32 state);int (*cpu_on)(unsigned long cpuid,unsigned long entry_point);int (*migrate)(unsigned long cpuid); int (*affinity_info)(unsigned long target_affinity,
@@ -84,7 +91,7 @@ enum psci_function { PSCI_FN_MAX, }; -static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state); +static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);static u32 psci_function_id[PSCI_FN_MAX ];
@@ -104,53 +111,28 @@ static int psci_to_linux_errno(int errno)return -EINVAL ; } -static u32 psci_power_state_pack (struct psci_power_state state) -{ -return ((state.id <<PSCI_0_2_POWER_STATE_ID_SHIFT ) - &PSCI_0_2_POWER_STATE_ID_MASK ) | - ((state.type <<PSCI_0_2_POWER_STATE_TYPE_SHIFT ) - &PSCI_0_2_POWER_STATE_TYPE_MASK ) | - ((state.affinity_level <<PSCI_0_2_POWER_STATE_AFFL_SHIFT ) - &PSCI_0_2_POWER_STATE_AFFL_MASK ); -} - -static void psci_power_state_unpack (u32 power_state, -struct psci_power_state *state) -{ - state->id = (power_state &PSCI_0_2_POWER_STATE_ID_MASK ) >> -PSCI_0_2_POWER_STATE_ID_SHIFT ; - state->type = (power_state &PSCI_0_2_POWER_STATE_TYPE_MASK ) >> -PSCI_0_2_POWER_STATE_TYPE_SHIFT ; - state->affinity_level = - (power_state &PSCI_0_2_POWER_STATE_AFFL_MASK ) >> -PSCI_0_2_POWER_STATE_AFFL_SHIFT ; -} -static u32 psci_get_version (void ) {return invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); } -static int psci_cpu_suspend (struct psci_power_state state, -unsigned long entry_point) +static int psci_cpu_suspend (u32 state,unsigned long entry_point) {int err; -u32 fn, power_state; +u32 fn; fn = psci_function_id[PSCI_FN_CPU_SUSPEND ]; - power_state =psci_power_state_pack (state); - err =invoke_psci_fn (fn, power_state, entry_point,0 ); + err =invoke_psci_fn (fn, state, entry_point,0 );return psci_to_linux_errno (err); } -static int psci_cpu_off (struct psci_power_state state) +static int psci_cpu_off (u32 state) {int err; -u32 fn, power_state; +u32 fn; fn = psci_function_id[PSCI_FN_CPU_OFF ]; - power_state =psci_power_state_pack (state); - err =invoke_psci_fn (fn, power_state,0 ,0 ); + err =invoke_psci_fn (fn, state,0 ,0 );return psci_to_linux_errno (err); }
@@ -195,7 +177,7 @@ static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node, unsigned int cpu) {int i, ret, count =0 ; -struct psci_power_state *psci_states; +u32 *psci_states;struct device_node *state_node;/*
@@ -220,13 +202,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node,return -ENOMEM ;for (i =0 ; i < count; i++) { -u32 psci_power_state; +u32 state; state_node =of_parse_phandle (cpu_node,"cpu-idle-states" , i); ret =of_property_read_u32 (state_node,"arm,psci-suspend-param" , - &psci_power_state); + &state);if (ret) {pr_warn (" * %s missing arm,psci-suspend-param property\n" , state_node->full_name);
@@ -235,9 +217,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node, }of_node_put (state_node); -pr_debug ("psci-power-state %#x index %d\n" , psci_power_state, - i); -psci_power_state_unpack (psci_power_state, &psci_states[i]); +pr_debug ("psci-power-state %#x index %d\n" , state, i); +if (!psci_power_state_is_valid (state)) { +pr_warn ("Invalid PSCI power state %#x\n" , state); + ret = -EINVAL ; + goto free_mem; + } + psci_states[i] = state; }/* Idle states parsed correctly, initialize per-cpu pointer */ per_cpu (psci_power_state, cpu) = psci_states;
@@ -520,9 +506,8 @@ static void cpu_psci_cpu_die(unsigned int cpu)* There are no known implementations of PSCI actually using the * power state field, pass a sensible default for now. */ -struct psci_power_state state = { - .type =PSCI_POWER_STATE_TYPE_POWER_DOWN , - }; +u32 state =PSCI_POWER_STATE_TYPE_POWER_DOWN << +PSCI_0_2_POWER_STATE_TYPE_SHIFT ; ret = psci_ops.cpu_off (state);
@@ -561,7 +546,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu)static int psci_suspend_finisher (unsigned long index) { -struct psci_power_state *state =__this_cpu_read (psci_power_state); +u32 *state =__this_cpu_read (psci_power_state);return psci_ops.cpu_suspend (state[index -1 ],virt_to_phys (cpu_resume));
@@ -570,7 +555,7 @@ static int psci_suspend_finisher(unsigned long index)static int __maybe_unused cpu_psci_cpu_suspend (unsigned long index) {int ret; -struct psci_power_state *state =__this_cpu_read (psci_power_state); +u32 *state =__this_cpu_read (psci_power_state);/* * idle state index 0 corresponds to wfi, should never be called * from the cpu_suspend operations
@@ -578,7 +563,7 @@ static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)if (WARN_ON_ONCE (!index))return -EINVAL ; -if (state[index -1 ].type ==PSCI_POWER_STATE_TYPE_STANDBY ) +if (!psci_power_state_loses_context (state[index -1 ])) ret = psci_ops.cpu_suspend (state[index -1 ],0 );else ret =__cpu_suspend (index, psci_suspend_finisher);
Signature · 1 line
1.9.1
PATCH 7/12 arm64: psci: kill psci_power_state
Quoted 12 lines · Mark Rutland
A PSCI 1.0 implementation may choose to use the new extended StateID format, the presence of which may be queried via the
PSCI_FEATUREScall. The layout of this new StateID format is incompatible with the existing format, and so to handle both we must abstract attempts to parse the fields.In preparation for PSCI 1.0 support, this patch introduces
psci_power_state_loses_contextandpsci_power_state_is_validfunctions to query information from a PSCI power state, which is no longer decomposed (and hence the pack/unpack functions are removed). As it is no longer decomposed, it is now passed round as an opaque u32 token.
Quoted 7 lines
Signed-off-by Mark Rutland <[email protected]>Cc Catalin Marinas <[email protected]>Cc Lorenzo Pieralisi <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm64/kernel/psci.c | 89 ++++++++++++++++++++---------------------------- 1 file changed, 37 insertions(+), 52 deletions(-)
Quoted 194 lines
arch/arm64/kernel/psci.c +37
-52@@ -37,11 +37,19 @@#define PSCI_POWER_STATE_TYPE_STANDBY 0#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 -struct psci_power_state { -u16 id; -u8 type; -u8 affinity_level; -}; +static bool psci_power_state_loses_context (u32 state) +{ +return !!(state &PSCI_0_2_POWER_STATE_TYPE_MASK ); +} + +static bool psci_power_state_is_valid (u32 state) +{ +const u32 valid_mask =PSCI_0_2_POWER_STATE_ID_MASK | +PSCI_0_2_POWER_STATE_TYPE_MASK | +PSCI_0_2_POWER_STATE_AFFL_MASK ; + +return !(state & ~valid_mask); +}/* * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF @@ -57,9 +65,8 @@ static bool psci_tos_resident_on(int cpu) }struct psci_operations { -int (*cpu_suspend)(struct psci_power_state state, -unsigned long entry_point); -int (*cpu_off)(struct psci_power_state state); +int (*cpu_suspend)(u32 state,unsigned long entry_point); +int (*cpu_off)(u32 state);int (*cpu_on)(unsigned long cpuid,unsigned long entry_point);int (*migrate)(unsigned long cpuid); int (*affinity_info)(unsigned long target_affinity,@@ -84,7 +91,7 @@ enum psci_function { PSCI_FN_MAX, }; -static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state); +static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);static u32 psci_function_id[PSCI_FN_MAX ];@@ -104,53 +111,28 @@ static int psci_to_linux_errno(int errno)return -EINVAL ; } -static u32 psci_power_state_pack (struct psci_power_state state) -{ -return ((state.id <<PSCI_0_2_POWER_STATE_ID_SHIFT ) - &PSCI_0_2_POWER_STATE_ID_MASK ) | - ((state.type <<PSCI_0_2_POWER_STATE_TYPE_SHIFT ) - &PSCI_0_2_POWER_STATE_TYPE_MASK ) | - ((state.affinity_level <<PSCI_0_2_POWER_STATE_AFFL_SHIFT ) - &PSCI_0_2_POWER_STATE_AFFL_MASK ); -} - -static void psci_power_state_unpack (u32 power_state, -struct psci_power_state *state) -{ - state->id = (power_state &PSCI_0_2_POWER_STATE_ID_MASK ) >> -PSCI_0_2_POWER_STATE_ID_SHIFT ; - state->type = (power_state &PSCI_0_2_POWER_STATE_TYPE_MASK ) >> -PSCI_0_2_POWER_STATE_TYPE_SHIFT ; - state->affinity_level = - (power_state &PSCI_0_2_POWER_STATE_AFFL_MASK ) >> -PSCI_0_2_POWER_STATE_AFFL_SHIFT ; -} -static u32 psci_get_version (void ) {return invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); } -static int psci_cpu_suspend (struct psci_power_state state, -unsigned long entry_point) +static int psci_cpu_suspend (u32 state,unsigned long entry_point) {int err; -u32 fn, power_state; +u32 fn; fn = psci_function_id[PSCI_FN_CPU_SUSPEND ]; - power_state =psci_power_state_pack (state); - err =invoke_psci_fn (fn, power_state, entry_point,0 ); + err =invoke_psci_fn (fn, state, entry_point,0 );return psci_to_linux_errno (err); } -static int psci_cpu_off (struct psci_power_state state) +static int psci_cpu_off (u32 state) {int err; -u32 fn, power_state; +u32 fn; fn = psci_function_id[PSCI_FN_CPU_OFF ]; - power_state =psci_power_state_pack (state); - err =invoke_psci_fn (fn, power_state,0 ,0 ); + err =invoke_psci_fn (fn, state,0 ,0 );return psci_to_linux_errno (err); }@@ -195,7 +177,7 @@ static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node, unsigned int cpu) {int i, ret, count =0 ; -struct psci_power_state *psci_states; +u32 *psci_states;struct device_node *state_node;/* @@ -220,13 +202,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node,return -ENOMEM ;for (i =0 ; i < count; i++) { -u32 psci_power_state; +u32 state; state_node =of_parse_phandle (cpu_node,"cpu-idle-states" , i); ret =of_property_read_u32 (state_node,"arm,psci-suspend-param" , - &psci_power_state); + &state);if (ret) {pr_warn (" * %s missing arm,psci-suspend-param property\n" , state_node->full_name);@@ -235,9 +217,13 @@ static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node, }of_node_put (state_node); -pr_debug ("psci-power-state %#x index %d\n" , psci_power_state, - i); -psci_power_state_unpack (psci_power_state, &psci_states[i]); +pr_debug ("psci-power-state %#x index %d\n" , state, i); +if (!psci_power_state_is_valid (state)) { +pr_warn ("Invalid PSCI power state %#x\n" , state); + ret = -EINVAL ; + goto free_mem; + } + psci_states[i] = state; }/* Idle states parsed correctly, initialize per-cpu pointer */ per_cpu (psci_power_state, cpu) = psci_states;@@ -520,9 +506,8 @@ static void cpu_psci_cpu_die(unsigned int cpu)* There are no known implementations of PSCI actually using the * power state field, pass a sensible default for now. */ -struct psci_power_state state = { - .type =PSCI_POWER_STATE_TYPE_POWER_DOWN , - }; +u32 state =PSCI_POWER_STATE_TYPE_POWER_DOWN << +PSCI_0_2_POWER_STATE_TYPE_SHIFT ; ret = psci_ops.cpu_off (state);@@ -561,7 +546,7 @@ static int cpu_psci_cpu_kill(unsigned int cpu)static int psci_suspend_finisher (unsigned long index) { -struct psci_power_state *state =__this_cpu_read (psci_power_state); +u32 *state =__this_cpu_read (psci_power_state);return psci_ops.cpu_suspend (state[index -1 ],virt_to_phys (cpu_resume));@@ -570,7 +555,7 @@ static int psci_suspend_finisher(unsigned long index)static int __maybe_unused cpu_psci_cpu_suspend (unsigned long index) {int ret; -struct psci_power_state *state =__this_cpu_read (psci_power_state); +u32 *state =__this_cpu_read (psci_power_state);/* * idle state index 0 corresponds to wfi, should never be called * from the cpu_suspend operations @@ -578,7 +563,7 @@ static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)if (WARN_ON_ONCE (!index))return -EINVAL ; -if (state[index -1 ].type ==PSCI_POWER_STATE_TYPE_STANDBY ) +if (!psci_power_state_loses_context (state[index -1 ])) ret = psci_ops.cpu_suspend (state[index -1 ],0 );else ret =__cpu_suspend (index, psci_suspend_finisher);Signature · 1 line
1.9.1
Mark Rutland
maintainerPATCH 8/12 arm64: psci: remove ACPI coupling
In reply to Mark RutlandThe 32-bit ARM port doesn't have ACPI headers, and conditionally including them is going to look horrendous. In preparation for sharing the PSCI invocation code with 32-bit, move the acpi_psci_* function declarations and definitions such that the PSCI client code need not include ACPI headers.
While it would seem like we could simply hide the ACPI includes in psci.h, the ACPI headers have hilarious circular dependencies which make this infeasible without reorganising most of ACPICA. So rather than doing that, move the acpi_psci_* prototypes into psci.h.
The psci_acpi_init function is made dependent on CONFIG_ACPI (with a stub implementation in asm/psci.h) such that it need not be built for 32-bit ARM or kernels without ACPI support. The currently missing __init annotations are added to the prototypes in the header.
--- arch/arm64/include/asm/acpi.h | 14 -------------- arch/arm64/include/asm/psci.h | 11 +++++++++-- arch/arm64/kernel/acpi.c | 11 +++++++++++ arch/arm64/kernel/psci.c | 4 ++-- 4 files changed, 22 insertions(+), 18 deletions(-)
arch/arm64/include/asm/acpi.h +0 -14
@@ -39,18 +39,6 @@ extern int acpi_disabled;extern int acpi_noirq;extern int acpi_pci_disabled; -/* 1 to indicate PSCI 0.2+ is implemented */ -static inline bool acpi_psci_present (void ) -{ -return acpi_gbl_FADT.arm_boot_flags &ACPI_FADT_PSCI_COMPLIANT ; -} - -/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */ -static inline bool acpi_psci_use_hvc (void ) -{ -return acpi_gbl_FADT.arm_boot_flags &ACPI_FADT_PSCI_USE_HVC ; -} -static inline void disable_acpi (void ) { acpi_disabled =1 ;
@@ -88,8 +76,6 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { }void __init acpi_init_cpus (void );#else -static inline bool acpi_psci_present (void ) {return false; } -static inline bool acpi_psci_use_hvc (void ) {return false; }static inline void acpi_init_cpus (void ) { }#endif /* CONFIG_ACPI */
arch/arm64/include/asm/psci.h +9 -2
@@ -14,7 +14,14 @@#ifndef __ASM_PSCI_H#define __ASM_PSCI_H -int psci_dt_init (void ); -int psci_acpi_init (void ); +int __init psci_dt_init (void ); + +#ifdef CONFIG_ACPI +int __init psci_acpi_init (void ); +bool __init acpi_psci_present (void ); +bool __init acpi_psci_use_hvc (void ); +#else +static inline int psci_acpi_init (void ) {return 0 ; } +#endif #endif /* __ASM_PSCI_H */
arch/arm64/kernel/acpi.c +11 -0
@@ -95,6 +95,17 @@ void __init __acpi_unmap_table(char *map, unsigned long size)early_memunmap (map, size); } +bool __init acpi_psci_present (void ) +{ +return acpi_gbl_FADT.arm_boot_flags &ACPI_FADT_PSCI_COMPLIANT ; +} + +/* Whether HVC must be used instead of SMC as the PSCI conduit */ +bool __init acpi_psci_use_hvc (void ) +{ +return acpi_gbl_FADT.arm_boot_flags &ACPI_FADT_PSCI_USE_HVC ; +} +/** * acpi_map_gic_cpu_interface - generates a logical cpu number * and map to MPIDR represented by GICC structure
arch/arm64/kernel/psci.c +2 -2
@@ -15,7 +15,6 @@#define pr_fmt (fmt) "psci: " fmt -#include <linux/acpi.h> #include <linux/init.h> #include <linux/of.h> #include <linux/smp.h>
@@ -25,7 +24,6 @@#include <linux/slab.h> #include <uapi/linux/psci.h> -#include <asm/acpi.h> #include <asm/compiler.h> #include <asm/cpu_ops.h> #include <asm/errno.h>
@@ -438,6 +436,7 @@ int __init psci_dt_init(void)return init_fn (np); } +#ifdef CONFIG_ACPI /* * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's * explicitly clarified in SBBR
@@ -458,6 +457,7 @@ int __init psci_acpi_init(void) return psci_probe(); } +#endif #ifdef CONFIG_SMP
Signature · 1 line
1.9.1
PATCH 8/12 arm64: psci: remove ACPI coupling
Quoted 141 lines · Mark Rutland
The 32-bit ARM port doesn't have ACPI headers, and conditionally including them is going to look horrendous. In preparation for sharing the PSCI invocation code with 32-bit, move the acpi_psci_* function declarations and definitions such that the PSCI client code need not include ACPI headers.
While it would seem like we could simply hide the ACPI includes in
psci.h, the ACPI headers have hilarious circular dependencies which make this infeasible without reorganising most of ACPICA. So rather than doing that, move the acpi_psci_* prototypes intopsci.h.The
psci_acpi_initfunction is made dependent onCONFIG_ACPI(with a stub implementation inasm/psci.h) such that it need not be built for 32-bit ARM or kernels without ACPI support. The currently missing__initannotations are added to the prototypes in the header.Signed-off-by Mark Rutland <[email protected]>Cc Al Stone <[email protected]>Cc Catalin Marinas <[email protected]>Cc Hanjun Guo <[email protected]>Cc Lorenzo Pieralisi <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm64/include/asm/acpi.h | 14 -------------- arch/arm64/include/asm/psci.h | 11 +++++++++-- arch/arm64/kernel/acpi.c | 11 +++++++++++ arch/arm64/kernel/psci.c | 4 ++-- 4 files changed, 22 insertions(+), 18 deletions(-)arch/arm64/include/asm/acpi.h +0
-14@@ -39,18 +39,6 @@ extern int acpi_disabled;extern int acpi_noirq;extern int acpi_pci_disabled; -/* 1 to indicate PSCI 0.2+ is implemented */ -static inline bool acpi_psci_present (void ) -{ -return acpi_gbl_FADT.arm_boot_flags &ACPI_FADT_PSCI_COMPLIANT ; -} - -/* 1 to indicate HVC must be used instead of SMC as the PSCI conduit */ -static inline bool acpi_psci_use_hvc (void ) -{ -return acpi_gbl_FADT.arm_boot_flags &ACPI_FADT_PSCI_USE_HVC ; -} -static inline void disable_acpi (void ) { acpi_disabled =1 ;@@ -88,8 +76,6 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { }void __init acpi_init_cpus (void );#else -static inline bool acpi_psci_present (void ) {return false; } -static inline bool acpi_psci_use_hvc (void ) {return false; }static inline void acpi_init_cpus (void ) { }#endif /* CONFIG_ACPI */ arch/arm64/include/asm/psci.h +9
-2@@ -14,7 +14,14 @@#ifndef __ASM_PSCI_H#define __ASM_PSCI_H -int psci_dt_init (void ); -int psci_acpi_init (void ); +int __init psci_dt_init (void ); + +#ifdef CONFIG_ACPI +int __init psci_acpi_init (void ); +bool __init acpi_psci_present (void ); +bool __init acpi_psci_use_hvc (void ); +#else +static inline int psci_acpi_init (void ) {return 0 ; } +#endif #endif /* __ASM_PSCI_H */ arch/arm64/kernel/acpi.c +11
-0@@ -95,6 +95,17 @@ void __init __acpi_unmap_table(char *map, unsigned long size)early_memunmap (map, size); } +bool __init acpi_psci_present (void ) +{ +return acpi_gbl_FADT.arm_boot_flags &ACPI_FADT_PSCI_COMPLIANT ; +} + +/* Whether HVC must be used instead of SMC as the PSCI conduit */ +bool __init acpi_psci_use_hvc (void ) +{ +return acpi_gbl_FADT.arm_boot_flags &ACPI_FADT_PSCI_USE_HVC ; +} +/** * acpi_map_gic_cpu_interface - generates a logical cpu number * and map to MPIDR represented by GICC structure arch/arm64/kernel/psci.c +2
-3@@ -15,7 +15,6 @@#define pr_fmt (fmt) "psci: " fmt -#include <linux/acpi.h> #include <linux/init.h> #include <linux/of.h> #include <linux/smp.h> @@ -25,7 +24,6 @@#include <linux/slab.h> #include <uapi/linux/psci.h> -#include <asm/acpi.h> #include <asm/compiler.h> #include <asm/cpu_ops.h> #include <asm/errno.h> @@ -438,6 +436,7 @@ int __init psci_dt_init(void)return init_fn (np); } +#ifdef CONFIG_ACPI /* * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's * explicitly clarified in SBBR @@ -458,6 +457,7 @@ int __init psci_acpi_init(void) return psci_probe(); } +#endif #ifdef CONFIG_SMP --
Quoted 2 lines
1.9.1
Mark Rutland
maintainerPATCH 9/12 arm64: psci: factor invocation code to drivers
In reply to Mark RutlandTo enable sharing with arm, move the core PSCI framework code to drivers/firmware. This results in a minor gain in lines of code, but this will quickly be amortised by the removal of code currently duplicated in arch/arm.
--- arch/arm64/Kconfig | 1 + arch/arm64/include/asm/psci.h | 27 ---- arch/arm64/kernel/psci.c | 356 +---------------------------------------- arch/arm64/kernel/setup.c | 2 +- drivers/firmware/Kconfig | 3 + drivers/firmware/Makefile | 1 + drivers/firmware/psci.c | 364 ++++++++++++++++++++++++++++++++++++++++++ include/linux/psci.h | 48 ++++++ 8 files changed, 420 insertions(+), 382 deletions(-) delete mode 100644 arch/arm64/include/asm/psci.h create mode 100644 drivers/firmware/psci.c create mode 100644 include/linux/psci.h
arch/arm64/Kconfig +1 -0
@@ -19,6 +19,7 @@ config ARM64 select ARM_GIC_V2M if PCI_MSI select ARM_GIC_V3 select ARM_GIC_V3_ITS if PCI_MSI + select ARM_PSCI_FW select BUILDTIME_EXTABLE_SORT select CLONE_BACKWARDS select COMMON_CLK
arch/arm64/include/asm/psci.h deleted +0 -27
@@ -1,27 +0,0 @@ -/* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* Copyright (C) 2013 ARM Limited -*/ - -#ifndef __ASM_PSCI_H -#define __ASM_PSCI_H - -int __init psci_dt_init (void ); - -#ifdef CONFIG_ACPI -int __init psci_acpi_init (void ); -bool __init acpi_psci_present (void ); -bool __init acpi_psci_use_hvc (void ); -#else -static inline int psci_acpi_init (void ) {return 0 ; } -#endif - -#endif /* __ASM_PSCI_H */
arch/arm64/kernel/psci.c +2 -354
385 lines not on this page · raw message
arch/arm64/kernel/setup.c +1 -1
@@ -46,6 +46,7 @@#include <linux/of_platform.h> #include <linux/efi.h> #include <linux/personality.h> +#include <linux/psci.h> #include <asm/acpi.h> #include <asm/fixmap.h>
@@ -61,7 +62,6 @@#include <asm/tlbflush.h> #include <asm/traps.h> #include <asm/memblock.h> -#include <asm/psci.h> #include <asm/efi.h> #include <asm/virt.h>
drivers/firmware/Kconfig +3 -0
@@ -5,6 +5,9 @@ menu "Firmware Drivers" +config ARM_PSCI_FW + bool + config EDD tristate "BIOS Enhanced Disk Drive calls determine boot disk" depends on X86
drivers/firmware/Makefile +1 -0
@@ -1,6 +1,7 @@ # # Makefile for the linux kernel. # +obj-$(CONFIG_ARM_PSCI_FW) += psci.o obj-$(CONFIG_DMI) += dmi_scan.o obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o obj-$(CONFIG_EDD) += edd.o
drivers/firmware/psci.c new file +364 -0
364 lines not on this page · raw message
include/linux/psci.h new file +48 -0
48 lines not on this page · raw message
Signature · 1 line
1.9.1
Mark Rutland
maintainerPATCH 9/12 arm64: psci: factor invocation code to drivers
[...]
include/linux/psci.h line 46
Quoted 9 lines
include/linux/psci.h new file +9
-0+int __init psci_dt_init (void ); + +#ifdef CONFIG_ACPI +int __init psci_acpi_init (void ); +bool __init acpi_psci_present (void ); +bool __init acpi_psci_use_hvc (void ); +#else +static inline int psci_acpi_init (void ) {return 0 ; } +#endif
I've just realised this could result in a build failure with CONFIG_ARM_PSCI_FW isn't selected. I've wrapped psci_dt_init in an ifdef and tightened the checks for psci_acpi_init.
That's all pushed out to a branch [1] on kernel.org.
Mark.
[1] git://git.kernel.org/pub/scm/linux/kernel/git/mark/linux.git psci/unification
Mark Rutland
maintainerPATCH 10/12 drivers: psci: support native SMC{32,64} calls
In reply to Mark RutlandA 32-bit OS cannot make calls with SMC64 IDs, while a 64-bit OS must invoke some PSCI functions with SMC64 IDs.
This patch introduces and makes use of a new macro to choose the appropriate IDs based on the register width of the OS, which will allow 32-bit callers to use the PSCI client code.
--- drivers/firmware/psci.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
drivers/firmware/psci.c +19 -6
@@ -27,6 +27,18 @@#include <asm/smp_plat.h> /* +* While a 64-bit OS can make calls with SMC32 calling conventions, for some +* calls it is necessary to use SMC64 to pass or return 64-bit values. For such +* calls PSCI_0_2_FN_NATIVE(x) will choose the appropriate (native-width) +* function ID. +*/ +#ifdef CONFIG_64BIT +#define PSCI_0_2_FN_NATIVE (name) PSCI_0_2_FN_##name +#else +#define PSCI_0_2_FN_NATIVE (name) PSCI_0_2_FN64_##name +#endif + +/* * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF * calls to its resident CPU, so we must avoid issuing those. We never migrate * a Trusted OS even if it claims to be capable of migration -- doing so will
@@ -121,8 +133,8 @@ static int psci_migrate(unsigned long cpuid)static int psci_affinity_info (unsigned long target_affinity,unsigned long lowest_affinity_level) { -return invoke_psci_fn (PSCI_0_2_FN64_AFFINITY_INFO , target_affinity, - lowest_affinity_level,0 ); +return invoke_psci_fn (PSCI_0_2_FN_NATIVE (AFFINITY_INFO ), + target_affinity, lowest_affinity_level,0 ); }static int psci_migrate_info_type (void )
@@ -132,7 +144,8 @@ static int psci_migrate_info_type(void)static unsigned long psci_migrate_info_up_cpu (void ) { -return invoke_psci_fn (PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU ,0 ,0 ,0 ); +return invoke_psci_fn (PSCI_0_2_FN_NATIVE (MIGRATE_INFO_UP_CPU ), +0 ,0 ,0 ); }static int get_set_conduit_method (struct device_node *np)
@@ -204,16 +217,16 @@ static void __init psci_init_migrate(void)static void __init psci_0_2_set_functions (void ) {pr_info ("Using standard PSCI v0.2 function IDs\n" ); - psci_function_id[PSCI_FN_CPU_SUSPEND ] =PSCI_0_2_FN64_CPU_SUSPEND ; + psci_function_id[PSCI_FN_CPU_SUSPEND ] =PSCI_0_2_FN_NATIVE (CPU_SUSPEND ); psci_ops.cpu_suspend = psci_cpu_suspend; psci_function_id[PSCI_FN_CPU_OFF ] =PSCI_0_2_FN_CPU_OFF ; psci_ops.cpu_off = psci_cpu_off; - psci_function_id[PSCI_FN_CPU_ON ] =PSCI_0_2_FN64_CPU_ON ; + psci_function_id[PSCI_FN_CPU_ON ] =PSCI_0_2_FN_NATIVE (CPU_ON ); psci_ops.cpu_on = psci_cpu_on; - psci_function_id[PSCI_FN_MIGRATE ] =PSCI_0_2_FN64_MIGRATE ; + psci_function_id[PSCI_FN_MIGRATE ] =PSCI_0_2_FN_NATIVE (MIGRATE ); psci_ops.migrate = psci_migrate; psci_ops.affinity_info = psci_affinity_info;
Signature · 1 line
1.9.1
Mark Rutland
maintainerPATCH 11/12 ARM: migrate to common PSCI client code
In reply to Mark RutlandNow that the common PSCI client code has been factored out to drivers/firmware, and made safe for 32-bit use, move the 32-bit ARM code over to it. This results in a moderate reduction of duplicated lines, and will prevent further duplication as the PSCI client code is updated for PSCI 1.0 and beyond.
The two legacy platform users of the PSCI invocation code are updated to account for interface changes. In both cases the power state parameter is changed to an opaque u32 token in preparation for PSCI 1.0 power state changes.
--- arch/arm/Kconfig | 1 + arch/arm/include/asm/psci.h | 23 --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/psci.c | 299 -------------------------------------- arch/arm/kernel/psci_smp.c | 29 +++- arch/arm/kernel/setup.c | 3 +- arch/arm/mach-highbank/highbank.c | 2 +- arch/arm/mach-highbank/pm.c | 8 +- drivers/cpuidle/cpuidle-calxeda.c | 7 +- 9 files changed, 32 insertions(+), 342 deletions(-) delete mode 100644 arch/arm/kernel/psci.c
arch/arm/Kconfig +1 -0
@@ -1465,6 +1465,7 @@ config HOTPLUG_CPU config ARM_PSCI bool "Support for the ARM Power State Coordination Interface (PSCI)" depends on CPU_V7 + select ARM_PSCI_FW help Say Y here if you want Linux to communicate with system firmware implementing the PSCI specification for CPU-centric power
arch/arm/include/asm/psci.h +0 -23
@@ -14,34 +14,11 @@#ifndef __ASM_ARM_PSCI_H#define __ASM_ARM_PSCI_H -#define PSCI_POWER_STATE_TYPE_STANDBY 0 -#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 - -struct psci_power_state { -u16 id; -u8 type; -u8 affinity_level; -}; - -struct psci_operations { -int (*cpu_suspend)(struct psci_power_state state, -unsigned long entry_point); -int (*cpu_off)(struct psci_power_state state); -int (*cpu_on)(unsigned long cpuid,unsigned long entry_point); -int (*migrate)(unsigned long cpuid); -int (*affinity_info)(unsigned long target_affinity, -unsigned long lowest_affinity_level); -int (*migrate_info_type)(void ); -}; - -extern struct psci_operations psci_ops;extern struct smp_operations psci_smp_ops;#ifdef CONFIG_ARM_PSCI -int psci_init (void );bool psci_smp_available (void );#else -static inline int psci_init (void ) {return 0 ; }static inline bool psci_smp_available (void ) {return false; }#endif
arch/arm/kernel/Makefile +1 -1
@@ -86,7 +86,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o ifeq ($(CONFIG_ARM_PSCI),y) -obj-y += psci.o psci-call.o +obj-y += psci-call.o obj-$(CONFIG_SMP) += psci_smp.o endif
arch/arm/kernel/psci.c deleted +0 -299
299 lines not on this page · raw message
arch/arm/kernel/psci_smp.c +22 -7
@@ -17,6 +17,8 @@#include <linux/smp.h> #include <linux/of.h> #include <linux/delay.h> +#include <linux/psci.h> +#include <uapi/linux/psci.h> #include <asm/psci.h>
@@ -56,17 +58,29 @@ static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) }#ifdef CONFIG_HOTPLUG_CPU +int psci_cpu_disable (unsigned int cpu) +{ +/* Fail early if we don't have CPU_OFF support */ +if (!psci_ops.cpu_off) +return 0 ; + +/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu)) +return 0 ; + +return 1 ; +} +void __ref psci_cpu_die (unsigned int cpu) { -const struct psci_power_state ps = { - .type =PSCI_POWER_STATE_TYPE_POWER_DOWN , - }; +u32 state =PSCI_POWER_STATE_TYPE_POWER_DOWN << +PSCI_0_2_POWER_STATE_TYPE_SHIFT ; -if (psci_ops.cpu_off) - psci_ops.cpu_off (ps); +if (psci_ops.cpu_off) + psci_ops.cpu_off (state); -/* We should never return */ -panic ("psci: cpu %d failed to shutdown\n" , cpu); +/* We should never return */ +panic ("psci: cpu %d failed to shutdown\n" , cpu); }int __ref psci_cpu_kill (unsigned int cpu)
@@ -109,6 +123,7 @@ bool __init psci_smp_available(void)struct smp_operations __initdata psci_smp_ops = { .smp_boot_secondary = psci_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU + .cpu_disable = psci_cpu_disable, .cpu_die = psci_cpu_die, .cpu_kill = psci_cpu_kill, #endif
arch/arm/kernel/setup.c +2 -1
@@ -31,6 +31,7 @@#include <linux/bug.h> #include <linux/compiler.h> #include <linux/sort.h> +#include <linux/psci.h> #include <asm/unified.h> #include <asm/cp15.h>
@@ -950,7 +951,7 @@ void __init setup_arch(char **cmdline_p)unflatten_device_tree ();arm_dt_init_cpu_maps (); -psci_init (); +psci_dt_init ();#ifdef CONFIG_SMP if (is_smp ()) {if (!mdesc->smp_init || !mdesc->smp_init ()) {
arch/arm/mach-highbank/highbank.c +1 -1
@@ -28,8 +28,8 @@#include <linux/reboot.h> #include <linux/amba/bus.h> #include <linux/platform_device.h> +#include <linux/psci.h> -#include <asm/psci.h> #include <asm/hardware/cache-l2x0.h> #include <asm/mach/arch.h> #include <asm/mach/map.h>
arch/arm/mach-highbank/pm.c +2 -6
@@ -16,18 +16,14 @@#include <linux/cpu_pm.h> #include <linux/init.h> +#include <linux/psci.h> #include <linux/suspend.h> #include <asm/suspend.h> -#include <asm/psci.h> static int highbank_suspend_finish (unsigned long val) { -const struct psci_power_state ps = { - .type =PSCI_POWER_STATE_TYPE_POWER_DOWN , - .affinity_level =1 , - }; - +u32 ps =0x01010000 ;/* Aff1 power down */ return psci_ops.cpu_suspend (ps,__pa (cpu_resume)); }
drivers/cpuidle/cpuidle-calxeda.c +3 -4
@@ -25,15 +25,14 @@#include <linux/init.h> #include <linux/mm.h> #include <linux/platform_device.h> +#include <linux/psci.h> +#include <asm/cpuidle.h> #include <asm/suspend.h> -#include <asm/psci.h> static int calxeda_idle_finish (unsigned long val) { -const struct psci_power_state ps = { - .type =PSCI_POWER_STATE_TYPE_POWER_DOWN , - }; +u32 ps =0x00010000 ;/* Aff0 power down */ return psci_ops.cpu_suspend (ps,__pa (cpu_resume)); }
Signature · 1 line
1.9.1
PATCH 11/12 ARM: migrate to common PSCI client code
Quoted 416 lines · Mark Rutland
Now that the common PSCI client code has been factored out to
drivers/firmware, and made safe for 32-bit use, move the 32-bit ARM code over to it. This results in a moderate reduction of duplicated lines, and will prevent further duplication as the PSCI client code is updated for PSCI 1.0 and beyond.The two legacy platform users of the PSCI invocation code are updated to account for interface changes. In both cases the power state parameter is changed to an opaque u32 token in preparation for PSCI 1.0 power state changes.
Signed-off-by Mark Rutland <[email protected]>Cc Ashwin Chaugule <[email protected]>Cc Catalin Marinas <[email protected]>Cc Lorenzo Pieralisi <[email protected]>Cc Rob Herring <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm/Kconfig | 1 + arch/arm/include/asm/psci.h | 23 --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/psci.c | 299 -------------------------------------- arch/arm/kernel/psci_smp.c | 29 +++- arch/arm/kernel/setup.c | 3 +- arch/arm/mach-highbank/highbank.c | 2 +- arch/arm/mach-highbank/pm.c | 8 +- drivers/cpuidle/cpuidle-calxeda.c | 7 +- 9 files changed, 32 insertions(+), 342 deletions(-) delete mode 100644 arch/arm/kernel/psci.carch/arm/Kconfig +1
-0@@ -1465,6 +1465,7 @@ config HOTPLUG_CPU config ARM_PSCI bool "Support for the ARM Power State Coordination Interface (PSCI)" depends on CPU_V7 + select ARM_PSCI_FW help Say Y here if you want Linux to communicate with system firmware implementing the PSCI specification for CPU-centric powerarch/arm/include/asm/psci.h +0
-23@@ -14,34 +14,11 @@#ifndef __ASM_ARM_PSCI_H#define __ASM_ARM_PSCI_H -#define PSCI_POWER_STATE_TYPE_STANDBY 0 -#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 - -struct psci_power_state { -u16 id; -u8 type; -u8 affinity_level; -}; - -struct psci_operations { -int (*cpu_suspend)(struct psci_power_state state, -unsigned long entry_point); -int (*cpu_off)(struct psci_power_state state); -int (*cpu_on)(unsigned long cpuid,unsigned long entry_point); -int (*migrate)(unsigned long cpuid); -int (*affinity_info)(unsigned long target_affinity, -unsigned long lowest_affinity_level); -int (*migrate_info_type)(void ); -}; - -extern struct psci_operations psci_ops;extern struct smp_operations psci_smp_ops;#ifdef CONFIG_ARM_PSCI -int psci_init (void );bool psci_smp_available (void );#else -static inline int psci_init (void ) {return 0 ; }static inline bool psci_smp_available (void ) {return false; }#endif arch/arm/kernel/Makefile +1
-1@@ -86,7 +86,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o ifeq ($(CONFIG_ARM_PSCI),y) -obj-y += psci.o psci-call.o +obj-y += psci-call.o obj-$(CONFIG_SMP) += psci_smp.o endifarch/arm/kernel/psci.c deleted +0
-299@@ -1,299 +0,0 @@ -/* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* Copyright (C) 2012 ARM Limited -* -* Author: Will Deacon <[email protected]> -*/ - -#define pr_fmt (fmt) "psci: " fmt - -#include <linux/init.h> -#include <linux/of.h> -#include <linux/reboot.h> -#include <linux/pm.h> -#include <uapi/linux/psci.h> - -#include <asm/compiler.h> -#include <asm/errno.h> -#include <asm/psci.h> -#include <asm/system_misc.h> - -struct psci_operations psci_ops; - -static int (*invoke_psci_fn)(u32 ,u32 ,u32 ,u32 ); -typedef int (*psci_initcall_t )(const struct device_node *); - -asmlinkage int __invoke_psci_fn_hvc(u32, u32, u32, u32); -asmlinkage int __invoke_psci_fn_smc(u32, u32, u32, u32); - -enum psci_function { -PSCI_FN_CPU_SUSPEND , -PSCI_FN_CPU_ON , -PSCI_FN_CPU_OFF , -PSCI_FN_MIGRATE , -PSCI_FN_AFFINITY_INFO , -PSCI_FN_MIGRATE_INFO_TYPE , -PSCI_FN_MAX , -}; - -static u32 psci_function_id[PSCI_FN_MAX ]; - -static int psci_to_linux_errno (int errno) -{ -switch (errno) { -case PSCI_RET_SUCCESS : -return 0 ; -case PSCI_RET_NOT_SUPPORTED : -return -EOPNOTSUPP ; -case PSCI_RET_INVALID_PARAMS : -return -EINVAL ; -case PSCI_RET_DENIED : -return -EPERM ; - }; - -return -EINVAL ; -} - -static u32 psci_power_state_pack (struct psci_power_state state) -{ -return ((state.id <<PSCI_0_2_POWER_STATE_ID_SHIFT ) - &PSCI_0_2_POWER_STATE_ID_MASK ) | - ((state.type <<PSCI_0_2_POWER_STATE_TYPE_SHIFT ) - &PSCI_0_2_POWER_STATE_TYPE_MASK ) | - ((state.affinity_level <<PSCI_0_2_POWER_STATE_AFFL_SHIFT ) - &PSCI_0_2_POWER_STATE_AFFL_MASK ); -} - -static int psci_get_version (void ) -{ -int err; - - err =invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); -return err; -} - -static int psci_cpu_suspend (struct psci_power_state state, -unsigned long entry_point) -{ -int err; -u32 fn, power_state; - - fn = psci_function_id[PSCI_FN_CPU_SUSPEND ]; - power_state =psci_power_state_pack (state); - err =invoke_psci_fn (fn, power_state, entry_point,0 ); -return psci_to_linux_errno (err); -} - -static int psci_cpu_off (struct psci_power_state state) -{ -int err; -u32 fn, power_state; - - fn = psci_function_id[PSCI_FN_CPU_OFF ]; - power_state =psci_power_state_pack (state); - err =invoke_psci_fn (fn, power_state,0 ,0 ); -return psci_to_linux_errno (err); -} - -static int psci_cpu_on (unsigned long cpuid,unsigned long entry_point) -{ -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_CPU_ON ]; - err =invoke_psci_fn (fn, cpuid, entry_point,0 ); -return psci_to_linux_errno (err); -} - -static int psci_migrate (unsigned long cpuid) -{ -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_MIGRATE ]; - err =invoke_psci_fn (fn, cpuid,0 ,0 ); -return psci_to_linux_errno (err); -} - -static int psci_affinity_info (unsigned long target_affinity, -unsigned long lowest_affinity_level) -{ -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_AFFINITY_INFO ]; - err =invoke_psci_fn (fn, target_affinity, lowest_affinity_level,0 ); -return err; -} - -static int psci_migrate_info_type (void ) -{ -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE ]; - err =invoke_psci_fn (fn,0 ,0 ,0 ); -return err; -} - -static int get_set_conduit_method (struct device_node *np) -{ -const char *method; - -pr_info ("probing for conduit method from DT.\n" ); - -if (of_property_read_string (np,"method" , &method)) { -pr_warn ("missing \"method\" property\n" ); -return -ENXIO ; - } - -if (!strcmp ("hvc" , method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; - }else if (!strcmp ("smc" , method)) { - invoke_psci_fn = __invoke_psci_fn_smc; - }else { -pr_warn ("invalid \"method\" property: %s\n" , method); -return -EINVAL ; - } -return 0 ; -} - -static void psci_sys_reset (enum reboot_mode reboot_mode,const char *cmd) -{ -invoke_psci_fn (PSCI_0_2_FN_SYSTEM_RESET ,0 ,0 ,0 ); -} - -static void psci_sys_poweroff (void ) -{ -invoke_psci_fn (PSCI_0_2_FN_SYSTEM_OFF ,0 ,0 ,0 ); -} - -/* -* PSCI Function IDs for v0.2+ are well defined so use -* standard values. -*/ -static int psci_0_2_init (struct device_node *np) -{ -int err, ver; - - err =get_set_conduit_method (np); - -if (err) - goto out_put_node; - - ver =psci_get_version (); - -if (ver ==PSCI_RET_NOT_SUPPORTED ) { -/* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */ -pr_err ("PSCI firmware does not comply with the v0.2 spec.\n" ); - err = -EOPNOTSUPP ; - goto out_put_node; - }else { -pr_info ("PSCIv%d.%d detected in firmware.\n" , -PSCI_VERSION_MAJOR (ver), -PSCI_VERSION_MINOR (ver)); - -if (PSCI_VERSION_MAJOR (ver) ==0 && -PSCI_VERSION_MINOR (ver) <2 ) { - err = -EINVAL ; -pr_err ("Conflicting PSCI version detected.\n" ); - goto out_put_node; - } - } - -pr_info ("Using standard PSCI v0.2 function IDs\n" ); - psci_function_id[PSCI_FN_CPU_SUSPEND ] =PSCI_0_2_FN_CPU_SUSPEND ; - psci_ops.cpu_suspend = psci_cpu_suspend; - - psci_function_id[PSCI_FN_CPU_OFF ] =PSCI_0_2_FN_CPU_OFF ; - psci_ops.cpu_off = psci_cpu_off; - - psci_function_id[PSCI_FN_CPU_ON ] =PSCI_0_2_FN_CPU_ON ; - psci_ops.cpu_on = psci_cpu_on; - - psci_function_id[PSCI_FN_MIGRATE ] =PSCI_0_2_FN_MIGRATE ; - psci_ops.migrate = psci_migrate; - - psci_function_id[PSCI_FN_AFFINITY_INFO ] =PSCI_0_2_FN_AFFINITY_INFO ; - psci_ops.affinity_info = psci_affinity_info; - - psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE ] = -PSCI_0_2_FN_MIGRATE_INFO_TYPE ; - psci_ops.migrate_info_type = psci_migrate_info_type; - - arm_pm_restart = psci_sys_reset; - - pm_power_off = psci_sys_poweroff; - -out_put_node: -of_node_put (np); -return err; -} - -/* -* PSCI < v0.2 get PSCI Function IDs via DT. -*/ -static int psci_0_1_init (struct device_node *np) -{ -u32 id; -int err; - - err =get_set_conduit_method (np); - -if (err) - goto out_put_node; - -pr_info ("Using PSCI v0.1 Function IDs from DT\n" ); - -if (!of_property_read_u32 (np,"cpu_suspend" , &id)) { - psci_function_id[PSCI_FN_CPU_SUSPEND ] = id; - psci_ops.cpu_suspend = psci_cpu_suspend; - } - -if (!of_property_read_u32 (np,"cpu_off" , &id)) { - psci_function_id[PSCI_FN_CPU_OFF ] = id; - psci_ops.cpu_off = psci_cpu_off; - } - -if (!of_property_read_u32 (np,"cpu_on" , &id)) { - psci_function_id[PSCI_FN_CPU_ON ] = id; - psci_ops.cpu_on = psci_cpu_on; - } - -if (!of_property_read_u32 (np,"migrate" , &id)) { - psci_function_id[PSCI_FN_MIGRATE ] = id; - psci_ops.migrate = psci_migrate; - } - -out_put_node: -of_node_put (np); -return err; -} - -static const struct of_device_id psci_of_match[]__initconst = { - { .compatible ="arm,psci" , .data = psci_0_1_init}, - { .compatible ="arm,psci-0.2" , .data = psci_0_2_init}, - {}, -}; - -int __init psci_init (void ) -{ -struct device_node *np; -const struct of_device_id *matched_np; -psci_initcall_t init_fn; - - np =of_find_matching_node_and_match (NULL , psci_of_match, &matched_np); -if (!np) -return -ENODEV ; - - init_fn = (psci_initcall_t )matched_np->data; -return init_fn (np); -}arch/arm/kernel/psci_smp.c +2
-0@@ -17,6 +17,8 @@#include <linux/smp.h> #include <linux/of.h> #include <linux/delay.h> +#include <linux/psci.h> +#include <uapi/linux/psci.h> #include <asm/psci.h> @@ -56,17 +58,29 @@ static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) }#ifdef CONFIG_HOTPLUG_CPU
arch/arm/kernel/psci_smp.c static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) · line 70
Quoted 10 lines
arch/arm/kernel/psci_smp.c +10
-0+int psci_cpu_disable (unsigned int cpu) +{ +/* Fail early if we don't have CPU_OFF support */ +if (!psci_ops.cpu_off) +return 0 ; + +/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu)) +return 0 ; +
Same question here. Seems like if MIGRATE_INFO_TYPE = 2 ( TOS is present or does not require migration), you should be able to call CPU_OFF. Otherwise the patch looks fine to me.
PATCH 11/12 ARM: migrate to common PSCI client code
Quoted 416 lines · Ashwin Chaugule
Quoted 415 lines · Mark Rutland
Now that the common PSCI client code has been factored out to
drivers/firmware, and made safe for 32-bit use, move the 32-bit ARM code over to it. This results in a moderate reduction of duplicated lines, and will prevent further duplication as the PSCI client code is updated for PSCI 1.0 and beyond.The two legacy platform users of the PSCI invocation code are updated to account for interface changes. In both cases the power state parameter is changed to an opaque u32 token in preparation for PSCI 1.0 power state changes.
Signed-off-by Mark Rutland <[email protected]>Cc Ashwin Chaugule <[email protected]>Cc Catalin Marinas <[email protected]>Cc Lorenzo Pieralisi <[email protected]>Cc Rob Herring <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm/Kconfig | 1 + arch/arm/include/asm/psci.h | 23 --- arch/arm/kernel/Makefile | 2 +- arch/arm/kernel/psci.c | 299 -------------------------------------- arch/arm/kernel/psci_smp.c | 29 +++- arch/arm/kernel/setup.c | 3 +- arch/arm/mach-highbank/highbank.c | 2 +- arch/arm/mach-highbank/pm.c | 8 +- drivers/cpuidle/cpuidle-calxeda.c | 7 +- 9 files changed, 32 insertions(+), 342 deletions(-) delete mode 100644 arch/arm/kernel/psci.carch/arm/Kconfig +1
-0@@ -1465,6 +1465,7 @@ config HOTPLUG_CPU config ARM_PSCI bool "Support for the ARM Power State Coordination Interface (PSCI)" depends on CPU_V7 + select ARM_PSCI_FW help Say Y here if you want Linux to communicate with system firmware implementing the PSCI specification for CPU-centric powerarch/arm/include/asm/psci.h +0
-23@@ -14,34 +14,11 @@#ifndef __ASM_ARM_PSCI_H#define __ASM_ARM_PSCI_H -#define PSCI_POWER_STATE_TYPE_STANDBY 0 -#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 - -struct psci_power_state { -u16 id; -u8 type; -u8 affinity_level; -}; - -struct psci_operations { -int (*cpu_suspend)(struct psci_power_state state, -unsigned long entry_point); -int (*cpu_off)(struct psci_power_state state); -int (*cpu_on)(unsigned long cpuid,unsigned long entry_point); -int (*migrate)(unsigned long cpuid); -int (*affinity_info)(unsigned long target_affinity, -unsigned long lowest_affinity_level); -int (*migrate_info_type)(void ); -}; - -extern struct psci_operations psci_ops;extern struct smp_operations psci_smp_ops;#ifdef CONFIG_ARM_PSCI -int psci_init (void );bool psci_smp_available (void );#else -static inline int psci_init (void ) {return 0 ; }static inline bool psci_smp_available (void ) {return false; }#endif arch/arm/kernel/Makefile +1
-1@@ -86,7 +86,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o ifeq ($(CONFIG_ARM_PSCI),y) -obj-y += psci.o psci-call.o +obj-y += psci-call.o obj-$(CONFIG_SMP) += psci_smp.o endifarch/arm/kernel/psci.c deleted +0
-299@@ -1,299 +0,0 @@ -/* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* Copyright (C) 2012 ARM Limited -* -* Author: Will Deacon <[email protected]> -*/ - -#define pr_fmt (fmt) "psci: " fmt - -#include <linux/init.h> -#include <linux/of.h> -#include <linux/reboot.h> -#include <linux/pm.h> -#include <uapi/linux/psci.h> - -#include <asm/compiler.h> -#include <asm/errno.h> -#include <asm/psci.h> -#include <asm/system_misc.h> - -struct psci_operations psci_ops; - -static int (*invoke_psci_fn)(u32 ,u32 ,u32 ,u32 ); -typedef int (*psci_initcall_t )(const struct device_node *); - -asmlinkage int __invoke_psci_fn_hvc(u32, u32, u32, u32); -asmlinkage int __invoke_psci_fn_smc(u32, u32, u32, u32); - -enum psci_function { -PSCI_FN_CPU_SUSPEND , -PSCI_FN_CPU_ON , -PSCI_FN_CPU_OFF , -PSCI_FN_MIGRATE , -PSCI_FN_AFFINITY_INFO , -PSCI_FN_MIGRATE_INFO_TYPE , -PSCI_FN_MAX , -}; - -static u32 psci_function_id[PSCI_FN_MAX ]; - -static int psci_to_linux_errno (int errno) -{ -switch (errno) { -case PSCI_RET_SUCCESS : -return 0 ; -case PSCI_RET_NOT_SUPPORTED : -return -EOPNOTSUPP ; -case PSCI_RET_INVALID_PARAMS : -return -EINVAL ; -case PSCI_RET_DENIED : -return -EPERM ; - }; - -return -EINVAL ; -} - -static u32 psci_power_state_pack (struct psci_power_state state) -{ -return ((state.id <<PSCI_0_2_POWER_STATE_ID_SHIFT ) - &PSCI_0_2_POWER_STATE_ID_MASK ) | - ((state.type <<PSCI_0_2_POWER_STATE_TYPE_SHIFT ) - &PSCI_0_2_POWER_STATE_TYPE_MASK ) | - ((state.affinity_level <<PSCI_0_2_POWER_STATE_AFFL_SHIFT ) - &PSCI_0_2_POWER_STATE_AFFL_MASK ); -} - -static int psci_get_version (void ) -{ -int err; - - err =invoke_psci_fn (PSCI_0_2_FN_PSCI_VERSION ,0 ,0 ,0 ); -return err; -} - -static int psci_cpu_suspend (struct psci_power_state state, -unsigned long entry_point) -{ -int err; -u32 fn, power_state; - - fn = psci_function_id[PSCI_FN_CPU_SUSPEND ]; - power_state =psci_power_state_pack (state); - err =invoke_psci_fn (fn, power_state, entry_point,0 ); -return psci_to_linux_errno (err); -} - -static int psci_cpu_off (struct psci_power_state state) -{ -int err; -u32 fn, power_state; - - fn = psci_function_id[PSCI_FN_CPU_OFF ]; - power_state =psci_power_state_pack (state); - err =invoke_psci_fn (fn, power_state,0 ,0 ); -return psci_to_linux_errno (err); -} - -static int psci_cpu_on (unsigned long cpuid,unsigned long entry_point) -{ -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_CPU_ON ]; - err =invoke_psci_fn (fn, cpuid, entry_point,0 ); -return psci_to_linux_errno (err); -} - -static int psci_migrate (unsigned long cpuid) -{ -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_MIGRATE ]; - err =invoke_psci_fn (fn, cpuid,0 ,0 ); -return psci_to_linux_errno (err); -} - -static int psci_affinity_info (unsigned long target_affinity, -unsigned long lowest_affinity_level) -{ -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_AFFINITY_INFO ]; - err =invoke_psci_fn (fn, target_affinity, lowest_affinity_level,0 ); -return err; -} - -static int psci_migrate_info_type (void ) -{ -int err; -u32 fn; - - fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE ]; - err =invoke_psci_fn (fn,0 ,0 ,0 ); -return err; -} - -static int get_set_conduit_method (struct device_node *np) -{ -const char *method; - -pr_info ("probing for conduit method from DT.\n" ); - -if (of_property_read_string (np,"method" , &method)) { -pr_warn ("missing \"method\" property\n" ); -return -ENXIO ; - } - -if (!strcmp ("hvc" , method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; - }else if (!strcmp ("smc" , method)) { - invoke_psci_fn = __invoke_psci_fn_smc; - }else { -pr_warn ("invalid \"method\" property: %s\n" , method); -return -EINVAL ; - } -return 0 ; -} - -static void psci_sys_reset (enum reboot_mode reboot_mode,const char *cmd) -{ -invoke_psci_fn (PSCI_0_2_FN_SYSTEM_RESET ,0 ,0 ,0 ); -} - -static void psci_sys_poweroff (void ) -{ -invoke_psci_fn (PSCI_0_2_FN_SYSTEM_OFF ,0 ,0 ,0 ); -} - -/* -* PSCI Function IDs for v0.2+ are well defined so use -* standard values. -*/ -static int psci_0_2_init (struct device_node *np) -{ -int err, ver; - - err =get_set_conduit_method (np); - -if (err) - goto out_put_node; - - ver =psci_get_version (); - -if (ver ==PSCI_RET_NOT_SUPPORTED ) { -/* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */ -pr_err ("PSCI firmware does not comply with the v0.2 spec.\n" ); - err = -EOPNOTSUPP ; - goto out_put_node; - }else { -pr_info ("PSCIv%d.%d detected in firmware.\n" , -PSCI_VERSION_MAJOR (ver), -PSCI_VERSION_MINOR (ver)); - -if (PSCI_VERSION_MAJOR (ver) ==0 && -PSCI_VERSION_MINOR (ver) <2 ) { - err = -EINVAL ; -pr_err ("Conflicting PSCI version detected.\n" ); - goto out_put_node; - } - } - -pr_info ("Using standard PSCI v0.2 function IDs\n" ); - psci_function_id[PSCI_FN_CPU_SUSPEND ] =PSCI_0_2_FN_CPU_SUSPEND ; - psci_ops.cpu_suspend = psci_cpu_suspend; - - psci_function_id[PSCI_FN_CPU_OFF ] =PSCI_0_2_FN_CPU_OFF ; - psci_ops.cpu_off = psci_cpu_off; - - psci_function_id[PSCI_FN_CPU_ON ] =PSCI_0_2_FN_CPU_ON ; - psci_ops.cpu_on = psci_cpu_on; - - psci_function_id[PSCI_FN_MIGRATE ] =PSCI_0_2_FN_MIGRATE ; - psci_ops.migrate = psci_migrate; - - psci_function_id[PSCI_FN_AFFINITY_INFO ] =PSCI_0_2_FN_AFFINITY_INFO ; - psci_ops.affinity_info = psci_affinity_info; - - psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE ] = -PSCI_0_2_FN_MIGRATE_INFO_TYPE ; - psci_ops.migrate_info_type = psci_migrate_info_type; - - arm_pm_restart = psci_sys_reset; - - pm_power_off = psci_sys_poweroff; - -out_put_node: -of_node_put (np); -return err; -} - -/* -* PSCI < v0.2 get PSCI Function IDs via DT. -*/ -static int psci_0_1_init (struct device_node *np) -{ -u32 id; -int err; - - err =get_set_conduit_method (np); - -if (err) - goto out_put_node; - -pr_info ("Using PSCI v0.1 Function IDs from DT\n" ); - -if (!of_property_read_u32 (np,"cpu_suspend" , &id)) { - psci_function_id[PSCI_FN_CPU_SUSPEND ] = id; - psci_ops.cpu_suspend = psci_cpu_suspend; - } - -if (!of_property_read_u32 (np,"cpu_off" , &id)) { - psci_function_id[PSCI_FN_CPU_OFF ] = id; - psci_ops.cpu_off = psci_cpu_off; - } - -if (!of_property_read_u32 (np,"cpu_on" , &id)) { - psci_function_id[PSCI_FN_CPU_ON ] = id; - psci_ops.cpu_on = psci_cpu_on; - } - -if (!of_property_read_u32 (np,"migrate" , &id)) { - psci_function_id[PSCI_FN_MIGRATE ] = id; - psci_ops.migrate = psci_migrate; - } - -out_put_node: -of_node_put (np); -return err; -} - -static const struct of_device_id psci_of_match[]__initconst = { - { .compatible ="arm,psci" , .data = psci_0_1_init}, - { .compatible ="arm,psci-0.2" , .data = psci_0_2_init}, - {}, -}; - -int __init psci_init (void ) -{ -struct device_node *np; -const struct of_device_id *matched_np; -psci_initcall_t init_fn; - - np =of_find_matching_node_and_match (NULL , psci_of_match, &matched_np); -if (!np) -return -ENODEV ; - - init_fn = (psci_initcall_t )matched_np->data; -return init_fn (np); -}arch/arm/kernel/psci_smp.c +2
-0@@ -17,6 +17,8 @@#include <linux/smp.h> #include <linux/of.h> #include <linux/delay.h> +#include <linux/psci.h> +#include <uapi/linux/psci.h> #include <asm/psci.h> @@ -56,17 +58,29 @@ static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) }
Quoted 15 lines
arch/arm/kernel/psci_smp.c static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) · line 70
Quoted 11 lines
arch/arm/kernel/psci_smp.c +10
-0#ifdef CONFIG_HOTPLUG_CPU +int psci_cpu_disable (unsigned int cpu) +{ +/* Fail early if we don't have CPU_OFF support */ +if (!psci_ops.cpu_off) +return 0 ; + +/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu)) +return 0 ; +Same question here. Seems like if
MIGRATE_INFO_TYPE= 2 ( TOS is present or does not require migration), you should be able to callCPU_OFF. Otherwise the patch looks fine to me.
err. Make that TOS is not present.
Mark Rutland
maintainerPATCH 11/12 ARM: migrate to common PSCI client code
Quoted 15 lines
Quoted 6 lines
Quoted 6 lines
arch/arm/kernel/psci_smp.c +6
-0+int psci_cpu_disable (unsigned int cpu) +{ +/* Fail early if we don't have CPU_OFF support */ +if (!psci_ops.cpu_off) +return 0 ; +Quoted 8 lines
arch/arm/kernel/psci_smp.c static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) · line 70
Quoted 4 lines
arch/arm/kernel/psci_smp.c +4
-0+/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu)) +return 0 ; +Same question here. Seems like if
MIGRATE_INFO_TYPE= 2 ( TOS is present or does not require migration), you should be able to callCPU_OFF. Otherwise the patch looks fine to me.
Quoted 1 line
err. Make that TOS is not present.
In the cases where migration is not required, resident_cpu == -1, and psci_tos_resident_on(cpu) will return false for any valid CPU. So I don't see that we would deny migration here.
What am I missing?
Thanks,
Mark.
PATCH 11/12 ARM: migrate to common PSCI client code
Quoted 15 lines · Mark Rutland
Quoted 15 lines
Quoted 14 lines
arch/arm/kernel/psci_smp.c static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) · line 70
Quoted 10 lines
arch/arm/kernel/psci_smp.c +10
-0+int psci_cpu_disable (unsigned int cpu) +{ +/* Fail early if we don't have CPU_OFF support */ +if (!psci_ops.cpu_off) +return 0 ; + +/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu)) +return 0 ; +Same question here. Seems like if
MIGRATE_INFO_TYPE= 2 ( TOS is present or does not require migration), you should be able to callCPU_OFF. Otherwise the patch looks fine to me.
Quoted 6 lines
Quoted 1 line
err. Make that TOS is not present.
In the cases where migration is not required,
resident_cpu== -1, andpsci_tos_resident_on(cpu)will return false for any valid CPU. So I don't see that we would deny migration here.
Hm. Perhaps I was confused by the "return -EPERM" in the arm64 version and "return 0" here. :)
Ashwin
Mark Rutland
maintainerPATCH 11/12 ARM: migrate to common PSCI client code
Quoted 18 lines · Ashwin Chaugule
Quoted 17 lines · Mark Rutland
Quoted 16 lines
Quoted 6 lines
Quoted 6 lines
arch/arm/kernel/psci_smp.c +6
-0+int psci_cpu_disable (unsigned int cpu) +{ +/* Fail early if we don't have CPU_OFF support */ +if (!psci_ops.cpu_off) +return 0 ; +Quoted 8 lines
arch/arm/kernel/psci_smp.c static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle) · line 70
Quoted 4 lines
arch/arm/kernel/psci_smp.c +4
-0+/* Trusted OS will deny CPU_OFF */ +if (psci_tos_resident_on (cpu)) +return 0 ; +Same question here. Seems like if
MIGRATE_INFO_TYPE= 2 ( TOS is present or does not require migration), you should be able to callCPU_OFF. Otherwise the patch looks fine to me.err. Make that TOS is not present.
Quoted 7 lines
Quoted 4 lines
In the cases where migration is not required,
resident_cpu== -1, andpsci_tos_resident_on(cpu)will return false for any valid CPU. So I don't see that we would deny migration here.Hm. Perhaps I was confused by the "return
-EPERM" in the arm64 version and "return 0" here. :)
Looking at this again, you're absolutely right, and I'd gotten myself confused about the expected return values. I'll respin this with corrected return codes (-EPERM instead of 0 and 0 instead of 1).
Thanks for spotting that, and sorry for being so dense!
Mark.
Mark Rutland
maintainerPATCH 12/12 MAINTAINERS: add PSCI entry
In reply to Mark RutlandAdd myself and Lorenzo as maintainers of the PSCI client code.
--- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+)
MAINTAINERS +9 -0
@@ -7761,6 +7761,15 @@ S: Maintained F: include/linux/power_supply.h F: drivers/power/ +POWER STATE COORDINATION INTERFACE (PSCI) +M: Mark Rutland <[email protected]> +M: Lorenzo Pieralisi <[email protected]> +L: linux-arm-kernel at lists.infradead.org +S: Maintained +F: drivers/firmware/psci.c +F: include/linux/psci.h +F: include/uapi/linux/psci.h + PNP SUPPORT M: Rafael J. Wysocki <[email protected]> S: Maintained
Signature · 1 line
1.9.1