diff options
author | Huang Ying <ying.huang@intel.com> | 2011-12-07 22:25:49 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-01-17 03:54:44 -0500 |
commit | b54ac6d2a25084667da781c7ca2cebef52a2bcdd (patch) | |
tree | b4dbaa790dcecff6b5b0772846d43b360f6389d7 /drivers/acpi | |
parent | b4e008dc53a31cb4bf6a12d9dbaf1d5c6070a838 (diff) |
ACPI, Record ACPI NVS regions
Some firmware will access memory in ACPI NVS region via APEI. That
is, instructions in APEI ERST/EINJ table will read/write ACPI NVS
region. The original resource conflict checking in APEI code will
check memory/ioport accessed by APEI via general resource management
mechanism. But ACPI NVS region is marked as busy already, so that the
false resource conflict will prevent APEI ERST/EINJ to work.
To fix this, this patch record ACPI NVS regions, so that we can avoid
request resources for memory region inside it.
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/Makefile | 3 | ||||
-rw-r--r-- | drivers/acpi/nvs.c | 53 |
2 files changed, 54 insertions, 2 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. |
21 | acpi-y += osl.o utils.o reboot.o | 21 | acpi-y += osl.o utils.o reboot.o |
22 | acpi-y += atomicio.o | 22 | acpi-y += atomicio.o |
23 | acpi-y += nvs.o | ||
23 | 24 | ||
24 | # sleep related files | 25 | # sleep related files |
25 | acpi-y += wakeup.o | 26 | acpi-y += wakeup.o |
26 | acpi-y += sleep.o | 27 | acpi-y += sleep.o |
27 | acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o | 28 | acpi-$(CONFIG_ACPI_SLEEP) += proc.o |
28 | 29 | ||
29 | 30 | ||
30 | # | 31 | # |
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 | |||
20 | struct nvs_region { | ||
21 | __u64 phys_start; | ||
22 | __u64 size; | ||
23 | struct list_head node; | ||
24 | }; | ||
25 | |||
26 | static LIST_HEAD(nvs_region_list); | ||
27 | |||
28 | #ifdef CONFIG_ACPI_SLEEP | ||
29 | static int suspend_nvs_register(unsigned long start, unsigned long size); | ||
30 | #else | ||
31 | static inline int suspend_nvs_register(unsigned long a, unsigned long b) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | #endif | ||
36 | |||
37 | int 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(®ion->node, &nvs_region_list); | ||
47 | |||
48 | return suspend_nvs_register(start, size); | ||
49 | } | ||
50 | |||
51 | int 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 | */ |
44 | int suspend_nvs_register(unsigned long start, unsigned long size) | 94 | static 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 | ||