diff mbox

[V2,3/8] powerpc/memory: Parse new memory property to initialize structures.

Message ID e94fff53-2433-d4e1-3d68-728a8b350de3@linux.vnet.ibm.com (mailing list archive)
State Superseded
Headers show

Commit Message

Michael Bringmann July 27, 2016, 2:23 p.m. UTC
powerpc/memory: Add parallel routines to parse the new property
"ibm,dynamic-memory-v2" property when it is present, and then to
finish initialization of the relevant memory structures with the
operating system.  This code is shared between the boot-time
initialization functions and the runtime functions for memory
hotplug, so it needs to be able to handle both formats.

Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
---

Comments

Nathan Fontenot July 28, 2016, 8:54 p.m. UTC | #1
On 07/27/2016 09:23 AM, 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
> finish initialization of the relevant memory structures with the
> operating system.  This code is shared between the boot-time
> initialization functions and the runtime functions for memory
> hotplug, so it needs to be able to handle both formats.
> 
> Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
> ---
> diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
> index 669a15e..18b4ee7 100644
> --- a/arch/powerpc/mm/numa.c
> +++ b/arch/powerpc/mm/numa.c
> @@ -405,9 +407,8 @@
>  
>  	*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.
>   */
> @@ -425,30 +426,55 @@
>  EXPORT_SYMBOL(read_drconf_cell_v2);
>  
>  /*
> - * Retrieve and validate the ibm,dynamic-memory property of the device tree.
> + * Retrieve and validate the ibm,dynamic-memory[-v2] property of the
> + * device tree.
> + *
> + * The layout of the ibm,dynamic-memory property is a number N of memory
> + * block description list entries followed by N memory block description
> + * list entries.  Each memory block description list entry contains
> + * information as laid out in the of_drconf_cell struct above.
>   *
> - * The layout of the ibm,dynamic-memory property is a number N of memblock
> - * list entries followed by N memblock list entries.  Each memblock list entry
> - * contains information as laid out in the of_drconf_cell struct above.
> + * The layout of the ibm,dynamic-memory-v2 property is a number N of memory
> + * block set description list entries, followed by N memory block set
> + * description set entries.
>   */
>  static int of_get_drconf_memory(struct device_node *memory, const __be32 **dm)
>  {
>  	const __be32 *prop;
>  	u32 len, entries;
>  
> -	prop = of_get_property(memory, "ibm,dynamic-memory", &len);
> -	if (!prop || len < sizeof(unsigned int))
> -		return 0;
> +	if (firmware_has_feature(FW_FEATURE_DYN_MEM_V2)) {
>  
> -	entries = of_read_number(prop++, 1);
> +		prop = of_get_property(memory, "ibm,dynamic-memory-v2", &len);
> +		if (!prop || len < sizeof(unsigned int))
> +			return 0;
>  
> -	/* Now that we know the number of entries, revalidate the size
> -	 * of the property read in to ensure we have everything
> -	 */
> -	if (len < (entries * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int))
> -		return 0;
> +		entries = of_read_number(prop++, 1);
> +
> +		/* Now that we know the number of set entries, revalidate the
> +		 * size of the property read in to ensure we have everything.
> +		 */
> +		if (len < dyn_mem_v2_len(entries))
> +			return 0;
> +
> +		*dm = prop;
> +	} else {
> +		prop = of_get_property(memory, "ibm,dynamic-memory", &len);
> +		if (!prop || len < sizeof(unsigned int))
> +			return 0;
> +
> +		entries = of_read_number(prop++, 1);
> +
> +		/* Now that we know the number of entries, revalidate the size
> +		 * of the property read in to ensure we have everything
> +		 */
> +		if (len < (entries * (n_mem_addr_cells + 4) + 1) *
> +			   sizeof(unsigned int))
> +			return 0;
> +
> +		*dm = prop;
> +	}
>  
> -	*dm = prop;
>  	return entries;
>  }
>  
> @@ -511,7 +537,7 @@
>   * 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 of_drconf_cell *drmem,
> +static int of_drconf_to_nid_single(u32 drmem_flags, u32 drmem_aa_index,
>  				   struct assoc_arrays *aa)
>  {
>  	int default_nid = 0;
> @@ -519,16 +545,16 @@
>  	int index;
>  
>  	if (min_common_depth > 0 && min_common_depth <= aa->array_sz &&
> -	    !(drmem->flags & DRCONF_MEM_AI_INVALID) &&
> -	    drmem->aa_index < aa->n_arrays) {
> -		index = drmem->aa_index * aa->array_sz + min_common_depth - 1;
> +	    !(drmem_flags & DRCONF_MEM_AI_INVALID) &&
> +	    drmem_aa_index < aa->n_arrays) {
> +		index = drmem_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 = drmem->aa_index * aa->array_sz;
> +			index = drmem_aa_index * aa->array_sz;
>  			initialize_distance_lookup_table(nid,
>  							&aa->arrays[index]);
>  		}
> @@ -671,7 +697,7 @@
>   * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
>   * node.  This assumes n_mem_{addr,size}_cells have been set.
>   */
> -static void __init parse_drconf_memory(struct device_node *memory)
> +static void __init parse_drconf_memory_v1(struct device_node *memory)
>  {
>  	const __be32 *uninitialized_var(dm), *usm;
>  	unsigned int n, rc, ranges, is_kexec_kdump = 0;
> @@ -721,10 +747,11 @@
>  				base = read_n_cells(n_mem_addr_cells, &usm);
>  				size = read_n_cells(n_mem_size_cells, &usm);
>  			}
> -			nid = of_drconf_to_nid_single(&drmem, &aa);
> +			nid = of_drconf_to_nid_single(drmem.flags,
> +							drmem.aa_index, &aa);
>  			fake_numa_create_new_node(
>  				((base + size) >> PAGE_SHIFT),
> -					   &nid);
> +					    &nid);
>  			node_set_online(nid);
>  			sz = numa_enforce_memory_limit(base, size);
>  			if (sz)
> @@ -734,6 +761,100 @@
>  	}
>  }
>  
> +static void __init parse_drconf_memory_v2(struct device_node *memory)
> +{
> +	const __be32 *uninitialized_var(dm);
> +	unsigned int num_lmb_sets, rc;
> +	unsigned long lmb_size, base;
> +	const __be32 *usm;
> +	unsigned int ranges, is_kexec_kdump = 0;
> +	unsigned long size, sz;
> +	int nid;
> +	struct assoc_arrays aa = { .arrays = NULL };
> +	const __be32 *prop, *p;
> +	u32	len;
> +
> +	prop = of_get_property(memory, "ibm,dynamic-memory-v2", &len);
> +	if (!prop)
> +		return;
> +	p = prop;
> +
> +	num_lmb_sets = of_get_drconf_memory(memory, &dm);
> +	if (!num_lmb_sets)
> +		return;

The of_get_drconf_memory() call does an of_get_property() so I think you
can get rid of the call to of_get_property() above.

-Nathan

> +
> +	lmb_size = of_get_lmb_size(memory);
> +	if (!lmb_size)
> +		return;
> +
> +	rc = of_get_assoc_arrays(memory, &aa);
> +	if (rc)
> +		return;
> +
> +	/* Check if this is a kexec/kdump kernel */
> +	usm = of_get_usable_memory(memory);
> +	if (usm != NULL)
> +		is_kexec_kdump = 1;
> +
> +	for (; num_lmb_sets != 0; num_lmb_sets--) {
> +		struct of_drconf_cell_v2 drmem;
> +		unsigned long nsl;
> +
> +		/* Get the current LMB set */
> +		read_drconf_cell_v2(&drmem, &dm);
> +		base = drmem.base_addr;
> +		nsl = drmem.num_seq_lmbs;
> +
> +		/* Skip this block if the reserved bit is set in
> +		 * flags (0x80) or if the block is not assigned
> +		 * to this partition (0x8)
> +		 */
> +		if ((drmem.flags & DRCONF_MEM_RESERVED)
> +		    || !(drmem.flags & DRCONF_MEM_ASSIGNED))
> +			continue;
> +
> +		for (; nsl != 0; nsl--) {
> +			size = lmb_size;
> +			ranges = 1;
> +
> +			if (is_kexec_kdump) {
> +				ranges = read_usm_ranges(&usm);
> +				if (!ranges)
> +					/* there are no (base, size) duple */
> +					continue;
> +			}
> +			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(drmem.flags,
> +							drmem.aa_index, &aa);
> +				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);
> +
> +			base += sz;
> +		}
> +	}
> +}
> +
> +static void __init parse_drconf_memory(struct device_node *memory)
> +{
> +	if (firmware_has_feature(FW_FEATURE_DYN_MEM_V2))
> +		parse_drconf_memory_v2(memory);
> +	else
> +		parse_drconf_memory_v1(memory);
> +}
> +
>  static int __init parse_numa_properties(void)
>  {
>  	struct device_node *memory;
> @@ -1072,8 +1211,8 @@ static int hot_add_drconf_scn_to_nid(struct device_node *memory,
>  		if ((scn_addr < drmem.base_addr)
>  		    || (scn_addr >= (drmem.base_addr + lmb_size)))
>  			continue;
> -
> -		nid = of_drconf_to_nid_single(&drmem, &aa);
> +		nid = of_drconf_to_nid_single(drmem.flags,
> +						drmem.aa_index, &aa);
>  		break;
>  	}
>  
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
>
diff mbox

Patch

diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 669a15e..18b4ee7 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -405,9 +407,8 @@ 
 
 	*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.
  */
@@ -425,30 +426,55 @@ 
 EXPORT_SYMBOL(read_drconf_cell_v2);
 
 /*
- * Retrieve and validate the ibm,dynamic-memory property of the device tree.
+ * Retrieve and validate the ibm,dynamic-memory[-v2] property of the
+ * device tree.
+ *
+ * The layout of the ibm,dynamic-memory property is a number N of memory
+ * block description list entries followed by N memory block description
+ * list entries.  Each memory block description list entry contains
+ * information as laid out in the of_drconf_cell struct above.
  *
- * The layout of the ibm,dynamic-memory property is a number N of memblock
- * list entries followed by N memblock list entries.  Each memblock list entry
- * contains information as laid out in the of_drconf_cell struct above.
+ * The layout of the ibm,dynamic-memory-v2 property is a number N of memory
+ * block set description list entries, followed by N memory block set
+ * description set entries.
  */
 static int of_get_drconf_memory(struct device_node *memory, const __be32 **dm)
 {
 	const __be32 *prop;
 	u32 len, entries;
 
-	prop = of_get_property(memory, "ibm,dynamic-memory", &len);
-	if (!prop || len < sizeof(unsigned int))
-		return 0;
+	if (firmware_has_feature(FW_FEATURE_DYN_MEM_V2)) {
 
-	entries = of_read_number(prop++, 1);
+		prop = of_get_property(memory, "ibm,dynamic-memory-v2", &len);
+		if (!prop || len < sizeof(unsigned int))
+			return 0;
 
-	/* Now that we know the number of entries, revalidate the size
-	 * of the property read in to ensure we have everything
-	 */
-	if (len < (entries * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int))
-		return 0;
+		entries = of_read_number(prop++, 1);
+
+		/* Now that we know the number of set entries, revalidate the
+		 * size of the property read in to ensure we have everything.
+		 */
+		if (len < dyn_mem_v2_len(entries))
+			return 0;
+
+		*dm = prop;
+	} else {
+		prop = of_get_property(memory, "ibm,dynamic-memory", &len);
+		if (!prop || len < sizeof(unsigned int))
+			return 0;
+
+		entries = of_read_number(prop++, 1);
+
+		/* Now that we know the number of entries, revalidate the size
+		 * of the property read in to ensure we have everything
+		 */
+		if (len < (entries * (n_mem_addr_cells + 4) + 1) *
+			   sizeof(unsigned int))
+			return 0;
+
+		*dm = prop;
+	}
 
-	*dm = prop;
 	return entries;
 }
 
@@ -511,7 +537,7 @@ 
  * 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 of_drconf_cell *drmem,
+static int of_drconf_to_nid_single(u32 drmem_flags, u32 drmem_aa_index,
 				   struct assoc_arrays *aa)
 {
 	int default_nid = 0;
@@ -519,16 +545,16 @@ 
 	int index;
 
 	if (min_common_depth > 0 && min_common_depth <= aa->array_sz &&
-	    !(drmem->flags & DRCONF_MEM_AI_INVALID) &&
-	    drmem->aa_index < aa->n_arrays) {
-		index = drmem->aa_index * aa->array_sz + min_common_depth - 1;
+	    !(drmem_flags & DRCONF_MEM_AI_INVALID) &&
+	    drmem_aa_index < aa->n_arrays) {
+		index = drmem_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 = drmem->aa_index * aa->array_sz;
+			index = drmem_aa_index * aa->array_sz;
 			initialize_distance_lookup_table(nid,
 							&aa->arrays[index]);
 		}
@@ -671,7 +697,7 @@ 
  * Extract NUMA information from the ibm,dynamic-reconfiguration-memory
  * node.  This assumes n_mem_{addr,size}_cells have been set.
  */
-static void __init parse_drconf_memory(struct device_node *memory)
+static void __init parse_drconf_memory_v1(struct device_node *memory)
 {
 	const __be32 *uninitialized_var(dm), *usm;
 	unsigned int n, rc, ranges, is_kexec_kdump = 0;
@@ -721,10 +747,11 @@ 
 				base = read_n_cells(n_mem_addr_cells, &usm);
 				size = read_n_cells(n_mem_size_cells, &usm);
 			}
-			nid = of_drconf_to_nid_single(&drmem, &aa);
+			nid = of_drconf_to_nid_single(drmem.flags,
+							drmem.aa_index, &aa);
 			fake_numa_create_new_node(
 				((base + size) >> PAGE_SHIFT),
-					   &nid);
+					    &nid);
 			node_set_online(nid);
 			sz = numa_enforce_memory_limit(base, size);
 			if (sz)
@@ -734,6 +761,100 @@ 
 	}
 }
 
