[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