Skip to content

Commit 26c790c

Browse files
Tvrtko Ursulingregkh
authored andcommitted
drm/v3d: Appease lockdep while updating GPU stats
[ Upstream commit 06c3c40 ] Lockdep thinks our seqcount_t usage is unsafe because the update path can be both from irq and worker context: [ ] ================================ [ ] WARNING: inconsistent lock state [ ] 6.10.3-v8-16k-numa torvalds#159 Tainted: G WC [ ] -------------------------------- [ ] inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage. [ ] swapper/0/0 [HC1[1]:SC0[0]:HE0:SE1] takes: [ ] ffff80003d7c08d0 (&v3d_priv->stats[i].lock){?.+.}-{0:0}, at: v3d_irq+0xc8/0x660 [v3d] [ ] {HARDIRQ-ON-W} state was registered at: [ ] lock_acquire+0x1f8/0x328 [ ] v3d_job_start_stats.isra.0+0xd8/0x218 [v3d] [ ] v3d_bin_job_run+0x23c/0x388 [v3d] [ ] drm_sched_run_job_work+0x520/0x6d0 [gpu_sched] [ ] process_one_work+0x62c/0xb48 [ ] worker_thread+0x468/0x5b0 [ ] kthread+0x1c4/0x1e0 [ ] ret_from_fork+0x10/0x20 [ ] irq event stamp: 337094 [ ] hardirqs last enabled at (337093): [<ffffc0008144ce7c>] default_idle_call+0x11c/0x140 [ ] hardirqs last disabled at (337094): [<ffffc0008144a354>] el1_interrupt+0x24/0x58 [ ] softirqs last enabled at (337082): [<ffffc00080061d90>] handle_softirqs+0x4e0/0x538 [ ] softirqs last disabled at (337073): [<ffffc00080010364>] __do_softirq+0x1c/0x28 [ ] other info that might help us debug this: [ ] Possible unsafe locking scenario: [ ] CPU0 [ ] ---- [ ] lock(&v3d_priv->stats[i].lock); [ ] <Interrupt> [ ] lock(&v3d_priv->stats[i].lock); [ ] *** DEADLOCK *** [ ] no locks held by swapper/0/0. [ ] stack backtrace: [ ] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G WC 6.10.3-v8-16k-numa torvalds#159 [ ] Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) [ ] Call trace: [ ] dump_backtrace+0x170/0x1b8 [ ] show_stack+0x20/0x38 [ ] dump_stack_lvl+0xb4/0xd0 [ ] dump_stack+0x18/0x28 [ ] print_usage_bug+0x3cc/0x3f0 [ ] mark_lock+0x4d0/0x968 [ ] __lock_acquire+0x784/0x18c8 [ ] lock_acquire+0x1f8/0x328 [ ] v3d_job_update_stats+0xec/0x2e0 [v3d] [ ] v3d_irq+0xc8/0x660 [v3d] [ ] __handle_irq_event_percpu+0x1f8/0x488 [ ] handle_irq_event+0x88/0x128 [ ] handle_fasteoi_irq+0x298/0x408 [ ] generic_handle_domain_irq+0x50/0x78 But it is a false positive because all the queue-stats pairs have their own lock and jobs are also one at a time. Nevertheless we can appease lockdep by disabling local interrupts to make it see lock usage is consistent. Cc: Maíra Canal <[email protected]> Fixes: 6abe93b ("drm/v3d: Fix race-condition between sysfs/fdinfo and interrupt handler") Signed-off-by: Tvrtko Ursulin <[email protected]> Signed-off-by: Maíra Canal <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Signed-off-by: Sasha Levin <[email protected]>
1 parent 4e56476 commit 26c790c

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

drivers/gpu/drm/v3d/v3d_sched.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,31 @@ v3d_job_start_stats(struct v3d_job *job, enum v3d_queue queue)
133133
struct v3d_stats *global_stats = &v3d->queue[queue].stats;
134134
struct v3d_stats *local_stats = &file->stats[queue];
135135
u64 now = local_clock();
136-
137-
preempt_disable();
136+
unsigned long flags;
137+
138+
/*
139+
* We only need to disable local interrupts to appease lockdep who
140+
* otherwise would think v3d_job_start_stats vs v3d_stats_update has an
141+
* unsafe in-irq vs no-irq-off usage problem. This is a false positive
142+
* because all the locks are per queue and stats type, and all jobs are
143+
* completely one at a time serialised. More specifically:
144+
*
145+
* 1. Locks for GPU queues are updated from interrupt handlers under a
146+
* spin lock and started here with preemption disabled.
147+
*
148+
* 2. Locks for CPU queues are updated from the worker with preemption
149+
* disabled and equally started here with preemption disabled.
150+
*
151+
* Therefore both are consistent.
152+
*
153+
* 3. Because next job can only be queued after the previous one has
154+
* been signaled, and locks are per queue, there is also no scope for
155+
* the start part to race with the update part.
156+
*/
157+
if (IS_ENABLED(CONFIG_LOCKDEP))
158+
local_irq_save(flags);
159+
else
160+
preempt_disable();
138161

139162
write_seqcount_begin(&local_stats->lock);
140163
local_stats->start_ns = now;
@@ -144,7 +167,10 @@ v3d_job_start_stats(struct v3d_job *job, enum v3d_queue queue)
144167
global_stats->start_ns = now;
145168
write_seqcount_end(&global_stats->lock);
146169

147-
preempt_enable();
170+
if (IS_ENABLED(CONFIG_LOCKDEP))
171+
local_irq_restore(flags);
172+
else
173+
preempt_enable();
148174
}
149175

150176
static void
@@ -165,11 +191,21 @@ v3d_job_update_stats(struct v3d_job *job, enum v3d_queue queue)
165191
struct v3d_stats *global_stats = &v3d->queue[queue].stats;
166192
struct v3d_stats *local_stats = &file->stats[queue];
167193
u64 now = local_clock();
194+
unsigned long flags;
195+
196+
/* See comment in v3d_job_start_stats() */
197+
if (IS_ENABLED(CONFIG_LOCKDEP))
198+
local_irq_save(flags);
199+
else
200+
preempt_disable();
168201

169-
preempt_disable();
170202
v3d_stats_update(local_stats, now);
171203
v3d_stats_update(global_stats, now);
172-
preempt_enable();
204+
205+
if (IS_ENABLED(CONFIG_LOCKDEP))
206+
local_irq_restore(flags);
207+
else
208+
preempt_enable();
173209
}
174210

175211
static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)

0 commit comments

Comments
 (0)