2 * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
3 * Institute of Computing Technology
4 * Author: Xiang Gao, gaoxiang@ict.ac.cn
5 * Huacai Chen, chenhc@lemote.com
6 * Xiaofu Meng, Shuangshuang Zhang
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
13 #include <linux/init.h>
14 #include <linux/kernel.h>
16 #include <linux/mmzone.h>
17 #include <linux/module.h>
18 #include <linux/nodemask.h>
19 #include <linux/swap.h>
20 #include <linux/memblock.h>
21 #include <linux/bootmem.h>
22 #include <linux/pfn.h>
23 #include <linux/highmem.h>
25 #include <asm/pgalloc.h>
26 #include <asm/sections.h>
27 #include <linux/irq.h>
28 #include <asm/bootinfo.h>
29 #include <asm/mc146818-time.h>
31 #include <asm/wbflush.h>
32 #include <boot_param.h>
34 static struct node_data prealloc__node_data
[MAX_NUMNODES
];
35 unsigned char __node_distances
[MAX_NUMNODES
][MAX_NUMNODES
];
36 EXPORT_SYMBOL(__node_distances
);
37 struct node_data
*__node_data
[MAX_NUMNODES
];
38 EXPORT_SYMBOL(__node_data
);
40 static void enable_lpa(void)
44 value
= __read_32bit_c0_register($
16, 3);
46 __write_32bit_c0_register($
16, 3, value
);
47 value
= __read_32bit_c0_register($
16, 3);
48 pr_info("CP0_Config3: CP0 16.3 (0x%lx)\n", value
);
50 value
= __read_32bit_c0_register($
5, 1);
52 __write_32bit_c0_register($
5, 1, value
);
53 value
= __read_32bit_c0_register($
5, 1);
54 pr_info("CP0_PageGrain: CP0 5.1 (0x%lx)\n", value
);
57 static void cpu_node_probe(void)
61 nodes_clear(node_possible_map
);
62 nodes_clear(node_online_map
);
63 for (i
= 0; i
< loongson_sysconf
.nr_nodes
; i
++) {
64 node_set_state(num_online_nodes(), N_POSSIBLE
);
65 node_set_online(num_online_nodes());
68 pr_info("NUMA: Discovered %d cpus on %d nodes\n",
69 loongson_sysconf
.nr_cpus
, num_online_nodes());
72 static int __init
compute_node_distance(int row
, int col
)
74 int package_row
= row
* loongson_sysconf
.cores_per_node
/
75 loongson_sysconf
.cores_per_package
;
76 int package_col
= col
* loongson_sysconf
.cores_per_node
/
77 loongson_sysconf
.cores_per_package
;
81 else if (package_row
== package_col
)
87 static void __init
init_topology_matrix(void)
91 for (row
= 0; row
< MAX_NUMNODES
; row
++)
92 for (col
= 0; col
< MAX_NUMNODES
; col
++)
93 __node_distances
[row
][col
] = -1;
95 for_each_online_node(row
) {
96 for_each_online_node(col
) {
97 __node_distances
[row
][col
] =
98 compute_node_distance(row
, col
);
103 static unsigned long nid_to_addroffset(unsigned int nid
)
105 unsigned long result
;
109 result
= NODE0_ADDRSPACE_OFFSET
;
112 result
= NODE1_ADDRSPACE_OFFSET
;
115 result
= NODE2_ADDRSPACE_OFFSET
;
118 result
= NODE3_ADDRSPACE_OFFSET
;
124 static void __init
szmem(unsigned int node
)
127 static unsigned long num_physpages
= 0;
128 u64 node_id
, node_psize
, start_pfn
, end_pfn
, mem_start
, mem_size
;
130 /* Parse memory information and activate */
131 for (i
= 0; i
< loongson_memmap
->nr_map
; i
++) {
132 node_id
= loongson_memmap
->map
[i
].node_id
;
136 mem_type
= loongson_memmap
->map
[i
].mem_type
;
137 mem_size
= loongson_memmap
->map
[i
].mem_size
;
138 mem_start
= loongson_memmap
->map
[i
].mem_start
;
142 start_pfn
= ((node_id
<< 44) + mem_start
) >> PAGE_SHIFT
;
143 node_psize
= (mem_size
<< 20) >> PAGE_SHIFT
;
144 end_pfn
= start_pfn
+ node_psize
;
145 num_physpages
+= node_psize
;
146 pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
147 (u32
)node_id
, mem_type
, mem_start
, mem_size
);
148 pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
149 start_pfn
, end_pfn
, num_physpages
);
150 add_memory_region((node_id
<< 44) + mem_start
,
151 (u64
)mem_size
<< 20, BOOT_MEM_RAM
);
152 memblock_add_node(PFN_PHYS(start_pfn
),
153 PFN_PHYS(end_pfn
- start_pfn
), node
);
155 case SYSTEM_RAM_HIGH
:
156 start_pfn
= ((node_id
<< 44) + mem_start
) >> PAGE_SHIFT
;
157 node_psize
= (mem_size
<< 20) >> PAGE_SHIFT
;
158 end_pfn
= start_pfn
+ node_psize
;
159 num_physpages
+= node_psize
;
160 pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
161 (u32
)node_id
, mem_type
, mem_start
, mem_size
);
162 pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
163 start_pfn
, end_pfn
, num_physpages
);
164 add_memory_region((node_id
<< 44) + mem_start
,
165 (u64
)mem_size
<< 20, BOOT_MEM_RAM
);
166 memblock_add_node(PFN_PHYS(start_pfn
),
167 PFN_PHYS(end_pfn
- start_pfn
), node
);
170 pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
171 (u32
)node_id
, mem_type
, mem_start
, mem_size
);
172 add_memory_region((node_id
<< 44) + mem_start
,
173 (u64
)mem_size
<< 20, BOOT_MEM_RESERVED
);
174 memblock_reserve(((node_id
<< 44) + mem_start
),
181 static void __init
node_mem_init(unsigned int node
)
183 unsigned long bootmap_size
;
184 unsigned long node_addrspace_offset
;
185 unsigned long start_pfn
, end_pfn
, freepfn
;
187 node_addrspace_offset
= nid_to_addroffset(node
);
188 pr_info("Node%d's addrspace_offset is 0x%lx\n",
189 node
, node_addrspace_offset
);
191 get_pfn_range_for_nid(node
, &start_pfn
, &end_pfn
);
194 freepfn
= PFN_UP(__pa_symbol(&_end
)); /* kernel end address */
195 pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx, freepfn=0x%lx\n",
196 node
, start_pfn
, end_pfn
, freepfn
);
198 __node_data
[node
] = prealloc__node_data
+ node
;
200 NODE_DATA(node
)->bdata
= &bootmem_node_data
[node
];
201 NODE_DATA(node
)->node_start_pfn
= start_pfn
;
202 NODE_DATA(node
)->node_spanned_pages
= end_pfn
- start_pfn
;
204 bootmap_size
= init_bootmem_node(NODE_DATA(node
), freepfn
,
206 free_bootmem_with_active_regions(node
, end_pfn
);
207 if (node
== 0) /* used by finalize_initrd() */
208 max_low_pfn
= end_pfn
;
210 /* This is reserved for the kernel and bdata->node_bootmem_map */
211 reserve_bootmem_node(NODE_DATA(node
), start_pfn
<< PAGE_SHIFT
,
212 ((freepfn
- start_pfn
) << PAGE_SHIFT
) + bootmap_size
,
215 if (node
== 0 && node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT
)) {
216 /* Reserve 0xff800000~0xffffffff for RS780E integrated GPU */
217 reserve_bootmem_node(NODE_DATA(node
),
218 (node_addrspace_offset
| 0xff800000),
219 8 << 20, BOOTMEM_DEFAULT
);
222 sparse_memory_present_with_active_regions(node
);
225 static __init
void prom_meminit(void)
227 unsigned int node
, cpu
, active_cpu
= 0;
230 init_topology_matrix();
232 for (node
= 0; node
< loongson_sysconf
.nr_nodes
; node
++) {
233 if (node_online(node
)) {
236 cpumask_clear(&__node_data
[(node
)]->cpumask
);
239 for (cpu
= 0; cpu
< loongson_sysconf
.nr_cpus
; cpu
++) {
240 node
= cpu
/ loongson_sysconf
.cores_per_node
;
241 if (node
>= num_online_nodes())
244 if (loongson_sysconf
.reserved_cpus_mask
& (1<<cpu
))
247 cpumask_set_cpu(active_cpu
, &__node_data
[(node
)]->cpumask
);
248 pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu
, node
);
254 void __init
paging_init(void)
257 unsigned long zones_size
[MAX_NR_ZONES
] = {0, };
261 for_each_online_node(node
) {
262 unsigned long start_pfn
, end_pfn
;
264 get_pfn_range_for_nid(node
, &start_pfn
, &end_pfn
);
266 if (end_pfn
> max_low_pfn
)
267 max_low_pfn
= end_pfn
;
269 #ifdef CONFIG_ZONE_DMA32
270 zones_size
[ZONE_DMA32
] = MAX_DMA32_PFN
;
272 zones_size
[ZONE_NORMAL
] = max_low_pfn
;
273 free_area_init_nodes(zones_size
);
276 void __init
mem_init(void)
278 high_memory
= (void *) __va(get_num_physpages() << PAGE_SHIFT
);
280 setup_zero_pages(); /* This comes from node 0 */
281 mem_init_print_info(NULL
);
284 /* All PCI device belongs to logical Node-0 */
285 int pcibus_to_node(struct pci_bus
*bus
)
289 EXPORT_SYMBOL(pcibus_to_node
);
291 void __init
prom_init_numa_memory(void)
296 EXPORT_SYMBOL(prom_init_numa_memory
);