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