diff options
Diffstat (limited to 'arch/sh/mm')
-rw-r--r-- | arch/sh/mm/Kconfig | 87 | ||||
-rw-r--r-- | arch/sh/mm/Makefile | 5 | ||||
-rw-r--r-- | arch/sh/mm/fault.c | 45 | ||||
-rw-r--r-- | arch/sh/mm/init.c | 107 | ||||
-rw-r--r-- | arch/sh/mm/numa.c | 92 | ||||
-rw-r--r-- | arch/sh/mm/pg-dma.c | 95 |
6 files changed, 248 insertions, 183 deletions
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 253346d7b316..28d79a474cde 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig | |||
@@ -1,5 +1,3 @@ | |||
1 | menu "Processor selection" | ||
2 | |||
3 | # | 1 | # |
4 | # Processor families | 2 | # Processor families |
5 | # | 3 | # |
@@ -38,27 +36,31 @@ config CPU_SUBTYPE_ST40 | |||
38 | config CPU_SHX2 | 36 | config CPU_SHX2 |
39 | bool | 37 | bool |
40 | 38 | ||
39 | config CPU_SHX3 | ||
40 | bool | ||
41 | |||
42 | choice | ||
43 | prompt "Processor sub-type selection" | ||
44 | |||
41 | # | 45 | # |
42 | # Processor subtypes | 46 | # Processor subtypes |
43 | # | 47 | # |
44 | 48 | ||
45 | comment "SH-2 Processor Support" | 49 | # SH-2 Processor Support |
46 | |||
47 | config CPU_SUBTYPE_SH7604 | ||
48 | bool "Support SH7604 processor" | ||
49 | select CPU_SH2 | ||
50 | 50 | ||
51 | config CPU_SUBTYPE_SH7619 | 51 | config CPU_SUBTYPE_SH7619 |
52 | bool "Support SH7619 processor" | 52 | bool "Support SH7619 processor" |
53 | select CPU_SH2 | 53 | select CPU_SH2 |
54 | select CPU_HAS_IPR_IRQ | ||
54 | 55 | ||
55 | comment "SH-2A Processor Support" | 56 | # SH-2A Processor Support |
56 | 57 | ||
57 | config CPU_SUBTYPE_SH7206 | 58 | config CPU_SUBTYPE_SH7206 |
58 | bool "Support SH7206 processor" | 59 | bool "Support SH7206 processor" |
59 | select CPU_SH2A | 60 | select CPU_SH2A |
61 | select CPU_HAS_IPR_IRQ | ||
60 | 62 | ||
61 | comment "SH-3 Processor Support" | 63 | # SH-3 Processor Support |
62 | 64 | ||
63 | config CPU_SUBTYPE_SH7300 | 65 | config CPU_SUBTYPE_SH7300 |
64 | bool "Support SH7300 processor" | 66 | bool "Support SH7300 processor" |
@@ -113,7 +115,7 @@ config CPU_SUBTYPE_SH7712 | |||
113 | help | 115 | help |
114 | Select SH7712 if you have a SH3-DSP SH7712 CPU. | 116 | Select SH7712 if you have a SH3-DSP SH7712 CPU. |
115 | 117 | ||
116 | comment "SH-4 Processor Support" | 118 | # SH-4 Processor Support |
117 | 119 | ||
118 | config CPU_SUBTYPE_SH7750 | 120 | config CPU_SUBTYPE_SH7750 |
119 | bool "Support SH7750 processor" | 121 | bool "Support SH7750 processor" |
@@ -125,7 +127,7 @@ config CPU_SUBTYPE_SH7750 | |||
125 | config CPU_SUBTYPE_SH7091 | 127 | config CPU_SUBTYPE_SH7091 |
126 | bool "Support SH7091 processor" | 128 | bool "Support SH7091 processor" |
127 | select CPU_SH4 | 129 | select CPU_SH4 |
128 | select CPU_SUBTYPE_SH7750 | 130 | select CPU_HAS_IPR_IRQ |
129 | help | 131 | help |
130 | Select SH7091 if you have an SH-4 based Sega device (such as | 132 | Select SH7091 if you have an SH-4 based Sega device (such as |
131 | the Dreamcast, Naomi, and Naomi 2). | 133 | the Dreamcast, Naomi, and Naomi 2). |
@@ -133,13 +135,11 @@ config CPU_SUBTYPE_SH7091 | |||
133 | config CPU_SUBTYPE_SH7750R | 135 | config CPU_SUBTYPE_SH7750R |
134 | bool "Support SH7750R processor" | 136 | bool "Support SH7750R processor" |
135 | select CPU_SH4 | 137 | select CPU_SH4 |
136 | select CPU_SUBTYPE_SH7750 | ||
137 | select CPU_HAS_IPR_IRQ | 138 | select CPU_HAS_IPR_IRQ |
138 | 139 | ||
139 | config CPU_SUBTYPE_SH7750S | 140 | config CPU_SUBTYPE_SH7750S |
140 | bool "Support SH7750S processor" | 141 | bool "Support SH7750S processor" |
141 | select CPU_SH4 | 142 | select CPU_SH4 |
142 | select CPU_SUBTYPE_SH7750 | ||
143 | select CPU_HAS_IPR_IRQ | 143 | select CPU_HAS_IPR_IRQ |
144 | 144 | ||
145 | config CPU_SUBTYPE_SH7751 | 145 | config CPU_SUBTYPE_SH7751 |
@@ -153,7 +153,6 @@ config CPU_SUBTYPE_SH7751 | |||
153 | config CPU_SUBTYPE_SH7751R | 153 | config CPU_SUBTYPE_SH7751R |
154 | bool "Support SH7751R processor" | 154 | bool "Support SH7751R processor" |
155 | select CPU_SH4 | 155 | select CPU_SH4 |
156 | select CPU_SUBTYPE_SH7751 | ||
157 | select CPU_HAS_IPR_IRQ | 156 | select CPU_HAS_IPR_IRQ |
158 | 157 | ||
159 | config CPU_SUBTYPE_SH7760 | 158 | config CPU_SUBTYPE_SH7760 |
@@ -166,7 +165,7 @@ config CPU_SUBTYPE_SH4_202 | |||
166 | bool "Support SH4-202 processor" | 165 | bool "Support SH4-202 processor" |
167 | select CPU_SH4 | 166 | select CPU_SH4 |
168 | 167 | ||
169 | comment "ST40 Processor Support" | 168 | # ST40 Processor Support |
170 | 169 | ||
171 | config CPU_SUBTYPE_ST40STB1 | 170 | config CPU_SUBTYPE_ST40STB1 |
172 | bool "Support ST40STB1/ST40RA processors" | 171 | bool "Support ST40STB1/ST40RA processors" |
@@ -181,7 +180,7 @@ config CPU_SUBTYPE_ST40GX1 | |||
181 | help | 180 | help |
182 | Select ST40GX1 if you have a ST40GX1 CPU. | 181 | Select ST40GX1 if you have a ST40GX1 CPU. |
183 | 182 | ||
184 | comment "SH-4A Processor Support" | 183 | # SH-4A Processor Support |
185 | 184 | ||
186 | config CPU_SUBTYPE_SH7770 | 185 | config CPU_SUBTYPE_SH7770 |
187 | bool "Support SH7770 processor" | 186 | bool "Support SH7770 processor" |
@@ -198,7 +197,13 @@ config CPU_SUBTYPE_SH7785 | |||
198 | select CPU_SHX2 | 197 | select CPU_SHX2 |
199 | select CPU_HAS_INTC2_IRQ | 198 | select CPU_HAS_INTC2_IRQ |
200 | 199 | ||
201 | comment "SH4AL-DSP Processor Support" | 200 | config CPU_SUBTYPE_SHX3 |
201 | bool "Support SH-X3 processor" | ||
202 | select CPU_SH4A | ||
203 | select CPU_SHX3 | ||
204 | select CPU_HAS_INTC2_IRQ | ||
205 | |||
206 | # SH4AL-DSP Processor Support | ||
202 | 207 | ||
203 | config CPU_SUBTYPE_SH73180 | 208 | config CPU_SUBTYPE_SH73180 |
204 | bool "Support SH73180 processor" | 209 | bool "Support SH73180 processor" |
@@ -213,8 +218,10 @@ config CPU_SUBTYPE_SH7722 | |||
213 | select CPU_SH4AL_DSP | 218 | select CPU_SH4AL_DSP |
214 | select CPU_SHX2 | 219 | select CPU_SHX2 |
215 | select CPU_HAS_IPR_IRQ | 220 | select CPU_HAS_IPR_IRQ |
221 | select ARCH_SPARSEMEM_ENABLE | ||
222 | select SYS_SUPPORTS_NUMA | ||
216 | 223 | ||
217 | endmenu | 224 | endchoice |
218 | 225 | ||
219 | menu "Memory management options" | 226 | menu "Memory management options" |
220 | 227 | ||
@@ -266,7 +273,7 @@ config MEMORY_SIZE | |||
266 | 273 | ||
267 | config 32BIT | 274 | config 32BIT |
268 | bool "Support 32-bit physical addressing through PMB" | 275 | bool "Support 32-bit physical addressing through PMB" |
269 | depends on CPU_SH4A && MMU && (!X2TLB || BROKEN) | 276 | depends on MMU && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785) |
270 | default y | 277 | default y |
271 | help | 278 | help |
272 | If you say Y here, physical addressing will be extended to | 279 | If you say Y here, physical addressing will be extended to |
@@ -295,6 +302,17 @@ config VSYSCALL | |||
295 | For systems with an MMU that can afford to give up a page, | 302 | For systems with an MMU that can afford to give up a page, |
296 | (the default value) say Y. | 303 | (the default value) say Y. |
297 | 304 | ||
305 | config NUMA | ||
306 | bool "Non Uniform Memory Access (NUMA) Support" | ||
307 | depends on MMU && SYS_SUPPORTS_NUMA && EXPERIMENTAL | ||
308 | default n | ||
309 | help | ||
310 | Some SH systems have many various memories scattered around | ||
311 | the address space, each with varying latencies. This enables | ||
312 | support for these blocks by binding them to nodes and allowing | ||
313 | memory policies to be used for prioritizing and controlling | ||
314 | allocation behaviour. | ||
315 | |||
298 | config NODES_SHIFT | 316 | config NODES_SHIFT |
299 | int | 317 | int |
300 | default "1" | 318 | default "1" |
@@ -302,14 +320,34 @@ config NODES_SHIFT | |||
302 | 320 | ||
303 | config ARCH_FLATMEM_ENABLE | 321 | config ARCH_FLATMEM_ENABLE |
304 | def_bool y | 322 | def_bool y |
323 | depends on !NUMA | ||
324 | |||
325 | config ARCH_SPARSEMEM_ENABLE | ||
326 | def_bool y | ||
327 | select SPARSEMEM_STATIC | ||
328 | |||
329 | config ARCH_SPARSEMEM_DEFAULT | ||
330 | def_bool y | ||
305 | 331 | ||
306 | config MAX_ACTIVE_REGIONS | 332 | config MAX_ACTIVE_REGIONS |
307 | int | 333 | int |
334 | default "2" if (CPU_SUBTYPE_SH7722 && SPARSEMEM) | ||
308 | default "1" | 335 | default "1" |
309 | 336 | ||
310 | config ARCH_POPULATES_NODE_MAP | 337 | config ARCH_POPULATES_NODE_MAP |
311 | def_bool y | 338 | def_bool y |
312 | 339 | ||
340 | config ARCH_SELECT_MEMORY_MODEL | ||
341 | def_bool y | ||
342 | |||
343 | config ARCH_ENABLE_MEMORY_HOTPLUG | ||
344 | def_bool y | ||
345 | depends on SPARSEMEM | ||
346 | |||
347 | config ARCH_MEMORY_PROBE | ||
348 | def_bool y | ||
349 | depends on MEMORY_HOTPLUG | ||
350 | |||
313 | choice | 351 | choice |
314 | prompt "Kernel page size" | 352 | prompt "Kernel page size" |
315 | default PAGE_SIZE_4KB | 353 | default PAGE_SIZE_4KB |
@@ -394,15 +432,4 @@ config SH_WRITETHROUGH | |||
394 | 432 | ||
395 | If unsure, say N. | 433 | If unsure, say N. |
396 | 434 | ||
397 | config SH_OCRAM | ||
398 | bool "Operand Cache RAM (OCRAM) support" | ||
399 | help | ||
400 | Selecting this option will automatically tear down the number of | ||
401 | sets in the dcache by half, which in turn exposes a memory range. | ||
402 | |||
403 | The addresses for the OC RAM base will vary according to the | ||
404 | processor version. Consult vendor documentation for specifics. | ||
405 | |||
406 | If unsure, say N. | ||
407 | |||
408 | endmenu | 435 | endmenu |
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 3ffd7f68c0a2..d677d7f3afc1 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile | |||
@@ -8,9 +8,6 @@ obj-$(CONFIG_CPU_SH2) += cache-sh2.o | |||
8 | obj-$(CONFIG_CPU_SH3) += cache-sh3.o | 8 | obj-$(CONFIG_CPU_SH3) += cache-sh3.o |
9 | obj-$(CONFIG_CPU_SH4) += cache-sh4.o | 9 | obj-$(CONFIG_CPU_SH4) += cache-sh4.o |
10 | 10 | ||
11 | obj-$(CONFIG_DMA_PAGE_OPS) += pg-dma.o | ||
12 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | ||
13 | |||
14 | mmu-y := fault-nommu.o tlb-nommu.o pg-nommu.o | 11 | mmu-y := fault-nommu.o tlb-nommu.o pg-nommu.o |
15 | mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \ | 12 | mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \ |
16 | ioremap.o | 13 | ioremap.o |
@@ -27,5 +24,7 @@ obj-$(CONFIG_CPU_SH4) += tlb-sh4.o pg-sh4.o | |||
27 | obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o | 24 | obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o |
28 | endif | 25 | endif |
29 | 26 | ||
27 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | ||
30 | obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o | 28 | obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o |
31 | obj-$(CONFIG_32BIT) += pmb.o | 29 | obj-$(CONFIG_32BIT) += pmb.o |
30 | obj-$(CONFIG_NUMA) += numa.o | ||
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index c878faa4ae46..0b3eaf6fbb28 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c | |||
@@ -32,7 +32,6 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, | |||
32 | struct task_struct *tsk; | 32 | struct task_struct *tsk; |
33 | struct mm_struct *mm; | 33 | struct mm_struct *mm; |
34 | struct vm_area_struct * vma; | 34 | struct vm_area_struct * vma; |
35 | unsigned long page; | ||
36 | int si_code; | 35 | int si_code; |
37 | siginfo_t info; | 36 | siginfo_t info; |
38 | 37 | ||
@@ -170,24 +169,38 @@ no_context: | |||
170 | * terminate things with extreme prejudice. | 169 | * terminate things with extreme prejudice. |
171 | * | 170 | * |
172 | */ | 171 | */ |
173 | if (address < PAGE_SIZE) | 172 | |
174 | printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); | 173 | bust_spinlocks(1); |
175 | else | 174 | |
176 | printk(KERN_ALERT "Unable to handle kernel paging request"); | 175 | if (oops_may_print()) { |
177 | printk(" at virtual address %08lx\n", address); | 176 | __typeof__(pte_val(__pte(0))) page; |
178 | printk(KERN_ALERT "pc = %08lx\n", regs->pc); | 177 | |
179 | page = (unsigned long)get_TTB(); | 178 | if (address < PAGE_SIZE) |
180 | if (page) { | 179 | printk(KERN_ALERT "Unable to handle kernel NULL " |
181 | page = ((unsigned long *) page)[address >> PGDIR_SHIFT]; | 180 | "pointer dereference"); |
182 | printk(KERN_ALERT "*pde = %08lx\n", page); | 181 | else |
183 | if (page & _PAGE_PRESENT) { | 182 | printk(KERN_ALERT "Unable to handle kernel paging " |
184 | page &= PAGE_MASK; | 183 | "request"); |
185 | address &= 0x003ff000; | 184 | printk(" at virtual address %08lx\n", address); |
186 | page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; | 185 | printk(KERN_ALERT "pc = %08lx\n", regs->pc); |
187 | printk(KERN_ALERT "*pte = %08lx\n", page); | 186 | page = (unsigned long)get_TTB(); |
187 | if (page) { | ||
188 | page = ((__typeof__(page) *) __va(page))[address >> | ||
189 | PGDIR_SHIFT]; | ||
190 | printk(KERN_ALERT "*pde = %08lx\n", page); | ||
191 | if (page & _PAGE_PRESENT) { | ||
192 | page &= PAGE_MASK; | ||
193 | address &= 0x003ff000; | ||
194 | page = ((__typeof__(page) *) | ||
195 | __va(page))[address >> | ||
196 | PAGE_SHIFT]; | ||
197 | printk(KERN_ALERT "*pte = %08lx\n", page); | ||
198 | } | ||
188 | } | 199 | } |
189 | } | 200 | } |
201 | |||
190 | die("Oops", regs, writeaccess); | 202 | die("Oops", regs, writeaccess); |
203 | bust_spinlocks(0); | ||
191 | do_exit(SIGKILL); | 204 | do_exit(SIGKILL); |
192 | 205 | ||
193 | /* | 206 | /* |
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index e0e644ff3204..82b68c789a5f 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/mmu_context.h> | 18 | #include <asm/mmu_context.h> |
19 | #include <asm/tlb.h> | 19 | #include <asm/tlb.h> |
20 | #include <asm/cacheflush.h> | 20 | #include <asm/cacheflush.h> |
21 | #include <asm/sections.h> | ||
21 | #include <asm/cache.h> | 22 | #include <asm/cache.h> |
22 | 23 | ||
23 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 24 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
@@ -36,14 +37,11 @@ void show_mem(void) | |||
36 | show_free_areas(); | 37 | show_free_areas(); |
37 | 38 | ||
38 | for_each_online_pgdat(pgdat) { | 39 | for_each_online_pgdat(pgdat) { |
39 | struct page *page, *end; | 40 | unsigned long flags, i; |
40 | unsigned long flags; | ||
41 | 41 | ||
42 | pgdat_resize_lock(pgdat, &flags); | 42 | pgdat_resize_lock(pgdat, &flags); |
43 | page = pgdat->node_mem_map; | 43 | for (i = 0; i < pgdat->node_spanned_pages; i++) { |
44 | end = page + pgdat->node_spanned_pages; | 44 | struct page *page = pgdat_page_nr(pgdat, i); |
45 | |||
46 | do { | ||
47 | total++; | 45 | total++; |
48 | if (PageReserved(page)) | 46 | if (PageReserved(page)) |
49 | reserved++; | 47 | reserved++; |
@@ -55,9 +53,7 @@ void show_mem(void) | |||
55 | free++; | 53 | free++; |
56 | else | 54 | else |
57 | shared += page_count(page) - 1; | 55 | shared += page_count(page) - 1; |
58 | page++; | 56 | } |
59 | } while (page < end); | ||
60 | |||
61 | pgdat_resize_unlock(pgdat, &flags); | 57 | pgdat_resize_unlock(pgdat, &flags); |
62 | } | 58 | } |
63 | 59 | ||
@@ -137,16 +133,12 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) | |||
137 | } | 133 | } |
138 | #endif /* CONFIG_MMU */ | 134 | #endif /* CONFIG_MMU */ |
139 | 135 | ||
140 | /* References to section boundaries */ | ||
141 | |||
142 | extern char _text, _etext, _edata, __bss_start, _end; | ||
143 | extern char __init_begin, __init_end; | ||
144 | |||
145 | /* | 136 | /* |
146 | * paging_init() sets up the page tables | 137 | * paging_init() sets up the page tables |
147 | */ | 138 | */ |
148 | void __init paging_init(void) | 139 | void __init paging_init(void) |
149 | { | 140 | { |
141 | unsigned long max_zone_pfns[MAX_NR_ZONES]; | ||
150 | int nid; | 142 | int nid; |
151 | 143 | ||
152 | /* We don't need to map the kernel through the TLB, as | 144 | /* We don't need to map the kernel through the TLB, as |
@@ -158,43 +150,39 @@ void __init paging_init(void) | |||
158 | * check for a null value. */ | 150 | * check for a null value. */ |
159 | set_TTB(swapper_pg_dir); | 151 | set_TTB(swapper_pg_dir); |
160 | 152 | ||
153 | memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); | ||
154 | |||
161 | for_each_online_node(nid) { | 155 | for_each_online_node(nid) { |
162 | pg_data_t *pgdat = NODE_DATA(nid); | 156 | pg_data_t *pgdat = NODE_DATA(nid); |
163 | unsigned long max_zone_pfns[MAX_NR_ZONES]; | ||
164 | unsigned long low, start_pfn; | 157 | unsigned long low, start_pfn; |
165 | 158 | ||
166 | memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); | ||
167 | |||
168 | start_pfn = pgdat->bdata->node_boot_start >> PAGE_SHIFT; | 159 | start_pfn = pgdat->bdata->node_boot_start >> PAGE_SHIFT; |
169 | low = pgdat->bdata->node_low_pfn; | 160 | low = pgdat->bdata->node_low_pfn; |
170 | 161 | ||
171 | max_zone_pfns[ZONE_NORMAL] = low; | 162 | if (max_zone_pfns[ZONE_NORMAL] < low) |
172 | add_active_range(nid, start_pfn, low); | 163 | max_zone_pfns[ZONE_NORMAL] = low; |
173 | 164 | ||
174 | printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n", | 165 | printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n", |
175 | nid, start_pfn, low); | 166 | nid, start_pfn, low); |
176 | |||
177 | free_area_init_nodes(max_zone_pfns); | ||
178 | |||
179 | printk("Node %u: mem_map starts at %p\n", | ||
180 | pgdat->node_id, pgdat->node_mem_map); | ||
181 | } | 167 | } |
168 | |||
169 | free_area_init_nodes(max_zone_pfns); | ||
182 | } | 170 | } |
183 | 171 | ||
184 | static struct kcore_list kcore_mem, kcore_vmalloc; | 172 | static struct kcore_list kcore_mem, kcore_vmalloc; |
185 | 173 | ||
186 | void __init mem_init(void) | 174 | void __init mem_init(void) |
187 | { | 175 | { |
188 | int codesize, reservedpages, datasize, initsize; | 176 | int codesize, datasize, initsize; |
189 | int nid; | 177 | int nid; |
190 | 178 | ||
191 | reservedpages = 0; | 179 | num_physpages = 0; |
180 | high_memory = NULL; | ||
192 | 181 | ||
193 | for_each_online_node(nid) { | 182 | for_each_online_node(nid) { |
194 | pg_data_t *pgdat = NODE_DATA(nid); | 183 | pg_data_t *pgdat = NODE_DATA(nid); |
195 | unsigned long node_pages = 0; | 184 | unsigned long node_pages = 0; |
196 | void *node_high_memory; | 185 | void *node_high_memory; |
197 | int i; | ||
198 | 186 | ||
199 | num_physpages += pgdat->node_present_pages; | 187 | num_physpages += pgdat->node_present_pages; |
200 | 188 | ||
@@ -203,13 +191,9 @@ void __init mem_init(void) | |||
203 | 191 | ||
204 | totalram_pages += node_pages; | 192 | totalram_pages += node_pages; |
205 | 193 | ||
206 | for (i = 0; i < node_pages; i++) | 194 | node_high_memory = (void *)__va((pgdat->node_start_pfn + |
207 | if (PageReserved(pgdat->node_mem_map + i)) | 195 | pgdat->node_spanned_pages) << |
208 | reservedpages++; | 196 | PAGE_SHIFT); |
209 | |||
210 | node_high_memory = (void *)((pgdat->node_start_pfn + | ||
211 | pgdat->node_spanned_pages) << | ||
212 | PAGE_SHIFT); | ||
213 | if (node_high_memory > high_memory) | 197 | if (node_high_memory > high_memory) |
214 | high_memory = node_high_memory; | 198 | high_memory = node_high_memory; |
215 | } | 199 | } |
@@ -239,11 +223,10 @@ void __init mem_init(void) | |||
239 | VMALLOC_END - VMALLOC_START); | 223 | VMALLOC_END - VMALLOC_START); |
240 | 224 | ||
241 | printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, " | 225 | printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, " |
242 | "%dk reserved, %dk data, %dk init)\n", | 226 | "%dk data, %dk init)\n", |
243 | (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), | 227 | (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), |
244 | totalram_pages << (PAGE_SHIFT-10), | 228 | num_physpages << (PAGE_SHIFT-10), |
245 | codesize >> 10, | 229 | codesize >> 10, |
246 | reservedpages << (PAGE_SHIFT-10), | ||
247 | datasize >> 10, | 230 | datasize >> 10, |
248 | initsize >> 10); | 231 | initsize >> 10); |
249 | 232 | ||
@@ -264,7 +247,9 @@ void free_initmem(void) | |||
264 | free_page(addr); | 247 | free_page(addr); |
265 | totalram_pages++; | 248 | totalram_pages++; |
266 | } | 249 | } |
267 | printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); | 250 | printk("Freeing unused kernel memory: %ldk freed\n", |
251 | ((unsigned long)&__init_end - | ||
252 | (unsigned long)&__init_begin) >> 10); | ||
268 | } | 253 | } |
269 | 254 | ||
270 | #ifdef CONFIG_BLK_DEV_INITRD | 255 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -277,6 +262,50 @@ void free_initrd_mem(unsigned long start, unsigned long end) | |||
277 | free_page(p); | 262 | free_page(p); |
278 | totalram_pages++; | 263 | totalram_pages++; |
279 | } | 264 | } |
280 | printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); | 265 | printk("Freeing initrd memory: %ldk freed\n", (end - start) >> 10); |
266 | } | ||
267 | #endif | ||
268 | |||
269 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
270 | void online_page(struct page *page) | ||
271 | { | ||
272 | ClearPageReserved(page); | ||
273 | init_page_count(page); | ||
274 | __free_page(page); | ||
275 | totalram_pages++; | ||
276 | num_physpages++; | ||
281 | } | 277 | } |
278 | |||
279 | int arch_add_memory(int nid, u64 start, u64 size) | ||
280 | { | ||
281 | pg_data_t *pgdat; | ||
282 | unsigned long start_pfn = start >> PAGE_SHIFT; | ||
283 | unsigned long nr_pages = size >> PAGE_SHIFT; | ||
284 | int ret; | ||
285 | |||
286 | pgdat = NODE_DATA(nid); | ||
287 | |||
288 | /* We only have ZONE_NORMAL, so this is easy.. */ | ||
289 | ret = __add_pages(pgdat->node_zones + ZONE_NORMAL, start_pfn, nr_pages); | ||
290 | if (unlikely(ret)) | ||
291 | printk("%s: Failed, __add_pages() == %d\n", __FUNCTION__, ret); | ||
292 | |||
293 | return ret; | ||
294 | } | ||
295 | EXPORT_SYMBOL_GPL(arch_add_memory); | ||
296 | |||
297 | int remove_memory(u64 start, u64 size) | ||
298 | { | ||
299 | return -EINVAL; | ||
300 | } | ||
301 | EXPORT_SYMBOL_GPL(remove_memory); | ||
302 | |||
303 | #ifdef CONFIG_NUMA | ||
304 | int memory_add_physaddr_to_nid(u64 addr) | ||
305 | { | ||
306 | /* Node 0 for now.. */ | ||
307 | return 0; | ||
308 | } | ||
309 | EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); | ||
310 | #endif | ||
282 | #endif | 311 | #endif |
diff --git a/arch/sh/mm/numa.c b/arch/sh/mm/numa.c new file mode 100644 index 000000000000..8aff065dd307 --- /dev/null +++ b/arch/sh/mm/numa.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * arch/sh/mm/numa.c - Multiple node support for SH machines | ||
3 | * | ||
4 | * Copyright (C) 2007 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/bootmem.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <linux/numa.h> | ||
14 | #include <linux/pfn.h> | ||
15 | #include <asm/sections.h> | ||
16 | |||
17 | static bootmem_data_t plat_node_bdata[MAX_NUMNODES]; | ||
18 | struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; | ||
19 | EXPORT_SYMBOL_GPL(node_data); | ||
20 | |||
21 | /* | ||
22 | * On SH machines the conventional approach is to stash system RAM | ||
23 | * in node 0, and other memory blocks in to node 1 and up, ordered by | ||
24 | * latency. Each node's pgdat is node-local at the beginning of the node, | ||
25 | * immediately followed by the node mem map. | ||
26 | */ | ||
27 | void __init setup_memory(void) | ||
28 | { | ||
29 | unsigned long free_pfn = PFN_UP(__pa(_end)); | ||
30 | |||
31 | /* | ||
32 | * Node 0 sets up its pgdat at the first available pfn, | ||
33 | * and bumps it up before setting up the bootmem allocator. | ||
34 | */ | ||
35 | NODE_DATA(0) = pfn_to_kaddr(free_pfn); | ||
36 | memset(NODE_DATA(0), 0, sizeof(struct pglist_data)); | ||
37 | free_pfn += PFN_UP(sizeof(struct pglist_data)); | ||
38 | NODE_DATA(0)->bdata = &plat_node_bdata[0]; | ||
39 | |||
40 | /* Set up node 0 */ | ||
41 | setup_bootmem_allocator(free_pfn); | ||
42 | |||
43 | /* Give the platforms a chance to hook up their nodes */ | ||
44 | plat_mem_setup(); | ||
45 | } | ||
46 | |||
47 | void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end) | ||
48 | { | ||
49 | unsigned long bootmap_pages, bootmap_start, bootmap_size; | ||
50 | unsigned long start_pfn, free_pfn, end_pfn; | ||
51 | |||
52 | /* Don't allow bogus node assignment */ | ||
53 | BUG_ON(nid > MAX_NUMNODES || nid == 0); | ||
54 | |||
55 | /* | ||
56 | * The free pfn starts at the beginning of the range, and is | ||
57 | * advanced as necessary for pgdat and node map allocations. | ||
58 | */ | ||
59 | free_pfn = start_pfn = start >> PAGE_SHIFT; | ||
60 | end_pfn = end >> PAGE_SHIFT; | ||
61 | |||
62 | add_active_range(nid, start_pfn, end_pfn); | ||
63 | |||
64 | /* Node-local pgdat */ | ||
65 | NODE_DATA(nid) = pfn_to_kaddr(free_pfn); | ||
66 | free_pfn += PFN_UP(sizeof(struct pglist_data)); | ||
67 | memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); | ||
68 | |||
69 | NODE_DATA(nid)->bdata = &plat_node_bdata[nid]; | ||
70 | NODE_DATA(nid)->node_start_pfn = start_pfn; | ||
71 | NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn; | ||
72 | |||
73 | /* Node-local bootmap */ | ||
74 | bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn); | ||
75 | bootmap_start = (unsigned long)pfn_to_kaddr(free_pfn); | ||
76 | bootmap_size = init_bootmem_node(NODE_DATA(nid), free_pfn, start_pfn, | ||
77 | end_pfn); | ||
78 | |||
79 | free_bootmem_with_active_regions(nid, end_pfn); | ||
80 | |||
81 | /* Reserve the pgdat and bootmap space with the bootmem allocator */ | ||
82 | reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT, | ||
83 | sizeof(struct pglist_data)); | ||
84 | reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT, | ||
85 | bootmap_pages << PAGE_SHIFT); | ||
86 | |||
87 | /* It's up */ | ||
88 | node_set_online(nid); | ||
89 | |||
90 | /* Kick sparsemem */ | ||
91 | sparse_memory_present_with_active_regions(nid); | ||
92 | } | ||
diff --git a/arch/sh/mm/pg-dma.c b/arch/sh/mm/pg-dma.c deleted file mode 100644 index bb23679369d6..000000000000 --- a/arch/sh/mm/pg-dma.c +++ /dev/null | |||
@@ -1,95 +0,0 @@ | |||
1 | /* | ||
2 | * arch/sh/mm/pg-dma.c | ||
3 | * | ||
4 | * Fast clear_page()/copy_page() implementation using the SH DMAC | ||
5 | * | ||
6 | * Copyright (C) 2003 Paul Mundt | ||
7 | * | ||
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 | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <asm/semaphore.h> | ||
16 | #include <asm/mmu_context.h> | ||
17 | #include <asm/addrspace.h> | ||
18 | #include <asm/atomic.h> | ||
19 | #include <asm/page.h> | ||
20 | #include <asm/dma.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | /* Channel to use for page ops, must be dual-address mode capable. */ | ||
24 | static int dma_channel = CONFIG_DMA_PAGE_OPS_CHANNEL; | ||
25 | |||
26 | static void copy_page_dma(void *to, void *from) | ||
27 | { | ||
28 | /* | ||
29 | * This doesn't seem to get triggered until further along in the | ||
30 | * boot process, at which point the DMAC is already initialized. | ||
31 | * Fix this in the same fashion as clear_page_dma() in the event | ||
32 | * that this crashes due to the DMAC not being initialized. | ||
33 | */ | ||
34 | |||
35 | flush_icache_range((unsigned long)from, PAGE_SIZE); | ||
36 | dma_write_page(dma_channel, (unsigned long)from, (unsigned long)to); | ||
37 | dma_wait_for_completion(dma_channel); | ||
38 | } | ||
39 | |||
40 | static void clear_page_dma(void *to) | ||
41 | { | ||
42 | /* | ||
43 | * We get invoked quite early on, if the DMAC hasn't been initialized | ||
44 | * yet, fall back on the slow manual implementation. | ||
45 | */ | ||
46 | if (dma_info[dma_channel].chan != dma_channel) { | ||
47 | clear_page_slow(to); | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | dma_write_page(dma_channel, (unsigned long)empty_zero_page, | ||
52 | (unsigned long)to); | ||
53 | |||
54 | /* | ||
55 | * FIXME: Something is a bit racy here, if we poll the counter right | ||
56 | * away, we seem to lock. flushing the page from the dcache doesn't | ||
57 | * seem to make a difference one way or the other, though either a full | ||
58 | * icache or dcache flush does. | ||
59 | * | ||
60 | * The location of this is important as well, and must happen prior to | ||
61 | * the completion loop but after the transfer was initiated. | ||
62 | * | ||
63 | * Oddly enough, this doesn't appear to be an issue for copy_page().. | ||
64 | */ | ||
65 | flush_icache_range((unsigned long)to, PAGE_SIZE); | ||
66 | |||
67 | dma_wait_for_completion(dma_channel); | ||
68 | } | ||
69 | |||
70 | static int __init pg_dma_init(void) | ||
71 | { | ||
72 | int ret; | ||
73 | |||
74 | ret = request_dma(dma_channel, "page ops"); | ||
75 | if (ret != 0) | ||
76 | return ret; | ||
77 | |||
78 | copy_page = copy_page_dma; | ||
79 | clear_page = clear_page_dma; | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | static void __exit pg_dma_exit(void) | ||
85 | { | ||
86 | free_dma(dma_channel); | ||
87 | } | ||
88 | |||
89 | module_init(pg_dma_init); | ||
90 | module_exit(pg_dma_exit); | ||
91 | |||
92 | MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); | ||
93 | MODULE_DESCRIPTION("Optimized page copy/clear routines using a dual-address mode capable DMAC channel"); | ||
94 | MODULE_LICENSE("GPL"); | ||
95 | |||