Commit 73f05330 authored by Len Brown's avatar Len Brown

Merge branch 'apei' into release

Conflicts:
	drivers/acpi/apei/apei-base.c

This was a conflict between

15afae60
(CPI, APEI: Fix incorrect APEI register bit width check and usage)

and

653f4b53
(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: default avatarLen Brown <len.brown@intel.com>
parents 1a05e467 8cdde126
......@@ -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, &reg->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);
rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
if (rc)
return rc;
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, &notrigger);
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment