x86, pat: Add PAT reserve free to io_mapping* APIs
authorVenkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Fri, 10 Jul 2009 16:57:35 +0000 (09:57 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Wed, 26 Aug 2009 22:41:16 +0000 (15:41 -0700)
io_mapping_* interfaces were added, mainly for graphics drivers.
Make this interface go through the PAT reserve/free, instead of
hardcoding WC mapping. This makes sure that there are no
aliases due to unconditional WC setting.

Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/include/asm/iomap.h
arch/x86/mm/iomap_32.c
include/linux/io-mapping.h

index 0e9fe1d..f35eb45 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
-int
-is_io_mapping_possible(resource_size_t base, unsigned long size);
-
 void *
 iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
 
 void
 iounmap_atomic(void *kvaddr, enum km_type type);
 
+int
+iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot);
+
+void
+iomap_free(resource_size_t base, unsigned long size);
+
 #endif /* _ASM_X86_IOMAP_H */
index fe6f84c..84e236c 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/module.h>
 #include <linux/highmem.h>
 
-int is_io_mapping_possible(resource_size_t base, unsigned long size)
+static int is_io_mapping_possible(resource_size_t base, unsigned long size)
 {
 #if !defined(CONFIG_X86_PAE) && defined(CONFIG_PHYS_ADDR_T_64BIT)
        /* There is no way to map greater than 1 << 32 address without PAE */
@@ -30,7 +30,30 @@ int is_io_mapping_possible(resource_size_t base, unsigned long size)
 #endif
        return 1;
 }
-EXPORT_SYMBOL_GPL(is_io_mapping_possible);
+
+int iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot)
+{
+       unsigned long flag = _PAGE_CACHE_WC;
+       int ret;
+
+       if (!is_io_mapping_possible(base, size))
+               return -EINVAL;
+
+       ret = io_reserve_memtype(base, base + size, &flag);
+       if (ret)
+               return ret;
+
+       *prot = __pgprot(__PAGE_KERNEL | flag);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iomap_create_wc);
+
+void
+iomap_free(resource_size_t base, unsigned long size)
+{
+       io_free_memtype(base, base + size);
+}
+EXPORT_SYMBOL_GPL(iomap_free);
 
 void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
 {
index 0adb0f9..97eb928 100644 (file)
@@ -49,23 +49,30 @@ static inline struct io_mapping *
 io_mapping_create_wc(resource_size_t base, unsigned long size)
 {
        struct io_mapping *iomap;
-
-       if (!is_io_mapping_possible(base, size))
-               return NULL;
+       pgprot_t prot;
 
        iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
        if (!iomap)
-               return NULL;
+               goto out_err;
+
+       if (iomap_create_wc(base, size, &prot))
+               goto out_free;
 
        iomap->base = base;
        iomap->size = size;
-       iomap->prot = pgprot_writecombine(__pgprot(__PAGE_KERNEL));
+       iomap->prot = prot;
        return iomap;
+
+out_free:
+       kfree(iomap);
+out_err:
+       return NULL;
 }
 
 static inline void
 io_mapping_free(struct io_mapping *mapping)
 {
+       iomap_free(mapping->base, mapping->size);
        kfree(mapping);
 }