[PATCH 1/1] acpi_init: move to full RCU free for IO mappings

Andy Whitcroft apw at canonical.com
Fri Sep 23 15:50:27 UTC 2011


During acpi_init we map and unmap a large number of mappings.  The existing
code uses 'simple' RCU based free, triggering a full sychronize_rcu()
against the caller.  If the machine is busy (for example unpacking the
initramfs) at the time this triggers a significant delay until all cpus
rendevous.  Move those to a delayed RCU free callback.

For our reference platform this cuts the average acpi_init time in half,
dropping boot time by .25s.

Signed-off-by: Andy Whitcroft <apw at canonical.com>
---
 drivers/acpi/atomicio.c |   12 +++++++++---
 drivers/acpi/osl.c      |   16 +++++++++++-----
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
index 7489b89..0a7a554 100644
--- a/drivers/acpi/atomicio.c
+++ b/drivers/acpi/atomicio.c
@@ -49,6 +49,7 @@ struct acpi_iomap {
 	unsigned long size;
 	phys_addr_t paddr;
 	struct kref ref;
+	struct rcu_head iomap_rcu;
 };
 
 /* acpi_iomaps_lock or RCU read lock must be held before calling */
@@ -161,6 +162,13 @@ static void __acpi_kref_del_iomap(struct kref *ref)
  * Used to post-unmap the specified IO memory area. The iounmap is
  * done only if the reference count goes zero.
  */
+static void acpi_post_unmap_rcu(struct rcu_head *rcu)
+{
+	struct acpi_iomap *map = container_of(rcu, 
+					struct acpi_iomap, iomap_rcu);
+	iounmap(map->vaddr);
+	kfree(map);
+}
 static void acpi_post_unmap(phys_addr_t paddr, unsigned long size)
 {
 	struct acpi_iomap *map;
@@ -176,9 +184,7 @@ static void acpi_post_unmap(phys_addr_t paddr, unsigned long size)
 	if (!del)
 		return;
 
-	synchronize_rcu();
-	iounmap(map->vaddr);
-	kfree(map);
+	call_rcu(&map->iomap_rcu, acpi_post_unmap_rcu);
 }
 
 /* In NMI handler, should set silent = 1 */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 372f9b7..9b3a520 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -105,6 +105,7 @@ struct acpi_ioremap {
 	acpi_physical_address phys;
 	acpi_size size;
 	unsigned long refcount;
+	struct rcu_head map_rcu;
 };
 
 static LIST_HEAD(acpi_ioremaps);
@@ -373,13 +374,18 @@ static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
 		list_del_rcu(&map->list);
 }
 
+static void acpi_os_map_cleanup_rcu(struct rcu_head *rcu)
+{
+	struct acpi_ioremap *map = container_of(rcu,
+					struct acpi_ioremap, map_rcu);
+	iounmap(map->virt);
+	kfree(map);
+}
+
 static void acpi_os_map_cleanup(struct acpi_ioremap *map)
 {
-	if (!map->refcount) {
-		synchronize_rcu();
-		iounmap(map->virt);
-		kfree(map);
-	}
+	if (!map->refcount)
+		call_rcu(&map->map_rcu, acpi_os_map_cleanup_rcu);
 }
 
 void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
-- 
1.7.4.1





More information about the kernel-team mailing list