162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2010 Loongson Inc. & Lemote Inc. & 462306a36Sopenharmony_ci * Institute of Computing Technology 562306a36Sopenharmony_ci * Author: Xiang Gao, gaoxiang@ict.ac.cn 662306a36Sopenharmony_ci * Huacai Chen, chenhc@lemote.com 762306a36Sopenharmony_ci * Xiaofu Meng, Shuangshuang Zhang 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/mm.h> 1262306a36Sopenharmony_ci#include <linux/mmzone.h> 1362306a36Sopenharmony_ci#include <linux/export.h> 1462306a36Sopenharmony_ci#include <linux/nodemask.h> 1562306a36Sopenharmony_ci#include <linux/swap.h> 1662306a36Sopenharmony_ci#include <linux/memblock.h> 1762306a36Sopenharmony_ci#include <linux/pfn.h> 1862306a36Sopenharmony_ci#include <linux/highmem.h> 1962306a36Sopenharmony_ci#include <asm/page.h> 2062306a36Sopenharmony_ci#include <asm/pgalloc.h> 2162306a36Sopenharmony_ci#include <asm/sections.h> 2262306a36Sopenharmony_ci#include <linux/irq.h> 2362306a36Sopenharmony_ci#include <asm/bootinfo.h> 2462306a36Sopenharmony_ci#include <asm/mc146818-time.h> 2562306a36Sopenharmony_ci#include <asm/time.h> 2662306a36Sopenharmony_ci#include <asm/wbflush.h> 2762306a36Sopenharmony_ci#include <boot_param.h> 2862306a36Sopenharmony_ci#include <loongson.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciunsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES]; 3162306a36Sopenharmony_ciEXPORT_SYMBOL(__node_distances); 3262306a36Sopenharmony_cistruct pglist_data *__node_data[MAX_NUMNODES]; 3362306a36Sopenharmony_ciEXPORT_SYMBOL(__node_data); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cicpumask_t __node_cpumask[MAX_NUMNODES]; 3662306a36Sopenharmony_ciEXPORT_SYMBOL(__node_cpumask); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void cpu_node_probe(void) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci int i; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci nodes_clear(node_possible_map); 4362306a36Sopenharmony_ci nodes_clear(node_online_map); 4462306a36Sopenharmony_ci for (i = 0; i < loongson_sysconf.nr_nodes; i++) { 4562306a36Sopenharmony_ci node_set_state(num_online_nodes(), N_POSSIBLE); 4662306a36Sopenharmony_ci node_set_online(num_online_nodes()); 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci pr_info("NUMA: Discovered %d cpus on %d nodes\n", 5062306a36Sopenharmony_ci loongson_sysconf.nr_cpus, num_online_nodes()); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int __init compute_node_distance(int row, int col) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci int package_row = row * loongson_sysconf.cores_per_node / 5662306a36Sopenharmony_ci loongson_sysconf.cores_per_package; 5762306a36Sopenharmony_ci int package_col = col * loongson_sysconf.cores_per_node / 5862306a36Sopenharmony_ci loongson_sysconf.cores_per_package; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci if (col == row) 6162306a36Sopenharmony_ci return LOCAL_DISTANCE; 6262306a36Sopenharmony_ci else if (package_row == package_col) 6362306a36Sopenharmony_ci return 40; 6462306a36Sopenharmony_ci else 6562306a36Sopenharmony_ci return 100; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void __init init_topology_matrix(void) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci int row, col; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (row = 0; row < MAX_NUMNODES; row++) 7362306a36Sopenharmony_ci for (col = 0; col < MAX_NUMNODES; col++) 7462306a36Sopenharmony_ci __node_distances[row][col] = -1; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci for_each_online_node(row) { 7762306a36Sopenharmony_ci for_each_online_node(col) { 7862306a36Sopenharmony_ci __node_distances[row][col] = 7962306a36Sopenharmony_ci compute_node_distance(row, col); 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void __init node_mem_init(unsigned int node) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct pglist_data *nd; 8762306a36Sopenharmony_ci unsigned long node_addrspace_offset; 8862306a36Sopenharmony_ci unsigned long start_pfn, end_pfn; 8962306a36Sopenharmony_ci unsigned long nd_pa; 9062306a36Sopenharmony_ci int tnid; 9162306a36Sopenharmony_ci const size_t nd_size = roundup(sizeof(pg_data_t), SMP_CACHE_BYTES); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci node_addrspace_offset = nid_to_addrbase(node); 9462306a36Sopenharmony_ci pr_info("Node%d's addrspace_offset is 0x%lx\n", 9562306a36Sopenharmony_ci node, node_addrspace_offset); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci get_pfn_range_for_nid(node, &start_pfn, &end_pfn); 9862306a36Sopenharmony_ci pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n", 9962306a36Sopenharmony_ci node, start_pfn, end_pfn); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci nd_pa = memblock_phys_alloc_try_nid(nd_size, SMP_CACHE_BYTES, node); 10262306a36Sopenharmony_ci if (!nd_pa) 10362306a36Sopenharmony_ci panic("Cannot allocate %zu bytes for node %d data\n", 10462306a36Sopenharmony_ci nd_size, node); 10562306a36Sopenharmony_ci nd = __va(nd_pa); 10662306a36Sopenharmony_ci memset(nd, 0, sizeof(struct pglist_data)); 10762306a36Sopenharmony_ci tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT); 10862306a36Sopenharmony_ci if (tnid != node) 10962306a36Sopenharmony_ci pr_info("NODE_DATA(%d) on node %d\n", node, tnid); 11062306a36Sopenharmony_ci __node_data[node] = nd; 11162306a36Sopenharmony_ci NODE_DATA(node)->node_start_pfn = start_pfn; 11262306a36Sopenharmony_ci NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (node == 0) { 11562306a36Sopenharmony_ci /* kernel start address */ 11662306a36Sopenharmony_ci unsigned long kernel_start_pfn = PFN_DOWN(__pa_symbol(&_text)); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* kernel end address */ 11962306a36Sopenharmony_ci unsigned long kernel_end_pfn = PFN_UP(__pa_symbol(&_end)); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* used by finalize_initrd() */ 12262306a36Sopenharmony_ci max_low_pfn = end_pfn; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Reserve the kernel text/data/bss */ 12562306a36Sopenharmony_ci memblock_reserve(kernel_start_pfn << PAGE_SHIFT, 12662306a36Sopenharmony_ci ((kernel_end_pfn - kernel_start_pfn) << PAGE_SHIFT)); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */ 12962306a36Sopenharmony_ci if (node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) 13062306a36Sopenharmony_ci memblock_reserve((node_addrspace_offset | 0xfe000000), 13162306a36Sopenharmony_ci 32 << 20); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Reserve pfn range 0~node[0]->node_start_pfn */ 13462306a36Sopenharmony_ci memblock_reserve(0, PAGE_SIZE * start_pfn); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic __init void prom_meminit(void) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci unsigned int node, cpu, active_cpu = 0; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci cpu_node_probe(); 14362306a36Sopenharmony_ci init_topology_matrix(); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci for (node = 0; node < loongson_sysconf.nr_nodes; node++) { 14662306a36Sopenharmony_ci if (node_online(node)) { 14762306a36Sopenharmony_ci szmem(node); 14862306a36Sopenharmony_ci node_mem_init(node); 14962306a36Sopenharmony_ci cpumask_clear(&__node_cpumask[node]); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci max_low_pfn = PHYS_PFN(memblock_end_of_DRAM()); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) { 15562306a36Sopenharmony_ci node = cpu / loongson_sysconf.cores_per_node; 15662306a36Sopenharmony_ci if (node >= num_online_nodes()) 15762306a36Sopenharmony_ci node = 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (loongson_sysconf.reserved_cpus_mask & (1<<cpu)) 16062306a36Sopenharmony_ci continue; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci cpumask_set_cpu(active_cpu, &__node_cpumask[node]); 16362306a36Sopenharmony_ci pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu, node); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci active_cpu++; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_civoid __init paging_init(void) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci unsigned long zones_size[MAX_NR_ZONES] = {0, }; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci pagetable_init(); 17462306a36Sopenharmony_ci zones_size[ZONE_DMA32] = MAX_DMA32_PFN; 17562306a36Sopenharmony_ci zones_size[ZONE_NORMAL] = max_low_pfn; 17662306a36Sopenharmony_ci free_area_init(zones_size); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_civoid __init mem_init(void) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT); 18262306a36Sopenharmony_ci memblock_free_all(); 18362306a36Sopenharmony_ci setup_zero_pages(); /* This comes from node 0 */ 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* All PCI device belongs to logical Node-0 */ 18762306a36Sopenharmony_ciint pcibus_to_node(struct pci_bus *bus) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci return 0; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ciEXPORT_SYMBOL(pcibus_to_node); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_civoid __init prom_init_numa_memory(void) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci pr_info("CP0_Config3: CP0 16.3 (0x%x)\n", read_c0_config3()); 19662306a36Sopenharmony_ci pr_info("CP0_PageGrain: CP0 5.1 (0x%x)\n", read_c0_pagegrain()); 19762306a36Sopenharmony_ci prom_meminit(); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cipg_data_t * __init arch_alloc_nodedata(int nid) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci return memblock_alloc(sizeof(pg_data_t), SMP_CACHE_BYTES); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_civoid arch_refresh_nodedata(int nid, pg_data_t *pgdat) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci __node_data[nid] = pgdat; 20862306a36Sopenharmony_ci} 209