18c2ecf20Sopenharmony_ci#include <errno.h>
28c2ecf20Sopenharmony_ci#include <inttypes.h>
38c2ecf20Sopenharmony_ci#include <asm/bug.h>
48c2ecf20Sopenharmony_ci#include <linux/bitmap.h>
58c2ecf20Sopenharmony_ci#include <linux/kernel.h>
68c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
78c2ecf20Sopenharmony_ci#include "debug.h"
88c2ecf20Sopenharmony_ci#include "env.h"
98c2ecf20Sopenharmony_ci#include "mem2node.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistruct phys_entry {
128c2ecf20Sopenharmony_ci	struct rb_node	rb_node;
138c2ecf20Sopenharmony_ci	u64	start;
148c2ecf20Sopenharmony_ci	u64	end;
158c2ecf20Sopenharmony_ci	u64	node;
168c2ecf20Sopenharmony_ci};
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic void phys_entry__insert(struct phys_entry *entry, struct rb_root *root)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct rb_node **p = &root->rb_node;
218c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL;
228c2ecf20Sopenharmony_ci	struct phys_entry *e;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	while (*p != NULL) {
258c2ecf20Sopenharmony_ci		parent = *p;
268c2ecf20Sopenharmony_ci		e = rb_entry(parent, struct phys_entry, rb_node);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci		if (entry->start < e->start)
298c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
308c2ecf20Sopenharmony_ci		else
318c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	rb_link_node(&entry->rb_node, parent, p);
358c2ecf20Sopenharmony_ci	rb_insert_color(&entry->rb_node, root);
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic void
398c2ecf20Sopenharmony_ciphys_entry__init(struct phys_entry *entry, u64 start, u64 bsize, u64 node)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	entry->start = start;
428c2ecf20Sopenharmony_ci	entry->end   = start + bsize;
438c2ecf20Sopenharmony_ci	entry->node  = node;
448c2ecf20Sopenharmony_ci	RB_CLEAR_NODE(&entry->rb_node);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ciint mem2node__init(struct mem2node *map, struct perf_env *env)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct memory_node *n, *nodes = &env->memory_nodes[0];
508c2ecf20Sopenharmony_ci	struct phys_entry *entries, *tmp_entries;
518c2ecf20Sopenharmony_ci	u64 bsize = env->memory_bsize;
528c2ecf20Sopenharmony_ci	int i, j = 0, max = 0;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	memset(map, 0x0, sizeof(*map));
558c2ecf20Sopenharmony_ci	map->root = RB_ROOT;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	for (i = 0; i < env->nr_memory_nodes; i++) {
588c2ecf20Sopenharmony_ci		n = &nodes[i];
598c2ecf20Sopenharmony_ci		max += bitmap_weight(n->set, n->size);
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	entries = zalloc(sizeof(*entries) * max);
638c2ecf20Sopenharmony_ci	if (!entries)
648c2ecf20Sopenharmony_ci		return -ENOMEM;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	for (i = 0; i < env->nr_memory_nodes; i++) {
678c2ecf20Sopenharmony_ci		u64 bit;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		n = &nodes[i];
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		for (bit = 0; bit < n->size; bit++) {
728c2ecf20Sopenharmony_ci			u64 start;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci			if (!test_bit(bit, n->set))
758c2ecf20Sopenharmony_ci				continue;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci			start = bit * bsize;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci			/*
808c2ecf20Sopenharmony_ci			 * Merge nearby areas, we walk in order
818c2ecf20Sopenharmony_ci			 * through the bitmap, so no need to sort.
828c2ecf20Sopenharmony_ci			 */
838c2ecf20Sopenharmony_ci			if (j > 0) {
848c2ecf20Sopenharmony_ci				struct phys_entry *prev = &entries[j - 1];
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci				if ((prev->end == start) &&
878c2ecf20Sopenharmony_ci				    (prev->node == n->node)) {
888c2ecf20Sopenharmony_ci					prev->end += bsize;
898c2ecf20Sopenharmony_ci					continue;
908c2ecf20Sopenharmony_ci				}
918c2ecf20Sopenharmony_ci			}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci			phys_entry__init(&entries[j++], start, bsize, n->node);
948c2ecf20Sopenharmony_ci		}
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	/* Cut unused entries, due to merging. */
988c2ecf20Sopenharmony_ci	tmp_entries = realloc(entries, sizeof(*entries) * j);
998c2ecf20Sopenharmony_ci	if (tmp_entries || WARN_ON_ONCE(j == 0))
1008c2ecf20Sopenharmony_ci		entries = tmp_entries;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	for (i = 0; i < j; i++) {
1038c2ecf20Sopenharmony_ci		pr_debug("mem2node %03" PRIu64 " [0x%016" PRIx64 "-0x%016" PRIx64 "]\n",
1048c2ecf20Sopenharmony_ci			 entries[i].node, entries[i].start, entries[i].end);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		phys_entry__insert(&entries[i], &map->root);
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	map->entries = entries;
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_civoid mem2node__exit(struct mem2node *map)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	zfree(&map->entries);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciint mem2node__node(struct mem2node *map, u64 addr)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct rb_node **p, *parent = NULL;
1218c2ecf20Sopenharmony_ci	struct phys_entry *entry;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	p = &map->root.rb_node;
1248c2ecf20Sopenharmony_ci	while (*p != NULL) {
1258c2ecf20Sopenharmony_ci		parent = *p;
1268c2ecf20Sopenharmony_ci		entry = rb_entry(parent, struct phys_entry, rb_node);
1278c2ecf20Sopenharmony_ci		if (addr < entry->start)
1288c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
1298c2ecf20Sopenharmony_ci		else if (addr >= entry->end)
1308c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
1318c2ecf20Sopenharmony_ci		else
1328c2ecf20Sopenharmony_ci			goto out;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	entry = NULL;
1368c2ecf20Sopenharmony_ciout:
1378c2ecf20Sopenharmony_ci	return entry ? (int) entry->node : -1;
1388c2ecf20Sopenharmony_ci}
139