aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/iomap.h3
-rw-r--r--arch/x86/mm/iomap_32.c18
-rw-r--r--include/linux/io-mapping.h46
3 files changed, 56 insertions, 11 deletions
diff --git a/arch/x86/include/asm/iomap.h b/arch/x86/include/asm/iomap.h
index c1f06289b14b..86af26091d6c 100644
--- a/arch/x86/include/asm/iomap.h
+++ b/arch/x86/include/asm/iomap.h
@@ -23,6 +23,9 @@
23#include <asm/pgtable.h> 23#include <asm/pgtable.h>
24#include <asm/tlbflush.h> 24#include <asm/tlbflush.h>
25 25
26int
27is_io_mapping_possible(resource_size_t base, unsigned long size);
28
26void * 29void *
27iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot); 30iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
28 31
diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c
index ca53224fc56c..6c2b1af16926 100644
--- a/arch/x86/mm/iomap_32.c
+++ b/arch/x86/mm/iomap_32.c
@@ -20,6 +20,24 @@
20#include <asm/pat.h> 20#include <asm/pat.h>
21#include <linux/module.h> 21#include <linux/module.h>
22 22
23#ifdef CONFIG_X86_PAE
24int
25is_io_mapping_possible(resource_size_t base, unsigned long size)
26{
27 return 1;
28}
29#else
30int
31is_io_mapping_possible(resource_size_t base, unsigned long size)
32{
33 /* There is no way to map greater than 1 << 32 address without PAE */
34 if (base + size > 0x100000000ULL)
35 return 0;
36
37 return 1;
38}
39#endif
40
23/* Map 'pfn' using fixed map 'type' and protections 'prot' 41/* Map 'pfn' using fixed map 'type' and protections 'prot'
24 */ 42 */
25void * 43void *
diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h
index 82df31726a54..cbc2f0cd631b 100644
--- a/include/linux/io-mapping.h
+++ b/include/linux/io-mapping.h
@@ -30,11 +30,14 @@
30 * See Documentation/io_mapping.txt 30 * See Documentation/io_mapping.txt
31 */ 31 */
32 32
33/* this struct isn't actually defined anywhere */
34struct io_mapping;
35
36#ifdef CONFIG_HAVE_ATOMIC_IOMAP 33#ifdef CONFIG_HAVE_ATOMIC_IOMAP
37 34
35struct io_mapping {
36 resource_size_t base;
37 unsigned long size;
38 pgprot_t prot;
39};
40
38/* 41/*
39 * For small address space machines, mapping large objects 42 * For small address space machines, mapping large objects
40 * into the kernel virtual space isn't practical. Where 43 * into the kernel virtual space isn't practical. Where
@@ -43,23 +46,40 @@ struct io_mapping;
43 */ 46 */
44 47
45static inline struct io_mapping * 48static inline struct io_mapping *
46io_mapping_create_wc(unsigned long base, unsigned long size) 49io_mapping_create_wc(resource_size_t base, unsigned long size)
47{ 50{
48 return (struct io_mapping *) base; 51 struct io_mapping *iomap;
52
53 if (!is_io_mapping_possible(base, size))
54 return NULL;
55
56 iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
57 if (!iomap)
58 return NULL;
59
60 iomap->base = base;
61 iomap->size = size;
62 iomap->prot = pgprot_writecombine(__pgprot(__PAGE_KERNEL));
63 return iomap;
49} 64}
50 65
51static inline void 66static inline void
52io_mapping_free(struct io_mapping *mapping) 67io_mapping_free(struct io_mapping *mapping)
53{ 68{
69 kfree(mapping);
54} 70}
55 71
56/* Atomic map/unmap */ 72/* Atomic map/unmap */
57static inline void * 73static inline void *
58io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset) 74io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
59{ 75{
60 offset += (unsigned long) mapping; 76 resource_size_t phys_addr;
61 return iomap_atomic_prot_pfn(offset >> PAGE_SHIFT, KM_USER0, 77 unsigned long pfn;
62 __pgprot(__PAGE_KERNEL_WC)); 78
79 BUG_ON(offset >= mapping->size);
80 phys_addr = mapping->base + offset;
81 pfn = (unsigned long) (phys_addr >> PAGE_SHIFT);
82 return iomap_atomic_prot_pfn(pfn, KM_USER0, mapping->prot);
63} 83}
64 84
65static inline void 85static inline void
@@ -71,8 +91,9 @@ io_mapping_unmap_atomic(void *vaddr)
71static inline void * 91static inline void *
72io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset) 92io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset)
73{ 93{
74 offset += (unsigned long) mapping; 94 BUG_ON(offset >= mapping->size);
75 return ioremap_wc(offset, PAGE_SIZE); 95 resource_size_t phys_addr = mapping->base + offset;
96 return ioremap_wc(phys_addr, PAGE_SIZE);
76} 97}
77 98
78static inline void 99static inline void
@@ -83,9 +104,12 @@ io_mapping_unmap(void *vaddr)
83 104
84#else 105#else
85 106
107/* this struct isn't actually defined anywhere */
108struct io_mapping;
109
86/* Create the io_mapping object*/ 110/* Create the io_mapping object*/
87static inline struct io_mapping * 111static inline struct io_mapping *
88io_mapping_create_wc(unsigned long base, unsigned long size) 112io_mapping_create_wc(resource_size_t base, unsigned long size)
89{ 113{
90 return (struct io_mapping *) ioremap_wc(base, size); 114 return (struct io_mapping *) ioremap_wc(base, size);
91} 115}