From patchwork Mon Jan 18 16:36:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ganapatrao Kulkarni X-Patchwork-Id: 8056201 X-Patchwork-Delegate: horms@verge.net.au Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 6D02CBEEE5 for ; Mon, 18 Jan 2016 16:38:10 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0C2B82022A for ; Mon, 18 Jan 2016 16:38:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 896DE200D9 for ; Mon, 18 Jan 2016 16:38:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755910AbcARQhe (ORCPT ); Mon, 18 Jan 2016 11:37:34 -0500 Received: from mail-bn1bon0066.outbound.protection.outlook.com ([157.56.111.66]:34449 "EHLO na01-bn1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1755773AbcARQh2 (ORCPT ); Mon, 18 Jan 2016 11:37:28 -0500 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Ganapatrao.Kulkarni@caviumnetworks.com; Received: from mypc.cavium.com.com (111.93.218.67) by BY1PR0701MB1691.namprd07.prod.outlook.com (10.162.110.29) with Microsoft SMTP Server (TLS) id 15.1.365.19; Mon, 18 Jan 2016 16:37:15 +0000 From: Ganapatrao Kulkarni To: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , CC: Subject: [PATCH v9 3/6] arm64/arm, numa, dt: adding numa dt binding implementation for arm64 platforms. Date: Mon, 18 Jan 2016 22:06:02 +0530 Message-ID: <1453134965-6125-4-git-send-email-gkulkarni@caviumnetworks.com> X-Mailer: git-send-email 1.8.1.4 In-Reply-To: <1453134965-6125-1-git-send-email-gkulkarni@caviumnetworks.com> References: <1453134965-6125-1-git-send-email-gkulkarni@caviumnetworks.com> MIME-Version: 1.0 X-Originating-IP: [111.93.218.67] X-ClientProxiedBy: MA1PR01CA0010.INDPRD01.PROD.OUTLOOK.COM (25.164.117.17) To BY1PR0701MB1691.namprd07.prod.outlook.com (25.162.110.29) X-Microsoft-Exchange-Diagnostics: 1; BY1PR0701MB1691; 2:iJM/+waw8Avg+/QCKR1Xt11ziXJp55Eg9Km+wcvPuZlAjtfCumThRItDgBk3rM5NlwdqpYYcN41MSx6dY5VYOFwLxYppUPAcbXnA6uaepAFbCS2zmyIYQhkQytH7Y5EuxzEF2lMDOf3UpS49bmP8uw==; 3:Vt3xgDtR3RepDByHwBjHwWnJiB5t2uEAu919gjwyLwPu89t870MIdE/5gsyscZ6UWDglTCTH1JtyNDdkhsXDxFSUdTHLjl1G6FikfqwlJWs4bswWztI2mfA5yIdd+7qj; 25:pUAb3EOVg0Wb7Uln/KjW5bvPLekKVR/KsrqnPEAuaDLQIIZYe05pUpxqqoJMlWhELcg1Iz8ZcXQtuHVMZ2PSIVeCLkOiPZOkR6ZKTHBwVh4zoYe0j0NJ+rEmRGigeXQv5iYIWV7nqchx3VCBkl6x1d8BnQvVUSmkOORlGnzbcoNM+OLP0Wju19d27cOfuquwJ3bIcDLeFZEvubH+bfjuhtHyfCKP0MfSyrq8LF0nv8tcxMGilERVhpIblHTmFy5C X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY1PR0701MB1691; X-MS-Office365-Filtering-Correlation-Id: 985fe2fb-4db4-4ccf-e14a-08d32025a5d8 X-Microsoft-Exchange-Diagnostics: 1; BY1PR0701MB1691; 20:iCAOKc16s9D6jRPsPTnNjwy9+chEQ7UhrdBY5X+iWFmSaSFAszQZ59dWcFni+IywHo6AvHgNJdV4vQg3voWjKHw3/Rdi5OoxbsMwM2unVXIHAhHQNIfXPz8ZVgGD8Y57OXVDfAfvtqz3qsU7ZhvOX5mG+kjym6N1TLpdeBYIgZmaGF5TT1JoWPT4C3TBV0NeF/x/c1SEJ3xX4ztGF0eESyUyyRwwM4q0+3uLi5NvXdTmLOygwS4kMqWS9VVwk8jEOygdfLzKBL7xSuIdzogWdlv21Hv6Mmv8x5nRbIeK6iWzcMBXblbqpwwhhouTVSthOYB9ctzgm31uVdjAlrCtbpLP/NDRx0O21Qi0FBGhB3x34LxOMv5S3Afvq48hZLnvPkQQGRDZt9OxDI3cvY8p5PCocjJ+cXC4VVZ37h0UFjKInGAS8kp4E042Nc5B+J+aOEwQKJDUsr+DcDJywX9fyfi2sK4vlaiinlblhiJiDTWXpnELH7/mYH8yX9BHOrURIeZLhDNRliWKRZy/8a28g3u4ar0+38JWaY4oBnnGOfuwJ5hYljBzdg9bPC3BwR8JuhuznHW/HsUQ7fWBGDDCG/GenY3UirQ/s/F+kyo5V/A= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(2401047)(5005006)(520078)(8121501046)(10201501046)(3002001); SRVR:BY1PR0701MB1691; BCL:0; PCL:0; RULEID:; SRVR:BY1PR0701MB1691; X-Microsoft-Exchange-Diagnostics: 1; BY1PR0701MB1691; 4:RZVkJlqoPRwQYjS5ApKUrU/kOMU+7L/ze8Uha6OTDwzK+F+fwEIemS7cm1KTuyuMIojdk5bGj08ljugyHZfxJ3eTHBoj5LdhJSh/b8dMHQEKN+Xi72mhrQSav/zBmDIhNMvUfB+/v559bRLXTFG6KX0jovURQCMcOK2OZH6RwgHvsrLDaxexkzBb6MFBhqvw0uOI2ilF+pKupc0VsHvV4egRvR944BNH452CVcD/03qWWu0Jzqq95QpBXXu061Sh8/FqIQC5urvtSznzQtK48yQpUwJoYyCZ1W9fr4V+qIT1cRl619No4eBDSQwk0YIKCNI7LCNdh+voL+I3zs1eDYiLtf6bsfvFqPM1HYmmWMHBHKaOHsJGN1IGFVRjpqFB X-Forefront-PRVS: 08252193F3 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(6009001)(199003)(189002)(5009440100003)(87976001)(66066001)(4326007)(6116002)(5008740100001)(2201001)(1096002)(36756003)(3846002)(586003)(189998001)(19580395003)(47776003)(5004730100002)(50466002)(2441003)(50226001)(19580405001)(76176999)(48376002)(97736004)(15975445007)(101416001)(50986999)(5001770100001)(5003940100001)(4001450100002)(33646002)(229853001)(92566002)(2906002)(40100003)(105586002)(42186005)(77096005)(106356001)(122386002)(2950100001)(7099028)(921003)(2004002)(83996005)(1121003)(2101003); DIR:OUT; SFP:1101; SCL:1; SRVR:BY1PR0701MB1691; H:mypc.cavium.com.com; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: caviumnetworks.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; BY1PR0701MB1691; 23:LUchXYzmfJtioNHAdRpJpbjzBWRhJIlnkEub2Lm?= =?us-ascii?Q?NI9u6kWNVdC+6/uMnXsMELkFsb5/ZalUGiG/eh1GCjs+gel88gL17UrGomML?= =?us-ascii?Q?eHHA17LRPMCsSnLDPL2KB9fYu0lJr3AuSrK4HgYnE0i1/MRX2wU42b/hG8rG?= =?us-ascii?Q?nzeHEkgWmb/mv05n6ThbqSyWFovn2x7btNoHRwrrrkHnKXQ3V7/4hzbjZnkl?= =?us-ascii?Q?nVK4zAHnZJ0bKwTBGGJhtgWCZCJSVnveCyPQamL0FlA4tUpWnoTc7ZE1LCIv?= =?us-ascii?Q?7VLjqtow9UJKhBQzVxi+htMVsefy1gMEgu3MMWRcOsPWzCrfIsSPcMhmvBnS?= =?us-ascii?Q?EssB+48VEyShgzyjkXtFkuftF7+kxxfrmEq+a7E0Q+Zl2nEwDDH/6DKYlkrr?= =?us-ascii?Q?K+UwxkLDi7c7JbhiDI5mAGjDZHWtbO8LVOk3pODg2W8ei+d+MdkkmN87bxRA?= =?us-ascii?Q?mES6PxWDnHtOH/QjS6vf6iUb96OLD+Flu56dcS332RLNamKojtbJIr0jUkUL?= =?us-ascii?Q?blDhNLmR/cnR+mRd9dm8o30Xfb1R3NJjfLMPMK8I4NTXyv6SOymV15cI4vmC?= =?us-ascii?Q?BVJvQ3RbmfePorw/3FIe3j/c6+9F5UhqsVbdv72tbVTPH3uS8Z2E2YkFr4su?= =?us-ascii?Q?WI7YIioIxNKy4EJGxD8/JulAojcppqN657YEHhQDjs7T+PFieP/0Ikn8dGWw?= =?us-ascii?Q?rfvUSuLfvAc4hPbPMAbQ5z/jtwoa4zFDhU6bkU02992daNgnjkbtPsDsUYvb?= =?us-ascii?Q?VEpIrfx3Okj2rkLJDZltyema48r/GEaPZ8aQtmjlr73p+qeZMTQqW61u6PPH?= =?us-ascii?Q?kUiEbp8eXI/FkXT2dMit9YYFAEXp/aPwnlx69RyyJmlJbWOl1nuhdS6Q/8PD?= =?us-ascii?Q?CKS95IKWDJYJe046CoUK9i4nYEtt4Au4pFAxqrh4sDE3dL9U3gnaTTWk/OXw?= =?us-ascii?Q?TShfAZFlkj4p0ocHFhBLXoF5DJSZylA8ak441+1oavZ04KdsARLFeL7gkJu3?= =?us-ascii?Q?lLKeUV2qyFZKL5eXFwIIKGrcL43ovgwKcOFFFGVYAkJPFE1Op08ZH9Vt2xvk?= =?us-ascii?Q?eGixBIMq6RfaRvPfb1+Z126bwr9XdviWbQChC6T3yYF/ODan8lj9XqH+TZ7C?= =?us-ascii?Q?NzUGvyT0qqSGhL2cFNj23T8r51HkACGVMCmJfaSWLAuTcLY17wTKSnVI75UC?= =?us-ascii?Q?Dap/0oxBMznRTvm4pkOYgfp73VSjBjOV8o90FoAwWiO7scVFByIfyXCwJ8Q?= =?us-ascii?Q?=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; BY1PR0701MB1691; 5:PghizFR2xvw7ET/W9QYqjMWFr5pgUwePIAp5WWmjDVSvRnCcwXqmZBW9pOAyr/UZgYAUbIWwNUH+c8UP7FUgAk0E6uOcVLqJVjrbcvIq42NVquadkRFqiB4e0MudxmKjILgPU27z7Q51J/FXj7qEHw==; 24:dJ5GUDfHz8NCbrSyp5v7VLifEQAikyz15WZ6EfeBF+fLRr+zvgPqzU9coWP3aXUFdYZSY1j8uBxZSh7YnHJFbZzipUnfH9r47Nn9ipPotCE= SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: caviumnetworks.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Jan 2016 16:37:15.8951 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY1PR0701MB1691 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Adding numa dt binding support for arm64 based platforms. dt node parsing for numa topology is done using device property numa-node-id and device node distance-map. Reviewed-by: Robert Richter Signed-off-by: Ganapatrao Kulkarni --- arch/arm64/Kconfig | 10 ++ arch/arm64/include/asm/numa.h | 10 ++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/of_numa.c | 257 ++++++++++++++++++++++++++++++++++++++++++ arch/arm64/kernel/smp.c | 2 + arch/arm64/mm/numa.c | 10 +- 6 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/kernel/of_numa.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 74f5d73..775cf4a 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -515,6 +515,16 @@ config NUMA local memory of the CPU and add some more NUMA awareness to the kernel. +config OF_NUMA + bool "Device Tree NUMA support" + depends on NUMA + depends on OF + default y + help + Enable Device Tree NUMA support. + This enables the numa mapping of cpu, memory, io and + inter node distances using dt bindings. + config NODES_SHIFT int "Maximum NUMA Nodes (as a power of 2)" range 1 10 diff --git a/arch/arm64/include/asm/numa.h b/arch/arm64/include/asm/numa.h index f28f15b0..54deb38 100644 --- a/arch/arm64/include/asm/numa.h +++ b/arch/arm64/include/asm/numa.h @@ -37,4 +37,14 @@ void numa_store_cpu_info(unsigned int cpu); static inline void numa_store_cpu_info(unsigned int cpu) { } static inline void arm64_numa_init(void) { } #endif /* CONFIG_NUMA */ + +struct device_node; +#ifdef CONFIG_OF_NUMA +int __init arm64_of_numa_init(void); +void __init of_numa_set_node_info(unsigned int cpu, struct device_node *dn); +#else +static inline void of_numa_set_node_info(unsigned int cpu, + struct device_node *dn) { } +#endif + #endif /* __ASM_NUMA_H */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 474691f..7987763 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -41,6 +41,7 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o arm64-obj-$(CONFIG_PCI) += pci.o arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o arm64-obj-$(CONFIG_ACPI) += acpi.o +arm64-obj-$(CONFIG_OF_NUMA) += of_numa.o obj-y += $(arm64-obj-y) vdso/ obj-m += $(arm64-obj-m) diff --git a/arch/arm64/kernel/of_numa.c b/arch/arm64/kernel/of_numa.c new file mode 100644 index 0000000..2f9e34b --- /dev/null +++ b/arch/arm64/kernel/of_numa.c @@ -0,0 +1,257 @@ +/* + * OF NUMA Parsing support. + * + * Copyright (C) 2015 Cavium Inc. + * Author: Ganapatrao Kulkarni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include + +/* define default numa node to 0 */ +#define DEFAULT_NODE 0 +#define OF_NUMA_PROP "numa-node-id" + +/* Returns nid in the range [0..MAX_NUMNODES-1], + * or NUMA_NO_NODE if no valid numa-node-id entry found + * or DEFAULT_NODE if no numa-node-id entry exists + */ +static int of_numa_prop_to_nid(const __be32 *of_numa_prop, int length) +{ + int nid; + + if (!of_numa_prop) + return DEFAULT_NODE; + + if (length != sizeof(*of_numa_prop)) { + pr_warn("NUMA: Invalid of_numa_prop length %d found.\n", + length); + return NUMA_NO_NODE; + } + + nid = of_read_number(of_numa_prop, 1); + if (nid >= MAX_NUMNODES) { + pr_warn("NUMA: Invalid numa node %d found.\n", nid); + return NUMA_NO_NODE; + } + + return nid; +} + +/* Must hold reference to node during call */ +static int of_get_numa_nid(struct device_node *device) +{ + int length; + const __be32 *of_numa_prop; + + of_numa_prop = of_get_property(device, OF_NUMA_PROP, &length); + + return of_numa_prop_to_nid(of_numa_prop, length); +} + +static int __init early_init_of_get_numa_nid(unsigned long node) +{ + int length; + const __be32 *of_numa_prop; + + of_numa_prop = of_get_flat_dt_prop(node, OF_NUMA_PROP, &length); + + return of_numa_prop_to_nid(of_numa_prop, length); +} + +/* Walk the device tree upwards, looking for a numa-node-id property */ +int of_node_to_nid(struct device_node *device) +{ + struct device_node *parent; + int nid = NUMA_NO_NODE; + + of_node_get(device); + while (device) { + const __be32 *of_numa_prop; + int length; + + of_numa_prop = of_get_property(device, OF_NUMA_PROP, &length); + if (of_numa_prop) { + nid = of_numa_prop_to_nid(of_numa_prop, length); + break; + } + + parent = device; + device = of_get_parent(parent); + of_node_put(parent); + } + of_node_put(device); + + return nid; +} + +void __init of_numa_set_node_info(unsigned int cpu, struct device_node *device) +{ + int nid = DEFAULT_NODE; + + if (device) + nid = of_get_numa_nid(device); + + cpu_to_node_map[cpu] = nid; +} + +/* + * Even though we connect cpus to numa domains later in SMP + * init, we need to know the node ids now for all cpus. +*/ +static int __init early_init_parse_cpu_node(unsigned long node) +{ + int nid; + + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + + /* We are scanning "cpu" nodes only */ + if (type == NULL) + return 0; + else if (strcmp(type, "cpu") != 0) + return 0; + + nid = early_init_of_get_numa_nid(node); + + if (nid == NUMA_NO_NODE) + return -EINVAL; + + node_set(nid, numa_nodes_parsed); + return 0; +} + +static int __init early_init_parse_memory_node(unsigned long node) +{ + const __be32 *reg, *endp; + int length; + int nid; + + const char *type = of_get_flat_dt_prop(node, "device_type", NULL); + + /* We are scanning "memory" nodes only */ + if (type == NULL) + return 0; + else if (strcmp(type, "memory") != 0) + return 0; + + nid = early_init_of_get_numa_nid(node); + + if (nid == NUMA_NO_NODE) + return -EINVAL; + + reg = of_get_flat_dt_prop(node, "reg", &length); + endp = reg + (length / sizeof(__be32)); + + while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { + u64 base, size; + + base = dt_mem_next_cell(dt_root_addr_cells, ®); + size = dt_mem_next_cell(dt_root_size_cells, ®); + pr_debug("NUMA-DT: base = %llx , node = %u\n", + base, nid); + + if (numa_add_memblk(nid, base, size) < 0) + return -EINVAL; + } + + return 0; +} + +static int __init early_init_parse_distance_map_v1(unsigned long node, + const char *uname) +{ + + const __be32 *prop_dist_matrix; + int length = 0, i, matrix_count; + int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT; + + pr_info("NUMA: parsing numa-distance-map-v1\n"); + + prop_dist_matrix = + of_get_flat_dt_prop(node, "distance-matrix", &length); + + if (!length) { + pr_err("NUMA: failed to parse distance-matrix\n"); + return -ENODEV; + } + + matrix_count = ((length / sizeof(__be32)) / (3 * nr_size_cells)); + + if ((matrix_count * sizeof(__be32) * 3 * nr_size_cells) != length) { + pr_warn("NUMA: invalid distance-matrix length %d\n", length); + return -EINVAL; + } + + for (i = 0; i < matrix_count; i++) { + u32 nodea, nodeb, distance; + + nodea = dt_mem_next_cell(nr_size_cells, &prop_dist_matrix); + nodeb = dt_mem_next_cell(nr_size_cells, &prop_dist_matrix); + distance = dt_mem_next_cell(nr_size_cells, &prop_dist_matrix); + numa_set_distance(nodea, nodeb, distance); + pr_debug("NUMA-DT: distance[node%d -> node%d] = %d\n", + nodea, nodeb, distance); + + /* Set default distance of node B->A same as A->B */ + if (nodeb > nodea) + numa_set_distance(nodeb, nodea, distance); + } + + return 0; +} + +static int __init early_init_parse_distance_map(unsigned long node, + const char *uname) +{ + + if (strcmp(uname, "distance-map") != 0) + return 0; + + if (of_flat_dt_is_compatible(node, "numa-distance-map-v1")) + return early_init_parse_distance_map_v1(node, uname); + + return -EINVAL; +} + +/** + * early_init_of_scan_numa_map - parse memory node and map nid to memory range. + */ +int __init early_init_of_scan_numa_map(unsigned long node, const char *uname, + int depth, void *data) +{ + int ret; + + ret = early_init_parse_cpu_node(node); + + if (!ret) + ret = early_init_parse_memory_node(node); + + if (!ret) + ret = early_init_parse_distance_map(node, uname); + + return ret; +} + +/* DT node mapping is done already early_init_of_scan_memory */ +int __init arm64_of_numa_init(void) +{ + return of_scan_flat_dt(early_init_of_scan_numa_map, NULL); +} diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index d6e7d6a..a2a8c2d 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -520,6 +520,8 @@ static void __init of_parse_and_init_cpus(void) pr_debug("cpu logical map 0x%llx\n", hwid); cpu_logical_map(cpu_count) = hwid; + /* map logical cpu to node */ + of_numa_set_node_info(cpu_count, dn); next: cpu_count++; } diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c index 050b083..9e8704b 100644 --- a/arch/arm64/mm/numa.c +++ b/arch/arm64/mm/numa.c @@ -383,5 +383,13 @@ static int __init dummy_numa_init(void) */ void __init arm64_numa_init(void) { - numa_init(dummy_numa_init); + int ret = -ENODEV; + +#ifdef CONFIG_OF_NUMA + if (!numa_off) + ret = numa_init(arm64_of_numa_init); +#endif + + if (ret) + numa_init(dummy_numa_init); }