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; |
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 |
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", |
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 |
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, |
297 "service_callback - service %lx(%d,%p), reason %d, header %lx, " |
298 "instance %lx, bulk_userdata %lx", 299 (unsigned long)user_service, |
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; |
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); |
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); |
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 |
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 |
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 |
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 --- |