drm/nouveau/flcn/msgq: move handling of init message to subdevs
authorBen Skeggs <bskeggs@redhat.com>
Tue, 14 Jan 2020 20:34:22 +0000 (06:34 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 15 Jan 2020 00:50:29 +0000 (10:50 +1000)
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:
drivers/gpu/drm/nouveau/include/nvfw/pmu.h
drivers/gpu/drm/nouveau/include/nvfw/sec2.h
drivers/gpu/drm/nouveau/include/nvkm/core/falcon.h
drivers/gpu/drm/nouveau/include/nvkm/core/msgqueue.h
drivers/gpu/drm/nouveau/include/nvkm/engine/sec2.h
drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
drivers/gpu/drm/nouveau/nvkm/engine/sec2/base.c
drivers/gpu/drm/nouveau/nvkm/engine/sec2/gp102.c
drivers/gpu/drm/nouveau/nvkm/engine/sec2/priv.h
drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c
drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm20b.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
drivers/gpu/drm/nouveau/nvkm/subdev/secboot/ls_ucode_msgqueue.c

index 6e86ce31f963d1d873b4c8a1b2a64e318351e247..f808998e2ea1400d8a1e2277435251a793bb1958 100644 (file)
@@ -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
index 2f7460fe1b76c4b51ab424cda6ca53fb78aab540..80753cfa4cb3769fbc6d8ad2a3db47dfa6feb796 100644 (file)
@@ -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
index 54e1f4d7568fdc3a27d54c04ecf097dfec048dcb..a37d2008406b2bb5031df3ad2ae505c680f27689 100644 (file)
@@ -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
index acb339f34bb5e6f27990fb08edb73eb10def48bb..19f2fdb3e7548342b890f1e9c6ec582637058ed0 100644 (file)
@@ -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 *);
index ca1b227a81f9633a8b6cfa331abbfbe5f05d30ad..44da8d3ac86e5d9a5583bd85b81a469f3a66951b 100644 (file)
@@ -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 **);
index 21607b40aee61d7505d15e7580a6dd0063a22a07..79351a74642e58d9aa49c43cb704f2e7b9857a3c 100644 (file)
@@ -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;
index d85aeb059c87920e48e968c0038c8420bc116fac..f6a453dc75adee609acd67ed41ab0f2be23b0bbe 100644 (file)
@@ -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;
 }
 
index 26f738d1202ed6a9a55a42be29b40dc694431ee0..26a4680477479e8d1af9cb070d0214d6f884beae 100644 (file)
@@ -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");
index 9c00e663449951d8eb448929facf439260a43c11..1992391832a11544f21fbd2c1c38a9cf986c504a 100644 (file)
@@ -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 *);
index 1c7dab86af8041130e3b1a480c4e4894b21a30af..b906534fc7fa33f76e224feea8dc08d954671976 100644 (file)
@@ -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
index 9867a32da42a7431298bf9b8de0ba5e17bbde62f..46e88937c453fc9219f9d01d4b3192be87a8c7e6 100644 (file)
@@ -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,
index bf714f391d42f88ae3cb67990109c40f41b47d10..1c4780a7856ad5321928510d04e57b55abe140bf 100644 (file)
  *
  */
 
-/**
- * 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 *,
index 7e450a91c62e8eb0d318bc8f5aecd3889a69da6c..f624f9cd90982cab05a88f673825c8d79fc7eae8 100644 (file)
 #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)
 {
index 51ae4a10b2131b16ff9c415960ae6634cbfe1410..0dc243b0b7742092b7835ff227905b928be61d63 100644 (file)
  * 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,
 };
 
 
index bc0eb84c2c907bb5a3519a56537fd1a164b9cdb5..706bbb782844563b4bb9b28039f7f857a7796cbb 100644 (file)
@@ -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;
 }
 
index e803cc4612274261cdba0b34841b15bcffb2257e..0e550612acc6eb1dc3c7c7fb3265c05166a151f8 100644 (file)
@@ -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)
index b2baf9b636a32b13ed2156d2d362bfcf946ce4b1..0e0ebd6857dac49176d9be25a42fc508ff62984b 100644 (file)
@@ -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)
index 0e7965028dcfa08bb9f0eecfb6423fc4eaf49c65..21ca224fc186c73b7fb7d70c227ee9e1097e9d5c 100644 (file)
@@ -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;
index 39dda09fc344aa657bf7f966cec4b122fab99c4e..7994ed1cdf97446d49f7724e0e50a7944452705d 100644 (file)
@@ -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);