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.
Unified · Split
| @@ -75,14 +75,34 @@ static u32 psci_function_id[PSCI_FN_MAX]; · 74 unmodified lines | |||
| 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) · 114 unmodified lines | |||
| 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) · 78 unmodified lines | |||
| 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 | ||
| @@ -58,6 +58,13 @@ · 57 unmodified lines | |||
| 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 @@ · 14 unmodified lines | |||
| 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 |