diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c index f7101a910bc7..d45d7947a964 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c @@ -501,6 +501,9 @@ nvkm_msgqueue_new(u32 version, struct nvkm_falcon *falcon, case 0x0137c63d: ret = msgqueue_0137c63d_new(falcon, sb, queue); break; + case 0x0137bca5: + ret = msgqueue_0137bca5_new(falcon, sb, queue); + break; case 0x0148cdec: ret = msgqueue_0148cdec_new(falcon, sb, queue); break; diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h index 2b3a6c3b8f6a..13b54f8d8e04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h @@ -205,6 +205,8 @@ void nvkm_msgqueue_process_msgs(struct nvkm_msgqueue *, int msgqueue_0137c63d_new(struct nvkm_falcon *, const struct nvkm_secboot *, struct nvkm_msgqueue **); +int msgqueue_0137bca5_new(struct nvkm_falcon *, const struct nvkm_secboot *, + struct nvkm_msgqueue **); int msgqueue_0148cdec_new(struct nvkm_falcon *, const struct nvkm_secboot *, struct nvkm_msgqueue **); diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c index 935b9a7e60a9..fec0273158f6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c @@ -43,6 +43,15 @@ struct msgqueue_0137c63d { #define msgqueue_0137c63d(q) \ container_of(q, struct msgqueue_0137c63d, base) +struct msgqueue_0137bca5 { + struct msgqueue_0137c63d base; + + u64 wpr_addr; +}; +#define msgqueue_0137bca5(q) \ + container_of(container_of(q, struct msgqueue_0137c63d, base), \ + struct msgqueue_0137bca5, base); + static struct nvkm_msgqueue_queue * msgqueue_0137c63d_cmd_queue(struct nvkm_msgqueue *queue, enum msgqueue_msg_priority priority) @@ -180,6 +189,7 @@ msgqueue_0137c63d_init_func = { enum { ACR_CMD_INIT_WPR_REGION = 0x00, ACR_CMD_BOOTSTRAP_FALCON = 0x01, + ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS = 0x03, }; static void @@ -286,11 +296,81 @@ acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon) return 0; } +static void +acr_boot_multiple_falcons_callback(struct nvkm_msgqueue *priv, + struct nvkm_msgqueue_hdr *hdr) +{ + struct acr_bootstrap_falcon_msg { + struct nvkm_msgqueue_msg base; + + u32 falcon_mask; + } *msg = (void *)hdr; + const struct nvkm_subdev *subdev = priv->falcon->owner; + 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; + } +} + +static int +acr_boot_multiple_falcons(struct nvkm_msgqueue *priv, unsigned long falcon_mask) +{ + DECLARE_COMPLETION_ONSTACK(completed); + /* + * flags - Flag specifying RESET or no RESET. + * falcon id - Falcon id specifying falcon to bootstrap. + */ + struct { + struct nvkm_msgqueue_hdr 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); + + 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); + nvkm_msgqueue_post(priv, MSGQUEUE_MSG_PRIORITY_HIGH, &cmd.hdr, + acr_boot_multiple_falcons_callback, &completed, true); + + if (!wait_for_completion_timeout(&completed, msecs_to_jiffies(1000))) + return -ETIMEDOUT; + + return 0; +} + 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) { @@ -322,3 +402,35 @@ msgqueue_0137c63d_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb, return 0; } + +static const struct nvkm_msgqueue_func +msgqueue_0137bca5_func = { + .init_func = &msgqueue_0137c63d_init_func, + .acr_func = &msgqueue_0137bca5_acr_func, + .cmd_queue = msgqueue_0137c63d_cmd_queue, + .recv = msgqueue_0137c63d_process_msgs, + .dtor = msgqueue_0137c63d_dtor, +}; + +int +msgqueue_0137bca5_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb, + struct nvkm_msgqueue **queue) +{ + struct msgqueue_0137bca5 *ret; + + ret = kzalloc(sizeof(*ret), GFP_KERNEL); + if (!ret) + return -ENOMEM; + + *queue = &ret->base.base; + + /* + * FIXME this must be set to the address of a *GPU* mapping within the + * ACR address space! + */ + /* ret->wpr_addr = sb->wpr_addr; */ + + nvkm_msgqueue_ctor(&msgqueue_0137bca5_func, falcon, &ret->base.base); + + return 0; +}