drm/nouveau/msgqueue: support for GP10B PMU firmware
authorAlexandre Courbot <acourbot@nvidia.com>
Wed, 29 Mar 2017 09:31:15 +0000 (18:31 +0900)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 6 Apr 2017 04:39:04 +0000 (14:39 +1000)
The GP10B firmware is very close to GM20B's. The only difference is that
it supports booting multiple falcons. In order to avoid having too much
functions and structures shared, implement its support in the same
source file as GM20B firmware.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
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

index f7101a9..d45d794 100644 (file)
@@ -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;
index 2b3a6c3..13b54f8 100644 (file)
@@ -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 **);
 
index 935b9a7..fec0273 100644 (file)
@@ -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;
+}