.. | .. |
---|
| 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 | { |
---|