blob: a9101f24264904af0f8bf22c07ee504498f3477f [file] [log] [blame]
Seemanta Dutta49944562017-03-06 16:41:50 -08001/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Seemanta Dutta49944562017-03-06 16:41:50 -080013#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/irqflags.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/debugfs.h>
19#include "cam_sync_util.h"
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -070020#include "cam_debug_util.h"
Seemanta Dutta49944562017-03-06 16:41:50 -080021
22struct sync_device *sync_dev;
23
24int cam_sync_create(int32_t *sync_obj, const char *name)
25{
26 int rc;
27 long idx;
Junzhe Zou688c22c2017-11-08 12:37:24 -080028 bool bit;
Seemanta Dutta49944562017-03-06 16:41:50 -080029
30 do {
31 idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
Junzhe Zoudf4a11f2017-11-02 12:01:22 -070032 if (idx >= CAM_SYNC_MAX_OBJS)
33 return -ENOMEM;
Vishalsingh Hajerib918d9a2017-12-01 16:39:04 -080034 CAM_DBG(CAM_SYNC, "Index location available at idx: %ld", idx);
Junzhe Zou688c22c2017-11-08 12:37:24 -080035 bit = test_and_set_bit(idx, sync_dev->bitmap);
36 } while (bit);
Seemanta Dutta49944562017-03-06 16:41:50 -080037
Junzhe Zou688c22c2017-11-08 12:37:24 -080038 spin_lock_bh(&sync_dev->row_spinlocks[idx]);
Seemanta Dutta49944562017-03-06 16:41:50 -080039 rc = cam_sync_init_object(sync_dev->sync_table, idx, name);
40 if (rc) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -070041 CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld",
42 idx);
Junzhe Zou688c22c2017-11-08 12:37:24 -080043 clear_bit(idx, sync_dev->bitmap);
Seemanta Dutta49944562017-03-06 16:41:50 -080044 spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
45 return -EINVAL;
46 }
47
Seemanta Dutta49944562017-03-06 16:41:50 -080048 *sync_obj = idx;
49 spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
50
51 return rc;
52}
53
54int cam_sync_register_callback(sync_callback cb_func,
55 void *userdata, int32_t sync_obj)
56{
57 struct sync_callback_info *sync_cb;
58 struct sync_callback_info *cb_info;
Seemanta Dutta49944562017-03-06 16:41:50 -080059 struct sync_table_row *row = NULL;
60
61 if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0 || !cb_func)
62 return -EINVAL;
63
64 spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
65 row = sync_dev->sync_table + sync_obj;
66
67 if (row->state == CAM_SYNC_STATE_INVALID) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -070068 CAM_ERR(CAM_SYNC,
69 "Error: accessing an uninitialized sync obj %d",
Seemanta Dutta49944562017-03-06 16:41:50 -080070 sync_obj);
71 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
72 return -EINVAL;
73 }
74
Harsh Shaha76fd1f2017-11-27 14:43:20 -080075 /* Don't register if callback was registered earlier */
76 list_for_each_entry(cb_info, &row->callback_list, list) {
77 if (cb_info->callback_func == cb_func &&
78 cb_info->cb_data == userdata) {
79 CAM_ERR(CAM_SYNC, "Duplicate register for sync_obj %d",
80 sync_obj);
81 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
82 return -EALREADY;
83 }
84 }
85
Seemanta Dutta49944562017-03-06 16:41:50 -080086 sync_cb = kzalloc(sizeof(*sync_cb), GFP_ATOMIC);
87 if (!sync_cb) {
88 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
89 return -ENOMEM;
90 }
91
92 /* Trigger callback if sync object is already in SIGNALED state */
93 if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
94 row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
95 sync_cb->callback_func = cb_func;
96 sync_cb->cb_data = userdata;
97 sync_cb->sync_obj = sync_obj;
98 INIT_WORK(&sync_cb->cb_dispatch_work,
99 cam_sync_util_cb_dispatch);
Seemanta Dutta49944562017-03-06 16:41:50 -0800100 sync_cb->status = row->state;
Vishalsingh Hajerib918d9a2017-12-01 16:39:04 -0800101 CAM_DBG(CAM_SYNC, "Callback trigger for sync object:%d",
102 sync_cb->sync_obj);
Seemanta Dutta49944562017-03-06 16:41:50 -0800103 queue_work(sync_dev->work_queue,
104 &sync_cb->cb_dispatch_work);
105
106 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
107 return 0;
108 }
109
Seemanta Dutta49944562017-03-06 16:41:50 -0800110 sync_cb->callback_func = cb_func;
111 sync_cb->cb_data = userdata;
112 sync_cb->sync_obj = sync_obj;
113 INIT_WORK(&sync_cb->cb_dispatch_work, cam_sync_util_cb_dispatch);
114 list_add_tail(&sync_cb->list, &row->callback_list);
115 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
116
117 return 0;
118}
119
120int cam_sync_deregister_callback(sync_callback cb_func,
121 void *userdata, int32_t sync_obj)
122{
123 struct sync_table_row *row = NULL;
124 struct sync_callback_info *sync_cb, *temp;
125
126 if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
127 return -EINVAL;
128
129 spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
130 row = sync_dev->sync_table + sync_obj;
131
132 if (row->state == CAM_SYNC_STATE_INVALID) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700133 CAM_ERR(CAM_SYNC,
134 "Error: accessing an uninitialized sync obj = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800135 sync_obj);
136 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
137 return -EINVAL;
138 }
139
Vishalsingh Hajerib918d9a2017-12-01 16:39:04 -0800140 CAM_DBG(CAM_SYNC, "deregistered callback for sync object:%d",
141 sync_obj);
Seemanta Dutta49944562017-03-06 16:41:50 -0800142 list_for_each_entry_safe(sync_cb, temp, &row->callback_list, list) {
143 if (sync_cb->callback_func == cb_func &&
144 sync_cb->cb_data == userdata) {
145 list_del_init(&sync_cb->list);
146 kfree(sync_cb);
147 }
148 }
149
150 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
151 return 0;
152}
153
154int cam_sync_signal(int32_t sync_obj, uint32_t status)
155{
156 int rc;
157 struct sync_table_row *row = NULL;
158 struct sync_table_row *parent_row = NULL;
159 struct sync_callback_info *sync_cb;
160 struct sync_user_payload *payload_info;
161 struct sync_parent_info *parent_info;
162 struct list_head sync_list;
163 struct cam_signalable_info *list_info = NULL;
164 struct cam_signalable_info *temp_list_info = NULL;
165
166 /* Objects to be signaled will be added into this list */
167 INIT_LIST_HEAD(&sync_list);
168
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700169 if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) {
170 CAM_ERR(CAM_SYNC, "Error: Out of range sync obj");
Seemanta Dutta49944562017-03-06 16:41:50 -0800171 return -EINVAL;
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700172 }
Seemanta Dutta49944562017-03-06 16:41:50 -0800173 row = sync_dev->sync_table + sync_obj;
174 if (row->state == CAM_SYNC_STATE_INVALID) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700175 CAM_ERR(CAM_SYNC,
176 "Error: accessing an uninitialized sync obj = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800177 sync_obj);
178 return -EINVAL;
179 }
180
181 spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
182 if (row->type == CAM_SYNC_TYPE_GROUP) {
183 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700184 CAM_ERR(CAM_SYNC, "Error: Signaling a GROUP sync object = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800185 sync_obj);
186 return -EINVAL;
187 }
188
189 if (row->state != CAM_SYNC_STATE_ACTIVE) {
190 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700191 CAM_ERR(CAM_SYNC,
192 "Error: Sync object already signaled sync_obj = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800193 sync_obj);
194 return -EALREADY;
195 }
196
197 if (status != CAM_SYNC_STATE_SIGNALED_SUCCESS &&
198 status != CAM_SYNC_STATE_SIGNALED_ERROR) {
199 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700200 CAM_ERR(CAM_SYNC,
201 "Error: signaling with undefined status = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800202 status);
203 return -EINVAL;
204 }
205
206 row->state = status;
207 rc = cam_sync_util_add_to_signalable_list(sync_obj, status, &sync_list);
208 if (rc < 0) {
209 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
Vishalsingh Hajerib918d9a2017-12-01 16:39:04 -0800210 CAM_ERR(CAM_SYNC,
211 "Error: Unable to add sync object :%d to signalable list",
212 sync_obj);
Seemanta Dutta49944562017-03-06 16:41:50 -0800213 return rc;
214 }
215
216 /*
217 * Now iterate over all parents of this object and if they too need to
218 * be signaled add them to the list
219 */
220 list_for_each_entry(parent_info,
221 &row->parents_list,
222 list) {
223 parent_row = sync_dev->sync_table + parent_info->sync_id;
224 spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
225 parent_row->remaining--;
226
227 parent_row->state = cam_sync_util_get_state(
228 parent_row->state,
229 status);
230
231 if (!parent_row->remaining) {
232 rc = cam_sync_util_add_to_signalable_list
233 (parent_info->sync_id,
234 parent_row->state,
235 &sync_list);
236 if (rc < 0) {
237 spin_unlock_bh(
238 &sync_dev->row_spinlocks[
239 parent_info->sync_id]);
Ravikishore Pampanacf0278c2017-11-15 13:34:31 +0530240 spin_unlock_bh(
241 &sync_dev->row_spinlocks[sync_obj]);
Seemanta Dutta49944562017-03-06 16:41:50 -0800242 return rc;
243 }
244 }
245 spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
246 }
247
Junzhe Zoud4061ea2017-11-21 22:14:55 -0800248 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
249
Seemanta Dutta49944562017-03-06 16:41:50 -0800250 /*
251 * Now dispatch the various sync objects collected so far, in our
252 * list
253 */
254 list_for_each_entry_safe(list_info,
255 temp_list_info,
256 &sync_list,
257 list) {
258 struct sync_table_row *signalable_row = NULL;
259 struct sync_callback_info *temp_sync_cb;
260 struct sync_user_payload *temp_payload_info;
261
262 signalable_row = sync_dev->sync_table + list_info->sync_obj;
Junzhe Zoud4061ea2017-11-21 22:14:55 -0800263
264 spin_lock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]);
Seemanta Dutta49944562017-03-06 16:41:50 -0800265 /* Dispatch kernel callbacks if any were registered earlier */
Vishalsingh Hajerib918d9a2017-12-01 16:39:04 -0800266
Seemanta Dutta49944562017-03-06 16:41:50 -0800267 list_for_each_entry_safe(sync_cb,
Junzhe Zoud4061ea2017-11-21 22:14:55 -0800268 temp_sync_cb, &signalable_row->callback_list, list) {
Seemanta Dutta49944562017-03-06 16:41:50 -0800269 sync_cb->status = list_info->status;
Junzhe Zoud4061ea2017-11-21 22:14:55 -0800270 list_del_init(&sync_cb->list);
Seemanta Dutta49944562017-03-06 16:41:50 -0800271 queue_work(sync_dev->work_queue,
272 &sync_cb->cb_dispatch_work);
Seemanta Dutta49944562017-03-06 16:41:50 -0800273 }
274
275 /* Dispatch user payloads if any were registered earlier */
276 list_for_each_entry_safe(payload_info, temp_payload_info,
Junzhe Zoud4061ea2017-11-21 22:14:55 -0800277 &signalable_row->user_payload_list, list) {
Seemanta Dutta49944562017-03-06 16:41:50 -0800278 spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
279 if (!sync_dev->cam_sync_eventq) {
280 spin_unlock_bh(
281 &sync_dev->cam_sync_eventq_lock);
282 break;
283 }
284 spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
285 cam_sync_util_send_v4l2_event(
286 CAM_SYNC_V4L_EVENT_ID_CB_TRIG,
287 list_info->sync_obj,
288 list_info->status,
289 payload_info->payload_data,
290 CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64));
291
292 list_del_init(&payload_info->list);
293 /*
294 * We can free the list node here because
295 * sending V4L event will make a deep copy
296 * anyway
297 */
298 kfree(payload_info);
299 }
300
301 /*
302 * This needs to be done because we want to unblock anyone
303 * who might be blocked and waiting on this sync object
304 */
305 complete_all(&signalable_row->signaled);
306
Junzhe Zoud4061ea2017-11-21 22:14:55 -0800307 spin_unlock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]);
308
Seemanta Dutta49944562017-03-06 16:41:50 -0800309 list_del_init(&list_info->list);
310 kfree(list_info);
311 }
312
Seemanta Dutta49944562017-03-06 16:41:50 -0800313 return rc;
314}
315
316int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj)
317{
318 int rc;
319 long idx = 0;
Junzhe Zou688c22c2017-11-08 12:37:24 -0800320 bool bit;
Seemanta Dutta49944562017-03-06 16:41:50 -0800321
Seemanta Dutta0155a002017-10-18 17:07:36 -0700322 if (!sync_obj || !merged_obj) {
323 CAM_ERR(CAM_SYNC, "Invalid pointer(s)");
324 return -EINVAL;
325 }
326
Seemanta Dutta49944562017-03-06 16:41:50 -0800327 rc = cam_sync_util_validate_merge(sync_obj,
328 num_objs);
329 if (rc < 0) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700330 CAM_ERR(CAM_SYNC, "Validation failed, Merge not allowed");
Seemanta Dutta49944562017-03-06 16:41:50 -0800331 return -EINVAL;
332 }
333
Junzhe Zoudf4a11f2017-11-02 12:01:22 -0700334 do {
335 idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
336 if (idx >= CAM_SYNC_MAX_OBJS)
337 return -ENOMEM;
Junzhe Zou688c22c2017-11-08 12:37:24 -0800338 bit = test_and_set_bit(idx, sync_dev->bitmap);
339 } while (bit);
Seemanta Dutta49944562017-03-06 16:41:50 -0800340
Junzhe Zou688c22c2017-11-08 12:37:24 -0800341 spin_lock_bh(&sync_dev->row_spinlocks[idx]);
Seemanta Dutta49944562017-03-06 16:41:50 -0800342
343 rc = cam_sync_init_group_object(sync_dev->sync_table,
344 idx, sync_obj,
345 num_objs);
Seemanta Dutta49944562017-03-06 16:41:50 -0800346 if (rc < 0) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700347 CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld",
348 idx);
Junzhe Zou688c22c2017-11-08 12:37:24 -0800349 clear_bit(idx, sync_dev->bitmap);
Junzhe Zoudf4a11f2017-11-02 12:01:22 -0700350 spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
Seemanta Dutta49944562017-03-06 16:41:50 -0800351 return -EINVAL;
352 }
Vishalsingh Hajerib918d9a2017-12-01 16:39:04 -0800353 CAM_DBG(CAM_SYNC, "Init row at idx:%ld to merge objects", idx);
Seemanta Dutta49944562017-03-06 16:41:50 -0800354 *merged_obj = idx;
Junzhe Zoudf4a11f2017-11-02 12:01:22 -0700355 spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
Seemanta Dutta49944562017-03-06 16:41:50 -0800356
357 return 0;
358}
359
360int cam_sync_destroy(int32_t sync_obj)
361{
Harsh Shahef1adcf2017-11-21 17:57:38 -0800362 return cam_sync_deinit_object(sync_dev->sync_table, sync_obj);
Seemanta Dutta49944562017-03-06 16:41:50 -0800363}
364
365int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms)
366{
367 unsigned long timeleft;
368 int rc = -EINVAL;
369 struct sync_table_row *row = NULL;
370
371 if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
372 return -EINVAL;
373
374 row = sync_dev->sync_table + sync_obj;
375
376 if (row->state == CAM_SYNC_STATE_INVALID) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700377 CAM_ERR(CAM_SYNC,
378 "Error: accessing an uninitialized sync obj = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800379 sync_obj);
380 return -EINVAL;
381 }
382
383 timeleft = wait_for_completion_timeout(&row->signaled,
384 msecs_to_jiffies(timeout_ms));
385
386 if (!timeleft) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700387 CAM_ERR(CAM_SYNC,
388 "Error: timed out for sync obj = %d", sync_obj);
Seemanta Dutta49944562017-03-06 16:41:50 -0800389 rc = -ETIMEDOUT;
390 } else {
391 switch (row->state) {
392 case CAM_SYNC_STATE_INVALID:
393 case CAM_SYNC_STATE_ACTIVE:
394 case CAM_SYNC_STATE_SIGNALED_ERROR:
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700395 CAM_ERR(CAM_SYNC,
396 "Error: Wait on invalid state = %d, obj = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800397 row->state, sync_obj);
398 rc = -EINVAL;
399 break;
400 case CAM_SYNC_STATE_SIGNALED_SUCCESS:
401 rc = 0;
402 break;
403 default:
404 rc = -EINVAL;
405 break;
406 }
407 }
408
409 return rc;
410}
411
412static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl)
413{
414 struct cam_sync_info sync_create;
415 int result;
416
417 if (k_ioctl->size != sizeof(struct cam_sync_info))
418 return -EINVAL;
419
420 if (!k_ioctl->ioctl_ptr)
421 return -EINVAL;
422
423 if (copy_from_user(&sync_create,
424 (void *)k_ioctl->ioctl_ptr,
425 k_ioctl->size))
426 return -EFAULT;
427
428 result = cam_sync_create(&sync_create.sync_obj,
429 sync_create.name);
430
431 if (!result)
432 if (copy_to_user((void *)k_ioctl->ioctl_ptr,
433 &sync_create,
434 k_ioctl->size))
435 return -EFAULT;
436
437 return result;
438}
439
440static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl)
441{
442 struct cam_sync_signal sync_signal;
443
444 if (k_ioctl->size != sizeof(struct cam_sync_signal))
445 return -EINVAL;
446
447 if (!k_ioctl->ioctl_ptr)
448 return -EINVAL;
449
450 if (copy_from_user(&sync_signal,
451 (void *)k_ioctl->ioctl_ptr,
452 k_ioctl->size))
453 return -EFAULT;
454
455 return cam_sync_signal(sync_signal.sync_obj,
456 sync_signal.sync_state);
457}
458
459static int cam_sync_handle_merge(struct cam_private_ioctl_arg *k_ioctl)
460{
461 struct cam_sync_merge sync_merge;
462 uint32_t *sync_objs;
463 uint32_t num_objs;
464 uint32_t size;
465 int result;
466
467 if (k_ioctl->size != sizeof(struct cam_sync_merge))
468 return -EINVAL;
469
470 if (!k_ioctl->ioctl_ptr)
471 return -EINVAL;
472
473 if (copy_from_user(&sync_merge,
474 (void *)k_ioctl->ioctl_ptr,
475 k_ioctl->size))
476 return -EFAULT;
477
478 if (sync_merge.num_objs >= CAM_SYNC_MAX_OBJS)
479 return -EINVAL;
480
481 size = sizeof(uint32_t) * sync_merge.num_objs;
482 sync_objs = kzalloc(size, GFP_ATOMIC);
483
484 if (!sync_objs)
485 return -ENOMEM;
486
487 if (copy_from_user(sync_objs,
488 (void *)sync_merge.sync_objs,
489 sizeof(uint32_t) * sync_merge.num_objs)) {
490 kfree(sync_objs);
491 return -EFAULT;
492 }
493
494 num_objs = sync_merge.num_objs;
495
496 result = cam_sync_merge(sync_objs,
497 num_objs,
498 &sync_merge.merged);
499
500 if (!result)
501 if (copy_to_user((void *)k_ioctl->ioctl_ptr,
502 &sync_merge,
503 k_ioctl->size)) {
504 kfree(sync_objs);
505 return -EFAULT;
506 }
507
508 kfree(sync_objs);
509
510 return result;
511}
512
513static int cam_sync_handle_wait(struct cam_private_ioctl_arg *k_ioctl)
514{
515 struct cam_sync_wait sync_wait;
516
517 if (k_ioctl->size != sizeof(struct cam_sync_wait))
518 return -EINVAL;
519
520 if (!k_ioctl->ioctl_ptr)
521 return -EINVAL;
522
523 if (copy_from_user(&sync_wait,
524 (void *)k_ioctl->ioctl_ptr,
525 k_ioctl->size))
526 return -EFAULT;
527
528 k_ioctl->result = cam_sync_wait(sync_wait.sync_obj,
529 sync_wait.timeout_ms);
530
531 return 0;
532}
533
534static int cam_sync_handle_destroy(struct cam_private_ioctl_arg *k_ioctl)
535{
536 struct cam_sync_info sync_create;
537
538 if (k_ioctl->size != sizeof(struct cam_sync_info))
539 return -EINVAL;
540
541 if (!k_ioctl->ioctl_ptr)
542 return -EINVAL;
543
544 if (copy_from_user(&sync_create,
545 (void *)k_ioctl->ioctl_ptr,
546 k_ioctl->size))
547 return -EFAULT;
548
549 return cam_sync_destroy(sync_create.sync_obj);
550}
551
552static int cam_sync_handle_register_user_payload(
553 struct cam_private_ioctl_arg *k_ioctl)
554{
555 struct cam_sync_userpayload_info userpayload_info;
556 struct sync_user_payload *user_payload_kernel;
557 struct sync_user_payload *user_payload_iter;
558 struct sync_user_payload *temp_upayload_kernel;
559 uint32_t sync_obj;
560 struct sync_table_row *row = NULL;
561
562 if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info))
563 return -EINVAL;
564
565 if (!k_ioctl->ioctl_ptr)
566 return -EINVAL;
567
568 if (copy_from_user(&userpayload_info,
569 (void *)k_ioctl->ioctl_ptr,
570 k_ioctl->size))
571 return -EFAULT;
572
573 sync_obj = userpayload_info.sync_obj;
574 if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
575 return -EINVAL;
576
577 user_payload_kernel = kzalloc(sizeof(*user_payload_kernel), GFP_KERNEL);
578 if (!user_payload_kernel)
579 return -ENOMEM;
580
581 memcpy(user_payload_kernel->payload_data,
582 userpayload_info.payload,
583 CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64));
584
585 spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
586 row = sync_dev->sync_table + sync_obj;
587
588 if (row->state == CAM_SYNC_STATE_INVALID) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700589 CAM_ERR(CAM_SYNC,
590 "Error: accessing an uninitialized sync obj = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800591 sync_obj);
592 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
593 kfree(user_payload_kernel);
594 return -EINVAL;
595 }
596
597 if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
598 row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
599
600 cam_sync_util_send_v4l2_event(CAM_SYNC_V4L_EVENT_ID_CB_TRIG,
601 sync_obj,
602 row->state,
603 user_payload_kernel->payload_data,
604 CAM_SYNC_USER_PAYLOAD_SIZE * sizeof(__u64));
605
606 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
607 kfree(user_payload_kernel);
608 return 0;
609 }
610
611 list_for_each_entry_safe(user_payload_iter,
612 temp_upayload_kernel,
613 &row->user_payload_list,
614 list) {
615 if (user_payload_iter->payload_data[0] ==
616 user_payload_kernel->payload_data[0] &&
617 user_payload_iter->payload_data[1] ==
618 user_payload_kernel->payload_data[1]) {
619
620 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
621 kfree(user_payload_kernel);
622 return -EALREADY;
623 }
624 }
625
626 list_add_tail(&user_payload_kernel->list, &row->user_payload_list);
627 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
628 return 0;
629}
630
631static int cam_sync_handle_deregister_user_payload(
632 struct cam_private_ioctl_arg *k_ioctl)
633{
634 struct cam_sync_userpayload_info userpayload_info;
635 struct sync_user_payload *user_payload_kernel, *temp;
636 uint32_t sync_obj;
637 struct sync_table_row *row = NULL;
638
639 if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info)) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700640 CAM_ERR(CAM_SYNC, "Incorrect ioctl size");
Seemanta Dutta49944562017-03-06 16:41:50 -0800641 return -EINVAL;
642 }
643
644 if (!k_ioctl->ioctl_ptr) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700645 CAM_ERR(CAM_SYNC, "Invalid embedded ioctl ptr");
Seemanta Dutta49944562017-03-06 16:41:50 -0800646 return -EINVAL;
647 }
648
649 if (copy_from_user(&userpayload_info,
650 (void *)k_ioctl->ioctl_ptr,
651 k_ioctl->size))
652 return -EFAULT;
653
654 sync_obj = userpayload_info.sync_obj;
655 if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
656 return -EINVAL;
657
658 spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
659 row = sync_dev->sync_table + sync_obj;
660
661 if (row->state == CAM_SYNC_STATE_INVALID) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700662 CAM_ERR(CAM_SYNC,
663 "Error: accessing an uninitialized sync obj = %d",
Seemanta Dutta49944562017-03-06 16:41:50 -0800664 sync_obj);
665 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
666 return -EINVAL;
667 }
668
669 list_for_each_entry_safe(user_payload_kernel, temp,
670 &row->user_payload_list, list) {
671 if (user_payload_kernel->payload_data[0] ==
672 userpayload_info.payload[0] &&
673 user_payload_kernel->payload_data[1] ==
674 userpayload_info.payload[1]) {
675 list_del_init(&user_payload_kernel->list);
676 kfree(user_payload_kernel);
677 }
678 }
679
680 spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
681 return 0;
682}
683
684static long cam_sync_dev_ioctl(struct file *filep, void *fh,
685 bool valid_prio, unsigned int cmd, void *arg)
686{
687 int32_t rc;
688 struct sync_device *sync_dev = video_drvdata(filep);
689 struct cam_private_ioctl_arg k_ioctl;
690
691 if (!sync_dev) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700692 CAM_ERR(CAM_SYNC, "sync_dev NULL");
Seemanta Dutta49944562017-03-06 16:41:50 -0800693 return -EINVAL;
694 }
695
696 if (!arg)
697 return -EINVAL;
698
699 if (cmd != CAM_PRIVATE_IOCTL_CMD)
700 return -ENOIOCTLCMD;
701
702 k_ioctl = *(struct cam_private_ioctl_arg *)arg;
703
704 switch (k_ioctl.id) {
705 case CAM_SYNC_CREATE:
706 rc = cam_sync_handle_create(&k_ioctl);
707 break;
708 case CAM_SYNC_DESTROY:
709 rc = cam_sync_handle_destroy(&k_ioctl);
710 break;
711 case CAM_SYNC_REGISTER_PAYLOAD:
712 rc = cam_sync_handle_register_user_payload(
713 &k_ioctl);
714 break;
715 case CAM_SYNC_DEREGISTER_PAYLOAD:
716 rc = cam_sync_handle_deregister_user_payload(
717 &k_ioctl);
718 break;
719 case CAM_SYNC_SIGNAL:
720 rc = cam_sync_handle_signal(&k_ioctl);
721 break;
722 case CAM_SYNC_MERGE:
723 rc = cam_sync_handle_merge(&k_ioctl);
724 break;
725 case CAM_SYNC_WAIT:
726 rc = cam_sync_handle_wait(&k_ioctl);
727 ((struct cam_private_ioctl_arg *)arg)->result =
728 k_ioctl.result;
729 break;
730 default:
731 rc = -ENOIOCTLCMD;
732 }
733
734 return rc;
735}
736
737static unsigned int cam_sync_poll(struct file *f,
738 struct poll_table_struct *pll_table)
739{
740 int rc = 0;
741 struct v4l2_fh *eventq = f->private_data;
742
743 if (!eventq)
744 return -EINVAL;
745
746 poll_wait(f, &eventq->wait, pll_table);
747
748 if (v4l2_event_pending(eventq))
749 rc = POLLPRI;
750
751 return rc;
752}
753
754static int cam_sync_open(struct file *filep)
755{
756 int rc;
757 struct sync_device *sync_dev = video_drvdata(filep);
758
759 if (!sync_dev) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700760 CAM_ERR(CAM_SYNC, "Sync device NULL");
Seemanta Dutta49944562017-03-06 16:41:50 -0800761 return -ENODEV;
762 }
763
764 mutex_lock(&sync_dev->table_lock);
765 if (sync_dev->open_cnt >= 1) {
766 mutex_unlock(&sync_dev->table_lock);
767 return -EALREADY;
768 }
769
770 rc = v4l2_fh_open(filep);
771 if (!rc) {
772 sync_dev->open_cnt++;
773 spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
774 sync_dev->cam_sync_eventq = filep->private_data;
775 spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
776 } else {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700777 CAM_ERR(CAM_SYNC, "v4l2_fh_open failed : %d", rc);
Seemanta Dutta49944562017-03-06 16:41:50 -0800778 }
779 mutex_unlock(&sync_dev->table_lock);
780
781 return rc;
782}
783
784static int cam_sync_close(struct file *filep)
785{
786 int rc = 0;
787 int i;
788 struct sync_device *sync_dev = video_drvdata(filep);
789
790 if (!sync_dev) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -0700791 CAM_ERR(CAM_SYNC, "Sync device NULL");
Seemanta Dutta49944562017-03-06 16:41:50 -0800792 rc = -ENODEV;
793 return rc;
794 }
795 mutex_lock(&sync_dev->table_lock);
796 sync_dev->open_cnt--;
797 if (!sync_dev->open_cnt) {
798 for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) {
799 struct sync_table_row *row =
800 sync_dev->sync_table + i;
Seemanta Dutta49944562017-03-06 16:41:50 -0800801
Seemanta Duttad9c78392017-08-09 15:19:37 -0700802 /*
803 * Signal all ACTIVE objects as ERR, but we don't
804 * care about the return status here apart from logging
805 * it.
Seemanta Dutta49944562017-03-06 16:41:50 -0800806 */
Seemanta Duttad9c78392017-08-09 15:19:37 -0700807 if (row->state == CAM_SYNC_STATE_ACTIVE) {
808 rc = cam_sync_signal(i,
809 CAM_SYNC_STATE_SIGNALED_ERROR);
810 if (rc < 0)
811 CAM_ERR(CAM_SYNC,
812 "Cleanup signal fail idx:%d\n",
813 i);
814 }
815 }
Seemanta Dutta49944562017-03-06 16:41:50 -0800816
Seemanta Duttad9c78392017-08-09 15:19:37 -0700817 /*
818 * Flush the work queue to wait for pending signal callbacks to
819 * finish
820 */
821 flush_workqueue(sync_dev->work_queue);
822
823 /*
824 * Now that all callbacks worker threads have finished,
825 * destroy the sync objects
826 */
827 for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) {
828 struct sync_table_row *row =
829 sync_dev->sync_table + i;
830
831 if (row->state != CAM_SYNC_STATE_INVALID) {
832 rc = cam_sync_destroy(i);
833 if (rc < 0)
834 CAM_ERR(CAM_SYNC,
835 "Cleanup destroy fail:idx:%d\n",
836 i);
837 }
Seemanta Dutta49944562017-03-06 16:41:50 -0800838 }
839 }
840 mutex_unlock(&sync_dev->table_lock);
841 spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
842 sync_dev->cam_sync_eventq = NULL;
843 spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
844 v4l2_fh_release(filep);
845
846 return rc;
847}
848
849int cam_sync_subscribe_event(struct v4l2_fh *fh,
850 const struct v4l2_event_subscription *sub)
851{
852 return v4l2_event_subscribe(fh, sub, CAM_SYNC_MAX_V4L2_EVENTS, NULL);
853}
854
855int cam_sync_unsubscribe_event(struct v4l2_fh *fh,
856 const struct v4l2_event_subscription *sub)
857{
858 return v4l2_event_unsubscribe(fh, sub);
859}
860
861static const struct v4l2_ioctl_ops g_cam_sync_ioctl_ops = {
862 .vidioc_subscribe_event = cam_sync_subscribe_event,
863 .vidioc_unsubscribe_event = cam_sync_unsubscribe_event,
864 .vidioc_default = cam_sync_dev_ioctl,
865};
866
867static struct v4l2_file_operations cam_sync_v4l2_fops = {
868 .owner = THIS_MODULE,
869 .open = cam_sync_open,
870 .release = cam_sync_close,
871 .poll = cam_sync_poll,
872 .unlocked_ioctl = video_ioctl2,
873#ifdef CONFIG_COMPAT
874 .compat_ioctl32 = video_ioctl2,
875#endif
876};
877
878#if defined(CONFIG_MEDIA_CONTROLLER)
879static int cam_sync_media_controller_init(struct sync_device *sync_dev,
880 struct platform_device *pdev)
881{
882 int rc;
883
884 sync_dev->v4l2_dev.mdev = kzalloc(sizeof(struct media_device),
885 GFP_KERNEL);
886 if (!sync_dev->v4l2_dev.mdev)
887 return -ENOMEM;
888
889 media_device_init(sync_dev->v4l2_dev.mdev);
890 strlcpy(sync_dev->v4l2_dev.mdev->model, CAM_SYNC_DEVICE_NAME,
891 sizeof(sync_dev->v4l2_dev.mdev->model));
892 sync_dev->v4l2_dev.mdev->dev = &(pdev->dev);
893
894 rc = media_device_register(sync_dev->v4l2_dev.mdev);
895 if (rc < 0)
896 goto register_fail;
897
898 rc = media_entity_pads_init(&sync_dev->vdev->entity, 0, NULL);
899 if (rc < 0)
900 goto entity_fail;
901
902 return 0;
903
904entity_fail:
905 media_device_unregister(sync_dev->v4l2_dev.mdev);
906register_fail:
907 media_device_cleanup(sync_dev->v4l2_dev.mdev);
908 return rc;
909}
910
911static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev)
912{
913 media_entity_cleanup(&sync_dev->vdev->entity);
914 media_device_unregister(sync_dev->v4l2_dev.mdev);
915 media_device_cleanup(sync_dev->v4l2_dev.mdev);
916 kfree(sync_dev->v4l2_dev.mdev);
917}
918
919static void cam_sync_init_entity(struct sync_device *sync_dev)
920{
921 sync_dev->vdev->entity.function = CAM_SYNC_DEVICE_TYPE;
922 sync_dev->vdev->entity.name =
923 video_device_node_name(sync_dev->vdev);
924}
925#else
926static int cam_sync_media_controller_init(struct sync_device *sync_dev,
927 struct platform_device *pdev)
928{
929 return 0;
930}
931
932static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev)
933{
934}
935
936static void cam_sync_init_entity(struct sync_device *sync_dev)
937{
938}
939#endif
940
941static int cam_sync_probe(struct platform_device *pdev)
942{
943 int rc;
944 int idx;
945
946 sync_dev = kzalloc(sizeof(*sync_dev), GFP_KERNEL);
947 if (!sync_dev)
948 return -ENOMEM;
949
950 mutex_init(&sync_dev->table_lock);
951 spin_lock_init(&sync_dev->cam_sync_eventq_lock);
952
953 for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++)
954 spin_lock_init(&sync_dev->row_spinlocks[idx]);
955
956 sync_dev->vdev = video_device_alloc();
957 if (!sync_dev->vdev) {
958 rc = -ENOMEM;
959 goto vdev_fail;
960 }
961
962 rc = cam_sync_media_controller_init(sync_dev, pdev);
963 if (rc < 0)
964 goto mcinit_fail;
965
966 sync_dev->vdev->v4l2_dev = &sync_dev->v4l2_dev;
967
968 rc = v4l2_device_register(&(pdev->dev), sync_dev->vdev->v4l2_dev);
969 if (rc < 0)
970 goto register_fail;
971
972 strlcpy(sync_dev->vdev->name, CAM_SYNC_NAME,
973 sizeof(sync_dev->vdev->name));
974 sync_dev->vdev->release = video_device_release;
975 sync_dev->vdev->fops = &cam_sync_v4l2_fops;
976 sync_dev->vdev->ioctl_ops = &g_cam_sync_ioctl_ops;
977 sync_dev->vdev->minor = -1;
978 sync_dev->vdev->vfl_type = VFL_TYPE_GRABBER;
979 rc = video_register_device(sync_dev->vdev,
980 VFL_TYPE_GRABBER, -1);
981 if (rc < 0)
982 goto v4l2_fail;
983
984 cam_sync_init_entity(sync_dev);
985 video_set_drvdata(sync_dev->vdev, sync_dev);
986 memset(&sync_dev->sync_table, 0, sizeof(sync_dev->sync_table));
987 memset(&sync_dev->bitmap, 0, sizeof(sync_dev->bitmap));
988 bitmap_zero(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
989
990 /*
991 * We treat zero as invalid handle, so we will keep the 0th bit set
992 * always
993 */
994 set_bit(0, sync_dev->bitmap);
995
996 sync_dev->work_queue = alloc_workqueue(CAM_SYNC_WORKQUEUE_NAME,
Seemanta Dutta25f140e2017-10-13 17:25:44 -0700997 WQ_HIGHPRI | WQ_UNBOUND, 1);
Seemanta Dutta49944562017-03-06 16:41:50 -0800998
999 if (!sync_dev->work_queue) {
Jigarkumar Zalaea7e56a2017-07-27 10:13:06 -07001000 CAM_ERR(CAM_SYNC,
1001 "Error: high priority work queue creation failed");
Seemanta Dutta49944562017-03-06 16:41:50 -08001002 rc = -ENOMEM;
1003 goto v4l2_fail;
1004 }
1005
1006 return rc;
1007
1008v4l2_fail:
1009 v4l2_device_unregister(sync_dev->vdev->v4l2_dev);
1010register_fail:
1011 cam_sync_media_controller_cleanup(sync_dev);
1012mcinit_fail:
1013 video_device_release(sync_dev->vdev);
1014vdev_fail:
1015 mutex_destroy(&sync_dev->table_lock);
1016 kfree(sync_dev);
1017 return rc;
1018}
1019
1020static int cam_sync_remove(struct platform_device *pdev)
1021{
1022 v4l2_device_unregister(sync_dev->vdev->v4l2_dev);
1023 cam_sync_media_controller_cleanup(sync_dev);
1024 video_device_release(sync_dev->vdev);
1025 kfree(sync_dev);
1026 sync_dev = NULL;
1027
1028 return 0;
1029}
1030
1031static struct platform_device cam_sync_device = {
1032 .name = "cam_sync",
1033 .id = -1,
1034};
1035
1036static struct platform_driver cam_sync_driver = {
1037 .probe = cam_sync_probe,
1038 .remove = cam_sync_remove,
1039 .driver = {
1040 .name = "cam_sync",
1041 .owner = THIS_MODULE,
1042 },
1043};
1044
1045static int __init cam_sync_init(void)
1046{
1047 int rc;
1048
1049 rc = platform_device_register(&cam_sync_device);
1050 if (rc)
1051 return -ENODEV;
1052
1053 return platform_driver_register(&cam_sync_driver);
1054}
1055
1056static void __exit cam_sync_exit(void)
1057{
1058 int idx;
1059
1060 for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++)
1061 spin_lock_init(&sync_dev->row_spinlocks[idx]);
1062 platform_driver_unregister(&cam_sync_driver);
1063 platform_device_unregister(&cam_sync_device);
1064 kfree(sync_dev);
1065}
1066
1067module_init(cam_sync_init);
1068module_exit(cam_sync_exit);
1069MODULE_DESCRIPTION("Camera sync driver");
1070MODULE_LICENSE("GPL v2");