Blob Blame History Raw
From d82c334ca37862a0209b6cdea706df16b687e43d Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Wed, 15 Jan 2020 06:34:22 +1000
Subject: drm/nouveau/flcn/cmdq: move command generation to subdevs
Git-commit: 86ce2a71539c47241dc8f471d8724f5bd1e41ae6
Patch-mainline: v5.6-rc1
References: jsc#SLE-12680, jsc#SLE-12880, jsc#SLE-12882, jsc#SLE-12883, jsc#SLE-13496, jsc#SLE-15322

This moves the code to generate commands for the ACR unit of the PMU/SEC2 LS
firmwares to those subdevs.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Signed-off-by: Patrik Jakobsson <pjakobsson@suse.de>
---
 drivers/gpu/drm/nouveau/include/nvfw/pmu.h    |  47 ++++++
 drivers/gpu/drm/nouveau/include/nvfw/sec2.h   |  30 ++++
 .../drm/nouveau/include/nvkm/core/msgqueue.h  |   3 -
 .../gpu/drm/nouveau/include/nvkm/subdev/acr.h |  23 ++-
 .../gpu/drm/nouveau/nvkm/engine/sec2/gp102.c  |  44 ++++++
 .../gpu/drm/nouveau/nvkm/engine/sec2/priv.h   |   1 +
 .../gpu/drm/nouveau/nvkm/falcon/msgqueue.c    |  28 ----
 .../gpu/drm/nouveau/nvkm/falcon/msgqueue.h    |  12 --
 .../nouveau/nvkm/falcon/msgqueue_0137c63d.c   | 142 ------------------
 .../nouveau/nvkm/falcon/msgqueue_0148cdec.c   |  76 ----------
 .../gpu/drm/nouveau/nvkm/subdev/acr/base.c    |  74 ++++++++-
 .../gpu/drm/nouveau/nvkm/subdev/acr/priv.h    |   7 +
 .../gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c   |  34 +++++
 .../gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c   |  36 +++++
 .../gpu/drm/nouveau/nvkm/subdev/pmu/priv.h    |   2 +
 .../nouveau/nvkm/subdev/secboot/acr_r352.c    |  17 +--
 16 files changed, 300 insertions(+), 276 deletions(-)
 create mode 100644 drivers/gpu/drm/nouveau/include/nvfw/pmu.h
 create mode 100644 drivers/gpu/drm/nouveau/include/nvfw/sec2.h

