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