|
@@ -268,6 +268,144 @@ static unsigned long __devinit read_n_cells(int n, const unsigned int **buf)
|
|
return result;
|
|
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.
|
|
* Figure out to which domain a cpu belongs and stick it there.
|
|
* Return the id of the domain used.
|
|
* 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)
|
|
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;
|
|
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;
|
|
return;
|
|
|
|
|
|
for (; n != 0; --n) {
|
|
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;
|
|
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);
|
|
node_set_online(nid);
|
|
|
|
|
|
- size = numa_enforce_memory_limit(start, lmb_size);
|
|
|
|
|
|
+ size = numa_enforce_memory_limit(drmem.base_addr, lmb_size);
|
|
if (!size)
|
|
if (!size)
|
|
continue;
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|