aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2012-01-18 00:18:10 -0500
committerLen Brown <len.brown@intel.com>2012-01-18 00:18:10 -0500
commit037d76f40430ba1269dc7d1fee22382cd9672997 (patch)
tree0a378e88951655aa0042645fbd12b7058be95c3e /drivers/acpi
parent5d1f86572685d577b76142b7c61453000e1a5e26 (diff)
parent4134b8c8811f23aa8a281db50dcee64dda414736 (diff)
Merge branch 'apei' into release
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/apei/apei-base.c48
-rw-r--r--drivers/acpi/apei/apei-internal.h3
-rw-r--r--drivers/acpi/apei/einj.c66
-rw-r--r--drivers/acpi/apei/erst.c5
-rw-r--r--drivers/acpi/apei/ghes.c92
-rw-r--r--drivers/acpi/apei/hest.c5
-rw-r--r--drivers/acpi/atomicio.c77
-rw-r--r--drivers/acpi/nvs.c53
9 files changed, 305 insertions, 47 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index ecb26b4f29a0..c07f44f05f9d 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -20,11 +20,12 @@ obj-y += acpi.o \
20# All the builtin files are in the "acpi." module_param namespace. 20# All the builtin files are in the "acpi." module_param namespace.
21acpi-y += osl.o utils.o reboot.o 21acpi-y += osl.o utils.o reboot.o
22acpi-y += atomicio.o 22acpi-y += atomicio.o
23acpi-y += nvs.o
23 24
24# sleep related files 25# sleep related files
25acpi-y += wakeup.o 26acpi-y += wakeup.o
26acpi-y += sleep.o 27acpi-y += sleep.o
27acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o 28acpi-$(CONFIG_ACPI_SLEEP) += proc.o
28 29
29 30
30# 31#
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 61540360d5ce..4abb6c74a938 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1,
421 return 0; 421 return 0;
422} 422}
423 423
424int apei_resources_add(struct apei_resources *resources,
425 unsigned long start, unsigned long size,
426 bool iomem)
427{
428 if (iomem)
429 return apei_res_add(&resources->iomem, start, size);
430 else
431 return apei_res_add(&resources->ioport, start, size);
432}
433EXPORT_SYMBOL_GPL(apei_resources_add);
434
424/* 435/*
425 * EINJ has two groups of GARs (EINJ table entry and trigger table 436 * EINJ has two groups of GARs (EINJ table entry and trigger table
426 * entry), so common resources are subtracted from the trigger table 437 * entry), so common resources are subtracted from the trigger table
@@ -438,8 +449,19 @@ int apei_resources_sub(struct apei_resources *resources1,
438} 449}
439EXPORT_SYMBOL_GPL(apei_resources_sub); 450EXPORT_SYMBOL_GPL(apei_resources_sub);
440 451
452static int apei_get_nvs_callback(__u64 start, __u64 size, void *data)
453{
454 struct apei_resources *resources = data;
455 return apei_res_add(&resources->iomem, start, size);
456}
457
458static int apei_get_nvs_resources(struct apei_resources *resources)
459{
460 return acpi_nvs_for_each_region(apei_get_nvs_callback, resources);
461}
462
441/* 463/*
442 * IO memory/port rersource management mechanism is used to check 464 * IO memory/port resource management mechanism is used to check
443 * whether memory/port area used by GARs conflicts with normal memory 465 * whether memory/port area used by GARs conflicts with normal memory
444 * or IO memory/port of devices. 466 * or IO memory/port of devices.
445 */ 467 */
@@ -448,21 +470,35 @@ int apei_resources_request(struct apei_resources *resources,
448{ 470{
449 struct apei_res *res, *res_bak = NULL; 471 struct apei_res *res, *res_bak = NULL;
450 struct resource *r; 472 struct resource *r;
473 struct apei_resources nvs_resources;
451 int rc; 474 int rc;
452 475
453 rc = apei_resources_sub(resources, &apei_resources_all); 476 rc = apei_resources_sub(resources, &apei_resources_all);
454 if (rc) 477 if (rc)
455 return rc; 478 return rc;
456 479
480 /*
481 * Some firmware uses ACPI NVS region, that has been marked as
482 * busy, so exclude it from APEI resources to avoid false
483 * conflict.
484 */
485 apei_resources_init(&nvs_resources);
486 rc = apei_get_nvs_resources(&nvs_resources);
487 if (rc)
488 goto res_fini;
489 rc = apei_resources_sub(resources, &nvs_resources);
490 if (rc)
491 goto res_fini;
492
457 rc = -EINVAL; 493 rc = -EINVAL;
458 list_for_each_entry(res, &resources->iomem, list) { 494 list_for_each_entry(res, &resources->iomem, list) {
459 r = request_mem_region(res->start, res->end - res->start, 495 r = request_mem_region(res->start, res->end - res->start,
460 desc); 496 desc);
461 if (!r) { 497 if (!r) {
462 pr_err(APEI_PFX 498 pr_err(APEI_PFX
463 "Can not request iomem region <%016llx-%016llx> for GARs.\n", 499 "Can not request [mem %#010llx-%#010llx] for %s registers\n",
464 (unsigned long long)res->start, 500 (unsigned long long)res->start,
465 (unsigned long long)res->end); 501 (unsigned long long)res->end - 1, desc);
466 res_bak = res; 502 res_bak = res;
467 goto err_unmap_iomem; 503 goto err_unmap_iomem;
468 } 504 }
@@ -472,9 +508,9 @@ int apei_resources_request(struct apei_resources *resources,
472 r = request_region(res->start, res->end - res->start, desc); 508 r = request_region(res->start, res->end - res->start, desc);
473 if (!r) { 509 if (!r) {
474 pr_err(APEI_PFX 510 pr_err(APEI_PFX
475 "Can not request ioport region <%016llx-%016llx> for GARs.\n", 511 "Can not request [io %#06llx-%#06llx] for %s registers\n",
476 (unsigned long long)res->start, 512 (unsigned long long)res->start,
477 (unsigned long long)res->end); 513 (unsigned long long)res->end - 1, desc);
478 res_bak = res; 514 res_bak = res;
479 goto err_unmap_ioport; 515 goto err_unmap_ioport;
480 } 516 }
@@ -500,6 +536,8 @@ err_unmap_iomem:
500 break; 536 break;
501 release_mem_region(res->start, res->end - res->start); 537 release_mem_region(res->start, res->end - res->start);
502 } 538 }
539res_fini:
540 apei_resources_fini(&nvs_resources);
503 return rc; 541 return rc;
504} 542}
505EXPORT_SYMBOL_GPL(apei_resources_request); 543EXPORT_SYMBOL_GPL(apei_resources_request);
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
index f57050e7a5e7..d778edd34fba 100644
--- a/drivers/acpi/apei/apei-internal.h
+++ b/drivers/acpi/apei/apei-internal.h
@@ -95,6 +95,9 @@ static inline void apei_resources_init(struct apei_resources *resources)
95} 95}
96 96
97void apei_resources_fini(struct apei_resources *resources); 97void apei_resources_fini(struct apei_resources *resources);
98int apei_resources_add(struct apei_resources *resources,
99 unsigned long start, unsigned long size,
100 bool iomem);
98int apei_resources_sub(struct apei_resources *resources1, 101int apei_resources_sub(struct apei_resources *resources1,
99 struct apei_resources *resources2); 102 struct apei_resources *resources2);
100int apei_resources_request(struct apei_resources *resources, 103int apei_resources_request(struct apei_resources *resources,
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 589b96c38704..6e6512e68a2d 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -194,8 +194,29 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
194 return 0; 194 return 0;
195} 195}
196 196
197static struct acpi_generic_address *einj_get_trigger_parameter_region(
198 struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2)
199{
200 int i;
201 struct acpi_whea_header *entry;
202
203 entry = (struct acpi_whea_header *)
204 ((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
205 for (i = 0; i < trigger_tab->entry_count; i++) {
206 if (entry->action == ACPI_EINJ_TRIGGER_ERROR &&
207 entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE &&
208 entry->register_region.space_id ==
209 ACPI_ADR_SPACE_SYSTEM_MEMORY &&
210 (entry->register_region.address & param2) == (param1 & param2))
211 return &entry->register_region;
212 entry++;
213 }
214
215 return NULL;
216}
197/* Execute instructions in trigger error action table */ 217/* Execute instructions in trigger error action table */
198static int __einj_error_trigger(u64 trigger_paddr) 218static int __einj_error_trigger(u64 trigger_paddr, u32 type,
219 u64 param1, u64 param2)
199{ 220{
200 struct acpi_einj_trigger *trigger_tab = NULL; 221 struct acpi_einj_trigger *trigger_tab = NULL;
201 struct apei_exec_context trigger_ctx; 222 struct apei_exec_context trigger_ctx;
@@ -204,14 +225,16 @@ static int __einj_error_trigger(u64 trigger_paddr)
204 struct resource *r; 225 struct resource *r;
205 u32 table_size; 226 u32 table_size;
206 int rc = -EIO; 227 int rc = -EIO;
228 struct acpi_generic_address *trigger_param_region = NULL;
207 229
208 r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), 230 r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
209 "APEI EINJ Trigger Table"); 231 "APEI EINJ Trigger Table");
210 if (!r) { 232 if (!r) {
211 pr_err(EINJ_PFX 233 pr_err(EINJ_PFX
212 "Can not request iomem region <%016llx-%016llx> for Trigger table.\n", 234 "Can not request [mem %#010llx-%#010llx] for Trigger table\n",
213 (unsigned long long)trigger_paddr, 235 (unsigned long long)trigger_paddr,
214 (unsigned long long)trigger_paddr+sizeof(*trigger_tab)); 236 (unsigned long long)trigger_paddr +
237 sizeof(*trigger_tab) - 1);
215 goto out; 238 goto out;
216 } 239 }
217 trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab)); 240 trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
@@ -232,9 +255,9 @@ static int __einj_error_trigger(u64 trigger_paddr)
232 "APEI EINJ Trigger Table"); 255 "APEI EINJ Trigger Table");
233 if (!r) { 256 if (!r) {
234 pr_err(EINJ_PFX 257 pr_err(EINJ_PFX
235"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n", 258"Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
236 (unsigned long long)trigger_paddr+sizeof(*trigger_tab), 259 (unsigned long long)trigger_paddr + sizeof(*trigger_tab),
237 (unsigned long long)trigger_paddr + table_size); 260 (unsigned long long)trigger_paddr + table_size - 1);
238 goto out_rel_header; 261 goto out_rel_header;
239 } 262 }
240 iounmap(trigger_tab); 263 iounmap(trigger_tab);
@@ -255,6 +278,30 @@ static int __einj_error_trigger(u64 trigger_paddr)
255 rc = apei_resources_sub(&trigger_resources, &einj_resources); 278 rc = apei_resources_sub(&trigger_resources, &einj_resources);
256 if (rc) 279 if (rc)
257 goto out_fini; 280 goto out_fini;
281 /*
282 * Some firmware will access target address specified in
283 * param1 to trigger the error when injecting memory error.
284 * This will cause resource conflict with regular memory. So
285 * remove it from trigger table resources.
286 */
287 if (param_extension && (type & 0x0038) && param2) {
288 struct apei_resources addr_resources;
289 apei_resources_init(&addr_resources);
290 trigger_param_region = einj_get_trigger_parameter_region(
291 trigger_tab, param1, param2);
292 if (trigger_param_region) {
293 rc = apei_resources_add(&addr_resources,
294 trigger_param_region->address,
295 trigger_param_region->bit_width/8, true);
296 if (rc)
297 goto out_fini;
298 rc = apei_resources_sub(&trigger_resources,
299 &addr_resources);
300 }
301 apei_resources_fini(&addr_resources);
302 if (rc)
303 goto out_fini;
304 }
258 rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger"); 305 rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");
259 if (rc) 306 if (rc)
260 goto out_fini; 307 goto out_fini;
@@ -324,7 +371,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
324 if (rc) 371 if (rc)
325 return rc; 372 return rc;
326 trigger_paddr = apei_exec_ctx_get_output(&ctx); 373 trigger_paddr = apei_exec_ctx_get_output(&ctx);
327 rc = __einj_error_trigger(trigger_paddr); 374 rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
328 if (rc) 375 if (rc)
329 return rc; 376 return rc;
330 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION); 377 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);
@@ -465,10 +512,9 @@ static int __init einj_init(void)
465 512
466 status = acpi_get_table(ACPI_SIG_EINJ, 0, 513 status = acpi_get_table(ACPI_SIG_EINJ, 0,
467 (struct acpi_table_header **)&einj_tab); 514 (struct acpi_table_header **)&einj_tab);
468 if (status == AE_NOT_FOUND) { 515 if (status == AE_NOT_FOUND)
469 pr_info(EINJ_PFX "Table is not found!\n");
470 return -ENODEV; 516 return -ENODEV;
471 } else if (ACPI_FAILURE(status)) { 517 else if (ACPI_FAILURE(status)) {
472 const char *msg = acpi_format_exception(status); 518 const char *msg = acpi_format_exception(status);
473 pr_err(EINJ_PFX "Failed to get table, %s\n", msg); 519 pr_err(EINJ_PFX "Failed to get table, %s\n", msg);
474 return -EINVAL; 520 return -EINVAL;
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 631b9477b99c..8e8d786c5d23 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -1125,10 +1125,9 @@ static int __init erst_init(void)
1125 1125
1126 status = acpi_get_table(ACPI_SIG_ERST, 0, 1126 status = acpi_get_table(ACPI_SIG_ERST, 0,
1127 (struct acpi_table_header **)&erst_tab); 1127 (struct acpi_table_header **)&erst_tab);
1128 if (status == AE_NOT_FOUND) { 1128 if (status == AE_NOT_FOUND)
1129 pr_info(ERST_PFX "Table is not found!\n");
1130 goto err; 1129 goto err;
1131 } else if (ACPI_FAILURE(status)) { 1130 else if (ACPI_FAILURE(status)) {
1132 const char *msg = acpi_format_exception(status); 1131 const char *msg = acpi_format_exception(status);
1133 pr_err(ERST_PFX "Failed to get table, %s\n", msg); 1132 pr_err(ERST_PFX "Failed to get table, %s\n", msg);
1134 rc = -EINVAL; 1133 rc = -EINVAL;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index b8e08cb67a18..aaf36090de1e 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -45,6 +45,8 @@
45#include <linux/irq_work.h> 45#include <linux/irq_work.h>
46#include <linux/llist.h> 46#include <linux/llist.h>
47#include <linux/genalloc.h> 47#include <linux/genalloc.h>
48#include <linux/pci.h>
49#include <linux/aer.h>
48#include <acpi/apei.h> 50#include <acpi/apei.h>
49#include <acpi/atomicio.h> 51#include <acpi/atomicio.h>
50#include <acpi/hed.h> 52#include <acpi/hed.h>
@@ -476,6 +478,27 @@ static void ghes_do_proc(const struct acpi_hest_generic_status *estatus)
476 } 478 }
477#endif 479#endif
478 } 480 }
481#ifdef CONFIG_ACPI_APEI_PCIEAER
482 else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
483 CPER_SEC_PCIE)) {
484 struct cper_sec_pcie *pcie_err;
485 pcie_err = (struct cper_sec_pcie *)(gdata+1);
486 if (sev == GHES_SEV_RECOVERABLE &&
487 sec_sev == GHES_SEV_RECOVERABLE &&
488 pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
489 pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
490 unsigned int devfn;
491 int aer_severity;
492 devfn = PCI_DEVFN(pcie_err->device_id.device,
493 pcie_err->device_id.function);
494 aer_severity = cper_severity_to_aer(sev);
495 aer_recover_queue(pcie_err->device_id.segment,
496 pcie_err->device_id.bus,
497 devfn, aer_severity);
498 }
499
500 }
501#endif
479 } 502 }
480} 503}
481 504
@@ -483,16 +506,22 @@ static void __ghes_print_estatus(const char *pfx,
483 const struct acpi_hest_generic *generic, 506 const struct acpi_hest_generic *generic,
484 const struct acpi_hest_generic_status *estatus) 507 const struct acpi_hest_generic_status *estatus)
485{ 508{
509 static atomic_t seqno;
510 unsigned int curr_seqno;
511 char pfx_seq[64];
512
486 if (pfx == NULL) { 513 if (pfx == NULL) {
487 if (ghes_severity(estatus->error_severity) <= 514 if (ghes_severity(estatus->error_severity) <=
488 GHES_SEV_CORRECTED) 515 GHES_SEV_CORRECTED)
489 pfx = KERN_WARNING HW_ERR; 516 pfx = KERN_WARNING;
490 else 517 else
491 pfx = KERN_ERR HW_ERR; 518 pfx = KERN_ERR;
492 } 519 }
520 curr_seqno = atomic_inc_return(&seqno);
521 snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno);
493 printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", 522 printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
494 pfx, generic->header.source_id); 523 pfx_seq, generic->header.source_id);
495 apei_estatus_print(pfx, estatus); 524 apei_estatus_print(pfx_seq, estatus);
496} 525}
497 526
498static int ghes_print_estatus(const char *pfx, 527static int ghes_print_estatus(const char *pfx,
@@ -711,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this,
711 return ret; 740 return ret;
712} 741}
713 742
743static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
744{
745 struct llist_node *next, *tail = NULL;
746
747 while (llnode) {
748 next = llnode->next;
749 llnode->next = tail;
750 tail = llnode;
751 llnode = next;
752 }
753
754 return tail;
755}
756
714static void ghes_proc_in_irq(struct irq_work *irq_work) 757static void ghes_proc_in_irq(struct irq_work *irq_work)
715{ 758{
716 struct llist_node *llnode, *next, *tail = NULL; 759 struct llist_node *llnode, *next;
717 struct ghes_estatus_node *estatus_node; 760 struct ghes_estatus_node *estatus_node;
718 struct acpi_hest_generic *generic; 761 struct acpi_hest_generic *generic;
719 struct acpi_hest_generic_status *estatus; 762 struct acpi_hest_generic_status *estatus;
720 u32 len, node_len; 763 u32 len, node_len;
721 764
765 llnode = llist_del_all(&ghes_estatus_llist);
722 /* 766 /*
723 * Because the time order of estatus in list is reversed, 767 * Because the time order of estatus in list is reversed,
724 * revert it back to proper order. 768 * revert it back to proper order.
725 */ 769 */
726 llnode = llist_del_all(&ghes_estatus_llist); 770 llnode = llist_nodes_reverse(llnode);
727 while (llnode) {
728 next = llnode->next;
729 llnode->next = tail;
730 tail = llnode;
731 llnode = next;
732 }
733 llnode = tail;
734 while (llnode) { 771 while (llnode) {
735 next = llnode->next; 772 next = llnode->next;
736 estatus_node = llist_entry(llnode, struct ghes_estatus_node, 773 estatus_node = llist_entry(llnode, struct ghes_estatus_node,
@@ -750,6 +787,32 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
750 } 787 }
751} 788}
752 789
790static void ghes_print_queued_estatus(void)
791{
792 struct llist_node *llnode;
793 struct ghes_estatus_node *estatus_node;
794 struct acpi_hest_generic *generic;
795 struct acpi_hest_generic_status *estatus;
796 u32 len, node_len;
797
798 llnode = llist_del_all(&ghes_estatus_llist);
799 /*
800 * Because the time order of estatus in list is reversed,
801 * revert it back to proper order.
802 */
803 llnode = llist_nodes_reverse(llnode);
804 while (llnode) {
805 estatus_node = llist_entry(llnode, struct ghes_estatus_node,
806 llnode);
807 estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
808 len = apei_estatus_len(estatus);
809 node_len = GHES_ESTATUS_NODE_LEN(len);
810 generic = estatus_node->generic;
811 ghes_print_estatus(NULL, generic, estatus);
812 llnode = llnode->next;
813 }
814}
815
753static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) 816static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
754{ 817{
755 struct ghes *ghes, *ghes_global = NULL; 818 struct ghes *ghes, *ghes_global = NULL;
@@ -775,7 +838,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
775 838
776 if (sev_global >= GHES_SEV_PANIC) { 839 if (sev_global >= GHES_SEV_PANIC) {
777 oops_begin(); 840 oops_begin();
778 __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global->generic, 841 ghes_print_queued_estatus();
842 __ghes_print_estatus(KERN_EMERG, ghes_global->generic,
779 ghes_global->estatus); 843 ghes_global->estatus);
780 /* reboot to log the error! */ 844 /* reboot to log the error! */
781 if (panic_timeout == 0) 845 if (panic_timeout == 0)
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index 05fee06f4d6e..f709269d4932 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -221,10 +221,9 @@ void __init acpi_hest_init(void)
221 221
222 status = acpi_get_table(ACPI_SIG_HEST, 0, 222 status = acpi_get_table(ACPI_SIG_HEST, 0,
223 (struct acpi_table_header **)&hest_tab); 223 (struct acpi_table_header **)&hest_tab);
224 if (status == AE_NOT_FOUND) { 224 if (status == AE_NOT_FOUND)
225 pr_info(HEST_PFX "Table not found.\n");
226 goto err; 225 goto err;
227 } else if (ACPI_FAILURE(status)) { 226 else if (ACPI_FAILURE(status)) {
228 const char *msg = acpi_format_exception(status); 227 const char *msg = acpi_format_exception(status);
229 pr_err(HEST_PFX "Failed to get table, %s\n", msg); 228 pr_err(HEST_PFX "Failed to get table, %s\n", msg);
230 rc = -EINVAL; 229 rc = -EINVAL;
diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
index cfc0cc10af39..d4a5b3d3657b 100644
--- a/drivers/acpi/atomicio.c
+++ b/drivers/acpi/atomicio.c
@@ -32,6 +32,8 @@
32#include <linux/rculist.h> 32#include <linux/rculist.h>
33#include <linux/interrupt.h> 33#include <linux/interrupt.h>
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <linux/mm.h>
36#include <linux/highmem.h>
35#include <acpi/atomicio.h> 37#include <acpi/atomicio.h>
36 38
37#define ACPI_PFX "ACPI: " 39#define ACPI_PFX "ACPI: "
@@ -97,6 +99,37 @@ static void __iomem *__acpi_try_ioremap(phys_addr_t paddr,
97 return NULL; 99 return NULL;
98} 100}
99 101
102#ifndef CONFIG_IA64
103#define should_use_kmap(pfn) page_is_ram(pfn)
104#else
105/* ioremap will take care of cache attributes */
106#define should_use_kmap(pfn) 0
107#endif
108
109static void __iomem *acpi_map(phys_addr_t pg_off, unsigned long pg_sz)
110{
111 unsigned long pfn;
112
113 pfn = pg_off >> PAGE_SHIFT;
114 if (should_use_kmap(pfn)) {
115 if (pg_sz > PAGE_SIZE)
116 return NULL;
117 return (void __iomem __force *)kmap(pfn_to_page(pfn));
118 } else
119 return ioremap(pg_off, pg_sz);
120}
121
122static void acpi_unmap(phys_addr_t pg_off, void __iomem *vaddr)
123{
124 unsigned long pfn;
125
126 pfn = pg_off >> PAGE_SHIFT;
127 if (page_is_ram(pfn))
128 kunmap(pfn_to_page(pfn));
129 else
130 iounmap(vaddr);
131}
132
100/* 133/*
101 * Used to pre-map the specified IO memory area. First try to find 134 * Used to pre-map the specified IO memory area. First try to find
102 * whether the area is already pre-mapped, if it is, increase the 135 * whether the area is already pre-mapped, if it is, increase the
@@ -119,7 +152,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
119 152
120 pg_off = paddr & PAGE_MASK; 153 pg_off = paddr & PAGE_MASK;
121 pg_sz = ((paddr + size + PAGE_SIZE - 1) & PAGE_MASK) - pg_off; 154 pg_sz = ((paddr + size + PAGE_SIZE - 1) & PAGE_MASK) - pg_off;
122 vaddr = ioremap(pg_off, pg_sz); 155 vaddr = acpi_map(pg_off, pg_sz);
123 if (!vaddr) 156 if (!vaddr)
124 return NULL; 157 return NULL;
125 map = kmalloc(sizeof(*map), GFP_KERNEL); 158 map = kmalloc(sizeof(*map), GFP_KERNEL);
@@ -135,7 +168,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
135 vaddr = __acpi_try_ioremap(paddr, size); 168 vaddr = __acpi_try_ioremap(paddr, size);
136 if (vaddr) { 169 if (vaddr) {
137 spin_unlock_irqrestore(&acpi_iomaps_lock, flags); 170 spin_unlock_irqrestore(&acpi_iomaps_lock, flags);
138 iounmap(map->vaddr); 171 acpi_unmap(pg_off, map->vaddr);
139 kfree(map); 172 kfree(map);
140 return vaddr; 173 return vaddr;
141 } 174 }
@@ -144,7 +177,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr,
144 177
145 return map->vaddr + (paddr - map->paddr); 178 return map->vaddr + (paddr - map->paddr);
146err_unmap: 179err_unmap:
147 iounmap(vaddr); 180 acpi_unmap(pg_off, vaddr);
148 return NULL; 181 return NULL;
149} 182}
150 183
@@ -177,7 +210,7 @@ static void acpi_post_unmap(phys_addr_t paddr, unsigned long size)
177 return; 210 return;
178 211
179 synchronize_rcu(); 212 synchronize_rcu();
180 iounmap(map->vaddr); 213 acpi_unmap(map->paddr, map->vaddr);
181 kfree(map); 214 kfree(map);
182} 215}
183 216
@@ -260,6 +293,21 @@ int acpi_post_unmap_gar(struct acpi_generic_address *reg)
260} 293}
261EXPORT_SYMBOL_GPL(acpi_post_unmap_gar); 294EXPORT_SYMBOL_GPL(acpi_post_unmap_gar);
262 295
296#ifdef readq
297static inline u64 read64(const volatile void __iomem *addr)
298{
299 return readq(addr);
300}
301#else
302static inline u64 read64(const volatile void __iomem *addr)
303{
304 u64 l, h;
305 l = readl(addr);
306 h = readl(addr+4);
307 return l | (h << 32);
308}
309#endif
310
263/* 311/*
264 * Can be used in atomic (including NMI) or process context. RCU read 312 * Can be used in atomic (including NMI) or process context. RCU read
265 * lock can only be released after the IO memory area accessing. 313 * lock can only be released after the IO memory area accessing.
@@ -280,11 +328,9 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
280 case 32: 328 case 32:
281 *val = readl(addr); 329 *val = readl(addr);
282 break; 330 break;
283#ifdef readq
284 case 64: 331 case 64:
285 *val = readq(addr); 332 *val = read64(addr);
286 break; 333 break;
287#endif
288 default: 334 default:
289 return -EINVAL; 335 return -EINVAL;
290 } 336 }
@@ -293,6 +339,19 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
293 return 0; 339 return 0;
294} 340}
295 341
342#ifdef writeq
343static inline void write64(u64 val, volatile void __iomem *addr)
344{
345 writeq(val, addr);
346}
347#else
348static inline void write64(u64 val, volatile void __iomem *addr)
349{
350 writel(val, addr);
351 writel(val>>32, addr+4);
352}
353#endif
354
296static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width) 355static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
297{ 356{
298 void __iomem *addr; 357 void __iomem *addr;
@@ -309,11 +368,9 @@ static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
309 case 32: 368 case 32:
310 writel(val, addr); 369 writel(val, addr);
311 break; 370 break;
312#ifdef writeq
313 case 64: 371 case 64:
314 writeq(val, addr); 372 write64(val, addr);
315 break; 373 break;
316#endif
317 default: 374 default:
318 return -EINVAL; 375 return -EINVAL;
319 } 376 }
diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c
index 096787b43c96..7a2035fa8c71 100644
--- a/drivers/acpi/nvs.c
+++ b/drivers/acpi/nvs.c
@@ -15,6 +15,56 @@
15#include <linux/acpi_io.h> 15#include <linux/acpi_io.h>
16#include <acpi/acpiosxf.h> 16#include <acpi/acpiosxf.h>
17 17
18/* ACPI NVS regions, APEI may use it */
19
20struct nvs_region {
21 __u64 phys_start;
22 __u64 size;
23 struct list_head node;
24};
25
26static LIST_HEAD(nvs_region_list);
27
28#ifdef CONFIG_ACPI_SLEEP
29static int suspend_nvs_register(unsigned long start, unsigned long size);
30#else
31static inline int suspend_nvs_register(unsigned long a, unsigned long b)
32{
33 return 0;
34}
35#endif
36
37int acpi_nvs_register(__u64 start, __u64 size)
38{
39 struct nvs_region *region;
40
41 region = kmalloc(sizeof(*region), GFP_KERNEL);
42 if (!region)
43 return -ENOMEM;
44 region->phys_start = start;
45 region->size = size;
46 list_add_tail(&region->node, &nvs_region_list);
47
48 return suspend_nvs_register(start, size);
49}
50
51int acpi_nvs_for_each_region(int (*func)(__u64 start, __u64 size, void *data),
52 void *data)
53{
54 int rc;
55 struct nvs_region *region;
56
57 list_for_each_entry(region, &nvs_region_list, node) {
58 rc = func(region->phys_start, region->size, data);
59 if (rc)
60 return rc;
61 }
62
63 return 0;
64}
65
66
67#ifdef CONFIG_ACPI_SLEEP
18/* 68/*
19 * Platforms, like ACPI, may want us to save some memory used by them during 69 * Platforms, like ACPI, may want us to save some memory used by them during
20 * suspend and to restore the contents of this memory during the subsequent 70 * suspend and to restore the contents of this memory during the subsequent
@@ -41,7 +91,7 @@ static LIST_HEAD(nvs_list);
41 * things so that the data from page-aligned addresses in this region will 91 * things so that the data from page-aligned addresses in this region will
42 * be copied into separate RAM pages. 92 * be copied into separate RAM pages.
43 */ 93 */
44int suspend_nvs_register(unsigned long start, unsigned long size) 94static int suspend_nvs_register(unsigned long start, unsigned long size)
45{ 95{
46 struct nvs_page *entry, *next; 96 struct nvs_page *entry, *next;
47 97
@@ -159,3 +209,4 @@ void suspend_nvs_restore(void)
159 if (entry->data) 209 if (entry->data)
160 memcpy(entry->kaddr, entry->data, entry->size); 210 memcpy(entry->kaddr, entry->data, entry->size);
161} 211}
212#endif