162306a36Sopenharmony_ci#include <errno.h> 262306a36Sopenharmony_ci#include <inttypes.h> 362306a36Sopenharmony_ci#include <asm/bug.h> 462306a36Sopenharmony_ci#include <linux/bitmap.h> 562306a36Sopenharmony_ci#include <linux/kernel.h> 662306a36Sopenharmony_ci#include <linux/zalloc.h> 762306a36Sopenharmony_ci#include "debug.h" 862306a36Sopenharmony_ci#include "env.h" 962306a36Sopenharmony_ci#include "mem2node.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistruct phys_entry { 1262306a36Sopenharmony_ci struct rb_node rb_node; 1362306a36Sopenharmony_ci u64 start; 1462306a36Sopenharmony_ci u64 end; 1562306a36Sopenharmony_ci u64 node; 1662306a36Sopenharmony_ci}; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic void phys_entry__insert(struct phys_entry *entry, struct rb_root *root) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct rb_node **p = &root->rb_node; 2162306a36Sopenharmony_ci struct rb_node *parent = NULL; 2262306a36Sopenharmony_ci struct phys_entry *e; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci while (*p != NULL) { 2562306a36Sopenharmony_ci parent = *p; 2662306a36Sopenharmony_ci e = rb_entry(parent, struct phys_entry, rb_node); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci if (entry->start < e->start) 2962306a36Sopenharmony_ci p = &(*p)->rb_left; 3062306a36Sopenharmony_ci else 3162306a36Sopenharmony_ci p = &(*p)->rb_right; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci rb_link_node(&entry->rb_node, parent, p); 3562306a36Sopenharmony_ci rb_insert_color(&entry->rb_node, root); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void 3962306a36Sopenharmony_ciphys_entry__init(struct phys_entry *entry, u64 start, u64 bsize, u64 node) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci entry->start = start; 4262306a36Sopenharmony_ci entry->end = start + bsize; 4362306a36Sopenharmony_ci entry->node = node; 4462306a36Sopenharmony_ci RB_CLEAR_NODE(&entry->rb_node); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciint mem2node__init(struct mem2node *map, struct perf_env *env) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci struct memory_node *n, *nodes = &env->memory_nodes[0]; 5062306a36Sopenharmony_ci struct phys_entry *entries, *tmp_entries; 5162306a36Sopenharmony_ci u64 bsize = env->memory_bsize; 5262306a36Sopenharmony_ci int i, j = 0, max = 0; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci memset(map, 0x0, sizeof(*map)); 5562306a36Sopenharmony_ci map->root = RB_ROOT; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci for (i = 0; i < env->nr_memory_nodes; i++) { 5862306a36Sopenharmony_ci n = &nodes[i]; 5962306a36Sopenharmony_ci max += bitmap_weight(n->set, n->size); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci entries = zalloc(sizeof(*entries) * max); 6362306a36Sopenharmony_ci if (!entries) 6462306a36Sopenharmony_ci return -ENOMEM; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci for (i = 0; i < env->nr_memory_nodes; i++) { 6762306a36Sopenharmony_ci u64 bit; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci n = &nodes[i]; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci for (bit = 0; bit < n->size; bit++) { 7262306a36Sopenharmony_ci u64 start; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (!test_bit(bit, n->set)) 7562306a36Sopenharmony_ci continue; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci start = bit * bsize; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * Merge nearby areas, we walk in order 8162306a36Sopenharmony_ci * through the bitmap, so no need to sort. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci if (j > 0) { 8462306a36Sopenharmony_ci struct phys_entry *prev = &entries[j - 1]; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if ((prev->end == start) && 8762306a36Sopenharmony_ci (prev->node == n->node)) { 8862306a36Sopenharmony_ci prev->end += bsize; 8962306a36Sopenharmony_ci continue; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci phys_entry__init(&entries[j++], start, bsize, n->node); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Cut unused entries, due to merging. */ 9862306a36Sopenharmony_ci tmp_entries = realloc(entries, sizeof(*entries) * j); 9962306a36Sopenharmony_ci if (tmp_entries || 10062306a36Sopenharmony_ci WARN_ONCE(j == 0, "No memory nodes, is CONFIG_MEMORY_HOTPLUG enabled?\n")) 10162306a36Sopenharmony_ci entries = tmp_entries; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci for (i = 0; i < j; i++) { 10462306a36Sopenharmony_ci pr_debug("mem2node %03" PRIu64 " [0x%016" PRIx64 "-0x%016" PRIx64 "]\n", 10562306a36Sopenharmony_ci entries[i].node, entries[i].start, entries[i].end); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci phys_entry__insert(&entries[i], &map->root); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci map->entries = entries; 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_civoid mem2node__exit(struct mem2node *map) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci zfree(&map->entries); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ciint mem2node__node(struct mem2node *map, u64 addr) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct rb_node **p, *parent = NULL; 12262306a36Sopenharmony_ci struct phys_entry *entry; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci p = &map->root.rb_node; 12562306a36Sopenharmony_ci while (*p != NULL) { 12662306a36Sopenharmony_ci parent = *p; 12762306a36Sopenharmony_ci entry = rb_entry(parent, struct phys_entry, rb_node); 12862306a36Sopenharmony_ci if (addr < entry->start) 12962306a36Sopenharmony_ci p = &(*p)->rb_left; 13062306a36Sopenharmony_ci else if (addr >= entry->end) 13162306a36Sopenharmony_ci p = &(*p)->rb_right; 13262306a36Sopenharmony_ci else 13362306a36Sopenharmony_ci goto out; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci entry = NULL; 13762306a36Sopenharmony_ciout: 13862306a36Sopenharmony_ci return entry ? (int) entry->node : -1; 13962306a36Sopenharmony_ci} 140