From: Ben Skeggs Date: Tue, 14 Jan 2020 20:34:22 +0000 (+1000) Subject: drm/nouveau/flcn/cmdq: move command generation to subdevs X-Git-Tag: v5.6-rc1~114^2~8^2~15 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=86ce2a71539c47241dc8f471d8724f5bd1e41ae6;p=linux.git drm/nouveau/flcn/cmdq: move command generation to subdevs 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 --- 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 #include +#include + +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 +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 #include +#include + +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 +#include + +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 #include +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;