Skip to content

Commit

Permalink
Merge branch 'apei' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
Len Brown committed Jan 18, 2012
2 parents 5d1f865 + 4134b8c commit 037d76f
Show file tree
Hide file tree
Showing 11 changed files with 321 additions and 55 deletions.
4 changes: 2 additions & 2 deletions arch/x86/kernel/e820.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ void __init e820_mark_nosave_regions(unsigned long limit_pfn)
}
#endif

#ifdef CONFIG_HIBERNATION
#ifdef CONFIG_ACPI
/**
* Mark ACPI NVS memory region, so that we can save/restore it during
* hibernation and the subsequent resume.
Expand All @@ -727,7 +727,7 @@ static int __init e820_mark_nvs_memory(void)
struct e820entry *ei = &e820.map[i];

if (ei->type == E820_NVS)
suspend_nvs_register(ei->addr, ei->size);
acpi_nvs_register(ei->addr, ei->size);
}

return 0;
Expand Down
3 changes: 2 additions & 1 deletion drivers/acpi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ obj-y += acpi.o \
# All the builtin files are in the "acpi." module_param namespace.
acpi-y += osl.o utils.o reboot.o
acpi-y += atomicio.o
acpi-y += nvs.o

# sleep related files
acpi-y += wakeup.o
acpi-y += sleep.o
acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o
acpi-$(CONFIG_ACPI_SLEEP) += proc.o


#
Expand Down
48 changes: 43 additions & 5 deletions drivers/acpi/apei/apei-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1,
return 0;
}

int apei_resources_add(struct apei_resources *resources,
unsigned long start, unsigned long size,
bool iomem)
{
if (iomem)
return apei_res_add(&resources->iomem, start, size);
else
return apei_res_add(&resources->ioport, start, size);
}
EXPORT_SYMBOL_GPL(apei_resources_add);

/*
* EINJ has two groups of GARs (EINJ table entry and trigger table
* entry), so common resources are subtracted from the trigger table
Expand All @@ -438,8 +449,19 @@ int apei_resources_sub(struct apei_resources *resources1,
}
EXPORT_SYMBOL_GPL(apei_resources_sub);

static int apei_get_nvs_callback(__u64 start, __u64 size, void *data)
{
struct apei_resources *resources = data;
return apei_res_add(&resources->iomem, start, size);
}

static int apei_get_nvs_resources(struct apei_resources *resources)
{
return acpi_nvs_for_each_region(apei_get_nvs_callback, resources);
}

/*
* IO memory/port rersource management mechanism is used to check
* IO memory/port resource management mechanism is used to check
* whether memory/port area used by GARs conflicts with normal memory
* or IO memory/port of devices.
*/
Expand All @@ -448,21 +470,35 @@ int apei_resources_request(struct apei_resources *resources,
{
struct apei_res *res, *res_bak = NULL;
struct resource *r;
struct apei_resources nvs_resources;
int rc;

rc = apei_resources_sub(resources, &apei_resources_all);
if (rc)
return rc;

/*
* Some firmware uses ACPI NVS region, that has been marked as
* busy, so exclude it from APEI resources to avoid false
* conflict.
*/
apei_resources_init(&nvs_resources);
rc = apei_get_nvs_resources(&nvs_resources);
if (rc)
goto res_fini;
rc = apei_resources_sub(resources, &nvs_resources);
if (rc)
goto res_fini;

rc = -EINVAL;
list_for_each_entry(res, &resources->iomem, list) {
r = request_mem_region(res->start, res->end - res->start,
desc);
if (!r) {
pr_err(APEI_PFX
"Can not request iomem region <%016llx-%016llx> for GARs.\n",
"Can not request [mem %#010llx-%#010llx] for %s registers\n",
(unsigned long long)res->start,
(unsigned long long)res->end);
(unsigned long long)res->end - 1, desc);
res_bak = res;
goto err_unmap_iomem;
}
Expand All @@ -472,9 +508,9 @@ int apei_resources_request(struct apei_resources *resources,
r = request_region(res->start, res->end - res->start, desc);
if (!r) {
pr_err(APEI_PFX
"Can not request ioport region <%016llx-%016llx> for GARs.\n",
"Can not request [io %#06llx-%#06llx] for %s registers\n",
(unsigned long long)res->start,
(unsigned long long)res->end);
(unsigned long long)res->end - 1, desc);
res_bak = res;
goto err_unmap_ioport;
}
Expand All @@ -500,6 +536,8 @@ int apei_resources_request(struct apei_resources *resources,
break;
release_mem_region(res->start, res->end - res->start);
}
res_fini:
apei_resources_fini(&nvs_resources);
return rc;
}
EXPORT_SYMBOL_GPL(apei_resources_request);
Expand Down
3 changes: 3 additions & 0 deletions drivers/acpi/apei/apei-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ static inline void apei_resources_init(struct apei_resources *resources)
}

