int __init erst_init(void) { int rc = 0; acpi_status status; struct apei_exec_context ctx; if (acpi_disabled) return -ENODEV; status = acpi_get_table(ACPI_SIG_ERST, 0, (struct acpi_table_header **)&erst_tab); if (status == AE_NOT_FOUND) { printk(KERN_INFO "ERST table was not found\n"); return -ENODEV; } else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); printk(KERN_WARNING "Failed to get ERST table: %s\n", msg); return -EINVAL; } rc = erst_check_table(erst_tab); if (rc) { printk(KERN_ERR "ERST table is invalid\n"); return rc; } erst_exec_ctx_init(&ctx); rc = apei_exec_pre_map_gars(&ctx); if (rc) return rc; rc = erst_get_erange(&erst_erange); if (rc) { if (rc == -ENODEV) printk(KERN_INFO "The corresponding hardware device or firmware " "implementation is not available.\n"); else printk(KERN_ERR "Failed to get Error Log Address Range.\n"); goto err_unmap_reg; } erst_erange.vaddr = apei_pre_map(erst_erange.base, erst_erange.size); if (!erst_erange.vaddr) { rc = -ENOMEM; goto err_unmap_reg; } printk(KERN_INFO "Xen ERST support is initialized.\n"); erst_enabled = 1; return 0; err_unmap_reg: apei_exec_post_unmap_gars(&ctx); return rc; }
static ssize_t __erst_get_record_count(void) { struct apei_exec_context ctx; int rc; erst_exec_ctx_init(&ctx); rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_COUNT); if (rc) return rc; return apei_exec_ctx_get_output(&ctx); }
static int __erst_get_next_record_id(u64 *record_id) { struct apei_exec_context ctx; int rc; erst_exec_ctx_init(&ctx); rc = apei_exec_run(&ctx, ACPI_ERST_GET_RECORD_ID); if (rc) return rc; *record_id = apei_exec_ctx_get_output(&ctx); return 0; }
static int __erst_read_from_storage(u64 record_id, u64 offset) { struct apei_exec_context ctx; u64 timeout = FIRMWARE_TIMEOUT; u64 val; int rc; erst_exec_ctx_init(&ctx); rc = apei_exec_run(&ctx, ACPI_ERST_BEGIN_READ); if (rc) return rc; apei_exec_ctx_set_input(&ctx, offset); rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_OFFSET); if (rc) return rc; apei_exec_ctx_set_input(&ctx, record_id); rc = apei_exec_run(&ctx, ACPI_ERST_SET_RECORD_ID); if (rc) return rc; rc = apei_exec_run(&ctx, ACPI_ERST_EXECUTE_OPERATION); if (rc) return rc; for (;;) { rc = apei_exec_run(&ctx, ACPI_ERST_CHECK_BUSY_STATUS); if (rc) return rc; val = apei_exec_ctx_get_output(&ctx); if (!val) break; if (erst_timedout(&timeout, SPIN_UNIT)) return -EIO; }; rc = apei_exec_run(&ctx, ACPI_ERST_GET_COMMAND_STATUS); if (rc) return rc; val = apei_exec_ctx_get_output(&ctx); rc = apei_exec_run(&ctx, ACPI_ERST_END); if (rc) return rc; return erst_errno(val); }
static int erst_get_erange(struct erst_erange *range) { struct apei_exec_context ctx; int rc; erst_exec_ctx_init(&ctx); rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_RANGE); if (rc) return rc; range->base = apei_exec_ctx_get_output(&ctx); rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_LENGTH); if (rc) return rc; range->size = apei_exec_ctx_get_output(&ctx); rc = apei_exec_run(&ctx, ACPI_ERST_GET_ERROR_ATTRIBUTES); if (rc) return rc; range->attr = apei_exec_ctx_get_output(&ctx); return 0; }
static int __init erst_init(void) { int rc = 0; acpi_status status; struct apei_exec_context ctx; struct apei_resources erst_resources; struct resource *r; if (acpi_disabled) goto err; if (erst_disable) { pr_info(ERST_PFX "Error Record Serialization Table (ERST) support is disabled.\n"); goto err; } status = acpi_get_table(ACPI_SIG_ERST, 0, (struct acpi_table_header **)&erst_tab); if (status == AE_NOT_FOUND) { pr_info(ERST_PFX "Table is not found!\n"); goto err; } else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err(ERST_PFX "Failed to get table, %s\n", msg); rc = -EINVAL; goto err; } rc = erst_check_table(erst_tab); if (rc) { pr_err(FW_BUG ERST_PFX "ERST table is invalid\n"); goto err; } apei_resources_init(&erst_resources); erst_exec_ctx_init(&ctx); rc = apei_exec_collect_resources(&ctx, &erst_resources); if (rc) goto err_fini; rc = apei_resources_request(&erst_resources, "APEI ERST"); if (rc) goto err_fini; rc = apei_exec_pre_map_gars(&ctx); if (rc) goto err_release; rc = erst_get_erange(&erst_erange); if (rc) { if (rc == -ENODEV) pr_info(ERST_PFX "The corresponding hardware device or firmware implementation " "is not available.\n"); else pr_err(ERST_PFX "Failed to get Error Log Address Range.\n"); goto err_unmap_reg; } r = request_mem_region(erst_erange.base, erst_erange.size, "APEI ERST"); if (!r) { pr_err(ERST_PFX "Can not request iomem region <0x%16llx-0x%16llx> for ERST.\n", (unsigned long long)erst_erange.base, (unsigned long long)erst_erange.base + erst_erange.size); rc = -EIO; goto err_unmap_reg; } rc = -ENOMEM; erst_erange.vaddr = ioremap_cache(erst_erange.base, erst_erange.size); if (!erst_erange.vaddr) goto err_release_erange; pr_info(ERST_PFX "Error Record Serialization Table (ERST) support is initialized.\n"); return 0; err_release_erange: release_mem_region(erst_erange.base, erst_erange.size); err_unmap_reg: apei_exec_post_unmap_gars(&ctx); err_release: apei_resources_release(&erst_resources); err_fini: apei_resources_fini(&erst_resources); err: erst_disable = 1; return rc; }