From 2217d7c68e5caf50ec86b8c75c76bf06eb4b2c45 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Fri, 22 May 2015 14:31:37 +0100 Subject: drivers: firmware: psci: add INVALID_ADDRESS return value PSCI 1.0 introduces the INVALID_ADDRESS return value for functions that take an address as input parameter (eg CPU_SUSPEND). This patch adds INVALID_ADDRESS return value to kernel code and updates the PSCI to linux error conversion to take it into account. The kernel error value associated to INVALID_ADDRESS is set to the error returned when the PSCI error code is INVALID_PARAMETERS to comply with current call sites expected return value, given that the kernel at present has no use for the additional error information reported. Signed-off-by: Lorenzo Pieralisi Acked-by: Sudeep Holla Acked-by: Mark Rutland Tested-by: Jisheng Zhang --- drivers/firmware/psci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 42700f09a8c5..0821e332c85a 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -78,6 +78,7 @@ static int psci_to_linux_errno(int errno) case PSCI_RET_NOT_SUPPORTED: return -EOPNOTSUPP; case PSCI_RET_INVALID_PARAMS: + case PSCI_RET_INVALID_ADDRESS: return -EINVAL; case PSCI_RET_DENIED: return -EPERM; -- cgit v1.2.3 From 068654c200cc32966ce7906ca0bd096b9b97e988 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 26 May 2015 16:49:01 +0100 Subject: drivers: firmware: psci: move power_state handling to generic code Functions implemented on arm64 to check if a power_state parameter is valid and if the power_state implies context loss are not arm64 specific and should be moved to generic code so that they can be reused on arm systems too. This patch moves the functions handling the power_state parameter to generic PSCI firmware layer code. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Acked-by: Sudeep Holla Tested-by: Jisheng Zhang Cc: Catalin Marinas Cc: Mark Rutland --- arch/arm64/kernel/psci.c | 14 -------------- drivers/firmware/psci.c | 15 +++++++++++++++ include/linux/psci.h | 2 ++ 3 files changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers/firmware') diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index aa94a88f6279..f67f35b6edb1 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -30,20 +30,6 @@ #include #include -static bool psci_power_state_loses_context(u32 state) -{ - return state & PSCI_0_2_POWER_STATE_TYPE_MASK; -} - -static bool psci_power_state_is_valid(u32 state) -{ - const u32 valid_mask = PSCI_0_2_POWER_STATE_ID_MASK | - PSCI_0_2_POWER_STATE_TYPE_MASK | - PSCI_0_2_POWER_STATE_AFFL_MASK; - - return !(state & ~valid_mask); -} - static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu) diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 0821e332c85a..3157eb0ef300 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -70,6 +70,21 @@ enum psci_function { static u32 psci_function_id[PSCI_FN_MAX]; +#define PSCI_0_2_POWER_STATE_MASK \ + (PSCI_0_2_POWER_STATE_ID_MASK | \ + PSCI_0_2_POWER_STATE_TYPE_MASK | \ + PSCI_0_2_POWER_STATE_AFFL_MASK) + +bool psci_power_state_loses_context(u32 state) +{ + return state & PSCI_0_2_POWER_STATE_TYPE_MASK; +} + +bool psci_power_state_is_valid(u32 state) +{ + return !(state & ~PSCI_0_2_POWER_STATE_MASK); +} + static int psci_to_linux_errno(int errno) { switch (errno) { diff --git a/include/linux/psci.h b/include/linux/psci.h index a682fcc91c33..12c4865457ad 100644 --- a/include/linux/psci.h +++ b/include/linux/psci.h @@ -21,6 +21,8 @@ #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 bool psci_tos_resident_on(int cpu); +bool psci_power_state_loses_context(u32 state); +bool psci_power_state_is_valid(u32 state); struct psci_operations { int (*cpu_suspend)(u32 state, unsigned long entry_point); -- cgit v1.2.3 From 5f004e0c9fb152a080b47d06dc48bdd29765a734 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 26 May 2015 17:06:21 +0100 Subject: drivers: firmware: psci: add PSCI_FEATURES call PSCI v1.0 introduces a PSCI_FEATURES call that allows to probe for features related to a specific function identifier. This patch adds PSCI_FEATURES support to the PSCI firmware layer. Signed-off-by: Lorenzo Pieralisi Tested-by: Jisheng Zhang Cc: Mark Rutland --- drivers/firmware/psci.c | 6 ++++++ include/uapi/linux/psci.h | 2 ++ 2 files changed, 8 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 3157eb0ef300..cec948b4ccd5 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -197,6 +197,12 @@ static void psci_sys_poweroff(void) invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); } +static int __init psci_features(u32 psci_func_id) +{ + return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES, + psci_func_id, 0, 0); +} + /* * Detect the presence of a resident Trusted OS which may cause CPU_OFF to * return DENIED (which would be fatal). diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h index 64469e64688f..187b828d77b3 100644 --- a/include/uapi/linux/psci.h +++ b/include/uapi/linux/psci.h @@ -46,6 +46,8 @@ #define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5) #define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) +#define PSCI_1_0_FN_PSCI_FEATURES PSCI_0_2_FN(10) + /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff #define PSCI_0_2_POWER_STATE_ID_SHIFT 0 -- cgit v1.2.3 From a5c00bb28da0bb34f901d090839fc448246aa996 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 26 May 2015 17:10:32 +0100 Subject: drivers: firmware: psci: add extended stateid power_state support PSCI v1.0 augmented the power_state parameter format specification (extended stateid) and introduced a way to probe it through the PSCI_FEATURES interface. This patch implements code that detects the power_state format at run-time through the PSCI_FEATURES interface, so that the power_state argument can be properly detected and validated in the kernel according to the information provided through firmware. Signed-off-by: Lorenzo Pieralisi Tested-by: Jisheng Zhang Cc: Mark Rutland --- drivers/firmware/psci.c | 34 ++++++++++++++++++++++++++++++++-- include/uapi/linux/psci.h | 12 ++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index cec948b4ccd5..384224320455 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -75,14 +75,34 @@ static u32 psci_function_id[PSCI_FN_MAX]; PSCI_0_2_POWER_STATE_TYPE_MASK | \ PSCI_0_2_POWER_STATE_AFFL_MASK) +#define PSCI_1_0_EXT_POWER_STATE_MASK \ + (PSCI_1_0_EXT_POWER_STATE_ID_MASK | \ + PSCI_1_0_EXT_POWER_STATE_TYPE_MASK) + +static u32 psci_cpu_suspend_feature; + +static inline bool psci_has_ext_power_state(void) +{ + return psci_cpu_suspend_feature & + PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK; +} + bool psci_power_state_loses_context(u32 state) { - return state & PSCI_0_2_POWER_STATE_TYPE_MASK; + const u32 mask = psci_has_ext_power_state() ? + PSCI_1_0_EXT_POWER_STATE_TYPE_MASK : + PSCI_0_2_POWER_STATE_TYPE_MASK; + + return state & mask; } bool psci_power_state_is_valid(u32 state) { - return !(state & ~PSCI_0_2_POWER_STATE_MASK); + const u32 valid_mask = psci_has_ext_power_state() ? + PSCI_1_0_EXT_POWER_STATE_MASK : + PSCI_0_2_POWER_STATE_MASK; + + return !(state & ~valid_mask); } static int psci_to_linux_errno(int errno) @@ -203,6 +223,14 @@ static int __init psci_features(u32 psci_func_id) psci_func_id, 0, 0); } +static void __init psci_init_cpu_suspend(void) +{ + int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]); + + if (feature != PSCI_RET_NOT_SUPPORTED) + psci_cpu_suspend_feature = feature; +} + /* * Detect the presence of a resident Trusted OS which may cause CPU_OFF to * return DENIED (which would be fatal). @@ -287,6 +315,8 @@ static int __init psci_probe(void) psci_init_migrate(); + psci_init_cpu_suspend(); + return 0; } diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h index 187b828d77b3..0a9485f3c6c3 100644 --- a/include/uapi/linux/psci.h +++ b/include/uapi/linux/psci.h @@ -58,6 +58,13 @@ #define PSCI_0_2_POWER_STATE_AFFL_MASK \ (0x3 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) +/* PSCI extended power state encoding for CPU_SUSPEND function */ +#define PSCI_1_0_EXT_POWER_STATE_ID_MASK 0xfffffff +#define PSCI_1_0_EXT_POWER_STATE_ID_SHIFT 0 +#define PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT 30 +#define PSCI_1_0_EXT_POWER_STATE_TYPE_MASK \ + (0x1 << PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT) + /* PSCI v0.2 affinity level state returned by AFFINITY_INFO */ #define PSCI_0_2_AFFINITY_LEVEL_ON 0 #define PSCI_0_2_AFFINITY_LEVEL_OFF 1 @@ -78,6 +85,11 @@ #define PSCI_VERSION_MINOR(ver) \ ((ver) & PSCI_VERSION_MINOR_MASK) +/* PSCI features decoding (>=1.0) */ +#define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1 +#define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK \ + (0x1 << PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT) + /* PSCI return values (inclusive of all PSCI versions) */ #define PSCI_RET_SUCCESS 0 #define PSCI_RET_NOT_SUPPORTED -1 -- cgit v1.2.3 From 0fc197c7cb3b1139fccb3b92e8db19a93f81f6fb Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 26 May 2015 13:06:57 +0100 Subject: drivers: firmware: psci: add PSCI v1.0 DT bindings PSCI 1.0 is designed to be fully compliant to the PSCI 0.2 specification, with minor differences that are described in the PSCI specification. In particular, PSCI v1.0 augments the specification with a new power_state format (extended stateid - probeable through the PSCI_FEATURES call), changes some function return codes and functions usage requirements wrt PSCI 0.2. These changes mean that 1.0 vs 0.2 compliancy should be enforced through a DT compatible string that allows firmware to specify 1.0 only compliancy so that older kernels are prevented from using PSCI 1.0 FW implementations in a non-compatible way (eg by calling a 1.0 FW implementation and expecting 0.2 behaviour). This patch adds PSCI 1.0 DT bindings and related compatible string. Signed-off-by: Lorenzo Pieralisi Acked-by: Sudeep Holla Tested-by: Jisheng Zhang Cc: Mark Rutland --- Documentation/devicetree/bindings/arm/psci.txt | 6 ++++++ drivers/firmware/psci.c | 1 + 2 files changed, 7 insertions(+) (limited to 'drivers/firmware') diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt index 5aa40ede0e99..a9adab84e2fe 100644 --- a/Documentation/devicetree/bindings/arm/psci.txt +++ b/Documentation/devicetree/bindings/arm/psci.txt @@ -31,6 +31,10 @@ Main node required properties: support, but are permitted to be present for compatibility with existing software when "arm,psci" is later in the compatible list. + * "arm,psci-1.0" : for implementations complying to PSCI 1.0. PSCI 1.0 is + backward compatible with PSCI 0.2 with minor specification updates, + as defined in the PSCI specification[2]. + - method : The method of calling the PSCI firmware. Permitted values are: @@ -100,3 +104,5 @@ Case 3: PSCI v0.2 and PSCI v0.1. [1] Kernel documentation - ARM idle states bindings Documentation/devicetree/bindings/arm/idle-states.txt +[2] Power State Coordination Interface (PSCI) specification + http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 384224320455..442a42b5cece 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -392,6 +392,7 @@ out_put_node: static const struct of_device_id const psci_of_match[] __initconst = { { .compatible = "arm,psci", .data = psci_0_1_init}, { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, + { .compatible = "arm,psci-1.0", .data = psci_0_2_init}, {}, }; -- cgit v1.2.3 From 029180b1c99046831c33ed43fdbdb620506cb15b Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 18 Jun 2015 15:41:33 +0100 Subject: drivers: firmware: psci: define more generic PSCI_FN_NATIVE macro This patch replaces the definition and usage of PSCI_0_2_FN_NATIVE with the new and more generic macro PSCI_FN_NATIVE that can be used with any version. This will be useful for the new features introduced in PSCIv1.0 and for any future revisions. Cc: Mark Rutland Cc: Lorenzo Pieralisi Signed-off-by: Sudeep Holla Acked-by: Lorenzo Pieralisi --- drivers/firmware/psci.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 442a42b5cece..1fa7284fb21d 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -29,14 +29,14 @@ /* * While a 64-bit OS can make calls with SMC32 calling conventions, for some - * calls it is necessary to use SMC64 to pass or return 64-bit values. For such - * calls PSCI_0_2_FN_NATIVE(x) will choose the appropriate (native-width) - * function ID. + * calls it is necessary to use SMC64 to pass or return 64-bit values. + * For such calls PSCI_FN_NATIVE(version, name) will choose the appropriate + * (native-width) function ID. */ #ifdef CONFIG_64BIT -#define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN64_##name +#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name #else -#define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN_##name +#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name #endif /* @@ -170,7 +170,7 @@ static int psci_migrate(unsigned long cpuid) static int psci_affinity_info(unsigned long target_affinity, unsigned long lowest_affinity_level) { - return invoke_psci_fn(PSCI_0_2_FN_NATIVE(AFFINITY_INFO), + return invoke_psci_fn(PSCI_FN_NATIVE(0_2, AFFINITY_INFO), target_affinity, lowest_affinity_level, 0); } @@ -181,7 +181,7 @@ static int psci_migrate_info_type(void) static unsigned long psci_migrate_info_up_cpu(void) { - return invoke_psci_fn(PSCI_0_2_FN_NATIVE(MIGRATE_INFO_UP_CPU), + return invoke_psci_fn(PSCI_FN_NATIVE(0_2, MIGRATE_INFO_UP_CPU), 0, 0, 0); } @@ -274,16 +274,17 @@ static void __init psci_init_migrate(void) static void __init psci_0_2_set_functions(void) { pr_info("Using standard PSCI v0.2 function IDs\n"); - psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_NATIVE(CPU_SUSPEND); + psci_function_id[PSCI_FN_CPU_SUSPEND] = + PSCI_FN_NATIVE(0_2, CPU_SUSPEND); psci_ops.cpu_suspend = psci_cpu_suspend; psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; psci_ops.cpu_off = psci_cpu_off; - psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_NATIVE(CPU_ON); + psci_function_id[PSCI_FN_CPU_ON] = PSCI_FN_NATIVE(0_2, CPU_ON); psci_ops.cpu_on = psci_cpu_on; - psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_NATIVE(MIGRATE); + psci_function_id[PSCI_FN_MIGRATE] = PSCI_FN_NATIVE(0_2, MIGRATE); psci_ops.migrate = psci_migrate; psci_ops.affinity_info = psci_affinity_info; -- cgit v1.2.3 From faf7ec4a92c0231d1079177095077c162eb9b466 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 18 Jun 2015 15:41:34 +0100 Subject: drivers: firmware: psci: add system suspend support PSCI v1.0 introduces a new API called PSCI_SYSTEM_SUSPEND. This API provides the mechanism by which the calling OS can request entry into the deepest possible system sleep state. It meets all the necessary preconditions for entering suspend to RAM state in Linux. This patch adds support for PSCI_SYSTEM_SUSPEND in psci firmware and registers a psci system suspend operation to implement the suspend-to-RAM(s2r) in a generic way on all the platforms implementing PSCI. Cc: Mark Rutland Cc: Lorenzo Pieralisi Signed-off-by: Sudeep Holla Acked-by: Lorenzo Pieralisi --- drivers/firmware/psci.c | 33 +++++++++++++++++++++++++++++++++ include/uapi/linux/psci.h | 3 +++ 2 files changed, 36 insertions(+) (limited to 'drivers/firmware') diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 1fa7284fb21d..492db42c4e08 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -20,12 +20,14 @@ #include #include #include +#include #include #include #include #include +#include /* * While a 64-bit OS can make calls with SMC32 calling conventions, for some @@ -223,6 +225,35 @@ static int __init psci_features(u32 psci_func_id) psci_func_id, 0, 0); } +static int psci_system_suspend(unsigned long unused) +{ + return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), + virt_to_phys(cpu_resume), 0, 0); +} + +static int psci_system_suspend_enter(suspend_state_t state) +{ + return cpu_suspend(0, psci_system_suspend); +} + +static const struct platform_suspend_ops psci_suspend_ops = { + .valid = suspend_valid_only_mem, + .enter = psci_system_suspend_enter, +}; + +static void __init psci_init_system_suspend(void) +{ + int ret; + + if (!IS_ENABLED(CONFIG_SUSPEND)) + return; + + ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND)); + + if (ret != PSCI_RET_NOT_SUPPORTED) + suspend_set_ops(&psci_suspend_ops); +} + static void __init psci_init_cpu_suspend(void) { int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]); @@ -318,6 +349,8 @@ static int __init psci_probe(void) psci_init_cpu_suspend(); + psci_init_system_suspend(); + return 0; } diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h index 0a9485f3c6c3..3d7a0fc021a7 100644 --- a/include/uapi/linux/psci.h +++ b/include/uapi/linux/psci.h @@ -47,6 +47,9 @@ #define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) #define PSCI_1_0_FN_PSCI_FEATURES PSCI_0_2_FN(10) +#define PSCI_1_0_FN_SYSTEM_SUSPEND PSCI_0_2_FN(14) + +#define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14) /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff -- cgit v1.2.3