Skip to content

Commit

Permalink
ACPI, Record ACPI NVS regions
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Len Brown <[email protected]>
  • Loading branch information
yhuang-intel authored and lenb committed Jan 17, 2012
1 parent b4e008d commit b54ac6d
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 10 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
53 changes: 52 additions & 1 deletion drivers/acpi/nvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,56 @@
#include <linux/acpi_io.h>
#include <acpi/acpiosxf.h>

/* ACPI NVS regions, APEI may use it */

struct nvs_region {
__u64 phys_start;
__u64 size;
struct list_head node;
};

static LIST_HEAD(nvs_region_list);

#ifdef CONFIG_ACPI_SLEEP
static int suspend_nvs_register(unsigned long start, unsigned long size);
#else
static inline int suspend_nvs_register(unsigned long a, unsigned long b)
{
return 0;
}
#endif

int acpi_nvs_register(__u64 start, __u64 size)
{
struct nvs_region *region;

region = kmalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return -ENOMEM;
region->phys_start = start;
region->size = size;
list_add_tail(&region->node, &nvs_region_list);

return suspend_nvs_register(start, size);
}

int acpi_nvs_for_each_region(int (*func)(__u64 start, __u64 size, void *data),
void *data)
{
int rc;
struct nvs_region *region;

list_for_each_entry(region, &nvs_region_list, node) {
rc = func(region->phys_start, region->size, data);
if (rc)
return rc;
}

return 0;
}


#ifdef CONFIG_ACPI_SLEEP
/*
* Platforms, like ACPI, may want us to save some memory used by them during
* suspend and to restore the contents of this memory during the subsequent
Expand All @@ -41,7 +91,7 @@ static LIST_HEAD(nvs_list);
* things so that the data from page-aligned addresses in this region will
* be copied into separate RAM pages.
*/
int suspend_nvs_register(unsigned long start, unsigned long size)
static int suspend_nvs_register(unsigned long start, unsigned long size)
{
struct nvs_page *entry, *next;

Expand Down Expand Up @@ -159,3 +209,4 @@ void suspend_nvs_restore(void)
if (entry->data)
memcpy(entry->kaddr, entry->data, entry->size);
}
#endif
20 changes: 14 additions & 6 deletions include/linux/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,11 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
u32 *mask, u32 req);
extern void acpi_early_init(void);

extern int acpi_nvs_register(__u64 start, __u64 size);

extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
void *data);

#else /* !CONFIG_ACPI */

#define acpi_disabled 1
Expand Down Expand Up @@ -348,15 +353,18 @@ static inline int acpi_table_parse(char *id,
{
return -1;
}
#endif /* !CONFIG_ACPI */

#ifdef CONFIG_ACPI_SLEEP
int suspend_nvs_register(unsigned long start, unsigned long size);
#else
static inline int suspend_nvs_register(unsigned long a, unsigned long b)
static inline int acpi_nvs_register(__u64 start, __u64 size)
{
return 0;
}
#endif

static inline int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
void *data)
{
return 0;
}

#endif /* !CONFIG_ACPI */

#endif /*_LINUX_ACPI_H*/

0 comments on commit b54ac6d

Please sign in to comment.