* [PATCH 2/8] powerpc/memory: Parse new memory property to register blocks.
@ 2016-07-25 22:21 Michael Bringmann
2016-07-25 23:54 ` Tyrel Datwyler
0 siblings, 1 reply; 2+ messages in thread
From: Michael Bringmann @ 2016-07-25 22:21 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Nathan Fontenot, Michael Bringmann
powerpc/memory: Add parallel routines to parse the new property
"ibm,dynamic-memory-v2" property when it is present, and then to
register the relevant memory blocks with the operating system.
This property format is intended to provide a more compact
representation of memory when communicating with the front end
processor, especially when describing vast amounts of RAM.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
---
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index 7f436ba..b9a1534 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -69,6 +69,8 @@ struct boot_param_header {
* OF address retreival & translation
*/
+extern int n_mem_addr_cells;
+
/* Parse the ibm,dma-window property of an OF node into the busno, phys and
* size parameters.
*/
@@ -81,8 +83,9 @@ extern void of_instantiate_rtc(void);
extern int of_get_ibm_chip_id(struct device_node *np);
/* The of_drconf_cell struct defines the layout of the LMB array
- * specified in the device tree property
- * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
+ * specified in the device tree properties,
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory-v2
*/
struct of_drconf_cell {
u64 base_addr;
@@ -92,9 +95,39 @@ struct of_drconf_cell {
u32 flags;
};
-#define DRCONF_MEM_ASSIGNED 0x00000008
-#define DRCONF_MEM_AI_INVALID 0x00000040
-#define DRCONF_MEM_RESERVED 0x00000080
+#define DRCONF_MEM_ASSIGNED 0x00000008
+#define DRCONF_MEM_AI_INVALID 0x00000040
+#define DRCONF_MEM_RESERVED 0x00000080
+
+ /* It is important to note that this structure can not
+ * be safely mapped onto the memory containing the
+ * 'ibm,dynamic-memory-v2'. This structure represents
+ * the order of the fields stored, but compiler alignment
+ * may insert extra bytes of padding between the fields
+ * 'num_seq_lmbs' and 'base_addr'.
+ */
+struct of_drconf_cell_v2 {
+ u32 num_seq_lmbs;
+ u64 base_addr;
+ u32 drc_index;
+ u32 aa_index;
+ u32 flags;
+};
+
+
+static inline int dyn_mem_v2_len(int entries)
+{
+ int drconf_v2_cells = (n_mem_addr_cells + 4);
+ int drconf_v2_cells_len = (drconf_v2_cells * sizeof(unsigned int));
+ return (((entries) * drconf_v2_cells_len) +
+ (1 * sizeof(unsigned int)));
+}
+
+extern void read_drconf_cell_v2(struct of_drconf_cell_v2 *drmem,
+ const __be32 **cellp);
+extern void read_one_drc_info(int **info, char **drc_type, char **drc_name,
+ unsigned long int *fdi_p, unsigned long int *nsl_p,
+ unsigned long int *si_p, unsigned long int *ldi_p);
/*
* There are two methods for telling firmware what our capabilities are.
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 669a15e..ad294ce 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -405,6 +405,24 @@ static void read_drconf_cell(struct of_drconf_cell *drmem, const __be32 **cellp)
*cellp = cp + 4;
}
+
+ /*
+ * Retrieve and validate the ibm,dynamic-memory property of the device tree.
+ * Read the next memory block set entry from the ibm,dynamic-memory-v2 property
+ * and return the information in the provided of_drconf_cell_v2 structure.
+ */
+void read_drconf_cell_v2(struct of_drconf_cell_v2 *drmem, const __be32 **cellp)
+{
+ const __be32 *cp = (const __be32 *)*cellp;
+ drmem->num_seq_lmbs = be32_to_cpu(*cp++);
+ drmem->base_addr = read_n_cells(n_mem_addr_cells, &cp);
+ drmem->drc_index = be32_to_cpu(*cp++);
+ drmem->aa_index = be32_to_cpu(*cp++);
+ drmem->flags = be32_to_cpu(*cp++);
+
+ *cellp = cp;
+}
+EXPORT_SYMBOL(read_drconf_cell_v2);
/*
* Retrieve and validate the ibm,dynamic-memory property of the device tree.
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 946e34f..a55bc1e 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -56,6 +56,7 @@
#include <asm/opal.h>
#include <asm/fadump.h>
#include <asm/debug.h>
+#include <asm/firmware.h>
#include <mm/mmu_decl.h>
@@ -441,12 +442,12 @@ static int __init early_init_dt_scan_chosen_ppc(unsigned long node,
#ifdef CONFIG_PPC_PSERIES
/*
- * Interpret the ibm,dynamic-memory property in the
- * /ibm,dynamic-reconfiguration-memory node.
+ * Interpret the ibm,dynamic-memory property/ibm,dynamic-memory-v2
+ * in the /ibm,dynamic-reconfiguration-memory node.
* This contains a list of memory blocks along with NUMA affinity
* information.
*/
-static int __init early_init_dt_scan_drconf_memory(unsigned long node)
+static int __init early_init_dt_scan_drconf_memory_v1(unsigned long node)
{
const __be32 *dm, *ls, *usm;
int l;
@@ -516,6 +517,105 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
memblock_dump_all();
return 0;
}
+
+static int __init early_init_dt_scan_drconf_memory_v2(unsigned long node)
+{
+ const __be32 *dm, *ls, *usm;
+ int l;
+ unsigned long num_sets;
+ u64 size, base, memblock_size;
+ unsigned int is_kexec_kdump = 0, rngs;
+
+ ls = of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
+ if (ls == NULL || l < dt_root_size_cells * sizeof(__be32))
+ return 0;
+ memblock_size = dt_mem_next_cell(dt_root_size_cells, &ls);
+
+ dm = of_get_flat_dt_prop(node, "ibm,dynamic-memory-v2", &l);
+ if (dm == NULL || l < sizeof(__be32))
+ return 0;
+
+ num_sets = of_read_number(dm++, 1);
+ if (l < (num_sets * (dt_root_addr_cells + 4) + 1) * sizeof(__be32))
+ return 0;
+
+ /* check if this is a kexec/kdump kernel. */
+ usm = of_get_flat_dt_prop(node, "linux,drconf-usable-memory", &l);
+ if (usm != NULL)
+ is_kexec_kdump = 1;
+
+ if (n_mem_addr_cells == 0)
+ n_mem_addr_cells = dt_root_addr_cells;
+
+ for (; num_sets != 0; --num_sets) {
+ struct of_drconf_cell_v2 drmem;
+ unsigned long nsl;
+
+ read_drconf_cell_v2(&drmem, &dm);
+ base = drmem.base_addr;
+ nsl = drmem.num_seq_lmbs;
+ size = memblock_size;
+
+ /* SKip this block if the reserved bit is set in flags
+ * or if the block is not assigned to this partition
+ */
+ if ((drmem.flags & DRCONF_MEM_RESERVED) ||
+ !(drmem.flags & DRCONF_MEM_ASSIGNED))
+ continue;
+
+ for (; nsl != 0; nsl--) {
+ size = memblock_size;
+ rngs = 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) {
+ 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;
+ }
+ memblock_add(base, size);
+ } while (--rngs);
+ }
+
+ base += size;
+ }
+ }
+
+ memblock_dump_all();
+ return 0;
+}
+
+static int __init early_init_dt_scan_drconf_memory(unsigned long node)
+{
+ if (firmware_has_feature(FW_FEATURE_RPS_DM2))
+ return early_init_dt_scan_drconf_memory_v2(node);
+ else
+ return early_init_dt_scan_drconf_memory_v1(node);
+}
+
#else
#define early_init_dt_scan_drconf_memory(node) 0
#endif /* CONFIG_PPC_PSERIES */
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH 2/8] powerpc/memory: Parse new memory property to register blocks.
2016-07-25 22:21 [PATCH 2/8] powerpc/memory: Parse new memory property to register blocks Michael Bringmann
@ 2016-07-25 23:54 ` Tyrel Datwyler
0 siblings, 0 replies; 2+ messages in thread
From: Tyrel Datwyler @ 2016-07-25 23:54 UTC (permalink / raw)
To: Michael Bringmann, linuxppc-dev; +Cc: Nathan Fontenot
On 07/25/2016 03:21 PM, Michael Bringmann wrote:
> powerpc/memory: Add parallel routines to parse the new property
> "ibm,dynamic-memory-v2" property when it is present, and then to
> register the relevant memory blocks with the operating system.
> This property format is intended to provide a more compact
> representation of memory when communicating with the front end
> processor, especially when describing vast amounts of RAM.
>
> Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
> ---
> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
> index 7f436ba..b9a1534 100644
> --- a/arch/powerpc/include/asm/prom.h
> +++ b/arch/powerpc/include/asm/prom.h
> @@ -69,6 +69,8 @@ struct boot_param_header {
> * OF address retreival & translation
> */
>
> +extern int n_mem_addr_cells;
> +
> /* Parse the ibm,dma-window property of an OF node into the busno, phys and
> * size parameters.
> */
> @@ -81,8 +83,9 @@ extern void of_instantiate_rtc(void);
> extern int of_get_ibm_chip_id(struct device_node *np);
>
> /* The of_drconf_cell struct defines the layout of the LMB array
> - * specified in the device tree property
> - * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
> + * specified in the device tree properties,
> + * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory
> + * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory-v2
> */
> struct of_drconf_cell {
> u64 base_addr;
> @@ -92,9 +95,39 @@ struct of_drconf_cell {
> u32 flags;
> };
>
> -#define DRCONF_MEM_ASSIGNED 0x00000008
> -#define DRCONF_MEM_AI_INVALID 0x00000040
> -#define DRCONF_MEM_RESERVED 0x00000080
> +#define DRCONF_MEM_ASSIGNED 0x00000008
> +#define DRCONF_MEM_AI_INVALID 0x00000040
> +#define DRCONF_MEM_RESERVED 0x00000080
> +
> + /* It is important to note that this structure can not
> + * be safely mapped onto the memory containing the
> + * 'ibm,dynamic-memory-v2'. This structure represents
> + * the order of the fields stored, but compiler alignment
> + * may insert extra bytes of padding between the fields
> + * 'num_seq_lmbs' and 'base_addr'.
> + */
The "packed" attribute should prevent the struct from being padded.
struct of_drconf_cell_v2 {
...
} __attribute__((packed));
or, simply
struct of_drconf_cell_v2 {
...
} __packed;
-Tyrel
> +struct of_drconf_cell_v2 {
> + u32 num_seq_lmbs;
> + u64 base_addr;
> + u32 drc_index;
> + u32 aa_index;
> + u32 flags;
> +};
> +
> +
> +static inline int dyn_mem_v2_len(int entries)
> +{
> + int drconf_v2_cells = (n_mem_addr_cells + 4);
> + int drconf_v2_cells_len = (drconf_v2_cells * sizeof(unsigned int));
> + return (((entries) * drconf_v2_cells_len) +
> + (1 * sizeof(unsigned int)));
> +}
> +
> +extern void read_drconf_cell_v2(struct of_drconf_cell_v2 *drmem,
> + const __be32 **cellp);
> +extern void read_one_drc_info(int **info, char **drc_type, char **drc_name,
> + unsigned long int *fdi_p, unsigned long int *nsl_p,
> + unsigned long int *si_p, unsigned long int *ldi_p);
>
> /*
> * There are two methods for telling firmware what our capabilities are.
> diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
> index 669a15e..ad294ce 100644
> --- a/arch/powerpc/mm/numa.c
> +++ b/arch/powerpc/mm/numa.c
> @@ -405,6 +405,24 @@ static void read_drconf_cell(struct of_drconf_cell *drmem, const __be32 **cellp)
>
> *cellp = cp + 4;
> }
> +
> + /*
> + * Retrieve and validate the ibm,dynamic-memory property of the device tree.
> + * Read the next memory block set entry from the ibm,dynamic-memory-v2 property
> + * and return the information in the provided of_drconf_cell_v2 structure.
> + */
> +void read_drconf_cell_v2(struct of_drconf_cell_v2 *drmem, const __be32 **cellp)
> +{
> + const __be32 *cp = (const __be32 *)*cellp;
> + drmem->num_seq_lmbs = be32_to_cpu(*cp++);
> + drmem->base_addr = read_n_cells(n_mem_addr_cells, &cp);
> + drmem->drc_index = be32_to_cpu(*cp++);
> + drmem->aa_index = be32_to_cpu(*cp++);
> + drmem->flags = be32_to_cpu(*cp++);
> +
> + *cellp = cp;
> +}
> +EXPORT_SYMBOL(read_drconf_cell_v2);
>
> /*
> * Retrieve and validate the ibm,dynamic-memory property of the device tree.
> diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
> index 946e34f..a55bc1e 100644
> --- a/arch/powerpc/kernel/prom.c
> +++ b/arch/powerpc/kernel/prom.c
> @@ -56,6 +56,7 @@
> #include <asm/opal.h>
> #include <asm/fadump.h>
> #include <asm/debug.h>
> +#include <asm/firmware.h>
>
> #include <mm/mmu_decl.h>
>
> @@ -441,12 +442,12 @@ static int __init early_init_dt_scan_chosen_ppc(unsigned long node,
>
> #ifdef CONFIG_PPC_PSERIES
> /*
> - * Interpret the ibm,dynamic-memory property in the
> - * /ibm,dynamic-reconfiguration-memory node.
> + * Interpret the ibm,dynamic-memory property/ibm,dynamic-memory-v2
> + * in the /ibm,dynamic-reconfiguration-memory node.
> * This contains a list of memory blocks along with NUMA affinity
> * information.
> */
> -static int __init early_init_dt_scan_drconf_memory(unsigned long node)
> +static int __init early_init_dt_scan_drconf_memory_v1(unsigned long node)
> {
> const __be32 *dm, *ls, *usm;
> int l;
> @@ -516,6 +517,105 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
> memblock_dump_all();
> return 0;
> }
> +
> +static int __init early_init_dt_scan_drconf_memory_v2(unsigned long node)
> +{
> + const __be32 *dm, *ls, *usm;
> + int l;
> + unsigned long num_sets;
> + u64 size, base, memblock_size;
> + unsigned int is_kexec_kdump = 0, rngs;
> +
> + ls = of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
> + if (ls == NULL || l < dt_root_size_cells * sizeof(__be32))
> + return 0;
> + memblock_size = dt_mem_next_cell(dt_root_size_cells, &ls);
> +
> + dm = of_get_flat_dt_prop(node, "ibm,dynamic-memory-v2", &l);
> + if (dm == NULL || l < sizeof(__be32))
> + return 0;
> +
> + num_sets = of_read_number(dm++, 1);
> + if (l < (num_sets * (dt_root_addr_cells + 4) + 1) * sizeof(__be32))
> + return 0;
> +
> + /* check if this is a kexec/kdump kernel. */
> + usm = of_get_flat_dt_prop(node, "linux,drconf-usable-memory", &l);
> + if (usm != NULL)
> + is_kexec_kdump = 1;
> +
> + if (n_mem_addr_cells == 0)
> + n_mem_addr_cells = dt_root_addr_cells;
> +
> + for (; num_sets != 0; --num_sets) {
> + struct of_drconf_cell_v2 drmem;
> + unsigned long nsl;
> +
> + read_drconf_cell_v2(&drmem, &dm);
> + base = drmem.base_addr;
> + nsl = drmem.num_seq_lmbs;
> + size = memblock_size;
> +
> + /* SKip this block if the reserved bit is set in flags
> + * or if the block is not assigned to this partition
> + */
> + if ((drmem.flags & DRCONF_MEM_RESERVED) ||
> + !(drmem.flags & DRCONF_MEM_ASSIGNED))
> + continue;
> +
> + for (; nsl != 0; nsl--) {
> + size = memblock_size;
> + rngs = 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) {
> + 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;
> + }
> + memblock_add(base, size);
> + } while (--rngs);
> + }
> +
> + base += size;
> + }
> + }
> +
> + memblock_dump_all();
> + return 0;
> +}
> +
> +static int __init early_init_dt_scan_drconf_memory(unsigned long node)
> +{
> + if (firmware_has_feature(FW_FEATURE_RPS_DM2))
> + return early_init_dt_scan_drconf_memory_v2(node);
> + else
> + return early_init_dt_scan_drconf_memory_v1(node);
> +}
> +
> #else
> #define early_init_dt_scan_drconf_memory(node) 0
> #endif /* CONFIG_PPC_PSERIES */
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2016-07-25 23:54 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-07-25 22:21 [PATCH 2/8] powerpc/memory: Parse new memory property to register blocks Michael Bringmann
2016-07-25 23:54 ` Tyrel Datwyler
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.