drm/nouveau/acr: store a mask of LS falcons the controlling LSFW can bootstrap
authorBen Skeggs <bskeggs@redhat.com>
Tue, 16 Jun 2020 04:57:31 +0000 (14:57 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 24 Jul 2020 08:50:48 +0000 (18:50 +1000)
This will prevent some pain with broken firmware trees, as under some
circumstances the HSFW can fail and leave the GPU in a state we don't
know how to recover from.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c

index 5d9c3a9..836d8b9 100644 (file)
@@ -39,6 +39,8 @@ struct nvkm_acr {
        struct list_head hsfw, hsf;
        struct list_head lsfw, lsf;
 
+       u64 managed_falcons;
+
        struct nvkm_memory *wpr;
        u64 wpr_start;
        u64 wpr_end;
@@ -107,6 +109,7 @@ struct nvkm_acr_lsf_func {
        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 a2a9a84..36b31bf 100644 (file)
@@ -115,6 +115,9 @@ gp102_sec2_acr_0 = {
        .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),
        .bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon,
 };
 
@@ -294,6 +297,9 @@ gp102_sec2_acr_1 = {
        .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),
        .bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon,
 };
 
index 51a669e..c962df9 100644 (file)
@@ -156,6 +156,9 @@ nvkm_acr_bootstrap_falcons(struct nvkm_device *device, unsigned long mask)
                return -ENOSYS;
        }
 
+       if ((mask & acrflcn->func->bootstrap_falcons) != mask)
+               return -ENOSYS;
+
        if (acrflcn->func->bootstrap_multiple_falcons) {
                return acrflcn->func->
                        bootstrap_multiple_falcons(acrflcn->falcon, mask);
@@ -174,13 +177,10 @@ bool
 nvkm_acr_managed_falcon(struct nvkm_device *device, enum nvkm_acr_lsf_id id)
 {
        struct nvkm_acr *acr = device->acr;
-       struct nvkm_acr_lsf *lsf;
 
        if (acr) {
-               list_for_each_entry(lsf, &acr->lsf, head) {
-                       if (lsf->id == id)
-                               return true;
-               }
+               if (acr->managed_falcons & BIT_ULL(id))
+                       return true;
        }
 
        return false;
@@ -220,6 +220,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
        struct nvkm_acr_lsfw *lsfw, *lsft;
        struct nvkm_acr_lsf *lsf;
        u32 wpr_size = 0;
+       u64 falcons;
        int ret, i;
 
        if (list_empty(&acr->hsfw)) {
@@ -255,12 +256,28 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
                lsf->falcon = lsfw->falcon;
                lsf->id = lsfw->id;
                list_add_tail(&lsf->head, &acr->lsf);
+               acr->managed_falcons |= BIT_ULL(lsf->id);
        }
 
        /* Ensure the falcon that'll provide ACR functions is booted first. */
        lsf = nvkm_acr_falcon(device);
-       if (lsf)
+       if (lsf) {
+               falcons = lsf->func->bootstrap_falcons;
                list_move(&lsf->head, &acr->lsf);
+       } else {
+               falcons = acr->func->bootstrap_falcons;
+       }
+
+       /* Cull falcons that can't be bootstrapped, or the HSFW can fail to
+        * boot and leave the GPU in a weird state.
+        */
+       list_for_each_entry_safe(lsfw, lsft, &acr->lsfw, head) {
+               if (!(falcons & BIT_ULL(lsfw->id))) {
+                       nvkm_warn(subdev, "%s falcon cannot be bootstrapped\n",
+                                 nvkm_acr_lsf_id(lsfw->id));
+                       nvkm_acr_lsfw_del(lsfw);
+               }
+       }
 
        if (!acr->wpr_fw || acr->wpr_comp)
                wpr_size = acr->func->wpr_layout(acr);
index 3a0cca3..cf91fd3 100644 (file)
@@ -126,6 +126,9 @@ gm20b_pmu_acr = {
        .bld_write = gm20b_pmu_acr_bld_write,
        .bld_patch = gm20b_pmu_acr_bld_patch,
        .boot = gm20b_pmu_acr_boot,
+       .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_PMU) |
+                            BIT_ULL(NVKM_ACR_LSF_FECS) |
+                            BIT_ULL(NVKM_ACR_LSF_GPCCS),
        .bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon,
 };
 
index fdfb147..9a4aca2 100644 (file)
@@ -69,6 +69,9 @@ gp10b_pmu_acr = {
        .bld_write = gm20b_pmu_acr_bld_write,
        .bld_patch = gm20b_pmu_acr_bld_patch,
        .boot = gm20b_pmu_acr_boot,
+       .bootstrap_falcons = BIT_ULL(NVKM_ACR_LSF_PMU) |
+                            BIT_ULL(NVKM_ACR_LSF_FECS) |
+                            BIT_ULL(NVKM_ACR_LSF_GPCCS),
        .bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon,
        .bootstrap_multiple_falcons = gp10b_pmu_acr_bootstrap_multiple_falcons,
 };