aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/ioremap.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/ioremap.c')
-rw-r--r--arch/x86/mm/ioremap.c152
1 files changed, 114 insertions, 38 deletions
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 794895c6dcc9..c590fd200e29 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -19,11 +19,7 @@
19#include <asm/pgtable.h> 19#include <asm/pgtable.h>
20#include <asm/tlbflush.h> 20#include <asm/tlbflush.h>
21#include <asm/pgalloc.h> 21#include <asm/pgalloc.h>
22 22#include <asm/pat.h>
23enum ioremap_mode {
24 IOR_MODE_UNCACHED,
25 IOR_MODE_CACHED,
26};
27 23
28#ifdef CONFIG_X86_64 24#ifdef CONFIG_X86_64
29 25
@@ -35,11 +31,23 @@ unsigned long __phys_addr(unsigned long x)
35} 31}
36EXPORT_SYMBOL(__phys_addr); 32EXPORT_SYMBOL(__phys_addr);
37 33
34static inline int phys_addr_valid(unsigned long addr)
35{
36 return addr < (1UL << boot_cpu_data.x86_phys_bits);
37}
38
39#else
40
41static inline int phys_addr_valid(unsigned long addr)
42{
43 return 1;
44}
45
38#endif 46#endif
39 47
40int page_is_ram(unsigned long pagenr) 48int page_is_ram(unsigned long pagenr)
41{ 49{
42 unsigned long addr, end; 50 resource_size_t addr, end;
43 int i; 51 int i;
44 52
45 /* 53 /*
@@ -78,19 +86,22 @@ int page_is_ram(unsigned long pagenr)
78 * Fix up the linear direct mapping of the kernel to avoid cache attribute 86 * Fix up the linear direct mapping of the kernel to avoid cache attribute
79 * conflicts. 87 * conflicts.
80 */ 88 */
81static int ioremap_change_attr(unsigned long vaddr, unsigned long size, 89int ioremap_change_attr(unsigned long vaddr, unsigned long size,
82 enum ioremap_mode mode) 90 unsigned long prot_val)
83{ 91{
84 unsigned long nrpages = size >> PAGE_SHIFT; 92 unsigned long nrpages = size >> PAGE_SHIFT;
85 int err; 93 int err;
86 94
87 switch (mode) { 95 switch (prot_val) {
88 case IOR_MODE_UNCACHED: 96 case _PAGE_CACHE_UC:
89 default: 97 default:
90 err = set_memory_uc(vaddr, nrpages); 98 err = _set_memory_uc(vaddr, nrpages);
99 break;
100 case _PAGE_CACHE_WC:
101 err = _set_memory_wc(vaddr, nrpages);
91 break; 102 break;
92 case IOR_MODE_CACHED: 103 case _PAGE_CACHE_WB:
93 err = set_memory_wb(vaddr, nrpages); 104 err = _set_memory_wb(vaddr, nrpages);
94 break; 105 break;
95 } 106 }
96 107
@@ -107,17 +118,27 @@ static int ioremap_change_attr(unsigned long vaddr, unsigned long size,
107 * caller shouldn't need to know that small detail. 118 * caller shouldn't need to know that small detail.
108 */ 119 */
109static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size, 120static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
110 enum ioremap_mode mode) 121 unsigned long prot_val)
111{ 122{
112 unsigned long pfn, offset, last_addr, vaddr; 123 unsigned long pfn, offset, vaddr;
124 resource_size_t last_addr;
113 struct vm_struct *area; 125 struct vm_struct *area;
126 unsigned long new_prot_val;
114 pgprot_t prot; 127 pgprot_t prot;
128 int retval;
115 129
116 /* Don't allow wraparound or zero size */ 130 /* Don't allow wraparound or zero size */
117 last_addr = phys_addr + size - 1; 131 last_addr = phys_addr + size - 1;
118 if (!size || last_addr < phys_addr) 132 if (!size || last_addr < phys_addr)
119 return NULL; 133 return NULL;
120 134
135 if (!phys_addr_valid(phys_addr)) {
136 printk(KERN_WARNING "ioremap: invalid physical address %llx\n",
137 phys_addr);
138 WARN_ON_ONCE(1);
139 return NULL;
140 }
141
121 /* 142 /*
122 * Don't remap the low PCI/ISA area, it's always mapped.. 143 * Don't remap the low PCI/ISA area, it's always mapped..
123 */ 144 */
@@ -127,25 +148,14 @@ static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
127 /* 148 /*
128 * Don't allow anybody to remap normal RAM that we're using.. 149 * Don't allow anybody to remap normal RAM that we're using..
129 */ 150 */
130 for (pfn = phys_addr >> PAGE_SHIFT; pfn < max_pfn_mapped && 151 for (pfn = phys_addr >> PAGE_SHIFT;
131 (pfn << PAGE_SHIFT) < last_addr; pfn++) { 152 (pfn << PAGE_SHIFT) < last_addr; pfn++) {
132 if (page_is_ram(pfn) && pfn_valid(pfn) &&
133 !PageReserved(pfn_to_page(pfn)))
134 return NULL;
135 }
136 153
137 switch (mode) { 154 int is_ram = page_is_ram(pfn);
138 case IOR_MODE_UNCACHED: 155
139 default: 156 if (is_ram && pfn_valid(pfn) && !PageReserved(pfn_to_page(pfn)))
140 /* 157 return NULL;
141 * FIXME: we will use UC MINUS for now, as video fb drivers 158 WARN_ON_ONCE(is_ram);
142 * depend on it. Upcoming ioremap_wc() will fix this behavior.
143 */
144 prot = PAGE_KERNEL_UC_MINUS;
145 break;
146 case IOR_MODE_CACHED:
147 prot = PAGE_KERNEL;
148 break;
149 } 159 }
150 160
151 /* 161 /*
@@ -155,6 +165,49 @@ static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
155 phys_addr &= PAGE_MASK; 165 phys_addr &= PAGE_MASK;
156 size = PAGE_ALIGN(last_addr+1) - phys_addr; 166 size = PAGE_ALIGN(last_addr+1) - phys_addr;
157 167
168 retval = reserve_memtype(phys_addr, phys_addr + size,
169 prot_val, &new_prot_val);
170 if (retval) {
171 pr_debug("Warning: reserve_memtype returned %d\n", retval);
172 return NULL;
173 }
174
175 if (prot_val != new_prot_val) {
176 /*
177 * Do not fallback to certain memory types with certain
178 * requested type:
179 * - request is uncached, return cannot be write-back
180 * - request is uncached, return cannot be write-combine
181 * - request is write-combine, return cannot be write-back
182 */
183 if ((prot_val == _PAGE_CACHE_UC &&
184 (new_prot_val == _PAGE_CACHE_WB ||
185 new_prot_val == _PAGE_CACHE_WC)) ||
186 (prot_val == _PAGE_CACHE_WC &&
187 new_prot_val == _PAGE_CACHE_WB)) {
188 pr_debug(
189 "ioremap error for 0x%llx-0x%llx, requested 0x%lx, got 0x%lx\n",
190 phys_addr, phys_addr + size,
191 prot_val, new_prot_val);
192 free_memtype(phys_addr, phys_addr + size);
193 return NULL;
194 }
195 prot_val = new_prot_val;
196 }
197
198 switch (prot_val) {
199 case _PAGE_CACHE_UC:
200 default:
201 prot = PAGE_KERNEL_NOCACHE;
202 break;
203 case _PAGE_CACHE_WC:
204 prot = PAGE_KERNEL_WC;
205 break;
206 case _PAGE_CACHE_WB:
207 prot = PAGE_KERNEL;
208 break;
209 }
210
158 /* 211 /*
159 * Ok, go for it.. 212 * Ok, go for it..
160 */ 213 */
@@ -164,11 +217,13 @@ static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
164 area->phys_addr = phys_addr; 217 area->phys_addr = phys_addr;
165 vaddr = (unsigned long) area->addr; 218 vaddr = (unsigned long) area->addr;
166 if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) { 219 if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) {
220 free_memtype(phys_addr, phys_addr + size);
167 free_vm_area(area); 221 free_vm_area(area);
168 return NULL; 222 return NULL;
169 } 223 }
170 224
171 if (ioremap_change_attr(vaddr, size, mode) < 0) { 225 if (ioremap_change_attr(vaddr, size, prot_val) < 0) {
226 free_memtype(phys_addr, phys_addr + size);
172 vunmap(area->addr); 227 vunmap(area->addr);
173 return NULL; 228 return NULL;
174 } 229 }
@@ -199,13 +254,32 @@ static void __iomem *__ioremap(resource_size_t phys_addr, unsigned long size,
199 */ 254 */
200void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size) 255void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
201{ 256{
202 return __ioremap(phys_addr, size, IOR_MODE_UNCACHED); 257 return __ioremap(phys_addr, size, _PAGE_CACHE_UC);
203} 258}
204EXPORT_SYMBOL(ioremap_nocache); 259EXPORT_SYMBOL(ioremap_nocache);
205 260
261/**
262 * ioremap_wc - map memory into CPU space write combined
263 * @offset: bus address of the memory
264 * @size: size of the resource to map
265 *
266 * This version of ioremap ensures that the memory is marked write combining.
267 * Write combining allows faster writes to some hardware devices.
268 *
269 * Must be freed with iounmap.
270 */
271void __iomem *ioremap_wc(unsigned long phys_addr, unsigned long size)
272{
273 if (pat_wc_enabled)
274 return __ioremap(phys_addr, size, _PAGE_CACHE_WC);
275 else
276 return ioremap_nocache(phys_addr, size);
277}
278EXPORT_SYMBOL(ioremap_wc);
279
206void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size) 280void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size)
207{ 281{
208 return __ioremap(phys_addr, size, IOR_MODE_CACHED); 282 return __ioremap(phys_addr, size, _PAGE_CACHE_WB);
209} 283}
210EXPORT_SYMBOL(ioremap_cache); 284EXPORT_SYMBOL(ioremap_cache);
211 285
@@ -252,6 +326,8 @@ void iounmap(volatile void __iomem *addr)
252 return; 326 return;
253 } 327 }
254 328
329 free_memtype(p->phys_addr, p->phys_addr + get_vm_area_size(p));
330
255 /* Finally remove it */ 331 /* Finally remove it */
256 o = remove_vm_area((void *)addr); 332 o = remove_vm_area((void *)addr);
257 BUG_ON(p != o || o == NULL); 333 BUG_ON(p != o || o == NULL);
@@ -272,8 +348,8 @@ static int __init early_ioremap_debug_setup(char *str)
272early_param("early_ioremap_debug", early_ioremap_debug_setup); 348early_param("early_ioremap_debug", early_ioremap_debug_setup);
273 349
274static __initdata int after_paging_init; 350static __initdata int after_paging_init;
275static __initdata pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)] 351static pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)]
276 __attribute__((aligned(PAGE_SIZE))); 352 __section(.bss.page_aligned);
277 353
278static inline pmd_t * __init early_ioremap_pmd(unsigned long addr) 354static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
279{ 355{