@@ -38,6 +38,7 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o
obj-y += mem_access.o
obj-y += mm.o
obj-y += monitor.o
+obj-$(CONFIG_NUMA) += numa.o
obj-y += p2m.o
obj-y += percpu.o
obj-y += platform.o
@@ -22,7 +22,19 @@ typedef u8 nodeid_t;
*/
#define NR_NODE_MEMBLKS NR_MEM_BANKS
+/*
+ * In ACPI spec, 0-9 are the reserved values for node distance,
+ * 10 indicates local node distance, 20 indicates remote node
+ * distance. Set node distance map in device tree will follow
+ * the ACPI's definition.
+ */
+#define NUMA_DISTANCE_UDF_MAX 9
+#define NUMA_LOCAL_DISTANCE 10
+#define NUMA_REMOTE_DISTANCE 20
+
extern bool numa_disabled(void);
+extern void numa_set_distance(nodeid_t from, nodeid_t to,
+ unsigned int distance);
#else
@@ -28,6 +28,11 @@ enum dt_numa_status {
static enum dt_numa_status __ro_after_init device_tree_numa = DT_NUMA_DEFAULT;
+static unsigned char __ro_after_init
+node_distance_map[MAX_NUMNODES][MAX_NUMNODES] = {
+ [0 ... MAX_NUMNODES - 1] = { [0 ... MAX_NUMNODES - 1] = NUMA_NO_DISTANCE }
+};
+
void __init numa_fw_bad(void)
{
printk(KERN_ERR "NUMA: device tree numa info table not used.\n");
@@ -48,3 +53,49 @@ int __init arch_numa_setup(const char *opt)
{
return -EINVAL;
}
+
+void __init numa_set_distance(nodeid_t from, nodeid_t to,
+ unsigned int distance)
+{
+ /*
+ * Since the NUMA device tree binding does not clearly specify the valid
+ * range of node distance, here we keep consistent with the ACPI, whose
+ * SLIT table uses 1 byte to describe the node distance. Hence node
+ * distances that cannot fit in 1 byte are invalid. Also, node distance
+ * 0-9 are undefined values.
+ * Reject all above-mentioned invalid distance values.
+ */
+ if ( (uint8_t)distance != distance || distance <= NUMA_DISTANCE_UDF_MAX )
+ {
+ printk(XENLOG_WARNING
+ "NUMA: invalid distance: from=%"PRIu8" to=%"PRIu8" distance=%u\n",
+ from, to, distance);
+ return;
+ }
+
+ node_distance_map[from][to] = distance;
+}
+
+unsigned char __node_distance(nodeid_t from, nodeid_t to)
+{
+ if ( from == to )
+ return NUMA_LOCAL_DISTANCE;
+
+ /*
+ * When NUMA is off, any distance will be treated as unreachable, so
+ * directly return NUMA_NO_DISTANCE from here as an optimization.
+ */
+ if ( numa_disabled() )
+ return NUMA_NO_DISTANCE;
+
+ /*
+ * Check whether the nodes are in the matrix range.
+ * When any node is out of range, except from and to nodes are the
+ * same (see above), we treat them as unreachable.
+ */
+ if ( from >= ARRAY_SIZE(node_distance_map) ||
+ to >= ARRAY_SIZE(node_distance_map[0]) )
+ return NUMA_NO_DISTANCE;
+
+ return node_distance_map[from][to];
+}
@@ -22,7 +22,6 @@ extern void init_cpu_to_node(void);
#define arch_want_default_dmazone() (num_online_nodes() > 1)
void srat_parse_regions(paddr_t addr);
-extern u8 __node_distance(nodeid_t a, nodeid_t b);
unsigned int arch_get_dma_bitsize(void);
#endif
@@ -328,7 +328,7 @@ unsigned int numa_node_to_arch_nid(nodeid_t n)
return 0;
}
-u8 __node_distance(nodeid_t a, nodeid_t b)
+unsigned char __node_distance(nodeid_t a, nodeid_t b)
{
unsigned index;
u8 slit_val;
@@ -114,6 +114,7 @@ extern bool numa_memblks_available(void);
extern bool numa_update_node_memblks(nodeid_t node, unsigned int arch_nid,
paddr_t start, paddr_t size, bool hotplug);
extern void numa_set_processor_nodes_parsed(nodeid_t node);
+extern unsigned char __node_distance(nodeid_t a, nodeid_t b);
#else