xref: /openbmc/linux/drivers/accel/qaic/qaic_control.c (revision e50e86dbcabda570fc8a1435fe2fca97e9ab7312)
1129776acSJeffrey Hugo // SPDX-License-Identifier: GPL-2.0-only
2129776acSJeffrey Hugo 
3129776acSJeffrey Hugo /* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. */
4129776acSJeffrey Hugo /* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. */
5129776acSJeffrey Hugo 
6129776acSJeffrey Hugo #include <asm/byteorder.h>
7129776acSJeffrey Hugo #include <linux/completion.h>
8129776acSJeffrey Hugo #include <linux/crc32.h>
9129776acSJeffrey Hugo #include <linux/delay.h>
10129776acSJeffrey Hugo #include <linux/dma-mapping.h>
11129776acSJeffrey Hugo #include <linux/kref.h>
12129776acSJeffrey Hugo #include <linux/list.h>
13129776acSJeffrey Hugo #include <linux/mhi.h>
14129776acSJeffrey Hugo #include <linux/mm.h>
15129776acSJeffrey Hugo #include <linux/moduleparam.h>
16129776acSJeffrey Hugo #include <linux/mutex.h>
17ea33cb6fSDan Carpenter #include <linux/overflow.h>
18129776acSJeffrey Hugo #include <linux/pci.h>
19129776acSJeffrey Hugo #include <linux/scatterlist.h>
20129776acSJeffrey Hugo #include <linux/types.h>
21129776acSJeffrey Hugo #include <linux/uaccess.h>
22129776acSJeffrey Hugo #include <linux/workqueue.h>
23129776acSJeffrey Hugo #include <linux/wait.h>
24129776acSJeffrey Hugo #include <drm/drm_device.h>
25129776acSJeffrey Hugo #include <drm/drm_file.h>
26129776acSJeffrey Hugo #include <uapi/drm/qaic_accel.h>
27129776acSJeffrey Hugo 
28129776acSJeffrey Hugo #include "qaic.h"
29129776acSJeffrey Hugo 
30129776acSJeffrey Hugo #define MANAGE_MAGIC_NUMBER		((__force __le32)0x43494151) /* "QAIC" in little endian */
31129776acSJeffrey Hugo #define QAIC_DBC_Q_GAP			SZ_256
32129776acSJeffrey Hugo #define QAIC_DBC_Q_BUF_ALIGN		SZ_4K
33129776acSJeffrey Hugo #define QAIC_MANAGE_EXT_MSG_LENGTH	SZ_64K /* Max DMA message length */
34129776acSJeffrey Hugo #define QAIC_WRAPPER_MAX_SIZE		SZ_4K
35129776acSJeffrey Hugo #define QAIC_MHI_RETRY_WAIT_MS		100
36129776acSJeffrey Hugo #define QAIC_MHI_RETRY_MAX		20
37129776acSJeffrey Hugo 
38129776acSJeffrey Hugo static unsigned int control_resp_timeout_s = 60; /* 60 sec default */
39129776acSJeffrey Hugo module_param(control_resp_timeout_s, uint, 0600);
40129776acSJeffrey Hugo MODULE_PARM_DESC(control_resp_timeout_s, "Timeout for NNC responses from QSM");
41129776acSJeffrey Hugo 
42129776acSJeffrey Hugo struct manage_msg {
43129776acSJeffrey Hugo 	u32 len;
44129776acSJeffrey Hugo 	u32 count;
45129776acSJeffrey Hugo 	u8 data[];
46129776acSJeffrey Hugo };
47129776acSJeffrey Hugo 
48129776acSJeffrey Hugo /*
49129776acSJeffrey Hugo  * wire encoding structures for the manage protocol.
50129776acSJeffrey Hugo  * All fields are little endian on the wire
51129776acSJeffrey Hugo  */
52129776acSJeffrey Hugo struct wire_msg_hdr {
53129776acSJeffrey Hugo 	__le32 crc32; /* crc of everything following this field in the message */
54129776acSJeffrey Hugo 	__le32 magic_number;
55129776acSJeffrey Hugo 	__le32 sequence_number;
56129776acSJeffrey Hugo 	__le32 len; /* length of this message */
57129776acSJeffrey Hugo 	__le32 count; /* number of transactions in this message */
58129776acSJeffrey Hugo 	__le32 handle; /* unique id to track the resources consumed */
59129776acSJeffrey Hugo 	__le32 partition_id; /* partition id for the request (signed) */
60129776acSJeffrey Hugo 	__le32 padding; /* must be 0 */
61129776acSJeffrey Hugo } __packed;
62129776acSJeffrey Hugo 
63129776acSJeffrey Hugo struct wire_msg {
64129776acSJeffrey Hugo 	struct wire_msg_hdr hdr;
65129776acSJeffrey Hugo 	u8 data[];
66129776acSJeffrey Hugo } __packed;
67129776acSJeffrey Hugo 
68129776acSJeffrey Hugo struct wire_trans_hdr {
69129776acSJeffrey Hugo 	__le32 type;
70129776acSJeffrey Hugo 	__le32 len;
71129776acSJeffrey Hugo } __packed;
72129776acSJeffrey Hugo 
73129776acSJeffrey Hugo /* Each message sent from driver to device are organized in a list of wrapper_msg */
74129776acSJeffrey Hugo struct wrapper_msg {
75129776acSJeffrey Hugo 	struct list_head list;
76129776acSJeffrey Hugo 	struct kref ref_count;
77129776acSJeffrey Hugo 	u32 len; /* length of data to transfer */
78129776acSJeffrey Hugo 	struct wrapper_list *head;
79129776acSJeffrey Hugo 	union {
80129776acSJeffrey Hugo 		struct wire_msg msg;
81129776acSJeffrey Hugo 		struct wire_trans_hdr trans;
82129776acSJeffrey Hugo 	};
83129776acSJeffrey Hugo };
84129776acSJeffrey Hugo 
85129776acSJeffrey Hugo struct wrapper_list {
86129776acSJeffrey Hugo 	struct list_head list;
87129776acSJeffrey Hugo 	spinlock_t lock; /* Protects the list state during additions and removals */
88129776acSJeffrey Hugo };
89129776acSJeffrey Hugo 
90129776acSJeffrey Hugo struct wire_trans_passthrough {
91129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
92129776acSJeffrey Hugo 	u8 data[];
93129776acSJeffrey Hugo } __packed;
94129776acSJeffrey Hugo 
95129776acSJeffrey Hugo struct wire_addr_size_pair {
96129776acSJeffrey Hugo 	__le64 addr;
97129776acSJeffrey Hugo 	__le64 size;
98129776acSJeffrey Hugo } __packed;
99129776acSJeffrey Hugo 
100129776acSJeffrey Hugo struct wire_trans_dma_xfer {
101129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
102129776acSJeffrey Hugo 	__le32 tag;
103129776acSJeffrey Hugo 	__le32 count;
104129776acSJeffrey Hugo 	__le32 dma_chunk_id;
105129776acSJeffrey Hugo 	__le32 padding;
106129776acSJeffrey Hugo 	struct wire_addr_size_pair data[];
107129776acSJeffrey Hugo } __packed;
108129776acSJeffrey Hugo 
109129776acSJeffrey Hugo /* Initiated by device to continue the DMA xfer of a large piece of data */
110129776acSJeffrey Hugo struct wire_trans_dma_xfer_cont {
111129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
112129776acSJeffrey Hugo 	__le32 dma_chunk_id;
113129776acSJeffrey Hugo 	__le32 padding;
114129776acSJeffrey Hugo 	__le64 xferred_size;
115129776acSJeffrey Hugo } __packed;
116129776acSJeffrey Hugo 
117129776acSJeffrey Hugo struct wire_trans_activate_to_dev {
118129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
119129776acSJeffrey Hugo 	__le64 req_q_addr;
120129776acSJeffrey Hugo 	__le64 rsp_q_addr;
121129776acSJeffrey Hugo 	__le32 req_q_size;
122129776acSJeffrey Hugo 	__le32 rsp_q_size;
123129776acSJeffrey Hugo 	__le32 buf_len;
124129776acSJeffrey Hugo 	__le32 options; /* unused, but BIT(16) has meaning to the device */
125129776acSJeffrey Hugo } __packed;
126129776acSJeffrey Hugo 
127129776acSJeffrey Hugo struct wire_trans_activate_from_dev {
128129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
129129776acSJeffrey Hugo 	__le32 status;
130129776acSJeffrey Hugo 	__le32 dbc_id;
131129776acSJeffrey Hugo 	__le64 options; /* unused */
132129776acSJeffrey Hugo } __packed;
133129776acSJeffrey Hugo 
134129776acSJeffrey Hugo struct wire_trans_deactivate_from_dev {
135129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
136129776acSJeffrey Hugo 	__le32 status;
137129776acSJeffrey Hugo 	__le32 dbc_id;
138129776acSJeffrey Hugo } __packed;
139129776acSJeffrey Hugo 
140129776acSJeffrey Hugo struct wire_trans_terminate_to_dev {
141129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
142129776acSJeffrey Hugo 	__le32 handle;
143129776acSJeffrey Hugo 	__le32 padding;
144129776acSJeffrey Hugo } __packed;
145129776acSJeffrey Hugo 
146129776acSJeffrey Hugo struct wire_trans_terminate_from_dev {
147129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
148129776acSJeffrey Hugo 	__le32 status;
149129776acSJeffrey Hugo 	__le32 padding;
150129776acSJeffrey Hugo } __packed;
151129776acSJeffrey Hugo 
152129776acSJeffrey Hugo struct wire_trans_status_to_dev {
153129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
154129776acSJeffrey Hugo } __packed;
155129776acSJeffrey Hugo 
156129776acSJeffrey Hugo struct wire_trans_status_from_dev {
157129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
158129776acSJeffrey Hugo 	__le16 major;
159129776acSJeffrey Hugo 	__le16 minor;
160129776acSJeffrey Hugo 	__le32 status;
161129776acSJeffrey Hugo 	__le64 status_flags;
162129776acSJeffrey Hugo } __packed;
163129776acSJeffrey Hugo 
164129776acSJeffrey Hugo struct wire_trans_validate_part_to_dev {
165129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
166129776acSJeffrey Hugo 	__le32 part_id;
167129776acSJeffrey Hugo 	__le32 padding;
168129776acSJeffrey Hugo } __packed;
169129776acSJeffrey Hugo 
170129776acSJeffrey Hugo struct wire_trans_validate_part_from_dev {
171129776acSJeffrey Hugo 	struct wire_trans_hdr hdr;
172129776acSJeffrey Hugo 	__le32 status;
173129776acSJeffrey Hugo 	__le32 padding;
174129776acSJeffrey Hugo } __packed;
175129776acSJeffrey Hugo 
176129776acSJeffrey Hugo struct xfer_queue_elem {
177129776acSJeffrey Hugo 	/*
178129776acSJeffrey Hugo 	 * Node in list of ongoing transfer request on control channel.
179129776acSJeffrey Hugo 	 * Maintained by root device struct.
180129776acSJeffrey Hugo 	 */
181129776acSJeffrey Hugo 	struct list_head list;
182129776acSJeffrey Hugo 	/* Sequence number of this transfer request */
183129776acSJeffrey Hugo 	u32 seq_num;
184129776acSJeffrey Hugo 	/* This is used to wait on until completion of transfer request */
185129776acSJeffrey Hugo 	struct completion xfer_done;
186129776acSJeffrey Hugo 	/* Received data from device */
187129776acSJeffrey Hugo 	void *buf;
188129776acSJeffrey Hugo };
189129776acSJeffrey Hugo 
190129776acSJeffrey Hugo struct dma_xfer {
191129776acSJeffrey Hugo 	/* Node in list of DMA transfers which is used for cleanup */
192129776acSJeffrey Hugo 	struct list_head list;
193129776acSJeffrey Hugo 	/* SG table of memory used for DMA */
194129776acSJeffrey Hugo 	struct sg_table *sgt;
195129776acSJeffrey Hugo 	/* Array pages used for DMA */
196129776acSJeffrey Hugo 	struct page **page_list;
197129776acSJeffrey Hugo 	/* Number of pages used for DMA */
198129776acSJeffrey Hugo 	unsigned long nr_pages;
199129776acSJeffrey Hugo };
200129776acSJeffrey Hugo 
201129776acSJeffrey Hugo struct ioctl_resources {
202129776acSJeffrey Hugo 	/* List of all DMA transfers which is used later for cleanup */
203129776acSJeffrey Hugo 	struct list_head dma_xfers;
204129776acSJeffrey Hugo 	/* Base address of request queue which belongs to a DBC */
205129776acSJeffrey Hugo 	void *buf;
206129776acSJeffrey Hugo 	/*
207129776acSJeffrey Hugo 	 * Base bus address of request queue which belongs to a DBC. Response
208129776acSJeffrey Hugo 	 * queue base bus address can be calculated by adding size of request
209129776acSJeffrey Hugo 	 * queue to base bus address of request queue.
210129776acSJeffrey Hugo 	 */
211129776acSJeffrey Hugo 	dma_addr_t dma_addr;
212129776acSJeffrey Hugo 	/* Total size of request queue and response queue in byte */
213129776acSJeffrey Hugo 	u32 total_size;
214129776acSJeffrey Hugo 	/* Total number of elements that can be queued in each of request and response queue */
215129776acSJeffrey Hugo 	u32 nelem;
216129776acSJeffrey Hugo 	/* Base address of response queue which belongs to a DBC */
217129776acSJeffrey Hugo 	void *rsp_q_base;
218129776acSJeffrey Hugo 	/* Status of the NNC message received */
219129776acSJeffrey Hugo 	u32 status;
220129776acSJeffrey Hugo 	/* DBC id of the DBC received from device */
221129776acSJeffrey Hugo 	u32 dbc_id;
222129776acSJeffrey Hugo 	/*
223129776acSJeffrey Hugo 	 * DMA transfer request messages can be big in size and it may not be
224129776acSJeffrey Hugo 	 * possible to send them in one shot. In such cases the messages are
225129776acSJeffrey Hugo 	 * broken into chunks, this field stores ID of such chunks.
226129776acSJeffrey Hugo 	 */
227129776acSJeffrey Hugo 	u32 dma_chunk_id;
228129776acSJeffrey Hugo 	/* Total number of bytes transferred for a DMA xfer request */
229129776acSJeffrey Hugo 	u64 xferred_dma_size;
230129776acSJeffrey Hugo 	/* Header of transaction message received from user. Used during DMA xfer request. */
231129776acSJeffrey Hugo 	void *trans_hdr;
232129776acSJeffrey Hugo };
233129776acSJeffrey Hugo 
234129776acSJeffrey Hugo struct resp_work {
235129776acSJeffrey Hugo 	struct work_struct work;
236129776acSJeffrey Hugo 	struct qaic_device *qdev;
237129776acSJeffrey Hugo 	void *buf;
238129776acSJeffrey Hugo };
239129776acSJeffrey Hugo 
240129776acSJeffrey Hugo /*
241129776acSJeffrey Hugo  * Since we're working with little endian messages, its useful to be able to
242129776acSJeffrey Hugo  * increment without filling a whole line with conversions back and forth just
243129776acSJeffrey Hugo  * to add one(1) to a message count.
244129776acSJeffrey Hugo  */
incr_le32(__le32 val)245129776acSJeffrey Hugo static __le32 incr_le32(__le32 val)
246129776acSJeffrey Hugo {
247129776acSJeffrey Hugo 	return cpu_to_le32(le32_to_cpu(val) + 1);
248129776acSJeffrey Hugo }
249129776acSJeffrey Hugo 
gen_crc(void * msg)250129776acSJeffrey Hugo static u32 gen_crc(void *msg)
251129776acSJeffrey Hugo {
252129776acSJeffrey Hugo 	struct wrapper_list *wrappers = msg;
253129776acSJeffrey Hugo 	struct wrapper_msg *w;
254129776acSJeffrey Hugo 	u32 crc = ~0;
255129776acSJeffrey Hugo 
256129776acSJeffrey Hugo 	list_for_each_entry(w, &wrappers->list, list)
257129776acSJeffrey Hugo 		crc = crc32(crc, &w->msg, w->len);
258129776acSJeffrey Hugo 
259129776acSJeffrey Hugo 	return crc ^ ~0;
260129776acSJeffrey Hugo }
261129776acSJeffrey Hugo 
gen_crc_stub(void * msg)262129776acSJeffrey Hugo static u32 gen_crc_stub(void *msg)
263129776acSJeffrey Hugo {
264129776acSJeffrey Hugo 	return 0;
265129776acSJeffrey Hugo }
266129776acSJeffrey Hugo 
valid_crc(void * msg)267129776acSJeffrey Hugo static bool valid_crc(void *msg)
268129776acSJeffrey Hugo {
269129776acSJeffrey Hugo 	struct wire_msg_hdr *hdr = msg;
270129776acSJeffrey Hugo 	bool ret;
271129776acSJeffrey Hugo 	u32 crc;
272129776acSJeffrey Hugo 
273129776acSJeffrey Hugo 	/*
274129776acSJeffrey Hugo 	 * The output of this algorithm is always converted to the native
275129776acSJeffrey Hugo 	 * endianness.
276129776acSJeffrey Hugo 	 */
277129776acSJeffrey Hugo 	crc = le32_to_cpu(hdr->crc32);
278129776acSJeffrey Hugo 	hdr->crc32 = 0;
279129776acSJeffrey Hugo 	ret = (crc32(~0, msg, le32_to_cpu(hdr->len)) ^ ~0) == crc;
280129776acSJeffrey Hugo 	hdr->crc32 = cpu_to_le32(crc);
281129776acSJeffrey Hugo 	return ret;
282129776acSJeffrey Hugo }
283129776acSJeffrey Hugo 
valid_crc_stub(void * msg)284129776acSJeffrey Hugo static bool valid_crc_stub(void *msg)
285129776acSJeffrey Hugo {
286129776acSJeffrey Hugo 	return true;
287129776acSJeffrey Hugo }
288129776acSJeffrey Hugo 
free_wrapper(struct kref * ref)289129776acSJeffrey Hugo static void free_wrapper(struct kref *ref)
290129776acSJeffrey Hugo {
291129776acSJeffrey Hugo 	struct wrapper_msg *wrapper = container_of(ref, struct wrapper_msg, ref_count);
292129776acSJeffrey Hugo 
293129776acSJeffrey Hugo 	list_del(&wrapper->list);
294129776acSJeffrey Hugo 	kfree(wrapper);
295129776acSJeffrey Hugo }
296129776acSJeffrey Hugo 
save_dbc_buf(struct qaic_device * qdev,struct ioctl_resources * resources,struct qaic_user * usr)297129776acSJeffrey Hugo static void save_dbc_buf(struct qaic_device *qdev, struct ioctl_resources *resources,
298129776acSJeffrey Hugo 			 struct qaic_user *usr)
299129776acSJeffrey Hugo {
300129776acSJeffrey Hugo 	u32 dbc_id = resources->dbc_id;
301129776acSJeffrey Hugo 
302129776acSJeffrey Hugo 	if (resources->buf) {
303129776acSJeffrey Hugo 		wait_event_interruptible(qdev->dbc[dbc_id].dbc_release, !qdev->dbc[dbc_id].in_use);
304129776acSJeffrey Hugo 		qdev->dbc[dbc_id].req_q_base = resources->buf;
305129776acSJeffrey Hugo 		qdev->dbc[dbc_id].rsp_q_base = resources->rsp_q_base;
306129776acSJeffrey Hugo 		qdev->dbc[dbc_id].dma_addr = resources->dma_addr;
307129776acSJeffrey Hugo 		qdev->dbc[dbc_id].total_size = resources->total_size;
308129776acSJeffrey Hugo 		qdev->dbc[dbc_id].nelem = resources->nelem;
309129776acSJeffrey Hugo 		enable_dbc(qdev, dbc_id, usr);
310129776acSJeffrey Hugo 		qdev->dbc[dbc_id].in_use = true;
311129776acSJeffrey Hugo 		resources->buf = NULL;
312129776acSJeffrey Hugo 	}
313129776acSJeffrey Hugo }
314129776acSJeffrey Hugo 
free_dbc_buf(struct qaic_device * qdev,struct ioctl_resources * resources)315129776acSJeffrey Hugo static void free_dbc_buf(struct qaic_device *qdev, struct ioctl_resources *resources)
316129776acSJeffrey Hugo {
317129776acSJeffrey Hugo 	if (resources->buf)
318129776acSJeffrey Hugo 		dma_free_coherent(&qdev->pdev->dev, resources->total_size, resources->buf,
319129776acSJeffrey Hugo 				  resources->dma_addr);
320129776acSJeffrey Hugo 	resources->buf = NULL;
321129776acSJeffrey Hugo }
322129776acSJeffrey Hugo 
free_dma_xfers(struct qaic_device * qdev,struct ioctl_resources * resources)323129776acSJeffrey Hugo static void free_dma_xfers(struct qaic_device *qdev, struct ioctl_resources *resources)
324129776acSJeffrey Hugo {
325129776acSJeffrey Hugo 	struct dma_xfer *xfer;
326129776acSJeffrey Hugo 	struct dma_xfer *x;
327129776acSJeffrey Hugo 	int i;
328129776acSJeffrey Hugo 
329129776acSJeffrey Hugo 	list_for_each_entry_safe(xfer, x, &resources->dma_xfers, list) {
330129776acSJeffrey Hugo 		dma_unmap_sgtable(&qdev->pdev->dev, xfer->sgt, DMA_TO_DEVICE, 0);
331129776acSJeffrey Hugo 		sg_free_table(xfer->sgt);
332129776acSJeffrey Hugo 		kfree(xfer->sgt);
333129776acSJeffrey Hugo 		for (i = 0; i < xfer->nr_pages; ++i)
334129776acSJeffrey Hugo 			put_page(xfer->page_list[i]);
335129776acSJeffrey Hugo 		kfree(xfer->page_list);
336129776acSJeffrey Hugo 		list_del(&xfer->list);
337129776acSJeffrey Hugo 		kfree(xfer);
338129776acSJeffrey Hugo 	}
339129776acSJeffrey Hugo }
340129776acSJeffrey Hugo 
add_wrapper(struct wrapper_list * wrappers,u32 size)341129776acSJeffrey Hugo static struct wrapper_msg *add_wrapper(struct wrapper_list *wrappers, u32 size)
342129776acSJeffrey Hugo {
343129776acSJeffrey Hugo 	struct wrapper_msg *w = kzalloc(size, GFP_KERNEL);
344129776acSJeffrey Hugo 
345129776acSJeffrey Hugo 	if (!w)
346129776acSJeffrey Hugo 		return NULL;
347129776acSJeffrey Hugo 	list_add_tail(&w->list, &wrappers->list);
348129776acSJeffrey Hugo 	kref_init(&w->ref_count);
349129776acSJeffrey Hugo 	w->head = wrappers;
350129776acSJeffrey Hugo 	return w;
351129776acSJeffrey Hugo }
352129776acSJeffrey Hugo 
encode_passthrough(struct qaic_device * qdev,void * trans,struct wrapper_list * wrappers,u32 * user_len)353129776acSJeffrey Hugo static int encode_passthrough(struct qaic_device *qdev, void *trans, struct wrapper_list *wrappers,
354129776acSJeffrey Hugo 			      u32 *user_len)
355129776acSJeffrey Hugo {
356129776acSJeffrey Hugo 	struct qaic_manage_trans_passthrough *in_trans = trans;
357129776acSJeffrey Hugo 	struct wire_trans_passthrough *out_trans;
358129776acSJeffrey Hugo 	struct wrapper_msg *trans_wrapper;
359129776acSJeffrey Hugo 	struct wrapper_msg *wrapper;
360129776acSJeffrey Hugo 	struct wire_msg *msg;
361129776acSJeffrey Hugo 	u32 msg_hdr_len;
362129776acSJeffrey Hugo 
363129776acSJeffrey Hugo 	wrapper = list_first_entry(&wrappers->list, struct wrapper_msg, list);
364129776acSJeffrey Hugo 	msg = &wrapper->msg;
365129776acSJeffrey Hugo 	msg_hdr_len = le32_to_cpu(msg->hdr.len);
366129776acSJeffrey Hugo 
367129776acSJeffrey Hugo 	if (in_trans->hdr.len % 8 != 0)
368129776acSJeffrey Hugo 		return -EINVAL;
369129776acSJeffrey Hugo 
37047d87f71SDan Carpenter 	if (size_add(msg_hdr_len, in_trans->hdr.len) > QAIC_MANAGE_EXT_MSG_LENGTH)
371129776acSJeffrey Hugo 		return -ENOSPC;
372129776acSJeffrey Hugo 
373129776acSJeffrey Hugo 	trans_wrapper = add_wrapper(wrappers,
374129776acSJeffrey Hugo 				    offsetof(struct wrapper_msg, trans) + in_trans->hdr.len);
375129776acSJeffrey Hugo 	if (!trans_wrapper)
376129776acSJeffrey Hugo 		return -ENOMEM;
377129776acSJeffrey Hugo 	trans_wrapper->len = in_trans->hdr.len;
378129776acSJeffrey Hugo 	out_trans = (struct wire_trans_passthrough *)&trans_wrapper->trans;
379129776acSJeffrey Hugo 
380129776acSJeffrey Hugo 	memcpy(out_trans->data, in_trans->data, in_trans->hdr.len - sizeof(in_trans->hdr));
381129776acSJeffrey Hugo 	msg->hdr.len = cpu_to_le32(msg_hdr_len + in_trans->hdr.len);
382129776acSJeffrey Hugo 	msg->hdr.count = incr_le32(msg->hdr.count);
383129776acSJeffrey Hugo 	*user_len += in_trans->hdr.len;
384129776acSJeffrey Hugo 	out_trans->hdr.type = cpu_to_le32(QAIC_TRANS_PASSTHROUGH_TO_DEV);
385129776acSJeffrey Hugo 	out_trans->hdr.len = cpu_to_le32(in_trans->hdr.len);
386129776acSJeffrey Hugo 
387129776acSJeffrey Hugo 	return 0;
388129776acSJeffrey Hugo }
389129776acSJeffrey Hugo 
390129776acSJeffrey Hugo /* returns error code for failure, 0 if enough pages alloc'd, 1 if dma_cont is needed */
find_and_map_user_pages(struct qaic_device * qdev,struct qaic_manage_trans_dma_xfer * in_trans,struct ioctl_resources * resources,struct dma_xfer * xfer)391129776acSJeffrey Hugo static int find_and_map_user_pages(struct qaic_device *qdev,
392129776acSJeffrey Hugo 				   struct qaic_manage_trans_dma_xfer *in_trans,
393129776acSJeffrey Hugo 				   struct ioctl_resources *resources, struct dma_xfer *xfer)
394129776acSJeffrey Hugo {
39596d3c1caSDan Carpenter 	u64 xfer_start_addr, remaining, end, total;
396129776acSJeffrey Hugo 	unsigned long need_pages;
397129776acSJeffrey Hugo 	struct page **page_list;
398129776acSJeffrey Hugo 	unsigned long nr_pages;
399129776acSJeffrey Hugo 	struct sg_table *sgt;
400129776acSJeffrey Hugo 	int ret;
401129776acSJeffrey Hugo 	int i;
402129776acSJeffrey Hugo 
40396d3c1caSDan Carpenter 	if (check_add_overflow(in_trans->addr, resources->xferred_dma_size, &xfer_start_addr))
40496d3c1caSDan Carpenter 		return -EINVAL;
405129776acSJeffrey Hugo 
40696d3c1caSDan Carpenter 	if (in_trans->size < resources->xferred_dma_size)
40796d3c1caSDan Carpenter 		return -EINVAL;
40896d3c1caSDan Carpenter 	remaining = in_trans->size - resources->xferred_dma_size;
40996d3c1caSDan Carpenter 	if (remaining == 0)
41096d3c1caSDan Carpenter 		return 0;
41196d3c1caSDan Carpenter 
41296d3c1caSDan Carpenter 	if (check_add_overflow(xfer_start_addr, remaining, &end))
41396d3c1caSDan Carpenter 		return -EINVAL;
41496d3c1caSDan Carpenter 
41596d3c1caSDan Carpenter 	total = remaining + offset_in_page(xfer_start_addr);
41696d3c1caSDan Carpenter 	if (total >= SIZE_MAX)
41796d3c1caSDan Carpenter 		return -EINVAL;
41896d3c1caSDan Carpenter 
41996d3c1caSDan Carpenter 	need_pages = DIV_ROUND_UP(total, PAGE_SIZE);
420129776acSJeffrey Hugo 
421129776acSJeffrey Hugo 	nr_pages = need_pages;
422129776acSJeffrey Hugo 
423129776acSJeffrey Hugo 	while (1) {
424129776acSJeffrey Hugo 		page_list = kmalloc_array(nr_pages, sizeof(*page_list), GFP_KERNEL | __GFP_NOWARN);
425129776acSJeffrey Hugo 		if (!page_list) {
426129776acSJeffrey Hugo 			nr_pages = nr_pages / 2;
427129776acSJeffrey Hugo 			if (!nr_pages)
428129776acSJeffrey Hugo 				return -ENOMEM;
429129776acSJeffrey Hugo 		} else {
430129776acSJeffrey Hugo 			break;
431129776acSJeffrey Hugo 		}
432129776acSJeffrey Hugo 	}
433129776acSJeffrey Hugo 
434129776acSJeffrey Hugo 	ret = get_user_pages_fast(xfer_start_addr, nr_pages, 0, page_list);
43573274c33SDan Carpenter 	if (ret < 0)
436129776acSJeffrey Hugo 		goto free_page_list;
43773274c33SDan Carpenter 	if (ret != nr_pages) {
43873274c33SDan Carpenter 		nr_pages = ret;
43973274c33SDan Carpenter 		ret = -EFAULT;
44073274c33SDan Carpenter 		goto put_pages;
441129776acSJeffrey Hugo 	}
442129776acSJeffrey Hugo 
443129776acSJeffrey Hugo 	sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
444129776acSJeffrey Hugo 	if (!sgt) {
445129776acSJeffrey Hugo 		ret = -ENOMEM;
446129776acSJeffrey Hugo 		goto put_pages;
447129776acSJeffrey Hugo 	}
448129776acSJeffrey Hugo 
449129776acSJeffrey Hugo 	ret = sg_alloc_table_from_pages(sgt, page_list, nr_pages,
450129776acSJeffrey Hugo 					offset_in_page(xfer_start_addr),
45196d3c1caSDan Carpenter 					remaining, GFP_KERNEL);
452129776acSJeffrey Hugo 	if (ret) {
453129776acSJeffrey Hugo 		ret = -ENOMEM;
454129776acSJeffrey Hugo 		goto free_sgt;
455129776acSJeffrey Hugo 	}
456129776acSJeffrey Hugo 
457129776acSJeffrey Hugo 	ret = dma_map_sgtable(&qdev->pdev->dev, sgt, DMA_TO_DEVICE, 0);
458129776acSJeffrey Hugo 	if (ret)
459129776acSJeffrey Hugo 		goto free_table;
460129776acSJeffrey Hugo 
461129776acSJeffrey Hugo 	xfer->sgt = sgt;
462129776acSJeffrey Hugo 	xfer->page_list = page_list;
463129776acSJeffrey Hugo 	xfer->nr_pages = nr_pages;
464129776acSJeffrey Hugo 
465129776acSJeffrey Hugo 	return need_pages > nr_pages ? 1 : 0;
466129776acSJeffrey Hugo 
467129776acSJeffrey Hugo free_table:
468129776acSJeffrey Hugo 	sg_free_table(sgt);
469129776acSJeffrey Hugo free_sgt:
470129776acSJeffrey Hugo 	kfree(sgt);
471129776acSJeffrey Hugo put_pages:
472129776acSJeffrey Hugo 	for (i = 0; i < nr_pages; ++i)
473129776acSJeffrey Hugo 		put_page(page_list[i]);
474129776acSJeffrey Hugo free_page_list:
475129776acSJeffrey Hugo 	kfree(page_list);
476129776acSJeffrey Hugo 	return ret;
477129776acSJeffrey Hugo }
478129776acSJeffrey Hugo 
479129776acSJeffrey Hugo /* returns error code for failure, 0 if everything was encoded, 1 if dma_cont is needed */
encode_addr_size_pairs(struct dma_xfer * xfer,struct wrapper_list * wrappers,struct ioctl_resources * resources,u32 msg_hdr_len,u32 * size,struct wire_trans_dma_xfer ** out_trans)480129776acSJeffrey Hugo static int encode_addr_size_pairs(struct dma_xfer *xfer, struct wrapper_list *wrappers,
481129776acSJeffrey Hugo 				  struct ioctl_resources *resources, u32 msg_hdr_len, u32 *size,
482129776acSJeffrey Hugo 				  struct wire_trans_dma_xfer **out_trans)
483129776acSJeffrey Hugo {
484129776acSJeffrey Hugo 	struct wrapper_msg *trans_wrapper;
485129776acSJeffrey Hugo 	struct sg_table *sgt = xfer->sgt;
486129776acSJeffrey Hugo 	struct wire_addr_size_pair *asp;
487129776acSJeffrey Hugo 	struct scatterlist *sg;
488129776acSJeffrey Hugo 	struct wrapper_msg *w;
489129776acSJeffrey Hugo 	unsigned int dma_len;
490129776acSJeffrey Hugo 	u64 dma_chunk_len;
491129776acSJeffrey Hugo 	void *boundary;
492129776acSJeffrey Hugo 	int nents_dma;
493129776acSJeffrey Hugo 	int nents;
494129776acSJeffrey Hugo 	int i;
495129776acSJeffrey Hugo 
496129776acSJeffrey Hugo 	nents = sgt->nents;
497129776acSJeffrey Hugo 	nents_dma = nents;
498129776acSJeffrey Hugo 	*size = QAIC_MANAGE_EXT_MSG_LENGTH - msg_hdr_len - sizeof(**out_trans);
499*1931dc14SPranjal Ramajor Asha Kanojiya 	for_each_sgtable_dma_sg(sgt, sg, i) {
500129776acSJeffrey Hugo 		*size -= sizeof(*asp);
501129776acSJeffrey Hugo 		/* Save 1K for possible follow-up transactions. */
502129776acSJeffrey Hugo 		if (*size < SZ_1K) {
503129776acSJeffrey Hugo 			nents_dma = i;
504129776acSJeffrey Hugo 			break;
505129776acSJeffrey Hugo 		}
506129776acSJeffrey Hugo 	}
507129776acSJeffrey Hugo 
508129776acSJeffrey Hugo 	trans_wrapper = add_wrapper(wrappers, QAIC_WRAPPER_MAX_SIZE);
509129776acSJeffrey Hugo 	if (!trans_wrapper)
510129776acSJeffrey Hugo 		return -ENOMEM;
511129776acSJeffrey Hugo 	*out_trans = (struct wire_trans_dma_xfer *)&trans_wrapper->trans;
512129776acSJeffrey Hugo 
513129776acSJeffrey Hugo 	asp = (*out_trans)->data;
514129776acSJeffrey Hugo 	boundary = (void *)trans_wrapper + QAIC_WRAPPER_MAX_SIZE;
515129776acSJeffrey Hugo 	*size = 0;
516129776acSJeffrey Hugo 
517129776acSJeffrey Hugo 	dma_len = 0;
518129776acSJeffrey Hugo 	w = trans_wrapper;
519129776acSJeffrey Hugo 	dma_chunk_len = 0;
520129776acSJeffrey Hugo 	for_each_sg(sgt->sgl, sg, nents_dma, i) {
521129776acSJeffrey Hugo 		asp->size = cpu_to_le64(dma_len);
522129776acSJeffrey Hugo 		dma_chunk_len += dma_len;
523129776acSJeffrey Hugo 		if (dma_len) {
524129776acSJeffrey Hugo 			asp++;
525129776acSJeffrey Hugo 			if ((void *)asp + sizeof(*asp) > boundary) {
526129776acSJeffrey Hugo 				w->len = (void *)asp - (void *)&w->msg;
527129776acSJeffrey Hugo 				*size += w->len;
528129776acSJeffrey Hugo 				w = add_wrapper(wrappers, QAIC_WRAPPER_MAX_SIZE);
529129776acSJeffrey Hugo 				if (!w)
530129776acSJeffrey Hugo 					return -ENOMEM;
531129776acSJeffrey Hugo 				boundary = (void *)w + QAIC_WRAPPER_MAX_SIZE;
532129776acSJeffrey Hugo 				asp = (struct wire_addr_size_pair *)&w->msg;
533129776acSJeffrey Hugo 			}
534129776acSJeffrey Hugo 		}
535129776acSJeffrey Hugo 		asp->addr = cpu_to_le64(sg_dma_address(sg));
536129776acSJeffrey Hugo 		dma_len = sg_dma_len(sg);
537129776acSJeffrey Hugo 	}
538129776acSJeffrey Hugo 	/* finalize the last segment */
539129776acSJeffrey Hugo 	asp->size = cpu_to_le64(dma_len);
540129776acSJeffrey Hugo 	w->len = (void *)asp + sizeof(*asp) - (void *)&w->msg;
541129776acSJeffrey Hugo 	*size += w->len;
542129776acSJeffrey Hugo 	dma_chunk_len += dma_len;
543129776acSJeffrey Hugo 	resources->xferred_dma_size += dma_chunk_len;
544129776acSJeffrey Hugo 
545129776acSJeffrey Hugo 	return nents_dma < nents ? 1 : 0;
546129776acSJeffrey Hugo }
547129776acSJeffrey Hugo 
cleanup_xfer(struct qaic_device * qdev,struct dma_xfer * xfer)548129776acSJeffrey Hugo static void cleanup_xfer(struct qaic_device *qdev, struct dma_xfer *xfer)
549129776acSJeffrey Hugo {
550129776acSJeffrey Hugo 	int i;
551129776acSJeffrey Hugo 
552129776acSJeffrey Hugo 	dma_unmap_sgtable(&qdev->pdev->dev, xfer->sgt, DMA_TO_DEVICE, 0);
553129776acSJeffrey Hugo 	sg_free_table(xfer->sgt);
554129776acSJeffrey Hugo 	kfree(xfer->sgt);
555129776acSJeffrey Hugo 	for (i = 0; i < xfer->nr_pages; ++i)
556129776acSJeffrey Hugo 		put_page(xfer->page_list[i]);
557129776acSJeffrey Hugo 	kfree(xfer->page_list);
558129776acSJeffrey Hugo }
559129776acSJeffrey Hugo 
encode_dma(struct qaic_device * qdev,void * trans,struct wrapper_list * wrappers,u32 * user_len,struct ioctl_resources * resources,struct qaic_user * usr)560129776acSJeffrey Hugo static int encode_dma(struct qaic_device *qdev, void *trans, struct wrapper_list *wrappers,
561129776acSJeffrey Hugo 		      u32 *user_len, struct ioctl_resources *resources, struct qaic_user *usr)
562129776acSJeffrey Hugo {
563129776acSJeffrey Hugo 	struct qaic_manage_trans_dma_xfer *in_trans = trans;
564129776acSJeffrey Hugo 	struct wire_trans_dma_xfer *out_trans;
565129776acSJeffrey Hugo 	struct wrapper_msg *wrapper;
566129776acSJeffrey Hugo 	struct dma_xfer *xfer;
567129776acSJeffrey Hugo 	struct wire_msg *msg;
568129776acSJeffrey Hugo 	bool need_cont_dma;
569129776acSJeffrey Hugo 	u32 msg_hdr_len;
570129776acSJeffrey Hugo 	u32 size;
571129776acSJeffrey Hugo 	int ret;
572129776acSJeffrey Hugo 
573129776acSJeffrey Hugo 	wrapper = list_first_entry(&wrappers->list, struct wrapper_msg, list);
574129776acSJeffrey Hugo 	msg = &wrapper->msg;
575129776acSJeffrey Hugo 	msg_hdr_len = le32_to_cpu(msg->hdr.len);
576129776acSJeffrey Hugo 
577129776acSJeffrey Hugo 	/* There should be enough space to hold at least one ASP entry. */
57847d87f71SDan Carpenter 	if (size_add(msg_hdr_len, sizeof(*out_trans) + sizeof(struct wire_addr_size_pair)) >
579129776acSJeffrey Hugo 	    QAIC_MANAGE_EXT_MSG_LENGTH)
580129776acSJeffrey Hugo 		return -ENOMEM;
581129776acSJeffrey Hugo 
582129776acSJeffrey Hugo 	xfer = kmalloc(sizeof(*xfer), GFP_KERNEL);
583129776acSJeffrey Hugo 	if (!xfer)
584129776acSJeffrey Hugo 		return -ENOMEM;
585129776acSJeffrey Hugo 
586129776acSJeffrey Hugo 	ret = find_and_map_user_pages(qdev, in_trans, resources, xfer);
587129776acSJeffrey Hugo 	if (ret < 0)
588129776acSJeffrey Hugo 		goto free_xfer;
589129776acSJeffrey Hugo 
590129776acSJeffrey Hugo 	need_cont_dma = (bool)ret;
591129776acSJeffrey Hugo 
592129776acSJeffrey Hugo 	ret = encode_addr_size_pairs(xfer, wrappers, resources, msg_hdr_len, &size, &out_trans);
593129776acSJeffrey Hugo 	if (ret < 0)
594129776acSJeffrey Hugo 		goto cleanup_xfer;
595129776acSJeffrey Hugo 
596129776acSJeffrey Hugo 	need_cont_dma = need_cont_dma || (bool)ret;
597129776acSJeffrey Hugo 
598129776acSJeffrey Hugo 	msg->hdr.len = cpu_to_le32(msg_hdr_len + size);
599129776acSJeffrey Hugo 	msg->hdr.count = incr_le32(msg->hdr.count);
600129776acSJeffrey Hugo 
601129776acSJeffrey Hugo 	out_trans->hdr.type = cpu_to_le32(QAIC_TRANS_DMA_XFER_TO_DEV);
602129776acSJeffrey Hugo 	out_trans->hdr.len = cpu_to_le32(size);
603129776acSJeffrey Hugo 	out_trans->tag = cpu_to_le32(in_trans->tag);
604129776acSJeffrey Hugo 	out_trans->count = cpu_to_le32((size - sizeof(*out_trans)) /
605129776acSJeffrey Hugo 								sizeof(struct wire_addr_size_pair));
606129776acSJeffrey Hugo 
607129776acSJeffrey Hugo 	*user_len += in_trans->hdr.len;
608129776acSJeffrey Hugo 
609129776acSJeffrey Hugo 	if (resources->dma_chunk_id) {
610129776acSJeffrey Hugo 		out_trans->dma_chunk_id = cpu_to_le32(resources->dma_chunk_id);
611129776acSJeffrey Hugo 	} else if (need_cont_dma) {
612129776acSJeffrey Hugo 		while (resources->dma_chunk_id == 0)
613129776acSJeffrey Hugo 			resources->dma_chunk_id = atomic_inc_return(&usr->chunk_id);
614129776acSJeffrey Hugo 
615129776acSJeffrey Hugo 		out_trans->dma_chunk_id = cpu_to_le32(resources->dma_chunk_id);
616129776acSJeffrey Hugo 	}
617129776acSJeffrey Hugo 	resources->trans_hdr = trans;
618129776acSJeffrey Hugo 
619129776acSJeffrey Hugo 	list_add(&xfer->list, &resources->dma_xfers);
620129776acSJeffrey Hugo 	return 0;
621129776acSJeffrey Hugo 
622129776acSJeffrey Hugo cleanup_xfer:
623129776acSJeffrey Hugo 	cleanup_xfer(qdev, xfer);
624129776acSJeffrey Hugo free_xfer:
625129776acSJeffrey Hugo 	kfree(xfer);
626129776acSJeffrey Hugo 	return ret;
627129776acSJeffrey Hugo }
628129776acSJeffrey Hugo 
encode_activate(struct qaic_device * qdev,void * trans,struct wrapper_list * wrappers,u32 * user_len,struct ioctl_resources * resources)629129776acSJeffrey Hugo static int encode_activate(struct qaic_device *qdev, void *trans, struct wrapper_list *wrappers,
630129776acSJeffrey Hugo 			   u32 *user_len, struct ioctl_resources *resources)
631129776acSJeffrey Hugo {
632129776acSJeffrey Hugo 	struct qaic_manage_trans_activate_to_dev *in_trans = trans;
633129776acSJeffrey Hugo 	struct wire_trans_activate_to_dev *out_trans;
634129776acSJeffrey Hugo 	struct wrapper_msg *trans_wrapper;
635129776acSJeffrey Hugo 	struct wrapper_msg *wrapper;
636129776acSJeffrey Hugo 	struct wire_msg *msg;
637129776acSJeffrey Hugo 	dma_addr_t dma_addr;
638129776acSJeffrey Hugo 	u32 msg_hdr_len;
639129776acSJeffrey Hugo 	void *buf;
640129776acSJeffrey Hugo 	u32 nelem;
641129776acSJeffrey Hugo 	u32 size;
642129776acSJeffrey Hugo 	int ret;
643129776acSJeffrey Hugo 
644129776acSJeffrey Hugo 	wrapper = list_first_entry(&wrappers->list, struct wrapper_msg, list);
645129776acSJeffrey Hugo 	msg = &wrapper->msg;
646129776acSJeffrey Hugo 	msg_hdr_len = le32_to_cpu(msg->hdr.len);
647129776acSJeffrey Hugo 
64847d87f71SDan Carpenter 	if (size_add(msg_hdr_len, sizeof(*out_trans)) > QAIC_MANAGE_MAX_MSG_LENGTH)
649129776acSJeffrey Hugo 		return -ENOSPC;
650129776acSJeffrey Hugo 
651129776acSJeffrey Hugo 	if (!in_trans->queue_size)
652129776acSJeffrey Hugo 		return -EINVAL;
653129776acSJeffrey Hugo 
654129776acSJeffrey Hugo 	if (in_trans->pad)
655129776acSJeffrey Hugo 		return -EINVAL;
656129776acSJeffrey Hugo 
657129776acSJeffrey Hugo 	nelem = in_trans->queue_size;
658129776acSJeffrey Hugo 	size = (get_dbc_req_elem_size() + get_dbc_rsp_elem_size()) * nelem;
659129776acSJeffrey Hugo 	if (size / nelem != get_dbc_req_elem_size() + get_dbc_rsp_elem_size())
660129776acSJeffrey Hugo 		return -EINVAL;
661129776acSJeffrey Hugo 
662129776acSJeffrey Hugo 	if (size + QAIC_DBC_Q_GAP + QAIC_DBC_Q_BUF_ALIGN < size)
663129776acSJeffrey Hugo 		return -EINVAL;
664129776acSJeffrey Hugo 
665129776acSJeffrey Hugo 	size = ALIGN((size + QAIC_DBC_Q_GAP), QAIC_DBC_Q_BUF_ALIGN);
666129776acSJeffrey Hugo 
667129776acSJeffrey Hugo 	buf = dma_alloc_coherent(&qdev->pdev->dev, size, &dma_addr, GFP_KERNEL);
668129776acSJeffrey Hugo 	if (!buf)
669129776acSJeffrey Hugo 		return -ENOMEM;
670129776acSJeffrey Hugo 
671129776acSJeffrey Hugo 	trans_wrapper = add_wrapper(wrappers,
672129776acSJeffrey Hugo 				    offsetof(struct wrapper_msg, trans) + sizeof(*out_trans));
673129776acSJeffrey Hugo 	if (!trans_wrapper) {
674129776acSJeffrey Hugo 		ret = -ENOMEM;
675129776acSJeffrey Hugo 		goto free_dma;
676129776acSJeffrey Hugo 	}
677129776acSJeffrey Hugo 	trans_wrapper->len = sizeof(*out_trans);
678129776acSJeffrey Hugo 	out_trans = (struct wire_trans_activate_to_dev *)&trans_wrapper->trans;
679129776acSJeffrey Hugo 
680129776acSJeffrey Hugo 	out_trans->hdr.type = cpu_to_le32(QAIC_TRANS_ACTIVATE_TO_DEV);
681129776acSJeffrey Hugo 	out_trans->hdr.len = cpu_to_le32(sizeof(*out_trans));
682129776acSJeffrey Hugo 	out_trans->buf_len = cpu_to_le32(size);
683129776acSJeffrey Hugo 	out_trans->req_q_addr = cpu_to_le64(dma_addr);
684129776acSJeffrey Hugo 	out_trans->req_q_size = cpu_to_le32(nelem);
685129776acSJeffrey Hugo 	out_trans->rsp_q_addr = cpu_to_le64(dma_addr + size - nelem * get_dbc_rsp_elem_size());
686129776acSJeffrey Hugo 	out_trans->rsp_q_size = cpu_to_le32(nelem);
687129776acSJeffrey Hugo 	out_trans->options = cpu_to_le32(in_trans->options);
688129776acSJeffrey Hugo 
689129776acSJeffrey Hugo 	*user_len += in_trans->hdr.len;
690129776acSJeffrey Hugo 	msg->hdr.len = cpu_to_le32(msg_hdr_len + sizeof(*out_trans));
691129776acSJeffrey Hugo 	msg->hdr.count = incr_le32(msg->hdr.count);
692129776acSJeffrey Hugo 
693129776acSJeffrey Hugo 	resources->buf = buf;
694129776acSJeffrey Hugo 	resources->dma_addr = dma_addr;
695129776acSJeffrey Hugo 	resources->total_size = size;
696129776acSJeffrey Hugo 	resources->nelem = nelem;
697129776acSJeffrey Hugo 	resources->rsp_q_base = buf + size - nelem * get_dbc_rsp_elem_size();
698129776acSJeffrey Hugo 	return 0;
699129776acSJeffrey Hugo 
700129776acSJeffrey Hugo free_dma:
701129776acSJeffrey Hugo 	dma_free_coherent(&qdev->pdev->dev, size, buf, dma_addr);
702129776acSJeffrey Hugo 	return ret;
703129776acSJeffrey Hugo }
704129776acSJeffrey Hugo 
encode_deactivate(struct qaic_device * qdev,void * trans,u32 * user_len,struct qaic_user * usr)705129776acSJeffrey Hugo static int encode_deactivate(struct qaic_device *qdev, void *trans,
706129776acSJeffrey Hugo 			     u32 *user_len, struct qaic_user *usr)
707129776acSJeffrey Hugo {
708129776acSJeffrey Hugo 	struct qaic_manage_trans_deactivate *in_trans = trans;
709129776acSJeffrey Hugo 
710129776acSJeffrey Hugo 	if (in_trans->dbc_id >= qdev->num_dbc || in_trans->pad)
711129776acSJeffrey Hugo 		return -EINVAL;
712129776acSJeffrey Hugo 
713129776acSJeffrey Hugo 	*user_len += in_trans->hdr.len;
714129776acSJeffrey Hugo 
715129776acSJeffrey Hugo 	return disable_dbc(qdev, in_trans->dbc_id, usr);
716129776acSJeffrey Hugo }
717129776acSJeffrey Hugo 
encode_status(struct qaic_device * qdev,void * trans,struct wrapper_list * wrappers,u32 * user_len)718129776acSJeffrey Hugo static int encode_status(struct qaic_device *qdev, void *trans, struct wrapper_list *wrappers,
719129776acSJeffrey Hugo 			 u32 *user_len)
720129776acSJeffrey Hugo {
721129776acSJeffrey Hugo 	struct qaic_manage_trans_status_to_dev *in_trans = trans;
722129776acSJeffrey Hugo 	struct wire_trans_status_to_dev *out_trans;
723129776acSJeffrey Hugo 	struct wrapper_msg *trans_wrapper;
724129776acSJeffrey Hugo 	struct wrapper_msg *wrapper;
725129776acSJeffrey Hugo 	struct wire_msg *msg;
726129776acSJeffrey Hugo 	u32 msg_hdr_len;
727129776acSJeffrey Hugo 
728129776acSJeffrey Hugo 	wrapper = list_first_entry(&wrappers->list, struct wrapper_msg, list);
729129776acSJeffrey Hugo 	msg = &wrapper->msg;
730129776acSJeffrey Hugo 	msg_hdr_len = le32_to_cpu(msg->hdr.len);
731129776acSJeffrey Hugo 
73247d87f71SDan Carpenter 	if (size_add(msg_hdr_len, in_trans->hdr.len) > QAIC_MANAGE_MAX_MSG_LENGTH)
733129776acSJeffrey Hugo 		return -ENOSPC;
734129776acSJeffrey Hugo 
735129776acSJeffrey Hugo 	trans_wrapper = add_wrapper(wrappers, sizeof(*trans_wrapper));
736129776acSJeffrey Hugo 	if (!trans_wrapper)
737129776acSJeffrey Hugo 		return -ENOMEM;
738129776acSJeffrey Hugo 
739129776acSJeffrey Hugo 	trans_wrapper->len = sizeof(*out_trans);
740129776acSJeffrey Hugo 	out_trans = (struct wire_trans_status_to_dev *)&trans_wrapper->trans;
741129776acSJeffrey Hugo 
742129776acSJeffrey Hugo 	out_trans->hdr.type = cpu_to_le32(QAIC_TRANS_STATUS_TO_DEV);
743129776acSJeffrey Hugo 	out_trans->hdr.len = cpu_to_le32(in_trans->hdr.len);
744129776acSJeffrey Hugo 	msg->hdr.len = cpu_to_le32(msg_hdr_len + in_trans->hdr.len);
745129776acSJeffrey Hugo 	msg->hdr.count = incr_le32(msg->hdr.count);
746129776acSJeffrey Hugo 	*user_len += in_trans->hdr.len;
747129776acSJeffrey Hugo 
748129776acSJeffrey Hugo 	return 0;
749129776acSJeffrey Hugo }
750129776acSJeffrey Hugo 
encode_message(struct qaic_device * qdev,struct manage_msg * user_msg,struct wrapper_list * wrappers,struct ioctl_resources * resources,struct qaic_user * usr)751129776acSJeffrey Hugo static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
752129776acSJeffrey Hugo 			  struct wrapper_list *wrappers, struct ioctl_resources *resources,
753129776acSJeffrey Hugo 			  struct qaic_user *usr)
754129776acSJeffrey Hugo {
755129776acSJeffrey Hugo 	struct qaic_manage_trans_hdr *trans_hdr;
756129776acSJeffrey Hugo 	struct wrapper_msg *wrapper;
757129776acSJeffrey Hugo 	struct wire_msg *msg;
758129776acSJeffrey Hugo 	u32 user_len = 0;
759129776acSJeffrey Hugo 	int ret;
760129776acSJeffrey Hugo 	int i;
761129776acSJeffrey Hugo 
762ea33cb6fSDan Carpenter 	if (!user_msg->count ||
763ea33cb6fSDan Carpenter 	    user_msg->len < sizeof(*trans_hdr)) {
764129776acSJeffrey Hugo 		ret = -EINVAL;
765129776acSJeffrey Hugo 		goto out;
766129776acSJeffrey Hugo 	}
767129776acSJeffrey Hugo 
768129776acSJeffrey Hugo 	wrapper = list_first_entry(&wrappers->list, struct wrapper_msg, list);
769129776acSJeffrey Hugo 	msg = &wrapper->msg;
770129776acSJeffrey Hugo 
771129776acSJeffrey Hugo 	msg->hdr.len = cpu_to_le32(sizeof(msg->hdr));
772129776acSJeffrey Hugo 
773129776acSJeffrey Hugo 	if (resources->dma_chunk_id) {
774129776acSJeffrey Hugo 		ret = encode_dma(qdev, resources->trans_hdr, wrappers, &user_len, resources, usr);
775129776acSJeffrey Hugo 		msg->hdr.count = cpu_to_le32(1);
776129776acSJeffrey Hugo 		goto out;
777129776acSJeffrey Hugo 	}
778129776acSJeffrey Hugo 
779129776acSJeffrey Hugo 	for (i = 0; i < user_msg->count; ++i) {
780ea33cb6fSDan Carpenter 		if (user_len > user_msg->len - sizeof(*trans_hdr)) {
781129776acSJeffrey Hugo 			ret = -EINVAL;
782129776acSJeffrey Hugo 			break;
783129776acSJeffrey Hugo 		}
784129776acSJeffrey Hugo 		trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len);
785ea33cb6fSDan Carpenter 		if (trans_hdr->len < sizeof(trans_hdr) ||
786ea33cb6fSDan Carpenter 		    size_add(user_len, trans_hdr->len) > user_msg->len) {
787129776acSJeffrey Hugo 			ret = -EINVAL;
788129776acSJeffrey Hugo 			break;
789129776acSJeffrey Hugo 		}
790129776acSJeffrey Hugo 
791129776acSJeffrey Hugo 		switch (trans_hdr->type) {
792129776acSJeffrey Hugo 		case QAIC_TRANS_PASSTHROUGH_FROM_USR:
793129776acSJeffrey Hugo 			ret = encode_passthrough(qdev, trans_hdr, wrappers, &user_len);
794129776acSJeffrey Hugo 			break;
795129776acSJeffrey Hugo 		case QAIC_TRANS_DMA_XFER_FROM_USR:
796129776acSJeffrey Hugo 			ret = encode_dma(qdev, trans_hdr, wrappers, &user_len, resources, usr);
797129776acSJeffrey Hugo 			break;
798129776acSJeffrey Hugo 		case QAIC_TRANS_ACTIVATE_FROM_USR:
799129776acSJeffrey Hugo 			ret = encode_activate(qdev, trans_hdr, wrappers, &user_len, resources);
800129776acSJeffrey Hugo 			break;
801129776acSJeffrey Hugo 		case QAIC_TRANS_DEACTIVATE_FROM_USR:
802129776acSJeffrey Hugo 			ret = encode_deactivate(qdev, trans_hdr, &user_len, usr);
803129776acSJeffrey Hugo 			break;
804129776acSJeffrey Hugo 		case QAIC_TRANS_STATUS_FROM_USR:
805129776acSJeffrey Hugo 			ret = encode_status(qdev, trans_hdr, wrappers, &user_len);
806129776acSJeffrey Hugo 			break;
807129776acSJeffrey Hugo 		default:
808129776acSJeffrey Hugo 			ret = -EINVAL;
809129776acSJeffrey Hugo 			break;
810129776acSJeffrey Hugo 		}
811129776acSJeffrey Hugo 
812129776acSJeffrey Hugo 		if (ret)
813129776acSJeffrey Hugo 			break;
814129776acSJeffrey Hugo 	}
815129776acSJeffrey Hugo 
816129776acSJeffrey Hugo 	if (user_len != user_msg->len)
817129776acSJeffrey Hugo 		ret = -EINVAL;
818129776acSJeffrey Hugo out:
819129776acSJeffrey Hugo 	if (ret) {
820129776acSJeffrey Hugo 		free_dma_xfers(qdev, resources);
821129776acSJeffrey Hugo 		free_dbc_buf(qdev, resources);
822129776acSJeffrey Hugo 		return ret;
823129776acSJeffrey Hugo 	}
824129776acSJeffrey Hugo 
825129776acSJeffrey Hugo 	return 0;
826129776acSJeffrey Hugo }
827129776acSJeffrey Hugo 
decode_passthrough(struct qaic_device * qdev,void * trans,struct manage_msg * user_msg,u32 * msg_len)828129776acSJeffrey Hugo static int decode_passthrough(struct qaic_device *qdev, void *trans, struct manage_msg *user_msg,
829129776acSJeffrey Hugo 			      u32 *msg_len)
830129776acSJeffrey Hugo {
831129776acSJeffrey Hugo 	struct qaic_manage_trans_passthrough *out_trans;
832129776acSJeffrey Hugo 	struct wire_trans_passthrough *in_trans = trans;
833129776acSJeffrey Hugo 	u32 len;
834129776acSJeffrey Hugo 
835129776acSJeffrey Hugo 	out_trans = (void *)user_msg->data + user_msg->len;
836129776acSJeffrey Hugo 
837129776acSJeffrey Hugo 	len = le32_to_cpu(in_trans->hdr.len);
838129776acSJeffrey Hugo 	if (len % 8 != 0)
839129776acSJeffrey Hugo 		return -EINVAL;
840129776acSJeffrey Hugo 
841129776acSJeffrey Hugo 	if (user_msg->len + len > QAIC_MANAGE_MAX_MSG_LENGTH)
842129776acSJeffrey Hugo 		return -ENOSPC;
843129776acSJeffrey Hugo 
844129776acSJeffrey Hugo 	memcpy(out_trans->data, in_trans->data, len - sizeof(in_trans->hdr));
845129776acSJeffrey Hugo 	user_msg->len += len;
846129776acSJeffrey Hugo 	*msg_len += len;
847129776acSJeffrey Hugo 	out_trans->hdr.type = le32_to_cpu(in_trans->hdr.type);
848129776acSJeffrey Hugo 	out_trans->hdr.len = len;
849129776acSJeffrey Hugo 
850129776acSJeffrey Hugo 	return 0;
851129776acSJeffrey Hugo }
852129776acSJeffrey Hugo 
decode_activate(struct qaic_device * qdev,void * trans,struct manage_msg * user_msg,u32 * msg_len,struct ioctl_resources * resources,struct qaic_user * usr)853129776acSJeffrey Hugo static int decode_activate(struct qaic_device *qdev, void *trans, struct manage_msg *user_msg,
854129776acSJeffrey Hugo 			   u32 *msg_len, struct ioctl_resources *resources, struct qaic_user *usr)
855129776acSJeffrey Hugo {
856129776acSJeffrey Hugo 	struct qaic_manage_trans_activate_from_dev *out_trans;
857129776acSJeffrey Hugo 	struct wire_trans_activate_from_dev *in_trans = trans;
858129776acSJeffrey Hugo 	u32 len;
859129776acSJeffrey Hugo 
860129776acSJeffrey Hugo 	out_trans = (void *)user_msg->data + user_msg->len;
861129776acSJeffrey Hugo 
862129776acSJeffrey Hugo 	len = le32_to_cpu(in_trans->hdr.len);
863129776acSJeffrey Hugo 	if (user_msg->len + len > QAIC_MANAGE_MAX_MSG_LENGTH)
864129776acSJeffrey Hugo 		return -ENOSPC;
865129776acSJeffrey Hugo 
866129776acSJeffrey Hugo 	user_msg->len += len;
867129776acSJeffrey Hugo 	*msg_len += len;
868129776acSJeffrey Hugo 	out_trans->hdr.type = le32_to_cpu(in_trans->hdr.type);
869129776acSJeffrey Hugo 	out_trans->hdr.len = len;
870129776acSJeffrey Hugo 	out_trans->status = le32_to_cpu(in_trans->status);
871129776acSJeffrey Hugo 	out_trans->dbc_id = le32_to_cpu(in_trans->dbc_id);
872129776acSJeffrey Hugo 	out_trans->options = le64_to_cpu(in_trans->options);
873129776acSJeffrey Hugo 
874129776acSJeffrey Hugo 	if (!resources->buf)
875129776acSJeffrey Hugo 		/* how did we get an activate response without a request? */
876129776acSJeffrey Hugo 		return -EINVAL;
877129776acSJeffrey Hugo 
878129776acSJeffrey Hugo 	if (out_trans->dbc_id >= qdev->num_dbc)
879129776acSJeffrey Hugo 		/*
880129776acSJeffrey Hugo 		 * The device assigned an invalid resource, which should never
881129776acSJeffrey Hugo 		 * happen. Return an error so the user can try to recover.
882129776acSJeffrey Hugo 		 */
883129776acSJeffrey Hugo 		return -ENODEV;
884129776acSJeffrey Hugo 
885129776acSJeffrey Hugo 	if (out_trans->status)
886129776acSJeffrey Hugo 		/*
887129776acSJeffrey Hugo 		 * Allocating resources failed on device side. This is not an
888129776acSJeffrey Hugo 		 * expected behaviour, user is expected to handle this situation.
889129776acSJeffrey Hugo 		 */
890129776acSJeffrey Hugo 		return -ECANCELED;
891129776acSJeffrey Hugo 
892129776acSJeffrey Hugo 	resources->status = out_trans->status;
893129776acSJeffrey Hugo 	resources->dbc_id = out_trans->dbc_id;
894129776acSJeffrey Hugo 	save_dbc_buf(qdev, resources, usr);
895129776acSJeffrey Hugo 
896129776acSJeffrey Hugo 	return 0;
897129776acSJeffrey Hugo }
898129776acSJeffrey Hugo 
decode_deactivate(struct qaic_device * qdev,void * trans,u32 * msg_len,struct qaic_user * usr)899129776acSJeffrey Hugo static int decode_deactivate(struct qaic_device *qdev, void *trans, u32 *msg_len,
900129776acSJeffrey Hugo 			     struct qaic_user *usr)
901129776acSJeffrey Hugo {
902129776acSJeffrey Hugo 	struct wire_trans_deactivate_from_dev *in_trans = trans;
903129776acSJeffrey Hugo 	u32 dbc_id = le32_to_cpu(in_trans->dbc_id);
904129776acSJeffrey Hugo 	u32 status = le32_to_cpu(in_trans->status);
905129776acSJeffrey Hugo 
906129776acSJeffrey Hugo 	if (dbc_id >= qdev->num_dbc)
907129776acSJeffrey Hugo 		/*
908129776acSJeffrey Hugo 		 * The device assigned an invalid resource, which should never
909129776acSJeffrey Hugo 		 * happen. Inject an error so the user can try to recover.
910129776acSJeffrey Hugo 		 */
911129776acSJeffrey Hugo 		return -ENODEV;
912129776acSJeffrey Hugo 
913129776acSJeffrey Hugo 	if (status) {
914129776acSJeffrey Hugo 		/*
915129776acSJeffrey Hugo 		 * Releasing resources failed on the device side, which puts
916129776acSJeffrey Hugo 		 * us in a bind since they may still be in use, so enable the
917129776acSJeffrey Hugo 		 * dbc. User is expected to retry deactivation.
918129776acSJeffrey Hugo 		 */
919129776acSJeffrey Hugo 		enable_dbc(qdev, dbc_id, usr);
920129776acSJeffrey Hugo 		return -ECANCELED;
921129776acSJeffrey Hugo 	}
922129776acSJeffrey Hugo 
923129776acSJeffrey Hugo 	release_dbc(qdev, dbc_id);
924129776acSJeffrey Hugo 	*msg_len += sizeof(*in_trans);
925129776acSJeffrey Hugo 
926129776acSJeffrey Hugo 	return 0;
927129776acSJeffrey Hugo }
928129776acSJeffrey Hugo 
decode_status(struct qaic_device * qdev,void * trans,struct manage_msg * user_msg,u32 * user_len,struct wire_msg * msg)929129776acSJeffrey Hugo static int decode_status(struct qaic_device *qdev, void *trans, struct manage_msg *user_msg,
930129776acSJeffrey Hugo 			 u32 *user_len, struct wire_msg *msg)
931129776acSJeffrey Hugo {
932129776acSJeffrey Hugo 	struct qaic_manage_trans_status_from_dev *out_trans;
933129776acSJeffrey Hugo 	struct wire_trans_status_from_dev *in_trans = trans;
934129776acSJeffrey Hugo 	u32 len;
935129776acSJeffrey Hugo 
936129776acSJeffrey Hugo 	out_trans = (void *)user_msg->data + user_msg->len;
937129776acSJeffrey Hugo 
938129776acSJeffrey Hugo 	len = le32_to_cpu(in_trans->hdr.len);
939129776acSJeffrey Hugo 	if (user_msg->len + len > QAIC_MANAGE_MAX_MSG_LENGTH)
940129776acSJeffrey Hugo 		return -ENOSPC;
941129776acSJeffrey Hugo 
942129776acSJeffrey Hugo 	out_trans->hdr.type = QAIC_TRANS_STATUS_FROM_DEV;
943129776acSJeffrey Hugo 	out_trans->hdr.len = len;
944129776acSJeffrey Hugo 	out_trans->major = le16_to_cpu(in_trans->major);
945129776acSJeffrey Hugo 	out_trans->minor = le16_to_cpu(in_trans->minor);
946129776acSJeffrey Hugo 	out_trans->status_flags = le64_to_cpu(in_trans->status_flags);
947129776acSJeffrey Hugo 	out_trans->status = le32_to_cpu(in_trans->status);
948129776acSJeffrey Hugo 	*user_len += le32_to_cpu(in_trans->hdr.len);
949129776acSJeffrey Hugo 	user_msg->len += len;
950129776acSJeffrey Hugo 
951129776acSJeffrey Hugo 	if (out_trans->status)
952129776acSJeffrey Hugo 		return -ECANCELED;
953129776acSJeffrey Hugo 	if (out_trans->status_flags & BIT(0) && !valid_crc(msg))
954129776acSJeffrey Hugo 		return -EPIPE;
955129776acSJeffrey Hugo 
956129776acSJeffrey Hugo 	return 0;
957129776acSJeffrey Hugo }
958129776acSJeffrey Hugo 
decode_message(struct qaic_device * qdev,struct manage_msg * user_msg,struct wire_msg * msg,struct ioctl_resources * resources,struct qaic_user * usr)959129776acSJeffrey Hugo static int decode_message(struct qaic_device *qdev, struct manage_msg *user_msg,
960129776acSJeffrey Hugo 			  struct wire_msg *msg, struct ioctl_resources *resources,
961129776acSJeffrey Hugo 			  struct qaic_user *usr)
962129776acSJeffrey Hugo {
963129776acSJeffrey Hugo 	u32 msg_hdr_len = le32_to_cpu(msg->hdr.len);
964129776acSJeffrey Hugo 	struct wire_trans_hdr *trans_hdr;
965129776acSJeffrey Hugo 	u32 msg_len = 0;
966129776acSJeffrey Hugo 	int ret;
967129776acSJeffrey Hugo 	int i;
968129776acSJeffrey Hugo 
96951b56382SDan Carpenter 	if (msg_hdr_len < sizeof(*trans_hdr) ||
97051b56382SDan Carpenter 	    msg_hdr_len > QAIC_MANAGE_MAX_MSG_LENGTH)
971129776acSJeffrey Hugo 		return -EINVAL;
972129776acSJeffrey Hugo 
973129776acSJeffrey Hugo 	user_msg->len = 0;
974129776acSJeffrey Hugo 	user_msg->count = le32_to_cpu(msg->hdr.count);
975129776acSJeffrey Hugo 
976129776acSJeffrey Hugo 	for (i = 0; i < user_msg->count; ++i) {
97751b56382SDan Carpenter 		u32 hdr_len;
97851b56382SDan Carpenter 
97951b56382SDan Carpenter 		if (msg_len > msg_hdr_len - sizeof(*trans_hdr))
98051b56382SDan Carpenter 			return -EINVAL;
98151b56382SDan Carpenter 
982129776acSJeffrey Hugo 		trans_hdr = (struct wire_trans_hdr *)(msg->data + msg_len);
98351b56382SDan Carpenter 		hdr_len = le32_to_cpu(trans_hdr->len);
98451b56382SDan Carpenter 		if (hdr_len < sizeof(*trans_hdr) ||
98551b56382SDan Carpenter 		    size_add(msg_len, hdr_len) > msg_hdr_len)
986129776acSJeffrey Hugo 			return -EINVAL;
987129776acSJeffrey Hugo 
988129776acSJeffrey Hugo 		switch (le32_to_cpu(trans_hdr->type)) {
989129776acSJeffrey Hugo 		case QAIC_TRANS_PASSTHROUGH_FROM_DEV:
990129776acSJeffrey Hugo 			ret = decode_passthrough(qdev, trans_hdr, user_msg, &msg_len);
991129776acSJeffrey Hugo 			break;
992129776acSJeffrey Hugo 		case QAIC_TRANS_ACTIVATE_FROM_DEV:
993129776acSJeffrey Hugo 			ret = decode_activate(qdev, trans_hdr, user_msg, &msg_len, resources, usr);
994129776acSJeffrey Hugo 			break;
995129776acSJeffrey Hugo 		case QAIC_TRANS_DEACTIVATE_FROM_DEV:
996129776acSJeffrey Hugo 			ret = decode_deactivate(qdev, trans_hdr, &msg_len, usr);
997129776acSJeffrey Hugo 			break;
998129776acSJeffrey Hugo 		case QAIC_TRANS_STATUS_FROM_DEV:
999129776acSJeffrey Hugo 			ret = decode_status(qdev, trans_hdr, user_msg, &msg_len, msg);
1000129776acSJeffrey Hugo 			break;
1001129776acSJeffrey Hugo 		default:
1002129776acSJeffrey Hugo 			return -EINVAL;
1003129776acSJeffrey Hugo 		}
1004129776acSJeffrey Hugo 
1005129776acSJeffrey Hugo 		if (ret)
1006129776acSJeffrey Hugo 			return ret;
1007129776acSJeffrey Hugo 	}
1008129776acSJeffrey Hugo 
1009129776acSJeffrey Hugo 	if (msg_len != (msg_hdr_len - sizeof(msg->hdr)))
1010129776acSJeffrey Hugo 		return -EINVAL;
1011129776acSJeffrey Hugo 
1012129776acSJeffrey Hugo 	return 0;
1013129776acSJeffrey Hugo }
1014129776acSJeffrey Hugo 
msg_xfer(struct qaic_device * qdev,struct wrapper_list * wrappers,u32 seq_num,bool ignore_signal)1015129776acSJeffrey Hugo static void *msg_xfer(struct qaic_device *qdev, struct wrapper_list *wrappers, u32 seq_num,
1016129776acSJeffrey Hugo 		      bool ignore_signal)
1017129776acSJeffrey Hugo {
1018129776acSJeffrey Hugo 	struct xfer_queue_elem elem;
1019129776acSJeffrey Hugo 	struct wire_msg *out_buf;
1020129776acSJeffrey Hugo 	struct wrapper_msg *w;
1021e997c218SJeffrey Hugo 	long ret = -EAGAIN;
1022e997c218SJeffrey Hugo 	int xfer_count = 0;
1023129776acSJeffrey Hugo 	int retry_count;
1024129776acSJeffrey Hugo 
1025129776acSJeffrey Hugo 	if (qdev->in_reset) {
1026129776acSJeffrey Hugo 		mutex_unlock(&qdev->cntl_mutex);
1027129776acSJeffrey Hugo 		return ERR_PTR(-ENODEV);
1028129776acSJeffrey Hugo 	}
1029129776acSJeffrey Hugo 
1030e997c218SJeffrey Hugo 	/* Attempt to avoid a partial commit of a message */
1031e997c218SJeffrey Hugo 	list_for_each_entry(w, &wrappers->list, list)
1032e997c218SJeffrey Hugo 		xfer_count++;
1033e997c218SJeffrey Hugo 
1034e997c218SJeffrey Hugo 	for (retry_count = 0; retry_count < QAIC_MHI_RETRY_MAX; retry_count++) {
1035e997c218SJeffrey Hugo 		if (xfer_count <= mhi_get_free_desc_count(qdev->cntl_ch, DMA_TO_DEVICE)) {
1036e997c218SJeffrey Hugo 			ret = 0;
1037e997c218SJeffrey Hugo 			break;
1038e997c218SJeffrey Hugo 		}
1039e997c218SJeffrey Hugo 		msleep_interruptible(QAIC_MHI_RETRY_WAIT_MS);
1040e997c218SJeffrey Hugo 		if (signal_pending(current))
1041e997c218SJeffrey Hugo 			break;
1042e997c218SJeffrey Hugo 	}
1043e997c218SJeffrey Hugo 
1044e997c218SJeffrey Hugo 	if (ret) {
1045e997c218SJeffrey Hugo 		mutex_unlock(&qdev->cntl_mutex);
1046e997c218SJeffrey Hugo 		return ERR_PTR(ret);
1047e997c218SJeffrey Hugo 	}
1048e997c218SJeffrey Hugo 
1049129776acSJeffrey Hugo 	elem.seq_num = seq_num;
1050129776acSJeffrey Hugo 	elem.buf = NULL;
1051129776acSJeffrey Hugo 	init_completion(&elem.xfer_done);
1052129776acSJeffrey Hugo 	if (likely(!qdev->cntl_lost_buf)) {
1053129776acSJeffrey Hugo 		/*
1054129776acSJeffrey Hugo 		 * The max size of request to device is QAIC_MANAGE_EXT_MSG_LENGTH.
1055129776acSJeffrey Hugo 		 * The max size of response from device is QAIC_MANAGE_MAX_MSG_LENGTH.
1056129776acSJeffrey Hugo 		 */
1057129776acSJeffrey Hugo 		out_buf = kmalloc(QAIC_MANAGE_MAX_MSG_LENGTH, GFP_KERNEL);
1058129776acSJeffrey Hugo 		if (!out_buf) {
1059129776acSJeffrey Hugo 			mutex_unlock(&qdev->cntl_mutex);
1060129776acSJeffrey Hugo 			return ERR_PTR(-ENOMEM);
1061129776acSJeffrey Hugo 		}
1062129776acSJeffrey Hugo 
1063129776acSJeffrey Hugo 		ret = mhi_queue_buf(qdev->cntl_ch, DMA_FROM_DEVICE, out_buf,
1064129776acSJeffrey Hugo 				    QAIC_MANAGE_MAX_MSG_LENGTH, MHI_EOT);
1065129776acSJeffrey Hugo 		if (ret) {
1066129776acSJeffrey Hugo 			mutex_unlock(&qdev->cntl_mutex);
1067129776acSJeffrey Hugo 			return ERR_PTR(ret);
1068129776acSJeffrey Hugo 		}
1069129776acSJeffrey Hugo 	} else {
1070129776acSJeffrey Hugo 		/*
1071129776acSJeffrey Hugo 		 * we lost a buffer because we queued a recv buf, but then
1072129776acSJeffrey Hugo 		 * queuing the corresponding tx buf failed. To try to avoid
1073129776acSJeffrey Hugo 		 * a memory leak, lets reclaim it and use it for this
1074129776acSJeffrey Hugo 		 * transaction.
1075129776acSJeffrey Hugo 		 */
1076129776acSJeffrey Hugo 		qdev->cntl_lost_buf = false;
1077129776acSJeffrey Hugo 	}
1078129776acSJeffrey Hugo 
1079129776acSJeffrey Hugo 	list_for_each_entry(w, &wrappers->list, list) {
1080129776acSJeffrey Hugo 		kref_get(&w->ref_count);
1081129776acSJeffrey Hugo 		retry_count = 0;
1082129776acSJeffrey Hugo 		ret = mhi_queue_buf(qdev->cntl_ch, DMA_TO_DEVICE, &w->msg, w->len,
1083129776acSJeffrey Hugo 				    list_is_last(&w->list, &wrappers->list) ? MHI_EOT : MHI_CHAIN);
1084129776acSJeffrey Hugo 		if (ret) {
1085129776acSJeffrey Hugo 			qdev->cntl_lost_buf = true;
1086129776acSJeffrey Hugo 			kref_put(&w->ref_count, free_wrapper);
1087129776acSJeffrey Hugo 			mutex_unlock(&qdev->cntl_mutex);
1088129776acSJeffrey Hugo 			return ERR_PTR(ret);
1089129776acSJeffrey Hugo 		}
1090129776acSJeffrey Hugo 	}
1091129776acSJeffrey Hugo 
1092129776acSJeffrey Hugo 	list_add_tail(&elem.list, &qdev->cntl_xfer_list);
1093129776acSJeffrey Hugo 	mutex_unlock(&qdev->cntl_mutex);
1094129776acSJeffrey Hugo 
1095129776acSJeffrey Hugo 	if (ignore_signal)
1096129776acSJeffrey Hugo 		ret = wait_for_completion_timeout(&elem.xfer_done, control_resp_timeout_s * HZ);
1097129776acSJeffrey Hugo 	else
1098129776acSJeffrey Hugo 		ret = wait_for_completion_interruptible_timeout(&elem.xfer_done,
1099129776acSJeffrey Hugo 								control_resp_timeout_s * HZ);
1100129776acSJeffrey Hugo 	/*
1101129776acSJeffrey Hugo 	 * not using _interruptable because we have to cleanup or we'll
1102129776acSJeffrey Hugo 	 * likely cause memory corruption
1103129776acSJeffrey Hugo 	 */
1104129776acSJeffrey Hugo 	mutex_lock(&qdev->cntl_mutex);
1105129776acSJeffrey Hugo 	if (!list_empty(&elem.list))
1106129776acSJeffrey Hugo 		list_del(&elem.list);
1107129776acSJeffrey Hugo 	if (!ret && !elem.buf)
1108129776acSJeffrey Hugo 		ret = -ETIMEDOUT;
1109129776acSJeffrey Hugo 	else if (ret > 0 && !elem.buf)
1110129776acSJeffrey Hugo 		ret = -EIO;
1111129776acSJeffrey Hugo 	mutex_unlock(&qdev->cntl_mutex);
1112129776acSJeffrey Hugo 
1113129776acSJeffrey Hugo 	if (ret < 0) {
1114129776acSJeffrey Hugo 		kfree(elem.buf);
1115129776acSJeffrey Hugo 		return ERR_PTR(ret);
1116129776acSJeffrey Hugo 	} else if (!qdev->valid_crc(elem.buf)) {
1117129776acSJeffrey Hugo 		kfree(elem.buf);
1118129776acSJeffrey Hugo 		return ERR_PTR(-EPIPE);
1119129776acSJeffrey Hugo 	}
1120129776acSJeffrey Hugo 
1121129776acSJeffrey Hugo 	return elem.buf;
1122129776acSJeffrey Hugo }
1123129776acSJeffrey Hugo 
1124129776acSJeffrey Hugo /* Add a transaction to abort the outstanding DMA continuation */
abort_dma_cont(struct qaic_device * qdev,struct wrapper_list * wrappers,u32 dma_chunk_id)1125129776acSJeffrey Hugo static int abort_dma_cont(struct qaic_device *qdev, struct wrapper_list *wrappers, u32 dma_chunk_id)
1126129776acSJeffrey Hugo {
1127129776acSJeffrey Hugo 	struct wire_trans_dma_xfer *out_trans;
1128129776acSJeffrey Hugo 	u32 size = sizeof(*out_trans);
1129129776acSJeffrey Hugo 	struct wrapper_msg *wrapper;
1130129776acSJeffrey Hugo 	struct wrapper_msg *w;
1131129776acSJeffrey Hugo 	struct wire_msg *msg;
1132129776acSJeffrey Hugo 
1133129776acSJeffrey Hugo 	wrapper = list_first_entry(&wrappers->list, struct wrapper_msg, list);
1134129776acSJeffrey Hugo 	msg = &wrapper->msg;
1135129776acSJeffrey Hugo 
1136129776acSJeffrey Hugo 	/* Remove all but the first wrapper which has the msg header */
1137129776acSJeffrey Hugo 	list_for_each_entry_safe(wrapper, w, &wrappers->list, list)
1138129776acSJeffrey Hugo 		if (!list_is_first(&wrapper->list, &wrappers->list))
1139129776acSJeffrey Hugo 			kref_put(&wrapper->ref_count, free_wrapper);
1140129776acSJeffrey Hugo 
1141129776acSJeffrey Hugo 	wrapper = add_wrapper(wrappers, offsetof(struct wrapper_msg, trans) + sizeof(*out_trans));
1142129776acSJeffrey Hugo 
1143129776acSJeffrey Hugo 	if (!wrapper)
1144129776acSJeffrey Hugo 		return -ENOMEM;
1145129776acSJeffrey Hugo 
1146129776acSJeffrey Hugo 	out_trans = (struct wire_trans_dma_xfer *)&wrapper->trans;
1147129776acSJeffrey Hugo 	out_trans->hdr.type = cpu_to_le32(QAIC_TRANS_DMA_XFER_TO_DEV);
1148129776acSJeffrey Hugo 	out_trans->hdr.len = cpu_to_le32(size);
1149129776acSJeffrey Hugo 	out_trans->tag = cpu_to_le32(0);
1150129776acSJeffrey Hugo 	out_trans->count = cpu_to_le32(0);
1151129776acSJeffrey Hugo 	out_trans->dma_chunk_id = cpu_to_le32(dma_chunk_id);
1152129776acSJeffrey Hugo 
1153129776acSJeffrey Hugo 	msg->hdr.len = cpu_to_le32(size + sizeof(*msg));
1154129776acSJeffrey Hugo 	msg->hdr.count = cpu_to_le32(1);
1155129776acSJeffrey Hugo 	wrapper->len = size;
1156129776acSJeffrey Hugo 
1157129776acSJeffrey Hugo 	return 0;
1158129776acSJeffrey Hugo }
1159129776acSJeffrey Hugo 
alloc_wrapper_list(void)1160129776acSJeffrey Hugo static struct wrapper_list *alloc_wrapper_list(void)
1161129776acSJeffrey Hugo {
1162129776acSJeffrey Hugo 	struct wrapper_list *wrappers;
1163129776acSJeffrey Hugo 
1164129776acSJeffrey Hugo 	wrappers = kmalloc(sizeof(*wrappers), GFP_KERNEL);
1165129776acSJeffrey Hugo 	if (!wrappers)
1166129776acSJeffrey Hugo 		return NULL;
1167129776acSJeffrey Hugo 	INIT_LIST_HEAD(&wrappers->list);
1168129776acSJeffrey Hugo 	spin_lock_init(&wrappers->lock);
1169129776acSJeffrey Hugo 
1170129776acSJeffrey Hugo 	return wrappers;
1171129776acSJeffrey Hugo }
1172129776acSJeffrey Hugo 
qaic_manage_msg_xfer(struct qaic_device * qdev,struct qaic_user * usr,struct manage_msg * user_msg,struct ioctl_resources * resources,struct wire_msg ** rsp)1173129776acSJeffrey Hugo static int qaic_manage_msg_xfer(struct qaic_device *qdev, struct qaic_user *usr,
1174129776acSJeffrey Hugo 				struct manage_msg *user_msg, struct ioctl_resources *resources,
1175129776acSJeffrey Hugo 				struct wire_msg **rsp)
1176129776acSJeffrey Hugo {
1177129776acSJeffrey Hugo 	struct wrapper_list *wrappers;
1178129776acSJeffrey Hugo 	struct wrapper_msg *wrapper;
1179129776acSJeffrey Hugo 	struct wrapper_msg *w;
1180129776acSJeffrey Hugo 	bool all_done = false;
1181129776acSJeffrey Hugo 	struct wire_msg *msg;
1182129776acSJeffrey Hugo 	int ret;
1183129776acSJeffrey Hugo 
1184129776acSJeffrey Hugo 	wrappers = alloc_wrapper_list();
1185129776acSJeffrey Hugo 	if (!wrappers)
1186129776acSJeffrey Hugo 		return -ENOMEM;
1187129776acSJeffrey Hugo 
1188129776acSJeffrey Hugo 	wrapper = add_wrapper(wrappers, sizeof(*wrapper));
1189129776acSJeffrey Hugo 	if (!wrapper) {
1190129776acSJeffrey Hugo 		kfree(wrappers);
1191129776acSJeffrey Hugo 		return -ENOMEM;
1192129776acSJeffrey Hugo 	}
1193129776acSJeffrey Hugo 
1194129776acSJeffrey Hugo 	msg = &wrapper->msg;
1195129776acSJeffrey Hugo 	wrapper->len = sizeof(*msg);
1196129776acSJeffrey Hugo 
1197129776acSJeffrey Hugo 	ret = encode_message(qdev, user_msg, wrappers, resources, usr);
1198129776acSJeffrey Hugo 	if (ret && resources->dma_chunk_id)
1199129776acSJeffrey Hugo 		ret = abort_dma_cont(qdev, wrappers, resources->dma_chunk_id);
1200129776acSJeffrey Hugo 	if (ret)
1201129776acSJeffrey Hugo 		goto encode_failed;
1202129776acSJeffrey Hugo 
1203129776acSJeffrey Hugo 	ret = mutex_lock_interruptible(&qdev->cntl_mutex);
1204129776acSJeffrey Hugo 	if (ret)
1205129776acSJeffrey Hugo 		goto lock_failed;
1206129776acSJeffrey Hugo 
1207129776acSJeffrey Hugo 	msg->hdr.magic_number = MANAGE_MAGIC_NUMBER;
1208129776acSJeffrey Hugo 	msg->hdr.sequence_number = cpu_to_le32(qdev->next_seq_num++);
1209129776acSJeffrey Hugo 
1210129776acSJeffrey Hugo 	if (usr) {
1211129776acSJeffrey Hugo 		msg->hdr.handle = cpu_to_le32(usr->handle);
1212129776acSJeffrey Hugo 		msg->hdr.partition_id = cpu_to_le32(usr->qddev->partition_id);
1213129776acSJeffrey Hugo 	} else {
1214129776acSJeffrey Hugo 		msg->hdr.handle = 0;
1215129776acSJeffrey Hugo 		msg->hdr.partition_id = cpu_to_le32(QAIC_NO_PARTITION);
1216129776acSJeffrey Hugo 	}
1217129776acSJeffrey Hugo 
1218129776acSJeffrey Hugo 	msg->hdr.padding = cpu_to_le32(0);
1219129776acSJeffrey Hugo 	msg->hdr.crc32 = cpu_to_le32(qdev->gen_crc(wrappers));
1220129776acSJeffrey Hugo 
1221129776acSJeffrey Hugo 	/* msg_xfer releases the mutex */
1222129776acSJeffrey Hugo 	*rsp = msg_xfer(qdev, wrappers, qdev->next_seq_num - 1, false);
1223129776acSJeffrey Hugo 	if (IS_ERR(*rsp))
1224129776acSJeffrey Hugo 		ret = PTR_ERR(*rsp);
1225129776acSJeffrey Hugo 
1226129776acSJeffrey Hugo lock_failed:
1227129776acSJeffrey Hugo 	free_dma_xfers(qdev, resources);
1228129776acSJeffrey Hugo encode_failed:
1229129776acSJeffrey Hugo 	spin_lock(&wrappers->lock);
1230129776acSJeffrey Hugo 	list_for_each_entry_safe(wrapper, w, &wrappers->list, list)
1231129776acSJeffrey Hugo 		kref_put(&wrapper->ref_count, free_wrapper);
1232129776acSJeffrey Hugo 	all_done = list_empty(&wrappers->list);
1233129776acSJeffrey Hugo 	spin_unlock(&wrappers->lock);
1234129776acSJeffrey Hugo 	if (all_done)
1235129776acSJeffrey Hugo 		kfree(wrappers);
1236129776acSJeffrey Hugo 
1237129776acSJeffrey Hugo 	return ret;
1238129776acSJeffrey Hugo }
1239129776acSJeffrey Hugo 
qaic_manage(struct qaic_device * qdev,struct qaic_user * usr,struct manage_msg * user_msg)1240129776acSJeffrey Hugo static int qaic_manage(struct qaic_device *qdev, struct qaic_user *usr, struct manage_msg *user_msg)
1241129776acSJeffrey Hugo {
1242129776acSJeffrey Hugo 	struct wire_trans_dma_xfer_cont *dma_cont = NULL;
1243129776acSJeffrey Hugo 	struct ioctl_resources resources;
1244129776acSJeffrey Hugo 	struct wire_msg *rsp = NULL;
1245129776acSJeffrey Hugo 	int ret;
1246129776acSJeffrey Hugo 
1247129776acSJeffrey Hugo 	memset(&resources, 0, sizeof(struct ioctl_resources));
1248129776acSJeffrey Hugo 
1249129776acSJeffrey Hugo 	INIT_LIST_HEAD(&resources.dma_xfers);
1250129776acSJeffrey Hugo 
1251129776acSJeffrey Hugo 	if (user_msg->len > QAIC_MANAGE_MAX_MSG_LENGTH ||
1252129776acSJeffrey Hugo 	    user_msg->count > QAIC_MANAGE_MAX_MSG_LENGTH / sizeof(struct qaic_manage_trans_hdr))
1253129776acSJeffrey Hugo 		return -EINVAL;
1254129776acSJeffrey Hugo 
1255129776acSJeffrey Hugo dma_xfer_continue:
1256129776acSJeffrey Hugo 	ret = qaic_manage_msg_xfer(qdev, usr, user_msg, &resources, &rsp);
1257129776acSJeffrey Hugo 	if (ret)
1258129776acSJeffrey Hugo 		return ret;
1259129776acSJeffrey Hugo 	/* dma_cont should be the only transaction if present */
1260129776acSJeffrey Hugo 	if (le32_to_cpu(rsp->hdr.count) == 1) {
1261129776acSJeffrey Hugo 		dma_cont = (struct wire_trans_dma_xfer_cont *)rsp->data;
1262129776acSJeffrey Hugo 		if (le32_to_cpu(dma_cont->hdr.type) != QAIC_TRANS_DMA_XFER_CONT)
1263129776acSJeffrey Hugo 			dma_cont = NULL;
1264129776acSJeffrey Hugo 	}
1265129776acSJeffrey Hugo 	if (dma_cont) {
1266129776acSJeffrey Hugo 		if (le32_to_cpu(dma_cont->dma_chunk_id) == resources.dma_chunk_id &&
1267129776acSJeffrey Hugo 		    le64_to_cpu(dma_cont->xferred_size) == resources.xferred_dma_size) {
1268129776acSJeffrey Hugo 			kfree(rsp);
1269129776acSJeffrey Hugo 			goto dma_xfer_continue;
1270129776acSJeffrey Hugo 		}
1271129776acSJeffrey Hugo 
1272129776acSJeffrey Hugo 		ret = -EINVAL;
1273129776acSJeffrey Hugo 		goto dma_cont_failed;
1274129776acSJeffrey Hugo 	}
1275129776acSJeffrey Hugo 
1276129776acSJeffrey Hugo 	ret = decode_message(qdev, user_msg, rsp, &resources, usr);
1277129776acSJeffrey Hugo 
1278129776acSJeffrey Hugo dma_cont_failed:
1279129776acSJeffrey Hugo 	free_dbc_buf(qdev, &resources);
1280129776acSJeffrey Hugo 	kfree(rsp);
1281129776acSJeffrey Hugo 	return ret;
1282129776acSJeffrey Hugo }
1283129776acSJeffrey Hugo 
qaic_manage_ioctl(struct drm_device * dev,void * data,struct drm_file * file_priv)1284129776acSJeffrey Hugo int qaic_manage_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
1285129776acSJeffrey Hugo {
1286d3b277b7SPranjal Ramajor Asha Kanojiya 	struct qaic_manage_msg *user_msg = data;
1287129776acSJeffrey Hugo 	struct qaic_device *qdev;
1288129776acSJeffrey Hugo 	struct manage_msg *msg;
1289129776acSJeffrey Hugo 	struct qaic_user *usr;
1290129776acSJeffrey Hugo 	u8 __user *user_data;
1291129776acSJeffrey Hugo 	int qdev_rcu_id;
1292129776acSJeffrey Hugo 	int usr_rcu_id;
1293129776acSJeffrey Hugo 	int ret;
1294129776acSJeffrey Hugo 
1295d3b277b7SPranjal Ramajor Asha Kanojiya 	if (user_msg->len > QAIC_MANAGE_MAX_MSG_LENGTH)
1296d3b277b7SPranjal Ramajor Asha Kanojiya 		return -EINVAL;
1297d3b277b7SPranjal Ramajor Asha Kanojiya 
1298129776acSJeffrey Hugo 	usr = file_priv->driver_priv;
1299129776acSJeffrey Hugo 
1300129776acSJeffrey Hugo 	usr_rcu_id = srcu_read_lock(&usr->qddev_lock);
1301129776acSJeffrey Hugo 	if (!usr->qddev) {
1302129776acSJeffrey Hugo 		srcu_read_unlock(&usr->qddev_lock, usr_rcu_id);
1303129776acSJeffrey Hugo 		return -ENODEV;
1304129776acSJeffrey Hugo 	}
1305129776acSJeffrey Hugo 
1306129776acSJeffrey Hugo 	qdev = usr->qddev->qdev;
1307129776acSJeffrey Hugo 
1308129776acSJeffrey Hugo 	qdev_rcu_id = srcu_read_lock(&qdev->dev_lock);
1309129776acSJeffrey Hugo 	if (qdev->in_reset) {
1310129776acSJeffrey Hugo 		srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id);
1311129776acSJeffrey Hugo 		srcu_read_unlock(&usr->qddev_lock, usr_rcu_id);
1312129776acSJeffrey Hugo 		return -ENODEV;
1313129776acSJeffrey Hugo 	}
1314129776acSJeffrey Hugo 
1315129776acSJeffrey Hugo 	msg = kzalloc(QAIC_MANAGE_MAX_MSG_LENGTH + sizeof(*msg), GFP_KERNEL);
1316129776acSJeffrey Hugo 	if (!msg) {
1317129776acSJeffrey Hugo 		ret = -ENOMEM;
1318129776acSJeffrey Hugo 		goto out;
1319129776acSJeffrey Hugo 	}
1320129776acSJeffrey Hugo 
1321129776acSJeffrey Hugo 	msg->len = user_msg->len;
1322129776acSJeffrey Hugo 	msg->count = user_msg->count;
1323129776acSJeffrey Hugo 
1324129776acSJeffrey Hugo 	user_data = u64_to_user_ptr(user_msg->data);
1325129776acSJeffrey Hugo 
1326129776acSJeffrey Hugo 	if (copy_from_user(msg->data, user_data, user_msg->len)) {
1327129776acSJeffrey Hugo 		ret = -EFAULT;
1328129776acSJeffrey Hugo 		goto free_msg;
1329129776acSJeffrey Hugo 	}
1330129776acSJeffrey Hugo 
1331129776acSJeffrey Hugo 	ret = qaic_manage(qdev, usr, msg);
1332129776acSJeffrey Hugo 
1333129776acSJeffrey Hugo 	/*
1334129776acSJeffrey Hugo 	 * If the qaic_manage() is successful then we copy the message onto
1335129776acSJeffrey Hugo 	 * userspace memory but we have an exception for -ECANCELED.
1336129776acSJeffrey Hugo 	 * For -ECANCELED, it means that device has NACKed the message with a
1337129776acSJeffrey Hugo 	 * status error code which userspace would like to know.
1338129776acSJeffrey Hugo 	 */
1339129776acSJeffrey Hugo 	if (ret == -ECANCELED || !ret) {
1340129776acSJeffrey Hugo 		if (copy_to_user(user_data, msg->data, msg->len)) {
1341129776acSJeffrey Hugo 			ret = -EFAULT;
1342129776acSJeffrey Hugo 		} else {
1343129776acSJeffrey Hugo 			user_msg->len = msg->len;
1344129776acSJeffrey Hugo 			user_msg->count = msg->count;
1345129776acSJeffrey Hugo 		}
1346129776acSJeffrey Hugo 	}
1347129776acSJeffrey Hugo 
1348129776acSJeffrey Hugo free_msg:
1349129776acSJeffrey Hugo 	kfree(msg);
1350129776acSJeffrey Hugo out:
1351129776acSJeffrey Hugo 	srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id);
1352129776acSJeffrey Hugo 	srcu_read_unlock(&usr->qddev_lock, usr_rcu_id);
1353129776acSJeffrey Hugo 	return ret;
1354129776acSJeffrey Hugo }
1355129776acSJeffrey Hugo 
get_cntl_version(struct qaic_device * qdev,struct qaic_user * usr,u16 * major,u16 * minor)1356129776acSJeffrey Hugo int get_cntl_version(struct qaic_device *qdev, struct qaic_user *usr, u16 *major, u16 *minor)
1357129776acSJeffrey Hugo {
1358129776acSJeffrey Hugo 	struct qaic_manage_trans_status_from_dev *status_result;
1359129776acSJeffrey Hugo 	struct qaic_manage_trans_status_to_dev *status_query;
1360129776acSJeffrey Hugo 	struct manage_msg *user_msg;
1361129776acSJeffrey Hugo 	int ret;
1362129776acSJeffrey Hugo 
1363129776acSJeffrey Hugo 	user_msg = kmalloc(sizeof(*user_msg) + sizeof(*status_result), GFP_KERNEL);
1364129776acSJeffrey Hugo 	if (!user_msg) {
1365129776acSJeffrey Hugo 		ret = -ENOMEM;
1366129776acSJeffrey Hugo 		goto out;
1367129776acSJeffrey Hugo 	}
1368129776acSJeffrey Hugo 	user_msg->len = sizeof(*status_query);
1369129776acSJeffrey Hugo 	user_msg->count = 1;
1370129776acSJeffrey Hugo 
1371129776acSJeffrey Hugo 	status_query = (struct qaic_manage_trans_status_to_dev *)user_msg->data;
1372129776acSJeffrey Hugo 	status_query->hdr.type = QAIC_TRANS_STATUS_FROM_USR;
1373129776acSJeffrey Hugo 	status_query->hdr.len = sizeof(status_query->hdr);
1374129776acSJeffrey Hugo 
1375129776acSJeffrey Hugo 	ret = qaic_manage(qdev, usr, user_msg);
1376129776acSJeffrey Hugo 	if (ret)
1377129776acSJeffrey Hugo 		goto kfree_user_msg;
1378129776acSJeffrey Hugo 	status_result = (struct qaic_manage_trans_status_from_dev *)user_msg->data;
1379129776acSJeffrey Hugo 	*major = status_result->major;
1380129776acSJeffrey Hugo 	*minor = status_result->minor;
1381129776acSJeffrey Hugo 
1382129776acSJeffrey Hugo 	if (status_result->status_flags & BIT(0)) { /* device is using CRC */
1383129776acSJeffrey Hugo 		/* By default qdev->gen_crc is programmed to generate CRC */
1384129776acSJeffrey Hugo 		qdev->valid_crc = valid_crc;
1385129776acSJeffrey Hugo 	} else {
1386129776acSJeffrey Hugo 		/* By default qdev->valid_crc is programmed to bypass CRC */
1387129776acSJeffrey Hugo 		qdev->gen_crc = gen_crc_stub;
1388129776acSJeffrey Hugo 	}
1389129776acSJeffrey Hugo 
1390129776acSJeffrey Hugo kfree_user_msg:
1391129776acSJeffrey Hugo 	kfree(user_msg);
1392129776acSJeffrey Hugo out:
1393129776acSJeffrey Hugo 	return ret;
1394129776acSJeffrey Hugo }
1395129776acSJeffrey Hugo 
resp_worker(struct work_struct * work)1396129776acSJeffrey Hugo static void resp_worker(struct work_struct *work)
1397129776acSJeffrey Hugo {
1398129776acSJeffrey Hugo 	struct resp_work *resp = container_of(work, struct resp_work, work);
1399129776acSJeffrey Hugo 	struct qaic_device *qdev = resp->qdev;
1400129776acSJeffrey Hugo 	struct wire_msg *msg = resp->buf;
1401129776acSJeffrey Hugo 	struct xfer_queue_elem *elem;
1402129776acSJeffrey Hugo 	struct xfer_queue_elem *i;
1403129776acSJeffrey Hugo 	bool found = false;
1404129776acSJeffrey Hugo 
1405129776acSJeffrey Hugo 	mutex_lock(&qdev->cntl_mutex);
1406129776acSJeffrey Hugo 	list_for_each_entry_safe(elem, i, &qdev->cntl_xfer_list, list) {
1407129776acSJeffrey Hugo 		if (elem->seq_num == le32_to_cpu(msg->hdr.sequence_number)) {
1408129776acSJeffrey Hugo 			found = true;
1409129776acSJeffrey Hugo 			list_del_init(&elem->list);
1410129776acSJeffrey Hugo 			elem->buf = msg;
1411129776acSJeffrey Hugo 			complete_all(&elem->xfer_done);
1412129776acSJeffrey Hugo 			break;
1413129776acSJeffrey Hugo 		}
1414129776acSJeffrey Hugo 	}
1415129776acSJeffrey Hugo 	mutex_unlock(&qdev->cntl_mutex);
1416129776acSJeffrey Hugo 
1417129776acSJeffrey Hugo 	if (!found)
1418129776acSJeffrey Hugo 		/* request must have timed out, drop packet */
1419129776acSJeffrey Hugo 		kfree(msg);
1420129776acSJeffrey Hugo 
1421129776acSJeffrey Hugo 	kfree(resp);
1422129776acSJeffrey Hugo }
1423129776acSJeffrey Hugo 
free_wrapper_from_list(struct wrapper_list * wrappers,struct wrapper_msg * wrapper)1424129776acSJeffrey Hugo static void free_wrapper_from_list(struct wrapper_list *wrappers, struct wrapper_msg *wrapper)
1425129776acSJeffrey Hugo {
1426129776acSJeffrey Hugo 	bool all_done = false;
1427129776acSJeffrey Hugo 
1428129776acSJeffrey Hugo 	spin_lock(&wrappers->lock);
1429129776acSJeffrey Hugo 	kref_put(&wrapper->ref_count, free_wrapper);
1430129776acSJeffrey Hugo 	all_done = list_empty(&wrappers->list);
1431129776acSJeffrey Hugo 	spin_unlock(&wrappers->lock);
1432129776acSJeffrey Hugo 
1433129776acSJeffrey Hugo 	if (all_done)
1434129776acSJeffrey Hugo 		kfree(wrappers);
1435129776acSJeffrey Hugo }
1436129776acSJeffrey Hugo 
qaic_mhi_ul_xfer_cb(struct mhi_device * mhi_dev,struct mhi_result * mhi_result)1437129776acSJeffrey Hugo void qaic_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
1438129776acSJeffrey Hugo {
1439129776acSJeffrey Hugo 	struct wire_msg *msg = mhi_result->buf_addr;
1440129776acSJeffrey Hugo 	struct wrapper_msg *wrapper = container_of(msg, struct wrapper_msg, msg);
1441129776acSJeffrey Hugo 
1442129776acSJeffrey Hugo 	free_wrapper_from_list(wrapper->head, wrapper);
1443129776acSJeffrey Hugo }
1444129776acSJeffrey Hugo 
qaic_mhi_dl_xfer_cb(struct mhi_device * mhi_dev,struct mhi_result * mhi_result)1445129776acSJeffrey Hugo void qaic_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
1446129776acSJeffrey Hugo {
1447129776acSJeffrey Hugo 	struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev);
1448129776acSJeffrey Hugo 	struct wire_msg *msg = mhi_result->buf_addr;
1449129776acSJeffrey Hugo 	struct resp_work *resp;
1450129776acSJeffrey Hugo 
1451129776acSJeffrey Hugo 	if (mhi_result->transaction_status || msg->hdr.magic_number != MANAGE_MAGIC_NUMBER) {
1452129776acSJeffrey Hugo 		kfree(msg);
1453129776acSJeffrey Hugo 		return;
1454129776acSJeffrey Hugo 	}
1455129776acSJeffrey Hugo 
1456129776acSJeffrey Hugo 	resp = kmalloc(sizeof(*resp), GFP_ATOMIC);
1457129776acSJeffrey Hugo 	if (!resp) {
1458129776acSJeffrey Hugo 		kfree(msg);
1459129776acSJeffrey Hugo 		return;
1460129776acSJeffrey Hugo 	}
1461129776acSJeffrey Hugo 
1462129776acSJeffrey Hugo 	INIT_WORK(&resp->work, resp_worker);
1463129776acSJeffrey Hugo 	resp->qdev = qdev;
1464129776acSJeffrey Hugo 	resp->buf = msg;
1465129776acSJeffrey Hugo 	queue_work(qdev->cntl_wq, &resp->work);
1466129776acSJeffrey Hugo }
1467129776acSJeffrey Hugo 
qaic_control_open(struct qaic_device * qdev)1468129776acSJeffrey Hugo int qaic_control_open(struct qaic_device *qdev)
1469129776acSJeffrey Hugo {
1470129776acSJeffrey Hugo 	if (!qdev->cntl_ch)
1471129776acSJeffrey Hugo 		return -ENODEV;
1472129776acSJeffrey Hugo 
1473129776acSJeffrey Hugo 	qdev->cntl_lost_buf = false;
1474129776acSJeffrey Hugo 	/*
1475129776acSJeffrey Hugo 	 * By default qaic should assume that device has CRC enabled.
1476129776acSJeffrey Hugo 	 * Qaic comes to know if device has CRC enabled or disabled during the
1477129776acSJeffrey Hugo 	 * device status transaction, which is the first transaction performed
1478129776acSJeffrey Hugo 	 * on control channel.
1479129776acSJeffrey Hugo 	 *
1480129776acSJeffrey Hugo 	 * So CRC validation of first device status transaction response is
1481129776acSJeffrey Hugo 	 * ignored (by calling valid_crc_stub) and is done later during decoding
1482129776acSJeffrey Hugo 	 * if device has CRC enabled.
1483129776acSJeffrey Hugo 	 * Now that qaic knows whether device has CRC enabled or not it acts
1484129776acSJeffrey Hugo 	 * accordingly.
1485129776acSJeffrey Hugo 	 */
1486129776acSJeffrey Hugo 	qdev->gen_crc = gen_crc;
1487129776acSJeffrey Hugo 	qdev->valid_crc = valid_crc_stub;
1488129776acSJeffrey Hugo 
1489129776acSJeffrey Hugo 	return mhi_prepare_for_transfer(qdev->cntl_ch);
1490129776acSJeffrey Hugo }
1491129776acSJeffrey Hugo 
qaic_control_close(struct qaic_device * qdev)1492129776acSJeffrey Hugo void qaic_control_close(struct qaic_device *qdev)
1493129776acSJeffrey Hugo {
1494129776acSJeffrey Hugo 	mhi_unprepare_from_transfer(qdev->cntl_ch);
1495129776acSJeffrey Hugo }
1496129776acSJeffrey Hugo 
qaic_release_usr(struct qaic_device * qdev,struct qaic_user * usr)1497129776acSJeffrey Hugo void qaic_release_usr(struct qaic_device *qdev, struct qaic_user *usr)
1498129776acSJeffrey Hugo {
1499129776acSJeffrey Hugo 	struct wire_trans_terminate_to_dev *trans;
1500129776acSJeffrey Hugo 	struct wrapper_list *wrappers;
1501129776acSJeffrey Hugo 	struct wrapper_msg *wrapper;
1502129776acSJeffrey Hugo 	struct wire_msg *msg;
1503129776acSJeffrey Hugo 	struct wire_msg *rsp;
1504129776acSJeffrey Hugo 
1505129776acSJeffrey Hugo 	wrappers = alloc_wrapper_list();
1506129776acSJeffrey Hugo 	if (!wrappers)
1507129776acSJeffrey Hugo 		return;
1508129776acSJeffrey Hugo 
1509129776acSJeffrey Hugo 	wrapper = add_wrapper(wrappers, sizeof(*wrapper) + sizeof(*msg) + sizeof(*trans));
1510129776acSJeffrey Hugo 	if (!wrapper)
1511129776acSJeffrey Hugo 		return;
1512129776acSJeffrey Hugo 
1513129776acSJeffrey Hugo 	msg = &wrapper->msg;
1514129776acSJeffrey Hugo 
1515129776acSJeffrey Hugo 	trans = (struct wire_trans_terminate_to_dev *)msg->data;
1516129776acSJeffrey Hugo 
1517129776acSJeffrey Hugo 	trans->hdr.type = cpu_to_le32(QAIC_TRANS_TERMINATE_TO_DEV);
1518129776acSJeffrey Hugo 	trans->hdr.len = cpu_to_le32(sizeof(*trans));
1519129776acSJeffrey Hugo 	trans->handle = cpu_to_le32(usr->handle);
1520129776acSJeffrey Hugo 
1521129776acSJeffrey Hugo 	mutex_lock(&qdev->cntl_mutex);
1522129776acSJeffrey Hugo 	wrapper->len = sizeof(msg->hdr) + sizeof(*trans);
1523129776acSJeffrey Hugo 	msg->hdr.magic_number = MANAGE_MAGIC_NUMBER;
1524129776acSJeffrey Hugo 	msg->hdr.sequence_number = cpu_to_le32(qdev->next_seq_num++);
1525129776acSJeffrey Hugo 	msg->hdr.len = cpu_to_le32(wrapper->len);
1526129776acSJeffrey Hugo 	msg->hdr.count = cpu_to_le32(1);
1527129776acSJeffrey Hugo 	msg->hdr.handle = cpu_to_le32(usr->handle);
1528129776acSJeffrey Hugo 	msg->hdr.padding = cpu_to_le32(0);
1529129776acSJeffrey Hugo 	msg->hdr.crc32 = cpu_to_le32(qdev->gen_crc(wrappers));
1530129776acSJeffrey Hugo 
1531129776acSJeffrey Hugo 	/*
1532129776acSJeffrey Hugo 	 * msg_xfer releases the mutex
1533129776acSJeffrey Hugo 	 * We don't care about the return of msg_xfer since we will not do
1534129776acSJeffrey Hugo 	 * anything different based on what happens.
1535129776acSJeffrey Hugo 	 * We ignore pending signals since one will be set if the user is
1536129776acSJeffrey Hugo 	 * killed, and we need give the device a chance to cleanup, otherwise
1537129776acSJeffrey Hugo 	 * DMA may still be in progress when we return.
1538129776acSJeffrey Hugo 	 */
1539129776acSJeffrey Hugo 	rsp = msg_xfer(qdev, wrappers, qdev->next_seq_num - 1, true);
1540129776acSJeffrey Hugo 	if (!IS_ERR(rsp))
1541129776acSJeffrey Hugo 		kfree(rsp);
1542129776acSJeffrey Hugo 	free_wrapper_from_list(wrappers, wrapper);
1543129776acSJeffrey Hugo }
1544129776acSJeffrey Hugo 
wake_all_cntl(struct qaic_device * qdev)1545129776acSJeffrey Hugo void wake_all_cntl(struct qaic_device *qdev)
1546129776acSJeffrey Hugo {
1547129776acSJeffrey Hugo 	struct xfer_queue_elem *elem;
1548129776acSJeffrey Hugo 	struct xfer_queue_elem *i;
1549129776acSJeffrey Hugo 
1550129776acSJeffrey Hugo 	mutex_lock(&qdev->cntl_mutex);
1551129776acSJeffrey Hugo 	list_for_each_entry_safe(elem, i, &qdev->cntl_xfer_list, list) {
1552129776acSJeffrey Hugo 		list_del_init(&elem->list);
1553129776acSJeffrey Hugo 		complete_all(&elem->xfer_done);
1554129776acSJeffrey Hugo 	}
1555129776acSJeffrey Hugo 	mutex_unlock(&qdev->cntl_mutex);
1556129776acSJeffrey Hugo }
1557