---
drivers/gpu/drm/v3d/v3d_drv.c | 16 +++++++++++++++-
drivers/gpu/drm/v3d/v3d_gem.c | 15 ++++++++++++++-
drivers/gpu/drm/v3d/v3d_sched.c | 29 +++++++++++++++++++++++++----
3 files changed, 54 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/v3d/v3d_drv.c b/drivers/gpu/drm/v3d/v3d_drv.c
index d7ff1f5fa481..4a5d3ab1281b 100644
--- a/drivers/gpu/drm/v3d/v3d_drv.c
+++ b/drivers/gpu/drm/v3d/v3d_drv.c
@@ -106,6 +106,8 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
static int
v3d_open(struct drm_device *dev, struct drm_file *file)
{
+ static struct lock_class_key v3d_stats_gpu_lock_class;
+ static struct lock_class_key v3d_stats_cpu_lock_class;
struct v3d_dev *v3d = to_v3d_dev(dev);
struct v3d_file_priv *v3d_priv;
struct drm_gpu_scheduler *sched;
@@ -118,13 +120,25 @@ v3d_open(struct drm_device *dev, struct drm_file *file)
v3d_priv->v3d = v3d;
for (i = 0; i < V3D_MAX_QUEUES; i++) {
+ struct lock_class_key *key;
+ char *name;
+
sched = &v3d->queue[i].sched;
drm_sched_entity_init(&v3d_priv->sched_entity[i],
DRM_SCHED_PRIORITY_NORMAL, &sched,
1, NULL);
memset(&v3d_priv->stats[i], 0, sizeof(v3d_priv->stats[i]));
- seqcount_init(&v3d_priv->stats[i].lock);
+
+ if (i == V3D_CACHE_CLEAN || i == V3D_CPU) {
+ key = &v3d_stats_cpu_lock_class;
+ name = "v3d_client_stats_cpu_lock";
+ } else {
+ key = &v3d_stats_gpu_lock_class;
+ name = "v3d_client_stats_gpu_lock";
+ }
+
+ __seqcount_init(&v3d_priv->stats[i].lock, name, key);
}
v3d_perfmon_open_file(v3d_priv);
diff --git a/drivers/gpu/drm/v3d/v3d_gem.c b/drivers/gpu/drm/v3d/v3d_gem.c
index da8faf3b9011..3567a80e603d 100644
--- a/drivers/gpu/drm/v3d/v3d_gem.c
+++ b/drivers/gpu/drm/v3d/v3d_gem.c
@@ -242,16 +242,29 @@ v3d_invalidate_caches(struct v3d_dev *v3d)
int
v3d_gem_init(struct drm_device *dev)
{
+ static struct lock_class_key v3d_stats_gpu_lock_class;
+ static struct lock_class_key v3d_stats_cpu_lock_class;
struct v3d_dev *v3d = to_v3d_dev(dev);
u32 pt_size = 4096 * 1024;
int ret, i;
for (i = 0; i < V3D_MAX_QUEUES; i++) {
struct v3d_queue_state *queue = &v3d->queue[i];
+ struct lock_class_key *key;
+ char *name;
queue->fence_context = dma_fence_context_alloc(1);
memset(&queue->stats, 0, sizeof(queue->stats));
- seqcount_init(&queue->stats.lock);
+
+ if (i == V3D_CACHE_CLEAN || i == V3D_CPU) {
+ key = &v3d_stats_cpu_lock_class;
+ name = "v3d_stats_cpu_lock";
+ } else {
+ key = &v3d_stats_gpu_lock_class;
+ name = "v3d_stats_gpu_lock";
+ }
+
+ __seqcount_init(&queue->stats.lock, name, key);
}
spin_lock_init(&v3d->mm_lock);
diff --git a/drivers/gpu/drm/v3d/v3d_sched.c b/drivers/gpu/drm/v3d/v3d_sched.c
index cc2e5a89467b..b2540e20d30c 100644
--- a/drivers/gpu/drm/v3d/v3d_sched.c
+++ b/drivers/gpu/drm/v3d/v3d_sched.c
@@ -149,6 +149,27 @@ v3d_job_start_stats(struct v3d_job *job, enum v3d_queue queue)
preempt_enable();
}
+/*
+ * We only need to disable local interrupts to appease lockdep who otherwise
+ * would think v3d_job_start_stats vs v3d_stats_update has an unsafe in-irq vs
+ * no-irq-off usage problem. This is a false positive becuase all the locks are
+ * per queue and stats type, and all jobs are completely one at a time
+ * serialised.
+ */
+static void
+v3d_job_start_stats_irqsave(struct v3d_job *job, enum v3d_queue queue)
+{
+#ifdef CONFIG_LOCKDEP
+ unsigned long flags;
+
+ local_irq_save(flags);
+#endif
+ v3d_job_start_stats(job, queue);
+#ifdef CONFIG_LOCKDEP
+ local_irq_restore(flags);
+#endif
+}
+
static void
v3d_stats_update(struct v3d_stats *stats, u64 now)
{
@@ -194,6 +215,7 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
* reuse the overflow attached to a previous job.
*/
V3D_CORE_WRITE(0, V3D_PTB_BPOS, 0);
+ v3d_job_start_stats(&job->base, V3D_BIN); /* Piggy-back on existing irq-off section. */
spin_unlock_irqrestore(&v3d->job_lock, irqflags);
v3d_invalidate_caches(v3d);
@@ -209,7 +231,6 @@ static struct dma_fence *v3d_bin_job_run(struct drm_sched_job *sched_job)
trace_v3d_submit_cl(dev, false, to_v3d_fence(fence)->seqno,
job->start, job->end);
- v3d_job_start_stats(&job->base, V3D_BIN);
v3d_switch_perfmon(v3d, &job->base);
/* Set the current and end address of the control list.
@@ -261,7 +282,7 @@ static struct dma_fence *v3d_render_job_run(struct drm_sched_job *sched_job)
trace_v3d_submit_cl(dev, true, to_v3d_fence(fence)->seqno,
job->start, job->end);
- v3d_job_start_stats(&job->base, V3D_RENDER);
+ v3d_job_start_stats_irqsave(&job->base, V3D_RENDER);
v3d_switch_perfmon(v3d, &job->base);
/* XXX: Set the QCFG */
@@ -294,7 +315,7 @@ v3d_tfu_job_run(struct drm_sched_job *sched_job)
trace_v3d_submit_tfu(dev, to_v3d_fence(fence)->seqno);
- v3d_job_start_stats(&job->base, V3D_TFU);
+ v3d_job_start_stats_irqsave(&job->base, V3D_TFU);
V3D_WRITE(V3D_TFU_IIA(v3d->ver), job->args.iia);
V3D_WRITE(V3D_TFU_IIS(v3d->ver), job->args.iis);
@@ -339,7 +360,7 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
trace_v3d_submit_csd(dev, to_v3d_fence(fence)->seqno);
- v3d_job_start_stats(&job->base, V3D_CSD);
+ v3d_job_start_stats_irqsave(&job->base, V3D_CSD);
v3d_switch_perfmon(v3d, &job->base);
csd_cfg0_reg = V3D_CSD_QUEUED_CFG0(v3d->ver);