+static void __init parse_drconf_memory_v2(struct device_node *memory)
+{
+	const __be32 *uninitialized_var(dm);
+	unsigned int num_lmb_sets, rc;
+	unsigned long lmb_size, base;
+	const __be32 *usm;
+	unsigned int ranges, is_kexec_kdump = 0;
+	unsigned long size, sz;
+	int nid;
+	struct assoc_arrays aa = { .arrays = NULL };
+	const __be32 *prop, *p;
+	u32	len;
+
+	prop = of_get_property(memory, "ibm,dynamic-memory-v2", &len);
+	if (!prop)
+		return;
+	p = prop;
+
+	num_lmb_sets = of_get_drconf_memory(memory, &dm);
+	if (!num_lmb_sets)
+		return;
+
+	lmb_size = of_get_lmb_size(memory);
+	if (!lmb_size)
+		return;
+
+	rc = of_get_assoc_arrays(memory, &aa);
+	if (rc)
+		return;
+
+	/* Check if this is a kexec/kdump kernel */
+	usm = of_get_usable_memory(memory);
+	if (usm != NULL)
+		is_kexec_kdump = 1;
+
+	for (; num_lmb_sets != 0; num_lmb_sets--) {
+		struct of_drconf_cell_v2 drmem;
+		unsigned long nsl;
+
+		/* Get the current LMB set */
+		read_drconf_cell_v2(&drmem, &dm);
+		base = drmem.base_addr;
+		nsl = drmem.num_seq_lmbs;
+
+		/* Skip this block if the reserved bit is set in
+		 * flags (0x80) or if the block is not assigned
+		 * to this partition (0x8)
+		 */
+		if ((drmem.flags & DRCONF_MEM_RESERVED)
+		    || !(drmem.flags & DRCONF_MEM_ASSIGNED))
+			continue;
+
+		for (; nsl != 0; nsl--) {
+			size = lmb_size;
+			ranges = 1;
+
+			if (is_kexec_kdump) {
+				ranges = read_usm_ranges(&usm);
+				if (!ranges)
+					/* there are no (base, size) duple */
+					continue;
+			}
+			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(drmem.flags,
+							drmem.aa_index, &aa);
+				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);
+
+			base += sz;
+		}
+	}
+}
+
+static void __init parse_drconf_memory(struct device_node *memory)
+{
+	if (firmware_has_feature(FW_FEATURE_DYN_MEM_V2))
+		parse_drconf_memory_v2(memory);
+	else
+		parse_drconf_memory_v1(memory);
+}
+
 static int __init parse_numa_properties(void)
 {
 	struct device_node *memory;
@@ -1072,8 +1211,8 @@  static int hot_add_drconf_scn_to_nid(struct device_node *memory,
 		if ((scn_addr < drmem.base_addr)
 		    || (scn_addr >= (drmem.base_addr + lmb_size)))
 			continue;
-
-		nid = of_drconf_to_nid_single(&drmem, &aa);
+		nid = of_drconf_to_nid_single(drmem.flags,
+						drmem.aa_index, &aa);
 		break;
 	}