linux/arch/mips/loongson64/loongson-3/numa.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
   3 *                    Institute of Computing Technology
   4 * Author:  Xiang Gao, gaoxiang@ict.ac.cn
   5 *          Huacai Chen, chenhc@lemote.com
   6 *          Xiaofu Meng, Shuangshuang Zhang
   7 *
   8 * This program is free software; you can redistribute  it and/or modify it
   9 * under  the terms of  the GNU General  Public License as published by the
  10 * Free Software Foundation;  either version 2 of the  License, or (at your
  11 * option) any later version.
  12 */
  13#include <linux/init.h>
  14#include <linux/kernel.h>
  15#include <linux/mm.h>
  16#include <linux/mmzone.h>
  17#include <linux/export.h>
  18#include <linux/nodemask.h>
  19#include <linux/swap.h>
  20#include <linux/memblock.h>
  21#include <linux/bootmem.h>
  22#include <linux/pfn.h>
  23#include <linux/highmem.h>
  24#include <asm/page.h>
  25#include <asm/pgalloc.h>
  26#include <asm/sections.h>
  27#include <linux/irq.h>
  28#include <asm/bootinfo.h>
  29#include <asm/mc146818-time.h>
  30#include <asm/time.h>
  31#include <asm/wbflush.h>
  32#include <boot_param.h>
  33
  34static struct node_data prealloc__node_data[MAX_NUMNODES];
  35unsigned char __node_distances[MAX_NUMNODES][MAX_NUMNODES];
  36EXPORT_SYMBOL(__node_distances);
  37struct node_data *__node_data[MAX_NUMNODES];
  38EXPORT_SYMBOL(__node_data);
  39
  40static void enable_lpa(void)
  41{
  42        unsigned long value;
  43
  44        value = __read_32bit_c0_register($16, 3);
  45        value |= 0x00000080;
  46        __write_32bit_c0_register($16, 3, value);
  47        value = __read_32bit_c0_register($16, 3);
  48        pr_info("CP0_Config3: CP0 16.3 (0x%lx)\n", value);
  49
  50        value = __read_32bit_c0_register($5, 1);
  51        value |= 0x20000000;
  52        __write_32bit_c0_register($5, 1, value);
  53        value = __read_32bit_c0_register($5, 1);
  54        pr_info("CP0_PageGrain: CP0 5.1 (0x%lx)\n", value);
  55}
  56
  57static void cpu_node_probe(void)
  58{
  59        int i;
  60
  61        nodes_clear(node_possible_map);
  62        nodes_clear(node_online_map);
  63        for (i = 0; i < loongson_sysconf.nr_nodes; i++) {
  64                node_set_state(num_online_nodes(), N_POSSIBLE);
  65                node_set_online(num_online_nodes());
  66        }
  67
  68        pr_info("NUMA: Discovered %d cpus on %d nodes\n",
  69                loongson_sysconf.nr_cpus, num_online_nodes());
  70}
  71
  72static int __init compute_node_distance(int row, int col)
  73{
  74        int package_row = row * loongson_sysconf.cores_per_node /
  75                                loongson_sysconf.cores_per_package;
  76        int package_col = col * loongson_sysconf.cores_per_node /
  77                                loongson_sysconf.cores_per_package;
  78
  79        if (col == row)
  80                return 0;
  81        else if (package_row == package_col)
  82                return 40;
  83        else
  84                return 100;
  85}
  86
  87static void __init init_topology_matrix(void)
  88{
  89        int row, col;
  90
  91        for (row = 0; row < MAX_NUMNODES; row++)
  92                for (col = 0; col < MAX_NUMNODES; col++)
  93                        __node_distances[row][col] = -1;
  94
  95        for_each_online_node(row) {
  96                for_each_online_node(col) {
  97                        __node_distances[row][col] =
  98                                compute_node_distance(row, col);
  99                }
 100        }
 101}
 102
 103static unsigned long nid_to_addroffset(unsigned int nid)
 104{
 105        unsigned long result;
 106        switch (nid) {
 107        case 0:
 108        default:
 109                result = NODE0_ADDRSPACE_OFFSET;
 110                break;
 111        case 1:
 112                result = NODE1_ADDRSPACE_OFFSET;
 113                break;
 114        case 2:
 115                result = NODE2_ADDRSPACE_OFFSET;
 116                break;
 117        case 3:
 118                result = NODE3_ADDRSPACE_OFFSET;
 119                break;
 120        }
 121        return result;
 122}
 123
 124static void __init szmem(unsigned int node)
 125{
 126        u32 i, mem_type;
 127        static unsigned long num_physpages = 0;
 128        u64 node_id, node_psize, start_pfn, end_pfn, mem_start, mem_size;
 129
 130        /* Parse memory information and activate */
 131        for (i = 0; i < loongson_memmap->nr_map; i++) {
 132                node_id = loongson_memmap->map[i].node_id;
 133                if (node_id != node)
 134                        continue;
 135
 136                mem_type = loongson_memmap->map[i].mem_type;
 137                mem_size = loongson_memmap->map[i].mem_size;
 138                mem_start = loongson_memmap->map[i].mem_start;
 139
 140                switch (mem_type) {
 141                case SYSTEM_RAM_LOW:
 142                        start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT;
 143                        node_psize = (mem_size << 20) >> PAGE_SHIFT;
 144                        end_pfn  = start_pfn + node_psize;
 145                        num_physpages += node_psize;
 146                        pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
 147                                (u32)node_id, mem_type, mem_start, mem_size);
 148                        pr_info("       start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
 149                                start_pfn, end_pfn, num_physpages);
 150                        add_memory_region((node_id << 44) + mem_start,
 151                                (u64)mem_size << 20, BOOT_MEM_RAM);
 152                        memblock_add_node(PFN_PHYS(start_pfn),
 153                                PFN_PHYS(end_pfn - start_pfn), node);
 154                        break;
 155                case SYSTEM_RAM_HIGH:
 156                        start_pfn = ((node_id << 44) + mem_start) >> PAGE_SHIFT;
 157                        node_psize = (mem_size << 20) >> PAGE_SHIFT;
 158                        end_pfn  = start_pfn + node_psize;
 159                        num_physpages += node_psize;
 160                        pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
 161                                (u32)node_id, mem_type, mem_start, mem_size);
 162                        pr_info("       start_pfn:0x%llx, end_pfn:0x%llx, num_physpages:0x%lx\n",
 163                                start_pfn, end_pfn, num_physpages);
 164                        add_memory_region((node_id << 44) + mem_start,
 165                                (u64)mem_size << 20, BOOT_MEM_RAM);
 166                        memblock_add_node(PFN_PHYS(start_pfn),
 167                                PFN_PHYS(end_pfn - start_pfn), node);
 168                        break;
 169                case MEM_RESERVED:
 170                        pr_info("Node%d: mem_type:%d, mem_start:0x%llx, mem_size:0x%llx MB\n",
 171                                (u32)node_id, mem_type, mem_start, mem_size);
 172                        add_memory_region((node_id << 44) + mem_start,
 173                                (u64)mem_size << 20, BOOT_MEM_RESERVED);
 174                        memblock_reserve(((node_id << 44) + mem_start),
 175                                mem_size << 20);
 176                        break;
 177                }
 178        }
 179}
 180
 181static void __init node_mem_init(unsigned int node)
 182{
 183        unsigned long bootmap_size;
 184        unsigned long node_addrspace_offset;
 185        unsigned long start_pfn, end_pfn, freepfn;
 186
 187        node_addrspace_offset = nid_to_addroffset(node);
 188        pr_info("Node%d's addrspace_offset is 0x%lx\n",
 189                        node, node_addrspace_offset);
 190
 191        get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
 192        freepfn = start_pfn;
 193        if (node == 0)
 194                freepfn = PFN_UP(__pa_symbol(&_end)); /* kernel end address */
 195        pr_info("Node%d: start_pfn=0x%lx, end_pfn=0x%lx, freepfn=0x%lx\n",
 196                node, start_pfn, end_pfn, freepfn);
 197
 198        __node_data[node] = prealloc__node_data + node;
 199
 200        NODE_DATA(node)->bdata = &bootmem_node_data[node];
 201        NODE_DATA(node)->node_start_pfn = start_pfn;
 202        NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
 203
 204        bootmap_size = init_bootmem_node(NODE_DATA(node), freepfn,
 205                                        start_pfn, end_pfn);
 206        free_bootmem_with_active_regions(node, end_pfn);
 207        if (node == 0) /* used by finalize_initrd() */
 208                max_low_pfn = end_pfn;
 209
 210        /* This is reserved for the kernel and bdata->node_bootmem_map */
 211        reserve_bootmem_node(NODE_DATA(node), start_pfn << PAGE_SHIFT,
 212                ((freepfn - start_pfn) << PAGE_SHIFT) + bootmap_size,
 213                BOOTMEM_DEFAULT);
 214
 215        if (node == 0 && node_end_pfn(0) >= (0xffffffff >> PAGE_SHIFT)) {
 216                /* Reserve 0xfe000000~0xffffffff for RS780E integrated GPU */
 217                reserve_bootmem_node(NODE_DATA(node),
 218                                (node_addrspace_offset | 0xfe000000),
 219                                32 << 20, BOOTMEM_DEFAULT);
 220        }
 221
 222        sparse_memory_present_with_active_regions(node);
 223}
 224
 225static __init void prom_meminit(void)
 226{
 227        unsigned int node, cpu, active_cpu = 0;
 228
 229        cpu_node_probe();
 230        init_topology_matrix();
 231
 232        for (node = 0; node < loongson_sysconf.nr_nodes; node++) {
 233                if (node_online(node)) {
 234                        szmem(node);
 235                        node_mem_init(node);
 236                        cpumask_clear(&__node_data[(node)]->cpumask);
 237                }
 238        }
 239        for (cpu = 0; cpu < loongson_sysconf.nr_cpus; cpu++) {
 240                node = cpu / loongson_sysconf.cores_per_node;
 241                if (node >= num_online_nodes())
 242                        node = 0;
 243
 244                if (loongson_sysconf.reserved_cpus_mask & (1<<cpu))
 245                        continue;
 246
 247                cpumask_set_cpu(active_cpu, &__node_data[(node)]->cpumask);
 248                pr_info("NUMA: set cpumask cpu %d on node %d\n", active_cpu, node);
 249
 250                active_cpu++;
 251        }
 252}
 253
 254void __init paging_init(void)
 255{
 256        unsigned node;
 257        unsigned long zones_size[MAX_NR_ZONES] = {0, };
 258
 259        pagetable_init();
 260
 261        for_each_online_node(node) {
 262                unsigned long  start_pfn, end_pfn;
 263
 264                get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
 265
 266                if (end_pfn > max_low_pfn)
 267                        max_low_pfn = end_pfn;
 268        }
 269#ifdef CONFIG_ZONE_DMA32
 270        zones_size[ZONE_DMA32] = MAX_DMA32_PFN;
 271#endif
 272        zones_size[ZONE_NORMAL] = max_low_pfn;
 273        free_area_init_nodes(zones_size);
 274}
 275
 276void __init mem_init(void)
 277{
 278        high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
 279        free_all_bootmem();
 280        setup_zero_pages();     /* This comes from node 0 */
 281        mem_init_print_info(NULL);
 282}
 283
 284/* All PCI device belongs to logical Node-0 */
 285int pcibus_to_node(struct pci_bus *bus)
 286{
 287        return 0;
 288}
 289EXPORT_SYMBOL(pcibus_to_node);
 290
 291void __init prom_init_numa_memory(void)
 292{
 293        enable_lpa();
 294        prom_meminit();
 295}
 296EXPORT_SYMBOL(prom_init_numa_memory);
 297