Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2010 Loongson Inc. & Lemote Inc. & * Institute of Computing Technology * Author: Xiang Gao, gaoxiang@ict.ac.cn * Huacai Chen, chenhc@lemote.com * Xiaofu Meng, Shuangshuang Zhang */ #include <linux/init.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/mmzone.h> #include <linux/export.h> #include <linux/nodemask.h> #include <linux/swap.h> #include <linux/memblock.h> #include <linux/pfn.h> #include <linux/highmem.h> #include <asm/page.h> #include <asm/pgalloc.h> #include <asm/sections.h> #include <linux/irq.h> #include <asm/bootinfo.h> #include <asm/mc146818-time.h> #include <asm/time.h> #include <asm/wbflush.h> #include <boot_param.h> #include <loongson.h> unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES]; EXPORT_SYMBOL(__node_distances); struct pglist_data *__node_data[MAX_NUMNODES]; EXPORT_SYMBOL(__node_data); cpumask_t __node_cpumask[MAX_NUMNODES]; EXPORT_SYMBOL(__node_cpumask); static void cpu_node_probe(void) { int i; nodes_clear(node_possible_map); nodes_clear(node_online_map); for (i = 0; i < loongson_sysconf.nr_nodes; i++) { node_set_state(num_online_nodes(), N_POSSIBLE); node_set_online(num_online_nodes()); } pr_info("NUMA: Discovered %d cpus on %d nodes\n", loongson_sysconf.nr_cpus, num_online_nodes()); } static int __init compute_node_distance(int row, int col) { int package_row = row * loongson_sysconf.cores_per_node / loongson_sysconf.cores_per_package; int package_col = col * loongson_sysconf.cores_per_node / loongson_sysconf.cores_per_package; if (col == row) return LOCAL_DISTANCE; else if (package_row == package_col) return 40; else return 100; } static void __init init_topology_matrix(void) { int row, col; for (row = 0; row < MAX_NUMNODES; row++) for (col = 0; col < MAX_NUMNODES; col++) __node_distances[row][col] = -1; for_each_online_node(row) { for_each_online_node(col) { __node_distances[row][col] = compute_node_distance(row, col); } } } static void __init node_mem_init(unsigned int node) { struct pglist_data *nd; unsigned long node_addrspace_offset; unsigned long start_pfn, end_pfn; unsigned long nd_pa; int tnid; const size_t nd_size = roundup(sizeof(pg_data_t), SMP_CACHE_BYTES); node_addrspace_offset = nid_to_addrbase(node); pr_info("Node%d's addrspace_offset is 0x%lx\n", node, node_addrspace_offset); get_pfn_range_for_nid(node, &start_pfn, &end_pfn); pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n", node, start_pfn, end_pfn); nd_pa = memblock_phys_alloc_try_nid(nd_size, SMP_CACHE_BYTES, node); if (!nd_pa) panic("Cannot allocate %zu bytes for node %d data\n", nd_size, node); nd = __va(nd_pa); memset(nd, 0, sizeof(struct pglist_data)); tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); if (tnid != node) pr_info("NODE_DATA(%d) on node %d\n", node, tnid); __node_data[node] = nd; NODE_DATA(node)->node_start_pfn = start_pfn; NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn; if (node == 0) { /* kernel start address */ unsigned long kernel_start_pfn = PFN_DOWN(__pa_symbol(&_text)); /* kernel end address */ unsigned long kernel_end_pfn = PFN_UP(__pa_symbol(&_end)); /* used by finalize_initrd() */ max_low_pfn = end_pfn; /* Reserve the kernel text/data/bss */ memblock_reserve(kernel_start_pfn << PAGE_SHIFT, ((kernel_end_pfn - kernel_start_pfn) << PAGE_SHIFT)); /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */ if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) memblock_reserve((node_addrspace_offset | 0xfe000000), 32 << 20); /* Reserve pfn range 0~node[0]->node_start_pfn */ memblock_reserve(0, PAGE_SIZE * start_pfn); } } static __init void prom_meminit(void) { unsigned int node, cpu, active_cpu = 0; cpu_node_probe(); init_topology_matrix(); for (node = 0; node < loongson_sysconf.nr_nodes; node++) { if (node_online(node)) { szmem(node); node_mem_init(node); cpumask_clear(&__node_cpumask[node]); } } max_low_pfn = PHYS_PFN(memblock_end_of_DRAM()); for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) { node = cpu / loongson_sysconf.cores_per_node; if (node >= num_online_nodes()) node = 0; if (loongson_sysconf.reserved_cpus_mask & (1<<cpu)) continue; cpumask_set_cpu(active_cpu, &__node_cpumask[node]); pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu, node); active_cpu++; } } void __init paging_init(void) { unsigned long zones_size[MAX_NR_ZONES] = {0, }; pagetable_init(); zones_size[ZONE_DMA32] = MAX_DMA32_PFN; zones_size[ZONE_NORMAL] = max_low_pfn; free_area_init(zones_size); } void __init mem_init(void) { high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT); memblock_free_all(); setup_zero_pages(); /* This comes from node 0 */ } /* All PCI device belongs to logical Node-0 */ int pcibus_to_node(struct pci_bus *bus) { return 0; } EXPORT_SYMBOL(pcibus_to_node); void __init prom_init_numa_memory(void) { pr_info("CP0_Config3: CP0 16.3 (0x%x)\n", read_c0_config3()); pr_info("CP0_PageGrain: CP0 5.1 (0x%x)\n", read_c0_pagegrain()); prom_meminit(); } pg_data_t * __init arch_alloc_nodedata(int nid) { return memblock_alloc(sizeof(pg_data_t), SMP_CACHE_BYTES); } void arch_refresh_nodedata(int nid, pg_data_t *pgdat) { __node_data[nid] = pgdat; } |