Subject: [PATCH v1 1/2] PSCI: Use DT Function ID values only for old versions of spec

From: [email-masked] (Christoffer Dall)
Date: Wed, 19 Mar 2014 20:06:14 -0700

On Wed, Mar 19, 2014 at 08:54:24PM -0400, Ashwin Chaugule wrote:
> The PSCI v0.2+ spec mandates specific values of Function IDs
> for ARM32 and ARM64. Use DT bindings of Function IDs only
> when using older versions. Use static values otherwise.
> This patch also prepares the code to easily use the ACPI API
> which is based off of PSCI v0.2+.
> 
> Signed-off-by: Ashwin Chaugule <[email-masked]>
> ---
>  arch/arm/include/asm/psci.h   |  15 ++++++
>  arch/arm/kernel/psci.c        | 110 +++++++++++++++++++++++++++++++++++++-----
>  arch/arm64/include/asm/psci.h |  12 +++++
>  arch/arm64/kernel/psci.c      | 106 +++++++++++++++++++++++++++++++++++-----
>  4 files changed, 218 insertions(+), 25 deletions(-)
> 
> diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
> index c4ae171..3f8ebf9 100644
> --- a/arch/arm/include/asm/psci.h
> +++ b/arch/arm/include/asm/psci.h
> @@ -17,6 +17,19 @@
>  #define PSCI_POWER_STATE_TYPE_STANDBY		0
>  #define PSCI_POWER_STATE_TYPE_POWER_DOWN	1
>  
> +/* PSCI Function ID's for ARM32 as per PSCI spec v0.2 */
> +
> +#define PSCI_ID_VERSION				0x84000000
> +#define PSCI_ID_CPU_SUSPEND			0x84000001
> +#define PSCI_ID_CPU_OFF				0x84000002
> +#define PSCI_ID_CPU_ON				0x84000003
> +#define PSCI_ID_AFFINITY_INFO		0x84000004
> +#define PSCI_ID_CPU_MIGRATE			0x84000005
> +#define PSCI_ID_MIGRATE_INFO_TYPE	0x84000006
> +#define PSCI_ID_MIGRATE_INFO_UP_CPU	0x84000007
> +#define PSCI_ID_SYSTEM_OFF			0x84000008
> +#define PSCI_ID_SYSTEM_RESET		0x84000009
> +
>  struct psci_power_state {
>  	u16	id;
>  	u8	type;
> @@ -36,9 +49,11 @@ extern struct smp_operations psci_smp_ops;
>  
>  #ifdef CONFIG_ARM_PSCI
>  void psci_init(void);
> +int psci_get_version(void);
>  bool psci_smp_available(void);
>  #else
>  static inline void psci_init(void) { }
> +static inline int psci_get_version(void) { }
>  static inline bool psci_smp_available(void) { return false; }
>  #endif
>  
> diff --git a/arch/arm/kernel/psci.c b/arch/arm/kernel/psci.c
> index 4693188..48e0b0a 100644
> --- a/arch/arm/kernel/psci.c
> +++ b/arch/arm/kernel/psci.c
> @@ -27,6 +27,7 @@
>  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,
> @@ -110,6 +111,20 @@ static noinline int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1,
>  	return function_id;
>  }
>  
> +#define PSCI_VER_MAJOR_MASK		0xffff0000
> +#define PSCI_VER_MINOR_MASK		0x0000ffff
> +#define PSCI_VER_MAJOR_SHIFT	16
> +
> +static int psci_get_version(void)
> +{
> +	int err;
> +	u32 fn;
> +
> +	fn = PSCI_ID_VERSION;
> +	err = invoke_psci_fn(fn, 0, 0, 0);
> +	return err;
> +}
> +
>  static int psci_cpu_suspend(struct psci_power_state state,
>  			    unsigned long entry_point)
>  {
> @@ -153,25 +168,65 @@ 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",	},
> -	{},
> -};
> +/*
> + * PSCI Function ID's for v0.2+ are well defined so use
> + * static values.
> + */
> +static int psci_static_init(struct device_node *np)
> +{
> +	const char *method;
> +	int err = 0;
> +
> +	pr_info("probing for conduit method from DT.\n");
> +
> +	if (of_property_read_string(np, "method", &method)) {
> +		pr_warn("missing \"method\" property\n");
> +		err = -ENXIO;
> +		goto out_put_node;
> +	}
> +
> +	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);
> +		err = -EINVAL;
> +		goto out_put_node;
> +	}
>  
> -void __init psci_init(void)
> +	pr_info("Using static PSCIv0.2+ function IDs\n");
> +	psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_ID_CPU_SUSPEND;
> +	psci_ops.cpu_suspend = psci_cpu_suspend;
> +
> +	psci_function_id[PSCI_FN_CPU_OFF] = PSCI_ID_CPU_OFF;
> +	psci_ops.cpu_off = psci_cpu_off;
> +
> +	psci_function_id[PSCI_FN_CPU_ON] = PSCI_ID_CPU_ON;
> +	psci_ops.cpu_on = psci_cpu_on;
> +
> +	psci_function_id[PSCI_FN_MIGRATE] = PSCI_ID_CPU_MIGRATE;
> +	psci_ops.migrate = psci_migrate;
> +
> +out_put_node:
> +	of_node_put(np);
> +	return err;
> +}
> +
> +/*
> + * PSCI < v0.2 can override PSCI function ID's via DT.
> + */
> +static int psci_of_init(struct device_node *np)
>  {
> -	struct device_node *np;
>  	const char *method;
>  	u32 id;
> -
> -	np = of_find_matching_node(NULL, psci_of_match);
> -	if (!np)
> -		return;
> +	int err = 0;
>  
>  	pr_info("probing function IDs from device-tree\n");
>  
>  	if (of_property_read_string(np, "method", &method)) {
> -		pr_warning("missing \"method\" property\n");
> +		pr_warn("missing \"method\" property\n");
> +		err = -EINVAL;
>  		goto out_put_node;
>  	}
>  
> @@ -180,7 +235,8 @@ 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);
> +		err = -ENXIO;
>  		goto out_put_node;
>  	}
>  
> @@ -206,5 +262,33 @@ void __init psci_init(void)
>  
>  out_put_node:
>  	of_node_put(np);
> -	return;
> +	return err;
> +}
> +
> +static const struct of_device_id psci_of_match[] __initconst = {
> +	{ .compatible = "arm,psci", .data = psci_of_init},
> +	{ .compatible = "arm,psci-0.2", .data = psci_static_init},
> +	{},
> +};
> +
> +int __init psci_init(void)
> +{
> +	struct device_node *np;
> +	const struct of_device_id *matched_np;
> +	psci_initcall_t init_fn;
> +	int ver = 0;
> +
> +	np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
> +	if (!np)
> +		return -ENODEV;
> +
> +	ver = psci_get_version();
> +
> +	pr_info("using static PSCIv%d.%d Function IDs\n",
> +			(ver & PSCI_VER_MAJOR_MASK) >> PSCI_VER_MAJOR_SHIFT,
> +			(ver & PSCI_VER_MINOR_MASK));
> +
> +
> +	init_fn = (psci_initcall_t)matched_np->data;
> +	return init_fn(np);
>  }
> diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
> index e5312ea..b72678f 100644
> --- a/arch/arm64/include/asm/psci.h
> +++ b/arch/arm64/include/asm/psci.h
> @@ -16,4 +16,16 @@
>  
>  int psci_init(void);
>  
> +/* PSCI Function ID's for ARM64 as per PSCI spec v0.2 */
> +#define PSCI_ID_VERSION				0x84000000
> +#define PSCI_ID_CPU_SUSPEND			0xc4000001
> +#define PSCI_ID_CPU_OFF				0x84000002
> +#define PSCI_ID_CPU_ON				0xc4000003
> +#define PSCI_ID_AFFINITY_INFO		0xc4000004
> +#define PSCI_ID_CPU_MIGRATE			0xc4000005
> +#define PSCI_ID_MIGRATE_INFO_TYPE	0x84000006
> +#define PSCI_ID_MIGRATE_INFO_UP_CPU	0xc4000007
> +#define PSCI_ID_SYSTEM_OFF			0x84000008
> +#define PSCI_ID_SYSTEM_RESET		0x84000009
> +
>  #endif /* __ASM_PSCI_H */
> diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
> index 4f97db3..d4cff4e 100644
> --- a/arch/arm64/kernel/psci.c
> +++ b/arch/arm64/kernel/psci.c
> @@ -45,12 +45,14 @@ 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 *);
>  
>  enum psci_function {
>  	PSCI_FN_CPU_SUSPEND,
>  	PSCI_FN_CPU_ON,
>  	PSCI_FN_CPU_OFF,
>  	PSCI_FN_MIGRATE,
> +	PSCI_FN_AFFINITY_INFO,
>  	PSCI_FN_MAX,
>  };
>  
> @@ -128,6 +130,20 @@ static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1,
>  	return function_id;
>  }
>  
> +#define PSCI_VER_MAJOR_MASK		0xffff0000
> +#define PSCI_VER_MINOR_MASK		0x0000ffff
> +#define PSCI_VER_MAJOR_SHIFT	16
> +
> +static int psci_get_version(void)
> +{
> +	int err;
> +	u32 fn;
> +
> +	fn = PSCI_ID_VERSION;
> +	err = invoke_psci_fn(fn, 0, 0, 0);
> +	return err;
> +}
> +
>  static int psci_cpu_suspend(struct psci_power_state state,
>  			    unsigned long entry_point)
>  {
> @@ -171,26 +187,64 @@ 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",	},
> -	{},
> -};
> +/*
> + * PSCI Function ID's for v0.2+ are well defined so use
> + * static values.
> + */
> +static int psci_static_init(struct device_node *np)
> +{
> +	const char *method;
> +	int err = 0;
>  
> -int __init psci_init(void)
> +	pr_info("probing for conduit method from DT.\n");
> +
> +	if (of_property_read_string(np, "method", &method)) {
> +		pr_warn("missing \"method\" property\n");
> +		err = -ENXIO;
> +		goto out_put_node;
> +	}
> +
> +	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);
> +		err = -EINVAL;
> +		goto out_put_node;
> +	}
> +
> +	pr_info("Using static PSCIv0.2+ function IDs\n");
> +	psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_ID_CPU_SUSPEND;
> +	psci_ops.cpu_suspend = psci_cpu_suspend;
> +
> +	psci_function_id[PSCI_FN_CPU_OFF] = PSCI_ID_CPU_OFF;
> +	psci_ops.cpu_off = psci_cpu_off;
> +
> +	psci_function_id[PSCI_FN_CPU_ON] = PSCI_ID_CPU_ON;
> +	psci_ops.cpu_on = psci_cpu_on;
> +
> +	psci_function_id[PSCI_FN_MIGRATE] = PSCI_ID_CPU_MIGRATE;
> +	psci_ops.migrate = psci_migrate;
> +
> +out_put_node:
> +	of_node_put(np);
> +	return err;

Can any of this code not be shared between arm and arm64?

Looks almost identical.

-Christoffer