diff options
-rw-r--r-- | arch/powerpc/Kconfig | 14 | ||||
-rw-r--r-- | arch/powerpc/mm/init_32.c | 8 | ||||
-rw-r--r-- | arch/powerpc/mm/mem.c | 32 | ||||
-rw-r--r-- | arch/powerpc/mm/pgtable_32.c | 23 | ||||
-rw-r--r-- | include/asm-powerpc/fixmap.h | 106 | ||||
-rw-r--r-- | include/asm-powerpc/highmem.h | 41 |
6 files changed, 177 insertions, 47 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index fdc755a05f70..20f45a8b87e3 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -626,20 +626,6 @@ config ADVANCED_OPTIONS | |||
626 | comment "Default settings for advanced configuration options are used" | 626 | comment "Default settings for advanced configuration options are used" |
627 | depends on !ADVANCED_OPTIONS | 627 | depends on !ADVANCED_OPTIONS |
628 | 628 | ||
629 | config HIGHMEM_START_BOOL | ||
630 | bool "Set high memory pool address" | ||
631 | depends on ADVANCED_OPTIONS && HIGHMEM | ||
632 | help | ||
633 | This option allows you to set the base address of the kernel virtual | ||
634 | area used to map high memory pages. This can be useful in | ||
635 | optimizing the layout of kernel virtual memory. | ||
636 | |||
637 | Say N here unless you know what you are doing. | ||
638 | |||
639 | config HIGHMEM_START | ||
640 | hex "Virtual start address of high memory pool" if HIGHMEM_START_BOOL | ||
641 | default "0xfe000000" | ||
642 | |||
643 | config LOWMEM_SIZE_BOOL | 629 | config LOWMEM_SIZE_BOOL |
644 | bool "Set maximum low memory" | 630 | bool "Set maximum low memory" |
645 | depends on ADVANCED_OPTIONS | 631 | depends on ADVANCED_OPTIONS |
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 578750e4ca88..1952b4d3fa7f 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c | |||
@@ -71,14 +71,6 @@ unsigned long agp_special_page; | |||
71 | EXPORT_SYMBOL(agp_special_page); | 71 | EXPORT_SYMBOL(agp_special_page); |
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | #ifdef CONFIG_HIGHMEM | ||
75 | pte_t *kmap_pte; | ||
76 | pgprot_t kmap_prot; | ||
77 | |||
78 | EXPORT_SYMBOL(kmap_prot); | ||
79 | EXPORT_SYMBOL(kmap_pte); | ||
80 | #endif | ||
81 | |||
82 | void MMU_init(void); | 74 | void MMU_init(void); |
83 | 75 | ||
84 | /* XXX should be in current.h -- paulus */ | 76 | /* XXX should be in current.h -- paulus */ |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 0062e6b1c555..5ccb579b81e4 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/tlb.h> | 45 | #include <asm/tlb.h> |
46 | #include <asm/sections.h> | 46 | #include <asm/sections.h> |
47 | #include <asm/vdso.h> | 47 | #include <asm/vdso.h> |
48 | #include <asm/fixmap.h> | ||
48 | 49 | ||
49 | #include "mmu_decl.h" | 50 | #include "mmu_decl.h" |
50 | 51 | ||
@@ -57,6 +58,20 @@ int init_bootmem_done; | |||
57 | int mem_init_done; | 58 | int mem_init_done; |
58 | unsigned long memory_limit; | 59 | unsigned long memory_limit; |
59 | 60 | ||
61 | #ifdef CONFIG_HIGHMEM | ||
62 | pte_t *kmap_pte; | ||
63 | pgprot_t kmap_prot; | ||
64 | |||
65 | EXPORT_SYMBOL(kmap_prot); | ||
66 | EXPORT_SYMBOL(kmap_pte); | ||
67 | |||
68 | static inline pte_t *virt_to_kpte(unsigned long vaddr) | ||
69 | { | ||
70 | return pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), | ||
71 | vaddr), vaddr), vaddr); | ||
72 | } | ||
73 | #endif | ||
74 | |||
60 | int page_is_ram(unsigned long pfn) | 75 | int page_is_ram(unsigned long pfn) |
61 | { | 76 | { |
62 | unsigned long paddr = (pfn << PAGE_SHIFT); | 77 | unsigned long paddr = (pfn << PAGE_SHIFT); |
@@ -311,14 +326,19 @@ void __init paging_init(void) | |||
311 | unsigned long top_of_ram = lmb_end_of_DRAM(); | 326 | unsigned long top_of_ram = lmb_end_of_DRAM(); |
312 | unsigned long max_zone_pfns[MAX_NR_ZONES]; | 327 | unsigned long max_zone_pfns[MAX_NR_ZONES]; |
313 | 328 | ||
329 | #ifdef CONFIG_PPC32 | ||
330 | unsigned long v = __fix_to_virt(__end_of_fixed_addresses - 1); | ||
331 | unsigned long end = __fix_to_virt(FIX_HOLE); | ||
332 | |||
333 | for (; v < end; v += PAGE_SIZE) | ||
334 | map_page(v, 0, 0); /* XXX gross */ | ||
335 | #endif | ||
336 | |||
314 | #ifdef CONFIG_HIGHMEM | 337 | #ifdef CONFIG_HIGHMEM |
315 | map_page(PKMAP_BASE, 0, 0); /* XXX gross */ | 338 | map_page(PKMAP_BASE, 0, 0); /* XXX gross */ |
316 | pkmap_page_table = pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k | 339 | pkmap_page_table = virt_to_kpte(PKMAP_BASE); |
317 | (PKMAP_BASE), PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); | 340 | |
318 | map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ | 341 | kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN)); |
319 | kmap_pte = pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k | ||
320 | (KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), | ||
321 | KMAP_FIX_BEGIN); | ||
322 | kmap_prot = PAGE_KERNEL; | 342 | kmap_prot = PAGE_KERNEL; |
323 | #endif /* CONFIG_HIGHMEM */ | 343 | #endif /* CONFIG_HIGHMEM */ |
324 | 344 | ||
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 64c44bcc68de..80d1babb230d 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #include <asm/pgtable.h> | 30 | #include <asm/pgtable.h> |
31 | #include <asm/pgalloc.h> | 31 | #include <asm/pgalloc.h> |
32 | #include <asm/fixmap.h> | ||
32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
33 | 34 | ||
34 | #include "mmu_decl.h" | 35 | #include "mmu_decl.h" |
@@ -387,3 +388,25 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
387 | change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0)); | 388 | change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0)); |
388 | } | 389 | } |
389 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | 390 | #endif /* CONFIG_DEBUG_PAGEALLOC */ |
391 | |||
392 | static int fixmaps; | ||
393 | unsigned long FIXADDR_TOP = 0xfffff000; | ||
394 | EXPORT_SYMBOL(FIXADDR_TOP); | ||
395 | |||
396 | void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags) | ||
397 | { | ||
398 | unsigned long address = __fix_to_virt(idx); | ||
399 | |||
400 | if (idx >= __end_of_fixed_addresses) { | ||
401 | BUG(); | ||
402 | return; | ||
403 | } | ||
404 | |||
405 | map_page(address, phys, flags); | ||
406 | fixmaps++; | ||
407 | } | ||
408 | |||
409 | void __this_fixmap_does_not_exist(void) | ||
410 | { | ||
411 | WARN_ON(1); | ||
412 | } | ||
diff --git a/include/asm-powerpc/fixmap.h b/include/asm-powerpc/fixmap.h new file mode 100644 index 000000000000..8428b38a3d30 --- /dev/null +++ b/include/asm-powerpc/fixmap.h | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * fixmap.h: compile-time virtual memory allocation | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 1998 Ingo Molnar | ||
9 | * | ||
10 | * Copyright 2008 Freescale Semiconductor Inc. | ||
11 | * Port to powerpc added by Kumar Gala | ||
12 | */ | ||
13 | |||
14 | #ifndef _ASM_FIXMAP_H | ||
15 | #define _ASM_FIXMAP_H | ||
16 | |||
17 | extern unsigned long FIXADDR_TOP; | ||
18 | |||
19 | #ifndef __ASSEMBLY__ | ||
20 | #include <linux/kernel.h> | ||
21 | #include <asm/page.h> | ||
22 | #ifdef CONFIG_HIGHMEM | ||
23 | #include <linux/threads.h> | ||
24 | #include <asm/kmap_types.h> | ||
25 | #endif | ||
26 | |||
27 | /* | ||
28 | * Here we define all the compile-time 'special' virtual | ||
29 | * addresses. The point is to have a constant address at | ||
30 | * compile time, but to set the physical address only | ||
31 | * in the boot process. We allocate these special addresses | ||
32 | * from the end of virtual memory (0xfffff000) backwards. | ||
33 | * Also this lets us do fail-safe vmalloc(), we | ||
34 | * can guarantee that these special addresses and | ||
35 | * vmalloc()-ed addresses never overlap. | ||
36 | * | ||
37 | * these 'compile-time allocated' memory buffers are | ||
38 | * fixed-size 4k pages. (or larger if used with an increment | ||
39 | * highger than 1) use fixmap_set(idx,phys) to associate | ||
40 | * physical memory with fixmap indices. | ||
41 | * | ||
42 | * TLB entries of such buffers will not be flushed across | ||
43 | * task switches. | ||
44 | */ | ||
45 | enum fixed_addresses { | ||
46 | FIX_HOLE, | ||
47 | #ifdef CONFIG_HIGHMEM | ||
48 | FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ | ||
49 | FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, | ||
50 | #endif | ||
51 | /* FIX_PCIE_MCFG, */ | ||
52 | __end_of_fixed_addresses | ||
53 | }; | ||
54 | |||
55 | extern void __set_fixmap (enum fixed_addresses idx, | ||
56 | phys_addr_t phys, pgprot_t flags); | ||
57 | |||
58 | #define set_fixmap(idx, phys) \ | ||
59 | __set_fixmap(idx, phys, PAGE_KERNEL) | ||
60 | /* | ||
61 | * Some hardware wants to get fixmapped without caching. | ||
62 | */ | ||
63 | #define set_fixmap_nocache(idx, phys) \ | ||
64 | __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) | ||
65 | |||
66 | #define clear_fixmap(idx) \ | ||
67 | __set_fixmap(idx, 0, __pgprot(0)) | ||
68 | |||
69 | #define __FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) | ||
70 | #define FIXADDR_START (FIXADDR_TOP - __FIXADDR_SIZE) | ||
71 | |||
72 | #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) | ||
73 | #define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) | ||
74 | |||
75 | extern void __this_fixmap_does_not_exist(void); | ||
76 | |||
77 | /* | ||
78 | * 'index to address' translation. If anyone tries to use the idx | ||
79 | * directly without tranlation, we catch the bug with a NULL-deference | ||
80 | * kernel oops. Illegal ranges of incoming indices are caught too. | ||
81 | */ | ||
82 | static __always_inline unsigned long fix_to_virt(const unsigned int idx) | ||
83 | { | ||
84 | /* | ||
85 | * this branch gets completely eliminated after inlining, | ||
86 | * except when someone tries to use fixaddr indices in an | ||
87 | * illegal way. (such as mixing up address types or using | ||
88 | * out-of-range indices). | ||
89 | * | ||
90 | * If it doesn't get removed, the linker will complain | ||
91 | * loudly with a reasonably clear error message.. | ||
92 | */ | ||
93 | if (idx >= __end_of_fixed_addresses) | ||
94 | __this_fixmap_does_not_exist(); | ||
95 | |||
96 | return __fix_to_virt(idx); | ||
97 | } | ||
98 | |||
99 | static inline unsigned long virt_to_fix(const unsigned long vaddr) | ||
100 | { | ||
101 | BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); | ||
102 | return __virt_to_fix(vaddr); | ||
103 | } | ||
104 | |||
105 | #endif /* !__ASSEMBLY__ */ | ||
106 | #endif | ||
diff --git a/include/asm-powerpc/highmem.h b/include/asm-powerpc/highmem.h index f7b21ee302b4..5d99b6489d56 100644 --- a/include/asm-powerpc/highmem.h +++ b/include/asm-powerpc/highmem.h | |||
@@ -27,9 +27,7 @@ | |||
27 | #include <asm/kmap_types.h> | 27 | #include <asm/kmap_types.h> |
28 | #include <asm/tlbflush.h> | 28 | #include <asm/tlbflush.h> |
29 | #include <asm/page.h> | 29 | #include <asm/page.h> |
30 | 30 | #include <asm/fixmap.h> | |
31 | /* undef for production */ | ||
32 | #define HIGHMEM_DEBUG 1 | ||
33 | 31 | ||
34 | extern pte_t *kmap_pte; | 32 | extern pte_t *kmap_pte; |
35 | extern pgprot_t kmap_prot; | 33 | extern pgprot_t kmap_prot; |
@@ -40,14 +38,12 @@ extern pte_t *pkmap_page_table; | |||
40 | * easily, subsequent pte tables have to be allocated in one physical | 38 | * easily, subsequent pte tables have to be allocated in one physical |
41 | * chunk of RAM. | 39 | * chunk of RAM. |
42 | */ | 40 | */ |
43 | #define PKMAP_BASE CONFIG_HIGHMEM_START | ||
44 | #define LAST_PKMAP (1 << PTE_SHIFT) | 41 | #define LAST_PKMAP (1 << PTE_SHIFT) |
45 | #define LAST_PKMAP_MASK (LAST_PKMAP-1) | 42 | #define LAST_PKMAP_MASK (LAST_PKMAP-1) |
43 | #define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE*(LAST_PKMAP + 1)) & PMD_MASK) | ||
46 | #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) | 44 | #define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) |
47 | #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) | 45 | #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) |
48 | 46 | ||
49 | #define KMAP_FIX_BEGIN (PKMAP_BASE + 0x00400000UL) | ||
50 | |||
51 | extern void *kmap_high(struct page *page); | 47 | extern void *kmap_high(struct page *page); |
52 | extern void kunmap_high(struct page *page); | 48 | extern void kunmap_high(struct page *page); |
53 | 49 | ||
@@ -73,7 +69,7 @@ static inline void kunmap(struct page *page) | |||
73 | * be used in IRQ contexts, so in some (very limited) cases we need | 69 | * be used in IRQ contexts, so in some (very limited) cases we need |
74 | * it. | 70 | * it. |
75 | */ | 71 | */ |
76 | static inline void *kmap_atomic(struct page *page, enum km_type type) | 72 | static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot) |
77 | { | 73 | { |
78 | unsigned int idx; | 74 | unsigned int idx; |
79 | unsigned long vaddr; | 75 | unsigned long vaddr; |
@@ -84,34 +80,39 @@ static inline void *kmap_atomic(struct page *page, enum km_type type) | |||
84 | return page_address(page); | 80 | return page_address(page); |
85 | 81 | ||
86 | idx = type + KM_TYPE_NR*smp_processor_id(); | 82 | idx = type + KM_TYPE_NR*smp_processor_id(); |
87 | vaddr = KMAP_FIX_BEGIN + idx * PAGE_SIZE; | 83 | vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); |
88 | #ifdef HIGHMEM_DEBUG | 84 | #ifdef CONFIG_DEBUG_HIGHMEM |
89 | BUG_ON(!pte_none(*(kmap_pte+idx))); | 85 | BUG_ON(!pte_none(*(kmap_pte-idx))); |
90 | #endif | 86 | #endif |
91 | set_pte_at(&init_mm, vaddr, kmap_pte+idx, mk_pte(page, kmap_prot)); | 87 | set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot)); |
92 | flush_tlb_page(NULL, vaddr); | 88 | flush_tlb_page(NULL, vaddr); |
93 | 89 | ||
94 | return (void*) vaddr; | 90 | return (void*) vaddr; |
95 | } | 91 | } |
96 | 92 | ||
93 | static inline void *kmap_atomic(struct page *page, enum km_type type) | ||
94 | { | ||
95 | return kmap_atomic_prot(page, type, kmap_prot); | ||
96 | } | ||
97 | |||
97 | static inline void kunmap_atomic(void *kvaddr, enum km_type type) | 98 | static inline void kunmap_atomic(void *kvaddr, enum km_type type) |
98 | { | 99 | { |
99 | #ifdef HIGHMEM_DEBUG | 100 | #ifdef CONFIG_DEBUG_HIGHMEM |
100 | unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; | 101 | unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; |
101 | unsigned int idx = type + KM_TYPE_NR*smp_processor_id(); | 102 | enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); |
102 | 103 | ||
103 | if (vaddr < KMAP_FIX_BEGIN) { // FIXME | 104 | if (vaddr < __fix_to_virt(FIX_KMAP_END)) { |
104 | pagefault_enable(); | 105 | pagefault_enable(); |
105 | return; | 106 | return; |
106 | } | 107 | } |
107 | 108 | ||
108 | BUG_ON(vaddr != KMAP_FIX_BEGIN + idx * PAGE_SIZE); | 109 | BUG_ON(vaddr != __fix_to_virt(FIX_KMAP_BEGIN + idx)); |
109 | 110 | ||
110 | /* | 111 | /* |
111 | * force other mappings to Oops if they'll try to access | 112 | * force other mappings to Oops if they'll try to access |
112 | * this pte without first remap it | 113 | * this pte without first remap it |
113 | */ | 114 | */ |
114 | pte_clear(&init_mm, vaddr, kmap_pte+idx); | 115 | pte_clear(&init_mm, vaddr, kmap_pte-idx); |
115 | flush_tlb_page(NULL, vaddr); | 116 | flush_tlb_page(NULL, vaddr); |
116 | #endif | 117 | #endif |
117 | pagefault_enable(); | 118 | pagefault_enable(); |
@@ -120,12 +121,14 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type) | |||
120 | static inline struct page *kmap_atomic_to_page(void *ptr) | 121 | static inline struct page *kmap_atomic_to_page(void *ptr) |
121 | { | 122 | { |
122 | unsigned long idx, vaddr = (unsigned long) ptr; | 123 | unsigned long idx, vaddr = (unsigned long) ptr; |
124 | pte_t *pte; | ||
123 | 125 | ||
124 | if (vaddr < KMAP_FIX_BEGIN) | 126 | if (vaddr < FIXADDR_START) |
125 | return virt_to_page(ptr); | 127 | return virt_to_page(ptr); |
126 | 128 | ||
127 | idx = (vaddr - KMAP_FIX_BEGIN) >> PAGE_SHIFT; | 129 | idx = virt_to_fix(vaddr); |
128 | return pte_page(kmap_pte[idx]); | 130 | pte = kmap_pte - (idx - FIX_KMAP_BEGIN); |
131 | return pte_page(*pte); | ||
129 | } | 132 | } |
130 | 133 | ||
131 | #define flush_cache_kmaps() flush_cache_all() | 134 | #define flush_cache_kmaps() flush_cache_all() |