void apei_resources_fini(struct apei_resources *resources);
int apei_resources_add(struct apei_resources *resources,
unsigned long start, unsigned long size,
bool iomem);
int apei_resources_sub(struct apei_resources *resources1,
struct apei_resources *resources2);
int apei_resources_request(struct apei_resources *resources,
Expand Down
66 changes: 56 additions & 10 deletions drivers/acpi/apei/einj.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,29 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
return 0;
}

static struct acpi_generic_address *einj_get_trigger_parameter_region(
struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2)
{
int i;
struct acpi_whea_header *entry;

entry = (struct acpi_whea_header *)
((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
for (i = 0; i < trigger_tab->entry_count; i++) {
if (entry->action == ACPI_EINJ_TRIGGER_ERROR &&
entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE &&
entry->register_region.space_id ==
ACPI_ADR_SPACE_SYSTEM_MEMORY &&
(entry->register_region.address & param2) == (param1 & param2))
return &entry->register_region;
entry++;
}

return NULL;
}
/* Execute instructions in trigger error action table */
static int __einj_error_trigger(u64 trigger_paddr)
static int __einj_error_trigger(u64 trigger_paddr, u32 type,
u64 param1, u64 param2)
{
struct acpi_einj_trigger *trigger_tab = NULL;
struct apei_exec_context trigger_ctx;
Expand All @@ -204,14 +225,16 @@ static int __einj_error_trigger(u64 trigger_paddr)
struct resource *r;
u32 table_size;
int rc = -EIO;
struct acpi_generic_address *trigger_param_region = NULL;

r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
"APEI EINJ Trigger Table");
if (!r) {
pr_err(EINJ_PFX
"Can not request iomem region <%016llx-%016llx> for Trigger table.\n",
"Can not request [mem %#010llx-%#010llx] for Trigger table\n",
(unsigned long long)trigger_paddr,
(unsigned long long)trigger_paddr+sizeof(*trigger_tab));
(unsigned long long)trigger_paddr +
sizeof(*trigger_tab) - 1);
goto out;
}
trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
Expand All @@ -232,9 +255,9 @@ static int __einj_error_trigger(u64 trigger_paddr)
"APEI EINJ Trigger Table");
if (!r) {
pr_err(EINJ_PFX
"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n",
(unsigned long long)trigger_paddr+sizeof(*trigger_tab),
(unsigned long long)trigger_paddr + table_size);
"Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
(unsigned long long)trigger_paddr + sizeof(*trigger_tab),
(unsigned long long)trigger_paddr + table_size - 1);
goto out_rel_header;
}
iounmap(trigger_tab);
Expand All @@ -255,6 +278,30 @@ static int __einj_error_trigger(u64 trigger_paddr)
rc = apei_resources_sub(&trigger_resources, &einj_resources);
if (rc)
goto out_fini;
/*
* Some firmware will access target address specified in
* param1 to trigger the error when injecting memory error.
* This will cause resource conflict with regular memory. So
* remove it from trigger table resources.
*/
if (param_extension && (type & 0x0038) && param2) {
struct apei_resources addr_resources;
apei_resources_init(&addr_resources);
trigger_param_region = einj_get_trigger_parameter_region(
trigger_tab, param1, param2);
if (trigger_param_region) {
rc = apei_resources_add(&addr_resources,
trigger_param_region->address,
trigger_param_region->bit_width/8, true);
if (rc)
goto out_fini;
rc = apei_resources_sub(&trigger_resources,
&addr_resources);
}
apei_resources_fini(&addr_resources);
if (rc)
goto out_fini;
}
rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");
if (rc)
goto out_fini;
Expand Down Expand Up @@ -324,7 +371,7 @@ 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);
rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
if (rc)
return rc;
rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);
Expand Down Expand Up @@ -465,10 +512,9 @@ static int __init einj_init(void)

status = acpi_get_table(ACPI_SIG_EINJ, 0,
(struct acpi_table_header **)&einj_tab);
if (status == AE_NOT_FOUND) {
pr_info(EINJ_PFX "Table is not found!\n");
if (status == AE_NOT_FOUND)
return -ENODEV;
} else if (ACPI_FAILURE(status)) {
else if (ACPI_FAILURE(status)) {
const char *msg = acpi_format_exception(status);
pr_err(EINJ_PFX "Failed to get table, %s\n", msg);
return -EINVAL;
Expand Down
5 changes: 2 additions & 3 deletions drivers/acpi/apei/erst.c
Original file line number Diff line number Diff line change
Expand Up @@ -1125,10 +1125,9 @@ static int __init erst_init(void)

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");
if (status == AE_NOT_FOUND)
goto err;
} else if (ACPI_FAILURE(status)) {
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;
Expand Down
Loading

0 comments on commit 037d76f

Please sign in to comment.