Deleted Added
full compact
1/**
2 * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
3 * Copyright (c) 2010-2012 Broadcom. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer,
10 * without modification.

--- 87 unchanged lines hidden (view full) ---

98static void vchiq_proc_remove_instance(VCHIQ_INSTANCE_T instance);
99#endif
100
101
102typedef struct user_service_struct {
103 VCHIQ_SERVICE_T *service;
104 void *userdata;
105 VCHIQ_INSTANCE_T instance;
105 int is_vchi;
106 int dequeue_pending;
106 char is_vchi;
107 char dequeue_pending;
108 char close_pending;
109 int message_available_pos;
110 int msg_insert;
111 int msg_remove;
112 struct semaphore insert_event;
113 struct semaphore remove_event;
114 struct semaphore close_event;
115 VCHIQ_HEADER_T * msg_queue[MSG_QUEUE_SIZE];
116} USER_SERVICE_T;
117
118struct bulk_waiter_node {
119 struct bulk_waiter bulk_waiter;
120 int pid;
121 struct list_head list;
122};

--- 6 unchanged lines hidden (view full) ---

129 struct semaphore insert_event;
130 struct semaphore remove_event;
131 struct mutex completion_mutex;
132
133 int connected;
134 int closing;
135 int pid;
136 int mark;
137 int use_close_delivered;
138 int trace;
139
140 struct list_head bulk_waiter_list;
141 struct mutex bulk_waiter_list_mutex;
142
138 struct proc_dir_entry *proc_entry;
143#ifdef notyet
144 VCHIQ_DEBUGFS_NODE_T proc_entry;
145#endif
146};
147
148typedef struct dump_context_struct {
149 char __user *buf;
150 size_t actual;
151 size_t space;
152 loff_t offset;
153} DUMP_CONTEXT_T;

--- 13 unchanged lines hidden (view full) ---

167 "AWAIT_COMPLETION",
168 "DEQUEUE_MESSAGE",
169 "GET_CLIENT_ID",
170 "GET_CONFIG",
171 "CLOSE_SERVICE",
172 "USE_SERVICE",
173 "RELEASE_SERVICE",
174 "SET_SERVICE_OPTION",
168 "DUMP_PHYS_MEM"
175 "DUMP_PHYS_MEM",
176 "LIB_VERSION",
177 "CLOSE_DELIVERED"
178};
179
180vchiq_static_assert((sizeof(ioctl_names)/sizeof(ioctl_names[0])) ==
181 (VCHIQ_IOC_MAX + 1));
182
183static eventhandler_tag vchiq_ehtag = NULL;
184static d_open_t vchiq_open;
185static d_close_t vchiq_close;

--- 50 unchanged lines hidden (view full) ---

236 (MAX_COMPLETIONS - 1)];
237
238 completion->header = header;
239 completion->reason = reason;
240 /* N.B. service_userdata is updated while processing AWAIT_COMPLETION */
241 completion->service_userdata = user_service->service;
242 completion->bulk_userdata = bulk_userdata;
243
235 if (reason == VCHIQ_SERVICE_CLOSED)
244 if (reason == VCHIQ_SERVICE_CLOSED) {
245 /* Take an extra reference, to be held until
246 this CLOSED notification is delivered. */
247 lock_service(user_service->service);
248 if (instance->use_close_delivered)
249 user_service->close_pending = 1;
250 }
251
252 /* A write barrier is needed here to ensure that the entire completion
253 record is written out before the insert point. */
254 wmb();
255
256 if (reason == VCHIQ_MESSAGE_AVAILABLE)
257 user_service->message_available_pos =
258 instance->completion_insert;

--- 30 unchanged lines hidden (view full) ---

