@@ -181,6 +181,7 @@ static int live_nop_switch(void *arg)
struct parallel_switch {
struct task_struct *tsk;
struct intel_context *ce[2];
+ bool running;
};
static int __live_parallel_switch1(void *data)
@@ -189,6 +190,7 @@ static int __live_parallel_switch1(void *data)
IGT_TIMEOUT(end_time);
unsigned long count;
+ WRITE_ONCE(arg->running, true);
count = 0;
do {
struct i915_request *rq = NULL;
@@ -233,6 +235,7 @@ static int __live_parallel_switchN(void *data)
unsigned long count;
int n;
+ WRITE_ONCE(arg->running, true);
count = 0;
do {
for (n = 0; n < ARRAY_SIZE(arg->ce); n++) {
@@ -370,7 +373,7 @@ static int live_parallel_switch(void *arg)
get_task_struct(data[n].tsk);
}
- yield(); /* start all threads before we kthread_stop() */
+ __igt_start_threads(data, count, tsk, running);
for (n = 0; n < count; n++) {
int status;
@@ -3479,6 +3479,7 @@ struct preempt_smoke {
unsigned int ncontext;
struct rnd_state prng;
unsigned long count;
+ bool running;
};
static struct i915_gem_context *smoke_context(struct preempt_smoke *smoke)
@@ -3544,6 +3545,7 @@ static int smoke_crescendo_thread(void *arg)
IGT_TIMEOUT(end_time);
unsigned long count;
+ WRITE_ONCE(smoke->running, true);
count = 0;
do {
struct i915_gem_context *ctx = smoke_context(smoke);
@@ -3576,23 +3578,25 @@ static int smoke_crescendo(struct preempt_smoke *smoke, unsigned int flags)
if (!arg)
return -ENOMEM;
+ memset(arg, 0, I915_NUM_ENGINES * sizeof(*arg));
+
for_each_engine(engine, smoke->gt, id) {
arg[id] = *smoke;
- arg[id].engine = engine;
if (!(flags & BATCH))
arg[id].batch = NULL;
arg[id].count = 0;
- tsk[id] = kthread_run(smoke_crescendo_thread, arg,
+ tsk[id] = kthread_run(smoke_crescendo_thread, &arg[id],
"igt/smoke:%d", id);
if (IS_ERR(tsk[id])) {
err = PTR_ERR(tsk[id]);
break;
}
+ arg[id].engine = engine;
get_task_struct(tsk[id]);
}
- yield(); /* start all threads before we kthread_stop() */
+ __igt_start_threads(arg, I915_NUM_ENGINES, engine, running);
count = 0;
for_each_engine(engine, smoke->gt, id) {
@@ -870,6 +870,7 @@ struct active_engine {
struct intel_engine_cs *engine;
unsigned long resets;
unsigned int flags;
+ bool running;
};
#define TEST_ACTIVE BIT(0)
@@ -910,6 +911,8 @@ static int active_engine(void *data)
unsigned long count;
int err = 0;
+ WRITE_ONCE(arg->running, true);
+
for (count = 0; count < ARRAY_SIZE(ce); count++) {
ce[count] = intel_context_create(engine);
if (IS_ERR(ce[count])) {
@@ -1048,7 +1051,7 @@ static int __igt_reset_engines(struct intel_gt *gt,
get_task_struct(tsk);
}
- yield(); /* start all threads before we begin */
+ __igt_start_threads(threads, I915_NUM_ENGINES, task, running);
st_engine_heartbeat_disable_no_pm(engine);
GEM_BUG_ON(test_and_set_bit(I915_RESET_ENGINE + id,
@@ -137,4 +137,16 @@ bool __igt_timeout(unsigned long timeout, const char *fmt, ...);
void igt_hexdump(const void *buf, size_t len);
+#define __igt_start_threads(array, num, cond, flag) \
+({ \
+ unsigned int n; \
+\
+restart: \
+ cond_resched(); \
+ for (n = 0; n < (num); n++) { \
+ if (array[n].cond && !READ_ONCE(array[n].running)) \
+ goto restart; \
+ } \
+})
+
#endif /* !__I915_SELFTEST_H__ */
@@ -299,9 +299,16 @@ __live_request_alloc(struct intel_context *ce)
return intel_context_create_request(ce);
}
+struct smoke_thread {
+ struct smoketest *t;
+ struct task_struct *task;
+ bool running;
+};
+
static int __igt_breadcrumbs_smoketest(void *arg)
{
- struct smoketest *t = arg;
+ struct smoke_thread *thread = arg;
+ struct smoketest *t = thread->t;
const unsigned int max_batch = min(t->ncontexts, t->max_batch) - 1;
const unsigned int total = 4 * t->ncontexts + 1;
unsigned int num_waits = 0, num_fences = 0;
@@ -319,6 +326,8 @@ static int __igt_breadcrumbs_smoketest(void *arg)
* that the fences were marked as signaled.
*/
+ WRITE_ONCE(thread->running, true);
+
requests = kcalloc(total, sizeof(*requests), GFP_KERNEL);
if (!requests)
return -ENOMEM;
@@ -450,7 +459,7 @@ static int mock_breadcrumbs_smoketest(void *arg)
.request_alloc = __mock_request_alloc
};
unsigned int ncpus = num_online_cpus();
- struct task_struct **threads;
+ struct smoke_thread *threads;
unsigned int n;
int ret = 0;
@@ -479,28 +488,30 @@ static int mock_breadcrumbs_smoketest(void *arg)
}
for (n = 0; n < ncpus; n++) {
- threads[n] = kthread_run(__igt_breadcrumbs_smoketest,
- &t, "igt/%d", n);
- if (IS_ERR(threads[n])) {
- ret = PTR_ERR(threads[n]);
+ threads[n].task = kthread_run(__igt_breadcrumbs_smoketest,
+ &threads[n], "igt/%d", n);
+ if (IS_ERR(threads[n].task)) {
+ ret = PTR_ERR(threads[n].task);
ncpus = n;
break;
+ } else {
+ threads[n].t = &t;
}
- get_task_struct(threads[n]);
+ get_task_struct(threads[n].task);
}
- yield(); /* start all threads before we begin */
+ __igt_start_threads(threads, ncpus, t, running);
msleep(jiffies_to_msecs(i915_selftest.timeout_jiffies));
for (n = 0; n < ncpus; n++) {
int err;
- err = kthread_stop(threads[n]);
+ err = kthread_stop(threads[n].task);
if (err < 0 && !ret)
ret = err;
- put_task_struct(threads[n]);
+ put_task_struct(threads[n].task);
}
pr_info("Completed %lu waits for %lu fence across %d cpus\n",
atomic_long_read(&t.num_waits),
@@ -1419,13 +1430,21 @@ static int live_sequential_engines(void *arg)
return err;
}
+struct parallel_thread {
+ struct task_struct *task;
+ struct intel_engine_cs *engine;
+ bool running;
+};
+
static int __live_parallel_engine1(void *arg)
{
- struct intel_engine_cs *engine = arg;
+ struct parallel_thread *thread = arg;
+ struct intel_engine_cs *engine = thread->engine;
IGT_TIMEOUT(end_time);
unsigned long count;
int err = 0;
+ WRITE_ONCE(thread->running, true);
count = 0;
intel_engine_pm_get(engine);
do {
@@ -1457,11 +1476,13 @@ static int __live_parallel_engine1(void *arg)
static int __live_parallel_engineN(void *arg)
{
- struct intel_engine_cs *engine = arg;
+ struct parallel_thread *thread = arg;
+ struct intel_engine_cs *engine = thread->engine;
IGT_TIMEOUT(end_time);
unsigned long count;
int err = 0;
+ WRITE_ONCE(thread->running, true);
count = 0;
intel_engine_pm_get(engine);
do {
@@ -1507,7 +1528,8 @@ static int wait_for_all(struct drm_i915_private *i915)
static int __live_parallel_spin(void *arg)
{
- struct intel_engine_cs *engine = arg;
+ struct parallel_thread *thread = arg;
+ struct intel_engine_cs *engine = thread->engine;
struct igt_spinner spin;
struct i915_request *rq;
int err = 0;
@@ -1518,6 +1540,8 @@ static int __live_parallel_spin(void *arg)
* able to start in time.
*/
+ WRITE_ONCE(thread->running, true);
+
if (igt_spinner_init(&spin, engine->gt)) {
wake_all(engine->i915);
return -ENOMEM;
@@ -1566,9 +1590,9 @@ static int live_parallel_engines(void *arg)
NULL,
};
const unsigned int nengines = num_uabi_engines(i915);
+ struct parallel_thread *threads;
struct intel_engine_cs *engine;
int (* const *fn)(void *arg);
- struct task_struct **tsk;
int err = 0;
/*
@@ -1576,8 +1600,8 @@ static int live_parallel_engines(void *arg)
* tests that we load up the system maximally.
*/
- tsk = kcalloc(nengines, sizeof(*tsk), GFP_KERNEL);
- if (!tsk)
+ threads = kcalloc(nengines, sizeof(*threads), GFP_KERNEL);
+ if (!threads)
return -ENOMEM;
for (fn = func; !err && *fn; fn++) {
@@ -1594,37 +1618,39 @@ static int live_parallel_engines(void *arg)
idx = 0;
for_each_uabi_engine(engine, i915) {
- tsk[idx] = kthread_run(*fn, engine,
- "igt/parallel:%s",
- engine->name);
- if (IS_ERR(tsk[idx])) {
- err = PTR_ERR(tsk[idx]);
+ threads[idx].running = false;
+ threads[idx].task =
+ kthread_run(*fn, &threads[idx],
+ "igt/parallel:%s", engine->name);
+ if (IS_ERR(threads[idx].task)) {
+ err = PTR_ERR(threads[idx].task);
+ threads[idx].task = NULL;
break;
}
- get_task_struct(tsk[idx++]);
+ get_task_struct(threads[idx++].task);
}
- yield(); /* start all threads before we kthread_stop() */
+ __igt_start_threads(threads, nengines, task, running);
idx = 0;
for_each_uabi_engine(engine, i915) {
int status;
- if (IS_ERR(tsk[idx]))
+ if (!threads[idx].task)
break;
- status = kthread_stop(tsk[idx]);
+ status = kthread_stop(threads[idx].task);
if (status && !err)
err = status;
- put_task_struct(tsk[idx++]);
+ put_task_struct(threads[idx++].task);
}
if (igt_live_test_end(&t))
err = -EIO;
}
- kfree(tsk);
+ kfree(threads);
return err;
}
@@ -1672,7 +1698,7 @@ static int live_breadcrumbs_smoketest(void *arg)
const unsigned int ncpus = num_online_cpus();
unsigned long num_waits, num_fences;
struct intel_engine_cs *engine;
- struct task_struct **threads;
+ struct smoke_thread *threads;
struct igt_live_test live;
intel_wakeref_t wakeref;
struct smoketest *smoke;
@@ -1749,20 +1775,22 @@ static int live_breadcrumbs_smoketest(void *arg)
struct task_struct *tsk;
tsk = kthread_run(__igt_breadcrumbs_smoketest,
- &smoke[idx], "igt/%d.%d", idx, n);
+ &threads[idx * ncpus + n],
+ "igt/%d.%d", idx, n);
if (IS_ERR(tsk)) {
ret = PTR_ERR(tsk);
goto out_flush;
}
get_task_struct(tsk);
- threads[idx * ncpus + n] = tsk;
+ threads[idx * ncpus + n].task = tsk;
+ threads[idx * ncpus + n].t = &smoke[idx];
}
idx++;
}
- yield(); /* start all threads before we begin */
+ __igt_start_threads(threads, ncpus * nengines, t, running);
msleep(jiffies_to_msecs(i915_selftest.timeout_jiffies));
out_flush:
@@ -1771,7 +1799,7 @@ static int live_breadcrumbs_smoketest(void *arg)
num_fences = 0;
for_each_uabi_engine(engine, i915) {
for (n = 0; n < ncpus; n++) {
- struct task_struct *tsk = threads[idx * ncpus + n];
+ struct task_struct *tsk = threads[idx * ncpus + n].task;
int err;
if (!tsk)
@@ -2891,9 +2919,17 @@ static int perf_series_engines(void *arg)
return err;
}
+struct p_thread {
+ struct perf_stats p;
+ struct task_struct *tsk;
+ struct intel_engine_cs *engine;
+ bool running;
+};
+
static int p_sync0(void *arg)
{
- struct perf_stats *p = arg;
+ struct p_thread *thread = arg;
+ struct perf_stats *p = &thread->p;
struct intel_engine_cs *engine = p->engine;
struct intel_context *ce;
IGT_TIMEOUT(end_time);
@@ -2901,6 +2937,8 @@ static int p_sync0(void *arg)
bool busy;
int err = 0;
+ WRITE_ONCE(thread->running, true);
+
ce = intel_context_create(engine);
if (IS_ERR(ce))
return PTR_ERR(ce);
@@ -2963,7 +3001,8 @@ static int p_sync0(void *arg)
static int p_sync1(void *arg)
{
- struct perf_stats *p = arg;
+ struct p_thread *thread = arg;
+ struct perf_stats *p = &thread->p;
struct intel_engine_cs *engine = p->engine;
struct i915_request *prev = NULL;
struct intel_context *ce;
@@ -2972,6 +3011,8 @@ static int p_sync1(void *arg)
bool busy;
int err = 0;
+ WRITE_ONCE(thread->running, true);
+
ce = intel_context_create(engine);
if (IS_ERR(ce))
return PTR_ERR(ce);
@@ -3036,7 +3077,8 @@ static int p_sync1(void *arg)
static int p_many(void *arg)
{
- struct perf_stats *p = arg;
+ struct p_thread *thread = arg;
+ struct perf_stats *p = &thread->p;
struct intel_engine_cs *engine = p->engine;
struct intel_context *ce;
IGT_TIMEOUT(end_time);
@@ -3044,6 +3086,8 @@ static int p_many(void *arg)
int err = 0;
bool busy;
+ WRITE_ONCE(thread->running, true);
+
ce = intel_context_create(engine);
if (IS_ERR(ce))
return PTR_ERR(ce);
@@ -3108,10 +3152,7 @@ static int perf_parallel_engines(void *arg)
struct intel_engine_cs *engine;
int (* const *fn)(void *arg);
struct pm_qos_request qos;
- struct {
- struct perf_stats p;
- struct task_struct *tsk;
- } *engines;
+ struct p_thread *engines;
int err = 0;
engines = kcalloc(nengines, sizeof(*engines), GFP_KERNEL);
@@ -3137,19 +3178,20 @@ static int perf_parallel_engines(void *arg)
intel_engine_pm_get(engine);
memset(&engines[idx].p, 0, sizeof(engines[idx].p));
- engines[idx].p.engine = engine;
- engines[idx].tsk = kthread_run(*fn, &engines[idx].p,
+ engines[idx].tsk = kthread_run(*fn, &engines[idx],
"igt:%s", engine->name);
if (IS_ERR(engines[idx].tsk)) {
err = PTR_ERR(engines[idx].tsk);
intel_engine_pm_put(engine);
break;
}
+ engines[idx].p.engine = engine;
+ engines[idx].engine = engine;
get_task_struct(engines[idx++].tsk);
}
- yield(); /* start all threads before we kthread_stop() */
+ __igt_start_threads(engines, nengines, engine, running);
idx = 0;
for_each_uabi_engine(engine, i915) {