Mark Rutland <mark.rutl...@arm.com> writes: > In some cases, it's useful to be able to select a random cpu from the > intersection of two masks, excluding a particular CPU.
Acked-by: Rusty Russell <ru...@rustcorp.com.au> Thanks, Rusty. > For example, in some systems an uncore PMU is shared by a subset of > CPUs, and management of this PMU is assigned to some arbitrary CPU in > this set. Whenever the management CPU is hotplugged out, we wish to > migrate responsibility to another arbitrary CPU which is both in this > set and online. > > Today we can use cpumask_any_and() to select an arbitrary CPU in the > intersection of two masks. We can also use cpumask_any_but() to select > any arbitrary cpu in a mask excluding, a particular CPU. > > To do both, we either need to use a temporary cpumask, which is > wasteful, or use some lower-level cpumask helpers, which can be unclear. > > This patch adds a new cpumask_any_and_but() to cater for these cases. > > Signed-off-by: Mark Rutland <mark.rutl...@arm.com> > Cc: Thomas Gleixner <t...@linutronix.de> > Cc: Andrew Morton <a...@linux-foundation.org> > Cc: Peter Zijlstra <pet...@infradead.org> > Cc: Rusty Russell <ru...@rustcorp.com.au> > Cc: linux-kernel@vger.kernel.org > --- > include/linux/cpumask.h | 3 +++ > lib/cpumask.c | 23 +++++++++++++++++++++++ > 2 files changed, 26 insertions(+) > > This patch would help in cases like the Qualcomm L2 cache PMU driver [1]. If > people are happy with this patch, I'd like to take it along with that patch > (modified to use the new helper). I'm also happy to leave this as a subsequent > cleanup. > > Thanks, > Mark. > > [1] > http://lists.infradead.org/pipermail/linux-arm-kernel/2017-February/485762.html > > diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h > index c717f5e..99dc550 100644 > --- a/include/linux/cpumask.h > +++ b/include/linux/cpumask.h > @@ -210,6 +210,9 @@ static inline unsigned int cpumask_next_zero(int n, const > struct cpumask *srcp) > > int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *); > int cpumask_any_but(const struct cpumask *mask, unsigned int cpu); > +int cpumask_any_and_but(const struct cpumask *mask1, > + const struct cpumask *mask2, > + unsigned int cpu); > unsigned int cpumask_local_spread(unsigned int i, int node); > > /** > diff --git a/lib/cpumask.c b/lib/cpumask.c > index 81dedaa..641b526 100644 > --- a/lib/cpumask.c > +++ b/lib/cpumask.c > @@ -43,6 +43,29 @@ int cpumask_any_but(const struct cpumask *mask, unsigned > int cpu) > } > EXPORT_SYMBOL(cpumask_any_but); > > +/** > + * cpumask_any_and_but - pick a "random" cpu from *mask1 & *mask2, but not > this one. > + * @mask1: the first input cpumask > + * @mask2: the second input cpumask > + * @cpu: the cpu to ignore > + * > + * Returns >= nr_cpu_ids if no cpus set. > + */ > +int cpumask_any_and_but(const struct cpumask *mask1, > + const struct cpumask *mask2, > + unsigned int cpu) > +{ > + unsigned int i; > + > + cpumask_check(cpu); > + i = cpumask_first_and(mask1, mask2); > + if (i != cpu) > + return i; > + > + return cpumask_next_and(cpu, mask1, mask2); > +} > +EXPORT_SYMBOL(cpumask_any_and_but); > + > /* These are not inline because of header tangles. */ > #ifdef CONFIG_CPUMASK_OFFSTACK > /** > -- > 1.9.1