Hello Ralf and all, On 26/06/14 05:41, Huacai Chen wrote: > Multiple Loongson-3A chips can be interconnected with HT0-bus. This is > a CC-NUMA system that every chip (node) has its own local memory and > cache coherency is maintained by hardware. The 64-bit physical memory > address format is as follows: > > 0x-0000-YZZZ-ZZZZ-ZZZZ > > The high 16 bits should be 0, which means the real physical address > supported by Loongson-3 is 48-bit. The "Y" bits is the base address of > each node, which can be also considered as the node-id. The "Z" bits is > the address offset within a node, which means every node has a 44 bits > address space. > > Macros XPHYSADDR and MAX_PHYSMEM_BITS are modified unconditionally, > because many other MIPS CPUs have also extended their address spaces. > > Signed-off-by: Huacai Chen <chenhc@xxxxxxxxxx> > --- > arch/mips/include/asm/addrspace.h | 2 +- > arch/mips/include/asm/mach-loongson/boot_param.h | 3 + > .../include/asm/mach-loongson/kernel-entry-init.h | 52 ++++ > arch/mips/include/asm/mach-loongson/mmzone.h | 53 ++++ > arch/mips/include/asm/mach-loongson/topology.h | 23 ++ > arch/mips/include/asm/sparsemem.h | 2 +- > arch/mips/kernel/setup.c | 2 +- > arch/mips/loongson/Kconfig | 1 + > arch/mips/loongson/common/env.c | 7 + > arch/mips/loongson/common/init.c | 4 + > arch/mips/loongson/loongson-3/Makefile | 2 + > arch/mips/loongson/loongson-3/numa.c | 291 ++++++++++++++++++++ > arch/mips/loongson/loongson-3/smp.c | 8 +- > 13 files changed, 445 insertions(+), 5 deletions(-) > create mode 100644 arch/mips/include/asm/mach-loongson/kernel-entry-init.h > create mode 100644 arch/mips/include/asm/mach-loongson/mmzone.h > create mode 100644 arch/mips/include/asm/mach-loongson/topology.h > create mode 100644 arch/mips/loongson/loongson-3/numa.c > > diff --git a/arch/mips/include/asm/addrspace.h b/arch/mips/include/asm/addrspace.h > index 3f74545..3b0e51d 100644 > --- a/arch/mips/include/asm/addrspace.h > +++ b/arch/mips/include/asm/addrspace.h > @@ -52,7 +52,7 @@ > */ > #define CPHYSADDR(a) ((_ACAST32_(a)) & 0x1fffffff) > #define XPHYSADDR(a) ((_ACAST64_(a)) & \ > - _CONST64_(0x000000ffffffffff)) > + _CONST64_(0x0000ffffffffffff)) > > #ifdef CONFIG_64BIT > > diff --git a/arch/mips/include/asm/mach-loongson/boot_param.h b/arch/mips/include/asm/mach-loongson/boot_param.h > index 829a7ec..8b06c96 100644 > --- a/arch/mips/include/asm/mach-loongson/boot_param.h > +++ b/arch/mips/include/asm/mach-loongson/boot_param.h > @@ -146,6 +146,9 @@ struct boot_params { > > struct loongson_system_configuration { > u32 nr_cpus; > + u32 nr_nodes; > + int cores_per_node; > + int cores_per_package; > enum loongson_cpu_type cputype; > u64 ht_control_base; > u64 pci_mem_start_addr; > diff --git a/arch/mips/include/asm/mach-loongson/kernel-entry-init.h b/arch/mips/include/asm/mach-loongson/kernel-entry-init.h > new file mode 100644 > index 0000000..df5fca8 > --- /dev/null > +++ b/arch/mips/include/asm/mach-loongson/kernel-entry-init.h > @@ -0,0 +1,52 @@ > +/* > + * This file is subject to the terms and conditions of the GNU General Public > + * License. See the file "COPYING" in the main directory of this archive > + * for more details. > + * > + * Copyright (C) 2005 Embedded Alley Solutions, Inc > + * Copyright (C) 2005 Ralf Baechle (ralf@xxxxxxxxxxxxxx) > + * Copyright (C) 2009 Jiajie Chen (chenjiajie@xxxxxxxxxxxxxxx) > + * Copyright (C) 2012 Huacai Chen (chenhc@xxxxxxxxxx) > + */ > +#ifndef __ASM_MACH_LOONGSON_KERNEL_ENTRY_H > +#define __ASM_MACH_LOONGSON_KERNEL_ENTRY_H > + > +/* > + * Override macros used in arch/mips/kernel/head.S. > + */ > + .macro kernel_entry_setup > +#ifdef CONFIG_CPU_LOONGSON3 > + .set push > + .set mips64 > + /* Set LPA on LOONGSON3 config3 */ > + mfc0 t0, $16, 3 > + or t0, (0x1 << 7) > + mtc0 t0, $16, 3 > + /* Set ELPA on LOONGSON3 pagegrain */ > + li t0, (0x1 << 29) > + mtc0 t0, $5, 1 > + _ehb > + .set pop > +#endif > + .endm > + > +/* > + * Do SMP slave processor setup. > + */ > + .macro smp_slave_setup > +#ifdef CONFIG_CPU_LOONGSON3 > + .set push > + .set mips64 > + /* Set LPA on LOONGSON3 config3 */ > + mfc0 t0, $16, 3 > + or t0, (0x1 << 7) > + mtc0 t0, $16, 3 > + /* Set ELPA on LOONGSON3 pagegrain */ > + li t0, (0x1 << 29) > + mtc0 t0, $5, 1 > + _ehb > + .set pop > +#endif > + .endm > + > +#endif /* __ASM_MACH_LOONGSON_KERNEL_ENTRY_H */ > diff --git a/arch/mips/include/asm/mach-loongson/mmzone.h b/arch/mips/include/asm/mach-loongson/mmzone.h > new file mode 100644 > index 0000000..37c08a2 > --- /dev/null > +++ b/arch/mips/include/asm/mach-loongson/mmzone.h > @@ -0,0 +1,53 @@ > +/* > + * Copyright (C) 2010 Loongson Inc. & Lemote Inc. & > + * Insititute of Computing Technology > + * Author: Xiang Gao, gaoxiang@xxxxxxxxx > + * Huacai Chen, chenhc@xxxxxxxxxx > + * Xiaofu Meng, Shuangshuang Zhang > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + */ > +#ifndef _ASM_MACH_MMZONE_H > +#define _ASM_MACH_MMZONE_H > + > +#include <boot_param.h> > +#define NODE_ADDRSPACE_SHIFT 44 > +#define NODE0_ADDRSPACE_OFFSET 0x000000000000UL > +#define NODE1_ADDRSPACE_OFFSET 0x100000000000UL > +#define NODE2_ADDRSPACE_OFFSET 0x200000000000UL > +#define NODE3_ADDRSPACE_OFFSET 0x300000000000UL > + > +#define pa_to_nid(addr) (((addr) & 0xf00000000000) >> NODE_ADDRSPACE_SHIFT) > + > +#define LEVELS_PER_SLICE 128 > + > +struct slice_data { > + unsigned long irq_enable_mask[2]; > + int level_to_irq[LEVELS_PER_SLICE]; > +}; > + > +struct hub_data { > + cpumask_t h_cpus; > + unsigned long slice_map; > + unsigned long irq_alloc_mask[2]; > + struct slice_data slice[2]; > +}; > + > +struct node_data { > + struct pglist_data pglist; > + struct hub_data hub; > + cpumask_t cpumask; > +}; > + > +extern struct node_data *__node_data[]; > + > +#define NODE_DATA(n) (&__node_data[(n)]->pglist) > +#define hub_data(n) (&__node_data[(n)]->hub) > + > +extern void setup_zero_pages(void); > +extern void __init prom_init_numa_memory(void); > + > +#endif /* _ASM_MACH_MMZONE_H */ > diff --git a/arch/mips/include/asm/mach-loongson/topology.h b/arch/mips/include/asm/mach-loongson/topology.h > new file mode 100644 > index 0000000..5598ba7 > --- /dev/null > +++ b/arch/mips/include/asm/mach-loongson/topology.h > @@ -0,0 +1,23 @@ > +#ifndef _ASM_MACH_TOPOLOGY_H > +#define _ASM_MACH_TOPOLOGY_H > + > +#ifdef CONFIG_NUMA > + > +#define cpu_to_node(cpu) ((cpu) >> 2) > +#define parent_node(node) (node) > +#define cpumask_of_node(node) (&__node_data[(node)]->cpumask) > + > +struct pci_bus; > +extern int pcibus_to_node(struct pci_bus *); > + > +#define cpumask_of_pcibus(bus) (cpu_online_mask) > + > +extern unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES]; > + > +#define node_distance(from, to) (__node_distances[(from)][(to)]) > + > +#endif > + > +#include <asm-generic/topology.h> > + > +#endif /* _ASM_MACH_TOPOLOGY_H */ > diff --git a/arch/mips/include/asm/sparsemem.h b/arch/mips/include/asm/sparsemem.h > index d2da53c..b1071c1 100644 > --- a/arch/mips/include/asm/sparsemem.h > +++ b/arch/mips/include/asm/sparsemem.h > @@ -11,7 +11,7 @@ > #else > # define SECTION_SIZE_BITS 28 > #endif > -#define MAX_PHYSMEM_BITS 35 > +#define MAX_PHYSMEM_BITS 48 this particular change has increased mem_section static array from 16k to 16M. Or total .bss of the kernel from 700k to >16M (v4.4). Logical solution would be to switch from SPARSEMEM_STATIC to SPARSEMEM_EXTREME, but there is commit 7de58fab ("[MIPS] Sparsemem fixes"), which warns against it. Do you have any idea, if the 11 years old warning is still actual? Any better ideas to repair this waste of memory? > > #endif /* CONFIG_SPARSEMEM */ > #endif /* _MIPS_SPARSEMEM_H */ > diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c > index 2f01201..7c1fe2b 100644 > --- a/arch/mips/kernel/setup.c > +++ b/arch/mips/kernel/setup.c > @@ -282,7 +282,7 @@ static unsigned long __init init_initrd(void) > * Initialize the bootmem allocator. It also setup initrd related data > * if needed. > */ > -#ifdef CONFIG_SGI_IP27 > +#if defined(CONFIG_SGI_IP27) || (defined(CONFIG_CPU_LOONGSON3) && defined(CONFIG_NUMA)) > > static void __init bootmem_init(void) > { > diff --git a/arch/mips/loongson/Kconfig b/arch/mips/loongson/Kconfig > index e6a86cc..a14a50d 100644 > --- a/arch/mips/loongson/Kconfig > +++ b/arch/mips/loongson/Kconfig > @@ -79,6 +79,7 @@ config LEMOTE_MACH3A > select SYS_HAS_EARLY_PRINTK > select SYS_SUPPORTS_SMP > select SYS_SUPPORTS_HOTPLUG_CPU > + select SYS_SUPPORTS_NUMA > select SYS_SUPPORTS_64BIT_KERNEL > select SYS_SUPPORTS_HIGHMEM > select SYS_SUPPORTS_LITTLE_ENDIAN > diff --git a/arch/mips/loongson/common/env.c b/arch/mips/loongson/common/env.c > index dc59241..33a13b9 100644 > --- a/arch/mips/loongson/common/env.c > +++ b/arch/mips/loongson/common/env.c > @@ -80,17 +80,24 @@ void __init prom_init_env(void) > cpu_clock_freq = ecpu->cpu_clock_freq; > loongson_sysconf.cputype = ecpu->cputype; > if (ecpu->cputype == Loongson_3A) { > + loongson_sysconf.cores_per_node = 4; > + loongson_sysconf.cores_per_package = 4; > loongson_chipcfg[0] = 0x900000001fe00180; > loongson_chipcfg[1] = 0x900010001fe00180; > loongson_chipcfg[2] = 0x900020001fe00180; > loongson_chipcfg[3] = 0x900030001fe00180; > } else { > + loongson_sysconf.cores_per_node = 1; > + loongson_sysconf.cores_per_package = 1; > loongson_chipcfg[0] = 0x900000001fe00180; > } > > loongson_sysconf.nr_cpus = ecpu->nr_cpus; > if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0) > loongson_sysconf.nr_cpus = NR_CPUS; > + loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus + > + loongson_sysconf.cores_per_node - 1) / > + loongson_sysconf.cores_per_node; > > loongson_sysconf.pci_mem_start_addr = eirq_source->pci_mem_start_addr; > loongson_sysconf.pci_mem_end_addr = eirq_source->pci_mem_end_addr; > diff --git a/arch/mips/loongson/common/init.c b/arch/mips/loongson/common/init.c > index f37fe54..f6af3ab 100644 > --- a/arch/mips/loongson/common/init.c > +++ b/arch/mips/loongson/common/init.c > @@ -30,7 +30,11 @@ void __init prom_init(void) > set_io_port_base((unsigned long) > ioremap(LOONGSON_PCIIO_BASE, LOONGSON_PCIIO_SIZE)); > > +#ifdef CONFIG_NUMA > + prom_init_numa_memory(); > +#else > prom_init_memory(); > +#endif > > /*init the uart base address */ > prom_init_uart_base(); > diff --git a/arch/mips/loongson/loongson-3/Makefile b/arch/mips/loongson/loongson-3/Makefile > index 70152b2..471b0f2a 100644 > --- a/arch/mips/loongson/loongson-3/Makefile > +++ b/arch/mips/loongson/loongson-3/Makefile > @@ -4,3 +4,5 @@ > obj-y += irq.o > > obj-$(CONFIG_SMP) += smp.o > + > +obj-$(CONFIG_NUMA) += numa.o > diff --git a/arch/mips/loongson/loongson-3/numa.c b/arch/mips/loongson/loongson-3/numa.c > new file mode 100644 > index 0000000..ca025a6 > --- /dev/null > +++ b/arch/mips/loongson/loongson-3/numa.c > @@ -0,0 +1,291 @@ > +/* > + * Copyright (C) 2010 Loongson Inc. & Lemote Inc. & > + * Insititute of Computing Technology > + * Author: Xiang Gao, gaoxiang@xxxxxxxxx > + * Huacai Chen, chenhc@xxxxxxxxxx > + * Xiaofu Meng, Shuangshuang Zhang > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + */ > +#include <linux/init.h> > +#include <linux/kernel.h> > +#include <linux/mm.h> > +#include <linux/mmzone.h> > +#include <linux/module.h> > +#include <linux/nodemask.h> > +#include <linux/swap.h> > +#include <linux/memblock.h> > +#include <linux/bootmem.h> > +#include <linux/pfn.h> > +#include <linux/highmem.h> > +#include <asm/page.h> > +#include <asm/pgalloc.h> > +#include <asm/sections.h> > +#include <linux/bootmem.h> > +#include <linux/init.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> > + > +static struct node_data prealloc__node_data[MAX_NUMNODES]; > +unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES]; > +struct node_data *__node_data[MAX_NUMNODES]; > +EXPORT_SYMBOL(__node_data); > + > +static void enable_lpa(void) > +{ > + unsigned long value; > + > + value = __read_32bit_c0_register($16, 3); > + value |= 0x00000080; > + __write_32bit_c0_register($16, 3, value); > + value = __read_32bit_c0_register($16, 3); > + pr_info("CP0_Config3: CP0 16.3 (0x%lx)\n", value); > + > + value = __read_32bit_c0_register($5, 1); > + value |= 0x20000000; > + __write_32bit_c0_register($5, 1, value); > + value = __read_32bit_c0_register($5, 1); > + pr_info("CP0_PageGrain: CP0 5.1 (0x%lx)\n", value); > +} > + > +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 0; > + 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 unsigned long nid_to_addroffset(unsigned int nid) > +{ > + unsigned long result; > + switch (nid) { > + case 0: > + default: > + result = NODE0_ADDRSPACE_OFFSET; > + break; > + case 1: > + result = NODE1_ADDRSPACE_OFFSET; > + break; > + case 2: > + result = NODE2_ADDRSPACE_OFFSET; > + break; > + case 3: > + result = NODE3_ADDRSPACE_OFFSET; > + break; > + } > + return result; > +} > + > +static void __init szmem(unsigned int node) > +{ > + u32 i, mem_type; > + static unsigned long num_physpages = 0; > + u64 node_id, node_psize, start_pfn, end_pfn, mem_start, mem_size; > + > + /* Parse memory information and activate */ > + for (i = 0; i < loongson_memmap->nr_map; i++) { > + node_id = loongson_memmap->map[i].node_id; > + if (node_id != node) > + continue; > + > + mem_type = loongson_memmap->map[i].mem_type; > + mem_size = loongson_memmap->map[i].mem_size; > + mem_start = loongson_memmap->map[i].mem_start; > + > + switch (mem_type) { > + case SYSTEM_RAM_LOW: > + start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT; > + node_psize = (mem_size << 20) >> PAGE_SHIFT; > + end_pfn = start_pfn + node_psize; > + num_physpages += node_psize; > + pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n", > + (u32)node_id, mem_type, mem_start, mem_size); > + pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", > + start_pfn, end_pfn, num_physpages); > + add_memory_region((node_id << 44) + mem_start, > + (u64)mem_size << 20, BOOT_MEM_RAM); > + memblock_add_node(PFN_PHYS(start_pfn), > + PFN_PHYS(end_pfn - start_pfn), node); > + break; > + case SYSTEM_RAM_HIGH: > + start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT; > + node_psize = (mem_size << 20) >> PAGE_SHIFT; > + end_pfn = start_pfn + node_psize; > + num_physpages += node_psize; > + pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n", > + (u32)node_id, mem_type, mem_start, mem_size); > + pr_info(" start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n", > + start_pfn, end_pfn, num_physpages); > + add_memory_region((node_id << 44) + mem_start, > + (u64)mem_size << 20, BOOT_MEM_RAM); > + memblock_add_node(PFN_PHYS(start_pfn), > + PFN_PHYS(end_pfn - start_pfn), node); > + break; > + case MEM_RESERVED: > + pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n", > + (u32)node_id, mem_type, mem_start, mem_size); > + add_memory_region((node_id << 44) + mem_start, > + (u64)mem_size << 20, BOOT_MEM_RESERVED); > + memblock_reserve(((node_id << 44) + mem_start), > + mem_size << 20); > + break; > + } > + } > +} > + > +static void __init node_mem_init(unsigned int node) > +{ > + unsigned long bootmap_size; > + unsigned long node_addrspace_offset; > + unsigned long start_pfn, end_pfn, freepfn; > + > + node_addrspace_offset = nid_to_addroffset(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); > + freepfn = start_pfn; > + if (node == 0) > + freepfn = PFN_UP(__pa_symbol(&_end)); /* kernel end address */ > + pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx, freepfn=0x%lx\n", > + node, start_pfn, end_pfn, freepfn); > + > + __node_data[node] = prealloc__node_data + node; > + > + NODE_DATA(node)->bdata = &bootmem_node_data[node]; > + NODE_DATA(node)->node_start_pfn = start_pfn; > + NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn; > + > + bootmap_size = init_bootmem_node(NODE_DATA(node), freepfn, > + start_pfn, end_pfn); > + free_bootmem_with_active_regions(node, end_pfn); > + if (node == 0) /* used by finalize_initrd() */ > + max_low_pfn = end_pfn; > + > + /* This is reserved for the kernel and bdata->node_bootmem_map */ > + reserve_bootmem_node(NODE_DATA(node), start_pfn << PAGE_SHIFT, > + ((freepfn - start_pfn) << PAGE_SHIFT) + bootmap_size, > + BOOTMEM_DEFAULT); > + > + if (node == 0 && node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) { > + /* Reserve 0xff800000~0xffffffff for RS780E integrated GPU */ > + reserve_bootmem_node(NODE_DATA(node), > + (node_addrspace_offset | 0xff800000), > + 8 << 20, BOOTMEM_DEFAULT); > + } > + > + sparse_memory_present_with_active_regions(node); > +} > + > +static __init void prom_meminit(void) > +{ > + unsigned int node, cpu; > + > + 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); > + cpus_clear(__node_data[(node)]->cpumask); > + } > + } > + for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) { > + node = cpu / loongson_sysconf.cores_per_node; > + if (node >= num_online_nodes()) > + node = 0; > + pr_info("NUMA: set cpumask cpu %d on node %d\n", cpu, node); > + cpu_set(cpu, __node_data[(node)]->cpumask); > + } > +} > + > +void __init paging_init(void) > +{ > + unsigned node; > + unsigned long zones_size[MAX_NR_ZONES] = {0, }; > + > + pagetable_init(); > + > + for_each_online_node(node) { > + unsigned long start_pfn, end_pfn; > + > + get_pfn_range_for_nid(node, &start_pfn, &end_pfn); > + > + if (end_pfn > max_low_pfn) > + max_low_pfn = end_pfn; > + } > +#ifdef CONFIG_ZONE_DMA32 > + zones_size[ZONE_DMA32] = MAX_DMA32_PFN; > +#endif > + zones_size[ZONE_NORMAL] = max_low_pfn; > + free_area_init_nodes(zones_size); > +} > + > +void __init mem_init(void) > +{ > + high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT); > + free_all_bootmem(); > + setup_zero_pages(); /* This comes from node 0 */ > + mem_init_print_info(NULL); > +} > + > +/* 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) > +{ > + enable_lpa(); > + prom_meminit(); > +} > +EXPORT_SYMBOL(prom_init_numa_memory); > diff --git a/arch/mips/loongson/loongson-3/smp.c b/arch/mips/loongson/loongson-3/smp.c > index 3c320e7..ed0e2d0 100644 > --- a/arch/mips/loongson/loongson-3/smp.c > +++ b/arch/mips/loongson/loongson-3/smp.c > @@ -203,6 +203,8 @@ static void loongson3_init_secondary(void) > for (i = 0; i < loongson_sysconf.nr_cpus; i++) > loongson3_ipi_write32(0xffffffff, ipi_en0_regs[i]); > > + cpu_data[cpu].package = cpu / loongson_sysconf.cores_per_package; > + cpu_data[cpu].core = cpu % loongson_sysconf.cores_per_package; > per_cpu(cpu_state, cpu) = CPU_ONLINE; > > i = 0; > @@ -394,17 +396,19 @@ static int loongson3_cpu_callback(struct notifier_block *nfb, > unsigned long action, void *hcpu) > { > unsigned int cpu = (unsigned long)hcpu; > + uint64_t core_id = cpu_data[cpu].core; > + uint64_t package_id = cpu_data[cpu].package; > > switch (action) { > case CPU_POST_DEAD: > case CPU_POST_DEAD_FROZEN: > pr_info("Disable clock for CPU#%d\n", cpu); > - LOONGSON_CHIPCFG(0) &= ~(1 << (12 + cpu)); > + LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id)); > break; > case CPU_UP_PREPARE: > case CPU_UP_PREPARE_FROZEN: > pr_info("Enable clock for CPU#%d\n", cpu); > - LOONGSON_CHIPCFG(0) |= 1 << (12 + cpu); > + LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id); > break; > } > > -- Best regards, Alexander Sverdlin.