drm/nouveau/secboot: allow to boot multiple falcons
authorAlexandre Courbot <acourbot@nvidia.com>
Wed, 29 Mar 2017 09:31:09 +0000 (18:31 +0900)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 6 Apr 2017 04:39:03 +0000 (14:39 +1000)
Change the secboot and msgqueue interfaces to take a mask of falcons to
reset instead of a single falcon. The GP10B firmware interface requires
FECS and GPCCS to be booted in a single firmware command.

For firmwares that only support single falcon boot, it is trivial to
loop over the mask and boot each falcons individually.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr.h
drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c

index fac0824197f1ccff37253b673cb92f1bbca4110c..5c902f8c042a1fafc8e4037c3bfb0a6c3f140272 100644 (file)
@@ -41,7 +41,6 @@ int nvkm_msgqueue_reinit(struct nvkm_msgqueue *);
 void nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *, void *);
 
 /* interface to ACR unit running on falcon (NVIDIA signed firmware) */
-int nvkm_msgqueue_acr_boot_falcon(struct nvkm_msgqueue *,
-                                 enum nvkm_secboot_falcon);
+int nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *, unsigned long);
 
 #endif
index d6a4bdb6573b41f66bacc950cd000bd348296bb2..a2d54d81e338989f352611e1c7f3efa93b082f55 100644 (file)
@@ -55,7 +55,7 @@ struct nvkm_secboot {
 #define nvkm_secboot(p) container_of((p), struct nvkm_secboot, subdev)
 
 bool nvkm_secboot_is_managed(struct nvkm_secboot *, enum nvkm_secboot_falcon);
-int nvkm_secboot_reset(struct nvkm_secboot *, enum nvkm_secboot_falcon);
+int nvkm_secboot_reset(struct nvkm_secboot *, unsigned long);
 
 int gm200_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);
 int gm20b_secboot_new(struct nvkm_device *, int, struct nvkm_secboot **);
index a4410ef19db53f1ab783862171447ca2e38d0489..99689f4de502d66b174825afc922a2fc3d397401 100644 (file)
@@ -1463,25 +1463,27 @@ gf100_gr_init_ctxctl_ext(struct gf100_gr *gr)
        struct nvkm_subdev *subdev = &gr->base.engine.subdev;
        struct nvkm_device *device = subdev->device;
        struct nvkm_secboot *sb = device->secboot;
-       int ret = 0;
+       u32 secboot_mask = 0;
 
        /* load fuc microcode */
        nvkm_mc_unk260(device, 0);
 
        /* securely-managed falcons must be reset using secure boot */
        if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_FECS))
-               ret = nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_FECS);
+               secboot_mask |= BIT(NVKM_SECBOOT_FALCON_FECS);
        else
                gf100_gr_init_fw(gr->fecs, &gr->fuc409c, &gr->fuc409d);
-       if (ret)
-               return ret;
 
        if (nvkm_secboot_is_managed(sb, NVKM_SECBOOT_FALCON_GPCCS))
-               ret = nvkm_secboot_reset(sb, NVKM_SECBOOT_FALCON_GPCCS);
+               secboot_mask |= BIT(NVKM_SECBOOT_FALCON_GPCCS);
        else
                gf100_gr_init_fw(gr->gpccs, &gr->fuc41ac, &gr->fuc41ad);
-       if (ret)
-               return ret;
+
+       if (secboot_mask != 0) {
+               int ret = nvkm_secboot_reset(sb, secboot_mask);
+               if (ret)
+                       return ret;
+       }
 
        nvkm_mc_unk260(device, 1);
 
index 982efedb4b13e576a3bf2608cda91e1a74cb5f24..0780d340c3eb207d79991051118ea8727ea343b4 100644 (file)
@@ -463,12 +463,31 @@ nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf)
 }
 
 int
