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