new file mode 100644
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MEMORY_TIERS_H
+#define _LINUX_MEMORY_TIERS_H
+
+#ifdef CONFIG_TIERED_MEMORY
+
+#define MEMORY_TIER_HBM_GPU 0
+#define MEMORY_TIER_DRAM 1
+#define MEMORY_TIER_PMEM 2
+
+#define MEMORY_RANK_HBM_GPU 300
+#define MEMORY_RANK_DRAM 200
+#define MEMORY_RANK_PMEM 100
+
+#define DEFAULT_MEMORY_TIER MEMORY_TIER_DRAM
+#define MAX_MEMORY_TIERS 3
+
+#endif /* CONFIG_TIERED_MEMORY */
+
+#endif
@@ -614,6 +614,9 @@ config ARCH_ENABLE_HUGEPAGE_MIGRATION
config ARCH_ENABLE_THP_MIGRATION
bool
+config TIERED_MEMORY
+ def_bool NUMA
+
config HUGETLB_PAGE_SIZE_VARIABLE
def_bool n
help
@@ -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_TIERED_MEMORY) += 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,89 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/types.h>
+#include <linux/nodemask.h>
+#include <linux/slab.h>
+#include <linux/memory-tiers.h>
+
+struct memory_tier {
+ struct list_head list;
+ nodemask_t nodelist;
+ int id;
+ int rank;
+};
+
+static DEFINE_MUTEX(memory_tier_lock);
+static LIST_HEAD(memory_tiers);
+
+/*
+ * Keep it simple by having direct mapping between
+ * tier index and rank value.
+ */
+static inline int get_rank_from_tier(unsigned int tier)
+{
+ switch (tier) {
+ case MEMORY_TIER_HBM_GPU:
+ return MEMORY_RANK_HBM_GPU;
+ case MEMORY_TIER_DRAM:
+ return MEMORY_RANK_DRAM;
+ case MEMORY_TIER_PMEM:
+ return MEMORY_RANK_PMEM;
+ }
+ return -1;
+}
+
+static void insert_memory_tier(struct memory_tier *memtier)
+{
+ struct list_head *ent;
+ struct memory_tier *tmp_memtier;
+
+ list_for_each(ent, &memory_tiers) {
+ tmp_memtier = list_entry(ent, struct memory_tier, list);
+ if (tmp_memtier->rank < memtier->rank) {
+ list_add_tail(&memtier->list, ent);
+ return;
+ }
+ }
+ list_add_tail(&memtier->list, &memory_tiers);
+}
+
+static struct memory_tier *register_memory_tier(unsigned int tier,
+ unsigned int rank)
+{
+ struct memory_tier *memtier;
+
+ if (tier >= MAX_MEMORY_TIERS)
+ return ERR_PTR(-EINVAL);
+
+ memtier = kzalloc(sizeof(struct memory_tier), GFP_KERNEL);
+ if (!memtier)
+ return ERR_PTR(-ENOMEM);
+
+ memtier->id = tier;
+ memtier->rank = rank;
+
+ insert_memory_tier(memtier);
+
+ return memtier;
+}
+
+static int __init memory_tier_init(void)
+{
+ struct memory_tier *memtier;
+
+ /*
+ * Register only default memory tier to hide all empty
+ * memory tier from sysfs.
+ */
+ memtier = register_memory_tier(DEFAULT_MEMORY_TIER,
+ get_rank_from_tier(DEFAULT_MEMORY_TIER));
+
+ 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];
+
+ return 0;
+}
+subsys_initcall(memory_tier_init);