-nvkm_msgqueue_acr_boot_falcon(struct nvkm_msgqueue *queue, enum nvkm_secboot_falcon falcon)
+nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *queue,
+                              unsigned long falcon_mask)
 {
-       if (!queue || !queue->func->acr_func || !queue->func->acr_func->boot_falcon)
+       unsigned long falcon;
+
+       if (!queue || !queue->func->acr_func)
+               return -ENODEV;
+
+       /* Does the firmware support booting multiple falcons? */
+       if (queue->func->acr_func->boot_multiple_falcons)
+               return queue->func->acr_func->boot_multiple_falcons(queue,
+                                                                  falcon_mask);
+
+       /* Else boot all requested falcons individually */
+       if (!queue->func->acr_func->boot_falcon)
                return -ENODEV;
 
-       return queue->func->acr_func->boot_falcon(queue, falcon);
+       for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
+               int ret = queue->func->acr_func->boot_falcon(queue, falcon);
+
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 int
index f37afe963d3eeb556980db4d7c8dc6afda9dc248..ea67a522a12e8d0495fc84df421799623cb7da7b 100644 (file)
@@ -101,9 +101,11 @@ struct nvkm_msgqueue_init_func {
  * struct nvkm_msgqueue_acr_func - msgqueue functions related to ACR
  *
  * @boot_falcon:       build and send the command to reset a given falcon
+ * @boot_multiple_falcons: build and send the command to reset several falcons
  */
 struct nvkm_msgqueue_acr_func {
        int (*boot_falcon)(struct nvkm_msgqueue *, enum nvkm_secboot_falcon);
+       int (*boot_multiple_falcons)(struct nvkm_msgqueue *, unsigned long);
 };
 
 struct nvkm_msgqueue_func {
index 93d804652d44e9b709c1afeedb77240431ec421f..b615fc81aca467f8451595d6f0365e768b1d10ca 100644 (file)
@@ -39,8 +39,7 @@ struct nvkm_acr_func {
        int (*fini)(struct nvkm_acr *, struct nvkm_secboot *, bool);
        int (*load)(struct nvkm_acr *, struct nvkm_falcon *,
                    struct nvkm_gpuobj *, u64);
-       int (*reset)(struct nvkm_acr *, struct nvkm_secboot *,
-                    enum nvkm_secboot_falcon);
+       int (*reset)(struct nvkm_acr *, struct nvkm_secboot *, unsigned long);
 };
 
 /**
index 993a38eb3ed5a8b0d8bd346714ba24cad228f7cc..aa4e75f0eb0ab1fa85d74cc2b7d63a5b25d14ac9 100644 (file)
@@ -976,15 +976,16 @@ acr_r352_bootstrap(struct acr_r352 *acr, struct nvkm_secboot *sb)
  */
 static int
 acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
-                    enum nvkm_secboot_falcon falcon)
+                    unsigned long falcon_mask)
 {
+       int falcon;
        int ret;
 
        /*
         * Perform secure boot each time we are called on FECS. Since only FECS
         * and GPCCS are managed and started together, this ought to be safe.
         */
-       if (falcon != NVKM_SECBOOT_FALCON_FECS)
+       if (!(falcon_mask & BIT(NVKM_SECBOOT_FALCON_FECS)))
                goto end;
 
        ret = acr_r352_shutdown(acr, sb);
@@ -996,7 +997,9 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
                return ret;
 
 end:
-       acr->falcon_state[falcon] = RESET;
+       for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
+               acr->falcon_state[falcon] = RESET;
+       }
        return 0;
 }
 
@@ -1009,11 +1012,11 @@ end:
  */
 static int
 acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
-              enum nvkm_secboot_falcon falcon)
+              unsigned long falcon_mask)
 {
        struct acr_r352 *acr = acr_r352(_acr);
        struct nvkm_msgqueue *queue;
-       const char *fname = nvkm_secboot_falcon_name[falcon];
+       int falcon;
        bool wpr_already_set = sb->wpr_set;
        int ret;
 
@@ -1026,7 +1029,7 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
        if (!nvkm_secboot_is_managed(sb, _acr->boot_falcon)) {
                /* Redo secure boot entirely if it was already done */
                if (wpr_already_set)
-                       return acr_r352_reset_nopmu(acr, sb, falcon);
+                       return acr_r352_reset_nopmu(acr, sb, falcon_mask);
                /* Else return the result of the initial invokation */
                else
                        return ret;
@@ -1044,13 +1047,15 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
        }
 
        /* Otherwise just ask the LS firmware to reset the falcon */
-       nvkm_debug(&sb->subdev, "resetting %s falcon\n", fname);
-       ret = nvkm_msgqueue_acr_boot_falcon(queue, falcon);
+       for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END)
+               nvkm_debug(&sb->subdev, "resetting %s falcon\n",
+                          nvkm_secboot_falcon_name[falcon]);
+       ret = nvkm_msgqueue_acr_boot_falcons(queue, falcon_mask);
        if (ret) {
-               nvkm_error(&sb->subdev, "cannot boot %s falcon\n", fname);
+               nvkm_error(&sb->subdev, "error during falcon reset: %d\n", ret);
                return ret;
        }
-       nvkm_debug(&sb->subdev, "falcon %s reset\n", fname);
+       nvkm_debug(&sb->subdev, "falcon reset done\n");
 
        return 0;
 }
index 5c11e8c5096483d21d31314a99e3041f850f0625..ee29c6c11afd524a10b8d3dc9eeb4fcca37e7d41 100644 (file)
@@ -102,15 +102,15 @@ nvkm_secboot_falcon_name[] = {
  * nvkm_secboot_reset() - reset specified falcon
  */
 int
-nvkm_secboot_reset(struct nvkm_secboot *sb, enum nvkm_secboot_falcon falcon)
+nvkm_secboot_reset(struct nvkm_secboot *sb, unsigned long falcon_mask)
 {
        /* Unmanaged falcon? */
-       if (!(BIT(falcon) & sb->acr->managed_falcons)) {
+       if ((falcon_mask | sb->acr->managed_falcons) != sb->acr->managed_falcons) {
                nvkm_error(&sb->subdev, "cannot reset unmanaged falcon!\n");
                return -EINVAL;
        }
 
-       return sb->acr->func->reset(sb->acr, sb, falcon);
+       return sb->acr->func->reset(sb->acr, sb, falcon_mask);
 }
 
 /**