linux/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 */
  23
  24#include "msgqueue.h"
  25#include <engine/falcon.h>
  26#include <subdev/secboot.h>
  27
  28/*
  29 * This firmware runs on the SEC falcon. It only has one command and one
  30 * message queue, and uses a different command line and init message.
  31 */
  32
  33enum {
  34        MSGQUEUE_0148CDEC_COMMAND_QUEUE = 0,
  35        MSGQUEUE_0148CDEC_MESSAGE_QUEUE = 1,
  36        MSGQUEUE_0148CDEC_NUM_QUEUES,
  37};
  38
  39struct msgqueue_0148cdec {
  40        struct nvkm_msgqueue base;
  41
  42        struct nvkm_msgqueue_queue queue[MSGQUEUE_0148CDEC_NUM_QUEUES];
  43};
  44#define msgqueue_0148cdec(q) \
  45        container_of(q, struct msgqueue_0148cdec, base)
  46
  47static struct nvkm_msgqueue_queue *
  48msgqueue_0148cdec_cmd_queue(struct nvkm_msgqueue *queue,
  49                            enum msgqueue_msg_priority priority)
  50{
  51        struct msgqueue_0148cdec *priv = msgqueue_0148cdec(queue);
  52
  53        return &priv->queue[MSGQUEUE_0148CDEC_COMMAND_QUEUE];
  54}
  55
  56static void
  57msgqueue_0148cdec_process_msgs(struct nvkm_msgqueue *queue)
  58{
  59        struct msgqueue_0148cdec *priv = msgqueue_0148cdec(queue);
  60        struct nvkm_msgqueue_queue *q_queue =
  61                &priv->queue[MSGQUEUE_0148CDEC_MESSAGE_QUEUE];
  62
  63        nvkm_msgqueue_process_msgs(&priv->base, q_queue);
  64}
  65
  66
  67/* Init unit */
  68#define MSGQUEUE_0148CDEC_UNIT_INIT 0x01
  69
  70enum {
  71        INIT_MSG_INIT = 0x0,
  72};
  73
  74static void
  75init_gen_cmdline(struct nvkm_msgqueue *queue, void *buf)
  76{
  77        struct {
  78                u32 freq_hz;
  79                u32 falc_trace_size;
  80                u32 falc_trace_dma_base;
  81                u32 falc_trace_dma_idx;
  82                bool secure_mode;
  83        } *args = buf;
  84
  85        args->secure_mode = false;
  86}
  87
  88static int
  89init_callback(struct nvkm_msgqueue *_queue, struct nvkm_msgqueue_hdr *hdr)
  90{
  91        struct msgqueue_0148cdec *priv = msgqueue_0148cdec(_queue);
  92        struct {
  93                struct nvkm_msgqueue_msg base;
  94
  95                u8 num_queues;
  96                u16 os_debug_entry_point;
  97
  98                struct {
  99                        u32 offset;
 100                        u16 size;
 101                        u8 index;
 102                        u8 id;
 103                } queue_info[MSGQUEUE_0148CDEC_NUM_QUEUES];
 104
 105                u16 sw_managed_area_offset;
 106                u16 sw_managed_area_size;
 107        } *init = (void *)hdr;
 108        const struct nvkm_subdev *subdev = _queue->falcon->owner;
 109        int i;
 110
 111        if (init->base.hdr.unit_id != MSGQUEUE_0148CDEC_UNIT_INIT) {
 112                nvkm_error(subdev, "expected message from init unit\n");
 113                return -EINVAL;
 114        }
 115
 116        if (init->base.msg_type != INIT_MSG_INIT) {
 117                nvkm_error(subdev, "expected SEC init msg\n");
 118                return -EINVAL;
 119        }
 120
 121        for (i = 0; i < MSGQUEUE_0148CDEC_NUM_QUEUES; i++) {
 122                u8 id = init->queue_info[i].id;
 123                struct nvkm_msgqueue_queue *queue = &priv->queue[id];
 124
 125                mutex_init(&queue->mutex);
 126
 127                queue->index = init->queue_info[i].index;
 128                queue->offset = init->queue_info[i].offset;
 129                queue->size = init->queue_info[i].size;
 130
 131                if (id == MSGQUEUE_0148CDEC_MESSAGE_QUEUE) {
 132                        queue->head_reg = 0xa30 + (queue->index * 8);
 133                        queue->tail_reg = 0xa34 + (queue->index * 8);
 134                } else {
 135                        queue->head_reg = 0xa00 + (queue->index * 8);
 136                        queue->tail_reg = 0xa04 + (queue->index * 8);
 137                }
 138
 139                nvkm_debug(subdev,
 140                           "queue %d: index %d, offset 0x%08x, size 0x%08x\n",
 141                           id, queue->index, queue->offset, queue->size);
 142        }
 143
 144        complete_all(&_queue->init_done);
 145
 146        return 0;
 147}
 148
 149static const struct nvkm_msgqueue_init_func
 150msgqueue_0148cdec_init_func = {
 151        .gen_cmdline = init_gen_cmdline,
 152        .init_callback = init_callback,
 153};
 154
 155
 156
 157/* ACR unit */
 158#define MSGQUEUE_0148CDEC_UNIT_ACR 0x08
 159
 160enum {
 161        ACR_CMD_BOOTSTRAP_FALCON = 0x00,
 162};
 163
 164static void
 165acr_boot_falcon_callback(struct nvkm_msgqueue *priv,
 166                         struct nvkm_msgqueue_hdr *hdr)
 167{
 168        struct acr_bootstrap_falcon_msg {
 169                struct nvkm_msgqueue_msg base;
 170
 171                u32 error_code;
 172                u32 falcon_id;
 173        } *msg = (void *)hdr;
 174        const struct nvkm_subdev *subdev = priv->falcon->owner;
 175        u32 falcon_id = msg->falcon_id;
 176
 177        if (msg->error_code) {
 178                nvkm_error(subdev, "in bootstrap falcon callback:\n");
 179                nvkm_error(subdev, "expected error code 0x%x\n",
 180                           msg->error_code);
 181                return;
 182        }
 183
 184        if (falcon_id >= NVKM_SECBOOT_FALCON_END) {
 185                nvkm_error(subdev, "in bootstrap falcon callback:\n");
 186                nvkm_error(subdev, "invalid falcon ID 0x%x\n", falcon_id);
 187                return;
 188        }
 189
 190        nvkm_debug(subdev, "%s booted\n", nvkm_secboot_falcon_name[falcon_id]);
 191}
 192
 193enum {
 194        ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES = 0,
 195        ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO = 1,
 196};
 197
 198static int
 199acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon)
 200{
 201        DECLARE_COMPLETION_ONSTACK(completed);
 202        /*
 203         * flags      - Flag specifying RESET or no RESET.
 204         * falcon id  - Falcon id specifying falcon to bootstrap.
 205         */
 206        struct {
 207                struct nvkm_msgqueue_hdr hdr;
 208                u8 cmd_type;
 209                u32 flags;
 210                u32 falcon_id;
 211        } cmd;
 212
 213        memset(&cmd, 0, sizeof(cmd));
 214
 215        cmd.hdr.unit_id = MSGQUEUE_0148CDEC_UNIT_ACR;
 216        cmd.hdr.size = sizeof(cmd);
 217        cmd.cmd_type = ACR_CMD_BOOTSTRAP_FALCON;
 218        cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES;
 219        cmd.falcon_id = falcon;
 220        nvkm_msgqueue_post(priv, MSGQUEUE_MSG_PRIORITY_HIGH, &cmd.hdr,
 221                           acr_boot_falcon_callback, &completed, true);
 222
 223        if (!wait_for_completion_timeout(&completed, msecs_to_jiffies(1000)))
 224                return -ETIMEDOUT;
 225
 226        return 0;
 227}
 228
 229const struct nvkm_msgqueue_acr_func
 230msgqueue_0148cdec_acr_func = {
 231        .boot_falcon = acr_boot_falcon,
 232};
 233
 234static void
 235msgqueue_0148cdec_dtor(struct nvkm_msgqueue *queue)
 236{
 237        kfree(msgqueue_0148cdec(queue));
 238}
 239
 240const struct nvkm_msgqueue_func
 241msgqueue_0148cdec_func = {
 242        .init_func = &msgqueue_0148cdec_init_func,
 243        .acr_func = &msgqueue_0148cdec_acr_func,
 244        .cmd_queue = msgqueue_0148cdec_cmd_queue,
 245        .recv = msgqueue_0148cdec_process_msgs,
 246        .dtor = msgqueue_0148cdec_dtor,
 247};
 248
 249int
 250msgqueue_0148cdec_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb,
 251                      struct nvkm_msgqueue **queue)
 252{
 253        struct msgqueue_0148cdec *ret;
 254
 255        ret = kzalloc(sizeof(*ret), GFP_KERNEL);
 256        if (!ret)
 257                return -ENOMEM;
 258
 259        *queue = &ret->base;
 260
 261        nvkm_msgqueue_ctor(&msgqueue_0148cdec_func, falcon, &ret->base);
 262
 263        return 0;
 264}
 265