diff --git a/drivers/gpu/drm/nouveau/include/nvfw/pmu.h b/drivers/gpu/drm/nouveau/include/nvfw/pmu.h
new file mode 100644
index 000000000000..6e86ce31f963
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvfw/pmu.h
@@ -0,0 +1,47 @@
+#ifndef __NVFW_PMU_H__
+#define __NVFW_PMU_H__
+
+#define NV_PMU_UNIT_ACR                                                    0x0a
+
+struct nv_pmu_acr_cmd {
+	struct nv_falcon_cmd hdr;
+#define NV_PMU_ACR_CMD_INIT_WPR_REGION                                     0x00
+#define NV_PMU_ACR_CMD_BOOTSTRAP_FALCON                                    0x01
+#define NV_PMU_ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS                          0x03
+	u8 cmd_type;
+};
+
+struct nv_pmu_acr_msg {
+	struct nv_falcon_cmd hdr;
+	u8 msg_type;
+};
+
+struct nv_pmu_acr_bootstrap_falcon_cmd {
+	struct nv_pmu_acr_cmd cmd;
+#define NV_PMU_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES                  0x00000000
+#define NV_PMU_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_NO                   0x00000001
+	u32 flags;
+	u32 falcon_id;
+};
+
+struct nv_pmu_acr_bootstrap_falcon_msg {
+	struct nv_pmu_acr_msg msg;
+	u32 falcon_id;
+};
+
+struct nv_pmu_acr_bootstrap_multiple_falcons_cmd {
+	struct nv_pmu_acr_cmd cmd;
+#define NV_PMU_ACR_BOOTSTRAP_MULTIPLE_FALCONS_FLAGS_RESET_YES        0x00000000
+#define NV_PMU_ACR_BOOTSTRAP_MULTIPLE_FALCONS_FLAGS_RESET_NO         0x00000001
+	u32 flags;
+	u32 falcon_mask;
+	u32 use_va_mask;
+	u32 wpr_lo;
+	u32 wpr_hi;
+};
+
+struct nv_pmu_acr_bootstrap_multiple_falcons_msg {
+	struct nv_pmu_acr_msg msg;
+	u32 falcon_mask;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvfw/sec2.h b/drivers/gpu/drm/nouveau/include/nvfw/sec2.h
new file mode 100644
index 000000000000..2f7460fe1b76
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvfw/sec2.h
@@ -0,0 +1,30 @@
+#ifndef __NVFW_SEC2_H__
+#define __NVFW_SEC2_H__
+
+#define NV_SEC2_UNIT_ACR                                                   0x08
+
+struct nv_sec2_acr_cmd {
+	struct nv_falcon_cmd hdr;
+#define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON                                   0x00
+	u8 cmd_type;
+};
+
+struct nv_sec2_acr_msg {
+	struct nv_falcon_cmd hdr;
+	u8 msg_type;
+};
+
+struct nv_sec2_acr_bootstrap_falcon_cmd {
+	struct nv_sec2_acr_cmd cmd;
+#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES                 0x00000000
+#define NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_NO                  0x00000001
+	u32 flags;
+	u32 falcon_id;
+};
+
+struct nv_sec2_acr_bootstrap_falcon_msg {
+	struct nv_sec2_acr_msg msg;
+	u32 error_code;
+	u32 falcon_id;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h b/drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h
index bf3e532665fb..acb339f34bb5 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h
@@ -37,7 +37,4 @@ int nvkm_msgqueue_reinit(struct nvkm_msgqueue *);
 /* useful if we run a NVIDIA-signed firmware */
 void nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *, void *);
 
-/* interface to ACR unit running on falcon (NVIDIA signed firmware) */
-int nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *, unsigned long);
-
 #endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
index 6b342a63e2cb..7e51bd4befce 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/acr.h
@@ -13,15 +13,34 @@ enum nvkm_acr_lsf_id {
 	NVKM_ACR_LSF_NVDEC = 4,
 	NVKM_ACR_LSF_SEC2 = 7,
 	NVKM_ACR_LSF_MINION = 10,
+	NVKM_ACR_LSF_NUM
 };
 
+static inline const char *
+nvkm_acr_lsf_id(enum nvkm_acr_lsf_id id)
+{
+	switch (id) {
+	case NVKM_ACR_LSF_PMU    : return "pmu";
+	case NVKM_ACR_LSF_GSPLITE: return "gsplite";
+	case NVKM_ACR_LSF_FECS   : return "fecs";
+	case NVKM_ACR_LSF_GPCCS  : return "gpccs";
+	case NVKM_ACR_LSF_NVDEC  : return "nvdec";
+	case NVKM_ACR_LSF_SEC2   : return "sec2";
+	case NVKM_ACR_LSF_MINION : return "minion";
+	default:
+		return "unknown";
+	}
+}
+
 struct nvkm_acr {
 	const struct nvkm_acr_func *func;
 	struct nvkm_subdev subdev;
 
-	struct list_head lsfw;
+	struct list_head lsfw, lsf;
 };
 
+int nvkm_acr_bootstrap_falcons(struct nvkm_device *, unsigned long mask);
+
 int gm200_acr_new(struct nvkm_device *, int, struct nvkm_acr **);
 int gm20b_acr_new(struct nvkm_device *, int, struct nvkm_acr **);
 int gp102_acr_new(struct nvkm_device *, int, struct nvkm_acr **);
