aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/mm
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2007-06-06 04:52:19 -0400
committerPaul Mundt <lethal@hera.kernel.org>2007-06-07 22:43:49 -0400
commitb241cb0c885e55839fb0f93c6a4539c5416cc39f (patch)
treedc12c8df833820d642b22d4a5f556602c3832dde /arch/sh/mm
parent07cbb41b5308b92f29649254ff755e48ea60e24c (diff)
sh: Support for multiple nodes.
This adds basic support for multiple nodes on SH machines. This is primarily useful for boards with many different memory blocks that are otherwise unused (SH7722/SH7785 URAM and so forth). Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/mm')
-rw-r--r--arch/sh/mm/Kconfig11
-rw-r--r--arch/sh/mm/Makefile1
-rw-r--r--arch/sh/mm/numa.c92
3 files changed, 104 insertions, 0 deletions
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 955a851c0c75..8c5b73ab4772 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -293,6 +293,17 @@ config VSYSCALL
293 For systems with an MMU that can afford to give up a page, 293 For systems with an MMU that can afford to give up a page,
294 (the default value) say Y. 294 (the default value) say Y.
295 295
296config NUMA
297 bool "Non Uniform Memory Access (NUMA) Support"
298 depends on MMU && EXPERIMENTAL
299 default n
300 help
301 Some SH systems have many various memories scattered around
302 the address space, each with varying latencies. This enables
303 support for these blocks by binding them to nodes and allowing
304 memory policies to be used for prioritizing and controlling
305 allocation behaviour.
306
296config NODES_SHIFT 307config NODES_SHIFT
297 int 308 int
298 default "1" 309 default "1"
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 3ffd7f68c0a2..47c330c528db 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -29,3 +29,4 @@ endif
29 29
30obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o 30obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
31obj-$(CONFIG_32BIT) += pmb.o 31obj-$(CONFIG_32BIT) += pmb.o
32obj-$(CONFIG_NUMA) += numa.o
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
17static bootmem_data_t plat_node_bdata[MAX_NUMNODES];
18struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
19EXPORT_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 */
27void __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
47void __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}