[Linaro-acpi] [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions
Sudeep Holla
sudeep.holla at arm.com
Mon Mar 31 12:52:50 EDT 2014
Hi Ashwin,
On 31/03/14 16:02, Ashwin Chaugule wrote:
> 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 <ashwin.chaugule at linaro.org>
> ---
> 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
>
> diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
> index c4ae171..b93e34a 100644
> --- a/arch/arm/include/asm/psci.h
> +++ b/arch/arm/include/asm/psci.h
> @@ -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
>
> diff --git a/arch/arm/kernel/psci.c b/arch/arm/kernel/psci.c
> index 4693188..46b23b6 100644
> --- a/arch/arm/kernel/psci.c
> +++ b/arch/arm/kernel/psci.c
> @@ -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;
> +
> + 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
More information about the linux-arm-kernel
mailing list