1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/types.h>
3 #include <linux/nodemask.h>
4 #include <linux/slab.h>
5 #include <linux/lockdep.h>
6 #include <linux/sysfs.h>
7 #include <linux/kobject.h>
8 #include <linux/memory-tiers.h>
11 /* hierarchy of memory tiers */
12 struct list_head list;
13 /* list of all memory types part of this tier */
14 struct list_head memory_types;
16 * start value of abstract distance. memory tier maps
17 * an abstract distance range,
18 * adistance_start .. adistance_start + MEMTIER_CHUNK_SIZE
23 struct memory_dev_type {
24 /* list of memory types that are part of same tier as this type */
25 struct list_head tier_sibiling;
26 /* abstract distance for this specific memory type */
28 /* Nodes of same abstract distance */
30 struct memory_tier *memtier;
33 static DEFINE_MUTEX(memory_tier_lock);
34 static LIST_HEAD(memory_tiers);
35 static struct memory_dev_type *node_memory_types[MAX_NUMNODES];
37 * For now we can have 4 faster memory tiers with smaller adistance
38 * than default DRAM tier.
40 static struct memory_dev_type default_dram_type = {
41 .adistance = MEMTIER_ADISTANCE_DRAM,
42 .tier_sibiling = LIST_HEAD_INIT(default_dram_type.tier_sibiling),
45 static struct memory_tier *find_create_memory_tier(struct memory_dev_type *memtype)
47 bool found_slot = false;
48 struct memory_tier *memtier, *new_memtier;
49 int adistance = memtype->adistance;
50 unsigned int memtier_adistance_chunk_size = MEMTIER_CHUNK_SIZE;
52 lockdep_assert_held_once(&memory_tier_lock);
55 * If the memtype is already part of a memory tier,
59 return memtype->memtier;
61 adistance = round_down(adistance, memtier_adistance_chunk_size);
62 list_for_each_entry(memtier, &memory_tiers, list) {
63 if (adistance == memtier->adistance_start) {
64 memtype->memtier = memtier;
65 list_add(&memtype->tier_sibiling, &memtier->memory_types);
67 } else if (adistance < memtier->adistance_start) {
73 new_memtier = kmalloc(sizeof(struct memory_tier), GFP_KERNEL);
75 return ERR_PTR(-ENOMEM);
77 new_memtier->adistance_start = adistance;
78 INIT_LIST_HEAD(&new_memtier->list);
79 INIT_LIST_HEAD(&new_memtier->memory_types);
81 list_add_tail(&new_memtier->list, &memtier->list);
83 list_add_tail(&new_memtier->list, &memory_tiers);
84 memtype->memtier = new_memtier;
85 list_add(&memtype->tier_sibiling, &new_memtier->memory_types);
89 static struct memory_tier *set_node_memory_tier(int node)
91 struct memory_tier *memtier;
92 struct memory_dev_type *memtype;
94 lockdep_assert_held_once(&memory_tier_lock);
96 if (!node_state(node, N_MEMORY))
97 return ERR_PTR(-EINVAL);
99 if (!node_memory_types[node])
100 node_memory_types[node] = &default_dram_type;
102 memtype = node_memory_types[node];
103 node_set(node, memtype->nodes);
104 memtier = find_create_memory_tier(memtype);
108 static int __init memory_tier_init(void)
111 struct memory_tier *memtier;
113 mutex_lock(&memory_tier_lock);
115 * Look at all the existing N_MEMORY nodes and add them to
116 * default memory tier or to a tier if we already have memory
119 for_each_node_state(node, N_MEMORY) {
120 memtier = set_node_memory_tier(node);
123 * Continue with memtiers we are able to setup
127 mutex_unlock(&memory_tier_lock);
131 subsys_initcall(memory_tier_init);
133 bool numa_demotion_enabled = false;
135 #ifdef CONFIG_MIGRATION
137 static ssize_t numa_demotion_enabled_show(struct kobject *kobj,
138 struct kobj_attribute *attr, char *buf)
140 return sysfs_emit(buf, "%s\n",
141 numa_demotion_enabled ? "true" : "false");
144 static ssize_t numa_demotion_enabled_store(struct kobject *kobj,
145 struct kobj_attribute *attr,
146 const char *buf, size_t count)
150 ret = kstrtobool(buf, &numa_demotion_enabled);
157 static struct kobj_attribute numa_demotion_enabled_attr =
158 __ATTR(demotion_enabled, 0644, numa_demotion_enabled_show,
159 numa_demotion_enabled_store);
161 static struct attribute *numa_attrs[] = {
162 &numa_demotion_enabled_attr.attr,
166 static const struct attribute_group numa_attr_group = {
170 static int __init numa_init_sysfs(void)
173 struct kobject *numa_kobj;
175 numa_kobj = kobject_create_and_add("numa", mm_kobj);
177 pr_err("failed to create numa kobject\n");
180 err = sysfs_create_group(numa_kobj, &numa_attr_group);
182 pr_err("failed to register numa group\n");
188 kobject_put(numa_kobj);
191 subsys_initcall(numa_init_sysfs);
192 #endif /* CONFIG_SYSFS */