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