Branch data Line data Source code
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 : : */
37 : : enum 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 : :
47 : : struct 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 : : */
62 : : struct 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 : : */
86 : : static inline int __must_check
87 : 0 : media_request_lock_for_access(struct media_request *req)
88 : : {
89 : : unsigned long flags;
90 : : int ret = -EBUSY;
91 : :
92 : 0 : spin_lock_irqsave(&req->lock, flags);
93 [ # # ]: 0 : if (req->state == MEDIA_REQUEST_STATE_COMPLETE) {
94 : 0 : req->access_count++;
95 : : ret = 0;
96 : : }
97 : : spin_unlock_irqrestore(&req->lock, flags);
98 : :
99 : 0 : 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 : : */
111 : 0 : static inline void media_request_unlock_for_access(struct media_request *req)
112 : : {
113 : : unsigned long flags;
114 : :
115 : 0 : spin_lock_irqsave(&req->lock, flags);
116 [ # # # # ]: 0 : if (!WARN_ON(!req->access_count))
117 : 0 : req->access_count--;
118 : : spin_unlock_irqrestore(&req->lock, flags);
119 : 0 : }
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 : : */
131 : : static inline int __must_check
132 : 0 : media_request_lock_for_update(struct media_request *req)
133 : : {
134 : : unsigned long flags;
135 : : int ret = 0;
136 : :
137 : 0 : spin_lock_irqsave(&req->lock, flags);
138 [ # # ]: 0 : if (req->state == MEDIA_REQUEST_STATE_IDLE ||
139 : : req->state == MEDIA_REQUEST_STATE_UPDATING) {
140 : 0 : req->state = MEDIA_REQUEST_STATE_UPDATING;
141 : 0 : req->updating_count++;
142 : : } else {
143 : : ret = -EBUSY;
144 : : }
145 : : spin_unlock_irqrestore(&req->lock, flags);
146 : :
147 : 0 : 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 : : */
159 : 0 : static inline void media_request_unlock_for_update(struct media_request *req)
160 : : {
161 : : unsigned long flags;
162 : :
163 : 0 : spin_lock_irqsave(&req->lock, flags);
164 [ # # ]: 0 : WARN_ON(req->updating_count <= 0);
165 [ # # ]: 0 : if (!--req->updating_count)
166 : 0 : req->state = MEDIA_REQUEST_STATE_IDLE;
167 : : spin_unlock_irqrestore(&req->lock, flags);
168 : 0 : }
169 : :
170 : : /**
171 : : * media_request_get - Get the media request
172 : : *
173 : : * @req: The media request
174 : : *
175 : : * Get the media request.
176 : : */
177 : : static inline void media_request_get(struct media_request *req)
178 : : {
179 : : kref_get(&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 : : */
190 : : void 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 : : */
207 : : struct media_request *
208 : : media_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 : : */
218 : : int media_request_alloc(struct media_device *mdev,
219 : : int *alloc_fd);
220 : :
221 : : #else
222 : :
223 : : static inline void media_request_get(struct media_request *req)
224 : : {
225 : : }
226 : :
227 : : static inline void media_request_put(struct media_request *req)
228 : : {
229 : : }
230 : :
231 : : static inline struct media_request *
232 : : media_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 : : */
247 : : struct 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 : : */
269 : : struct 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 : : */
287 : : static inline void media_request_object_get(struct media_request_object *obj)
288 : : {
289 : : kref_get(&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 : : */
300 : : void 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 : : */
317 : : struct media_request_object *
318 : : media_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 : : */
331 : : void 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 : : */
356 : : int 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 : : */
368 : : void 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 : : */
378 : : void media_request_object_complete(struct media_request_object *obj);
379 : :
380 : : #else
381 : :
382 : : static inline int __must_check
383 : : media_request_lock_for_access(struct media_request *req)
384 : : {
385 : : return -EINVAL;
386 : : }
387 : :
388 : : static inline void media_request_unlock_for_access(struct media_request *req)
389 : : {
390 : : }
391 : :
392 : : static inline int __must_check
393 : : media_request_lock_for_update(struct media_request *req)
394 : : {
395 : : return -EINVAL;
396 : : }
397 : :
398 : : static inline void media_request_unlock_for_update(struct media_request *req)
399 : : {
400 : : }
401 : :
402 : : static inline void media_request_object_get(struct media_request_object *obj)
403 : : {
404 : : }
405 : :
406 : : static inline void media_request_object_put(struct media_request_object *obj)
407 : : {
408 : : }
409 : :
410 : : static inline struct media_request_object *
411 : : media_request_object_find(struct media_request *req,
412 : : const struct media_request_object_ops *ops,
413 : : void *priv)
414 : : {
415 : : return NULL;
416 : : }
417 : :
418 : : static inline void media_request_object_init(struct media_request_object *obj)
419 : : {
420 : : obj->ops = NULL;
421 : : obj->req = NULL;
422 : : }
423 : :
424 : : static 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 : :
432 : : static inline void media_request_object_unbind(struct media_request_object *obj)
433 : : {
434 : : }
435 : :
436 : : static inline void media_request_object_complete(struct media_request_object *obj)
437 : : {
438 : : }
439 : :
440 : : #endif
441 : :
442 : : #endif
|