summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2018-05-21 04:54:27 -0400
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-08-31 11:04:51 -0400
commit10905d70d78841a6fa191be5ec193e3c0d63555f (patch)
treeeb0db2d23b491a32b75227c13eb13974941212c8
parent66431c0bab0fb8bdd62930575869bea98eb2baf0 (diff)
media: media-request: implement media requests
Add initial media request support: 1) Add MEDIA_IOC_REQUEST_ALLOC ioctl support to media-device.c 2) Add struct media_request to store request objects. 3) Add struct media_request_object to represent a request object. 4) Add MEDIA_REQUEST_IOC_QUEUE/REINIT ioctl support. Basic lifecycle: the application allocates a request, adds objects to it, queues the request, polls until it is completed and can then read the final values of the objects at the time of completion. When it closes the file descriptor the request memory will be freed (actually, when the last user of that request releases the request). Drivers will bind an object to a request (the 'adds objects to it' phase), when MEDIA_REQUEST_IOC_QUEUE is called the request is validated (req_validate op), then queued (the req_queue op). When done with an object it can either be unbound from the request (e.g. when the driver has finished with a vb2 buffer) or marked as completed (e.g. for controls associated with a buffer). When all objects in the request are completed (or unbound), then the request fd will signal an exception (poll). Co-developed-by: Sakari Ailus <sakari.ailus@linux.intel.com> Co-developed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Co-developed-by: Alexandre Courbot <acourbot@chromium.org> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Reviewed-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
-rw-r--r--drivers/media/Makefile3
-rw-r--r--drivers/media/media-device.c24
-rw-r--r--drivers/media/media-request.c464
-rw-r--r--include/media/media-device.h29
-rw-r--r--include/media/media-request.h334
5 files changed, 849 insertions, 5 deletions
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 594b462ddf0e..985d35ec6b29 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -3,7 +3,8 @@
3# Makefile for the kernel multimedia device drivers. 3# Makefile for the kernel multimedia device drivers.
4# 4#
5 5
6media-objs := media-device.o media-devnode.o media-entity.o 6media-objs := media-device.o media-devnode.o media-entity.o \
7 media-request.o
7 8
8# 9#
9# I2C drivers should come before other drivers, otherwise they'll fail 10# I2C drivers should come before other drivers, otherwise they'll fail
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 3bae24b15eaa..4dd2b1dae03d 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -30,6 +30,7 @@
30#include <media/media-device.h> 30#include <media/media-device.h>
31#include <media/media-devnode.h> 31#include <media/media-devnode.h>
32#include <media/media-entity.h> 32#include <media/media-entity.h>
33#include <media/media-request.h>
33 34
34#ifdef CONFIG_MEDIA_CONTROLLER 35#ifdef CONFIG_MEDIA_CONTROLLER
35 36
@@ -377,10 +378,19 @@ static long media_device_get_topology(struct media_device *mdev, void *arg)
377 return ret; 378 return ret;
378} 379}
379 380
381static long media_device_request_alloc(struct media_device *mdev,
382 int *alloc_fd)
383{
384 if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue)
385 return -ENOTTY;
386
387 return media_request_alloc(mdev, alloc_fd);
388}
389
380static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd) 390static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
381{ 391{
382 /* All media IOCTLs are _IOWR() */ 392 if ((_IOC_DIR(cmd) & _IOC_WRITE) &&
383 if (copy_from_user(karg, uarg, _IOC_SIZE(cmd))) 393 copy_from_user(karg, uarg, _IOC_SIZE(cmd)))
384 return -EFAULT; 394 return -EFAULT;
385 395
386 return 0; 396 return 0;
@@ -388,8 +398,8 @@ static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
388 398
389static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd) 399static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd)
390{ 400{
391 /* All media IOCTLs are _IOWR() */ 401 if ((_IOC_DIR(cmd) & _IOC_READ) &&
392 if (copy_to_user(uarg, karg, _IOC_SIZE(cmd))) 402 copy_to_user(uarg, karg, _IOC_SIZE(cmd)))
393 return -EFAULT; 403 return -EFAULT;
394 404
395 return 0; 405 return 0;
@@ -425,6 +435,7 @@ static const struct media_ioctl_info ioctl_info[] = {
425 MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX), 435 MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX),
426 MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX), 436 MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX),
427 MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX), 437 MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX),
438 MEDIA_IOC(REQUEST_ALLOC, media_device_request_alloc, 0),
428}; 439};
429 440
430static long media_device_ioctl(struct file *filp, unsigned int cmd, 441static long media_device_ioctl(struct file *filp, unsigned int cmd,
@@ -691,9 +702,13 @@ void media_device_init(struct media_device *mdev)
691 INIT_LIST_HEAD(&mdev->pads); 702 INIT_LIST_HEAD(&mdev->pads);
692 INIT_LIST_HEAD(&mdev->links); 703 INIT_LIST_HEAD(&mdev->links);
693 INIT_LIST_HEAD(&mdev->entity_notify); 704 INIT_LIST_HEAD(&mdev->entity_notify);
705
706 mutex_init(&mdev->req_queue_mutex);
694 mutex_init(&mdev->graph_mutex); 707 mutex_init(&mdev->graph_mutex);
695 ida_init(&mdev->entity_internal_idx); 708 ida_init(&mdev->entity_internal_idx);
696 709
710 atomic_set(&mdev->request_id, 0);
711
697 dev_dbg(mdev->dev, "Media device initialized\n"); 712 dev_dbg(mdev->dev, "Media device initialized\n");
698} 713}
699EXPORT_SYMBOL_GPL(media_device_init); 714EXPORT_SYMBOL_GPL(media_device_init);
@@ -704,6 +719,7 @@ void media_device_cleanup(struct media_device *mdev)
704 mdev->entity_internal_idx_max = 0; 719 mdev->entity_internal_idx_max = 0;
705 media_graph_walk_cleanup(&mdev->pm_count_walk); 720 media_graph_walk_cleanup(&mdev->pm_count_walk);
706 mutex_destroy(&mdev->graph_mutex); 721 mutex_destroy(&mdev->graph_mutex);
722 mutex_destroy(&mdev->req_queue_mutex);
707} 723}
708EXPORT_SYMBOL_GPL(media_device_cleanup); 724EXPORT_SYMBOL_GPL(media_device_cleanup);
709 725
diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c
new file mode 100644
index 000000000000..8d3c7360c8f3
--- /dev/null
+++ b/drivers/media/media-request.c
@@ -0,0 +1,464 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Media device request objects
4 *
5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 * Copyright (C) 2018 Intel Corporation
7 * Copyright (C) 2018 Google, Inc.
8 *
9 * Author: Hans Verkuil <hans.verkuil@cisco.com>
10 * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
11 */
12
13#include <linux/anon_inodes.h>
14#include <linux/file.h>
15#include <linux/refcount.h>
16
17#include <media/media-device.h>
18#include <media/media-request.h>
19
20static const char * const request_state[] = {
21 [MEDIA_REQUEST_STATE_IDLE] = "idle",
22 [MEDIA_REQUEST_STATE_VALIDATING] = "validating",
23 [MEDIA_REQUEST_STATE_QUEUED] = "queued",
24 [MEDIA_REQUEST_STATE_COMPLETE] = "complete",
25 [MEDIA_REQUEST_STATE_CLEANING] = "cleaning",
26 [MEDIA_REQUEST_STATE_UPDATING] = "updating",
27};
28
29static const char *
30media_request_state_str(enum media_request_state state)
31{
32 BUILD_BUG_ON(ARRAY_SIZE(request_state) != NR_OF_MEDIA_REQUEST_STATE);
33
34 if (WARN_ON(state >= ARRAY_SIZE(request_state)))
35 return "invalid";
36 return request_state[state];
37}
38
39static void media_request_clean(struct media_request *req)
40{
41 struct media_request_object *obj, *obj_safe;
42
43 /* Just a sanity check. No other code path is allowed to change this. */
44 WARN_ON(req->state != MEDIA_REQUEST_STATE_CLEANING);
45 WARN_ON(req->updating_count);
46
47 list_for_each_entry_safe(obj, obj_safe, &req->objects, list) {
48 media_request_object_unbind(obj);
49 media_request_object_put(obj);
50 }
51
52 req->updating_count = 0;
53 WARN_ON(req->num_incomplete_objects);
54 req->num_incomplete_objects = 0;
55 wake_up_interruptible_all(&req->poll_wait);
56}
57
58static void media_request_release(struct kref *kref)
59{
60 struct media_request *req =
61 container_of(kref, struct media_request, kref);
62 struct media_device *mdev = req->mdev;
63
64 dev_dbg(mdev->dev, "request: release %s\n", req->debug_str);
65
66 /* No other users, no need for a spinlock */
67 req->state = MEDIA_REQUEST_STATE_CLEANING;
68
69 media_request_clean(req);
70
71 if (mdev->ops->req_free)
72 mdev->ops->req_free(req);
73 else
74 kfree(req);
75}
76
77void media_request_put(struct media_request *req)
78{
79 kref_put(&req->kref, media_request_release);
80}
81EXPORT_SYMBOL_GPL(media_request_put);
82
83static int media_request_close(struct inode *inode, struct file *filp)
84{
85 struct media_request *req = filp->private_data;
86
87 media_request_put(req);
88 return 0;
89}
90
91static __poll_t media_request_poll(struct file *filp,
92 struct poll_table_struct *wait)
93{
94 struct media_request *req = filp->private_data;
95 unsigned long flags;
96 __poll_t ret = 0;
97
98 if (!(poll_requested_events(wait) & EPOLLPRI))
99 return 0;
100
101 spin_lock_irqsave(&req->lock, flags);
102 if (req->state == MEDIA_REQUEST_STATE_COMPLETE) {
103 ret = EPOLLPRI;
104 goto unlock;
105 }
106 if (req->state != MEDIA_REQUEST_STATE_QUEUED) {
107 ret = EPOLLERR;
108 goto unlock;
109 }
110
111 poll_wait(filp, &req->poll_wait, wait);
112
113unlock:
114 spin_unlock_irqrestore(&req->lock, flags);
115 return ret;
116}
117
118static long media_request_ioctl_queue(struct media_request *req)
119{
120 struct media_device *mdev = req->mdev;
121 enum media_request_state state;
122 unsigned long flags;
123 int ret;
124
125 dev_dbg(mdev->dev, "request: queue %s\n", req->debug_str);
126
127 /*
128 * Ensure the request that is validated will be the one that gets queued
129 * next by serialising the queueing process. This mutex is also used
130 * to serialize with canceling a vb2 queue and with setting values such
131 * as controls in a request.
132 */
133 mutex_lock(&mdev->req_queue_mutex);
134
135 media_request_get(req);
136
137 spin_lock_irqsave(&req->lock, flags);
138 if (req->state == MEDIA_REQUEST_STATE_IDLE)
139 req->state = MEDIA_REQUEST_STATE_VALIDATING;
140 state = req->state;
141 spin_unlock_irqrestore(&req->lock, flags);
142 if (state != MEDIA_REQUEST_STATE_VALIDATING) {
143 dev_dbg(mdev->dev,
144 "request: unable to queue %s, request in state %s\n",
145 req->debug_str, media_request_state_str(state));
146 media_request_put(req);
147 mutex_unlock(&mdev->req_queue_mutex);
148 return -EBUSY;
149 }
150
151 ret = mdev->ops->req_validate(req);
152
153 /*
154 * If the req_validate was successful, then we mark the state as QUEUED
155 * and call req_queue. The reason we set the state first is that this
156 * allows req_queue to unbind or complete the queued objects in case
157 * they are immediately 'consumed'. State changes from QUEUED to another
158 * state can only happen if either the driver changes the state or if
159 * the user cancels the vb2 queue. The driver can only change the state
160 * after each object is queued through the req_queue op (and note that
161 * that op cannot fail), so setting the state to QUEUED up front is
162 * safe.
163 *
164 * The other reason for changing the state is if the vb2 queue is
165 * canceled, and that uses the req_queue_mutex which is still locked
166 * while req_queue is called, so that's safe as well.
167 */
168 spin_lock_irqsave(&req->lock, flags);
169 req->state = ret ? MEDIA_REQUEST_STATE_IDLE
170 : MEDIA_REQUEST_STATE_QUEUED;
171 spin_unlock_irqrestore(&req->lock, flags);
172
173 if (!ret)
174 mdev->ops->req_queue(req);
175
176 mutex_unlock(&mdev->req_queue_mutex);
177
178 if (ret) {
179 dev_dbg(mdev->dev, "request: can't queue %s (%d)\n",
180 req->debug_str, ret);
181 media_request_put(req);
182 }
183
184 return ret;
185}
186
187static long media_request_ioctl_reinit(struct media_request *req)
188{
189 struct media_device *mdev = req->mdev;
190 unsigned long flags;
191
192 spin_lock_irqsave(&req->lock, flags);
193 if (req->state != MEDIA_REQUEST_STATE_IDLE &&
194 req->state != MEDIA_REQUEST_STATE_COMPLETE) {
195 dev_dbg(mdev->dev,
196 "request: %s not in idle or complete state, cannot reinit\n",
197 req->debug_str);
198 spin_unlock_irqrestore(&req->lock, flags);
199 return -EBUSY;
200 }
201 req->state = MEDIA_REQUEST_STATE_CLEANING;
202 spin_unlock_irqrestore(&req->lock, flags);
203
204 media_request_clean(req);
205
206 spin_lock_irqsave(&req->lock, flags);
207 req->state = MEDIA_REQUEST_STATE_IDLE;
208 spin_unlock_irqrestore(&req->lock, flags);
209
210 return 0;
211}
212
213static long media_request_ioctl(struct file *filp, unsigned int cmd,
214 unsigned long arg)
215{
216 struct media_request *req = filp->private_data;
217
218 switch (cmd) {
219 case MEDIA_REQUEST_IOC_QUEUE:
220 return media_request_ioctl_queue(req);
221 case MEDIA_REQUEST_IOC_REINIT:
222 return media_request_ioctl_reinit(req);
223 default:
224 return -ENOIOCTLCMD;
225 }
226}
227
228static const struct file_operations request_fops = {
229 .owner = THIS_MODULE,
230 .poll = media_request_poll,
231 .unlocked_ioctl = media_request_ioctl,
232 .release = media_request_close,
233};
234
235struct media_request *
236media_request_get_by_fd(struct media_device *mdev, int request_fd)
237{
238 struct file *filp;
239 struct media_request *req;
240
241 if (!mdev || !mdev->ops ||
242 !mdev->ops->req_validate || !mdev->ops->req_queue)
243 return ERR_PTR(-EPERM);
244
245 filp = fget(request_fd);
246 if (!filp)
247 return ERR_PTR(-ENOENT);
248
249 if (filp->f_op != &request_fops)
250 goto err_fput;
251 req = filp->private_data;
252 if (req->mdev != mdev)
253 goto err_fput;
254
255 /*
256 * Note: as long as someone has an open filehandle of the request,
257 * the request can never be released. The fget() above ensures that
258 * even if userspace closes the request filehandle, the release()
259 * fop won't be called, so the media_request_get() always succeeds
260 * and there is no race condition where the request was released
261 * before media_request_get() is called.
262 */
263 media_request_get(req);
264 fput(filp);
265
266 return req;
267
268err_fput:
269 fput(filp);
270
271 return ERR_PTR(-ENOENT);
272}
273EXPORT_SYMBOL_GPL(media_request_get_by_fd);
274
275int media_request_alloc(struct media_device *mdev, int *alloc_fd)
276{
277 struct media_request *req;
278 struct file *filp;
279 int fd;
280 int ret;
281
282 /* Either both are NULL or both are non-NULL */
283 if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free))
284 return -ENOMEM;
285
286 fd = get_unused_fd_flags(O_CLOEXEC);
287 if (fd < 0)
288 return fd;
289
290 filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC);
291 if (IS_ERR(filp)) {
292 ret = PTR_ERR(filp);
293 goto err_put_fd;
294 }
295
296 if (mdev->ops->req_alloc)
297 req = mdev->ops->req_alloc(mdev);
298 else
299 req = kzalloc(sizeof(*req), GFP_KERNEL);
300 if (!req) {
301 ret = -ENOMEM;
302 goto err_fput;
303 }
304
305 filp->private_data = req;
306 req->mdev = mdev;
307 req->state = MEDIA_REQUEST_STATE_IDLE;
308 req->num_incomplete_objects = 0;
309 kref_init(&req->kref);
310 INIT_LIST_HEAD(&req->objects);
311 spin_lock_init(&req->lock);
312 init_waitqueue_head(&req->poll_wait);
313 req->updating_count = 0;
314
315 *alloc_fd = fd;
316
317 snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d",
318 atomic_inc_return(&mdev->request_id), fd);
319 dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str);
320
321 fd_install(fd, filp);
322
323 return 0;
324
325err_fput:
326 fput(filp);
327
328err_put_fd:
329 put_unused_fd(fd);
330
331 return ret;
332}
333
334static void media_request_object_release(struct kref *kref)
335{
336 struct media_request_object *obj =
337 container_of(kref, struct media_request_object, kref);
338 struct media_request *req = obj->req;
339
340 if (WARN_ON(req))
341 media_request_object_unbind(obj);
342 obj->ops->release(obj);
343}
344
345void media_request_object_put(struct media_request_object *obj)
346{
347 kref_put(&obj->kref, media_request_object_release);
348}
349EXPORT_SYMBOL_GPL(media_request_object_put);
350
351void media_request_object_init(struct media_request_object *obj)
352{
353 obj->ops = NULL;
354 obj->req = NULL;
355 obj->priv = NULL;
356 obj->completed = false;
357 INIT_LIST_HEAD(&obj->list);
358 kref_init(&obj->kref);
359}
360EXPORT_SYMBOL_GPL(media_request_object_init);
361
362int media_request_object_bind(struct media_request *req,
363 const struct media_request_object_ops *ops,
364 void *priv, bool is_buffer,
365 struct media_request_object *obj)
366{
367 unsigned long flags;
368 int ret = -EBUSY;
369
370 if (WARN_ON(!ops->release))
371 return -EPERM;
372
373 spin_lock_irqsave(&req->lock, flags);
374
375 if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
376 goto unlock;
377
378 obj->req = req;
379 obj->ops = ops;
380 obj->priv = priv;
381
382 if (is_buffer)
383 list_add_tail(&obj->list, &req->objects);
384 else
385 list_add(&obj->list, &req->objects);
386 req->num_incomplete_objects++;
387 ret = 0;
388
389unlock:
390 spin_unlock_irqrestore(&req->lock, flags);
391 return ret;
392}
393EXPORT_SYMBOL_GPL(media_request_object_bind);
394
395void media_request_object_unbind(struct media_request_object *obj)
396{
397 struct media_request *req = obj->req;
398 unsigned long flags;
399 bool completed = false;
400
401 if (WARN_ON(!req))
402 return;
403
404 spin_lock_irqsave(&req->lock, flags);
405 list_del(&obj->list);
406 obj->req = NULL;
407
408 if (req->state == MEDIA_REQUEST_STATE_COMPLETE)
409 goto unlock;
410
411 if (WARN_ON(req->state == MEDIA_REQUEST_STATE_VALIDATING))
412 goto unlock;
413
414 if (req->state == MEDIA_REQUEST_STATE_CLEANING) {
415 if (!obj->completed)
416 req->num_incomplete_objects--;
417 goto unlock;
418 }
419
420 if (WARN_ON(!req->num_incomplete_objects))
421 goto unlock;
422
423 req->num_incomplete_objects--;
424 if (req->state == MEDIA_REQUEST_STATE_QUEUED &&
425 !req->num_incomplete_objects) {
426 req->state = MEDIA_REQUEST_STATE_COMPLETE;
427 completed = true;
428 wake_up_interruptible_all(&req->poll_wait);
429 }
430
431unlock:
432 spin_unlock_irqrestore(&req->lock, flags);
433 if (obj->ops->unbind)
434 obj->ops->unbind(obj);
435 if (completed)
436 media_request_put(req);
437}
438EXPORT_SYMBOL_GPL(media_request_object_unbind);
439
440void media_request_object_complete(struct media_request_object *obj)
441{
442 struct media_request *req = obj->req;
443 unsigned long flags;
444 bool completed = false;
445
446 spin_lock_irqsave(&req->lock, flags);
447 if (obj->completed)
448 goto unlock;
449 obj->completed = true;
450 if (WARN_ON(!req->num_incomplete_objects) ||
451 WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
452 goto unlock;
453
454 if (!--req->num_incomplete_objects) {
455 req->state = MEDIA_REQUEST_STATE_COMPLETE;
456 wake_up_interruptible_all(&req->poll_wait);
457 completed = true;
458 }
459unlock:
460 spin_unlock_irqrestore(&req->lock, flags);
461 if (completed)
462 media_request_put(req);
463}
464EXPORT_SYMBOL_GPL(media_request_object_complete);
diff --git a/include/media/media-device.h b/include/media/media-device.h
index bcc6ec434f1f..c8ddbfe8b74c 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -27,6 +27,7 @@
27 27
28struct ida; 28struct ida;
29struct device; 29struct device;
30struct media_device;
30 31
31/** 32/**
32 * struct media_entity_notify - Media Entity Notify 33 * struct media_entity_notify - Media Entity Notify
@@ -50,10 +51,32 @@ struct media_entity_notify {
50 * struct media_device_ops - Media device operations 51 * struct media_device_ops - Media device operations
51 * @link_notify: Link state change notification callback. This callback is 52 * @link_notify: Link state change notification callback. This callback is
52 * called with the graph_mutex held. 53 * called with the graph_mutex held.
54 * @req_alloc: Allocate a request. Set this if you need to allocate a struct
55 * larger then struct media_request. @req_alloc and @req_free must
56 * either both be set or both be NULL.
57 * @req_free: Free a request. Set this if @req_alloc was set as well, leave
58 * to NULL otherwise.
59 * @req_validate: Validate a request, but do not queue yet. The req_queue_mutex
60 * lock is held when this op is called.
61 * @req_queue: Queue a validated request, cannot fail. If something goes
62 * wrong when queueing this request then it should be marked
63 * as such internally in the driver and any related buffers
64 * must eventually return to vb2 with state VB2_BUF_STATE_ERROR.
65 * The req_queue_mutex lock is held when this op is called.
66 * It is important that vb2 buffer objects are queued last after
67 * all other object types are queued: queueing a buffer kickstarts
68 * the request processing, so all other objects related to the
69 * request (and thus the buffer) must be available to the driver.
70 * And once a buffer is queued, then the driver can complete
71 * or delete objects from the request before req_queue exits.
53 */ 72 */
54struct media_device_ops { 73struct media_device_ops {
55 int (*link_notify)(struct media_link *link, u32 flags, 74 int (*link_notify)(struct media_link *link, u32 flags,
56 unsigned int notification); 75 unsigned int notification);
76 struct media_request *(*req_alloc)(struct media_device *mdev);
77 void (*req_free)(struct media_request *req);
78 int (*req_validate)(struct media_request *req);
79 void (*req_queue)(struct media_request *req);
57}; 80};
58 81
59/** 82/**
@@ -88,6 +111,9 @@ struct media_device_ops {
88 * @disable_source: Disable Source Handler function pointer 111 * @disable_source: Disable Source Handler function pointer
89 * 112 *
90 * @ops: Operation handler callbacks 113 * @ops: Operation handler callbacks
114 * @req_queue_mutex: Serialise the MEDIA_REQUEST_IOC_QUEUE ioctl w.r.t.
115 * other operations that stop or start streaming.
116 * @request_id: Used to generate unique request IDs
91 * 117 *
92 * This structure represents an abstract high-level media device. It allows easy 118 * This structure represents an abstract high-level media device. It allows easy
93 * access to entities and provides basic media device-level support. The 119 * access to entities and provides basic media device-level support. The
@@ -158,6 +184,9 @@ struct media_device {
158 void (*disable_source)(struct media_entity *entity); 184 void (*disable_source)(struct media_entity *entity);
159 185
160 const struct media_device_ops *ops; 186 const struct media_device_ops *ops;
187
188 struct mutex req_queue_mutex;
189 atomic_t request_id;
161}; 190};
162 191
163/* We don't need to include pci.h or usb.h here */ 192/* We don't need to include pci.h or usb.h here */
diff --git a/include/media/media-request.h b/include/media/media-request.h
new file mode 100644
index 000000000000..9664ebac5dc4
--- /dev/null
+++ b/include/media/media-request.h
@@ -0,0 +1,334 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Media device request objects
4 *
5 * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 * Copyright (C) 2018 Intel Corporation
7 *
8 * Author: Hans Verkuil <hans.verkuil@cisco.com>
9 * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
10 */
11
12#ifndef MEDIA_REQUEST_H
13#define MEDIA_REQUEST_H
14
15#include <linux/list.h>
16#include <linux/slab.h>
17#include <linux/spinlock.h>
18#include <linux/refcount.h>
19
20#include <media/media-device.h>
21
22/**
23 * enum media_request_state - media request state
24 *
25 * @MEDIA_REQUEST_STATE_IDLE: Idle
26 * @MEDIA_REQUEST_STATE_VALIDATING: Validating the request, no state changes
27 * allowed
28 * @MEDIA_REQUEST_STATE_QUEUED: Queued
29 * @MEDIA_REQUEST_STATE_COMPLETE: Completed, the request is done
30 * @MEDIA_REQUEST_STATE_CLEANING: Cleaning, the request is being re-inited
31 * @MEDIA_REQUEST_STATE_UPDATING: The request is being updated, i.e.
32 * request objects are being added,
33 * modified or removed
34 * @NR_OF_MEDIA_REQUEST_STATE: The number of media request states, used
35 * internally for sanity check purposes
36 */
37enum media_request_state {
38 MEDIA_REQUEST_STATE_IDLE,
39 MEDIA_REQUEST_STATE_VALIDATING,
40 MEDIA_REQUEST_STATE_QUEUED,
41 MEDIA_REQUEST_STATE_COMPLETE,
42 MEDIA_REQUEST_STATE_CLEANING,
43 MEDIA_REQUEST_STATE_UPDATING,
44 NR_OF_MEDIA_REQUEST_STATE,
45};
46
47struct media_request_object;
48
49/**
50 * struct media_request - Media device request
51 * @mdev: Media device this request belongs to
52 * @kref: Reference count
53 * @debug_str: Prefix for debug messages (process name:fd)
54 * @state: The state of the request
55 * @updating_count: count the number of request updates that are in progress
56 * @objects: List of @struct media_request_object request objects
57 * @num_incomplete_objects: The number of incomplete objects in the request
58 * @poll_wait: Wait queue for poll
59 * @lock: Serializes access to this struct
60 */
61struct media_request {
62 struct media_device *mdev;
63 struct kref kref;
64 char debug_str[TASK_COMM_LEN + 11];
65 enum media_request_state state;
66 unsigned int updating_count;
67 struct list_head objects;
68 unsigned int num_incomplete_objects;
69 struct wait_queue_head poll_wait;
70 spinlock_t lock;
71};
72
73#ifdef CONFIG_MEDIA_CONTROLLER
74
75/**
76 * media_request_lock_for_update - Lock the request for updating its objects
77 *
78 * @req: The media request
79 *
80 * Use before updating a request, i.e. adding, modifying or removing a request
81 * object in it. A reference to the request must be held during the update. This
82 * usually takes place automatically through a file handle. Use
83 * @media_request_unlock_for_update when done.
84 */
85static inline int __must_check
86media_request_lock_for_update(struct media_request *req)
87{
88 unsigned long flags;
89 int ret = 0;
90
91 spin_lock_irqsave(&req->lock, flags);
92 if (req->state == MEDIA_REQUEST_STATE_IDLE ||
93 req->state == MEDIA_REQUEST_STATE_UPDATING) {
94 req->state = MEDIA_REQUEST_STATE_UPDATING;
95 req->updating_count++;
96 } else {
97 ret = -EBUSY;
98 }
99 spin_unlock_irqrestore(&req->lock, flags);
100
101 return ret;
102}
103
104/**
105 * media_request_unlock_for_update - Unlock a request previously locked for
106 * update
107 *
108 * @req: The media request
109 *
110 * Unlock a request that has previously been locked using
111 * @media_request_lock_for_update.
112 */
113static inline void media_request_unlock_for_update(struct media_request *req)
114{
115 unsigned long flags;
116
117 spin_lock_irqsave(&req->lock, flags);
118 WARN_ON(req->updating_count <= 0);
119 if (!--req->updating_count)
120 req->state = MEDIA_REQUEST_STATE_IDLE;
121 spin_unlock_irqrestore(&req->lock, flags);
122}
123
124/**
125 * media_request_get - Get the media request
126 *
127 * @req: The media request
128 *
129 * Get the media request.
130 */
131static inline void media_request_get(struct media_request *req)
132{
133 kref_get(&req->kref);
134}
135
136/**
137 * media_request_put - Put the media request
138 *
139 * @req: The media request
140 *
141 * Put the media request. The media request will be released
142 * when the refcount reaches 0.
143 */
144void media_request_put(struct media_request *req);
145
146/**
147 * media_request_alloc - Allocate the media request
148 *
149 * @mdev: Media device this request belongs to
150 * @alloc_fd: Store the request's file descriptor in this int
151 *
152 * Allocated the media request and put the fd in @alloc_fd.
153 */
154int media_request_alloc(struct media_device *mdev,
155 int *alloc_fd);
156
157#else
158
159static inline void media_request_get(struct media_request *req)
160{
161}
162
163static inline void media_request_put(struct media_request *req)
164{
165}
166
167#endif
168
169/**
170 * struct media_request_object_ops - Media request object operations
171 * @prepare: Validate and prepare the request object, optional.
172 * @unprepare: Unprepare the request object, optional.
173 * @queue: Queue the request object, optional.
174 * @unbind: Unbind the request object, optional.
175 * @release: Release the request object, required.
176 */
177struct media_request_object_ops {
178 int (*prepare)(struct media_request_object *object);
179 void (*unprepare)(struct media_request_object *object);
180 void (*queue)(struct media_request_object *object);
181 void (*unbind)(struct media_request_object *object);
182 void (*release)(struct media_request_object *object);
183};
184
185/**
186 * struct media_request_object - An opaque object that belongs to a media
187 * request
188 *
189 * @ops: object's operations
190 * @priv: object's priv pointer
191 * @req: the request this object belongs to (can be NULL)
192 * @list: List entry of the object for @struct media_request
193 * @kref: Reference count of the object, acquire before releasing req->lock
194 * @completed: If true, then this object was completed.
195 *
196 * An object related to the request. This struct is always embedded in
197 * another struct that contains the actual data for this request object.
198 */
199struct media_request_object {
200 const struct media_request_object_ops *ops;
201 void *priv;
202 struct media_request *req;
203 struct list_head list;
204 struct kref kref;
205 bool completed;
206};
207
208#ifdef CONFIG_MEDIA_CONTROLLER
209
210/**
211 * media_request_object_get - Get a media request object
212 *
213 * @obj: The object
214 *
215 * Get a media request object.
216 */
217static inline void media_request_object_get(struct media_request_object *obj)
218{
219 kref_get(&obj->kref);
220}
221
222/**
223 * media_request_object_put - Put a media request object
224 *
225 * @obj: The object
226 *
227 * Put a media request object. Once all references are gone, the
228 * object's memory is released.
229 */
230void media_request_object_put(struct media_request_object *obj);
231
232/**
233 * media_request_object_init - Initialise a media request object
234 *
235 * @obj: The object
236 *
237 * Initialise a media request object. The object will be released using the
238 * release callback of the ops once it has no references (this function
239 * initialises references to one).
240 */
241void media_request_object_init(struct media_request_object *obj);
242
243/**
244 * media_request_object_bind - Bind a media request object to a request
245 *
246 * @req: The media request
247 * @ops: The object ops for this object
248 * @priv: A driver-specific priv pointer associated with this object
249 * @is_buffer: Set to true if the object a buffer object.
250 * @obj: The object
251 *
252 * Bind this object to the request and set the ops and priv values of
253 * the object so it can be found later with media_request_object_find().
254 *
255 * Every bound object must be unbound or completed by the kernel at some
256 * point in time, otherwise the request will never complete. When the
257 * request is released all completed objects will be unbound by the
258 * request core code.
259 *
260 * Buffer objects will be added to the end of the request's object
261 * list, non-buffer objects will be added to the front of the list.
262 * This ensures that all buffer objects are at the end of the list
263 * and that all non-buffer objects that they depend on are processed
264 * first.
265 */
266int media_request_object_bind(struct media_request *req,
267 const struct media_request_object_ops *ops,
268 void *priv, bool is_buffer,
269 struct media_request_object *obj);
270
271/**
272 * media_request_object_unbind - Unbind a media request object
273 *
274 * @obj: The object
275 *
276 * Unbind the media request object from the request.
277 */
278void media_request_object_unbind(struct media_request_object *obj);
279
280/**
281 * media_request_object_complete - Mark the media request object as complete
282 *
283 * @obj: The object
284 *
285 * Mark the media request object as complete. Only bound objects can
286 * be completed.
287 */
288void media_request_object_complete(struct media_request_object *obj);
289
290#else
291
292static inline int __must_check
293media_request_lock_for_update(struct media_request *req)
294{
295 return -EINVAL;
296}
297
298static inline void media_request_unlock_for_update(struct media_request *req)
299{
300}
301
302static inline void media_request_object_get(struct media_request_object *obj)
303{
304}
305
306static inline void media_request_object_put(struct media_request_object *obj)
307{
308}
309
310static inline void media_request_object_init(struct media_request_object *obj)
311{
312 obj->ops = NULL;
313 obj->req = NULL;
314}
315
316static inline int media_request_object_bind(struct media_request *req,
317 const struct media_request_object_ops *ops,
318 void *priv, bool is_buffer,
319 struct media_request_object *obj)
320{
321 return 0;
322}
323
324static inline void media_request_object_unbind(struct media_request_object *obj)
325{
326}
327
328static inline void media_request_object_complete(struct media_request_object *obj)
329{
330}
331
332#endif
333
334#endif