289 BUG_ON(!service);
290 user_service = (USER_SERVICE_T *)service->base.userdata;
291 instance = user_service->instance;
292
293 if (!instance || instance->closing)
294 return VCHIQ_SUCCESS;
295
296 vchiq_log_trace(vchiq_arm_log_level,
285 "service_callback - service %lx(%d), handle %x, reason %d, header %lx, "
297 "service_callback - service %lx(%d,%p), reason %d, header %lx, "
298 "instance %lx, bulk_userdata %lx",
299 (unsigned long)user_service,
288 service->localport, service->handle,
300 service->localport, user_service->userdata,
301 reason, (unsigned long)header,
302 (unsigned long)instance, (unsigned long)bulk_userdata);
303
304 if (header && user_service->is_vchi) {
305 spin_lock(&msg_queue_spinlock);
306 while (user_service->msg_insert ==
307 (user_service->msg_remove + MSG_QUEUE_SIZE)) {
308 spin_unlock(&msg_queue_spinlock);

--- 75 unchanged lines hidden (view full) ---

384 _sema_destroy(&user_service->insert_event);
385 _sema_destroy(&user_service->remove_event);
386
387 kfree(user_service);
388}
389
390/****************************************************************************
391*
392* close_delivered
393*
394***************************************************************************/
395static void close_delivered(USER_SERVICE_T *user_service)
396{
397 vchiq_log_info(vchiq_arm_log_level,
398 "close_delivered(handle=%x)",
399 user_service->service->handle);
400
401 if (user_service->close_pending) {
402 /* Allow the underlying service to be culled */
403 unlock_service(user_service->service);
404
405 /* Wake the user-thread blocked in close_ or remove_service */
406 up(&user_service->close_event);
407
408 user_service->close_pending = 0;
409 }
410}
411
412/****************************************************************************
413*
414* vchiq_ioctl
415*
416***************************************************************************/
417
418static int
419vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
420 struct thread *td)
421{

--- 103 unchanged lines hidden (view full) ---

525 instance->state,
526 &args.params, srvstate,
527 instance, user_service_free);
528
529 if (service != NULL) {
530 user_service->service = service;
531 user_service->userdata = userdata;
532 user_service->instance = instance;
499 user_service->is_vchi = args.is_vchi;
533 user_service->is_vchi = (args.is_vchi != 0);
534 user_service->dequeue_pending = 0;
535 user_service->close_pending = 0;
536 user_service->message_available_pos =
537 instance->completion_remove - 1;
538 user_service->msg_insert = 0;
539 user_service->msg_remove = 0;
540 _sema_init(&user_service->insert_event, 0);
541 _sema_init(&user_service->remove_event, 0);
542 _sema_init(&user_service->close_event, 0);
543
544 if (args.is_open) {
545 status = vchiq_open_service_internal
546 (service, instance->pid);
547 if (status != VCHIQ_SUCCESS) {
548 vchiq_remove_service(service->handle);
549 service = NULL;
550 ret = (status == VCHIQ_RETRY) ?

--- 23 unchanged lines hidden (view full) ---

574
575 memcpy(&handle, (const void*)arg, sizeof(handle));
576
577#ifdef VCHIQ_IOCTL_DEBUG
578 printf("%s: [CLOSE SERVICE] handle = %08x\n", __func__, handle);
579#endif
580
581 service = find_service_for_instance(instance, handle);
546 if (service != NULL)
547 status = vchiq_close_service(service->handle);
582 if (service != NULL) {
583 USER_SERVICE_T *user_service =
584 (USER_SERVICE_T *)service->base.userdata;
585 /* close_pending is false on first entry, and when the
586 wait in vchiq_close_service has been interrupted. */
587 if (!user_service->close_pending) {
588 status = vchiq_close_service(service->handle);
589 if (status != VCHIQ_SUCCESS)
590 break;
591 }
592
593 /* close_pending is true once the underlying service
594 has been closed until the client library calls the
595 CLOSE_DELIVERED ioctl, signalling close_event. */
596 if (user_service->close_pending &&
597 down_interruptible(&user_service->close_event))
598 status = VCHIQ_RETRY;
599 }
600 else
601 ret = -EINVAL;
602 } break;
603
604 case VCHIQ_IOC_REMOVE_SERVICE: {
605 VCHIQ_SERVICE_HANDLE_T handle;
606
607 memcpy(&handle, (const void*)arg, sizeof(handle));
608
609#ifdef VCHIQ_IOCTL_DEBUG
610 printf("%s: [REMOVE SERVICE] handle = %08x\n", __func__, handle);
611#endif
612
613 service = find_service_for_instance(instance, handle);
562 if (service != NULL)
563 status = vchiq_remove_service(service->handle);
614 if (service != NULL) {
615 USER_SERVICE_T *user_service =
616 (USER_SERVICE_T *)service->base.userdata;
617 /* close_pending is false on first entry, and when the
618 wait in vchiq_close_service has been interrupted. */
619 if (!user_service->close_pending) {
620 status = vchiq_remove_service(service->handle);
621 if (status != VCHIQ_SUCCESS)
622 break;
623 }
624
625 /* close_pending is true once the underlying service
626 has been closed until the client library calls the
627 CLOSE_DELIVERED ioctl, signalling close_event. */
628 if (user_service->close_pending &&
629 down_interruptible(&user_service->close_event))
630 status = VCHIQ_RETRY;
631 }
632 else
633 ret = -EINVAL;
634 } break;
635
636 case VCHIQ_IOC_USE_SERVICE:
637 case VCHIQ_IOC_RELEASE_SERVICE: {
638 VCHIQ_SERVICE_HANDLE_T handle;
639

--- 247 unchanged lines hidden (view full) ---

887 vchiq_release_message(service1->handle,
888 header);
889
890 /* The completion must point to the
891 ** msgbuf. */
892 completion->header = msgbuf;
893 }
894
827 if (completion->reason ==
828 VCHIQ_SERVICE_CLOSED)
895 if ((completion->reason ==
896 VCHIQ_SERVICE_CLOSED) &&
897 !instance->use_close_delivered)
898 unlock_service(service1);
899
900 if (copy_to_user((void __user *)(
901 (size_t)args.buf +
902 count * sizeof(VCHIQ_COMPLETION_DATA_T)),
903 completion,
904 sizeof(VCHIQ_COMPLETION_DATA_T)) != 0) {
905 if (ret == 0)

--- 165 unchanged lines hidden (view full) ---

1071
1072 memcpy(&args, (const void*)arg, sizeof(args));
1073 printf("IMPLEMENT ME: %s:%d\n", __FILE__, __LINE__);
1074#if 0
1075 dump_phys_mem(args.virt_addr, args.num_bytes);
1076#endif
1077 } break;
1078
1079 case VCHIQ_IOC_LIB_VERSION: {
1080 unsigned int lib_version = (unsigned int)arg;
1081
1082 if (lib_version < VCHIQ_VERSION_MIN)
1083 ret = -EINVAL;
1084 else if (lib_version >= VCHIQ_VERSION_CLOSE_DELIVERED)
1085 instance->use_close_delivered = 1;
1086 } break;
1087
1088 case VCHIQ_IOC_CLOSE_DELIVERED: {
1089 VCHIQ_SERVICE_HANDLE_T handle;
1090 memcpy(&handle, (const void*)arg, sizeof(handle));
1091
1092 service = find_closed_service_for_instance(instance, handle);
1093 if (service != NULL) {
1094 USER_SERVICE_T *user_service =
1095 (USER_SERVICE_T *)service->base.userdata;
1096 close_delivered(user_service);
1097 }
1098 else
1099 ret = -EINVAL;
1100 } break;
1101
1102 default:
1103 ret = -ENOTTY;
1104 break;
1105 }
1106
1107 if (service)
1108 unlock_service(service);
1109

--- 186 unchanged lines hidden (view full) ---

1296 instance->completion_insert) {
1297 VCHIQ_COMPLETION_DATA_T *completion;
1298 VCHIQ_SERVICE_T *service1;
1299 completion = &instance->completions[
1300 instance->completion_remove &
1301 (MAX_COMPLETIONS - 1)];
1302 service1 = completion->service_userdata;
1303 if (completion->reason == VCHIQ_SERVICE_CLOSED)
1304 {
1305 USER_SERVICE_T *user_service =
1306 service->base.userdata;
1307
1308 /* Wake any blocked user-thread */
1309 if (instance->use_close_delivered)
1310 up(&user_service->close_event);
1311 unlock_service(service1);
1312 }
1313 instance->completion_remove++;
1314 }
1315
1316 /* Release the PEER service count. */
1317 vchiq_release_internal(instance->state, NULL);
1318
1319 {
1320 struct list_head *pos, *next;

--- 478 unchanged lines hidden (view full) ---

1799** VC_RESUME_RESUMED - Resume has completed successfully. Videocore is running.
1800** Call complete_all on the resume completion to unblock
1801** any threads waiting for resume. Also reset the suspend
1802** state machine to it's idle state.
1803**
1804** VC_RESUME_FAILED - Currently unused - no mechanism to fail resume exists.
1805*/
1806
1707inline void
1807void
1808set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
1809 enum vc_suspend_status new_state)
1810{
1811 /* set the state in all cases */
1812 arm_state->vc_suspend_state = new_state;
1813
1814 /* state specific additional actions */
1815 switch (new_state) {

--- 4 unchanged lines hidden (view full) ---

1820 complete_all(&arm_state->vc_suspend_complete);
1821 break;
1822 case VC_SUSPEND_FAILED:
1823 complete_all(&arm_state->vc_suspend_complete);
1824 arm_state->vc_resume_state = VC_RESUME_RESUMED;
1825 complete_all(&arm_state->vc_resume_complete);
1826 break;
1827 case VC_SUSPEND_IDLE:
1828 /* TODO: reinit_completion */
1829 INIT_COMPLETION(arm_state->vc_suspend_complete);
1830 break;
1831 case VC_SUSPEND_REQUESTED:
1832 break;
1833 case VC_SUSPEND_IN_PROGRESS:
1834 set_resume_state(arm_state, VC_RESUME_IDLE);
1835 break;
1836 case VC_SUSPEND_SUSPENDED:
1837 complete_all(&arm_state->vc_suspend_complete);
1838 break;
1839 default:
1840 BUG();
1841 break;
1842 }
1843}
1844
1744inline void
1845void
1846set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
1847 enum vc_resume_status new_state)
1848{
1849 /* set the state in all cases */
1850 arm_state->vc_resume_state = new_state;
1851
1852 /* state specific additional actions */
1853 switch (new_state) {
1854 case VC_RESUME_FAILED:
1855 break;
1856 case VC_RESUME_IDLE:
1857 /* TODO: reinit_completion */
1858 INIT_COMPLETION(arm_state->vc_resume_complete);
1859 break;
1860 case VC_RESUME_REQUESTED:
1861 break;
1862 case VC_RESUME_IN_PROGRESS:
1863 break;
1864 case VC_RESUME_RESUMED:
1865 complete_all(&arm_state->vc_resume_complete);

--- 46 unchanged lines hidden (view full) ---

1912 int resume_count = 0;
1913
1914 /* Allow any threads which were blocked by the last force suspend to
1915 * complete if they haven't already. Only give this one shot; if
1916 * blocked_count is incremented after blocked_blocker is completed
1917 * (which only happens when blocked_count hits 0) then those threads
1918 * will have to wait until next time around */
1919 if (arm_state->blocked_count) {
1920 /* TODO: reinit_completion */
1921 INIT_COMPLETION(arm_state->blocked_blocker);
1922 write_unlock_bh(&arm_state->susp_res_lock);
1923 vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
1924 "blocked clients", __func__);
1925 if (wait_for_completion_interruptible_timeout(
1926 &arm_state->blocked_blocker, timeout_val)
1927 <= 0) {
1928 vchiq_log_error(vchiq_susp_log_level, "%s wait for "

--- 29 unchanged lines hidden (view full) ---

1958 status = VCHIQ_ERROR;
1959 write_lock_bh(&arm_state->susp_res_lock);
1960 goto out;
1961 }
1962 vchiq_log_info(vchiq_susp_log_level, "%s resumed", __func__);
1963 write_lock_bh(&arm_state->susp_res_lock);
1964 resume_count++;
1965 }
1966 /* TODO: reinit_completion */
1967 INIT_COMPLETION(arm_state->resume_blocker);
1968 arm_state->resume_blocked = 1;
1969
1970out:
1971 return status;
1972}
1973
1974static inline void

--- 939 unchanged lines hidden ---