diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /arch/sh/mm | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'arch/sh/mm')
-rw-r--r-- | arch/sh/mm/Kconfig | 4 | ||||
-rw-r--r-- | arch/sh/mm/Makefile | 8 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh2a.c | 125 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 5 | ||||
-rw-r--r-- | arch/sh/mm/cache.c | 12 | ||||
-rw-r--r-- | arch/sh/mm/consistent.c | 6 | ||||
-rw-r--r-- | arch/sh/mm/fault.c | 514 | ||||
-rw-r--r-- | arch/sh/mm/flush-sh4.c | 2 | ||||
-rw-r--r-- | arch/sh/mm/init.c | 12 | ||||
-rw-r--r-- | arch/sh/mm/mmap.c | 139 | ||||
-rw-r--r-- | arch/sh/mm/pmb.c | 1 | ||||
-rw-r--r-- | arch/sh/mm/sram.c | 1 | ||||
-rw-r--r-- | arch/sh/mm/tlb-pteaex.c | 1 | ||||
-rw-r--r-- | arch/sh/mm/tlb-sh3.c | 1 | ||||
-rw-r--r-- | arch/sh/mm/tlb-sh4.c | 1 | ||||
-rw-r--r-- | arch/sh/mm/tlb-sh5.c | 42 | ||||
-rw-r--r-- | arch/sh/mm/tlbex_32.c | 78 | ||||
-rw-r--r-- | arch/sh/mm/tlbex_64.c | 166 | ||||
-rw-r--r-- | arch/sh/mm/tlbflush_64.c | 295 |
19 files changed, 476 insertions, 937 deletions
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 0f7c852f355..c3e61b36649 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig | |||
@@ -111,7 +111,6 @@ config VSYSCALL | |||
111 | config NUMA | 111 | config NUMA |
112 | bool "Non Uniform Memory Access (NUMA) Support" | 112 | bool "Non Uniform Memory Access (NUMA) Support" |
113 | depends on MMU && SYS_SUPPORTS_NUMA && EXPERIMENTAL | 113 | depends on MMU && SYS_SUPPORTS_NUMA && EXPERIMENTAL |
114 | select ARCH_WANT_NUMA_VARIABLE_LOCALITY | ||
115 | default n | 114 | default n |
116 | help | 115 | help |
117 | Some SH systems have many various memories scattered around | 116 | Some SH systems have many various memories scattered around |
@@ -144,6 +143,9 @@ config MAX_ACTIVE_REGIONS | |||
144 | CPU_SUBTYPE_SH7785) | 143 | CPU_SUBTYPE_SH7785) |
145 | default "1" | 144 | default "1" |
146 | 145 | ||
146 | config ARCH_POPULATES_NODE_MAP | ||
147 | def_bool y | ||
148 | |||
147 | config ARCH_SELECT_MEMORY_MODEL | 149 | config ARCH_SELECT_MEMORY_MODEL |
148 | def_bool y | 150 | def_bool y |
149 | 151 | ||
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index cee6b9999d8..2228c8cee4d 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile | |||
@@ -15,8 +15,8 @@ cacheops-$(CONFIG_CPU_SHX3) += cache-shx3.o | |||
15 | obj-y += $(cacheops-y) | 15 | obj-y += $(cacheops-y) |
16 | 16 | ||
17 | mmu-y := nommu.o extable_32.o | 17 | mmu-y := nommu.o extable_32.o |
18 | mmu-$(CONFIG_MMU) := extable_$(BITS).o fault.o gup.o ioremap.o kmap.o \ | 18 | mmu-$(CONFIG_MMU) := extable_$(BITS).o fault_$(BITS).o gup.o \ |
19 | pgtable.o tlbex_$(BITS).o tlbflush_$(BITS).o | 19 | ioremap.o kmap.o pgtable.o tlbflush_$(BITS).o |
20 | 20 | ||
21 | obj-y += $(mmu-y) | 21 | obj-y += $(mmu-y) |
22 | 22 | ||
@@ -44,7 +44,7 @@ obj-$(CONFIG_HAVE_SRAM_POOL) += sram.o | |||
44 | 44 | ||
45 | GCOV_PROFILE_pmb.o := n | 45 | GCOV_PROFILE_pmb.o := n |
46 | 46 | ||
47 | # Special flags for tlbex_64.o. This puts restrictions on the number of | 47 | # Special flags for fault_64.o. This puts restrictions on the number of |
48 | # caller-save registers that the compiler can target when building this file. | 48 | # caller-save registers that the compiler can target when building this file. |
49 | # This is required because the code is called from a context in entry.S where | 49 | # This is required because the code is called from a context in entry.S where |
50 | # very few registers have been saved in the exception handler (for speed | 50 | # very few registers have been saved in the exception handler (for speed |
@@ -59,7 +59,7 @@ GCOV_PROFILE_pmb.o := n | |||
59 | # The resources not listed below are callee save, i.e. the compiler is free to | 59 | # The resources not listed below are callee save, i.e. the compiler is free to |
60 | # use any of them and will spill them to the stack itself. | 60 | # use any of them and will spill them to the stack itself. |
61 | 61 | ||
62 | CFLAGS_tlbex_64.o += -ffixed-r7 \ | 62 | CFLAGS_fault_64.o += -ffixed-r7 \ |
63 | -ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \ | 63 | -ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \ |
64 | -ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \ | 64 | -ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \ |
65 | -ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \ | 65 | -ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \ |
diff --git a/arch/sh/mm/cache-sh2a.c b/arch/sh/mm/cache-sh2a.c index 949e2d3138a..1f51225426a 100644 --- a/arch/sh/mm/cache-sh2a.c +++ b/arch/sh/mm/cache-sh2a.c | |||
@@ -15,80 +15,35 @@ | |||
15 | #include <asm/cacheflush.h> | 15 | #include <asm/cacheflush.h> |
16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
17 | 17 | ||
18 | /* | ||
19 | * The maximum number of pages we support up to when doing ranged dcache | ||
20 | * flushing. Anything exceeding this will simply flush the dcache in its | ||
21 | * entirety. | ||
22 | */ | ||
23 | #define MAX_OCACHE_PAGES 32 | ||
24 | #define MAX_ICACHE_PAGES 32 | ||
25 | |||
26 | #ifdef CONFIG_CACHE_WRITEBACK | ||
27 | static void sh2a_flush_oc_line(unsigned long v, int way) | ||
28 | { | ||
29 | unsigned long addr = (v & 0x000007f0) | (way << 11); | ||
30 | unsigned long data; | ||
31 | |||
32 | data = __raw_readl(CACHE_OC_ADDRESS_ARRAY | addr); | ||
33 | if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { | ||
34 | data &= ~SH_CACHE_UPDATED; | ||
35 | __raw_writel(data, CACHE_OC_ADDRESS_ARRAY | addr); | ||
36 | } | ||
37 | } | ||
38 | #endif | ||
39 | |||
40 | static void sh2a_invalidate_line(unsigned long cache_addr, unsigned long v) | ||
41 | { | ||
42 | /* Set associative bit to hit all ways */ | ||
43 | unsigned long addr = (v & 0x000007f0) | SH_CACHE_ASSOC; | ||
44 | __raw_writel((addr & CACHE_PHYSADDR_MASK), cache_addr | addr); | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * Write back the dirty D-caches, but not invalidate them. | ||
49 | */ | ||
50 | static void sh2a__flush_wback_region(void *start, int size) | 18 | static void sh2a__flush_wback_region(void *start, int size) |
51 | { | 19 | { |
52 | #ifdef CONFIG_CACHE_WRITEBACK | ||
53 | unsigned long v; | 20 | unsigned long v; |
54 | unsigned long begin, end; | 21 | unsigned long begin, end; |
55 | unsigned long flags; | 22 | unsigned long flags; |
56 | int nr_ways; | ||
57 | 23 | ||
58 | begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); | 24 | begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); |
59 | end = ((unsigned long)start + size + L1_CACHE_BYTES-1) | 25 | end = ((unsigned long)start + size + L1_CACHE_BYTES-1) |
60 | & ~(L1_CACHE_BYTES-1); | 26 | & ~(L1_CACHE_BYTES-1); |
61 | nr_ways = current_cpu_data.dcache.ways; | ||
62 | 27 | ||
63 | local_irq_save(flags); | 28 | local_irq_save(flags); |
64 | jump_to_uncached(); | 29 | jump_to_uncached(); |
65 | 30 | ||
66 | /* If there are too many pages then flush the entire cache */ | 31 | for (v = begin; v < end; v+=L1_CACHE_BYTES) { |
67 | if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) { | 32 | unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0); |
68 | begin = CACHE_OC_ADDRESS_ARRAY; | ||
69 | end = begin + (nr_ways * current_cpu_data.dcache.way_size); | ||
70 | |||
71 | for (v = begin; v < end; v += L1_CACHE_BYTES) { | ||
72 | unsigned long data = __raw_readl(v); | ||
73 | if (data & SH_CACHE_UPDATED) | ||
74 | __raw_writel(data & ~SH_CACHE_UPDATED, v); | ||
75 | } | ||
76 | } else { | ||
77 | int way; | 33 | int way; |
78 | for (way = 0; way < nr_ways; way++) { | 34 | for (way = 0; way < 4; way++) { |
79 | for (v = begin; v < end; v += L1_CACHE_BYTES) | 35 | unsigned long data = __raw_readl(addr | (way << 11)); |
80 | sh2a_flush_oc_line(v, way); | 36 | if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { |
37 | data &= ~SH_CACHE_UPDATED; | ||
38 | __raw_writel(data, addr | (way << 11)); | ||
39 | } | ||
81 | } | 40 | } |
82 | } | 41 | } |
83 | 42 | ||
84 | back_to_cached(); | 43 | back_to_cached(); |
85 | local_irq_restore(flags); | 44 | local_irq_restore(flags); |
86 | #endif | ||
87 | } | 45 | } |
88 | 46 | ||
89 | /* | ||
90 | * Write back the dirty D-caches and invalidate them. | ||
91 | */ | ||
92 | static void sh2a__flush_purge_region(void *start, int size) | 47 | static void sh2a__flush_purge_region(void *start, int size) |
93 | { | 48 | { |
94 | unsigned long v; | 49 | unsigned long v; |
@@ -103,22 +58,13 @@ static void sh2a__flush_purge_region(void *start, int size) | |||
103 | jump_to_uncached(); | 58 | jump_to_uncached(); |
104 | 59 | ||
105 | for (v = begin; v < end; v+=L1_CACHE_BYTES) { | 60 | for (v = begin; v < end; v+=L1_CACHE_BYTES) { |
106 | #ifdef CONFIG_CACHE_WRITEBACK | 61 | __raw_writel((v & CACHE_PHYSADDR_MASK), |
107 | int way; | 62 | CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008); |
108 | int nr_ways = current_cpu_data.dcache.ways; | ||
109 | for (way = 0; way < nr_ways; way++) | ||
110 | sh2a_flush_oc_line(v, way); | ||
111 | #endif | ||
112 | sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v); | ||
113 | } | 63 | } |
114 | |||
115 | back_to_cached(); | 64 | back_to_cached(); |
116 | local_irq_restore(flags); | 65 | local_irq_restore(flags); |
117 | } | 66 | } |
118 | 67 | ||
119 | /* | ||
120 | * Invalidate the D-caches, but no write back please | ||
121 | */ | ||
122 | static void sh2a__flush_invalidate_region(void *start, int size) | 68 | static void sh2a__flush_invalidate_region(void *start, int size) |
123 | { | 69 | { |
124 | unsigned long v; | 70 | unsigned long v; |
@@ -128,25 +74,29 @@ static void sh2a__flush_invalidate_region(void *start, int size) | |||
128 | begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); | 74 | begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); |
129 | end = ((unsigned long)start + size + L1_CACHE_BYTES-1) | 75 | end = ((unsigned long)start + size + L1_CACHE_BYTES-1) |
130 | & ~(L1_CACHE_BYTES-1); | 76 | & ~(L1_CACHE_BYTES-1); |
131 | |||
132 | local_irq_save(flags); | 77 | local_irq_save(flags); |
133 | jump_to_uncached(); | 78 | jump_to_uncached(); |
134 | 79 | ||
135 | /* If there are too many pages then just blow the cache */ | 80 | #ifdef CONFIG_CACHE_WRITEBACK |
136 | if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) { | 81 | __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR); |
137 | __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR); | 82 | /* I-cache invalidate */ |
138 | } else { | 83 | for (v = begin; v < end; v+=L1_CACHE_BYTES) { |
139 | for (v = begin; v < end; v += L1_CACHE_BYTES) | 84 | __raw_writel((v & CACHE_PHYSADDR_MASK), |
140 | sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v); | 85 | CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008); |
141 | } | 86 | } |
142 | 87 | #else | |
88 | for (v = begin; v < end; v+=L1_CACHE_BYTES) { | ||
89 | __raw_writel((v & CACHE_PHYSADDR_MASK), | ||
90 | CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008); | ||
91 | __raw_writel((v & CACHE_PHYSADDR_MASK), | ||
92 | CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008); | ||
93 | } | ||
94 | #endif | ||
143 | back_to_cached(); | 95 | back_to_cached(); |
144 | local_irq_restore(flags); | 96 | local_irq_restore(flags); |
145 | } | 97 | } |
146 | 98 | ||
147 | /* | 99 | /* WBack O-Cache and flush I-Cache */ |
148 | * Write back the range of D-cache, and purge the I-cache. | ||
149 | */ | ||
150 | static void sh2a_flush_icache_range(void *args) | 100 | static void sh2a_flush_icache_range(void *args) |
151 | { | 101 | { |
152 | struct flusher_data *data = args; | 102 | struct flusher_data *data = args; |
@@ -157,20 +107,23 @@ static void sh2a_flush_icache_range(void *args) | |||
157 | start = data->addr1 & ~(L1_CACHE_BYTES-1); | 107 | start = data->addr1 & ~(L1_CACHE_BYTES-1); |
158 | end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); | 108 | end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); |
159 | 109 | ||
160 | #ifdef CONFIG_CACHE_WRITEBACK | ||
161 | sh2a__flush_wback_region((void *)start, end-start); | ||
162 | #endif | ||
163 | |||
164 | local_irq_save(flags); | 110 | local_irq_save(flags); |
165 | jump_to_uncached(); | 111 | jump_to_uncached(); |
166 | 112 | ||
167 | /* I-Cache invalidate */ | 113 | for (v = start; v < end; v+=L1_CACHE_BYTES) { |
168 | /* If there are too many pages then just blow the cache */ | 114 | unsigned long addr = (v & 0x000007f0); |
169 | if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { | 115 | int way; |
170 | __raw_writel(__raw_readl(CCR) | CCR_ICACHE_INVALIDATE, CCR); | 116 | /* O-Cache writeback */ |
171 | } else { | 117 | for (way = 0; way < 4; way++) { |
172 | for (v = start; v < end; v += L1_CACHE_BYTES) | 118 | unsigned long data = __raw_readl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); |
173 | sh2a_invalidate_line(CACHE_IC_ADDRESS_ARRAY, v); | 119 | if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { |
120 | data &= ~SH_CACHE_UPDATED; | ||
121 | __raw_writel(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11)); | ||
122 | } | ||
123 | } | ||
124 | /* I-Cache invalidate */ | ||
125 | __raw_writel(addr, | ||
126 | CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008); | ||
174 | } | 127 | } |
175 | 128 | ||
176 | back_to_cached(); | 129 | back_to_cached(); |
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 0e529285b28..92eb98633ab 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/highmem.h> | 18 | #include <linux/highmem.h> |
19 | #include <asm/pgtable.h> | 19 | #include <asm/pgtable.h> |
20 | #include <asm/mmu_context.h> | 20 | #include <asm/mmu_context.h> |
21 | #include <asm/cache_insns.h> | ||
22 | #include <asm/cacheflush.h> | 21 | #include <asm/cacheflush.h> |
23 | 22 | ||
24 | /* | 23 | /* |
@@ -245,7 +244,7 @@ static void sh4_flush_cache_page(void *args) | |||
245 | if (map_coherent) | 244 | if (map_coherent) |
246 | vaddr = kmap_coherent(page, address); | 245 | vaddr = kmap_coherent(page, address); |
247 | else | 246 | else |
248 | vaddr = kmap_atomic(page); | 247 | vaddr = kmap_atomic(page, KM_USER0); |
249 | 248 | ||
250 | address = (unsigned long)vaddr; | 249 | address = (unsigned long)vaddr; |
251 | } | 250 | } |
@@ -260,7 +259,7 @@ static void sh4_flush_cache_page(void *args) | |||
260 | if (map_coherent) | 259 | if (map_coherent) |
261 | kunmap_coherent(vaddr); | 260 | kunmap_coherent(vaddr); |
262 | else | 261 | else |
263 | kunmap_atomic(vaddr); | 262 | kunmap_atomic(vaddr, KM_USER0); |
264 | } | 263 | } |
265 | } | 264 | } |
266 | 265 | ||
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index 616966a96cb..5a580ea0442 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c | |||
@@ -95,7 +95,7 @@ void copy_user_highpage(struct page *to, struct page *from, | |||
95 | { | 95 | { |
96 | void *vfrom, *vto; | 96 | void *vfrom, *vto; |
97 | 97 | ||
98 | vto = kmap_atomic(to); | 98 | vto = kmap_atomic(to, KM_USER1); |
99 | 99 | ||
100 | if (boot_cpu_data.dcache.n_aliases && page_mapped(from) && | 100 | if (boot_cpu_data.dcache.n_aliases && page_mapped(from) && |
101 | test_bit(PG_dcache_clean, &from->flags)) { | 101 | test_bit(PG_dcache_clean, &from->flags)) { |
@@ -103,16 +103,16 @@ void copy_user_highpage(struct page *to, struct page *from, | |||
103 | copy_page(vto, vfrom); | 103 | copy_page(vto, vfrom); |
104 | kunmap_coherent(vfrom); | 104 | kunmap_coherent(vfrom); |
105 | } else { | 105 | } else { |
106 | vfrom = kmap_atomic(from); | 106 | vfrom = kmap_atomic(from, KM_USER0); |
107 | copy_page(vto, vfrom); | 107 | copy_page(vto, vfrom); |
108 | kunmap_atomic(vfrom); | 108 | kunmap_atomic(vfrom, KM_USER0); |
109 | } | 109 | } |
110 | 110 | ||
111 | if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK) || | 111 | if (pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK) || |
112 | (vma->vm_flags & VM_EXEC)) | 112 | (vma->vm_flags & VM_EXEC)) |
113 | __flush_purge_region(vto, PAGE_SIZE); | 113 | __flush_purge_region(vto, PAGE_SIZE); |
114 | 114 | ||
115 | kunmap_atomic(vto); | 115 | kunmap_atomic(vto, KM_USER1); |
116 | /* Make sure this page is cleared on other CPU's too before using it */ | 116 | /* Make sure this page is cleared on other CPU's too before using it */ |
117 | smp_wmb(); | 117 | smp_wmb(); |
118 | } | 118 | } |
@@ -120,14 +120,14 @@ EXPORT_SYMBOL(copy_user_highpage); | |||
120 | 120 | ||
121 | void clear_user_highpage(struct page *page, unsigned long vaddr) | 121 | void clear_user_highpage(struct page *page, unsigned long vaddr) |
122 | { | 122 | { |
123 | void *kaddr = kmap_atomic(page); | 123 | void *kaddr = kmap_atomic(page, KM_USER0); |
124 | 124 | ||
125 | clear_page(kaddr); | 125 | clear_page(kaddr); |
126 | 126 | ||
127 | if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) | 127 | if (pages_do_alias((unsigned long)kaddr, vaddr & PAGE_MASK)) |
128 | __flush_purge_region(kaddr, PAGE_SIZE); | 128 | __flush_purge_region(kaddr, PAGE_SIZE); |
129 | 129 | ||
130 | kunmap_atomic(kaddr); | 130 | kunmap_atomic(kaddr, KM_USER0); |
131 | } | 131 | } |
132 | EXPORT_SYMBOL(clear_user_highpage); | 132 | EXPORT_SYMBOL(clear_user_highpage); |
133 | 133 | ||
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index b81d9dbf9fe..f251b5f2765 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c | |||
@@ -33,8 +33,7 @@ static int __init dma_init(void) | |||
33 | fs_initcall(dma_init); | 33 | fs_initcall(dma_init); |
34 | 34 | ||
35 | void *dma_generic_alloc_coherent(struct device *dev, size_t size, | 35 | void *dma_generic_alloc_coherent(struct device *dev, size_t size, |
36 | dma_addr_t *dma_handle, gfp_t gfp, | 36 | dma_addr_t *dma_handle, gfp_t gfp) |
37 | struct dma_attrs *attrs) | ||
38 | { | 37 | { |
39 | void *ret, *ret_nocache; | 38 | void *ret, *ret_nocache; |
40 | int order = get_order(size); | 39 | int order = get_order(size); |
@@ -65,8 +64,7 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size, | |||
65 | } | 64 | } |
66 | 65 | ||
67 | void dma_generic_free_coherent(struct device *dev, size_t size, | 66 | void dma_generic_free_coherent(struct device *dev, size_t size, |
68 | void *vaddr, dma_addr_t dma_handle, | 67 | void *vaddr, dma_addr_t dma_handle) |
69 | struct dma_attrs *attrs) | ||
70 | { | 68 | { |
71 | int order = get_order(size); | 69 | int order = get_order(size); |
72 | unsigned long pfn = dma_handle >> PAGE_SHIFT; | 70 | unsigned long pfn = dma_handle >> PAGE_SHIFT; |
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c deleted file mode 100644 index 1f49c28affa..00000000000 --- a/arch/sh/mm/fault.c +++ /dev/null | |||
@@ -1,514 +0,0 @@ | |||
1 | /* | ||
2 | * Page fault handler for SH with an MMU. | ||
3 | * | ||
4 | * Copyright (C) 1999 Niibe Yutaka | ||
5 | * Copyright (C) 2003 - 2012 Paul Mundt | ||
6 | * | ||
7 | * Based on linux/arch/i386/mm/fault.c: | ||
8 | * Copyright (C) 1995 Linus Torvalds | ||
9 | * | ||
10 | * This file is subject to the terms and conditions of the GNU General Public | ||
11 | * License. See the file "COPYING" in the main directory of this archive | ||
12 | * for more details. | ||
13 | */ | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/hardirq.h> | ||
17 | #include <linux/kprobes.h> | ||
18 | #include <linux/perf_event.h> | ||
19 | #include <linux/kdebug.h> | ||
20 | #include <asm/io_trapped.h> | ||
21 | #include <asm/mmu_context.h> | ||
22 | #include <asm/tlbflush.h> | ||
23 | #include <asm/traps.h> | ||
24 | |||
25 | static inline int notify_page_fault(struct pt_regs *regs, int trap) | ||
26 | { | ||
27 | int ret = 0; | ||
28 | |||
29 | if (kprobes_built_in() && !user_mode(regs)) { | ||
30 | preempt_disable(); | ||
31 | if (kprobe_running() && kprobe_fault_handler(regs, trap)) | ||
32 | ret = 1; | ||
33 | preempt_enable(); | ||
34 | } | ||
35 | |||
36 | return ret; | ||
37 | } | ||
38 | |||
39 | static void | ||
40 | force_sig_info_fault(int si_signo, int si_code, unsigned long address, | ||
41 | struct task_struct *tsk) | ||
42 | { | ||
43 | siginfo_t info; | ||
44 | |||
45 | info.si_signo = si_signo; | ||
46 | info.si_errno = 0; | ||
47 | info.si_code = si_code; | ||
48 | info.si_addr = (void __user *)address; | ||
49 | |||
50 | force_sig_info(si_signo, &info, tsk); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * This is useful to dump out the page tables associated with | ||
55 | * 'addr' in mm 'mm'. | ||
56 | */ | ||
57 | static void show_pte(struct mm_struct *mm, unsigned long addr) | ||
58 | { | ||
59 | pgd_t *pgd; | ||
60 | |||
61 | if (mm) { | ||
62 | pgd = mm->pgd; | ||
63 | } else { | ||
64 | pgd = get_TTB(); | ||
65 | |||
66 | if (unlikely(!pgd)) | ||
67 | pgd = swapper_pg_dir; | ||
68 | } | ||
69 | |||
70 | printk(KERN_ALERT "pgd = %p\n", pgd); | ||
71 | pgd += pgd_index(addr); | ||
72 | printk(KERN_ALERT "[%08lx] *pgd=%0*Lx", addr, | ||
73 | (u32)(sizeof(*pgd) * 2), (u64)pgd_val(*pgd)); | ||
74 | |||
75 | do { | ||
76 | pud_t *pud; | ||
77 | pmd_t *pmd; | ||
78 | pte_t *pte; | ||
79 | |||
80 | if (pgd_none(*pgd)) | ||
81 | break; | ||
82 | |||
83 | if (pgd_bad(*pgd)) { | ||
84 | printk("(bad)"); | ||
85 | break; | ||
86 | } | ||
87 | |||
88 | pud = pud_offset(pgd, addr); | ||
89 | if (PTRS_PER_PUD != 1) | ||
90 | printk(", *pud=%0*Lx", (u32)(sizeof(*pud) * 2), | ||
91 | (u64)pud_val(*pud)); | ||
92 | |||
93 | if (pud_none(*pud)) | ||
94 | break; | ||
95 | |||
96 | if (pud_bad(*pud)) { | ||
97 | printk("(bad)"); | ||
98 | break; | ||
99 | } | ||
100 | |||
101 | pmd = pmd_offset(pud, addr); | ||
102 | if (PTRS_PER_PMD != 1) | ||
103 | printk(", *pmd=%0*Lx", (u32)(sizeof(*pmd) * 2), | ||
104 | (u64)pmd_val(*pmd)); | ||
105 | |||
106 | if (pmd_none(*pmd)) | ||
107 | break; | ||
108 | |||
109 | if (pmd_bad(*pmd)) { | ||
110 | printk("(bad)"); | ||
111 | break; | ||
112 | } | ||
113 | |||
114 | /* We must not map this if we have highmem enabled */ | ||
115 | if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT))) | ||
116 | break; | ||
117 | |||
118 | pte = pte_offset_kernel(pmd, addr); | ||
119 | printk(", *pte=%0*Lx", (u32)(sizeof(*pte) * 2), | ||
120 | (u64)pte_val(*pte)); | ||
121 | } while (0); | ||
122 | |||
123 | printk("\n"); | ||
124 | } | ||
125 | |||
126 | static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) | ||
127 | { | ||
128 | unsigned index = pgd_index(address); | ||
129 | pgd_t *pgd_k; | ||
130 | pud_t *pud, *pud_k; | ||
131 | pmd_t *pmd, *pmd_k; | ||
132 | |||
133 | pgd += index; | ||
134 | pgd_k = init_mm.pgd + index; | ||
135 | |||
136 | if (!pgd_present(*pgd_k)) | ||
137 | return NULL; | ||
138 | |||
139 | pud = pud_offset(pgd, address); | ||
140 | pud_k = pud_offset(pgd_k, address); | ||
141 | if (!pud_present(*pud_k)) | ||
142 | return NULL; | ||
143 | |||
144 | if (!pud_present(*pud)) | ||
145 | set_pud(pud, *pud_k); | ||
146 | |||
147 | pmd = pmd_offset(pud, address); | ||
148 | pmd_k = pmd_offset(pud_k, address); | ||
149 | if (!pmd_present(*pmd_k)) | ||
150 | return NULL; | ||
151 | |||
152 | if (!pmd_present(*pmd)) | ||
153 | set_pmd(pmd, *pmd_k); | ||
154 | else { | ||
155 | /* | ||
156 | * The page tables are fully synchronised so there must | ||
157 | * be another reason for the fault. Return NULL here to | ||
158 | * signal that we have not taken care of the fault. | ||
159 | */ | ||
160 | BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); | ||
161 | return NULL; | ||
162 | } | ||
163 | |||
164 | return pmd_k; | ||
165 | } | ||
166 | |||
167 | #ifdef CONFIG_SH_STORE_QUEUES | ||
168 | #define __FAULT_ADDR_LIMIT P3_ADDR_MAX | ||
169 | #else | ||
170 | #define __FAULT_ADDR_LIMIT VMALLOC_END | ||
171 | #endif | ||
172 | |||
173 | /* | ||
174 | * Handle a fault on the vmalloc or module mapping area | ||
175 | */ | ||
176 | static noinline int vmalloc_fault(unsigned long address) | ||
177 | { | ||
178 | pgd_t *pgd_k; | ||
179 | pmd_t *pmd_k; | ||
180 | pte_t *pte_k; | ||
181 | |||
182 | /* Make sure we are in vmalloc/module/P3 area: */ | ||
183 | if (!(address >= VMALLOC_START && address < __FAULT_ADDR_LIMIT)) | ||
184 | return -1; | ||
185 | |||
186 | /* | ||
187 | * Synchronize this task's top level page-table | ||
188 | * with the 'reference' page table. | ||
189 | * | ||
190 | * Do _not_ use "current" here. We might be inside | ||
191 | * an interrupt in the middle of a task switch.. | ||
192 | */ | ||
193 | pgd_k = get_TTB(); | ||
194 | pmd_k = vmalloc_sync_one(pgd_k, address); | ||
195 | if (!pmd_k) | ||
196 | return -1; | ||
197 | |||
198 | pte_k = pte_offset_kernel(pmd_k, address); | ||
199 | if (!pte_present(*pte_k)) | ||
200 | return -1; | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static void | ||
206 | show_fault_oops(struct pt_regs *regs, unsigned long address) | ||
207 | { | ||
208 | if (!oops_may_print()) | ||
209 | return; | ||
210 | |||
211 | printk(KERN_ALERT "BUG: unable to handle kernel "); | ||
212 | if (address < PAGE_SIZE) | ||
213 | printk(KERN_CONT "NULL pointer dereference"); | ||
214 | else | ||
215 | printk(KERN_CONT "paging request"); | ||
216 | |||
217 | printk(KERN_CONT " at %08lx\n", address); | ||
218 | printk(KERN_ALERT "PC:"); | ||
219 | printk_address(regs->pc, 1); | ||
220 | |||
221 | show_pte(NULL, address); | ||
222 | } | ||
223 | |||
224 | static noinline void | ||
225 | no_context(struct pt_regs *regs, unsigned long error_code, | ||
226 | unsigned long address) | ||
227 | { | ||
228 | /* Are we prepared to handle this kernel fault? */ | ||
229 | if (fixup_exception(regs)) | ||
230 | return; | ||
231 | |||
232 | if (handle_trapped_io(regs, address)) | ||
233 | return; | ||
234 | |||
235 | /* | ||
236 | * Oops. The kernel tried to access some bad page. We'll have to | ||
237 | * terminate things with extreme prejudice. | ||
238 | */ | ||
239 | bust_spinlocks(1); | ||
240 | |||
241 | show_fault_oops(regs, address); | ||
242 | |||
243 | die("Oops", regs, error_code); | ||
244 | bust_spinlocks(0); | ||
245 | do_exit(SIGKILL); | ||
246 | } | ||
247 | |||
248 | static void | ||
249 | __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | ||
250 | unsigned long address, int si_code) | ||
251 | { | ||
252 | struct task_struct *tsk = current; | ||
253 | |||
254 | /* User mode accesses just cause a SIGSEGV */ | ||
255 | if (user_mode(regs)) { | ||
256 | /* | ||
257 | * It's possible to have interrupts off here: | ||
258 | */ | ||
259 | local_irq_enable(); | ||
260 | |||
261 | force_sig_info_fault(SIGSEGV, si_code, address, tsk); | ||
262 | |||
263 | return; | ||
264 | } | ||
265 | |||
266 | no_context(regs, error_code, address); | ||
267 | } | ||
268 | |||
269 | static noinline void | ||
270 | bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code, | ||
271 | unsigned long address) | ||
272 | { | ||
273 | __bad_area_nosemaphore(regs, error_code, address, SEGV_MAPERR); | ||
274 | } | ||
275 | |||
276 | static void | ||
277 | __bad_area(struct pt_regs *regs, unsigned long error_code, | ||
278 | unsigned long address, int si_code) | ||
279 | { | ||
280 | struct mm_struct *mm = current->mm; | ||
281 | |||
282 | /* | ||
283 | * Something tried to access memory that isn't in our memory map.. | ||
284 | * Fix it, but check if it's kernel or user first.. | ||
285 | */ | ||
286 | up_read(&mm->mmap_sem); | ||
287 | |||
288 | __bad_area_nosemaphore(regs, error_code, address, si_code); | ||
289 | } | ||
290 | |||
291 | static noinline void | ||
292 | bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address) | ||
293 | { | ||
294 | __bad_area(regs, error_code, address, SEGV_MAPERR); | ||
295 | } | ||
296 | |||
297 | static noinline void | ||
298 | bad_area_access_error(struct pt_regs *regs, unsigned long error_code, | ||
299 | unsigned long address) | ||
300 | { | ||
301 | __bad_area(regs, error_code, address, SEGV_ACCERR); | ||
302 | } | ||
303 | |||
304 | static void | ||
305 | do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address) | ||
306 | { | ||
307 | struct task_struct *tsk = current; | ||
308 | struct mm_struct *mm = tsk->mm; | ||
309 | |||
310 | up_read(&mm->mmap_sem); | ||
311 | |||
312 | /* Kernel mode? Handle exceptions or die: */ | ||
313 | if (!user_mode(regs)) | ||
314 | no_context(regs, error_code, address); | ||
315 | |||
316 | force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk); | ||
317 | } | ||
318 | |||
319 | static noinline int | ||
320 | mm_fault_error(struct pt_regs *regs, unsigned long error_code, | ||
321 | unsigned long address, unsigned int fault) | ||
322 | { | ||
323 | /* | ||
324 | * Pagefault was interrupted by SIGKILL. We have no reason to | ||
325 | * continue pagefault. | ||
326 | */ | ||
327 | if (fatal_signal_pending(current)) { | ||
328 | if (!(fault & VM_FAULT_RETRY)) | ||
329 | up_read(¤t->mm->mmap_sem); | ||
330 | if (!user_mode(regs)) | ||
331 | no_context(regs, error_code, address); | ||
332 | return 1; | ||
333 | } | ||
334 | |||
335 | if (!(fault & VM_FAULT_ERROR)) | ||
336 | return 0; | ||
337 | |||
338 | if (fault & VM_FAULT_OOM) { | ||
339 | /* Kernel mode? Handle exceptions or die: */ | ||
340 | if (!user_mode(regs)) { | ||
341 | up_read(¤t->mm->mmap_sem); | ||
342 | no_context(regs, error_code, address); | ||
343 | return 1; | ||
344 | } | ||
345 | up_read(¤t->mm->mmap_sem); | ||
346 | |||
347 | /* | ||
348 | * We ran out of memory, call the OOM killer, and return the | ||
349 | * userspace (which will retry the fault, or kill us if we got | ||
350 | * oom-killed): | ||
351 | */ | ||
352 | pagefault_out_of_memory(); | ||
353 | } else { | ||
354 | if (fault & VM_FAULT_SIGBUS) | ||
355 | do_sigbus(regs, error_code, address); | ||
356 | else | ||
357 | BUG(); | ||
358 | } | ||
359 | |||
360 | return 1; | ||
361 | } | ||
362 | |||
363 | static inline int access_error(int error_code, struct vm_area_struct *vma) | ||
364 | { | ||
365 | if (error_code & FAULT_CODE_WRITE) { | ||
366 | /* write, present and write, not present: */ | ||
367 | if (unlikely(!(vma->vm_flags & VM_WRITE))) | ||
368 | return 1; | ||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | /* ITLB miss on NX page */ | ||
373 | if (unlikely((error_code & FAULT_CODE_ITLB) && | ||
374 | !(vma->vm_flags & VM_EXEC))) | ||
375 | return 1; | ||
376 | |||
377 | /* read, not present: */ | ||
378 | if (unlikely(!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))) | ||
379 | return 1; | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static int fault_in_kernel_space(unsigned long address) | ||
385 | { | ||
386 | return address >= TASK_SIZE; | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * This routine handles page faults. It determines the address, | ||
391 | * and the problem, and then passes it off to one of the appropriate | ||
392 | * routines. | ||
393 | */ | ||
394 | asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, | ||
395 | unsigned long error_code, | ||
396 | unsigned long address) | ||
397 | { | ||
398 | unsigned long vec; | ||
399 | struct task_struct *tsk; | ||
400 | struct mm_struct *mm; | ||
401 | struct vm_area_struct * vma; | ||
402 | int fault; | ||
403 | int write = error_code & FAULT_CODE_WRITE; | ||
404 | unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | | ||
405 | (write ? FAULT_FLAG_WRITE : 0)); | ||
406 | |||
407 | tsk = current; | ||
408 | mm = tsk->mm; | ||
409 | vec = lookup_exception_vector(); | ||
410 | |||
411 | /* | ||
412 | * We fault-in kernel-space virtual memory on-demand. The | ||
413 | * 'reference' page table is init_mm.pgd. | ||
414 | * | ||
415 | * NOTE! We MUST NOT take any locks for this case. We may | ||
416 | * be in an interrupt or a critical region, and should | ||
417 | * only copy the information from the master page table, | ||
418 | * nothing more. | ||
419 | */ | ||
420 | if (unlikely(fault_in_kernel_space(address))) { | ||
421 | if (vmalloc_fault(address) >= 0) | ||
422 | return; | ||
423 | if (notify_page_fault(regs, vec)) | ||
424 | return; | ||
425 | |||
426 | bad_area_nosemaphore(regs, error_code, address); | ||
427 | return; | ||
428 | } | ||
429 | |||
430 | if (unlikely(notify_page_fault(regs, vec))) | ||
431 | return; | ||
432 | |||
433 | /* Only enable interrupts if they were on before the fault */ | ||
434 | if ((regs->sr & SR_IMASK) != SR_IMASK) | ||
435 | local_irq_enable(); | ||
436 | |||
437 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); | ||
438 | |||
439 | /* | ||
440 | * If we're in an interrupt, have no user context or are running | ||
441 | * in an atomic region then we must not take the fault: | ||
442 | */ | ||
443 | if (unlikely(in_atomic() || !mm)) { | ||
444 | bad_area_nosemaphore(regs, error_code, address); | ||
445 | return; | ||
446 | } | ||
447 | |||
448 | retry: | ||
449 | down_read(&mm->mmap_sem); | ||
450 | |||
451 | vma = find_vma(mm, address); | ||
452 | if (unlikely(!vma)) { | ||
453 | bad_area(regs, error_code, address); | ||
454 | return; | ||
455 | } | ||
456 | if (likely(vma->vm_start <= address)) | ||
457 | goto good_area; | ||
458 | if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) { | ||
459 | bad_area(regs, error_code, address); | ||
460 | return; | ||
461 | } | ||
462 | if (unlikely(expand_stack(vma, address))) { | ||
463 | bad_area(regs, error_code, address); | ||
464 | return; | ||
465 | } | ||
466 | |||
467 | /* | ||
468 | * Ok, we have a good vm_area for this memory access, so | ||
469 | * we can handle it.. | ||
470 | */ | ||
471 | good_area: | ||
472 | if (unlikely(access_error(error_code, vma))) { | ||
473 | bad_area_access_error(regs, error_code, address); | ||
474 | return; | ||
475 | } | ||
476 | |||
477 | set_thread_fault_code(error_code); | ||
478 | |||
479 | /* | ||
480 | * If for any reason at all we couldn't handle the fault, | ||
481 | * make sure we exit gracefully rather than endlessly redo | ||
482 | * the fault. | ||
483 | */ | ||
484 | fault = handle_mm_fault(mm, vma, address, flags); | ||
485 | |||
486 | if (unlikely(fault & (VM_FAULT_RETRY | VM_FAULT_ERROR))) | ||
487 | if (mm_fault_error(regs, error_code, address, fault)) | ||
488 | return; | ||
489 | |||
490 | if (flags & FAULT_FLAG_ALLOW_RETRY) { | ||
491 | if (fault & VM_FAULT_MAJOR) { | ||
492 | tsk->maj_flt++; | ||
493 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, | ||
494 | regs, address); | ||
495 | } else { | ||
496 | tsk->min_flt++; | ||
497 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, | ||
498 | regs, address); | ||
499 | } | ||
500 | if (fault & VM_FAULT_RETRY) { | ||
501 | flags &= ~FAULT_FLAG_ALLOW_RETRY; | ||
502 | flags |= FAULT_FLAG_TRIED; | ||
503 | |||
504 | /* | ||
505 | * No need to up_read(&mm->mmap_sem) as we would | ||
506 | * have already released it in __lock_page_or_retry | ||
507 | * in mm/filemap.c. | ||
508 | */ | ||
509 | goto retry; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | up_read(&mm->mmap_sem); | ||
514 | } | ||
diff --git a/arch/sh/mm/flush-sh4.c b/arch/sh/mm/flush-sh4.c index 0b85dd9dd3a..cef402678f4 100644 --- a/arch/sh/mm/flush-sh4.c +++ b/arch/sh/mm/flush-sh4.c | |||
@@ -1,8 +1,6 @@ | |||
1 | #include <linux/mm.h> | 1 | #include <linux/mm.h> |
2 | #include <asm/mmu_context.h> | 2 | #include <asm/mmu_context.h> |
3 | #include <asm/cache_insns.h> | ||
4 | #include <asm/cacheflush.h> | 3 | #include <asm/cacheflush.h> |
5 | #include <asm/traps.h> | ||
6 | 4 | ||
7 | /* | 5 | /* |
8 | * Write back the dirty D-caches, but not invalidate them. | 6 | * Write back the dirty D-caches, but not invalidate them. |
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 82cc576fab1..58a93fb3d96 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/memblock.h> | 19 | #include <linux/memblock.h> |
20 | #include <linux/dma-mapping.h> | 20 | #include <linux/dma-mapping.h> |
21 | #include <linux/export.h> | ||
22 | #include <asm/mmu_context.h> | 21 | #include <asm/mmu_context.h> |
23 | #include <asm/mmzone.h> | 22 | #include <asm/mmzone.h> |
24 | #include <asm/kexec.h> | 23 | #include <asm/kexec.h> |
@@ -288,8 +287,6 @@ static void __init do_init_bootmem(void) | |||
288 | static void __init early_reserve_mem(void) | 287 | static void __init early_reserve_mem(void) |
289 | { | 288 | { |
290 | unsigned long start_pfn; | 289 | unsigned long start_pfn; |
291 | u32 zero_base = (u32)__MEMORY_START + (u32)PHYSICAL_OFFSET; | ||
292 | u32 start = zero_base + (u32)CONFIG_ZERO_PAGE_OFFSET; | ||
293 | 290 | ||
294 | /* | 291 | /* |
295 | * Partially used pages are not usable - thus | 292 | * Partially used pages are not usable - thus |
@@ -303,13 +300,15 @@ static void __init early_reserve_mem(void) | |||
303 | * this catches the (definitely buggy) case of us accidentally | 300 | * this catches the (definitely buggy) case of us accidentally |
304 | * initializing the bootmem allocator with an invalid RAM area. | 301 | * initializing the bootmem allocator with an invalid RAM area. |
305 | */ | 302 | */ |
306 | memblock_reserve(start, (PFN_PHYS(start_pfn) + PAGE_SIZE - 1) - start); | 303 | memblock_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET, |
304 | (PFN_PHYS(start_pfn) + PAGE_SIZE - 1) - | ||
305 | (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET)); | ||
307 | 306 | ||
308 | /* | 307 | /* |
309 | * Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET. | 308 | * Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET. |
310 | */ | 309 | */ |
311 | if (CONFIG_ZERO_PAGE_OFFSET != 0) | 310 | if (CONFIG_ZERO_PAGE_OFFSET != 0) |
312 | memblock_reserve(zero_base, CONFIG_ZERO_PAGE_OFFSET); | 311 | memblock_reserve(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET); |
313 | 312 | ||
314 | /* | 313 | /* |
315 | * Handle additional early reservations | 314 | * Handle additional early reservations |
@@ -324,6 +323,7 @@ void __init paging_init(void) | |||
324 | unsigned long vaddr, end; | 323 | unsigned long vaddr, end; |
325 | int nid; | 324 | int nid; |
326 | 325 | ||
326 | memblock_init(); | ||
327 | sh_mv.mv_mem_init(); | 327 | sh_mv.mv_mem_init(); |
328 | 328 | ||
329 | early_reserve_mem(); | 329 | early_reserve_mem(); |
@@ -336,7 +336,7 @@ void __init paging_init(void) | |||
336 | sh_mv.mv_mem_reserve(); | 336 | sh_mv.mv_mem_reserve(); |
337 | 337 | ||
338 | memblock_enforce_memory_limit(memory_limit); | 338 | memblock_enforce_memory_limit(memory_limit); |
339 | memblock_allow_resize(); | 339 | memblock_analyze(); |
340 | 340 | ||
341 | memblock_dump_all(); | 341 | memblock_dump_all(); |
342 | 342 | ||
diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index 6777177807c..afeb710ec5c 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c | |||
@@ -30,13 +30,25 @@ static inline unsigned long COLOUR_ALIGN(unsigned long addr, | |||
30 | return base + off; | 30 | return base + off; |
31 | } | 31 | } |
32 | 32 | ||
33 | static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr, | ||
34 | unsigned long pgoff) | ||
35 | { | ||
36 | unsigned long base = addr & ~shm_align_mask; | ||
37 | unsigned long off = (pgoff << PAGE_SHIFT) & shm_align_mask; | ||
38 | |||
39 | if (base + off <= addr) | ||
40 | return base + off; | ||
41 | |||
42 | return base - off; | ||
43 | } | ||
44 | |||
33 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, | 45 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, |
34 | unsigned long len, unsigned long pgoff, unsigned long flags) | 46 | unsigned long len, unsigned long pgoff, unsigned long flags) |
35 | { | 47 | { |
36 | struct mm_struct *mm = current->mm; | 48 | struct mm_struct *mm = current->mm; |
37 | struct vm_area_struct *vma; | 49 | struct vm_area_struct *vma; |
50 | unsigned long start_addr; | ||
38 | int do_colour_align; | 51 | int do_colour_align; |
39 | struct vm_unmapped_area_info info; | ||
40 | 52 | ||
41 | if (flags & MAP_FIXED) { | 53 | if (flags & MAP_FIXED) { |
42 | /* We do not accept a shared mapping if it would violate | 54 | /* We do not accept a shared mapping if it would violate |
@@ -67,13 +79,47 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, | |||
67 | return addr; | 79 | return addr; |
68 | } | 80 | } |
69 | 81 | ||
70 | info.flags = 0; | 82 | if (len > mm->cached_hole_size) { |
71 | info.length = len; | 83 | start_addr = addr = mm->free_area_cache; |
72 | info.low_limit = TASK_UNMAPPED_BASE; | 84 | } else { |
73 | info.high_limit = TASK_SIZE; | 85 | mm->cached_hole_size = 0; |
74 | info.align_mask = do_colour_align ? (PAGE_MASK & shm_align_mask) : 0; | 86 | start_addr = addr = TASK_UNMAPPED_BASE; |
75 | info.align_offset = pgoff << PAGE_SHIFT; | 87 | } |
76 | return vm_unmapped_area(&info); | 88 | |
89 | full_search: | ||
90 | if (do_colour_align) | ||
91 | addr = COLOUR_ALIGN(addr, pgoff); | ||
92 | else | ||
93 | addr = PAGE_ALIGN(mm->free_area_cache); | ||
94 | |||
95 | for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { | ||
96 | /* At this point: (!vma || addr < vma->vm_end). */ | ||
97 | if (unlikely(TASK_SIZE - len < addr)) { | ||
98 | /* | ||
99 | * Start a new search - just in case we missed | ||
100 | * some holes. | ||
101 | */ | ||
102 | if (start_addr != TASK_UNMAPPED_BASE) { | ||
103 | start_addr = addr = TASK_UNMAPPED_BASE; | ||
104 | mm->cached_hole_size = 0; | ||
105 | goto full_search; | ||
106 | } | ||
107 | return -ENOMEM; | ||
108 | } | ||
109 | if (likely(!vma || addr + len <= vma->vm_start)) { | ||
110 | /* | ||
111 | * Remember the place where we stopped the search: | ||
112 | */ | ||
113 | mm->free_area_cache = addr + len; | ||
114 | return addr; | ||
115 | } | ||
116 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
117 | mm->cached_hole_size = vma->vm_start - addr; | ||
118 | |||
119 | addr = vma->vm_end; | ||
120 | if (do_colour_align) | ||
121 | addr = COLOUR_ALIGN(addr, pgoff); | ||
122 | } | ||
77 | } | 123 | } |
78 | 124 | ||
79 | unsigned long | 125 | unsigned long |
@@ -85,7 +131,6 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
85 | struct mm_struct *mm = current->mm; | 131 | struct mm_struct *mm = current->mm; |
86 | unsigned long addr = addr0; | 132 | unsigned long addr = addr0; |
87 | int do_colour_align; | 133 | int do_colour_align; |
88 | struct vm_unmapped_area_info info; | ||
89 | 134 | ||
90 | if (flags & MAP_FIXED) { | 135 | if (flags & MAP_FIXED) { |
91 | /* We do not accept a shared mapping if it would violate | 136 | /* We do not accept a shared mapping if it would violate |
@@ -117,27 +162,73 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
117 | return addr; | 162 | return addr; |
118 | } | 163 | } |
119 | 164 | ||
120 | info.flags = VM_UNMAPPED_AREA_TOPDOWN; | 165 | /* check if free_area_cache is useful for us */ |
121 | info.length = len; | 166 | if (len <= mm->cached_hole_size) { |
122 | info.low_limit = PAGE_SIZE; | 167 | mm->cached_hole_size = 0; |
123 | info.high_limit = mm->mmap_base; | 168 | mm->free_area_cache = mm->mmap_base; |
124 | info.align_mask = do_colour_align ? (PAGE_MASK & shm_align_mask) : 0; | 169 | } |
125 | info.align_offset = pgoff << PAGE_SHIFT; | 170 | |
126 | addr = vm_unmapped_area(&info); | 171 | /* either no address requested or can't fit in requested address hole */ |
172 | addr = mm->free_area_cache; | ||
173 | if (do_colour_align) { | ||
174 | unsigned long base = COLOUR_ALIGN_DOWN(addr-len, pgoff); | ||
127 | 175 | ||
176 | addr = base + len; | ||
177 | } | ||
178 | |||
179 | /* make sure it can fit in the remaining address space */ | ||
180 | if (likely(addr > len)) { | ||
181 | vma = find_vma(mm, addr-len); | ||
182 | if (!vma || addr <= vma->vm_start) { | ||
183 | /* remember the address as a hint for next time */ | ||
184 | return (mm->free_area_cache = addr-len); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | if (unlikely(mm->mmap_base < len)) | ||
189 | goto bottomup; | ||
190 | |||
191 | addr = mm->mmap_base-len; | ||
192 | if (do_colour_align) | ||
193 | addr = COLOUR_ALIGN_DOWN(addr, pgoff); | ||
194 | |||
195 | do { | ||
196 | /* | ||
197 | * Lookup failure means no vma is above this address, | ||
198 | * else if new region fits below vma->vm_start, | ||
199 | * return with success: | ||
200 | */ | ||
201 | vma = find_vma(mm, addr); | ||
202 | if (likely(!vma || addr+len <= vma->vm_start)) { | ||
203 | /* remember the address as a hint for next time */ | ||
204 | return (mm->free_area_cache = addr); | ||
205 | } | ||
206 | |||
207 | /* remember the largest hole we saw so far */ | ||
208 | if (addr + mm->cached_hole_size < vma->vm_start) | ||
209 | mm->cached_hole_size = vma->vm_start - addr; | ||
210 | |||
211 | /* try just below the current vma->vm_start */ | ||
212 | addr = vma->vm_start-len; | ||
213 | if (do_colour_align) | ||
214 | addr = COLOUR_ALIGN_DOWN(addr, pgoff); | ||
215 | } while (likely(len < vma->vm_start)); | ||
216 | |||
217 | bottomup: | ||
128 | /* | 218 | /* |
129 | * A failed mmap() very likely causes application failure, | 219 | * A failed mmap() very likely causes application failure, |
130 | * so fall back to the bottom-up function here. This scenario | 220 | * so fall back to the bottom-up function here. This scenario |
131 | * can happen with large stack limits and large mmap() | 221 | * can happen with large stack limits and large mmap() |
132 | * allocations. | 222 | * allocations. |
133 | */ | 223 | */ |
134 | if (addr & ~PAGE_MASK) { | 224 | mm->cached_hole_size = ~0UL; |
135 | VM_BUG_ON(addr != -ENOMEM); | 225 | mm->free_area_cache = TASK_UNMAPPED_BASE; |
136 | info.flags = 0; | 226 | addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); |
137 | info.low_limit = TASK_UNMAPPED_BASE; | 227 | /* |
138 | info.high_limit = TASK_SIZE; | 228 | * Restore the topdown base: |
139 | addr = vm_unmapped_area(&info); | 229 | */ |
140 | } | 230 | mm->free_area_cache = mm->mmap_base; |
231 | mm->cached_hole_size = ~0UL; | ||
141 | 232 | ||
142 | return addr; | 233 | return addr; |
143 | } | 234 | } |
@@ -147,7 +238,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, | |||
147 | * You really shouldn't be using read() or write() on /dev/mem. This | 238 | * You really shouldn't be using read() or write() on /dev/mem. This |
148 | * might go away in the future. | 239 | * might go away in the future. |
149 | */ | 240 | */ |
150 | int valid_phys_addr_range(phys_addr_t addr, size_t count) | 241 | int valid_phys_addr_range(unsigned long addr, size_t count) |
151 | { | 242 | { |
152 | if (addr < __MEMORY_START) | 243 | if (addr < __MEMORY_START) |
153 | return 0; | 244 | return 0; |
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 7160c9fd6fe..fad52f1f681 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
26 | #include <asm/cacheflush.h> | 26 | #include <asm/cacheflush.h> |
27 | #include <asm/sizes.h> | 27 | #include <asm/sizes.h> |
28 | #include <asm/system.h> | ||
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
29 | #include <asm/pgtable.h> | 30 | #include <asm/pgtable.h> |
30 | #include <asm/page.h> | 31 | #include <asm/page.h> |
diff --git a/arch/sh/mm/sram.c b/arch/sh/mm/sram.c index 2d8fa718d55..bc156ec4545 100644 --- a/arch/sh/mm/sram.c +++ b/arch/sh/mm/sram.c | |||
@@ -9,7 +9,6 @@ | |||
9 | */ | 9 | */ |
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/errno.h> | ||
13 | #include <asm/sram.h> | 12 | #include <asm/sram.h> |
14 | 13 | ||
15 | /* | 14 | /* |
diff --git a/arch/sh/mm/tlb-pteaex.c b/arch/sh/mm/tlb-pteaex.c index 4db21adfe5d..b71db6af806 100644 --- a/arch/sh/mm/tlb-pteaex.c +++ b/arch/sh/mm/tlb-pteaex.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/mm.h> | 13 | #include <linux/mm.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <asm/system.h> | ||
15 | #include <asm/mmu_context.h> | 16 | #include <asm/mmu_context.h> |
16 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
17 | 18 | ||
diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index 6554fb439f0..7a940dbfc2e 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/smp.h> | 20 | #include <linux/smp.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | 22 | ||
23 | #include <asm/system.h> | ||
23 | #include <asm/io.h> | 24 | #include <asm/io.h> |
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
25 | #include <asm/pgalloc.h> | 26 | #include <asm/pgalloc.h> |
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c index d42dd7e443d..cfdf7930d29 100644 --- a/arch/sh/mm/tlb-sh4.c +++ b/arch/sh/mm/tlb-sh4.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
14 | #include <asm/system.h> | ||
14 | #include <asm/mmu_context.h> | 15 | #include <asm/mmu_context.h> |
15 | #include <asm/cacheflush.h> | 16 | #include <asm/cacheflush.h> |
16 | 17 | ||
diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c index ff1c40a31cb..f27dbe1c159 100644 --- a/arch/sh/mm/tlb-sh5.c +++ b/arch/sh/mm/tlb-sh5.c | |||
@@ -17,7 +17,7 @@ | |||
17 | /** | 17 | /** |
18 | * sh64_tlb_init - Perform initial setup for the DTLB and ITLB. | 18 | * sh64_tlb_init - Perform initial setup for the DTLB and ITLB. |
19 | */ | 19 | */ |
20 | int __cpuinit sh64_tlb_init(void) | 20 | int __init sh64_tlb_init(void) |
21 | { | 21 | { |
22 | /* Assign some sane DTLB defaults */ | 22 | /* Assign some sane DTLB defaults */ |
23 | cpu_data->dtlb.entries = 64; | 23 | cpu_data->dtlb.entries = 64; |
@@ -182,43 +182,3 @@ void tlb_unwire_entry(void) | |||
182 | 182 | ||
183 | local_irq_restore(flags); | 183 | local_irq_restore(flags); |
184 | } | 184 | } |
185 | |||
186 | void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) | ||
187 | { | ||
188 | unsigned long long ptel; | ||
189 | unsigned long long pteh=0; | ||
190 | struct tlb_info *tlbp; | ||
191 | unsigned long long next; | ||
192 | unsigned int fault_code = get_thread_fault_code(); | ||
193 | |||
194 | /* Get PTEL first */ | ||
195 | ptel = pte.pte_low; | ||
196 | |||
197 | /* | ||
198 | * Set PTEH register | ||
199 | */ | ||
200 | pteh = neff_sign_extend(address & MMU_VPN_MASK); | ||
201 | |||
202 | /* Set the ASID. */ | ||
203 | pteh |= get_asid() << PTEH_ASID_SHIFT; | ||
204 | pteh |= PTEH_VALID; | ||
205 | |||
206 | /* Set PTEL register, set_pte has performed the sign extension */ | ||
207 | ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ | ||
208 | |||
209 | if (fault_code & FAULT_CODE_ITLB) | ||
210 | tlbp = &cpu_data->itlb; | ||
211 | else | ||
212 | tlbp = &cpu_data->dtlb; | ||
213 | |||
214 | next = tlbp->next; | ||
215 | __flush_tlb_slot(next); | ||
216 | asm volatile ("putcfg %0,1,%2\n\n\t" | ||
217 | "putcfg %0,0,%1\n" | ||
218 | : : "r" (next), "r" (pteh), "r" (ptel) ); | ||
219 | |||
220 | next += TLB_STEP; | ||
221 | if (next > tlbp->last) | ||
222 | next = tlbp->first; | ||
223 | tlbp->next = next; | ||
224 | } | ||
diff --git a/arch/sh/mm/tlbex_32.c b/arch/sh/mm/tlbex_32.c deleted file mode 100644 index 382262dc0c4..00000000000 --- a/arch/sh/mm/tlbex_32.c +++ /dev/null | |||
@@ -1,78 +0,0 @@ | |||
1 | /* | ||
2 | * TLB miss handler for SH with an MMU. | ||
3 | * | ||
4 | * Copyright (C) 1999 Niibe Yutaka | ||
5 | * Copyright (C) 2003 - 2012 Paul Mundt | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/kprobes.h> | ||
14 | #include <linux/kdebug.h> | ||
15 | #include <asm/mmu_context.h> | ||
16 | #include <asm/thread_info.h> | ||
17 | |||
18 | /* | ||
19 | * Called with interrupts disabled. | ||
20 | */ | ||
21 | asmlinkage int __kprobes | ||
22 | handle_tlbmiss(struct pt_regs *regs, unsigned long error_code, | ||
23 | unsigned long address) | ||
24 | { | ||
25 | pgd_t *pgd; | ||
26 | pud_t *pud; | ||
27 | pmd_t *pmd; | ||
28 | pte_t *pte; | ||
29 | pte_t entry; | ||
30 | |||
31 | /* | ||
32 | * We don't take page faults for P1, P2, and parts of P4, these | ||
33 | * are always mapped, whether it be due to legacy behaviour in | ||
34 | * 29-bit mode, or due to PMB configuration in 32-bit mode. | ||
35 | */ | ||
36 | if (address >= P3SEG && address < P3_ADDR_MAX) { | ||
37 | pgd = pgd_offset_k(address); | ||
38 | } else { | ||
39 | if (unlikely(address >= TASK_SIZE || !current->mm)) | ||
40 | return 1; | ||
41 | |||
42 | pgd = pgd_offset(current->mm, address); | ||
43 | } | ||
44 | |||
45 | pud = pud_offset(pgd, address); | ||
46 | if (pud_none_or_clear_bad(pud)) | ||
47 | return 1; | ||
48 | pmd = pmd_offset(pud, address); | ||
49 | if (pmd_none_or_clear_bad(pmd)) | ||
50 | return 1; | ||
51 | pte = pte_offset_kernel(pmd, address); | ||
52 | entry = *pte; | ||
53 | if (unlikely(pte_none(entry) || pte_not_present(entry))) | ||
54 | return 1; | ||
55 | if (unlikely(error_code && !pte_write(entry))) | ||
56 | return 1; | ||
57 | |||
58 | if (error_code) | ||
59 | entry = pte_mkdirty(entry); | ||
60 | entry = pte_mkyoung(entry); | ||
61 | |||
62 | set_pte(pte, entry); | ||
63 | |||
64 | #if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP) | ||
65 | /* | ||
66 | * SH-4 does not set MMUCR.RC to the corresponding TLB entry in | ||
67 | * the case of an initial page write exception, so we need to | ||
68 | * flush it in order to avoid potential TLB entry duplication. | ||
69 | */ | ||
70 | if (error_code == FAULT_CODE_INITIAL) | ||
71 | local_flush_tlb_one(get_asid(), address & PAGE_MASK); | ||
72 | #endif | ||
73 | |||
74 | set_thread_fault_code(error_code); | ||
75 | update_mmu_cache(NULL, address, pte); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
diff --git a/arch/sh/mm/tlbex_64.c b/arch/sh/mm/tlbex_64.c deleted file mode 100644 index 8557548fc53..00000000000 --- a/arch/sh/mm/tlbex_64.c +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
1 | /* | ||
2 | * The SH64 TLB miss. | ||
3 | * | ||
4 | * Original code from fault.c | ||
5 | * Copyright (C) 2000, 2001 Paolo Alberelli | ||
6 | * | ||
7 | * Fast PTE->TLB refill path | ||
8 | * Copyright (C) 2003 Richard.Curnow@superh.com | ||
9 | * | ||
10 | * IMPORTANT NOTES : | ||
11 | * The do_fast_page_fault function is called from a context in entry.S | ||
12 | * where very few registers have been saved. In particular, the code in | ||
13 | * this file must be compiled not to use ANY caller-save registers that | ||
14 | * are not part of the restricted save set. Also, it means that code in | ||
15 | * this file must not make calls to functions elsewhere in the kernel, or | ||
16 | * else the excepting context will see corruption in its caller-save | ||
17 | * registers. Plus, the entry.S save area is non-reentrant, so this code | ||
18 | * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic | ||
19 | * on any exception. | ||
20 | * | ||
21 | * This file is subject to the terms and conditions of the GNU General Public | ||
22 | * License. See the file "COPYING" in the main directory of this archive | ||
23 | * for more details. | ||
24 | */ | ||
25 | #include <linux/signal.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/types.h> | ||
31 | #include <linux/ptrace.h> | ||
32 | #include <linux/mman.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/smp.h> | ||
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/kprobes.h> | ||
37 | #include <asm/tlb.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | #include <asm/pgalloc.h> | ||
41 | #include <asm/mmu_context.h> | ||
42 | |||
43 | static int handle_tlbmiss(unsigned long long protection_flags, | ||
44 | unsigned long address) | ||
45 | { | ||
46 | pgd_t *pgd; | ||
47 | pud_t *pud; | ||
48 | pmd_t *pmd; | ||
49 | pte_t *pte; | ||
50 | pte_t entry; | ||
51 | |||
52 | if (is_vmalloc_addr((void *)address)) { | ||
53 | pgd = pgd_offset_k(address); | ||
54 | } else { | ||
55 | if (unlikely(address >= TASK_SIZE || !current->mm)) | ||
56 | return 1; | ||
57 | |||
58 | pgd = pgd_offset(current->mm, address); | ||
59 | } | ||
60 | |||
61 | pud = pud_offset(pgd, address); | ||
62 | if (pud_none(*pud) || !pud_present(*pud)) | ||
63 | return 1; | ||
64 | |||
65 | pmd = pmd_offset(pud, address); | ||
66 | if (pmd_none(*pmd) || !pmd_present(*pmd)) | ||
67 | return 1; | ||
68 | |||
69 | pte = pte_offset_kernel(pmd, address); | ||
70 | entry = *pte; | ||
71 | if (pte_none(entry) || !pte_present(entry)) | ||
72 | return 1; | ||
73 | |||
74 | /* | ||
75 | * If the page doesn't have sufficient protection bits set to | ||
76 | * service the kind of fault being handled, there's not much | ||
77 | * point doing the TLB refill. Punt the fault to the general | ||
78 | * handler. | ||
79 | */ | ||
80 | if ((pte_val(entry) & protection_flags) != protection_flags) | ||
81 | return 1; | ||
82 | |||
83 | update_mmu_cache(NULL, address, pte); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * Put all this information into one structure so that everything is just | ||
90 | * arithmetic relative to a single base address. This reduces the number | ||
91 | * of movi/shori pairs needed just to load addresses of static data. | ||
92 | */ | ||
93 | struct expevt_lookup { | ||
94 | unsigned short protection_flags[8]; | ||
95 | unsigned char is_text_access[8]; | ||
96 | unsigned char is_write_access[8]; | ||
97 | }; | ||
98 | |||
99 | #define PRU (1<<9) | ||
100 | #define PRW (1<<8) | ||
101 | #define PRX (1<<7) | ||
102 | #define PRR (1<<6) | ||
103 | |||
104 | /* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether | ||
105 | the fault happened in user mode or privileged mode. */ | ||
106 | static struct expevt_lookup expevt_lookup_table = { | ||
107 | .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW}, | ||
108 | .is_text_access = {1, 1, 0, 0, 0, 0, 0, 0} | ||
109 | }; | ||
110 | |||
111 | static inline unsigned int | ||
112 | expevt_to_fault_code(unsigned long expevt) | ||
113 | { | ||
114 | if (expevt == 0xa40) | ||
115 | return FAULT_CODE_ITLB; | ||
116 | else if (expevt == 0x060) | ||
117 | return FAULT_CODE_WRITE; | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | This routine handles page faults that can be serviced just by refilling a | ||
124 | TLB entry from an existing page table entry. (This case represents a very | ||
125 | large majority of page faults.) Return 1 if the fault was successfully | ||
126 | handled. Return 0 if the fault could not be handled. (This leads into the | ||
127 | general fault handling in fault.c which deals with mapping file-backed | ||
128 | pages, stack growth, segmentation faults, swapping etc etc) | ||
129 | */ | ||
130 | asmlinkage int __kprobes | ||
131 | do_fast_page_fault(unsigned long long ssr_md, unsigned long long expevt, | ||
132 | unsigned long address) | ||
133 | { | ||
134 | unsigned long long protection_flags; | ||
135 | unsigned long long index; | ||
136 | unsigned long long expevt4; | ||
137 | unsigned int fault_code; | ||
138 | |||
139 | /* The next few lines implement a way of hashing EXPEVT into a | ||
140 | * small array index which can be used to lookup parameters | ||
141 | * specific to the type of TLBMISS being handled. | ||
142 | * | ||
143 | * Note: | ||
144 | * ITLBMISS has EXPEVT==0xa40 | ||
145 | * RTLBMISS has EXPEVT==0x040 | ||
146 | * WTLBMISS has EXPEVT==0x060 | ||
147 | */ | ||
148 | expevt4 = (expevt >> 4); | ||
149 | /* TODO : xor ssr_md into this expression too. Then we can check | ||
150 | * that PRU is set when it needs to be. */ | ||
151 | index = expevt4 ^ (expevt4 >> 5); | ||
152 | index &= 7; | ||
153 | |||
154 | fault_code = expevt_to_fault_code(expevt); | ||
155 | |||
156 | protection_flags = expevt_lookup_table.protection_flags[index]; | ||
157 | |||
158 | if (expevt_lookup_table.is_text_access[index]) | ||
159 | fault_code |= FAULT_CODE_ITLB; | ||
160 | if (!ssr_md) | ||
161 | fault_code |= FAULT_CODE_USER; | ||
162 | |||
163 | set_thread_fault_code(fault_code); | ||
164 | |||
165 | return handle_tlbmiss(protection_flags, address); | ||
166 | } | ||
diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c index f33fdd2558e..e3430e093d4 100644 --- a/arch/sh/mm/tlbflush_64.c +++ b/arch/sh/mm/tlbflush_64.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (C) 2000, 2001 Paolo Alberelli | 4 | * Copyright (C) 2000, 2001 Paolo Alberelli |
5 | * Copyright (C) 2003 Richard Curnow (/proc/tlb, bug fixes) | 5 | * Copyright (C) 2003 Richard Curnow (/proc/tlb, bug fixes) |
6 | * Copyright (C) 2003 - 2012 Paul Mundt | 6 | * Copyright (C) 2003 - 2009 Paul Mundt |
7 | * | 7 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 8 | * This file is subject to the terms and conditions of the GNU General Public |
9 | * License. See the file "COPYING" in the main directory of this archive | 9 | * License. See the file "COPYING" in the main directory of this archive |
@@ -22,12 +22,301 @@ | |||
22 | #include <linux/smp.h> | 22 | #include <linux/smp.h> |
23 | #include <linux/perf_event.h> | 23 | #include <linux/perf_event.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <asm/system.h> | ||
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
26 | #include <asm/tlb.h> | 27 | #include <asm/tlb.h> |
27 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
28 | #include <asm/pgalloc.h> | 29 | #include <asm/pgalloc.h> |
29 | #include <asm/mmu_context.h> | 30 | #include <asm/mmu_context.h> |
30 | 31 | ||
32 | extern void die(const char *,struct pt_regs *,long); | ||
33 | |||
34 | #define PFLAG(val,flag) (( (val) & (flag) ) ? #flag : "" ) | ||
35 | #define PPROT(flag) PFLAG(pgprot_val(prot),flag) | ||
36 | |||
37 | static inline void print_prots(pgprot_t prot) | ||
38 | { | ||
39 | printk("prot is 0x%016llx\n",pgprot_val(prot)); | ||
40 | |||
41 | printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ), | ||
42 | PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER)); | ||
43 | } | ||
44 | |||
45 | static inline void print_vma(struct vm_area_struct *vma) | ||
46 | { | ||
47 | printk("vma start 0x%08lx\n", vma->vm_start); | ||
48 | printk("vma end 0x%08lx\n", vma->vm_end); | ||
49 | |||
50 | print_prots(vma->vm_page_prot); | ||
51 | printk("vm_flags 0x%08lx\n", vma->vm_flags); | ||
52 | } | ||
53 | |||
54 | static inline void print_task(struct task_struct *tsk) | ||
55 | { | ||
56 | printk("Task pid %d\n", task_pid_nr(tsk)); | ||
57 | } | ||
58 | |||
59 | static pte_t *lookup_pte(struct mm_struct *mm, unsigned long address) | ||
60 | { | ||
61 | pgd_t *dir; | ||
62 | pud_t *pud; | ||
63 | pmd_t *pmd; | ||
64 | pte_t *pte; | ||
65 | pte_t entry; | ||
66 | |||
67 | dir = pgd_offset(mm, address); | ||
68 | if (pgd_none(*dir)) | ||
69 | return NULL; | ||
70 | |||
71 | pud = pud_offset(dir, address); | ||
72 | if (pud_none(*pud)) | ||
73 | return NULL; | ||
74 | |||
75 | pmd = pmd_offset(pud, address); | ||
76 | if (pmd_none(*pmd)) | ||
77 | return NULL; | ||
78 | |||
79 | pte = pte_offset_kernel(pmd, address); | ||
80 | entry = *pte; | ||
81 | if (pte_none(entry) || !pte_present(entry)) | ||
82 | return NULL; | ||
83 | |||
84 | return pte; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * This routine handles page faults. It determines the address, | ||
89 | * and the problem, and then passes it off to one of the appropriate | ||
90 | * routines. | ||
91 | */ | ||
92 | asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, | ||
93 | unsigned long textaccess, unsigned long address) | ||
94 | { | ||
95 | struct task_struct *tsk; | ||
96 | struct mm_struct *mm; | ||
97 | struct vm_area_struct * vma; | ||
98 | const struct exception_table_entry *fixup; | ||
99 | pte_t *pte; | ||
100 | int fault; | ||
101 | |||
102 | /* SIM | ||
103 | * Note this is now called with interrupts still disabled | ||
104 | * This is to cope with being called for a missing IO port | ||
105 | * address with interrupts disabled. This should be fixed as | ||
106 | * soon as we have a better 'fast path' miss handler. | ||
107 | * | ||
108 | * Plus take care how you try and debug this stuff. | ||
109 | * For example, writing debug data to a port which you | ||
110 | * have just faulted on is not going to work. | ||
111 | */ | ||
112 | |||
113 | tsk = current; | ||
114 | mm = tsk->mm; | ||
115 | |||
116 | /* Not an IO address, so reenable interrupts */ | ||
117 | local_irq_enable(); | ||
118 | |||
119 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); | ||
120 | |||
121 | /* | ||
122 | * If we're in an interrupt or have no user | ||
123 | * context, we must not take the fault.. | ||
124 | */ | ||
125 | if (in_atomic() || !mm) | ||
126 | goto no_context; | ||
127 | |||
128 | /* TLB misses upon some cache flushes get done under cli() */ | ||
129 | down_read(&mm->mmap_sem); | ||
130 | |||
131 | vma = find_vma(mm, address); | ||
132 | |||
133 | if (!vma) { | ||
134 | #ifdef DEBUG_FAULT | ||
135 | print_task(tsk); | ||
136 | printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n", | ||
137 | __func__, __LINE__, | ||
138 | address,regs->pc,textaccess,writeaccess); | ||
139 | show_regs(regs); | ||
140 | #endif | ||
141 | goto bad_area; | ||
142 | } | ||
143 | if (vma->vm_start <= address) { | ||
144 | goto good_area; | ||
145 | } | ||
146 | |||
147 | if (!(vma->vm_flags & VM_GROWSDOWN)) { | ||
148 | #ifdef DEBUG_FAULT | ||
149 | print_task(tsk); | ||
150 | printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n", | ||
151 | __func__, __LINE__, | ||
152 | address,regs->pc,textaccess,writeaccess); | ||
153 | show_regs(regs); | ||
154 | |||
155 | print_vma(vma); | ||
156 | #endif | ||
157 | goto bad_area; | ||
158 | } | ||
159 | if (expand_stack(vma, address)) { | ||
160 | #ifdef DEBUG_FAULT | ||
161 | print_task(tsk); | ||
162 | printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n", | ||
163 | __func__, __LINE__, | ||
164 | address,regs->pc,textaccess,writeaccess); | ||
165 | show_regs(regs); | ||
166 | #endif | ||
167 | goto bad_area; | ||
168 | } | ||
169 | /* | ||
170 | * Ok, we have a good vm_area for this memory access, so | ||
171 | * we can handle it.. | ||
172 | */ | ||
173 | good_area: | ||
174 | if (textaccess) { | ||
175 | if (!(vma->vm_flags & VM_EXEC)) | ||
176 | goto bad_area; | ||
177 | } else { | ||
178 | if (writeaccess) { | ||
179 | if (!(vma->vm_flags & VM_WRITE)) | ||
180 | goto bad_area; | ||
181 | } else { | ||
182 | if (!(vma->vm_flags & VM_READ)) | ||
183 | goto bad_area; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * If for any reason at all we couldn't handle the fault, | ||
189 | * make sure we exit gracefully rather than endlessly redo | ||
190 | * the fault. | ||
191 | */ | ||
192 | fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0); | ||
193 | if (unlikely(fault & VM_FAULT_ERROR)) { | ||
194 | if (fault & VM_FAULT_OOM) | ||
195 | goto out_of_memory; | ||
196 | else if (fault & VM_FAULT_SIGBUS) | ||
197 | goto do_sigbus; | ||
198 | BUG(); | ||
199 | } | ||
200 | |||
201 | if (fault & VM_FAULT_MAJOR) { | ||
202 | tsk->maj_flt++; | ||
203 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, | ||
204 | regs, address); | ||
205 | } else { | ||
206 | tsk->min_flt++; | ||
207 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, | ||
208 | regs, address); | ||
209 | } | ||
210 | |||
211 | /* If we get here, the page fault has been handled. Do the TLB refill | ||
212 | now from the newly-setup PTE, to avoid having to fault again right | ||
213 | away on the same instruction. */ | ||
214 | pte = lookup_pte (mm, address); | ||
215 | if (!pte) { | ||
216 | /* From empirical evidence, we can get here, due to | ||
217 | !pte_present(pte). (e.g. if a swap-in occurs, and the page | ||
218 | is swapped back out again before the process that wanted it | ||
219 | gets rescheduled?) */ | ||
220 | goto no_pte; | ||
221 | } | ||
222 | |||
223 | __do_tlb_refill(address, textaccess, pte); | ||
224 | |||
225 | no_pte: | ||
226 | |||
227 | up_read(&mm->mmap_sem); | ||
228 | return; | ||
229 | |||
230 | /* | ||
231 | * Something tried to access memory that isn't in our memory map.. | ||
232 | * Fix it, but check if it's kernel or user first.. | ||
233 | */ | ||
234 | bad_area: | ||
235 | #ifdef DEBUG_FAULT | ||
236 | printk("fault:bad area\n"); | ||
237 | #endif | ||
238 | up_read(&mm->mmap_sem); | ||
239 | |||
240 | if (user_mode(regs)) { | ||
241 | static int count=0; | ||
242 | siginfo_t info; | ||
243 | if (count < 4) { | ||
244 | /* This is really to help debug faults when starting | ||
245 | * usermode, so only need a few */ | ||
246 | count++; | ||
247 | printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx\n", | ||
248 | address, task_pid_nr(current), current->comm, | ||
249 | (unsigned long) regs->pc); | ||
250 | #if 0 | ||
251 | show_regs(regs); | ||
252 | #endif | ||
253 | } | ||
254 | if (is_global_init(tsk)) { | ||
255 | panic("INIT had user mode bad_area\n"); | ||
256 | } | ||
257 | tsk->thread.address = address; | ||
258 | tsk->thread.error_code = writeaccess; | ||
259 | info.si_signo = SIGSEGV; | ||
260 | info.si_errno = 0; | ||
261 | info.si_addr = (void *) address; | ||
262 | force_sig_info(SIGSEGV, &info, tsk); | ||
263 | return; | ||
264 | } | ||
265 | |||
266 | no_context: | ||
267 | #ifdef DEBUG_FAULT | ||
268 | printk("fault:No context\n"); | ||
269 | #endif | ||
270 | /* Are we prepared to handle this kernel fault? */ | ||
271 | fixup = search_exception_tables(regs->pc); | ||
272 | if (fixup) { | ||
273 | regs->pc = fixup->fixup; | ||
274 | return; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * Oops. The kernel tried to access some bad page. We'll have to | ||
279 | * terminate things with extreme prejudice. | ||
280 | * | ||
281 | */ | ||
282 | if (address < PAGE_SIZE) | ||
283 | printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); | ||
284 | else | ||
285 | printk(KERN_ALERT "Unable to handle kernel paging request"); | ||
286 | printk(" at virtual address %08lx\n", address); | ||
287 | printk(KERN_ALERT "pc = %08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff); | ||
288 | die("Oops", regs, writeaccess); | ||
289 | do_exit(SIGKILL); | ||
290 | |||
291 | /* | ||
292 | * We ran out of memory, or some other thing happened to us that made | ||
293 | * us unable to handle the page fault gracefully. | ||
294 | */ | ||
295 | out_of_memory: | ||
296 | up_read(&mm->mmap_sem); | ||
297 | if (!user_mode(regs)) | ||
298 | goto no_context; | ||
299 | pagefault_out_of_memory(); | ||
300 | return; | ||
301 | |||
302 | do_sigbus: | ||
303 | printk("fault:Do sigbus\n"); | ||
304 | up_read(&mm->mmap_sem); | ||
305 | |||
306 | /* | ||
307 | * Send a sigbus, regardless of whether we were in kernel | ||
308 | * or user mode. | ||
309 | */ | ||
310 | tsk->thread.address = address; | ||
311 | tsk->thread.error_code = writeaccess; | ||
312 | tsk->thread.trap_no = 14; | ||
313 | force_sig(SIGBUS, tsk); | ||
314 | |||
315 | /* Kernel mode? Handle exceptions or die */ | ||
316 | if (!user_mode(regs)) | ||
317 | goto no_context; | ||
318 | } | ||
319 | |||
31 | void local_flush_tlb_one(unsigned long asid, unsigned long page) | 320 | void local_flush_tlb_one(unsigned long asid, unsigned long page) |
32 | { | 321 | { |
33 | unsigned long long match, pteh=0, lpage; | 322 | unsigned long long match, pteh=0, lpage; |
@@ -170,3 +459,7 @@ void __flush_tlb_global(void) | |||
170 | { | 459 | { |
171 | flush_tlb_all(); | 460 | flush_tlb_all(); |
172 | } | 461 | } |
462 | |||
463 | void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) | ||
464 | { | ||
465 | } | ||