ACPI: Introduce acpi_os_ioremap()
authorRafael J. Wysocki <rjw@sisk.pl>
Wed, 19 Jan 2011 21:27:14 +0000 (22:27 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 21 Jan 2011 02:30:17 +0000 (18:30 -0800)
Commit ca9b600be38c ("ACPI / PM: Make suspend_nvs_save() use
acpi_os_map_memory()") attempted to prevent the code in osl.c and nvs.c
from using different ioremap() variants by making the latter use
acpi_os_map_memory() for mapping the NVS pages.  However, that also
requires acpi_os_unmap_memory() to be used for unmapping them, which
causes synchronize_rcu() to be executed many times in a row
unnecessarily and introduces substantial delays during resume on some
systems.

Instead of using acpi_os_map_memory() for mapping the NVS pages in nvs.c
introduce acpi_os_ioremap() calling ioremap_cache() and make the code in
both osl.c and nvs.c use it.

Reported-by: Jeff Chua <jeff.chua.linux@gmail.com>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/acpi/nvs.c
drivers/acpi/osl.c
include/linux/acpi.h
include/linux/acpi_io.h [new file with mode: 0644]

index 54b6ab8040a6ed05039ce59d576969371e7fa3f8..fa5a1df42b79a40a817d27f036789d7bcd3a3c38 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
+#include <linux/acpi_io.h>
 #include <acpi/acpiosxf.h>
 
 /*
@@ -80,7 +81,7 @@ void suspend_nvs_free(void)
                        free_page((unsigned long)entry->data);
                        entry->data = NULL;
                        if (entry->kaddr) {
-                               acpi_os_unmap_memory(entry->kaddr, entry->size);
+                               iounmap(entry->kaddr);
                                entry->kaddr = NULL;
                        }
                }
@@ -114,8 +115,8 @@ int suspend_nvs_save(void)
 
        list_for_each_entry(entry, &nvs_list, node)
                if (entry->data) {
-                       entry->kaddr = acpi_os_map_memory(entry->phys_start,
-                                                         entry->size);
+                       entry->kaddr = acpi_os_ioremap(entry->phys_start,
+                                                   entry->size);
                        if (!entry->kaddr) {
                                suspend_nvs_free();
                                return -ENOMEM;
index e2dd6de5d50c8dbd01246416a59f26dcda51c954..b0931818cf98f133bf000f49e7200c8bbd9611fb 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/workqueue.h>
 #include <linux/nmi.h>
 #include <linux/acpi.h>
+#include <linux/acpi_io.h>
 #include <linux/efi.h>
 #include <linux/ioport.h>
 #include <linux/list.h>
@@ -302,9 +303,10 @@ void __iomem *__init_refok
 acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
        struct acpi_ioremap *map, *tmp_map;
-       unsigned long flags, pg_sz;
+       unsigned long flags;
        void __iomem *virt;
-       phys_addr_t pg_off;
+       acpi_physical_address pg_off;
+       acpi_size pg_sz;
 
        if (phys > ULONG_MAX) {
                printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@@ -320,7 +322,7 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 
        pg_off = round_down(phys, PAGE_SIZE);
        pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
-       virt = ioremap_cache(pg_off, pg_sz);
+       virt = acpi_os_ioremap(pg_off, pg_sz);
        if (!virt) {
                kfree(map);
                return NULL;
@@ -642,7 +644,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
        rcu_read_unlock();
        if (!virt_addr) {
-               virt_addr = ioremap_cache(phys_addr, size);
+               virt_addr = acpi_os_ioremap(phys_addr, size);
                unmap = 1;
        }
        if (!value)
@@ -678,7 +680,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
        virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
        rcu_read_unlock();
        if (!virt_addr) {
-               virt_addr = ioremap_cache(phys_addr, size);
+               virt_addr = acpi_os_ioremap(phys_addr, size);
                unmap = 1;
        }
 
index eb176bb1b15b722f8c1f78b1650f38302e85a60f..a2e910e01293a01fd229cd59dfb1c1bb69f7be1a 100644 (file)
@@ -306,9 +306,6 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
                                             u32 *mask, u32 req);
 extern void acpi_early_init(void);
 
-int acpi_os_map_generic_address(struct acpi_generic_address *addr);
-void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
-
 #else  /* !CONFIG_ACPI */
 
 #define acpi_disabled 1
diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h
new file mode 100644 (file)
index 0000000..7180013
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _ACPI_IO_H_
+#define _ACPI_IO_H_
+
+#include <linux/io.h>
+#include <acpi/acpi.h>
+
+static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys,
+                                           acpi_size size)
+{
+       return ioremap_cache(phys, size);
+}
+
+int acpi_os_map_generic_address(struct acpi_generic_address *addr);
+void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
+
+#endif