diff options
author | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2015-05-26 12:10:32 -0400 |
---|---|---|
committer | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2015-10-02 09:35:17 -0400 |
commit | a5c00bb28da0bb34f901d090839fc448246aa996 (patch) | |
tree | 2588a66ac9d6d872e3e3dabd2c0ecc629a537dea | |
parent | 5f004e0c9fb152a080b47d06dc48bdd29765a734 (diff) |
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 <lorenzo.pieralisi@arm.com>
Tested-by: Jisheng Zhang <jszhang@marvell.com>
Cc: Mark Rutland <mark.rutland@arm.com>
-rw-r--r-- | drivers/firmware/psci.c | 34 | ||||
-rw-r--r-- | include/uapi/linux/psci.h | 12 |
2 files changed, 44 insertions, 2 deletions
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]; | |||
75 | PSCI_0_2_POWER_STATE_TYPE_MASK | \ | 75 | PSCI_0_2_POWER_STATE_TYPE_MASK | \ |
76 | PSCI_0_2_POWER_STATE_AFFL_MASK) | 76 | PSCI_0_2_POWER_STATE_AFFL_MASK) |
77 | 77 | ||
78 | #define PSCI_1_0_EXT_POWER_STATE_MASK \ | ||
79 | (PSCI_1_0_EXT_POWER_STATE_ID_MASK | \ | ||
80 | PSCI_1_0_EXT_POWER_STATE_TYPE_MASK) | ||
81 | |||
82 | static u32 psci_cpu_suspend_feature; | ||
83 | |||
84 | static inline bool psci_has_ext_power_state(void) | ||
85 | { | ||
86 | return psci_cpu_suspend_feature & | ||
87 | PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK; | ||
88 | } | ||
89 | |||
78 | bool psci_power_state_loses_context(u32 state) | 90 | bool psci_power_state_loses_context(u32 state) |
79 | { | 91 | { |
80 | return state & PSCI_0_2_POWER_STATE_TYPE_MASK; | 92 | const u32 mask = psci_has_ext_power_state() ? |
93 | PSCI_1_0_EXT_POWER_STATE_TYPE_MASK : | ||
94 | PSCI_0_2_POWER_STATE_TYPE_MASK; | ||
95 | |||
96 | return state & mask; | ||
81 | } | 97 | } |
82 | 98 | ||
83 | bool psci_power_state_is_valid(u32 state) | 99 | bool psci_power_state_is_valid(u32 state) |
84 | { | 100 | { |
85 | return !(state & ~PSCI_0_2_POWER_STATE_MASK); | 101 | const u32 valid_mask = psci_has_ext_power_state() ? |
102 | PSCI_1_0_EXT_POWER_STATE_MASK : | ||
103 | PSCI_0_2_POWER_STATE_MASK; | ||
104 | |||
105 | return !(state & ~valid_mask); | ||
86 | } | 106 | } |
87 | 107 | ||
88 | static int psci_to_linux_errno(int errno) | 108 | static int psci_to_linux_errno(int errno) |
@@ -203,6 +223,14 @@ static int __init psci_features(u32 psci_func_id) | |||
203 | psci_func_id, 0, 0); | 223 | psci_func_id, 0, 0); |
204 | } | 224 | } |
205 | 225 | ||
226 | static void __init psci_init_cpu_suspend(void) | ||
227 | { | ||
228 | int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]); | ||
229 | |||
230 | if (feature != PSCI_RET_NOT_SUPPORTED) | ||
231 | psci_cpu_suspend_feature = feature; | ||
232 | } | ||
233 | |||
206 | /* | 234 | /* |
207 | * Detect the presence of a resident Trusted OS which may cause CPU_OFF to | 235 | * Detect the presence of a resident Trusted OS which may cause CPU_OFF to |
208 | * return DENIED (which would be fatal). | 236 | * return DENIED (which would be fatal). |
@@ -287,6 +315,8 @@ static int __init psci_probe(void) | |||
287 | 315 | ||
288 | psci_init_migrate(); | 316 | psci_init_migrate(); |
289 | 317 | ||
318 | psci_init_cpu_suspend(); | ||
319 | |||
290 | return 0; | 320 | return 0; |
291 | } | 321 | } |
292 | 322 | ||
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 @@ | |||
58 | #define PSCI_0_2_POWER_STATE_AFFL_MASK \ | 58 | #define PSCI_0_2_POWER_STATE_AFFL_MASK \ |
59 | (0x3 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | 59 | (0x3 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) |
60 | 60 | ||
61 | /* PSCI extended power state encoding for CPU_SUSPEND function */ | ||
62 | #define PSCI_1_0_EXT_POWER_STATE_ID_MASK 0xfffffff | ||
63 | #define PSCI_1_0_EXT_POWER_STATE_ID_SHIFT 0 | ||
64 | #define PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT 30 | ||
65 | #define PSCI_1_0_EXT_POWER_STATE_TYPE_MASK \ | ||
66 | (0x1 << PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT) | ||
67 | |||
61 | /* PSCI v0.2 affinity level state returned by AFFINITY_INFO */ | 68 | /* PSCI v0.2 affinity level state returned by AFFINITY_INFO */ |
62 | #define PSCI_0_2_AFFINITY_LEVEL_ON 0 | 69 | #define PSCI_0_2_AFFINITY_LEVEL_ON 0 |
63 | #define PSCI_0_2_AFFINITY_LEVEL_OFF 1 | 70 | #define PSCI_0_2_AFFINITY_LEVEL_OFF 1 |
@@ -78,6 +85,11 @@ | |||
78 | #define PSCI_VERSION_MINOR(ver) \ | 85 | #define PSCI_VERSION_MINOR(ver) \ |
79 | ((ver) & PSCI_VERSION_MINOR_MASK) | 86 | ((ver) & PSCI_VERSION_MINOR_MASK) |
80 | 87 | ||
88 | /* PSCI features decoding (>=1.0) */ | ||
89 | #define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1 | ||
90 | #define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK \ | ||
91 | (0x1 << PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT) | ||
92 | |||
81 | /* PSCI return values (inclusive of all PSCI versions) */ | 93 | /* PSCI return values (inclusive of all PSCI versions) */ |
82 | #define PSCI_RET_SUCCESS 0 | 94 | #define PSCI_RET_SUCCESS 0 |
83 | #define PSCI_RET_NOT_SUPPORTED -1 | 95 | #define PSCI_RET_NOT_SUPPORTED -1 |