Blob Blame History Raw
From cf9518b50a9c68cafb07e05fc54731071228ced3 Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Thu, 13 Jun 2019 13:58:50 +1000
Subject: drm/nouveau/fifo/gf1xx: convert to using nvkm_fault_data
Git-commit: cf9518b50a9c68cafb07e05fc54731071228ced3
Patch-mainline: v5.4-rc1
References: bsc#1152489

Would like to be able to reuse gf100_fifo_intr_fault() for (some of) the
later chipsets too, as it's identical.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
---
 .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c  | 188 ++++++++++--------
 .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c  |   2 +-
 .../gpu/drm/nouveau/nvkm/engine/fifo/priv.h   |   2 +
 3 files changed, 106 insertions(+), 86 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
index 10a2e7039a75..5a39e51d42d7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
@@ -28,6 +28,7 @@
 #include <core/enum.h>
 #include <core/gpuobj.h>
 #include <subdev/bar.h>
+#include <subdev/fault.h>
 #include <engine/sw.h>
 
 #include <nvif/class.h>
@@ -193,68 +194,6 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine,
 	nvkm_fifo_kevent(&fifo->base, chid);
 }
 
-static const struct nvkm_enum
-gf100_fifo_sched_reason[] = {
-	{ 0x0a, "CTXSW_TIMEOUT" },
-	{}
-};
-
-static void
-gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo)
-{
-	struct nvkm_device *device = fifo->base.engine.subdev.device;
-	struct nvkm_engine *engine;
-	struct gf100_fifo_chan *chan;
-	unsigned long flags;
-	u32 engn;
-
-	spin_lock_irqsave(&fifo->base.lock, flags);
-	for (engn = 0; engn < 6; engn++) {
-		u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04));
-		u32 busy = (stat & 0x80000000);
-		u32 save = (stat & 0x00100000); /* maybe? */
-		u32 unk0 = (stat & 0x00040000);
-		u32 unk1 = (stat & 0x00001000);
-		u32 chid = (stat & 0x0000007f);
-		(void)save;
-
-		if (busy && unk0 && unk1) {
-			list_for_each_entry(chan, &fifo->chan, head) {
-				if (chan->base.chid == chid) {
-					engine = gf100_fifo_engine(fifo, engn);
-					if (!engine)
-						break;
-					gf100_fifo_recover(fifo, engine, chan);
-					break;
-				}
-			}
-		}
-	}
-	spin_unlock_irqrestore(&fifo->base.lock, flags);
-}
-
-static void
-gf100_fifo_intr_sched(struct gf100_fifo *fifo)
-{
-	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
-	struct nvkm_device *device = subdev->device;
-	u32 intr = nvkm_rd32(device, 0x00254c);
-	u32 code = intr & 0x000000ff;
-	const struct nvkm_enum *en;
-
-	en = nvkm_enum_find(gf100_fifo_sched_reason, code);
-
-	nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : "");
-
-	switch (code) {
-	case 0x0a:
-		gf100_fifo_intr_sched_ctxsw(fifo);
-		break;
-	default:
-		break;
-	}
-}
-
 static const struct nvkm_enum
 gf100_fifo_fault_engine[] = {
 	{ 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR },
@@ -315,32 +254,24 @@ gf100_fifo_fault_gpcclient[] = {
 };
 
 static void
-gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit)
+gf100_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
 {
+	struct gf100_fifo *fifo = gf100_fifo(base);
 	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
 	struct nvkm_device *device = subdev->device;
-	u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10));
-	u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10));
-	u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10));
-	u32 stat = nvkm_rd32(device, 0x00280c + (unit * 0x10));
-	u32 gpc    = (stat & 0x1f000000) >> 24;
-	u32 client = (stat & 0x00001f00) >> 8;
-	u32 write  = (stat & 0x00000080);
-	u32 hub    = (stat & 0x00000040);
-	u32 reason = (stat & 0x0000000f);
 	const struct nvkm_enum *er, *eu, *ec;
 	struct nvkm_engine *engine = NULL;
 	struct nvkm_fifo_chan *chan;
 	unsigned long flags;
 	char gpcid[8] = "";
 
-	er = nvkm_enum_find(gf100_fifo_fault_reason, reason);
-	eu = nvkm_enum_find(gf100_fifo_fault_engine, unit);
-	if (hub) {
-		ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client);
+	er = nvkm_enum_find(gf100_fifo_fault_reason, info->reason);
+	eu = nvkm_enum_find(gf100_fifo_fault_engine, info->engine);
+	if (info->hub) {
+		ec = nvkm_enum_find(gf100_fifo_fault_hubclient, info->client);
 	} else {
-		ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client);
-		snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc);
+		ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, info->client);
+		snprintf(gpcid, sizeof(gpcid), "GPC%d/", info->gpc);
 	}
 
 	if (eu && eu->data2) {
@@ -360,22 +291,108 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit)
 		}
 	}
 
