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