Blob Blame History Raw
From 2369108e6df4eb3f7c589a359a09cd4688c74332 Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Wed, 1 Jun 2022 20:46:31 +1000
Subject: drm/nouveau/disp: add supervisor mutex
Git-commit: a6fd8f936402c3bcc5ac6aed9cca8e73b5ca08f7
Patch-mainline: v6.0-rc1
References: jsc#PED-1166 jsc#PED-1168 jsc#PED-1170 jsc#PED-1218 jsc#PED-1220 jsc#PED-1222 jsc#PED-1223 jsc#PED-1225 jsc#PED-2849

Will be used to protect NVIF_CLASS_OUTP method calls from racing with
in-progress supervisor handling.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Patrik Jakobsson <pjakobsson@suse.de>
---
 drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h | 1 +
 drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c    | 6 +++++-
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c   | 4 ++++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c   | 8 ++++++--
 drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c    | 6 +++++-
 5 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
index 64bda44a13e5..8b5d8a434be8 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
@@ -22,6 +22,7 @@ struct nvkm_disp {
 		struct workqueue_struct *wq;
 		struct work_struct work;
 		u32 pending;
+		struct mutex mutex;
 	} super;
 
 #define NVKM_DISP_EVENT_CHAN_AWAKEN BIT(0)
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
index 10d4a3359a3f..65c99d948b68 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
@@ -399,8 +399,11 @@ nvkm_disp_dtor(struct nvkm_engine *engine)
 	nvkm_gpuobj_del(&disp->inst);
 
 	nvkm_event_fini(&disp->uevent);
-	if (disp->super.wq)
+
+	if (disp->super.wq) {
 		destroy_workqueue(disp->super.wq);
+		mutex_destroy(&disp->super.mutex);
+	}
 
 	nvkm_event_fini(&disp->vblank);
 	nvkm_event_fini(&disp->hpd);
@@ -467,6 +470,7 @@ nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device,
 			return -ENOMEM;
 
 		INIT_WORK(&disp->super.work, func->super);
+		mutex_init(&disp->super.mutex);
 	}
 
 	return nvkm_event_init(func->uevent, 1, ARRAY_SIZE(disp->chan), &disp->uevent);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index 3af527d2328c..39822f1b5b95 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -995,6 +995,8 @@ gf119_disp_super(struct work_struct *work)
 	u32 mask[4];
 
 	nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super.pending));
+	mutex_lock(&disp->super.mutex);
+
 	list_for_each_entry(head, &disp->heads, head) {
 		mask[head->id] = nvkm_rd32(device, 0x6101d4 + (head->id * 0x800));
 		HEAD_DBG(head, "%08x", mask[head->id]);
@@ -1037,7 +1039,9 @@ gf119_disp_super(struct work_struct *work)
 
 	list_for_each_entry(head, &disp->heads, head)
 		nvkm_wr32(device, 0x6101d4 + (head->id * 0x800), 0x00000000);
+
 	nvkm_wr32(device, 0x6101d0, 0x80000000);
+	mutex_unlock(&disp->super.mutex);
 }
 
 void
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
index 9106743a6368..6b9d49270fa7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
@@ -818,8 +818,10 @@ gv100_disp_super(struct work_struct *work)
 	struct nvkm_subdev *subdev = &disp->engine.subdev;
 	struct nvkm_device *device = subdev->device;
 	struct nvkm_head *head;
-	u32 stat = nvkm_rd32(device, 0x6107a8);
-	u32 mask[4];
+	u32 stat, mask[4];
+
+	mutex_lock(&disp->super.mutex);
+	stat = nvkm_rd32(device, 0x6107a8);
 
 	nvkm_debug(subdev, "supervisor %d: %08x\n", ffs(disp->super.pending), stat);
 	list_for_each_entry(head, &disp->heads, head) {
@@ -864,7 +866,9 @@ gv100_disp_super(struct work_struct *work)
 
 	list_for_each_entry(head, &disp->heads, head)
 		nvkm_wr32(device, 0x6107ac + (head->id * 4), 0x00000000);
+
 	nvkm_wr32(device, 0x6107a8, 0x80000000);
+	mutex_unlock(&disp->super.mutex);
 }
 
 static void
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index 237f5aa06850..a46e13cc9ff1 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -1345,7 +1345,10 @@ nv50_disp_super(struct work_struct *work)
 	struct nvkm_subdev *subdev = &disp->engine.subdev;
 	struct nvkm_device *device = subdev->device;
 	struct nvkm_head *head;
-	u32 super = nvkm_rd32(device, 0x610030);
+	u32 super;
+
+	mutex_lock(&disp->super.mutex);
+	super = nvkm_rd32(device, 0x610030);
 
 	nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super.pending, super);
 
@@ -1387,6 +1390,7 @@ nv50_disp_super(struct work_struct *work)
 	}
 
 	nvkm_wr32(device, 0x610030, 0x80000000);
+	mutex_unlock(&disp->super.mutex);
 }
 
 const struct nvkm_enum
-- 
2.38.1