* [PATCH v4 0/3] PSCI v0.2 support and DT bindings
@ 2014-03-31 15:02 Ashwin Chaugule
2014-03-31 15:02 ` [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions Ashwin Chaugule
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Ashwin Chaugule @ 2014-03-31 15:02 UTC (permalink / raw)
To: linux-arm-kernel
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
--
1.8.3.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions
2014-03-31 15:02 [PATCH v4 0/3] PSCI v0.2 support and DT bindings Ashwin Chaugule
@ 2014-03-31 15:02 ` Ashwin Chaugule
2014-03-31 16:52 ` [Linaro-acpi] " Sudeep Holla
2014-03-31 15:02 ` [PATCH v4 2/3] Documentation: devicetree: Add new binding for PSCIv0.2 Ashwin Chaugule
2014-03-31 15:02 ` [PATCH v4 3/3] ARM: Check if a CPU has gone offline Ashwin Chaugule
2 siblings, 1 reply; 8+ messages in thread
From: Ashwin Chaugule @ 2014-03-31 15:02 UTC (permalink / raw)
To: linux-arm-kernel
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");
+ } else {
+ pr_info("PSCIv%d.%d detected in firmware.\n",
+ PSCI_VER_MAJOR(ver), PSCI_VER_MINOR(ver));
+
+ if (PSCI_VER_MAJOR(ver) == 0 && PSCI_VER_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_ID_CPU_SUSPEND_32;
+ 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_32;
+ psci_ops.cpu_on = psci_cpu_on;
+
+ psci_function_id[PSCI_FN_MIGRATE] = PSCI_ID_CPU_MIGRATE_32;
+ psci_ops.migrate = psci_migrate;
+
+ psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_ID_AFFINITY_INFO_32;
+ psci_ops.affinity_info = psci_affinity_info;
+
+ psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = PSCI_ID_MIGRATE_INFO_TYPE;
+ psci_ops.migrate_info_type = psci_migrate_info_type;
+
+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;
@@ -206,5 +285,25 @@ 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_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);
}
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index 4f97db3..46b72b6 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
+#include <uapi/linux/psci.h>
#include <asm/compiler.h>
#include <asm/cpu_ops.h>
@@ -40,27 +41,28 @@ 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);
};
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_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) {
@@ -77,13 +79,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)
@@ -128,6 +123,14 @@ static noinline int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 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)
{
@@ -171,28 +174,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;
-int __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 = 0;
+ int err;
+ u32 fn;
- np = of_find_matching_node(NULL, psci_of_match);
- if (!np)
- return -ENODEV;
+ 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");
- err = -ENXIO;
- goto out_put_node;
+ pr_warn("missing \"method\" property\n");
+ return -ENXIO;
}
if (!strcmp("hvc", method)) {
@@ -200,11 +211,79 @@ int __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);
- err = -EINVAL;
+ 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");
+ } else {
+ pr_info("PSCIv%d.%d detected in firmware.\n",
+ PSCI_VER_MAJOR(ver), PSCI_VER_MINOR(ver));
+
+ if (PSCI_VER_MAJOR(ver) == 0 && PSCI_VER_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_ID_CPU_SUSPEND_64;
+ 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_64;
+ psci_ops.cpu_on = psci_cpu_on;
+
+ psci_function_id[PSCI_FN_MIGRATE] = PSCI_ID_CPU_MIGRATE_64;
+ psci_ops.migrate = psci_migrate;
+
+ psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_ID_AFFINITY_INFO_64;
+ psci_ops.affinity_info = psci_affinity_info;
+
+ psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = PSCI_ID_MIGRATE_INFO_TYPE;
+ psci_ops.migrate_info_type = psci_migrate_info_type;
+
+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;
@@ -230,6 +309,27 @@ out_put_node:
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);
+}
+
#ifdef CONFIG_SMP
static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu)
diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h
new file mode 100644
index 0000000..0354bb1
--- /dev/null
+++ b/include/uapi/linux/psci.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _UAPI_LINUX_PSCI_H
+#define _UAPI_LINUX_PSCI_H
+
+/* PSCI Function IDs as per PSCI spec v0.2 */
+#define PSCI_ID_VERSION 0x84000000
+#define PSCI_ID_CPU_SUSPEND_32 0x84000001
+#define PSCI_ID_CPU_SUSPEND_64 0xc4000001
+#define PSCI_ID_CPU_OFF 0x84000002
+#define PSCI_ID_CPU_ON_32 0x84000003
+#define PSCI_ID_CPU_ON_64 0xC4000003
+#define PSCI_ID_AFFINITY_INFO_32 0x84000004
+#define PSCI_ID_AFFINITY_INFO_64 0xC4000004
+#define PSCI_ID_CPU_MIGRATE_32 0x84000005
+#define PSCI_ID_CPU_MIGRATE_64 0xc4000005
+#define PSCI_ID_MIGRATE_INFO_TYPE 0x84000006
+#define PSCI_ID_MIGRATE_INFO_UP_CPU_32 0x84000007
+#define PSCI_ID_MIGRATE_INFO_UP_CPU_64 0xc4000007
+#define PSCI_ID_SYSTEM_OFF 0x84000008
+#define PSCI_ID_SYSTEM_RESET 0x84000009
+
+#define PSCI_RET_SUCCESS 0
+#define PSCI_RET_EOPNOTSUPP -1
+#define PSCI_RET_EINVAL -2
+#define PSCI_RET_EPERM -3
+#define PSCI_RET_ALREADY_ON -4
+#define PSCI_RET_ON_PENDING -5
+#define PSCI_RET_INTERNAL_FAILURE -6
+#define PSCI_RET_NOT_PRESENT -7
+#define PSCI_RET_DISABLED -8
+
+#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
+
+#define PSCI_VER_MAJOR_MASK 0xffff0000
+#define PSCI_VER_MINOR_MASK 0x0000ffff
+#define PSCI_VER_MAJOR_SHIFT 16
+#define PSCI_VER_MAJOR(ver) \
+ ((ver & PSCI_VER_MAJOR_MASK) >> PSCI_VER_MAJOR_SHIFT)
+#define PSCI_VER_MINOR(ver) (ver & PSCI_VER_MINOR_MASK)
+
+#endif /* _UAPI_LINUX_PSCI_H */
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 2/3] Documentation: devicetree: Add new binding for PSCIv0.2
2014-03-31 15:02 [PATCH v4 0/3] PSCI v0.2 support and DT bindings Ashwin Chaugule
2014-03-31 15:02 ` [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions Ashwin Chaugule
@ 2014-03-31 15:02 ` Ashwin Chaugule
2014-03-31 15:02 ` [PATCH v4 3/3] ARM: Check if a CPU has gone offline Ashwin Chaugule
2 siblings, 0 replies; 8+ messages in thread
From: Ashwin Chaugule @ 2014-03-31 15:02 UTC (permalink / raw)
To: linux-arm-kernel
The 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.
Signed-off-by: Ashwin Chaugule <ashwin.chaugule@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/arm/psci.txt | 35 +++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
index 433afe9..d01a90b 100644
--- a/Documentation/devicetree/bindings/arm/psci.txt
+++ b/Documentation/devicetree/bindings/arm/psci.txt
@@ -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 >;
+
+ ...
+ };
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v4 3/3] ARM: Check if a CPU has gone offline
2014-03-31 15:02 [PATCH v4 0/3] PSCI v0.2 support and DT bindings Ashwin Chaugule
2014-03-31 15:02 ` [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions Ashwin Chaugule
2014-03-31 15:02 ` [PATCH v4 2/3] Documentation: devicetree: Add new binding for PSCIv0.2 Ashwin Chaugule
@ 2014-03-31 15:02 ` Ashwin Chaugule
2 siblings, 0 replies; 8+ messages in thread
From: Ashwin Chaugule @ 2014-03-31 15:02 UTC (permalink / raw)
To: linux-arm-kernel
PSCIv0.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.
Signed-off-by: Ashwin Chaugule <ashwin.chaugule@linaro.org>
Reviewed-by: Rob Herring <robh@kernel.org>
---
arch/arm/kernel/psci_smp.c | 21 +++++++++++++++++++++
include/uapi/linux/psci.h | 5 +++++
2 files changed, 26 insertions(+)
diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c
index 570a48c..c6f1420 100644
--- a/arch/arm/kernel/psci_smp.c
+++ b/arch/arm/kernel/psci_smp.c
@@ -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
};
diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h
index 0354bb1..65b4878 100644
--- a/include/uapi/linux/psci.h
+++ b/include/uapi/linux/psci.h
@@ -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 */
--
1.8.3.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [Linaro-acpi] [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions
2014-03-31 15:02 ` [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions Ashwin Chaugule
@ 2014-03-31 16:52 ` Sudeep Holla
2014-03-31 17:09 ` Ashwin Chaugule
0 siblings, 1 reply; 8+ messages in thread
From: Sudeep Holla @ 2014-03-31 16:52 UTC (permalink / raw)
To: linux-arm-kernel
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
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Linaro-acpi] [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions
2014-03-31 16:52 ` [Linaro-acpi] " Sudeep Holla
@ 2014-03-31 17:09 ` Ashwin Chaugule
2014-03-31 17:25 ` Ashwin Chaugule
0 siblings, 1 reply; 8+ messages in thread
From: Ashwin Chaugule @ 2014-03-31 17:09 UTC (permalink / raw)
To: linux-arm-kernel
Hi Sudeep,
On 31 March 2014 12:52, Sudeep Holla <sudeep.holla@arm.com> wrote:
>> + 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
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Linaro-acpi] [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions
2014-03-31 17:09 ` Ashwin Chaugule
@ 2014-03-31 17:25 ` Ashwin Chaugule
2014-03-31 18:25 ` Sudeep Holla
0 siblings, 1 reply; 8+ messages in thread
From: Ashwin Chaugule @ 2014-03-31 17:25 UTC (permalink / raw)
To: linux-arm-kernel
On 31 March 2014 13:09, Ashwin Chaugule <ashwin.chaugule@linaro.org> wrote:
> Hi Sudeep,
>
> On 31 March 2014 12:52, Sudeep Holla <sudeep.holla@arm.com> wrote:
>
>>> + 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.
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;
>
> Cheers,
> Ashwin
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Linaro-acpi] [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions
2014-03-31 17:25 ` Ashwin Chaugule
@ 2014-03-31 18:25 ` Sudeep Holla
0 siblings, 0 replies; 8+ messages in thread
From: Sudeep Holla @ 2014-03-31 18:25 UTC (permalink / raw)
To: linux-arm-kernel
Hi Ashwin,
On 31/03/14 18:25, Ashwin Chaugule wrote:
> On 31 March 2014 13:09, Ashwin Chaugule <ashwin.chaugule@linaro.org> wrote:
>> Hi Sudeep,
>>
>> On 31 March 2014 12:52, Sudeep Holla <sudeep.holla@arm.com> wrote:
>>
>>>> + 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.
>
> 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
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2014-03-31 18:25 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-31 15:02 [PATCH v4 0/3] PSCI v0.2 support and DT bindings Ashwin Chaugule
2014-03-31 15:02 ` [PATCH v4 1/3] PSCI: Add initial support for PSCIv0.2 functions Ashwin Chaugule
2014-03-31 16:52 ` [Linaro-acpi] " Sudeep Holla
2014-03-31 17:09 ` Ashwin Chaugule
2014-03-31 17:25 ` Ashwin Chaugule
2014-03-31 18:25 ` Sudeep Holla
2014-03-31 15:02 ` [PATCH v4 2/3] Documentation: devicetree: Add new binding for PSCIv0.2 Ashwin Chaugule
2014-03-31 15:02 ` [PATCH v4 3/3] ARM: Check if a CPU has gone offline Ashwin Chaugule
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).