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@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