diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/falcon')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/base.c | 87 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c | 214 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c | 213 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c | 577 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h | 213 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c | 436 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c | 264 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/priv.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.c | 87 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h | 89 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/falcon/v1.c | 86 |
12 files changed, 669 insertions, 1609 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild b/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild index b5665ada850a..d79d783904ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/Kbuild @@ -1,6 +1,6 @@ # SPDX-License-Identifier: MIT nvkm-y += nvkm/falcon/base.o +nvkm-y += nvkm/falcon/cmdq.o +nvkm-y += nvkm/falcon/msgq.o +nvkm-y += nvkm/falcon/qmgr.o nvkm-y += nvkm/falcon/v1.o -nvkm-y += nvkm/falcon/msgqueue.o -nvkm-y += nvkm/falcon/msgqueue_0137c63d.o -nvkm-y += nvkm/falcon/msgqueue_0148cdec.o diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c index 366c87de6e72..c6a3448180d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/base.c @@ -22,6 +22,7 @@ #include "priv.h" #include <subdev/mc.h> +#include <subdev/top.h> void nvkm_falcon_load_imem(struct nvkm_falcon *falcon, void *data, u32 start, @@ -134,6 +135,37 @@ nvkm_falcon_clear_interrupt(struct nvkm_falcon *falcon, u32 mask) return falcon->func->clear_interrupt(falcon, mask); } +static int +nvkm_falcon_oneinit(struct nvkm_falcon *falcon) +{ + const struct nvkm_falcon_func *func = falcon->func; + const struct nvkm_subdev *subdev = falcon->owner; + u32 reg; + + if (!falcon->addr) { + falcon->addr = nvkm_top_addr(subdev->device, subdev->index); + if (WARN_ON(!falcon->addr)) + return -ENODEV; + } + + reg = nvkm_falcon_rd32(falcon, 0x12c); + falcon->version = reg & 0xf; + falcon->secret = (reg >> 4) & 0x3; + falcon->code.ports = (reg >> 8) & 0xf; + falcon->data.ports = (reg >> 12) & 0xf; + + reg = nvkm_falcon_rd32(falcon, 0x108); + falcon->code.limit = (reg & 0x1ff) << 8; + falcon->data.limit = (reg & 0x3fe00) >> 1; + + if (func->debug) { + u32 val = nvkm_falcon_rd32(falcon, func->debug); + falcon->debug = (val >> 20) & 0x1; + } + + return 0; +} + void nvkm_falcon_put(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) { @@ -151,6 +183,8 @@ nvkm_falcon_put(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) int nvkm_falcon_get(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) { + int ret = 0; + mutex_lock(&falcon->mutex); if (falcon->user) { nvkm_error(user, "%s falcon already acquired by %s!\n", @@ -160,70 +194,37 @@ nvkm_falcon_get(struct nvkm_falcon *falcon, const struct nvkm_subdev *user) } nvkm_debug(user, "acquired %s falcon\n", falcon->name); + if (!falcon->oneinit) + ret = nvkm_falcon_oneinit(falcon); falcon->user = user; mutex_unlock(&falcon->mutex); - return 0; + return ret; } void +nvkm_falcon_dtor(struct nvkm_falcon *falcon) +{ +} + +int nvkm_falcon_ctor(const struct nvkm_falcon_func *func, struct nvkm_subdev *subdev, const char *name, u32 addr, struct nvkm_falcon *falcon) { - u32 debug_reg; - u32 reg; - falcon->func = func; falcon->owner = subdev; falcon->name = name; falcon->addr = addr; mutex_init(&falcon->mutex); mutex_init(&falcon->dmem_mutex); - - reg = nvkm_falcon_rd32(falcon, 0x12c); - falcon->version = reg & 0xf; - falcon->secret = (reg >> 4) & 0x3; - falcon->code.ports = (reg >> 8) & 0xf; - falcon->data.ports = (reg >> 12) & 0xf; - - reg = nvkm_falcon_rd32(falcon, 0x108); - falcon->code.limit = (reg & 0x1ff) << 8; - falcon->data.limit = (reg & 0x3fe00) >> 1; - - switch (subdev->index) { - case NVKM_ENGINE_GR: - debug_reg = 0x0; - break; - case NVKM_SUBDEV_PMU: - debug_reg = 0xc08; - break; - case NVKM_ENGINE_NVDEC0: - debug_reg = 0xd00; - break; - case NVKM_ENGINE_SEC2: - debug_reg = 0x408; - falcon->has_emem = true; - break; - case NVKM_SUBDEV_GSP: - debug_reg = 0x0; /*XXX*/ - break; - default: - nvkm_warn(subdev, "unsupported falcon %s!\n", - nvkm_subdev_name[subdev->index]); - debug_reg = 0; - break; - } - - if (debug_reg) { - u32 val = nvkm_falcon_rd32(falcon, debug_reg); - falcon->debug = (val >> 20) & 0x1; - } + return 0; } void nvkm_falcon_del(struct nvkm_falcon **pfalcon) { if (*pfalcon) { + nvkm_falcon_dtor(*pfalcon); kfree(*pfalcon); *pfalcon = NULL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c b/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c new file mode 100644 index 000000000000..40e3f3fc83ef --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/cmdq.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include "qmgr.h" + +static bool +nvkm_falcon_cmdq_has_room(struct nvkm_falcon_cmdq *cmdq, u32 size, bool *rewind) +{ + u32 head = nvkm_falcon_rd32(cmdq->qmgr->falcon, cmdq->head_reg); + u32 tail = nvkm_falcon_rd32(cmdq->qmgr->falcon, cmdq->tail_reg); + u32 free; + + size = ALIGN(size, QUEUE_ALIGNMENT); + + if (head >= tail) { + free = cmdq->offset + cmdq->size - head; + free -= HDR_SIZE; + + if (size > free) { + *rewind = true; + head = cmdq->offset; + } + } + + if (head < tail) + free = tail - head - 1; + + return size <= free; +} + +static void +nvkm_falcon_cmdq_push(struct nvkm_falcon_cmdq *cmdq, void *data, u32 size) +{ + struct nvkm_falcon *falcon = cmdq->qmgr->falcon; + nvkm_falcon_load_dmem(falcon, data, cmdq->position, size, 0); + cmdq->position += ALIGN(size, QUEUE_ALIGNMENT); +} + +static void +nvkm_falcon_cmdq_rewind(struct nvkm_falcon_cmdq *cmdq) +{ + struct nv_falcon_cmd cmd; + + cmd.unit_id = NV_FALCON_CMD_UNIT_ID_REWIND; + cmd.size = sizeof(cmd); + nvkm_falcon_cmdq_push(cmdq, &cmd, cmd.size); + + cmdq->position = cmdq->offset; +} + +static int +nvkm_falcon_cmdq_open(struct nvkm_falcon_cmdq *cmdq, u32 size) +{ + struct nvkm_falcon *falcon = cmdq->qmgr->falcon; + bool rewind = false; + + mutex_lock(&cmdq->mutex); + + if (!nvkm_falcon_cmdq_has_room(cmdq, size, &rewind)) { + FLCNQ_DBG(cmdq, "queue full"); + mutex_unlock(&cmdq->mutex); + return -EAGAIN; + } + + cmdq->position = nvkm_falcon_rd32(falcon, cmdq->head_reg); + + if (rewind) + nvkm_falcon_cmdq_rewind(cmdq); + + return 0; +} + +static void +nvkm_falcon_cmdq_close(struct nvkm_falcon_cmdq *cmdq) +{ + nvkm_falcon_wr32(cmdq->qmgr->falcon, cmdq->head_reg, cmdq->position); + mutex_unlock(&cmdq->mutex); +} + +static int +nvkm_falcon_cmdq_write(struct nvkm_falcon_cmdq *cmdq, struct nv_falcon_cmd *cmd) +{ + static unsigned timeout = 2000; + unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); + int ret = -EAGAIN; + + while (ret == -EAGAIN && time_before(jiffies, end_jiffies)) + ret = nvkm_falcon_cmdq_open(cmdq, cmd->size); + if (ret) { + FLCNQ_ERR(cmdq, "timeout waiting for queue space"); + return ret; + } + + nvkm_falcon_cmdq_push(cmdq, cmd, cmd->size); + nvkm_falcon_cmdq_close(cmdq); + return ret; +} + +/* specifies that we want to know the command status in the answer message */ +#define CMD_FLAGS_STATUS BIT(0) +/* specifies that we want an interrupt when the answer message is queued */ +#define CMD_FLAGS_INTR BIT(1) + +int +nvkm_falcon_cmdq_send(struct nvkm_falcon_cmdq *cmdq, struct nv_falcon_cmd *cmd, + nvkm_falcon_qmgr_callback cb, void *priv, + unsigned long timeout) +{ + struct nvkm_falcon_qmgr_seq *seq; + int ret; + + if (!wait_for_completion_timeout(&cmdq->ready, + msecs_to_jiffies(1000))) { + FLCNQ_ERR(cmdq, "timeout waiting for queue ready"); + return -ETIMEDOUT; + } + + seq = nvkm_falcon_qmgr_seq_acquire(cmdq->qmgr); + if (IS_ERR(seq)) + return PTR_ERR(seq); + + cmd->seq_id = seq->id; + cmd->ctrl_flags = CMD_FLAGS_STATUS | CMD_FLAGS_INTR; + + seq->state = SEQ_STATE_USED; + seq->async = !timeout; + seq->callback = cb; + seq->priv = priv; + + ret = nvkm_falcon_cmdq_write(cmdq, cmd); + if (ret) { + seq->state = SEQ_STATE_PENDING; + nvkm_falcon_qmgr_seq_release(cmdq->qmgr, seq); + return ret; + } + + if (!seq->async) { + if (!wait_for_completion_timeout(&seq->done, timeout)) { + FLCNQ_ERR(cmdq, "timeout waiting for reply"); + return -ETIMEDOUT; + } + ret = seq->result; + nvkm_falcon_qmgr_seq_release(cmdq->qmgr, seq); + } + + return ret; +} + +void +nvkm_falcon_cmdq_fini(struct nvkm_falcon_cmdq *cmdq) +{ + reinit_completion(&cmdq->ready); +} + +void +nvkm_falcon_cmdq_init(struct nvkm_falcon_cmdq *cmdq, + u32 index, u32 offset, u32 size) +{ + const struct nvkm_falcon_func *func = cmdq->qmgr->falcon->func; + + cmdq->head_reg = func->cmdq.head + index * func->cmdq.stride; + cmdq->tail_reg = func->cmdq.tail + index * func->cmdq.stride; + cmdq->offset = offset; + cmdq->size = size; + complete_all(&cmdq->ready); + + FLCNQ_DBG(cmdq, "initialised @ index %d offset 0x%08x size 0x%08x", + index, cmdq->offset, cmdq->size); +} + +void +nvkm_falcon_cmdq_del(struct nvkm_falcon_cmdq **pcmdq) +{ + struct nvkm_falcon_cmdq *cmdq = *pcmdq; + if (cmdq) { + kfree(*pcmdq); + *pcmdq = NULL; + } +} + +int +nvkm_falcon_cmdq_new(struct nvkm_falcon_qmgr *qmgr, const char *name, + struct nvkm_falcon_cmdq **pcmdq) +{ + struct nvkm_falcon_cmdq *cmdq = *pcmdq; + + if (!(cmdq = *pcmdq = kzalloc(sizeof(*cmdq), GFP_KERNEL))) + return -ENOMEM; + + cmdq->qmgr = qmgr; + cmdq->name = name; + mutex_init(&cmdq->mutex); + init_completion(&cmdq->ready); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c new file mode 100644 index 000000000000..cbfe09a561a1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/msgq.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include "qmgr.h" + +static void +nvkm_falcon_msgq_open(struct nvkm_falcon_msgq *msgq) +{ + mutex_lock(&msgq->mutex); + msgq->position = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->tail_reg); +} + +static void +nvkm_falcon_msgq_close(struct nvkm_falcon_msgq *msgq, bool commit) +{ + struct nvkm_falcon *falcon = msgq->qmgr->falcon; + + if (commit) + nvkm_falcon_wr32(falcon, msgq->tail_reg, msgq->position); + + mutex_unlock(&msgq->mutex); +} + +static bool +nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *msgq) +{ + u32 head = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->head_reg); + u32 tail = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->tail_reg); + return head == tail; +} + +static int +nvkm_falcon_msgq_pop(struct nvkm_falcon_msgq *msgq, void *data, u32 size) +{ + struct nvkm_falcon *falcon = msgq->qmgr->falcon; + u32 head, tail, available; + + head = nvkm_falcon_rd32(falcon, msgq->head_reg); + /* has the buffer looped? */ + if (head < msgq->position) + msgq->position = msgq->offset; + + tail = msgq->position; + + available = head - tail; + if (size > available) { + FLCNQ_ERR(msgq, "requested %d bytes, but only %d available", + size, available); + return -EINVAL; + } + + nvkm_falcon_read_dmem(falcon, tail, size, 0, data); + msgq->position += ALIGN(size, QUEUE_ALIGNMENT); + return 0; +} + +static int +nvkm_falcon_msgq_read(struct nvkm_falcon_msgq *msgq, struct nv_falcon_msg *hdr) +{ + int ret = 0; + + nvkm_falcon_msgq_open(msgq); + + if (nvkm_falcon_msgq_empty(msgq)) + goto close; + + ret = nvkm_falcon_msgq_pop(msgq, hdr, HDR_SIZE); + if (ret) { + FLCNQ_ERR(msgq, "failed to read message header"); + goto close; + } + + if (hdr->size > MSG_BUF_SIZE) { + FLCNQ_ERR(msgq, "message too big, %d bytes", hdr->size); + ret = -ENOSPC; + goto close; + } + + if (hdr->size > HDR_SIZE) { + u32 read_size = hdr->size - HDR_SIZE; + + ret = nvkm_falcon_msgq_pop(msgq, (hdr + 1), read_size); + if (ret) { + FLCNQ_ERR(msgq, "failed to read message data"); + goto close; + } + } + + ret = 1; +close: + nvkm_falcon_msgq_close(msgq, (ret >= 0)); + return ret; +} + +static int +nvkm_falcon_msgq_exec(struct nvkm_falcon_msgq *msgq, struct nv_falcon_msg *hdr) +{ + struct nvkm_falcon_qmgr_seq *seq; + + seq = &msgq->qmgr->seq.id[hdr->seq_id]; + if (seq->state != SEQ_STATE_USED && seq->state != SEQ_STATE_CANCELLED) { + FLCNQ_ERR(msgq, "message for unknown sequence %08x", seq->id); + return -EINVAL; + } + + if (seq->state == SEQ_STATE_USED) { + if (seq->callback) + seq->result = seq->callback(seq->priv, hdr); + } + + if (seq->async) { + nvkm_falcon_qmgr_seq_release(msgq->qmgr, seq); + return 0; + } + + complete_all(&seq->done); + return 0; +} + +void +nvkm_falcon_msgq_recv(struct nvkm_falcon_msgq *msgq) +{ + /* + * We are invoked from a worker thread, so normally we have plenty of + * stack space to work with. + */ + u8 msg_buffer[MSG_BUF_SIZE]; + struct nv_falcon_msg *hdr = (void *)msg_buffer; + + while (nvkm_falcon_msgq_read(msgq, hdr) > 0) + nvkm_falcon_msgq_exec(msgq, hdr); +} + +int +nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *msgq, + void *data, u32 size) +{ + struct nvkm_falcon *falcon = msgq->qmgr->falcon; + struct nv_falcon_msg *hdr = data; + int ret; + + msgq->head_reg = falcon->func->msgq.head; + msgq->tail_reg = falcon->func->msgq.tail; + msgq->offset = nvkm_falcon_rd32(falcon, falcon->func->msgq.tail); + + nvkm_falcon_msgq_open(msgq); + ret = nvkm_falcon_msgq_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_msgq_close(msgq, ret == 0); + return ret; +} + +void +nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *msgq, + u32 index, u32 offset, u32 size) +{ + const struct nvkm_falcon_func *func = msgq->qmgr->falcon->func; + + msgq->head_reg = func->msgq.head + index * func->msgq.stride; + msgq->tail_reg = func->msgq.tail + index * func->msgq.stride; + msgq->offset = offset; + + FLCNQ_DBG(msgq, "initialised @ index %d offset 0x%08x size 0x%08x", + index, msgq->offset, size); +} + +void +nvkm_falcon_msgq_del(struct nvkm_falcon_msgq **pmsgq) +{ + struct nvkm_falcon_msgq *msgq = *pmsgq; + if (msgq) { + kfree(*pmsgq); + *pmsgq = NULL; + } +} + +int +nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *qmgr, const char *name, + struct nvkm_falcon_msgq **pmsgq) +{ + struct nvkm_falcon_msgq *msgq = *pmsgq; + + if (!(msgq = *pmsgq = kzalloc(sizeof(*msgq), GFP_KERNEL))) + return -ENOMEM; + + msgq->qmgr = qmgr; + msgq->name = name; + mutex_init(&msgq->mutex); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c deleted file mode 100644 index a8bee1e046aa..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include "msgqueue.h" -#include <engine/falcon.h> - -#include <subdev/secboot.h> - - -#define HDR_SIZE sizeof(struct nvkm_msgqueue_hdr) -#define QUEUE_ALIGNMENT 4 -/* max size of the messages we can receive */ -#define MSG_BUF_SIZE 128 - -static int -msg_queue_open(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue) -{ - struct nvkm_falcon *falcon = priv->falcon; - - mutex_lock(&queue->mutex); - - queue->position = nvkm_falcon_rd32(falcon, queue->tail_reg); - - return 0; -} - -static void -msg_queue_close(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, - bool commit) -{ - struct nvkm_falcon *falcon = priv->falcon; - - if (commit) - nvkm_falcon_wr32(falcon, queue->tail_reg, queue->position); - - mutex_unlock(&queue->mutex); -} - -static bool -msg_queue_empty(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue) -{ - struct nvkm_falcon *falcon = priv->falcon; - u32 head, tail; - - head = nvkm_falcon_rd32(falcon, queue->head_reg); - tail = nvkm_falcon_rd32(falcon, queue->tail_reg); - - return head == tail; -} - -static int -msg_queue_pop(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, - void *data, u32 size) -{ - struct nvkm_falcon *falcon = priv->falcon; - const struct nvkm_subdev *subdev = priv->falcon->owner; - u32 head, tail, available; - - head = nvkm_falcon_rd32(falcon, queue->head_reg); - /* has the buffer looped? */ - if (head < queue->position) - queue->position = queue->offset; - - tail = queue->position; - - available = head - tail; - - if (available == 0) { - nvkm_warn(subdev, "no message data available\n"); - return 0; - } - - if (size > available) { - nvkm_warn(subdev, "message data smaller than read request\n"); - size = available; - } - - nvkm_falcon_read_dmem(priv->falcon, tail, size, 0, data); - queue->position += ALIGN(size, QUEUE_ALIGNMENT); - - return size; -} - -static int -msg_queue_read(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, - struct nvkm_msgqueue_hdr *hdr) -{ - const struct nvkm_subdev *subdev = priv->falcon->owner; - int err; - - err = msg_queue_open(priv, queue); - if (err) { - nvkm_error(subdev, "fail to open queue %d\n", queue->index); - return err; - } - - if (msg_queue_empty(priv, queue)) { - err = 0; - goto close; - } - - err = msg_queue_pop(priv, queue, hdr, HDR_SIZE); - if (err >= 0 && err != HDR_SIZE) - err = -EINVAL; - if (err < 0) { - nvkm_error(subdev, "failed to read message header: %d\n", err); - goto close; - } - - if (hdr->size > MSG_BUF_SIZE) { - nvkm_error(subdev, "message too big (%d bytes)\n", hdr->size); - err = -ENOSPC; - goto close; - } - - if (hdr->size > HDR_SIZE) { - u32 read_size = hdr->size - HDR_SIZE; - - err = msg_queue_pop(priv, queue, (hdr + 1), read_size); - if (err >= 0 && err != read_size) - err = -EINVAL; - if (err < 0) { - nvkm_error(subdev, "failed to read message: %d\n", err); - goto close; - } - } - -close: - msg_queue_close(priv, queue, (err >= 0)); - - return err; -} - -static bool -cmd_queue_has_room(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, - u32 size, bool *rewind) -{ - struct nvkm_falcon *falcon = priv->falcon; - u32 head, tail, free; - - size = ALIGN(size, QUEUE_ALIGNMENT); - - head = nvkm_falcon_rd32(falcon, queue->head_reg); - tail = nvkm_falcon_rd32(falcon, queue->tail_reg); - - if (head >= tail) { - free = queue->offset + queue->size - head; - free -= HDR_SIZE; - - if (size > free) { - *rewind = true; - head = queue->offset; - } - } - - if (head < tail) - free = tail - head - 1; - - return size <= free; -} - -static int -cmd_queue_push(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, - void *data, u32 size) -{ - nvkm_falcon_load_dmem(priv->falcon, data, queue->position, size, 0); - queue->position += ALIGN(size, QUEUE_ALIGNMENT); - - return 0; -} - -/* REWIND unit is always 0x00 */ -#define MSGQUEUE_UNIT_REWIND 0x00 - -static void -cmd_queue_rewind(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue) -{ - const struct nvkm_subdev *subdev = priv->falcon->owner; - struct nvkm_msgqueue_hdr cmd; - int err; - - cmd.unit_id = MSGQUEUE_UNIT_REWIND; - cmd.size = sizeof(cmd); - err = cmd_queue_push(priv, queue, &cmd, cmd.size); - if (err) - nvkm_error(subdev, "queue %d rewind failed\n", queue->index); - else - nvkm_error(subdev, "queue %d rewinded\n", queue->index); - - queue->position = queue->offset; -} - -static int -cmd_queue_open(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, - u32 size) -{ - struct nvkm_falcon *falcon = priv->falcon; - const struct nvkm_subdev *subdev = priv->falcon->owner; - bool rewind = false; - - mutex_lock(&queue->mutex); - - if (!cmd_queue_has_room(priv, queue, size, &rewind)) { - nvkm_error(subdev, "queue full\n"); - mutex_unlock(&queue->mutex); - return -EAGAIN; - } - - queue->position = nvkm_falcon_rd32(falcon, queue->head_reg); - - if (rewind) - cmd_queue_rewind(priv, queue); - - return 0; -} - -static void -cmd_queue_close(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_queue *queue, - bool commit) -{ - struct nvkm_falcon *falcon = priv->falcon; - - if (commit) - nvkm_falcon_wr32(falcon, queue->head_reg, queue->position); - - mutex_unlock(&queue->mutex); -} - -static int -cmd_write(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_hdr *cmd, - struct nvkm_msgqueue_queue *queue) -{ - const struct nvkm_subdev *subdev = priv->falcon->owner; - static unsigned timeout = 2000; - unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout); - int ret = -EAGAIN; - bool commit = true; - - while (ret == -EAGAIN && time_before(jiffies, end_jiffies)) - ret = cmd_queue_open(priv, queue, cmd->size); - if (ret) { - nvkm_error(subdev, "pmu_queue_open_write failed\n"); - return ret; - } - - ret = cmd_queue_push(priv, queue, cmd, cmd->size); - if (ret) { - nvkm_error(subdev, "pmu_queue_push failed\n"); - commit = false; - } - - cmd_queue_close(priv, queue, commit); - - return ret; -} - -static struct nvkm_msgqueue_seq * -msgqueue_seq_acquire(struct nvkm_msgqueue *priv) -{ - const struct nvkm_subdev *subdev = priv->falcon->owner; - struct nvkm_msgqueue_seq *seq; - u32 index; - - mutex_lock(&priv->seq_lock); - - index = find_first_zero_bit(priv->seq_tbl, NVKM_MSGQUEUE_NUM_SEQUENCES); - - if (index >= NVKM_MSGQUEUE_NUM_SEQUENCES) { - nvkm_error(subdev, "no free sequence available\n"); - mutex_unlock(&priv->seq_lock); - return ERR_PTR(-EAGAIN); - } - - set_bit(index, priv->seq_tbl); - - mutex_unlock(&priv->seq_lock); - - seq = &priv->seq[index]; - seq->state = SEQ_STATE_PENDING; - - return seq; -} - -static void -msgqueue_seq_release(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_seq *seq) -{ - /* no need to acquire seq_lock since clear_bit is atomic */ - seq->state = SEQ_STATE_FREE; - seq->callback = NULL; - seq->completion = NULL; - clear_bit(seq->id, priv->seq_tbl); -} - -/* specifies that we want to know the command status in the answer message */ -#define CMD_FLAGS_STATUS BIT(0) -/* specifies that we want an interrupt when the answer message is queued */ -#define CMD_FLAGS_INTR BIT(1) - -int -nvkm_msgqueue_post(struct nvkm_msgqueue *priv, enum msgqueue_msg_priority prio, - struct nvkm_msgqueue_hdr *cmd, nvkm_msgqueue_callback cb, - struct completion *completion, bool wait_init) -{ - struct nvkm_msgqueue_seq *seq; - struct nvkm_msgqueue_queue *queue; - int ret; - - if (wait_init && !wait_for_completion_timeout(&priv->init_done, - msecs_to_jiffies(1000))) - return -ETIMEDOUT; - - queue = priv->func->cmd_queue(priv, prio); - if (IS_ERR(queue)) - return PTR_ERR(queue); - - seq = msgqueue_seq_acquire(priv); - if (IS_ERR(seq)) - return PTR_ERR(seq); - - cmd->seq_id = seq->id; - cmd->ctrl_flags = CMD_FLAGS_STATUS | CMD_FLAGS_INTR; - - seq->callback = cb; - seq->state = SEQ_STATE_USED; - seq->completion = completion; - - ret = cmd_write(priv, cmd, queue); - if (ret) { - seq->state = SEQ_STATE_PENDING; - msgqueue_seq_release(priv, seq); - } - - return ret; -} - -static int -msgqueue_msg_handle(struct nvkm_msgqueue *priv, struct nvkm_msgqueue_hdr *hdr) -{ - const struct nvkm_subdev *subdev = priv->falcon->owner; - struct nvkm_msgqueue_seq *seq; - - seq = &priv->seq[hdr->seq_id]; - if (seq->state != SEQ_STATE_USED && seq->state != SEQ_STATE_CANCELLED) { - nvkm_error(subdev, "msg for unknown sequence %d", seq->id); - return -EINVAL; - } - - if (seq->state == SEQ_STATE_USED) { - if (seq->callback) - seq->callback(priv, hdr); - } - - if (seq->completion) - complete(seq->completion); - - msgqueue_seq_release(priv, seq); - - return 0; -} - -static int -msgqueue_handle_init_msg(struct nvkm_msgqueue *priv, - struct nvkm_msgqueue_hdr *hdr) -{ - struct nvkm_falcon *falcon = priv->falcon; - const struct nvkm_subdev *subdev = falcon->owner; - u32 tail; - u32 tail_reg; - int ret; - - /* - * Of course the message queue registers vary depending on the falcon - * used... - */ - switch (falcon->owner->index) { - case NVKM_SUBDEV_PMU: - tail_reg = 0x4cc; - break; - case NVKM_ENGINE_SEC2: - tail_reg = 0xa34; - break; - default: - nvkm_error(subdev, "falcon %s unsupported for msgqueue!\n", - nvkm_subdev_name[falcon->owner->index]); - return -EINVAL; - } - - /* - * 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); - - if (hdr->size > MSG_BUF_SIZE) { - nvkm_error(subdev, "message too big (%d bytes)\n", hdr->size); - return -ENOSPC; - } - - 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; -} - -void -nvkm_msgqueue_process_msgs(struct nvkm_msgqueue *priv, - struct nvkm_msgqueue_queue *queue) -{ - /* - * We are invoked from a worker thread, so normally we have plenty of - * stack space to work with. - */ - u8 msg_buffer[MSG_BUF_SIZE]; - struct nvkm_msgqueue_hdr *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, hdr); - if (!ret) - priv->init_msg_received = true; - } else { - while (msg_queue_read(priv, queue, hdr) > 0) - msgqueue_msg_handle(priv, hdr); - } -} - -void -nvkm_msgqueue_write_cmdline(struct nvkm_msgqueue *queue, void *buf) -{ - if (!queue || !queue->func || !queue->func->init_func) - return; - - queue->func->init_func->gen_cmdline(queue, buf); -} - -int -nvkm_msgqueue_acr_boot_falcons(struct nvkm_msgqueue *queue, - unsigned long falcon_mask) -{ - unsigned long falcon; - - if (!queue || !queue->func->acr_func) - return -ENODEV; - - /* Does the firmware support booting multiple falcons? */ - if (queue->func->acr_func->boot_multiple_falcons) - return queue->func->acr_func->boot_multiple_falcons(queue, - falcon_mask); - - /* Else boot all requested falcons individually */ - if (!queue->func->acr_func->boot_falcon) - return -ENODEV; - - for_each_set_bit(falcon, &falcon_mask, NVKM_SECBOOT_FALCON_END) { - int ret = queue->func->acr_func->boot_falcon(queue, falcon); - - if (ret) - return ret; - } - - return 0; -} - -int -nvkm_msgqueue_new(u32 version, struct nvkm_falcon *falcon, - const struct nvkm_secboot *sb, struct nvkm_msgqueue **queue) -{ - const struct nvkm_subdev *subdev = falcon->owner; - int ret = -EINVAL; - - switch (version) { - case 0x0137c63d: - ret = msgqueue_0137c63d_new(falcon, sb, queue); - break; - case 0x0137bca5: - ret = msgqueue_0137bca5_new(falcon, sb, queue); - break; - case 0x0148cdec: - case 0x015ccf3e: - case 0x0167d263: - ret = msgqueue_0148cdec_new(falcon, sb, queue); - break; - default: - nvkm_error(subdev, "unhandled firmware version 0x%08x\n", - version); - break; - } - - if (ret == 0) { - nvkm_debug(subdev, "firmware version: 0x%08x\n", version); - (*queue)->fw_version = version; - } - - return ret; -} - -void -nvkm_msgqueue_del(struct nvkm_msgqueue **queue) -{ - if (*queue) { - (*queue)->func->dtor(*queue); - *queue = NULL; - } -} - -void -nvkm_msgqueue_recv(struct nvkm_msgqueue *queue) -{ - if (!queue->func || !queue->func->recv) { - const struct nvkm_subdev *subdev = queue->falcon->owner; - - nvkm_warn(subdev, "missing msgqueue recv function\n"); - return; - } - - 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; - reinit_completion(&queue->init_done); - - return 0; -} - -void -nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *func, - struct nvkm_falcon *falcon, - struct nvkm_msgqueue *queue) -{ - int i; - - queue->func = func; - queue->falcon = falcon; - mutex_init(&queue->seq_lock); - for (i = 0; i < NVKM_MSGQUEUE_NUM_SEQUENCES; i++) - queue->seq[i].id = i; - - init_completion(&queue->init_done); - - -} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h deleted file mode 100644 index 13b54f8d8e04..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __NVKM_CORE_FALCON_MSGQUEUE_H -#define __NVKM_CORE_FALCON_MSGQUEUE_H - -#include <core/msgqueue.h> - -/* - * The struct nvkm_msgqueue (named so for lack of better candidate) manages - * a firmware (typically, NVIDIA signed firmware) running under a given falcon. - * - * Such firmwares expect to receive commands (through one or several command - * queues) and will reply to such command by sending messages (using one - * message queue). - * - * Each firmware can support one or several units - ACR for managing secure - * falcons, PMU for power management, etc. A unit can be seen as a class to - * which command can be sent. - * - * One usage example would be to send a command to the SEC falcon to ask it to - * reset a secure falcon. The SEC falcon will receive the command, process it, - * and send a message to signal success or failure. Only when the corresponding - * message is received can the requester assume the request has been processed. - * - * Since we expect many variations between the firmwares NVIDIA will release - * across GPU generations, this library is built in a very modular way. Message - * formats and queues details (such as number of usage) are left to - * specializations of struct nvkm_msgqueue, while the functions in msgqueue.c - * take care of posting commands and processing messages in a fashion that is - * universal. - * - */ - -enum msgqueue_msg_priority { - MSGQUEUE_MSG_PRIORITY_HIGH, - MSGQUEUE_MSG_PRIORITY_LOW, -}; - -/** - * 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; -typedef void -(*nvkm_msgqueue_callback)(struct nvkm_msgqueue *, struct nvkm_msgqueue_hdr *); - -/** - * struct nvkm_msgqueue_init_func - msgqueue functions related to initialization - * - * @gen_cmdline: build the commandline into a pre-allocated buffer - * @init_callback: called to process the init message - */ -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_acr_func - msgqueue functions related to ACR - * - * @boot_falcon: build and send the command to reset a given falcon - * @boot_multiple_falcons: build and send the command to reset several falcons - */ -struct nvkm_msgqueue_acr_func { - int (*boot_falcon)(struct nvkm_msgqueue *, enum nvkm_secboot_falcon); - int (*boot_multiple_falcons)(struct nvkm_msgqueue *, unsigned long); -}; - -struct nvkm_msgqueue_func { - const struct nvkm_msgqueue_init_func *init_func; - const struct nvkm_msgqueue_acr_func *acr_func; - void (*dtor)(struct nvkm_msgqueue *); - struct nvkm_msgqueue_queue *(*cmd_queue)(struct nvkm_msgqueue *, - enum msgqueue_msg_priority); - void (*recv)(struct nvkm_msgqueue *queue); -}; - -/** - * struct nvkm_msgqueue_queue - information about a command or message queue - * - * The number of queues is firmware-dependent. All queues must have their - * information filled by the init message handler. - * - * @mutex_lock: to be acquired when the queue is being used - * @index: physical queue index - * @offset: DMEM offset where this queue begins - * @size: size allocated to this queue in DMEM (in bytes) - * @position: current write position - * @head_reg: address of the HEAD register for this queue - * @tail_reg: address of the TAIL register for this queue - */ -struct nvkm_msgqueue_queue { - struct mutex mutex; - u32 index; - u32 offset; - u32 size; - u32 position; - - u32 head_reg; - u32 tail_reg; -}; - -/** - * struct nvkm_msgqueue_seq - keep track of ongoing commands - * - * Every time a command is sent, a sequence is assigned to it so the - * corresponding message can be matched. Upon receiving the message, a callback - * can be called and/or a completion signaled. - * - * @id: sequence ID - * @state: current state - * @callback: callback to call upon receiving matching message - * @completion: completion to signal after callback is called - */ -struct nvkm_msgqueue_seq { - u16 id; - enum { - SEQ_STATE_FREE = 0, - SEQ_STATE_PENDING, - SEQ_STATE_USED, - SEQ_STATE_CANCELLED - } state; - nvkm_msgqueue_callback callback; - struct completion *completion; -}; - -/* - * We can have an arbitrary number of sequences, but realistically we will - * probably not use that much simultaneously. - */ -#define NVKM_MSGQUEUE_NUM_SEQUENCES 16 - -/** - * struct nvkm_msgqueue - manage a command/message based FW on a falcon - * - * @falcon: falcon to be managed - * @func: implementation of the firmware to use - * @init_msg_received: whether the init message has already been received - * @init_done: whether all init is complete and commands can be processed - * @seq_lock: protects seq and seq_tbl - * @seq: sequences to match commands and messages - * @seq_tbl: bitmap of sequences currently in use - */ -struct nvkm_msgqueue { - struct nvkm_falcon *falcon; - const struct nvkm_msgqueue_func *func; - u32 fw_version; - bool init_msg_received; - struct completion init_done; - - struct mutex seq_lock; - struct nvkm_msgqueue_seq seq[NVKM_MSGQUEUE_NUM_SEQUENCES]; - unsigned long seq_tbl[BITS_TO_LONGS(NVKM_MSGQUEUE_NUM_SEQUENCES)]; -}; - -void nvkm_msgqueue_ctor(const struct nvkm_msgqueue_func *, struct nvkm_falcon *, - struct nvkm_msgqueue *); -int nvkm_msgqueue_post(struct nvkm_msgqueue *, enum msgqueue_msg_priority, - struct nvkm_msgqueue_hdr *, nvkm_msgqueue_callback, - struct completion *, bool); -void nvkm_msgqueue_process_msgs(struct nvkm_msgqueue *, - struct nvkm_msgqueue_queue *); - -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 **); - -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c deleted file mode 100644 index fec0273158f6..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0137c63d.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include "msgqueue.h" -#include <engine/falcon.h> -#include <subdev/secboot.h> - -/* Queues identifiers */ -enum { - /* High Priority Command Queue for Host -> PMU communication */ - MSGQUEUE_0137C63D_COMMAND_QUEUE_HPQ = 0, - /* Low Priority Command Queue for Host -> PMU communication */ - MSGQUEUE_0137C63D_COMMAND_QUEUE_LPQ = 1, - /* Message queue for PMU -> Host communication */ - MSGQUEUE_0137C63D_MESSAGE_QUEUE = 4, - MSGQUEUE_0137C63D_NUM_QUEUES = 5, -}; - -struct msgqueue_0137c63d { - struct nvkm_msgqueue base; - - struct nvkm_msgqueue_queue queue[MSGQUEUE_0137C63D_NUM_QUEUES]; -}; -#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) -{ - struct msgqueue_0137c63d *priv = msgqueue_0137c63d(queue); - const struct nvkm_subdev *subdev = priv->base.falcon->owner; - - switch (priority) { - case MSGQUEUE_MSG_PRIORITY_HIGH: - return &priv->queue[MSGQUEUE_0137C63D_COMMAND_QUEUE_HPQ]; - case MSGQUEUE_MSG_PRIORITY_LOW: - return &priv->queue[MSGQUEUE_0137C63D_COMMAND_QUEUE_LPQ]; - default: - nvkm_error(subdev, "invalid command queue!\n"); - return ERR_PTR(-EINVAL); - } -} - -static void -msgqueue_0137c63d_process_msgs(struct nvkm_msgqueue *queue) -{ - struct msgqueue_0137c63d *priv = msgqueue_0137c63d(queue); - struct nvkm_msgqueue_queue *q_queue = - &priv->queue[MSGQUEUE_0137C63D_MESSAGE_QUEUE]; - - nvkm_msgqueue_process_msgs(&priv->base, q_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) -{ - struct { - u32 reserved; - u32 freq_hz; - u32 trace_size; - u32 trace_dma_base; - u16 trace_dma_base1; - u8 trace_dma_offset; - u32 trace_dma_idx; - bool secure_mode; - bool raise_priv_sec; - struct { - u32 dma_base; - u16 dma_base1; - u8 dma_offset; - u16 fb_size; - u8 dma_idx; - } gc6_ctx; - u8 pad; - } *args = 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; - int i; - - 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; - } - - for (i = 0; i < MSGQUEUE_0137C63D_NUM_QUEUES; i++) { - struct nvkm_msgqueue_queue *queue = &priv->queue[i]; - - mutex_init(&queue->mutex); - - queue->index = init->queue_info[i].index; - queue->offset = init->queue_info[i].offset; - queue->size = init->queue_info[i].size; - - if (i != MSGQUEUE_0137C63D_MESSAGE_QUEUE) { - queue->head_reg = 0x4a0 + (queue->index * 4); - queue->tail_reg = 0x4b0 + (queue->index * 4); - } else { - queue->head_reg = 0x4c8; - queue->tail_reg = 0x4cc; - } - - nvkm_debug(subdev, - "queue %d: index %d, offset 0x%08x, size 0x%08x\n", - i, queue->index, queue->offset, queue->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, - ACR_CMD_BOOTSTRAP_FALCON = 0x01, - ACR_CMD_BOOTSTRAP_MULTIPLE_FALCONS = 0x03, -}; - -static void -acr_init_wpr_callback(struct nvkm_msgqueue *queue, - struct nvkm_msgqueue_hdr *hdr) -{ - struct { - struct nvkm_msgqueue_msg base; - u32 error_code; - } *msg = (void *)hdr; - const struct nvkm_subdev *subdev = queue->falcon->owner; - - if (msg->error_code) { - nvkm_error(subdev, "ACR WPR init failure: %d\n", - msg->error_code); - return; - } - - nvkm_debug(subdev, "ACR WPR init complete\n"); - complete_all(&queue->init_done); -} - -static int -acr_init_wpr(struct nvkm_msgqueue *queue) -{ - /* - * region_id: region ID in WPR region - * wpr_offset: offset in WPR region - */ - struct { - struct nvkm_msgqueue_hdr 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; - - nvkm_msgqueue_post(queue, MSGQUEUE_MSG_PRIORITY_HIGH, &cmd.hdr, - acr_init_wpr_callback, NULL, false); - - return 0; -} - - -static void -acr_boot_falcon_callback(struct nvkm_msgqueue *priv, - struct nvkm_msgqueue_hdr *hdr) -{ - struct acr_bootstrap_falcon_msg { - struct nvkm_msgqueue_msg base; - - u32 falcon_id; - } *msg = (void *)hdr; - const struct nvkm_subdev *subdev = priv->falcon->owner; - u32 falcon_id = msg->falcon_id; - - if (falcon_id >= NVKM_SECBOOT_FALCON_END) { - nvkm_error(subdev, "in bootstrap falcon callback:\n"); - nvkm_error(subdev, "invalid falcon ID 0x%x\n", falcon_id); - return; - } - nvkm_debug(subdev, "%s booted\n", nvkm_secboot_falcon_name[falcon_id]); -} - -enum { - ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES = 0, - ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO = 1, -}; - -static int -acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon) -{ - 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_id; - } cmd; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.hdr.unit_id = MSGQUEUE_0137C63D_UNIT_ACR; - cmd.hdr.size = sizeof(cmd); - cmd.cmd_type = ACR_CMD_BOOTSTRAP_FALCON; - cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES; - cmd.falcon_id = falcon; - nvkm_msgqueue_post(priv, MSGQUEUE_MSG_PRIORITY_HIGH, &cmd.hdr, - acr_boot_falcon_callback, &completed, true); - - if (!wait_for_completion_timeout(&completed, msecs_to_jiffies(1000))) - return -ETIMEDOUT; - - 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) -{ - kfree(msgqueue_0137c63d(queue)); -} - -static const struct nvkm_msgqueue_func -msgqueue_0137c63d_func = { - .init_func = &msgqueue_0137c63d_init_func, - .acr_func = &msgqueue_0137c63d_acr_func, - .cmd_queue = msgqueue_0137c63d_cmd_queue, - .recv = msgqueue_0137c63d_process_msgs, - .dtor = msgqueue_0137c63d_dtor, -}; - -int -msgqueue_0137c63d_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb, - struct nvkm_msgqueue **queue) -{ - struct msgqueue_0137c63d *ret; - - ret = kzalloc(sizeof(*ret), GFP_KERNEL); - if (!ret) - return -ENOMEM; - - *queue = &ret->base; - - nvkm_msgqueue_ctor(&msgqueue_0137c63d_func, falcon, &ret->base); - - 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; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c b/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c deleted file mode 100644 index 9424803b9ef4..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/msgqueue_0148cdec.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include "msgqueue.h" -#include <engine/falcon.h> -#include <subdev/secboot.h> - -/* - * This firmware runs on the SEC falcon. It only has one command and one - * 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; - - struct nvkm_msgqueue_queue queue[MSGQUEUE_0148CDEC_NUM_QUEUES]; -}; -#define msgqueue_0148cdec(q) \ - container_of(q, struct msgqueue_0148cdec, base) - -static struct nvkm_msgqueue_queue * -msgqueue_0148cdec_cmd_queue(struct nvkm_msgqueue *queue, - enum msgqueue_msg_priority priority) -{ - struct msgqueue_0148cdec *priv = msgqueue_0148cdec(queue); - - return &priv->queue[MSGQUEUE_0148CDEC_COMMAND_QUEUE]; -} - -static void -msgqueue_0148cdec_process_msgs(struct nvkm_msgqueue *queue) -{ - struct msgqueue_0148cdec *priv = msgqueue_0148cdec(queue); - struct nvkm_msgqueue_queue *q_queue = - &priv->queue[MSGQUEUE_0148CDEC_MESSAGE_QUEUE]; - - nvkm_msgqueue_process_msgs(&priv->base, q_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) -{ - struct { - u32 freq_hz; - u32 falc_trace_size; - u32 falc_trace_dma_base; - u32 falc_trace_dma_idx; - bool secure_mode; - } *args = buf; - - args->secure_mode = false; -} - -static int -init_callback(struct nvkm_msgqueue *_queue, struct nvkm_msgqueue_hdr *hdr) -{ - struct msgqueue_0148cdec *priv = msgqueue_0148cdec(_queue); - 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; - 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; - struct nvkm_msgqueue_queue *queue = &priv->queue[id]; - - mutex_init(&queue->mutex); - - queue->index = init->queue_info[i].index; - queue->offset = init->queue_info[i].offset; - queue->size = init->queue_info[i].size; - - if (id == MSGQUEUE_0148CDEC_MESSAGE_QUEUE) { - queue->head_reg = 0xa30 + (queue->index * 8); - queue->tail_reg = 0xa34 + (queue->index * 8); - } else { - queue->head_reg = 0xa00 + (queue->index * 8); - queue->tail_reg = 0xa04 + (queue->index * 8); - } - - nvkm_debug(subdev, - "queue %d: index %d, offset 0x%08x, size 0x%08x\n", - id, queue->index, queue->offset, queue->size); - } - - complete_all(&_queue->init_done); - - return 0; -} - -static const struct nvkm_msgqueue_init_func -msgqueue_0148cdec_init_func = { - .gen_cmdline = init_gen_cmdline, - .init_callback = init_callback, -}; - - - -/* ACR unit */ -#define MSGQUEUE_0148CDEC_UNIT_ACR 0x08 - -enum { - ACR_CMD_BOOTSTRAP_FALCON = 0x00, -}; - -static void -acr_boot_falcon_callback(struct nvkm_msgqueue *priv, - struct nvkm_msgqueue_hdr *hdr) -{ - struct acr_bootstrap_falcon_msg { - struct nvkm_msgqueue_msg base; - - u32 error_code; - u32 falcon_id; - } *msg = (void *)hdr; - const struct nvkm_subdev *subdev = priv->falcon->owner; - u32 falcon_id = msg->falcon_id; - - if (msg->error_code) { - nvkm_error(subdev, "in bootstrap falcon callback:\n"); - nvkm_error(subdev, "expected error code 0x%x\n", - msg->error_code); - return; - } - - if (falcon_id >= NVKM_SECBOOT_FALCON_END) { - nvkm_error(subdev, "in bootstrap falcon callback:\n"); - nvkm_error(subdev, "invalid falcon ID 0x%x\n", falcon_id); - return; - } - - nvkm_debug(subdev, "%s booted\n", nvkm_secboot_falcon_name[falcon_id]); -} - -enum { - ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES = 0, - ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_NO = 1, -}; - -static int -acr_boot_falcon(struct nvkm_msgqueue *priv, enum nvkm_secboot_falcon falcon) -{ - 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_id; - } cmd; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.hdr.unit_id = MSGQUEUE_0148CDEC_UNIT_ACR; - cmd.hdr.size = sizeof(cmd); - cmd.cmd_type = ACR_CMD_BOOTSTRAP_FALCON; - cmd.flags = ACR_CMD_BOOTSTRAP_FALCON_FLAGS_RESET_YES; - cmd.falcon_id = falcon; - nvkm_msgqueue_post(priv, MSGQUEUE_MSG_PRIORITY_HIGH, &cmd.hdr, - acr_boot_falcon_callback, &completed, true); - - if (!wait_for_completion_timeout(&completed, msecs_to_jiffies(1000))) - return -ETIMEDOUT; - - return 0; -} - -const struct nvkm_msgqueue_acr_func -msgqueue_0148cdec_acr_func = { - .boot_falcon = acr_boot_falcon, -}; - -static void -msgqueue_0148cdec_dtor(struct nvkm_msgqueue *queue) -{ - kfree(msgqueue_0148cdec(queue)); -} - -const struct nvkm_msgqueue_func -msgqueue_0148cdec_func = { - .init_func = &msgqueue_0148cdec_init_func, - .acr_func = &msgqueue_0148cdec_acr_func, - .cmd_queue = msgqueue_0148cdec_cmd_queue, - .recv = msgqueue_0148cdec_process_msgs, - .dtor = msgqueue_0148cdec_dtor, -}; - -int -msgqueue_0148cdec_new(struct nvkm_falcon *falcon, const struct nvkm_secboot *sb, - struct nvkm_msgqueue **queue) -{ - struct msgqueue_0148cdec *ret; - - ret = kzalloc(sizeof(*ret), GFP_KERNEL); - if (!ret) - return -ENOMEM; - - *queue = &ret->base; - - nvkm_msgqueue_ctor(&msgqueue_0148cdec_func, falcon, &ret->base); - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h b/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h index 900fe1d37b4d..466188752eb0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/priv.h @@ -1,9 +1,5 @@ /* SPDX-License-Identifier: MIT */ #ifndef __NVKM_FALCON_PRIV_H__ #define __NVKM_FALCON_PRIV_H__ -#include <engine/falcon.h> - -void -nvkm_falcon_ctor(const struct nvkm_falcon_func *, struct nvkm_subdev *, - const char *, u32, struct nvkm_falcon *); +#include <core/falcon.h> #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.c b/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.c new file mode 100644 index 000000000000..a453de341a75 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ +#include "qmgr.h" + +struct nvkm_falcon_qmgr_seq * +nvkm_falcon_qmgr_seq_acquire(struct nvkm_falcon_qmgr *qmgr) +{ + const struct nvkm_subdev *subdev = qmgr->falcon->owner; + struct nvkm_falcon_qmgr_seq *seq; + u32 index; + + mutex_lock(&qmgr->seq.mutex); + index = find_first_zero_bit(qmgr->seq.tbl, NVKM_FALCON_QMGR_SEQ_NUM); + if (index >= NVKM_FALCON_QMGR_SEQ_NUM) { + nvkm_error(subdev, "no free sequence available\n"); + mutex_unlock(&qmgr->seq.mutex); + return ERR_PTR(-EAGAIN); + } + + set_bit(index, qmgr->seq.tbl); + mutex_unlock(&qmgr->seq.mutex); + + seq = &qmgr->seq.id[index]; + seq->state = SEQ_STATE_PENDING; + return seq; +} + +void +nvkm_falcon_qmgr_seq_release(struct nvkm_falcon_qmgr *qmgr, + struct nvkm_falcon_qmgr_seq *seq) +{ + /* no need to acquire seq.mutex since clear_bit is atomic */ + seq->state = SEQ_STATE_FREE; + seq->callback = NULL; + reinit_completion(&seq->done); + clear_bit(seq->id, qmgr->seq.tbl); +} + +void +nvkm_falcon_qmgr_del(struct nvkm_falcon_qmgr **pqmgr) +{ + struct nvkm_falcon_qmgr *qmgr = *pqmgr; + if (qmgr) { + kfree(*pqmgr); + *pqmgr = NULL; + } +} + +int +nvkm_falcon_qmgr_new(struct nvkm_falcon *falcon, + struct nvkm_falcon_qmgr **pqmgr) +{ + struct nvkm_falcon_qmgr *qmgr; + int i; + + if (!(qmgr = *pqmgr = kzalloc(sizeof(*qmgr), GFP_KERNEL))) + return -ENOMEM; + + qmgr->falcon = falcon; + mutex_init(&qmgr->seq.mutex); + for (i = 0; i < NVKM_FALCON_QMGR_SEQ_NUM; i++) { + qmgr->seq.id[i].id = i; + init_completion(&qmgr->seq.id[i].done); + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h b/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h new file mode 100644 index 000000000000..a45cd705e4f7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/qmgr.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NVKM_FALCON_QMGR_H__ +#define __NVKM_FALCON_QMGR_H__ +#include <core/falcon.h> + +#define HDR_SIZE sizeof(struct nv_falcon_msg) +#define QUEUE_ALIGNMENT 4 +/* max size of the messages we can receive */ +#define MSG_BUF_SIZE 128 + +/** + * struct nvkm_falcon_qmgr_seq - keep track of ongoing commands + * + * Every time a command is sent, a sequence is assigned to it so the + * corresponding message can be matched. Upon receiving the message, a callback + * can be called and/or a completion signaled. + * + * @id: sequence ID + * @state: current state + * @callback: callback to call upon receiving matching message + * @completion: completion to signal after callback is called + */ +struct nvkm_falcon_qmgr_seq { + u16 id; + enum { + SEQ_STATE_FREE = 0, + SEQ_STATE_PENDING, + SEQ_STATE_USED, + SEQ_STATE_CANCELLED + } state; + bool async; + nvkm_falcon_qmgr_callback callback; + void *priv; + struct completion done; + int result; +}; + +/* + * We can have an arbitrary number of sequences, but realistically we will + * probably not use that much simultaneously. + */ +#define NVKM_FALCON_QMGR_SEQ_NUM 16 + +struct nvkm_falcon_qmgr { + struct nvkm_falcon *falcon; + + struct { + struct mutex mutex; + struct nvkm_falcon_qmgr_seq id[NVKM_FALCON_QMGR_SEQ_NUM]; + unsigned long tbl[BITS_TO_LONGS(NVKM_FALCON_QMGR_SEQ_NUM)]; + } seq; +}; + +struct nvkm_falcon_qmgr_seq * +nvkm_falcon_qmgr_seq_acquire(struct nvkm_falcon_qmgr *); +void nvkm_falcon_qmgr_seq_release(struct nvkm_falcon_qmgr *, + struct nvkm_falcon_qmgr_seq *); + +struct nvkm_falcon_cmdq { + struct nvkm_falcon_qmgr *qmgr; + const char *name; + struct mutex mutex; + struct completion ready; + + u32 head_reg; + u32 tail_reg; + u32 offset; + u32 size; + + u32 position; +}; + +struct nvkm_falcon_msgq { + struct nvkm_falcon_qmgr *qmgr; + const char *name; + struct mutex mutex; + + u32 head_reg; + u32 tail_reg; + u32 offset; + + u32 position; +}; + +#define FLCNQ_PRINTK(t,q,f,a...) \ + FLCN_PRINTK(t, (q)->qmgr->falcon, "%s: "f, (q)->name, ##a) +#define FLCNQ_DBG(q,f,a...) FLCNQ_PRINTK(debug, (q), f, ##a) +#define FLCNQ_ERR(q,f,a...) FLCNQ_PRINTK(error, (q), f, ##a) +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c b/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c index 6d978feebbd7..1ff9b9c2e651 100644 --- a/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c +++ b/drivers/gpu/drm/nouveau/nvkm/falcon/v1.c @@ -25,7 +25,7 @@ #include <core/memory.h> #include <subdev/timer.h> -static void +void nvkm_falcon_v1_load_imem(struct nvkm_falcon *falcon, void *data, u32 start, u32 size, u16 tag, u8 port, bool secure) { @@ -89,18 +89,17 @@ nvkm_falcon_v1_load_emem(struct nvkm_falcon *falcon, void *data, u32 start, } } -static const u32 EMEM_START_ADDR = 0x1000000; - -static void +void nvkm_falcon_v1_load_dmem(struct nvkm_falcon *falcon, void *data, u32 start, - u32 size, u8 port) + u32 size, u8 port) { + const struct nvkm_falcon_func *func = falcon->func; u8 rem = size % 4; int i; - if (start >= EMEM_START_ADDR && falcon->has_emem) + if (func->emem_addr && start >= func->emem_addr) return nvkm_falcon_v1_load_emem(falcon, data, - start - EMEM_START_ADDR, size, + start - func->emem_addr, size, port); size -= rem; @@ -148,15 +147,16 @@ nvkm_falcon_v1_read_emem(struct nvkm_falcon *falcon, u32 start, u32 size, } } -static void +void nvkm_falcon_v1_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size, u8 port, void *data) { + const struct nvkm_falcon_func *func = falcon->func; u8 rem = size % 4; int i; - if (start >= EMEM_START_ADDR && falcon->has_emem) - return nvkm_falcon_v1_read_emem(falcon, start - EMEM_START_ADDR, + if (func->emem_addr && start >= func->emem_addr) + return nvkm_falcon_v1_read_emem(falcon, start - func->emem_addr, size, port, data); size -= rem; @@ -179,12 +179,11 @@ nvkm_falcon_v1_read_dmem(struct nvkm_falcon *falcon, u32 start, u32 size, } } -static void +void nvkm_falcon_v1_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *ctx) { - struct nvkm_device *device = falcon->owner->device; + const u32 fbif = falcon->func->fbif; u32 inst_loc; - u32 fbif; /* disable instance block binding */ if (ctx == NULL) { @@ -192,20 +191,6 @@ nvkm_falcon_v1_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *ctx) return; } - switch (falcon->owner->index) { - case NVKM_ENGINE_NVENC0: - case NVKM_ENGINE_NVENC1: - case NVKM_ENGINE_NVENC2: - fbif = 0x800; - break; - case NVKM_SUBDEV_PMU: - fbif = 0xe00; - break; - default: - fbif = 0x600; - break; - } - nvkm_falcon_wr32(falcon, 0x10c, 0x1); /* setup apertures - virtual */ @@ -234,50 +219,15 @@ nvkm_falcon_v1_bind_context(struct nvkm_falcon *falcon, struct nvkm_memory *ctx) nvkm_falcon_mask(falcon, 0x090, 0x10000, 0x10000); nvkm_falcon_mask(falcon, 0x0a4, 0x8, 0x8); - - /* Not sure if this is a WAR for a HW issue, or some additional - * programming sequence that's needed to properly complete the - * context switch we trigger above. - * - * Fixes unreliability of booting the SEC2 RTOS on Quadro P620, - * particularly when resuming from suspend. - * - * Also removes the need for an odd workaround where we needed - * to program SEC2's FALCON_CPUCTL_ALIAS_STARTCPU twice before - * the SEC2 RTOS would begin executing. - */ - switch (falcon->owner->index) { - case NVKM_SUBDEV_GSP: - case NVKM_ENGINE_SEC2: - nvkm_msec(device, 10, - u32 irqstat = nvkm_falcon_rd32(falcon, 0x008); - u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc); - if ((irqstat & 0x00000008) && - (flcn0dc & 0x00007000) == 0x00005000) - break; - ); - - nvkm_falcon_mask(falcon, 0x004, 0x00000008, 0x00000008); - nvkm_falcon_mask(falcon, 0x058, 0x00000002, 0x00000002); - - nvkm_msec(device, 10, - u32 flcn0dc = nvkm_falcon_rd32(falcon, 0x0dc); - if ((flcn0dc & 0x00007000) == 0x00000000) - break; - ); - break; - default: - break; - } } -static void +void nvkm_falcon_v1_set_start_addr(struct nvkm_falcon *falcon, u32 start_addr) { nvkm_falcon_wr32(falcon, 0x104, start_addr); } -static void +void nvkm_falcon_v1_start(struct nvkm_falcon *falcon) { u32 reg = nvkm_falcon_rd32(falcon, 0x100); @@ -288,7 +238,7 @@ nvkm_falcon_v1_start(struct nvkm_falcon *falcon) nvkm_falcon_wr32(falcon, 0x100, 0x2); } -static int +int nvkm_falcon_v1_wait_for_halt(struct nvkm_falcon *falcon, u32 ms) { struct nvkm_device *device = falcon->owner->device; @@ -301,7 +251,7 @@ nvkm_falcon_v1_wait_for_halt(struct nvkm_falcon *falcon, u32 ms) return 0; } -static int +int nvkm_falcon_v1_clear_interrupt(struct nvkm_falcon *falcon, u32 mask) { struct nvkm_device *device = falcon->owner->device; @@ -330,7 +280,7 @@ falcon_v1_wait_idle(struct nvkm_falcon *falcon) return 0; } -static int +int nvkm_falcon_v1_enable(struct nvkm_falcon *falcon) { struct nvkm_device *device = falcon->owner->device; @@ -352,7 +302,7 @@ nvkm_falcon_v1_enable(struct nvkm_falcon *falcon) return 0; } -static void +void nvkm_falcon_v1_disable(struct nvkm_falcon *falcon) { /* disable IRQs and wait for any previous code to complete */ |