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 * @access_count: count the number of request accesses that are in progress
57 * @objects: List of @struct media_request_object request objects
58 * @num_incomplete_objects: The number of incomplete objects in the request
59 * @poll_wait: Wait queue for poll
60 * @lock: Serializes access to this struct
61 */
62struct media_request {
63 struct media_device *mdev;
64 struct kref kref;
65 char debug_str[TASK_COMM_LEN + 11];
66 enum media_request_state state;
67 unsigned int updating_count;
68 unsigned int access_count;
69 struct list_head objects;
70 unsigned int num_incomplete_objects;
71 wait_queue_head_t poll_wait;
72 spinlock_t lock;
73};
74
75#ifdef CONFIG_MEDIA_CONTROLLER
76
77/**
78 * media_request_lock_for_access - Lock the request to access its objects
79 *
80 * @req: The media request
81 *
82 * Use before accessing a completed request. A reference to the request must
83 * be held during the access. This usually takes place automatically through
84 * a file handle. Use @media_request_unlock_for_access when done.
85 */
86static inline int __must_check
87media_request_lock_for_access(struct media_request *req)
88{
89 unsigned long flags;
90 int ret = -EBUSY;
91
92 spin_lock_irqsave(&req->lock, flags);
93 if (req->state == MEDIA_REQUEST_STATE_COMPLETE) {
94 req->access_count++;
95 ret = 0;
96 }
97 spin_unlock_irqrestore(lock: &req->lock, flags);
98
99 return ret;
100}
101
102/**
103 * media_request_unlock_for_access - Unlock a request previously locked for
104 * access
105 *
106 * @req: The media request
107 *
108 * Unlock a request that has previously been locked using
109 * @media_request_lock_for_access.
110 */
111static inline void media_request_unlock_for_access(struct media_request *req)
112{
113 unsigned long flags;
114
115 spin_lock_irqsave(&req->lock, flags);
116 if (!WARN_ON(!req->access_count))
117 req->access_count--;
118 spin_unlock_irqrestore(lock: &req->lock, flags);
119}
120
121/**
122 * media_request_lock_for_update - Lock the request for updating its objects
123 *
124 * @req: The media request
125 *
126 * Use before updating a request, i.e. adding, modifying or removing a request
127 * object in it. A reference to the request must be held during the update. This
128 * usually takes place automatically through a file handle. Use
129 * @media_request_unlock_for_update when done.
130 */
131static inline int __must_check
132media_request_lock_for_update(struct media_request *req)
133{
134 unsigned long flags;
135 int ret = 0;
136
137 spin_lock_irqsave(&req->lock, flags);
138 if (req->state == MEDIA_REQUEST_STATE_IDLE ||
139 req->state == MEDIA_REQUEST_STATE_UPDATING) {
140 req->state = MEDIA_REQUEST_STATE_UPDATING;
141 req->updating_count++;
142 } else {
143 ret = -EBUSY;
144 }
145 spin_unlock_irqrestore(lock: &req->lock, flags);
146
147 return ret;
148}
149
150/**
151 * media_request_unlock_for_update - Unlock a request previously locked for
152 * update
153 *
154 * @req: The media request
155 *
156 * Unlock a request that has previously been locked using
157 * @media_request_lock_for_update.
158 */
159static inline void media_request_unlock_for_update(struct media_request *req)
160{
161 unsigned long flags;
162
163 spin_lock_irqsave(&req->lock, flags);
164 WARN_ON(req->updating_count <= 0);
165 if (!--req->updating_count)
166 req->state = MEDIA_REQUEST_STATE_IDLE;
167 spin_unlock_irqrestore(lock: &req->lock, flags);
168}
169
170/**
171 * media_request_get - Get the media request
172 *
173 * @req: The media request
174 *
175 * Get the media request.
176 */
177static inline void media_request_get(struct media_request *req)
178{
179 kref_get(kref: &req->kref);
180}
181
182/**
183 * media_request_put - Put the media request
184 *
185 * @req: The media request
186 *
187 * Put the media request. The media request will be released
188 * when the refcount reaches 0.
189 */
190void media_request_put(struct media_request *req);
191
192/**
193 * media_request_get_by_fd - Get a media request by fd
194 *
195 * @mdev: Media device this request belongs to
196 * @request_fd: The file descriptor of the request
197 *
198 * Get the request represented by @request_fd that is owned
199 * by the media device.
200 *
201 * Return a -EBADR error pointer if requests are not supported
202 * by this driver. Return -EINVAL if the request was not found.
203 * Return the pointer to the request if found: the caller will
204 * have to call @media_request_put when it finished using the
205 * request.
206 */
207struct media_request *
208media_request_get_by_fd(struct media_device *mdev, int request_fd);
209
210/**
211 * media_request_alloc - Allocate the media request
212 *
213 * @mdev: Media device this request belongs to
214 * @alloc_fd: Store the request's file descriptor in this int
215 *
216 * Allocated the media request and put the fd in @alloc_fd.
217 */
218int media_request_alloc(struct media_device *mdev,
219 int *alloc_fd);
220
221#else
222
223static inline void media_request_get(struct media_request *req)
224{
225}
226
227static inline void media_request_put(struct media_request *req)
228{
229}
230
231static inline struct media_request *
232media_request_get_by_fd(struct media_device *mdev, int request_fd)
233{
234 return ERR_PTR(-EBADR);
235}
236
237#endif
238
239/**
240 * struct media_request_object_ops - Media request object operations
241 * @prepare: Validate and prepare the request object, optional.
242 * @unprepare: Unprepare the request object, optional.
243 * @queue: Queue the request object, optional.
244 * @unbind: Unbind the request object, optional.
245 * @release: Release the request object, required.
246 */
247struct media_request_object_ops {
248 int (*prepare)(struct media_request_object *object);
249 void (*unprepare)(struct media_request_object *object);
250 void (*queue)(struct media_request_object *object);
251 void (*unbind)(struct media_request_object *object);
252 void (*release)(struct media_request_object *object);
253};
254
255/**
256 * struct media_request_object - An opaque object that belongs to a media
257 * request
258 *
259 * @ops: object's operations
260 * @priv: object's priv pointer
261 * @req: the request this object belongs to (can be NULL)
262 * @list: List entry of the object for @struct media_request
263 * @kref: Reference count of the object, acquire before releasing req->lock
264 * @completed: If true, then this object was completed.
265 *
266 * An object related to the request. This struct is always embedded in
267 * another struct that contains the actual data for this request object.
268 */
269struct media_request_object {
270 const struct media_request_object_ops *ops;
271 void *priv;
272 struct media_request *req;
273 struct list_head list;
274 struct kref kref;
275 bool completed;
276};
277
278#ifdef CONFIG_MEDIA_CONTROLLER
279
280/**
281 * media_request_object_get - Get a media request object
282 *
283 * @obj: The object
284 *
285 * Get a media request object.
286 */
287static inline void media_request_object_get(struct media_request_object *obj)
288{
289 kref_get(kref: &obj->kref);
290}
291
292/**
293 * media_request_object_put - Put a media request object
294 *
295 * @obj: The object
296 *
297 * Put a media request object. Once all references are gone, the
298 * object's memory is released.
299 */
300void media_request_object_put(struct media_request_object *obj);
301
302/**
303 * media_request_object_find - Find an object in a request
304 *
305 * @req: The media request
306 * @ops: Find an object with this ops value
307 * @priv: Find an object with this priv value
308 *
309 * Both @ops and @priv must be non-NULL.
310 *
311 * Returns the object pointer or NULL if not found. The caller must
312 * call media_request_object_put() once it finished using the object.
313 *
314 * Since this function needs to walk the list of objects it takes
315 * the @req->lock spin lock to make this safe.
316 */
317struct media_request_object *
318media_request_object_find(struct media_request *req,
319 const struct media_request_object_ops *ops,
320 void *priv);
321
322/**
323 * media_request_object_init - Initialise a media request object
324 *
325 * @obj: The object
326 *
327 * Initialise a media request object. The object will be released using the
328 * release callback of the ops once it has no references (this function
329 * initialises references to one).
330 */
331void media_request_object_init(struct media_request_object *obj);
332
333/**
334 * media_request_object_bind - Bind a media request object to a request
335 *
336 * @req: The media request
337 * @ops: The object ops for this object
338 * @priv: A driver-specific priv pointer associated with this object
339 * @is_buffer: Set to true if the object a buffer object.
340 * @obj: The object
341 *
342 * Bind this object to the request and set the ops and priv values of
343 * the object so it can be found later with media_request_object_find().
344 *
345 * Every bound object must be unbound or completed by the kernel at some
346 * point in time, otherwise the request will never complete. When the
347 * request is released all completed objects will be unbound by the
348 * request core code.
349 *
350 * Buffer objects will be added to the end of the request's object
351 * list, non-buffer objects will be added to the front of the list.
352 * This ensures that all buffer objects are at the end of the list
353 * and that all non-buffer objects that they depend on are processed
354 * first.
355 */
356int media_request_object_bind(struct media_request *req,
357 const struct media_request_object_ops *ops,
358 void *priv, bool is_buffer,
359 struct media_request_object *obj);
360
361/**
362 * media_request_object_unbind - Unbind a media request object
363 *
364 * @obj: The object
365 *
366 * Unbind the media request object from the request.
367 */
368void media_request_object_unbind(struct media_request_object *obj);
369
370/**
371 * media_request_object_complete - Mark the media request object as complete
372 *
373 * @obj: The object
374 *
375 * Mark the media request object as complete. Only bound objects can
376 * be completed.
377 */
378void media_request_object_complete(struct media_request_object *obj);
379
380#else
381
382static inline int __must_check
383media_request_lock_for_access(struct media_request *req)
384{
385 return -EINVAL;
386}
387
388static inline void media_request_unlock_for_access(struct media_request *req)
389{
390}
391
392static inline int __must_check
393media_request_lock_for_update(struct media_request *req)
394{
395 return -EINVAL;
396}
397
398static inline void media_request_unlock_for_update(struct media_request *req)
399{
400}
401
402static inline void media_request_object_get(struct media_request_object *obj)
403{
404}
405
406static inline void media_request_object_put(struct media_request_object *obj)
407{
408}
409
410static inline struct media_request_object *
411media_request_object_find(struct media_request *req,
412 const struct media_request_object_ops *ops,
413 void *priv)
414{
415 return NULL;
416}
417
418static inline void media_request_object_init(struct media_request_object *obj)
419{
420 obj->ops = NULL;
421 obj->req = NULL;
422}
423
424static inline int media_request_object_bind(struct media_request *req,
425 const struct media_request_object_ops *ops,
426 void *priv, bool is_buffer,
427 struct media_request_object *obj)
428{
429 return 0;
430}
431
432static inline void media_request_object_unbind(struct media_request_object *obj)
433{
434}
435
436static inline void media_request_object_complete(struct media_request_object *obj)
437{
438}
439
440#endif
441
442#endif
443

source code of linux/include/media/media-request.h