@@ -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
150176static 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
175211static struct dma_fence * v3d_bin_job_run (struct drm_sched_job * sched_job )
0 commit comments