aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2017-02-19 20:12:58 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-02-27 16:53:11 -0500
commit41139ac3cd76c6dff8286102a8ac62933c680463 (patch)
tree8bfa944d00dfd110a542233dc5e571135c644abf
parentd222678426faa5b0a5c14a468f78c32beb089937 (diff)
ACPI: APEI: Fix BERT resources conflict with ACPI NVS area
It was reported that on some machines, there is overlap between ACPI NVS area and BERT address range. This appears reasonable because BERT contents need to be non-volatile across reboot. But this will cause resources conflict in current Linux kernel implementation because the ACPI NVS area is marked as busy. The resource conflict is fixed via excluding the ACPI NVS area when requesting IO resources for BERT. When accessing the BERT contents, the whole BERT address range will be ioremapped and accessed. Reported-and-tested-by: Hans Kristian Rosbach <hansr@raskesider.no> Signed-off-by: Ying Huang <ying.huang@intel.com> Acked-by: Borislav Petkov <bp@suse.de> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/apei/bert.c20
1 files changed, 12 insertions, 8 deletions
diff --git a/drivers/acpi/apei/bert.c b/drivers/acpi/apei/bert.c
index a05b5c0cf181..12771fcf0417 100644
--- a/drivers/acpi/apei/bert.c
+++ b/drivers/acpi/apei/bert.c
@@ -97,6 +97,7 @@ static int __init bert_check_table(struct acpi_table_bert *bert_tab)
97 97
98static int __init bert_init(void) 98static int __init bert_init(void)
99{ 99{
100 struct apei_resources bert_resources;
100 struct acpi_bert_region *boot_error_region; 101 struct acpi_bert_region *boot_error_region;
101 struct acpi_table_bert *bert_tab; 102 struct acpi_table_bert *bert_tab;
102 unsigned int region_len; 103 unsigned int region_len;
@@ -127,13 +128,14 @@ static int __init bert_init(void)
127 } 128 }
128 129
129 region_len = bert_tab->region_length; 130 region_len = bert_tab->region_length;
130 if (!request_mem_region(bert_tab->address, region_len, "APEI BERT")) { 131 apei_resources_init(&bert_resources);
131 pr_err("Can't request iomem region <%016llx-%016llx>.\n", 132 rc = apei_resources_add(&bert_resources, bert_tab->address,
132 (unsigned long long)bert_tab->address, 133 region_len, true);
133 (unsigned long long)bert_tab->address + region_len - 1); 134 if (rc)
134 return -EIO; 135 return rc;
135 } 136 rc = apei_resources_request(&bert_resources, "APEI BERT");
136 137 if (rc)
138 goto out_fini;
137 boot_error_region = ioremap_cache(bert_tab->address, region_len); 139 boot_error_region = ioremap_cache(bert_tab->address, region_len);
138 if (boot_error_region) { 140 if (boot_error_region) {
139 bert_print_all(boot_error_region, region_len); 141 bert_print_all(boot_error_region, region_len);
@@ -142,7 +144,9 @@ static int __init bert_init(void)
142 rc = -ENOMEM; 144 rc = -ENOMEM;
143 } 145 }
144 146
145 release_mem_region(bert_tab->address, region_len); 147 apei_resources_release(&bert_resources);
148out_fini:
149 apei_resources_fini(&bert_resources);
146 150
147 return rc; 151 return rc;
148} 152}