@@ -55,6 +74,8 @@ struct nvkm_acr_lsfw {
 };
 
 struct nvkm_acr_lsf_func {
+	int (*bootstrap_falcon)(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
+	int (*bootstrap_multiple_falcons)(struct nvkm_falcon *, u32 mask);
 };
 
 int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
index 9a5bae1a03cd..26f738d1202e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
@@ -20,11 +20,53 @@
  * DEALINGS IN THE SOFTWARE.
  */
 #include "priv.h"
+
 #include <subdev/acr.h>
 #include <subdev/timer.h>
 
+#include <nvfw/sec2.h>
+
+static int
+gp102_sec2_acr_bootstrap_falcon_callback(void *priv, struct nv_falcon_msg *hdr)
+{
+	struct nv_sec2_acr_bootstrap_falcon_msg *msg =
+		container_of(hdr, typeof(*msg), msg.hdr);
+	struct nvkm_subdev *subdev = priv;
+	const char *name = nvkm_acr_lsf_id(msg->falcon_id);
+
+	if (msg->error_code) {
+		nvkm_error(subdev, "ACR_BOOTSTRAP_FALCON failed for "
+				   "falcon %d [%s]: %08x\n",
+			   msg->falcon_id, name, msg->error_code);
+		return -EINVAL;
+	}
+
+	nvkm_debug(subdev, "%s booted\n", name);
+	return 0;
+}
+
+static int
+gp102_sec2_acr_bootstrap_falcon(struct nvkm_falcon *falcon,
+			        enum nvkm_acr_lsf_id id)
+{
+	struct nvkm_sec2 *sec2 = container_of(falcon, typeof(*sec2), falcon);
+	struct nv_sec2_acr_bootstrap_falcon_cmd cmd = {
+		.cmd.hdr.unit_id = sec2->func->unit_acr,
+		.cmd.hdr.size = sizeof(cmd),
+		.cmd.cmd_type = NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON,
+		.flags = NV_SEC2_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES,
+		.falcon_id = id,
+	};
+
+	return nvkm_falcon_cmdq_send(sec2->cmdq, &cmd.cmd.hdr,
+				     gp102_sec2_acr_bootstrap_falcon_callback,
+				     &sec2->engine.subdev,
+				     msecs_to_jiffies(1000));
+}
+
 static const struct nvkm_acr_lsf_func
 gp102_sec2_acr_0 = {
+	.bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon,
 };
 
 void
@@ -117,6 +159,7 @@ gp102_sec2_flcn = {
 const struct nvkm_sec2_func
 gp102_sec2 = {
 	.flcn = &gp102_sec2_flcn,
+	.unit_acr = NV_SEC2_UNIT_ACR,
 	.intr = gp102_sec2_intr,
 };
 
@@ -135,6 +178,7 @@ MODULE_FIRMWARE("nvidia/gp107/sec2/sig.bin");
 
 const struct nvkm_acr_lsf_func
 gp102_sec2_acr_1 = {
+	.bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon,
 };
 
 int
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
index e5ba6df3d500..9c00e6634499 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
@@ -5,6 +5,7 @@
 
 struct nvkm_sec2_func {
 	const struct nvkm_falcon_func *flcn;
+	u8 unit_acr;
 	void (*intr)(struct nvkm_sec2 *);
 };
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
index 3e14c7bc3e32..9867a32da42a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
@@ -35,34 +35,6 @@ nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf)
 	queue->func->init_func->gen_cmdline(queue, buf);
 }
 
