18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/slab.h> 38c2ecf20Sopenharmony_ci#include <linux/kernel.h> 48c2ecf20Sopenharmony_ci#include <linux/bitops.h> 58c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 68c2ecf20Sopenharmony_ci#include <linux/export.h> 78c2ecf20Sopenharmony_ci#include <linux/memblock.h> 88c2ecf20Sopenharmony_ci#include <linux/numa.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/** 118c2ecf20Sopenharmony_ci * cpumask_next - get the next cpu in a cpumask 128c2ecf20Sopenharmony_ci * @n: the cpu prior to the place to search (ie. return will be > @n) 138c2ecf20Sopenharmony_ci * @srcp: the cpumask pointer 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Returns >= nr_cpu_ids if no further cpus set. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ciunsigned int cpumask_next(int n, const struct cpumask *srcp) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci /* -1 is a legal arg here. */ 208c2ecf20Sopenharmony_ci if (n != -1) 218c2ecf20Sopenharmony_ci cpumask_check(n); 228c2ecf20Sopenharmony_ci return find_next_bit(cpumask_bits(srcp), nr_cpumask_bits, n + 1); 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpumask_next); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/** 278c2ecf20Sopenharmony_ci * cpumask_next_and - get the next cpu in *src1p & *src2p 288c2ecf20Sopenharmony_ci * @n: the cpu prior to the place to search (ie. return will be > @n) 298c2ecf20Sopenharmony_ci * @src1p: the first cpumask pointer 308c2ecf20Sopenharmony_ci * @src2p: the second cpumask pointer 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Returns >= nr_cpu_ids if no further cpus set in both. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ciint cpumask_next_and(int n, const struct cpumask *src1p, 358c2ecf20Sopenharmony_ci const struct cpumask *src2p) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci /* -1 is a legal arg here. */ 388c2ecf20Sopenharmony_ci if (n != -1) 398c2ecf20Sopenharmony_ci cpumask_check(n); 408c2ecf20Sopenharmony_ci return find_next_and_bit(cpumask_bits(src1p), cpumask_bits(src2p), 418c2ecf20Sopenharmony_ci nr_cpumask_bits, n + 1); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpumask_next_and); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/** 468c2ecf20Sopenharmony_ci * cpumask_any_but - return a "random" in a cpumask, but not this one. 478c2ecf20Sopenharmony_ci * @mask: the cpumask to search 488c2ecf20Sopenharmony_ci * @cpu: the cpu to ignore. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * Often used to find any cpu but smp_processor_id() in a mask. 518c2ecf20Sopenharmony_ci * Returns >= nr_cpu_ids if no cpus set. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ciint cpumask_any_but(const struct cpumask *mask, unsigned int cpu) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci unsigned int i; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci cpumask_check(cpu); 588c2ecf20Sopenharmony_ci for_each_cpu(i, mask) 598c2ecf20Sopenharmony_ci if (i != cpu) 608c2ecf20Sopenharmony_ci break; 618c2ecf20Sopenharmony_ci return i; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpumask_any_but); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/** 668c2ecf20Sopenharmony_ci * cpumask_next_wrap - helper to implement for_each_cpu_wrap 678c2ecf20Sopenharmony_ci * @n: the cpu prior to the place to search 688c2ecf20Sopenharmony_ci * @mask: the cpumask pointer 698c2ecf20Sopenharmony_ci * @start: the start point of the iteration 708c2ecf20Sopenharmony_ci * @wrap: assume @n crossing @start terminates the iteration 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * Returns >= nr_cpu_ids on completion 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * Note: the @wrap argument is required for the start condition when 758c2ecf20Sopenharmony_ci * we cannot assume @start is set in @mask. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_ciint cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int next; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ciagain: 828c2ecf20Sopenharmony_ci next = cpumask_next(n, mask); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (wrap && n < start && next >= start) { 858c2ecf20Sopenharmony_ci return nr_cpumask_bits; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci } else if (next >= nr_cpumask_bits) { 888c2ecf20Sopenharmony_ci wrap = true; 898c2ecf20Sopenharmony_ci n = -1; 908c2ecf20Sopenharmony_ci goto again; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return next; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpumask_next_wrap); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci/* These are not inline because of header tangles. */ 988c2ecf20Sopenharmony_ci#ifdef CONFIG_CPUMASK_OFFSTACK 998c2ecf20Sopenharmony_ci/** 1008c2ecf20Sopenharmony_ci * alloc_cpumask_var_node - allocate a struct cpumask on a given node 1018c2ecf20Sopenharmony_ci * @mask: pointer to cpumask_var_t where the cpumask is returned 1028c2ecf20Sopenharmony_ci * @flags: GFP_ flags 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is 1058c2ecf20Sopenharmony_ci * a nop returning a constant 1 (in <linux/cpumask.h>) 1068c2ecf20Sopenharmony_ci * Returns TRUE if memory allocation succeeded, FALSE otherwise. 1078c2ecf20Sopenharmony_ci * 1088c2ecf20Sopenharmony_ci * In addition, mask will be NULL if this fails. Note that gcc is 1098c2ecf20Sopenharmony_ci * usually smart enough to know that mask can never be NULL if 1108c2ecf20Sopenharmony_ci * CONFIG_CPUMASK_OFFSTACK=n, so does code elimination in that case 1118c2ecf20Sopenharmony_ci * too. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_cibool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci *mask = kmalloc_node(cpumask_size(), flags, node); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_PER_CPU_MAPS 1188c2ecf20Sopenharmony_ci if (!*mask) { 1198c2ecf20Sopenharmony_ci printk(KERN_ERR "=> alloc_cpumask_var: failed!\n"); 1208c2ecf20Sopenharmony_ci dump_stack(); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci#endif 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci return *mask != NULL; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(alloc_cpumask_var_node); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cibool zalloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci return alloc_cpumask_var_node(mask, flags | __GFP_ZERO, node); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zalloc_cpumask_var_node); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/** 1358c2ecf20Sopenharmony_ci * alloc_cpumask_var - allocate a struct cpumask 1368c2ecf20Sopenharmony_ci * @mask: pointer to cpumask_var_t where the cpumask is returned 1378c2ecf20Sopenharmony_ci * @flags: GFP_ flags 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is 1408c2ecf20Sopenharmony_ci * a nop returning a constant 1 (in <linux/cpumask.h>). 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci * See alloc_cpumask_var_node. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_cibool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci return alloc_cpumask_var_node(mask, flags, NUMA_NO_NODE); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(alloc_cpumask_var); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cibool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci return alloc_cpumask_var(mask, flags | __GFP_ZERO); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(zalloc_cpumask_var); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/** 1578c2ecf20Sopenharmony_ci * alloc_bootmem_cpumask_var - allocate a struct cpumask from the bootmem arena. 1588c2ecf20Sopenharmony_ci * @mask: pointer to cpumask_var_t where the cpumask is returned 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is 1618c2ecf20Sopenharmony_ci * a nop (in <linux/cpumask.h>). 1628c2ecf20Sopenharmony_ci * Either returns an allocated (zero-filled) cpumask, or causes the 1638c2ecf20Sopenharmony_ci * system to panic. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_civoid __init alloc_bootmem_cpumask_var(cpumask_var_t *mask) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci *mask = memblock_alloc(cpumask_size(), SMP_CACHE_BYTES); 1688c2ecf20Sopenharmony_ci if (!*mask) 1698c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %u bytes\n", __func__, 1708c2ecf20Sopenharmony_ci cpumask_size()); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * free_cpumask_var - frees memory allocated for a struct cpumask. 1758c2ecf20Sopenharmony_ci * @mask: cpumask to free 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * This is safe on a NULL mask. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_civoid free_cpumask_var(cpumask_var_t mask) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci kfree(mask); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ciEXPORT_SYMBOL(free_cpumask_var); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci/** 1868c2ecf20Sopenharmony_ci * free_bootmem_cpumask_var - frees result of alloc_bootmem_cpumask_var 1878c2ecf20Sopenharmony_ci * @mask: cpumask to free 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_civoid __init free_bootmem_cpumask_var(cpumask_var_t mask) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci memblock_free_early(__pa(mask), cpumask_size()); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci#endif 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/** 1968c2ecf20Sopenharmony_ci * cpumask_local_spread - select the i'th cpu with local numa cpu's first 1978c2ecf20Sopenharmony_ci * @i: index number 1988c2ecf20Sopenharmony_ci * @node: local numa_node 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * This function selects an online CPU according to a numa aware policy; 2018c2ecf20Sopenharmony_ci * local cpus are returned first, followed by non-local ones, then it 2028c2ecf20Sopenharmony_ci * wraps around. 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * It's not very efficient, but useful for setup. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ciunsigned int cpumask_local_spread(unsigned int i, int node) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci int cpu; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Wrap: we always want a cpu. */ 2118c2ecf20Sopenharmony_ci i %= num_online_cpus(); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (node == NUMA_NO_NODE) { 2148c2ecf20Sopenharmony_ci for_each_cpu(cpu, cpu_online_mask) 2158c2ecf20Sopenharmony_ci if (i-- == 0) 2168c2ecf20Sopenharmony_ci return cpu; 2178c2ecf20Sopenharmony_ci } else { 2188c2ecf20Sopenharmony_ci /* NUMA first. */ 2198c2ecf20Sopenharmony_ci for_each_cpu_and(cpu, cpumask_of_node(node), cpu_online_mask) 2208c2ecf20Sopenharmony_ci if (i-- == 0) 2218c2ecf20Sopenharmony_ci return cpu; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci for_each_cpu(cpu, cpu_online_mask) { 2248c2ecf20Sopenharmony_ci /* Skip NUMA nodes, done above. */ 2258c2ecf20Sopenharmony_ci if (cpumask_test_cpu(cpu, cpumask_of_node(node))) 2268c2ecf20Sopenharmony_ci continue; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (i-- == 0) 2298c2ecf20Sopenharmony_ci return cpu; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci BUG(); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpumask_local_spread); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(int, distribute_cpu_mask_prev); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/** 2398c2ecf20Sopenharmony_ci * Returns an arbitrary cpu within srcp1 & srcp2. 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Iterated calls using the same srcp1 and srcp2 will be distributed within 2428c2ecf20Sopenharmony_ci * their intersection. 2438c2ecf20Sopenharmony_ci * 2448c2ecf20Sopenharmony_ci * Returns >= nr_cpu_ids if the intersection is empty. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_ciint cpumask_any_and_distribute(const struct cpumask *src1p, 2478c2ecf20Sopenharmony_ci const struct cpumask *src2p) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int next, prev; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* NOTE: our first selection will skip 0. */ 2528c2ecf20Sopenharmony_ci prev = __this_cpu_read(distribute_cpu_mask_prev); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci next = cpumask_next_and(prev, src1p, src2p); 2558c2ecf20Sopenharmony_ci if (next >= nr_cpu_ids) 2568c2ecf20Sopenharmony_ci next = cpumask_first_and(src1p, src2p); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (next < nr_cpu_ids) 2598c2ecf20Sopenharmony_ci __this_cpu_write(distribute_cpu_mask_prev, next); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return next; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(cpumask_any_and_distribute); 264