@@ -34,6 +34,26 @@ static int __init fdt_numa_processor_affinity_init(nodeid_t node)
return 0;
}
+/* Callback for parsing of the memory regions affinity */
+static int __init fdt_numa_memory_affinity_init(nodeid_t node,
+ paddr_t start, paddr_t size)
+{
+ if ( !numa_memblks_available() )
+ {
+ dprintk(XENLOG_WARNING,
+ "Too many NUMA entries, try bigger NR_NODE_MEMBLKS\n");
+ return -EINVAL;
+ }
+
+ numa_fw_nid_name = "numa-node-id";
+ if ( !numa_update_node_memblks(node, node, start, size, false) )
+ return -EINVAL;
+
+ device_tree_numa = DT_NUMA_ON;
+
+ return 0;
+}
+
/* Parse CPU NUMA node info */
static int __init fdt_parse_numa_cpu_node(const void *fdt, int node)
{
@@ -62,3 +82,72 @@ static int __init fdt_parse_numa_cpu_node(const void *fdt, int node)
return fdt_numa_processor_affinity_init(nid);
}
+
+/* Parse memory node NUMA info */
+static int __init fdt_parse_numa_memory_node(const void *fdt, int node,
+ const char *name,
+ unsigned int addr_cells,
+ unsigned int size_cells)
+{
+ unsigned int nid;
+ int ret = 0, len;
+ paddr_t addr, size;
+ const struct fdt_property *prop;
+ unsigned int idx, ranges;
+ const __be32 *addresses;
+
+ if ( numa_disabled() )
+ return -EINVAL;
+
+ /*
+ * device_tree_get_u32 will return NUMA_NO_NODE when this memory
+ * DT node doesn't have numa-node-id. This can help us to
+ * distinguish a bad DTB and a normal DTB without NUMA info.
+ */
+ nid = device_tree_get_u32(fdt, node, "numa-node-id", NUMA_NO_NODE);
+ if ( node == NUMA_NO_NODE )
+ {
+ numa_fw_bad();
+ return -ENODATA;
+ }
+ else if ( nid >= MAX_NUMNODES )
+ {
+ printk(XENLOG_WARNING "Node id %u exceeds maximum value\n", nid);
+ goto invalid_data;
+ }
+
+ prop = fdt_get_property(fdt, node, "reg", &len);
+ if ( !prop )
+ {
+ printk(XENLOG_WARNING
+ "fdt: node `%s': missing `reg' property\n", name);
+ goto invalid_data;
+ }
+
+ addresses = (const __be32 *)prop->data;
+ ranges = len / (sizeof(__be32)* (addr_cells + size_cells));
+ for ( idx = 0; idx < ranges; idx++ )
+ {
+ device_tree_get_reg(&addresses, addr_cells, size_cells, &addr, &size);
+ /* Skip zero size ranges */
+ if ( !size )
+ continue;
+
+ ret = fdt_numa_memory_affinity_init(nid, addr, size);
+ if ( ret )
+ goto invalid_data;
+ }
+
+ if ( idx == 0 )
+ {
+ printk(XENLOG_ERR
+ "bad property in memory node, idx=%d ret=%d\n", idx, ret);
+ goto invalid_data;
+ }
+
+ return 0;
+
+invalid_data:
+ numa_fw_bad();
+ return -EINVAL;
+}