1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
4 * Institute of Computing Technology
5 * Author: Xiang Gao, gaoxiang@ict.ac.cn
6 * Huacai Chen, chenhc@lemote.com
7 * Xiaofu Meng, Shuangshuang Zhang
9 #include <linux/init.h>
10 #include <linux/kernel.h>
12 #include <linux/mmzone.h>
13 #include <linux/export.h>
14 #include <linux/nodemask.h>
15 #include <linux/swap.h>
16 #include <linux/memblock.h>
17 #include <linux/pfn.h>
18 #include <linux/highmem.h>
20 #include <asm/pgalloc.h>
21 #include <asm/sections.h>
22 #include <linux/irq.h>
23 #include <asm/bootinfo.h>
24 #include <asm/mc146818-time.h>
26 #include <asm/wbflush.h>
27 #include <boot_param.h>
29 static struct pglist_data prealloc__node_data
[MAX_NUMNODES
];
30 unsigned char __node_distances
[MAX_NUMNODES
][MAX_NUMNODES
];
31 EXPORT_SYMBOL(__node_distances
);
32 struct pglist_data
*__node_data
[MAX_NUMNODES
];
33 EXPORT_SYMBOL(__node_data
);
35 cpumask_t __node_cpumask
[MAX_NUMNODES
];
36 EXPORT_SYMBOL(__node_cpumask
);
38 static void enable_lpa(void)
42 value
= __read_32bit_c0_register($
16, 3);
44 __write_32bit_c0_register($
16, 3, value
);
45 value
= __read_32bit_c0_register($
16, 3);
46 pr_info("CP0_Config3: CP0 16.3 (0x%lx)\n", value
);
48 value
= __read_32bit_c0_register($
5, 1);
50 __write_32bit_c0_register($
5, 1, value
);
51 value
= __read_32bit_c0_register($
5, 1);
52 pr_info("CP0_PageGrain: CP0 5.1 (0x%lx)\n", value
);
55 static void cpu_node_probe(void)
59 nodes_clear(node_possible_map
);
60 nodes_clear(node_online_map
);
61 for (i
= 0; i
< loongson_sysconf
.nr_nodes
; i
++) {
62 node_set_state(num_online_nodes(), N_POSSIBLE
);
63 node_set_online(num_online_nodes());
66 pr_info("NUMA: Discovered %d cpus on %d nodes\n",
67 loongson_sysconf
.nr_cpus
, num_online_nodes());
70 static int __init
compute_node_distance(int row
, int col
)
72 int package_row
= row
* loongson_sysconf
.cores_per_node
/
73 loongson_sysconf
.cores_per_package
;
74 int package_col
= col
* loongson_sysconf
.cores_per_node
/
75 loongson_sysconf
.cores_per_package
;
78 return LOCAL_DISTANCE
;
79 else if (package_row
== package_col
)
85 static void __init
init_topology_matrix(void)
89 for (row
= 0; row
< MAX_NUMNODES
; row
++)
90 for (col
= 0; col
< MAX_NUMNODES
; col
++)
91 __node_distances
[row
][col
] = -1;
93 for_each_online_node(row
) {
94 for_each_online_node(col
) {
95 __node_distances
[row
][col
] =
96 compute_node_distance(row
, col
);
101 static unsigned long nid_to_addroffset(unsigned int nid
)
103 unsigned long result
;
107 result
= NODE0_ADDRSPACE_OFFSET
;
110 result
= NODE1_ADDRSPACE_OFFSET
;
113 result
= NODE2_ADDRSPACE_OFFSET
;
116 result
= NODE3_ADDRSPACE_OFFSET
;
122 static void __init
szmem(unsigned int node
)
125 static unsigned long num_physpages
= 0;
126 u64 node_id
, node_psize
, start_pfn
, end_pfn
, mem_start
, mem_size
;
128 /* Parse memory information and activate */
129 for (i
= 0; i
< loongson_memmap
->nr_map
; i
++) {
130 node_id
= loongson_memmap
->map
[i
].node_id
;
134 mem_type
= loongson_memmap
->map
[i
].mem_type
;
135 mem_size
= loongson_memmap
->map
[i
].mem_size
;
136 mem_start
= loongson_memmap
->map
[i
].mem_start
;
140 start_pfn
= ((node_id
<< 44) + mem_start
) >> PAGE_SHIFT
;
141 node_psize
= (mem_size
<< 20) >> PAGE_SHIFT
;
142 end_pfn
= start_pfn
+ node_psize
;
143 num_physpages
+= node_psize
;
144 pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
145 (u32
)node_id
, mem_type
, mem_start
, mem_size
);
146 pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
147 start_pfn
, end_pfn
, num_physpages
);
148 memblock_add_node(PFN_PHYS(start_pfn
),
149 PFN_PHYS(end_pfn
- start_pfn
), node
);
151 case SYSTEM_RAM_HIGH
:
152 start_pfn
= ((node_id
<< 44) + mem_start
) >> PAGE_SHIFT
;
153 node_psize
= (mem_size
<< 20) >> PAGE_SHIFT
;
154 end_pfn
= start_pfn
+ node_psize
;
155 num_physpages
+= node_psize
;
156 pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
157 (u32
)node_id
, mem_type
, mem_start
, mem_size
);
158 pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
159 start_pfn
, end_pfn
, num_physpages
);
160 memblock_add_node(PFN_PHYS(start_pfn
),
161 PFN_PHYS(end_pfn
- start_pfn
), node
);
163 case SYSTEM_RAM_RESERVED
:
164 pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
165 (u32
)node_id
, mem_type
, mem_start
, mem_size
);
166 memblock_reserve(((node_id
<< 44) + mem_start
),
173 static void __init
node_mem_init(unsigned int node
)
175 unsigned long node_addrspace_offset
;
176 unsigned long start_pfn
, end_pfn
;
178 node_addrspace_offset
= nid_to_addroffset(node
);
179 pr_info("Node%d's addrspace_offset is 0x%lx\n",
180 node
, node_addrspace_offset
);
182 get_pfn_range_for_nid(node
, &start_pfn
, &end_pfn
);
183 pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n",
184 node
, start_pfn
, end_pfn
);
186 __node_data
[node
] = prealloc__node_data
+ node
;
188 NODE_DATA(node
)->node_start_pfn
= start_pfn
;
189 NODE_DATA(node
)->node_spanned_pages
= end_pfn
- start_pfn
;
192 /* kernel end address */
193 unsigned long kernel_end_pfn
= PFN_UP(__pa_symbol(&_end
));
195 /* used by finalize_initrd() */
196 max_low_pfn
= end_pfn
;
198 /* Reserve the kernel text/data/bss */
199 memblock_reserve(start_pfn
<< PAGE_SHIFT
,
200 ((kernel_end_pfn
- start_pfn
) << PAGE_SHIFT
));
202 /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */
203 if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT
))
204 memblock_reserve((node_addrspace_offset
| 0xfe000000),
209 static __init
void prom_meminit(void)
211 unsigned int node
, cpu
, active_cpu
= 0;
214 init_topology_matrix();
216 for (node
= 0; node
< loongson_sysconf
.nr_nodes
; node
++) {
217 if (node_online(node
)) {
220 cpumask_clear(&__node_cpumask
[node
]);
224 max_low_pfn
= PHYS_PFN(memblock_end_of_DRAM());
226 for (cpu
= 0; cpu
< loongson_sysconf
.nr_cpus
; cpu
++) {
227 node
= cpu
/ loongson_sysconf
.cores_per_node
;
228 if (node
>= num_online_nodes())
231 if (loongson_sysconf
.reserved_cpus_mask
& (1<<cpu
))
234 cpumask_set_cpu(active_cpu
, &__node_cpumask
[node
]);
235 pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu
, node
);
241 void __init
paging_init(void)
243 unsigned long zones_size
[MAX_NR_ZONES
] = {0, };
246 #ifdef CONFIG_ZONE_DMA32
247 zones_size
[ZONE_DMA32
] = MAX_DMA32_PFN
;
249 zones_size
[ZONE_NORMAL
] = max_low_pfn
;
250 free_area_init_nodes(zones_size
);
253 void __init
mem_init(void)
255 high_memory
= (void *) __va(get_num_physpages() << PAGE_SHIFT
);
257 setup_zero_pages(); /* This comes from node 0 */
258 mem_init_print_info(NULL
);
261 /* All PCI device belongs to logical Node-0 */
262 int pcibus_to_node(struct pci_bus
*bus
)
266 EXPORT_SYMBOL(pcibus_to_node
);
268 void __init
prom_init_numa_memory(void)
273 EXPORT_SYMBOL(prom_init_numa_memory
);