]> Pileus Git - ~andy/linux/blobdiff - drivers/acpi/nvs.c
Merge tag 'md-3.3-fixes' of git://neil.brown.name/md
[~andy/linux] / drivers / acpi / nvs.c
index fa5a1df42b79a40a817d27f036789d7bcd3a3c38..7a2035fa8c713d660a697d0d49e0a430476ed9fa 100644 (file)
 #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
@@ -26,6 +76,7 @@ struct nvs_page {
        unsigned int size;
        void *kaddr;
        void *data;
+       bool unmap;
        struct list_head node;
 };
 
@@ -40,10 +91,13 @@ 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;
 
+       pr_info("PM: Registering ACPI NVS region at %lx (%ld bytes)\n",
+               start, size);
+
        while (size > 0) {
                unsigned int nr_bytes;
 
@@ -81,7 +135,13 @@ void suspend_nvs_free(void)
                        free_page((unsigned long)entry->data);
                        entry->data = NULL;
                        if (entry->kaddr) {
-                               iounmap(entry->kaddr);
+                               if (entry->unmap) {
+                                       iounmap(entry->kaddr);
+                                       entry->unmap = false;
+                               } else {
+                                       acpi_os_unmap_memory(entry->kaddr,
+                                                            entry->size);
+                               }
                                entry->kaddr = NULL;
                        }
                }
@@ -115,8 +175,14 @@ int suspend_nvs_save(void)
 
        list_for_each_entry(entry, &nvs_list, node)
                if (entry->data) {
-                       entry->kaddr = acpi_os_ioremap(entry->phys_start,
-                                                   entry->size);
+                       unsigned long phys = entry->phys_start;
+                       unsigned int size = entry->size;
+
+                       entry->kaddr = acpi_os_get_iomem(phys, size);
+                       if (!entry->kaddr) {
+                               entry->kaddr = acpi_os_ioremap(phys, size);
+                               entry->unmap = !!entry->kaddr;
+                       }
                        if (!entry->kaddr) {
                                suspend_nvs_free();
                                return -ENOMEM;
@@ -143,3 +209,4 @@ void suspend_nvs_restore(void)
                if (entry->data)
                        memcpy(entry->kaddr, entry->data, entry->size);
 }
+#endif