PSCI v0.2 support and DT bindings
v4 cover PSCI v0.2 support and DT bindings
Changes in v4:
- Correct copyright banner format.
- Check if PSCI Version ID is supported.
- Add all PSCI RET codes in uapi header.
- Explicitely ret 1 from psci_cpu_kill()
Changes in v3:
- Roll up common functionality for getting conduit method.
- Remove #defines for ARM32 and ARM64 in uapi/linux/psci.h
- Remove functions not supported by PSCI v0.1
- Misc cleanups.
- Add PSCI_AFFINITY_INFO return types in uapi header.
- Changed function names for PSCI v0.1 and PSCI v0.2
- Added copyright info to uapi header.
- Fixed args to affinity_info call.
- Fix typo in psci_init definition when PSCI is not defined.Changes in v2:
- Add AFFINITY_INFO and MIGRATE_INFO_TYPE functions.
- Add binding Documentation.
- Add function to get PSCI version.
- Add common #defines in uapi/linux/psci.h
- Implement cpu_kill and check if CPU is dead via AFFINITY_INFO.
- Misc cleanups.Changes in v1:
- Add new binding "arm, psci-0.2"
- Separate conduit and PSCI function assignment methods.
Ashwin Chaugule (3):
PSCI: Add initial support for PSCIv0.2 functions
Documentation: devicetree: Add new binding for PSCIv0.2
ARM: Check if a CPU has gone offline
Documentation/devicetree/bindings/arm/psci.txt | 35 +++++- arch/arm/include/asm/psci.h | 7 +- arch/arm/kernel/psci.c | 155 +++++++++++++++++++----- arch/arm/kernel/psci_smp.c | 21 ++++ arch/arm64/kernel/psci.c | 160 ++++++++++++++++++++----- include/uapi/linux/psci.h | 66 ++++++++++ 6 files changed, 383 insertions(+), 61 deletions(-) create mode 100644 include/uapi/linux/psci.h
Signature · 1 line
1.8.3.2
PATCH v4 1/3 PSCI: Add initial support for PSCIv0.2 functions
The PSCIv0.2 spec defines standard values of function IDs and introduces a few new functions. Detect version of PSCI and appropriately select the right PSCI functions.
--- arch/arm/include/asm/psci.h | 7 +- arch/arm/kernel/psci.c | 155 ++++++++++++++++++++++++++++++++++-------- arch/arm64/kernel/psci.c | 160 +++++++++++++++++++++++++++++++++++--------- include/uapi/linux/psci.h | 61 +++++++++++++++++ 4 files changed, 323 insertions(+), 60 deletions(-) create mode 100644 include/uapi/linux/psci.h
arch/arm/include/asm/psci.h +5 -2
@@ -29,16 +29,19 @@ struct psci_operations {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 -void psci_init (void ); +int psci_init (void );bool psci_smp_available (void );#else -static inline void psci_init (void ) { } +static inline int psci_init (void ) { }static inline bool psci_smp_available (void ) {return false; }#endif
arch/arm/kernel/psci.c +127 -28
215 lines not on this page · raw message
arch/arm64/kernel/psci.c +130 -30
227 lines not on this page · raw message
include/uapi/linux/psci.h new file +61 -0
61 lines not on this page · raw message
Signature · 1 line
1.8.3.2
PATCH v4 1/3 PSCI: Add initial support for PSCIv0.2 functions
Hi Ashwin,
Quoted 175 lines · Ashwin Chaugule
The PSCIv0.2 spec defines standard values of function IDs and introduces a few new functions. Detect version of PSCI and appropriately select the right PSCI functions.
Signed-off-by Ashwin Chaugule <[email protected]>--- arch/arm/include/asm/psci.h | 7 +- arch/arm/kernel/psci.c | 155 ++++++++++++++++++++++++++++++++++-------- arch/arm64/kernel/psci.c | 160 +++++++++++++++++++++++++++++++++++--------- include/uapi/linux/psci.h | 61 +++++++++++++++++ 4 files changed, 323 insertions(+), 60 deletions(-) create mode 100644 include/uapi/linux/psci.harch/arm/include/asm/psci.h +5
-2@@ -29,16 +29,19 @@ struct psci_operations {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 -void psci_init (void ); +int psci_init (void );bool psci_smp_available (void );#else -static inline void psci_init (void ) { } +static inline int psci_init (void ) { }static inline bool psci_smp_available (void ) {return false; }#endif arch/arm/kernel/psci.c +49
-27@@ -17,6 +17,7 @@#include <linux/init.h> #include <linux/of.h> +#include <uapi/linux/psci.h> #include <asm/compiler.h> #include <asm/errno.h> @@ -27,22 +28,20 @@struct psci_operations psci_ops;static int (*invoke_psci_fn)(u32 ,u32 ,u32 ,u32 ); +typedef int (*psci_initcall_t )(const struct device_node *);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 ]; -#define PSCI_RET_SUCCESS 0 -#define PSCI_RET_EOPNOTSUPP -1 -#define PSCI_RET_EINVAL -2 -#define PSCI_RET_EPERM -3 -static int psci_to_linux_errno (int errno) {switch (errno) {@@ -59,13 +58,6 @@ static int psci_to_linux_errno(int errno)return -EINVAL ; } -#define PSCI_POWER_STATE_ID_MASK 0xffff -#define PSCI_POWER_STATE_ID_SHIFT 0 -#define PSCI_POWER_STATE_TYPE_MASK 0x1 -#define PSCI_POWER_STATE_TYPE_SHIFT 16 -#define PSCI_POWER_STATE_AFFL_MASK 0x3 -#define PSCI_POWER_STATE_AFFL_SHIFT 24 -static u32 psci_power_state_pack (struct psci_power_state state) { return ((state.id & PSCI_POWER_STATE_ID_MASK)@@ -110,6 +102,14 @@ static noinline int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1,return function_id; } +static int psci_get_version (void ) +{ +int err; + + err =invoke_psci_fn (PSCI_ID_VERSION ,0 ,0 ,0 ); +return err; +} +static int psci_cpu_suspend (struct psci_power_state state,unsigned long entry_point) {@@ -153,26 +153,36 @@ static int psci_migrate(unsigned long cpuid)return psci_to_linux_errno (err); } -static const struct of_device_id psci_of_match[]__initconst = { - { .compatible ="arm,psci" , }, - {}, -}; +static int psci_affinity_info (unsigned long target_affinity, +unsigned long lowest_affinity_level) +{ +int err; +u32 fn; -void __init psci_init (void ) + 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 ) { -struct device_node *np; -const char *method; -u32 id; +int err; +u32 fn; - np =of_find_matching_node (NULL , psci_of_match); -if (!np) -return ; + fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE ]; + err =invoke_psci_fn (fn,0 ,0 ,0 ); +return err; +} -pr_info ("probing function IDs from device-tree\n" ); +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_warning ("missing \"method\" property\n" ); - goto out_put_node; +pr_warn ("missing \"method\" property\n" ); +return -ENXIO ; }if (!strcmp ("hvc" , method)) {@@ -180,10 +190,79 @@ void __init psci_init(void) }else if (!strcmp ("smc" , method)) { invoke_psci_fn = __invoke_psci_fn_smc; }else { -pr_warning ("invalid \"method\" property: %s\n" , method); +pr_warn ("invalid \"method\" property: %s\n" , method); +return -EINVAL ; + } +return 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;
arch/arm/kernel/psci.c void __init psci_init(void) · line 215
Quoted 10 lines
arch/arm/kernel/psci.c +9
-0+ + err =get_set_conduit_method (np); + +if (err) goto out_put_node; + + ver =psci_get_version (); + +if (ver ==PSCI_RET_EOPNOTSUPP ) { +pr_info ("PSCI_ID_VERSION Function not supported in firmware.\n" );
IMO you should stop here as the implementation conforming to the specification must return a minor version number of 2 and major version number of 0. You can't proceed, assume ids and use them.
Regards,
Sudeep
PATCH v4 1/3 PSCI: Add initial support for PSCIv0.2 functions
Hi Sudeep,
Quoted 7 lines · Sudeep Holla
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (ver == PSCI_RET_EOPNOTSUPP) { + pr_info("PSCI_ID_VERSION Function not supported in firmware.\n");IMO you should stop here as the implementation conforming to the specification must return a minor version number of 2 and major version number of 0. You can't proceed, assume ids and use them.
hm, you're right, I missed that.
Cheers,
Ashwin
PATCH v4 1/3 PSCI: Add initial support for PSCIv0.2 functions
Quoted 7 lines · Ashwin Chaugule
Hi Sudeep,
Quoted 3 lines · Sudeep Holla
Quoted 2 lines
(quoted diff) +2
-0+ if (ver == PSCI_RET_EOPNOTSUPP) { + pr_info("PSCI_ID_VERSION Function not supported in firmware.\n");
Quoted 6 lines
Quoted 4 lines
IMO you should stop here as the implementation conforming to the specification must return a minor version number of 2 and major version number of 0. You can't proceed, assume ids and use them.
hm, you're right, I missed that.
Something like this?
if (ver == PSCI_RET_EOPNOTSUPP) {
/* 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;Quoted 3 lines
Cheers,
Ashwin
PATCH v4 1/3 PSCI: Add initial support for PSCIv0.2 functions
Hi Ashwin,
Quoted 15 lines · Ashwin Chaugule
Quoted 7 lines · Ashwin Chaugule
Hi Sudeep,
Quoted 3 lines · Sudeep Holla
Quoted 2 lines
(quoted diff) +2
-0+ if (ver == PSCI_RET_EOPNOTSUPP) { + pr_info("PSCI_ID_VERSION Function not supported in firmware.\n");Quoted 6 lines
Quoted 4 lines
IMO you should stop here as the implementation conforming to the specification must return a minor version number of 2 and major version number of 0. You can't proceed, assume ids and use them.
hm, you're right, I missed that.
Quoted 8 lines
Something like this?
if (ver == PSCI_RET_EOPNOTSUPP) { /* 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;
Yes that looks fine to me.
Regards,
Sudeep
PATCH v4 2/3 Documentation: devicetree: Add new binding for PSCIv0.2
In reply to Ashwin ChauguleThe PSCI v0.2+ spec defines standard values for PSCI function IDs. Add a new binding entry so that pre v0.2 implementations can use DT entries for function IDs and v0.2+ implementations use standard entries as defined by the PSCIv0.2 specification.
--- Documentation/devicetree/bindings/arm/psci.txt | 35 +++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/arm/psci.txt +34 -1
@@ -21,7 +21,15 @@ to #0. Main node required properties: - - compatible : Must be "arm,psci" + - compatible : should contain at least one of: + + * "arm,psci" : for implementations complying to PSCI versions prior to + 0.2. For these cases function IDs must be provided. + + * "arm,psci-0.2" : for implementations complying to PSCI 0.2. Function + IDs are not required and should be ignored by an OS with PSCI 0.2 + support, but are permitted to be present for compatibility with + existing software when "arm,psci" is later in the compatible list. - method : The method of calling the PSCI firmware. Permitted values are:
@@ -45,6 +53,8 @@ Main node optional properties: Example: +Case 1: PSCI v0.1 only. + psci { compatible = "arm,psci"; method = "smc";
@@ -53,3 +63,26 @@ Example: cpu_on = <0x95c10002>; migrate = <0x95c10003>; }; + + +Case 2: PSCI v0.2 only + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + +Case 3: PSCI v0.2 and PSCI v0.1. + + As described above, for compatibility with existing kernels, the + hypervisor will likely want to provide IDs, e.g. + + psci { + compatible = "arm,psci-0.2", "arm,psci"; + method = "hvc"; + + cpu_on = < arbitrary value >; + cpu_off = < arbitrary value >; + + ... + };
Signature · 1 line
1.8.3.2
PATCH v4 3/3 ARM: Check if a CPU has gone offline
In reply to Ashwin ChaugulePSCIv0.2 adds a new function called AFFINITY_INFO, which can be used to query if a specified CPU has actually gone offline. Calling this function via cpu_kill ensures that a CPU has quiesced after a call to cpu_die.
--- arch/arm/kernel/psci_smp.c | 21 +++++++++++++++++++++ include/uapi/linux/psci.h | 5 +++++ 2 files changed, 26 insertions(+)
arch/arm/kernel/psci_smp.c +21 -0
@@ -16,6 +16,7 @@#include <linux/init.h> #include <linux/smp.h> #include <linux/of.h> +#include <uapi/linux/psci.h> #include <asm/psci.h> #include <asm/smp_plat.h>
@@ -66,6 +67,25 @@ void __ref psci_cpu_die(unsigned int cpu)/* We should never return */ panic("psci: cpu %d failed to shutdown\n", cpu); } + +int __ref psci_cpu_kill (unsigned int cpu) +{ +int err; + +if (!psci_ops.affinity_info) +return 1 ; + + err = psci_ops.affinity_info (cpu_logical_map (cpu),0 ); + +if (err !=PSCI_AFFINITY_INFO_RET_OFF ) { +pr_err ("psci: Cannot kill CPU:%d, psci ret val: %d\n" , + cpu, err); +/* Make platform_cpu_kill() fail. */ +return 0 ; + } +return 1 ; +} +#endif bool __init psci_smp_available (void )
@@ -78,5 +98,6 @@ struct smp_operations __initdata psci_smp_ops = { .smp_boot_secondary = psci_boot_secondary, #ifdef CONFIG_HOTPLUG_CPU .cpu_die = psci_cpu_die, + .cpu_kill = psci_cpu_kill,#endif };
include/uapi/linux/psci.h +5 -0
@@ -58,4 +58,9 @@ ((ver & PSCI_VER_MAJOR_MASK) >> PSCI_VER_MAJOR_SHIFT)#define PSCI_VER_MINOR (ver) (ver & PSCI_VER_MINOR_MASK) +/* Return values from the PSCI_ID_AFFINITY_INFO Function. */ +#define PSCI_AFFINITY_INFO_RET_ON 0 +#define PSCI_AFFINITY_INFO_RET_OFF 1 +#define PSCI_AFFINITY_INFO_RET_ON_PENDING 2 +#endif /* _UAPI_LINUX_PSCI_H */
Signature · 1 line
1.8.3.2