diff options
-rw-r--r-- | arch/arm64/kernel/acpi.c | 95 |
1 files changed, 59 insertions, 36 deletions
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index a70f7141c0f6..172b7c9f6881 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c | |||
@@ -218,43 +218,60 @@ void __init acpi_init_cpus(void) | |||
218 | pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); | 218 | pr_info("%d CPUs enabled, %d CPUs total\n", enabled_cpus, total_cpus); |
219 | } | 219 | } |
220 | 220 | ||
221 | static int __init acpi_parse_fadt(struct acpi_table_header *table) | 221 | /* |
222 | * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity | ||
223 | * checks on it | ||
224 | * | ||
225 | * Return 0 on success, <0 on failure | ||
226 | */ | ||
227 | static int __init acpi_fadt_sanity_check(void) | ||
222 | { | 228 | { |
223 | struct acpi_table_fadt *fadt = (struct acpi_table_fadt *)table; | 229 | struct acpi_table_header *table; |
230 | struct acpi_table_fadt *fadt; | ||
231 | acpi_status status; | ||
232 | acpi_size tbl_size; | ||
233 | int ret = 0; | ||
234 | |||
235 | /* | ||
236 | * FADT is required on arm64; retrieve it to check its presence | ||
237 | * and carry out revision and ACPI HW reduced compliancy tests | ||
238 | */ | ||
239 | status = acpi_get_table_with_size(ACPI_SIG_FADT, 0, &table, &tbl_size); | ||
240 | if (ACPI_FAILURE(status)) { | ||
241 | const char *msg = acpi_format_exception(status); | ||
242 | |||
243 | pr_err("Failed to get FADT table, %s\n", msg); | ||
244 | return -ENODEV; | ||
245 | } | ||
246 | |||
247 | fadt = (struct acpi_table_fadt *)table; | ||
224 | 248 | ||
225 | /* | 249 | /* |
226 | * Revision in table header is the FADT Major revision, and there | 250 | * Revision in table header is the FADT Major revision, and there |
227 | * is a minor revision of FADT which was introduced by ACPI 5.1, | 251 | * is a minor revision of FADT which was introduced by ACPI 5.1, |
228 | * we only deal with ACPI 5.1 or newer revision to get GIC and SMP | 252 | * we only deal with ACPI 5.1 or newer revision to get GIC and SMP |
229 | * boot protocol configuration data, or we will disable ACPI. | 253 | * boot protocol configuration data. |
230 | */ | 254 | */ |
231 | if (table->revision > 5 || | 255 | if (table->revision < 5 || |
232 | (table->revision == 5 && fadt->minor_revision >= 1)) { | 256 | (table->revision == 5 && fadt->minor_revision < 1)) { |
233 | if (!acpi_gbl_reduced_hardware) { | 257 | pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n", |
234 | pr_err("Not hardware reduced ACPI mode, will not be supported\n"); | 258 | table->revision, fadt->minor_revision); |
235 | goto disable_acpi; | 259 | ret = -EINVAL; |
236 | } | 260 | goto out; |
237 | |||
238 | /* | ||
239 | * ACPI 5.1 only has two explicit methods to boot up SMP, | ||
240 | * PSCI and Parking protocol, but the Parking protocol is | ||
241 | * only specified for ARMv7 now, so make PSCI as the only | ||
242 | * way for the SMP boot protocol before some updates for | ||
243 | * the Parking protocol spec. | ||
244 | */ | ||
245 | if (acpi_psci_present()) | ||
246 | return 0; | ||
247 | |||
248 | pr_warn("No PSCI support, will not bring up secondary CPUs\n"); | ||
249 | return -EOPNOTSUPP; | ||
250 | } | 261 | } |
251 | 262 | ||
252 | pr_warn("Unsupported FADT revision %d.%d, should be 5.1+, will disable ACPI\n", | 263 | if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) { |
253 | table->revision, fadt->minor_revision); | 264 | pr_err("FADT not ACPI hardware reduced compliant\n"); |
265 | ret = -EINVAL; | ||
266 | } | ||
254 | 267 | ||
255 | disable_acpi: | 268 | out: |
256 | disable_acpi(); | 269 | /* |
257 | return -EINVAL; | 270 | * acpi_get_table_with_size() creates FADT table mapping that |
271 | * should be released after parsing and before resuming boot | ||
272 | */ | ||
273 | early_acpi_os_unmap_memory(table, tbl_size); | ||
274 | return ret; | ||
258 | } | 275 | } |
259 | 276 | ||
260 | /* | 277 | /* |
@@ -262,9 +279,13 @@ disable_acpi: | |||
262 | * 1. find RSDP and get its address, and then find XSDT | 279 | * 1. find RSDP and get its address, and then find XSDT |
263 | * 2. extract all tables and checksums them all | 280 | * 2. extract all tables and checksums them all |
264 | * 3. check ACPI FADT revision | 281 | * 3. check ACPI FADT revision |
282 | * 4. check ACPI FADT HW reduced flag | ||
265 | * | 283 | * |
266 | * We can parse ACPI boot-time tables such as MADT after | 284 | * We can parse ACPI boot-time tables such as MADT after |
267 | * this function is called. | 285 | * this function is called. |
286 | * | ||
287 | * ACPI is enabled on return if ACPI tables initialized and sanity checks | ||
288 | * passed, disabled otherwise | ||
268 | */ | 289 | */ |
269 | void __init acpi_boot_table_init(void) | 290 | void __init acpi_boot_table_init(void) |
270 | { | 291 | { |
@@ -278,18 +299,20 @@ void __init acpi_boot_table_init(void) | |||
278 | (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL))) | 299 | (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL))) |
279 | return; | 300 | return; |
280 | 301 | ||
302 | /* | ||
303 | * ACPI is disabled at this point. Enable it in order to parse | ||
304 | * the ACPI tables and carry out sanity checks | ||
305 | */ | ||
281 | enable_acpi(); | 306 | enable_acpi(); |
282 | 307 | ||
283 | /* Initialize the ACPI boot-time table parser. */ | 308 | /* |
284 | if (acpi_table_init()) { | 309 | * If ACPI tables are initialized and FADT sanity checks passed, |
285 | disable_acpi(); | 310 | * leave ACPI enabled and carry on booting; otherwise disable ACPI |
286 | return; | 311 | * on initialization error. |
287 | } | 312 | */ |
288 | 313 | if (acpi_table_init() || acpi_fadt_sanity_check()) { | |
289 | if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt)) { | 314 | pr_err("Failed to init ACPI tables\n"); |
290 | /* disable ACPI if no FADT is found */ | ||
291 | disable_acpi(); | 315 | disable_acpi(); |
292 | pr_err("Can't find FADT\n"); | ||
293 | } | 316 | } |
294 | } | 317 | } |
295 | 318 | ||