18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Author: Xiang Gao <gaoxiang@loongson.cn> 48c2ecf20Sopenharmony_ci * Huacai Chen <chenhuacai@loongson.cn> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2020-2021 Loongson Technology Corporation Limited 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/mm.h> 118c2ecf20Sopenharmony_ci#include <linux/mmzone.h> 128c2ecf20Sopenharmony_ci#include <linux/export.h> 138c2ecf20Sopenharmony_ci#include <linux/nodemask.h> 148c2ecf20Sopenharmony_ci#include <linux/swap.h> 158c2ecf20Sopenharmony_ci#include <linux/memblock.h> 168c2ecf20Sopenharmony_ci#include <linux/pfn.h> 178c2ecf20Sopenharmony_ci#include <linux/acpi.h> 188c2ecf20Sopenharmony_ci#include <linux/efi.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <asm/page.h> 218c2ecf20Sopenharmony_ci#include <asm/pgalloc.h> 228c2ecf20Sopenharmony_ci#include <asm/sections.h> 238c2ecf20Sopenharmony_ci#include <linux/irq.h> 248c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 258c2ecf20Sopenharmony_ci#include <asm/time.h> 268c2ecf20Sopenharmony_ci#include <loongson.h> 278c2ecf20Sopenharmony_ci#include <asm/numa.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciint numa_off; 308c2ecf20Sopenharmony_cistruct pglist_data *node_data[MAX_NUMNODES]; 318c2ecf20Sopenharmony_ciunsigned char node_distances[MAX_NUMNODES][MAX_NUMNODES]; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(node_data); 348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(node_distances); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct numa_meminfo numa_meminfo; 378c2ecf20Sopenharmony_cicpumask_t cpus_on_node[MAX_NUMNODES]; 388c2ecf20Sopenharmony_cicpumask_t phys_cpus_on_node[MAX_NUMNODES]; 398c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpus_on_node); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * apicid, cpu, node mappings 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_cis16 __cpuid_to_node[CONFIG_NR_CPUS] = { 458c2ecf20Sopenharmony_ci [0 ... CONFIG_NR_CPUS - 1] = NUMA_NO_NODE 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__cpuid_to_node); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cinodemask_t numa_nodes_parsed __initdata; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA 528c2ecf20Sopenharmony_ciunsigned long __per_cpu_offset[NR_CPUS] __read_mostly; 538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__per_cpu_offset); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int __init pcpu_cpu_distance(unsigned int from, unsigned int to) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci if (early_cpu_to_node(from) == early_cpu_to_node(to)) 588c2ecf20Sopenharmony_ci return LOCAL_DISTANCE; 598c2ecf20Sopenharmony_ci else 608c2ecf20Sopenharmony_ci return REMOTE_DISTANCE; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, 648c2ecf20Sopenharmony_ci size_t align) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci return memblock_alloc_try_nid(size, align, __pa(MAX_DMA_ADDRESS), 678c2ecf20Sopenharmony_ci MEMBLOCK_ALLOC_ACCESSIBLE, early_cpu_to_node(cpu)); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic void __init pcpu_fc_free(void *ptr, size_t size) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci memblock_free_early(__pa(ptr), size); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void __init pcpu_populate_pte(unsigned long addr) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci populate_kernel_pte(addr); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_civoid __init setup_per_cpu_areas(void) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci unsigned long delta; 838c2ecf20Sopenharmony_ci unsigned int cpu; 848c2ecf20Sopenharmony_ci int rc = -EINVAL; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (pcpu_chosen_fc == PCPU_FC_AUTO) { 878c2ecf20Sopenharmony_ci if (nr_node_ids >= 8) 888c2ecf20Sopenharmony_ci pcpu_chosen_fc = PCPU_FC_PAGE; 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci pcpu_chosen_fc = PCPU_FC_EMBED; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* 948c2ecf20Sopenharmony_ci * Always reserve area for module percpu variables. That's 958c2ecf20Sopenharmony_ci * what the legacy allocator did. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci if (pcpu_chosen_fc != PCPU_FC_PAGE) { 988c2ecf20Sopenharmony_ci rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE, 998c2ecf20Sopenharmony_ci PERCPU_DYNAMIC_RESERVE, PMD_SIZE, 1008c2ecf20Sopenharmony_ci pcpu_cpu_distance, 1018c2ecf20Sopenharmony_ci pcpu_fc_alloc, pcpu_fc_free); 1028c2ecf20Sopenharmony_ci if (rc < 0) 1038c2ecf20Sopenharmony_ci pr_warn("%s allocator failed (%d), falling back to page size\n", 1048c2ecf20Sopenharmony_ci pcpu_fc_names[pcpu_chosen_fc], rc); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci if (rc < 0) 1078c2ecf20Sopenharmony_ci rc = pcpu_page_first_chunk(PERCPU_MODULE_RESERVE, 1088c2ecf20Sopenharmony_ci pcpu_fc_alloc, pcpu_fc_free, 1098c2ecf20Sopenharmony_ci pcpu_populate_pte); 1108c2ecf20Sopenharmony_ci if (rc < 0) 1118c2ecf20Sopenharmony_ci panic("cannot initialize percpu area (err=%d)", rc); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; 1148c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) 1158c2ecf20Sopenharmony_ci __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci#endif 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Get nodeid by logical cpu number. 1218c2ecf20Sopenharmony_ci * __cpuid_to_node maps phyical cpu id to node, so we 1228c2ecf20Sopenharmony_ci * should use cpu_logical_map(cpu) to index it. 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * This routine is only used in early phase during 1258c2ecf20Sopenharmony_ci * booting, after setup_per_cpu_areas calling and numa_node 1268c2ecf20Sopenharmony_ci * initialization, cpu_to_node will be used instead. 1278c2ecf20Sopenharmony_ci * */ 1288c2ecf20Sopenharmony_ciint early_cpu_to_node(int cpu) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci int physid = cpu_logical_map(cpu); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (physid < 0) 1338c2ecf20Sopenharmony_ci return NUMA_NO_NODE; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci return __cpuid_to_node[physid]; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_civoid __init early_numa_add_cpu(int cpuid, s16 node) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int cpu = __cpu_number_map[cpuid]; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (cpu < 0) 1438c2ecf20Sopenharmony_ci return; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci cpumask_set_cpu(cpu, &cpus_on_node[node]); 1468c2ecf20Sopenharmony_ci cpumask_set_cpu(cpuid, &phys_cpus_on_node[node]); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_civoid numa_add_cpu(unsigned int cpu) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci int nid = cpu_to_node(cpu); 1528c2ecf20Sopenharmony_ci cpumask_set_cpu(cpu, &cpus_on_node[nid]); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_civoid numa_remove_cpu(unsigned int cpu) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int nid = cpu_to_node(cpu); 1588c2ecf20Sopenharmony_ci cpumask_clear_cpu(cpu, &cpus_on_node[nid]); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int __init numa_add_memblk_to(int nid, u64 start, u64 end, 1628c2ecf20Sopenharmony_ci struct numa_meminfo *mi) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci /* ignore zero length blks */ 1658c2ecf20Sopenharmony_ci if (start == end) 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* whine about and ignore invalid blks */ 1698c2ecf20Sopenharmony_ci if (start > end || nid < 0 || nid >= MAX_NUMNODES) { 1708c2ecf20Sopenharmony_ci pr_warn("NUMA: Warning: invalid memblk node %d [mem %#010Lx-%#010Lx]\n", 1718c2ecf20Sopenharmony_ci nid, start, end - 1); 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (mi->nr_blks >= NR_NODE_MEMBLKS) { 1768c2ecf20Sopenharmony_ci pr_err("NUMA: too many memblk ranges\n"); 1778c2ecf20Sopenharmony_ci return -EINVAL; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci mi->blk[mi->nr_blks].start = PFN_ALIGN(start); 1818c2ecf20Sopenharmony_ci mi->blk[mi->nr_blks].end = PFN_ALIGN(end - PAGE_SIZE + 1); 1828c2ecf20Sopenharmony_ci mi->blk[mi->nr_blks].nid = nid; 1838c2ecf20Sopenharmony_ci mi->nr_blks++; 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/** 1888c2ecf20Sopenharmony_ci * numa_add_memblk - Add one numa_memblk to numa_meminfo 1898c2ecf20Sopenharmony_ci * @nid: NUMA node ID of the new memblk 1908c2ecf20Sopenharmony_ci * @start: Start address of the new memblk 1918c2ecf20Sopenharmony_ci * @end: End address of the new memblk 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * Add a new memblk to the default numa_meminfo. 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * RETURNS: 1968c2ecf20Sopenharmony_ci * 0 on success, -errno on failure. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ciint __init numa_add_memblk(int nid, u64 start, u64 end) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci return numa_add_memblk_to(nid, start, end, &numa_meminfo); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void __init alloc_node_data(int nid) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci void *nd; 2068c2ecf20Sopenharmony_ci unsigned long nd_pa; 2078c2ecf20Sopenharmony_ci size_t nd_sz = roundup(sizeof(pg_data_t), PAGE_SIZE); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci nd_pa = memblock_phys_alloc_try_nid(nd_sz, SMP_CACHE_BYTES, nid); 2108c2ecf20Sopenharmony_ci if (!nd_pa) { 2118c2ecf20Sopenharmony_ci pr_err("Cannot find %zu Byte for node_data (initial node: %d)\n", nd_sz, nid); 2128c2ecf20Sopenharmony_ci return; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci nd = __va(nd_pa); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci node_data[nid] = nd; 2188c2ecf20Sopenharmony_ci memset(nd, 0, sizeof(pg_data_t)); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void __init node_mem_init(unsigned int node) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci unsigned long start_pfn, end_pfn; 2248c2ecf20Sopenharmony_ci unsigned long node_addrspace_offset; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci node_addrspace_offset = nid_to_addrbase(node); 2278c2ecf20Sopenharmony_ci pr_info("Node%d's addrspace_offset is 0x%lx\n", 2288c2ecf20Sopenharmony_ci node, node_addrspace_offset); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci get_pfn_range_for_nid(node, &start_pfn, &end_pfn); 2318c2ecf20Sopenharmony_ci pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx\n", 2328c2ecf20Sopenharmony_ci node, start_pfn, end_pfn); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci alloc_node_data(node); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_NUMA 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci/* 2408c2ecf20Sopenharmony_ci * Sanity check to catch more bad NUMA configurations (they are amazingly 2418c2ecf20Sopenharmony_ci * common). Make sure the nodes cover all memory. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_cistatic bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci u64 numaram, biosram; 2468c2ecf20Sopenharmony_ci int i; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci numaram = 0; 2498c2ecf20Sopenharmony_ci for (i = 0; i < mi->nr_blks; i++) { 2508c2ecf20Sopenharmony_ci u64 s = mi->blk[i].start >> PAGE_SHIFT; 2518c2ecf20Sopenharmony_ci u64 e = mi->blk[i].end >> PAGE_SHIFT; 2528c2ecf20Sopenharmony_ci numaram += e - s; 2538c2ecf20Sopenharmony_ci numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); 2548c2ecf20Sopenharmony_ci if ((s64)numaram < 0) 2558c2ecf20Sopenharmony_ci numaram = 0; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci max_pfn = max_low_pfn; 2588c2ecf20Sopenharmony_ci biosram = max_pfn - absent_pages_in_range(0, max_pfn); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci BUG_ON((s64)(biosram - numaram) >= (1 << (20 - PAGE_SHIFT))); 2618c2ecf20Sopenharmony_ci return true; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void __init add_node_intersection(u32 node, u64 start, u64 size, u32 type) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci static unsigned long num_physpages; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci num_physpages += (size >> PAGE_SHIFT); 2698c2ecf20Sopenharmony_ci pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n", 2708c2ecf20Sopenharmony_ci node, type, start, size); 2718c2ecf20Sopenharmony_ci pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", 2728c2ecf20Sopenharmony_ci start >> PAGE_SHIFT, (start + size) >> PAGE_SHIFT, num_physpages); 2738c2ecf20Sopenharmony_ci memblock_set_node(start, size, &memblock.memory, node); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* 2778c2ecf20Sopenharmony_ci * add_numamem_region 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * Add a uasable memory region described by BIOS. The 2808c2ecf20Sopenharmony_ci * routine gets each intersection between BIOS's region 2818c2ecf20Sopenharmony_ci * and node's region, and adds them into node's memblock 2828c2ecf20Sopenharmony_ci * pool. 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic void __init add_numamem_region(u64 start, u64 end, u32 type) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci u32 i; 2888c2ecf20Sopenharmony_ci u64 ofs = start; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (start >= end) { 2918c2ecf20Sopenharmony_ci pr_debug("Invalid region: %016llx-%016llx\n", start, end); 2928c2ecf20Sopenharmony_ci return; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci for (i = 0; i < numa_meminfo.nr_blks; i++) { 2968c2ecf20Sopenharmony_ci struct numa_memblk *mb = &numa_meminfo.blk[i]; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (ofs > mb->end) 2998c2ecf20Sopenharmony_ci continue; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (end > mb->end) { 3028c2ecf20Sopenharmony_ci add_node_intersection(mb->nid, ofs, mb->end - ofs, type); 3038c2ecf20Sopenharmony_ci ofs = mb->end; 3048c2ecf20Sopenharmony_ci } else { 3058c2ecf20Sopenharmony_ci add_node_intersection(mb->nid, ofs, end - ofs, type); 3068c2ecf20Sopenharmony_ci break; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic void __init init_node_memblock(void) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci u32 mem_type; 3148c2ecf20Sopenharmony_ci u64 mem_end, mem_start, mem_size; 3158c2ecf20Sopenharmony_ci efi_memory_desc_t *md; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Parse memory information and activate */ 3188c2ecf20Sopenharmony_ci for_each_efi_memory_desc(md) { 3198c2ecf20Sopenharmony_ci mem_type = md->type; 3208c2ecf20Sopenharmony_ci mem_start = md->phys_addr; 3218c2ecf20Sopenharmony_ci mem_size = md->num_pages << EFI_PAGE_SHIFT; 3228c2ecf20Sopenharmony_ci mem_end = mem_start + mem_size; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci switch (mem_type) { 3258c2ecf20Sopenharmony_ci case EFI_LOADER_CODE: 3268c2ecf20Sopenharmony_ci case EFI_LOADER_DATA: 3278c2ecf20Sopenharmony_ci case EFI_BOOT_SERVICES_CODE: 3288c2ecf20Sopenharmony_ci case EFI_BOOT_SERVICES_DATA: 3298c2ecf20Sopenharmony_ci case EFI_PERSISTENT_MEMORY: 3308c2ecf20Sopenharmony_ci case EFI_CONVENTIONAL_MEMORY: 3318c2ecf20Sopenharmony_ci add_numamem_region(mem_start, mem_end, mem_type); 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case EFI_PAL_CODE: 3348c2ecf20Sopenharmony_ci case EFI_UNUSABLE_MEMORY: 3358c2ecf20Sopenharmony_ci case EFI_ACPI_RECLAIM_MEMORY: 3368c2ecf20Sopenharmony_ci add_numamem_region(mem_start, mem_end, mem_type); 3378c2ecf20Sopenharmony_ci fallthrough; 3388c2ecf20Sopenharmony_ci case EFI_RESERVED_TYPE: 3398c2ecf20Sopenharmony_ci case EFI_RUNTIME_SERVICES_CODE: 3408c2ecf20Sopenharmony_ci case EFI_RUNTIME_SERVICES_DATA: 3418c2ecf20Sopenharmony_ci case EFI_MEMORY_MAPPED_IO: 3428c2ecf20Sopenharmony_ci case EFI_MEMORY_MAPPED_IO_PORT_SPACE: 3438c2ecf20Sopenharmony_ci pr_info("Resvd: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx Bytes\n", 3448c2ecf20Sopenharmony_ci mem_type, mem_start, mem_size); 3458c2ecf20Sopenharmony_ci break; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic void __init numa_default_distance(void) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci int row, col; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci for (row = 0; row < MAX_NUMNODES; row++) 3558c2ecf20Sopenharmony_ci for (col = 0; col < MAX_NUMNODES; col++) { 3568c2ecf20Sopenharmony_ci if (col == row) 3578c2ecf20Sopenharmony_ci node_distances[row][col] = LOCAL_DISTANCE; 3588c2ecf20Sopenharmony_ci else 3598c2ecf20Sopenharmony_ci /* We assume that one node per package here! 3608c2ecf20Sopenharmony_ci * 3618c2ecf20Sopenharmony_ci * A SLIT should be used for multiple nodes 3628c2ecf20Sopenharmony_ci * per package to override default setting. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci node_distances[row][col] = REMOTE_DISTANCE; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ciint __init init_numa_memory(void) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci int i; 3718c2ecf20Sopenharmony_ci int ret; 3728c2ecf20Sopenharmony_ci int node; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for (i = 0; i < NR_CPUS; i++) 3758c2ecf20Sopenharmony_ci set_cpuid_to_node(i, NUMA_NO_NODE); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci numa_default_distance(); 3788c2ecf20Sopenharmony_ci nodes_clear(numa_nodes_parsed); 3798c2ecf20Sopenharmony_ci nodes_clear(node_possible_map); 3808c2ecf20Sopenharmony_ci nodes_clear(node_online_map); 3818c2ecf20Sopenharmony_ci memset(&numa_meminfo, 0, sizeof(numa_meminfo)); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Parse SRAT and SLIT if provided by firmware. */ 3848c2ecf20Sopenharmony_ci ret = acpi_numa_init(); 3858c2ecf20Sopenharmony_ci if (ret < 0) 3868c2ecf20Sopenharmony_ci return ret; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci node_possible_map = numa_nodes_parsed; 3898c2ecf20Sopenharmony_ci if (WARN_ON(nodes_empty(node_possible_map))) 3908c2ecf20Sopenharmony_ci return -EINVAL; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci init_node_memblock(); 3938c2ecf20Sopenharmony_ci if (numa_meminfo_cover_memory(&numa_meminfo) == false) 3948c2ecf20Sopenharmony_ci return -EINVAL; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci for_each_node_mask(node, node_possible_map) { 3978c2ecf20Sopenharmony_ci node_mem_init(node); 3988c2ecf20Sopenharmony_ci node_set_online(node); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci max_low_pfn = PHYS_PFN(memblock_end_of_DRAM()); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci setup_nr_node_ids(); 4038c2ecf20Sopenharmony_ci loongson_sysconf.nr_nodes = nr_node_ids; 4048c2ecf20Sopenharmony_ci loongson_sysconf.cores_per_node = cpumask_weight(&phys_cpus_on_node[0]); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci#endif 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_civoid __init paging_init(void) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci unsigned int node; 4148c2ecf20Sopenharmony_ci unsigned long zones_size[MAX_NR_ZONES] = {0, }; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci for_each_online_node(node) { 4178c2ecf20Sopenharmony_ci unsigned long start_pfn, end_pfn; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci get_pfn_range_for_nid(node, &start_pfn, &end_pfn); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (end_pfn > max_low_pfn) 4228c2ecf20Sopenharmony_ci max_low_pfn = end_pfn; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci#ifdef CONFIG_ZONE_DMA32 4258c2ecf20Sopenharmony_ci zones_size[ZONE_DMA32] = MAX_DMA32_PFN; 4268c2ecf20Sopenharmony_ci#endif 4278c2ecf20Sopenharmony_ci zones_size[ZONE_NORMAL] = max_low_pfn; 4288c2ecf20Sopenharmony_ci free_area_init(zones_size); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_civoid __init mem_init(void) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT); 4348c2ecf20Sopenharmony_ci memblock_free_all(); 4358c2ecf20Sopenharmony_ci mem_init_print_info(NULL); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ciint pcibus_to_node(struct pci_bus *bus) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci return dev_to_node(&bus->dev); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pcibus_to_node); 443