17e1659ccSBen Skeggs /*
27e1659ccSBen Skeggs * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
37e1659ccSBen Skeggs *
47e1659ccSBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
57e1659ccSBen Skeggs * copy of this software and associated documentation files (the "Software"),
67e1659ccSBen Skeggs * to deal in the Software without restriction, including without limitation
77e1659ccSBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87e1659ccSBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
97e1659ccSBen Skeggs * Software is furnished to do so, subject to the following conditions:
107e1659ccSBen Skeggs *
117e1659ccSBen Skeggs * The above copyright notice and this permission notice shall be included in
127e1659ccSBen Skeggs * all copies or substantial portions of the Software.
137e1659ccSBen Skeggs *
147e1659ccSBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157e1659ccSBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
167e1659ccSBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
177e1659ccSBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
187e1659ccSBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
197e1659ccSBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
207e1659ccSBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
217e1659ccSBen Skeggs *
227e1659ccSBen Skeggs */
237e1659ccSBen Skeggs #include "qmgr.h"
247e1659ccSBen Skeggs
25f09a3ee3SBen Skeggs static void
nvkm_falcon_msgq_open(struct nvkm_falcon_msgq * msgq)2691a4e83aSBen Skeggs nvkm_falcon_msgq_open(struct nvkm_falcon_msgq *msgq)
277e1659ccSBen Skeggs {
283b330f08SBen Skeggs spin_lock(&msgq->lock);
2991a4e83aSBen Skeggs msgq->position = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->tail_reg);
307e1659ccSBen Skeggs }
317e1659ccSBen Skeggs
327e1659ccSBen Skeggs static void
nvkm_falcon_msgq_close(struct nvkm_falcon_msgq * msgq,bool commit)3391a4e83aSBen Skeggs nvkm_falcon_msgq_close(struct nvkm_falcon_msgq *msgq, bool commit)
347e1659ccSBen Skeggs {
3591a4e83aSBen Skeggs struct nvkm_falcon *falcon = msgq->qmgr->falcon;
367e1659ccSBen Skeggs
377e1659ccSBen Skeggs if (commit)
3891a4e83aSBen Skeggs nvkm_falcon_wr32(falcon, msgq->tail_reg, msgq->position);
397e1659ccSBen Skeggs
403b330f08SBen Skeggs spin_unlock(&msgq->lock);
417e1659ccSBen Skeggs }
427e1659ccSBen Skeggs
433b330f08SBen Skeggs bool
nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq * msgq)4491a4e83aSBen Skeggs nvkm_falcon_msgq_empty(struct nvkm_falcon_msgq *msgq)
457e1659ccSBen Skeggs {
4691a4e83aSBen Skeggs u32 head = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->head_reg);
4791a4e83aSBen Skeggs u32 tail = nvkm_falcon_rd32(msgq->qmgr->falcon, msgq->tail_reg);
487e1659ccSBen Skeggs return head == tail;
497e1659ccSBen Skeggs }
507e1659ccSBen Skeggs
517e1659ccSBen Skeggs static int
nvkm_falcon_msgq_pop(struct nvkm_falcon_msgq * msgq,void * data,u32 size)5291a4e83aSBen Skeggs nvkm_falcon_msgq_pop(struct nvkm_falcon_msgq *msgq, void *data, u32 size)
537e1659ccSBen Skeggs {
5491a4e83aSBen Skeggs struct nvkm_falcon *falcon = msgq->qmgr->falcon;
557e1659ccSBen Skeggs u32 head, tail, available;
567e1659ccSBen Skeggs
5791a4e83aSBen Skeggs head = nvkm_falcon_rd32(falcon, msgq->head_reg);
587e1659ccSBen Skeggs /* has the buffer looped? */
5991a4e83aSBen Skeggs if (head < msgq->position)
6091a4e83aSBen Skeggs msgq->position = msgq->offset;
617e1659ccSBen Skeggs
6291a4e83aSBen Skeggs tail = msgq->position;
637e1659ccSBen Skeggs
647e1659ccSBen Skeggs available = head - tail;
657e1659ccSBen Skeggs if (size > available) {
6691a4e83aSBen Skeggs FLCNQ_ERR(msgq, "requested %d bytes, but only %d available",
6777b1ab61SBen Skeggs size, available);
68e9602a1bSBen Skeggs return -EINVAL;
697e1659ccSBen Skeggs }
707e1659ccSBen Skeggs
71*2541626cSBen Skeggs nvkm_falcon_pio_rd(falcon, 0, DMEM, tail, data, 0, size);
7291a4e83aSBen Skeggs msgq->position += ALIGN(size, QUEUE_ALIGNMENT);
73e9602a1bSBen Skeggs return 0;
747e1659ccSBen Skeggs }
757e1659ccSBen Skeggs
767e1659ccSBen Skeggs static int
nvkm_falcon_msgq_read(struct nvkm_falcon_msgq * msgq,struct nvfw_falcon_msg * hdr)77b448a266STimur Tabi nvkm_falcon_msgq_read(struct nvkm_falcon_msgq *msgq, struct nvfw_falcon_msg *hdr)
787e1659ccSBen Skeggs {
79e9602a1bSBen Skeggs int ret = 0;
807e1659ccSBen Skeggs
8191a4e83aSBen Skeggs nvkm_falcon_msgq_open(msgq);
827e1659ccSBen Skeggs
8391a4e83aSBen Skeggs if (nvkm_falcon_msgq_empty(msgq))
847e1659ccSBen Skeggs goto close;
857e1659ccSBen Skeggs
8691a4e83aSBen Skeggs ret = nvkm_falcon_msgq_pop(msgq, hdr, HDR_SIZE);
87e9602a1bSBen Skeggs if (ret) {
8891a4e83aSBen Skeggs FLCNQ_ERR(msgq, "failed to read message header");
897e1659ccSBen Skeggs goto close;
907e1659ccSBen Skeggs }
917e1659ccSBen Skeggs
927e1659ccSBen Skeggs if (hdr->size > MSG_BUF_SIZE) {
9391a4e83aSBen Skeggs FLCNQ_ERR(msgq, "message too big, %d bytes", hdr->size);
947e1659ccSBen Skeggs ret = -ENOSPC;
957e1659ccSBen Skeggs goto close;
967e1659ccSBen Skeggs }
977e1659ccSBen Skeggs
987e1659ccSBen Skeggs if (hdr->size > HDR_SIZE) {
997e1659ccSBen Skeggs u32 read_size = hdr->size - HDR_SIZE;
1007e1659ccSBen Skeggs
10191a4e83aSBen Skeggs ret = nvkm_falcon_msgq_pop(msgq, (hdr + 1), read_size);
102e9602a1bSBen Skeggs if (ret) {
10391a4e83aSBen Skeggs FLCNQ_ERR(msgq, "failed to read message data");
1047e1659ccSBen Skeggs goto close;
1057e1659ccSBen Skeggs }
1067e1659ccSBen Skeggs }
1077e1659ccSBen Skeggs
108e9602a1bSBen Skeggs ret = 1;
1097e1659ccSBen Skeggs close:
11091a4e83aSBen Skeggs nvkm_falcon_msgq_close(msgq, (ret >= 0));
1117e1659ccSBen Skeggs return ret;
1127e1659ccSBen Skeggs }
1137e1659ccSBen Skeggs
1147e1659ccSBen Skeggs static int
nvkm_falcon_msgq_exec(struct nvkm_falcon_msgq * msgq,struct nvfw_falcon_msg * hdr)115b448a266STimur Tabi nvkm_falcon_msgq_exec(struct nvkm_falcon_msgq *msgq, struct nvfw_falcon_msg *hdr)
1167e1659ccSBen Skeggs {
117a15d8f58SBen Skeggs struct nvkm_falcon_qmgr_seq *seq;
1187e1659ccSBen Skeggs
119a15d8f58SBen Skeggs seq = &msgq->qmgr->seq.id[hdr->seq_id];
1207e1659ccSBen Skeggs if (seq->state != SEQ_STATE_USED && seq->state != SEQ_STATE_CANCELLED) {
12177b1ab61SBen Skeggs FLCNQ_ERR(msgq, "message for unknown sequence %08x", seq->id);
1227e1659ccSBen Skeggs return -EINVAL;
1237e1659ccSBen Skeggs }
1247e1659ccSBen Skeggs
1257e1659ccSBen Skeggs if (seq->state == SEQ_STATE_USED) {
1267e1659ccSBen Skeggs if (seq->callback)
127c80157a2SBen Skeggs seq->result = seq->callback(seq->priv, hdr);
1287e1659ccSBen Skeggs }
1297e1659ccSBen Skeggs
1308e90a98dSBen Skeggs if (seq->async) {
1310ae59432SBen Skeggs nvkm_falcon_qmgr_seq_release(msgq->qmgr, seq);
1327e1659ccSBen Skeggs return 0;
1337e1659ccSBen Skeggs }
1347e1659ccSBen Skeggs
1358e90a98dSBen Skeggs complete_all(&seq->done);
1368e90a98dSBen Skeggs return 0;
1378e90a98dSBen Skeggs }
1388e90a98dSBen Skeggs
13991a4e83aSBen Skeggs void
nvkm_falcon_msgq_recv(struct nvkm_falcon_msgq * msgq)14091a4e83aSBen Skeggs nvkm_falcon_msgq_recv(struct nvkm_falcon_msgq *msgq)
14191a4e83aSBen Skeggs {
14291a4e83aSBen Skeggs /*
14391a4e83aSBen Skeggs * We are invoked from a worker thread, so normally we have plenty of
14491a4e83aSBen Skeggs * stack space to work with.
14591a4e83aSBen Skeggs */
14691a4e83aSBen Skeggs u8 msg_buffer[MSG_BUF_SIZE];
147b448a266STimur Tabi struct nvfw_falcon_msg *hdr = (void *)msg_buffer;
14891a4e83aSBen Skeggs
14991a4e83aSBen Skeggs while (nvkm_falcon_msgq_read(msgq, hdr) > 0)
15091a4e83aSBen Skeggs nvkm_falcon_msgq_exec(msgq, hdr);
15191a4e83aSBen Skeggs }
15291a4e83aSBen Skeggs
153d114a139SBen Skeggs int
nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq * msgq,void * data,u32 size)154d114a139SBen Skeggs nvkm_falcon_msgq_recv_initmsg(struct nvkm_falcon_msgq *msgq,
155d114a139SBen Skeggs void *data, u32 size)
1567e1659ccSBen Skeggs {
157d114a139SBen Skeggs struct nvkm_falcon *falcon = msgq->qmgr->falcon;
158b448a266STimur Tabi struct nvfw_falcon_msg *hdr = data;
1597e1659ccSBen Skeggs int ret;
1607e1659ccSBen Skeggs
161d114a139SBen Skeggs msgq->head_reg = falcon->func->msgq.head;
162d114a139SBen Skeggs msgq->tail_reg = falcon->func->msgq.tail;
163d114a139SBen Skeggs msgq->offset = nvkm_falcon_rd32(falcon, falcon->func->msgq.tail);
1647e1659ccSBen Skeggs
16591a4e83aSBen Skeggs nvkm_falcon_msgq_open(msgq);
16691a4e83aSBen Skeggs ret = nvkm_falcon_msgq_pop(msgq, data, size);
167d114a139SBen Skeggs if (ret == 0 && hdr->size != size) {
168d114a139SBen Skeggs FLCN_ERR(falcon, "unexpected init message size %d vs %d",
169d114a139SBen Skeggs hdr->size, size);
170d114a139SBen Skeggs ret = -EINVAL;
1717e1659ccSBen Skeggs }
17291a4e83aSBen Skeggs nvkm_falcon_msgq_close(msgq, ret == 0);
1737e1659ccSBen Skeggs return ret;
1747e1659ccSBen Skeggs }
1757e1659ccSBen Skeggs
1767e1659ccSBen Skeggs void
nvkm_falcon_msgq_init(struct nvkm_falcon_msgq * msgq,u32 index,u32 offset,u32 size)17722431189SBen Skeggs nvkm_falcon_msgq_init(struct nvkm_falcon_msgq *msgq,
17822431189SBen Skeggs u32 index, u32 offset, u32 size)
17922431189SBen Skeggs {
18022431189SBen Skeggs const struct nvkm_falcon_func *func = msgq->qmgr->falcon->func;
18122431189SBen Skeggs
18222431189SBen Skeggs msgq->head_reg = func->msgq.head + index * func->msgq.stride;
18322431189SBen Skeggs msgq->tail_reg = func->msgq.tail + index * func->msgq.stride;
18422431189SBen Skeggs msgq->offset = offset;
18522431189SBen Skeggs
18622431189SBen Skeggs FLCNQ_DBG(msgq, "initialised @ index %d offset 0x%08x size 0x%08x",
18722431189SBen Skeggs index, msgq->offset, size);
18822431189SBen Skeggs }
18922431189SBen Skeggs
19022431189SBen Skeggs void
nvkm_falcon_msgq_del(struct nvkm_falcon_msgq ** pmsgq)19122431189SBen Skeggs nvkm_falcon_msgq_del(struct nvkm_falcon_msgq **pmsgq)
19222431189SBen Skeggs {
19322431189SBen Skeggs struct nvkm_falcon_msgq *msgq = *pmsgq;
19422431189SBen Skeggs if (msgq) {
19522431189SBen Skeggs kfree(*pmsgq);
19622431189SBen Skeggs *pmsgq = NULL;
19722431189SBen Skeggs }
19822431189SBen Skeggs }
19922431189SBen Skeggs
20022431189SBen Skeggs int
nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr * qmgr,const char * name,struct nvkm_falcon_msgq ** pmsgq)20122431189SBen Skeggs nvkm_falcon_msgq_new(struct nvkm_falcon_qmgr *qmgr, const char *name,
20222431189SBen Skeggs struct nvkm_falcon_msgq **pmsgq)
20322431189SBen Skeggs {
20422431189SBen Skeggs struct nvkm_falcon_msgq *msgq = *pmsgq;
20522431189SBen Skeggs
20622431189SBen Skeggs if (!(msgq = *pmsgq = kzalloc(sizeof(*msgq), GFP_KERNEL)))
20722431189SBen Skeggs return -ENOMEM;
20822431189SBen Skeggs
20922431189SBen Skeggs msgq->qmgr = qmgr;
21022431189SBen Skeggs msgq->name = name;
2113b330f08SBen Skeggs spin_lock_init(&msgq->lock);
21222431189SBen Skeggs return 0;
21322431189SBen Skeggs }
214