xref: /aosp_15_r20/external/virtio-media/driver/scatterlist_filler.c (revision 1b4853f54772485c5dd4001ae33a7a958bcc97a1)
1*1b4853f5SAndroid Build Coastguard Worker // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0+
2*1b4853f5SAndroid Build Coastguard Worker 
3*1b4853f5SAndroid Build Coastguard Worker /*
4*1b4853f5SAndroid Build Coastguard Worker  * Scatterlist filler helpers for virtio-media.
5*1b4853f5SAndroid Build Coastguard Worker  *
6*1b4853f5SAndroid Build Coastguard Worker  * Copyright (c) 2023-2024 Google LLC.
7*1b4853f5SAndroid Build Coastguard Worker  */
8*1b4853f5SAndroid Build Coastguard Worker 
9*1b4853f5SAndroid Build Coastguard Worker #include <linux/scatterlist.h>
10*1b4853f5SAndroid Build Coastguard Worker #include <linux/moduleparam.h>
11*1b4853f5SAndroid Build Coastguard Worker #include <media/videobuf2-memops.h>
12*1b4853f5SAndroid Build Coastguard Worker 
13*1b4853f5SAndroid Build Coastguard Worker #include "scatterlist_filler.h"
14*1b4853f5SAndroid Build Coastguard Worker #include "session.h"
15*1b4853f5SAndroid Build Coastguard Worker 
16*1b4853f5SAndroid Build Coastguard Worker /**
17*1b4853f5SAndroid Build Coastguard Worker  * If set to `true`, then the driver will always copy the data passed to the
18*1b4853f5SAndroid Build Coastguard Worker  * host into the shadow buffer (instead of trying to map the source memory into
19*1b4853f5SAndroid Build Coastguard Worker  * the SG table directly).
20*1b4853f5SAndroid Build Coastguard Worker  */
21*1b4853f5SAndroid Build Coastguard Worker static bool always_use_shadow_buffer = false;
22*1b4853f5SAndroid Build Coastguard Worker module_param(always_use_shadow_buffer, bool, 0660);
23*1b4853f5SAndroid Build Coastguard Worker 
24*1b4853f5SAndroid Build Coastguard Worker /* Convert a V4L2 IOCTL into the IOCTL code we can give to the host */
25*1b4853f5SAndroid Build Coastguard Worker #define VIRTIO_MEDIA_IOCTL_CODE(IOCTL) ((IOCTL >> _IOC_NRSHIFT) & _IOC_NRMASK)
26*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_add_sg(struct scatterlist_filler * filler,struct scatterlist * sg)27*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_add_sg(struct scatterlist_filler *filler,
28*1b4853f5SAndroid Build Coastguard Worker 			      struct scatterlist *sg)
29*1b4853f5SAndroid Build Coastguard Worker {
30*1b4853f5SAndroid Build Coastguard Worker 	if (filler->cur_sg >= filler->num_sgs)
31*1b4853f5SAndroid Build Coastguard Worker 		return -ENOSPC;
32*1b4853f5SAndroid Build Coastguard Worker 	filler->sgs[filler->cur_sg++] = sg;
33*1b4853f5SAndroid Build Coastguard Worker 
34*1b4853f5SAndroid Build Coastguard Worker 	return 0;
35*1b4853f5SAndroid Build Coastguard Worker }
36*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_add_data(struct scatterlist_filler * filler,void * data,size_t len)37*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_add_data(struct scatterlist_filler *filler, void *data,
38*1b4853f5SAndroid Build Coastguard Worker 				size_t len)
39*1b4853f5SAndroid Build Coastguard Worker {
40*1b4853f5SAndroid Build Coastguard Worker 	BUG_ON(len == 0);
41*1b4853f5SAndroid Build Coastguard Worker 
42*1b4853f5SAndroid Build Coastguard Worker 	if (filler->cur_sg >= filler->num_sgs)
43*1b4853f5SAndroid Build Coastguard Worker 		return -ENOMEM;
44*1b4853f5SAndroid Build Coastguard Worker 
45*1b4853f5SAndroid Build Coastguard Worker 	if (filler->cur_desc >= filler->num_descs)
46*1b4853f5SAndroid Build Coastguard Worker 		return -ENOSPC;
47*1b4853f5SAndroid Build Coastguard Worker 	filler->sgs[filler->cur_sg] = &filler->descs[filler->cur_desc];
48*1b4853f5SAndroid Build Coastguard Worker 
49*1b4853f5SAndroid Build Coastguard Worker 	if (!always_use_shadow_buffer && virt_addr_valid(data + len)) {
50*1b4853f5SAndroid Build Coastguard Worker 		/*
51*1b4853f5SAndroid Build Coastguard Worker 		 * If "data" is in the 1:1 physical memory mapping then we can
52*1b4853f5SAndroid Build Coastguard Worker 		 * use a single SG entry and avoid copying.
53*1b4853f5SAndroid Build Coastguard Worker 		 */
54*1b4853f5SAndroid Build Coastguard Worker 		struct page *page = virt_to_page(data);
55*1b4853f5SAndroid Build Coastguard Worker 		size_t offset = (((size_t)data) & ~PAGE_MASK);
56*1b4853f5SAndroid Build Coastguard Worker 		struct scatterlist *next_desc =
57*1b4853f5SAndroid Build Coastguard Worker 			&filler->descs[filler->cur_desc];
58*1b4853f5SAndroid Build Coastguard Worker 
59*1b4853f5SAndroid Build Coastguard Worker 		memset(next_desc, 0, sizeof(*next_desc));
60*1b4853f5SAndroid Build Coastguard Worker 		sg_set_page(next_desc, page, len, offset);
61*1b4853f5SAndroid Build Coastguard Worker 		filler->cur_desc++;
62*1b4853f5SAndroid Build Coastguard Worker 	} else if (!always_use_shadow_buffer && is_vmalloc_addr(data)) {
63*1b4853f5SAndroid Build Coastguard Worker 		int prev_pfn = -2;
64*1b4853f5SAndroid Build Coastguard Worker 
65*1b4853f5SAndroid Build Coastguard Worker 		/*
66*1b4853f5SAndroid Build Coastguard Worker 		 * If "data" has been vmalloc'ed, we need one at most entry per
67*1b4853f5SAndroid Build Coastguard Worker 		 * memory page but can avoid copying.
68*1b4853f5SAndroid Build Coastguard Worker 		 */
69*1b4853f5SAndroid Build Coastguard Worker 		while (len > 0) {
70*1b4853f5SAndroid Build Coastguard Worker 			struct page *page = vmalloc_to_page(data);
71*1b4853f5SAndroid Build Coastguard Worker 			int cur_pfn = page_to_pfn(page);
72*1b4853f5SAndroid Build Coastguard Worker 			/* All pages but the first will start at offset 0. */
73*1b4853f5SAndroid Build Coastguard Worker 			unsigned long offset =
74*1b4853f5SAndroid Build Coastguard Worker 				(((unsigned long)data) & ~PAGE_MASK);
75*1b4853f5SAndroid Build Coastguard Worker 			size_t len_in_page = min(PAGE_SIZE - offset, len);
76*1b4853f5SAndroid Build Coastguard Worker 			struct scatterlist *next_desc =
77*1b4853f5SAndroid Build Coastguard Worker 				&filler->descs[filler->cur_desc];
78*1b4853f5SAndroid Build Coastguard Worker 
79*1b4853f5SAndroid Build Coastguard Worker 			if (filler->cur_desc >= filler->num_descs)
80*1b4853f5SAndroid Build Coastguard Worker 				return -ENOSPC;
81*1b4853f5SAndroid Build Coastguard Worker 
82*1b4853f5SAndroid Build Coastguard Worker 			/* Optimize contiguous pages */
83*1b4853f5SAndroid Build Coastguard Worker 			if (cur_pfn == prev_pfn + 1) {
84*1b4853f5SAndroid Build Coastguard Worker 				(next_desc - 1)->length += len_in_page;
85*1b4853f5SAndroid Build Coastguard Worker 			} else {
86*1b4853f5SAndroid Build Coastguard Worker 				memset(next_desc, 0, sizeof(*next_desc));
87*1b4853f5SAndroid Build Coastguard Worker 				sg_set_page(next_desc, page, len_in_page,
88*1b4853f5SAndroid Build Coastguard Worker 					    offset);
89*1b4853f5SAndroid Build Coastguard Worker 				filler->cur_desc++;
90*1b4853f5SAndroid Build Coastguard Worker 			}
91*1b4853f5SAndroid Build Coastguard Worker 			data += len_in_page;
92*1b4853f5SAndroid Build Coastguard Worker 			len -= len_in_page;
93*1b4853f5SAndroid Build Coastguard Worker 			prev_pfn = cur_pfn;
94*1b4853f5SAndroid Build Coastguard Worker 		}
95*1b4853f5SAndroid Build Coastguard Worker 	} else {
96*1b4853f5SAndroid Build Coastguard Worker 		/*
97*1b4853f5SAndroid Build Coastguard Worker 		 * As a last resort, copy into the shadow buffer and reference
98*1b4853f5SAndroid Build Coastguard Worker 		 * it with a single SG entry.
99*1b4853f5SAndroid Build Coastguard Worker 		 */
100*1b4853f5SAndroid Build Coastguard Worker 		void *shadow_buffer =
101*1b4853f5SAndroid Build Coastguard Worker 			filler->shadow_buffer + filler->shadow_buffer_pos;
102*1b4853f5SAndroid Build Coastguard Worker 		struct page *page = virt_to_page(shadow_buffer);
103*1b4853f5SAndroid Build Coastguard Worker 		unsigned long offset =
104*1b4853f5SAndroid Build Coastguard Worker 			(((unsigned long)shadow_buffer) & ~PAGE_MASK);
105*1b4853f5SAndroid Build Coastguard Worker 		struct scatterlist *next_desc =
106*1b4853f5SAndroid Build Coastguard Worker 			&filler->descs[filler->cur_desc];
107*1b4853f5SAndroid Build Coastguard Worker 
108*1b4853f5SAndroid Build Coastguard Worker 		if (len >
109*1b4853f5SAndroid Build Coastguard Worker 		    filler->shadow_buffer_size - filler->shadow_buffer_pos)
110*1b4853f5SAndroid Build Coastguard Worker 			return -ENOSPC;
111*1b4853f5SAndroid Build Coastguard Worker 
112*1b4853f5SAndroid Build Coastguard Worker 		memcpy(shadow_buffer, data, len);
113*1b4853f5SAndroid Build Coastguard Worker 		memset(next_desc, 0, sizeof(*next_desc));
114*1b4853f5SAndroid Build Coastguard Worker 		sg_set_page(next_desc, page, len, offset);
115*1b4853f5SAndroid Build Coastguard Worker 		filler->cur_desc++;
116*1b4853f5SAndroid Build Coastguard Worker 		filler->shadow_buffer_pos += len;
117*1b4853f5SAndroid Build Coastguard Worker 	}
118*1b4853f5SAndroid Build Coastguard Worker 
119*1b4853f5SAndroid Build Coastguard Worker 	sg_mark_end(&filler->descs[filler->cur_desc - 1]);
120*1b4853f5SAndroid Build Coastguard Worker 	filler->cur_sg++;
121*1b4853f5SAndroid Build Coastguard Worker 
122*1b4853f5SAndroid Build Coastguard Worker 	return 0;
123*1b4853f5SAndroid Build Coastguard Worker }
124*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_add_ioctl_cmd(struct scatterlist_filler * filler,struct virtio_media_session * session,u32 ioctl_code)125*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_add_ioctl_cmd(struct scatterlist_filler *filler,
126*1b4853f5SAndroid Build Coastguard Worker 				     struct virtio_media_session *session,
127*1b4853f5SAndroid Build Coastguard Worker 				     u32 ioctl_code)
128*1b4853f5SAndroid Build Coastguard Worker {
129*1b4853f5SAndroid Build Coastguard Worker 	struct virtio_media_cmd_ioctl *cmd_ioctl = &session->cmd.ioctl;
130*1b4853f5SAndroid Build Coastguard Worker 
131*1b4853f5SAndroid Build Coastguard Worker 	cmd_ioctl->hdr.cmd = VIRTIO_MEDIA_CMD_IOCTL;
132*1b4853f5SAndroid Build Coastguard Worker 	cmd_ioctl->session_id = session->id;
133*1b4853f5SAndroid Build Coastguard Worker 	cmd_ioctl->code = VIRTIO_MEDIA_IOCTL_CODE(ioctl_code);
134*1b4853f5SAndroid Build Coastguard Worker 
135*1b4853f5SAndroid Build Coastguard Worker 	return scatterlist_filler_add_data(filler, cmd_ioctl,
136*1b4853f5SAndroid Build Coastguard Worker 					   sizeof(*cmd_ioctl));
137*1b4853f5SAndroid Build Coastguard Worker }
138*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_add_ioctl_resp(struct scatterlist_filler * filler,struct virtio_media_session * session)139*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_add_ioctl_resp(struct scatterlist_filler *filler,
140*1b4853f5SAndroid Build Coastguard Worker 				      struct virtio_media_session *session)
141*1b4853f5SAndroid Build Coastguard Worker {
142*1b4853f5SAndroid Build Coastguard Worker 	struct virtio_media_resp_ioctl *resp_ioctl = &session->resp.ioctl;
143*1b4853f5SAndroid Build Coastguard Worker 
144*1b4853f5SAndroid Build Coastguard Worker 	return scatterlist_filler_add_data(filler, resp_ioctl,
145*1b4853f5SAndroid Build Coastguard Worker 					   sizeof(*resp_ioctl));
146*1b4853f5SAndroid Build Coastguard Worker }
147*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_retrieve_data(struct virtio_media_session * session,struct scatterlist * sg,void * data,size_t len)148*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_retrieve_data(struct virtio_media_session *session,
149*1b4853f5SAndroid Build Coastguard Worker 				     struct scatterlist *sg, void *data,
150*1b4853f5SAndroid Build Coastguard Worker 				     size_t len)
151*1b4853f5SAndroid Build Coastguard Worker {
152*1b4853f5SAndroid Build Coastguard Worker 	void *shadow_buf = session->shadow_buf;
153*1b4853f5SAndroid Build Coastguard Worker 	void *kaddr = pfn_to_kaddr(page_to_pfn(sg_page(sg))) + sg->offset;
154*1b4853f5SAndroid Build Coastguard Worker 
155*1b4853f5SAndroid Build Coastguard Worker 	BUG_ON(len == 0);
156*1b4853f5SAndroid Build Coastguard Worker 
157*1b4853f5SAndroid Build Coastguard Worker 	/*
158*1b4853f5SAndroid Build Coastguard Worker 	 * If our SG entry points inside the shadow buffer, copy the data back to its
159*1b4853f5SAndroid Build Coastguard Worker 	 * origin.
160*1b4853f5SAndroid Build Coastguard Worker 	 */
161*1b4853f5SAndroid Build Coastguard Worker 	if (kaddr >= shadow_buf &&
162*1b4853f5SAndroid Build Coastguard Worker 	    kaddr < shadow_buf + VIRTIO_SHADOW_BUF_SIZE) {
163*1b4853f5SAndroid Build Coastguard Worker 		if (kaddr + len >= shadow_buf + VIRTIO_SHADOW_BUF_SIZE)
164*1b4853f5SAndroid Build Coastguard Worker 			return -EINVAL;
165*1b4853f5SAndroid Build Coastguard Worker 
166*1b4853f5SAndroid Build Coastguard Worker 		BUG_ON(sg->length != len);
167*1b4853f5SAndroid Build Coastguard Worker 
168*1b4853f5SAndroid Build Coastguard Worker 		memcpy(data, kaddr, len);
169*1b4853f5SAndroid Build Coastguard Worker 	}
170*1b4853f5SAndroid Build Coastguard Worker 
171*1b4853f5SAndroid Build Coastguard Worker 	return 0;
172*1b4853f5SAndroid Build Coastguard Worker }
173*1b4853f5SAndroid Build Coastguard Worker 
174*1b4853f5SAndroid Build Coastguard Worker /*
175*1b4853f5SAndroid Build Coastguard Worker  * num_planes if the number of planes in the original buffer provided by user-space.
176*1b4853f5SAndroid Build Coastguard Worker  *
177*1b4853f5SAndroid Build Coastguard Worker  * @num_buffer_sgs: number of SGs that were used by this buffer. Useful to know
178*1b4853f5SAndroid Build Coastguard Worker  * if we have SG lists for USERPTR buffers that we need to free.
179*1b4853f5SAndroid Build Coastguard Worker  */
scatterlist_filler_retrieve_buffer(struct virtio_media_session * session,struct scatterlist ** buffer_sgs,struct v4l2_buffer * b,size_t num_planes)180*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_retrieve_buffer(struct virtio_media_session *session,
181*1b4853f5SAndroid Build Coastguard Worker 				       struct scatterlist **buffer_sgs,
182*1b4853f5SAndroid Build Coastguard Worker 				       struct v4l2_buffer *b, size_t num_planes)
183*1b4853f5SAndroid Build Coastguard Worker {
184*1b4853f5SAndroid Build Coastguard Worker 	struct v4l2_plane *planes = NULL;
185*1b4853f5SAndroid Build Coastguard Worker 	int i = 0;
186*1b4853f5SAndroid Build Coastguard Worker 	int ret;
187*1b4853f5SAndroid Build Coastguard Worker 
188*1b4853f5SAndroid Build Coastguard Worker 	/* Keep data that will be overwritten but that we need to check later */
189*1b4853f5SAndroid Build Coastguard Worker 	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
190*1b4853f5SAndroid Build Coastguard Worker 		planes = b->m.planes;
191*1b4853f5SAndroid Build Coastguard Worker 	}
192*1b4853f5SAndroid Build Coastguard Worker 
193*1b4853f5SAndroid Build Coastguard Worker 	ret = scatterlist_filler_retrieve_data(session, buffer_sgs[i++], b,
194*1b4853f5SAndroid Build Coastguard Worker 					       sizeof(*b));
195*1b4853f5SAndroid Build Coastguard Worker 	if (ret)
196*1b4853f5SAndroid Build Coastguard Worker 		return ret;
197*1b4853f5SAndroid Build Coastguard Worker 
198*1b4853f5SAndroid Build Coastguard Worker 	if (planes != NULL && num_planes > 0) {
199*1b4853f5SAndroid Build Coastguard Worker 		b->m.planes = planes;
200*1b4853f5SAndroid Build Coastguard Worker 		if (b->length > num_planes)
201*1b4853f5SAndroid Build Coastguard Worker 			return -ENOSPC;
202*1b4853f5SAndroid Build Coastguard Worker 
203*1b4853f5SAndroid Build Coastguard Worker 		ret = scatterlist_filler_retrieve_data(
204*1b4853f5SAndroid Build Coastguard Worker 			session, buffer_sgs[i++], b->m.planes,
205*1b4853f5SAndroid Build Coastguard Worker 			sizeof(struct v4l2_plane) * num_planes);
206*1b4853f5SAndroid Build Coastguard Worker 		if (ret)
207*1b4853f5SAndroid Build Coastguard Worker 			return ret;
208*1b4853f5SAndroid Build Coastguard Worker 	}
209*1b4853f5SAndroid Build Coastguard Worker 
210*1b4853f5SAndroid Build Coastguard Worker 	return 0;
211*1b4853f5SAndroid Build Coastguard Worker }
212*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_retrieve_ext_ctrls(struct virtio_media_session * session,struct scatterlist ** ctrls_sgs,int num_ctrls_sgs,struct v4l2_ext_controls * ctrls)213*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_retrieve_ext_ctrls(struct virtio_media_session *session,
214*1b4853f5SAndroid Build Coastguard Worker 					  struct scatterlist **ctrls_sgs,
215*1b4853f5SAndroid Build Coastguard Worker 					  int num_ctrls_sgs,
216*1b4853f5SAndroid Build Coastguard Worker 					  struct v4l2_ext_controls *ctrls)
217*1b4853f5SAndroid Build Coastguard Worker {
218*1b4853f5SAndroid Build Coastguard Worker 	struct v4l2_ext_control *controls_backup = ctrls->controls;
219*1b4853f5SAndroid Build Coastguard Worker 	int i = 0;
220*1b4853f5SAndroid Build Coastguard Worker 	int ret;
221*1b4853f5SAndroid Build Coastguard Worker 
222*1b4853f5SAndroid Build Coastguard Worker 	ret = scatterlist_filler_retrieve_data(session, ctrls_sgs[i++], ctrls,
223*1b4853f5SAndroid Build Coastguard Worker 					       sizeof(*ctrls));
224*1b4853f5SAndroid Build Coastguard Worker 	if (ret)
225*1b4853f5SAndroid Build Coastguard Worker 		return ret;
226*1b4853f5SAndroid Build Coastguard Worker 
227*1b4853f5SAndroid Build Coastguard Worker 	ctrls->controls = controls_backup;
228*1b4853f5SAndroid Build Coastguard Worker 
229*1b4853f5SAndroid Build Coastguard Worker 	if (ctrls->count > 0 && ctrls->controls) {
230*1b4853f5SAndroid Build Coastguard Worker 		ret = scatterlist_filler_retrieve_data(
231*1b4853f5SAndroid Build Coastguard Worker 			session, ctrls_sgs[i++], ctrls->controls,
232*1b4853f5SAndroid Build Coastguard Worker 			sizeof(struct v4l2_ext_control) * ctrls->count);
233*1b4853f5SAndroid Build Coastguard Worker 		if (ret)
234*1b4853f5SAndroid Build Coastguard Worker 			return ret;
235*1b4853f5SAndroid Build Coastguard Worker 	}
236*1b4853f5SAndroid Build Coastguard Worker 
237*1b4853f5SAndroid Build Coastguard Worker 	return 0;
238*1b4853f5SAndroid Build Coastguard Worker }
239*1b4853f5SAndroid Build Coastguard Worker 
240*1b4853f5SAndroid Build Coastguard Worker /**
241*1b4853f5SAndroid Build Coastguard Worker  * prepare_userptr_to_host -
242*1b4853f5SAndroid Build Coastguard Worker  *
243*1b4853f5SAndroid Build Coastguard Worker  * Returns -EFAULT if `userptr` was not a valid user address, which is a case
244*1b4853f5SAndroid Build Coastguard Worker  * the driver should consider as "normal" operation. All other failures signal
245*1b4853f5SAndroid Build Coastguard Worker  * a problem with the driver.
246*1b4853f5SAndroid Build Coastguard Worker  */
prepare_userptr_to_host(struct scatterlist_filler * filler,unsigned long userptr,unsigned long length,struct virtio_media_sg_entry ** sg_list,int * nents)247*1b4853f5SAndroid Build Coastguard Worker static int prepare_userptr_to_host(struct scatterlist_filler *filler,
248*1b4853f5SAndroid Build Coastguard Worker 				   unsigned long userptr, unsigned long length,
249*1b4853f5SAndroid Build Coastguard Worker 				   struct virtio_media_sg_entry **sg_list,
250*1b4853f5SAndroid Build Coastguard Worker 				   int *nents)
251*1b4853f5SAndroid Build Coastguard Worker {
252*1b4853f5SAndroid Build Coastguard Worker 	struct sg_table sg_table = {};
253*1b4853f5SAndroid Build Coastguard Worker 	struct frame_vector *framevec;
254*1b4853f5SAndroid Build Coastguard Worker 	struct scatterlist *sg_iter;
255*1b4853f5SAndroid Build Coastguard Worker 	struct page **pages;
256*1b4853f5SAndroid Build Coastguard Worker 	unsigned int pages_count;
257*1b4853f5SAndroid Build Coastguard Worker 	unsigned int offset = userptr & ~PAGE_MASK;
258*1b4853f5SAndroid Build Coastguard Worker 	size_t entries_size;
259*1b4853f5SAndroid Build Coastguard Worker 	int i;
260*1b4853f5SAndroid Build Coastguard Worker 	int ret;
261*1b4853f5SAndroid Build Coastguard Worker 
262*1b4853f5SAndroid Build Coastguard Worker 	framevec = vb2_create_framevec(userptr, length, true);
263*1b4853f5SAndroid Build Coastguard Worker 	if (IS_ERR(framevec)) {
264*1b4853f5SAndroid Build Coastguard Worker 		if (PTR_ERR(framevec) != -EFAULT) {
265*1b4853f5SAndroid Build Coastguard Worker 			printk("error creating frame vector for userptr 0x%lx, length 0x%lx: %ld\n",
266*1b4853f5SAndroid Build Coastguard Worker 			       userptr, length, PTR_ERR(framevec));
267*1b4853f5SAndroid Build Coastguard Worker 		} else {
268*1b4853f5SAndroid Build Coastguard Worker 			/* -EINVAL is expected in case of invalid userptr. */
269*1b4853f5SAndroid Build Coastguard Worker 			framevec = ERR_PTR(-EINVAL);
270*1b4853f5SAndroid Build Coastguard Worker 		}
271*1b4853f5SAndroid Build Coastguard Worker 		return PTR_ERR(framevec);
272*1b4853f5SAndroid Build Coastguard Worker 	}
273*1b4853f5SAndroid Build Coastguard Worker 
274*1b4853f5SAndroid Build Coastguard Worker 	pages = frame_vector_pages(framevec);
275*1b4853f5SAndroid Build Coastguard Worker 	if (IS_ERR(pages)) {
276*1b4853f5SAndroid Build Coastguard Worker 		printk("error getting vector pages\n");
277*1b4853f5SAndroid Build Coastguard Worker 		ret = PTR_ERR(pages);
278*1b4853f5SAndroid Build Coastguard Worker 		goto done;
279*1b4853f5SAndroid Build Coastguard Worker 	}
280*1b4853f5SAndroid Build Coastguard Worker 	pages_count = frame_vector_count(framevec);
281*1b4853f5SAndroid Build Coastguard Worker 	/* TODO turn into a SG list directly here and skip the sg table step */
282*1b4853f5SAndroid Build Coastguard Worker 	ret = sg_alloc_table_from_pages(&sg_table, pages, pages_count, offset,
283*1b4853f5SAndroid Build Coastguard Worker 					length, 0);
284*1b4853f5SAndroid Build Coastguard Worker 	if (ret) {
285*1b4853f5SAndroid Build Coastguard Worker 		printk("error creating sg table\n");
286*1b4853f5SAndroid Build Coastguard Worker 		goto done;
287*1b4853f5SAndroid Build Coastguard Worker 	}
288*1b4853f5SAndroid Build Coastguard Worker 
289*1b4853f5SAndroid Build Coastguard Worker 	/* Allocate our actual SG in the shadow buffer. */
290*1b4853f5SAndroid Build Coastguard Worker 	*nents = sg_nents(sg_table.sgl);
291*1b4853f5SAndroid Build Coastguard Worker 	entries_size = sizeof(**sg_list) * *nents;
292*1b4853f5SAndroid Build Coastguard Worker 	if (filler->shadow_buffer_pos + entries_size >
293*1b4853f5SAndroid Build Coastguard Worker 	    filler->shadow_buffer_size) {
294*1b4853f5SAndroid Build Coastguard Worker 		ret = -ENOMEM;
295*1b4853f5SAndroid Build Coastguard Worker 		goto free_sg;
296*1b4853f5SAndroid Build Coastguard Worker 	}
297*1b4853f5SAndroid Build Coastguard Worker 
298*1b4853f5SAndroid Build Coastguard Worker 	*sg_list = filler->shadow_buffer + filler->shadow_buffer_pos;
299*1b4853f5SAndroid Build Coastguard Worker 	filler->shadow_buffer_pos += entries_size;
300*1b4853f5SAndroid Build Coastguard Worker 
301*1b4853f5SAndroid Build Coastguard Worker 	for_each_sgtable_sg(&sg_table, sg_iter, i) {
302*1b4853f5SAndroid Build Coastguard Worker 		struct virtio_media_sg_entry *sg_entry = &(*sg_list)[i];
303*1b4853f5SAndroid Build Coastguard Worker 		sg_entry->start = sg_phys(sg_iter);
304*1b4853f5SAndroid Build Coastguard Worker 		sg_entry->len = sg_iter->length;
305*1b4853f5SAndroid Build Coastguard Worker 	}
306*1b4853f5SAndroid Build Coastguard Worker 
307*1b4853f5SAndroid Build Coastguard Worker free_sg:
308*1b4853f5SAndroid Build Coastguard Worker 	sg_free_table(&sg_table);
309*1b4853f5SAndroid Build Coastguard Worker 
310*1b4853f5SAndroid Build Coastguard Worker done:
311*1b4853f5SAndroid Build Coastguard Worker 	vb2_destroy_framevec(framevec);
312*1b4853f5SAndroid Build Coastguard Worker 	return ret;
313*1b4853f5SAndroid Build Coastguard Worker }
314*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_add_userptr(struct scatterlist_filler * filler,unsigned long userptr,unsigned long length)315*1b4853f5SAndroid Build Coastguard Worker static int scatterlist_filler_add_userptr(struct scatterlist_filler *filler,
316*1b4853f5SAndroid Build Coastguard Worker 					  unsigned long userptr,
317*1b4853f5SAndroid Build Coastguard Worker 					  unsigned long length)
318*1b4853f5SAndroid Build Coastguard Worker {
319*1b4853f5SAndroid Build Coastguard Worker 	int ret;
320*1b4853f5SAndroid Build Coastguard Worker 	int nents;
321*1b4853f5SAndroid Build Coastguard Worker 	struct virtio_media_sg_entry *sg_list;
322*1b4853f5SAndroid Build Coastguard Worker 
323*1b4853f5SAndroid Build Coastguard Worker 	ret = prepare_userptr_to_host(filler, userptr, length, &sg_list,
324*1b4853f5SAndroid Build Coastguard Worker 				      &nents);
325*1b4853f5SAndroid Build Coastguard Worker 	if (ret)
326*1b4853f5SAndroid Build Coastguard Worker 		return ret;
327*1b4853f5SAndroid Build Coastguard Worker 
328*1b4853f5SAndroid Build Coastguard Worker 	ret = scatterlist_filler_add_data(filler, sg_list,
329*1b4853f5SAndroid Build Coastguard Worker 					  sizeof(*sg_list) * nents);
330*1b4853f5SAndroid Build Coastguard Worker 	if (ret)
331*1b4853f5SAndroid Build Coastguard Worker 		return ret;
332*1b4853f5SAndroid Build Coastguard Worker 
333*1b4853f5SAndroid Build Coastguard Worker 	return 0;
334*1b4853f5SAndroid Build Coastguard Worker }
335*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_add_buffer(struct scatterlist_filler * filler,struct v4l2_buffer * b)336*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_add_buffer(struct scatterlist_filler *filler,
337*1b4853f5SAndroid Build Coastguard Worker 				  struct v4l2_buffer *b)
338*1b4853f5SAndroid Build Coastguard Worker {
339*1b4853f5SAndroid Build Coastguard Worker 	int i;
340*1b4853f5SAndroid Build Coastguard Worker 	int ret;
341*1b4853f5SAndroid Build Coastguard Worker 
342*1b4853f5SAndroid Build Coastguard Worker 	/* Fixup: plane length must be zero if userptr is NULL */
343*1b4853f5SAndroid Build Coastguard Worker 	if (!V4L2_TYPE_IS_MULTIPLANAR(b->type) &&
344*1b4853f5SAndroid Build Coastguard Worker 	    b->memory == V4L2_MEMORY_USERPTR && b->m.userptr == 0)
345*1b4853f5SAndroid Build Coastguard Worker 		b->length = 0;
346*1b4853f5SAndroid Build Coastguard Worker 
347*1b4853f5SAndroid Build Coastguard Worker 	/* v4l2_buffer */
348*1b4853f5SAndroid Build Coastguard Worker 	ret = scatterlist_filler_add_data(filler, b, sizeof(*b));
349*1b4853f5SAndroid Build Coastguard Worker 	if (ret)
350*1b4853f5SAndroid Build Coastguard Worker 		return ret;
351*1b4853f5SAndroid Build Coastguard Worker 
352*1b4853f5SAndroid Build Coastguard Worker 	if (V4L2_TYPE_IS_MULTIPLANAR(b->type) && b->length > 0) {
353*1b4853f5SAndroid Build Coastguard Worker 		/* Fixup: plane length must be zero if userptr is NULL */
354*1b4853f5SAndroid Build Coastguard Worker 		if (b->memory == V4L2_MEMORY_USERPTR) {
355*1b4853f5SAndroid Build Coastguard Worker 			for (i = 0; i < b->length; i++) {
356*1b4853f5SAndroid Build Coastguard Worker 				struct v4l2_plane *plane = &b->m.planes[i];
357*1b4853f5SAndroid Build Coastguard Worker 
358*1b4853f5SAndroid Build Coastguard Worker 				if (plane->m.userptr == 0)
359*1b4853f5SAndroid Build Coastguard Worker 					plane->length = 0;
360*1b4853f5SAndroid Build Coastguard Worker 			}
361*1b4853f5SAndroid Build Coastguard Worker 		}
362*1b4853f5SAndroid Build Coastguard Worker 
363*1b4853f5SAndroid Build Coastguard Worker 		/* Array of v4l2_planes */
364*1b4853f5SAndroid Build Coastguard Worker 		ret = scatterlist_filler_add_data(filler, b->m.planes,
365*1b4853f5SAndroid Build Coastguard Worker 						  sizeof(struct v4l2_plane) *
366*1b4853f5SAndroid Build Coastguard Worker 							  b->length);
367*1b4853f5SAndroid Build Coastguard Worker 		if (ret)
368*1b4853f5SAndroid Build Coastguard Worker 			return ret;
369*1b4853f5SAndroid Build Coastguard Worker 	}
370*1b4853f5SAndroid Build Coastguard Worker 
371*1b4853f5SAndroid Build Coastguard Worker 	return 0;
372*1b4853f5SAndroid Build Coastguard Worker }
373*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_add_buffer_userptr(struct scatterlist_filler * filler,struct v4l2_buffer * b)374*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_add_buffer_userptr(struct scatterlist_filler *filler,
375*1b4853f5SAndroid Build Coastguard Worker 					  struct v4l2_buffer *b)
376*1b4853f5SAndroid Build Coastguard Worker {
377*1b4853f5SAndroid Build Coastguard Worker 	int i;
378*1b4853f5SAndroid Build Coastguard Worker 	int ret;
379*1b4853f5SAndroid Build Coastguard Worker 
380*1b4853f5SAndroid Build Coastguard Worker 	if (b->memory != V4L2_MEMORY_USERPTR)
381*1b4853f5SAndroid Build Coastguard Worker 		return 0;
382*1b4853f5SAndroid Build Coastguard Worker 
383*1b4853f5SAndroid Build Coastguard Worker 	if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
384*1b4853f5SAndroid Build Coastguard Worker 		for (i = 0; i < b->length; i++) {
385*1b4853f5SAndroid Build Coastguard Worker 			struct v4l2_plane *plane = &b->m.planes[i];
386*1b4853f5SAndroid Build Coastguard Worker 			if (b->memory == V4L2_MEMORY_USERPTR &&
387*1b4853f5SAndroid Build Coastguard Worker 			    plane->length > 0) {
388*1b4853f5SAndroid Build Coastguard Worker 				ret = scatterlist_filler_add_userptr(
389*1b4853f5SAndroid Build Coastguard Worker 					filler, plane->m.userptr,
390*1b4853f5SAndroid Build Coastguard Worker 					plane->length);
391*1b4853f5SAndroid Build Coastguard Worker 				if (ret)
392*1b4853f5SAndroid Build Coastguard Worker 					return ret;
393*1b4853f5SAndroid Build Coastguard Worker 			}
394*1b4853f5SAndroid Build Coastguard Worker 		}
395*1b4853f5SAndroid Build Coastguard Worker 	} else if (b->length > 0) {
396*1b4853f5SAndroid Build Coastguard Worker 		ret = scatterlist_filler_add_userptr(filler, b->m.userptr,
397*1b4853f5SAndroid Build Coastguard Worker 						     b->length);
398*1b4853f5SAndroid Build Coastguard Worker 		if (ret)
399*1b4853f5SAndroid Build Coastguard Worker 			return ret;
400*1b4853f5SAndroid Build Coastguard Worker 	}
401*1b4853f5SAndroid Build Coastguard Worker 
402*1b4853f5SAndroid Build Coastguard Worker 	return 0;
403*1b4853f5SAndroid Build Coastguard Worker }
404*1b4853f5SAndroid Build Coastguard Worker 
scatterlist_filler_add_ext_ctrls(struct scatterlist_filler * filler,struct v4l2_ext_controls * ctrls,bool add_userptrs)405*1b4853f5SAndroid Build Coastguard Worker int scatterlist_filler_add_ext_ctrls(struct scatterlist_filler *filler,
406*1b4853f5SAndroid Build Coastguard Worker 				     struct v4l2_ext_controls *ctrls,
407*1b4853f5SAndroid Build Coastguard Worker 				     bool add_userptrs)
408*1b4853f5SAndroid Build Coastguard Worker {
409*1b4853f5SAndroid Build Coastguard Worker 	int i;
410*1b4853f5SAndroid Build Coastguard Worker 	int ret;
411*1b4853f5SAndroid Build Coastguard Worker 
412*1b4853f5SAndroid Build Coastguard Worker 	/* v4l2_ext_controls */
413*1b4853f5SAndroid Build Coastguard Worker 	ret = scatterlist_filler_add_data(filler, ctrls, sizeof(*ctrls));
414*1b4853f5SAndroid Build Coastguard Worker 	if (ret)
415*1b4853f5SAndroid Build Coastguard Worker 		return ret;
416*1b4853f5SAndroid Build Coastguard Worker 
417*1b4853f5SAndroid Build Coastguard Worker 	if (ctrls->count > 0) {
418*1b4853f5SAndroid Build Coastguard Worker 		/* array of v4l2_controls */
419*1b4853f5SAndroid Build Coastguard Worker 		ret = scatterlist_filler_add_data(filler, ctrls->controls,
420*1b4853f5SAndroid Build Coastguard Worker 						  sizeof(ctrls->controls[0]) *
421*1b4853f5SAndroid Build Coastguard Worker 							  ctrls->count);
422*1b4853f5SAndroid Build Coastguard Worker 		if (ret)
423*1b4853f5SAndroid Build Coastguard Worker 			return ret;
424*1b4853f5SAndroid Build Coastguard Worker 	}
425*1b4853f5SAndroid Build Coastguard Worker 
426*1b4853f5SAndroid Build Coastguard Worker 	if (!add_userptrs)
427*1b4853f5SAndroid Build Coastguard Worker 		return 0;
428*1b4853f5SAndroid Build Coastguard Worker 
429*1b4853f5SAndroid Build Coastguard Worker 	/* Pointers to user memory in individual controls */
430*1b4853f5SAndroid Build Coastguard Worker 	for (i = 0; i < ctrls->count; i++) {
431*1b4853f5SAndroid Build Coastguard Worker 		struct v4l2_ext_control *ctrl = &ctrls->controls[i];
432*1b4853f5SAndroid Build Coastguard Worker 		if (ctrl->size > 0) {
433*1b4853f5SAndroid Build Coastguard Worker 			ret = scatterlist_filler_add_userptr(
434*1b4853f5SAndroid Build Coastguard Worker 				filler, (unsigned long)ctrl->ptr, ctrl->size);
435*1b4853f5SAndroid Build Coastguard Worker 			if (ret)
436*1b4853f5SAndroid Build Coastguard Worker 				return ret;
437*1b4853f5SAndroid Build Coastguard Worker 		}
438*1b4853f5SAndroid Build Coastguard Worker 	}
439*1b4853f5SAndroid Build Coastguard Worker 
440*1b4853f5SAndroid Build Coastguard Worker 	return 0;
441*1b4853f5SAndroid Build Coastguard Worker }
442