-int
-nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *queue,
-			       unsigned long falcon_mask)
-{
-	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;
-
-	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
 nvkm_msgqueue_new(u32 version, struct nvkm_falcon *falcon,
 		  const struct nvkm_secboot *sb, struct nvkm_msgqueue **queue)
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
index 65a2a045fae7..bf714f391d42 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
@@ -90,20 +90,8 @@ struct nvkm_msgqueue_init_func {
 	int (*init_callback)(struct nvkm_msgqueue *, struct nvkm_msgqueue_hdr *);
 };
 
-/**
- * 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 {
 	const struct nvkm_msgqueue_init_func *init_func;
-	const struct nvkm_msgqueue_acr_func *acr_func;
 	void (*dtor)(struct nvkm_msgqueue *);
 	void (*recv)(struct nvkm_msgqueue *queue);
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c
index b8c0fcdff156..7e450a91c62e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c
@@ -147,8 +147,6 @@ msgqueue_0137c63d_init_func = {
 
 enum {
 	ACR_CMD_INIT_WPR_REGION = 0x00,
-	ACR_CMD_BOOTSTRAP_FALCON = 0x01,
-	ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS = 0x03,
 };
 
 static int
@@ -198,144 +196,6 @@ acr_init_wpr(struct nvkm_msgqueue *queue)
 				     pmu, 0);
 }
 
-
-static int
-acr_boot_falcon_callback(void *priv, struct nv_falcon_msg *hdr)
-{
-	struct acr_bootstrap_falcon_msg {
-		struct nv_falcon_msg base;
-		u8 msg_type;
-		u32 falcon_id;
-	} *msg = (void *)hdr;
-	struct nvkm_subdev *subdev = priv;
-	u32 falcon_id = msg->falcon_id;
-
-	if (falcon_id >= NVKM_SECBOOT_FALCON_END) {
-		nvkm_error(subdev, "in bootstrap falcon callback:\n");
-		nvkm_error(subdev, "invalid falcon ID 0x%x\n", falcon_id);
-		return -EINVAL;
-	}
-
-	nvkm_debug(subdev, "%s booted\n", nvkm_secboot_falcon_name[falcon_id]);
-	return 0;
-}
-
-enum {
-	ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES = 0,
-	ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO = 1,
-};
-
-static int
-acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon)
-{
-	struct nvkm_pmu *pmu = priv->falcon->owner->device->pmu;
-	/*
-	 * flags      - Flag specifying RESET or no RESET.
-	 * falcon id  - Falcon id specifying falcon to bootstrap.
-	 */
-	struct {
-		struct nv_falcon_cmd hdr;
-		u8 cmd_type;
-		u32 flags;
-		u32 falcon_id;
-	} cmd;
-
-	if (!wait_for_completion_timeout(&pmu->wpr_ready,
-					 msecs_to_jiffies(1000))) {
-		nvkm_error(&pmu->subdev, "timeout waiting for WPR init\n");
-		return -ETIMEDOUT;
-	}
-
-	memset(&cmd, 0, sizeof(cmd));
-
-	cmd.hdr.unit_id = MSGQUEUE_0137C63D_UNIT_ACR;
-	cmd.hdr.size = sizeof(cmd);
-	cmd.cmd_type = ACR_CMD_BOOTSTRAP_FALCON;
-	cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
-	cmd.falcon_id = falcon;
-	return nvkm_falcon_cmdq_send(pmu->hpq, &cmd.hdr,
-				     acr_boot_falcon_callback, &pmu->subdev,
-				     msecs_to_jiffies(1000));
-}
-
-static int
-acr_boot_multiple_falcons_callback(void *priv, struct nv_falcon_msg *hdr)
-{
-	struct acr_bootstrap_falcon_msg {
-		struct nv_falcon_msg base;
-		u8 msg_type;
-		u32 falcon_mask;
-	} *msg = (void *)hdr;
-	const struct nvkm_subdev *subdev = priv;
-	unsigned long falcon_mask = msg->falcon_mask;
-	u32 falcon_id, falcon_treated = 0;
-
-	for_each_set_bit(falcon_id, &falcon_mask, NVKM_SECBOOT_FALCON_END) {
-		nvkm_debug(subdev, "%s booted\n",
-			   nvkm_secboot_falcon_name[falcon_id]);
-		falcon_treated |= BIT(falcon_id);
-	}
-
-	if (falcon_treated != msg->falcon_mask) {
-		nvkm_error(subdev, "in bootstrap falcon callback:\n");
-		nvkm_error(subdev, "invalid falcon mask 0x%x\n",
-			   msg->falcon_mask);
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int
-acr_boot_multiple_falcons(struct nvkm_msgqueue *priv, unsigned long falcon_mask)
-{
-	struct nvkm_pmu *pmu = priv->falcon->owner->device->pmu;
-	/*
-	 * flags      - Flag specifying RESET or no RESET.
-	 * falcon id  - Falcon id specifying falcon to bootstrap.
-	 */
-	struct {
-		struct nv_falcon_cmd hdr;
-		u8 cmd_type;
-		u32 flags;
-		u32 falcon_mask;
-		u32 use_va_mask;
-		u32 wpr_lo;
-		u32 wpr_hi;
-	} cmd;
-	struct msgqueue_0137bca5 *queue = msgqueue_0137bca5(priv);
-
-	if (!wait_for_completion_timeout(&pmu->wpr_ready,
-					 msecs_to_jiffies(1000))) {
-		nvkm_error(&pmu->subdev, "timeout waiting for WPR init\n");
-		return -ETIMEDOUT;
-	}
-
-	memset(&cmd, 0, sizeof(cmd));
-
-	cmd.hdr.unit_id = MSGQUEUE_0137C63D_UNIT_ACR;
-	cmd.hdr.size = sizeof(cmd);
-	cmd.cmd_type = ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS;
-	cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
-	cmd.falcon_mask = falcon_mask;
-	cmd.wpr_lo = lower_32_bits(queue->wpr_addr);
-	cmd.wpr_hi = upper_32_bits(queue->wpr_addr);
-	return nvkm_falcon_cmdq_send(pmu->hpq, &cmd.hdr,
-				     acr_boot_multiple_falcons_callback,
-				     &pmu->subdev, msecs_to_jiffies(1000));
-}
-
-static const struct nvkm_msgqueue_acr_func
-msgqueue_0137c63d_acr_func = {
-	.boot_falcon = acr_boot_falcon,
-};
-
-static const struct nvkm_msgqueue_acr_func
-msgqueue_0137bca5_acr_func = {
-	.boot_falcon = acr_boot_falcon,
-	.boot_multiple_falcons = acr_boot_multiple_falcons,
-};
-
 static void
 msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue)
 {
@@ -345,7 +205,6 @@ msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue)
 static const struct nvkm_msgqueue_func
 msgqueue_0137c63d_func = {
 	.init_func = &msgqueue_0137c63d_init_func,
-	.acr_func = &msgqueue_0137c63d_acr_func,
 	.recv = msgqueue_0137c63d_process_msgs,
 	.dtor = msgqueue_0137c63d_dtor,
 };
@@ -370,7 +229,6 @@ msgqueue_0137c63d_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb,
 static const struct nvkm_msgqueue_func
 msgqueue_0137bca5_func = {
 	.init_func = &msgqueue_0137c63d_init_func,
-	.acr_func = &msgqueue_0137bca5_acr_func,
 	.recv = msgqueue_0137c63d_process_msgs,
 	.dtor = msgqueue_0137c63d_dtor,
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c
index 2826822cd0fc..51ae4a10b213 100644
--- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c
+++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c
@@ -130,81 +130,6 @@ msgqueue_0148cdec_init_func = {
 };
 
 
-
-/* ACR unit */
-#define MSGQUEUE_0148CDEC_UNIT_ACR 0x08
-
-enum {
-	ACR_CMD_BOOTSTRAP_FALCON = 0x00,
-};
-
-static int
-acr_boot_falcon_callback(void *priv, struct nv_falcon_msg *hdr)
-{
-	struct acr_bootstrap_falcon_msg {
-		struct nv_falcon_msg base;
-		u8 msg_type;
-		u32 error_code;
-		u32 falcon_id;
-	} *msg = (void *)hdr;
-	const struct nvkm_subdev *subdev = priv;
-	u32 falcon_id = msg->falcon_id;
-
-	if (msg->error_code) {
-		nvkm_error(subdev, "in bootstrap falcon callback:\n");
-		nvkm_error(subdev, "expected error code 0x%x\n",
-			   msg->error_code);
-		return -EINVAL;
-	}
-
-	if (falcon_id >= NVKM_SECBOOT_FALCON_END) {
-		nvkm_error(subdev, "in bootstrap falcon callback:\n");
-		nvkm_error(subdev, "invalid falcon ID 0x%x\n", falcon_id);
-		return -EINVAL;
-	}
-
-	nvkm_debug(subdev, "%s booted\n", nvkm_secboot_falcon_name[falcon_id]);
-	return 0;
-}
-
-enum {
-	ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES = 0,
-	ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO = 1,
-};
-
-static int
-acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon)
-{
-	struct nvkm_sec2 *sec2 = priv->falcon->owner->device->sec2;
-	/*
-	 * flags      - Flag specifying RESET or no RESET.
-	 * falcon id  - Falcon id specifying falcon to bootstrap.
-	 */
-	struct {
-		struct nv_falcon_cmd hdr;
-		u8 cmd_type;
-		u32 flags;
-		u32 falcon_id;
-	} cmd;
-
-	memset(&cmd, 0, sizeof(cmd));
-
-	cmd.hdr.unit_id = MSGQUEUE_0148CDEC_UNIT_ACR;
-	cmd.hdr.size = sizeof(cmd);
-	cmd.cmd_type = ACR_CMD_BOOTSTRAP_FALCON;
-	cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
-	cmd.falcon_id = falcon;
-	return nvkm_falcon_cmdq_send(sec2->cmdq, &cmd.hdr,
-				     acr_boot_falcon_callback,
-				     &sec2->engine.subdev,
-				     msecs_to_jiffies(1000));
-}
-
-const struct nvkm_msgqueue_acr_func
-msgqueue_0148cdec_acr_func = {
-	.boot_falcon = acr_boot_falcon,
-};
-
 static void
 msgqueue_0148cdec_dtor(struct nvkm_msgqueue *queue)
 {
@@ -214,7 +139,6 @@ msgqueue_0148cdec_dtor(struct nvkm_msgqueue *queue)
 const struct nvkm_msgqueue_func
 msgqueue_0148cdec_func = {
 	.init_func = &msgqueue_0148cdec_init_func,
-	.acr_func = &msgqueue_0148cdec_acr_func,
 	.recv = msgqueue_0148cdec_process_msgs,
 	.dtor = msgqueue_0148cdec_dtor,
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
index 11658a4afc7a..6caced3589bc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
@@ -23,19 +23,90 @@
 
 #include <core/firmware.h>
 
+static struct nvkm_acr_lsf *
+nvkm_acr_falcon(struct nvkm_device *device)
+{
+	struct nvkm_acr *acr = device->acr;
+	struct nvkm_acr_lsf *lsf;
+
+	if (acr) {
+		list_for_each_entry(lsf, &acr->lsf, head) {
+			if (lsf->func->bootstrap_falcon)
+				return lsf;
+		}
+	}
+
+	return NULL;
+}
+
+int
+nvkm_acr_bootstrap_falcons(struct nvkm_device *device, unsigned long mask)
+{
+	struct nvkm_acr_lsf *acrflcn = nvkm_acr_falcon(device);
+	unsigned long id;
+
+	if (!acrflcn)
+		return -ENOSYS;
+
+	if (acrflcn->func->bootstrap_multiple_falcons) {
+		return acrflcn->func->
+			bootstrap_multiple_falcons(acrflcn->falcon, mask);
+	}
+
+	for_each_set_bit(id, &mask, NVKM_ACR_LSF_NUM) {
+		int ret = acrflcn->func->bootstrap_falcon(acrflcn->falcon, id);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void
+nvkm_acr_cleanup(struct nvkm_acr *acr)
+{
+	nvkm_acr_lsfw_del_all(acr);
+}
+
+static int
+nvkm_acr_oneinit(struct nvkm_subdev *subdev)
+{
+	struct nvkm_acr *acr = nvkm_acr(subdev);
+	struct nvkm_acr_lsfw *lsfw;
+	struct nvkm_acr_lsf *lsf;
+
+	list_for_each_entry(lsfw, &acr->lsfw, head) {
+		if (!(lsf = kmalloc(sizeof(*lsf), GFP_KERNEL)))
+			return -ENOMEM;
+		lsf->func = lsfw->func;
+		lsf->falcon = lsfw->falcon;
+		lsf->id = lsfw->id;
+		list_add_tail(&lsf->head, &acr->lsf);
+	}
+
+	nvkm_acr_cleanup(acr);
+	return 0;
+}
+
 static void *
 nvkm_acr_dtor(struct nvkm_subdev *subdev)
 {
 	struct nvkm_acr *acr = nvkm_acr(subdev);
+	struct nvkm_acr_lsf *lsf, *lst;
 
-	nvkm_acr_lsfw_del_all(acr);
+	list_for_each_entry_safe(lsf, lst, &acr->lsf, head) {
+		list_del(&lsf->head);
+		kfree(lsf);
+	}
 
+	nvkm_acr_cleanup(acr);
 	return acr;
 }
 
 static const struct nvkm_subdev_func
 nvkm_acr = {
 	.dtor = nvkm_acr_dtor,
+	.oneinit = nvkm_acr_oneinit,
 };
 
 int
@@ -48,6 +119,7 @@ nvkm_acr_new_(const struct nvkm_acr_fwif *fwif, struct nvkm_device *device,
 		return -ENOMEM;
 	nvkm_subdev_ctor(&nvkm_acr, device, index, &acr->subdev);
 	INIT_LIST_HEAD(&acr->lsfw);
+	INIT_LIST_HEAD(&acr->lsf);
 
 	fwif = nvkm_firmware_load(&acr->subdev, fwif, "Acr", acr);
 	if (IS_ERR(fwif))
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h
index 882290423c01..808ba7f191b4 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/priv.h
@@ -18,6 +18,13 @@ struct nvkm_acr_func {
 int nvkm_acr_new_(const struct nvkm_acr_fwif *, struct nvkm_device *, int,
 		  struct nvkm_acr **);
 
+struct nvkm_acr_lsf {
+	const struct nvkm_acr_lsf_func *func;
+	struct nvkm_falcon *falcon;
+	enum nvkm_acr_lsf_id id;
+	struct list_head head;
+};
+
 struct nvkm_acr_lsfw *nvkm_acr_lsfw_add(const struct nvkm_acr_lsf_func *,
 					struct nvkm_acr *, struct nvkm_falcon *,
 					enum nvkm_acr_lsf_id);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
index 5c262a28aa23..e803cc461227 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
@@ -20,11 +20,45 @@
  * DEALINGS IN THE SOFTWARE.
  */
 #include "priv.h"
+
 #include <core/msgqueue.h>
 #include <subdev/acr.h>
 
+#include <nvfw/pmu.h>
+
+static int
+gm20b_pmu_acr_bootstrap_falcon_cb(void *priv, struct nv_falcon_msg *hdr)
+{
+	struct nv_pmu_acr_bootstrap_falcon_msg *msg =
+		container_of(hdr, typeof(*msg), msg.hdr);
+	return msg->falcon_id;
+}
+
+int
+gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *falcon,
+			       enum nvkm_acr_lsf_id id)
+{
+	struct nvkm_pmu *pmu = container_of(falcon, typeof(*pmu), falcon);
+	struct nv_pmu_acr_bootstrap_falcon_cmd cmd = {
+		.cmd.hdr.unit_id = NV_PMU_UNIT_ACR,
+		.cmd.hdr.size = sizeof(cmd),
+		.cmd.cmd_type = NV_PMU_ACR_CMD_BOOTSTRAP_FALCON,
+		.flags = NV_PMU_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES,
+		.falcon_id = id,
+	};
+	int ret;
+
+	ret = nvkm_falcon_cmdq_send(pmu->hpq, &cmd.cmd.hdr,
+				    gm20b_pmu_acr_bootstrap_falcon_cb,
+				    &pmu->subdev, msecs_to_jiffies(1000));
+	if (ret >= 0 && ret != cmd.falcon_id)
+		ret = -EIO;
+	return ret;
+}
+
 static const struct nvkm_acr_lsf_func
 gm20b_pmu_acr = {
+	.bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon,
 };
 
 void
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
index 7134ef9d91af..b2baf9b636a3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
@@ -20,10 +20,46 @@
  * DEALINGS IN THE SOFTWARE.
  */
 #include "priv.h"
+
 #include <subdev/acr.h>
 
+#include <nvfw/pmu.h>
+
+static int
+gp10b_pmu_acr_bootstrap_multiple_falcons_cb(void *priv,
+					    struct nv_falcon_msg *hdr)
+{
+	struct nv_pmu_acr_bootstrap_multiple_falcons_msg *msg =
+		container_of(hdr, typeof(*msg), msg.hdr);
+	return msg->falcon_mask;
+}
+static int
+gp10b_pmu_acr_bootstrap_multiple_falcons(struct nvkm_falcon *falcon, u32 mask)
+{
+	struct nvkm_pmu *pmu = container_of(falcon, typeof(*pmu), falcon);
+	struct nv_pmu_acr_bootstrap_multiple_falcons_cmd cmd = {
+		.cmd.hdr.unit_id = NV_PMU_UNIT_ACR,
+		.cmd.hdr.size = sizeof(cmd),
+		.cmd.cmd_type = NV_PMU_ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS,
+		.flags = NV_PMU_ACR_BOOTSTRAP_MULTIPLE_FALCONS_FLAGS_RESET_YES,
+		.falcon_mask = mask,
+		.wpr_lo = 0, /*XXX*/
+		.wpr_hi = 0, /*XXX*/
+	};
+	int ret;
+
+	ret = nvkm_falcon_cmdq_send(pmu->hpq, &cmd.cmd.hdr,
+				    gp10b_pmu_acr_bootstrap_multiple_falcons_cb,
+				    &pmu->subdev, msecs_to_jiffies(1000));
+	if (ret >= 0 && ret != cmd.falcon_mask)
+		ret = -EIO;
+	return ret;
+}
+
 static const struct nvkm_acr_lsf_func
 gp10b_pmu_acr = {
+	.bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon,
+	.bootstrap_multiple_falcons = gp10b_pmu_acr_bootstrap_multiple_falcons,
 };
 
 static const struct nvkm_pmu_func
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
index 91b4a2d3ad4c..0e7965028dcf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
@@ -4,6 +4,7 @@
 #define nvkm_pmu(p) container_of((p), struct nvkm_pmu, subdev)
 #include <subdev/pmu.h>
 #include <subdev/pmu/fuc/os.h>
+enum nvkm_acr_lsf_id;
 
 struct nvkm_pmu_func {
 	const struct nvkm_falcon_func *flcn;
@@ -41,6 +42,7 @@ void gf100_pmu_reset(struct nvkm_pmu *);
 
 void gk110_pmu_pgob(struct nvkm_pmu *, bool);
 
+int gm20b_pmu_acr_bootstrap_falcon(struct nvkm_falcon *, enum nvkm_acr_lsf_id);
 void gm20b_pmu_recv(struct nvkm_pmu *);
 
 struct nvkm_pmu_fwif {
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
index 53770ecdbb2f..dcb6eb24ba6a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
@@ -991,12 +991,13 @@ acr_r352_reset_nopmu(struct acr_r352 *acr, struct nvkm_secboot *sb,
  * load the HS firmware and run it, so once the falcon stops all the managed
  * falcons should have their LS firmware loaded and be ready to run.
  */
+int nvkm_acr_bootstrap_falcons(struct nvkm_device *, unsigned long);
+
 static int
 acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
 	       unsigned long falcon_mask)
 {
 	struct acr_r352 *acr = acr_r352(_acr);
-	struct nvkm_msgqueue *queue;
 	int falcon;
 	bool wpr_already_set = sb->wpr_set;
 	int ret;
@@ -1016,22 +1017,12 @@ acr_r352_reset(struct nvkm_acr *_acr, struct nvkm_secboot *sb,
 			return ret;
 	}
 
-	switch (_acr->boot_falcon) {
-	case NVKM_SECBOOT_FALCON_PMU:
-		queue = sb->subdev.device->pmu->queue;
-		break;
-	case NVKM_SECBOOT_FALCON_SEC2:
-		queue = sb->subdev.device->sec2->queue;
-		break;
-	default:
-		return -EINVAL;
-	}
-
 	/* Otherwise just ask the LS firmware to reset the 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);
+
+	ret = nvkm_acr_bootstrap_falcons(sb->subdev.device, falcon_mask);
 	if (ret) {
 		nvkm_error(&sb->subdev, "error during falcon reset: %d\n", ret);
 		return ret;
-- 
2.28.0