powerpc/pseries: Split code into helper routines for drconf memory
authorNathan Fontenot <nfont@austin.ibm.com>
Thu, 3 Jul 2008 03:35:54 +0000 (13:35 +1000)
committerPaul Mackerras <paulus@samba.org>
Thu, 3 Jul 2008 06:58:17 +0000 (16:58 +1000)
This splits off several pieces of code that parse the
ibm,dynamic-reconfiguration-memory node of the device tree into separate
helper routines.  This is in preparation for the next commit that will
use these helper routines.  There are no functional changes in this patch.

Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/mm/numa.c

index dc704da363eb77897d392781591bf87ac337a8dd..39328da32edf0ee0948160cb4393d09b3f491c46 100644 (file)
@@ -268,6 +268,144 @@ static unsigned long __devinit read_n_cells(int n, const unsigned int **buf)
        return result;
 }
 
+struct of_drconf_cell {
+       u64     base_addr;
+       u32     drc_index;
+       u32     reserved;
+       u32     aa_index;
+       u32     flags;
+};
+
+#define DRCONF_MEM_ASSIGNED    0x00000008
+#define DRCONF_MEM_AI_INVALID  0x00000040
+#define DRCONF_MEM_RESERVED    0x00000080
+
+/*
+ * Read the next lmb list entry from the ibm,dynamic-memory property
+ * and return the information in the provided of_drconf_cell structure.
+ */
+static void read_drconf_cell(struct of_drconf_cell *drmem, const u32 **cellp)
+{
+       const u32 *cp;
+
+       drmem->base_addr = read_n_cells(n_mem_addr_cells, cellp);
+
+       cp = *cellp;
+       drmem->drc_index = cp[0];
+       drmem->reserved = cp[1];
+       drmem->aa_index = cp[2];
+       drmem->flags = cp[3];
+
+       *cellp = cp + 4;
+}
+
+/*
+ * Retreive and validate the ibm,dynamic-memory property of the device tree.
+ *
+ * The layout of the ibm,dynamic-memory property is a number N of lmb
+ * list entries followed by N lmb list entries.  Each lmb list entry
+ * contains information as layed out in the of_drconf_cell struct above.
+ */
+static int of_get_drconf_memory(struct device_node *memory, const u32 **dm)
+{
+       const u32 *prop;
+       u32 len, entries;
+
+       prop = of_get_property(memory, "ibm,dynamic-memory", &len);
+       if (!prop || len < sizeof(unsigned int))
+               return 0;
+
+       entries = *prop++;
+
+       /* 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;
+       return entries;
+}
+
+/*
+ * Retreive and validate the ibm,lmb-size property for drconf memory
+ * from the device tree.
+ */
+static u64 of_get_lmb_size(struct device_node *memory)
+{
+       const u32 *prop;
+       u32 len;
+
+       prop = of_get_property(memory, "ibm,lmb-size", &len);
+       if (!prop || len < sizeof(unsigned int))
+               return 0;
+
+       return read_n_cells(n_mem_size_cells, &prop);
+}
+
+struct assoc_arrays {
+       u32     n_arrays;
+       u32     array_sz;
+       const u32 *arrays;
+};
+
+/*
+ * Retreive 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 device_node *memory,
+                              struct assoc_arrays *aa)
+{
+       const u32 *prop;
+       u32 len;
+
+       prop = of_get_property(memory, "ibm,associativity-lookup-arrays", &len);
+       if (!prop || len < 2 * sizeof(unsigned int))
+               return -1;
+
+       aa->n_arrays = *prop++;
+       aa->array_sz = *prop++;
+
+       /* Now that we know the number of arrrays 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 of_drconf_cell *drmem,
+                                  struct assoc_arrays *aa)
+{
+       int default_nid = 0;
+       int nid = default_nid;
+       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;
+               nid = aa->arrays[index];
+
+               if (nid == 0xffff || nid >= MAX_NUMNODES)
+                       nid = default_nid;
+       }
+
+       return nid;
+}
+
 /*
  * Figure out to which domain a cpu belongs and stick it there.
  * Return the id of the domain used.
@@ -355,57 +493,50 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
  */
 static void __init parse_drconf_memory(struct device_node *memory)
 {
-       const unsigned int *lm, *dm, *aa;
-       unsigned int ls, ld, la;
-       unsigned int n, aam, aalen;
-       unsigned long lmb_size, size, start;
-       int nid, default_nid = 0;
-       unsigned int ai, flags;
-
-       lm = of_get_property(memory, "ibm,lmb-size", &ls);
-       dm = of_get_property(memory, "ibm,dynamic-memory", &ld);
-       aa = of_get_property(memory, "ibm,associativity-lookup-arrays", &la);
-       if (!lm || !dm || !aa ||
-           ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
-           la < 2 * sizeof(unsigned int))
+       const u32 *dm;
+       unsigned int n, rc;
+       unsigned long lmb_size, size;
+       int nid;
+       struct assoc_arrays aa;
+
+       n = of_get_drconf_memory(memory, &dm);
+       if (!n)
                return;
 
-       lmb_size = read_n_cells(n_mem_size_cells, &lm);
-       n = *dm++;              /* number of LMBs */
-       aam = *aa++;            /* number of associativity lists */
-       aalen = *aa++;          /* length of each associativity list */
-       if (ld < (n * (n_mem_addr_cells + 4) + 1) * sizeof(unsigned int) ||
-           la < (aam * aalen + 2) * sizeof(unsigned int))
+       lmb_size = of_get_lmb_size(memory);
+       if (!lmb_size)
+               return;
+
+       rc = of_get_assoc_arrays(memory, &aa);
+       if (rc)
                return;
 
        for (; n != 0; --n) {
-               start = read_n_cells(n_mem_addr_cells, &dm);
-               ai = dm[2];
-               flags = dm[3];
-               dm += 4;
-               /* 0x80 == reserved, 0x8 = assigned to us */
-               if ((flags & 0x80) || !(flags & 0x8))
+               struct of_drconf_cell drmem;
+
+               read_drconf_cell(&drmem, &dm);
+
+               /* 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;
-               nid = default_nid;
-               /* flags & 0x40 means associativity index is invalid */
-               if (min_common_depth > 0 && min_common_depth <= aalen &&
-                   (flags & 0x40) == 0 && ai < aam) {
-                       /* this is like of_node_to_nid_single */
-                       nid = aa[ai * aalen + min_common_depth - 1];
-                       if (nid == 0xffff || nid >= MAX_NUMNODES)
-                               nid = default_nid;
-               }
 
-               fake_numa_create_new_node(((start + lmb_size) >> PAGE_SHIFT),
-                                               &nid);
+               nid = of_drconf_to_nid_single(&drmem, &aa);
+
+               fake_numa_create_new_node(
+                               ((drmem.base_addr + lmb_size) >> PAGE_SHIFT),
+                                          &nid);
+
                node_set_online(nid);
 
-               size = numa_enforce_memory_limit(start, lmb_size);
+               size = numa_enforce_memory_limit(drmem.base_addr, lmb_size);
                if (!size)
                        continue;
 
-               add_active_range(nid, start >> PAGE_SHIFT,
-                                (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT));
+               add_active_range(nid, drmem.base_addr >> PAGE_SHIFT,
+                                (drmem.base_addr >> PAGE_SHIFT)
+                                + (size >> PAGE_SHIFT));
        }
 }