drm/nouveau/sec2: unload RTOS before tearing down WPR
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Jun 2022 10:47:49 +0000 (20:47 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 9 Nov 2022 00:44:58 +0000 (10:44 +1000)
Reset regs won't be available on Ampere while SEC2 RTOS is running, and
we're apparently supposed to be doing this on earlier GPUs too.

v2:
- fixed some excessive indentation

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
drivers/gpu/drm/nouveau/include/nvfw/sec2.h
drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h
drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
drivers/gpu/drm/nouveau/nvkm/engine/sec2/tu102.c
drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c
drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h
drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c

index 9a37ad4..07d7094 100644 (file)
@@ -10,6 +10,7 @@ struct nv_sec2_args {
 };
 
 #define NV_SEC2_UNIT_INIT                                                  0x01
+#define NV_SEC2_UNIT_UNLOAD                                                0x06
 #define NV_SEC2_UNIT_ACR                                                   0x08
 
 struct nv_sec2_init_msg {
@@ -57,4 +58,8 @@ struct nv_sec2_acr_bootstrap_falcon_msg {
        u32 error_code;
        u32 falcon_id;
 };
+
+#define NV_SEC2_UNIT_V2_INIT   0x01
+#define NV_SEC2_UNIT_V2_UNLOAD 0x05
+#define NV_SEC2_UNIT_V2_ACR    0x07
 #endif
index d647d8a..2db6b5d 100644 (file)
@@ -72,6 +72,7 @@ int nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *, const char *name,
 void nvkm_falcon_msgq_del(struct nvkm_falcon_msgq **);
 void nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *,
                           u32 index, u32 offset, u32 size);
+bool nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *);
 int nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *, void *, u32 size);
 void nvkm_falcon_msgq_recv(struct nvkm_falcon_msgq *);
 #endif
index 06264c8..a41b864 100644 (file)
@@ -10,12 +10,14 @@ struct nvkm_sec2 {
        struct nvkm_engine engine;
        struct nvkm_falcon falcon;
 
+       atomic_t running;
+       atomic_t initmsg;
+
        struct nvkm_falcon_qmgr *qmgr;
        struct nvkm_falcon_cmdq *cmdq;
        struct nvkm_falcon_msgq *msgq;
 
        struct work_struct work;
-       bool initmsg_received;
 };
 
 int gp102_sec2_new(struct nvkm_device *, enum nvkm_subdev_type, int inst, struct nvkm_sec2 **);
