diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2020-01-15 06:34:22 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2020-01-15 10:50:29 +1000 |
commit | d114a1393fa01c4034d895072905578319a903f9 (patch) | |
tree | b919222d6234608a07eab974b156945a0cc65ba1 | |
parent | 2d063981d710391cdea4e8c6483d94b519b1cde2 (diff) |
drm/nouveau/flcn/msgq: move handling of init message to subdevs
When the PMU/SEC2 LS FWs have booted, they'll send a message to the host
with various information, including the configuration of message/command
queues that are available.
Move the handling for this to the relevant subdevs.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
19 files changed, 202 insertions, 265 deletions
diff --git a/drivers/gpu/drm/nouveau/include/nvfw/pmu.h b/drivers/gpu/drm/nouveau/include/nvfw/pmu.h index 6e86ce31f963..f808998e2ea1 100644 --- a/drivers/gpu/drm/nouveau/include/nvfw/pmu.h +++ b/drivers/gpu/drm/nouveau/include/nvfw/pmu.h @@ -1,8 +1,28 @@ #ifndef __NVFW_PMU_H__ #define __NVFW_PMU_H__ +#define NV_PMU_UNIT_INIT 0x07 #define NV_PMU_UNIT_ACR 0x0a +struct nv_pmu_init_msg { + struct nv_falcon_msg hdr; +#define NV_PMU_INIT_MSG_INIT 0x00 + u8 msg_type; + + u8 pad; + u16 os_debug_entry_point; + + struct { + u16 size; + u16 offset; + u8 index; + u8 pad; + } queue_info[5]; + + u16 sw_managed_area_offset; + u16 sw_managed_area_size; +}; + struct nv_pmu_acr_cmd { struct nv_falcon_cmd hdr; #define NV_PMU_ACR_CMD_INIT_WPR_REGION 0x00 @@ -16,6 +36,17 @@ struct nv_pmu_acr_msg { u8 msg_type; }; +struct nv_pmu_acr_init_wpr_region_cmd { + struct nv_pmu_acr_cmd cmd; + u32 region_id; + u32 wpr_offset; +}; + +struct nv_pmu_acr_init_wpr_region_msg { + struct nv_pmu_acr_msg msg; + u32 error_code; +}; + struct nv_pmu_acr_bootstrap_falcon_cmd { struct nv_pmu_acr_cmd cmd; #define NV_PMU_ACR_BOOTSTRAP_FALCON_FLAGS_RESET_YES 0x00000000 diff --git a/drivers/gpu/drm/nouveau/include/nvfw/sec2.h b/drivers/gpu/drm/nouveau/include/nvfw/sec2.h index 2f7460fe1b76..80753cfa4cb3 100644 --- a/drivers/gpu/drm/nouveau/include/nvfw/sec2.h +++ b/drivers/gpu/drm/nouveau/include/nvfw/sec2.h @@ -1,8 +1,30 @@ #ifndef __NVFW_SEC2_H__ #define __NVFW_SEC2_H__ +#define NV_SEC2_UNIT_INIT 0x01 #define NV_SEC2_UNIT_ACR 0x08 +struct nv_sec2_init_msg { + struct nv_falcon_msg hdr; +#define NV_SEC2_INIT_MSG_INIT 0x00 + u8 msg_type; + + u8 num_queues; + u16 os_debug_entry_point; + + struct { + u32 offset; + u16 size; + u8 index; +#define NV_SEC2_INIT_MSG_QUEUE_ID_CMDQ 0x00 +#define NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ 0x01 + u8 id; + } queue_info[2]; + + u32 sw_managed_area_offset; + u16 sw_managed_area_size; +}; + struct nv_sec2_acr_cmd { struct nv_falcon_cmd hdr; #define NV_SEC2_ACR_CMD_BOOTSTRAP_FALCON 0x00 diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h index 54e1f4d7568f..a37d2008406b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h @@ -72,4 +72,5 @@ int nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *, const char *name, void nvkm_falcon_msgq_del(struct nvkm_falcon_msgq **); void nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *, u32 index, u32 offset, u32 size); +int nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *, void *, u32 size); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h b/drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h index acb339f34bb5..19f2fdb3e754 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h @@ -32,7 +32,6 @@ int nvkm_msgqueue_new(u32, struct nvkm_falcon *, const struct nvkm_secboot *, struct nvkm_msgqueue **); void nvkm_msgqueue_del(struct nvkm_msgqueue **); void nvkm_msgqueue_recv(struct nvkm_msgqueue *); -int nvkm_msgqueue_reinit(struct nvkm_msgqueue *); /* useful if we run a NVIDIA-signed firmware */ void nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *, void *); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h index ca1b227a81f9..44da8d3ac86e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h @@ -14,7 +14,9 @@ struct nvkm_sec2 { struct nvkm_falcon_cmdq *cmdq; struct nvkm_falcon_msgq *msgq; struct nvkm_msgqueue *queue; + struct work_struct work; + bool initmsg_received; }; int gp102_sec2_new(struct nvkm_device *, int, struct nvkm_sec2 **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h index 21607b40aee6..79351a74642e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h @@ -13,6 +13,7 @@ struct nvkm_pmu { struct nvkm_falcon_cmdq *hpq; struct nvkm_falcon_cmdq *lpq; struct nvkm_falcon_msgq *msgq; + bool initmsg_received; struct nvkm_msgqueue *queue; struct completion wpr_ready; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c index d85aeb059c87..f6a453dc75ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c @@ -30,6 +30,17 @@ nvkm_sec2_recv(struct work_struct *work) { struct nvkm_sec2 *sec2 = container_of(work, typeof(*sec2), work); + if (!sec2->initmsg_received) { + int ret = sec2->func->initmsg(sec2); + if (ret) { + nvkm_error(&sec2->engine.subdev, + "error parsing init message: %d\n", ret); + return; + } + + sec2->initmsg_received = true; + } + if (!sec2->queue) { nvkm_warn(&sec2->engine.subdev, "recv function called while no firmware set!\n"); @@ -50,8 +61,14 @@ static int nvkm_sec2_fini(struct nvkm_engine *engine, bool suspend) { struct nvkm_sec2 *sec2 = nvkm_sec2(engine); + flush_work(&sec2->work); - nvkm_falcon_cmdq_fini(sec2->cmdq); + + if (suspend) { + nvkm_falcon_cmdq_fini(sec2->cmdq); + sec2->initmsg_received = false; + } + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c index 26f738d1202e..26a468047747 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c @@ -69,6 +69,37 @@ gp102_sec2_acr_0 = { .bootstrap_falcon = gp102_sec2_acr_bootstrap_falcon, }; +int +gp102_sec2_initmsg(struct nvkm_sec2 *sec2) +{ + struct nv_sec2_init_msg msg; + int ret, i; + + ret = nvkm_falcon_msgq_recv_initmsg(sec2->msgq, &msg, sizeof(msg)); + if (ret) + return ret; + + if (msg.hdr.unit_id != NV_SEC2_UNIT_INIT || + msg.msg_type != NV_SEC2_INIT_MSG_INIT) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(msg.queue_info); i++) { + if (msg.queue_info[i].id == NV_SEC2_INIT_MSG_QUEUE_ID_MSGQ) { + nvkm_falcon_msgq_init(sec2->msgq, + msg.queue_info[i].index, + msg.queue_info[i].offset, + msg.queue_info[i].size); + } else { + nvkm_falcon_cmdq_init(sec2->cmdq, + msg.queue_info[i].index, + msg.queue_info[i].offset, + msg.queue_info[i].size); + } + } + + return 0; +} + void gp102_sec2_intr(struct nvkm_sec2 *sec2) { @@ -161,6 +192,7 @@ gp102_sec2 = { .flcn = &gp102_sec2_flcn, .unit_acr = NV_SEC2_UNIT_ACR, .intr = gp102_sec2_intr, + .initmsg = gp102_sec2_initmsg, }; MODULE_FIRMWARE("nvidia/gp102/sec2/desc.bin"); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h index 9c00e6634499..1992391832a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h @@ -7,6 +7,7 @@ struct nvkm_sec2_func { const struct nvkm_falcon_func *flcn; u8 unit_acr; void (*intr)(struct nvkm_sec2 *); + int (*initmsg)(struct nvkm_sec2 *); }; void gp102_sec2_intr(struct nvkm_sec2 *); diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c index 1c7dab86af80..b906534fc7fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c @@ -136,40 +136,27 @@ msgqueue_msg_handle(struct nvkm_falcon_msgq *msgq, struct nv_falcon_msg *hdr) return 0; } -static int -msgqueue_handle_init_msg(struct nvkm_msgqueue *priv) +int +nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *msgq, + void *data, u32 size) { - struct nvkm_falcon *falcon = priv->falcon; - const struct nvkm_subdev *subdev = falcon->owner; - const u32 tail_reg = falcon->func->msgq.tail; - u8 msg_buffer[MSG_BUF_SIZE]; - struct nvkm_msgqueue_hdr *hdr = (void *)msg_buffer; - u32 tail; + struct nvkm_falcon *falcon = msgq->qmgr->falcon; + struct nv_falcon_msg *hdr = data; int ret; - /* - * Read the message - queues are not initialized yet so we cannot rely - * on msg_queue_read() - */ - tail = nvkm_falcon_rd32(falcon, tail_reg); - nvkm_falcon_read_dmem(falcon, tail, HDR_SIZE, 0, hdr); + msgq->head_reg = falcon->func->msgq.head; + msgq->tail_reg = falcon->func->msgq.tail; + msgq->offset = nvkm_falcon_rd32(falcon, falcon->func->msgq.tail); - if (hdr->size > MSG_BUF_SIZE) { - nvkm_error(subdev, "message too big (%d bytes)\n", hdr->size); - return -ENOSPC; + msg_queue_open(msgq); + ret = msg_queue_pop(msgq, data, size); + if (ret == 0 && hdr->size != size) { + FLCN_ERR(falcon, "unexpected init message size %d vs %d", + hdr->size, size); + ret = -EINVAL; } - - nvkm_falcon_read_dmem(falcon, tail + HDR_SIZE, hdr->size - HDR_SIZE, 0, - (hdr + 1)); - - tail += ALIGN(hdr->size, QUEUE_ALIGNMENT); - nvkm_falcon_wr32(falcon, tail_reg, tail); - - ret = priv->func->init_func->init_callback(priv, hdr); - if (ret) - return ret; - - return 0; + msg_queue_close(msgq, ret == 0); + return ret; } void @@ -182,17 +169,9 @@ nvkm_msgqueue_process_msgs(struct nvkm_msgqueue *priv, */ u8 msg_buffer[MSG_BUF_SIZE]; struct nv_falcon_msg *hdr = (void *)msg_buffer; - int ret; - /* the first message we receive must be the init message */ - if ((!priv->init_msg_received)) { - ret = msgqueue_handle_init_msg(priv); - if (!ret) - priv->init_msg_received = true; - } else { - while (msg_queue_read(queue, hdr) > 0) - msgqueue_msg_handle(queue, hdr); - } + while (msg_queue_read(queue, hdr) > 0) + msgqueue_msg_handle(queue, hdr); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c index 9867a32da42a..46e88937c453 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c @@ -90,17 +90,6 @@ nvkm_msgqueue_recv(struct nvkm_msgqueue *queue) queue->func->recv(queue); } -int -nvkm_msgqueue_reinit(struct nvkm_msgqueue *queue) -{ - /* firmware not set yet... */ - if (!queue) - return 0; - - queue->init_msg_received = false; - return 0; -} - void nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *func, struct nvkm_falcon *falcon, diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h index bf714f391d42..1c4780a7856a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h @@ -52,31 +52,6 @@ * */ -/** - * struct nvkm_msgqueue_hdr - header for all commands/messages - * @unit_id: id of firmware using receiving the command/sending the message - * @size: total size of command/message - * @ctrl_flags: type of command/message - * @seq_id: used to match a message from its corresponding command - */ -struct nvkm_msgqueue_hdr { - u8 unit_id; - u8 size; - u8 ctrl_flags; - u8 seq_id; -}; - -/** - * struct nvkm_msgqueue_msg - base message. - * - * This is just a header and a message (or command) type. Useful when - * building command-specific structures. - */ -struct nvkm_msgqueue_msg { - struct nvkm_msgqueue_hdr hdr; - u8 msg_type; -}; - struct nvkm_msgqueue; /** @@ -87,7 +62,6 @@ struct nvkm_msgqueue; */ struct nvkm_msgqueue_init_func { void (*gen_cmdline)(struct nvkm_msgqueue *, void *); - int (*init_callback)(struct nvkm_msgqueue *, struct nvkm_msgqueue_hdr *); }; struct nvkm_msgqueue_func { @@ -136,7 +110,6 @@ struct nvkm_msgqueue { struct nvkm_falcon *falcon; const struct nvkm_msgqueue_func *func; u32 fw_version; - bool init_msg_received; }; void nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *, struct nvkm_falcon *, diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c index 7e450a91c62e..f624f9cd9098 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c @@ -25,11 +25,6 @@ #include <subdev/pmu.h> #include <subdev/secboot.h> -/* Queues identifiers */ -enum { - MSGQUEUE_0137C63D_NUM_QUEUES = 5, -}; - struct msgqueue_0137c63d { struct nvkm_msgqueue base; }; @@ -52,12 +47,6 @@ msgqueue_0137c63d_process_msgs(struct nvkm_msgqueue *queue) } /* Init unit */ -#define MSGQUEUE_0137C63D_UNIT_INIT 0x07 - -enum { - INIT_MSG_INIT = 0x0, -}; - static void init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf) { @@ -84,118 +73,11 @@ init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf) args->secure_mode = 1; } -/* forward declaration */ -static int acr_init_wpr(struct nvkm_msgqueue *queue); - -static int -init_callback(struct nvkm_msgqueue *_queue, struct nvkm_msgqueue_hdr *hdr) -{ - struct msgqueue_0137c63d *priv = msgqueue_0137c63d(_queue); - struct { - struct nvkm_msgqueue_msg base; - - u8 pad; - u16 os_debug_entry_point; - - struct { - u16 size; - u16 offset; - u8 index; - u8 pad; - } queue_info[MSGQUEUE_0137C63D_NUM_QUEUES]; - - u16 sw_managed_area_offset; - u16 sw_managed_area_size; - } *init = (void *)hdr; - const struct nvkm_subdev *subdev = _queue->falcon->owner; - struct nvkm_pmu *pmu = subdev->device->pmu; - - if (init->base.hdr.unit_id != MSGQUEUE_0137C63D_UNIT_INIT) { - nvkm_error(subdev, "expected message from init unit\n"); - return -EINVAL; - } - - if (init->base.msg_type != INIT_MSG_INIT) { - nvkm_error(subdev, "expected PMU init msg\n"); - return -EINVAL; - } - - nvkm_falcon_cmdq_init(pmu->hpq, init->queue_info[0].index, - init->queue_info[0].offset, - init->queue_info[0].size); - nvkm_falcon_cmdq_init(pmu->lpq, init->queue_info[1].index, - init->queue_info[1].offset, - init->queue_info[1].size); - nvkm_falcon_msgq_init(pmu->msgq, init->queue_info[4].index, - init->queue_info[4].offset, - init->queue_info[4].size); - - /* Complete initialization by initializing WPR region */ - return acr_init_wpr(&priv->base); -} - static const struct nvkm_msgqueue_init_func msgqueue_0137c63d_init_func = { .gen_cmdline = init_gen_cmdline, - .init_callback = init_callback, }; - - -/* ACR unit */ -#define MSGQUEUE_0137C63D_UNIT_ACR 0x0a - -enum { - ACR_CMD_INIT_WPR_REGION = 0x00, -}; - -static int -acr_init_wpr_callback(void *priv, struct nv_falcon_msg *hdr) -{ - struct nvkm_pmu *pmu = priv; - struct nvkm_subdev *subdev = &pmu->subdev; - struct { - struct nv_falcon_msg base; - u8 msg_type; - u32 error_code; - } *msg = (void *)hdr; - - if (msg->error_code) { - nvkm_error(subdev, "ACR WPR init failure: %d\n", - msg->error_code); - return -EINVAL; - } - - nvkm_debug(subdev, "ACR WPR init complete\n"); - complete_all(&pmu->wpr_ready); - return 0; -} - -static int -acr_init_wpr(struct nvkm_msgqueue *queue) -{ - struct nvkm_pmu *pmu = queue->falcon->owner->device->pmu; - /* - * region_id: region ID in WPR region - * wpr_offset: offset in WPR region - */ - struct { - struct nv_falcon_cmd hdr; - u8 cmd_type; - u32 region_id; - u32 wpr_offset; - } cmd; - memset(&cmd, 0, sizeof(cmd)); - - cmd.hdr.unit_id = MSGQUEUE_0137C63D_UNIT_ACR; - cmd.hdr.size = sizeof(cmd); - cmd.cmd_type = ACR_CMD_INIT_WPR_REGION; - cmd.region_id = 0x01; - cmd.wpr_offset = 0x00; - return nvkm_falcon_cmdq_send(pmu->hpq, &cmd.hdr, acr_init_wpr_callback, - pmu, 0); -} - static void msgqueue_0137c63d_dtor(struct nvkm_msgqueue *queue) { diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c index 51ae4a10b213..0dc243b0b774 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c @@ -31,12 +31,6 @@ * message queue, and uses a different command line and init message. */ -enum { - MSGQUEUE_0148CDEC_COMMAND_QUEUE = 0, - MSGQUEUE_0148CDEC_MESSAGE_QUEUE = 1, - MSGQUEUE_0148CDEC_NUM_QUEUES, -}; - struct msgqueue_0148cdec { struct nvkm_msgqueue base; }; @@ -50,13 +44,6 @@ msgqueue_0148cdec_process_msgs(struct nvkm_msgqueue *queue) } -/* Init unit */ -#define MSGQUEUE_0148CDEC_UNIT_INIT 0x01 - -enum { - INIT_MSG_INIT = 0x0, -}; - static void init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf) { @@ -71,62 +58,9 @@ init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf) args->secure_mode = false; } -static int -init_callback(struct nvkm_msgqueue *_queue, struct nvkm_msgqueue_hdr *hdr) -{ - struct { - struct nvkm_msgqueue_msg base; - - u8 num_queues; - u16 os_debug_entry_point; - - struct { - u32 offset; - u16 size; - u8 index; - u8 id; - } queue_info[MSGQUEUE_0148CDEC_NUM_QUEUES]; - - u16 sw_managed_area_offset; - u16 sw_managed_area_size; - } *init = (void *)hdr; - const struct nvkm_subdev *subdev = _queue->falcon->owner; - struct nvkm_sec2 *sec2 = subdev->device->sec2; - int i; - - if (init->base.hdr.unit_id != MSGQUEUE_0148CDEC_UNIT_INIT) { - nvkm_error(subdev, "expected message from init unit\n"); - return -EINVAL; - } - - if (init->base.msg_type != INIT_MSG_INIT) { - nvkm_error(subdev, "expected SEC init msg\n"); - return -EINVAL; - } - - for (i = 0; i < MSGQUEUE_0148CDEC_NUM_QUEUES; i++) { - u8 id = init->queue_info[i].id; - - if (id == MSGQUEUE_0148CDEC_MESSAGE_QUEUE) { - nvkm_falcon_msgq_init(sec2->msgq, - init->queue_info[i].index, - init->queue_info[i].offset, - init->queue_info[i].size); - } else { - nvkm_falcon_cmdq_init(sec2->cmdq, - init->queue_info[i].index, - init->queue_info[i].offset, - init->queue_info[i].size); - } - } - - return 0; -} - static const struct nvkm_msgqueue_init_func msgqueue_0148cdec_init_func = { .gen_cmdline = init_gen_cmdline, - .init_callback = init_callback, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index bc0eb84c2c90..706bbb782844 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -91,6 +91,7 @@ nvkm_pmu_fini(struct nvkm_subdev *subdev, bool suspend) nvkm_falcon_cmdq_fini(pmu->lpq); nvkm_falcon_cmdq_fini(pmu->hpq); + pmu->initmsg_received = false; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c index e803cc461227..0e550612acc6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c @@ -61,9 +61,80 @@ gm20b_pmu_acr = { .bootstrap_falcon = gm20b_pmu_acr_bootstrap_falcon, }; +static int +gm20b_pmu_acr_init_wpr_callback(void *priv, struct nv_falcon_msg *hdr) +{ + struct nv_pmu_acr_init_wpr_region_msg *msg = + container_of(hdr, typeof(*msg), msg.hdr); + struct nvkm_pmu *pmu = priv; + struct nvkm_subdev *subdev = &pmu->subdev; + + if (msg->error_code) { + nvkm_error(subdev, "ACR WPR init failure: %d\n", + msg->error_code); + return -EINVAL; + } + + nvkm_debug(subdev, "ACR WPR init complete\n"); + complete_all(&pmu->wpr_ready); + return 0; +} + +static int +gm20b_pmu_acr_init_wpr(struct nvkm_pmu *pmu) +{ + struct nv_pmu_acr_init_wpr_region_cmd cmd = { + .cmd.hdr.unit_id = NV_PMU_UNIT_ACR, + .cmd.hdr.size = sizeof(cmd), + .cmd.cmd_type = NV_PMU_ACR_CMD_INIT_WPR_REGION, + .region_id = 1, + .wpr_offset = 0, + }; + + return nvkm_falcon_cmdq_send(pmu->hpq, &cmd.cmd.hdr, + gm20b_pmu_acr_init_wpr_callback, pmu, 0); +} + +int +gm20b_pmu_initmsg(struct nvkm_pmu *pmu) +{ + struct nv_pmu_init_msg msg; + int ret; + + ret = nvkm_falcon_msgq_recv_initmsg(pmu->msgq, &msg, sizeof(msg)); + if (ret) + return ret; + + if (msg.hdr.unit_id != NV_PMU_UNIT_INIT || + msg.msg_type != NV_PMU_INIT_MSG_INIT) + return -EINVAL; + + nvkm_falcon_cmdq_init(pmu->hpq, msg.queue_info[0].index, + msg.queue_info[0].offset, + msg.queue_info[0].size); + nvkm_falcon_cmdq_init(pmu->lpq, msg.queue_info[1].index, + msg.queue_info[1].offset, + msg.queue_info[1].size); + nvkm_falcon_msgq_init(pmu->msgq, msg.queue_info[4].index, + msg.queue_info[4].offset, + msg.queue_info[4].size); + return gm20b_pmu_acr_init_wpr(pmu); +} + void gm20b_pmu_recv(struct nvkm_pmu *pmu) { + if (!pmu->initmsg_received) { + int ret = pmu->func->initmsg(pmu); + if (ret) { + nvkm_error(&pmu->subdev, + "error parsing init message: %d\n", ret); + return; + } + + pmu->initmsg_received = true; + } + if (!pmu->queue) { nvkm_warn(&pmu->subdev, "recv function called while no firmware set!\n"); @@ -79,6 +150,7 @@ gm20b_pmu = { .enabled = gf100_pmu_enabled, .intr = gt215_pmu_intr, .recv = gm20b_pmu_recv, + .initmsg = gm20b_pmu_initmsg, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c index b2baf9b636a3..0e0ebd6857da 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c @@ -68,6 +68,7 @@ gp10b_pmu = { .enabled = gf100_pmu_enabled, .intr = gt215_pmu_intr, .recv = gm20b_pmu_recv, + .initmsg = gm20b_pmu_initmsg, }; #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h index 0e7965028dcf..21ca224fc186 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h @@ -27,6 +27,7 @@ struct nvkm_pmu_func { int (*send)(struct nvkm_pmu *, u32 reply[2], u32 process, u32 message, u32 data0, u32 data1); void (*recv)(struct nvkm_pmu *); + int (*initmsg)(struct nvkm_pmu *); void (*pgob)(struct nvkm_pmu *, bool); }; @@ -44,6 +45,7 @@ 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 *); +int gm20b_pmu_initmsg(struct nvkm_pmu *); struct nvkm_pmu_fwif { int version; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/ls_ucode_msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/ls_ucode_msgqueue.c index 39dda09fc344..7994ed1cdf97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/ls_ucode_msgqueue.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/ls_ucode_msgqueue.c @@ -85,8 +85,6 @@ acr_ls_msgqueue_post_run(struct nvkm_msgqueue *queue, memset(buf, 0, sizeof(buf)); nvkm_msgqueue_write_cmdline(queue, buf); nvkm_falcon_load_dmem(falcon, buf, addr_args, sizeof(buf), 0); - /* rearm the queue so it will wait for the init message */ - nvkm_msgqueue_reinit(queue); /* Enable interrupts */ nvkm_falcon_wr32(falcon, 0x10, 0xff); |