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. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The names of the above-listed copyright holders may not be used 15 * to endorse or promote products derived from this software without 16 * specific prior written permission. 17 * 18 * ALTERNATIVELY, this software may be distributed under the terms of the 19 * GNU General Public License ("GPL") version 2, as published by the Free 20 * Software Foundation. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 23 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/file.h> 39 #include <sys/filedesc.h> 40 #include <sys/kmem.h> 41 42 #include "vchiq_core.h" 43 #include "vchiq_ioctl.h" 44 #include "vchiq_arm.h" 45 #include "vchiq_debugfs.h" 46 47 #define DEVICE_NAME "vchiq" 48 49 /* Override the default prefix, which would be vchiq_arm (from the filename) */ 50 #undef MODULE_PARAM_PREFIX 51 #define MODULE_PARAM_PREFIX DEVICE_NAME "." 52 53 #define VCHIQ_MINOR 0 54 55 /* Some per-instance constants */ 56 #define MAX_COMPLETIONS 128 57 #define MAX_SERVICES 64 58 #define MAX_ELEMENTS 8 59 #define MSG_QUEUE_SIZE 128 60 61 #define KEEPALIVE_VER 1 62 #define KEEPALIVE_VER_MIN KEEPALIVE_VER 63 64 MALLOC_DEFINE(M_VCHIQ, "vchiq_cdev", "VideoCore cdev memory"); 65 66 /* Run time control of log level, based on KERN_XXX level. */ 67 int vchiq_arm_log_level = VCHIQ_LOG_DEFAULT; 68 int vchiq_susp_log_level = VCHIQ_LOG_ERROR; 69 70 #define SUSPEND_TIMER_TIMEOUT_MS 100 71 #define SUSPEND_RETRY_TIMER_TIMEOUT_MS 1000 72 73 #define VC_SUSPEND_NUM_OFFSET 3 /* number of values before idle which are -ve */ 74 static const char *const suspend_state_names[] = { 75 "VC_SUSPEND_FORCE_CANCELED", 76 "VC_SUSPEND_REJECTED", 77 "VC_SUSPEND_FAILED", 78 "VC_SUSPEND_IDLE", 79 "VC_SUSPEND_REQUESTED", 80 "VC_SUSPEND_IN_PROGRESS", 81 "VC_SUSPEND_SUSPENDED" 82 }; 83 #define VC_RESUME_NUM_OFFSET 1 /* number of values before idle which are -ve */ 84 static const char *const resume_state_names[] = { 85 "VC_RESUME_FAILED", 86 "VC_RESUME_IDLE", 87 "VC_RESUME_REQUESTED", 88 "VC_RESUME_IN_PROGRESS", 89 "VC_RESUME_RESUMED" 90 }; 91 /* The number of times we allow force suspend to timeout before actually 92 ** _forcing_ suspend. This is to cater for SW which fails to release vchiq 93 ** correctly - we don't want to prevent ARM suspend indefinitely in this case. 94 */ 95 #define FORCE_SUSPEND_FAIL_MAX 8 96 97 /* The time in ms allowed for videocore to go idle when force suspend has been 98 * requested */ 99 #define FORCE_SUSPEND_TIMEOUT_MS 200 100 101 102 static void suspend_timer_callback(unsigned long context); 103 104 105 typedef struct user_service_struct { 106 VCHIQ_SERVICE_T *service; 107 void *userdata; 108 VCHIQ_INSTANCE_T instance; 109 char is_vchi; 110 char dequeue_pending; 111 char close_pending; 112 int message_available_pos; 113 int msg_insert; 114 int msg_remove; 115 struct semaphore insert_event; 116 struct semaphore remove_event; 117 struct semaphore close_event; 118 VCHIQ_HEADER_T * msg_queue[MSG_QUEUE_SIZE]; 119 } USER_SERVICE_T; 120 121 struct bulk_waiter_node { 122 struct bulk_waiter bulk_waiter; 123 int pid; 124 struct list_head list; 125 }; 126 127 struct vchiq_instance_struct { 128 VCHIQ_STATE_T *state; 129 VCHIQ_COMPLETION_DATA_T completions[MAX_COMPLETIONS]; 130 int completion_insert; 131 int completion_remove; 132 struct semaphore insert_event; 133 struct semaphore remove_event; 134 struct mutex completion_mutex; 135 136 int connected; 137 int closing; 138 int pid; 139 int mark; 140 int use_close_delivered; 141 int trace; 142 143 struct list_head bulk_waiter_list; 144 struct mutex bulk_waiter_list_mutex; 145 146 VCHIQ_DEBUGFS_NODE_T debugfs_node; 147 }; 148 149 typedef struct dump_context_struct { 150 char __user *buf; 151 size_t actual; 152 size_t space; 153 loff_t offset; 154 } DUMP_CONTEXT_T; 155 156 VCHIQ_STATE_T g_state; 157 static DEFINE_SPINLOCK(msg_queue_spinlock); 158 159 static const char *const ioctl_names[] = { 160 "CONNECT", 161 "SHUTDOWN", 162 "CREATE_SERVICE", 163 "REMOVE_SERVICE", 164 "QUEUE_MESSAGE", 165 "QUEUE_BULK_TRANSMIT", 166 "QUEUE_BULK_RECEIVE", 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 180 vchiq_static_assert((sizeof(ioctl_names)/sizeof(ioctl_names[0])) == 181 (VCHIQ_IOC_MAX + 1)); 182 183 static dev_type_open(vchiq_open); 184 185 struct cdevsw vchiq_cdevsw = { 186 .d_open = vchiq_open, 187 .d_close = noclose, 188 .d_read = noread, 189 .d_write = nowrite, 190 .d_ioctl = noioctl, 191 .d_stop = nostop, 192 .d_tty = notty, 193 .d_poll = nopoll, 194 .d_mmap = nommap, 195 .d_kqfilter = nokqfilter, 196 .d_discard = nodiscard, 197 .d_flag = D_OTHER | D_MPSAFE 198 }; 199 200 extern struct cfdriver vchiq_cd; 201 202 static int vchiq_ioctl(struct file *, u_long, void *); 203 static int vchiq_close(struct file *); 204 static int vchiq_read(struct file *, off_t *, struct uio *, kauth_cred_t, int); 205 206 static const struct fileops vchiq_fileops = { 207 .fo_name = "vchiq", 208 .fo_read = vchiq_read, 209 .fo_write = fbadop_write, 210 .fo_ioctl = vchiq_ioctl, 211 .fo_fcntl = fnullop_fcntl, 212 .fo_poll = fnullop_poll, 213 .fo_stat = fbadop_stat, 214 .fo_close = vchiq_close, 215 .fo_kqfilter = fnullop_kqfilter, 216 }; 217 218 #if 0 219 static void 220 dump_phys_mem(void *virt_addr, uint32_t num_bytes); 221 #endif 222 223 /**************************************************************************** 224 * 225 * add_completion 226 * 227 ***************************************************************************/ 228 229 static VCHIQ_STATUS_T 230 add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, 231 VCHIQ_HEADER_T *header, USER_SERVICE_T *user_service, 232 void *bulk_userdata) 233 { 234 VCHIQ_COMPLETION_DATA_T *completion; 235 int insert; 236 DEBUG_INITIALISE(g_state.local) 237 238 insert = instance->completion_insert; 239 while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) { 240 /* Out of space - wait for the client */ 241 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 242 vchiq_log_trace(vchiq_arm_log_level, 243 "add_completion - completion queue full"); 244 DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT); 245 246 if (down_interruptible(&instance->remove_event) != 0) { 247 vchiq_log_info(vchiq_arm_log_level, 248 "service_callback interrupted"); 249 return VCHIQ_RETRY; 250 } 251 252 if (instance->closing) { 253 vchiq_log_info(vchiq_arm_log_level, 254 "service_callback closing"); 255 return VCHIQ_SUCCESS; 256 } 257 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 258 } 259 260 completion = &instance->completions[insert & (MAX_COMPLETIONS - 1)]; 261 262 completion->header = header; 263 completion->reason = reason; 264 /* N.B. service_userdata is updated while processing AWAIT_COMPLETION */ 265 completion->service_userdata = user_service->service; 266 completion->bulk_userdata = bulk_userdata; 267 268 if (reason == VCHIQ_SERVICE_CLOSED) { 269 /* Take an extra reference, to be held until 270 this CLOSED notification is delivered. */ 271 lock_service(user_service->service); 272 if (instance->use_close_delivered) 273 user_service->close_pending = 1; 274 } 275 276 /* A write barrier is needed here to ensure that the entire completion 277 record is written out before the insert point. */ 278 wmb(); 279 280 if (reason == VCHIQ_MESSAGE_AVAILABLE) 281 user_service->message_available_pos = insert; 282 283 instance->completion_insert = ++insert; 284 285 up(&instance->insert_event); 286 287 return VCHIQ_SUCCESS; 288 } 289 290 /**************************************************************************** 291 * 292 * service_callback 293 * 294 ***************************************************************************/ 295 296 static VCHIQ_STATUS_T 297 service_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, 298 VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata) 299 { 300 /* How do we ensure the callback goes to the right client? 301 ** The service_user data points to a USER_SERVICE_T record containing 302 ** the original callback and the user state structure, which contains a 303 ** circular buffer for completion records. 304 */ 305 USER_SERVICE_T *user_service; 306 VCHIQ_SERVICE_T *service; 307 VCHIQ_INSTANCE_T instance; 308 int skip_completion = 0; 309 DEBUG_INITIALISE(g_state.local) 310 311 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 312 313 service = handle_to_service(handle); 314 BUG_ON(!service); 315 user_service = (USER_SERVICE_T *)service->base.userdata; 316 instance = user_service->instance; 317 318 if (!instance || instance->closing) 319 return VCHIQ_SUCCESS; 320 321 vchiq_log_trace(vchiq_arm_log_level, 322 "service_callback - service %lx(%d,%p), reason %d, header %lx, " 323 "instance %lx, bulk_userdata %lx", 324 (unsigned long)user_service, 325 service->localport, user_service->userdata, 326 reason, (unsigned long)header, 327 (unsigned long)instance, (unsigned long)bulk_userdata); 328 329 if (header && user_service->is_vchi) { 330 spin_lock(&msg_queue_spinlock); 331 while (user_service->msg_insert == 332 (user_service->msg_remove + MSG_QUEUE_SIZE)) { 333 spin_unlock(&msg_queue_spinlock); 334 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 335 DEBUG_COUNT(MSG_QUEUE_FULL_COUNT); 336 vchiq_log_trace(vchiq_arm_log_level, 337 "service_callback - msg queue full"); 338 /* If there is no MESSAGE_AVAILABLE in the completion 339 ** queue, add one 340 */ 341 if ((user_service->message_available_pos - 342 instance->completion_remove) < 0) { 343 VCHIQ_STATUS_T status; 344 vchiq_log_info(vchiq_arm_log_level, 345 "Inserting extra MESSAGE_AVAILABLE"); 346 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 347 status = add_completion(instance, reason, 348 NULL, user_service, bulk_userdata); 349 if (status != VCHIQ_SUCCESS) { 350 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 351 return status; 352 } 353 } 354 355 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 356 if (down_interruptible(&user_service->remove_event) 357 != 0) { 358 vchiq_log_info(vchiq_arm_log_level, 359 "service_callback interrupted"); 360 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 361 return VCHIQ_RETRY; 362 } else if (instance->closing) { 363 vchiq_log_info(vchiq_arm_log_level, 364 "service_callback closing"); 365 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 366 return VCHIQ_ERROR; 367 } 368 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 369 spin_lock(&msg_queue_spinlock); 370 } 371 372 user_service->msg_queue[user_service->msg_insert & 373 (MSG_QUEUE_SIZE - 1)] = header; 374 user_service->msg_insert++; 375 376 /* If there is a thread waiting in DEQUEUE_MESSAGE, or if 377 ** there is a MESSAGE_AVAILABLE in the completion queue then 378 ** bypass the completion queue. 379 */ 380 if (((user_service->message_available_pos - 381 instance->completion_remove) >= 0) || 382 user_service->dequeue_pending) { 383 user_service->dequeue_pending = 0; 384 skip_completion = 1; 385 } 386 387 spin_unlock(&msg_queue_spinlock); 388 389 up(&user_service->insert_event); 390 391 header = NULL; 392 } 393 394 if (skip_completion) { 395 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 396 return VCHIQ_SUCCESS; 397 } 398 399 DEBUG_TRACE(SERVICE_CALLBACK_LINE); 400 401 return add_completion(instance, reason, header, user_service, 402 bulk_userdata); 403 } 404 405 /**************************************************************************** 406 * 407 * user_service_free 408 * 409 ***************************************************************************/ 410 static void 411 user_service_free(void *userdata) 412 { 413 USER_SERVICE_T *user_service = userdata; 414 415 _sema_destroy(&user_service->insert_event); 416 _sema_destroy(&user_service->remove_event); 417 418 kfree(user_service); 419 } 420 421 /**************************************************************************** 422 * 423 * close_delivered 424 * 425 ***************************************************************************/ 426 static void close_delivered(USER_SERVICE_T *user_service) 427 { 428 vchiq_log_info(vchiq_arm_log_level, 429 "close_delivered(handle=%x)", 430 user_service->service->handle); 431 432 if (user_service->close_pending) { 433 /* Allow the underlying service to be culled */ 434 unlock_service(user_service->service); 435 436 /* Wake the user-thread blocked in close_ or remove_service */ 437 up(&user_service->close_event); 438 439 user_service->close_pending = 0; 440 } 441 } 442 443 struct vchiq_io_copy_callback_context { 444 VCHIQ_ELEMENT_T *current_element; 445 size_t current_element_offset; 446 unsigned long elements_to_go; 447 size_t current_offset; 448 }; 449 450 static ssize_t 451 vchiq_ioc_copy_element_data( 452 void *context, 453 void *dest, 454 size_t offset, 455 size_t maxsize) 456 { 457 long res; 458 size_t bytes_this_round; 459 struct vchiq_io_copy_callback_context *copy_context = 460 (struct vchiq_io_copy_callback_context *)context; 461 462 if (offset != copy_context->current_offset) 463 return 0; 464 465 if (!copy_context->elements_to_go) 466 return 0; 467 468 /* 469 * Complex logic here to handle the case of 0 size elements 470 * in the middle of the array of elements. 471 * 472 * Need to skip over these 0 size elements. 473 */ 474 while (1) { 475 bytes_this_round = min(copy_context->current_element->size - 476 copy_context->current_element_offset, 477 maxsize); 478 479 if (bytes_this_round) 480 break; 481 482 copy_context->elements_to_go--; 483 copy_context->current_element++; 484 copy_context->current_element_offset = 0; 485 486 if (!copy_context->elements_to_go) 487 return 0; 488 } 489 490 const uint8_t *src = copy_context->current_element->data; 491 src += copy_context->current_element_offset; 492 493 res = copy_from_user(dest, 494 src, 495 bytes_this_round); 496 497 if (res != 0) 498 return -EFAULT; 499 500 copy_context->current_element_offset += bytes_this_round; 501 copy_context->current_offset += bytes_this_round; 502 503 /* 504 * Check if done with current element, and if so advance to the next. 505 */ 506 if (copy_context->current_element_offset == 507 copy_context->current_element->size) { 508 copy_context->elements_to_go--; 509 copy_context->current_element++; 510 copy_context->current_element_offset = 0; 511 } 512 513 return bytes_this_round; 514 } 515 516 /************************************************************************** 517 * 518 * vchiq_ioc_queue_message 519 * 520 **************************************************************************/ 521 static VCHIQ_STATUS_T 522 vchiq_ioc_queue_message(VCHIQ_SERVICE_HANDLE_T handle, 523 VCHIQ_ELEMENT_T *elements, 524 unsigned long count) 525 { 526 struct vchiq_io_copy_callback_context context; 527 unsigned long i; 528 size_t total_size = 0; 529 530 context.current_element = elements; 531 context.current_element_offset = 0; 532 context.elements_to_go = count; 533 context.current_offset = 0; 534 535 for (i = 0; i < count; i++) { 536 if (!elements[i].data && elements[i].size != 0) 537 return -EFAULT; 538 539 total_size += elements[i].size; 540 } 541 542 return vchiq_queue_message(handle, vchiq_ioc_copy_element_data, 543 &context, total_size); 544 } 545 546 /**************************************************************************** 547 * 548 * vchiq_ioctl 549 * 550 ***************************************************************************/ 551 552 static int 553 vchiq_ioctl(struct file *fp, u_long cmd, void *arg) 554 { 555 VCHIQ_INSTANCE_T instance = fp->f_data; 556 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 557 VCHIQ_SERVICE_T *service = NULL; 558 int ret = 0; 559 int i, rc; 560 DEBUG_INITIALISE(g_state.local) 561 562 /* XXXBSD: HACK! */ 563 #define _IOC_NR(x) ((x) & 0xff) 564 #define _IOC_TYPE(x) IOCGROUP(x) 565 566 vchiq_log_trace(vchiq_arm_log_level, 567 "vchiq_ioctl - instance %p, cmd %s, arg %p", 568 instance, 569 ((_IOC_TYPE(cmd) == VCHIQ_IOC_MAGIC) && 570 (_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ? 571 ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg); 572 573 switch (cmd) { 574 case VCHIQ_IOC_SHUTDOWN: 575 if (!instance->connected) 576 break; 577 578 /* Remove all services */ 579 i = 0; 580 while ((service = next_service_by_instance(instance->state, 581 instance, &i)) != NULL) { 582 status = vchiq_remove_service(service->handle); 583 unlock_service(service); 584 if (status != VCHIQ_SUCCESS) 585 break; 586 } 587 service = NULL; 588 589 if (status == VCHIQ_SUCCESS) { 590 /* Wake the completion thread and ask it to exit */ 591 instance->closing = 1; 592 up(&instance->insert_event); 593 } 594 595 break; 596 597 case VCHIQ_IOC_CONNECT: 598 if (instance->connected) { 599 ret = -EINVAL; 600 break; 601 } 602 rc = lmutex_lock_interruptible(&instance->state->mutex); 603 if (rc != 0) { 604 vchiq_log_error(vchiq_arm_log_level, 605 "vchiq: connect: could not lock mutex for " 606 "state %d: %d", 607 instance->state->id, rc); 608 ret = -EINTR; 609 break; 610 } 611 status = vchiq_connect_internal(instance->state, instance); 612 lmutex_unlock(&instance->state->mutex); 613 614 if (status == VCHIQ_SUCCESS) 615 instance->connected = 1; 616 else 617 vchiq_log_error(vchiq_arm_log_level, 618 "vchiq: could not connect: %d", status); 619 break; 620 621 case VCHIQ_IOC_CREATE_SERVICE: { 622 VCHIQ_CREATE_SERVICE_T *pargs = arg; 623 VCHIQ_CREATE_SERVICE_T args = *pargs; 624 USER_SERVICE_T *user_service = NULL; 625 void *userdata; 626 int srvstate; 627 628 /* XXXNH kmalloc */ 629 user_service = kzalloc(sizeof(USER_SERVICE_T), GFP_KERNEL); 630 if (!user_service) { 631 ret = -ENOMEM; 632 break; 633 } 634 635 if (args.is_open) { 636 if (!instance->connected) { 637 ret = -ENOTCONN; 638 kfree(user_service); 639 break; 640 } 641 srvstate = VCHIQ_SRVSTATE_OPENING; 642 } else { 643 srvstate = 644 instance->connected ? 645 VCHIQ_SRVSTATE_LISTENING : 646 VCHIQ_SRVSTATE_HIDDEN; 647 } 648 649 userdata = args.params.userdata; 650 pargs->params.callback = service_callback; 651 pargs->params.userdata = user_service; 652 args.params.callback = service_callback; 653 args.params.userdata = user_service; 654 service = vchiq_add_service_internal( 655 instance->state, 656 &pargs->params, srvstate, 657 instance, user_service_free); 658 659 if (service != NULL) { 660 user_service->service = service; 661 user_service->userdata = userdata; 662 user_service->instance = instance; 663 user_service->is_vchi = (args.is_vchi != 0); 664 user_service->dequeue_pending = 0; 665 user_service->close_pending = 0; 666 user_service->message_available_pos = 667 instance->completion_remove - 1; 668 user_service->msg_insert = 0; 669 user_service->msg_remove = 0; 670 _sema_init(&user_service->insert_event, 0); 671 _sema_init(&user_service->remove_event, 0); 672 _sema_init(&user_service->close_event, 0); 673 674 if (args.is_open) { 675 status = vchiq_open_service_internal 676 (service, instance->pid); 677 if (status != VCHIQ_SUCCESS) { 678 vchiq_remove_service(service->handle); 679 service = NULL; 680 ret = (status == VCHIQ_RETRY) ? 681 -EINTR : -EIO; 682 break; 683 } 684 } 685 686 #ifdef VCHIQ_IOCTL_DEBUG 687 printf("%s: [CREATE SERVICE] handle = %08x\n", __func__, service->handle); 688 #endif 689 pargs->handle = service->handle; 690 691 service = NULL; 692 } else { 693 ret = -EEXIST; 694 kfree(user_service); 695 } 696 } break; 697 698 case VCHIQ_IOC_CLOSE_SERVICE: { 699 VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg; 700 701 #ifdef VCHIQ_IOCTL_DEBUG 702 printf("%s: [CLOSE SERVICE] handle = %08x\n", __func__, handle); 703 #endif 704 705 service = find_service_for_instance(instance, handle); 706 if (service != NULL) { 707 USER_SERVICE_T *user_service = 708 (USER_SERVICE_T *)service->base.userdata; 709 /* close_pending is false on first entry, and when the 710 wait in vchiq_close_service has been interrupted. */ 711 if (!user_service->close_pending) { 712 status = vchiq_close_service(service->handle); 713 if (status != VCHIQ_SUCCESS) 714 break; 715 } 716 717 /* close_pending is true once the underlying service 718 has been closed until the client library calls the 719 CLOSE_DELIVERED ioctl, signalling close_event. */ 720 if (user_service->close_pending && 721 down_interruptible(&user_service->close_event)) 722 status = VCHIQ_RETRY; 723 } 724 else 725 ret = -EINVAL; 726 } break; 727 728 case VCHIQ_IOC_REMOVE_SERVICE: { 729 VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg; 730 731 #ifdef VCHIQ_IOCTL_DEBUG 732 printf("%s: [REMOVE SERVICE] handle = %08x\n", __func__, handle); 733 #endif 734 735 service = find_service_for_instance(instance, handle); 736 if (service != NULL) { 737 USER_SERVICE_T *user_service = 738 (USER_SERVICE_T *)service->base.userdata; 739 /* close_pending is false on first entry, and when the 740 wait in vchiq_close_service has been interrupted. */ 741 if (!user_service->close_pending) { 742 status = vchiq_remove_service(service->handle); 743 if (status != VCHIQ_SUCCESS) 744 break; 745 } 746 747 /* close_pending is true once the underlying service 748 has been closed until the client library calls the 749 CLOSE_DELIVERED ioctl, signalling close_event. */ 750 if (user_service->close_pending && 751 down_interruptible(&user_service->close_event)) 752 status = VCHIQ_RETRY; 753 } 754 else 755 ret = -EINVAL; 756 } break; 757 758 case VCHIQ_IOC_USE_SERVICE: 759 case VCHIQ_IOC_RELEASE_SERVICE: { 760 VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg; 761 762 #ifdef VCHIQ_IOCTL_DEBUG 763 printf("%s: [%s SERVICE] handle = %08x\n", __func__, 764 cmd == VCHIQ_IOC_USE_SERVICE ? "USE" : "RELEASE", handle); 765 #endif 766 767 service = find_service_for_instance(instance, handle); 768 if (service != NULL) { 769 status = (cmd == VCHIQ_IOC_USE_SERVICE) ? 770 vchiq_use_service_internal(service) : 771 vchiq_release_service_internal(service); 772 if (status != VCHIQ_SUCCESS) { 773 vchiq_log_error(vchiq_susp_log_level, 774 "%s: cmd %s returned error %d for " 775 "service %c%c%c%c:%8x", 776 __func__, 777 (cmd == VCHIQ_IOC_USE_SERVICE) ? 778 "VCHIQ_IOC_USE_SERVICE" : 779 "VCHIQ_IOC_RELEASE_SERVICE", 780 status, 781 VCHIQ_FOURCC_AS_4CHARS( 782 service->base.fourcc), 783 service->client_id); 784 ret = -EINVAL; 785 } 786 } else 787 ret = -EINVAL; 788 } break; 789 790 case VCHIQ_IOC_QUEUE_MESSAGE: { 791 VCHIQ_QUEUE_MESSAGE_T *pargs = arg; 792 VCHIQ_QUEUE_MESSAGE_T args = *pargs; 793 794 #ifdef VCHIQ_IOCTL_DEBUG 795 printf("%s: [QUEUE MESSAGE] handle = %08x\n", __func__, args.handle); 796 #endif 797 798 service = find_service_for_instance(instance, args.handle); 799 800 if ((service != NULL) && (args.count <= MAX_ELEMENTS)) { 801 /* Copy elements into kernel space */ 802 VCHIQ_ELEMENT_T elements[MAX_ELEMENTS]; 803 if (copy_from_user(elements, args.elements, 804 args.count * sizeof(VCHIQ_ELEMENT_T)) == 0) 805 status = vchiq_ioc_queue_message 806 (args.handle, 807 elements, args.count); 808 else 809 ret = -EFAULT; 810 } else { 811 ret = -EINVAL; 812 } 813 } break; 814 815 case VCHIQ_IOC_QUEUE_BULK_TRANSMIT: 816 case VCHIQ_IOC_QUEUE_BULK_RECEIVE: { 817 VCHIQ_QUEUE_BULK_TRANSFER_T *pargs = arg; 818 VCHIQ_QUEUE_BULK_TRANSFER_T args = *pargs; 819 struct bulk_waiter_node *waiter = NULL; 820 VCHIQ_BULK_DIR_T dir = 821 (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ? 822 VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE; 823 824 service = find_service_for_instance(instance, args.handle); 825 if (!service) { 826 ret = -EINVAL; 827 break; 828 } 829 830 if (args.mode == VCHIQ_BULK_MODE_BLOCKING) { 831 waiter = kzalloc(sizeof(struct bulk_waiter_node), 832 GFP_KERNEL); 833 if (!waiter) { 834 ret = -ENOMEM; 835 break; 836 } 837 args.userdata = &waiter->bulk_waiter; 838 } else if (args.mode == VCHIQ_BULK_MODE_WAITING) { 839 struct list_head *pos; 840 lmutex_lock(&instance->bulk_waiter_list_mutex); 841 list_for_each(pos, &instance->bulk_waiter_list) { 842 if (list_entry(pos, struct bulk_waiter_node, 843 list)->pid == current->l_proc->p_pid) { 844 waiter = list_entry(pos, 845 struct bulk_waiter_node, 846 list); 847 list_del(pos); 848 break; 849 } 850 851 } 852 lmutex_unlock(&instance->bulk_waiter_list_mutex); 853 if (!waiter) { 854 vchiq_log_error(vchiq_arm_log_level, 855 "no bulk_waiter found for pid %d", 856 current->l_proc->p_pid); 857 ret = -ESRCH; 858 break; 859 } 860 vchiq_log_info(vchiq_arm_log_level, 861 "found bulk_waiter %p for pid %d", 862 waiter, current->l_proc->p_pid); 863 args.userdata = &waiter->bulk_waiter; 864 } 865 status = vchiq_bulk_transfer 866 (args.handle, 867 VCHI_MEM_HANDLE_INVALID, 868 args.data, args.size, 869 args.userdata, args.mode, 870 dir); 871 if (!waiter) 872 break; 873 if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || 874 !waiter->bulk_waiter.bulk) { 875 if (waiter->bulk_waiter.bulk) { 876 /* Cancel the signal when the transfer 877 ** completes. */ 878 spin_lock(&bulk_waiter_spinlock); 879 waiter->bulk_waiter.bulk->userdata = NULL; 880 spin_unlock(&bulk_waiter_spinlock); 881 } 882 _sema_destroy(&waiter->bulk_waiter.event); 883 kfree(waiter); 884 } else { 885 const VCHIQ_BULK_MODE_T mode_waiting = 886 VCHIQ_BULK_MODE_WAITING; 887 waiter->pid = current->l_proc->p_pid; 888 lmutex_lock(&instance->bulk_waiter_list_mutex); 889 list_add(&waiter->list, &instance->bulk_waiter_list); 890 lmutex_unlock(&instance->bulk_waiter_list_mutex); 891 vchiq_log_info(vchiq_arm_log_level, 892 "saved bulk_waiter %p for pid %d", 893 waiter, current->l_proc->p_pid); 894 895 pargs->mode = mode_waiting; 896 } 897 } break; 898 899 case VCHIQ_IOC_AWAIT_COMPLETION: { 900 VCHIQ_AWAIT_COMPLETION_T *pargs = arg; 901 VCHIQ_AWAIT_COMPLETION_T args = *pargs; 902 int count = 0; 903 904 DEBUG_TRACE(AWAIT_COMPLETION_LINE); 905 if (!instance->connected) { 906 ret = -ENOTCONN; 907 break; 908 } 909 910 lmutex_lock(&instance->completion_mutex); 911 912 DEBUG_TRACE(AWAIT_COMPLETION_LINE); 913 while ((instance->completion_remove == 914 instance->completion_insert) 915 && !instance->closing) { 916 DEBUG_TRACE(AWAIT_COMPLETION_LINE); 917 lmutex_unlock(&instance->completion_mutex); 918 rc = down_interruptible(&instance->insert_event); 919 lmutex_lock(&instance->completion_mutex); 920 if (rc != 0) { 921 DEBUG_TRACE(AWAIT_COMPLETION_LINE); 922 vchiq_log_info(vchiq_arm_log_level, 923 "AWAIT_COMPLETION interrupted"); 924 ret = -EINTR; 925 break; 926 } 927 } 928 DEBUG_TRACE(AWAIT_COMPLETION_LINE); 929 930 if (ret == 0) { 931 int msgbufcount = args.msgbufcount; 932 int remove; 933 934 remove = instance->completion_remove; 935 936 for (count = 0; count < args.count; count++) { 937 VCHIQ_COMPLETION_DATA_T *completion; 938 VCHIQ_SERVICE_T *service1; 939 USER_SERVICE_T *user_service; 940 VCHIQ_HEADER_T *header; 941 942 if (remove == instance->completion_insert) 943 break; 944 945 completion = &instance->completions[ 946 remove & (MAX_COMPLETIONS - 1)]; 947 948 /* A read memory barrier is needed to prevent 949 ** the prefetch of a stale completion record 950 */ 951 rmb(); 952 953 954 service1 = completion->service_userdata; 955 user_service = service1->base.userdata; 956 completion->service_userdata = 957 user_service->userdata; 958 959 header = completion->header; 960 if (header) { 961 void __user *msgbuf; 962 int msglen; 963 964 msglen = header->size + 965 sizeof(VCHIQ_HEADER_T); 966 /* This must be a VCHIQ-style service */ 967 if (args.msgbufsize < msglen) { 968 vchiq_log_error( 969 vchiq_arm_log_level, 970 "header %p: msgbufsize" 971 " %x < msglen %x", 972 header, 973 args.msgbufsize, 974 msglen); 975 WARN(1, "invalid message " 976 "size\n"); 977 if (count == 0) 978 ret = -EMSGSIZE; 979 break; 980 } 981 if (msgbufcount <= 0) 982 /* Stall here for lack of a 983 ** buffer for the message. */ 984 break; 985 /* Get the pointer from user space */ 986 msgbufcount--; 987 if (copy_from_user(&msgbuf, 988 (const void __user *) 989 &args.msgbufs[msgbufcount], 990 sizeof(msgbuf)) != 0) { 991 if (count == 0) 992 ret = -EFAULT; 993 break; 994 } 995 996 /* Copy the message to user space */ 997 if (copy_to_user(msgbuf, header, 998 msglen) != 0) { 999 if (count == 0) 1000 ret = -EFAULT; 1001 break; 1002 } 1003 1004 /* Now it has been copied, the message 1005 ** can be released. */ 1006 vchiq_release_message(service1->handle, 1007 header); 1008 1009 /* The completion must point to the 1010 ** msgbuf. */ 1011 completion->header = msgbuf; 1012 } 1013 1014 if ((completion->reason == 1015 VCHIQ_SERVICE_CLOSED) && 1016 !instance->use_close_delivered) 1017 unlock_service(service1); 1018 1019 if (copy_to_user((void __user *)( 1020 (size_t)args.buf + 1021 count * sizeof(VCHIQ_COMPLETION_DATA_T)), 1022 completion, 1023 sizeof(VCHIQ_COMPLETION_DATA_T)) != 0) { 1024 if (count == 0) 1025 ret = -EFAULT; 1026 break; 1027 } 1028 1029 /* Ensure that the above copy has completed 1030 ** before advancing the remove pointer. */ 1031 mb(); 1032 1033 instance->completion_remove = ++remove; 1034 } 1035 1036 pargs->msgbufcount = msgbufcount; 1037 pargs->count = count; 1038 } 1039 if (count != 0) 1040 up(&instance->remove_event); 1041 1042 lmutex_unlock(&instance->completion_mutex); 1043 DEBUG_TRACE(AWAIT_COMPLETION_LINE); 1044 } break; 1045 1046 case VCHIQ_IOC_DEQUEUE_MESSAGE: { 1047 VCHIQ_DEQUEUE_MESSAGE_T *pargs = arg; 1048 VCHIQ_DEQUEUE_MESSAGE_T args = *pargs; 1049 USER_SERVICE_T *user_service; 1050 VCHIQ_HEADER_T *header; 1051 1052 DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); 1053 service = find_service_for_instance(instance, args.handle); 1054 if (!service) { 1055 ret = -EINVAL; 1056 break; 1057 } 1058 user_service = (USER_SERVICE_T *)service->base.userdata; 1059 if (user_service->is_vchi == 0) { 1060 ret = -EINVAL; 1061 break; 1062 } 1063 1064 spin_lock(&msg_queue_spinlock); 1065 if (user_service->msg_remove == user_service->msg_insert) { 1066 if (!args.blocking) { 1067 spin_unlock(&msg_queue_spinlock); 1068 DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); 1069 ret = -EWOULDBLOCK; 1070 break; 1071 } 1072 user_service->dequeue_pending = 1; 1073 do { 1074 spin_unlock(&msg_queue_spinlock); 1075 DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); 1076 if (down_interruptible( 1077 &user_service->insert_event) != 0) { 1078 vchiq_log_info(vchiq_arm_log_level, 1079 "DEQUEUE_MESSAGE interrupted"); 1080 ret = -EINTR; 1081 break; 1082 } 1083 spin_lock(&msg_queue_spinlock); 1084 } while (user_service->msg_remove == 1085 user_service->msg_insert); 1086 1087 if (ret) 1088 break; 1089 } 1090 1091 BUG_ON((int)(user_service->msg_insert - 1092 user_service->msg_remove) < 0); 1093 1094 header = user_service->msg_queue[user_service->msg_remove & 1095 (MSG_QUEUE_SIZE - 1)]; 1096 user_service->msg_remove++; 1097 spin_unlock(&msg_queue_spinlock); 1098 1099 up(&user_service->remove_event); 1100 if (header == NULL) 1101 ret = -ENOTCONN; 1102 else if (header->size <= args.bufsize) { 1103 /* Copy to user space if msgbuf is not NULL */ 1104 if ((args.buf == NULL) || 1105 (copy_to_user((void __user *)args.buf, 1106 header->data, 1107 header->size) == 0)) { 1108 pargs->bufsize = header->size; 1109 vchiq_release_message( 1110 service->handle, 1111 header); 1112 } else 1113 ret = -EFAULT; 1114 } else { 1115 vchiq_log_error(vchiq_arm_log_level, 1116 "header %p: bufsize %x < size %x", 1117 header, args.bufsize, 1118 header->size); 1119 WARN(1, "invalid size\n"); 1120 ret = -EMSGSIZE; 1121 } 1122 DEBUG_TRACE(DEQUEUE_MESSAGE_LINE); 1123 } break; 1124 1125 case VCHIQ_IOC_GET_CLIENT_ID: { 1126 VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg; 1127 1128 ret = vchiq_get_client_id(handle); 1129 } break; 1130 1131 case VCHIQ_IOC_GET_CONFIG: { 1132 VCHIQ_GET_CONFIG_T *pargs = arg; 1133 VCHIQ_GET_CONFIG_T args = *pargs; 1134 VCHIQ_CONFIG_T config; 1135 1136 if (args.config_size > sizeof(config)) { 1137 ret = -EINVAL; 1138 break; 1139 } 1140 status = vchiq_get_config(instance, args.config_size, &config); 1141 if (status == VCHIQ_SUCCESS) { 1142 if (copy_to_user((void __user *)args.pconfig, 1143 &config, args.config_size) != 0) { 1144 ret = -EFAULT; 1145 break; 1146 } 1147 } 1148 } break; 1149 1150 case VCHIQ_IOC_SET_SERVICE_OPTION: { 1151 VCHIQ_SET_SERVICE_OPTION_T *pargs = arg; 1152 VCHIQ_SET_SERVICE_OPTION_T args = *pargs; 1153 1154 service = find_service_for_instance(instance, args.handle); 1155 if (!service) { 1156 ret = -EINVAL; 1157 break; 1158 } 1159 1160 status = vchiq_set_service_option( 1161 args.handle, args.option, args.value); 1162 } break; 1163 1164 case VCHIQ_IOC_DUMP_PHYS_MEM: { 1165 #if 0 1166 VCHIQ_DUMP_MEM_T *pargs = arg; 1167 #endif 1168 1169 printf("IMPLEMENT ME: %s:%d\n", __FILE__, __LINE__); 1170 #if 0 1171 dump_phys_mem(pargs->virt_addr, pargs->num_bytes); 1172 #endif 1173 } break; 1174 1175 case VCHIQ_IOC_LIB_VERSION: { 1176 unsigned int lib_version = (uintptr_t)arg; 1177 1178 if (lib_version < VCHIQ_VERSION_MIN) 1179 ret = -EINVAL; 1180 else if (lib_version >= VCHIQ_VERSION_CLOSE_DELIVERED) 1181 instance->use_close_delivered = 1; 1182 } break; 1183 1184 case VCHIQ_IOC_CLOSE_DELIVERED: { 1185 VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg; 1186 1187 service = find_closed_service_for_instance(instance, handle); 1188 if (service != NULL) { 1189 USER_SERVICE_T *user_service = 1190 (USER_SERVICE_T *)service->base.userdata; 1191 close_delivered(user_service); 1192 } 1193 else 1194 ret = -EINVAL; 1195 } break; 1196 1197 default: 1198 ret = -ENOTTY; 1199 break; 1200 } 1201 1202 if (service) 1203 unlock_service(service); 1204 1205 if (ret == 0) { 1206 if (status == VCHIQ_ERROR) 1207 ret = -EIO; 1208 else if (status == VCHIQ_RETRY) 1209 ret = -EINTR; 1210 } 1211 1212 if ((status == VCHIQ_SUCCESS) && (ret < 0) && (ret != -EINTR) && 1213 (ret != -EWOULDBLOCK)) 1214 vchiq_log_info(vchiq_arm_log_level, 1215 " ioctl instance %lx, cmd %s -> status %d, %d", 1216 (unsigned long)instance, 1217 (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ? 1218 ioctl_names[_IOC_NR(cmd)] : 1219 "<invalid>", 1220 status, ret); 1221 else 1222 vchiq_log_trace(vchiq_arm_log_level, 1223 " ioctl instance %lx, cmd %s -> status %d, %d", 1224 (unsigned long)instance, 1225 (_IOC_NR(cmd) <= VCHIQ_IOC_MAX) ? 1226 ioctl_names[_IOC_NR(cmd)] : 1227 "<invalid>", 1228 status, ret); 1229 1230 /* XXXBSD: report BSD-style error to userland */ 1231 if (ret < 0) 1232 ret = -ret; 1233 1234 return ret; 1235 } 1236 1237 /**************************************************************************** 1238 * 1239 * vchiq_open 1240 * 1241 ***************************************************************************/ 1242 1243 static int 1244 vchiq_open(dev_t dev, int flags, int mode, lwp_t *l) 1245 { 1246 VCHIQ_INSTANCE_T instance = NULL; 1247 struct file *fp; 1248 int err, fd; 1249 1250 vchiq_log_info(vchiq_arm_log_level, "vchiq_open"); 1251 1252 /* XXXBSD: do we really need this check? */ 1253 if (device_lookup_private(&vchiq_cd, minor(dev)) != NULL) { 1254 VCHIQ_STATE_T *state; 1255 int i; 1256 1257 for (i=0; i<10; ++i) { 1258 state = vchiq_get_state(); 1259 if (state) 1260 break; 1261 delay(500); 1262 } 1263 1264 if (!state) { 1265 vchiq_log_error(vchiq_arm_log_level, 1266 "vchiq has no connection to VideoCore"); 1267 return -ENOTCONN; 1268 } 1269 1270 instance = kzalloc(sizeof(*instance), GFP_KERNEL); 1271 if (!instance) 1272 return -ENOMEM; 1273 1274 err = fd_allocfile(&fp, &fd); 1275 if (err) { 1276 kfree(instance); 1277 return -err; 1278 } 1279 1280 instance->state = state; 1281 instance->pid = current->l_proc->p_pid; 1282 1283 #ifdef notyet 1284 ret = vchiq_debugfs_add_instance(instance); 1285 if (ret != 0) { 1286 kfree(instance); 1287 return ret; 1288 } 1289 #endif 1290 1291 _sema_init(&instance->insert_event, 0); 1292 _sema_init(&instance->remove_event, 0); 1293 lmutex_init(&instance->completion_mutex); 1294 lmutex_init(&instance->bulk_waiter_list_mutex); 1295 INIT_LIST_HEAD(&instance->bulk_waiter_list); 1296 1297 } 1298 else { 1299 vchiq_log_error(vchiq_arm_log_level, 1300 "Unknown minor device"); 1301 return -ENXIO; 1302 } 1303 1304 return fd_clone(fp, fd, flags, &vchiq_fileops, instance); 1305 } 1306 1307 /**************************************************************************** 1308 * 1309 * vchiq_release 1310 * 1311 ***************************************************************************/ 1312 1313 static int 1314 vchiq_close(struct file *fp) 1315 { 1316 int ret = 0; 1317 if (1) { 1318 VCHIQ_INSTANCE_T instance = fp->f_data; 1319 VCHIQ_STATE_T *state = vchiq_get_state(); 1320 VCHIQ_SERVICE_T *service; 1321 int i; 1322 1323 vchiq_log_info(vchiq_arm_log_level, 1324 "vchiq_release: instance=%lx", 1325 (unsigned long)instance); 1326 1327 if (!state) { 1328 ret = -EPERM; 1329 goto out; 1330 } 1331 1332 /* Ensure videocore is awake to allow termination. */ 1333 vchiq_use_internal(instance->state, NULL, 1334 USE_TYPE_VCHIQ); 1335 1336 lmutex_lock(&instance->completion_mutex); 1337 1338 /* Wake the completion thread and ask it to exit */ 1339 instance->closing = 1; 1340 up(&instance->insert_event); 1341 1342 lmutex_unlock(&instance->completion_mutex); 1343 1344 /* Wake the slot handler if the completion queue is full. */ 1345 up(&instance->remove_event); 1346 1347 /* Mark all services for termination... */ 1348 i = 0; 1349 while ((service = next_service_by_instance(state, instance, 1350 &i)) != NULL) { 1351 USER_SERVICE_T *user_service = service->base.userdata; 1352 1353 /* Wake the slot handler if the msg queue is full. */ 1354 up(&user_service->remove_event); 1355 1356 vchiq_terminate_service_internal(service); 1357 unlock_service(service); 1358 } 1359 1360 /* ...and wait for them to die */ 1361 i = 0; 1362 while ((service = next_service_by_instance(state, instance, &i)) 1363 != NULL) { 1364 USER_SERVICE_T *user_service = service->base.userdata; 1365 1366 down(&service->remove_event); 1367 1368 BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE); 1369 1370 spin_lock(&msg_queue_spinlock); 1371 1372 while (user_service->msg_remove != 1373 user_service->msg_insert) { 1374 VCHIQ_HEADER_T *header = user_service-> 1375 msg_queue[user_service->msg_remove & 1376 (MSG_QUEUE_SIZE - 1)]; 1377 user_service->msg_remove++; 1378 spin_unlock(&msg_queue_spinlock); 1379 1380 if (header) 1381 vchiq_release_message( 1382 service->handle, 1383 header); 1384 spin_lock(&msg_queue_spinlock); 1385 } 1386 1387 spin_unlock(&msg_queue_spinlock); 1388 1389 unlock_service(service); 1390 } 1391 1392 /* Release any closed services */ 1393 while (instance->completion_remove != 1394 instance->completion_insert) { 1395 VCHIQ_COMPLETION_DATA_T *completion; 1396 VCHIQ_SERVICE_T *service1; 1397 completion = &instance->completions[ 1398 instance->completion_remove & 1399 (MAX_COMPLETIONS - 1)]; 1400 service1 = completion->service_userdata; 1401 if (completion->reason == VCHIQ_SERVICE_CLOSED) 1402 { 1403 USER_SERVICE_T *user_service = 1404 service->base.userdata; 1405 1406 /* Wake any blocked user-thread */ 1407 if (instance->use_close_delivered) 1408 up(&user_service->close_event); 1409 unlock_service(service1); 1410 } 1411 instance->completion_remove++; 1412 } 1413 1414 /* Release the PEER service count. */ 1415 vchiq_release_internal(instance->state, NULL); 1416 1417 { 1418 struct list_head *pos, *next; 1419 list_for_each_safe(pos, next, 1420 &instance->bulk_waiter_list) { 1421 struct bulk_waiter_node *waiter; 1422 waiter = list_entry(pos, 1423 struct bulk_waiter_node, 1424 list); 1425 list_del(pos); 1426 vchiq_log_info(vchiq_arm_log_level, 1427 "bulk_waiter - cleaned up %p " 1428 "for pid %d", 1429 waiter, waiter->pid); 1430 _sema_destroy(&waiter->bulk_waiter.event); 1431 kfree(waiter); 1432 } 1433 } 1434 1435 } 1436 else { 1437 vchiq_log_error(vchiq_arm_log_level, 1438 "Unknown minor device"); 1439 ret = -ENXIO; 1440 } 1441 1442 out: 1443 return ret; 1444 } 1445 1446 /**************************************************************************** 1447 * 1448 * vchiq_dump 1449 * 1450 ***************************************************************************/ 1451 1452 void 1453 vchiq_dump(void *dump_context, const char *str, int len) 1454 { 1455 DUMP_CONTEXT_T *context = (DUMP_CONTEXT_T *)dump_context; 1456 1457 if (context->actual < context->space) { 1458 int copy_bytes; 1459 if (context->offset > 0) { 1460 int skip_bytes = min(len, (int)context->offset); 1461 str += skip_bytes; 1462 len -= skip_bytes; 1463 context->offset -= skip_bytes; 1464 if (context->offset > 0) 1465 return; 1466 } 1467 copy_bytes = min(len, (int)(context->space - context->actual)); 1468 if (copy_bytes == 0) 1469 return; 1470 memcpy(context->buf + context->actual, str, copy_bytes); 1471 context->actual += copy_bytes; 1472 len -= copy_bytes; 1473 1474 /* If tne terminating NUL is included in the length, then it 1475 ** marks the end of a line and should be replaced with a 1476 ** carriage return. */ 1477 if ((len == 0) && (str[copy_bytes - 1] == '\0')) { 1478 char cr = '\n'; 1479 memcpy(context->buf + context->actual - 1, &cr, 1); 1480 } 1481 } 1482 } 1483 1484 /**************************************************************************** 1485 * 1486 * vchiq_dump_platform_instance_state 1487 * 1488 ***************************************************************************/ 1489 1490 void 1491 vchiq_dump_platform_instances(void *dump_context) 1492 { 1493 VCHIQ_STATE_T *state = vchiq_get_state(); 1494 char buf[80]; 1495 int len; 1496 int i; 1497 1498 /* There is no list of instances, so instead scan all services, 1499 marking those that have been dumped. */ 1500 1501 for (i = 0; i < state->unused_service; i++) { 1502 VCHIQ_SERVICE_T *service = state->services[i]; 1503 VCHIQ_INSTANCE_T instance; 1504 1505 if (service && (service->base.callback == service_callback)) { 1506 instance = service->instance; 1507 if (instance) 1508 instance->mark = 0; 1509 } 1510 } 1511 1512 for (i = 0; i < state->unused_service; i++) { 1513 VCHIQ_SERVICE_T *service = state->services[i]; 1514 VCHIQ_INSTANCE_T instance; 1515 1516 if (service && (service->base.callback == service_callback)) { 1517 instance = service->instance; 1518 if (instance && !instance->mark) { 1519 len = snprintf(buf, sizeof(buf), 1520 "Instance %p: pid %d,%s completions " 1521 "%d/%d", 1522 instance, instance->pid, 1523 instance->connected ? " connected, " : 1524 "", 1525 instance->completion_insert - 1526 instance->completion_remove, 1527 MAX_COMPLETIONS); 1528 1529 vchiq_dump(dump_context, buf, len + 1); 1530 1531 instance->mark = 1; 1532 } 1533 } 1534 } 1535 } 1536 1537 /**************************************************************************** 1538 * 1539 * vchiq_dump_platform_service_state 1540 * 1541 ***************************************************************************/ 1542 1543 void 1544 vchiq_dump_platform_service_state(void *dump_context, VCHIQ_SERVICE_T *service) 1545 { 1546 USER_SERVICE_T *user_service = (USER_SERVICE_T *)service->base.userdata; 1547 char buf[80]; 1548 int len; 1549 1550 len = snprintf(buf, sizeof(buf), " instance %p", 1551 service->instance); 1552 1553 if ((service->base.callback == service_callback) && 1554 user_service->is_vchi) { 1555 len += snprintf(buf + len, sizeof(buf) - len, 1556 ", %d/%d messages", 1557 user_service->msg_insert - user_service->msg_remove, 1558 MSG_QUEUE_SIZE); 1559 1560 if (user_service->dequeue_pending) 1561 len += snprintf(buf + len, sizeof(buf) - len, 1562 " (dequeue pending)"); 1563 } 1564 1565 vchiq_dump(dump_context, buf, len + 1); 1566 } 1567 1568 #ifdef notyet 1569 /**************************************************************************** 1570 * 1571 * dump_user_mem 1572 * 1573 ***************************************************************************/ 1574 1575 static void 1576 dump_phys_mem(void *virt_addr, uint32_t num_bytes) 1577 { 1578 int rc; 1579 uint8_t *end_virt_addr = virt_addr + num_bytes; 1580 int num_pages; 1581 int offset; 1582 int end_offset; 1583 int page_idx; 1584 int prev_idx; 1585 struct page *page; 1586 struct page **pages; 1587 uint8_t *kmapped_virt_ptr; 1588 1589 /* Align virtAddr and endVirtAddr to 16 byte boundaries. */ 1590 1591 virt_addr = (void *)((unsigned long)virt_addr & ~0x0fuL); 1592 end_virt_addr = (void *)(((unsigned long)end_virt_addr + 15uL) & 1593 ~0x0fuL); 1594 1595 offset = (int)(long)virt_addr & (PAGE_SIZE - 1); 1596 end_offset = (int)(long)end_virt_addr & (PAGE_SIZE - 1); 1597 1598 num_pages = (offset + num_bytes + PAGE_SIZE - 1) / PAGE_SIZE; 1599 1600 pages = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL); 1601 if (pages == NULL) { 1602 vchiq_log_error(vchiq_arm_log_level, 1603 "Unable to allocation memory for %d pages", 1604 num_pages); 1605 return; 1606 } 1607 1608 down_read(¤t->mm->mmap_sem); 1609 rc = get_user_pages(current, /* task */ 1610 current->mm, /* mm */ 1611 (unsigned long)virt_addr, /* start */ 1612 num_pages, /* len */ 1613 0, /* write */ 1614 0, /* force */ 1615 pages, /* pages (array of page pointers) */ 1616 NULL); /* vmas */ 1617 up_read(¤t->mm->mmap_sem); 1618 1619 prev_idx = -1; 1620 page = NULL; 1621 1622 while (offset < end_offset) { 1623 1624 int page_offset = offset % PAGE_SIZE; 1625 page_idx = offset / PAGE_SIZE; 1626 1627 if (page_idx != prev_idx) { 1628 1629 if (page != NULL) 1630 kunmap(page); 1631 page = pages[page_idx]; 1632 kmapped_virt_ptr = kmap(page); 1633 1634 prev_idx = page_idx; 1635 } 1636 1637 if (vchiq_arm_log_level >= VCHIQ_LOG_TRACE) 1638 vchiq_log_dump_mem("ph", 1639 (uint32_t)(unsigned long)&kmapped_virt_ptr[ 1640 page_offset], 1641 &kmapped_virt_ptr[page_offset], 16); 1642 1643 offset += 16; 1644 } 1645 if (page != NULL) 1646 kunmap(page); 1647 1648 for (page_idx = 0; page_idx < num_pages; page_idx++) 1649 page_cache_release(pages[page_idx]); 1650 1651 kfree(pages); 1652 } 1653 #endif 1654 1655 /**************************************************************************** 1656 * 1657 * vchiq_read 1658 * 1659 ***************************************************************************/ 1660 1661 static int 1662 vchiq_read(struct file *file, off_t *ppos, struct uio *uio, kauth_cred_t cred, 1663 int flags) 1664 { 1665 int result; 1666 1667 char *buf = kmem_zalloc(PAGE_SIZE, KM_SLEEP); 1668 1669 DUMP_CONTEXT_T context; 1670 context.buf = buf; 1671 context.actual = 0; 1672 context.space = PAGE_SIZE; 1673 context.offset = *ppos; 1674 1675 vchiq_dump_state(&context, &g_state); 1676 1677 *ppos += context.actual; 1678 1679 result = uiomove(buf, context.actual, uio); 1680 kmem_free(buf, PAGE_SIZE); 1681 1682 return result; 1683 } 1684 1685 VCHIQ_STATE_T * 1686 vchiq_get_state(void) 1687 { 1688 1689 if (g_state.remote == NULL) 1690 printk(KERN_ERR "%s: g_state.remote == NULL\n", __func__); 1691 else if (le32toh(g_state.remote->initialised) != 1) 1692 printk(KERN_NOTICE "%s: g_state.remote->initialised != 1 (%d)\n", 1693 __func__, le32toh(g_state.remote->initialised)); 1694 1695 return ((g_state.remote != NULL) && 1696 (le32toh(g_state.remote->initialised) == 1)) ? &g_state : NULL; 1697 } 1698 1699 /* 1700 * Autosuspend related functionality 1701 */ 1702 1703 int 1704 vchiq_videocore_wanted(VCHIQ_STATE_T *state) 1705 { 1706 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 1707 if (!arm_state) 1708 /* autosuspend not supported - always return wanted */ 1709 return 1; 1710 else if (arm_state->blocked_count) 1711 return 1; 1712 else if (!arm_state->videocore_use_count) 1713 /* usage count zero - check for override unless we're forcing */ 1714 if (arm_state->resume_blocked) 1715 return 0; 1716 else 1717 return vchiq_platform_videocore_wanted(state); 1718 else 1719 /* non-zero usage count - videocore still required */ 1720 return 1; 1721 } 1722 1723 static VCHIQ_STATUS_T 1724 vchiq_keepalive_vchiq_callback(VCHIQ_REASON_T reason, 1725 VCHIQ_HEADER_T *header, 1726 VCHIQ_SERVICE_HANDLE_T service_user, 1727 void *bulk_user) 1728 { 1729 vchiq_log_error(vchiq_susp_log_level, 1730 "%s callback reason %d", __func__, reason); 1731 return 0; 1732 } 1733 1734 static int 1735 vchiq_keepalive_thread_func(void *v) 1736 { 1737 VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v; 1738 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 1739 1740 VCHIQ_STATUS_T status; 1741 VCHIQ_INSTANCE_T instance; 1742 VCHIQ_SERVICE_HANDLE_T ka_handle; 1743 1744 VCHIQ_SERVICE_PARAMS_T params = { 1745 .fourcc = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'), 1746 .callback = vchiq_keepalive_vchiq_callback, 1747 .version = KEEPALIVE_VER, 1748 .version_min = KEEPALIVE_VER_MIN 1749 }; 1750 1751 status = vchiq_initialise(&instance); 1752 if (status != VCHIQ_SUCCESS) { 1753 vchiq_log_error(vchiq_susp_log_level, 1754 "%s vchiq_initialise failed %d", __func__, status); 1755 goto exit; 1756 } 1757 1758 status = vchiq_connect(instance); 1759 if (status != VCHIQ_SUCCESS) { 1760 vchiq_log_error(vchiq_susp_log_level, 1761 "%s vchiq_connect failed %d", __func__, status); 1762 goto shutdown; 1763 } 1764 1765 status = vchiq_add_service(instance, ¶ms, &ka_handle); 1766 if (status != VCHIQ_SUCCESS) { 1767 vchiq_log_error(vchiq_susp_log_level, 1768 "%s vchiq_open_service failed %d", __func__, status); 1769 goto shutdown; 1770 } 1771 1772 while (1) { 1773 long rc = 0, uc = 0; 1774 if (wait_for_completion_interruptible(&arm_state->ka_evt) 1775 != 0) { 1776 vchiq_log_error(vchiq_susp_log_level, 1777 "%s interrupted", __func__); 1778 flush_signals(current); 1779 continue; 1780 } 1781 1782 /* read and clear counters. Do release_count then use_count to 1783 * prevent getting more releases than uses */ 1784 rc = atomic_xchg(&arm_state->ka_release_count, 0); 1785 uc = atomic_xchg(&arm_state->ka_use_count, 0); 1786 1787 /* Call use/release service the requisite number of times. 1788 * Process use before release so use counts don't go negative */ 1789 while (uc--) { 1790 atomic_inc(&arm_state->ka_use_ack_count); 1791 status = vchiq_use_service(ka_handle); 1792 if (status != VCHIQ_SUCCESS) { 1793 vchiq_log_error(vchiq_susp_log_level, 1794 "%s vchiq_use_service error %d", 1795 __func__, status); 1796 } 1797 } 1798 while (rc--) { 1799 status = vchiq_release_service(ka_handle); 1800 if (status != VCHIQ_SUCCESS) { 1801 vchiq_log_error(vchiq_susp_log_level, 1802 "%s vchiq_release_service error %d", 1803 __func__, status); 1804 } 1805 } 1806 } 1807 1808 shutdown: 1809 vchiq_shutdown(instance); 1810 exit: 1811 return 0; 1812 } 1813 1814 1815 1816 VCHIQ_STATUS_T 1817 vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state) 1818 { 1819 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 1820 1821 if (arm_state) { 1822 rwlock_init(&arm_state->susp_res_lock); 1823 1824 init_completion(&arm_state->ka_evt); 1825 atomic_set(&arm_state->ka_use_count, 0); 1826 atomic_set(&arm_state->ka_use_ack_count, 0); 1827 atomic_set(&arm_state->ka_release_count, 0); 1828 1829 init_completion(&arm_state->vc_suspend_complete); 1830 1831 init_completion(&arm_state->vc_resume_complete); 1832 /* Initialise to 'done' state. We only want to block on resume 1833 * completion while videocore is suspended. */ 1834 set_resume_state(arm_state, VC_RESUME_RESUMED); 1835 1836 init_completion(&arm_state->resume_blocker); 1837 /* Initialise to 'done' state. We only want to block on this 1838 * completion while resume is blocked */ 1839 complete_all(&arm_state->resume_blocker); 1840 1841 init_completion(&arm_state->blocked_blocker); 1842 /* Initialise to 'done' state. We only want to block on this 1843 * completion while things are waiting on the resume blocker */ 1844 complete_all(&arm_state->blocked_blocker); 1845 1846 arm_state->suspend_timer_timeout = SUSPEND_TIMER_TIMEOUT_MS; 1847 arm_state->suspend_timer_running = 0; 1848 init_timer(&arm_state->suspend_timer); 1849 arm_state->suspend_timer.data = (unsigned long)(state); 1850 arm_state->suspend_timer.function = suspend_timer_callback; 1851 1852 arm_state->first_connect = 0; 1853 1854 } 1855 return status; 1856 } 1857 1858 /* 1859 ** Functions to modify the state variables; 1860 ** set_suspend_state 1861 ** set_resume_state 1862 ** 1863 ** There are more state variables than we might like, so ensure they remain in 1864 ** step. Suspend and resume state are maintained separately, since most of 1865 ** these state machines can operate independently. However, there are a few 1866 ** states where state transitions in one state machine cause a reset to the 1867 ** other state machine. In addition, there are some completion events which 1868 ** need to occur on state machine reset and end-state(s), so these are also 1869 ** dealt with in these functions. 1870 ** 1871 ** In all states we set the state variable according to the input, but in some 1872 ** cases we perform additional steps outlined below; 1873 ** 1874 ** VC_SUSPEND_IDLE - Initialise the suspend completion at the same time. 1875 ** The suspend completion is completed after any suspend 1876 ** attempt. When we reset the state machine we also reset 1877 ** the completion. This reset occurs when videocore is 1878 ** resumed, and also if we initiate suspend after a suspend 1879 ** failure. 1880 ** 1881 ** VC_SUSPEND_IN_PROGRESS - This state is considered the point of no return for 1882 ** suspend - ie from this point on we must try to suspend 1883 ** before resuming can occur. We therefore also reset the 1884 ** resume state machine to VC_RESUME_IDLE in this state. 1885 ** 1886 ** VC_SUSPEND_SUSPENDED - Suspend has completed successfully. Also call 1887 ** complete_all on the suspend completion to notify 1888 ** anything waiting for suspend to happen. 1889 ** 1890 ** VC_SUSPEND_REJECTED - Videocore rejected suspend. Videocore will also 1891 ** initiate resume, so no need to alter resume state. 1892 ** We call complete_all on the suspend completion to notify 1893 ** of suspend rejection. 1894 ** 1895 ** VC_SUSPEND_FAILED - We failed to initiate videocore suspend. We notify the 1896 ** suspend completion and reset the resume state machine. 1897 ** 1898 ** VC_RESUME_IDLE - Initialise the resume completion at the same time. The 1899 ** resume completion is in it's 'done' state whenever 1900 ** videcore is running. Therfore, the VC_RESUME_IDLE state 1901 ** implies that videocore is suspended. 1902 ** Hence, any thread which needs to wait until videocore is 1903 ** running can wait on this completion - it will only block 1904 ** if videocore is suspended. 1905 ** 1906 ** VC_RESUME_RESUMED - Resume has completed successfully. Videocore is running. 1907 ** Call complete_all on the resume completion to unblock 1908 ** any threads waiting for resume. Also reset the suspend 1909 ** state machine to it's idle state. 1910 ** 1911 ** VC_RESUME_FAILED - Currently unused - no mechanism to fail resume exists. 1912 */ 1913 1914 inline void 1915 set_suspend_state(VCHIQ_ARM_STATE_T *arm_state, 1916 enum vc_suspend_status new_state) 1917 { 1918 /* set the state in all cases */ 1919 arm_state->vc_suspend_state = new_state; 1920 1921 /* state specific additional actions */ 1922 switch (new_state) { 1923 case VC_SUSPEND_FORCE_CANCELED: 1924 complete_all(&arm_state->vc_suspend_complete); 1925 break; 1926 case VC_SUSPEND_REJECTED: 1927 complete_all(&arm_state->vc_suspend_complete); 1928 break; 1929 case VC_SUSPEND_FAILED: 1930 complete_all(&arm_state->vc_suspend_complete); 1931 arm_state->vc_resume_state = VC_RESUME_RESUMED; 1932 complete_all(&arm_state->vc_resume_complete); 1933 break; 1934 case VC_SUSPEND_IDLE: 1935 reinit_completion(&arm_state->vc_suspend_complete); 1936 break; 1937 case VC_SUSPEND_REQUESTED: 1938 break; 1939 case VC_SUSPEND_IN_PROGRESS: 1940 set_resume_state(arm_state, VC_RESUME_IDLE); 1941 break; 1942 case VC_SUSPEND_SUSPENDED: 1943 complete_all(&arm_state->vc_suspend_complete); 1944 break; 1945 default: 1946 BUG(); 1947 break; 1948 } 1949 } 1950 1951 inline void 1952 set_resume_state(VCHIQ_ARM_STATE_T *arm_state, 1953 enum vc_resume_status new_state) 1954 { 1955 /* set the state in all cases */ 1956 arm_state->vc_resume_state = new_state; 1957 1958 /* state specific additional actions */ 1959 switch (new_state) { 1960 case VC_RESUME_FAILED: 1961 break; 1962 case VC_RESUME_IDLE: 1963 reinit_completion(&arm_state->vc_resume_complete); 1964 break; 1965 case VC_RESUME_REQUESTED: 1966 break; 1967 case VC_RESUME_IN_PROGRESS: 1968 break; 1969 case VC_RESUME_RESUMED: 1970 complete_all(&arm_state->vc_resume_complete); 1971 set_suspend_state(arm_state, VC_SUSPEND_IDLE); 1972 break; 1973 default: 1974 BUG(); 1975 break; 1976 } 1977 } 1978 1979 1980 /* should be called with the write lock held */ 1981 inline void 1982 start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state) 1983 { 1984 del_timer(&arm_state->suspend_timer); 1985 arm_state->suspend_timer.expires = jiffies + 1986 msecs_to_jiffies(arm_state-> 1987 suspend_timer_timeout); 1988 add_timer(&arm_state->suspend_timer); 1989 arm_state->suspend_timer_running = 1; 1990 } 1991 1992 /* should be called with the write lock held */ 1993 static inline void 1994 stop_suspend_timer(VCHIQ_ARM_STATE_T *arm_state) 1995 { 1996 if (arm_state->suspend_timer_running) { 1997 del_timer(&arm_state->suspend_timer); 1998 arm_state->suspend_timer_running = 0; 1999 } 2000 } 2001 2002 static inline int 2003 need_resume(VCHIQ_STATE_T *state) 2004 { 2005 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2006 return (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) && 2007 (arm_state->vc_resume_state < VC_RESUME_REQUESTED) && 2008 vchiq_videocore_wanted(state); 2009 } 2010 2011 static int 2012 block_resume(VCHIQ_ARM_STATE_T *arm_state) 2013 { 2014 int status = VCHIQ_SUCCESS; 2015 const unsigned long timeout_val = 2016 msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS); 2017 int resume_count = 0; 2018 2019 /* Allow any threads which were blocked by the last force suspend to 2020 * complete if they haven't already. Only give this one shot; if 2021 * blocked_count is incremented after blocked_blocker is completed 2022 * (which only happens when blocked_count hits 0) then those threads 2023 * will have to wait until next time around */ 2024 if (arm_state->blocked_count) { 2025 reinit_completion(&arm_state->blocked_blocker); 2026 write_unlock_bh(&arm_state->susp_res_lock); 2027 vchiq_log_info(vchiq_susp_log_level, "%s wait for previously " 2028 "blocked clients", __func__); 2029 if (wait_for_completion_interruptible_timeout( 2030 &arm_state->blocked_blocker, timeout_val) 2031 <= 0) { 2032 vchiq_log_error(vchiq_susp_log_level, "%s wait for " 2033 "previously blocked clients failed" , __func__); 2034 status = VCHIQ_ERROR; 2035 write_lock_bh(&arm_state->susp_res_lock); 2036 goto out; 2037 } 2038 vchiq_log_info(vchiq_susp_log_level, "%s previously blocked " 2039 "clients resumed", __func__); 2040 write_lock_bh(&arm_state->susp_res_lock); 2041 } 2042 2043 /* We need to wait for resume to complete if it's in process */ 2044 while (arm_state->vc_resume_state != VC_RESUME_RESUMED && 2045 arm_state->vc_resume_state > VC_RESUME_IDLE) { 2046 if (resume_count > 1) { 2047 status = VCHIQ_ERROR; 2048 vchiq_log_error(vchiq_susp_log_level, "%s waited too " 2049 "many times for resume" , __func__); 2050 goto out; 2051 } 2052 write_unlock_bh(&arm_state->susp_res_lock); 2053 vchiq_log_info(vchiq_susp_log_level, "%s wait for resume", 2054 __func__); 2055 if (wait_for_completion_interruptible_timeout( 2056 &arm_state->vc_resume_complete, timeout_val) 2057 <= 0) { 2058 vchiq_log_error(vchiq_susp_log_level, "%s wait for " 2059 "resume failed (%s)", __func__, 2060 resume_state_names[arm_state->vc_resume_state + 2061 VC_RESUME_NUM_OFFSET]); 2062 status = VCHIQ_ERROR; 2063 write_lock_bh(&arm_state->susp_res_lock); 2064 goto out; 2065 } 2066 vchiq_log_info(vchiq_susp_log_level, "%s resumed", __func__); 2067 write_lock_bh(&arm_state->susp_res_lock); 2068 resume_count++; 2069 } 2070 reinit_completion(&arm_state->resume_blocker); 2071 arm_state->resume_blocked = 1; 2072 2073 out: 2074 return status; 2075 } 2076 2077 static inline void 2078 unblock_resume(VCHIQ_ARM_STATE_T *arm_state) 2079 { 2080 complete_all(&arm_state->resume_blocker); 2081 arm_state->resume_blocked = 0; 2082 } 2083 2084 /* Initiate suspend via slot handler. Should be called with the write lock 2085 * held */ 2086 VCHIQ_STATUS_T 2087 vchiq_arm_vcsuspend(VCHIQ_STATE_T *state) 2088 { 2089 VCHIQ_STATUS_T status = VCHIQ_ERROR; 2090 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2091 2092 if (!arm_state) 2093 goto out; 2094 2095 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2096 status = VCHIQ_SUCCESS; 2097 2098 2099 switch (arm_state->vc_suspend_state) { 2100 case VC_SUSPEND_REQUESTED: 2101 vchiq_log_info(vchiq_susp_log_level, "%s: suspend already " 2102 "requested", __func__); 2103 break; 2104 case VC_SUSPEND_IN_PROGRESS: 2105 vchiq_log_info(vchiq_susp_log_level, "%s: suspend already in " 2106 "progress", __func__); 2107 break; 2108 2109 default: 2110 /* We don't expect to be in other states, so log but continue 2111 * anyway */ 2112 vchiq_log_error(vchiq_susp_log_level, 2113 "%s unexpected suspend state %s", __func__, 2114 suspend_state_names[arm_state->vc_suspend_state + 2115 VC_SUSPEND_NUM_OFFSET]); 2116 /* fall through */ 2117 case VC_SUSPEND_REJECTED: 2118 case VC_SUSPEND_FAILED: 2119 /* Ensure any idle state actions have been run */ 2120 set_suspend_state(arm_state, VC_SUSPEND_IDLE); 2121 /* fall through */ 2122 case VC_SUSPEND_IDLE: 2123 vchiq_log_info(vchiq_susp_log_level, 2124 "%s: suspending", __func__); 2125 set_suspend_state(arm_state, VC_SUSPEND_REQUESTED); 2126 /* kick the slot handler thread to initiate suspend */ 2127 request_poll(state, NULL, 0); 2128 break; 2129 } 2130 2131 out: 2132 vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status); 2133 return status; 2134 } 2135 2136 void 2137 vchiq_platform_check_suspend(VCHIQ_STATE_T *state) 2138 { 2139 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2140 int susp = 0; 2141 2142 if (!arm_state) 2143 goto out; 2144 2145 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2146 2147 write_lock_bh(&arm_state->susp_res_lock); 2148 if (arm_state->vc_suspend_state == VC_SUSPEND_REQUESTED && 2149 arm_state->vc_resume_state == VC_RESUME_RESUMED) { 2150 set_suspend_state(arm_state, VC_SUSPEND_IN_PROGRESS); 2151 susp = 1; 2152 } 2153 write_unlock_bh(&arm_state->susp_res_lock); 2154 2155 if (susp) 2156 vchiq_platform_suspend(state); 2157 2158 out: 2159 vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__); 2160 return; 2161 } 2162 2163 2164 static void 2165 output_timeout_error(VCHIQ_STATE_T *state) 2166 { 2167 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2168 char service_err[50] = ""; 2169 int vc_use_count = arm_state->videocore_use_count; 2170 int active_services = state->unused_service; 2171 int i; 2172 2173 if (!arm_state->videocore_use_count) { 2174 snprintf(service_err, 50, " Videocore usecount is 0"); 2175 goto output_msg; 2176 } 2177 for (i = 0; i < active_services; i++) { 2178 VCHIQ_SERVICE_T *service_ptr = state->services[i]; 2179 if (service_ptr && service_ptr->service_use_count && 2180 (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE)) { 2181 snprintf(service_err, 50, " %c%c%c%c(%8x) service has " 2182 "use count %d%s", VCHIQ_FOURCC_AS_4CHARS( 2183 service_ptr->base.fourcc), 2184 service_ptr->client_id, 2185 service_ptr->service_use_count, 2186 service_ptr->service_use_count == 2187 vc_use_count ? "" : " (+ more)"); 2188 break; 2189 } 2190 } 2191 2192 output_msg: 2193 vchiq_log_error(vchiq_susp_log_level, 2194 "timed out waiting for vc suspend (%d).%s", 2195 arm_state->autosuspend_override, service_err); 2196 2197 } 2198 2199 /* Try to get videocore into suspended state, regardless of autosuspend state. 2200 ** We don't actually force suspend, since videocore may get into a bad state 2201 ** if we force suspend at a bad time. Instead, we wait for autosuspend to 2202 ** determine a good point to suspend. If this doesn't happen within 100ms we 2203 ** report failure. 2204 ** 2205 ** Returns VCHIQ_SUCCESS if videocore suspended successfully, VCHIQ_RETRY if 2206 ** videocore failed to suspend in time or VCHIQ_ERROR if interrupted. 2207 */ 2208 VCHIQ_STATUS_T 2209 vchiq_arm_force_suspend(VCHIQ_STATE_T *state) 2210 { 2211 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2212 VCHIQ_STATUS_T status = VCHIQ_ERROR; 2213 long rc = 0; 2214 int repeat = -1; 2215 2216 if (!arm_state) 2217 goto out; 2218 2219 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2220 2221 write_lock_bh(&arm_state->susp_res_lock); 2222 2223 status = block_resume(arm_state); 2224 if (status != VCHIQ_SUCCESS) 2225 goto unlock; 2226 if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) { 2227 /* Already suspended - just block resume and exit */ 2228 vchiq_log_info(vchiq_susp_log_level, "%s already suspended", 2229 __func__); 2230 status = VCHIQ_SUCCESS; 2231 goto unlock; 2232 } else if (arm_state->vc_suspend_state <= VC_SUSPEND_IDLE) { 2233 /* initiate suspend immediately in the case that we're waiting 2234 * for the timeout */ 2235 stop_suspend_timer(arm_state); 2236 if (!vchiq_videocore_wanted(state)) { 2237 vchiq_log_info(vchiq_susp_log_level, "%s videocore " 2238 "idle, initiating suspend", __func__); 2239 status = vchiq_arm_vcsuspend(state); 2240 } else if (arm_state->autosuspend_override < 2241 FORCE_SUSPEND_FAIL_MAX) { 2242 vchiq_log_info(vchiq_susp_log_level, "%s letting " 2243 "videocore go idle", __func__); 2244 status = VCHIQ_SUCCESS; 2245 } else { 2246 vchiq_log_warning(vchiq_susp_log_level, "%s failed too " 2247 "many times - attempting suspend", __func__); 2248 status = vchiq_arm_vcsuspend(state); 2249 } 2250 } else { 2251 vchiq_log_info(vchiq_susp_log_level, "%s videocore suspend " 2252 "in progress - wait for completion", __func__); 2253 status = VCHIQ_SUCCESS; 2254 } 2255 2256 /* Wait for suspend to happen due to system idle (not forced..) */ 2257 if (status != VCHIQ_SUCCESS) 2258 goto unblock_resume; 2259 2260 do { 2261 write_unlock_bh(&arm_state->susp_res_lock); 2262 2263 rc = wait_for_completion_interruptible_timeout( 2264 &arm_state->vc_suspend_complete, 2265 msecs_to_jiffies(FORCE_SUSPEND_TIMEOUT_MS)); 2266 2267 write_lock_bh(&arm_state->susp_res_lock); 2268 if (rc < 0) { 2269 vchiq_log_warning(vchiq_susp_log_level, "%s " 2270 "interrupted waiting for suspend", __func__); 2271 status = VCHIQ_ERROR; 2272 goto unblock_resume; 2273 } else if (rc == 0) { 2274 if (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) { 2275 /* Repeat timeout once if in progress */ 2276 if (repeat < 0) { 2277 repeat = 1; 2278 continue; 2279 } 2280 } 2281 arm_state->autosuspend_override++; 2282 output_timeout_error(state); 2283 2284 status = VCHIQ_RETRY; 2285 goto unblock_resume; 2286 } 2287 } while (0 < (repeat--)); 2288 2289 /* Check and report state in case we need to abort ARM suspend */ 2290 if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED) { 2291 status = VCHIQ_RETRY; 2292 vchiq_log_error(vchiq_susp_log_level, 2293 "%s videocore suspend failed (state %s)", __func__, 2294 suspend_state_names[arm_state->vc_suspend_state + 2295 VC_SUSPEND_NUM_OFFSET]); 2296 /* Reset the state only if it's still in an error state. 2297 * Something could have already initiated another suspend. */ 2298 if (arm_state->vc_suspend_state < VC_SUSPEND_IDLE) 2299 set_suspend_state(arm_state, VC_SUSPEND_IDLE); 2300 2301 goto unblock_resume; 2302 } 2303 2304 /* successfully suspended - unlock and exit */ 2305 goto unlock; 2306 2307 unblock_resume: 2308 /* all error states need to unblock resume before exit */ 2309 unblock_resume(arm_state); 2310 2311 unlock: 2312 write_unlock_bh(&arm_state->susp_res_lock); 2313 2314 out: 2315 vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status); 2316 return status; 2317 } 2318 2319 void 2320 vchiq_check_suspend(VCHIQ_STATE_T *state) 2321 { 2322 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2323 2324 if (!arm_state) 2325 goto out; 2326 2327 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2328 2329 write_lock_bh(&arm_state->susp_res_lock); 2330 if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED && 2331 arm_state->first_connect && 2332 !vchiq_videocore_wanted(state)) { 2333 vchiq_arm_vcsuspend(state); 2334 } 2335 write_unlock_bh(&arm_state->susp_res_lock); 2336 2337 out: 2338 vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__); 2339 return; 2340 } 2341 2342 2343 int 2344 vchiq_arm_allow_resume(VCHIQ_STATE_T *state) 2345 { 2346 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2347 int resume = 0; 2348 int ret = -1; 2349 2350 if (!arm_state) 2351 goto out; 2352 2353 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2354 2355 write_lock_bh(&arm_state->susp_res_lock); 2356 unblock_resume(arm_state); 2357 resume = vchiq_check_resume(state); 2358 write_unlock_bh(&arm_state->susp_res_lock); 2359 2360 if (resume) { 2361 if (wait_for_completion_interruptible( 2362 &arm_state->vc_resume_complete) < 0) { 2363 vchiq_log_error(vchiq_susp_log_level, 2364 "%s interrupted", __func__); 2365 /* failed, cannot accurately derive suspend 2366 * state, so exit early. */ 2367 goto out; 2368 } 2369 } 2370 2371 read_lock_bh(&arm_state->susp_res_lock); 2372 if (arm_state->vc_suspend_state == VC_SUSPEND_SUSPENDED) { 2373 vchiq_log_info(vchiq_susp_log_level, 2374 "%s: Videocore remains suspended", __func__); 2375 } else { 2376 vchiq_log_info(vchiq_susp_log_level, 2377 "%s: Videocore resumed", __func__); 2378 ret = 0; 2379 } 2380 read_unlock_bh(&arm_state->susp_res_lock); 2381 out: 2382 vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret); 2383 return ret; 2384 } 2385 2386 /* This function should be called with the write lock held */ 2387 int 2388 vchiq_check_resume(VCHIQ_STATE_T *state) 2389 { 2390 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2391 int resume = 0; 2392 2393 if (!arm_state) 2394 goto out; 2395 2396 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2397 2398 if (need_resume(state)) { 2399 set_resume_state(arm_state, VC_RESUME_REQUESTED); 2400 request_poll(state, NULL, 0); 2401 resume = 1; 2402 } 2403 2404 out: 2405 vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__); 2406 return resume; 2407 } 2408 2409 #ifdef notyet 2410 void 2411 vchiq_platform_check_resume(VCHIQ_STATE_T *state) 2412 { 2413 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2414 int res = 0; 2415 2416 if (!arm_state) 2417 goto out; 2418 2419 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2420 2421 write_lock_bh(&arm_state->susp_res_lock); 2422 if (arm_state->wake_address == 0) { 2423 vchiq_log_info(vchiq_susp_log_level, 2424 "%s: already awake", __func__); 2425 goto unlock; 2426 } 2427 if (arm_state->vc_resume_state == VC_RESUME_IN_PROGRESS) { 2428 vchiq_log_info(vchiq_susp_log_level, 2429 "%s: already resuming", __func__); 2430 goto unlock; 2431 } 2432 2433 if (arm_state->vc_resume_state == VC_RESUME_REQUESTED) { 2434 set_resume_state(arm_state, VC_RESUME_IN_PROGRESS); 2435 res = 1; 2436 } else 2437 vchiq_log_trace(vchiq_susp_log_level, 2438 "%s: not resuming (resume state %s)", __func__, 2439 resume_state_names[arm_state->vc_resume_state + 2440 VC_RESUME_NUM_OFFSET]); 2441 2442 unlock: 2443 write_unlock_bh(&arm_state->susp_res_lock); 2444 2445 if (res) 2446 vchiq_platform_resume(state); 2447 2448 out: 2449 vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__); 2450 return; 2451 2452 } 2453 #endif 2454 2455 2456 2457 VCHIQ_STATUS_T 2458 vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, 2459 enum USE_TYPE_E use_type) 2460 { 2461 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2462 VCHIQ_STATUS_T ret = VCHIQ_SUCCESS; 2463 char entity[16]; 2464 int *entity_uc; 2465 int local_uc, local_entity_uc; 2466 2467 if (!arm_state) 2468 goto out; 2469 2470 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2471 2472 if (use_type == USE_TYPE_VCHIQ) { 2473 snprintf(entity, sizeof(entity), "VCHIQ: "); 2474 entity_uc = &arm_state->peer_use_count; 2475 } else if (service) { 2476 snprintf(entity, sizeof(entity), "%c%c%c%c:%8x", 2477 VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc), 2478 service->client_id); 2479 entity_uc = &service->service_use_count; 2480 } else { 2481 vchiq_log_error(vchiq_susp_log_level, "%s null service " 2482 "ptr", __func__); 2483 ret = VCHIQ_ERROR; 2484 goto out; 2485 } 2486 2487 write_lock_bh(&arm_state->susp_res_lock); 2488 while (arm_state->resume_blocked) { 2489 /* If we call 'use' while force suspend is waiting for suspend, 2490 * then we're about to block the thread which the force is 2491 * waiting to complete, so we're bound to just time out. In this 2492 * case, set the suspend state such that the wait will be 2493 * canceled, so we can complete as quickly as possible. */ 2494 if (arm_state->resume_blocked && arm_state->vc_suspend_state == 2495 VC_SUSPEND_IDLE) { 2496 set_suspend_state(arm_state, VC_SUSPEND_FORCE_CANCELED); 2497 break; 2498 } 2499 /* If suspend is already in progress then we need to block */ 2500 if (!try_wait_for_completion(&arm_state->resume_blocker)) { 2501 /* Indicate that there are threads waiting on the resume 2502 * blocker. These need to be allowed to complete before 2503 * a _second_ call to force suspend can complete, 2504 * otherwise low priority threads might never actually 2505 * continue */ 2506 arm_state->blocked_count++; 2507 write_unlock_bh(&arm_state->susp_res_lock); 2508 vchiq_log_info(vchiq_susp_log_level, "%s %s resume " 2509 "blocked - waiting...", __func__, entity); 2510 if (wait_for_completion_killable( 2511 &arm_state->resume_blocker) != 0) { 2512 vchiq_log_error(vchiq_susp_log_level, "%s %s " 2513 "wait for resume blocker interrupted", 2514 __func__, entity); 2515 ret = VCHIQ_ERROR; 2516 write_lock_bh(&arm_state->susp_res_lock); 2517 arm_state->blocked_count--; 2518 write_unlock_bh(&arm_state->susp_res_lock); 2519 goto out; 2520 } 2521 vchiq_log_info(vchiq_susp_log_level, "%s %s resume " 2522 "unblocked", __func__, entity); 2523 write_lock_bh(&arm_state->susp_res_lock); 2524 if (--arm_state->blocked_count == 0) 2525 complete_all(&arm_state->blocked_blocker); 2526 } 2527 } 2528 2529 stop_suspend_timer(arm_state); 2530 2531 local_uc = ++arm_state->videocore_use_count; 2532 local_entity_uc = ++(*entity_uc); 2533 2534 /* If there's a pending request which hasn't yet been serviced then 2535 * just clear it. If we're past VC_SUSPEND_REQUESTED state then 2536 * vc_resume_complete will block until we either resume or fail to 2537 * suspend */ 2538 if (arm_state->vc_suspend_state <= VC_SUSPEND_REQUESTED) 2539 set_suspend_state(arm_state, VC_SUSPEND_IDLE); 2540 2541 if ((use_type != USE_TYPE_SERVICE_NO_RESUME) && need_resume(state)) { 2542 set_resume_state(arm_state, VC_RESUME_REQUESTED); 2543 vchiq_log_info(vchiq_susp_log_level, 2544 "%s %s count %d, state count %d", 2545 __func__, entity, local_entity_uc, local_uc); 2546 request_poll(state, NULL, 0); 2547 } else 2548 vchiq_log_trace(vchiq_susp_log_level, 2549 "%s %s count %d, state count %d", 2550 __func__, entity, *entity_uc, local_uc); 2551 2552 2553 write_unlock_bh(&arm_state->susp_res_lock); 2554 2555 /* Completion is in a done state when we're not suspended, so this won't 2556 * block for the non-suspended case. */ 2557 if (!try_wait_for_completion(&arm_state->vc_resume_complete)) { 2558 vchiq_log_info(vchiq_susp_log_level, "%s %s wait for resume", 2559 __func__, entity); 2560 if (wait_for_completion_killable( 2561 &arm_state->vc_resume_complete) != 0) { 2562 vchiq_log_error(vchiq_susp_log_level, "%s %s wait for " 2563 "resume interrupted", __func__, entity); 2564 ret = VCHIQ_ERROR; 2565 goto out; 2566 } 2567 vchiq_log_info(vchiq_susp_log_level, "%s %s resumed", __func__, 2568 entity); 2569 } 2570 2571 if (ret == VCHIQ_SUCCESS) { 2572 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 2573 long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0); 2574 while (ack_cnt && (status == VCHIQ_SUCCESS)) { 2575 /* Send the use notify to videocore */ 2576 status = vchiq_send_remote_use_active(state); 2577 if (status == VCHIQ_SUCCESS) 2578 ack_cnt--; 2579 else 2580 atomic_add(ack_cnt, 2581 &arm_state->ka_use_ack_count); 2582 } 2583 } 2584 2585 out: 2586 vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret); 2587 return ret; 2588 } 2589 2590 VCHIQ_STATUS_T 2591 vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service) 2592 { 2593 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2594 VCHIQ_STATUS_T ret = VCHIQ_SUCCESS; 2595 char entity[16]; 2596 int *entity_uc; 2597 2598 if (!arm_state) 2599 goto out; 2600 2601 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2602 2603 if (service) { 2604 snprintf(entity, sizeof(entity), "%c%c%c%c:%8x", 2605 VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc), 2606 service->client_id); 2607 entity_uc = &service->service_use_count; 2608 } else { 2609 snprintf(entity, sizeof(entity), "PEER: "); 2610 entity_uc = &arm_state->peer_use_count; 2611 } 2612 2613 write_lock_bh(&arm_state->susp_res_lock); 2614 if (!arm_state->videocore_use_count || !(*entity_uc)) { 2615 /* Don't use BUG_ON - don't allow user thread to crash kernel */ 2616 WARN_ON(!arm_state->videocore_use_count); 2617 WARN_ON(!(*entity_uc)); 2618 ret = VCHIQ_ERROR; 2619 goto unlock; 2620 } 2621 --arm_state->videocore_use_count; 2622 --(*entity_uc); 2623 2624 if (!vchiq_videocore_wanted(state)) { 2625 if (vchiq_platform_use_suspend_timer() && 2626 !arm_state->resume_blocked) { 2627 /* Only use the timer if we're not trying to force 2628 * suspend (=> resume_blocked) */ 2629 start_suspend_timer(arm_state); 2630 } else { 2631 vchiq_log_info(vchiq_susp_log_level, 2632 "%s %s count %d, state count %d - suspending", 2633 __func__, entity, *entity_uc, 2634 arm_state->videocore_use_count); 2635 vchiq_arm_vcsuspend(state); 2636 } 2637 } else 2638 vchiq_log_trace(vchiq_susp_log_level, 2639 "%s %s count %d, state count %d", 2640 __func__, entity, *entity_uc, 2641 arm_state->videocore_use_count); 2642 2643 unlock: 2644 write_unlock_bh(&arm_state->susp_res_lock); 2645 2646 out: 2647 vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, ret); 2648 return ret; 2649 } 2650 2651 void 2652 vchiq_on_remote_use(VCHIQ_STATE_T *state) 2653 { 2654 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2655 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2656 atomic_inc(&arm_state->ka_use_count); 2657 complete(&arm_state->ka_evt); 2658 } 2659 2660 void 2661 vchiq_on_remote_release(VCHIQ_STATE_T *state) 2662 { 2663 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2664 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2665 atomic_inc(&arm_state->ka_release_count); 2666 complete(&arm_state->ka_evt); 2667 } 2668 2669 VCHIQ_STATUS_T 2670 vchiq_use_service_internal(VCHIQ_SERVICE_T *service) 2671 { 2672 return vchiq_use_internal(service->state, service, USE_TYPE_SERVICE); 2673 } 2674 2675 VCHIQ_STATUS_T 2676 vchiq_release_service_internal(VCHIQ_SERVICE_T *service) 2677 { 2678 return vchiq_release_internal(service->state, service); 2679 } 2680 2681 #ifdef notyet 2682 VCHIQ_DEBUGFS_NODE_T * 2683 vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance) 2684 { 2685 return &instance->debugfs_node; 2686 } 2687 2688 int 2689 vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance) 2690 { 2691 VCHIQ_SERVICE_T *service; 2692 int use_count = 0, i; 2693 i = 0; 2694 while ((service = next_service_by_instance(instance->state, 2695 instance, &i)) != NULL) { 2696 use_count += service->service_use_count; 2697 unlock_service(service); 2698 } 2699 return use_count; 2700 } 2701 2702 int 2703 vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance) 2704 { 2705 return instance->pid; 2706 } 2707 2708 int 2709 vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance) 2710 { 2711 return instance->trace; 2712 } 2713 2714 void 2715 vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace) 2716 { 2717 VCHIQ_SERVICE_T *service; 2718 int i; 2719 i = 0; 2720 while ((service = next_service_by_instance(instance->state, 2721 instance, &i)) != NULL) { 2722 service->trace = trace; 2723 unlock_service(service); 2724 } 2725 instance->trace = (trace != 0); 2726 } 2727 #endif 2728 2729 static void suspend_timer_callback(unsigned long context) 2730 { 2731 VCHIQ_STATE_T *state = (VCHIQ_STATE_T *)context; 2732 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2733 if (!arm_state) 2734 goto out; 2735 vchiq_log_info(vchiq_susp_log_level, 2736 "%s - suspend timer expired - check suspend", __func__); 2737 vchiq_check_suspend(state); 2738 out: 2739 return; 2740 } 2741 2742 VCHIQ_STATUS_T 2743 vchiq_use_service_no_resume(VCHIQ_SERVICE_HANDLE_T handle) 2744 { 2745 VCHIQ_STATUS_T ret = VCHIQ_ERROR; 2746 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 2747 if (service) { 2748 ret = vchiq_use_internal(service->state, service, 2749 USE_TYPE_SERVICE_NO_RESUME); 2750 unlock_service(service); 2751 } 2752 return ret; 2753 } 2754 2755 VCHIQ_STATUS_T 2756 vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle) 2757 { 2758 VCHIQ_STATUS_T ret = VCHIQ_ERROR; 2759 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 2760 if (service) { 2761 ret = vchiq_use_internal(service->state, service, 2762 USE_TYPE_SERVICE); 2763 unlock_service(service); 2764 } 2765 return ret; 2766 } 2767 2768 VCHIQ_STATUS_T 2769 vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle) 2770 { 2771 VCHIQ_STATUS_T ret = VCHIQ_ERROR; 2772 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 2773 if (service) { 2774 ret = vchiq_release_internal(service->state, service); 2775 unlock_service(service); 2776 } 2777 return ret; 2778 } 2779 2780 void 2781 vchiq_dump_service_use_state(VCHIQ_STATE_T *state) 2782 { 2783 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2784 int i, j = 0; 2785 /* Only dump 64 services */ 2786 #define local_max_services 64 2787 /* If there's more than 64 services, only dump ones with 2788 * non-zero counts */ 2789 int only_nonzero = 0; 2790 static const char *nz = "<-- preventing suspend"; 2791 2792 enum vc_suspend_status vc_suspend_state; 2793 enum vc_resume_status vc_resume_state; 2794 int peer_count; 2795 int vc_use_count; 2796 int active_services; 2797 struct service_data_struct { 2798 int fourcc; 2799 int clientid; 2800 int use_count; 2801 } service_data[local_max_services]; 2802 2803 if (!arm_state) 2804 return; 2805 2806 read_lock_bh(&arm_state->susp_res_lock); 2807 vc_suspend_state = arm_state->vc_suspend_state; 2808 vc_resume_state = arm_state->vc_resume_state; 2809 peer_count = arm_state->peer_use_count; 2810 vc_use_count = arm_state->videocore_use_count; 2811 active_services = state->unused_service; 2812 if (active_services > local_max_services) 2813 only_nonzero = 1; 2814 2815 for (i = 0; (i < active_services) && (j < local_max_services); i++) { 2816 VCHIQ_SERVICE_T *service_ptr = state->services[i]; 2817 if (!service_ptr) 2818 continue; 2819 2820 if (only_nonzero && !service_ptr->service_use_count) 2821 continue; 2822 2823 if (service_ptr->srvstate != VCHIQ_SRVSTATE_FREE) { 2824 service_data[j].fourcc = service_ptr->base.fourcc; 2825 service_data[j].clientid = service_ptr->client_id; 2826 service_data[j++].use_count = service_ptr-> 2827 service_use_count; 2828 } 2829 } 2830 2831 read_unlock_bh(&arm_state->susp_res_lock); 2832 2833 vchiq_log_warning(vchiq_susp_log_level, 2834 "-- Videcore suspend state: %s --", 2835 suspend_state_names[vc_suspend_state + VC_SUSPEND_NUM_OFFSET]); 2836 vchiq_log_warning(vchiq_susp_log_level, 2837 "-- Videcore resume state: %s --", 2838 resume_state_names[vc_resume_state + VC_RESUME_NUM_OFFSET]); 2839 2840 if (only_nonzero) 2841 vchiq_log_warning(vchiq_susp_log_level, "Too many active " 2842 "services (%d). Only dumping up to first %d services " 2843 "with non-zero use-count", active_services, 2844 local_max_services); 2845 2846 for (i = 0; i < j; i++) { 2847 vchiq_log_warning(vchiq_susp_log_level, 2848 "----- %c%c%c%c:%d service count %d %s", 2849 VCHIQ_FOURCC_AS_4CHARS(service_data[i].fourcc), 2850 service_data[i].clientid, 2851 service_data[i].use_count, 2852 service_data[i].use_count ? nz : ""); 2853 } 2854 vchiq_log_warning(vchiq_susp_log_level, 2855 "----- VCHIQ use count count %d", peer_count); 2856 vchiq_log_warning(vchiq_susp_log_level, 2857 "--- Overall vchiq instance use count %d", vc_use_count); 2858 2859 vchiq_dump_platform_use_state(state); 2860 } 2861 2862 VCHIQ_STATUS_T 2863 vchiq_check_service(VCHIQ_SERVICE_T *service) 2864 { 2865 VCHIQ_ARM_STATE_T *arm_state; 2866 VCHIQ_STATUS_T ret = VCHIQ_ERROR; 2867 2868 if (!service || !service->state) 2869 goto out; 2870 2871 vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); 2872 2873 arm_state = vchiq_platform_get_arm_state(service->state); 2874 2875 read_lock_bh(&arm_state->susp_res_lock); 2876 if (service->service_use_count) 2877 ret = VCHIQ_SUCCESS; 2878 read_unlock_bh(&arm_state->susp_res_lock); 2879 2880 if (ret == VCHIQ_ERROR) { 2881 vchiq_log_error(vchiq_susp_log_level, 2882 "%s ERROR - %c%c%c%c:%8x service count %d, " 2883 "state count %d, videocore suspend state %s", __func__, 2884 VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc), 2885 service->client_id, service->service_use_count, 2886 arm_state->videocore_use_count, 2887 suspend_state_names[arm_state->vc_suspend_state + 2888 VC_SUSPEND_NUM_OFFSET]); 2889 vchiq_dump_service_use_state(service->state); 2890 } 2891 out: 2892 return ret; 2893 } 2894 2895 /* stub functions */ 2896 void vchiq_on_remote_use_active(VCHIQ_STATE_T *state) 2897 { 2898 (void)state; 2899 } 2900 2901 void vchiq_platform_conn_state_changed(VCHIQ_STATE_T *state, 2902 VCHIQ_CONNSTATE_T oldstate, VCHIQ_CONNSTATE_T newstate) 2903 { 2904 VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state); 2905 vchiq_log_info(vchiq_susp_log_level, "%d: %s->%s", state->id, 2906 get_conn_state_name(oldstate), get_conn_state_name(newstate)); 2907 if (state->conn_state == VCHIQ_CONNSTATE_CONNECTED) { 2908 write_lock_bh(&arm_state->susp_res_lock); 2909 if (!arm_state->first_connect) { 2910 char threadname[10]; 2911 arm_state->first_connect = 1; 2912 write_unlock_bh(&arm_state->susp_res_lock); 2913 snprintf(threadname, sizeof(threadname), "VCHIQka-%d", 2914 state->id); 2915 arm_state->ka_thread = vchiq_thread_create( 2916 &vchiq_keepalive_thread_func, 2917 (void *)state, 2918 threadname); 2919 if (arm_state->ka_thread == NULL) { 2920 vchiq_log_error(vchiq_susp_log_level, 2921 "vchiq: FATAL: couldn't create thread %s", 2922 threadname); 2923 } else { 2924 wake_up_process(arm_state->ka_thread); 2925 } 2926 } else 2927 write_unlock_bh(&arm_state->susp_res_lock); 2928 } 2929 } 2930 2931 2932 /**************************************************************************** 2933 * 2934 * vchiq_init - called when the module is loaded. 2935 * 2936 ***************************************************************************/ 2937 2938 int __init vchiq_init(void); 2939 int __init 2940 vchiq_init(void) 2941 { 2942 int err; 2943 2944 #ifdef notyet 2945 /* create proc entries */ 2946 err = vchiq_proc_init(); 2947 if (err != 0) 2948 goto failed_proc_init; 2949 #endif 2950 2951 spin_lock_init(&msg_queue_spinlock); 2952 2953 err = vchiq_platform_init(&g_state); 2954 if (err != 0) 2955 goto failed_platform_init; 2956 2957 vchiq_log_info(vchiq_arm_log_level, 2958 "vchiq: initialised - version %d (min %d)", 2959 VCHIQ_VERSION, VCHIQ_VERSION_MIN); 2960 2961 return 0; 2962 2963 failed_platform_init: 2964 vchiq_log_warning(vchiq_arm_log_level, "could not load vchiq"); 2965 return err; 2966 } 2967 2968 /**************************************************************************** 2969 * 2970 * vchiq_exit - called when the module is unloaded. 2971 * 2972 ***************************************************************************/ 2973 2974 void vchiq_exit(void); 2975 void 2976 vchiq_exit(void) 2977 { 2978 vchiq_platform_exit(&g_state); 2979 } 2980