diff options
Diffstat (limited to 'arch/sh/mm')
-rw-r--r-- | arch/sh/mm/Kconfig | 20 | ||||
-rw-r--r-- | arch/sh/mm/cache-debugfs.c | 2 | ||||
-rw-r--r-- | arch/sh/mm/cache-sh4.c | 67 | ||||
-rw-r--r-- | arch/sh/mm/consistent.c | 128 | ||||
-rw-r--r-- | arch/sh/mm/fault_32.c | 12 | ||||
-rw-r--r-- | arch/sh/mm/pg-sh4.c | 2 | ||||
-rw-r--r-- | arch/sh/mm/pg-sh7705.c | 2 | ||||
-rw-r--r-- | arch/sh/mm/pmb.c | 2 |
8 files changed, 98 insertions, 137 deletions
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 5fd218430b19..56d0a7daa34b 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig | |||
@@ -145,25 +145,39 @@ choice | |||
145 | 145 | ||
146 | config PAGE_SIZE_4KB | 146 | config PAGE_SIZE_4KB |
147 | bool "4kB" | 147 | bool "4kB" |
148 | depends on !X2TLB | 148 | depends on !MMU || !X2TLB |
149 | help | 149 | help |
150 | This is the default page size used by all SuperH CPUs. | 150 | This is the default page size used by all SuperH CPUs. |
151 | 151 | ||
152 | config PAGE_SIZE_8KB | 152 | config PAGE_SIZE_8KB |
153 | bool "8kB" | 153 | bool "8kB" |
154 | depends on X2TLB | 154 | depends on !MMU || X2TLB |
155 | help | 155 | help |
156 | This enables 8kB pages as supported by SH-X2 and later MMUs. | 156 | This enables 8kB pages as supported by SH-X2 and later MMUs. |
157 | 157 | ||
158 | config PAGE_SIZE_16KB | ||
159 | bool "16kB" | ||
160 | depends on !MMU | ||
161 | help | ||
162 | This enables 16kB pages on MMU-less SH systems. | ||
163 | |||
158 | config PAGE_SIZE_64KB | 164 | config PAGE_SIZE_64KB |
159 | bool "64kB" | 165 | bool "64kB" |
160 | depends on CPU_SH4 || CPU_SH5 | 166 | depends on !MMU || CPU_SH4 || CPU_SH5 |
161 | help | 167 | help |
162 | This enables support for 64kB pages, possible on all SH-4 | 168 | This enables support for 64kB pages, possible on all SH-4 |
163 | CPUs and later. | 169 | CPUs and later. |
164 | 170 | ||
165 | endchoice | 171 | endchoice |
166 | 172 | ||
173 | config ENTRY_OFFSET | ||
174 | hex | ||
175 | default "0x00001000" if PAGE_SIZE_4KB | ||
176 | default "0x00002000" if PAGE_SIZE_8KB | ||
177 | default "0x00004000" if PAGE_SIZE_16KB | ||
178 | default "0x00010000" if PAGE_SIZE_64KB | ||
179 | default "0x00000000" | ||
180 | |||
167 | choice | 181 | choice |
168 | prompt "HugeTLB page size" | 182 | prompt "HugeTLB page size" |
169 | depends on HUGETLB_PAGE && (CPU_SH4 || CPU_SH5) && MMU | 183 | depends on HUGETLB_PAGE && (CPU_SH4 || CPU_SH5) && MMU |
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c index c5b56d52b7d2..0e189ccd4a77 100644 --- a/arch/sh/mm/cache-debugfs.c +++ b/arch/sh/mm/cache-debugfs.c | |||
@@ -120,7 +120,7 @@ static const struct file_operations cache_debugfs_fops = { | |||
120 | .open = cache_debugfs_open, | 120 | .open = cache_debugfs_open, |
121 | .read = seq_read, | 121 | .read = seq_read, |
122 | .llseek = seq_lseek, | 122 | .llseek = seq_lseek, |
123 | .release = seq_release, | 123 | .release = single_release, |
124 | }; | 124 | }; |
125 | 125 | ||
126 | static int __init cache_debugfs_init(void) | 126 | static int __init cache_debugfs_init(void) |
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index 43d7ff6b6ec7..1fdc8d90254a 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | 4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka |
5 | * Copyright (C) 2001 - 2007 Paul Mundt | 5 | * Copyright (C) 2001 - 2007 Paul Mundt |
6 | * Copyright (C) 2003 Richard Curnow | 6 | * Copyright (C) 2003 Richard Curnow |
7 | * Copyright (c) 2007 STMicroelectronics (R&D) Ltd. | ||
7 | * | 8 | * |
8 | * This file is subject to the terms and conditions of the GNU General Public | 9 | * 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 | 10 | * License. See the file "COPYING" in the main directory of this archive |
@@ -22,6 +23,7 @@ | |||
22 | * entirety. | 23 | * entirety. |
23 | */ | 24 | */ |
24 | #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ | 25 | #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ |
26 | #define MAX_ICACHE_PAGES 32 | ||
25 | 27 | ||
26 | static void __flush_dcache_segment_1way(unsigned long start, | 28 | static void __flush_dcache_segment_1way(unsigned long start, |
27 | unsigned long extent); | 29 | unsigned long extent); |
@@ -178,42 +180,45 @@ void __flush_invalidate_region(void *start, int size) | |||
178 | /* | 180 | /* |
179 | * Write back the range of D-cache, and purge the I-cache. | 181 | * Write back the range of D-cache, and purge the I-cache. |
180 | * | 182 | * |
181 | * Called from kernel/module.c:sys_init_module and routine for a.out format. | 183 | * Called from kernel/module.c:sys_init_module and routine for a.out format, |
184 | * signal handler code and kprobes code | ||
182 | */ | 185 | */ |
183 | void flush_icache_range(unsigned long start, unsigned long end) | 186 | void flush_icache_range(unsigned long start, unsigned long end) |
184 | { | 187 | { |
185 | flush_cache_all(); | 188 | int icacheaddr; |
186 | } | 189 | unsigned long flags, v; |
187 | |||
188 | /* | ||
189 | * Write back the D-cache and purge the I-cache for signal trampoline. | ||
190 | * .. which happens to be the same behavior as flush_icache_range(). | ||
191 | * So, we simply flush out a line. | ||
192 | */ | ||
193 | void __uses_jump_to_uncached flush_cache_sigtramp(unsigned long addr) | ||
194 | { | ||
195 | unsigned long v, index; | ||
196 | unsigned long flags; | ||
197 | int i; | 190 | int i; |
198 | 191 | ||
199 | v = addr & ~(L1_CACHE_BYTES-1); | 192 | /* If there are too many pages then just blow the caches */ |
200 | asm volatile("ocbwb %0" | 193 | if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { |
201 | : /* no output */ | 194 | flush_cache_all(); |
202 | : "m" (__m(v))); | 195 | } else { |
203 | 196 | /* selectively flush d-cache then invalidate the i-cache */ | |
204 | index = CACHE_IC_ADDRESS_ARRAY | | 197 | /* this is inefficient, so only use for small ranges */ |
205 | (v & boot_cpu_data.icache.entry_mask); | 198 | start &= ~(L1_CACHE_BYTES-1); |
206 | 199 | end += L1_CACHE_BYTES-1; | |
207 | local_irq_save(flags); | 200 | end &= ~(L1_CACHE_BYTES-1); |
208 | jump_to_uncached(); | 201 | |
209 | 202 | local_irq_save(flags); | |
210 | for (i = 0; i < boot_cpu_data.icache.ways; | 203 | jump_to_uncached(); |
211 | i++, index += boot_cpu_data.icache.way_incr) | 204 | |
212 | ctrl_outl(0, index); /* Clear out Valid-bit */ | 205 | for (v = start; v < end; v+=L1_CACHE_BYTES) { |
213 | 206 | asm volatile("ocbwb %0" | |
214 | back_to_cached(); | 207 | : /* no output */ |
215 | wmb(); | 208 | : "m" (__m(v))); |
216 | local_irq_restore(flags); | 209 | |
210 | icacheaddr = CACHE_IC_ADDRESS_ARRAY | ( | ||
211 | v & cpu_data->icache.entry_mask); | ||
212 | |||
213 | for (i = 0; i < cpu_data->icache.ways; | ||
214 | i++, icacheaddr += cpu_data->icache.way_incr) | ||
215 | /* Clear i-cache line valid-bit */ | ||
216 | ctrl_outl(0, icacheaddr); | ||
217 | } | ||
218 | |||
219 | back_to_cached(); | ||
220 | local_irq_restore(flags); | ||
221 | } | ||
217 | } | 222 | } |
218 | 223 | ||
219 | static inline void flush_cache_4096(unsigned long start, | 224 | static inline void flush_cache_4096(unsigned long start, |
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index d3c33fc5b1c2..b2ce014401b5 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c | |||
@@ -10,6 +10,7 @@ | |||
10 | * for more details. | 10 | * for more details. |
11 | */ | 11 | */ |
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/platform_device.h> | ||
13 | #include <linux/dma-mapping.h> | 14 | #include <linux/dma-mapping.h> |
14 | #include <asm/cacheflush.h> | 15 | #include <asm/cacheflush.h> |
15 | #include <asm/addrspace.h> | 16 | #include <asm/addrspace.h> |
@@ -27,21 +28,10 @@ void *dma_alloc_coherent(struct device *dev, size_t size, | |||
27 | dma_addr_t *dma_handle, gfp_t gfp) | 28 | dma_addr_t *dma_handle, gfp_t gfp) |
28 | { | 29 | { |
29 | void *ret, *ret_nocache; | 30 | void *ret, *ret_nocache; |
30 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | ||
31 | int order = get_order(size); | 31 | int order = get_order(size); |
32 | 32 | ||
33 | if (mem) { | 33 | if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) |
34 | int page = bitmap_find_free_region(mem->bitmap, mem->size, | 34 | return ret; |
35 | order); | ||
36 | if (page >= 0) { | ||
37 | *dma_handle = mem->device_base + (page << PAGE_SHIFT); | ||
38 | ret = mem->virt_base + (page << PAGE_SHIFT); | ||
39 | memset(ret, 0, size); | ||
40 | return ret; | ||
41 | } | ||
42 | if (mem->flags & DMA_MEMORY_EXCLUSIVE) | ||
43 | return NULL; | ||
44 | } | ||
45 | 35 | ||
46 | ret = (void *)__get_free_pages(gfp, order); | 36 | ret = (void *)__get_free_pages(gfp, order); |
47 | if (!ret) | 37 | if (!ret) |
@@ -71,11 +61,7 @@ void dma_free_coherent(struct device *dev, size_t size, | |||
71 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; | 61 | struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; |
72 | int order = get_order(size); | 62 | int order = get_order(size); |
73 | 63 | ||
74 | if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { | 64 | if (!dma_release_from_coherent(dev, order, vaddr)) { |
75 | int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; | ||
76 | |||
77 | bitmap_release_region(mem->bitmap, page, order); | ||
78 | } else { | ||
79 | WARN_ON(irqs_disabled()); /* for portability */ | 65 | WARN_ON(irqs_disabled()); /* for portability */ |
80 | BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE); | 66 | BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE); |
81 | free_pages((unsigned long)phys_to_virt(dma_handle), order); | 67 | free_pages((unsigned long)phys_to_virt(dma_handle), order); |
@@ -84,83 +70,6 @@ void dma_free_coherent(struct device *dev, size_t size, | |||
84 | } | 70 | } |
85 | EXPORT_SYMBOL(dma_free_coherent); | 71 | EXPORT_SYMBOL(dma_free_coherent); |
86 | 72 | ||
87 | int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | ||
88 | dma_addr_t device_addr, size_t size, int flags) | ||
89 | { | ||
90 | void __iomem *mem_base = NULL; | ||
91 | int pages = size >> PAGE_SHIFT; | ||
92 | int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); | ||
93 | |||
94 | if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0) | ||
95 | goto out; | ||
96 | if (!size) | ||
97 | goto out; | ||
98 | if (dev->dma_mem) | ||
99 | goto out; | ||
100 | |||
101 | /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ | ||
102 | |||
103 | mem_base = ioremap_nocache(bus_addr, size); | ||
104 | if (!mem_base) | ||
105 | goto out; | ||
106 | |||
107 | dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); | ||
108 | if (!dev->dma_mem) | ||
109 | goto out; | ||
110 | dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); | ||
111 | if (!dev->dma_mem->bitmap) | ||
112 | goto free1_out; | ||
113 | |||
114 | dev->dma_mem->virt_base = mem_base; | ||
115 | dev->dma_mem->device_base = device_addr; | ||
116 | dev->dma_mem->size = pages; | ||
117 | dev->dma_mem->flags = flags; | ||
118 | |||
119 | if (flags & DMA_MEMORY_MAP) | ||
120 | return DMA_MEMORY_MAP; | ||
121 | |||
122 | return DMA_MEMORY_IO; | ||
123 | |||
124 | free1_out: | ||
125 | kfree(dev->dma_mem); | ||
126 | out: | ||
127 | if (mem_base) | ||
128 | iounmap(mem_base); | ||
129 | return 0; | ||
130 | } | ||
131 | EXPORT_SYMBOL(dma_declare_coherent_memory); | ||
132 | |||
133 | void dma_release_declared_memory(struct device *dev) | ||
134 | { | ||
135 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
136 | |||
137 | if (!mem) | ||
138 | return; | ||
139 | dev->dma_mem = NULL; | ||
140 | iounmap(mem->virt_base); | ||
141 | kfree(mem->bitmap); | ||
142 | kfree(mem); | ||
143 | } | ||
144 | EXPORT_SYMBOL(dma_release_declared_memory); | ||
145 | |||
146 | void *dma_mark_declared_memory_occupied(struct device *dev, | ||
147 | dma_addr_t device_addr, size_t size) | ||
148 | { | ||
149 | struct dma_coherent_mem *mem = dev->dma_mem; | ||
150 | int pages = (size + (device_addr & ~PAGE_MASK) + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
151 | int pos, err; | ||
152 | |||
153 | if (!mem) | ||
154 | return ERR_PTR(-EINVAL); | ||
155 | |||
156 | pos = (device_addr - mem->device_base) >> PAGE_SHIFT; | ||
157 | err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages)); | ||
158 | if (err != 0) | ||
159 | return ERR_PTR(err); | ||
160 | return mem->virt_base + (pos << PAGE_SHIFT); | ||
161 | } | ||
162 | EXPORT_SYMBOL(dma_mark_declared_memory_occupied); | ||
163 | |||
164 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, | 73 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, |
165 | enum dma_data_direction direction) | 74 | enum dma_data_direction direction) |
166 | { | 75 | { |
@@ -185,3 +94,32 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size, | |||
185 | } | 94 | } |
186 | } | 95 | } |
187 | EXPORT_SYMBOL(dma_cache_sync); | 96 | EXPORT_SYMBOL(dma_cache_sync); |
97 | |||
98 | int platform_resource_setup_memory(struct platform_device *pdev, | ||
99 | char *name, unsigned long memsize) | ||
100 | { | ||
101 | struct resource *r; | ||
102 | dma_addr_t dma_handle; | ||
103 | void *buf; | ||
104 | |||
105 | r = pdev->resource + pdev->num_resources - 1; | ||
106 | if (r->flags) { | ||
107 | pr_warning("%s: unable to find empty space for resource\n", | ||
108 | name); | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | |||
112 | buf = dma_alloc_coherent(NULL, memsize, &dma_handle, GFP_KERNEL); | ||
113 | if (!buf) { | ||
114 | pr_warning("%s: unable to allocate memory\n", name); | ||
115 | return -ENOMEM; | ||
116 | } | ||
117 | |||
118 | memset(buf, 0, memsize); | ||
119 | |||
120 | r->flags = IORESOURCE_MEM; | ||
121 | r->start = dma_handle; | ||
122 | r->end = r->start + memsize - 1; | ||
123 | r->name = name; | ||
124 | return 0; | ||
125 | } | ||
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index d1fa27594c6e..0c776fdfbdda 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c | |||
@@ -37,16 +37,12 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, | |||
37 | int fault; | 37 | int fault; |
38 | siginfo_t info; | 38 | siginfo_t info; |
39 | 39 | ||
40 | trace_hardirqs_on(); | ||
41 | local_irq_enable(); | ||
42 | |||
43 | #ifdef CONFIG_SH_KGDB | 40 | #ifdef CONFIG_SH_KGDB |
44 | if (kgdb_nofault && kgdb_bus_err_hook) | 41 | if (kgdb_nofault && kgdb_bus_err_hook) |
45 | kgdb_bus_err_hook(); | 42 | kgdb_bus_err_hook(); |
46 | #endif | 43 | #endif |
47 | 44 | ||
48 | tsk = current; | 45 | tsk = current; |
49 | mm = tsk->mm; | ||
50 | si_code = SEGV_MAPERR; | 46 | si_code = SEGV_MAPERR; |
51 | 47 | ||
52 | if (unlikely(address >= TASK_SIZE)) { | 48 | if (unlikely(address >= TASK_SIZE)) { |
@@ -88,6 +84,14 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, | |||
88 | return; | 84 | return; |
89 | } | 85 | } |
90 | 86 | ||
87 | /* Only enable interrupts if they were on before the fault */ | ||
88 | if ((regs->sr & SR_IMASK) != SR_IMASK) { | ||
89 | trace_hardirqs_on(); | ||
90 | local_irq_enable(); | ||
91 | } | ||
92 | |||
93 | mm = tsk->mm; | ||
94 | |||
91 | /* | 95 | /* |
92 | * If we're in an interrupt or have no user | 96 | * If we're in an interrupt or have no user |
93 | * context, we must not take the fault.. | 97 | * context, we must not take the fault.. |
diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c index 8c7a9ca79879..38870e0fc182 100644 --- a/arch/sh/mm/pg-sh4.c +++ b/arch/sh/mm/pg-sh4.c | |||
@@ -111,7 +111,7 @@ EXPORT_SYMBOL(copy_user_highpage); | |||
111 | /* | 111 | /* |
112 | * For SH-4, we have our own implementation for ptep_get_and_clear | 112 | * For SH-4, we have our own implementation for ptep_get_and_clear |
113 | */ | 113 | */ |
114 | inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 114 | pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
115 | { | 115 | { |
116 | pte_t pte = *ptep; | 116 | pte_t pte = *ptep; |
117 | 117 | ||
diff --git a/arch/sh/mm/pg-sh7705.c b/arch/sh/mm/pg-sh7705.c index 7f885b7f8aff..eaf25147194c 100644 --- a/arch/sh/mm/pg-sh7705.c +++ b/arch/sh/mm/pg-sh7705.c | |||
@@ -118,7 +118,7 @@ void copy_user_page(void *to, void *from, unsigned long address, struct page *pg | |||
118 | * For SH7705, we have our own implementation for ptep_get_and_clear | 118 | * For SH7705, we have our own implementation for ptep_get_and_clear |
119 | * Copied from pg-sh4.c | 119 | * Copied from pg-sh4.c |
120 | */ | 120 | */ |
121 | inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | 121 | pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) |
122 | { | 122 | { |
123 | pte_t pte = *ptep; | 123 | pte_t pte = *ptep; |
124 | 124 | ||
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 46911bcbf17b..cef727669c87 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c | |||
@@ -385,7 +385,7 @@ static const struct file_operations pmb_debugfs_fops = { | |||
385 | .open = pmb_debugfs_open, | 385 | .open = pmb_debugfs_open, |
386 | .read = seq_read, | 386 | .read = seq_read, |
387 | .llseek = seq_lseek, | 387 | .llseek = seq_lseek, |
388 | .release = seq_release, | 388 | .release = single_release, |
389 | }; | 389 | }; |
390 | 390 | ||
391 | static int __init pmb_debugfs_init(void) | 391 | static int __init pmb_debugfs_init(void) |