diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2009-04-25 05:25:34 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2009-05-14 08:50:29 -0400 |
commit | bb86bf28aec6d0a207ae09f38a43e94133d4d6db (patch) | |
tree | 34bd8f653eb10dc4eb82aa8ef2576475346070e1 | |
parent | 0b54352600b820a6d25f151cbd8975ed9b2aeb09 (diff) |
MIPS: Fix highmem.
Commit 351336929ccf222ae38ff0cb7a8dd5fd5c6236a0 (kernel.org) rsp.
b3594a089f1c17ff919f8f78505c3f20e1f6f8ce (linux-mips.org):
> From: Chris Dearman <chris@mips.com>
> Date: Wed, 19 Sep 2007 00:58:24 +0100
> Subject: [PATCH] [MIPS] Allow setting of the cache attribute at run time.
>
> Slightly tacky, but there is a precedent in the sparc archirecture code.
introduces the variable _page_cachable_default, which defaults to zero and.
is used to create the prototype PTE for __kmap_atomic in
arch/mips/mm/init.c:kmap_init before initialization in
arch/mips/mm/c-r4k.c:coherency_setup, so the default value of 0 will be
used as the CCA of kmap atomic pages which on many processors is not a
defined CCA value and may result in writes to kmap_atomic pages getting
corrupted. Debugged by Jon Fraser (jfraser@broadcom.com).
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/include/asm/fixmap.h | 3 | ||||
-rw-r--r-- | arch/mips/include/asm/highmem.h | 6 | ||||
-rw-r--r-- | arch/mips/mm/highmem.c | 25 | ||||
-rw-r--r-- | arch/mips/mm/init.c | 26 |
4 files changed, 26 insertions, 34 deletions
diff --git a/arch/mips/include/asm/fixmap.h b/arch/mips/include/asm/fixmap.h index 9cc8522a394f..0f5caa1307f1 100644 --- a/arch/mips/include/asm/fixmap.h +++ b/arch/mips/include/asm/fixmap.h | |||
@@ -108,6 +108,9 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr) | |||
108 | return __virt_to_fix(vaddr); | 108 | return __virt_to_fix(vaddr); |
109 | } | 109 | } |
110 | 110 | ||
111 | #define kmap_get_fixmap_pte(vaddr) \ | ||
112 | pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) | ||
113 | |||
111 | /* | 114 | /* |
112 | * Called from pgtable_init() | 115 | * Called from pgtable_init() |
113 | */ | 116 | */ |
diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h index 4374ab2adc75..25adfb02923d 100644 --- a/arch/mips/include/asm/highmem.h +++ b/arch/mips/include/asm/highmem.h | |||
@@ -30,8 +30,6 @@ | |||
30 | /* declarations for highmem.c */ | 30 | /* declarations for highmem.c */ |
31 | extern unsigned long highstart_pfn, highend_pfn; | 31 | extern unsigned long highstart_pfn, highend_pfn; |
32 | 32 | ||
33 | extern pte_t *kmap_pte; | ||
34 | extern pgprot_t kmap_prot; | ||
35 | extern pte_t *pkmap_page_table; | 33 | extern pte_t *pkmap_page_table; |
36 | 34 | ||
37 | /* | 35 | /* |
@@ -62,6 +60,10 @@ extern struct page *__kmap_atomic_to_page(void *ptr); | |||
62 | 60 | ||
63 | #define flush_cache_kmaps() flush_cache_all() | 61 | #define flush_cache_kmaps() flush_cache_all() |
64 | 62 | ||
63 | extern void kmap_init(void); | ||
64 | |||
65 | #define kmap_prot PAGE_KERNEL | ||
66 | |||
65 | #endif /* __KERNEL__ */ | 67 | #endif /* __KERNEL__ */ |
66 | 68 | ||
67 | #endif /* _ASM_HIGHMEM_H */ | 69 | #endif /* _ASM_HIGHMEM_H */ |
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c index 4481656d1065..2b1309b2580a 100644 --- a/arch/mips/mm/highmem.c +++ b/arch/mips/mm/highmem.c | |||
@@ -1,7 +1,12 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include <linux/highmem.h> | 2 | #include <linux/highmem.h> |
3 | #include <asm/fixmap.h> | ||
3 | #include <asm/tlbflush.h> | 4 | #include <asm/tlbflush.h> |
4 | 5 | ||
6 | static pte_t *kmap_pte; | ||
7 | |||
8 | unsigned long highstart_pfn, highend_pfn; | ||
9 | |||
5 | void *__kmap(struct page *page) | 10 | void *__kmap(struct page *page) |
6 | { | 11 | { |
7 | void *addr; | 12 | void *addr; |
@@ -14,6 +19,7 @@ void *__kmap(struct page *page) | |||
14 | 19 | ||
15 | return addr; | 20 | return addr; |
16 | } | 21 | } |
22 | EXPORT_SYMBOL(__kmap); | ||
17 | 23 | ||
18 | void __kunmap(struct page *page) | 24 | void __kunmap(struct page *page) |
19 | { | 25 | { |
@@ -22,6 +28,7 @@ void __kunmap(struct page *page) | |||
22 | return; | 28 | return; |
23 | kunmap_high(page); | 29 | kunmap_high(page); |
24 | } | 30 | } |
31 | EXPORT_SYMBOL(__kunmap); | ||
25 | 32 | ||
26 | /* | 33 | /* |
27 | * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because | 34 | * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap because |
@@ -48,11 +55,12 @@ void *__kmap_atomic(struct page *page, enum km_type type) | |||
48 | #ifdef CONFIG_DEBUG_HIGHMEM | 55 | #ifdef CONFIG_DEBUG_HIGHMEM |
49 | BUG_ON(!pte_none(*(kmap_pte - idx))); | 56 | BUG_ON(!pte_none(*(kmap_pte - idx))); |
50 | #endif | 57 | #endif |
51 | set_pte(kmap_pte-idx, mk_pte(page, kmap_prot)); | 58 | set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL)); |
52 | local_flush_tlb_one((unsigned long)vaddr); | 59 | local_flush_tlb_one((unsigned long)vaddr); |
53 | 60 | ||
54 | return (void*) vaddr; | 61 | return (void*) vaddr; |
55 | } | 62 | } |
63 | EXPORT_SYMBOL(__kmap_atomic); | ||
56 | 64 | ||
57 | void __kunmap_atomic(void *kvaddr, enum km_type type) | 65 | void __kunmap_atomic(void *kvaddr, enum km_type type) |
58 | { | 66 | { |
@@ -77,6 +85,7 @@ void __kunmap_atomic(void *kvaddr, enum km_type type) | |||
77 | 85 | ||
78 | pagefault_enable(); | 86 | pagefault_enable(); |
79 | } | 87 | } |
88 | EXPORT_SYMBOL(__kunmap_atomic); | ||
80 | 89 | ||
81 | /* | 90 | /* |
82 | * This is the same as kmap_atomic() but can map memory that doesn't | 91 | * This is the same as kmap_atomic() but can map memory that doesn't |
@@ -92,7 +101,7 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type) | |||
92 | debug_kmap_atomic(type); | 101 | debug_kmap_atomic(type); |
93 | idx = type + KM_TYPE_NR*smp_processor_id(); | 102 | idx = type + KM_TYPE_NR*smp_processor_id(); |
94 | vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); | 103 | vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); |
95 | set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot)); | 104 | set_pte(kmap_pte-idx, pfn_pte(pfn, PAGE_KERNEL)); |
96 | flush_tlb_one(vaddr); | 105 | flush_tlb_one(vaddr); |
97 | 106 | ||
98 | return (void*) vaddr; | 107 | return (void*) vaddr; |
@@ -111,7 +120,11 @@ struct page *__kmap_atomic_to_page(void *ptr) | |||
111 | return pte_page(*pte); | 120 | return pte_page(*pte); |
112 | } | 121 | } |
113 | 122 | ||
114 | EXPORT_SYMBOL(__kmap); | 123 | void __init kmap_init(void) |
115 | EXPORT_SYMBOL(__kunmap); | 124 | { |
116 | EXPORT_SYMBOL(__kmap_atomic); | 125 | unsigned long kmap_vstart; |
117 | EXPORT_SYMBOL(__kunmap_atomic); | 126 | |
127 | /* cache the first kmap pte */ | ||
128 | kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); | ||
129 | kmap_pte = kmap_get_fixmap_pte(kmap_vstart); | ||
130 | } | ||
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index d9348946a19e..c5511294a9ee 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c | |||
@@ -104,14 +104,6 @@ unsigned long setup_zero_pages(void) | |||
104 | return 1UL << order; | 104 | return 1UL << order; |
105 | } | 105 | } |
106 | 106 | ||
107 | /* | ||
108 | * These are almost like kmap_atomic / kunmap_atmic except they take an | ||
109 | * additional address argument as the hint. | ||
110 | */ | ||
111 | |||
112 | #define kmap_get_fixmap_pte(vaddr) \ | ||
113 | pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) | ||
114 | |||
115 | #ifdef CONFIG_MIPS_MT_SMTC | 107 | #ifdef CONFIG_MIPS_MT_SMTC |
116 | static pte_t *kmap_coherent_pte; | 108 | static pte_t *kmap_coherent_pte; |
117 | static void __init kmap_coherent_init(void) | 109 | static void __init kmap_coherent_init(void) |
@@ -264,24 +256,6 @@ void copy_from_user_page(struct vm_area_struct *vma, | |||
264 | } | 256 | } |
265 | } | 257 | } |
266 | 258 | ||
267 | #ifdef CONFIG_HIGHMEM | ||
268 | unsigned long highstart_pfn, highend_pfn; | ||
269 | |||
270 | pte_t *kmap_pte; | ||
271 | pgprot_t kmap_prot; | ||
272 | |||
273 | static void __init kmap_init(void) | ||
274 | { | ||
275 | unsigned long kmap_vstart; | ||
276 | |||
277 | /* cache the first kmap pte */ | ||
278 | kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); | ||
279 | kmap_pte = kmap_get_fixmap_pte(kmap_vstart); | ||
280 | |||
281 | kmap_prot = PAGE_KERNEL; | ||
282 | } | ||
283 | #endif /* CONFIG_HIGHMEM */ | ||
284 | |||
285 | void __init fixrange_init(unsigned long start, unsigned long end, | 259 | void __init fixrange_init(unsigned long start, unsigned long end, |
286 | pgd_t *pgd_base) | 260 | pgd_t *pgd_base) |
287 | { | 261 | { |