-	chan = nvkm_fifo_chan_inst(&fifo->base, (u64)inst << 12, &flags);
+	chan = nvkm_fifo_chan_inst(&fifo->base, info->inst, &flags);
 
 	nvkm_error(subdev,
 		   "%s fault at %010llx engine %02x [%s] client %02x [%s%s] "
 		   "reason %02x [%s] on channel %d [%010llx %s]\n",
-		   write ? "write" : "read", (u64)vahi << 32 | valo,
-		   unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "",
-		   reason, er ? er->name : "", chan ? chan->chid : -1,
-		   (u64)inst << 12,
-		   chan ? chan->object.client->name : "unknown");
+		   info->access ? "write" : "read", info->addr,
+		   info->engine, eu ? eu->name : "",
+		   info->client, gpcid, ec ? ec->name : "",
+		   info->reason, er ? er->name : "", chan ? chan->chid : -1,
+		   info->inst, chan ? chan->object.client->name : "unknown");
 
 	if (engine && chan)
 		gf100_fifo_recover(fifo, engine, (void *)chan);
 	nvkm_fifo_chan_put(&fifo->base, flags, &chan);
 }
 
+static const struct nvkm_enum
+gf100_fifo_sched_reason[] = {
+	{ 0x0a, "CTXSW_TIMEOUT" },
+	{}
+};
+
+static void
+gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo)
+{
+	struct nvkm_device *device = fifo->base.engine.subdev.device;
+	struct nvkm_engine *engine;
+	struct gf100_fifo_chan *chan;
+	unsigned long flags;
+	u32 engn;
+
+	spin_lock_irqsave(&fifo->base.lock, flags);
+	for (engn = 0; engn < 6; engn++) {
+		u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04));
+		u32 busy = (stat & 0x80000000);
+		u32 save = (stat & 0x00100000); /* maybe? */
+		u32 unk0 = (stat & 0x00040000);
+		u32 unk1 = (stat & 0x00001000);
+		u32 chid = (stat & 0x0000007f);
+		(void)save;
+
+		if (busy && unk0 && unk1) {
+			list_for_each_entry(chan, &fifo->chan, head) {
+				if (chan->base.chid == chid) {
+					engine = gf100_fifo_engine(fifo, engn);
+					if (!engine)
+						break;
+					gf100_fifo_recover(fifo, engine, chan);
+					break;
+				}
+			}
+		}
+	}
+	spin_unlock_irqrestore(&fifo->base.lock, flags);
+}
+
+static void
+gf100_fifo_intr_sched(struct gf100_fifo *fifo)
+{
+	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
+	u32 intr = nvkm_rd32(device, 0x00254c);
+	u32 code = intr & 0x000000ff;
+	const struct nvkm_enum *en;
+
+	en = nvkm_enum_find(gf100_fifo_sched_reason, code);
+
+	nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : "");
+
+	switch (code) {
+	case 0x0a:
+		gf100_fifo_intr_sched_ctxsw(fifo);
+		break;
+	default:
+		break;
+	}
+}
+
+void
+gf100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit)
+{
+	struct nvkm_device *device = fifo->engine.subdev.device;
+	u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10));
+	u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10));
+	u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10));
+	u32 type = nvkm_rd32(device, 0x00280c + (unit * 0x10));
+	struct nvkm_fault_data info;
+
+	info.inst   =  (u64)inst << 12;
+	info.addr   = ((u64)vahi << 32) | valo;
+	info.time   = 0;
+	info.engine = unit;
+	info.valid  = 1;
+	info.gpc    = (type & 0x1f000000) >> 24;
+	info.client = (type & 0x00001f00) >> 8;
+	info.access = (type & 0x00000080) >> 7;
+	info.hub    = (type & 0x00000040) >> 6;
+	info.reason = (type & 0x0000000f);
+
+	nvkm_fifo_fault(fifo, &info);
+}
+
 static const struct nvkm_bitfield
 gf100_fifo_pbdma_intr[] = {
 /*	{ 0x00008000, "" }	seen with null ib push */
@@ -518,7 +535,7 @@ gf100_fifo_intr(struct nvkm_fifo *base)
 		u32 mask = nvkm_rd32(device, 0x00259c);
 		while (mask) {
 			u32 unit = __ffs(mask);
-			gf100_fifo_intr_fault(fifo, unit);
+			gf100_fifo_intr_fault(&fifo->base, unit);
 			nvkm_wr32(device, 0x00259c, (1 << unit));
 			mask &= ~(1 << unit);
 		}
@@ -655,6 +672,7 @@ gf100_fifo = {
 	.init = gf100_fifo_init,
 	.fini = gf100_fifo_fini,
 	.intr = gf100_fifo_intr,
+	.fault = gf100_fifo_fault,
 	.uevent_init = gf100_fifo_uevent_init,
 	.uevent_fini = gf100_fifo_uevent_fini,
 	.chan = {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
index 1053fe796466..ac9abcc1470a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -666,7 +666,7 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit)
 	info.client = (type & 0x00001f00) >> 8;
 	info.access = (type & 0x00000080) >> 7;
 	info.hub    = (type & 0x00000040) >> 6;
-	info.reason = (type & 0x000000ff);
+	info.reason = (type & 0x0000001f);
 
 	nvkm_fifo_fault(&fifo->base, &info);
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
index c66f5370b21f..0ef8baab513e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
@@ -37,4 +37,6 @@ struct nvkm_fifo_func {
 void nv04_fifo_intr(struct nvkm_fifo *);
 void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *);
 void nv04_fifo_start(struct nvkm_fifo *, unsigned long *);
+
+void gf100_fifo_intr_fault(struct nvkm_fifo *, int);
 #endif
-- 
2.28.0