162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/slab.h> 362306a36Sopenharmony_ci#include <linux/kernel.h> 462306a36Sopenharmony_ci#include <linux/bitops.h> 562306a36Sopenharmony_ci#include <linux/cpumask.h> 662306a36Sopenharmony_ci#include <linux/export.h> 762306a36Sopenharmony_ci#include <linux/memblock.h> 862306a36Sopenharmony_ci#include <linux/numa.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/** 1162306a36Sopenharmony_ci * cpumask_next_wrap - helper to implement for_each_cpu_wrap 1262306a36Sopenharmony_ci * @n: the cpu prior to the place to search 1362306a36Sopenharmony_ci * @mask: the cpumask pointer 1462306a36Sopenharmony_ci * @start: the start point of the iteration 1562306a36Sopenharmony_ci * @wrap: assume @n crossing @start terminates the iteration 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Returns >= nr_cpu_ids on completion 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Note: the @wrap argument is required for the start condition when 2062306a36Sopenharmony_ci * we cannot assume @start is set in @mask. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ciunsigned int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci unsigned int next; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciagain: 2762306a36Sopenharmony_ci next = cpumask_next(n, mask); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (wrap && n < start && next >= start) { 3062306a36Sopenharmony_ci return nr_cpumask_bits; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci } else if (next >= nr_cpumask_bits) { 3362306a36Sopenharmony_ci wrap = true; 3462306a36Sopenharmony_ci n = -1; 3562306a36Sopenharmony_ci goto again; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci return next; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ciEXPORT_SYMBOL(cpumask_next_wrap); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* These are not inline because of header tangles. */ 4362306a36Sopenharmony_ci#ifdef CONFIG_CPUMASK_OFFSTACK 4462306a36Sopenharmony_ci/** 4562306a36Sopenharmony_ci * alloc_cpumask_var_node - allocate a struct cpumask on a given node 4662306a36Sopenharmony_ci * @mask: pointer to cpumask_var_t where the cpumask is returned 4762306a36Sopenharmony_ci * @flags: GFP_ flags 4862306a36Sopenharmony_ci * @node: memory node from which to allocate or %NUMA_NO_NODE 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is 5162306a36Sopenharmony_ci * a nop returning a constant 1 (in <linux/cpumask.h>) 5262306a36Sopenharmony_ci * Returns TRUE if memory allocation succeeded, FALSE otherwise. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * In addition, mask will be NULL if this fails. Note that gcc is 5562306a36Sopenharmony_ci * usually smart enough to know that mask can never be NULL if 5662306a36Sopenharmony_ci * CONFIG_CPUMASK_OFFSTACK=n, so does code elimination in that case 5762306a36Sopenharmony_ci * too. 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_cibool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci *mask = kmalloc_node(cpumask_size(), flags, node); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_PER_CPU_MAPS 6462306a36Sopenharmony_ci if (!*mask) { 6562306a36Sopenharmony_ci printk(KERN_ERR "=> alloc_cpumask_var: failed!\n"); 6662306a36Sopenharmony_ci dump_stack(); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci#endif 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return *mask != NULL; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ciEXPORT_SYMBOL(alloc_cpumask_var_node); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/** 7562306a36Sopenharmony_ci * alloc_bootmem_cpumask_var - allocate a struct cpumask from the bootmem arena. 7662306a36Sopenharmony_ci * @mask: pointer to cpumask_var_t where the cpumask is returned 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is 7962306a36Sopenharmony_ci * a nop (in <linux/cpumask.h>). 8062306a36Sopenharmony_ci * Either returns an allocated (zero-filled) cpumask, or causes the 8162306a36Sopenharmony_ci * system to panic. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_civoid __init alloc_bootmem_cpumask_var(cpumask_var_t *mask) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci *mask = memblock_alloc(cpumask_size(), SMP_CACHE_BYTES); 8662306a36Sopenharmony_ci if (!*mask) 8762306a36Sopenharmony_ci panic("%s: Failed to allocate %u bytes\n", __func__, 8862306a36Sopenharmony_ci cpumask_size()); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/** 9262306a36Sopenharmony_ci * free_cpumask_var - frees memory allocated for a struct cpumask. 9362306a36Sopenharmony_ci * @mask: cpumask to free 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * This is safe on a NULL mask. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_civoid free_cpumask_var(cpumask_var_t mask) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci kfree(mask); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ciEXPORT_SYMBOL(free_cpumask_var); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/** 10462306a36Sopenharmony_ci * free_bootmem_cpumask_var - frees result of alloc_bootmem_cpumask_var 10562306a36Sopenharmony_ci * @mask: cpumask to free 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_civoid __init free_bootmem_cpumask_var(cpumask_var_t mask) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci memblock_free(mask, cpumask_size()); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci#endif 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/** 11462306a36Sopenharmony_ci * cpumask_local_spread - select the i'th cpu based on NUMA distances 11562306a36Sopenharmony_ci * @i: index number 11662306a36Sopenharmony_ci * @node: local numa_node 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * Returns online CPU according to a numa aware policy; local cpus are returned 11962306a36Sopenharmony_ci * first, followed by non-local ones, then it wraps around. 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * For those who wants to enumerate all CPUs based on their NUMA distances, 12262306a36Sopenharmony_ci * i.e. call this function in a loop, like: 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * for (i = 0; i < num_online_cpus(); i++) { 12562306a36Sopenharmony_ci * cpu = cpumask_local_spread(i, node); 12662306a36Sopenharmony_ci * do_something(cpu); 12762306a36Sopenharmony_ci * } 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * There's a better alternative based on for_each()-like iterators: 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * for_each_numa_hop_mask(mask, node) { 13262306a36Sopenharmony_ci * for_each_cpu_andnot(cpu, mask, prev) 13362306a36Sopenharmony_ci * do_something(cpu); 13462306a36Sopenharmony_ci * prev = mask; 13562306a36Sopenharmony_ci * } 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * It's simpler and more verbose than above. Complexity of iterator-based 13862306a36Sopenharmony_ci * enumeration is O(sched_domains_numa_levels * nr_cpu_ids), while 13962306a36Sopenharmony_ci * cpumask_local_spread() when called for each cpu is 14062306a36Sopenharmony_ci * O(sched_domains_numa_levels * nr_cpu_ids * log(nr_cpu_ids)). 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ciunsigned int cpumask_local_spread(unsigned int i, int node) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci unsigned int cpu; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* Wrap: we always want a cpu. */ 14762306a36Sopenharmony_ci i %= num_online_cpus(); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci cpu = (node == NUMA_NO_NODE) ? 15062306a36Sopenharmony_ci cpumask_nth(i, cpu_online_mask) : 15162306a36Sopenharmony_ci sched_numa_find_nth_cpu(cpu_online_mask, i, node); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci WARN_ON(cpu >= nr_cpu_ids); 15462306a36Sopenharmony_ci return cpu; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ciEXPORT_SYMBOL(cpumask_local_spread); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic DEFINE_PER_CPU(int, distribute_cpu_mask_prev); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/** 16162306a36Sopenharmony_ci * cpumask_any_and_distribute - Return an arbitrary cpu within src1p & src2p. 16262306a36Sopenharmony_ci * @src1p: first &cpumask for intersection 16362306a36Sopenharmony_ci * @src2p: second &cpumask for intersection 16462306a36Sopenharmony_ci * 16562306a36Sopenharmony_ci * Iterated calls using the same srcp1 and srcp2 will be distributed within 16662306a36Sopenharmony_ci * their intersection. 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * Returns >= nr_cpu_ids if the intersection is empty. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ciunsigned int cpumask_any_and_distribute(const struct cpumask *src1p, 17162306a36Sopenharmony_ci const struct cpumask *src2p) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci unsigned int next, prev; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* NOTE: our first selection will skip 0. */ 17662306a36Sopenharmony_ci prev = __this_cpu_read(distribute_cpu_mask_prev); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci next = find_next_and_bit_wrap(cpumask_bits(src1p), cpumask_bits(src2p), 17962306a36Sopenharmony_ci nr_cpumask_bits, prev + 1); 18062306a36Sopenharmony_ci if (next < nr_cpu_ids) 18162306a36Sopenharmony_ci __this_cpu_write(distribute_cpu_mask_prev, next); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return next; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ciEXPORT_SYMBOL(cpumask_any_and_distribute); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciunsigned int cpumask_any_distribute(const struct cpumask *srcp) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci unsigned int next, prev; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* NOTE: our first selection will skip 0. */ 19262306a36Sopenharmony_ci prev = __this_cpu_read(distribute_cpu_mask_prev); 19362306a36Sopenharmony_ci next = find_next_bit_wrap(cpumask_bits(srcp), nr_cpumask_bits, prev + 1); 19462306a36Sopenharmony_ci if (next < nr_cpu_ids) 19562306a36Sopenharmony_ci __this_cpu_write(distribute_cpu_mask_prev, next); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return next; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ciEXPORT_SYMBOL(cpumask_any_distribute); 200