| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * NUMA support, based on the x86 implementation. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2015 Cavium Inc. |
|---|
| 5 | 6 | * Author: Ganapatrao Kulkarni <gkulkarni@cavium.com> |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 8 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 9 | | - * published by the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
|---|
| 18 | 7 | */ |
|---|
| 19 | 8 | |
|---|
| 20 | 9 | #define pr_fmt(fmt) "NUMA: " fmt |
|---|
| 21 | 10 | |
|---|
| 22 | 11 | #include <linux/acpi.h> |
|---|
| 23 | | -#include <linux/bootmem.h> |
|---|
| 24 | 12 | #include <linux/memblock.h> |
|---|
| 25 | 13 | #include <linux/module.h> |
|---|
| 26 | 14 | #include <linux/of.h> |
|---|
| .. | .. |
|---|
| 41 | 29 | { |
|---|
| 42 | 30 | if (!opt) |
|---|
| 43 | 31 | return -EINVAL; |
|---|
| 44 | | - if (!strncmp(opt, "off", 3)) |
|---|
| 32 | + if (str_has_prefix(opt, "off")) |
|---|
| 45 | 33 | numa_off = true; |
|---|
| 46 | 34 | |
|---|
| 47 | 35 | return 0; |
|---|
| .. | .. |
|---|
| 125 | 113 | } |
|---|
| 126 | 114 | |
|---|
| 127 | 115 | /* cpumask_of_node() will now work */ |
|---|
| 128 | | - pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids); |
|---|
| 116 | + pr_debug("Node to cpumask map for %u nodes\n", nr_node_ids); |
|---|
| 129 | 117 | } |
|---|
| 130 | 118 | |
|---|
| 131 | 119 | /* |
|---|
| 132 | | - * Set the cpu to node and mem mapping |
|---|
| 120 | + * Set the cpu to node and mem mapping |
|---|
| 133 | 121 | */ |
|---|
| 134 | 122 | void numa_store_cpu_info(unsigned int cpu) |
|---|
| 135 | 123 | { |
|---|
| .. | .. |
|---|
| 172 | 160 | { |
|---|
| 173 | 161 | int nid = early_cpu_to_node(cpu); |
|---|
| 174 | 162 | |
|---|
| 175 | | - return memblock_virt_alloc_try_nid(size, align, |
|---|
| 163 | + return memblock_alloc_try_nid(size, align, |
|---|
| 176 | 164 | __pa(MAX_DMA_ADDRESS), MEMBLOCK_ALLOC_ACCESSIBLE, nid); |
|---|
| 177 | 165 | } |
|---|
| 178 | 166 | |
|---|
| .. | .. |
|---|
| 205 | 193 | #endif |
|---|
| 206 | 194 | |
|---|
| 207 | 195 | /** |
|---|
| 208 | | - * numa_add_memblk - Set node id to memblk |
|---|
| 196 | + * numa_add_memblk() - Set node id to memblk |
|---|
| 209 | 197 | * @nid: NUMA node ID of the new memblk |
|---|
| 210 | 198 | * @start: Start address of the new memblk |
|---|
| 211 | 199 | * @end: End address of the new memblk |
|---|
| .. | .. |
|---|
| 228 | 216 | return ret; |
|---|
| 229 | 217 | } |
|---|
| 230 | 218 | |
|---|
| 231 | | -/** |
|---|
| 219 | +/* |
|---|
| 232 | 220 | * Initialize NODE_DATA for a node on the local memory |
|---|
| 233 | 221 | */ |
|---|
| 234 | 222 | static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn) |
|---|
| .. | .. |
|---|
| 241 | 229 | if (start_pfn >= end_pfn) |
|---|
| 242 | 230 | pr_info("Initmem setup node %d [<memory-less node>]\n", nid); |
|---|
| 243 | 231 | |
|---|
| 244 | | - nd_pa = memblock_alloc_try_nid(nd_size, SMP_CACHE_BYTES, nid); |
|---|
| 232 | + nd_pa = memblock_phys_alloc_try_nid(nd_size, SMP_CACHE_BYTES, nid); |
|---|
| 233 | + if (!nd_pa) |
|---|
| 234 | + panic("Cannot allocate %zu bytes for node %d data\n", |
|---|
| 235 | + nd_size, nid); |
|---|
| 236 | + |
|---|
| 245 | 237 | nd = __va(nd_pa); |
|---|
| 246 | 238 | |
|---|
| 247 | 239 | /* report and initialize */ |
|---|
| .. | .. |
|---|
| 258 | 250 | NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn; |
|---|
| 259 | 251 | } |
|---|
| 260 | 252 | |
|---|
| 261 | | -/** |
|---|
| 253 | +/* |
|---|
| 262 | 254 | * numa_free_distance |
|---|
| 263 | 255 | * |
|---|
| 264 | 256 | * The current table is freed. |
|---|
| .. | .. |
|---|
| 278 | 270 | numa_distance = NULL; |
|---|
| 279 | 271 | } |
|---|
| 280 | 272 | |
|---|
| 281 | | -/** |
|---|
| 282 | | - * |
|---|
| 273 | +/* |
|---|
| 283 | 274 | * Create a new NUMA distance table. |
|---|
| 284 | | - * |
|---|
| 285 | 275 | */ |
|---|
| 286 | 276 | static int __init numa_alloc_distance(void) |
|---|
| 287 | 277 | { |
|---|
| .. | .. |
|---|
| 312 | 302 | } |
|---|
| 313 | 303 | |
|---|
| 314 | 304 | /** |
|---|
| 315 | | - * numa_set_distance - Set inter node NUMA distance from node to node. |
|---|
| 305 | + * numa_set_distance() - Set inter node NUMA distance from node to node. |
|---|
| 316 | 306 | * @from: the 'from' node to set distance |
|---|
| 317 | 307 | * @to: the 'to' node to set distance |
|---|
| 318 | 308 | * @distance: NUMA distance |
|---|
| .. | .. |
|---|
| 322 | 312 | * |
|---|
| 323 | 313 | * If @from or @to is higher than the highest known node or lower than zero |
|---|
| 324 | 314 | * or @distance doesn't make sense, the call is ignored. |
|---|
| 325 | | - * |
|---|
| 326 | 315 | */ |
|---|
| 327 | 316 | void __init numa_set_distance(int from, int to, int distance) |
|---|
| 328 | 317 | { |
|---|
| .. | .. |
|---|
| 348 | 337 | numa_distance[from * numa_distance_cnt + to] = distance; |
|---|
| 349 | 338 | } |
|---|
| 350 | 339 | |
|---|
| 351 | | -/** |
|---|
| 340 | +/* |
|---|
| 352 | 341 | * Return NUMA distance @from to @to |
|---|
| 353 | 342 | */ |
|---|
| 354 | 343 | int __node_distance(int from, int to) |
|---|
| .. | .. |
|---|
| 365 | 354 | struct memblock_region *mblk; |
|---|
| 366 | 355 | |
|---|
| 367 | 356 | /* Check that valid nid is set to memblks */ |
|---|
| 368 | | - for_each_memblock(memory, mblk) |
|---|
| 369 | | - if (mblk->nid == NUMA_NO_NODE || mblk->nid >= MAX_NUMNODES) { |
|---|
| 357 | + for_each_mem_region(mblk) { |
|---|
| 358 | + int mblk_nid = memblock_get_region_node(mblk); |
|---|
| 359 | + |
|---|
| 360 | + if (mblk_nid == NUMA_NO_NODE || mblk_nid >= MAX_NUMNODES) { |
|---|
| 370 | 361 | pr_warn("Warning: invalid memblk node %d [mem %#010Lx-%#010Lx]\n", |
|---|
| 371 | | - mblk->nid, mblk->base, |
|---|
| 362 | + mblk_nid, mblk->base, |
|---|
| 372 | 363 | mblk->base + mblk->size - 1); |
|---|
| 373 | 364 | return -EINVAL; |
|---|
| 374 | 365 | } |
|---|
| 366 | + } |
|---|
| 375 | 367 | |
|---|
| 376 | 368 | /* Finally register nodes. */ |
|---|
| 377 | 369 | for_each_node_mask(nid, numa_nodes_parsed) { |
|---|
| .. | .. |
|---|
| 395 | 387 | nodes_clear(numa_nodes_parsed); |
|---|
| 396 | 388 | nodes_clear(node_possible_map); |
|---|
| 397 | 389 | nodes_clear(node_online_map); |
|---|
| 398 | | - numa_free_distance(); |
|---|
| 399 | 390 | |
|---|
| 400 | 391 | ret = numa_alloc_distance(); |
|---|
| 401 | 392 | if (ret < 0) |
|---|
| .. | .. |
|---|
| 403 | 394 | |
|---|
| 404 | 395 | ret = init_func(); |
|---|
| 405 | 396 | if (ret < 0) |
|---|
| 406 | | - return ret; |
|---|
| 397 | + goto out_free_distance; |
|---|
| 407 | 398 | |
|---|
| 408 | 399 | if (nodes_empty(numa_nodes_parsed)) { |
|---|
| 409 | 400 | pr_info("No NUMA configuration found\n"); |
|---|
| 410 | | - return -EINVAL; |
|---|
| 401 | + ret = -EINVAL; |
|---|
| 402 | + goto out_free_distance; |
|---|
| 411 | 403 | } |
|---|
| 412 | 404 | |
|---|
| 413 | 405 | ret = numa_register_nodes(); |
|---|
| 414 | 406 | if (ret < 0) |
|---|
| 415 | | - return ret; |
|---|
| 407 | + goto out_free_distance; |
|---|
| 416 | 408 | |
|---|
| 417 | 409 | setup_node_to_cpumask_map(); |
|---|
| 418 | 410 | |
|---|
| 419 | 411 | return 0; |
|---|
| 412 | +out_free_distance: |
|---|
| 413 | + numa_free_distance(); |
|---|
| 414 | + return ret; |
|---|
| 420 | 415 | } |
|---|
| 421 | 416 | |
|---|
| 422 | 417 | /** |
|---|
| 423 | | - * dummy_numa_init - Fallback dummy NUMA init |
|---|
| 418 | + * dummy_numa_init() - Fallback dummy NUMA init |
|---|
| 424 | 419 | * |
|---|
| 425 | 420 | * Used if there's no underlying NUMA architecture, NUMA initialization |
|---|
| 426 | 421 | * fails, or NUMA is disabled on the command line. |
|---|
| 427 | 422 | * |
|---|
| 428 | 423 | * Must online at least one node (node 0) and add memory blocks that cover all |
|---|
| 429 | 424 | * allowed memory. It is unlikely that this function fails. |
|---|
| 425 | + * |
|---|
| 426 | + * Return: 0 on success, -errno on failure. |
|---|
| 430 | 427 | */ |
|---|
| 431 | 428 | static int __init dummy_numa_init(void) |
|---|
| 432 | 429 | { |
|---|
| 430 | + phys_addr_t start = memblock_start_of_DRAM(); |
|---|
| 431 | + phys_addr_t end = memblock_end_of_DRAM(); |
|---|
| 433 | 432 | int ret; |
|---|
| 434 | | - struct memblock_region *mblk; |
|---|
| 435 | 433 | |
|---|
| 436 | 434 | if (numa_off) |
|---|
| 437 | 435 | pr_info("NUMA disabled\n"); /* Forced off on command line. */ |
|---|
| 438 | | - pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n", |
|---|
| 439 | | - memblock_start_of_DRAM(), memblock_end_of_DRAM() - 1); |
|---|
| 436 | + pr_info("Faking a node at [mem %#018Lx-%#018Lx]\n", start, end - 1); |
|---|
| 440 | 437 | |
|---|
| 441 | | - for_each_memblock(memory, mblk) { |
|---|
| 442 | | - ret = numa_add_memblk(0, mblk->base, mblk->base + mblk->size); |
|---|
| 443 | | - if (!ret) |
|---|
| 444 | | - continue; |
|---|
| 445 | | - |
|---|
| 438 | + ret = numa_add_memblk(0, start, end); |
|---|
| 439 | + if (ret) { |
|---|
| 446 | 440 | pr_err("NUMA init failed\n"); |
|---|
| 447 | 441 | return ret; |
|---|
| 448 | 442 | } |
|---|
| .. | .. |
|---|
| 452 | 446 | } |
|---|
| 453 | 447 | |
|---|
| 454 | 448 | /** |
|---|
| 455 | | - * arm64_numa_init - Initialize NUMA |
|---|
| 449 | + * arm64_numa_init() - Initialize NUMA |
|---|
| 456 | 450 | * |
|---|
| 457 | | - * Try each configured NUMA initialization method until one succeeds. The |
|---|
| 458 | | - * last fallback is dummy single node config encomapssing whole memory. |
|---|
| 451 | + * Try each configured NUMA initialization method until one succeeds. The |
|---|
| 452 | + * last fallback is dummy single node config encompassing whole memory. |
|---|
| 459 | 453 | */ |
|---|
| 460 | 454 | void __init arm64_numa_init(void) |
|---|
| 461 | 455 | { |
|---|