diff options
Diffstat (limited to 'drivers/acpi/apei/ghes.c')
-rw-r--r-- | drivers/acpi/apei/ghes.c | 64 |
1 files changed, 54 insertions, 10 deletions
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 0c8330ed1ffd..8fa0fe36f050 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -41,6 +41,7 @@ #include <linux/uuid.h> #include <linux/ras.h> #include <linux/task_work.h> +#include <linux/of.h> #include <acpi/actbl1.h> #include <acpi/ghes.h> @@ -143,6 +144,24 @@ static atomic_t ghes_estatus_cache_alloced; static int ghes_panic_timeout __read_mostly = 30; + +/* + * Checks device tree for support of sdei-ghes [driver]. + * This driver supports GHES in the absence of ACPI. + * on entry: + * void + * returns: + * true if sdei-ghes support found in Device Tree else false + */ +static bool sdei_ghes_present_dt(void) +{ + struct device_node *np; + + np = of_find_node_by_name(NULL, "sdei-ghes"); + of_node_put(np); + return !!np; +} + static void __iomem *ghes_map(u64 pfn, enum fixed_addresses fixmap_idx) { phys_addr_t paddr; @@ -231,6 +250,20 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) return ERR_PTR(-ENOMEM); ghes->generic = generic; + + /* If sdei-ghes is present (via device tree), ACPI mappings are not + * available and will be relegated to 'early_mem_remap()'. However, any + * such outstanding 'early' mappings will be detected as leaks during + * late kernel initialization - see 'check_early_ioremap_leak()'. + * Since this mapping is a 'sanity check' only (the mapping isn't used), + * skip this step to avoid it being detected as an [errant] leak. + * Notes: + * * the presence of the Device Tree disables ACPI + * * the status register is actually mapped at run-time, when accessed + */ + if (sdei_ghes_present_dt()) + goto skip_map_status; + if (is_hest_type_generic_v2(ghes)) { rc = map_gen_v2(ghes); if (rc) @@ -240,6 +273,8 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) rc = apei_map_generic_address(&generic->error_status_address); if (rc) goto err_unmap_read_ack_addr; + +skip_map_status: error_block_length = generic->error_block_length; if (error_block_length > GHES_ESTATUS_MAX_SIZE) { pr_warn(FW_WARN GHES_PFX @@ -257,6 +292,9 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) return ghes; err_unmap_status_addr: + /* if sdei-ghes is present, status was not mapped - skip the UNmap */ + if (sdei_ghes_present_dt()) + goto err_free; apei_unmap_generic_address(&generic->error_status_address); err_unmap_read_ack_addr: if (is_hest_type_generic_v2(ghes)) @@ -269,6 +307,9 @@ err_free: static void ghes_fini(struct ghes *ghes) { kfree(ghes->estatus); + /* if sdei-ghes is present, status was not mapped - skip the UNmap */ + if (sdei_ghes_present_dt()) + return; apei_unmap_generic_address(&ghes->generic->error_status_address); if (is_hest_type_generic_v2(ghes)) unmap_gen_v2(ghes); @@ -1461,7 +1502,8 @@ static int __init ghes_init(void) { int rc; - if (acpi_disabled) + /* permit GHES initialization if either ACPI or SDEI_GHES is present */ + if (acpi_disabled && !sdei_ghes_present_dt()) return -ENODEV; switch (hest_disable) { @@ -1485,15 +1527,17 @@ static int __init ghes_init(void) if (rc) goto err; - rc = apei_osc_setup(); - if (rc == 0 && osc_sb_apei_support_acked) - pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit and WHEA _OSC.\n"); - else if (rc == 0 && !osc_sb_apei_support_acked) - pr_info(GHES_PFX "APEI firmware first mode is enabled by WHEA _OSC.\n"); - else if (rc && osc_sb_apei_support_acked) - pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit.\n"); - else - pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n"); + if (!acpi_disabled) { + rc = apei_osc_setup(); + if (rc == 0 && osc_sb_apei_support_acked) + pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit and WHEA _OSC.\n"); + else if (rc == 0 && !osc_sb_apei_support_acked) + pr_info(GHES_PFX "APEI firmware first mode is enabled by WHEA _OSC.\n"); + else if (rc && osc_sb_apei_support_acked) + pr_info(GHES_PFX "APEI firmware first mode is enabled by APEI bit.\n"); + else + pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n"); + } return 0; err: |