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 | media_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 | */ |
111 | static 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 | */ |
131 | static inline int __must_check |
132 | media_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 | */ |
159 | static 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 | */ |
177 | static 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 | */ |
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(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 | */ |
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 |
443 | |