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