ANDROID: stop_machine: stop_one_cpu_async

This new interface allows to trigger a stopper on a given CPU and wait
for the end of the work in a separated function cpu_stop_work_wait().

This differs from stop_one_cpu_nowait() by allowing the usage of the
cpu_stop completion mechanism.

Bug: 161210528
Change-Id: Ida51371e32897d008ece0639190fc21feabb0f28
Signed-off-by: Vincent Donnefort <vincent.donnefort@arm.com>
This commit is contained in:
Vincent Donnefort
2020-11-03 11:47:46 +00:00
committed by Todd Kjos
parent bce40b72a3
commit d9f0cedbaf
2 changed files with 63 additions and 10 deletions

View File

@@ -28,6 +28,16 @@ struct cpu_stop_work {
struct cpu_stop_done *done; struct cpu_stop_done *done;
}; };
/*
* Structure to determine completion condition and record errors. May
* be shared by works on different cpus.
*/
struct cpu_stop_done {
atomic_t nr_todo; /* nr left to execute */
int ret; /* collected return value */
struct completion completion; /* fired if nr_todo reaches 0 */
};
int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg); int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *arg); int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *arg);
bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg, bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
@@ -35,6 +45,10 @@ bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
void stop_machine_park(int cpu); void stop_machine_park(int cpu);
void stop_machine_unpark(int cpu); void stop_machine_unpark(int cpu);
void stop_machine_yield(const struct cpumask *cpumask); void stop_machine_yield(const struct cpumask *cpumask);
int stop_one_cpu_async(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
struct cpu_stop_work *work_buf,
struct cpu_stop_done *done);
void cpu_stop_work_wait(struct cpu_stop_work *work_buf);
#else /* CONFIG_SMP */ #else /* CONFIG_SMP */

View File

@@ -22,16 +22,7 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/nmi.h> #include <linux/nmi.h>
#include <linux/sched/wake_q.h> #include <linux/sched/wake_q.h>
#include <linux/slab.h>
/*
* Structure to determine completion condition and record errors. May
* be shared by works on different cpus.
*/
struct cpu_stop_done {
atomic_t nr_todo; /* nr left to execute */
int ret; /* collected return value */
struct completion completion; /* fired if nr_todo reaches 0 */
};
/* the actual stopper, one per every possible cpu, enabled on online cpus */ /* the actual stopper, one per every possible cpu, enabled on online cpus */
struct cpu_stopper { struct cpu_stopper {
@@ -372,6 +363,54 @@ bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
} }
EXPORT_SYMBOL_GPL(stop_one_cpu_nowait); EXPORT_SYMBOL_GPL(stop_one_cpu_nowait);
/**
* stop_one_cpu_async - stop a cpu and wait for completion in a separated
* function: stop_wait_work()
* @cpu: cpu to stop
* @fn: function to execute
* @arg: argument to @fn
* @work_buf: pointer to cpu_stop_work structure
*
* CONTEXT:
* Might sleep.
*
* RETURNS:
* 0 if cpu_stop_work was queued successfully and @fn will be called.
* ENOENT if @fn(@arg) was not executed because @cpu was offline.
*/
int stop_one_cpu_async(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
struct cpu_stop_work *work_buf,
struct cpu_stop_done *done)
{
cpu_stop_init_done(done, 1);
work_buf->done = done;
work_buf->fn = fn;
work_buf->arg = arg;
if (cpu_stop_queue_work(cpu, work_buf))
return 0;
work_buf->done = NULL;
return -ENOENT;
}
/**
* cpu_stop_work_wait - wait for a stop initiated by stop_one_cpu_async().
* @work_buf: pointer to cpu_stop_work structure
*
* CONTEXT:
* Might sleep.
*/
void cpu_stop_work_wait(struct cpu_stop_work *work_buf)
{
struct cpu_stop_done *done = work_buf->done;
wait_for_completion(&done->completion);
work_buf->done = NULL;
}
static bool queue_stop_cpus_work(const struct cpumask *cpumask, static bool queue_stop_cpus_work(const struct cpumask *cpumask,
cpu_stop_fn_t fn, void *arg, cpu_stop_fn_t fn, void *arg,
struct cpu_stop_done *done) struct cpu_stop_done *done)