From patchwork Tue Nov 27 20:32:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Bringmann X-Patchwork-Id: 1004006 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 434Ftj5msWz9s0n for ; Wed, 28 Nov 2018 07:36:29 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 434Ftj1n2bzDqZT for ; Wed, 28 Nov 2018 07:36:29 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=mwb@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 434Fp02XVqzDqRG for ; Wed, 28 Nov 2018 07:32:24 +1100 (AEDT) Received: from pps.filterd (m0098416.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id wARK9rIg093891 for ; Tue, 27 Nov 2018 15:32:22 -0500 Received: from e15.ny.us.ibm.com (e15.ny.us.ibm.com [129.33.205.205]) by mx0b-001b2d01.pphosted.com with ESMTP id 2p1ch99cyq-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 27 Nov 2018 15:32:21 -0500 Received: from localhost by e15.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 27 Nov 2018 20:32:21 -0000 Received: from b01cxnp22036.gho.pok.ibm.com (9.57.198.26) by e15.ny.us.ibm.com (146.89.104.202) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 27 Nov 2018 20:32:18 -0000 Received: from b01ledav002.gho.pok.ibm.com (b01ledav002.gho.pok.ibm.com [9.57.199.107]) by b01cxnp22036.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id wARKWHHP17760358 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 27 Nov 2018 20:32:17 GMT Received: from b01ledav002.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B6DAF12405E; Tue, 27 Nov 2018 20:32:17 +0000 (GMT) Received: from b01ledav002.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 786C712405B; Tue, 27 Nov 2018 20:32:17 +0000 (GMT) Received: from ltczep4-lp5.aus.stglabs.ibm.com (unknown [9.40.193.67]) by b01ledav002.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 27 Nov 2018 20:32:17 +0000 (GMT) Received: from ltczep4-lp5.aus.stglabs.ibm.com (localhost [IPv6:::1]) by ltczep4-lp5.aus.stglabs.ibm.com (Postfix) with ESMTP id 296DC400C857; Tue, 27 Nov 2018 14:32:17 -0600 (CST) Subject: [PATCH 1/4] powerpc/pseries: Relocate drmem.c to pseries From: Michael Bringmann To: linuxppc-dev@lists.ozlabs.org, linuxppc-dev@lists.ozlabs.org Date: Tue, 27 Nov 2018 14:32:17 -0600 In-Reply-To: <20181127203129.12853.49746.stgit@ltczep4-lp5.aus.stglabs.ibm.com> References: <20181127203129.12853.49746.stgit@ltczep4-lp5.aus.stglabs.ibm.com> User-Agent: StGit/0.18-105-g416a-dirty MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 18112720-0068-0000-0000-00000367E530 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00010132; HX=3.00000242; KW=3.00000007; PH=3.00000004; SC=3.00000270; SDB=6.01123647; UDB=6.00583329; IPR=6.00903776; MB=3.00024358; MTD=3.00000008; XFM=3.00000015; UTC=2018-11-27 20:32:19 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18112720-0069-0000-0000-000046919C55 Message-Id: <20181127203158.12853.98967.stgit@ltczep4-lp5.aus.stglabs.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-11-27_17:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1811270172 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: mwb@linux.vnet.ibm.com, minkim@us.ibm.com, tlfalcon@linux.vnet.ibm.com, tyreld@linux.vnet.ibm.com Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" The implementation of the pseries-specific dynamic memory features is currently implemented in several non-pseries-specific files. This patch set moves the implementation of the device-tree parsing code for the properties ibm,dynamic-memory, ibm,dynamic-memory-v2, and its representation in the kernel into the platform-specific directory to the Pseries features. This patch moves drmem.c from kernel directory arch/powerpc/mm to powerpc/platforms/pseries. Signed-off-by: Michael Bringmann --- arch/powerpc/mm/Makefile | 2 arch/powerpc/mm/drmem.c | 447 ------------------------------- arch/powerpc/platforms/pseries/Makefile | 3 arch/powerpc/platforms/pseries/drmem.c | 447 +++++++++++++++++++++++++++++++ 4 files changed, 450 insertions(+), 449 deletions(-) delete mode 100644 arch/powerpc/mm/drmem.c create mode 100644 arch/powerpc/platforms/pseries/drmem.c diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index ca96e7b..06281e0f 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -9,7 +9,7 @@ CFLAGS_REMOVE_slb.o = $(CC_FLAGS_FTRACE) obj-y := fault.o mem.o pgtable.o mmap.o \ init_$(BITS).o pgtable_$(BITS).o \ - init-common.o mmu_context.o drmem.o + init-common.o mmu_context.o obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \ tlb_nohash_low.o obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(BITS)e.o diff --git a/arch/powerpc/mm/drmem.c b/arch/powerpc/mm/drmem.c deleted file mode 100644 index 3f18036..0000000 --- a/arch/powerpc/mm/drmem.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Dynamic reconfiguration memory support - * - * Copyright 2017 IBM Corporation - * - * 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. - */ - -#define pr_fmt(fmt) "drmem: " fmt - -#include -#include -#include -#include -#include -#include - -static struct drmem_lmb_info __drmem_info; -struct drmem_lmb_info *drmem_info = &__drmem_info; - -u64 drmem_lmb_memory_max(void) -{ - struct drmem_lmb *last_lmb; - - last_lmb = &drmem_info->lmbs[drmem_info->n_lmbs - 1]; - return last_lmb->base_addr + drmem_lmb_size(); -} - -static u32 drmem_lmb_flags(struct drmem_lmb *lmb) -{ - /* - * Return the value of the lmb flags field minus the reserved - * bit used internally for hotplug processing. - */ - return lmb->flags & ~DRMEM_LMB_RESERVED; -} - -static struct property *clone_property(struct property *prop, u32 prop_sz) -{ - struct property *new_prop; - - new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); - if (!new_prop) - return NULL; - - new_prop->name = kstrdup(prop->name, GFP_KERNEL); - new_prop->value = kzalloc(prop_sz, GFP_KERNEL); - if (!new_prop->name || !new_prop->value) { - kfree(new_prop->name); - kfree(new_prop->value); - kfree(new_prop); - return NULL; - } - - new_prop->length = prop_sz; -#if defined(CONFIG_OF_DYNAMIC) - of_property_set_flag(new_prop, OF_DYNAMIC); -#endif - return new_prop; -} - -static int drmem_update_dt_v1(struct device_node *memory, - struct property *prop) -{ - struct property *new_prop; - struct of_drconf_cell_v1 *dr_cell; - struct drmem_lmb *lmb; - u32 *p; - - new_prop = clone_property(prop, prop->length); - if (!new_prop) - return -1; - - p = new_prop->value; - *p++ = cpu_to_be32(drmem_info->n_lmbs); - - dr_cell = (struct of_drconf_cell_v1 *)p; - - for_each_drmem_lmb(lmb) { - dr_cell->base_addr = cpu_to_be64(lmb->base_addr); - dr_cell->drc_index = cpu_to_be32(lmb->drc_index); - dr_cell->aa_index = cpu_to_be32(lmb->aa_index); - dr_cell->flags = cpu_to_be32(drmem_lmb_flags(lmb)); - - dr_cell++; - } - - of_update_property(memory, new_prop); - return 0; -} - -static void init_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, - struct drmem_lmb *lmb) -{ - dr_cell->base_addr = cpu_to_be64(lmb->base_addr); - dr_cell->drc_index = cpu_to_be32(lmb->drc_index); - dr_cell->aa_index = cpu_to_be32(lmb->aa_index); - dr_cell->flags = cpu_to_be32(drmem_lmb_flags(lmb)); -} - -static int drmem_update_dt_v2(struct device_node *memory, - struct property *prop) -{ - struct property *new_prop; - struct of_drconf_cell_v2 *dr_cell; - struct drmem_lmb *lmb, *prev_lmb; - u32 lmb_sets, prop_sz, seq_lmbs; - u32 *p; - - /* First pass, determine how many LMB sets are needed. */ - lmb_sets = 0; - prev_lmb = NULL; - for_each_drmem_lmb(lmb) { - if (!prev_lmb) { - prev_lmb = lmb; - lmb_sets++; - continue; - } - - if (prev_lmb->aa_index != lmb->aa_index || - drmem_lmb_flags(prev_lmb) != drmem_lmb_flags(lmb)) - lmb_sets++; - - prev_lmb = lmb; - } - - prop_sz = lmb_sets * sizeof(*dr_cell) + sizeof(__be32); - new_prop = clone_property(prop, prop_sz); - if (!new_prop) - return -1; - - p = new_prop->value; - *p++ = cpu_to_be32(lmb_sets); - - dr_cell = (struct of_drconf_cell_v2 *)p; - - /* Second pass, populate the LMB set data */ - prev_lmb = NULL; - seq_lmbs = 0; - for_each_drmem_lmb(lmb) { - if (prev_lmb == NULL) { - /* Start of first LMB set */ - prev_lmb = lmb; - init_drconf_v2_cell(dr_cell, lmb); - seq_lmbs++; - continue; - } - - if (prev_lmb->aa_index != lmb->aa_index || - drmem_lmb_flags(prev_lmb) != drmem_lmb_flags(lmb)) { - /* end of one set, start of another */ - dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs); - dr_cell++; - - init_drconf_v2_cell(dr_cell, lmb); - seq_lmbs = 1; - } else { - seq_lmbs++; - } - - prev_lmb = lmb; - } - - /* close out last LMB set */ - dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs); - of_update_property(memory, new_prop); - return 0; -} - -int drmem_update_dt(void) -{ - struct device_node *memory; - struct property *prop; - int rc = -1; - - memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); - if (!memory) - return -1; - - prop = of_find_property(memory, "ibm,dynamic-memory", NULL); - if (prop) { - rc = drmem_update_dt_v1(memory, prop); - } else { - prop = of_find_property(memory, "ibm,dynamic-memory-v2", NULL); - if (prop) - rc = drmem_update_dt_v2(memory, prop); - } - - of_node_put(memory); - return rc; -} - -static void __init read_drconf_v1_cell(struct drmem_lmb *lmb, - const __be32 **prop) -{ - const __be32 *p = *prop; - - lmb->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p); - lmb->drc_index = of_read_number(p++, 1); - - p++; /* skip reserved field */ - - lmb->aa_index = of_read_number(p++, 1); - lmb->flags = of_read_number(p++, 1); - - *prop = p; -} - -static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm, - void (*func)(struct drmem_lmb *, const __be32 **)) -{ - struct drmem_lmb lmb; - u32 i, n_lmbs; - - n_lmbs = of_read_number(prop++, 1); - if (n_lmbs == 0) - return; - - for (i = 0; i < n_lmbs; i++) { - read_drconf_v1_cell(&lmb, &prop); - func(&lmb, &usm); - } -} - -static void __init read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, - const __be32 **prop) -{ - const __be32 *p = *prop; - - dr_cell->seq_lmbs = of_read_number(p++, 1); - dr_cell->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p); - dr_cell->drc_index = of_read_number(p++, 1); - dr_cell->aa_index = of_read_number(p++, 1); - dr_cell->flags = of_read_number(p++, 1); - - *prop = p; -} - -static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm, - void (*func)(struct drmem_lmb *, const __be32 **)) -{ - struct of_drconf_cell_v2 dr_cell; - struct drmem_lmb lmb; - u32 i, j, lmb_sets; - - lmb_sets = of_read_number(prop++, 1); - if (lmb_sets == 0) - return; - - for (i = 0; i < lmb_sets; i++) { - read_drconf_v2_cell(&dr_cell, &prop); - - for (j = 0; j < dr_cell.seq_lmbs; j++) { - lmb.base_addr = dr_cell.base_addr; - dr_cell.base_addr += drmem_lmb_size(); - - lmb.drc_index = dr_cell.drc_index; - dr_cell.drc_index++; - - lmb.aa_index = dr_cell.aa_index; - lmb.flags = dr_cell.flags; - - func(&lmb, &usm); - } - } -} - -#ifdef CONFIG_PPC_PSERIES -void __init walk_drmem_lmbs_early(unsigned long node, - void (*func)(struct drmem_lmb *, const __be32 **)) -{ - const __be32 *prop, *usm; - int len; - - prop = of_get_flat_dt_prop(node, "ibm,lmb-size", &len); - if (!prop || len < dt_root_size_cells * sizeof(__be32)) - return; - - drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop); - - usm = of_get_flat_dt_prop(node, "linux,drconf-usable-memory", &len); - - prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &len); - if (prop) { - __walk_drmem_v1_lmbs(prop, usm, func); - } else { - prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory-v2", - &len); - if (prop) - __walk_drmem_v2_lmbs(prop, usm, func); - } - - memblock_dump_all(); -} - -#endif - -static int __init init_drmem_lmb_size(struct device_node *dn) -{ - const __be32 *prop; - int len; - - if (drmem_info->lmb_size) - return 0; - - prop = of_get_property(dn, "ibm,lmb-size", &len); - if (!prop || len < dt_root_size_cells * sizeof(__be32)) { - pr_info("Could not determine LMB size\n"); - return -1; - } - - drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop); - return 0; -} - -/* - * Returns the property linux,drconf-usable-memory if - * it exists (the property exists only in kexec/kdump kernels, - * added by kexec-tools) - */ -static const __be32 *of_get_usable_memory(struct device_node *dn) -{ - const __be32 *prop; - u32 len; - - prop = of_get_property(dn, "linux,drconf-usable-memory", &len); - if (!prop || len < sizeof(unsigned int)) - return NULL; - - return prop; -} - -void __init walk_drmem_lmbs(struct device_node *dn, - void (*func)(struct drmem_lmb *, const __be32 **)) -{ - const __be32 *prop, *usm; - - if (init_drmem_lmb_size(dn)) - return; - - usm = of_get_usable_memory(dn); - - prop = of_get_property(dn, "ibm,dynamic-memory", NULL); - if (prop) { - __walk_drmem_v1_lmbs(prop, usm, func); - } else { - prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL); - if (prop) - __walk_drmem_v2_lmbs(prop, usm, func); - } -} - -static void __init init_drmem_v1_lmbs(const __be32 *prop) -{ - struct drmem_lmb *lmb; - - drmem_info->n_lmbs = of_read_number(prop++, 1); - if (drmem_info->n_lmbs == 0) - return; - - drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), - GFP_KERNEL); - if (!drmem_info->lmbs) - return; - - for_each_drmem_lmb(lmb) - read_drconf_v1_cell(lmb, &prop); -} - -static void __init init_drmem_v2_lmbs(const __be32 *prop) -{ - struct drmem_lmb *lmb; - struct of_drconf_cell_v2 dr_cell; - const __be32 *p; - u32 i, j, lmb_sets; - int lmb_index; - - lmb_sets = of_read_number(prop++, 1); - if (lmb_sets == 0) - return; - - /* first pass, calculate the number of LMBs */ - p = prop; - for (i = 0; i < lmb_sets; i++) { - read_drconf_v2_cell(&dr_cell, &p); - drmem_info->n_lmbs += dr_cell.seq_lmbs; - } - - drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), - GFP_KERNEL); - if (!drmem_info->lmbs) - return; - - /* second pass, read in the LMB information */ - lmb_index = 0; - p = prop; - - for (i = 0; i < lmb_sets; i++) { - read_drconf_v2_cell(&dr_cell, &p); - - for (j = 0; j < dr_cell.seq_lmbs; j++) { - lmb = &drmem_info->lmbs[lmb_index++]; - - lmb->base_addr = dr_cell.base_addr; - dr_cell.base_addr += drmem_info->lmb_size; - - lmb->drc_index = dr_cell.drc_index; - dr_cell.drc_index++; - - lmb->aa_index = dr_cell.aa_index; - lmb->flags = dr_cell.flags; - } - } -} - -static int __init drmem_init(void) -{ - struct device_node *dn; - const __be32 *prop; - - dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); - if (!dn) { - pr_info("No dynamic reconfiguration memory found\n"); - return 0; - } - - if (init_drmem_lmb_size(dn)) { - of_node_put(dn); - return 0; - } - - prop = of_get_property(dn, "ibm,dynamic-memory", NULL); - if (prop) { - init_drmem_v1_lmbs(prop); - } else { - prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL); - if (prop) - init_drmem_v2_lmbs(prop); - } - - of_node_put(dn); - return 0; -} -late_initcall(drmem_init); diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index a43ec84..4278690 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -6,7 +6,8 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ of_helpers.o \ setup.o iommu.o event_sources.o ras.o \ firmware.o power.o dlpar.o mobility.o rng.o \ - pci.o pci_dlpar.o eeh_pseries.o msi.o + pci.o pci_dlpar.o eeh_pseries.o msi.o \ + drmem.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SCANLOG) += scanlog.o obj-$(CONFIG_KEXEC_CORE) += kexec.o diff --git a/arch/powerpc/platforms/pseries/drmem.c b/arch/powerpc/platforms/pseries/drmem.c new file mode 100644 index 0000000..3f18036 --- /dev/null +++ b/arch/powerpc/platforms/pseries/drmem.c @@ -0,0 +1,447 @@ +/* + * Dynamic reconfiguration memory support + * + * Copyright 2017 IBM Corporation + * + * 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. + */ + +#define pr_fmt(fmt) "drmem: " fmt + +#include +#include +#include +#include +#include +#include + +static struct drmem_lmb_info __drmem_info; +struct drmem_lmb_info *drmem_info = &__drmem_info; + +u64 drmem_lmb_memory_max(void) +{ + struct drmem_lmb *last_lmb; + + last_lmb = &drmem_info->lmbs[drmem_info->n_lmbs - 1]; + return last_lmb->base_addr + drmem_lmb_size(); +} + +static u32 drmem_lmb_flags(struct drmem_lmb *lmb) +{ + /* + * Return the value of the lmb flags field minus the reserved + * bit used internally for hotplug processing. + */ + return lmb->flags & ~DRMEM_LMB_RESERVED; +} + +static struct property *clone_property(struct property *prop, u32 prop_sz) +{ + struct property *new_prop; + + new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); + if (!new_prop) + return NULL; + + new_prop->name = kstrdup(prop->name, GFP_KERNEL); + new_prop->value = kzalloc(prop_sz, GFP_KERNEL); + if (!new_prop->name || !new_prop->value) { + kfree(new_prop->name); + kfree(new_prop->value); + kfree(new_prop); + return NULL; + } + + new_prop->length = prop_sz; +#if defined(CONFIG_OF_DYNAMIC) + of_property_set_flag(new_prop, OF_DYNAMIC); +#endif + return new_prop; +} + +static int drmem_update_dt_v1(struct device_node *memory, + struct property *prop) +{ + struct property *new_prop; + struct of_drconf_cell_v1 *dr_cell; + struct drmem_lmb *lmb; + u32 *p; + + new_prop = clone_property(prop, prop->length); + if (!new_prop) + return -1; + + p = new_prop->value; + *p++ = cpu_to_be32(drmem_info->n_lmbs); + + dr_cell = (struct of_drconf_cell_v1 *)p; + + for_each_drmem_lmb(lmb) { + dr_cell->base_addr = cpu_to_be64(lmb->base_addr); + dr_cell->drc_index = cpu_to_be32(lmb->drc_index); + dr_cell->aa_index = cpu_to_be32(lmb->aa_index); + dr_cell->flags = cpu_to_be32(drmem_lmb_flags(lmb)); + + dr_cell++; + } + + of_update_property(memory, new_prop); + return 0; +} + +static void init_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, + struct drmem_lmb *lmb) +{ + dr_cell->base_addr = cpu_to_be64(lmb->base_addr); + dr_cell->drc_index = cpu_to_be32(lmb->drc_index); + dr_cell->aa_index = cpu_to_be32(lmb->aa_index); + dr_cell->flags = cpu_to_be32(drmem_lmb_flags(lmb)); +} + +static int drmem_update_dt_v2(struct device_node *memory, + struct property *prop) +{ + struct property *new_prop; + struct of_drconf_cell_v2 *dr_cell; + struct drmem_lmb *lmb, *prev_lmb; + u32 lmb_sets, prop_sz, seq_lmbs; + u32 *p; + + /* First pass, determine how many LMB sets are needed. */ + lmb_sets = 0; + prev_lmb = NULL; + for_each_drmem_lmb(lmb) { + if (!prev_lmb) { + prev_lmb = lmb; + lmb_sets++; + continue; + } + + if (prev_lmb->aa_index != lmb->aa_index || + drmem_lmb_flags(prev_lmb) != drmem_lmb_flags(lmb)) + lmb_sets++; + + prev_lmb = lmb; + } + + prop_sz = lmb_sets * sizeof(*dr_cell) + sizeof(__be32); + new_prop = clone_property(prop, prop_sz); + if (!new_prop) + return -1; + + p = new_prop->value; + *p++ = cpu_to_be32(lmb_sets); + + dr_cell = (struct of_drconf_cell_v2 *)p; + + /* Second pass, populate the LMB set data */ + prev_lmb = NULL; + seq_lmbs = 0; + for_each_drmem_lmb(lmb) { + if (prev_lmb == NULL) { + /* Start of first LMB set */ + prev_lmb = lmb; + init_drconf_v2_cell(dr_cell, lmb); + seq_lmbs++; + continue; + } + + if (prev_lmb->aa_index != lmb->aa_index || + drmem_lmb_flags(prev_lmb) != drmem_lmb_flags(lmb)) { + /* end of one set, start of another */ + dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs); + dr_cell++; + + init_drconf_v2_cell(dr_cell, lmb); + seq_lmbs = 1; + } else { + seq_lmbs++; + } + + prev_lmb = lmb; + } + + /* close out last LMB set */ + dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs); + of_update_property(memory, new_prop); + return 0; +} + +int drmem_update_dt(void) +{ + struct device_node *memory; + struct property *prop; + int rc = -1; + + memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (!memory) + return -1; + + prop = of_find_property(memory, "ibm,dynamic-memory", NULL); + if (prop) { + rc = drmem_update_dt_v1(memory, prop); + } else { + prop = of_find_property(memory, "ibm,dynamic-memory-v2", NULL); + if (prop) + rc = drmem_update_dt_v2(memory, prop); + } + + of_node_put(memory); + return rc; +} + +static void __init read_drconf_v1_cell(struct drmem_lmb *lmb, + const __be32 **prop) +{ + const __be32 *p = *prop; + + lmb->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p); + lmb->drc_index = of_read_number(p++, 1); + + p++; /* skip reserved field */ + + lmb->aa_index = of_read_number(p++, 1); + lmb->flags = of_read_number(p++, 1); + + *prop = p; +} + +static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm, + void (*func)(struct drmem_lmb *, const __be32 **)) +{ + struct drmem_lmb lmb; + u32 i, n_lmbs; + + n_lmbs = of_read_number(prop++, 1); + if (n_lmbs == 0) + return; + + for (i = 0; i < n_lmbs; i++) { + read_drconf_v1_cell(&lmb, &prop); + func(&lmb, &usm); + } +} + +static void __init read_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell, + const __be32 **prop) +{ + const __be32 *p = *prop; + + dr_cell->seq_lmbs = of_read_number(p++, 1); + dr_cell->base_addr = dt_mem_next_cell(dt_root_addr_cells, &p); + dr_cell->drc_index = of_read_number(p++, 1); + dr_cell->aa_index = of_read_number(p++, 1); + dr_cell->flags = of_read_number(p++, 1); + + *prop = p; +} + +static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm, + void (*func)(struct drmem_lmb *, const __be32 **)) +{ + struct of_drconf_cell_v2 dr_cell; + struct drmem_lmb lmb; + u32 i, j, lmb_sets; + + lmb_sets = of_read_number(prop++, 1); + if (lmb_sets == 0) + return; + + for (i = 0; i < lmb_sets; i++) { + read_drconf_v2_cell(&dr_cell, &prop); + + for (j = 0; j < dr_cell.seq_lmbs; j++) { + lmb.base_addr = dr_cell.base_addr; + dr_cell.base_addr += drmem_lmb_size(); + + lmb.drc_index = dr_cell.drc_index; + dr_cell.drc_index++; + + lmb.aa_index = dr_cell.aa_index; + lmb.flags = dr_cell.flags; + + func(&lmb, &usm); + } + } +} + +#ifdef CONFIG_PPC_PSERIES +void __init walk_drmem_lmbs_early(unsigned long node, + void (*func)(struct drmem_lmb *, const __be32 **)) +{ + const __be32 *prop, *usm; + int len; + + prop = of_get_flat_dt_prop(node, "ibm,lmb-size", &len); + if (!prop || len < dt_root_size_cells * sizeof(__be32)) + return; + + drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop); + + usm = of_get_flat_dt_prop(node, "linux,drconf-usable-memory", &len); + + prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory", &len); + if (prop) { + __walk_drmem_v1_lmbs(prop, usm, func); + } else { + prop = of_get_flat_dt_prop(node, "ibm,dynamic-memory-v2", + &len); + if (prop) + __walk_drmem_v2_lmbs(prop, usm, func); + } + + memblock_dump_all(); +} + +#endif + +static int __init init_drmem_lmb_size(struct device_node *dn) +{ + const __be32 *prop; + int len; + + if (drmem_info->lmb_size) + return 0; + + prop = of_get_property(dn, "ibm,lmb-size", &len); + if (!prop || len < dt_root_size_cells * sizeof(__be32)) { + pr_info("Could not determine LMB size\n"); + return -1; + } + + drmem_info->lmb_size = dt_mem_next_cell(dt_root_size_cells, &prop); + return 0; +} + +/* + * Returns the property linux,drconf-usable-memory if + * it exists (the property exists only in kexec/kdump kernels, + * added by kexec-tools) + */ +static const __be32 *of_get_usable_memory(struct device_node *dn) +{ + const __be32 *prop; + u32 len; + + prop = of_get_property(dn, "linux,drconf-usable-memory", &len); + if (!prop || len < sizeof(unsigned int)) + return NULL; + + return prop; +} + +void __init walk_drmem_lmbs(struct device_node *dn, + void (*func)(struct drmem_lmb *, const __be32 **)) +{ + const __be32 *prop, *usm; + + if (init_drmem_lmb_size(dn)) + return; + + usm = of_get_usable_memory(dn); + + prop = of_get_property(dn, "ibm,dynamic-memory", NULL); + if (prop) { + __walk_drmem_v1_lmbs(prop, usm, func); + } else { + prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL); + if (prop) + __walk_drmem_v2_lmbs(prop, usm, func); + } +} + +static void __init init_drmem_v1_lmbs(const __be32 *prop) +{ + struct drmem_lmb *lmb; + + drmem_info->n_lmbs = of_read_number(prop++, 1); + if (drmem_info->n_lmbs == 0) + return; + + drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), + GFP_KERNEL); + if (!drmem_info->lmbs) + return; + + for_each_drmem_lmb(lmb) + read_drconf_v1_cell(lmb, &prop); +} + +static void __init init_drmem_v2_lmbs(const __be32 *prop) +{ + struct drmem_lmb *lmb; + struct of_drconf_cell_v2 dr_cell; + const __be32 *p; + u32 i, j, lmb_sets; + int lmb_index; + + lmb_sets = of_read_number(prop++, 1); + if (lmb_sets == 0) + return; + + /* first pass, calculate the number of LMBs */ + p = prop; + for (i = 0; i < lmb_sets; i++) { + read_drconf_v2_cell(&dr_cell, &p); + drmem_info->n_lmbs += dr_cell.seq_lmbs; + } + + drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb), + GFP_KERNEL); + if (!drmem_info->lmbs) + return; + + /* second pass, read in the LMB information */ + lmb_index = 0; + p = prop; + + for (i = 0; i < lmb_sets; i++) { + read_drconf_v2_cell(&dr_cell, &p); + + for (j = 0; j < dr_cell.seq_lmbs; j++) { + lmb = &drmem_info->lmbs[lmb_index++]; + + lmb->base_addr = dr_cell.base_addr; + dr_cell.base_addr += drmem_info->lmb_size; + + lmb->drc_index = dr_cell.drc_index; + dr_cell.drc_index++; + + lmb->aa_index = dr_cell.aa_index; + lmb->flags = dr_cell.flags; + } + } +} + +static int __init drmem_init(void) +{ + struct device_node *dn; + const __be32 *prop; + + dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (!dn) { + pr_info("No dynamic reconfiguration memory found\n"); + return 0; + } + + if (init_drmem_lmb_size(dn)) { + of_node_put(dn); + return 0; + } + + prop = of_get_property(dn, "ibm,dynamic-memory", NULL); + if (prop) { + init_drmem_v1_lmbs(prop); + } else { + prop = of_get_property(dn, "ibm,dynamic-memory-v2", NULL); + if (prop) + init_drmem_v2_lmbs(prop); + } + + of_node_put(dn); + return 0; +} +late_initcall(drmem_init); From patchwork Tue Nov 27 20:35:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Bringmann X-Patchwork-Id: 1004007 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 434FxC4zfCz9s3Z for ; Wed, 28 Nov 2018 07:38:39 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 434FxC2Z8GzDq6j for ; Wed, 28 Nov 2018 07:38:39 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=mwb@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 434FsX2q9szDqjZ for ; Wed, 28 Nov 2018 07:35:28 +1100 (AEDT) Received: from pps.filterd (m0098419.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id wARKY3HP003867 for ; Tue, 27 Nov 2018 15:35:26 -0500 Received: from e16.ny.us.ibm.com (e16.ny.us.ibm.com [129.33.205.206]) by mx0b-001b2d01.pphosted.com with ESMTP id 2p1cnah2je-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 27 Nov 2018 15:35:25 -0500 Received: from localhost by e16.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 27 Nov 2018 20:35:25 -0000 Received: from b01cxnp23032.gho.pok.ibm.com (9.57.198.27) by e16.ny.us.ibm.com (146.89.104.203) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 27 Nov 2018 20:35:23 -0000 Received: from b01ledav003.gho.pok.ibm.com (b01ledav003.gho.pok.ibm.com [9.57.199.108]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id wARKZMOa19005678 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 27 Nov 2018 20:35:22 GMT Received: from b01ledav003.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 93E31B2066; Tue, 27 Nov 2018 20:35:22 +0000 (GMT) Received: from b01ledav003.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0D31DB205F; Tue, 27 Nov 2018 20:35:21 +0000 (GMT) Received: from oc5000245537.ibm.com (unknown [9.53.179.223]) by b01ledav003.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 27 Nov 2018 20:35:21 +0000 (GMT) To: linuxppc-dev@lists.ozlabs.org From: Michael Bringmann Subject: [PATCH 2/4] powerpc/pseries: Move DRMEM processing out of prom.c Openpgp: preference=signencrypt Autocrypt: addr=mwb@linux.vnet.ibm.com; prefer-encrypt=mutual; keydata= xsBNBFcY7GcBCADzw3en+yzo9ASFGCfldVkIg95SAMPK0myXp2XJYET3zT45uBsX/uj9/2nA lBmXXeOSXnPfJ9V3vtiwcfATnWIsVt3tL6n1kqikzH9nXNxZT7MU/7gqzWZngMAWh/GJ9qyg DTOZdjsvdUNUWxtiLvBo7y+reA4HjlQhwhYxxvCpXBeRoF0qDWfQ8DkneemqINzDZPwSQ7zY t4F5iyN1I9GC5RNK8Y6jiKmm6bDkrrbtXPOtzXKs0J0FqWEIab/u3BDrRP3STDVPdXqViHua AjEzthQbGZm0VCxI4a7XjMi99g614/qDcXZCs00GLZ/VYIE8hB9C5Q+l66S60PLjRrxnABEB AAHNLU1pY2hhZWwgVy4gQnJpbmdtYW5uIDxtd2JAbGludXgudm5ldC5pYm0uY29tPsLAeAQT AQIAIgUCVxjsZwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQSEdag3dpuTI0NAf8 CKYTDKQLgOSjVrU2L5rM4lXaJRmQV6oidD3vIhKSnWRvPq9C29ifRG6ri20prTHAlc0vycgm 41HHg0y2vsGgNXGTWC2ObemoZBI7mySXe/7Tq5mD/semGzOp0YWZ7teqrkiSR8Bw0p+LdE7K QmT7tpjjvuhrtQ3RRojUYcuy1nWUsc4D+2cxsnZslsx84FUKxPbLagDgZmgBhUw/sUi40s6S AkdViVCVS0WANddLIpG0cfdsV0kCae/XdjK3mRK6drFKv1z+QFjvOhc8QIkkxFD0da9w3tJj oqnqHFV5gLcHO6/wizPx/NV90y6RngeBORkQiRFWxTXS4Oj9GVI/Us7ATQRXGOxnAQgAmJ5Y ikTWrMWPfiveUacETyEhWVl7u8UhZcx3yy2te8O0ay7t9fYcZgIEfQPPVVus89acIXlG3wYL DDPvb21OprLxi+ZJ2a0S5we+LcSWN1jByxJlbWBq+/LcMtGAOhNLpysY1gD0Y4UW/eKS+TFZ 562qKC3k1dBvnV9JXCgeS1taYFxRdVAn+2DwK3nuyG/DDq/XgJ5BtmyC3MMx8CiW3POj+O+l 6SedIeAfZlZ7/xhijx82g93h07VavUQRwMZgZFsqmuxBxVGiav2HB+dNvs3PFB087Pvc9OHe qhajPWOP/gNLMmvBvknn1NToM9a8/E8rzcIZXoYs4RggRRYh6wARAQABwsBfBBgBAgAJBQJX GOxnAhsMAAoJEEhHWoN3abky+RUH/jE08/r5QzaNKYeVhu0uVbgXu5fsxqr2cAxhf+KuwT3T efhEP2alarxzUZdEh4MsG6c+X2NYLbD3cryiXxVx/7kSAJEFQJfA5P06g8NLR25Qpq9BLsN7 ++dxQ+CLKzSEb1X24hYAJZpOhS8ev3ii+M/XIo+olDBKuTaTgB6elrg3CaxUsVgLBJ+jbRkW yQe2S5f/Ja1ThDpSSLLWLiLK/z7+gaqwhnwjQ8Z8Y9D2itJQcj4itHilwImsqwLG7SxzC0NX IQ5KaAFYdRcOgwR8VhhkOIVd70ObSZU+E4pTET1WDz4o65xZ89yfose1No0+r5ht/xWOOrh8 53/hcWvxHVs= Organization: IBM Linux Technology Center Date: Tue, 27 Nov 2018 14:35:21 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 Content-Language: en-US X-TM-AS-GCONF: 00 x-cbid: 18112720-0072-0000-0000-000003D0111C X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00010132; HX=3.00000242; KW=3.00000007; PH=3.00000004; SC=3.00000270; SDB=6.01123648; UDB=6.00582089; IPR=6.00903777; MB=3.00024358; MTD=3.00000008; XFM=3.00000015; UTC=2018-11-27 20:35:25 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18112720-0073-0000-0000-00004A400774 Message-Id: <26d3e11f-ec62-8d58-0d45-0e836db2231c@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-11-27_17:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1811270173 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Michael Bringmann , Juliet Kim , Thomas Falcon , Tyrel Datwyler Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" The implementation of the pseries-specific dynamic memory features is currently implemented in several non-pseries-specific files. This patch set moves the implementation of the device-tree parsing code for the properties ibm,dynamic-memory, ibm,dynamic-memory-v2, and its representation in the kernel into the platform-specific directory to the Pseries features. This patch refactors references to drmem features out of prom.c, so that they can be moved to drmem.c. Changes include creating a platform function platform_early_init_dt_scan_memory_ppc that any powerpc platform may implement, and moving a support function to powerpc/include/asm/sparsemem.h Signed-off-by: Michael Bringmann --- arch/powerpc/include/asm/platform.h | 23 ++++++++ arch/powerpc/include/asm/prom.h | 3 + arch/powerpc/include/asm/sparsemem.h | 19 +++++++ arch/powerpc/kernel/prom.c | 90 +------------------------------- arch/powerpc/platforms/pseries/drmem.c | 73 ++++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 86 deletions(-) create mode 100644 arch/powerpc/include/asm/platform.h diff --git a/arch/powerpc/include/asm/platform.h b/arch/powerpc/include/asm/platform.h new file mode 100644 index 0000000..36f0f9e --- /dev/null +++ b/arch/powerpc/include/asm/platform.h @@ -0,0 +1,23 @@ +#ifndef _POWERPC_PLATFORM_H +#define _POWERPC_PLATFORM_H +#ifdef __KERNEL__ + +/* + * Definitions for talking to the Platform-specific functions of PowerPC + * + * Copyright (C) 2018 Michael Bringmann, IBM Corp. + * + * 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 + +/* Memory initialization support */ +extern int platform_early_init_dt_scan_memory_ppc(unsigned long node, + const char *uname, + int depth, void *data); + +#endif /* __KERNEL__ */ +#endif /* _POWERPC_PLATFORM_H */ diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h index b04c5ce..4504773 100644 --- a/arch/powerpc/include/asm/prom.h +++ b/arch/powerpc/include/asm/prom.h @@ -180,5 +180,8 @@ extern int of_read_drc_info_cell(struct property **prop, /* Option Vector 6: IBM PAPR hints */ #define OV6_LINUX 0x02 /* Linux is our OS */ +/* Other functions */ +extern bool validate_mem_limit(u64 base, u64 *size); + #endif /* __KERNEL__ */ #endif /* _POWERPC_PROM_H */ diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h index 68da493..25edfc2 100644 --- a/arch/powerpc/include/asm/sparsemem.h +++ b/arch/powerpc/include/asm/sparsemem.h @@ -32,5 +32,24 @@ static inline int hot_add_scn_to_nid(unsigned long scn_addr) #endif /* CONFIG_NUMA */ #endif /* CONFIG_MEMORY_HOTPLUG */ + +#ifdef CONFIG_SPARSEMEM +static inline bool validate_mem_limit(u64 base, u64 *size) +{ + u64 max_mem = 1UL << (MAX_PHYSMEM_BITS); + + if (base >= max_mem) + return false; + if ((base + *size) > max_mem) + *size = max_mem - base; + return true; +} +#else +static inline bool validate_mem_limit(u64 base, u64 *size) +{ + return true; +} +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SPARSEMEM_H */ diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index fe758ce..ea32fee 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -58,7 +58,7 @@ #include #include #include -#include +#include #include @@ -444,96 +444,14 @@ static int __init early_init_dt_scan_chosen_ppc(unsigned long node, * size if it cross the limit. */ -#ifdef CONFIG_SPARSEMEM -static bool validate_mem_limit(u64 base, u64 *size) -{ - u64 max_mem = 1UL << (MAX_PHYSMEM_BITS); - - if (base >= max_mem) - return false; - if ((base + *size) > max_mem) - *size = max_mem - base; - return true; -} -#else -static bool validate_mem_limit(u64 base, u64 *size) -{ - return true; -} -#endif - -#ifdef CONFIG_PPC_PSERIES -/* - * Interpret the ibm dynamic reconfiguration memory LMBs. - * This contains a list of memory blocks along with NUMA affinity - * information. - */ -static void __init early_init_drmem_lmb(struct drmem_lmb *lmb, - const __be32 **usm) -{ - u64 base, size; - int is_kexec_kdump = 0, rngs; - - base = lmb->base_addr; - size = drmem_lmb_size(); - rngs = 1; - - /* - * Skip this block if the reserved bit is set in flags - * or if the block is not assigned to this partition. - */ - if ((lmb->flags & DRCONF_MEM_RESERVED) || - !(lmb->flags & DRCONF_MEM_ASSIGNED)) - return; - - if (*usm) - is_kexec_kdump = 1; - - if (is_kexec_kdump) { - /* - * For each memblock in ibm,dynamic-memory, a - * corresponding entry in linux,drconf-usable-memory - * property contains a counter 'p' followed by 'p' - * (base, size) duple. Now read the counter from - * linux,drconf-usable-memory property - */ - rngs = dt_mem_next_cell(dt_root_size_cells, usm); - if (!rngs) /* there are no (base, size) duple */ - return; - } - - do { - if (is_kexec_kdump) { - base = dt_mem_next_cell(dt_root_addr_cells, usm); - size = dt_mem_next_cell(dt_root_size_cells, usm); - } - - if (iommu_is_off) { - if (base >= 0x80000000ul) - continue; - if ((base + size) > 0x80000000ul) - size = 0x80000000ul - base; - } - - DBG("Adding: %llx -> %llx\n", base, size); - if (validate_mem_limit(base, &size)) - memblock_add(base, size); - } while (--rngs); -} -#endif /* CONFIG_PPC_PSERIES */ - static int __init early_init_dt_scan_memory_ppc(unsigned long node, const char *uname, int depth, void *data) { -#ifdef CONFIG_PPC_PSERIES - if (depth == 1 && - strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) { - walk_drmem_lmbs_early(node, early_init_drmem_lmb); + if (!platform_early_init_dt_scan_memory_ppc(node, uname, + depth, data)) return 0; - } -#endif - + return early_init_dt_scan_memory(node, uname, depth, data); } diff --git a/arch/powerpc/platforms/pseries/drmem.c b/arch/powerpc/platforms/pseries/drmem.c index 3f18036..ccb0d3b 100644 --- a/arch/powerpc/platforms/pseries/drmem.c +++ b/arch/powerpc/platforms/pseries/drmem.c @@ -17,6 +17,7 @@ #include #include #include +#include static struct drmem_lmb_info __drmem_info; struct drmem_lmb_info *drmem_info = &__drmem_info; @@ -445,3 +446,75 @@ static int __init drmem_init(void) return 0; } late_initcall(drmem_init); + + +/* + * Interpret the ibm dynamic reconfiguration memory LMBs. + * This contains a list of memory blocks along with NUMA affinity + * information. + */ +static void __init early_init_drmem_lmb(struct drmem_lmb *lmb, + const __be32 **usm) +{ + u64 base, size; + int is_kexec_kdump = 0, rngs; + + base = lmb->base_addr; + size = drmem_lmb_size(); + rngs = 1; + + /* + * Skip this block if the reserved bit is set in flags + * or if the block is not assigned to this partition. + */ + if ((lmb->flags & DRCONF_MEM_RESERVED) || + !(lmb->flags & DRCONF_MEM_ASSIGNED)) + return; + + if (*usm) + is_kexec_kdump = 1; + + if (is_kexec_kdump) { + /* + * For each memblock in ibm,dynamic-memory, a + * corresponding entry in linux,drconf-usable-memory + * property contains a counter 'p' followed by 'p' + * (base, size) duple. Now read the counter from + * linux,drconf-usable-memory property + */ + rngs = dt_mem_next_cell(dt_root_size_cells, usm); + if (!rngs) /* there are no (base, size) duple */ + return; + } + + do { + if (is_kexec_kdump) { + base = dt_mem_next_cell(dt_root_addr_cells, usm); + size = dt_mem_next_cell(dt_root_size_cells, usm); + } + + if (iommu_is_off) { + if (base >= 0x80000000ul) + continue; + if ((base + size) > 0x80000000ul) + size = 0x80000000ul - base; + } + + DBG("Adding: %llx -> %llx\n", base, size); + if (validate_mem_limit(base, &size)) + memblock_add(base, size); + } while (--rngs); +} + +int __init platform_early_init_dt_scan_memory_ppc(unsigned long node, + const char *uname, + int depth, void *data) +{ + if (depth == 1 && + strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) { + walk_drmem_lmbs_early(node, early_init_drmem_lmb); + return 0; + } + + return -ENODEV; +} From patchwork Tue Nov 27 20:37:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Bringmann X-Patchwork-Id: 1004008 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 434G0D1D6Qz9s0n for ; Wed, 28 Nov 2018 07:41:16 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 434G0C6kK8zDqkP for ; Wed, 28 Nov 2018 07:41:15 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (mailfrom) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=mwb@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 434FvV395xzDqG6 for ; Wed, 28 Nov 2018 07:37:10 +1100 (AEDT) Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id wARKY7pS069969 for ; Tue, 27 Nov 2018 15:37:08 -0500 Received: from e15.ny.us.ibm.com (e15.ny.us.ibm.com [129.33.205.205]) by mx0a-001b2d01.pphosted.com with ESMTP id 2p187xmucj-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 27 Nov 2018 15:37:07 -0500 Received: from localhost by e15.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 27 Nov 2018 20:37:06 -0000 Received: from b01cxnp23032.gho.pok.ibm.com (9.57.198.27) by e15.ny.us.ibm.com (146.89.104.202) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 27 Nov 2018 20:37:04 -0000 Received: from b01ledav003.gho.pok.ibm.com (b01ledav003.gho.pok.ibm.com [9.57.199.108]) by b01cxnp23032.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id wARKb3CR17825848 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 27 Nov 2018 20:37:03 GMT Received: from b01ledav003.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CB79EB2064; Tue, 27 Nov 2018 20:37:03 +0000 (GMT) Received: from b01ledav003.gho.pok.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 25E0DB2068; Tue, 27 Nov 2018 20:37:03 +0000 (GMT) Received: from oc5000245537.ibm.com (unknown [9.53.179.223]) by b01ledav003.gho.pok.ibm.com (Postfix) with ESMTP; Tue, 27 Nov 2018 20:37:03 +0000 (GMT) In-Reply-To: <20181127203129.12853.49746.stgit@ltczep4-lp5.aus.stglabs.ibm.com> To: linuxppc-dev@lists.ozlabs.org From: Michael Bringmann Subject: [PATCH 4/4] powerpc/pseries: Move DRMEM processing out of numa.c Openpgp: preference=signencrypt Autocrypt: addr=mwb@linux.vnet.ibm.com; prefer-encrypt=mutual; keydata= xsBNBFcY7GcBCADzw3en+yzo9ASFGCfldVkIg95SAMPK0myXp2XJYET3zT45uBsX/uj9/2nA lBmXXeOSXnPfJ9V3vtiwcfATnWIsVt3tL6n1kqikzH9nXNxZT7MU/7gqzWZngMAWh/GJ9qyg DTOZdjsvdUNUWxtiLvBo7y+reA4HjlQhwhYxxvCpXBeRoF0qDWfQ8DkneemqINzDZPwSQ7zY t4F5iyN1I9GC5RNK8Y6jiKmm6bDkrrbtXPOtzXKs0J0FqWEIab/u3BDrRP3STDVPdXqViHua AjEzthQbGZm0VCxI4a7XjMi99g614/qDcXZCs00GLZ/VYIE8hB9C5Q+l66S60PLjRrxnABEB AAHNLU1pY2hhZWwgVy4gQnJpbmdtYW5uIDxtd2JAbGludXgudm5ldC5pYm0uY29tPsLAeAQT AQIAIgUCVxjsZwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQSEdag3dpuTI0NAf8 CKYTDKQLgOSjVrU2L5rM4lXaJRmQV6oidD3vIhKSnWRvPq9C29ifRG6ri20prTHAlc0vycgm 41HHg0y2vsGgNXGTWC2ObemoZBI7mySXe/7Tq5mD/semGzOp0YWZ7teqrkiSR8Bw0p+LdE7K QmT7tpjjvuhrtQ3RRojUYcuy1nWUsc4D+2cxsnZslsx84FUKxPbLagDgZmgBhUw/sUi40s6S AkdViVCVS0WANddLIpG0cfdsV0kCae/XdjK3mRK6drFKv1z+QFjvOhc8QIkkxFD0da9w3tJj oqnqHFV5gLcHO6/wizPx/NV90y6RngeBORkQiRFWxTXS4Oj9GVI/Us7ATQRXGOxnAQgAmJ5Y ikTWrMWPfiveUacETyEhWVl7u8UhZcx3yy2te8O0ay7t9fYcZgIEfQPPVVus89acIXlG3wYL DDPvb21OprLxi+ZJ2a0S5we+LcSWN1jByxJlbWBq+/LcMtGAOhNLpysY1gD0Y4UW/eKS+TFZ 562qKC3k1dBvnV9JXCgeS1taYFxRdVAn+2DwK3nuyG/DDq/XgJ5BtmyC3MMx8CiW3POj+O+l 6SedIeAfZlZ7/xhijx82g93h07VavUQRwMZgZFsqmuxBxVGiav2HB+dNvs3PFB087Pvc9OHe qhajPWOP/gNLMmvBvknn1NToM9a8/E8rzcIZXoYs4RggRRYh6wARAQABwsBfBBgBAgAJBQJX GOxnAhsMAAoJEEhHWoN3abky+RUH/jE08/r5QzaNKYeVhu0uVbgXu5fsxqr2cAxhf+KuwT3T efhEP2alarxzUZdEh4MsG6c+X2NYLbD3cryiXxVx/7kSAJEFQJfA5P06g8NLR25Qpq9BLsN7 ++dxQ+CLKzSEb1X24hYAJZpOhS8ev3ii+M/XIo+olDBKuTaTgB6elrg3CaxUsVgLBJ+jbRkW yQe2S5f/Ja1ThDpSSLLWLiLK/z7+gaqwhnwjQ8Z8Y9D2itJQcj4itHilwImsqwLG7SxzC0NX IQ5KaAFYdRcOgwR8VhhkOIVd70ObSZU+E4pTET1WDz4o65xZ89yfose1No0+r5ht/xWOOrh8 53/hcWvxHVs= Organization: IBM Linux Technology Center Date: Tue, 27 Nov 2018 14:37:02 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 Content-Language: en-US X-TM-AS-GCONF: 00 x-cbid: 18112720-0068-0000-0000-00000367E5A1 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00010132; HX=3.00000242; KW=3.00000007; PH=3.00000004; SC=3.00000270; SDB=6.01123648; UDB=6.00583330; IPR=6.00903778; MB=3.00024358; MTD=3.00000008; XFM=3.00000015; UTC=2018-11-27 20:37:05 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18112720-0069-0000-0000-000046919EDF Message-Id: <3a12822f-d205-4921-7fdb-b5c3b07cd8b2@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2018-11-27_17:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1811270173 X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Michael Bringmann , Juliet Kim , Thomas Falcon , Tyrel Datwyler Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" The implementation of the pseries-specific dynamic memory features is currently implemented in several non-pseries-specific files. This patch set moves the implementation of the device-tree parsing code for the properties ibm,dynamic-memory, ibm,dynamic-memory-v2, and its representation in the kernel into the platform-specific directory to the Pseries features. This patch refactors references to drmem features out of numa.c, so that they can be moved to drmem.c. Changes include exporting a few support functions from numa.c via powerpc/include/asm/topology.h, and the creation of platform function platform_parse_numa_properties that any powerpc platform may implement. Signed-off-by: Michael Bringmann --- arch/powerpc/include/asm/topology.h | 13 + arch/powerpc/mm/numa.c | 238 +++-------------------- arch/powerpc/platforms/pseries/drmem.c | 330 ++++++++++++++++++++++++++++---- 3 files changed, 329 insertions(+), 252 deletions(-) diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index a4a718d..0c1ad7e 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -135,5 +135,18 @@ static inline void shared_proc_topology_init(void) {} #endif #endif +extern unsigned long numa_enforce_memory_limit(unsigned long start, + unsigned long size); +extern void initialize_distance_lookup_table(int nid, + const __be32 *associativity); +extern int fake_numa_create_new_node(unsigned long end_pfn, + unsigned int *nid); + +struct assoc_arrays { + u32 n_arrays; + u32 array_sz; + const __be32 *arrays; +}; + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_TOPOLOGY_H */ diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 3a048e9..6c982df 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -39,7 +39,6 @@ #include #include #include -#include static int numa_enabled = 1; @@ -87,8 +86,8 @@ static void __init setup_node_to_cpumask_map(void) dbg("Node to cpumask map for %d nodes\n", nr_node_ids); } -static int __init fake_numa_create_new_node(unsigned long end_pfn, - unsigned int *nid) +int __init fake_numa_create_new_node(unsigned long end_pfn, + unsigned int *nid) { unsigned long long mem; char *p = cmdline; @@ -194,7 +193,7 @@ int __node_distance(int a, int b) } EXPORT_SYMBOL(__node_distance); -static void initialize_distance_lookup_table(int nid, +void initialize_distance_lookup_table(int nid, const __be32 *associativity) { int i; @@ -209,6 +208,7 @@ static void initialize_distance_lookup_table(int nid, distance_lookup_table[nid][i] = of_read_number(entry, 1); } } +EXPORT_SYMBOL(initialize_distance_lookup_table); /* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa * info is found. @@ -356,98 +356,6 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) of_node_put(memory); } -static unsigned long read_n_cells(int n, const __be32 **buf) -{ - unsigned long result = 0; - - while (n--) { - result = (result << 32) | of_read_number(*buf, 1); - (*buf)++; - } - return result; -} - -struct assoc_arrays { - u32 n_arrays; - u32 array_sz; - const __be32 *arrays; -}; - -/* - * Retrieve and validate the list of associativity arrays for drconf - * memory from the ibm,associativity-lookup-arrays property of the - * device tree.. - * - * The layout of the ibm,associativity-lookup-arrays property is a number N - * indicating the number of associativity arrays, followed by a number M - * indicating the size of each associativity array, followed by a list - * of N associativity arrays. - */ -static int of_get_assoc_arrays(struct assoc_arrays *aa) -{ - struct device_node *memory; - const __be32 *prop; - u32 len; - - memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); - if (!memory) - return -1; - - prop = of_get_property(memory, "ibm,associativity-lookup-arrays", &len); - if (!prop || len < 2 * sizeof(unsigned int)) { - of_node_put(memory); - return -1; - } - - aa->n_arrays = of_read_number(prop++, 1); - aa->array_sz = of_read_number(prop++, 1); - - of_node_put(memory); - - /* Now that we know the number of arrays and size of each array, - * revalidate the size of the property read in. - */ - if (len < (aa->n_arrays * aa->array_sz + 2) * sizeof(unsigned int)) - return -1; - - aa->arrays = prop; - return 0; -} - -/* - * This is like of_node_to_nid_single() for memory represented in the - * ibm,dynamic-reconfiguration-memory node. - */ -static int of_drconf_to_nid_single(struct drmem_lmb *lmb) -{ - struct assoc_arrays aa = { .arrays = NULL }; - int default_nid = 0; - int nid = default_nid; - int rc, index; - - rc = of_get_assoc_arrays(&aa); - if (rc) - return default_nid; - - if (min_common_depth > 0 && min_common_depth <= aa.array_sz && - !(lmb->flags & DRCONF_MEM_AI_INVALID) && - lmb->aa_index < aa.n_arrays) { - index = lmb->aa_index * aa.array_sz + min_common_depth - 1; - nid = of_read_number(&aa.arrays[index], 1); - - if (nid == 0xffff || nid >= MAX_NUMNODES) - nid = default_nid; - - if (nid > 0) { - index = lmb->aa_index * aa.array_sz; - initialize_distance_lookup_table(nid, - &aa.arrays[index]); - } - } - - return nid; -} - /* * Figure out to which domain a cpu belongs and stick it there. * Return the id of the domain used. @@ -536,7 +444,7 @@ static int ppc_numa_cpu_dead(unsigned int cpu) * or zero. If the returned value of size is 0 the region should be * discarded as it lies wholly above the memory limit. */ -static unsigned long __init numa_enforce_memory_limit(unsigned long start, +unsigned long __init numa_enforce_memory_limit(unsigned long start, unsigned long size) { /* @@ -555,67 +463,20 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start, return memblock_end_of_DRAM() - start; } -/* - * Reads the counter for a given entry in - * linux,drconf-usable-memory property - */ -static inline int __init read_usm_ranges(const __be32 **usm) +static inline unsigned long read_n_cells(int n, const __be32 **buf) { - /* - * For each lmb in ibm,dynamic-memory a corresponding - * entry in linux,drconf-usable-memory property contains - * a counter followed by that many (base, size) duple. - * read the counter from linux,drconf-usable-memory - */ - return read_n_cells(n_mem_size_cells, usm); -} - -/* - * Extract NUMA information from the ibm,dynamic-reconfiguration-memory - * node. This assumes n_mem_{addr,size}_cells have been set. - */ -static void __init numa_setup_drmem_lmb(struct drmem_lmb *lmb, - const __be32 **usm) -{ - unsigned int ranges, is_kexec_kdump = 0; - unsigned long base, size, sz; - int nid; - - /* - * Skip this block if the reserved bit is set in flags (0x80) - * or if the block is not assigned to this partition (0x8) - */ - if ((lmb->flags & DRCONF_MEM_RESERVED) - || !(lmb->flags & DRCONF_MEM_ASSIGNED)) - return; - - if (*usm) - is_kexec_kdump = 1; - - base = lmb->base_addr; - size = drmem_lmb_size(); - ranges = 1; + unsigned long result = 0; - if (is_kexec_kdump) { - ranges = read_usm_ranges(usm); - if (!ranges) /* there are no (base, size) duple */ - return; + while (n--) { + result = (result << 32) | of_read_number(*buf, 1); + (*buf)++; } + return result; +} - do { - if (is_kexec_kdump) { - base = read_n_cells(n_mem_addr_cells, usm); - size = read_n_cells(n_mem_size_cells, usm); - } - - nid = of_drconf_to_nid_single(lmb); - fake_numa_create_new_node(((base + size) >> PAGE_SHIFT), - &nid); - node_set_online(nid); - sz = numa_enforce_memory_limit(base, size); - if (sz) - memblock_set_node(base, sz, &memblock.memory, nid); - } while (--ranges); +int __weak platform_parse_numa_properties(int min_common_depth) +{ + return min_common_depth; } static int __init parse_numa_properties(void) @@ -704,16 +565,7 @@ static int __init parse_numa_properties(void) goto new_range; } - /* - * Now do the same thing for each MEMBLOCK listed in the - * ibm,dynamic-memory property in the - * ibm,dynamic-reconfiguration-memory node. - */ - memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); - if (memory) { - walk_drmem_lmbs(memory, numa_setup_drmem_lmb); - of_node_put(memory); - } + min_common_depth = platform_parse_numa_properties(min_common_depth); return 0; } @@ -922,37 +774,6 @@ static int __init early_topology_updates(char *p) #ifdef CONFIG_MEMORY_HOTPLUG /* - * Find the node associated with a hot added memory section for - * memory represented in the device tree by the property - * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory. - */ -static int hot_add_drconf_scn_to_nid(unsigned long scn_addr) -{ - struct drmem_lmb *lmb; - unsigned long lmb_size; - int nid = -1; - - lmb_size = drmem_lmb_size(); - - for_each_drmem_lmb(lmb) { - /* skip this block if it is reserved or not assigned to - * this partition */ - if ((lmb->flags & DRCONF_MEM_RESERVED) - || !(lmb->flags & DRCONF_MEM_ASSIGNED)) - continue; - - if ((scn_addr < lmb->base_addr) - || (scn_addr >= (lmb->base_addr + lmb_size))) - continue; - - nid = of_drconf_to_nid_single(lmb); - break; - } - - return nid; -} - -/* * Find the node associated with a hot added memory section for memory * represented in the device tree as a node (i.e. memory@XXXX) for * each memblock. @@ -995,6 +816,11 @@ static int hot_add_node_scn_to_nid(unsigned long scn_addr) return nid; } +int __weak platform_hot_add_scn_to_nid(unsigned long scn_addr) +{ + return NUMA_NO_NODE; +} + /* * Find the node associated with a hot added memory section. Section * corresponds to a SPARSEMEM section, not an MEMBLOCK. It is assumed that @@ -1002,17 +828,14 @@ static int hot_add_node_scn_to_nid(unsigned long scn_addr) */ int hot_add_scn_to_nid(unsigned long scn_addr) { - struct device_node *memory = NULL; int nid; if (!numa_enabled || (min_common_depth < 0)) return first_online_node; - memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); - if (memory) { - nid = hot_add_drconf_scn_to_nid(scn_addr); - of_node_put(memory); - } else { + nid = platform_hot_add_scn_to_nid(scn_addr); + if (nid != NUMA_NO_NODE) + { nid = hot_add_node_scn_to_nid(scn_addr); } @@ -1022,9 +845,13 @@ int hot_add_scn_to_nid(unsigned long scn_addr) return nid; } +u64 __weak platform_hot_add_drconf_memory_max(void) +{ + return 0; +} + static u64 hot_add_drconf_memory_max(void) { - struct device_node *memory = NULL; struct device_node *dn = NULL; const __be64 *lrdr = NULL; @@ -1036,12 +863,7 @@ static u64 hot_add_drconf_memory_max(void) return be64_to_cpup(lrdr); } - memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); - if (memory) { - of_node_put(memory); - return drmem_lmb_memory_max(); - } - return 0; + return platform_hot_add_drconf_memory_max(); } /* diff --git a/arch/powerpc/platforms/pseries/drmem.c b/arch/powerpc/platforms/pseries/drmem.c index ccb0d3b..01ac651 100644 --- a/arch/powerpc/platforms/pseries/drmem.c +++ b/arch/powerpc/platforms/pseries/drmem.c @@ -16,8 +16,8 @@ #include #include #include +#include #include -#include static struct drmem_lmb_info __drmem_info; struct drmem_lmb_info *drmem_info = &__drmem_info; @@ -297,6 +297,76 @@ void __init walk_drmem_lmbs_early(unsigned long node, memblock_dump_all(); } +/* + * Interpret the ibm dynamic reconfiguration memory LMBs. + * This contains a list of memory blocks along with NUMA affinity + * information. + */ +static void __init early_init_drmem_lmb(struct drmem_lmb *lmb, + const __be32 **usm) +{ + u64 base, size; + int is_kexec_kdump = 0, rngs; + + base = lmb->base_addr; + size = drmem_lmb_size(); + rngs = 1; + + /* + * Skip this block if the reserved bit is set in flags + * or if the block is not assigned to this partition. + */ + if ((lmb->flags & DRCONF_MEM_RESERVED) || + !(lmb->flags & DRCONF_MEM_ASSIGNED)) + return; + + if (*usm) + is_kexec_kdump = 1; + + if (is_kexec_kdump) { + /* + * For each memblock in ibm,dynamic-memory, a + * corresponding entry in linux,drconf-usable-memory + * property contains a counter 'p' followed by 'p' + * (base, size) duple. Now read the counter from + * linux,drconf-usable-memory property + */ + rngs = dt_mem_next_cell(dt_root_size_cells, usm); + if (!rngs) /* there are no (base, size) duple */ + return; + } + + do { + if (is_kexec_kdump) { + base = dt_mem_next_cell(dt_root_addr_cells, usm); + size = dt_mem_next_cell(dt_root_size_cells, usm); + } + + if (iommu_is_off) { + if (base >= 0x80000000ul) + continue; + if ((base + size) > 0x80000000ul) + size = 0x80000000ul - base; + } + + pr_debug("Adding: %llx -> %llx\n", base, size); + if (validate_mem_limit(base, &size)) + memblock_add(base, size); + } while (--rngs); +} + +int __init platform_early_init_dt_scan_memory_ppc(unsigned long node, + const char *uname, + int depth, void *data) +{ + if (depth == 1 && + strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) { + walk_drmem_lmbs_early(node, early_init_drmem_lmb); + return 0; + } + + return -ENODEV; +} #endif static int __init init_drmem_lmb_size(struct device_node *dn) @@ -447,74 +517,246 @@ static int __init drmem_init(void) } late_initcall(drmem_init); +/* + * Retrieve and validate the list of associativity arrays for drconf + * memory from the ibm,associativity-lookup-arrays property of the + * device tree.. + * + * The layout of the ibm,associativity-lookup-arrays property is a number N + * indicating the number of associativity arrays, followed by a number M + * indicating the size of each associativity array, followed by a list + * of N associativity arrays. + */ +static int of_get_assoc_arrays(struct assoc_arrays *aa) +{ + struct device_node *memory; + const __be32 *prop; + u32 len; + + memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (!memory) + return -1; + + prop = of_get_property(memory, "ibm,associativity-lookup-arrays", &len); + if (!prop || len < 2 * sizeof(unsigned int)) { + of_node_put(memory); + return -1; + } + + aa->n_arrays = of_read_number(prop++, 1); + aa->array_sz = of_read_number(prop++, 1); + + of_node_put(memory); + + /* Now that we know the number of arrays and size of each array, + * revalidate the size of the property read in. + */ + if (len < (aa->n_arrays * aa->array_sz + 2) * sizeof(unsigned int)) + return -1; + + aa->arrays = prop; + return 0; +} + +static int current_min_common_depth; +static int n_mem_addr_cells, n_mem_size_cells; /* - * Interpret the ibm dynamic reconfiguration memory LMBs. - * This contains a list of memory blocks along with NUMA affinity - * information. + * This is like numa.c:of_node_to_nid_single() for memory represented + * in the ibm,dynamic-reconfiguration-memory node. */ -static void __init early_init_drmem_lmb(struct drmem_lmb *lmb, - const __be32 **usm) +static int of_drconf_to_nid_single(struct drmem_lmb *lmb) { - u64 base, size; - int is_kexec_kdump = 0, rngs; + struct assoc_arrays aa = { .arrays = NULL }; + int default_nid = 0; + int nid = default_nid; + int rc, index; + + rc = of_get_assoc_arrays(&aa); + if (rc) + return default_nid; + + if (current_min_common_depth > 0 && current_min_common_depth <= aa.array_sz && + !(lmb->flags & DRCONF_MEM_AI_INVALID) && + lmb->aa_index < aa.n_arrays) { + index = lmb->aa_index * aa.array_sz + current_min_common_depth - 1; + nid = of_read_number(&aa.arrays[index], 1); + + if (nid == 0xffff || nid >= MAX_NUMNODES) + nid = default_nid; + + if (nid > 0) { + index = lmb->aa_index * aa.array_sz; + initialize_distance_lookup_table(nid, + &aa.arrays[index]); + } + } - base = lmb->base_addr; - size = drmem_lmb_size(); - rngs = 1; + return nid; +} +static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells) +{ + struct device_node *memory = NULL; + + memory = of_find_node_by_type(memory, "memory"); + if (!memory) + panic("numa.c: No memory nodes found!"); + + *n_addr_cells = of_n_addr_cells(memory); + *n_size_cells = of_n_size_cells(memory); + of_node_put(memory); +} + +static inline unsigned long read_n_cells(int n, const __be32 **buf) +{ + unsigned long result = 0; + + while (n--) { + result = (result << 32) | of_read_number(*buf, 1); + (*buf)++; + } + return result; +} + +/* + * Reads the counter for a given entry in + * linux,drconf-usable-memory property + */ +static inline int __init read_usm_ranges(const __be32 **usm) +{ /* - * Skip this block if the reserved bit is set in flags - * or if the block is not assigned to this partition. + * For each lmb in ibm,dynamic-memory a corresponding + * entry in linux,drconf-usable-memory property contains + * a counter followed by that many (base, size) duple. + * read the counter from linux,drconf-usable-memory */ - if ((lmb->flags & DRCONF_MEM_RESERVED) || - !(lmb->flags & DRCONF_MEM_ASSIGNED)) + return read_n_cells(n_mem_size_cells, usm); +} + +/* + * Extract NUMA information from the ibm,dynamic-reconfiguration-memory + * node. This assumes n_mem_{addr,size}_cells have been set. + */ +static void __init numa_setup_drmem_lmb(struct drmem_lmb *lmb, + const __be32 **usm) +{ + unsigned int ranges, is_kexec_kdump = 0; + unsigned long base, size, sz; + int nid; + + /* + * Skip this block if the reserved bit is set in flags (0x80) + * or if the block is not assigned to this partition (0x8) + */ + if ((lmb->flags & DRCONF_MEM_RESERVED) + || !(lmb->flags & DRCONF_MEM_ASSIGNED)) return; if (*usm) is_kexec_kdump = 1; + base = lmb->base_addr; + size = drmem_lmb_size(); + ranges = 1; + if (is_kexec_kdump) { - /* - * For each memblock in ibm,dynamic-memory, a - * corresponding entry in linux,drconf-usable-memory - * property contains a counter 'p' followed by 'p' - * (base, size) duple. Now read the counter from - * linux,drconf-usable-memory property - */ - rngs = dt_mem_next_cell(dt_root_size_cells, usm); - if (!rngs) /* there are no (base, size) duple */ + ranges = read_usm_ranges(usm); + if (!ranges) /* there are no (base, size) duple */ return; } + get_n_mem_cells(&n_mem_addr_cells, &n_mem_size_cells); + do { if (is_kexec_kdump) { - base = dt_mem_next_cell(dt_root_addr_cells, usm); - size = dt_mem_next_cell(dt_root_size_cells, usm); + base = read_n_cells(n_mem_addr_cells, usm); + size = read_n_cells(n_mem_size_cells, usm); } - if (iommu_is_off) { - if (base >= 0x80000000ul) - continue; - if ((base + size) > 0x80000000ul) - size = 0x80000000ul - base; - } + nid = of_drconf_to_nid_single(lmb); + fake_numa_create_new_node(((base + size) >> PAGE_SHIFT), + &nid); + node_set_online(nid); + sz = numa_enforce_memory_limit(base, size); + if (sz) + memblock_set_node(base, sz, &memblock.memory, nid); + } while (--ranges); +} - DBG("Adding: %llx -> %llx\n", base, size); - if (validate_mem_limit(base, &size)) - memblock_add(base, size); - } while (--rngs); +int __init platform_parse_numa_properties(int min_common_depth) +{ + struct device_node *memory; + + /* + * Now do the same thing for each MEMBLOCK listed in the + * ibm,dynamic-memory property in the + * ibm,dynamic-reconfiguration-memory node. + */ + current_min_common_depth = min_common_depth; + memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (memory) { + walk_drmem_lmbs(memory, numa_setup_drmem_lmb); + of_node_put(memory); + } + return current_min_common_depth; } -int __init platform_early_init_dt_scan_memory_ppc(unsigned long node, - const char *uname, - int depth, void *data) +u64 platform_hot_add_drconf_memory_max(void) { - if (depth == 1 && - strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) { - walk_drmem_lmbs_early(node, early_init_drmem_lmb); - return 0; + struct device_node *memory = NULL; + + memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (memory) { + of_node_put(memory); + return drmem_lmb_memory_max(); + } + return 0; +} + + +/* + * Find the node associated with a hot added memory section for + * memory represented in the device tree by the property + * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory. + */ +static int hot_add_drconf_scn_to_nid(unsigned long scn_addr) +{ + struct drmem_lmb *lmb; + unsigned long lmb_size; + int nid = -1; + + lmb_size = drmem_lmb_size(); + + for_each_drmem_lmb(lmb) { + /* skip this block if it is reserved or not assigned to + * this partition */ + if ((lmb->flags & DRCONF_MEM_RESERVED) + || !(lmb->flags & DRCONF_MEM_ASSIGNED)) + continue; + + if ((scn_addr < lmb->base_addr) + || (scn_addr >= (lmb->base_addr + lmb_size))) + continue; + + nid = of_drconf_to_nid_single(lmb); + break; } - return -ENODEV; + return nid; +} + +int platform_hot_add_scn_to_nid(unsigned long scn_addr) +{ + struct device_node *memory = NULL; + int nid; + + memory = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (memory) { + nid = hot_add_drconf_scn_to_nid(scn_addr); + of_node_put(memory); + return nid; + } else { + return NUMA_NO_NODE; + } }