aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/ioremap_32.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-01-30 07:34:05 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:34:05 -0500
commite9332cacd74b25548a517b8dd4fff0216f7907db (patch)
tree200a1678dcb177614fe5f862854d10995401646f /arch/x86/mm/ioremap_32.c
parent74ff2857f099951020a47420872f5c1460f32c27 (diff)
x86: switch to change_page_attr_addr in ioremap_32.c
Use change_page_attr_addr() instead of change_page_attr(), which simplifies the code significantly and matches the 64bit implementation. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/mm/ioremap_32.c')
-rw-r--r--arch/x86/mm/ioremap_32.c90
1 files changed, 49 insertions, 41 deletions
diff --git a/arch/x86/mm/ioremap_32.c b/arch/x86/mm/ioremap_32.c
index 213ace58a188..ae7e55c8c647 100644
--- a/arch/x86/mm/ioremap_32.c
+++ b/arch/x86/mm/ioremap_32.c
@@ -6,6 +6,7 @@
6 * (C) Copyright 1995 1996 Linus Torvalds 6 * (C) Copyright 1995 1996 Linus Torvalds
7 */ 7 */
8 8
9#include <linux/bootmem.h>
9#include <linux/init.h> 10#include <linux/init.h>
10#include <linux/io.h> 11#include <linux/io.h>
11#include <linux/module.h> 12#include <linux/module.h>
@@ -19,6 +20,42 @@
19#include <asm/tlbflush.h> 20#include <asm/tlbflush.h>
20 21
21/* 22/*
23 * Fix up the linear direct mapping of the kernel to avoid cache attribute
24 * conflicts.
25 */
26static int ioremap_change_attr(unsigned long phys_addr, unsigned long size,
27 pgprot_t prot)
28{
29 unsigned long npages, vaddr, last_addr = phys_addr + size - 1;
30 int err, level;
31
32 /* No change for pages after the last mapping */
33 if (last_addr >= (max_pfn_mapped << PAGE_SHIFT))
34 return 0;
35
36 npages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
37 vaddr = (unsigned long) __va(phys_addr);
38
39 /*
40 * If there is no identity map for this address,
41 * change_page_attr_addr is unnecessary
42 */
43 if (!lookup_address(vaddr, &level))
44 return 0;
45
46 /*
47 * Must use an address here and not struct page because the
48 * phys addr can be a in hole between nodes and not have a
49 * memmap entry.
50 */
51 err = change_page_attr_addr(vaddr, npages, prot);
52 if (!err)
53 global_flush_tlb();
54
55 return err;
56}
57
58/*
22 * Remap an arbitrary physical address space into the kernel virtual 59 * Remap an arbitrary physical address space into the kernel virtual
23 * address space. Needed when the kernel wants to access high addresses 60 * address space. Needed when the kernel wants to access high addresses
24 * directly. 61 * directly.
@@ -33,7 +70,7 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
33 void __iomem *addr; 70 void __iomem *addr;
34 struct vm_struct *area; 71 struct vm_struct *area;
35 unsigned long offset, last_addr; 72 unsigned long offset, last_addr;
36 pgprot_t prot; 73 pgprot_t pgprot;
37 74
38 /* Don't allow wraparound or zero size */ 75 /* Don't allow wraparound or zero size */
39 last_addr = phys_addr + size - 1; 76 last_addr = phys_addr + size - 1;
@@ -62,7 +99,7 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
62 return NULL; 99 return NULL;
63 } 100 }
64 101
65 prot = MAKE_GLOBAL(__PAGE_KERNEL | flags); 102 pgprot = MAKE_GLOBAL(__PAGE_KERNEL | flags);
66 103
67 /* 104 /*
68 * Mappings have to be page-aligned 105 * Mappings have to be page-aligned
@@ -79,11 +116,17 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
79 return NULL; 116 return NULL;
80 area->phys_addr = phys_addr; 117 area->phys_addr = phys_addr;
81 addr = (void __iomem *) area->addr; 118 addr = (void __iomem *) area->addr;
82 if (ioremap_page_range((unsigned long) addr, 119 if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
83 (unsigned long) addr + size, phys_addr, prot)) { 120 phys_addr, pgprot)) {
84 vunmap((void __force *) addr); 121 vunmap((void __force *) addr);
85 return NULL; 122 return NULL;
86 } 123 }
124
125 if (ioremap_change_attr(phys_addr, size, pgprot) < 0) {
126 vunmap(addr);
127 return NULL;
128 }
129
87 return (void __iomem *) (offset + (char __iomem *)addr); 130 return (void __iomem *) (offset + (char __iomem *)addr);
88} 131}
89EXPORT_SYMBOL(__ioremap); 132EXPORT_SYMBOL(__ioremap);
@@ -111,37 +154,7 @@ EXPORT_SYMBOL(__ioremap);
111 */ 154 */
112void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size) 155void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size)
113{ 156{
114 unsigned long last_addr; 157 return __ioremap(phys_addr, size, _PAGE_PCD | _PAGE_PWT);
115 void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD | _PAGE_PWT);
116
117 if (!p)
118 return p;
119
120 /* Guaranteed to be > phys_addr, as per __ioremap() */
121 last_addr = phys_addr + size - 1;
122
123 if (last_addr < virt_to_phys(high_memory) - 1) {
124 struct page *ppage = virt_to_page(__va(phys_addr));
125 unsigned long npages;
126
127 phys_addr &= PAGE_MASK;
128
129 /* This might overflow and become zero.. */
130 last_addr = PAGE_ALIGN(last_addr);
131
132 /* .. but that's ok, because modulo-2**n arithmetic will make
133 * the page-aligned "last - first" come out right.
134 */
135 npages = (last_addr - phys_addr) >> PAGE_SHIFT;
136
137 if (change_page_attr(ppage, npages, PAGE_KERNEL_NOCACHE) < 0) {
138 iounmap(p);
139 p = NULL;
140 }
141 global_flush_tlb();
142 }
143
144 return p;
145} 158}
146EXPORT_SYMBOL(ioremap_nocache); 159EXPORT_SYMBOL(ioremap_nocache);
147 160
@@ -189,12 +202,7 @@ void iounmap(volatile void __iomem *addr)
189 } 202 }
190 203
191 /* Reset the direct mapping. Can block */ 204 /* Reset the direct mapping. Can block */
192 if (p->phys_addr < virt_to_phys(high_memory) - 1) { 205 ioremap_change_attr(p->phys_addr, p->size, PAGE_KERNEL);
193 change_page_attr(virt_to_page(__va(p->phys_addr)),
194 get_vm_area_size(p) >> PAGE_SHIFT,
195 PAGE_KERNEL);
196 global_flush_tlb();
197 }
198 206
199 /* Finally remove it */ 207 /* Finally remove it */
200 o = remove_vm_area((void *)addr); 208 o = remove_vm_area((void *)addr);