io-mapping: Always create a struct to hold metadata about the io-mapping
authorChris Wilson <chris@chris-wilson.co.uk>
Fri, 19 Aug 2016 15:54:26 +0000 (16:54 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Fri, 19 Aug 2016 16:13:35 +0000 (17:13 +0100)
Currently, we only allocate a structure to hold metadata if we need to
allocate an ioremap for every access, such as on x86-32. However, it
would be useful to store basic information about the io-mapping, such as
its page protection, on all platforms.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: linux-mm@kvack.org
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20160819155428.1670-4-chris@chris-wilson.co.uk
include/linux/io-mapping.h

index 645ad06..b4c4b5c 100644 (file)
  * See Documentation/io-mapping.txt
  */
 
-#ifdef CONFIG_HAVE_ATOMIC_IOMAP
-
-#include <asm/iomap.h>
-
 struct io_mapping {
        resource_size_t base;
        unsigned long size;
        pgprot_t prot;
+       void __iomem *iomem;
 };
 
+#ifdef CONFIG_HAVE_ATOMIC_IOMAP
+
+#include <asm/iomap.h>
 /*
  * For small address space machines, mapping large objects
  * into the kernel virtual space isn't practical. Where
@@ -49,34 +49,25 @@ struct io_mapping {
  */
 
 static inline struct io_mapping *
-io_mapping_create_wc(resource_size_t base, unsigned long size)
+io_mapping_init_wc(struct io_mapping *iomap,
+                  resource_size_t base,
+                  unsigned long size)
 {
-       struct io_mapping *iomap;
        pgprot_t prot;
 
-       iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
-       if (!iomap)
-               goto out_err;
-
        if (iomap_create_wc(base, size, &prot))
-               goto out_free;
+               return NULL;
 
        iomap->base = base;
        iomap->size = size;
        iomap->prot = prot;
        return iomap;
-
-out_free:
-       kfree(iomap);
-out_err:
-       return NULL;
 }
 
 static inline void
-io_mapping_free(struct io_mapping *mapping)
+io_mapping_fini(struct io_mapping *mapping)
 {
        iomap_free(mapping->base, mapping->size);
-       kfree(mapping);
 }
 
 /* Atomic map/unmap */
@@ -121,21 +112,40 @@ io_mapping_unmap(void __iomem *vaddr)
 #else
 
 #include <linux/uaccess.h>
-
-/* this struct isn't actually defined anywhere */
-struct io_mapping;
+#include <asm/pgtable_types.h>
 
 /* Create the io_mapping object*/
 static inline struct io_mapping *
-io_mapping_create_wc(resource_size_t base, unsigned long size)
+io_mapping_init_wc(struct io_mapping *iomap,
+                  resource_size_t base,
+                  unsigned long size)
+{
+       iomap->base = base;
+       iomap->size = size;
+       iomap->iomem = ioremap_wc(base, size);
+       iomap->prot = pgprot_writecombine(PAGE_KERNEL_IO);
+
+       return iomap;
+}
+
+static inline void
+io_mapping_fini(struct io_mapping *mapping)
+{
+       iounmap(mapping->iomem);
+}
+
+/* Non-atomic map/unmap */
+static inline void __iomem *
+io_mapping_map_wc(struct io_mapping *mapping,
+                 unsigned long offset,
+                 unsigned long size)
 {
-       return (struct io_mapping __force *) ioremap_wc(base, size);
+       return mapping->iomem + offset;
 }
 
 static inline void
-io_mapping_free(struct io_mapping *mapping)
+io_mapping_unmap(void __iomem *vaddr)
 {
-       iounmap((void __force __iomem *) mapping);
 }
 
 /* Atomic map/unmap */
@@ -145,30 +155,42 @@ io_mapping_map_atomic_wc(struct io_mapping *mapping,
 {
        preempt_disable();
        pagefault_disable();
-       return ((char __force __iomem *) mapping) + offset;
+       return io_mapping_map_wc(mapping, offset, PAGE_SIZE);
 }
 
 static inline void
 io_mapping_unmap_atomic(void __iomem *vaddr)
 {
+       io_mapping_unmap(vaddr);
        pagefault_enable();
        preempt_enable();
 }
 
-/* Non-atomic map/unmap */
-static inline void __iomem *
-io_mapping_map_wc(struct io_mapping *mapping,
-                 unsigned long offset,
-                 unsigned long size)
+#endif /* HAVE_ATOMIC_IOMAP */
+
+static inline struct io_mapping *
+io_mapping_create_wc(resource_size_t base,
+                    unsigned long size)
 {
-       return ((char __force __iomem *) mapping) + offset;
+       struct io_mapping *iomap;
+
+       iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
+       if (!iomap)
+               return NULL;
+
+       if (!io_mapping_init_wc(iomap, base, size)) {
+               kfree(iomap);
+               return NULL;
+       }
+
+       return iomap;
 }
 
 static inline void
-io_mapping_unmap(void __iomem *vaddr)
+io_mapping_free(struct io_mapping *iomap)
 {
+       io_mapping_fini(iomap);
+       kfree(iomap);
 }
 
-#endif /* HAVE_ATOMIC_IOMAP */
-
 #endif /* _LINUX_IO_MAPPING_H */