ACPI, EINJ: Enhance error injection tolerance level

Some BIOSes utilize PCI MMCFG space read/write opertion to trigger
specific errors. EINJ will report errors as below when hitting such
cases:

APEI: Can not request [mem 0x83f990a0-0x83f990a3] for APEI EINJ Trigger registers

It is because on x86 platform ACPI based PCI MMCFG logic has
reserved all MMCFG spaces so that EINJ can't reserve it again.
We already trust the ACPI/APEI code when using the EINJ interface
so it is not a big leap to also trust it to access the right
MMCFG addresses. Skip address checking to allow the access.

Signed-off-by: Chen, Gong <gong.chen@linux.intel.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
This commit is contained in:
Chen, Gong 2014-12-10 13:53:26 -08:00 committed by Tony Luck
parent b2776bf714
commit d91525eb8e
2 changed files with 54 additions and 6 deletions

View File

@ -610,6 +610,32 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
return 0; return 0;
} }
#ifdef CONFIG_ACPI_APEI
extern int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
void *data), void *data);
static int pci_mmcfg_for_each_region(int (*func)(__u64 start, __u64 size,
void *data), void *data)
{
struct pci_mmcfg_region *cfg;
int rc;
if (list_empty(&pci_mmcfg_list))
return 0;
list_for_each_entry(cfg, &pci_mmcfg_list, list) {
rc = func(cfg->res.start, resource_size(&cfg->res), data);
if (rc)
return rc;
}
return 0;
}
#define set_apei_filter() (arch_apei_filter_addr = pci_mmcfg_for_each_region)
#else
#define set_apei_filter()
#endif
static void __init __pci_mmcfg_init(int early) static void __init __pci_mmcfg_init(int early)
{ {
pci_mmcfg_reject_broken(early); pci_mmcfg_reject_broken(early);
@ -644,6 +670,8 @@ void __init pci_mmcfg_early_init(void)
else else
acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg); acpi_sfi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
__pci_mmcfg_init(1); __pci_mmcfg_init(1);
set_apei_filter();
} }
} }

View File

@ -449,7 +449,7 @@ int apei_resources_sub(struct apei_resources *resources1,
} }
EXPORT_SYMBOL_GPL(apei_resources_sub); EXPORT_SYMBOL_GPL(apei_resources_sub);
static int apei_get_nvs_callback(__u64 start, __u64 size, void *data) static int apei_get_res_callback(__u64 start, __u64 size, void *data)
{ {
struct apei_resources *resources = data; struct apei_resources *resources = data;
return apei_res_add(&resources->iomem, start, size); return apei_res_add(&resources->iomem, start, size);
@ -457,7 +457,15 @@ static int apei_get_nvs_callback(__u64 start, __u64 size, void *data)
static int apei_get_nvs_resources(struct apei_resources *resources) static int apei_get_nvs_resources(struct apei_resources *resources)
{ {
return acpi_nvs_for_each_region(apei_get_nvs_callback, resources); return acpi_nvs_for_each_region(apei_get_res_callback, resources);
}
int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
void *data), void *data);
static int apei_get_arch_resources(struct apei_resources *resources)
{
return arch_apei_filter_addr(apei_get_res_callback, resources);
} }
/* /*
@ -470,7 +478,7 @@ int apei_resources_request(struct apei_resources *resources,
{ {
struct apei_res *res, *res_bak = NULL; struct apei_res *res, *res_bak = NULL;
struct resource *r; struct resource *r;
struct apei_resources nvs_resources; struct apei_resources nvs_resources, arch_res;
int rc; int rc;
rc = apei_resources_sub(resources, &apei_resources_all); rc = apei_resources_sub(resources, &apei_resources_all);
@ -485,10 +493,20 @@ int apei_resources_request(struct apei_resources *resources,
apei_resources_init(&nvs_resources); apei_resources_init(&nvs_resources);
rc = apei_get_nvs_resources(&nvs_resources); rc = apei_get_nvs_resources(&nvs_resources);
if (rc) if (rc)
goto res_fini; goto nvs_res_fini;
rc = apei_resources_sub(resources, &nvs_resources); rc = apei_resources_sub(resources, &nvs_resources);
if (rc) if (rc)
goto res_fini; goto nvs_res_fini;
if (arch_apei_filter_addr) {
apei_resources_init(&arch_res);
rc = apei_get_arch_resources(&arch_res);
if (rc)
goto arch_res_fini;
rc = apei_resources_sub(resources, &arch_res);
if (rc)
goto arch_res_fini;
}
rc = -EINVAL; rc = -EINVAL;
list_for_each_entry(res, &resources->iomem, list) { list_for_each_entry(res, &resources->iomem, list) {
@ -536,7 +554,9 @@ err_unmap_iomem:
break; break;
release_mem_region(res->start, res->end - res->start); release_mem_region(res->start, res->end - res->start);
} }
res_fini: arch_res_fini:
apei_resources_fini(&arch_res);
nvs_res_fini:
apei_resources_fini(&nvs_resources); apei_resources_fini(&nvs_resources);
return rc; return rc;
} }