0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/init.h>
0010 #include <linux/kernel.h>
0011 #include <linux/mm.h>
0012 #include <linux/mmzone.h>
0013 #include <linux/export.h>
0014 #include <linux/nodemask.h>
0015 #include <linux/swap.h>
0016 #include <linux/memblock.h>
0017 #include <linux/pfn.h>
0018 #include <linux/highmem.h>
0019 #include <asm/page.h>
0020 #include <asm/pgalloc.h>
0021 #include <asm/sections.h>
0022 #include <linux/irq.h>
0023 #include <asm/bootinfo.h>
0024 #include <asm/mc146818-time.h>
0025 #include <asm/time.h>
0026 #include <asm/wbflush.h>
0027 #include <boot_param.h>
0028 #include <loongson.h>
0029
0030 unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
0031 EXPORT_SYMBOL(__node_distances);
0032 struct pglist_data *__node_data[MAX_NUMNODES];
0033 EXPORT_SYMBOL(__node_data);
0034
0035 cpumask_t __node_cpumask[MAX_NUMNODES];
0036 EXPORT_SYMBOL(__node_cpumask);
0037
0038 static void cpu_node_probe(void)
0039 {
0040 int i;
0041
0042 nodes_clear(node_possible_map);
0043 nodes_clear(node_online_map);
0044 for (i = 0; i < loongson_sysconf.nr_nodes; i++) {
0045 node_set_state(num_online_nodes(), N_POSSIBLE);
0046 node_set_online(num_online_nodes());
0047 }
0048
0049 pr_info("NUMA: Discovered %d cpus on %d nodes\n",
0050 loongson_sysconf.nr_cpus, num_online_nodes());
0051 }
0052
0053 static int __init compute_node_distance(int row, int col)
0054 {
0055 int package_row = row * loongson_sysconf.cores_per_node /
0056 loongson_sysconf.cores_per_package;
0057 int package_col = col * loongson_sysconf.cores_per_node /
0058 loongson_sysconf.cores_per_package;
0059
0060 if (col == row)
0061 return LOCAL_DISTANCE;
0062 else if (package_row == package_col)
0063 return 40;
0064 else
0065 return 100;
0066 }
0067
0068 static void __init init_topology_matrix(void)
0069 {
0070 int row, col;
0071
0072 for (row = 0; row < MAX_NUMNODES; row++)
0073 for (col = 0; col < MAX_NUMNODES; col++)
0074 __node_distances[row][col] = -1;
0075
0076 for_each_online_node(row) {
0077 for_each_online_node(col) {
0078 __node_distances[row][col] =
0079 compute_node_distance(row, col);
0080 }
0081 }
0082 }
0083
0084 static void __init node_mem_init(unsigned int node)
0085 {
0086 struct pglist_data *nd;
0087 unsigned long node_addrspace_offset;
0088 unsigned long start_pfn, end_pfn;
0089 unsigned long nd_pa;
0090 int tnid;
0091 const size_t nd_size = roundup(sizeof(pg_data_t), SMP_CACHE_BYTES);
0092
0093 node_addrspace_offset = nid_to_addrbase(node);
0094 pr_info("Node%d's addrspace_offset is 0x%lx\n",
0095 node, node_addrspace_offset);
0096
0097 get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
0098 pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n",
0099 node, start_pfn, end_pfn);
0100
0101 nd_pa = memblock_phys_alloc_try_nid(nd_size, SMP_CACHE_BYTES, node);
0102 if (!nd_pa)
0103 panic("Cannot allocate %zu bytes for node %d data\n",
0104 nd_size, node);
0105 nd = __va(nd_pa);
0106 memset(nd, 0, sizeof(struct pglist_data));
0107 tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT);
0108 if (tnid != node)
0109 pr_info("NODE_DATA(%d) on node %d\n", node, tnid);
0110 __node_data[node] = nd;
0111 NODE_DATA(node)->node_start_pfn = start_pfn;
0112 NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
0113
0114 if (node == 0) {
0115
0116 unsigned long kernel_start_pfn = PFN_DOWN(__pa_symbol(&_text));
0117
0118
0119 unsigned long kernel_end_pfn = PFN_UP(__pa_symbol(&_end));
0120
0121
0122 max_low_pfn = end_pfn;
0123
0124
0125 memblock_reserve(kernel_start_pfn << PAGE_SHIFT,
0126 ((kernel_end_pfn - kernel_start_pfn) << PAGE_SHIFT));
0127
0128
0129 if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT))
0130 memblock_reserve((node_addrspace_offset | 0xfe000000),
0131 32 << 20);
0132
0133
0134 memblock_reserve(0, PAGE_SIZE * start_pfn);
0135 }
0136 }
0137
0138 static __init void prom_meminit(void)
0139 {
0140 unsigned int node, cpu, active_cpu = 0;
0141
0142 cpu_node_probe();
0143 init_topology_matrix();
0144
0145 for (node = 0; node < loongson_sysconf.nr_nodes; node++) {
0146 if (node_online(node)) {
0147 szmem(node);
0148 node_mem_init(node);
0149 cpumask_clear(&__node_cpumask[node]);
0150 }
0151 }
0152 max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());
0153
0154 for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) {
0155 node = cpu / loongson_sysconf.cores_per_node;
0156 if (node >= num_online_nodes())
0157 node = 0;
0158
0159 if (loongson_sysconf.reserved_cpus_mask & (1<<cpu))
0160 continue;
0161
0162 cpumask_set_cpu(active_cpu, &__node_cpumask[node]);
0163 pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu, node);
0164
0165 active_cpu++;
0166 }
0167 }
0168
0169 void __init paging_init(void)
0170 {
0171 unsigned long zones_size[MAX_NR_ZONES] = {0, };
0172
0173 pagetable_init();
0174 zones_size[ZONE_DMA32] = MAX_DMA32_PFN;
0175 zones_size[ZONE_NORMAL] = max_low_pfn;
0176 free_area_init(zones_size);
0177 }
0178
0179 void __init mem_init(void)
0180 {
0181 high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
0182 memblock_free_all();
0183 setup_zero_pages();
0184 }
0185
0186
0187 int pcibus_to_node(struct pci_bus *bus)
0188 {
0189 return 0;
0190 }
0191 EXPORT_SYMBOL(pcibus_to_node);
0192
0193 void __init prom_init_numa_memory(void)
0194 {
0195 pr_info("CP0_Config3: CP0 16.3 (0x%x)\n", read_c0_config3());
0196 pr_info("CP0_PageGrain: CP0 5.1 (0x%x)\n", read_c0_pagegrain());
0197 prom_meminit();
0198 }
0199
0200 pg_data_t * __init arch_alloc_nodedata(int nid)
0201 {
0202 return memblock_alloc(sizeof(pg_data_t), SMP_CACHE_BYTES);
0203 }
0204
0205 void arch_refresh_nodedata(int nid, pg_data_t *pgdat)
0206 {
0207 __node_data[nid] = pgdat;
0208 }