Merge branch 'apei' into release
Conflicts: drivers/acpi/apei/apei-base.c This was a conflict between15afae6046
(CPI, APEI: Fix incorrect APEI register bit width check and usage) and653f4b538f
(ACPICA: Expand OSL memory read/write interfaces to 64 bits) The former changed a parameter in the call to acpi_os_read_memory64() and the later replaced all calls to acpi_os_read_memory64() with calls to acpi_os_read_memory(). Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
commit
73f0533049
5 changed files with 64 additions and 26 deletions
|
@ -53,6 +53,14 @@ directory apei/einj. The following files are provided.
|
|||
This file is used to set the second error parameter value. Effect of
|
||||
parameter depends on error_type specified.
|
||||
|
||||
- notrigger
|
||||
The EINJ mechanism is a two step process. First inject the error, then
|
||||
perform some actions to trigger it. Setting "notrigger" to 1 skips the
|
||||
trigger phase, which *may* allow the user to cause the error in some other
|
||||
context by a simple access to the cpu, memory location, or device that is
|
||||
the target of the error injection. Whether this actually works depends
|
||||
on what operations the BIOS actually includes in the trigger phase.
|
||||
|
||||
BIOS versions based in the ACPI 4.0 specification have limited options
|
||||
to control where the errors are injected. Your BIOS may support an
|
||||
extension (enabled with the param_extension=1 module parameter, or
|
||||
|
|
|
@ -558,33 +558,48 @@ void apei_resources_release(struct apei_resources *resources)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(apei_resources_release);
|
||||
|
||||
static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr)
|
||||
static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr,
|
||||
u32 *access_bit_width)
|
||||
{
|
||||
u32 width, space_id;
|
||||
u32 bit_width, bit_offset, access_size_code, space_id;
|
||||
|
||||
width = reg->bit_width;
|
||||
bit_width = reg->bit_width;
|
||||
bit_offset = reg->bit_offset;
|
||||
access_size_code = reg->access_width;
|
||||
space_id = reg->space_id;
|
||||
/* Handle possible alignment issues */
|
||||
memcpy(paddr, ®->address, sizeof(*paddr));
|
||||
if (!*paddr) {
|
||||
pr_warning(FW_BUG APEI_PFX
|
||||
"Invalid physical address in GAR [0x%llx/%u/%u]\n",
|
||||
*paddr, width, space_id);
|
||||
"Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n",
|
||||
*paddr, bit_width, bit_offset, access_size_code,
|
||||
space_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) {
|
||||
if (access_size_code < 1 || access_size_code > 4) {
|
||||
pr_warning(FW_BUG APEI_PFX
|
||||
"Invalid bit width in GAR [0x%llx/%u/%u]\n",
|
||||
*paddr, width, space_id);
|
||||
"Invalid access size code in GAR [0x%llx/%u/%u/%u/%u]\n",
|
||||
*paddr, bit_width, bit_offset, access_size_code,
|
||||
space_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
*access_bit_width = 1UL << (access_size_code + 2);
|
||||
|
||||
if ((bit_width + bit_offset) > *access_bit_width) {
|
||||
pr_warning(FW_BUG APEI_PFX
|
||||
"Invalid bit width + offset in GAR [0x%llx/%u/%u/%u/%u]\n",
|
||||
*paddr, bit_width, bit_offset, access_size_code,
|
||||
space_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
|
||||
space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
|
||||
pr_warning(FW_BUG APEI_PFX
|
||||
"Invalid address space type in GAR [0x%llx/%u/%u]\n",
|
||||
*paddr, width, space_id);
|
||||
"Invalid address space type in GAR [0x%llx/%u/%u/%u/%u]\n",
|
||||
*paddr, bit_width, bit_offset, access_size_code,
|
||||
space_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -595,23 +610,25 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr)
|
|||
int apei_read(u64 *val, struct acpi_generic_address *reg)
|
||||
{
|
||||
int rc;
|
||||
u32 access_bit_width;
|
||||
u64 address;
|
||||
acpi_status status;
|
||||
|
||||
rc = apei_check_gar(reg, &address);
|
||||
rc = apei_check_gar(reg, &address, &access_bit_width);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
*val = 0;
|
||||
switch(reg->space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||
status = acpi_os_read_memory((acpi_physical_address)
|
||||
address, val, reg->bit_width);
|
||||
status = acpi_os_read_memory((acpi_physical_address) address,
|
||||
val, access_bit_width);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
break;
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
status = acpi_os_read_port(address, (u32 *)val, reg->bit_width);
|
||||
status = acpi_os_read_port(address, (u32 *)val,
|
||||
access_bit_width);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
break;
|
||||
|
@ -627,22 +644,23 @@ EXPORT_SYMBOL_GPL(apei_read);
|
|||
int apei_write(u64 val, struct acpi_generic_address *reg)
|
||||
{
|
||||
int rc;
|
||||
u32 access_bit_width;
|
||||
u64 address;
|
||||
acpi_status status;
|
||||
|
||||
rc = apei_check_gar(reg, &address);
|
||||
rc = apei_check_gar(reg, &address, &access_bit_width);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (reg->space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||
status = acpi_os_write_memory((acpi_physical_address)
|
||||
address, val, reg->bit_width);
|
||||
status = acpi_os_write_memory((acpi_physical_address) address,
|
||||
val, access_bit_width);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
break;
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
status = acpi_os_write_port(address, val, reg->bit_width);
|
||||
status = acpi_os_write_port(address, val, access_bit_width);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EIO;
|
||||
break;
|
||||
|
@ -661,23 +679,24 @@ static int collect_res_callback(struct apei_exec_context *ctx,
|
|||
struct apei_resources *resources = data;
|
||||
struct acpi_generic_address *reg = &entry->register_region;
|
||||
u8 ins = entry->instruction;
|
||||
u32 access_bit_width;
|
||||
u64 paddr;
|
||||
int rc;
|
||||
|
||||
if (!(ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER))
|
||||
return 0;
|
||||
|
||||
rc = apei_check_gar(reg, &paddr);
|
||||
rc = apei_check_gar(reg, &paddr, &access_bit_width);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (reg->space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||
return apei_res_add(&resources->iomem, paddr,
|
||||
reg->bit_width / 8);
|
||||
access_bit_width / 8);
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
return apei_res_add(&resources->ioport, paddr,
|
||||
reg->bit_width / 8);
|
||||
access_bit_width / 8);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -362,6 +362,7 @@ void apei_estatus_print(const char *pfx,
|
|||
gedata_len = gdata->error_data_length;
|
||||
apei_estatus_print_section(pfx, gdata, sec_no);
|
||||
data_len -= gedata_len + sizeof(*gdata);
|
||||
gdata = (void *)(gdata + 1) + gedata_len;
|
||||
sec_no++;
|
||||
}
|
||||
}
|
||||
|
@ -396,6 +397,7 @@ int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
|
|||
if (gedata_len > data_len - sizeof(*gdata))
|
||||
return -EINVAL;
|
||||
data_len -= gedata_len + sizeof(*gdata);
|
||||
gdata = (void *)(gdata + 1) + gedata_len;
|
||||
}
|
||||
if (data_len)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -74,6 +74,8 @@ struct vendor_error_type_extension {
|
|||
u8 reserved[3];
|
||||
};
|
||||
|
||||
static u32 notrigger;
|
||||
|
||||
static u32 vendor_flags;
|
||||
static struct debugfs_blob_wrapper vendor_blob;
|
||||
static char vendor_dev[64];
|
||||
|
@ -238,7 +240,7 @@ static void *einj_get_parameter_address(void)
|
|||
return v5param;
|
||||
}
|
||||
}
|
||||
if (paddrv4) {
|
||||
if (param_extension && paddrv4) {
|
||||
struct einj_parameter *v4param;
|
||||
|
||||
v4param = acpi_os_map_memory(paddrv4, sizeof(*v4param));
|
||||
|
@ -496,9 +498,11 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
|
|||
if (rc)
|
||||
return rc;
|
||||
trigger_paddr = apei_exec_ctx_get_output(&ctx);
|
||||
if (notrigger == 0) {
|
||||
rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);
|
||||
|
||||
return rc;
|
||||
|
@ -700,6 +704,11 @@ static int __init einj_init(void)
|
|||
einj_debug_dir, &error_param2);
|
||||
if (!fentry)
|
||||
goto err_unmap;
|
||||
|
||||
fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
|
||||
einj_debug_dir, ¬rigger);
|
||||
if (!fentry)
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
if (vendor_dev[0]) {
|
||||
|
|
|
@ -917,7 +917,7 @@ static int erst_check_table(struct acpi_table_erst *erst_tab)
|
|||
{
|
||||
if ((erst_tab->header_length !=
|
||||
(sizeof(struct acpi_table_erst) - sizeof(erst_tab->header)))
|
||||
&& (erst_tab->header_length != sizeof(struct acpi_table_einj)))
|
||||
&& (erst_tab->header_length != sizeof(struct acpi_table_erst)))
|
||||
return -EINVAL;
|
||||
if (erst_tab->header.length < sizeof(struct acpi_table_erst))
|
||||
return -EINVAL;
|
||||
|
|
Loading…
Reference in a new issue