| /* | |
| * NUMA support for s390 | |
| * | |
| * NUMA emulation (aka fake NUMA) distributes the available memory to nodes | |
| * without using real topology information about the physical memory of the | |
| * machine. | |
| * | |
| * It distributes the available CPUs to nodes while respecting the original | |
| * machine topology information. This is done by trying to avoid to separate | |
| * CPUs which reside on the same book or even on the same MC. | |
| * | |
| * Because the current Linux scheduler code requires a stable cpu to node | |
| * mapping, cores are pinned to nodes when the first CPU thread is set online. | |
| * | |
| * Copyright IBM Corp. 2015 | |
| */ | |
| #define KMSG_COMPONENT "numa_emu" | |
| #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | |
| #include <linux/kernel.h> | |
| #include <linux/cpumask.h> | |
| #include <linux/memblock.h> | |
| #include <linux/node.h> | |
| #include <linux/memory.h> | |
| #include <linux/slab.h> | |
| #include <asm/smp.h> | |
| #include <asm/topology.h> | |
| #include "numa_mode.h" | |
| #include "toptree.h" | |
| /* Distances between the different system components */ | |
| #define DIST_EMPTY 0 | |
| #define DIST_CORE 1 | |
| #define DIST_MC 2 | |
| #define DIST_BOOK 3 | |
| #define DIST_DRAWER 4 | |
| #define DIST_MAX 5 | |
| /* Node distance reported to common code */ | |
| #define EMU_NODE_DIST 10 | |
| /* Node ID for free (not yet pinned) cores */ | |
| #define NODE_ID_FREE -1 | |
| /* Different levels of toptree */ | |
| enum toptree_level {CORE, MC, BOOK, DRAWER, NODE, TOPOLOGY}; | |
| /* The two toptree IDs */ | |
| enum {TOPTREE_ID_PHYS, TOPTREE_ID_NUMA}; | |
| /* Number of NUMA nodes */ | |
| static int emu_nodes = 1; | |
| /* NUMA stripe size */ | |
| static unsigned long emu_size; | |
| /* | |
| * Node to core pinning information updates are protected by | |
| * "sched_domains_mutex". | |
| */ | |
| static struct { | |
| s32 to_node_id[CONFIG_NR_CPUS]; /* Pinned core to node mapping */ | |
| int total; /* Total number of pinned cores */ | |
| int per_node_target; /* Cores per node without extra cores */ | |
| int per_node[MAX_NUMNODES]; /* Number of cores pinned to node */ | |
| } *emu_cores; | |
| /* | |
| * Pin a core to a node | |
| */ | |
| static void pin_core_to_node(int core_id, int node_id) | |
| { | |
| if (emu_cores->to_node_id[core_id] == NODE_ID_FREE) { | |
| emu_cores->per_node[node_id]++; | |
| emu_cores->to_node_id[core_id] = node_id; | |
| emu_cores->total++; | |
| } else { | |
| WARN_ON(emu_cores->to_node_id[core_id] != node_id); | |
| } | |
| } | |
| /* | |
| * Number of pinned cores of a node | |
| */ | |
| static int cores_pinned(struct toptree *node) | |
| { | |
| return emu_cores->per_node[node->id]; | |
| } | |
| /* | |
| * ID of the node where the core is pinned (or NODE_ID_FREE) | |
| */ | |
| static int core_pinned_to_node_id(struct toptree *core) | |
| { | |
| return emu_cores->to_node_id[core->id]; | |
| } | |
| /* | |
| * Number of cores in the tree that are not yet pinned | |
| */ | |
| static int cores_free(struct toptree *tree) | |
| { | |
| struct toptree *core; | |
| int count = 0; | |
| toptree_for_each(core, tree, CORE) { | |
| if (core_pinned_to_node_id(core) == NODE_ID_FREE) | |
| count++; | |
| } | |
| return count; | |
| } | |
| /* | |
| * Return node of core | |
| */ | |
| static struct toptree *core_node(struct toptree *core) | |
| { | |
| return core->parent->parent->parent->parent; | |
| } | |
| /* | |
| * Return drawer of core | |
| */ | |
| static struct toptree *core_drawer(struct toptree *core) | |
| { | |
| return core->parent->parent->parent; | |
| } | |
| /* | |
| * Return book of core | |
| */ | |
| static struct toptree *core_book(struct toptree *core) | |
| { | |
| return core->parent->parent; | |
| } | |
| /* | |
| * Return mc of core | |
| */ | |
| static struct toptree *core_mc(struct toptree *core) | |
| { | |
| return core->parent; | |
| } | |
| /* | |
| * Distance between two cores | |
| */ | |
| static int dist_core_to_core(struct toptree *core1, struct toptree *core2) | |
| { | |
| if (core_drawer(core1)->id != core_drawer(core2)->id) | |
| return DIST_DRAWER; | |
| if (core_book(core1)->id != core_book(core2)->id) | |
| return DIST_BOOK; | |
| if (core_mc(core1)->id != core_mc(core2)->id) | |
| return DIST_MC; | |
| /* Same core or sibling on same MC */ | |
| return DIST_CORE; | |
| } | |
| /* | |
| * Distance of a node to a core | |
| */ | |
| static int dist_node_to_core(struct toptree *node, struct toptree *core) | |
| { | |
| struct toptree *core_node; | |
| int dist_min = DIST_MAX; | |
| toptree_for_each(core_node, node, CORE) | |
| dist_min = min(dist_min, dist_core_to_core(core_node, core)); | |
| return dist_min == DIST_MAX ? DIST_EMPTY : dist_min; | |
| } | |
| /* | |
| * Unify will delete empty nodes, therefore recreate nodes. | |
| */ | |
| static void toptree_unify_tree(struct toptree *tree) | |
| { | |
| int nid; | |
| toptree_unify(tree); | |
| for (nid = 0; nid < emu_nodes; nid++) | |
| toptree_get_child(tree, nid); | |
| } | |
| /* | |
| * Find the best/nearest node for a given core and ensure that no node | |
| * gets more than "emu_cores->per_node_target + extra" cores. | |
| */ | |
| static struct toptree *node_for_core(struct toptree *numa, struct toptree *core, | |
| int extra) | |
| { | |
| struct toptree *node, *node_best = NULL; | |
| int dist_cur, dist_best, cores_target; | |
| cores_target = emu_cores->per_node_target + extra; | |
| dist_best = DIST_MAX; | |
| node_best = NULL; | |
| toptree_for_each(node, numa, NODE) { | |
| /* Already pinned cores must use their nodes */ | |
| if (core_pinned_to_node_id(core) == node->id) { | |
| node_best = node; | |
| break; | |
| } | |
| /* Skip nodes that already have enough cores */ | |
| if (cores_pinned(node) >= cores_target) | |
| continue; | |
| dist_cur = dist_node_to_core(node, core); | |
| if (dist_cur < dist_best) { | |
| dist_best = dist_cur; | |
| node_best = node; | |
| } | |
| } | |
| return node_best; | |
| } | |
| /* | |
| * Find the best node for each core with respect to "extra" core count | |
| */ | |
| static void toptree_to_numa_single(struct toptree *numa, struct toptree *phys, | |
| int extra) | |
| { | |
| struct toptree *node, *core, *tmp; | |
| toptree_for_each_safe(core, tmp, phys, CORE) { | |
| node = node_for_core(numa, core, extra); | |
| if (!node) | |
| return; | |
| toptree_move(core, node); | |
| pin_core_to_node(core->id, node->id); | |
| } | |
| } | |
| /* | |
| * Move structures of given level to specified NUMA node | |
| */ | |
| static void move_level_to_numa_node(struct toptree *node, struct toptree *phys, | |
| enum toptree_level level, bool perfect) | |
| { | |
| int cores_free, cores_target = emu_cores->per_node_target; | |
| struct toptree *cur, *tmp; | |
| toptree_for_each_safe(cur, tmp, phys, level) { | |
| cores_free = cores_target - toptree_count(node, CORE); | |
| if (perfect) { | |
| if (cores_free == toptree_count(cur, CORE)) | |
| toptree_move(cur, node); | |
| } else { | |
| if (cores_free >= toptree_count(cur, CORE)) | |
| toptree_move(cur, node); | |
| } | |
| } | |
| } | |
| /* | |
| * Move structures of a given level to NUMA nodes. If "perfect" is specified | |
| * move only perfectly fitting structures. Otherwise move also smaller | |
| * than needed structures. | |
| */ | |
| static void move_level_to_numa(struct toptree *numa, struct toptree *phys, | |
| enum toptree_level level, bool perfect) | |
| { | |
| struct toptree *node; | |
| toptree_for_each(node, numa, NODE) | |
| move_level_to_numa_node(node, phys, level, perfect); | |
| } | |
| /* | |
| * For the first run try to move the big structures | |
| */ | |
| static void toptree_to_numa_first(struct toptree *numa, struct toptree *phys) | |
| { | |
| struct toptree *core; | |
| /* Always try to move perfectly fitting structures first */ | |
| move_level_to_numa(numa, phys, DRAWER, true); | |
| move_level_to_numa(numa, phys, DRAWER, false); | |
| move_level_to_numa(numa, phys, BOOK, true); | |
| move_level_to_numa(numa, phys, BOOK, false); | |
| move_level_to_numa(numa, phys, MC, true); | |
| move_level_to_numa(numa, phys, MC, false); | |
| /* Now pin all the moved cores */ | |
| toptree_for_each(core, numa, CORE) | |
| pin_core_to_node(core->id, core_node(core)->id); | |
| } | |
| /* | |
| * Allocate new topology and create required nodes | |
| */ | |
| static struct toptree *toptree_new(int id, int nodes) | |
| { | |
| struct toptree *tree; | |
| int nid; | |
| tree = toptree_alloc(TOPOLOGY, id); | |
| if (!tree) | |
| goto fail; | |
| for (nid = 0; nid < nodes; nid++) { | |
| if (!toptree_get_child(tree, nid)) | |
| goto fail; | |
| } | |
| return tree; | |
| fail: | |
| panic("NUMA emulation could not allocate topology"); | |
| } | |
| /* | |
| * Allocate and initialize core to node mapping | |
| */ | |
| static void create_core_to_node_map(void) | |
| { | |
| int i; | |
| emu_cores = kzalloc(sizeof(*emu_cores), GFP_KERNEL); | |
| if (emu_cores == NULL) | |
| panic("Could not allocate cores to node memory"); | |
| for (i = 0; i < ARRAY_SIZE(emu_cores->to_node_id); i++) | |
| emu_cores->to_node_id[i] = NODE_ID_FREE; | |
| } | |
| /* | |
| * Move cores from physical topology into NUMA target topology | |
| * and try to keep as much of the physical topology as possible. | |
| */ | |
| static struct toptree *toptree_to_numa(struct toptree *phys) | |
| { | |
| static int first = 1; | |
| struct toptree *numa; | |
| int cores_total; | |
| cores_total = emu_cores->total + cores_free(phys); | |
| emu_cores->per_node_target = cores_total / emu_nodes; | |
| numa = toptree_new(TOPTREE_ID_NUMA, emu_nodes); | |
| if (first) { | |
| toptree_to_numa_first(numa, phys); | |
| first = 0; | |
| } | |
| toptree_to_numa_single(numa, phys, 0); | |
| toptree_to_numa_single(numa, phys, 1); | |
| toptree_unify_tree(numa); | |
| WARN_ON(cpumask_weight(&phys->mask)); | |
| return numa; | |
| } | |
| /* | |
| * Create a toptree out of the physical topology that we got from the hypervisor | |
| */ | |
| static struct toptree *toptree_from_topology(void) | |
| { | |
| struct toptree *phys, *node, *drawer, *book, *mc, *core; | |
| struct cpu_topology_s390 *top; | |
| int cpu; | |
| phys = toptree_new(TOPTREE_ID_PHYS, 1); | |
| for_each_online_cpu(cpu) { | |
| top = &per_cpu(cpu_topology, cpu); | |
| node = toptree_get_child(phys, 0); | |
| drawer = toptree_get_child(node, top->drawer_id); | |
| book = toptree_get_child(drawer, top->book_id); | |
| mc = toptree_get_child(book, top->socket_id); | |
| core = toptree_get_child(mc, top->core_id); | |
| if (!drawer || !book || !mc || !core) | |
| panic("NUMA emulation could not allocate memory"); | |
| cpumask_set_cpu(cpu, &core->mask); | |
| toptree_update_mask(mc); | |
| } | |
| return phys; | |
| } | |
| /* | |
| * Add toptree core to topology and create correct CPU masks | |
| */ | |
| static void topology_add_core(struct toptree *core) | |
| { | |
| struct cpu_topology_s390 *top; | |
| int cpu; | |
| for_each_cpu(cpu, &core->mask) { | |
| top = &per_cpu(cpu_topology, cpu); | |
| cpumask_copy(&top->thread_mask, &core->mask); | |
| cpumask_copy(&top->core_mask, &core_mc(core)->mask); | |
| cpumask_copy(&top->book_mask, &core_book(core)->mask); | |
| cpumask_copy(&top->drawer_mask, &core_drawer(core)->mask); | |
| cpumask_set_cpu(cpu, &node_to_cpumask_map[core_node(core)->id]); | |
| top->node_id = core_node(core)->id; | |
| } | |
| } | |
| /* | |
| * Apply toptree to topology and create CPU masks | |
| */ | |
| static void toptree_to_topology(struct toptree *numa) | |
| { | |
| struct toptree *core; | |
| int i; | |
| /* Clear all node masks */ | |
| for (i = 0; i < MAX_NUMNODES; i++) | |
| cpumask_clear(&node_to_cpumask_map[i]); | |
| /* Rebuild all masks */ | |
| toptree_for_each(core, numa, CORE) | |
| topology_add_core(core); | |
| } | |
| /* | |
| * Show the node to core mapping | |
| */ | |
| static void print_node_to_core_map(void) | |
| { | |
| int nid, cid; | |
| if (!numa_debug_enabled) | |
| return; | |
| printk(KERN_DEBUG "NUMA node to core mapping\n"); | |
| for (nid = 0; nid < emu_nodes; nid++) { | |
| printk(KERN_DEBUG " node %3d: ", nid); | |
| for (cid = 0; cid < ARRAY_SIZE(emu_cores->to_node_id); cid++) { | |
| if (emu_cores->to_node_id[cid] == nid) | |
| printk(KERN_CONT "%d ", cid); | |
| } | |
| printk(KERN_CONT "\n"); | |
| } | |
| } | |
| /* | |
| * Transfer physical topology into a NUMA topology and modify CPU masks | |
| * according to the NUMA topology. | |
| * | |
| * Must be called with "sched_domains_mutex" lock held. | |
| */ | |
| static void emu_update_cpu_topology(void) | |
| { | |
| struct toptree *phys, *numa; | |
| if (emu_cores == NULL) | |
| create_core_to_node_map(); | |
| phys = toptree_from_topology(); | |
| numa = toptree_to_numa(phys); | |
| toptree_free(phys); | |
| toptree_to_topology(numa); | |
| toptree_free(numa); | |
| print_node_to_core_map(); | |
| } | |
| /* | |
| * If emu_size is not set, use CONFIG_EMU_SIZE. Then round to minimum | |
| * alignment (needed for memory hotplug). | |
| */ | |
| static unsigned long emu_setup_size_adjust(unsigned long size) | |
| { | |
| unsigned long size_new; | |
| size = size ? : CONFIG_EMU_SIZE; | |
| size_new = roundup(size, memory_block_size_bytes()); | |
| if (size_new == size) | |
| return size; | |
| pr_warn("Increasing memory stripe size from %ld MB to %ld MB\n", | |
| size >> 20, size_new >> 20); | |
| return size_new; | |
| } | |
| /* | |
| * If we have not enough memory for the specified nodes, reduce the node count. | |
| */ | |
| static int emu_setup_nodes_adjust(int nodes) | |
| { | |
| int nodes_max; | |
| nodes_max = memblock.memory.total_size / emu_size; | |
| nodes_max = max(nodes_max, 1); | |
| if (nodes_max >= nodes) | |
| return nodes; | |
| pr_warn("Not enough memory for %d nodes, reducing node count\n", nodes); | |
| return nodes_max; | |
| } | |
| /* | |
| * Early emu setup | |
| */ | |
| static void emu_setup(void) | |
| { | |
| int nid; | |
| emu_size = emu_setup_size_adjust(emu_size); | |
| emu_nodes = emu_setup_nodes_adjust(emu_nodes); | |
| for (nid = 0; nid < emu_nodes; nid++) | |
| node_set(nid, node_possible_map); | |
| pr_info("Creating %d nodes with memory stripe size %ld MB\n", | |
| emu_nodes, emu_size >> 20); | |
| } | |
| /* | |
| * Return node id for given page number | |
| */ | |
| static int emu_pfn_to_nid(unsigned long pfn) | |
| { | |
| return (pfn / (emu_size >> PAGE_SHIFT)) % emu_nodes; | |
| } | |
| /* | |
| * Return stripe size | |
| */ | |
| static unsigned long emu_align(void) | |
| { | |
| return emu_size; | |
| } | |
| /* | |
| * Return distance between two nodes | |
| */ | |
| static int emu_distance(int node1, int node2) | |
| { | |
| return (node1 != node2) * EMU_NODE_DIST; | |
| } | |
| /* | |
| * Define callbacks for generic s390 NUMA infrastructure | |
| */ | |
| const struct numa_mode numa_mode_emu = { | |
| .name = "emu", | |
| .setup = emu_setup, | |
| .update_cpu_topology = emu_update_cpu_topology, | |
| .__pfn_to_nid = emu_pfn_to_nid, | |
| .align = emu_align, | |
| .distance = emu_distance, | |
| }; | |
| /* | |
| * Kernel parameter: emu_nodes=<n> | |
| */ | |
| static int __init early_parse_emu_nodes(char *p) | |
| { | |
| int count; | |
| if (kstrtoint(p, 0, &count) != 0 || count <= 0) | |
| return 0; | |
| if (count <= 0) | |
| return 0; | |
| emu_nodes = min(count, MAX_NUMNODES); | |
| return 0; | |
| } | |
| early_param("emu_nodes", early_parse_emu_nodes); | |
| /* | |
| * Kernel parameter: emu_size=[<n>[k|M|G|T]] | |
| */ | |
| static int __init early_parse_emu_size(char *p) | |
| { | |
| emu_size = memparse(p, NULL); | |
| return 0; | |
| } | |
| early_param("emu_size", early_parse_emu_size); |