aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/sh/mm/Kconfig11
-rw-r--r--arch/sh/mm/Makefile1
-rw-r--r--arch/sh/mm/numa.c92
-rw-r--r--include/asm-sh/mmzone.h46
-rw-r--r--include/asm-sh/topology.h30
5 files changed, 180 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}
diff --git a/include/asm-sh/mmzone.h b/include/asm-sh/mmzone.h
new file mode 100644
index 000000000000..7969f381dff2
--- /dev/null
+++ b/include/asm-sh/mmzone.h
@@ -0,0 +1,46 @@
1#ifndef __ASM_SH_MMZONE_H
2#define __ASM_SH_MMZONE_H
3
4#ifdef __KERNEL__
5
6#ifdef CONFIG_NEED_MULTIPLE_NODES
7extern struct pglist_data *node_data[];
8#define NODE_DATA(nid) (node_data[nid])
9
10#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
11#define node_end_pfn(nid) (NODE_DATA(nid)->node_start_pfn + \
12 NODE_DATA(nid)->node_spanned_pages)
13
14static inline int pfn_to_nid(unsigned long pfn)
15{
16 int nid;
17
18 for (nid = 0; nid < MAX_NUMNODES; nid++)
19 if (pfn >= node_start_pfn(nid) && pfn <= node_end_pfn(nid))
20 break;
21
22 return nid;
23}
24
25static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn)
26{
27 return NODE_DATA(pfn_to_nid(pfn));
28}
29
30/* arch/sh/mm/numa.c */
31void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end);
32#else
33static inline void
34setup_bootmem_node(int nid, unsigned long start, unsigned long end)
35{
36}
37#endif /* CONFIG_NEED_MULTIPLE_NODES */
38
39/* Platform specific mem init */
40void __init plat_mem_setup(void);
41
42/* arch/sh/kernel/setup.c */
43void __init setup_bootmem_allocator(unsigned long start_pfn);
44
45#endif /* __KERNEL__ */
46#endif /* __ASM_SH_MMZONE_H */
diff --git a/include/asm-sh/topology.h b/include/asm-sh/topology.h
index cff001c316fe..f402a3b1cfa4 100644
--- a/include/asm-sh/topology.h
+++ b/include/asm-sh/topology.h
@@ -1,6 +1,36 @@
1#ifndef _ASM_SH_TOPOLOGY_H 1#ifndef _ASM_SH_TOPOLOGY_H
2#define _ASM_SH_TOPOLOGY_H 2#define _ASM_SH_TOPOLOGY_H
3 3
4#ifdef CONFIG_NUMA
5
6/* sched_domains SD_NODE_INIT for sh machines */
7#define SD_NODE_INIT (struct sched_domain) { \
8 .span = CPU_MASK_NONE, \
9 .parent = NULL, \
10 .child = NULL, \
11 .groups = NULL, \
12 .min_interval = 8, \
13 .max_interval = 32, \
14 .busy_factor = 32, \
15 .imbalance_pct = 125, \
16 .cache_nice_tries = 2, \
17 .busy_idx = 3, \
18 .idle_idx = 2, \
19 .newidle_idx = 0, \
20 .wake_idx = 1, \
21 .forkexec_idx = 1, \
22 .flags = SD_LOAD_BALANCE \
23 | SD_BALANCE_FORK \
24 | SD_BALANCE_EXEC \
25 | SD_SERIALIZE \
26 | SD_WAKE_BALANCE, \
27 .last_balance = jiffies, \
28 .balance_interval = 1, \
29 .nr_balance_failed = 0, \
30}
31
32#endif
33
4#include <asm-generic/topology.h> 34#include <asm-generic/topology.h>
5 35
6#endif /* _ASM_SH_TOPOLOGY_H */ 36#endif /* _ASM_SH_TOPOLOGY_H */