From: Myron Stowe <myron.stowe@hp.com>
To: lenb@kernel.org
Cc: linux-acpi@vger.kernel.org, ak@linux.intel.com, ying.huang@intel.com
Subject: [PATCH 2/7] ACPI: Maintain a list of ACPI memory mapped I/O remappings
Date: Thu, 21 Oct 2010 14:23:53 -0600 [thread overview]
Message-ID: <20101021202353.9220.89287.stgit@bob.kio> (raw)
In-Reply-To: <20101021201916.9220.5711.stgit@bob.kio>
For memory mapped I/O (MMIO) remappings, add a list to maintain the
remappings and augment the corresponding mapping and unmapping interface
routines (acpi_os_map_memory() and acpi_os_unmap_memory()) to
dynamically add to, and delete from, the list.
The current ACPI I/O accessing methods - acpi_read() and acpi_write() -
end up calling ioremap() when accessing MMIO. This prevents use of these
methods within interrupt context (IRQ and/or NMI), since ioremap() may
block to allocate memory. Maintaining a list of MMIO remappings enables
accesses to such areas from within interrupt context provided they have
been pre-mapped.
Signed-off-by: Myron Stowe <myron.stowe@hp.com>
---
drivers/acpi/osl.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 113 insertions(+), 15 deletions(-)
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 58842fb..bd72129 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -95,6 +95,20 @@ struct acpi_res_list {
static LIST_HEAD(resource_list_head);
static DEFINE_SPINLOCK(acpi_res_lock);
+/*
+ * This list of permanent mappings is for memory that may be accessed from
+ * interrupt context, where we can't do the ioremap().
+ */
+struct acpi_ioremap {
+ struct list_head list;
+ void __iomem *virt;
+ acpi_physical_address phys;
+ acpi_size size;
+};
+
+static LIST_HEAD(acpi_ioremaps);
+static DEFINE_SPINLOCK(acpi_ioremap_lock);
+
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
static char osi_additional_string[OSI_STRING_LENGTH_MAX];
@@ -260,29 +274,95 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
}
}
+/* Must be called with 'acpi_ioremap_lock' lock held. */
+static void __iomem *
+acpi_map_vaddr_lookup(acpi_physical_address phys, acpi_size size)
+{
+ struct acpi_ioremap *map;
+
+ list_for_each_entry(map, &acpi_ioremaps, list)
+ if (map->phys <= phys &&
+ phys + size <= map->phys + map->size)
+ return map->virt + (phys - map->phys);
+
+ return NULL;
+}
+
+/* Must be called with 'acpi_ioremap_lock' lock held. */
+static struct acpi_ioremap *
+acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
+{
+ struct acpi_ioremap *map;
+
+ list_for_each_entry(map, &acpi_ioremaps, list)
+ if (map->virt == virt && map->size == size)
+ return map;
+
+ return NULL;
+}
+
void __iomem *__init_refok
acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{
+ struct acpi_ioremap *map;
+ unsigned long flags;
+ void __iomem *virt;
+
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
return NULL;
}
- if (acpi_gbl_permanent_mmap)
- /*
- * ioremap checks to ensure this is in reserved space
- */
- return ioremap((unsigned long)phys, size);
- else
+
+ if (!acpi_gbl_permanent_mmap)
return __acpi_map_table((unsigned long)phys, size);
+
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return NULL;
+
+ virt = ioremap(phys, size);
+ if (!virt) {
+ kfree(map);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&map->list);
+ map->virt = virt;
+ map->phys = phys;
+ map->size = size;
+
+ spin_lock_irqsave(&acpi_ioremap_lock, flags);
+ list_add_tail(&map->list, &acpi_ioremaps);
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+ return virt;
}
EXPORT_SYMBOL_GPL(acpi_os_map_memory);
void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
{
- if (acpi_gbl_permanent_mmap)
- iounmap(virt);
- else
+ struct acpi_ioremap *map;
+ unsigned long flags;
+
+ if (!acpi_gbl_permanent_mmap) {
__acpi_unmap_table(virt, size);
+ return;
+ }
+
+ spin_lock_irqsave(&acpi_ioremap_lock, flags);
+ map = acpi_map_lookup_virt(virt, size);
+ if (!map) {
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+ printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt);
+ dump_stack();
+ return;
+ }
+
+ list_del(&map->list);
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+
+ iounmap(map->virt);
+ kfree(map);
}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
@@ -495,8 +575,16 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
{
u32 dummy;
void __iomem *virt_addr;
-
- virt_addr = ioremap(phys_addr, width / 8);
+ int size = width / 8, unmap = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&acpi_ioremap_lock, flags);
+ virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+ if (!virt_addr) {
+ virt_addr = ioremap(phys_addr, size);
+ unmap = 1;
+ }
if (!value)
value = &dummy;
@@ -514,7 +602,8 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
BUG();
}
- iounmap(virt_addr);
+ if (unmap)
+ iounmap(virt_addr);
return AE_OK;
}
@@ -523,8 +612,16 @@ acpi_status
acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
{
void __iomem *virt_addr;
-
- virt_addr = ioremap(phys_addr, width / 8);
+ int size = width / 8, unmap = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&acpi_ioremap_lock, flags);
+ virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
+ spin_unlock_irqrestore(&acpi_ioremap_lock, flags);
+ if (!virt_addr) {
+ virt_addr = ioremap(phys_addr, size);
+ unmap = 1;
+ }
switch (width) {
case 8:
@@ -540,7 +637,8 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
BUG();
}
- iounmap(virt_addr);
+ if (unmap)
+ iounmap(virt_addr);
return AE_OK;
}
next prev parent reply other threads:[~2010-10-21 20:23 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-21 20:23 [PATCH 0/7] ACPI: Memory Mapped I/O (MMIO) pre-mapping Myron Stowe
2010-10-21 20:23 ` [PATCH 1/7] ACPI: Fix ioremap size for MMIO reads and writes Myron Stowe
2010-10-21 20:23 ` Myron Stowe [this message]
2010-10-21 20:23 ` [PATCH 3/7] ACPI: Add interfaces for ioremapping/iounmapping ACPI registers Myron Stowe
2010-10-21 20:24 ` [PATCH 4/7] ACPI: Pre-map 'system event' related register blocks Myron Stowe
2010-10-21 20:24 ` [PATCH 5/7] ACPI: Convert simple locking to RCU based locking Myron Stowe
2010-10-21 20:24 ` [PATCH 6/7] ACPI: Page based coalescing of I/O remappings optimization Myron Stowe
2010-10-22 1:03 ` Huang Ying
2010-10-22 3:23 ` Myron Stowe
2010-10-22 5:17 ` Huang Ying
2010-10-22 16:27 ` Myron Stowe
2010-10-25 1:22 ` Huang Ying
2010-10-21 20:24 ` [PATCH 7/7] ACPI: Re-factor and remove ./drivers/acpi/atomicio.[ch] Myron Stowe
2010-10-22 2:43 ` [PATCH 0/7] ACPI: Memory Mapped I/O (MMIO) pre-mapping Shaohua Li
2010-10-22 2:57 ` Huang Ying
2010-10-22 3:16 ` Shaohua Li
2010-10-22 3:24 ` Huang Ying
2010-10-22 17:10 ` Bjorn Helgaas
2010-10-25 8:34 ` Andi Kleen
2010-10-25 8:43 ` Huang Ying
2010-10-25 9:29 ` Andi Kleen
2010-10-25 3:38 ` Len Brown
2010-10-25 15:34 ` Myron Stowe
2010-10-25 18:34 ` Andi Kleen
2010-10-28 1:53 ` Len Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20101021202353.9220.89287.stgit@bob.kio \
--to=myron.stowe@hp.com \
--cc=ak@linux.intel.com \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=ying.huang@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.