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