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 "vchiq_core.h" 35 36 #define VCHIQ_SLOT_HANDLER_STACK 8192 37 38 #define HANDLE_STATE_SHIFT 12 39 40 #define SLOT_INFO_FROM_INDEX(state, index) (state->slot_info + (index)) 41 #define SLOT_DATA_FROM_INDEX(state, index) (state->slot_data + (index)) 42 #define SLOT_INDEX_FROM_DATA(state, data) \ 43 (((unsigned int)((char *)data - (char *)state->slot_data)) / \ 44 VCHIQ_SLOT_SIZE) 45 #define SLOT_INDEX_FROM_INFO(state, info) \ 46 ((unsigned int)(info - state->slot_info)) 47 #define SLOT_QUEUE_INDEX_FROM_POS(pos) \ 48 ((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE)) 49 50 #define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1)) 51 52 #define SRVTRACE_LEVEL(srv) \ 53 (((srv) && (srv)->trace) ? VCHIQ_LOG_TRACE : vchiq_core_msg_log_level) 54 #define SRVTRACE_ENABLED(srv, lev) \ 55 (((srv) && (srv)->trace) || (vchiq_core_msg_log_level >= (lev))) 56 57 struct vchiq_open_payload { 58 int32_t fourcc; 59 int32_t client_id; 60 int16_t version; 61 int16_t version_min; 62 }; 63 64 struct vchiq_openack_payload { 65 uint16_t version; 66 }; 67 68 enum 69 { 70 QMFLAGS_IS_BLOCKING = (1 << 0), 71 QMFLAGS_NO_MUTEX_LOCK = (1 << 1), 72 QMFLAGS_NO_MUTEX_UNLOCK = (1 << 2) 73 }; 74 75 /* we require this for consistency between endpoints */ 76 vchiq_static_assert(sizeof(VCHIQ_HEADER_T) == 8); 77 vchiq_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T))); 78 vchiq_static_assert(IS_POW2(VCHIQ_NUM_CURRENT_BULKS)); 79 vchiq_static_assert(IS_POW2(VCHIQ_NUM_SERVICE_BULKS)); 80 vchiq_static_assert(IS_POW2(VCHIQ_MAX_SERVICES)); 81 vchiq_static_assert(VCHIQ_VERSION >= VCHIQ_VERSION_MIN); 82 83 /* Run time control of log level, based on KERN_XXX level. */ 84 int vchiq_core_log_level = VCHIQ_LOG_DEFAULT; 85 int vchiq_core_msg_log_level = VCHIQ_LOG_DEFAULT; 86 int vchiq_sync_log_level = VCHIQ_LOG_DEFAULT; 87 88 static atomic_t pause_bulks_count = ATOMIC_INIT(0); 89 90 static DEFINE_SPINLOCK(service_spinlock); 91 DEFINE_SPINLOCK(bulk_waiter_spinlock); 92 DEFINE_SPINLOCK(quota_spinlock); 93 94 void 95 vchiq_core_initialize(void) 96 { 97 spin_lock_init(&service_spinlock); 98 spin_lock_init(&bulk_waiter_spinlock); 99 spin_lock_init("a_spinlock); 100 } 101 102 VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES]; 103 static unsigned int handle_seq; 104 105 static const char *const srvstate_names[] = { 106 "FREE", 107 "HIDDEN", 108 "LISTENING", 109 "OPENING", 110 "OPEN", 111 "OPENSYNC", 112 "CLOSESENT", 113 "CLOSERECVD", 114 "CLOSEWAIT", 115 "CLOSED" 116 }; 117 118 static const char *const reason_names[] = { 119 "SERVICE_OPENED", 120 "SERVICE_CLOSED", 121 "MESSAGE_AVAILABLE", 122 "BULK_TRANSMIT_DONE", 123 "BULK_RECEIVE_DONE", 124 "BULK_TRANSMIT_ABORTED", 125 "BULK_RECEIVE_ABORTED" 126 }; 127 128 static const char *const conn_state_names[] = { 129 "DISCONNECTED", 130 "CONNECTING", 131 "CONNECTED", 132 "PAUSING", 133 "PAUSE_SENT", 134 "PAUSED", 135 "RESUMING", 136 "PAUSE_TIMEOUT", 137 "RESUME_TIMEOUT" 138 }; 139 140 141 static void 142 release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header); 143 144 static const char *msg_type_str(unsigned int msg_type) 145 { 146 switch (msg_type) { 147 case VCHIQ_MSG_PADDING: return "PADDING"; 148 case VCHIQ_MSG_CONNECT: return "CONNECT"; 149 case VCHIQ_MSG_OPEN: return "OPEN"; 150 case VCHIQ_MSG_OPENACK: return "OPENACK"; 151 case VCHIQ_MSG_CLOSE: return "CLOSE"; 152 case VCHIQ_MSG_DATA: return "DATA"; 153 case VCHIQ_MSG_BULK_RX: return "BULK_RX"; 154 case VCHIQ_MSG_BULK_TX: return "BULK_TX"; 155 case VCHIQ_MSG_BULK_RX_DONE: return "BULK_RX_DONE"; 156 case VCHIQ_MSG_BULK_TX_DONE: return "BULK_TX_DONE"; 157 case VCHIQ_MSG_PAUSE: return "PAUSE"; 158 case VCHIQ_MSG_RESUME: return "RESUME"; 159 case VCHIQ_MSG_REMOTE_USE: return "REMOTE_USE"; 160 case VCHIQ_MSG_REMOTE_RELEASE: return "REMOTE_RELEASE"; 161 case VCHIQ_MSG_REMOTE_USE_ACTIVE: return "REMOTE_USE_ACTIVE"; 162 } 163 return "???"; 164 } 165 166 static inline void 167 vchiq_set_service_state(VCHIQ_SERVICE_T *service, int newstate) 168 { 169 vchiq_log_info(vchiq_core_log_level, "%d: srv:%d %s->%s", 170 service->state->id, service->localport, 171 srvstate_names[service->srvstate], 172 srvstate_names[newstate]); 173 service->srvstate = newstate; 174 } 175 176 VCHIQ_SERVICE_T * 177 find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle) 178 { 179 VCHIQ_SERVICE_T *service; 180 181 spin_lock(&service_spinlock); 182 service = handle_to_service(handle); 183 if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) && 184 (service->handle == handle)) { 185 BUG_ON(service->ref_count == 0); 186 service->ref_count++; 187 } else 188 service = NULL; 189 spin_unlock(&service_spinlock); 190 191 if (!service) 192 vchiq_log_info(vchiq_core_log_level, 193 "Invalid service handle 0x%x", handle); 194 195 return service; 196 } 197 198 VCHIQ_SERVICE_T * 199 find_service_by_port(VCHIQ_STATE_T *state, int localport) 200 { 201 VCHIQ_SERVICE_T *service = NULL; 202 if ((unsigned int)localport <= VCHIQ_PORT_MAX) { 203 spin_lock(&service_spinlock); 204 service = state->services[localport]; 205 if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE)) { 206 BUG_ON(service->ref_count == 0); 207 service->ref_count++; 208 } else 209 service = NULL; 210 spin_unlock(&service_spinlock); 211 } 212 213 if (!service) 214 vchiq_log_info(vchiq_core_log_level, 215 "Invalid port %d", localport); 216 217 return service; 218 } 219 220 VCHIQ_SERVICE_T * 221 find_service_for_instance(VCHIQ_INSTANCE_T instance, 222 VCHIQ_SERVICE_HANDLE_T handle) { 223 VCHIQ_SERVICE_T *service; 224 225 spin_lock(&service_spinlock); 226 service = handle_to_service(handle); 227 if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) && 228 (service->handle == handle) && 229 (service->instance == instance)) { 230 BUG_ON(service->ref_count == 0); 231 service->ref_count++; 232 } else 233 service = NULL; 234 spin_unlock(&service_spinlock); 235 236 if (!service) 237 vchiq_log_info(vchiq_core_log_level, 238 "Invalid service handle 0x%x", handle); 239 240 return service; 241 } 242 243 VCHIQ_SERVICE_T * 244 find_closed_service_for_instance(VCHIQ_INSTANCE_T instance, 245 VCHIQ_SERVICE_HANDLE_T handle) { 246 VCHIQ_SERVICE_T *service; 247 248 spin_lock(&service_spinlock); 249 service = handle_to_service(handle); 250 if (service && 251 ((service->srvstate == VCHIQ_SRVSTATE_FREE) || 252 (service->srvstate == VCHIQ_SRVSTATE_CLOSED)) && 253 (service->handle == handle) && 254 (service->instance == instance)) { 255 BUG_ON(service->ref_count == 0); 256 service->ref_count++; 257 } else 258 service = NULL; 259 spin_unlock(&service_spinlock); 260 261 if (!service) 262 vchiq_log_info(vchiq_core_log_level, 263 "Invalid service handle 0x%x", handle); 264 265 return service; 266 } 267 268 VCHIQ_SERVICE_T * 269 next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance, 270 int *pidx) 271 { 272 VCHIQ_SERVICE_T *service = NULL; 273 int idx = *pidx; 274 275 spin_lock(&service_spinlock); 276 while (idx < state->unused_service) { 277 VCHIQ_SERVICE_T *srv = state->services[idx++]; 278 if (srv && (srv->srvstate != VCHIQ_SRVSTATE_FREE) && 279 (srv->instance == instance)) { 280 service = srv; 281 BUG_ON(service->ref_count == 0); 282 service->ref_count++; 283 break; 284 } 285 } 286 spin_unlock(&service_spinlock); 287 288 *pidx = idx; 289 290 return service; 291 } 292 293 void 294 lock_service(VCHIQ_SERVICE_T *service) 295 { 296 spin_lock(&service_spinlock); 297 BUG_ON(!service); 298 if (service) { 299 BUG_ON(service->ref_count == 0); 300 service->ref_count++; 301 } 302 spin_unlock(&service_spinlock); 303 } 304 305 void 306 unlock_service(VCHIQ_SERVICE_T *service) 307 { 308 spin_lock(&service_spinlock); 309 if (!service) { 310 vchiq_log_warning(vchiq_core_log_level, 311 "%s: service is NULL\n", __func__); 312 goto unlock; 313 } 314 if (!service->ref_count) { 315 vchiq_log_warning(vchiq_core_log_level, 316 "%s: ref_count is zero\n", __func__); 317 goto unlock; 318 } 319 service->ref_count--; 320 if (!service->ref_count) { 321 VCHIQ_STATE_T *state = service->state; 322 323 WARN_ON(service->srvstate != VCHIQ_SRVSTATE_FREE); 324 state->services[service->localport] = NULL; 325 } else 326 service = NULL; 327 unlock: 328 spin_unlock(&service_spinlock); 329 330 if (service && service->userdata_term) 331 service->userdata_term(service->base.userdata); 332 333 kfree(service); 334 } 335 336 int 337 vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle) 338 { 339 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 340 int id; 341 342 id = service ? service->client_id : 0; 343 if (service) 344 unlock_service(service); 345 346 return id; 347 } 348 349 void * 350 vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle) 351 { 352 VCHIQ_SERVICE_T *service = handle_to_service(handle); 353 354 return service ? service->base.userdata : NULL; 355 } 356 357 int 358 vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T handle) 359 { 360 VCHIQ_SERVICE_T *service = handle_to_service(handle); 361 362 return service ? service->base.fourcc : 0; 363 } 364 365 static void 366 mark_service_closing_internal(VCHIQ_SERVICE_T *service, int sh_thread) 367 { 368 VCHIQ_STATE_T *state = service->state; 369 VCHIQ_SERVICE_QUOTA_T *service_quota; 370 371 service->closing = 1; 372 373 /* Synchronise with other threads. */ 374 lmutex_lock(&state->recycle_mutex); 375 lmutex_unlock(&state->recycle_mutex); 376 if (!sh_thread || (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT)) { 377 /* If we're pausing then the slot_mutex is held until resume 378 * by the slot handler. Therefore don't try to acquire this 379 * mutex if we're the slot handler and in the pause sent state. 380 * We don't need to in this case anyway. */ 381 lmutex_lock(&state->slot_mutex); 382 lmutex_unlock(&state->slot_mutex); 383 } 384 385 /* Unblock any sending thread. */ 386 service_quota = &state->service_quotas[service->localport]; 387 up(&service_quota->quota_event); 388 } 389 390 static void 391 mark_service_closing(VCHIQ_SERVICE_T *service) 392 { 393 mark_service_closing_internal(service, 0); 394 } 395 396 static inline VCHIQ_STATUS_T 397 make_service_callback(VCHIQ_SERVICE_T *service, VCHIQ_REASON_T reason, 398 VCHIQ_HEADER_T *header, void *bulk_userdata) 399 { 400 VCHIQ_STATUS_T status; 401 402 vchiq_log_trace(vchiq_core_log_level, "%d: callback:%d (%s, %p, %p)", 403 service->state->id, service->localport, reason_names[reason], 404 header, bulk_userdata); 405 status = service->base.callback(reason, header, service->handle, 406 bulk_userdata); 407 if (status == VCHIQ_ERROR) { 408 vchiq_log_warning(vchiq_core_log_level, 409 "%d: ignoring ERROR from callback to service %x", 410 service->state->id, service->handle); 411 status = VCHIQ_SUCCESS; 412 } 413 return status; 414 } 415 416 inline void 417 vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate) 418 { 419 VCHIQ_CONNSTATE_T oldstate = state->conn_state; 420 421 vchiq_log_info(vchiq_core_log_level, "%d: %s->%s", state->id, 422 conn_state_names[oldstate], 423 conn_state_names[newstate]); 424 state->conn_state = newstate; 425 vchiq_platform_conn_state_changed(state, oldstate, newstate); 426 } 427 428 static inline void 429 remote_event_create(VCHIQ_STATE_T *state, REMOTE_EVENT_T *event) 430 { 431 event->armed = htole32(0); 432 /* Don't clear the 'fired' flag because it may already have been set 433 ** by the other side. */ 434 _sema_init((struct semaphore *)((char *)state + le32toh(event->event)), 0); 435 } 436 437 static inline int 438 remote_event_wait(VCHIQ_STATE_T *state, REMOTE_EVENT_T *event) 439 { 440 if (!/*le32toh*/(event->fired)) { 441 event->armed = htole32(1); 442 dsb(sy); 443 if (!/*le32toh*/(event->fired)) { 444 if (down_interruptible( 445 (struct semaphore *) 446 ((char *)state + le32toh(event->event))) != 0) { 447 event->armed = htole32(0); 448 return 0; 449 } 450 } 451 event->armed = htole32(0); 452 wmb(); 453 } 454 455 event->fired = htole32(0); 456 return 1; 457 } 458 459 static inline void 460 remote_event_signal_local(VCHIQ_STATE_T *state, REMOTE_EVENT_T *event) 461 { 462 event->armed = htole32(0); 463 up((struct semaphore *)((char *)state + le32toh(event->event))); 464 } 465 466 static inline void 467 remote_event_poll(VCHIQ_STATE_T *state, REMOTE_EVENT_T *event) 468 { 469 if (/*le32toh*/(event->fired) && /*le32toh*/(event->armed)) 470 remote_event_signal_local(state, event); 471 } 472 473 void 474 remote_event_pollall(VCHIQ_STATE_T *state) 475 { 476 remote_event_poll(state, &state->local->sync_trigger); 477 remote_event_poll(state, &state->local->sync_release); 478 remote_event_poll(state, &state->local->trigger); 479 remote_event_poll(state, &state->local->recycle); 480 } 481 482 /* Round up message sizes so that any space at the end of a slot is always big 483 ** enough for a header. This relies on header size being a power of two, which 484 ** has been verified earlier by a static assertion. */ 485 486 static inline unsigned int 487 calc_stride(unsigned int size) 488 { 489 /* Allow room for the header */ 490 size += sizeof(VCHIQ_HEADER_T); 491 492 /* Round up */ 493 return (size + sizeof(VCHIQ_HEADER_T) - 1) & ~(sizeof(VCHIQ_HEADER_T) 494 - 1); 495 } 496 497 /* Called by the slot handler thread */ 498 static VCHIQ_SERVICE_T * 499 get_listening_service(VCHIQ_STATE_T *state, int fourcc) 500 { 501 int i; 502 503 WARN_ON(fourcc == VCHIQ_FOURCC_INVALID); 504 505 for (i = 0; i < state->unused_service; i++) { 506 VCHIQ_SERVICE_T *service = state->services[i]; 507 if (service && 508 (service->public_fourcc == fourcc) && 509 ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) || 510 ((service->srvstate == VCHIQ_SRVSTATE_OPEN) && 511 (service->remoteport == VCHIQ_PORT_FREE)))) { 512 lock_service(service); 513 return service; 514 } 515 } 516 517 return NULL; 518 } 519 520 /* Called by the slot handler thread */ 521 static VCHIQ_SERVICE_T * 522 get_connected_service(VCHIQ_STATE_T *state, unsigned int port) 523 { 524 int i; 525 for (i = 0; i < state->unused_service; i++) { 526 VCHIQ_SERVICE_T *service = state->services[i]; 527 if (service && (service->srvstate == VCHIQ_SRVSTATE_OPEN) 528 && (service->remoteport == port)) { 529 lock_service(service); 530 return service; 531 } 532 } 533 return NULL; 534 } 535 536 inline void 537 request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type) 538 { 539 uint32_t value; 540 541 if (service) { 542 do { 543 value = atomic_read(&service->poll_flags); 544 } while (atomic_cmpxchg(&service->poll_flags, value, 545 value | (1 << poll_type)) != value); 546 547 do { 548 value = atomic_read(&state->poll_services[ 549 service->localport>>5]); 550 } while (atomic_cmpxchg( 551 &state->poll_services[service->localport>>5], 552 value, value | (1 << (service->localport & 0x1f))) 553 != value); 554 } 555 556 state->poll_needed = 1; 557 wmb(); 558 559 /* ... and ensure the slot handler runs. */ 560 remote_event_signal_local(state, &state->local->trigger); 561 } 562 563 /* Called from queue_message, by the slot handler and application threads, 564 ** with slot_mutex held */ 565 static VCHIQ_HEADER_T * 566 reserve_space(VCHIQ_STATE_T *state, int space, int is_blocking) 567 { 568 VCHIQ_SHARED_STATE_T *local = state->local; 569 int tx_pos = state->local_tx_pos; 570 int slot_space = VCHIQ_SLOT_SIZE - (tx_pos & VCHIQ_SLOT_MASK); 571 572 if (space > slot_space) { 573 VCHIQ_HEADER_T *header; 574 /* Fill the remaining space with padding */ 575 WARN_ON(state->tx_data == NULL); 576 header = (VCHIQ_HEADER_T *) 577 (state->tx_data + (tx_pos & VCHIQ_SLOT_MASK)); 578 header->msgid = htole32(VCHIQ_MSGID_PADDING); 579 header->size = htole32(slot_space - sizeof(VCHIQ_HEADER_T)); 580 581 tx_pos += slot_space; 582 } 583 584 /* If necessary, get the next slot. */ 585 if ((tx_pos & VCHIQ_SLOT_MASK) == 0) { 586 int slot_index; 587 588 /* If there is no free slot... */ 589 590 if (down_trylock(&state->slot_available_event) != 0) { 591 /* ...wait for one. */ 592 593 VCHIQ_STATS_INC(state, slot_stalls); 594 595 /* But first, flush through the last slot. */ 596 state->local_tx_pos = tx_pos; 597 local->tx_pos = htole32(tx_pos); 598 remote_event_signal(&state->remote->trigger); 599 600 if (!is_blocking || 601 (down_interruptible( 602 &state->slot_available_event) != 0)) 603 return NULL; /* No space available */ 604 } 605 606 BUG_ON(tx_pos == 607 (state->slot_queue_available * VCHIQ_SLOT_SIZE)); 608 609 slot_index = le32toh(local->slot_queue[ 610 SLOT_QUEUE_INDEX_FROM_POS(tx_pos) & 611 VCHIQ_SLOT_QUEUE_MASK]); 612 state->tx_data = 613 (char *)SLOT_DATA_FROM_INDEX(state, slot_index); 614 } 615 616 state->local_tx_pos = tx_pos + space; 617 618 return (VCHIQ_HEADER_T *)(state->tx_data + (tx_pos & VCHIQ_SLOT_MASK)); 619 } 620 621 /* Called by the recycle thread. */ 622 static void 623 process_free_queue(VCHIQ_STATE_T *state) 624 { 625 VCHIQ_SHARED_STATE_T *local = state->local; 626 BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)]; 627 int slot_queue_available; 628 629 /* Find slots which have been freed by the other side, and return them 630 ** to the available queue. */ 631 slot_queue_available = state->slot_queue_available; 632 633 /* Use a memory barrier to ensure that any state that may have been 634 ** modified by another thread is not masked by stale prefetched 635 ** values. */ 636 mb(); 637 638 while (slot_queue_available != le32toh(local->slot_queue_recycle)) { 639 unsigned int pos; 640 int slot_index = le32toh(local->slot_queue[slot_queue_available++ & 641 VCHIQ_SLOT_QUEUE_MASK]); 642 char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index); 643 int data_found = 0; 644 645 rmb(); 646 647 vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%p %x %x", 648 state->id, slot_index, data, 649 le32toh(local->slot_queue_recycle), slot_queue_available); 650 651 /* Initialise the bitmask for services which have used this 652 ** slot */ 653 BITSET_ZERO(service_found); 654 655 pos = 0; 656 657 while (pos < VCHIQ_SLOT_SIZE) { 658 VCHIQ_HEADER_T *header = 659 (VCHIQ_HEADER_T *)(data + pos); 660 uint32_t msgid = le32toh(header->msgid); 661 if (VCHIQ_MSG_TYPE(msgid) == VCHIQ_MSG_DATA) { 662 unsigned int port = VCHIQ_MSG_SRCPORT(msgid); 663 VCHIQ_SERVICE_QUOTA_T *service_quota = 664 &state->service_quotas[port]; 665 int count; 666 spin_lock("a_spinlock); 667 count = service_quota->message_use_count; 668 if (count > 0) 669 service_quota->message_use_count = 670 count - 1; 671 spin_unlock("a_spinlock); 672 673 if (count == service_quota->message_quota) 674 /* Signal the service that it 675 ** has dropped below its quota 676 */ 677 up(&service_quota->quota_event); 678 else if (count == 0) { 679 vchiq_log_error(vchiq_core_log_level, 680 "service %d " 681 "message_use_count=%d " 682 "(header %p, msgid %x, " 683 "header->msgid %x, " 684 "header->size %x)", 685 port, 686 service_quota-> 687 message_use_count, 688 header, msgid, 689 le32toh(header->msgid), 690 le32toh(header->size)); 691 WARN(1, "invalid message use count\n"); 692 } 693 if (!BITSET_IS_SET(service_found, port)) { 694 /* Set the found bit for this service */ 695 BITSET_SET(service_found, port); 696 697 spin_lock("a_spinlock); 698 count = service_quota->slot_use_count; 699 if (count > 0) 700 service_quota->slot_use_count = 701 count - 1; 702 spin_unlock("a_spinlock); 703 704 if (count > 0) { 705 /* Signal the service in case 706 ** it has dropped below its 707 ** quota */ 708 up(&service_quota->quota_event); 709 vchiq_log_trace( 710 vchiq_core_log_level, 711 "%d: pfq:%d %x@%p - " 712 "slot_use->%d", 713 state->id, port, 714 le32toh(header->size), 715 header, 716 count - 1); 717 } else { 718 vchiq_log_error( 719 vchiq_core_log_level, 720 "service %d " 721 "slot_use_count" 722 "=%d (header %p" 723 ", msgid %x, " 724 "header->msgid" 725 " %x, header->" 726 "size %x)", 727 port, count, 728 header, 729 msgid, 730 le32toh(header->msgid), 731 le32toh(header->size)); 732 WARN(1, "bad slot use count\n"); 733 } 734 } 735 736 data_found = 1; 737 } 738 739 pos += calc_stride(le32toh(header->size)); 740 if (pos > VCHIQ_SLOT_SIZE) { 741 vchiq_log_error(vchiq_core_log_level, 742 "pfq - pos %x: header %p, msgid %x, " 743 "header->msgid %x, header->size %x", 744 pos, header, msgid, 745 le32toh(header->msgid), le32toh(header->size)); 746 WARN(1, "invalid slot position\n"); 747 } 748 } 749 750 if (data_found) { 751 int count; 752 spin_lock("a_spinlock); 753 count = state->data_use_count; 754 if (count > 0) 755 state->data_use_count = 756 count - 1; 757 spin_unlock("a_spinlock); 758 if (count == state->data_quota) 759 up(&state->data_quota_event); 760 } 761 762 mb(); 763 764 state->slot_queue_available = slot_queue_available; 765 up(&state->slot_available_event); 766 } 767 } 768 769 /* Called by the slot handler and application threads */ 770 static VCHIQ_STATUS_T 771 queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, 772 uint32_t msgid, const VCHIQ_ELEMENT_T *elements, 773 int count, int size, int flags) 774 { 775 VCHIQ_SHARED_STATE_T *local; 776 VCHIQ_SERVICE_QUOTA_T *service_quota = NULL; 777 VCHIQ_HEADER_T *header; 778 uint32_t type = VCHIQ_MSG_TYPE(msgid); 779 780 unsigned int stride; 781 782 local = state->local; 783 784 stride = calc_stride(size); 785 786 WARN_ON(!(stride <= VCHIQ_SLOT_SIZE)); 787 788 if (!(flags & QMFLAGS_NO_MUTEX_LOCK) && 789 (lmutex_lock_interruptible(&state->slot_mutex) != 0)) 790 return VCHIQ_RETRY; 791 792 if (type == VCHIQ_MSG_DATA) { 793 int tx_end_index; 794 795 BUG_ON(!service); 796 BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | 797 QMFLAGS_NO_MUTEX_UNLOCK)) != 0); 798 799 if (service->closing) { 800 /* The service has been closed */ 801 lmutex_unlock(&state->slot_mutex); 802 return VCHIQ_ERROR; 803 } 804 805 service_quota = &state->service_quotas[service->localport]; 806 807 spin_lock("a_spinlock); 808 809 /* Ensure this service doesn't use more than its quota of 810 ** messages or slots */ 811 tx_end_index = SLOT_QUEUE_INDEX_FROM_POS( 812 state->local_tx_pos + stride - 1); 813 814 /* Ensure data messages don't use more than their quota of 815 ** slots */ 816 while ((tx_end_index != state->previous_data_index) && 817 (state->data_use_count == state->data_quota)) { 818 VCHIQ_STATS_INC(state, data_stalls); 819 spin_unlock("a_spinlock); 820 lmutex_unlock(&state->slot_mutex); 821 822 if (down_interruptible(&state->data_quota_event) 823 != 0) 824 return VCHIQ_RETRY; 825 826 lmutex_lock(&state->slot_mutex); 827 spin_lock("a_spinlock); 828 tx_end_index = SLOT_QUEUE_INDEX_FROM_POS( 829 state->local_tx_pos + stride - 1); 830 if ((tx_end_index == state->previous_data_index) || 831 (state->data_use_count < state->data_quota)) { 832 /* Pass the signal on to other waiters */ 833 up(&state->data_quota_event); 834 break; 835 } 836 } 837 838 while ((service_quota->message_use_count == 839 service_quota->message_quota) || 840 ((tx_end_index != service_quota->previous_tx_index) && 841 (service_quota->slot_use_count == 842 service_quota->slot_quota))) { 843 spin_unlock("a_spinlock); 844 vchiq_log_trace(vchiq_core_log_level, 845 "%d: qm:%d %s,%x - quota stall " 846 "(msg %d, slot %d)", 847 state->id, service->localport, 848 msg_type_str(type), size, 849 service_quota->message_use_count, 850 service_quota->slot_use_count); 851 VCHIQ_SERVICE_STATS_INC(service, quota_stalls); 852 lmutex_unlock(&state->slot_mutex); 853 if (down_interruptible(&service_quota->quota_event) 854 != 0) 855 return VCHIQ_RETRY; 856 if (service->closing) 857 return VCHIQ_ERROR; 858 if (lmutex_lock_interruptible(&state->slot_mutex) != 0) 859 return VCHIQ_RETRY; 860 if (service->srvstate != VCHIQ_SRVSTATE_OPEN) { 861 /* The service has been closed */ 862 lmutex_unlock(&state->slot_mutex); 863 return VCHIQ_ERROR; 864 } 865 spin_lock("a_spinlock); 866 tx_end_index = SLOT_QUEUE_INDEX_FROM_POS( 867 state->local_tx_pos + stride - 1); 868 } 869 870 spin_unlock("a_spinlock); 871 } 872 873 header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING); 874 875 if (!header) { 876 if (service) 877 VCHIQ_SERVICE_STATS_INC(service, slot_stalls); 878 /* In the event of a failure, return the mutex to the 879 state it was in */ 880 if (!(flags & QMFLAGS_NO_MUTEX_LOCK)) 881 lmutex_unlock(&state->slot_mutex); 882 return VCHIQ_RETRY; 883 } 884 885 if (type == VCHIQ_MSG_DATA) { 886 int i, pos; 887 int tx_end_index; 888 int slot_use_count; 889 890 vchiq_log_info(vchiq_core_log_level, 891 "%d: qm %s@%p,%x (%d->%d)", 892 state->id, 893 msg_type_str(VCHIQ_MSG_TYPE(msgid)), 894 header, size, 895 VCHIQ_MSG_SRCPORT(msgid), 896 VCHIQ_MSG_DSTPORT(msgid)); 897 898 BUG_ON(!service); 899 BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK | 900 QMFLAGS_NO_MUTEX_UNLOCK)) != 0); 901 902 for (i = 0, pos = 0; i < (unsigned int)count; 903 pos += elements[i++].size) 904 if (elements[i].size) { 905 if (vchiq_copy_from_user 906 (header->data + pos, elements[i].data, 907 (size_t) elements[i].size) != 908 VCHIQ_SUCCESS) { 909 lmutex_unlock(&state->slot_mutex); 910 VCHIQ_SERVICE_STATS_INC(service, 911 error_count); 912 return VCHIQ_ERROR; 913 } 914 } 915 916 if (SRVTRACE_ENABLED(service, 917 VCHIQ_LOG_INFO)) 918 vchiq_log_dump_mem("Sent", 0, 919 header->data, 920 min(16, pos)); 921 922 spin_lock("a_spinlock); 923 service_quota->message_use_count++; 924 925 tx_end_index = 926 SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos - 1); 927 928 /* If this transmission can't fit in the last slot used by any 929 ** service, the data_use_count must be increased. */ 930 if (tx_end_index != state->previous_data_index) { 931 state->previous_data_index = tx_end_index; 932 state->data_use_count++; 933 } 934 935 /* If this isn't the same slot last used by this service, 936 ** the service's slot_use_count must be increased. */ 937 if (tx_end_index != service_quota->previous_tx_index) { 938 service_quota->previous_tx_index = tx_end_index; 939 slot_use_count = ++service_quota->slot_use_count; 940 } else { 941 slot_use_count = 0; 942 } 943 944 spin_unlock("a_spinlock); 945 946 if (slot_use_count) 947 vchiq_log_trace(vchiq_core_log_level, 948 "%d: qm:%d %s,%x - slot_use->%d (hdr %p)", 949 state->id, service->localport, 950 msg_type_str(VCHIQ_MSG_TYPE(msgid)), size, 951 slot_use_count, header); 952 953 VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count); 954 VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size); 955 } else { 956 vchiq_log_info(vchiq_core_log_level, 957 "%d: qm %s@%p,%x (%d->%d)", state->id, 958 msg_type_str(VCHIQ_MSG_TYPE(msgid)), 959 header, size, 960 VCHIQ_MSG_SRCPORT(msgid), 961 VCHIQ_MSG_DSTPORT(msgid)); 962 if (size != 0) { 963 WARN_ON(!((count == 1) && (size == elements[0].size))); 964 memcpy(header->data, elements[0].data, 965 elements[0].size); 966 } 967 VCHIQ_STATS_INC(state, ctrl_tx_count); 968 } 969 970 header->msgid = htole32(msgid); 971 header->size = htole32(size); 972 973 { 974 int svc_fourcc; 975 976 svc_fourcc = service 977 ? service->base.fourcc 978 : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); 979 980 vchiq_log_info(SRVTRACE_LEVEL(service), 981 "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d", 982 msg_type_str(VCHIQ_MSG_TYPE(msgid)), 983 VCHIQ_MSG_TYPE(msgid), 984 VCHIQ_FOURCC_AS_4CHARS(svc_fourcc), 985 VCHIQ_MSG_SRCPORT(msgid), 986 VCHIQ_MSG_DSTPORT(msgid), 987 size); 988 } 989 990 /* Make sure the new header is visible to the peer. */ 991 wmb(); 992 993 /* Make the new tx_pos visible to the peer. */ 994 local->tx_pos = htole32(state->local_tx_pos); 995 wmb(); 996 997 if (service && (type == VCHIQ_MSG_CLOSE)) 998 vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT); 999 1000 if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK)) 1001 lmutex_unlock(&state->slot_mutex); 1002 1003 remote_event_signal(&state->remote->trigger); 1004 1005 return VCHIQ_SUCCESS; 1006 } 1007 1008 /* Called by the slot handler and application threads */ 1009 static VCHIQ_STATUS_T 1010 queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, 1011 uint32_t msgid, const VCHIQ_ELEMENT_T *elements, 1012 int count, int size, int is_blocking) 1013 { 1014 VCHIQ_SHARED_STATE_T *local; 1015 VCHIQ_HEADER_T *header; 1016 1017 local = state->local; 1018 1019 if ((VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_RESUME) && 1020 (lmutex_lock_interruptible(&state->sync_mutex) != 0)) 1021 return VCHIQ_RETRY; 1022 1023 remote_event_wait(state, &local->sync_release); 1024 1025 rmb(); 1026 1027 header = (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, 1028 le32toh(local->slot_sync)); 1029 1030 { 1031 uint32_t oldmsgid = le32toh(header->msgid); 1032 if (oldmsgid != VCHIQ_MSGID_PADDING) 1033 vchiq_log_error(vchiq_core_log_level, 1034 "%d: qms - msgid %x, not PADDING", 1035 state->id, oldmsgid); 1036 } 1037 1038 if (service) { 1039 int i, pos; 1040 1041 vchiq_log_info(vchiq_sync_log_level, 1042 "%d: qms %s@%p,%x (%d->%d)", state->id, 1043 msg_type_str(VCHIQ_MSG_TYPE(msgid)), 1044 header, size, 1045 VCHIQ_MSG_SRCPORT(msgid), 1046 VCHIQ_MSG_DSTPORT(msgid)); 1047 1048 for (i = 0, pos = 0; i < (unsigned int)count; 1049 pos += elements[i++].size) 1050 if (elements[i].size) { 1051 if (vchiq_copy_from_user 1052 (header->data + pos, elements[i].data, 1053 (size_t) elements[i].size) != 1054 VCHIQ_SUCCESS) { 1055 lmutex_unlock(&state->sync_mutex); 1056 VCHIQ_SERVICE_STATS_INC(service, 1057 error_count); 1058 return VCHIQ_ERROR; 1059 } 1060 } 1061 1062 if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) 1063 vchiq_log_dump_mem("Sent Sync", 1064 0, header->data, 1065 min(16, pos)); 1066 1067 VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count); 1068 VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size); 1069 } else { 1070 vchiq_log_info(vchiq_sync_log_level, 1071 "%d: qms %s@%p,%x (%d->%d)", state->id, 1072 msg_type_str(VCHIQ_MSG_TYPE(msgid)), 1073 header, size, 1074 VCHIQ_MSG_SRCPORT(msgid), 1075 VCHIQ_MSG_DSTPORT(msgid)); 1076 if (size != 0) { 1077 WARN_ON(!((count == 1) && (size == elements[0].size))); 1078 memcpy(header->data, elements[0].data, 1079 elements[0].size); 1080 } 1081 VCHIQ_STATS_INC(state, ctrl_tx_count); 1082 } 1083 1084 header->size = htole32(size); 1085 header->msgid = htole32(msgid); 1086 1087 if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) { 1088 int svc_fourcc; 1089 1090 svc_fourcc = service 1091 ? service->base.fourcc 1092 : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); 1093 1094 vchiq_log_trace(vchiq_sync_log_level, 1095 "Sent Sync Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d", 1096 msg_type_str(VCHIQ_MSG_TYPE(msgid)), 1097 VCHIQ_MSG_TYPE(msgid), 1098 VCHIQ_FOURCC_AS_4CHARS(svc_fourcc), 1099 VCHIQ_MSG_SRCPORT(msgid), 1100 VCHIQ_MSG_DSTPORT(msgid), 1101 size); 1102 } 1103 1104 /* Make sure the new header is visible to the peer. */ 1105 wmb(); 1106 1107 remote_event_signal(&state->remote->sync_trigger); 1108 1109 if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE) 1110 lmutex_unlock(&state->sync_mutex); 1111 1112 return VCHIQ_SUCCESS; 1113 } 1114 1115 static inline void 1116 claim_slot(VCHIQ_SLOT_INFO_T *slot) 1117 { 1118 slot->use_count = htole16(le16toh(slot->use_count) + 1); 1119 } 1120 1121 static void 1122 release_slot(VCHIQ_STATE_T *state, VCHIQ_SLOT_INFO_T *slot_info, 1123 VCHIQ_HEADER_T *header, VCHIQ_SERVICE_T *service) 1124 { 1125 int release_count; 1126 1127 lmutex_lock(&state->recycle_mutex); 1128 1129 if (header) { 1130 uint32_t msgid = le32toh(header->msgid); 1131 if (((msgid & VCHIQ_MSGID_CLAIMED) == 0) || 1132 (service && service->closing)) { 1133 lmutex_unlock(&state->recycle_mutex); 1134 return; 1135 } 1136 1137 /* Rewrite the message header to prevent a double 1138 ** release */ 1139 header->msgid = htole32(msgid & ~VCHIQ_MSGID_CLAIMED); 1140 } 1141 1142 release_count = le16toh(slot_info->release_count); 1143 slot_info->release_count = htole16(++release_count); 1144 1145 if (release_count == le16toh(slot_info->use_count)) { 1146 int slot_queue_recycle; 1147 /* Add to the freed queue */ 1148 1149 /* A read barrier is necessary here to prevent speculative 1150 ** fetches of remote->slot_queue_recycle from overtaking the 1151 ** mutex. */ 1152 rmb(); 1153 1154 slot_queue_recycle = le32toh(state->remote->slot_queue_recycle); 1155 state->remote->slot_queue[slot_queue_recycle & 1156 VCHIQ_SLOT_QUEUE_MASK] = 1157 htole32(SLOT_INDEX_FROM_INFO(state, slot_info)); 1158 state->remote->slot_queue_recycle = htole32(slot_queue_recycle + 1); 1159 vchiq_log_info(vchiq_core_log_level, 1160 "%d: release_slot %d - recycle->%x", 1161 state->id, SLOT_INDEX_FROM_INFO(state, slot_info), 1162 le32toh(state->remote->slot_queue_recycle)); 1163 1164 /* A write barrier is necessary, but remote_event_signal 1165 ** contains one. */ 1166 remote_event_signal(&state->remote->recycle); 1167 } 1168 1169 lmutex_unlock(&state->recycle_mutex); 1170 } 1171 1172 /* Called by the slot handler - don't hold the bulk mutex */ 1173 static VCHIQ_STATUS_T 1174 notify_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue, 1175 int retry_poll) 1176 { 1177 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 1178 1179 vchiq_log_trace(vchiq_core_log_level, 1180 "%d: nb:%d %cx - p=%x rn=%x r=%x", 1181 service->state->id, service->localport, 1182 (queue == &service->bulk_tx) ? 't' : 'r', 1183 queue->process, queue->remote_notify, queue->remove); 1184 1185 if (service->state->is_master) { 1186 while (queue->remote_notify != queue->process) { 1187 VCHIQ_BULK_T *bulk = 1188 &queue->bulks[BULK_INDEX(queue->remote_notify)]; 1189 uint32_t msgtype = (bulk->dir == VCHIQ_BULK_TRANSMIT) ? 1190 VCHIQ_MSG_BULK_RX_DONE : VCHIQ_MSG_BULK_TX_DONE; 1191 uint32_t msgid = VCHIQ_MAKE_MSG(msgtype, service->localport, 1192 service->remoteport); 1193 uint32_t actual = htole32(bulk->actual); 1194 VCHIQ_ELEMENT_T element = { &actual, 4 }; 1195 /* Only reply to non-dummy bulk requests */ 1196 if (bulk->remote_data) { 1197 status = queue_message(service->state, NULL, 1198 msgid, &element, 1, 4, 0); 1199 if (status != VCHIQ_SUCCESS) 1200 break; 1201 } 1202 queue->remote_notify++; 1203 } 1204 } else { 1205 queue->remote_notify = queue->process; 1206 } 1207 1208 if (status == VCHIQ_SUCCESS) { 1209 while (queue->remove != queue->remote_notify) { 1210 VCHIQ_BULK_T *bulk = 1211 &queue->bulks[BULK_INDEX(queue->remove)]; 1212 1213 /* Only generate callbacks for non-dummy bulk 1214 ** requests, and non-terminated services */ 1215 if (bulk->data && service->instance) { 1216 if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) { 1217 if (bulk->dir == VCHIQ_BULK_TRANSMIT) { 1218 VCHIQ_SERVICE_STATS_INC(service, 1219 bulk_tx_count); 1220 VCHIQ_SERVICE_STATS_ADD(service, 1221 bulk_tx_bytes, 1222 bulk->actual); 1223 } else { 1224 VCHIQ_SERVICE_STATS_INC(service, 1225 bulk_rx_count); 1226 VCHIQ_SERVICE_STATS_ADD(service, 1227 bulk_rx_bytes, 1228 bulk->actual); 1229 } 1230 } else { 1231 VCHIQ_SERVICE_STATS_INC(service, 1232 bulk_aborted_count); 1233 } 1234 if (bulk->mode == VCHIQ_BULK_MODE_BLOCKING) { 1235 struct bulk_waiter *waiter; 1236 spin_lock(&bulk_waiter_spinlock); 1237 waiter = bulk->userdata; 1238 if (waiter) { 1239 waiter->actual = bulk->actual; 1240 up(&waiter->event); 1241 } 1242 spin_unlock(&bulk_waiter_spinlock); 1243 } else if (bulk->mode == 1244 VCHIQ_BULK_MODE_CALLBACK) { 1245 VCHIQ_REASON_T reason = (bulk->dir == 1246 VCHIQ_BULK_TRANSMIT) ? 1247 ((bulk->actual == 1248 VCHIQ_BULK_ACTUAL_ABORTED) ? 1249 VCHIQ_BULK_TRANSMIT_ABORTED : 1250 VCHIQ_BULK_TRANSMIT_DONE) : 1251 ((bulk->actual == 1252 VCHIQ_BULK_ACTUAL_ABORTED) ? 1253 VCHIQ_BULK_RECEIVE_ABORTED : 1254 VCHIQ_BULK_RECEIVE_DONE); 1255 status = make_service_callback(service, 1256 reason, NULL, bulk->userdata); 1257 if (status == VCHIQ_RETRY) 1258 break; 1259 } 1260 } 1261 1262 queue->remove++; 1263 up(&service->bulk_remove_event); 1264 } 1265 if (!retry_poll) 1266 status = VCHIQ_SUCCESS; 1267 } 1268 1269 if (status == VCHIQ_RETRY) 1270 request_poll(service->state, service, 1271 (queue == &service->bulk_tx) ? 1272 VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY); 1273 1274 return status; 1275 } 1276 1277 /* Called by the slot handler thread */ 1278 static void 1279 poll_services(VCHIQ_STATE_T *state) 1280 { 1281 int group, i; 1282 1283 for (group = 0; group < BITSET_SIZE(state->unused_service); group++) { 1284 uint32_t flags; 1285 flags = atomic_xchg(&state->poll_services[group], 0); 1286 for (i = 0; flags; i++) { 1287 if (flags & (1 << i)) { 1288 VCHIQ_SERVICE_T *service = 1289 find_service_by_port(state, 1290 (group<<5) + i); 1291 uint32_t service_flags; 1292 flags &= ~(1 << i); 1293 if (!service) 1294 continue; 1295 service_flags = 1296 atomic_xchg(&service->poll_flags, 0); 1297 if (service_flags & 1298 (1 << VCHIQ_POLL_REMOVE)) { 1299 vchiq_log_info(vchiq_core_log_level, 1300 "%d: ps - remove %d<->%d", 1301 state->id, service->localport, 1302 service->remoteport); 1303 1304 /* Make it look like a client, because 1305 it must be removed and not left in 1306 the LISTENING state. */ 1307 service->public_fourcc = 1308 VCHIQ_FOURCC_INVALID; 1309 1310 if (vchiq_close_service_internal( 1311 service, 0/*!close_recvd*/) != 1312 VCHIQ_SUCCESS) 1313 request_poll(state, service, 1314 VCHIQ_POLL_REMOVE); 1315 } else if (service_flags & 1316 (1 << VCHIQ_POLL_TERMINATE)) { 1317 vchiq_log_info(vchiq_core_log_level, 1318 "%d: ps - terminate %d<->%d", 1319 state->id, service->localport, 1320 service->remoteport); 1321 if (vchiq_close_service_internal( 1322 service, 0/*!close_recvd*/) != 1323 VCHIQ_SUCCESS) 1324 request_poll(state, service, 1325 VCHIQ_POLL_TERMINATE); 1326 } 1327 if (service_flags & (1 << VCHIQ_POLL_TXNOTIFY)) 1328 notify_bulks(service, 1329 &service->bulk_tx, 1330 1/*retry_poll*/); 1331 if (service_flags & (1 << VCHIQ_POLL_RXNOTIFY)) 1332 notify_bulks(service, 1333 &service->bulk_rx, 1334 1/*retry_poll*/); 1335 unlock_service(service); 1336 } 1337 } 1338 } 1339 } 1340 1341 /* Called by the slot handler or application threads, holding the bulk mutex. */ 1342 static int 1343 resolve_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue) 1344 { 1345 VCHIQ_STATE_T *state = service->state; 1346 int resolved = 0; 1347 int rc; 1348 1349 while ((queue->process != queue->local_insert) && 1350 (queue->process != queue->remote_insert)) { 1351 VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)]; 1352 1353 vchiq_log_trace(vchiq_core_log_level, 1354 "%d: rb:%d %cx - li=%x ri=%x p=%x", 1355 state->id, service->localport, 1356 (queue == &service->bulk_tx) ? 't' : 'r', 1357 queue->local_insert, queue->remote_insert, 1358 queue->process); 1359 1360 WARN_ON(!((int)(queue->local_insert - queue->process) > 0)); 1361 WARN_ON(!((int)(queue->remote_insert - queue->process) > 0)); 1362 1363 rc = lmutex_lock_interruptible(&state->bulk_transfer_mutex); 1364 if (rc != 0) 1365 break; 1366 1367 vchiq_transfer_bulk(bulk); 1368 lmutex_unlock(&state->bulk_transfer_mutex); 1369 1370 if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) { 1371 const char *header = (queue == &service->bulk_tx) ? 1372 "Send Bulk to" : "Recv Bulk from"; 1373 if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED) 1374 vchiq_log_info(SRVTRACE_LEVEL(service), 1375 "%s %c%c%c%c d:%d len:%d %p<->%p", 1376 header, 1377 VCHIQ_FOURCC_AS_4CHARS( 1378 service->base.fourcc), 1379 service->remoteport, 1380 bulk->size, 1381 bulk->data, 1382 bulk->remote_data); 1383 else 1384 vchiq_log_info(SRVTRACE_LEVEL(service), 1385 "%s %c%c%c%c d:%d ABORTED - tx len:%d," 1386 " rx len:%d %p<->%p", 1387 header, 1388 VCHIQ_FOURCC_AS_4CHARS( 1389 service->base.fourcc), 1390 service->remoteport, 1391 bulk->size, 1392 bulk->remote_size, 1393 bulk->data, 1394 bulk->remote_data); 1395 } 1396 1397 vchiq_complete_bulk(bulk); 1398 queue->process++; 1399 resolved++; 1400 } 1401 return resolved; 1402 } 1403 1404 /* Called with the bulk_mutex held */ 1405 static void 1406 abort_outstanding_bulks(VCHIQ_SERVICE_T *service, VCHIQ_BULK_QUEUE_T *queue) 1407 { 1408 int is_tx = (queue == &service->bulk_tx); 1409 vchiq_log_trace(vchiq_core_log_level, 1410 "%d: aob:%d %cx - li=%x ri=%x p=%x", 1411 service->state->id, service->localport, is_tx ? 't' : 'r', 1412 queue->local_insert, queue->remote_insert, queue->process); 1413 1414 WARN_ON(!((int)(queue->local_insert - queue->process) >= 0)); 1415 WARN_ON(!((int)(queue->remote_insert - queue->process) >= 0)); 1416 1417 while ((queue->process != queue->local_insert) || 1418 (queue->process != queue->remote_insert)) { 1419 VCHIQ_BULK_T *bulk = &queue->bulks[BULK_INDEX(queue->process)]; 1420 1421 if (queue->process == queue->remote_insert) { 1422 /* fabricate a matching dummy bulk */ 1423 bulk->remote_data = NULL; 1424 bulk->remote_size = 0; 1425 queue->remote_insert++; 1426 } 1427 1428 if (queue->process != queue->local_insert) { 1429 vchiq_complete_bulk(bulk); 1430 1431 vchiq_log_info(SRVTRACE_LEVEL(service), 1432 "%s %c%c%c%c d:%d ABORTED - tx len:%d, " 1433 "rx len:%d", 1434 is_tx ? "Send Bulk to" : "Recv Bulk from", 1435 VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc), 1436 service->remoteport, 1437 bulk->size, 1438 bulk->remote_size); 1439 } else { 1440 /* fabricate a matching dummy bulk */ 1441 bulk->data = NULL; 1442 bulk->size = 0; 1443 bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED; 1444 bulk->dir = is_tx ? VCHIQ_BULK_TRANSMIT : 1445 VCHIQ_BULK_RECEIVE; 1446 queue->local_insert++; 1447 } 1448 1449 queue->process++; 1450 } 1451 } 1452 1453 /* Called from the slot handler thread */ 1454 static void 1455 pause_bulks(VCHIQ_STATE_T *state) 1456 { 1457 if (unlikely(atomic_inc_return(&pause_bulks_count) != 1)) { 1458 WARN_ON_ONCE(1); 1459 atomic_set(&pause_bulks_count, 1); 1460 return; 1461 } 1462 1463 /* Block bulk transfers from all services */ 1464 lmutex_lock(&state->bulk_transfer_mutex); 1465 } 1466 1467 /* Called from the slot handler thread */ 1468 static void 1469 resume_bulks(VCHIQ_STATE_T *state) 1470 { 1471 int i; 1472 if (unlikely(atomic_dec_return(&pause_bulks_count) != 0)) { 1473 WARN_ON_ONCE(1); 1474 atomic_set(&pause_bulks_count, 0); 1475 return; 1476 } 1477 1478 /* Allow bulk transfers from all services */ 1479 lmutex_unlock(&state->bulk_transfer_mutex); 1480 1481 if (state->deferred_bulks == 0) 1482 return; 1483 1484 /* Deal with any bulks which had to be deferred due to being in 1485 * paused state. Don't try to match up to number of deferred bulks 1486 * in case we've had something come and close the service in the 1487 * interim - just process all bulk queues for all services */ 1488 vchiq_log_info(vchiq_core_log_level, "%s: processing %d deferred bulks", 1489 __func__, state->deferred_bulks); 1490 1491 for (i = 0; i < state->unused_service; i++) { 1492 VCHIQ_SERVICE_T *service = state->services[i]; 1493 int resolved_rx = 0; 1494 int resolved_tx = 0; 1495 if (!service || (service->srvstate != VCHIQ_SRVSTATE_OPEN)) 1496 continue; 1497 1498 lmutex_lock(&service->bulk_mutex); 1499 resolved_rx = resolve_bulks(service, &service->bulk_rx); 1500 resolved_tx = resolve_bulks(service, &service->bulk_tx); 1501 lmutex_unlock(&service->bulk_mutex); 1502 if (resolved_rx) 1503 notify_bulks(service, &service->bulk_rx, 1); 1504 if (resolved_tx) 1505 notify_bulks(service, &service->bulk_tx, 1); 1506 } 1507 state->deferred_bulks = 0; 1508 } 1509 1510 static int 1511 parse_open(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header) 1512 { 1513 VCHIQ_SERVICE_T *service = NULL; 1514 uint32_t msgid; 1515 int size; 1516 unsigned int localport, remoteport; 1517 1518 msgid = le32toh(header->msgid); 1519 size = le32toh(header->size); 1520 //uint32_t type = VCHIQ_MSG_TYPE(msgid); 1521 localport = VCHIQ_MSG_DSTPORT(msgid); 1522 remoteport = VCHIQ_MSG_SRCPORT(msgid); 1523 if (size >= sizeof(struct vchiq_open_payload)) { 1524 const struct vchiq_open_payload *payload = 1525 (struct vchiq_open_payload *)header->data; 1526 unsigned int fourcc; 1527 1528 fourcc = le32toh(payload->fourcc); 1529 vchiq_log_info(vchiq_core_log_level, 1530 "%d: prs OPEN@%p (%d->'%c%c%c%c')", 1531 state->id, header, 1532 localport, 1533 VCHIQ_FOURCC_AS_4CHARS(fourcc)); 1534 1535 service = get_listening_service(state, fourcc); 1536 1537 if (service) { 1538 /* A matching service exists */ 1539 short v = le16toh(payload->version); 1540 short version_min = le16toh(payload->version_min); 1541 if ((service->version < version_min) || 1542 (v < service->version_min)) { 1543 /* Version mismatch */ 1544 vchiq_loud_error_header(); 1545 vchiq_loud_error("%d: service %d (%c%c%c%c) " 1546 "version mismatch - local (%d, min %d)" 1547 " vs. remote (%d, min %d)", 1548 state->id, service->localport, 1549 VCHIQ_FOURCC_AS_4CHARS(fourcc), 1550 service->version, service->version_min, 1551 v, version_min); 1552 vchiq_loud_error_footer(); 1553 unlock_service(service); 1554 goto fail_open; 1555 } 1556 service->peer_version = v; 1557 1558 if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) { 1559 struct vchiq_openack_payload ack_payload = { 1560 htole16(service->version) 1561 }; 1562 VCHIQ_ELEMENT_T body = { 1563 &ack_payload, 1564 sizeof(ack_payload) 1565 }; 1566 1567 if (state->version_common < 1568 VCHIQ_VERSION_SYNCHRONOUS_MODE) 1569 service->sync = 0; 1570 1571 /* Acknowledge the OPEN */ 1572 if (service->sync && 1573 (state->version_common >= 1574 VCHIQ_VERSION_SYNCHRONOUS_MODE)) { 1575 if (queue_message_sync(state, NULL, 1576 VCHIQ_MAKE_MSG( 1577 VCHIQ_MSG_OPENACK, 1578 service->localport, 1579 remoteport), 1580 &body, 1, sizeof(ack_payload), 1581 0) == VCHIQ_RETRY) 1582 goto bail_not_ready; 1583 } else { 1584 if (queue_message(state, NULL, 1585 VCHIQ_MAKE_MSG( 1586 VCHIQ_MSG_OPENACK, 1587 service->localport, 1588 remoteport), 1589 &body, 1, sizeof(ack_payload), 1590 0) == VCHIQ_RETRY) 1591 goto bail_not_ready; 1592 } 1593 1594 /* The service is now open */ 1595 vchiq_set_service_state(service, 1596 service->sync ? VCHIQ_SRVSTATE_OPENSYNC 1597 : VCHIQ_SRVSTATE_OPEN); 1598 } 1599 1600 service->remoteport = remoteport; 1601 service->client_id = le32toh(((uint32_t *)header->data)[1]); 1602 if (make_service_callback(service, VCHIQ_SERVICE_OPENED, 1603 NULL, NULL) == VCHIQ_RETRY) { 1604 /* Bail out if not ready */ 1605 service->remoteport = VCHIQ_PORT_FREE; 1606 goto bail_not_ready; 1607 } 1608 1609 /* Success - the message has been dealt with */ 1610 unlock_service(service); 1611 return 1; 1612 } 1613 } 1614 1615 fail_open: 1616 /* No available service, or an invalid request - send a CLOSE */ 1617 if (queue_message(state, NULL, 1618 VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)), 1619 NULL, 0, 0, 0) == VCHIQ_RETRY) 1620 goto bail_not_ready; 1621 1622 return 1; 1623 1624 bail_not_ready: 1625 if (service) 1626 unlock_service(service); 1627 1628 return 0; 1629 } 1630 1631 /* Called by the slot handler thread */ 1632 static void 1633 parse_rx_slots(VCHIQ_STATE_T *state) 1634 { 1635 VCHIQ_SHARED_STATE_T *remote = state->remote; 1636 VCHIQ_SERVICE_T *service = NULL; 1637 int tx_pos; 1638 DEBUG_INITIALISE(state->local) 1639 1640 tx_pos = le32toh(remote->tx_pos); 1641 1642 while (state->rx_pos != tx_pos) { 1643 VCHIQ_HEADER_T *header; 1644 uint32_t msgid; 1645 int size; 1646 uint32_t type; 1647 unsigned int localport, remoteport; 1648 1649 DEBUG_TRACE(PARSE_LINE); 1650 if (!state->rx_data) { 1651 int rx_index; 1652 WARN_ON(!((state->rx_pos & VCHIQ_SLOT_MASK) == 0)); 1653 rx_index = le32toh(remote->slot_queue[ 1654 SLOT_QUEUE_INDEX_FROM_POS(state->rx_pos) & 1655 VCHIQ_SLOT_QUEUE_MASK]); 1656 state->rx_data = (char *)SLOT_DATA_FROM_INDEX(state, 1657 rx_index); 1658 state->rx_info = SLOT_INFO_FROM_INDEX(state, rx_index); 1659 1660 /* Initialise use_count to one, and increment 1661 ** release_count at the end of the slot to avoid 1662 ** releasing the slot prematurely. */ 1663 state->rx_info->use_count = htole16(1); 1664 state->rx_info->release_count = htole16(0); 1665 } 1666 1667 header = (VCHIQ_HEADER_T *)(state->rx_data + 1668 (state->rx_pos & VCHIQ_SLOT_MASK)); 1669 DEBUG_VALUE(PARSE_HEADER, (int)(intptr_t)header); 1670 msgid = le32toh(header->msgid); 1671 DEBUG_VALUE(PARSE_MSGID, msgid); 1672 size = le32toh(header->size); 1673 type = VCHIQ_MSG_TYPE(msgid); 1674 localport = VCHIQ_MSG_DSTPORT(msgid); 1675 remoteport = VCHIQ_MSG_SRCPORT(msgid); 1676 1677 if (type != VCHIQ_MSG_DATA) 1678 VCHIQ_STATS_INC(state, ctrl_rx_count); 1679 1680 switch (type) { 1681 case VCHIQ_MSG_OPENACK: 1682 case VCHIQ_MSG_CLOSE: 1683 case VCHIQ_MSG_DATA: 1684 case VCHIQ_MSG_BULK_RX: 1685 case VCHIQ_MSG_BULK_TX: 1686 case VCHIQ_MSG_BULK_RX_DONE: 1687 case VCHIQ_MSG_BULK_TX_DONE: 1688 service = find_service_by_port(state, localport); 1689 if ((!service || 1690 ((service->remoteport != remoteport) && 1691 (service->remoteport != VCHIQ_PORT_FREE))) && 1692 (localport == 0) && 1693 (type == VCHIQ_MSG_CLOSE)) { 1694 /* This could be a CLOSE from a client which 1695 hadn't yet received the OPENACK - look for 1696 the connected service */ 1697 if (service) 1698 unlock_service(service); 1699 service = get_connected_service(state, 1700 remoteport); 1701 if (service) 1702 vchiq_log_warning(vchiq_core_log_level, 1703 "%d: prs %s@%p (%d->%d) - " 1704 "found connected service %d", 1705 state->id, msg_type_str(type), 1706 header, 1707 remoteport, localport, 1708 service->localport); 1709 } 1710 1711 if (!service) { 1712 vchiq_log_error(vchiq_core_log_level, 1713 "%d: prs %s@%p (%d->%d) - " 1714 "invalid/closed service %d", 1715 state->id, msg_type_str(type), 1716 header, 1717 remoteport, localport, localport); 1718 goto skip_message; 1719 } 1720 break; 1721 default: 1722 break; 1723 } 1724 1725 if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) { 1726 int svc_fourcc; 1727 1728 svc_fourcc = service 1729 ? service->base.fourcc 1730 : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); 1731 vchiq_log_info(SRVTRACE_LEVEL(service), 1732 "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d " 1733 "len:%d", 1734 msg_type_str(type), type, 1735 VCHIQ_FOURCC_AS_4CHARS(svc_fourcc), 1736 remoteport, localport, size); 1737 if (size > 0) 1738 vchiq_log_dump_mem("Rcvd", 0, header->data, 1739 min(16, size)); 1740 } 1741 1742 if (((unsigned int)(uintptr_t)header & VCHIQ_SLOT_MASK) + calc_stride(size) 1743 > VCHIQ_SLOT_SIZE) { 1744 vchiq_log_error(vchiq_core_log_level, 1745 "header %p (msgid %x) - size %x too big for " 1746 "slot", 1747 header, msgid, 1748 (unsigned int)size); 1749 WARN(1, "oversized for slot\n"); 1750 } 1751 1752 switch (type) { 1753 case VCHIQ_MSG_OPEN: 1754 WARN_ON(!(VCHIQ_MSG_DSTPORT(msgid) == 0)); 1755 if (!parse_open(state, header)) 1756 goto bail_not_ready; 1757 break; 1758 case VCHIQ_MSG_OPENACK: 1759 if (size >= sizeof(struct vchiq_openack_payload)) { 1760 const struct vchiq_openack_payload *payload = 1761 (struct vchiq_openack_payload *) 1762 header->data; 1763 service->peer_version = le16toh(payload->version); 1764 } 1765 vchiq_log_info(vchiq_core_log_level, 1766 "%d: prs OPENACK@%p,%x (%d->%d) v:%d", 1767 state->id, header, size, 1768 remoteport, localport, service->peer_version); 1769 if (service->srvstate == 1770 VCHIQ_SRVSTATE_OPENING) { 1771 service->remoteport = remoteport; 1772 vchiq_set_service_state(service, 1773 VCHIQ_SRVSTATE_OPEN); 1774 up(&service->remove_event); 1775 } else 1776 vchiq_log_error(vchiq_core_log_level, 1777 "OPENACK received in state %s", 1778 srvstate_names[service->srvstate]); 1779 break; 1780 case VCHIQ_MSG_CLOSE: 1781 WARN_ON(size != 0); /* There should be no data */ 1782 1783 vchiq_log_info(vchiq_core_log_level, 1784 "%d: prs CLOSE@%p (%d->%d)", 1785 state->id, header, 1786 remoteport, localport); 1787 1788 mark_service_closing_internal(service, 1); 1789 1790 if (vchiq_close_service_internal(service, 1791 1/*close_recvd*/) == VCHIQ_RETRY) 1792 goto bail_not_ready; 1793 1794 vchiq_log_info(vchiq_core_log_level, 1795 "Close Service %c%c%c%c s:%u d:%d", 1796 VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc), 1797 service->localport, 1798 service->remoteport); 1799 break; 1800 case VCHIQ_MSG_DATA: 1801 vchiq_log_info(vchiq_core_log_level, 1802 "%d: prs DATA@%p,%x (%d->%d)", 1803 state->id, header, size, 1804 remoteport, localport); 1805 1806 if ((service->remoteport == remoteport) 1807 && (service->srvstate == 1808 VCHIQ_SRVSTATE_OPEN)) { 1809 header->msgid = htole32(msgid | VCHIQ_MSGID_CLAIMED); 1810 claim_slot(state->rx_info); 1811 DEBUG_TRACE(PARSE_LINE); 1812 if (make_service_callback(service, 1813 VCHIQ_MESSAGE_AVAILABLE, header, 1814 NULL) == VCHIQ_RETRY) { 1815 DEBUG_TRACE(PARSE_LINE); 1816 goto bail_not_ready; 1817 } 1818 VCHIQ_SERVICE_STATS_INC(service, ctrl_rx_count); 1819 VCHIQ_SERVICE_STATS_ADD(service, ctrl_rx_bytes, 1820 size); 1821 } else { 1822 VCHIQ_STATS_INC(state, error_count); 1823 } 1824 break; 1825 case VCHIQ_MSG_CONNECT: 1826 vchiq_log_info(vchiq_core_log_level, 1827 "%d: prs CONNECT@%p", 1828 state->id, header); 1829 state->version_common = le16toh(((VCHIQ_SLOT_ZERO_T *) 1830 state->slot_data)->version); 1831 up(&state->connect); 1832 break; 1833 case VCHIQ_MSG_BULK_RX: 1834 case VCHIQ_MSG_BULK_TX: { 1835 VCHIQ_BULK_QUEUE_T *queue; 1836 WARN_ON(!state->is_master); 1837 queue = (type == VCHIQ_MSG_BULK_RX) ? 1838 &service->bulk_tx : &service->bulk_rx; 1839 if ((service->remoteport == remoteport) 1840 && (service->srvstate == 1841 VCHIQ_SRVSTATE_OPEN)) { 1842 VCHIQ_BULK_T *bulk; 1843 int resolved = 0; 1844 uint32_t remote_data, remote_size; 1845 1846 DEBUG_TRACE(PARSE_LINE); 1847 if (lmutex_lock_interruptible( 1848 &service->bulk_mutex) != 0) { 1849 DEBUG_TRACE(PARSE_LINE); 1850 goto bail_not_ready; 1851 } 1852 1853 WARN_ON(!(queue->remote_insert < queue->remove + 1854 VCHIQ_NUM_SERVICE_BULKS)); 1855 bulk = &queue->bulks[ 1856 BULK_INDEX(queue->remote_insert)]; 1857 remote_data = ((uint32_t *)header->data)[0]; 1858 bulk->remote_data = 1859 (void *)(uintptr_t)le32toh(remote_data); 1860 remote_size = ((uint32_t *)header->data)[1]; 1861 bulk->remote_size = le32toh(remote_size); 1862 wmb(); 1863 1864 vchiq_log_info(vchiq_core_log_level, 1865 "%d: prs %s@%p (%d->%d) %x@%p", 1866 state->id, msg_type_str(type), 1867 header, 1868 remoteport, localport, 1869 bulk->remote_size, 1870 bulk->remote_data); 1871 1872 queue->remote_insert++; 1873 1874 if (atomic_read(&pause_bulks_count)) { 1875 state->deferred_bulks++; 1876 vchiq_log_info(vchiq_core_log_level, 1877 "%s: deferring bulk (%d)", 1878 __func__, 1879 state->deferred_bulks); 1880 if (state->conn_state != 1881 VCHIQ_CONNSTATE_PAUSE_SENT) 1882 vchiq_log_error( 1883 vchiq_core_log_level, 1884 "%s: bulks paused in " 1885 "unexpected state %s", 1886 __func__, 1887 conn_state_names[ 1888 state->conn_state]); 1889 } else if (state->conn_state == 1890 VCHIQ_CONNSTATE_CONNECTED) { 1891 DEBUG_TRACE(PARSE_LINE); 1892 resolved = resolve_bulks(service, 1893 queue); 1894 } 1895 1896 lmutex_unlock(&service->bulk_mutex); 1897 if (resolved) 1898 notify_bulks(service, queue, 1899 1/*retry_poll*/); 1900 } 1901 } break; 1902 case VCHIQ_MSG_BULK_RX_DONE: 1903 case VCHIQ_MSG_BULK_TX_DONE: 1904 WARN_ON(state->is_master); 1905 if ((service->remoteport == remoteport) 1906 && (service->srvstate != 1907 VCHIQ_SRVSTATE_FREE)) { 1908 VCHIQ_BULK_QUEUE_T *queue; 1909 VCHIQ_BULK_T *bulk; 1910 1911 queue = (type == VCHIQ_MSG_BULK_RX_DONE) ? 1912 &service->bulk_rx : &service->bulk_tx; 1913 1914 DEBUG_TRACE(PARSE_LINE); 1915 if (lmutex_lock_interruptible( 1916 &service->bulk_mutex) != 0) { 1917 DEBUG_TRACE(PARSE_LINE); 1918 goto bail_not_ready; 1919 } 1920 if ((int)(queue->remote_insert - 1921 queue->local_insert) >= 0) { 1922 vchiq_log_error(vchiq_core_log_level, 1923 "%d: prs %s@%p (%d->%d) " 1924 "unexpected (ri=%d,li=%d)", 1925 state->id, msg_type_str(type), 1926 header, 1927 remoteport, localport, 1928 queue->remote_insert, 1929 queue->local_insert); 1930 lmutex_unlock(&service->bulk_mutex); 1931 break; 1932 } 1933 1934 if (queue->process != queue->remote_insert) { 1935 pr_err("%s: p %x != ri %x\n", 1936 __func__, 1937 queue->process, 1938 queue->remote_insert); 1939 lmutex_unlock(&service->bulk_mutex); 1940 goto bail_not_ready; 1941 } 1942 1943 bulk = &queue->bulks[ 1944 BULK_INDEX(queue->remote_insert)]; 1945 bulk->actual = le32toh(*(uint32_t *)header->data); 1946 queue->remote_insert++; 1947 1948 vchiq_log_info(vchiq_core_log_level, 1949 "%d: prs %s@%p (%d->%d) %x@%p", 1950 state->id, msg_type_str(type), 1951 header, 1952 remoteport, localport, 1953 bulk->actual, bulk->data); 1954 1955 vchiq_log_trace(vchiq_core_log_level, 1956 "%d: prs:%d %cx li=%x ri=%x p=%x", 1957 state->id, localport, 1958 (type == VCHIQ_MSG_BULK_RX_DONE) ? 1959 'r' : 't', 1960 queue->local_insert, 1961 queue->remote_insert, queue->process); 1962 1963 DEBUG_TRACE(PARSE_LINE); 1964 WARN_ON(queue->process == queue->local_insert); 1965 vchiq_complete_bulk(bulk); 1966 queue->process++; 1967 lmutex_unlock(&service->bulk_mutex); 1968 DEBUG_TRACE(PARSE_LINE); 1969 notify_bulks(service, queue, 1/*retry_poll*/); 1970 DEBUG_TRACE(PARSE_LINE); 1971 } 1972 break; 1973 case VCHIQ_MSG_PADDING: 1974 vchiq_log_trace(vchiq_core_log_level, 1975 "%d: prs PADDING@%p,%x", 1976 state->id, header, size); 1977 break; 1978 case VCHIQ_MSG_PAUSE: 1979 /* If initiated, signal the application thread */ 1980 vchiq_log_trace(vchiq_core_log_level, 1981 "%d: prs PAUSE@%p,%x", 1982 state->id, header, size); 1983 if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) { 1984 vchiq_log_error(vchiq_core_log_level, 1985 "%d: PAUSE received in state PAUSED", 1986 state->id); 1987 break; 1988 } 1989 if (state->conn_state != VCHIQ_CONNSTATE_PAUSE_SENT) { 1990 /* Send a PAUSE in response */ 1991 if (queue_message(state, NULL, 1992 VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), 1993 NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK) 1994 == VCHIQ_RETRY) 1995 goto bail_not_ready; 1996 if (state->is_master) 1997 pause_bulks(state); 1998 } 1999 /* At this point slot_mutex is held */ 2000 vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED); 2001 vchiq_platform_paused(state); 2002 break; 2003 case VCHIQ_MSG_RESUME: 2004 vchiq_log_trace(vchiq_core_log_level, 2005 "%d: prs RESUME@%p,%x", 2006 state->id, header, size); 2007 /* Release the slot mutex */ 2008 lmutex_unlock(&state->slot_mutex); 2009 if (state->is_master) 2010 resume_bulks(state); 2011 vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED); 2012 vchiq_platform_resumed(state); 2013 break; 2014 2015 case VCHIQ_MSG_REMOTE_USE: 2016 vchiq_on_remote_use(state); 2017 break; 2018 case VCHIQ_MSG_REMOTE_RELEASE: 2019 vchiq_on_remote_release(state); 2020 break; 2021 case VCHIQ_MSG_REMOTE_USE_ACTIVE: 2022 vchiq_on_remote_use_active(state); 2023 break; 2024 2025 default: 2026 vchiq_log_error(vchiq_core_log_level, 2027 "%d: prs invalid msgid %x@%p,%x", 2028 state->id, msgid, header, size); 2029 WARN(1, "invalid message\n"); 2030 break; 2031 } 2032 2033 skip_message: 2034 if (service) { 2035 unlock_service(service); 2036 service = NULL; 2037 } 2038 2039 state->rx_pos += calc_stride(size); 2040 2041 DEBUG_TRACE(PARSE_LINE); 2042 /* Perform some housekeeping when the end of the slot is 2043 ** reached. */ 2044 if ((state->rx_pos & VCHIQ_SLOT_MASK) == 0) { 2045 /* Remove the extra reference count. */ 2046 release_slot(state, state->rx_info, NULL, NULL); 2047 state->rx_data = NULL; 2048 } 2049 } 2050 2051 bail_not_ready: 2052 if (service) 2053 unlock_service(service); 2054 } 2055 2056 /* Called by the slot handler thread */ 2057 static int slot_handler_func(void *v); 2058 static int 2059 slot_handler_func(void *v) 2060 { 2061 VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v; 2062 VCHIQ_SHARED_STATE_T *local = state->local; 2063 DEBUG_INITIALISE(local) 2064 2065 while (1) { 2066 DEBUG_COUNT(SLOT_HANDLER_COUNT); 2067 DEBUG_TRACE(SLOT_HANDLER_LINE); 2068 remote_event_wait(state, &local->trigger); 2069 2070 rmb(); 2071 2072 DEBUG_TRACE(SLOT_HANDLER_LINE); 2073 if (state->poll_needed) { 2074 /* Check if we need to suspend - may change our 2075 * conn_state */ 2076 vchiq_platform_check_suspend(state); 2077 2078 state->poll_needed = 0; 2079 2080 /* Handle service polling and other rare conditions here 2081 ** out of the mainline code */ 2082 switch (state->conn_state) { 2083 case VCHIQ_CONNSTATE_CONNECTED: 2084 /* Poll the services as requested */ 2085 poll_services(state); 2086 break; 2087 2088 case VCHIQ_CONNSTATE_PAUSING: 2089 if (state->is_master) 2090 pause_bulks(state); 2091 if (queue_message(state, NULL, 2092 VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0), 2093 NULL, 0, 0, 2094 QMFLAGS_NO_MUTEX_UNLOCK) 2095 != VCHIQ_RETRY) { 2096 vchiq_set_conn_state(state, 2097 VCHIQ_CONNSTATE_PAUSE_SENT); 2098 } else { 2099 if (state->is_master) 2100 resume_bulks(state); 2101 /* Retry later */ 2102 state->poll_needed = 1; 2103 } 2104 break; 2105 2106 case VCHIQ_CONNSTATE_PAUSED: 2107 vchiq_platform_resume(state); 2108 break; 2109 2110 case VCHIQ_CONNSTATE_RESUMING: 2111 if (queue_message(state, NULL, 2112 VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0), 2113 NULL, 0, 0, QMFLAGS_NO_MUTEX_LOCK) 2114 != VCHIQ_RETRY) { 2115 if (state->is_master) 2116 resume_bulks(state); 2117 vchiq_set_conn_state(state, 2118 VCHIQ_CONNSTATE_CONNECTED); 2119 vchiq_platform_resumed(state); 2120 } else { 2121 /* This should really be impossible, 2122 ** since the PAUSE should have flushed 2123 ** through outstanding messages. */ 2124 vchiq_log_error(vchiq_core_log_level, 2125 "Failed to send RESUME " 2126 "message"); 2127 BUG(); 2128 } 2129 break; 2130 2131 case VCHIQ_CONNSTATE_PAUSE_TIMEOUT: 2132 case VCHIQ_CONNSTATE_RESUME_TIMEOUT: 2133 vchiq_platform_handle_timeout(state); 2134 break; 2135 default: 2136 break; 2137 } 2138 2139 2140 } 2141 2142 DEBUG_TRACE(SLOT_HANDLER_LINE); 2143 parse_rx_slots(state); 2144 } 2145 return 0; 2146 } 2147 2148 2149 /* Called by the recycle thread */ 2150 static int recycle_func(void *v); 2151 static int 2152 recycle_func(void *v) 2153 { 2154 VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v; 2155 VCHIQ_SHARED_STATE_T *local = state->local; 2156 2157 while (1) { 2158 remote_event_wait(state, &local->recycle); 2159 2160 process_free_queue(state); 2161 } 2162 return 0; 2163 } 2164 2165 2166 /* Called by the sync thread */ 2167 static int sync_func(void *v); 2168 static int 2169 sync_func(void *v) 2170 { 2171 VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v; 2172 VCHIQ_SHARED_STATE_T *local = state->local; 2173 VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, 2174 le32toh(state->remote->slot_sync)); 2175 2176 while (1) { 2177 VCHIQ_SERVICE_T *service; 2178 uint32_t msgid; 2179 int size; 2180 uint32_t type; 2181 unsigned int localport, remoteport; 2182 2183 remote_event_wait(state, &local->sync_trigger); 2184 2185 rmb(); 2186 2187 msgid = le32toh(header->msgid); 2188 size = le32toh(header->size); 2189 type = VCHIQ_MSG_TYPE(msgid); 2190 localport = VCHIQ_MSG_DSTPORT(msgid); 2191 remoteport = VCHIQ_MSG_SRCPORT(msgid); 2192 2193 service = find_service_by_port(state, localport); 2194 2195 if (!service) { 2196 vchiq_log_error(vchiq_sync_log_level, 2197 "%d: sf %s@%p (%d->%d) - " 2198 "invalid/closed service %d", 2199 state->id, msg_type_str(type), 2200 header, 2201 remoteport, localport, localport); 2202 release_message_sync(state, header); 2203 continue; 2204 } 2205 2206 if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE) { 2207 int svc_fourcc; 2208 2209 svc_fourcc = service 2210 ? service->base.fourcc 2211 : VCHIQ_MAKE_FOURCC('?', '?', '?', '?'); 2212 vchiq_log_trace(vchiq_sync_log_level, 2213 "Rcvd Msg %s from %c%c%c%c s:%d d:%d len:%d", 2214 msg_type_str(type), 2215 VCHIQ_FOURCC_AS_4CHARS(svc_fourcc), 2216 remoteport, localport, size); 2217 if (size > 0) 2218 vchiq_log_dump_mem("Rcvd", 0, header->data, 2219 min(16, size)); 2220 } 2221 2222 switch (type) { 2223 case VCHIQ_MSG_OPENACK: 2224 if (size >= sizeof(struct vchiq_openack_payload)) { 2225 const struct vchiq_openack_payload *payload = 2226 (struct vchiq_openack_payload *) 2227 header->data; 2228 service->peer_version = le16toh(payload->version); 2229 } 2230 vchiq_log_info(vchiq_sync_log_level, 2231 "%d: sf OPENACK@%p,%x (%d->%d) v:%d", 2232 state->id, header, size, 2233 remoteport, localport, service->peer_version); 2234 if (service->srvstate == VCHIQ_SRVSTATE_OPENING) { 2235 service->remoteport = remoteport; 2236 vchiq_set_service_state(service, 2237 VCHIQ_SRVSTATE_OPENSYNC); 2238 service->sync = 1; 2239 up(&service->remove_event); 2240 } 2241 release_message_sync(state, header); 2242 break; 2243 2244 case VCHIQ_MSG_DATA: 2245 vchiq_log_trace(vchiq_sync_log_level, 2246 "%d: sf DATA@%p,%x (%d->%d)", 2247 state->id, header, size, 2248 remoteport, localport); 2249 2250 if ((service->remoteport == remoteport) && 2251 (service->srvstate == 2252 VCHIQ_SRVSTATE_OPENSYNC)) { 2253 if (make_service_callback(service, 2254 VCHIQ_MESSAGE_AVAILABLE, header, 2255 NULL) == VCHIQ_RETRY) 2256 vchiq_log_error(vchiq_sync_log_level, 2257 "synchronous callback to " 2258 "service %d returns " 2259 "VCHIQ_RETRY", 2260 localport); 2261 } 2262 break; 2263 2264 default: 2265 vchiq_log_error(vchiq_sync_log_level, 2266 "%d: sf unexpected msgid %x@%p,%x", 2267 state->id, msgid, header, size); 2268 release_message_sync(state, header); 2269 break; 2270 } 2271 2272 unlock_service(service); 2273 } 2274 2275 return 0; 2276 } 2277 2278 2279 static void 2280 init_bulk_queue(VCHIQ_BULK_QUEUE_T *queue) 2281 { 2282 queue->local_insert = 0; 2283 queue->remote_insert = 0; 2284 queue->process = 0; 2285 queue->remote_notify = 0; 2286 queue->remove = 0; 2287 } 2288 2289 2290 inline const char * 2291 get_conn_state_name(VCHIQ_CONNSTATE_T conn_state) 2292 { 2293 return conn_state_names[conn_state]; 2294 } 2295 2296 2297 VCHIQ_SLOT_ZERO_T * 2298 vchiq_init_slots(void *mem_base, int mem_size) 2299 { 2300 int mem_align = (VCHIQ_SLOT_SIZE - (intptr_t)mem_base) & VCHIQ_SLOT_MASK; 2301 VCHIQ_SLOT_ZERO_T *slot_zero = 2302 (VCHIQ_SLOT_ZERO_T *)((char *)mem_base + mem_align); 2303 int num_slots = (mem_size - mem_align)/VCHIQ_SLOT_SIZE; 2304 int first_data_slot = VCHIQ_SLOT_ZERO_SLOTS; 2305 2306 /* Ensure there is enough memory to run an absolutely minimum system */ 2307 num_slots -= first_data_slot; 2308 2309 if (num_slots < 4) { 2310 vchiq_log_error(vchiq_core_log_level, 2311 "vchiq_init_slots - insufficient memory %x bytes", 2312 mem_size); 2313 return NULL; 2314 } 2315 2316 memset(slot_zero, 0, sizeof(VCHIQ_SLOT_ZERO_T)); 2317 2318 slot_zero->magic = htole32(VCHIQ_MAGIC); 2319 slot_zero->version = htole16(VCHIQ_VERSION); 2320 slot_zero->version_min = htole16(VCHIQ_VERSION_MIN); 2321 slot_zero->slot_zero_size = htole32(sizeof(VCHIQ_SLOT_ZERO_T)); 2322 slot_zero->slot_size = htole32(VCHIQ_SLOT_SIZE); 2323 slot_zero->max_slots = htole32(VCHIQ_MAX_SLOTS); 2324 slot_zero->max_slots_per_side = htole32(VCHIQ_MAX_SLOTS_PER_SIDE); 2325 2326 slot_zero->master.slot_sync = htole32(first_data_slot); 2327 slot_zero->master.slot_first = htole32(first_data_slot + 1); 2328 slot_zero->master.slot_last = htole32(first_data_slot + (num_slots/2) - 1); 2329 slot_zero->slave.slot_sync = htole32(first_data_slot + (num_slots/2)); 2330 slot_zero->slave.slot_first = htole32(first_data_slot + (num_slots/2) + 1); 2331 slot_zero->slave.slot_last = htole32(first_data_slot + num_slots - 1); 2332 2333 return slot_zero; 2334 } 2335 2336 VCHIQ_STATUS_T 2337 vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero, 2338 int is_master) 2339 { 2340 VCHIQ_SHARED_STATE_T *local; 2341 VCHIQ_SHARED_STATE_T *remote; 2342 VCHIQ_STATUS_T status; 2343 char threadname[10]; 2344 int i; 2345 2346 vchiq_log_warning(vchiq_core_log_level, 2347 "%s: slot_zero = %p, is_master = %d", 2348 __func__, slot_zero, is_master); 2349 2350 if (vchiq_states[0]) { 2351 pr_err("%s: VCHIQ state already initialized\n", __func__); 2352 return VCHIQ_ERROR; 2353 } 2354 2355 /* Check the input configuration */ 2356 2357 if (le32toh(slot_zero->magic) != VCHIQ_MAGIC) { 2358 vchiq_loud_error_header(); 2359 vchiq_loud_error("Invalid VCHIQ magic value found."); 2360 vchiq_loud_error("slot_zero=%p: magic=%x (expected %x)", 2361 slot_zero, le32toh(slot_zero->magic), VCHIQ_MAGIC); 2362 vchiq_loud_error_footer(); 2363 return VCHIQ_ERROR; 2364 } 2365 2366 vchiq_log_warning(vchiq_core_log_level, 2367 "local ver %d (min %d), remote ver %d.", 2368 VCHIQ_VERSION, VCHIQ_VERSION_MIN, 2369 le16toh(slot_zero->version)); 2370 2371 if (le16toh(slot_zero->version) < VCHIQ_VERSION_MIN) { 2372 vchiq_loud_error_header(); 2373 vchiq_loud_error("Incompatible VCHIQ versions found."); 2374 vchiq_loud_error("slot_zero=%p: VideoCore version=%d " 2375 "(minimum %d)", 2376 slot_zero, le16toh(slot_zero->version), 2377 VCHIQ_VERSION_MIN); 2378 vchiq_loud_error("Restart with a newer VideoCore image."); 2379 vchiq_loud_error_footer(); 2380 return VCHIQ_ERROR; 2381 } 2382 2383 if (VCHIQ_VERSION < le16toh(slot_zero->version_min)) { 2384 vchiq_loud_error_header(); 2385 vchiq_loud_error("Incompatible VCHIQ versions found."); 2386 vchiq_loud_error("slot_zero=%p: version=%d (VideoCore " 2387 "minimum %d)", 2388 slot_zero, VCHIQ_VERSION, 2389 le16toh(slot_zero->version_min)); 2390 vchiq_loud_error("Restart with a newer kernel."); 2391 vchiq_loud_error_footer(); 2392 return VCHIQ_ERROR; 2393 } 2394 2395 if ((le32toh(slot_zero->slot_zero_size) != sizeof(VCHIQ_SLOT_ZERO_T)) || 2396 (le32toh(slot_zero->slot_size) != VCHIQ_SLOT_SIZE) || 2397 (le32toh(slot_zero->max_slots) != VCHIQ_MAX_SLOTS) || 2398 (le32toh(slot_zero->max_slots_per_side) != VCHIQ_MAX_SLOTS_PER_SIDE)) { 2399 vchiq_loud_error_header(); 2400 if (le32toh(slot_zero->slot_zero_size) != sizeof(VCHIQ_SLOT_ZERO_T)) 2401 vchiq_loud_error("slot_zero=%p: slot_zero_size=%x " 2402 "(expected %zx)", 2403 slot_zero, 2404 le32toh(slot_zero->slot_zero_size), 2405 sizeof(VCHIQ_SLOT_ZERO_T)); 2406 if (le32toh(slot_zero->slot_size) != VCHIQ_SLOT_SIZE) 2407 vchiq_loud_error("slot_zero=%p: slot_size=%d " 2408 "(expected %d", 2409 slot_zero, le32toh(slot_zero->slot_size), 2410 VCHIQ_SLOT_SIZE); 2411 if (le32toh(slot_zero->max_slots) != VCHIQ_MAX_SLOTS) 2412 vchiq_loud_error("slot_zero=%p: max_slots=%d " 2413 "(expected %d)", 2414 slot_zero, le32toh(slot_zero->max_slots), 2415 VCHIQ_MAX_SLOTS); 2416 if (le32toh(slot_zero->max_slots_per_side) != VCHIQ_MAX_SLOTS_PER_SIDE) 2417 vchiq_loud_error("slot_zero=%p: max_slots_per_side=%d " 2418 "(expected %d)", 2419 slot_zero, 2420 le32toh(slot_zero->max_slots_per_side), 2421 VCHIQ_MAX_SLOTS_PER_SIDE); 2422 vchiq_loud_error_footer(); 2423 return VCHIQ_ERROR; 2424 } 2425 2426 if (VCHIQ_VERSION < le16toh(slot_zero->version)) 2427 slot_zero->version = htole16(VCHIQ_VERSION); 2428 2429 if (is_master) { 2430 local = &slot_zero->master; 2431 remote = &slot_zero->slave; 2432 } else { 2433 local = &slot_zero->slave; 2434 remote = &slot_zero->master; 2435 } 2436 2437 if (local->initialised) { 2438 vchiq_loud_error_header(); 2439 if (remote->initialised) 2440 vchiq_loud_error("local state has already been " 2441 "initialised"); 2442 else 2443 vchiq_loud_error("master/slave mismatch - two %ss", 2444 is_master ? "master" : "slave"); 2445 vchiq_loud_error_footer(); 2446 return VCHIQ_ERROR; 2447 } 2448 2449 memset(state, 0, sizeof(VCHIQ_STATE_T)); 2450 2451 state->is_master = is_master; 2452 2453 /* 2454 initialize shared state pointers 2455 */ 2456 2457 state->local = local; 2458 state->remote = remote; 2459 state->slot_data = (VCHIQ_SLOT_T *)slot_zero; 2460 2461 /* 2462 initialize events and mutexes 2463 */ 2464 2465 _sema_init(&state->connect, 0); 2466 lmutex_init(&state->mutex); 2467 2468 lmutex_init(&state->slot_mutex); 2469 lmutex_init(&state->recycle_mutex); 2470 lmutex_init(&state->sync_mutex); 2471 lmutex_init(&state->bulk_transfer_mutex); 2472 2473 _sema_init(&state->slot_available_event, 0); 2474 _sema_init(&state->slot_remove_event, 0); 2475 _sema_init(&state->data_quota_event, 0); 2476 2477 state->slot_queue_available = 0; 2478 2479 for (i = 0; i < VCHIQ_MAX_SERVICES; i++) { 2480 VCHIQ_SERVICE_QUOTA_T *service_quota = 2481 &state->service_quotas[i]; 2482 _sema_init(&service_quota->quota_event, 0); 2483 } 2484 2485 for (i = le32toh(local->slot_first); i <= le32toh(local->slot_last); i++) { 2486 local->slot_queue[state->slot_queue_available++] = htole32(i); 2487 up(&state->slot_available_event); 2488 } 2489 2490 state->default_slot_quota = state->slot_queue_available/2; 2491 state->default_message_quota = 2492 min((unsigned short)(state->default_slot_quota * 256), 2493 (unsigned short)~0); 2494 2495 state->previous_data_index = -1; 2496 state->data_use_count = 0; 2497 state->data_quota = state->slot_queue_available - 1; 2498 2499 local->trigger.event = htole32(offsetof(VCHIQ_STATE_T, trigger_event)); 2500 remote_event_create(state, &local->trigger); 2501 local->tx_pos = htole32(0); 2502 2503 local->recycle.event = htole32(offsetof(VCHIQ_STATE_T, recycle_event)); 2504 remote_event_create(state, &local->recycle); 2505 local->slot_queue_recycle = htole32(state->slot_queue_available); 2506 2507 local->sync_trigger.event = htole32(offsetof(VCHIQ_STATE_T, sync_trigger_event)); 2508 remote_event_create(state, &local->sync_trigger); 2509 2510 local->sync_release.event = htole32(offsetof(VCHIQ_STATE_T, sync_release_event)); 2511 remote_event_create(state, &local->sync_release); 2512 2513 /* At start-of-day, the slot is empty and available */ 2514 ((VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, le32toh(local->slot_sync)))->msgid 2515 = htole32(VCHIQ_MSGID_PADDING); 2516 remote_event_signal_local(state, &local->sync_release); 2517 2518 local->debug[DEBUG_ENTRIES] = htole32(DEBUG_MAX); 2519 2520 status = vchiq_platform_init_state(state); 2521 if (status != VCHIQ_SUCCESS) 2522 return VCHIQ_ERROR; 2523 2524 /* 2525 bring up slot handler thread 2526 */ 2527 snprintf(threadname, sizeof(threadname), "VCHIQ-%d", state->id); 2528 state->slot_handler_thread = vchiq_thread_create(&slot_handler_func, 2529 (void *)state, 2530 threadname); 2531 2532 if (state->slot_handler_thread == NULL) { 2533 vchiq_loud_error_header(); 2534 vchiq_loud_error("couldn't create thread %s", threadname); 2535 vchiq_loud_error_footer(); 2536 return VCHIQ_ERROR; 2537 } 2538 set_user_nice(state->slot_handler_thread, -19); 2539 wake_up_process(state->slot_handler_thread); 2540 2541 snprintf(threadname, sizeof(threadname), "VCHIQr-%d", state->id); 2542 state->recycle_thread = vchiq_thread_create(&recycle_func, 2543 (void *)state, 2544 threadname); 2545 if (state->recycle_thread == NULL) { 2546 vchiq_loud_error_header(); 2547 vchiq_loud_error("couldn't create thread %s", threadname); 2548 vchiq_loud_error_footer(); 2549 return VCHIQ_ERROR; 2550 } 2551 set_user_nice(state->recycle_thread, -19); 2552 wake_up_process(state->recycle_thread); 2553 2554 snprintf(threadname, sizeof(threadname), "VCHIQs-%d", state->id); 2555 state->sync_thread = vchiq_thread_create(&sync_func, 2556 (void *)state, 2557 threadname); 2558 if (state->sync_thread == NULL) { 2559 vchiq_loud_error_header(); 2560 vchiq_loud_error("couldn't create thread %s", threadname); 2561 vchiq_loud_error_footer(); 2562 return VCHIQ_ERROR; 2563 } 2564 set_user_nice(state->sync_thread, -20); 2565 wake_up_process(state->sync_thread); 2566 2567 BUG_ON(state->id >= VCHIQ_MAX_STATES); 2568 vchiq_states[0] = state; 2569 2570 /* Indicate readiness to the other side */ 2571 local->initialised = htole32(1); 2572 2573 vchiq_log_info(vchiq_core_log_level, 2574 "%s: local initialized\n", __func__); 2575 2576 return status; 2577 } 2578 2579 /* Called from application thread when a client or server service is created. */ 2580 VCHIQ_SERVICE_T * 2581 vchiq_add_service_internal(VCHIQ_STATE_T *state, 2582 const VCHIQ_SERVICE_PARAMS_T *params, int srvstate, 2583 VCHIQ_INSTANCE_T instance, VCHIQ_USERDATA_TERM_T userdata_term) 2584 { 2585 VCHIQ_SERVICE_T *service; 2586 2587 service = kmalloc(sizeof(VCHIQ_SERVICE_T), GFP_KERNEL); 2588 if (service) { 2589 service->base.fourcc = params->fourcc; 2590 service->base.callback = params->callback; 2591 service->base.userdata = params->userdata; 2592 service->handle = VCHIQ_SERVICE_HANDLE_INVALID; 2593 service->ref_count = 1; 2594 service->srvstate = VCHIQ_SRVSTATE_FREE; 2595 service->userdata_term = userdata_term; 2596 service->localport = VCHIQ_PORT_FREE; 2597 service->remoteport = VCHIQ_PORT_FREE; 2598 2599 service->public_fourcc = (srvstate == VCHIQ_SRVSTATE_OPENING) ? 2600 VCHIQ_FOURCC_INVALID : params->fourcc; 2601 service->client_id = 0; 2602 service->auto_close = 1; 2603 service->sync = 0; 2604 service->closing = 0; 2605 service->trace = 0; 2606 atomic_set(&service->poll_flags, 0); 2607 service->version = params->version; 2608 service->version_min = params->version_min; 2609 service->state = state; 2610 service->instance = instance; 2611 service->service_use_count = 0; 2612 init_bulk_queue(&service->bulk_tx); 2613 init_bulk_queue(&service->bulk_rx); 2614 _sema_init(&service->remove_event, 0); 2615 _sema_init(&service->bulk_remove_event, 0); 2616 lmutex_init(&service->bulk_mutex); 2617 memset(&service->stats, 0, sizeof(service->stats)); 2618 } else { 2619 vchiq_log_error(vchiq_core_log_level, 2620 "Out of memory"); 2621 } 2622 2623 if (service) { 2624 VCHIQ_SERVICE_T **pservice = NULL; 2625 int i; 2626 2627 /* Although it is perfectly possible to use service_spinlock 2628 ** to protect the creation of services, it is overkill as it 2629 ** disables interrupts while the array is searched. 2630 ** The only danger is of another thread trying to create a 2631 ** service - service deletion is safe. 2632 ** Therefore it is preferable to use state->mutex which, 2633 ** although slower to claim, doesn't block interrupts while 2634 ** it is held. 2635 */ 2636 2637 lmutex_lock(&state->mutex); 2638 2639 /* Prepare to use a previously unused service */ 2640 if (state->unused_service < VCHIQ_MAX_SERVICES) 2641 pservice = &state->services[state->unused_service]; 2642 2643 if (srvstate == VCHIQ_SRVSTATE_OPENING) { 2644 for (i = 0; i < state->unused_service; i++) { 2645 VCHIQ_SERVICE_T *srv = state->services[i]; 2646 if (!srv) { 2647 pservice = &state->services[i]; 2648 break; 2649 } 2650 } 2651 } else { 2652 for (i = (state->unused_service - 1); i >= 0; i--) { 2653 VCHIQ_SERVICE_T *srv = state->services[i]; 2654 if (!srv) 2655 pservice = &state->services[i]; 2656 else if ((srv->public_fourcc == params->fourcc) 2657 && ((srv->instance != instance) || 2658 (srv->base.callback != 2659 params->callback))) { 2660 /* There is another server using this 2661 ** fourcc which doesn't match. */ 2662 pservice = NULL; 2663 break; 2664 } 2665 } 2666 } 2667 2668 if (pservice) { 2669 service->localport = (pservice - state->services); 2670 if (!handle_seq) 2671 handle_seq = VCHIQ_MAX_STATES * 2672 VCHIQ_MAX_SERVICES; 2673 service->handle = handle_seq | 2674 (state->id * VCHIQ_MAX_SERVICES) | 2675 service->localport; 2676 handle_seq += VCHIQ_MAX_STATES * VCHIQ_MAX_SERVICES; 2677 *pservice = service; 2678 if (pservice == &state->services[state->unused_service]) 2679 state->unused_service++; 2680 } 2681 2682 lmutex_unlock(&state->mutex); 2683 2684 if (!pservice) { 2685 _sema_destroy(&service->remove_event); 2686 _sema_destroy(&service->bulk_remove_event); 2687 lmutex_destroy(&service->bulk_mutex); 2688 2689 kfree(service); 2690 service = NULL; 2691 } 2692 } 2693 2694 if (service) { 2695 VCHIQ_SERVICE_QUOTA_T *service_quota = 2696 &state->service_quotas[service->localport]; 2697 service_quota->slot_quota = state->default_slot_quota; 2698 service_quota->message_quota = state->default_message_quota; 2699 if (service_quota->slot_use_count == 0) 2700 service_quota->previous_tx_index = 2701 SLOT_QUEUE_INDEX_FROM_POS(state->local_tx_pos) 2702 - 1; 2703 2704 /* Bring this service online */ 2705 vchiq_set_service_state(service, srvstate); 2706 2707 vchiq_log_info(vchiq_core_msg_log_level, 2708 "%s Service %c%c%c%c SrcPort:%d", 2709 (srvstate == VCHIQ_SRVSTATE_OPENING) 2710 ? "Open" : "Add", 2711 VCHIQ_FOURCC_AS_4CHARS(params->fourcc), 2712 service->localport); 2713 } 2714 2715 /* Don't unlock the service - leave it with a ref_count of 1. */ 2716 2717 return service; 2718 } 2719 2720 VCHIQ_STATUS_T 2721 vchiq_open_service_internal(VCHIQ_SERVICE_T *service, int client_id) 2722 { 2723 struct vchiq_open_payload payload = { 2724 htole32(service->base.fourcc), 2725 htole32(client_id), 2726 htole16(service->version), 2727 htole16(service->version_min) 2728 }; 2729 VCHIQ_ELEMENT_T body = { &payload, sizeof(payload) }; 2730 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 2731 2732 service->client_id = client_id; 2733 vchiq_use_service_internal(service); 2734 status = queue_message(service->state, NULL, 2735 VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0), 2736 &body, 1, sizeof(payload), QMFLAGS_IS_BLOCKING); 2737 if (status == VCHIQ_SUCCESS) { 2738 /* Wait for the ACK/NAK */ 2739 if (down_interruptible(&service->remove_event) != 0) { 2740 status = VCHIQ_RETRY; 2741 vchiq_release_service_internal(service); 2742 } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) && 2743 (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) { 2744 if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) 2745 vchiq_log_error(vchiq_core_log_level, 2746 "%d: osi - srvstate = %s (ref %d)", 2747 service->state->id, 2748 srvstate_names[service->srvstate], 2749 service->ref_count); 2750 status = VCHIQ_ERROR; 2751 VCHIQ_SERVICE_STATS_INC(service, error_count); 2752 vchiq_release_service_internal(service); 2753 } 2754 } 2755 return status; 2756 } 2757 2758 static void 2759 release_service_messages(VCHIQ_SERVICE_T *service) 2760 { 2761 VCHIQ_STATE_T *state = service->state; 2762 int slot_last = le32toh(state->remote->slot_last); 2763 int i; 2764 2765 /* Release any claimed messages aimed at this service */ 2766 2767 if (service->sync) { 2768 VCHIQ_HEADER_T *header = 2769 (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, 2770 le32toh(state->remote->slot_sync)); 2771 if (VCHIQ_MSG_DSTPORT(le32toh(header->msgid)) == service->localport) 2772 release_message_sync(state, header); 2773 2774 return; 2775 } 2776 2777 for (i = le32toh(state->remote->slot_first); i <= slot_last; i++) { 2778 VCHIQ_SLOT_INFO_T *slot_info = 2779 SLOT_INFO_FROM_INDEX(state, i); 2780 if (le16toh(slot_info->release_count) != le16toh(slot_info->use_count)) { 2781 char *data = 2782 (char *)SLOT_DATA_FROM_INDEX(state, i); 2783 unsigned int pos, end; 2784 2785 end = VCHIQ_SLOT_SIZE; 2786 if (data == state->rx_data) 2787 /* This buffer is still being read from - stop 2788 ** at the current read position */ 2789 end = state->rx_pos & VCHIQ_SLOT_MASK; 2790 2791 pos = 0; 2792 2793 while (pos < end) { 2794 VCHIQ_HEADER_T *header = 2795 (VCHIQ_HEADER_T *)(data + pos); 2796 uint32_t msgid = le32toh(header->msgid); 2797 int port = VCHIQ_MSG_DSTPORT(msgid); 2798 if ((port == service->localport) && 2799 (msgid & VCHIQ_MSGID_CLAIMED)) { 2800 vchiq_log_info(vchiq_core_log_level, 2801 " fsi - hdr %p", 2802 header); 2803 release_slot(state, slot_info, header, 2804 NULL); 2805 } 2806 pos += calc_stride(le32toh(header->size)); 2807 if (pos > VCHIQ_SLOT_SIZE) { 2808 vchiq_log_error(vchiq_core_log_level, 2809 "fsi - pos %x: header %p, " 2810 "msgid %x, header->msgid %x, " 2811 "header->size %x", 2812 pos, header, 2813 msgid, le32toh(header->msgid), 2814 le32toh(header->size)); 2815 WARN(1, "invalid slot position\n"); 2816 } 2817 } 2818 } 2819 } 2820 } 2821 2822 static int 2823 do_abort_bulks(VCHIQ_SERVICE_T *service) 2824 { 2825 VCHIQ_STATUS_T status; 2826 2827 /* Abort any outstanding bulk transfers */ 2828 if (lmutex_lock_interruptible(&service->bulk_mutex) != 0) 2829 return 0; 2830 abort_outstanding_bulks(service, &service->bulk_tx); 2831 abort_outstanding_bulks(service, &service->bulk_rx); 2832 lmutex_unlock(&service->bulk_mutex); 2833 2834 status = notify_bulks(service, &service->bulk_tx, 0/*!retry_poll*/); 2835 if (status == VCHIQ_SUCCESS) 2836 status = notify_bulks(service, &service->bulk_rx, 2837 0/*!retry_poll*/); 2838 return (status == VCHIQ_SUCCESS); 2839 } 2840 2841 static VCHIQ_STATUS_T 2842 close_service_complete(VCHIQ_SERVICE_T *service, int failstate) 2843 { 2844 VCHIQ_STATUS_T status; 2845 int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID); 2846 int newstate; 2847 2848 switch (service->srvstate) { 2849 case VCHIQ_SRVSTATE_OPEN: 2850 case VCHIQ_SRVSTATE_CLOSESENT: 2851 case VCHIQ_SRVSTATE_CLOSERECVD: 2852 if (is_server) { 2853 if (service->auto_close) { 2854 service->client_id = 0; 2855 service->remoteport = VCHIQ_PORT_FREE; 2856 newstate = VCHIQ_SRVSTATE_LISTENING; 2857 } else 2858 newstate = VCHIQ_SRVSTATE_CLOSEWAIT; 2859 } else 2860 newstate = VCHIQ_SRVSTATE_CLOSED; 2861 vchiq_set_service_state(service, newstate); 2862 break; 2863 case VCHIQ_SRVSTATE_LISTENING: 2864 break; 2865 default: 2866 vchiq_log_error(vchiq_core_log_level, 2867 "close_service_complete(%x) called in state %s", 2868 service->handle, srvstate_names[service->srvstate]); 2869 WARN(1, "close_service_complete in unexpected state\n"); 2870 return VCHIQ_ERROR; 2871 } 2872 2873 status = make_service_callback(service, 2874 VCHIQ_SERVICE_CLOSED, NULL, NULL); 2875 2876 if (status != VCHIQ_RETRY) { 2877 int uc = service->service_use_count; 2878 int i; 2879 /* Complete the close process */ 2880 for (i = 0; i < uc; i++) 2881 /* cater for cases where close is forced and the 2882 ** client may not close all it's handles */ 2883 vchiq_release_service_internal(service); 2884 2885 service->client_id = 0; 2886 service->remoteport = VCHIQ_PORT_FREE; 2887 2888 if (service->srvstate == VCHIQ_SRVSTATE_CLOSED) 2889 vchiq_free_service_internal(service); 2890 else if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) { 2891 if (is_server) 2892 service->closing = 0; 2893 2894 up(&service->remove_event); 2895 } 2896 } else 2897 vchiq_set_service_state(service, failstate); 2898 2899 return status; 2900 } 2901 2902 /* Called by the slot handler */ 2903 VCHIQ_STATUS_T 2904 vchiq_close_service_internal(VCHIQ_SERVICE_T *service, int close_recvd) 2905 { 2906 VCHIQ_STATE_T *state = service->state; 2907 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 2908 int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID); 2909 2910 vchiq_log_info(vchiq_core_log_level, "%d: csi:%d,%d (%s)", 2911 service->state->id, service->localport, close_recvd, 2912 srvstate_names[service->srvstate]); 2913 2914 switch (service->srvstate) { 2915 case VCHIQ_SRVSTATE_CLOSED: 2916 case VCHIQ_SRVSTATE_HIDDEN: 2917 case VCHIQ_SRVSTATE_LISTENING: 2918 case VCHIQ_SRVSTATE_CLOSEWAIT: 2919 if (close_recvd) 2920 vchiq_log_error(vchiq_core_log_level, 2921 "vchiq_close_service_internal(1) called " 2922 "in state %s", 2923 srvstate_names[service->srvstate]); 2924 else if (is_server) { 2925 if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) { 2926 status = VCHIQ_ERROR; 2927 } else { 2928 service->client_id = 0; 2929 service->remoteport = VCHIQ_PORT_FREE; 2930 if (service->srvstate == 2931 VCHIQ_SRVSTATE_CLOSEWAIT) 2932 vchiq_set_service_state(service, 2933 VCHIQ_SRVSTATE_LISTENING); 2934 } 2935 up(&service->remove_event); 2936 } else 2937 vchiq_free_service_internal(service); 2938 break; 2939 case VCHIQ_SRVSTATE_OPENING: 2940 if (close_recvd) { 2941 /* The open was rejected - tell the user */ 2942 vchiq_set_service_state(service, 2943 VCHIQ_SRVSTATE_CLOSEWAIT); 2944 up(&service->remove_event); 2945 } else { 2946 /* Shutdown mid-open - let the other side know */ 2947 status = queue_message(state, service, 2948 VCHIQ_MAKE_MSG 2949 (VCHIQ_MSG_CLOSE, 2950 service->localport, 2951 VCHIQ_MSG_DSTPORT(service->remoteport)), 2952 NULL, 0, 0, 0); 2953 } 2954 break; 2955 2956 case VCHIQ_SRVSTATE_OPENSYNC: 2957 lmutex_lock(&state->sync_mutex); 2958 /* Drop through */ 2959 2960 case VCHIQ_SRVSTATE_OPEN: 2961 if (state->is_master || close_recvd) { 2962 if (!do_abort_bulks(service)) 2963 status = VCHIQ_RETRY; 2964 } 2965 2966 release_service_messages(service); 2967 2968 if (status == VCHIQ_SUCCESS) 2969 status = queue_message(state, service, 2970 VCHIQ_MAKE_MSG 2971 (VCHIQ_MSG_CLOSE, 2972 service->localport, 2973 VCHIQ_MSG_DSTPORT(service->remoteport)), 2974 NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK); 2975 2976 if (status == VCHIQ_SUCCESS) { 2977 if (!close_recvd) { 2978 /* Change the state while the mutex is 2979 still held */ 2980 vchiq_set_service_state(service, 2981 VCHIQ_SRVSTATE_CLOSESENT); 2982 lmutex_unlock(&state->slot_mutex); 2983 if (service->sync) 2984 lmutex_unlock(&state->sync_mutex); 2985 break; 2986 } 2987 } else if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC) { 2988 lmutex_unlock(&state->sync_mutex); 2989 break; 2990 } else 2991 break; 2992 2993 /* Change the state while the mutex is still held */ 2994 vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD); 2995 lmutex_unlock(&state->slot_mutex); 2996 if (service->sync) 2997 lmutex_unlock(&state->sync_mutex); 2998 2999 status = close_service_complete(service, 3000 VCHIQ_SRVSTATE_CLOSERECVD); 3001 break; 3002 3003 case VCHIQ_SRVSTATE_CLOSESENT: 3004 if (!close_recvd) 3005 /* This happens when a process is killed mid-close */ 3006 break; 3007 3008 if (!state->is_master) { 3009 if (!do_abort_bulks(service)) { 3010 status = VCHIQ_RETRY; 3011 break; 3012 } 3013 } 3014 3015 if (status == VCHIQ_SUCCESS) 3016 status = close_service_complete(service, 3017 VCHIQ_SRVSTATE_CLOSERECVD); 3018 break; 3019 3020 case VCHIQ_SRVSTATE_CLOSERECVD: 3021 if (!close_recvd && is_server) 3022 /* Force into LISTENING mode */ 3023 vchiq_set_service_state(service, 3024 VCHIQ_SRVSTATE_LISTENING); 3025 status = close_service_complete(service, 3026 VCHIQ_SRVSTATE_CLOSERECVD); 3027 break; 3028 3029 default: 3030 vchiq_log_error(vchiq_core_log_level, 3031 "vchiq_close_service_internal(%d) called in state %s", 3032 close_recvd, srvstate_names[service->srvstate]); 3033 break; 3034 } 3035 3036 return status; 3037 } 3038 3039 /* Called from the application process upon process death */ 3040 void 3041 vchiq_terminate_service_internal(VCHIQ_SERVICE_T *service) 3042 { 3043 VCHIQ_STATE_T *state = service->state; 3044 3045 vchiq_log_info(vchiq_core_log_level, "%d: tsi - (%d<->%d)", 3046 state->id, service->localport, service->remoteport); 3047 3048 mark_service_closing(service); 3049 3050 /* Mark the service for removal by the slot handler */ 3051 request_poll(state, service, VCHIQ_POLL_REMOVE); 3052 } 3053 3054 /* Called from the slot handler */ 3055 void 3056 vchiq_free_service_internal(VCHIQ_SERVICE_T *service) 3057 { 3058 VCHIQ_STATE_T *state = service->state; 3059 3060 vchiq_log_info(vchiq_core_log_level, "%d: fsi - (%d)", 3061 state->id, service->localport); 3062 3063 switch (service->srvstate) { 3064 case VCHIQ_SRVSTATE_OPENING: 3065 case VCHIQ_SRVSTATE_CLOSED: 3066 case VCHIQ_SRVSTATE_HIDDEN: 3067 case VCHIQ_SRVSTATE_LISTENING: 3068 case VCHIQ_SRVSTATE_CLOSEWAIT: 3069 break; 3070 default: 3071 vchiq_log_error(vchiq_core_log_level, 3072 "%d: fsi - (%d) in state %s", 3073 state->id, service->localport, 3074 srvstate_names[service->srvstate]); 3075 return; 3076 } 3077 3078 vchiq_set_service_state(service, VCHIQ_SRVSTATE_FREE); 3079 3080 up(&service->remove_event); 3081 3082 /* Release the initial lock */ 3083 unlock_service(service); 3084 } 3085 3086 VCHIQ_STATUS_T 3087 vchiq_connect_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance) 3088 { 3089 VCHIQ_SERVICE_T *service; 3090 int i; 3091 3092 /* Find all services registered to this client and enable them. */ 3093 i = 0; 3094 while ((service = next_service_by_instance(state, instance, 3095 &i)) != NULL) { 3096 if (service->srvstate == VCHIQ_SRVSTATE_HIDDEN) 3097 vchiq_set_service_state(service, 3098 VCHIQ_SRVSTATE_LISTENING); 3099 unlock_service(service); 3100 } 3101 3102 if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) { 3103 if (queue_message(state, NULL, 3104 VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0, 3105 0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY) 3106 return VCHIQ_RETRY; 3107 3108 vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING); 3109 } 3110 3111 if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) { 3112 if (down_interruptible(&state->connect) != 0) 3113 return VCHIQ_RETRY; 3114 3115 vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED); 3116 up(&state->connect); 3117 } 3118 3119 return VCHIQ_SUCCESS; 3120 } 3121 3122 VCHIQ_STATUS_T 3123 vchiq_shutdown_internal(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance) 3124 { 3125 VCHIQ_SERVICE_T *service; 3126 int i; 3127 3128 /* Find all services registered to this client and enable them. */ 3129 i = 0; 3130 while ((service = next_service_by_instance(state, instance, 3131 &i)) != NULL) { 3132 (void)vchiq_remove_service(service->handle); 3133 unlock_service(service); 3134 } 3135 3136 return VCHIQ_SUCCESS; 3137 } 3138 3139 VCHIQ_STATUS_T 3140 vchiq_pause_internal(VCHIQ_STATE_T *state) 3141 { 3142 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 3143 3144 switch (state->conn_state) { 3145 case VCHIQ_CONNSTATE_CONNECTED: 3146 /* Request a pause */ 3147 vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSING); 3148 request_poll(state, NULL, 0); 3149 break; 3150 default: 3151 vchiq_log_error(vchiq_core_log_level, 3152 "vchiq_pause_internal in state %s", 3153 conn_state_names[state->conn_state]); 3154 status = VCHIQ_ERROR; 3155 VCHIQ_STATS_INC(state, error_count); 3156 break; 3157 } 3158 3159 return status; 3160 } 3161 3162 VCHIQ_STATUS_T 3163 vchiq_resume_internal(VCHIQ_STATE_T *state) 3164 { 3165 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 3166 3167 if (state->conn_state == VCHIQ_CONNSTATE_PAUSED) { 3168 vchiq_set_conn_state(state, VCHIQ_CONNSTATE_RESUMING); 3169 request_poll(state, NULL, 0); 3170 } else { 3171 status = VCHIQ_ERROR; 3172 VCHIQ_STATS_INC(state, error_count); 3173 } 3174 3175 return status; 3176 } 3177 3178 VCHIQ_STATUS_T 3179 vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle) 3180 { 3181 /* Unregister the service */ 3182 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 3183 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 3184 3185 if (!service) 3186 return VCHIQ_ERROR; 3187 3188 vchiq_log_info(vchiq_core_log_level, 3189 "%d: close_service:%d", 3190 service->state->id, service->localport); 3191 3192 if ((service->srvstate == VCHIQ_SRVSTATE_FREE) || 3193 (service->srvstate == VCHIQ_SRVSTATE_LISTENING) || 3194 (service->srvstate == VCHIQ_SRVSTATE_HIDDEN)) { 3195 unlock_service(service); 3196 return VCHIQ_ERROR; 3197 } 3198 3199 mark_service_closing(service); 3200 3201 if (current == service->state->slot_handler_thread) { 3202 status = vchiq_close_service_internal(service, 3203 0/*!close_recvd*/); 3204 BUG_ON(status == VCHIQ_RETRY); 3205 } else { 3206 /* Mark the service for termination by the slot handler */ 3207 request_poll(service->state, service, VCHIQ_POLL_TERMINATE); 3208 } 3209 3210 while (1) { 3211 if (down_interruptible(&service->remove_event) != 0) { 3212 status = VCHIQ_RETRY; 3213 break; 3214 } 3215 3216 if ((service->srvstate == VCHIQ_SRVSTATE_FREE) || 3217 (service->srvstate == VCHIQ_SRVSTATE_LISTENING) || 3218 (service->srvstate == VCHIQ_SRVSTATE_OPEN)) 3219 break; 3220 3221 vchiq_log_warning(vchiq_core_log_level, 3222 "%d: close_service:%d - waiting in state %s", 3223 service->state->id, service->localport, 3224 srvstate_names[service->srvstate]); 3225 } 3226 3227 if ((status == VCHIQ_SUCCESS) && 3228 (service->srvstate != VCHIQ_SRVSTATE_FREE) && 3229 (service->srvstate != VCHIQ_SRVSTATE_LISTENING)) 3230 status = VCHIQ_ERROR; 3231 3232 unlock_service(service); 3233 3234 return status; 3235 } 3236 3237 VCHIQ_STATUS_T 3238 vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle) 3239 { 3240 /* Unregister the service */ 3241 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 3242 VCHIQ_STATUS_T status = VCHIQ_SUCCESS; 3243 3244 if (!service) 3245 return VCHIQ_ERROR; 3246 3247 vchiq_log_info(vchiq_core_log_level, 3248 "%d: remove_service:%d", 3249 service->state->id, service->localport); 3250 3251 if (service->srvstate == VCHIQ_SRVSTATE_FREE) { 3252 unlock_service(service); 3253 return VCHIQ_ERROR; 3254 } 3255 3256 mark_service_closing(service); 3257 3258 if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) || 3259 (current == service->state->slot_handler_thread)) { 3260 /* Make it look like a client, because it must be removed and 3261 not left in the LISTENING state. */ 3262 service->public_fourcc = VCHIQ_FOURCC_INVALID; 3263 3264 status = vchiq_close_service_internal(service, 3265 0/*!close_recvd*/); 3266 BUG_ON(status == VCHIQ_RETRY); 3267 } else { 3268 /* Mark the service for removal by the slot handler */ 3269 request_poll(service->state, service, VCHIQ_POLL_REMOVE); 3270 } 3271 while (1) { 3272 if (down_interruptible(&service->remove_event) != 0) { 3273 status = VCHIQ_RETRY; 3274 break; 3275 } 3276 3277 if ((service->srvstate == VCHIQ_SRVSTATE_FREE) || 3278 (service->srvstate == VCHIQ_SRVSTATE_OPEN)) 3279 break; 3280 3281 vchiq_log_warning(vchiq_core_log_level, 3282 "%d: remove_service:%d - waiting in state %s", 3283 service->state->id, service->localport, 3284 srvstate_names[service->srvstate]); 3285 } 3286 3287 if ((status == VCHIQ_SUCCESS) && 3288 (service->srvstate != VCHIQ_SRVSTATE_FREE)) 3289 status = VCHIQ_ERROR; 3290 3291 unlock_service(service); 3292 3293 return status; 3294 } 3295 3296 3297 /* This function may be called by kernel threads or user threads. 3298 * User threads may receive VCHIQ_RETRY to indicate that a signal has been 3299 * received and the call should be retried after being returned to user 3300 * context. 3301 * When called in blocking mode, the userdata field points to a bulk_waiter 3302 * structure. 3303 */ 3304 VCHIQ_STATUS_T 3305 vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, 3306 VCHI_MEM_HANDLE_T memhandle, void *offset, int size, void *userdata, 3307 VCHIQ_BULK_MODE_T mode, VCHIQ_BULK_DIR_T dir) 3308 { 3309 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 3310 VCHIQ_BULK_QUEUE_T *queue; 3311 VCHIQ_BULK_T *bulk; 3312 VCHIQ_STATE_T *state; 3313 struct bulk_waiter *bulk_waiter = NULL; 3314 const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r'; 3315 const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ? 3316 VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX; 3317 VCHIQ_STATUS_T status = VCHIQ_ERROR; 3318 3319 if (!service || 3320 (service->srvstate != VCHIQ_SRVSTATE_OPEN) || 3321 ((memhandle == VCHI_MEM_HANDLE_INVALID) && (offset == NULL)) || 3322 (vchiq_check_service(service) != VCHIQ_SUCCESS)) 3323 goto error_exit; 3324 3325 switch (mode) { 3326 case VCHIQ_BULK_MODE_NOCALLBACK: 3327 case VCHIQ_BULK_MODE_CALLBACK: 3328 break; 3329 case VCHIQ_BULK_MODE_BLOCKING: 3330 bulk_waiter = (struct bulk_waiter *)userdata; 3331 _sema_init(&bulk_waiter->event, 0); 3332 bulk_waiter->actual = 0; 3333 bulk_waiter->bulk = NULL; 3334 break; 3335 case VCHIQ_BULK_MODE_WAITING: 3336 bulk_waiter = (struct bulk_waiter *)userdata; 3337 bulk = bulk_waiter->bulk; 3338 goto waiting; 3339 default: 3340 goto error_exit; 3341 } 3342 3343 state = service->state; 3344 3345 queue = (dir == VCHIQ_BULK_TRANSMIT) ? 3346 &service->bulk_tx : &service->bulk_rx; 3347 3348 if (lmutex_lock_interruptible(&service->bulk_mutex) != 0) { 3349 status = VCHIQ_RETRY; 3350 goto error_exit; 3351 } 3352 3353 if (queue->local_insert == queue->remove + VCHIQ_NUM_SERVICE_BULKS) { 3354 VCHIQ_SERVICE_STATS_INC(service, bulk_stalls); 3355 do { 3356 lmutex_unlock(&service->bulk_mutex); 3357 if (down_interruptible(&service->bulk_remove_event) 3358 != 0) { 3359 status = VCHIQ_RETRY; 3360 goto error_exit; 3361 } 3362 if (lmutex_lock_interruptible(&service->bulk_mutex) 3363 != 0) { 3364 status = VCHIQ_RETRY; 3365 goto error_exit; 3366 } 3367 } while (queue->local_insert == queue->remove + 3368 VCHIQ_NUM_SERVICE_BULKS); 3369 } 3370 3371 bulk = &queue->bulks[BULK_INDEX(queue->local_insert)]; 3372 3373 bulk->mode = mode; 3374 bulk->dir = dir; 3375 bulk->userdata = userdata; 3376 bulk->size = size; 3377 bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED; 3378 3379 if (vchiq_prepare_bulk_data(bulk, memhandle, offset, size, dir) != 3380 VCHIQ_SUCCESS) 3381 goto unlock_error_exit; 3382 3383 wmb(); 3384 3385 vchiq_log_info(vchiq_core_log_level, 3386 "%d: bt (%d->%d) %cx %x@%p %p", 3387 state->id, 3388 service->localport, service->remoteport, dir_char, 3389 size, bulk->data, userdata); 3390 3391 /* The slot mutex must be held when the service is being closed, so 3392 claim it here to ensure that isn't happening */ 3393 if (lmutex_lock_interruptible(&state->slot_mutex) != 0) { 3394 status = VCHIQ_RETRY; 3395 goto cancel_bulk_error_exit; 3396 } 3397 3398 if (service->srvstate != VCHIQ_SRVSTATE_OPEN) 3399 goto unlock_both_error_exit; 3400 3401 if (state->is_master) { 3402 queue->local_insert++; 3403 if (resolve_bulks(service, queue)) 3404 request_poll(state, service, 3405 (dir == VCHIQ_BULK_TRANSMIT) ? 3406 VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY); 3407 } else { 3408 uint32_t payload[2] = { htole32((uintptr_t)bulk->data), htole32(bulk->size) }; 3409 VCHIQ_ELEMENT_T element = { payload, sizeof(payload) }; 3410 3411 status = queue_message(state, NULL, 3412 VCHIQ_MAKE_MSG(dir_msgtype, 3413 service->localport, service->remoteport), 3414 &element, 1, sizeof(payload), 3415 QMFLAGS_IS_BLOCKING | 3416 QMFLAGS_NO_MUTEX_LOCK | 3417 QMFLAGS_NO_MUTEX_UNLOCK); 3418 if (status != VCHIQ_SUCCESS) { 3419 goto unlock_both_error_exit; 3420 } 3421 queue->local_insert++; 3422 } 3423 3424 lmutex_unlock(&state->slot_mutex); 3425 lmutex_unlock(&service->bulk_mutex); 3426 3427 vchiq_log_trace(vchiq_core_log_level, 3428 "%d: bt:%d %cx li=%x ri=%x p=%x", 3429 state->id, 3430 service->localport, dir_char, 3431 queue->local_insert, queue->remote_insert, queue->process); 3432 3433 waiting: 3434 unlock_service(service); 3435 3436 status = VCHIQ_SUCCESS; 3437 3438 if (bulk_waiter) { 3439 bulk_waiter->bulk = bulk; 3440 if (down_interruptible(&bulk_waiter->event) != 0) 3441 status = VCHIQ_RETRY; 3442 else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED) 3443 status = VCHIQ_ERROR; 3444 } 3445 3446 return status; 3447 3448 unlock_both_error_exit: 3449 lmutex_unlock(&state->slot_mutex); 3450 cancel_bulk_error_exit: 3451 vchiq_complete_bulk(bulk); 3452 unlock_error_exit: 3453 lmutex_unlock(&service->bulk_mutex); 3454 3455 error_exit: 3456 if (service) 3457 unlock_service(service); 3458 return status; 3459 } 3460 3461 VCHIQ_STATUS_T 3462 vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle, 3463 const VCHIQ_ELEMENT_T *elements, unsigned int count) 3464 { 3465 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 3466 VCHIQ_STATUS_T status = VCHIQ_ERROR; 3467 3468 unsigned int size = 0; 3469 unsigned int i; 3470 3471 if (!service || 3472 (vchiq_check_service(service) != VCHIQ_SUCCESS)) 3473 goto error_exit; 3474 3475 for (i = 0; i < (unsigned int)count; i++) { 3476 if (elements[i].size) { 3477 if (elements[i].data == NULL) { 3478 VCHIQ_SERVICE_STATS_INC(service, error_count); 3479 goto error_exit; 3480 } 3481 size += elements[i].size; 3482 } 3483 } 3484 3485 if (size > VCHIQ_MAX_MSG_SIZE) { 3486 VCHIQ_SERVICE_STATS_INC(service, error_count); 3487 goto error_exit; 3488 } 3489 3490 switch (service->srvstate) { 3491 case VCHIQ_SRVSTATE_OPEN: 3492 status = queue_message(service->state, service, 3493 VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA, 3494 service->localport, 3495 service->remoteport), 3496 elements, count, size, 1); 3497 break; 3498 case VCHIQ_SRVSTATE_OPENSYNC: 3499 status = queue_message_sync(service->state, service, 3500 VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA, 3501 service->localport, 3502 service->remoteport), 3503 elements, count, size, 1); 3504 break; 3505 default: 3506 status = VCHIQ_ERROR; 3507 break; 3508 } 3509 3510 error_exit: 3511 if (service) 3512 unlock_service(service); 3513 3514 return status; 3515 } 3516 3517 void 3518 vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle, VCHIQ_HEADER_T *header) 3519 { 3520 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 3521 VCHIQ_SHARED_STATE_T *remote; 3522 VCHIQ_STATE_T *state; 3523 int slot_index; 3524 3525 if (!service) 3526 return; 3527 3528 state = service->state; 3529 remote = state->remote; 3530 3531 slot_index = SLOT_INDEX_FROM_DATA(state, (void *)header); 3532 3533 if ((slot_index >= le32toh(remote->slot_first)) && 3534 (slot_index <= le32toh(remote->slot_last))) { 3535 uint32_t msgid = le32toh(header->msgid); 3536 if (msgid & VCHIQ_MSGID_CLAIMED) { 3537 VCHIQ_SLOT_INFO_T *slot_info = 3538 SLOT_INFO_FROM_INDEX(state, slot_index); 3539 3540 release_slot(state, slot_info, header, service); 3541 } 3542 } else if (slot_index == le32toh(remote->slot_sync)) 3543 release_message_sync(state, header); 3544 3545 unlock_service(service); 3546 } 3547 3548 static void 3549 release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header) 3550 { 3551 header->msgid = htole32(VCHIQ_MSGID_PADDING); 3552 wmb(); 3553 remote_event_signal(&state->remote->sync_release); 3554 } 3555 3556 VCHIQ_STATUS_T 3557 vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle, short *peer_version) 3558 { 3559 VCHIQ_STATUS_T status = VCHIQ_ERROR; 3560 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 3561 3562 if (!service || 3563 (vchiq_check_service(service) != VCHIQ_SUCCESS) || 3564 !peer_version) 3565 goto exit; 3566 *peer_version = service->peer_version; 3567 status = VCHIQ_SUCCESS; 3568 3569 exit: 3570 if (service) 3571 unlock_service(service); 3572 return status; 3573 } 3574 3575 VCHIQ_STATUS_T 3576 vchiq_get_config(VCHIQ_INSTANCE_T instance, 3577 int config_size, VCHIQ_CONFIG_T *pconfig) 3578 { 3579 VCHIQ_CONFIG_T config; 3580 3581 (void)instance; 3582 3583 config.max_msg_size = VCHIQ_MAX_MSG_SIZE; 3584 config.bulk_threshold = VCHIQ_MAX_MSG_SIZE; 3585 config.max_outstanding_bulks = VCHIQ_NUM_SERVICE_BULKS; 3586 config.max_services = VCHIQ_MAX_SERVICES; 3587 config.version = VCHIQ_VERSION; 3588 config.version_min = VCHIQ_VERSION_MIN; 3589 3590 if (config_size > sizeof(VCHIQ_CONFIG_T)) 3591 return VCHIQ_ERROR; 3592 3593 memcpy(pconfig, &config, 3594 min(config_size, (int)(sizeof(VCHIQ_CONFIG_T)))); 3595 3596 return VCHIQ_SUCCESS; 3597 } 3598 3599 VCHIQ_STATUS_T 3600 vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle, 3601 VCHIQ_SERVICE_OPTION_T option, int value) 3602 { 3603 VCHIQ_SERVICE_T *service = find_service_by_handle(handle); 3604 VCHIQ_STATUS_T status = VCHIQ_ERROR; 3605 3606 if (service) { 3607 switch (option) { 3608 case VCHIQ_SERVICE_OPTION_AUTOCLOSE: 3609 service->auto_close = value; 3610 status = VCHIQ_SUCCESS; 3611 break; 3612 3613 case VCHIQ_SERVICE_OPTION_SLOT_QUOTA: { 3614 VCHIQ_SERVICE_QUOTA_T *service_quota = 3615 &service->state->service_quotas[ 3616 service->localport]; 3617 if (value == 0) 3618 value = service->state->default_slot_quota; 3619 if ((value >= service_quota->slot_use_count) && 3620 (value < (unsigned short)~0)) { 3621 service_quota->slot_quota = value; 3622 if ((value >= service_quota->slot_use_count) && 3623 (service_quota->message_quota >= 3624 service_quota->message_use_count)) { 3625 /* Signal the service that it may have 3626 ** dropped below its quota */ 3627 up(&service_quota->quota_event); 3628 } 3629 status = VCHIQ_SUCCESS; 3630 } 3631 } break; 3632 3633 case VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA: { 3634 VCHIQ_SERVICE_QUOTA_T *service_quota = 3635 &service->state->service_quotas[ 3636 service->localport]; 3637 if (value == 0) 3638 value = service->state->default_message_quota; 3639 if ((value >= service_quota->message_use_count) && 3640 (value < (unsigned short)~0)) { 3641 service_quota->message_quota = value; 3642 if ((value >= 3643 service_quota->message_use_count) && 3644 (service_quota->slot_quota >= 3645 service_quota->slot_use_count)) 3646 /* Signal the service that it may have 3647 ** dropped below its quota */ 3648 up(&service_quota->quota_event); 3649 status = VCHIQ_SUCCESS; 3650 } 3651 } break; 3652 3653 case VCHIQ_SERVICE_OPTION_SYNCHRONOUS: 3654 if ((service->srvstate == VCHIQ_SRVSTATE_HIDDEN) || 3655 (service->srvstate == 3656 VCHIQ_SRVSTATE_LISTENING)) { 3657 service->sync = value; 3658 status = VCHIQ_SUCCESS; 3659 } 3660 break; 3661 3662 case VCHIQ_SERVICE_OPTION_TRACE: 3663 service->trace = value; 3664 status = VCHIQ_SUCCESS; 3665 break; 3666 3667 default: 3668 break; 3669 } 3670 unlock_service(service); 3671 } 3672 3673 return status; 3674 } 3675 3676 static void 3677 vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state, 3678 VCHIQ_SHARED_STATE_T *shared, const char *label) 3679 { 3680 static const char *const debug_names[] = { 3681 "<entries>", 3682 "SLOT_HANDLER_COUNT", 3683 "SLOT_HANDLER_LINE", 3684 "PARSE_LINE", 3685 "PARSE_HEADER", 3686 "PARSE_MSGID", 3687 "AWAIT_COMPLETION_LINE", 3688 "DEQUEUE_MESSAGE_LINE", 3689 "SERVICE_CALLBACK_LINE", 3690 "MSG_QUEUE_FULL_COUNT", 3691 "COMPLETION_QUEUE_FULL_COUNT" 3692 }; 3693 int i; 3694 3695 char buf[80]; 3696 int len; 3697 len = snprintf(buf, sizeof(buf), 3698 " %s: slots %d-%d tx_pos=%x recycle=%x", 3699 label, le32toh(shared->slot_first), le32toh(shared->slot_last), 3700 le32toh(shared->tx_pos), le32toh(shared->slot_queue_recycle)); 3701 vchiq_dump(dump_context, buf, len + 1); 3702 3703 len = snprintf(buf, sizeof(buf), 3704 " Slots claimed:"); 3705 vchiq_dump(dump_context, buf, len + 1); 3706 3707 for (i = le32toh(shared->slot_first); i <= le32toh(shared->slot_last); i++) { 3708 VCHIQ_SLOT_INFO_T slot_info = *SLOT_INFO_FROM_INDEX(state, i); 3709 if (le16toh(slot_info.use_count) != le16toh(slot_info.release_count)) { 3710 len = snprintf(buf, sizeof(buf), 3711 " %d: %d/%d", i, le16toh(slot_info.use_count), 3712 le16toh(slot_info.release_count)); 3713 vchiq_dump(dump_context, buf, len + 1); 3714 } 3715 } 3716 3717 for (i = 1; i < le32toh(shared->debug[DEBUG_ENTRIES]); i++) { 3718 len = snprintf(buf, sizeof(buf), " DEBUG: %s = %d(%x)", 3719 debug_names[i], le32toh(shared->debug[i]), le32toh(shared->debug[i])); 3720 vchiq_dump(dump_context, buf, len + 1); 3721 } 3722 } 3723 3724 void 3725 vchiq_dump_state(void *dump_context, VCHIQ_STATE_T *state) 3726 { 3727 char buf[80]; 3728 int len; 3729 int i; 3730 3731 len = snprintf(buf, sizeof(buf), "State %d: %s", state->id, 3732 conn_state_names[state->conn_state]); 3733 vchiq_dump(dump_context, buf, len + 1); 3734 3735 len = snprintf(buf, sizeof(buf), 3736 " tx_pos=%x(@%x), rx_pos=%x(@%x)", 3737 state->local->tx_pos, 3738 (uint32_t)(uintptr_t)state->tx_data + 3739 (state->local_tx_pos & VCHIQ_SLOT_MASK), 3740 state->rx_pos, 3741 (uint32_t)(uintptr_t)state->rx_data + 3742 (state->rx_pos & VCHIQ_SLOT_MASK)); 3743 vchiq_dump(dump_context, buf, len + 1); 3744 3745 len = snprintf(buf, sizeof(buf), 3746 " Version: %d (min %d)", 3747 VCHIQ_VERSION, VCHIQ_VERSION_MIN); 3748 vchiq_dump(dump_context, buf, len + 1); 3749 3750 if (VCHIQ_ENABLE_STATS) { 3751 len = snprintf(buf, sizeof(buf), 3752 " Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, " 3753 "error_count=%d", 3754 state->stats.ctrl_tx_count, state->stats.ctrl_rx_count, 3755 state->stats.error_count); 3756 vchiq_dump(dump_context, buf, len + 1); 3757 } 3758 3759 len = snprintf(buf, sizeof(buf), 3760 " Slots: %d available (%d data), %d recyclable, %d stalls " 3761 "(%d data)", 3762 ((state->slot_queue_available * VCHIQ_SLOT_SIZE) - 3763 state->local_tx_pos) / VCHIQ_SLOT_SIZE, 3764 state->data_quota - state->data_use_count, 3765 state->local->slot_queue_recycle - state->slot_queue_available, 3766 state->stats.slot_stalls, state->stats.data_stalls); 3767 vchiq_dump(dump_context, buf, len + 1); 3768 3769 vchiq_dump_platform_state(dump_context); 3770 3771 vchiq_dump_shared_state(dump_context, state, state->local, "Local"); 3772 vchiq_dump_shared_state(dump_context, state, state->remote, "Remote"); 3773 3774 vchiq_dump_platform_instances(dump_context); 3775 3776 for (i = 0; i < state->unused_service; i++) { 3777 VCHIQ_SERVICE_T *service = find_service_by_port(state, i); 3778 3779 if (service) { 3780 vchiq_dump_service_state(dump_context, service); 3781 unlock_service(service); 3782 } 3783 } 3784 } 3785 3786 void 3787 vchiq_dump_service_state(void *dump_context, VCHIQ_SERVICE_T *service) 3788 { 3789 char buf[120]; 3790 int len; 3791 3792 len = snprintf(buf, sizeof(buf), "Service %d: %s (ref %u)", 3793 service->localport, srvstate_names[service->srvstate], 3794 service->ref_count - 1); /*Don't include the lock just taken*/ 3795 3796 if (service->srvstate != VCHIQ_SRVSTATE_FREE) { 3797 char remoteport[30]; 3798 VCHIQ_SERVICE_QUOTA_T *service_quota = 3799 &service->state->service_quotas[service->localport]; 3800 int fourcc = service->base.fourcc; 3801 int tx_pending, rx_pending; 3802 if (service->remoteport != VCHIQ_PORT_FREE) { 3803 int len2 = snprintf(remoteport, sizeof(remoteport), 3804 "%d", service->remoteport); 3805 if (service->public_fourcc != VCHIQ_FOURCC_INVALID) 3806 snprintf(remoteport + len2, 3807 sizeof(remoteport) - len2, 3808 " (client %8x)", service->client_id); 3809 } else 3810 strcpy(remoteport, "n/a"); 3811 3812 len += snprintf(buf + len, sizeof(buf) - len, 3813 " '%c%c%c%c' remote %s (msg use %d/%d, slot use %d/%d)", 3814 VCHIQ_FOURCC_AS_4CHARS(fourcc), 3815 remoteport, 3816 service_quota->message_use_count, 3817 service_quota->message_quota, 3818 service_quota->slot_use_count, 3819 service_quota->slot_quota); 3820 3821 vchiq_dump(dump_context, buf, len + 1); 3822 3823 tx_pending = service->bulk_tx.local_insert - 3824 service->bulk_tx.remote_insert; 3825 3826 rx_pending = service->bulk_rx.local_insert - 3827 service->bulk_rx.remote_insert; 3828 3829 len = snprintf(buf, sizeof(buf), 3830 " Bulk: tx_pending=%d (size %d)," 3831 " rx_pending=%d (size %d)", 3832 tx_pending, 3833 tx_pending ? service->bulk_tx.bulks[ 3834 BULK_INDEX(service->bulk_tx.remove)].size : 0, 3835 rx_pending, 3836 rx_pending ? service->bulk_rx.bulks[ 3837 BULK_INDEX(service->bulk_rx.remove)].size : 0); 3838 3839 if (VCHIQ_ENABLE_STATS) { 3840 vchiq_dump(dump_context, buf, len + 1); 3841 3842 len = snprintf(buf, sizeof(buf), 3843 " Ctrl: tx_count=%d, tx_bytes=%" PRIu64 ", " 3844 "rx_count=%d, rx_bytes=%" PRIu64, 3845 service->stats.ctrl_tx_count, 3846 service->stats.ctrl_tx_bytes, 3847 service->stats.ctrl_rx_count, 3848 service->stats.ctrl_rx_bytes); 3849 vchiq_dump(dump_context, buf, len + 1); 3850 3851 len = snprintf(buf, sizeof(buf), 3852 " Bulk: tx_count=%d, tx_bytes=%" PRIu64 ", " 3853 "rx_count=%d, rx_bytes=%" PRIu64, 3854 service->stats.bulk_tx_count, 3855 service->stats.bulk_tx_bytes, 3856 service->stats.bulk_rx_count, 3857 service->stats.bulk_rx_bytes); 3858 vchiq_dump(dump_context, buf, len + 1); 3859 3860 len = snprintf(buf, sizeof(buf), 3861 " %d quota stalls, %d slot stalls, " 3862 "%d bulk stalls, %d aborted, %d errors", 3863 service->stats.quota_stalls, 3864 service->stats.slot_stalls, 3865 service->stats.bulk_stalls, 3866 service->stats.bulk_aborted_count, 3867 service->stats.error_count); 3868 } 3869 } 3870 3871 vchiq_dump(dump_context, buf, len + 1); 3872 3873 if (service->srvstate != VCHIQ_SRVSTATE_FREE) 3874 vchiq_dump_platform_service_state(dump_context, service); 3875 } 3876 3877 3878 void 3879 vchiq_loud_error_header(void) 3880 { 3881 vchiq_log_error(vchiq_core_log_level, 3882 "============================================================" 3883 "================"); 3884 vchiq_log_error(vchiq_core_log_level, 3885 "============================================================" 3886 "================"); 3887 vchiq_log_error(vchiq_core_log_level, "====="); 3888 } 3889 3890 void 3891 vchiq_loud_error_footer(void) 3892 { 3893 vchiq_log_error(vchiq_core_log_level, "====="); 3894 vchiq_log_error(vchiq_core_log_level, 3895 "============================================================" 3896 "================"); 3897 vchiq_log_error(vchiq_core_log_level, 3898 "============================================================" 3899 "================"); 3900 } 3901 3902 3903 VCHIQ_STATUS_T vchiq_send_remote_use(VCHIQ_STATE_T *state) 3904 { 3905 VCHIQ_STATUS_T status = VCHIQ_RETRY; 3906 if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) 3907 status = queue_message(state, NULL, 3908 VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0), 3909 NULL, 0, 0, 0); 3910 return status; 3911 } 3912 3913 VCHIQ_STATUS_T vchiq_send_remote_release(VCHIQ_STATE_T *state) 3914 { 3915 VCHIQ_STATUS_T status = VCHIQ_RETRY; 3916 if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) 3917 status = queue_message(state, NULL, 3918 VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE, 0, 0), 3919 NULL, 0, 0, 0); 3920 return status; 3921 } 3922 3923 VCHIQ_STATUS_T vchiq_send_remote_use_active(VCHIQ_STATE_T *state) 3924 { 3925 VCHIQ_STATUS_T status = VCHIQ_RETRY; 3926 if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) 3927 status = queue_message(state, NULL, 3928 VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0), 3929 NULL, 0, 0, 0); 3930 return status; 3931 } 3932 3933 void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem, 3934 size_t numBytes) 3935 { 3936 const uint8_t *mem = (const uint8_t *)voidMem; 3937 size_t offset; 3938 char lineBuf[100]; 3939 char *s; 3940 3941 while (numBytes > 0) { 3942 s = lineBuf; 3943 3944 for (offset = 0; offset < 16; offset++) { 3945 if (offset < numBytes) 3946 s += snprintf(s, 4, "%02x ", mem[offset]); 3947 else 3948 s += snprintf(s, 4, " "); 3949 } 3950 3951 for (offset = 0; offset < 16; offset++) { 3952 if (offset < numBytes) { 3953 uint8_t ch = mem[offset]; 3954 3955 if ((ch < ' ') || (ch > '~')) 3956 ch = '.'; 3957 *s++ = (char)ch; 3958 } 3959 } 3960 *s++ = '\0'; 3961 3962 if ((label != NULL) && (*label != '\0')) 3963 vchiq_log_trace(VCHIQ_LOG_TRACE, 3964 "%s: %08x: %s", label, addr, lineBuf); 3965 else 3966 vchiq_log_trace(VCHIQ_LOG_TRACE, 3967 "%08x: %s", addr, lineBuf); 3968 3969 addr += 16; 3970 mem += 16; 3971 if (numBytes > 16) 3972 numBytes -= 16; 3973 else 3974 numBytes = 0; 3975 } 3976 } 3977