diff options
-rw-r--r-- | arch/x86/mm/ioremap.c | 57 |
1 files changed, 35 insertions, 22 deletions
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 8777bb7688f4..b86f66fa5185 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -19,6 +19,11 @@ | |||
19 | #include <asm/pgtable.h> | 19 | #include <asm/pgtable.h> |
20 | #include <asm/tlbflush.h> | 20 | #include <asm/tlbflush.h> |
21 | 21 | ||
22 | enum ioremap_mode { | ||
23 | IOR_MODE_UNCACHED, | ||
24 | IOR_MODE_CACHED, | ||
25 | }; | ||
26 | |||
22 | #ifdef CONFIG_X86_64 | 27 | #ifdef CONFIG_X86_64 |
23 | 28 | ||
24 | unsigned long __phys_addr(unsigned long x) | 29 | unsigned long __phys_addr(unsigned long x) |
@@ -64,19 +69,17 @@ int page_is_ram(unsigned long pagenr) | |||
64 | * Fix up the linear direct mapping of the kernel to avoid cache attribute | 69 | * Fix up the linear direct mapping of the kernel to avoid cache attribute |
65 | * conflicts. | 70 | * conflicts. |
66 | */ | 71 | */ |
67 | static int ioremap_change_attr(unsigned long phys_addr, unsigned long size, | 72 | static int ioremap_change_attr(unsigned long paddr, unsigned long size, |
68 | pgprot_t prot) | 73 | enum ioremap_mode mode) |
69 | { | 74 | { |
70 | unsigned long npages, vaddr, last_addr = phys_addr + size - 1; | 75 | unsigned long vaddr = (unsigned long)__va(paddr); |
76 | unsigned long nrpages = size >> PAGE_SHIFT; | ||
71 | int err, level; | 77 | int err, level; |
72 | 78 | ||
73 | /* No change for pages after the last mapping */ | 79 | /* No change for pages after the last mapping */ |
74 | if (last_addr >= (max_pfn_mapped << PAGE_SHIFT)) | 80 | if ((paddr + size - 1) >= (max_pfn_mapped << PAGE_SHIFT)) |
75 | return 0; | 81 | return 0; |
76 | 82 | ||
77 | npages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
78 | vaddr = (unsigned long) __va(phys_addr); | ||
79 | |||
80 | /* | 83 | /* |
81 | * If there is no identity map for this address, | 84 | * If there is no identity map for this address, |
82 | * change_page_attr_addr is unnecessary | 85 | * change_page_attr_addr is unnecessary |
@@ -84,13 +87,15 @@ static int ioremap_change_attr(unsigned long phys_addr, unsigned long size, | |||
84 | if (!lookup_address(vaddr, &level)) | 87 | if (!lookup_address(vaddr, &level)) |
85 | return 0; | 88 | return 0; |
86 | 89 | ||
87 | /* | 90 | switch (mode) { |
88 | * Must use an address here and not struct page because the | 91 | case IOR_MODE_UNCACHED: |
89 | * phys addr can be a in hole between nodes and not have a | 92 | default: |
90 | * memmap entry. | 93 | err = set_memory_uc(vaddr, nrpages); |
91 | */ | 94 | break; |
92 | err = change_page_attr_addr(vaddr, npages, prot); | 95 | case IOR_MODE_CACHED: |
93 | 96 | err = set_memory_wb(vaddr, nrpages); | |
97 | break; | ||
98 | } | ||
94 | if (!err) | 99 | if (!err) |
95 | global_flush_tlb(); | 100 | global_flush_tlb(); |
96 | 101 | ||
@@ -107,12 +112,12 @@ static int ioremap_change_attr(unsigned long phys_addr, unsigned long size, | |||
107 | * caller shouldn't need to know that small detail. | 112 | * caller shouldn't need to know that small detail. |
108 | */ | 113 | */ |
109 | static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size, | 114 | static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size, |
110 | unsigned long flags) | 115 | enum ioremap_mode mode) |
111 | { | 116 | { |
112 | void __iomem *addr; | 117 | void __iomem *addr; |
113 | struct vm_struct *area; | 118 | struct vm_struct *area; |
114 | unsigned long offset, last_addr; | 119 | unsigned long offset, last_addr; |
115 | pgprot_t pgprot; | 120 | pgprot_t prot; |
116 | 121 | ||
117 | /* Don't allow wraparound or zero size */ | 122 | /* Don't allow wraparound or zero size */ |
118 | last_addr = phys_addr + size - 1; | 123 | last_addr = phys_addr + size - 1; |
@@ -134,7 +139,15 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size, | |||
134 | return NULL; | 139 | return NULL; |
135 | } | 140 | } |
136 | 141 | ||
137 | pgprot = MAKE_GLOBAL(__PAGE_KERNEL | flags); | 142 | switch (mode) { |
143 | case IOR_MODE_UNCACHED: | ||
144 | default: | ||
145 | prot = PAGE_KERNEL_NOCACHE; | ||
146 | break; | ||
147 | case IOR_MODE_CACHED: | ||
148 | prot = PAGE_KERNEL; | ||
149 | break; | ||
150 | } | ||
138 | 151 | ||
139 | /* | 152 | /* |
140 | * Mappings have to be page-aligned | 153 | * Mappings have to be page-aligned |
@@ -152,12 +165,12 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size, | |||
152 | area->phys_addr = phys_addr; | 165 | area->phys_addr = phys_addr; |
153 | addr = (void __iomem *) area->addr; | 166 | addr = (void __iomem *) area->addr; |
154 | if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, | 167 | if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, |
155 | phys_addr, pgprot)) { | 168 | phys_addr, prot)) { |
156 | remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr)); | 169 | remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr)); |
157 | return NULL; | 170 | return NULL; |
158 | } | 171 | } |
159 | 172 | ||
160 | if (ioremap_change_attr(phys_addr, size, pgprot) < 0) { | 173 | if (ioremap_change_attr(phys_addr, size, mode) < 0) { |
161 | vunmap(addr); | 174 | vunmap(addr); |
162 | return NULL; | 175 | return NULL; |
163 | } | 176 | } |
@@ -188,13 +201,13 @@ static void __iomem *__ioremap(unsigned long phys_addr, unsigned long size, | |||
188 | */ | 201 | */ |
189 | void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size) | 202 | void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size) |
190 | { | 203 | { |
191 | return __ioremap(phys_addr, size, _PAGE_PCD | _PAGE_PWT); | 204 | return __ioremap(phys_addr, size, IOR_MODE_UNCACHED); |
192 | } | 205 | } |
193 | EXPORT_SYMBOL(ioremap_nocache); | 206 | EXPORT_SYMBOL(ioremap_nocache); |
194 | 207 | ||
195 | void __iomem *ioremap_cache(unsigned long phys_addr, unsigned long size) | 208 | void __iomem *ioremap_cache(unsigned long phys_addr, unsigned long size) |
196 | { | 209 | { |
197 | return __ioremap(phys_addr, size, 0); | 210 | return __ioremap(phys_addr, size, IOR_MODE_CACHED); |
198 | } | 211 | } |
199 | EXPORT_SYMBOL(ioremap_cache); | 212 | EXPORT_SYMBOL(ioremap_cache); |
200 | 213 | ||
@@ -242,7 +255,7 @@ void iounmap(volatile void __iomem *addr) | |||
242 | } | 255 | } |
243 | 256 | ||
244 | /* Reset the direct mapping. Can block */ | 257 | /* Reset the direct mapping. Can block */ |
245 | ioremap_change_attr(p->phys_addr, p->size, PAGE_KERNEL); | 258 | ioremap_change_attr(p->phys_addr, p->size, IOR_MODE_CACHED); |
246 | 259 | ||
247 | /* Finally remove it */ | 260 | /* Finally remove it */ |
248 | o = remove_vm_area((void *)addr); | 261 | o = remove_vm_area((void *)addr); |