1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
25a0e3ad6STejun Heo #include <linux/slab.h>
3ccb46000SAndrew Morton #include <linux/kernel.h>
4ccb46000SAndrew Morton #include <linux/bitops.h>
5ccb46000SAndrew Morton #include <linux/cpumask.h>
68bc3bcc9SPaul Gortmaker #include <linux/export.h>
757c8a661SMike Rapoport #include <linux/memblock.h>
898fa15f3SAnshuman Khandual #include <linux/numa.h>
9ccb46000SAndrew Morton
102d3854a3SRusty Russell /**
11c743f0a5SPeter Zijlstra * cpumask_next_wrap - helper to implement for_each_cpu_wrap
12c743f0a5SPeter Zijlstra * @n: the cpu prior to the place to search
13c743f0a5SPeter Zijlstra * @mask: the cpumask pointer
14c743f0a5SPeter Zijlstra * @start: the start point of the iteration
15c743f0a5SPeter Zijlstra * @wrap: assume @n crossing @start terminates the iteration
16c743f0a5SPeter Zijlstra *
17c743f0a5SPeter Zijlstra * Returns >= nr_cpu_ids on completion
18c743f0a5SPeter Zijlstra *
19c743f0a5SPeter Zijlstra * Note: the @wrap argument is required for the start condition when
20c743f0a5SPeter Zijlstra * we cannot assume @start is set in @mask.
21c743f0a5SPeter Zijlstra */
cpumask_next_wrap(int n,const struct cpumask * mask,int start,bool wrap)228b6b795dSYury Norov unsigned int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap)
23c743f0a5SPeter Zijlstra {
248b6b795dSYury Norov unsigned int next;
25c743f0a5SPeter Zijlstra
26c743f0a5SPeter Zijlstra again:
27c743f0a5SPeter Zijlstra next = cpumask_next(n, mask);
28c743f0a5SPeter Zijlstra
29c743f0a5SPeter Zijlstra if (wrap && n < start && next >= start) {
30c743f0a5SPeter Zijlstra return nr_cpumask_bits;
31c743f0a5SPeter Zijlstra
32c743f0a5SPeter Zijlstra } else if (next >= nr_cpumask_bits) {
33c743f0a5SPeter Zijlstra wrap = true;
34c743f0a5SPeter Zijlstra n = -1;
35c743f0a5SPeter Zijlstra goto again;
36c743f0a5SPeter Zijlstra }
37c743f0a5SPeter Zijlstra
38c743f0a5SPeter Zijlstra return next;
39c743f0a5SPeter Zijlstra }
40c743f0a5SPeter Zijlstra EXPORT_SYMBOL(cpumask_next_wrap);
41c743f0a5SPeter Zijlstra
422d3854a3SRusty Russell /* These are not inline because of header tangles. */
432d3854a3SRusty Russell #ifdef CONFIG_CPUMASK_OFFSTACK
44ec26b805SMike Travis /**
45ec26b805SMike Travis * alloc_cpumask_var_node - allocate a struct cpumask on a given node
46ec26b805SMike Travis * @mask: pointer to cpumask_var_t where the cpumask is returned
47ec26b805SMike Travis * @flags: GFP_ flags
48dcb60f9cSRandy Dunlap * @node: memory node from which to allocate or %NUMA_NO_NODE
49ec26b805SMike Travis *
50ec26b805SMike Travis * Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is
51ec26b805SMike Travis * a nop returning a constant 1 (in <linux/cpumask.h>)
52ec26b805SMike Travis * Returns TRUE if memory allocation succeeded, FALSE otherwise.
53ec26b805SMike Travis *
54ec26b805SMike Travis * In addition, mask will be NULL if this fails. Note that gcc is
55ec26b805SMike Travis * usually smart enough to know that mask can never be NULL if
56ec26b805SMike Travis * CONFIG_CPUMASK_OFFSTACK=n, so does code elimination in that case
57ec26b805SMike Travis * too.
58ec26b805SMike Travis */
alloc_cpumask_var_node(cpumask_var_t * mask,gfp_t flags,int node)597b4967c5SMike Travis bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node)
602d3854a3SRusty Russell {
617b4967c5SMike Travis *mask = kmalloc_node(cpumask_size(), flags, node);
6238c7fed2SYinghai Lu
632d3854a3SRusty Russell #ifdef CONFIG_DEBUG_PER_CPU_MAPS
642d3854a3SRusty Russell if (!*mask) {
652d3854a3SRusty Russell printk(KERN_ERR "=> alloc_cpumask_var: failed!\n");
662d3854a3SRusty Russell dump_stack();
672d3854a3SRusty Russell }
682d3854a3SRusty Russell #endif
692a530080SRusty Russell
702d3854a3SRusty Russell return *mask != NULL;
712d3854a3SRusty Russell }
727b4967c5SMike Travis EXPORT_SYMBOL(alloc_cpumask_var_node);
737b4967c5SMike Travis
74ec26b805SMike Travis /**
75ec26b805SMike Travis * alloc_bootmem_cpumask_var - allocate a struct cpumask from the bootmem arena.
76ec26b805SMike Travis * @mask: pointer to cpumask_var_t where the cpumask is returned
77ec26b805SMike Travis *
78ec26b805SMike Travis * Only defined when CONFIG_CPUMASK_OFFSTACK=y, otherwise is
79e9690a6eSLi Zefan * a nop (in <linux/cpumask.h>).
80ec26b805SMike Travis * Either returns an allocated (zero-filled) cpumask, or causes the
81ec26b805SMike Travis * system to panic.
82ec26b805SMike Travis */
alloc_bootmem_cpumask_var(cpumask_var_t * mask)832d3854a3SRusty Russell void __init alloc_bootmem_cpumask_var(cpumask_var_t *mask)
842d3854a3SRusty Russell {
857e1c4e27SMike Rapoport *mask = memblock_alloc(cpumask_size(), SMP_CACHE_BYTES);
868a7f97b9SMike Rapoport if (!*mask)
878a7f97b9SMike Rapoport panic("%s: Failed to allocate %u bytes\n", __func__,
888a7f97b9SMike Rapoport cpumask_size());
892d3854a3SRusty Russell }
902d3854a3SRusty Russell
91ec26b805SMike Travis /**
92ec26b805SMike Travis * free_cpumask_var - frees memory allocated for a struct cpumask.
93ec26b805SMike Travis * @mask: cpumask to free
94ec26b805SMike Travis *
95ec26b805SMike Travis * This is safe on a NULL mask.
96ec26b805SMike Travis */
free_cpumask_var(cpumask_var_t mask)972d3854a3SRusty Russell void free_cpumask_var(cpumask_var_t mask)
982d3854a3SRusty Russell {
992d3854a3SRusty Russell kfree(mask);
1002d3854a3SRusty Russell }
1012d3854a3SRusty Russell EXPORT_SYMBOL(free_cpumask_var);
102cd83e42cSRusty Russell
103ec26b805SMike Travis /**
104ec26b805SMike Travis * free_bootmem_cpumask_var - frees result of alloc_bootmem_cpumask_var
105ec26b805SMike Travis * @mask: cpumask to free
106ec26b805SMike Travis */
free_bootmem_cpumask_var(cpumask_var_t mask)107984f2f37SRusty Russell void __init free_bootmem_cpumask_var(cpumask_var_t mask)
108cd83e42cSRusty Russell {
1094421cca0SMike Rapoport memblock_free(mask, cpumask_size());
110cd83e42cSRusty Russell }
1112d3854a3SRusty Russell #endif
112da91309eSAmir Vadai
113da91309eSAmir Vadai /**
114406d394aSYury Norov * cpumask_local_spread - select the i'th cpu based on NUMA distances
115da91309eSAmir Vadai * @i: index number
116f36963c9SRusty Russell * @node: local numa_node
117da91309eSAmir Vadai *
1182ac4980cSYury Norov * Returns online CPU according to a numa aware policy; local cpus are returned
1192ac4980cSYury Norov * first, followed by non-local ones, then it wraps around.
120da91309eSAmir Vadai *
1212ac4980cSYury Norov * For those who wants to enumerate all CPUs based on their NUMA distances,
1222ac4980cSYury Norov * i.e. call this function in a loop, like:
1232ac4980cSYury Norov *
1242ac4980cSYury Norov * for (i = 0; i < num_online_cpus(); i++) {
1252ac4980cSYury Norov * cpu = cpumask_local_spread(i, node);
1262ac4980cSYury Norov * do_something(cpu);
1272ac4980cSYury Norov * }
1282ac4980cSYury Norov *
1292ac4980cSYury Norov * There's a better alternative based on for_each()-like iterators:
1302ac4980cSYury Norov *
1312ac4980cSYury Norov * for_each_numa_hop_mask(mask, node) {
1322ac4980cSYury Norov * for_each_cpu_andnot(cpu, mask, prev)
1332ac4980cSYury Norov * do_something(cpu);
1342ac4980cSYury Norov * prev = mask;
1352ac4980cSYury Norov * }
1362ac4980cSYury Norov *
1372ac4980cSYury Norov * It's simpler and more verbose than above. Complexity of iterator-based
1382ac4980cSYury Norov * enumeration is O(sched_domains_numa_levels * nr_cpu_ids), while
1392ac4980cSYury Norov * cpumask_local_spread() when called for each cpu is
1402ac4980cSYury Norov * O(sched_domains_numa_levels * nr_cpu_ids * log(nr_cpu_ids)).
141da91309eSAmir Vadai */
cpumask_local_spread(unsigned int i,int node)142f36963c9SRusty Russell unsigned int cpumask_local_spread(unsigned int i, int node)
143da91309eSAmir Vadai {
1448b6b795dSYury Norov unsigned int cpu;
145da91309eSAmir Vadai
146f36963c9SRusty Russell /* Wrap: we always want a cpu. */
1472452483dSThomas Gleixner i %= num_online_cpus();
148da91309eSAmir Vadai
149*97f38170SYury Norov cpu = sched_numa_find_nth_cpu(cpu_online_mask, i, node);
150b1beed72SYury Norov
151b1beed72SYury Norov WARN_ON(cpu >= nr_cpu_ids);
152f36963c9SRusty Russell return cpu;
153da91309eSAmir Vadai }
154f36963c9SRusty Russell EXPORT_SYMBOL(cpumask_local_spread);
15546a87b38SPaul Turner
15646a87b38SPaul Turner static DEFINE_PER_CPU(int, distribute_cpu_mask_prev);
15746a87b38SPaul Turner
15846a87b38SPaul Turner /**
159dcb60f9cSRandy Dunlap * cpumask_any_and_distribute - Return an arbitrary cpu within src1p & src2p.
160dcb60f9cSRandy Dunlap * @src1p: first &cpumask for intersection
161dcb60f9cSRandy Dunlap * @src2p: second &cpumask for intersection
16246a87b38SPaul Turner *
16346a87b38SPaul Turner * Iterated calls using the same srcp1 and srcp2 will be distributed within
16446a87b38SPaul Turner * their intersection.
16546a87b38SPaul Turner *
16646a87b38SPaul Turner * Returns >= nr_cpu_ids if the intersection is empty.
16746a87b38SPaul Turner */
cpumask_any_and_distribute(const struct cpumask * src1p,const struct cpumask * src2p)1688b6b795dSYury Norov unsigned int cpumask_any_and_distribute(const struct cpumask *src1p,
16946a87b38SPaul Turner const struct cpumask *src2p)
17046a87b38SPaul Turner {
1718b6b795dSYury Norov unsigned int next, prev;
17246a87b38SPaul Turner
17346a87b38SPaul Turner /* NOTE: our first selection will skip 0. */
17446a87b38SPaul Turner prev = __this_cpu_read(distribute_cpu_mask_prev);
17546a87b38SPaul Turner
1766cc18331SYury Norov next = find_next_and_bit_wrap(cpumask_bits(src1p), cpumask_bits(src2p),
1776cc18331SYury Norov nr_cpumask_bits, prev + 1);
17846a87b38SPaul Turner if (next < nr_cpu_ids)
17946a87b38SPaul Turner __this_cpu_write(distribute_cpu_mask_prev, next);
18046a87b38SPaul Turner
18146a87b38SPaul Turner return next;
18246a87b38SPaul Turner }
18346a87b38SPaul Turner EXPORT_SYMBOL(cpumask_any_and_distribute);
18414e292f8SPeter Zijlstra
cpumask_any_distribute(const struct cpumask * srcp)1858b6b795dSYury Norov unsigned int cpumask_any_distribute(const struct cpumask *srcp)
18614e292f8SPeter Zijlstra {
1878b6b795dSYury Norov unsigned int next, prev;
18814e292f8SPeter Zijlstra
18914e292f8SPeter Zijlstra /* NOTE: our first selection will skip 0. */
19014e292f8SPeter Zijlstra prev = __this_cpu_read(distribute_cpu_mask_prev);
1916cc18331SYury Norov next = find_next_bit_wrap(cpumask_bits(srcp), nr_cpumask_bits, prev + 1);
19214e292f8SPeter Zijlstra if (next < nr_cpu_ids)
19314e292f8SPeter Zijlstra __this_cpu_write(distribute_cpu_mask_prev, next);
19414e292f8SPeter Zijlstra
19514e292f8SPeter Zijlstra return next;
19614e292f8SPeter Zijlstra }
19714e292f8SPeter Zijlstra EXPORT_SYMBOL(cpumask_any_distribute);
198