@@ -20,6 +20,7 @@
#include <linux/pm_runtime.h>
#include <linux/swap.h>
#include <linux/slab.h>
+#include <linux/memory-tiers.h>
static struct bus_type node_subsys = {
.name = "node",
@@ -560,11 +561,52 @@ static ssize_t node_read_distance(struct device *dev,
}
static DEVICE_ATTR(distance, 0444, node_read_distance, NULL);
+#ifdef CONFIG_NUMA
+static ssize_t memtier_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int node = dev->id;
+ int tier_index = node_get_memory_tier_id(node);
+
+ /*
+ * CPU only NUMA node is not part of memory tiers.
+ */
+ if (tier_index != -1)
+ return sysfs_emit(buf, "%d\n", tier_index);
+ return 0;
+}
+
+static ssize_t memtier_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long tier;
+ int node = dev->id;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &tier);
+ if (ret)
+ return ret;
+
+ ret = node_update_memory_tier(node, tier);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(memtier);
+#endif
+
static struct attribute *node_dev_attrs[] = {
&dev_attr_meminfo.attr,
&dev_attr_numastat.attr,
&dev_attr_distance.attr,
&dev_attr_vmstat.attr,
+#ifdef CONFIG_NUMA
+ &dev_attr_memtier.attr,
+#endif
NULL
};
@@ -23,6 +23,8 @@ static inline int next_demotion_node(int node)
return NUMA_NO_NODE;
}
#endif
+int node_get_memory_tier_id(int node);
+int node_update_memory_tier(int node, int tier);
#else
@@ -288,6 +288,48 @@ static int node_set_memory_tier(int node, int tier)
return ret;
}
+int node_get_memory_tier_id(int node)
+{
+ int tier = -1;
+ struct memory_tier *memtier;
+ /*
+ * Make sure memory tier is not unregistered
+ * while it is being read.
+ */
+ mutex_lock(&memory_tier_lock);
+ memtier = __node_get_memory_tier(node);
+ if (memtier)
+ tier = memtier->dev.id;
+ mutex_unlock(&memory_tier_lock);
+
+ return tier;
+}
+
+int node_update_memory_tier(int node, int tier)
+{
+ struct memory_tier *current_tier;
+ int ret = 0;
+
+ mutex_lock(&memory_tier_lock);
+
+ current_tier = __node_get_memory_tier(node);
+ if (!current_tier || current_tier->dev.id == tier)
+ goto out;
+
+ node_clear(node, current_tier->nodelist);
+
+ ret = __node_create_and_set_memory_tier(node, tier);
+
+ if (nodes_empty(current_tier->nodelist))
+ unregister_memory_tier(current_tier);
+
+ establish_migration_targets();
+out:
+ mutex_unlock(&memory_tier_lock);
+
+ return ret;
+}
+
#ifdef CONFIG_MIGRATION
/**
* next_demotion_node() - Get the next node in the demotion path