[Nouveau] [PATCH 01/15] secboot: allow to boot multiple falcons

Alexandre Courbot acourbot at nvidia.com
Wed Mar 29 09:31:09 UTC 2017


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 at nvidia.com>
---
 drm/nouveau/include/nvkm/core/msgqueue.h   |  3 +--
 drm/nouveau/include/nvkm/subdev/secboot.h  |  2 +-
 drm/nouveau/nvkm/engine/gr/gf100.c         | 16 +++++++++-------
 drm/nouveau/nvkm/falcon/msgqueue.c         | 25 ++++++++++++++++++++++---
 drm/nouveau/nvkm/falcon/msgqueue.h         |  2 ++
 drm/nouveau/nvkm/subdev/secboot/acr.h      |  3 +--
 drm/nouveau/nvkm/subdev/secboot/acr_r352.c | 25 +++++++++++++++----------
 drm/nouveau/nvkm/subdev/secboot/base.c     |  6 +++---
 8 files changed, 54 insertions(+), 28 deletions(-)

diff --git a/drm/nouveau/include/nvkm/core/msgqueue.h b/drm/nouveau/include/nvkm/core/msgqueue.h
index fac0824197f1..5c902f8c042a 100644
--- a/drm/nouveau/include/nvkm/core/msgqueue.h
+++ b/drm/nouveau/include/nvkm/core/msgqueue.h
@@ -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
diff --git a/drm/nouveau/include/nvkm/subdev/secboot.h b/drm/nouveau/include/nvkm/subdev/secboot.h
index d6a4bdb6573b..a2d54d81e338 100644
--- a/drm/nouveau/include/nvkm/subdev/secboot.h
+++ b/drm/nouveau/include/nvkm/subdev/secboot.h
@@ -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 **);
diff --git a/drm/nouveau/nvkm/engine/gr/gf100.c b/drm/nouveau/nvkm/engine/gr/gf100.c
index a4410ef19db5..99689f4de502 100644
--- a/drm/nouveau/nvkm/engine/gr/gf100.c
+++ b/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -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);
 
diff --git a/drm/nouveau/nvkm/falcon/msgqueue.c b/drm/nouveau/nvkm/falcon/msgqueue.c
index 982efedb4b13..0780d340c3eb 100644
--- a/drm/nouveau/nvkm/falcon/msgqueue.c
+++ b/drm/nouveau/nvkm/falcon/msgqueue.c
@@ -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
diff --git a/drm/nouveau/nvkm/falcon/msgqueue.h b/drm/nouveau/nvkm/falcon/msgqueue.h
index f37afe963d3e..ea67a522a12e 100644
--- a/drm/nouveau/nvkm/falcon/msgqueue.h
+++ b/drm/nouveau/nvkm/falcon/msgqueue.h
@@ -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 {
diff --git a/drm/nouveau/nvkm/subdev/secboot/acr.h b/drm/nouveau/nvkm/subdev/secboot/acr.h
index 93d804652d44..b615fc81aca4 100644
--- a/drm/nouveau/nvkm/subdev/secboot/acr.h
+++ b/drm/nouveau/nvkm/subdev/secboot/acr.h
@@ -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);
 };
 
 /**
diff --git a/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
index 993a38eb3ed5..aa4e75f0eb0a 100644
--- a/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
+++ b/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
@@ -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;
 }
diff --git a/drm/nouveau/nvkm/subdev/secboot/base.c b/drm/nouveau/nvkm/subdev/secboot/base.c
index 5c11e8c50964..ee29c6c11afd 100644
--- a/drm/nouveau/nvkm/subdev/secboot/base.c
+++ b/drm/nouveau/nvkm/subdev/secboot/base.c
@@ -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);
 }
 
 /**
-- 
2.12.0



More information about the Nouveau mailing list