drm/nouveau/fifo: add chan/cgrp preempt()
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Jun 2022 10:47:33 +0000 (20:47 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 9 Nov 2022 00:44:49 +0000 (10:44 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
19 files changed:
drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/cgrp.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk110.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm107.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gp100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/gv100.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/runl.h
drivers/gpu/drm/nouveau/nvkm/engine/fifo/tu102.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/uchan.c

index 549e4b1..1c3c349 100644 (file)
 #include <nvif/unpack.h>
 
 void
-nvkm_fifo_recover_chan(struct nvkm_fifo *fifo, int chid)
-{
-       unsigned long flags;
-       if (WARN_ON(!fifo->func->recover_chan))
-               return;
-       spin_lock_irqsave(&fifo->lock, flags);
-       fifo->func->recover_chan(fifo, chid);
-       spin_unlock_irqrestore(&fifo->lock, flags);
-}
-
-void
 nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags)
 {
        return fifo->func->pause(fifo, flags);
index 50ba7c7..1440c72 100644 (file)
@@ -22,6 +22,7 @@ struct nvkm_ectx {
 
 struct nvkm_cgrp {
        const struct nvkm_cgrp_func {
+               void (*preempt)(struct nvkm_cgrp *);
        } *func;
        char name[64];
        struct nvkm_runl *runl;
index 4f11448..9b8f346 100644 (file)
@@ -222,6 +222,7 @@ nvkm_chan_cctx_bind(struct nvkm_chan *chan, struct nvkm_oproxy *oproxy, struct n
                nvkm_runl_block(runl);
        else
                nvkm_chan_block(chan);
+       nvkm_chan_preempt(chan, true);
 
        /* Update context pointer. */
        if (cctx)
@@ -300,6 +301,33 @@ done:
        return ret;
 }
 
+int
+nvkm_chan_preempt_locked(struct nvkm_chan *chan, bool wait)
+{
+       struct nvkm_runl *runl = chan->cgrp->runl;
+
+       CHAN_TRACE(chan, "preempt");
+       chan->func->preempt(chan);
+       if (!wait)
+               return 0;
+
+       return nvkm_runl_preempt_wait(runl);
+}
+
+int
+nvkm_chan_preempt(struct nvkm_chan *chan, bool wait)
+{
+       int ret;
+
+       if (!chan->func->preempt)
+               return 0;
+
+       mutex_lock(&chan->cgrp->runl->mutex);
+       ret = nvkm_chan_preempt_locked(chan, wait);
+       mutex_unlock(&chan->cgrp->runl->mutex);
+       return ret;
+}
+
 static int
 nvkm_fifo_chan_map(struct nvkm_object *object, void *argv, u32 argc,
                   enum nvkm_object_map *type, u64 *addr, u64 *size)
@@ -346,6 +374,8 @@ nvkm_chan_error(struct nvkm_chan *chan, bool preempt)
        if (atomic_inc_return(&chan->errored) == 1) {
                CHAN_ERROR(chan, "errored - disabling channel");
                nvkm_chan_block_locked(chan);
+               if (preempt)
+                       chan->func->preempt(chan);
                nvkm_event_ntfy(&chan->cgrp->runl->chid->event, chan->id, NVKM_CHAN_EVENT_ERRORED);
        }
        spin_unlock_irqrestore(&chan->lock, flags);
index d573d9f..2ad3859 100644 (file)
@@ -20,6 +20,7 @@ struct nvkm_chan_func {
        void (*unbind)(struct nvkm_chan *);
        void (*start)(struct nvkm_chan *);
        void (*stop)(struct nvkm_chan *);
+       void (*preempt)(struct nvkm_chan *);
        u32 (*doorbell_handle)(struct nvkm_chan *);
 
        void *(*dtor)(struct nvkm_fifo_chan *);
@@ -43,6 +44,8 @@ void nvkm_chan_del(struct nvkm_chan **);
 void nvkm_chan_allow(struct nvkm_chan *);
 void nvkm_chan_block(struct nvkm_chan *);
 void nvkm_chan_error(struct nvkm_chan *, bool preempt);
+int nvkm_chan_preempt(struct nvkm_chan *, bool wait);
+int nvkm_chan_preempt_locked(struct nvkm_chan *, bool wait);
 int nvkm_chan_cctx_get(struct nvkm_chan *, struct nvkm_engn *, struct nvkm_cctx **,
                       struct nvkm_client * /*TODO: remove need for this */);
 void nvkm_chan_cctx_put(struct nvkm_chan *, struct nvkm_cctx **);
index 9713dae..7a83b86 100644 (file)
@@ -33,8 +33,6 @@ int gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *, struct nvkm_engine *,
                                  struct nvkm_object *);
 void gk104_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *,
                                   struct nvkm_engine *);
-int gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *);
-int gk104_fifo_gpfifo_kick_locked(struct gk104_fifo_chan *);
 
 int gv100_fifo_gpfifo_new(struct gk104_fifo *, const struct nvkm_oclass *,
                          void *data, u32 size, struct nvkm_object **);
index e47ca11..4c3338c 100644 (file)
 
 #include <nvif/class.h>
 
+void
+gf100_chan_preempt(struct nvkm_chan *chan)
+{
+       nvkm_wr32(chan->cgrp->runl->fifo->engine.subdev.device, 0x002634, chan->id);
+}
+
 static void
 gf100_chan_stop(struct nvkm_chan *chan)
 {
@@ -83,6 +89,7 @@ gf100_chan = {
        .unbind = gf100_chan_unbind,
        .start = gf100_chan_start,
        .stop = gf100_chan_stop,
+       .preempt = gf100_chan_preempt,
 };
 
 static const struct nvkm_engn_func
@@ -158,6 +165,12 @@ gf100_runq = {
        .intr_0_names = gf100_runq_intr_0_names,
 };
 
+bool
+gf100_runl_preempt_pending(struct nvkm_runl *runl)
+{
+       return nvkm_rd32(runl->fifo->engine.subdev.device, 0x002634) & 0x00100000;
+}
+
 static void
 gf100_runl_allow(struct nvkm_runl *runl, u32 engm)
 {
@@ -238,6 +251,7 @@ gf100_runl = {
        .pending = gf100_runl_pending,
        .block = gf100_runl_block,
        .allow = gf100_runl_allow,
+       .preempt_pending = gf100_runl_preempt_pending,
 };
 
 static void
index 5ba922c..bcaa0ef 100644 (file)
@@ -86,6 +86,7 @@ gk104_chan = {
        .unbind = gk104_chan_unbind,
        .start = gk104_chan_start,
        .stop = gk104_chan_stop,
+       .preempt = gf100_chan_preempt,
 };
 
 void
@@ -366,6 +367,7 @@ gk104_runl = {
        .pending = gk104_runl_pending,
        .block = gk104_runl_block,
        .allow = gk104_runl_allow,
+       .preempt_pending = gf100_runl_preempt_pending,
 };
 
 int
index 3582b9f..a88e24b 100644 (file)
 #include "changk104.h"
 
 #include <core/memory.h>
+#include <subdev/timer.h>
 
 #include <nvif/class.h>
 
+void
+gk110_chan_preempt(struct nvkm_chan *chan)
+{
+       struct nvkm_cgrp *cgrp = chan->cgrp;
+
+       if (cgrp->hw) {
+               cgrp->func->preempt(cgrp);
+               return;
+       }
+
+       gf100_chan_preempt(chan);
+}
+
 const struct nvkm_chan_func
 gk110_chan = {
        .bind = gk104_chan_bind,
        .unbind = gk104_chan_unbind,
        .start = gk104_chan_start,
        .stop = gk104_chan_stop,
+       .preempt = gk110_chan_preempt,
 };
 
+static void
+gk110_cgrp_preempt(struct nvkm_cgrp *cgrp)
+{
+       nvkm_wr32(cgrp->runl->fifo->engine.subdev.device, 0x002634, 0x01000000 | cgrp->id);
+}
+
 const struct nvkm_cgrp_func
 gk110_cgrp = {
+       .preempt = gk110_cgrp_preempt,
 };
 
 void
@@ -68,6 +90,7 @@ gk110_runl = {
        .pending = gk104_runl_pending,
        .block = gk104_runl_block,
        .allow = gk104_runl_allow,
+       .preempt_pending = gf100_runl_preempt_pending,
 };
 
 int
index 2924ce1..a98ea71 100644 (file)
@@ -38,6 +38,7 @@ gm107_chan = {
        .unbind = gk104_chan_unbind,
        .start = gk104_chan_start,
        .stop = gk104_chan_stop,
+       .preempt = gk110_chan_preempt,
 };
 
 static void
@@ -62,6 +63,7 @@ gm107_runl = {
        .pending = gk104_runl_pending,
        .block = gk104_runl_block,
        .allow = gk104_runl_allow,
+       .preempt_pending = gf100_runl_preempt_pending,
 };
 
 static const struct nvkm_enum
index 4dd3fb0..ddac252 100644 (file)
@@ -35,6 +35,7 @@ gp100_runl = {
        .pending = gk104_runl_pending,
        .block = gk104_runl_block,
        .allow = gk104_runl_allow,
+       .preempt_pending = gf100_runl_preempt_pending,
 };
 
 static const struct nvkm_enum
index 29783d2..77a4f23 100644 (file)
@@ -62,26 +62,9 @@ gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
 {
        const u32 offset = gf100_fifo_gpfifo_engine_addr(engine);
        struct gf100_fifo_chan *chan = gf100_fifo_chan(base);
-       struct nvkm_subdev *subdev = &chan->fifo->base.engine.subdev;
-       struct nvkm_device *device = subdev->device;
        struct nvkm_gpuobj *inst = chan->base.inst;
        int ret = 0;
 
-       mutex_lock(&chan->fifo->base.mutex);
-       nvkm_wr32(device, 0x002634, chan->base.chid);
-       if (nvkm_msec(device, 2000,
-               if (nvkm_rd32(device, 0x002634) == chan->base.chid)
-                       break;
-       ) < 0) {
-               nvkm_error(subdev, "channel %d [%s] kick timeout\n",
-                          chan->base.chid, chan->base.object.client->name);
-               ret = -ETIMEDOUT;
-       }
-       mutex_unlock(&chan->fifo->base.mutex);
-
-       if (ret && suspend)
-               return ret;
-
        if (offset) {
                nvkm_kmap(inst);
                nvkm_wo32(inst, offset + 0x00, 0x00000000);
index 1847b1b..9440cf5 100644 (file)
 #include <nvif/cla06f.h>
 #include <nvif/unpack.h>
 
-int
-gk104_fifo_gpfifo_kick_locked(struct gk104_fifo_chan *chan)
-{
-       struct gk104_fifo *fifo = chan->fifo;
-       struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
-       struct nvkm_device *device = subdev->device;
-       struct nvkm_client *client = chan->base.object.client;
-       struct nvkm_fifo_cgrp *cgrp = chan->cgrp;
-       int ret = 0;
-
-       if (cgrp)
-               nvkm_wr32(device, 0x002634, cgrp->id | 0x01000000);
-       else
-               nvkm_wr32(device, 0x002634, chan->base.chid);
-       if (nvkm_msec(device, 2000,
-               if (!(nvkm_rd32(device, 0x002634) & 0x00100000))
-                       break;
-       ) < 0) {
-               nvkm_error(subdev, "%s %d [%s] kick timeout\n",
-                          cgrp ? "tsg" : "channel",
-                          cgrp ? cgrp->id : chan->base.chid, client->name);
-               nvkm_fifo_recover_chan(&fifo->base, chan->base.chid);
-               ret = -ETIMEDOUT;
-       }
-       return ret;
-}
-
-int
-gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan)
-{
-       int ret;
-       mutex_lock(&chan->base.fifo->mutex);
-       ret = gk104_fifo_gpfifo_kick_locked(chan);
-       mutex_unlock(&chan->base.fifo->mutex);
-       return ret;
-}
-
 static u32
 gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine)
 {
@@ -110,11 +73,6 @@ gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
        struct gk104_fifo_chan *chan = gk104_fifo_chan(base);
        struct nvkm_gpuobj *inst = chan->base.inst;
        u32 offset = gk104_fifo_gpfifo_engine_addr(engine);
-       int ret;
-
-       ret = gk104_fifo_gpfifo_kick(chan);
-       if (ret && suspend)
-               return ret;
 
        if (offset) {
                nvkm_kmap(inst);
@@ -127,7 +85,7 @@ gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base,
                nvkm_done(inst);
        }
 
-       return ret;
+       return 0;
 }
 
 static int
@@ -202,7 +160,6 @@ gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base)
 
        if (!list_empty(&chan->head)) {
                gk104_fifo_runlist_remove(fifo, chan);
-               gk104_fifo_gpfifo_kick(chan);
                gk104_fifo_runlist_update(fifo, chan->runl);
        }
 }
index a901ce2..66d6079 100644 (file)
@@ -33,23 +33,15 @@ gv100_fifo_gpfifo_engine_valid(struct gk104_fifo_chan *chan, bool ce, bool valid
 {
        const u32 mask = ce ? 0x00020000 : 0x00010000;
        const u32 data = valid ? mask : 0x00000000;
-       int ret;
-
-       /* Block runlist to prevent the channel from being rescheduled. */
-       mutex_lock(&chan->fifo->base.mutex);
 
-       /* Preempt the channel. */
-       ret = gk104_fifo_gpfifo_kick_locked(chan);
-       if (ret == 0) {
+       if (1) {
                /* Update engine context validity. */
                nvkm_kmap(chan->base.inst);
                nvkm_mo32(chan->base.inst, 0x0ac, mask, data);
                nvkm_done(chan->base.inst);
        }
 
-       /* Resume runlist. */
-       mutex_unlock(&chan->fifo->base.mutex);
-       return ret;
+       return 0;
 }
 
 int
index 0e9e070..2e61a7b 100644 (file)
@@ -43,6 +43,7 @@ gv100_chan = {
        .unbind = gk104_chan_unbind,
        .start = gk104_chan_start,
        .stop = gk104_chan_stop,
+       .preempt = gk110_chan_preempt,
        .doorbell_handle = gv100_chan_doorbell_handle,
 };
 
@@ -99,6 +100,7 @@ gv100_runl = {
        .pending = gk104_runl_pending,
        .block = gk104_runl_block,
        .allow = gk104_runl_allow,
+       .preempt_pending = gf100_runl_preempt_pending,
 };
 
 const struct nvkm_enum
index d9de5ab..1a0d94b 100644 (file)
@@ -11,8 +11,6 @@ struct nvkm_runq;
 struct gk104_fifo;
 struct gk104_fifo_chan;
 
-void nvkm_fifo_recover_chan(struct nvkm_fifo *, int chid);
-
 struct nvkm_fifo_chan_oclass;
 struct nvkm_fifo_func {
        void *(*dtor)(struct nvkm_fifo *);
@@ -107,6 +105,7 @@ extern const struct nvkm_engn_func nv50_engn_sw;
 void nv50_chan_unbind(struct nvkm_chan *);
 void nv50_chan_start(struct nvkm_chan *);
 void nv50_chan_stop(struct nvkm_chan *);
+void nv50_chan_preempt(struct nvkm_chan *);
 
 extern const struct nvkm_event_func g84_fifo_nonstall;
 extern const struct nvkm_engn_func g84_engn;
@@ -120,9 +119,11 @@ void gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *, int);
 void gf100_fifo_mmu_fault_recover(struct nvkm_fifo *, struct nvkm_fault_data *);
 extern const struct nvkm_enum gf100_fifo_mmu_fault_access[];
 extern const struct nvkm_event_func gf100_fifo_nonstall;
+bool gf100_runl_preempt_pending(struct nvkm_runl *);
 void gf100_runq_init(struct nvkm_runq *);
 bool gf100_runq_intr(struct nvkm_runq *, struct nvkm_runl *);
 extern const struct nvkm_engn_func gf100_engn_sw;
+void gf100_chan_preempt(struct nvkm_chan *);
 
 int gk104_fifo_chid_nr(struct nvkm_fifo *);
 int gk104_fifo_runl_ctor(struct nvkm_fifo *);
@@ -156,6 +157,7 @@ int gk110_fifo_chid_ctor(struct nvkm_fifo *, int);
 extern const struct nvkm_runl_func gk110_runl;
 extern const struct nvkm_cgrp_func gk110_cgrp;
 extern const struct nvkm_chan_func gk110_chan;
+void gk110_chan_preempt(struct nvkm_chan *);
 
 extern const struct nvkm_runq_func gk208_runq;
 void gk208_runq_init(struct nvkm_runq *);
index 438e884..325c4de 100644 (file)
@@ -26,6 +26,7 @@
 #include "priv.h"
 
 #include <core/gpuobj.h>
+#include <subdev/timer.h>
 #include <subdev/top.h>
 
 struct nvkm_chan *
@@ -73,6 +74,17 @@ nvkm_runl_chan_get_chid(struct nvkm_runl *runl, int id, unsigned long *pirqflags
        return NULL;
 }
 
+int
+nvkm_runl_preempt_wait(struct nvkm_runl *runl)
+{
+       return nvkm_msec(runl->fifo->engine.subdev.device, runl->fifo->timeout.chan_msec,
+               if (!runl->func->preempt_pending(runl))
+                       break;
+
+               usleep_range(1, 2);
+       ) < 0 ? -ETIMEDOUT : 0;
+}
+
 bool
 nvkm_runl_update_pending(struct nvkm_runl *runl)
 {
index 35dce7c..68d6854 100644 (file)
@@ -28,6 +28,7 @@ struct nvkm_runl {
                bool (*pending)(struct nvkm_runl *);
                void (*block)(struct nvkm_runl *, u32 engm);
                void (*allow)(struct nvkm_runl *, u32 engm);
+               bool (*preempt_pending)(struct nvkm_runl *);
        } *func;
        struct nvkm_fifo *fifo;
        int id;
@@ -60,6 +61,7 @@ void nvkm_runl_del(struct nvkm_runl *);
 void nvkm_runl_block(struct nvkm_runl *);
 void nvkm_runl_allow(struct nvkm_runl *);
 bool nvkm_runl_update_pending(struct nvkm_runl *);
+int nvkm_runl_preempt_wait(struct nvkm_runl *);
 
 struct nvkm_chan *nvkm_runl_chan_get_chid(struct nvkm_runl *, int chid, unsigned long *irqflags);
 struct nvkm_chan *nvkm_runl_chan_get_inst(struct nvkm_runl *, u64 inst, unsigned long *irqflags);
index 4ae8544..641c1ff 100644 (file)
@@ -53,6 +53,7 @@ tu102_chan = {
        .unbind = gk104_chan_unbind,
        .start = tu102_chan_start,
        .stop = gk104_chan_stop,
+       .preempt = gk110_chan_preempt,
        .doorbell_handle = tu102_chan_doorbell_handle,
 };
 
@@ -91,6 +92,7 @@ tu102_runl = {
        .pending = tu102_runl_pending,
        .block = gk104_runl_block,
        .allow = gk104_runl_allow,
+       .preempt_pending = gf100_runl_preempt_pending,
 };
 
 static const struct nvkm_enum
index 096e09f..1fe7bd6 100644 (file)
@@ -216,6 +216,7 @@ nvkm_uchan_fini(struct nvkm_object *object, bool suspend)
        int ret;
 
        nvkm_chan_block(chan);
+       nvkm_chan_preempt(chan, true);
 
        ret = chan->object.func->fini(&chan->object, suspend);
        if (ret && suspend)