index 3a269bb..fe5024b 100644 (file)
@@ -109,7 +109,6 @@ struct nvkm_acr_lsf_func {
        u32 bld_size;
        void (*bld_write)(struct nvkm_acr *, u32 bld, struct nvkm_acr_lsfw *);
        void (*bld_patch)(struct nvkm_acr *, u32 bld, s64 adjust);
-       int (*boot)(struct nvkm_falcon *);
        u64 bootstrap_falcons;
        int (*bootstrap_falcon)(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
        int (*bootstrap_multiple_falcons)(struct nvkm_falcon *, u32 mask);
index 092c6d0..428bbda 100644 (file)
 #include "priv.h"
 
 #include <core/firmware.h>
-#include <subdev/top.h>
+#include <subdev/timer.h>
 
-static void
-nvkm_sec2_recv(struct work_struct *work)
-{
-       struct nvkm_sec2 *sec2 = container_of(work, typeof(*sec2), work);
-
-       if (!sec2->initmsg_received) {
-               int ret = sec2->func->initmsg(sec2);
-               if (ret) {
-                       nvkm_error(&sec2->engine.subdev,
-                                  "error parsing init message: %d\n", ret);
-                       return;
-               }
+#include <nvfw/sec2.h>
 
-               sec2->initmsg_received = true;
-       }
+static int
+nvkm_sec2_finimsg(void *priv, struct nvfw_falcon_msg *hdr)
+{
+       struct nvkm_sec2 *sec2 = priv;
 
-       nvkm_falcon_msgq_recv(sec2->msgq);
+       atomic_set(&sec2->running, 0);
+       return 0;
 }
 
 static void
@@ -54,14 +46,52 @@ static int
 nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend)
 {
        struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
+       struct nvkm_subdev *subdev = &sec2->engine.subdev;
+       struct nvkm_falcon *falcon = &sec2->falcon;
+       struct nvkm_falcon_cmdq *cmdq = sec2->cmdq;
+       struct nvfw_falcon_cmd cmd = {
+               .unit_id = sec2->func->unit_unload,
+               .size = sizeof(cmd),
+       };
+       int ret;
+
+       if (!subdev->use.enabled)
+               return 0;
 
-       flush_work(&sec2->work);
+       if (atomic_read(&sec2->initmsg) == 1) {
+               ret = nvkm_falcon_cmdq_send(cmdq, &cmd, nvkm_sec2_finimsg, sec2,
+                                           msecs_to_jiffies(1000));
+               WARN_ON(ret);
 
-       if (suspend) {
-               nvkm_falcon_cmdq_fini(sec2->cmdq);
-               sec2->initmsg_received = false;
+               nvkm_msec(subdev->device, 2000,
+                       if (nvkm_falcon_rd32(falcon, 0x100) & 0x00000010)
+                               break;
+               );
        }
 
+       nvkm_falcon_cmdq_fini(cmdq);
+       falcon->func->disable(falcon);
+       nvkm_falcon_put(falcon, subdev);
+       return 0;
+}
+
+static int
+nvkm_sec2_init(struct nvkm_engine *engine)
+{
+       struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
+       struct nvkm_subdev *subdev = &sec2->engine.subdev;
+       struct nvkm_falcon *falcon = &sec2->falcon;
+       int ret;
+
+       ret = nvkm_falcon_get(falcon, subdev);
+       if (ret)
+               return ret;
+
+       nvkm_falcon_wr32(falcon, 0x014, 0xffffffff);
+       atomic_set(&sec2->initmsg, 0);
+       atomic_set(&sec2->running, 1);
+
+       nvkm_falcon_start(falcon);
        return 0;
 }
 
@@ -69,6 +99,7 @@ static void *
 nvkm_sec2_dtor(struct nvkm_engine *engine)
 {
        struct nvkm_sec2 *sec2 = nvkm_sec2(engine);
+
        nvkm_falcon_msgq_del(&sec2->msgq);
        nvkm_falcon_cmdq_del(&sec2->cmdq);
        nvkm_falcon_qmgr_del(&sec2->qmgr);
@@ -79,6 +110,7 @@ nvkm_sec2_dtor(struct nvkm_engine *engine)
 static const struct nvkm_engine_func
 nvkm_sec2 = {
        .dtor = nvkm_sec2_dtor,
+       .init = nvkm_sec2_init,
        .fini = nvkm_sec2_fini,
        .intr = nvkm_sec2_intr,
 };
@@ -113,6 +145,5 @@ nvkm_sec2_new_(const struct nvkm_sec2_fwif *fwif, struct nvkm_device *device,
            (ret = nvkm_falcon_msgq_new(sec2->qmgr, "msgq", &sec2->msgq)))
                return ret;
 
-       INIT_WORK(&sec2->work, nvkm_sec2_recv);
        return 0;
 };
index 44e39f5..fb6d541 100644 (file)
@@ -74,16 +74,6 @@ gp102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon,
                                     msecs_to_jiffies(1000));
 }
 
-static int
-gp102_sec2_acr_boot(struct nvkm_falcon *falcon)
-{
-       struct nv_sec2_args args = {};
-       nvkm_falcon_load_dmem(falcon, &args,
-                             falcon->func->emem_addr, sizeof(args), 0);
-       nvkm_falcon_start(falcon);
-       return 0;
-}
-
 static void
 gp102_sec2_acr_bld_patch(struct nvkm_acr *acr, u32 bld, s64 adjust)
 {
@@ -122,7 +112,6 @@ gp102_sec2_acr_0 = {
        .bld_size = sizeof(struct loader_config_v1),
        .bld_write = gp102_sec2_acr_bld_write,
        .bld_patch = gp102_sec2_acr_bld_patch,
-       .boot = gp102_sec2_acr_boot,
        .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) |
                             BIT_ULL(NVKM_ACR_LSF_GPCCS) |
                             BIT_ULL(NVKM_ACR_LSF_SEC2),
@@ -169,11 +158,29 @@ gp102_sec2_intr(struct nvkm_sec2 *sec2)
        u32 intr = nvkm_falcon_rd32(falcon, 0x008) & disp & ~(disp >> 16);
 
        if (intr & 0x00000040) {
-               schedule_work(&sec2->work);
+               if (unlikely(atomic_read(&sec2->initmsg) == 0)) {
+                       int ret = sec2->func->initmsg(sec2);
+
+                       if (ret)
+                               nvkm_error(subdev, "error parsing init message: %d\n", ret);
+
+                       atomic_set(&sec2->initmsg, ret ?: 1);
+               }
+
+               if (atomic_read(&sec2->initmsg) > 0) {
+                       if (!nvkm_falcon_msgq_empty(sec2->msgq))
+                               nvkm_falcon_msgq_recv(sec2->msgq);
+               }
+
                nvkm_falcon_wr32(falcon, 0x004, 0x00000040);
                intr &= ~0x00000040;
        }
 
+       if (intr & 0x00000010) {
+               nvkm_falcon_wr32(falcon, 0x004, 0x00000010);
+               intr &= ~0x00000010;
+       }
+
        if (intr) {
                nvkm_error(subdev, "unhandled intr %08x\n", intr);
                nvkm_falcon_wr32(falcon, 0x004, intr);
@@ -250,6 +257,7 @@ gp102_sec2_flcn = {
 const struct nvkm_sec2_func
 gp102_sec2 = {
        .flcn = &gp102_sec2_flcn,
+       .unit_unload = NV_SEC2_UNIT_UNLOAD,
        .unit_acr = NV_SEC2_UNIT_ACR,
        .intr = gp102_sec2_intr,
        .initmsg = gp102_sec2_initmsg,
@@ -304,7 +312,6 @@ gp102_sec2_acr_1 = {
        .bld_size = sizeof(struct flcn_bl_dmem_desc_v2),
        .bld_write = gp102_sec2_acr_bld_write_1,
        .bld_patch = gp102_sec2_acr_bld_patch_1,
-       .boot = gp102_sec2_acr_boot,
        .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_FECS) |
                             BIT_ULL(NVKM_ACR_LSF_GPCCS) |
                             BIT_ULL(NVKM_ACR_LSF_SEC2),
index af19229..814a5f1 100644 (file)
@@ -5,6 +5,7 @@
 
 struct nvkm_sec2_func {
        const struct nvkm_falcon_func *flcn;
+       u8 unit_unload;
        u8 unit_acr;
        void (*intr)(struct nvkm_sec2 *);
        int (*initmsg)(struct nvkm_sec2 *);
index f3faeb7..39e42be 100644 (file)
@@ -22,6 +22,8 @@
 #include "priv.h"
 #include <subdev/acr.h>
 
+#include <nvfw/sec2.h>
+
 static const struct nvkm_falcon_func
 tu102_sec2_flcn = {
        .debug = 0x408,
@@ -44,7 +46,8 @@ tu102_sec2_flcn = {
 static const struct nvkm_sec2_func
 tu102_sec2 = {
        .flcn = &tu102_sec2_flcn,
-       .unit_acr = 0x07,
+       .unit_unload = NV_SEC2_UNIT_V2_UNLOAD,
+       .unit_acr = NV_SEC2_UNIT_V2_ACR,
        .intr = gp102_sec2_intr,
        .initmsg = gp102_sec2_initmsg,
 };
index e74371d..04f8531 100644 (file)
@@ -25,7 +25,7 @@
 static void
 nvkm_falcon_msgq_open(struct nvkm_falcon_msgq *msgq)
 {
-       mutex_lock(&msgq->mutex);
+       spin_lock(&msgq->lock);
        msgq->position = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->tail_reg);
 }
 
@@ -37,10 +37,10 @@ nvkm_falcon_msgq_close(struct nvkm_falcon_msgq *msgq, bool commit)
        if (commit)
                nvkm_falcon_wr32(falcon, msgq->tail_reg, msgq->position);
 
-       mutex_unlock(&msgq->mutex);
+       spin_unlock(&msgq->lock);
 }
 
-static bool
+bool
 nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *msgq)
 {
        u32 head = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->head_reg);
@@ -208,6 +208,6 @@ nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *qmgr, const char *name,
 
        msgq->qmgr = qmgr;
        msgq->name = name;
-       mutex_init(&msgq->mutex);
+       spin_lock_init(&msgq->lock);
        return 0;
 }
index 33564ac..79f0da9 100644 (file)
@@ -73,7 +73,7 @@ struct nvkm_falcon_cmdq {
 struct nvkm_falcon_msgq {
        struct nvkm_falcon_qmgr *qmgr;
        const char *name;
-       struct mutex mutex;
+       spinlock_t lock;
 
        u32 head_reg;
        u32 tail_reg;
index 777b6cb..882d8d3 100644 (file)
@@ -97,7 +97,6 @@ nvkm_acr_load(struct nvkm_acr *acr)
 {
        struct nvkm_subdev *subdev = &acr->subdev;
        struct nvkm_acr_lsf *rtos = nvkm_acr_rtos(acr);
-       struct nvkm_acr_lsf *lsf;
        u64 start, limit;
        int ret;
 
@@ -129,14 +128,6 @@ nvkm_acr_load(struct nvkm_acr *acr)
                acr->rtos = rtos;
        }
 
-       list_for_each_entry(lsf, &acr->lsf, head) {
-               if (lsf->func->boot) {
-                       ret = lsf->func->boot(lsf->falcon);
-                       if (ret)
-                               break;
-               }
-       }
-
        return ret;
 }