new file mode 100644
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MEMORY_TIERS_H
+#define _LINUX_MEMORY_TIERS_H
+
+#ifdef CONFIG_NUMA
+
+#define MEMORY_TIER_HBM_GPU 300
+#define MEMORY_TIER_DRAM 200
+#define MEMORY_TIER_PMEM 100
+
+#define DEFAULT_MEMORY_TIER MEMORY_TIER_DRAM
+#define MAX_MEMORY_TIER_ID 400
+
+#endif /* CONFIG_NUMA */
+#endif /* _LINUX_MEMORY_TIERS_H */
@@ -92,6 +92,7 @@ obj-$(CONFIG_KFENCE) += kfence/
obj-$(CONFIG_FAILSLAB) += failslab.o
obj-$(CONFIG_MEMTEST) += memtest.o
obj-$(CONFIG_MIGRATION) += migrate.o
+obj-$(CONFIG_NUMA) += memory-tiers.o
obj-$(CONFIG_DEVICE_MIGRATION) += migrate_device.o
obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o khugepaged.o
obj-$(CONFIG_PAGE_COUNTER) += page_counter.o
new file mode 100644
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/types.h>
+#include <linux/nodemask.h>
+#include <linux/slab.h>
+#include <linux/lockdep.h>
+#include <linux/moduleparam.h>
+#include <linux/memory-tiers.h>
+
+struct memory_tier {
+ struct list_head list;
+ nodemask_t nodelist;
+ int id;
+};
+
+static DEFINE_MUTEX(memory_tier_lock);
+static LIST_HEAD(memory_tiers);
+
+static void insert_memory_tier(struct memory_tier *memtier)
+{
+ struct list_head *ent;
+ struct memory_tier *tmp_memtier;
+
+ lockdep_assert_held_once(&memory_tier_lock);
+
+ list_for_each(ent, &memory_tiers) {
+ tmp_memtier = list_entry(ent, struct memory_tier, list);
+ if (tmp_memtier->id < memtier->id) {
+ list_add_tail(&memtier->list, ent);
+ return;
+ }
+ }
+ list_add_tail(&memtier->list, &memory_tiers);
+}
+
+static struct memory_tier *register_memory_tier(unsigned int tier)
+{
+ struct memory_tier *memtier;
+
+ if (tier > MAX_MEMORY_TIER_ID)
+ return ERR_PTR(-EINVAL);
+
+ memtier = kzalloc(sizeof(struct memory_tier), GFP_KERNEL);
+ if (!memtier)
+ return ERR_PTR(-ENOMEM);
+
+ memtier->id = tier;
+
+ insert_memory_tier(memtier);
+
+ return memtier;
+}
+
+static unsigned int default_memtier = DEFAULT_MEMORY_TIER;
+core_param(default_memory_tier, default_memtier, uint, 0644);
+
+static int __init memory_tier_init(void)
+{
+ struct memory_tier *memtier;
+
+ /*
+ * Register only default memory tier to hide all empty
+ * memory tier from sysfs. Since this is early during
+ * boot, we could avoid holding memtory_tier_lock. But
+ * keep it simple by holding locks. So we can add lock
+ * held debug checks in other functions.
+ */
+ mutex_lock(&memory_tier_lock);
+ memtier = register_memory_tier(default_memtier);
+ if (IS_ERR(memtier))
+ panic("%s() failed to register memory tier: %ld\n",
+ __func__, PTR_ERR(memtier));
+
+ /* CPU only nodes are not part of memory tiers. */
+ memtier->nodelist = node_states[N_MEMORY];
+ mutex_unlock(&memory_tier_lock);
+ return 0;
+}
+subsys_initcall(memory_tier_init);