Provide devm_ioremap_cache() and fix up devm_ioremap_resource() to
actually provide cacheable mappings.  On archs that implement
ioremap_cache() devm_ioremap_resource() is always silently falling back
to uncached when IORESOURCE_CACHEABLE is specified.

Cc: Toshi Kani <toshi.k...@hp.com>
Cc: Arnd Bergmann <a...@arndb.de>
Signed-off-by: Dan Williams <dan.j.willi...@intel.com>
---
 include/linux/io.h |    2 ++
 lib/devres.c       |   53 +++++++++++++++++++++++++---------------------------
 2 files changed, 27 insertions(+), 28 deletions(-)

diff --git a/include/linux/io.h b/include/linux/io.h
index 04cce4da3685..1c9ad4c6d485 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -70,6 +70,8 @@ static inline void devm_ioport_unmap(struct device *dev, void 
__iomem *addr)
 
 void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
                           resource_size_t size);
+void __iomem *devm_ioremap_cache(struct device *dev, resource_size_t offset,
+                          resource_size_t size);
 void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
                                   resource_size_t size);
 void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
diff --git a/lib/devres.c b/lib/devres.c
index f4001d90d24d..c8e75cdaf816 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -14,6 +14,8 @@ static int devm_ioremap_match(struct device *dev, void *res, 
void *match_data)
        return *(void **)res == match_data;
 }
 
+typedef void __iomem *(*ioremap_fn)(resource_size_t offset, unsigned long 
size);
+
 /**
  * devm_ioremap - Managed ioremap()
  * @dev: Generic device to remap IO address for
@@ -22,8 +24,9 @@ static int devm_ioremap_match(struct device *dev, void *res, 
void *match_data)
  *
  * Managed ioremap().  Map is automatically unmapped on driver detach.
  */
-void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
-                          resource_size_t size)
+static void __iomem *devm_ioremap_type(struct device *dev,
+               resource_size_t offset, resource_size_t size,
+               ioremap_fn ioremap_type)
 {
        void __iomem **ptr, *addr;
 
@@ -31,7 +34,7 @@ void __iomem *devm_ioremap(struct device *dev, 
resource_size_t offset,
        if (!ptr)
                return NULL;
 
-       addr = ioremap(offset, size);
+       addr = ioremap_type(offset, size);
        if (addr) {
                *ptr = addr;
                devres_add(dev, ptr);
@@ -40,34 +43,25 @@ void __iomem *devm_ioremap(struct device *dev, 
resource_size_t offset,
 
        return addr;
 }
+
+void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
+                          resource_size_t size)
+{
+       return devm_ioremap_type(dev, offset, size, ioremap);
+}
 EXPORT_SYMBOL(devm_ioremap);
 
-/**
- * devm_ioremap_nocache - Managed ioremap_nocache()
- * @dev: Generic device to remap IO address for
- * @offset: BUS offset to map
- * @size: Size of map
- *
- * Managed ioremap_nocache().  Map is automatically unmapped on driver
- * detach.
- */
+void __iomem *devm_ioremap_cache(struct device *dev, resource_size_t offset,
+                          resource_size_t size)
+{
+       return devm_ioremap_type(dev, offset, size, ioremap_cache);
+}
+EXPORT_SYMBOL(devm_ioremap_cache);
+
 void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
                                   resource_size_t size)
 {
-       void __iomem **ptr, *addr;
-
-       ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
-       if (!ptr)
-               return NULL;
-
-       addr = ioremap_nocache(offset, size);
-       if (addr) {
-               *ptr = addr;
-               devres_add(dev, ptr);
-       } else
-               devres_free(ptr);
-
-       return addr;
+       return devm_ioremap_type(dev, offset, size, ioremap_nocache);
 }
 EXPORT_SYMBOL(devm_ioremap_nocache);
 
@@ -153,8 +147,11 @@ void __iomem *devm_ioremap_resource(struct device *dev, 
struct resource *res)
                return IOMEM_ERR_PTR(-EBUSY);
        }
 
-       /* FIXME: add devm_ioremap_cache support */
-       dest_ptr = devm_ioremap(dev, res->start, size);
+       if (res->flags & IORESOURCE_CACHEABLE)
+               dest_ptr = devm_ioremap_cache(dev, res->start, size);
+       else
+               dest_ptr = devm_ioremap_nocache(dev, res->start, size);
+
        if (!dest_ptr) {
                dev_err(dev, "ioremap failed for resource %pR\n", res);
                devm_release_mem_region(dev, res->start, size);

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to