2 * Copyright (c) 2010-2012 Broadcom. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
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.
34 #include "vchiq_core.h"
35 #include "vchiq_killable.h"
37 #define VCHIQ_SLOT_HANDLER_STACK 8192
39 #define HANDLE_STATE_SHIFT 12
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)) / \
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))
51 #define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
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)))
58 struct vchiq_open_payload
{
65 struct vchiq_openack_payload
{
71 QMFLAGS_IS_BLOCKING
= (1 << 0),
72 QMFLAGS_NO_MUTEX_LOCK
= (1 << 1),
73 QMFLAGS_NO_MUTEX_UNLOCK
= (1 << 2)
76 /* we require this for consistency between endpoints */
77 vchiq_static_assert(sizeof(VCHIQ_HEADER_T
) == 8);
78 vchiq_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T
)));
79 vchiq_static_assert(IS_POW2(VCHIQ_NUM_CURRENT_BULKS
));
80 vchiq_static_assert(IS_POW2(VCHIQ_NUM_SERVICE_BULKS
));
81 vchiq_static_assert(IS_POW2(VCHIQ_MAX_SERVICES
));
82 vchiq_static_assert(VCHIQ_VERSION
>= VCHIQ_VERSION_MIN
);
84 /* Run time control of log level, based on KERN_XXX level. */
85 int vchiq_core_log_level
= VCHIQ_LOG_DEFAULT
;
86 int vchiq_core_msg_log_level
= VCHIQ_LOG_DEFAULT
;
87 int vchiq_sync_log_level
= VCHIQ_LOG_DEFAULT
;
89 static atomic_t pause_bulks_count
= ATOMIC_INIT(0);
91 static DEFINE_SPINLOCK(service_spinlock
);
92 DEFINE_SPINLOCK(bulk_waiter_spinlock
);
93 DEFINE_SPINLOCK(quota_spinlock
);
95 VCHIQ_STATE_T
*vchiq_states
[VCHIQ_MAX_STATES
];
96 static unsigned int handle_seq
;
98 static const char *const srvstate_names
[] = {
111 static const char *const reason_names
[] = {
115 "BULK_TRANSMIT_DONE",
117 "BULK_TRANSMIT_ABORTED",
118 "BULK_RECEIVE_ABORTED"
121 static const char *const conn_state_names
[] = {
135 release_message_sync(VCHIQ_STATE_T
*state
, VCHIQ_HEADER_T
*header
);
137 static const char *msg_type_str(unsigned int msg_type
)
140 case VCHIQ_MSG_PADDING
: return "PADDING";
141 case VCHIQ_MSG_CONNECT
: return "CONNECT";
142 case VCHIQ_MSG_OPEN
: return "OPEN";
143 case VCHIQ_MSG_OPENACK
: return "OPENACK";
144 case VCHIQ_MSG_CLOSE
: return "CLOSE";
145 case VCHIQ_MSG_DATA
: return "DATA";
146 case VCHIQ_MSG_BULK_RX
: return "BULK_RX";
147 case VCHIQ_MSG_BULK_TX
: return "BULK_TX";
148 case VCHIQ_MSG_BULK_RX_DONE
: return "BULK_RX_DONE";
149 case VCHIQ_MSG_BULK_TX_DONE
: return "BULK_TX_DONE";
150 case VCHIQ_MSG_PAUSE
: return "PAUSE";
151 case VCHIQ_MSG_RESUME
: return "RESUME";
152 case VCHIQ_MSG_REMOTE_USE
: return "REMOTE_USE";
153 case VCHIQ_MSG_REMOTE_RELEASE
: return "REMOTE_RELEASE";
154 case VCHIQ_MSG_REMOTE_USE_ACTIVE
: return "REMOTE_USE_ACTIVE";
160 vchiq_set_service_state(VCHIQ_SERVICE_T
*service
, int newstate
)
162 vchiq_log_info(vchiq_core_log_level
, "%d: srv:%d %s->%s",
163 service
->state
->id
, service
->localport
,
164 srvstate_names
[service
->srvstate
],
165 srvstate_names
[newstate
]);
166 service
->srvstate
= newstate
;
170 find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle
)
172 VCHIQ_SERVICE_T
*service
;
174 spin_lock(&service_spinlock
);
175 service
= handle_to_service(handle
);
176 if (service
&& (service
->srvstate
!= VCHIQ_SRVSTATE_FREE
) &&
177 (service
->handle
== handle
)) {
178 BUG_ON(service
->ref_count
== 0);
179 service
->ref_count
++;
182 spin_unlock(&service_spinlock
);
185 vchiq_log_info(vchiq_core_log_level
,
186 "Invalid service handle 0x%x", handle
);
192 find_service_by_port(VCHIQ_STATE_T
*state
, int localport
)
194 VCHIQ_SERVICE_T
*service
= NULL
;
195 if ((unsigned int)localport
<= VCHIQ_PORT_MAX
) {
196 spin_lock(&service_spinlock
);
197 service
= state
->services
[localport
];
198 if (service
&& (service
->srvstate
!= VCHIQ_SRVSTATE_FREE
)) {
199 BUG_ON(service
->ref_count
== 0);
200 service
->ref_count
++;
203 spin_unlock(&service_spinlock
);
207 vchiq_log_info(vchiq_core_log_level
,
208 "Invalid port %d", localport
);
214 find_service_for_instance(VCHIQ_INSTANCE_T instance
,
215 VCHIQ_SERVICE_HANDLE_T handle
) {
216 VCHIQ_SERVICE_T
*service
;
218 spin_lock(&service_spinlock
);
219 service
= handle_to_service(handle
);
220 if (service
&& (service
->srvstate
!= VCHIQ_SRVSTATE_FREE
) &&
221 (service
->handle
== handle
) &&
222 (service
->instance
== instance
)) {
223 BUG_ON(service
->ref_count
== 0);
224 service
->ref_count
++;
227 spin_unlock(&service_spinlock
);
230 vchiq_log_info(vchiq_core_log_level
,
231 "Invalid service handle 0x%x", handle
);
237 find_closed_service_for_instance(VCHIQ_INSTANCE_T instance
,
238 VCHIQ_SERVICE_HANDLE_T handle
) {
239 VCHIQ_SERVICE_T
*service
;
241 spin_lock(&service_spinlock
);
242 service
= handle_to_service(handle
);
244 ((service
->srvstate
== VCHIQ_SRVSTATE_FREE
) ||
245 (service
->srvstate
== VCHIQ_SRVSTATE_CLOSED
)) &&
246 (service
->handle
== handle
) &&
247 (service
->instance
== instance
)) {
248 BUG_ON(service
->ref_count
== 0);
249 service
->ref_count
++;
252 spin_unlock(&service_spinlock
);
255 vchiq_log_info(vchiq_core_log_level
,
256 "Invalid service handle 0x%x", handle
);
262 next_service_by_instance(VCHIQ_STATE_T
*state
, VCHIQ_INSTANCE_T instance
,
265 VCHIQ_SERVICE_T
*service
= NULL
;
268 spin_lock(&service_spinlock
);
269 while (idx
< state
->unused_service
) {
270 VCHIQ_SERVICE_T
*srv
= state
->services
[idx
++];
271 if (srv
&& (srv
->srvstate
!= VCHIQ_SRVSTATE_FREE
) &&
272 (srv
->instance
== instance
)) {
274 BUG_ON(service
->ref_count
== 0);
275 service
->ref_count
++;
279 spin_unlock(&service_spinlock
);
287 lock_service(VCHIQ_SERVICE_T
*service
)
289 spin_lock(&service_spinlock
);
290 BUG_ON(!service
|| (service
->ref_count
== 0));
292 service
->ref_count
++;
293 spin_unlock(&service_spinlock
);
297 unlock_service(VCHIQ_SERVICE_T
*service
)
299 spin_lock(&service_spinlock
);
300 BUG_ON(!service
|| (service
->ref_count
== 0));
301 if (service
&& service
->ref_count
) {
302 service
->ref_count
--;
303 if (!service
->ref_count
) {
304 VCHIQ_STATE_T
*state
= service
->state
;
306 BUG_ON(service
->srvstate
!= VCHIQ_SRVSTATE_FREE
);
307 state
->services
[service
->localport
] = NULL
;
311 spin_unlock(&service_spinlock
);
313 if (service
&& service
->userdata_term
)
314 service
->userdata_term(service
->base
.userdata
);
320 vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle
)
322 VCHIQ_SERVICE_T
*service
= find_service_by_handle(handle
);
325 id
= service
? service
->client_id
: 0;
327 unlock_service(service
);
333 vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle
)
335 VCHIQ_SERVICE_T
*service
= handle_to_service(handle
);
337 return service
? service
->base
.userdata
: NULL
;
341 vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T handle
)
343 VCHIQ_SERVICE_T
*service
= handle_to_service(handle
);
345 return service
? service
->base
.fourcc
: 0;
349 mark_service_closing_internal(VCHIQ_SERVICE_T
*service
, int sh_thread
)
351 VCHIQ_STATE_T
*state
= service
->state
;
352 VCHIQ_SERVICE_QUOTA_T
*service_quota
;
354 service
->closing
= 1;
356 /* Synchronise with other threads. */
357 mutex_lock(&state
->recycle_mutex
);
358 mutex_unlock(&state
->recycle_mutex
);
359 if (!sh_thread
|| (state
->conn_state
!= VCHIQ_CONNSTATE_PAUSE_SENT
)) {
360 /* If we're pausing then the slot_mutex is held until resume
361 * by the slot handler. Therefore don't try to acquire this
362 * mutex if we're the slot handler and in the pause sent state.
363 * We don't need to in this case anyway. */
364 mutex_lock(&state
->slot_mutex
);
365 mutex_unlock(&state
->slot_mutex
);
368 /* Unblock any sending thread. */
369 service_quota
= &state
->service_quotas
[service
->localport
];
370 up(&service_quota
->quota_event
);
374 mark_service_closing(VCHIQ_SERVICE_T
*service
)
376 mark_service_closing_internal(service
, 0);
379 static inline VCHIQ_STATUS_T
380 make_service_callback(VCHIQ_SERVICE_T
*service
, VCHIQ_REASON_T reason
,
381 VCHIQ_HEADER_T
*header
, void *bulk_userdata
)
383 VCHIQ_STATUS_T status
;
384 vchiq_log_trace(vchiq_core_log_level
, "%d: callback:%d (%s, %pK, %pK)",
385 service
->state
->id
, service
->localport
, reason_names
[reason
],
386 header
, bulk_userdata
);
387 status
= service
->base
.callback(reason
, header
, service
->handle
,
389 if (status
== VCHIQ_ERROR
) {
390 vchiq_log_warning(vchiq_core_log_level
,
391 "%d: ignoring ERROR from callback to service %x",
392 service
->state
->id
, service
->handle
);
393 status
= VCHIQ_SUCCESS
;
399 vchiq_set_conn_state(VCHIQ_STATE_T
*state
, VCHIQ_CONNSTATE_T newstate
)
401 VCHIQ_CONNSTATE_T oldstate
= state
->conn_state
;
402 vchiq_log_info(vchiq_core_log_level
, "%d: %s->%s", state
->id
,
403 conn_state_names
[oldstate
],
404 conn_state_names
[newstate
]);
405 state
->conn_state
= newstate
;
406 vchiq_platform_conn_state_changed(state
, oldstate
, newstate
);
410 remote_event_create(VCHIQ_STATE_T
*state
, REMOTE_EVENT_T
*event
)
413 /* Don't clear the 'fired' flag because it may already have been set
414 ** by the other side. */
415 sema_init((struct semaphore
*)((char *)state
+ event
->event
), 0);
419 remote_event_wait(VCHIQ_STATE_T
*state
, REMOTE_EVENT_T
*event
)
425 if (down_interruptible(
427 ((char *)state
+ event
->event
)) != 0) {
441 remote_event_signal_local(VCHIQ_STATE_T
*state
, REMOTE_EVENT_T
*event
)
444 up((struct semaphore
*)((char *)state
+ event
->event
));
448 remote_event_poll(VCHIQ_STATE_T
*state
, REMOTE_EVENT_T
*event
)
450 if (event
->fired
&& event
->armed
)
451 remote_event_signal_local(state
, event
);
455 remote_event_pollall(VCHIQ_STATE_T
*state
)
457 remote_event_poll(state
, &state
->local
->sync_trigger
);
458 remote_event_poll(state
, &state
->local
->sync_release
);
459 remote_event_poll(state
, &state
->local
->trigger
);
460 remote_event_poll(state
, &state
->local
->recycle
);
463 /* Round up message sizes so that any space at the end of a slot is always big
464 ** enough for a header. This relies on header size being a power of two, which
465 ** has been verified earlier by a static assertion. */
467 static inline unsigned int
468 calc_stride(unsigned int size
)
470 /* Allow room for the header */
471 size
+= sizeof(VCHIQ_HEADER_T
);
474 return (size
+ sizeof(VCHIQ_HEADER_T
) - 1) & ~(sizeof(VCHIQ_HEADER_T
)
478 /* Called by the slot handler thread */
479 static VCHIQ_SERVICE_T
*
480 get_listening_service(VCHIQ_STATE_T
*state
, int fourcc
)
484 WARN_ON(fourcc
== VCHIQ_FOURCC_INVALID
);
486 for (i
= 0; i
< state
->unused_service
; i
++) {
487 VCHIQ_SERVICE_T
*service
= state
->services
[i
];
489 (service
->public_fourcc
== fourcc
) &&
490 ((service
->srvstate
== VCHIQ_SRVSTATE_LISTENING
) ||
491 ((service
->srvstate
== VCHIQ_SRVSTATE_OPEN
) &&
492 (service
->remoteport
== VCHIQ_PORT_FREE
)))) {
493 lock_service(service
);
501 /* Called by the slot handler thread */
502 static VCHIQ_SERVICE_T
*
503 get_connected_service(VCHIQ_STATE_T
*state
, unsigned int port
)
506 for (i
= 0; i
< state
->unused_service
; i
++) {
507 VCHIQ_SERVICE_T
*service
= state
->services
[i
];
508 if (service
&& (service
->srvstate
== VCHIQ_SRVSTATE_OPEN
)
509 && (service
->remoteport
== port
)) {
510 lock_service(service
);
518 request_poll(VCHIQ_STATE_T
*state
, VCHIQ_SERVICE_T
*service
, int poll_type
)
524 value
= atomic_read(&service
->poll_flags
);
525 } while (atomic_cmpxchg(&service
->poll_flags
, value
,
526 value
| (1 << poll_type
)) != value
);
529 value
= atomic_read(&state
->poll_services
[
530 service
->localport
>>5]);
531 } while (atomic_cmpxchg(
532 &state
->poll_services
[service
->localport
>>5],
533 value
, value
| (1 << (service
->localport
& 0x1f)))
537 state
->poll_needed
= 1;
540 /* ... and ensure the slot handler runs. */
541 remote_event_signal_local(state
, &state
->local
->trigger
);
544 /* Called from queue_message, by the slot handler and application threads,
545 ** with slot_mutex held */
546 static VCHIQ_HEADER_T
*
547 reserve_space(VCHIQ_STATE_T
*state
, int space
, int is_blocking
)
549 VCHIQ_SHARED_STATE_T
*local
= state
->local
;
550 int tx_pos
= state
->local_tx_pos
;
551 int slot_space
= VCHIQ_SLOT_SIZE
- (tx_pos
& VCHIQ_SLOT_MASK
);
553 if (space
> slot_space
) {
554 VCHIQ_HEADER_T
*header
;
555 /* Fill the remaining space with padding */
556 WARN_ON(state
->tx_data
== NULL
);
557 header
= (VCHIQ_HEADER_T
*)
558 (state
->tx_data
+ (tx_pos
& VCHIQ_SLOT_MASK
));
559 header
->msgid
= VCHIQ_MSGID_PADDING
;
560 header
->size
= slot_space
- sizeof(VCHIQ_HEADER_T
);
562 tx_pos
+= slot_space
;
565 /* If necessary, get the next slot. */
566 if ((tx_pos
& VCHIQ_SLOT_MASK
) == 0) {
569 /* If there is no free slot... */
571 if (down_trylock(&state
->slot_available_event
) != 0) {
572 /* ...wait for one. */
574 VCHIQ_STATS_INC(state
, slot_stalls
);
576 /* But first, flush through the last slot. */
577 state
->local_tx_pos
= tx_pos
;
578 local
->tx_pos
= tx_pos
;
579 remote_event_signal(&state
->remote
->trigger
);
583 &state
->slot_available_event
) != 0))
584 return NULL
; /* No space available */
588 (state
->slot_queue_available
* VCHIQ_SLOT_SIZE
));
590 slot_index
= local
->slot_queue
[
591 SLOT_QUEUE_INDEX_FROM_POS(tx_pos
) &
592 VCHIQ_SLOT_QUEUE_MASK
];
594 (char *)SLOT_DATA_FROM_INDEX(state
, slot_index
);
597 state
->local_tx_pos
= tx_pos
+ space
;
599 return (VCHIQ_HEADER_T
*)(state
->tx_data
+ (tx_pos
& VCHIQ_SLOT_MASK
));
602 /* Called by the recycle thread. */
604 process_free_queue(VCHIQ_STATE_T
*state
)
606 VCHIQ_SHARED_STATE_T
*local
= state
->local
;
607 BITSET_T service_found
[BITSET_SIZE(VCHIQ_MAX_SERVICES
)];
608 int slot_queue_available
;
610 /* Find slots which have been freed by the other side, and return them
611 ** to the available queue. */
612 slot_queue_available
= state
->slot_queue_available
;
614 /* Use a memory barrier to ensure that any state that may have been
615 ** modified by another thread is not masked by stale prefetched
619 while (slot_queue_available
!= local
->slot_queue_recycle
) {
621 int slot_index
= local
->slot_queue
[slot_queue_available
++ &
622 VCHIQ_SLOT_QUEUE_MASK
];
623 char *data
= (char *)SLOT_DATA_FROM_INDEX(state
, slot_index
);
628 vchiq_log_trace(vchiq_core_log_level
, "%d: pfq %d=%pK %x %x",
629 state
->id
, slot_index
, data
,
630 local
->slot_queue_recycle
, slot_queue_available
);
632 /* Initialise the bitmask for services which have used this
634 BITSET_ZERO(service_found
);
638 while (pos
< VCHIQ_SLOT_SIZE
) {
639 VCHIQ_HEADER_T
*header
=
640 (VCHIQ_HEADER_T
*)(data
+ pos
);
641 int msgid
= header
->msgid
;
642 if (VCHIQ_MSG_TYPE(msgid
) == VCHIQ_MSG_DATA
) {
643 int port
= VCHIQ_MSG_SRCPORT(msgid
);
644 VCHIQ_SERVICE_QUOTA_T
*service_quota
=
645 &state
->service_quotas
[port
];
647 spin_lock("a_spinlock
);
648 count
= service_quota
->message_use_count
;
650 service_quota
->message_use_count
=
652 spin_unlock("a_spinlock
);
654 if (count
== service_quota
->message_quota
)
655 /* Signal the service that it
656 ** has dropped below its quota
658 up(&service_quota
->quota_event
);
659 else if (count
== 0) {
660 vchiq_log_error(vchiq_core_log_level
,
661 "service %d message_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
663 service_quota
->message_use_count
,
664 header
, msgid
, header
->msgid
,
666 WARN(1, "invalid message use count\n");
668 if (!BITSET_IS_SET(service_found
, port
)) {
669 /* Set the found bit for this service */
670 BITSET_SET(service_found
, port
);
672 spin_lock("a_spinlock
);
673 count
= service_quota
->slot_use_count
;
675 service_quota
->slot_use_count
=
677 spin_unlock("a_spinlock
);
680 /* Signal the service in case
681 ** it has dropped below its
683 up(&service_quota
->quota_event
);
685 vchiq_core_log_level
,
686 "%d: pfq:%d %x@%pK - slot_use->%d",
688 header
->size
, header
,
692 vchiq_core_log_level
,
693 "service %d slot_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
695 msgid
, header
->msgid
,
697 WARN(1, "bad slot use count\n");
704 pos
+= calc_stride(header
->size
);
705 if (pos
> VCHIQ_SLOT_SIZE
) {
706 vchiq_log_error(vchiq_core_log_level
,
707 "pfq - pos %x: header %pK, msgid %x, header->msgid %x, header->size %x",
708 pos
, header
, msgid
, header
->msgid
,
710 WARN(1, "invalid slot position\n");
716 spin_lock("a_spinlock
);
717 count
= state
->data_use_count
;
719 state
->data_use_count
=
721 spin_unlock("a_spinlock
);
722 if (count
== state
->data_quota
)
723 up(&state
->data_quota_event
);
728 state
->slot_queue_available
= slot_queue_available
;
729 up(&state
->slot_available_event
);
733 /* Called by the slot handler and application threads */
734 static VCHIQ_STATUS_T
735 queue_message(VCHIQ_STATE_T
*state
, VCHIQ_SERVICE_T
*service
,
736 int msgid
, const VCHIQ_ELEMENT_T
*elements
,
737 int count
, int size
, int flags
)
739 VCHIQ_SHARED_STATE_T
*local
;
740 VCHIQ_SERVICE_QUOTA_T
*service_quota
= NULL
;
741 VCHIQ_HEADER_T
*header
;
742 int type
= VCHIQ_MSG_TYPE(msgid
);
746 local
= state
->local
;
748 stride
= calc_stride(size
);
750 WARN_ON(!(stride
<= VCHIQ_SLOT_SIZE
));
752 if (!(flags
& QMFLAGS_NO_MUTEX_LOCK
) &&
753 (mutex_lock_killable(&state
->slot_mutex
) != 0))
756 if (type
== VCHIQ_MSG_DATA
) {
760 BUG_ON((flags
& (QMFLAGS_NO_MUTEX_LOCK
|
761 QMFLAGS_NO_MUTEX_UNLOCK
)) != 0);
763 if (service
->closing
) {
764 /* The service has been closed */
765 mutex_unlock(&state
->slot_mutex
);
769 service_quota
= &state
->service_quotas
[service
->localport
];
771 spin_lock("a_spinlock
);
773 /* Ensure this service doesn't use more than its quota of
774 ** messages or slots */
775 tx_end_index
= SLOT_QUEUE_INDEX_FROM_POS(
776 state
->local_tx_pos
+ stride
- 1);
778 /* Ensure data messages don't use more than their quota of
780 while ((tx_end_index
!= state
->previous_data_index
) &&
781 (state
->data_use_count
== state
->data_quota
)) {
782 VCHIQ_STATS_INC(state
, data_stalls
);
783 spin_unlock("a_spinlock
);
784 mutex_unlock(&state
->slot_mutex
);
786 if (down_interruptible(&state
->data_quota_event
)
790 mutex_lock(&state
->slot_mutex
);
791 spin_lock("a_spinlock
);
792 tx_end_index
= SLOT_QUEUE_INDEX_FROM_POS(
793 state
->local_tx_pos
+ stride
- 1);
794 if ((tx_end_index
== state
->previous_data_index
) ||
795 (state
->data_use_count
< state
->data_quota
)) {
796 /* Pass the signal on to other waiters */
797 up(&state
->data_quota_event
);
802 while ((service_quota
->message_use_count
==
803 service_quota
->message_quota
) ||
804 ((tx_end_index
!= service_quota
->previous_tx_index
) &&
805 (service_quota
->slot_use_count
==
806 service_quota
->slot_quota
))) {
807 spin_unlock("a_spinlock
);
808 vchiq_log_trace(vchiq_core_log_level
,
809 "%d: qm:%d %s,%zx - quota stall "
811 state
->id
, service
->localport
,
812 msg_type_str(type
), size
,
813 service_quota
->message_use_count
,
814 service_quota
->slot_use_count
);
815 VCHIQ_SERVICE_STATS_INC(service
, quota_stalls
);
816 mutex_unlock(&state
->slot_mutex
);
817 if (down_interruptible(&service_quota
->quota_event
)
820 if (service
->closing
)
822 if (mutex_lock_killable(&state
->slot_mutex
) != 0)
824 if (service
->srvstate
!= VCHIQ_SRVSTATE_OPEN
) {
825 /* The service has been closed */
826 mutex_unlock(&state
->slot_mutex
);
829 spin_lock("a_spinlock
);
830 tx_end_index
= SLOT_QUEUE_INDEX_FROM_POS(
831 state
->local_tx_pos
+ stride
- 1);
834 spin_unlock("a_spinlock
);
837 header
= reserve_space(state
, stride
, flags
& QMFLAGS_IS_BLOCKING
);
841 VCHIQ_SERVICE_STATS_INC(service
, slot_stalls
);
842 /* In the event of a failure, return the mutex to the
844 if (!(flags
& QMFLAGS_NO_MUTEX_LOCK
))
845 mutex_unlock(&state
->slot_mutex
);
849 if (type
== VCHIQ_MSG_DATA
) {
854 vchiq_log_info(vchiq_core_log_level
,
855 "%d: qm %s@%pK,%zx (%d->%d)",
856 state
->id
, msg_type_str(VCHIQ_MSG_TYPE(msgid
)),
857 header
, size
, VCHIQ_MSG_SRCPORT(msgid
),
858 VCHIQ_MSG_DSTPORT(msgid
));
861 BUG_ON((flags
& (QMFLAGS_NO_MUTEX_LOCK
|
862 QMFLAGS_NO_MUTEX_UNLOCK
)) != 0);
864 for (i
= 0, pos
= 0; i
< (unsigned int)count
;
865 pos
+= elements
[i
++].size
)
866 if (elements
[i
].size
) {
867 if (vchiq_copy_from_user
868 (header
->data
+ pos
, elements
[i
].data
,
869 (size_t) elements
[i
].size
) !=
871 mutex_unlock(&state
->slot_mutex
);
872 VCHIQ_SERVICE_STATS_INC(service
,
878 if (SRVTRACE_ENABLED(service
,
880 vchiq_log_dump_mem("Sent", 0,
884 spin_lock("a_spinlock
);
885 service_quota
->message_use_count
++;
888 SLOT_QUEUE_INDEX_FROM_POS(state
->local_tx_pos
- 1);
890 /* If this transmission can't fit in the last slot used by any
891 ** service, the data_use_count must be increased. */
892 if (tx_end_index
!= state
->previous_data_index
) {
893 state
->previous_data_index
= tx_end_index
;
894 state
->data_use_count
++;
897 /* If this isn't the same slot last used by this service,
898 ** the service's slot_use_count must be increased. */
899 if (tx_end_index
!= service_quota
->previous_tx_index
) {
900 service_quota
->previous_tx_index
= tx_end_index
;
901 slot_use_count
= ++service_quota
->slot_use_count
;
906 spin_unlock("a_spinlock
);
909 vchiq_log_trace(vchiq_core_log_level
,
910 "%d: qm:%d %s,%zx - slot_use->%d (hdr %p)",
911 state
->id
, service
->localport
,
912 msg_type_str(VCHIQ_MSG_TYPE(msgid
)), size
,
913 slot_use_count
, header
);
915 VCHIQ_SERVICE_STATS_INC(service
, ctrl_tx_count
);
916 VCHIQ_SERVICE_STATS_ADD(service
, ctrl_tx_bytes
, size
);
918 vchiq_log_info(vchiq_core_log_level
,
919 "%d: qm %s@%pK,%zx (%d->%d)", state
->id
,
920 msg_type_str(VCHIQ_MSG_TYPE(msgid
)),
921 header
, size
, VCHIQ_MSG_SRCPORT(msgid
),
922 VCHIQ_MSG_DSTPORT(msgid
));
924 WARN_ON(!((count
== 1) && (size
== elements
[0].size
)));
925 memcpy(header
->data
, elements
[0].data
,
928 VCHIQ_STATS_INC(state
, ctrl_tx_count
);
931 header
->msgid
= msgid
;
938 ? service
->base
.fourcc
939 : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
941 vchiq_log_info(SRVTRACE_LEVEL(service
),
942 "Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%zu",
943 msg_type_str(VCHIQ_MSG_TYPE(msgid
)),
944 VCHIQ_MSG_TYPE(msgid
),
945 VCHIQ_FOURCC_AS_4CHARS(svc_fourcc
),
946 VCHIQ_MSG_SRCPORT(msgid
),
947 VCHIQ_MSG_DSTPORT(msgid
),
951 /* Make sure the new header is visible to the peer. */
954 /* Make the new tx_pos visible to the peer. */
955 local
->tx_pos
= state
->local_tx_pos
;
958 if (service
&& (type
== VCHIQ_MSG_CLOSE
))
959 vchiq_set_service_state(service
, VCHIQ_SRVSTATE_CLOSESENT
);
961 if (!(flags
& QMFLAGS_NO_MUTEX_UNLOCK
))
962 mutex_unlock(&state
->slot_mutex
);
964 remote_event_signal(&state
->remote
->trigger
);
966 return VCHIQ_SUCCESS
;
969 /* Called by the slot handler and application threads */
970 static VCHIQ_STATUS_T
971 queue_message_sync(VCHIQ_STATE_T
*state
, VCHIQ_SERVICE_T
*service
,
972 int msgid
, const VCHIQ_ELEMENT_T
*elements
,
973 int count
, int size
, int is_blocking
)
975 VCHIQ_SHARED_STATE_T
*local
;
976 VCHIQ_HEADER_T
*header
;
978 local
= state
->local
;
980 if ((VCHIQ_MSG_TYPE(msgid
) != VCHIQ_MSG_RESUME
) &&
981 (mutex_lock_killable(&state
->sync_mutex
) != 0))
984 remote_event_wait(state
, &local
->sync_release
);
988 header
= (VCHIQ_HEADER_T
*)SLOT_DATA_FROM_INDEX(state
,
992 int oldmsgid
= header
->msgid
;
993 if (oldmsgid
!= VCHIQ_MSGID_PADDING
)
994 vchiq_log_error(vchiq_core_log_level
,
995 "%d: qms - msgid %x, not PADDING",
996 state
->id
, oldmsgid
);
1002 vchiq_log_info(vchiq_sync_log_level
,
1003 "%d: qms %s@%pK,%x (%d->%d)", state
->id
,
1004 msg_type_str(VCHIQ_MSG_TYPE(msgid
)),
1005 header
, size
, VCHIQ_MSG_SRCPORT(msgid
),
1006 VCHIQ_MSG_DSTPORT(msgid
));
1008 for (i
= 0, pos
= 0; i
< (unsigned int)count
;
1009 pos
+= elements
[i
++].size
)
1010 if (elements
[i
].size
) {
1011 if (vchiq_copy_from_user
1012 (header
->data
+ pos
, elements
[i
].data
,
1013 (size_t) elements
[i
].size
) !=
1015 mutex_unlock(&state
->sync_mutex
);
1016 VCHIQ_SERVICE_STATS_INC(service
,
1022 if (vchiq_sync_log_level
>= VCHIQ_LOG_TRACE
)
1023 vchiq_log_dump_mem("Sent Sync",
1027 VCHIQ_SERVICE_STATS_INC(service
, ctrl_tx_count
);
1028 VCHIQ_SERVICE_STATS_ADD(service
, ctrl_tx_bytes
, size
);
1030 vchiq_log_info(vchiq_sync_log_level
,
1031 "%d: qms %s@%pK,%x (%d->%d)", state
->id
,
1032 msg_type_str(VCHIQ_MSG_TYPE(msgid
)),
1033 header
, size
, VCHIQ_MSG_SRCPORT(msgid
),
1034 VCHIQ_MSG_DSTPORT(msgid
));
1036 WARN_ON(!((count
== 1) && (size
== elements
[0].size
)));
1037 memcpy(header
->data
, elements
[0].data
,
1040 VCHIQ_STATS_INC(state
, ctrl_tx_count
);
1043 header
->size
= size
;
1044 header
->msgid
= msgid
;
1046 if (vchiq_sync_log_level
>= VCHIQ_LOG_TRACE
) {
1049 svc_fourcc
= service
1050 ? service
->base
.fourcc
1051 : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
1053 vchiq_log_trace(vchiq_sync_log_level
,
1054 "Sent Sync Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
1055 msg_type_str(VCHIQ_MSG_TYPE(msgid
)),
1056 VCHIQ_MSG_TYPE(msgid
),
1057 VCHIQ_FOURCC_AS_4CHARS(svc_fourcc
),
1058 VCHIQ_MSG_SRCPORT(msgid
),
1059 VCHIQ_MSG_DSTPORT(msgid
),
1063 /* Make sure the new header is visible to the peer. */
1066 remote_event_signal(&state
->remote
->sync_trigger
);
1068 if (VCHIQ_MSG_TYPE(msgid
) != VCHIQ_MSG_PAUSE
)
1069 mutex_unlock(&state
->sync_mutex
);
1071 return VCHIQ_SUCCESS
;
1075 claim_slot(VCHIQ_SLOT_INFO_T
*slot
)
1081 release_slot(VCHIQ_STATE_T
*state
, VCHIQ_SLOT_INFO_T
*slot_info
,
1082 VCHIQ_HEADER_T
*header
, VCHIQ_SERVICE_T
*service
)
1086 mutex_lock(&state
->recycle_mutex
);
1089 int msgid
= header
->msgid
;
1090 if (((msgid
& VCHIQ_MSGID_CLAIMED
) == 0) ||
1091 (service
&& service
->closing
)) {
1092 mutex_unlock(&state
->recycle_mutex
);
1096 /* Rewrite the message header to prevent a double
1098 header
->msgid
= msgid
& ~VCHIQ_MSGID_CLAIMED
;
1101 release_count
= slot_info
->release_count
;
1102 slot_info
->release_count
= ++release_count
;
1104 if (release_count
== slot_info
->use_count
) {
1105 int slot_queue_recycle
;
1106 /* Add to the freed queue */
1108 /* A read barrier is necessary here to prevent speculative
1109 ** fetches of remote->slot_queue_recycle from overtaking the
1113 slot_queue_recycle
= state
->remote
->slot_queue_recycle
;
1114 state
->remote
->slot_queue
[slot_queue_recycle
&
1115 VCHIQ_SLOT_QUEUE_MASK
] =
1116 SLOT_INDEX_FROM_INFO(state
, slot_info
);
1117 state
->remote
->slot_queue_recycle
= slot_queue_recycle
+ 1;
1118 vchiq_log_info(vchiq_core_log_level
,
1119 "%d: release_slot %d - recycle->%x",
1120 state
->id
, SLOT_INDEX_FROM_INFO(state
, slot_info
),
1121 state
->remote
->slot_queue_recycle
);
1123 /* A write barrier is necessary, but remote_event_signal
1125 remote_event_signal(&state
->remote
->recycle
);
1128 mutex_unlock(&state
->recycle_mutex
);
1131 /* Called by the slot handler - don't hold the bulk mutex */
1132 static VCHIQ_STATUS_T
1133 notify_bulks(VCHIQ_SERVICE_T
*service
, VCHIQ_BULK_QUEUE_T
*queue
,
1136 VCHIQ_STATUS_T status
= VCHIQ_SUCCESS
;
1138 vchiq_log_trace(vchiq_core_log_level
,
1139 "%d: nb:%d %cx - p=%x rn=%x r=%x",
1140 service
->state
->id
, service
->localport
,
1141 (queue
== &service
->bulk_tx
) ? 't' : 'r',
1142 queue
->process
, queue
->remote_notify
, queue
->remove
);
1144 if (service
->state
->is_master
) {
1145 while (queue
->remote_notify
!= queue
->process
) {
1146 VCHIQ_BULK_T
*bulk
=
1147 &queue
->bulks
[BULK_INDEX(queue
->remote_notify
)];
1148 int msgtype
= (bulk
->dir
== VCHIQ_BULK_TRANSMIT
) ?
1149 VCHIQ_MSG_BULK_RX_DONE
: VCHIQ_MSG_BULK_TX_DONE
;
1150 int msgid
= VCHIQ_MAKE_MSG(msgtype
, service
->localport
,
1151 service
->remoteport
);
1152 VCHIQ_ELEMENT_T element
= { &bulk
->actual
, 4 };
1153 /* Only reply to non-dummy bulk requests */
1154 if (bulk
->remote_data
) {
1155 status
= queue_message(service
->state
, NULL
,
1156 msgid
, &element
, 1, 4, 0);
1157 if (status
!= VCHIQ_SUCCESS
)
1160 queue
->remote_notify
++;
1163 queue
->remote_notify
= queue
->process
;
1166 if (status
== VCHIQ_SUCCESS
) {
1167 while (queue
->remove
!= queue
->remote_notify
) {
1168 VCHIQ_BULK_T
*bulk
=
1169 &queue
->bulks
[BULK_INDEX(queue
->remove
)];
1171 /* Only generate callbacks for non-dummy bulk
1172 ** requests, and non-terminated services */
1173 if (bulk
->data
&& service
->instance
) {
1174 if (bulk
->actual
!= VCHIQ_BULK_ACTUAL_ABORTED
) {
1175 if (bulk
->dir
== VCHIQ_BULK_TRANSMIT
) {
1176 VCHIQ_SERVICE_STATS_INC(service
,
1178 VCHIQ_SERVICE_STATS_ADD(service
,
1182 VCHIQ_SERVICE_STATS_INC(service
,
1184 VCHIQ_SERVICE_STATS_ADD(service
,
1189 VCHIQ_SERVICE_STATS_INC(service
,
1190 bulk_aborted_count
);
1192 if (bulk
->mode
== VCHIQ_BULK_MODE_BLOCKING
) {
1193 struct bulk_waiter
*waiter
;
1194 spin_lock(&bulk_waiter_spinlock
);
1195 waiter
= bulk
->userdata
;
1197 waiter
->actual
= bulk
->actual
;
1200 spin_unlock(&bulk_waiter_spinlock
);
1201 } else if (bulk
->mode
==
1202 VCHIQ_BULK_MODE_CALLBACK
) {
1203 VCHIQ_REASON_T reason
= (bulk
->dir
==
1204 VCHIQ_BULK_TRANSMIT
) ?
1206 VCHIQ_BULK_ACTUAL_ABORTED
) ?
1207 VCHIQ_BULK_TRANSMIT_ABORTED
:
1208 VCHIQ_BULK_TRANSMIT_DONE
) :
1210 VCHIQ_BULK_ACTUAL_ABORTED
) ?
1211 VCHIQ_BULK_RECEIVE_ABORTED
:
1212 VCHIQ_BULK_RECEIVE_DONE
);
1213 status
= make_service_callback(service
,
1214 reason
, NULL
, bulk
->userdata
);
1215 if (status
== VCHIQ_RETRY
)
1221 up(&service
->bulk_remove_event
);
1224 status
= VCHIQ_SUCCESS
;
1227 if (status
== VCHIQ_RETRY
)
1228 request_poll(service
->state
, service
,
1229 (queue
== &service
->bulk_tx
) ?
1230 VCHIQ_POLL_TXNOTIFY
: VCHIQ_POLL_RXNOTIFY
);
1235 /* Called by the slot handler thread */
1237 poll_services(VCHIQ_STATE_T
*state
)
1241 for (group
= 0; group
< BITSET_SIZE(state
->unused_service
); group
++) {
1243 flags
= atomic_xchg(&state
->poll_services
[group
], 0);
1244 for (i
= 0; flags
; i
++) {
1245 if (flags
& (1 << i
)) {
1246 VCHIQ_SERVICE_T
*service
=
1247 find_service_by_port(state
,
1249 uint32_t service_flags
;
1254 atomic_xchg(&service
->poll_flags
, 0);
1256 (1 << VCHIQ_POLL_REMOVE
)) {
1257 vchiq_log_info(vchiq_core_log_level
,
1258 "%d: ps - remove %d<->%d",
1259 state
->id
, service
->localport
,
1260 service
->remoteport
);
1262 /* Make it look like a client, because
1263 it must be removed and not left in
1264 the LISTENING state. */
1265 service
->public_fourcc
=
1266 VCHIQ_FOURCC_INVALID
;
1268 if (vchiq_close_service_internal(
1269 service
, 0/*!close_recvd*/) !=
1271 request_poll(state
, service
,
1273 } else if (service_flags
&
1274 (1 << VCHIQ_POLL_TERMINATE
)) {
1275 vchiq_log_info(vchiq_core_log_level
,
1276 "%d: ps - terminate %d<->%d",
1277 state
->id
, service
->localport
,
1278 service
->remoteport
);
1279 if (vchiq_close_service_internal(
1280 service
, 0/*!close_recvd*/) !=
1282 request_poll(state
, service
,
1283 VCHIQ_POLL_TERMINATE
);
1285 if (service_flags
& (1 << VCHIQ_POLL_TXNOTIFY
))
1286 notify_bulks(service
,
1289 if (service_flags
& (1 << VCHIQ_POLL_RXNOTIFY
))
1290 notify_bulks(service
,
1293 unlock_service(service
);
1299 /* Called by the slot handler or application threads, holding the bulk mutex. */
1301 resolve_bulks(VCHIQ_SERVICE_T
*service
, VCHIQ_BULK_QUEUE_T
*queue
)
1303 VCHIQ_STATE_T
*state
= service
->state
;
1307 while ((queue
->process
!= queue
->local_insert
) &&
1308 (queue
->process
!= queue
->remote_insert
)) {
1309 VCHIQ_BULK_T
*bulk
= &queue
->bulks
[BULK_INDEX(queue
->process
)];
1311 vchiq_log_trace(vchiq_core_log_level
,
1312 "%d: rb:%d %cx - li=%x ri=%x p=%x",
1313 state
->id
, service
->localport
,
1314 (queue
== &service
->bulk_tx
) ? 't' : 'r',
1315 queue
->local_insert
, queue
->remote_insert
,
1318 WARN_ON(!((int)(queue
->local_insert
- queue
->process
) > 0));
1319 WARN_ON(!((int)(queue
->remote_insert
- queue
->process
) > 0));
1321 rc
= mutex_lock_killable(&state
->bulk_transfer_mutex
);
1325 vchiq_transfer_bulk(bulk
);
1326 mutex_unlock(&state
->bulk_transfer_mutex
);
1328 if (SRVTRACE_ENABLED(service
, VCHIQ_LOG_INFO
)) {
1329 const char *header
= (queue
== &service
->bulk_tx
) ?
1330 "Send Bulk to" : "Recv Bulk from";
1331 if (bulk
->actual
!= VCHIQ_BULK_ACTUAL_ABORTED
)
1332 vchiq_log_info(SRVTRACE_LEVEL(service
),
1333 "%s %c%c%c%c d:%d len:%d %pK<->%pK",
1335 VCHIQ_FOURCC_AS_4CHARS(
1336 service
->base
.fourcc
),
1337 service
->remoteport
, bulk
->size
,
1338 bulk
->data
, bulk
->remote_data
);
1340 vchiq_log_info(SRVTRACE_LEVEL(service
),
1341 "%s %c%c%c%c d:%d ABORTED - tx len:%d,"
1342 " rx len:%d %pK<->%pK",
1344 VCHIQ_FOURCC_AS_4CHARS(
1345 service
->base
.fourcc
),
1346 service
->remoteport
,
1347 bulk
->size
, bulk
->remote_size
,
1348 bulk
->data
, bulk
->remote_data
);
1351 vchiq_complete_bulk(bulk
);
1358 /* Called with the bulk_mutex held */
1360 abort_outstanding_bulks(VCHIQ_SERVICE_T
*service
, VCHIQ_BULK_QUEUE_T
*queue
)
1362 int is_tx
= (queue
== &service
->bulk_tx
);
1363 vchiq_log_trace(vchiq_core_log_level
,
1364 "%d: aob:%d %cx - li=%x ri=%x p=%x",
1365 service
->state
->id
, service
->localport
, is_tx
? 't' : 'r',
1366 queue
->local_insert
, queue
->remote_insert
, queue
->process
);
1368 WARN_ON(!((int)(queue
->local_insert
- queue
->process
) >= 0));
1369 WARN_ON(!((int)(queue
->remote_insert
- queue
->process
) >= 0));
1371 while ((queue
->process
!= queue
->local_insert
) ||
1372 (queue
->process
!= queue
->remote_insert
)) {
1373 VCHIQ_BULK_T
*bulk
= &queue
->bulks
[BULK_INDEX(queue
->process
)];
1375 if (queue
->process
== queue
->remote_insert
) {
1376 /* fabricate a matching dummy bulk */
1377 bulk
->remote_data
= NULL
;
1378 bulk
->remote_size
= 0;
1379 queue
->remote_insert
++;
1382 if (queue
->process
!= queue
->local_insert
) {
1383 vchiq_complete_bulk(bulk
);
1385 vchiq_log_info(SRVTRACE_LEVEL(service
),
1386 "%s %c%c%c%c d:%d ABORTED - tx len:%d, "
1388 is_tx
? "Send Bulk to" : "Recv Bulk from",
1389 VCHIQ_FOURCC_AS_4CHARS(service
->base
.fourcc
),
1390 service
->remoteport
,
1394 /* fabricate a matching dummy bulk */
1397 bulk
->actual
= VCHIQ_BULK_ACTUAL_ABORTED
;
1398 bulk
->dir
= is_tx
? VCHIQ_BULK_TRANSMIT
:
1400 queue
->local_insert
++;
1407 /* Called from the slot handler thread */
1409 pause_bulks(VCHIQ_STATE_T
*state
)
1411 if (unlikely(atomic_inc_return(&pause_bulks_count
) != 1)) {
1413 atomic_set(&pause_bulks_count
, 1);
1417 /* Block bulk transfers from all services */
1418 mutex_lock(&state
->bulk_transfer_mutex
);
1421 /* Called from the slot handler thread */
1423 resume_bulks(VCHIQ_STATE_T
*state
)
1426 if (unlikely(atomic_dec_return(&pause_bulks_count
) != 0)) {
1428 atomic_set(&pause_bulks_count
, 0);
1432 /* Allow bulk transfers from all services */
1433 mutex_unlock(&state
->bulk_transfer_mutex
);
1435 if (state
->deferred_bulks
== 0)
1438 /* Deal with any bulks which had to be deferred due to being in
1439 * paused state. Don't try to match up to number of deferred bulks
1440 * in case we've had something come and close the service in the
1441 * interim - just process all bulk queues for all services */
1442 vchiq_log_info(vchiq_core_log_level
, "%s: processing %d deferred bulks",
1443 __func__
, state
->deferred_bulks
);
1445 for (i
= 0; i
< state
->unused_service
; i
++) {
1446 VCHIQ_SERVICE_T
*service
= state
->services
[i
];
1447 int resolved_rx
= 0;
1448 int resolved_tx
= 0;
1449 if (!service
|| (service
->srvstate
!= VCHIQ_SRVSTATE_OPEN
))
1452 mutex_lock(&service
->bulk_mutex
);
1453 resolved_rx
= resolve_bulks(service
, &service
->bulk_rx
);
1454 resolved_tx
= resolve_bulks(service
, &service
->bulk_tx
);
1455 mutex_unlock(&service
->bulk_mutex
);
1457 notify_bulks(service
, &service
->bulk_rx
, 1);
1459 notify_bulks(service
, &service
->bulk_tx
, 1);
1461 state
->deferred_bulks
= 0;
1465 parse_open(VCHIQ_STATE_T
*state
, VCHIQ_HEADER_T
*header
)
1467 VCHIQ_SERVICE_T
*service
= NULL
;
1470 unsigned int localport
, remoteport
;
1472 msgid
= header
->msgid
;
1473 size
= header
->size
;
1474 type
= VCHIQ_MSG_TYPE(msgid
);
1475 localport
= VCHIQ_MSG_DSTPORT(msgid
);
1476 remoteport
= VCHIQ_MSG_SRCPORT(msgid
);
1477 if (size
>= sizeof(struct vchiq_open_payload
)) {
1478 const struct vchiq_open_payload
*payload
=
1479 (struct vchiq_open_payload
*)header
->data
;
1480 unsigned int fourcc
;
1482 fourcc
= payload
->fourcc
;
1483 vchiq_log_info(vchiq_core_log_level
,
1484 "%d: prs OPEN@%pK (%d->'%c%c%c%c')",
1485 state
->id
, header
, localport
,
1486 VCHIQ_FOURCC_AS_4CHARS(fourcc
));
1488 service
= get_listening_service(state
, fourcc
);
1491 /* A matching service exists */
1492 short version
= payload
->version
;
1493 short version_min
= payload
->version_min
;
1494 if ((service
->version
< version_min
) ||
1495 (version
< service
->version_min
)) {
1496 /* Version mismatch */
1497 vchiq_loud_error_header();
1498 vchiq_loud_error("%d: service %d (%c%c%c%c) "
1499 "version mismatch - local (%d, min %d)"
1500 " vs. remote (%d, min %d)",
1501 state
->id
, service
->localport
,
1502 VCHIQ_FOURCC_AS_4CHARS(fourcc
),
1503 service
->version
, service
->version_min
,
1504 version
, version_min
);
1505 vchiq_loud_error_footer();
1506 unlock_service(service
);
1510 service
->peer_version
= version
;
1512 if (service
->srvstate
== VCHIQ_SRVSTATE_LISTENING
) {
1513 struct vchiq_openack_payload ack_payload
= {
1516 VCHIQ_ELEMENT_T body
= {
1521 if (state
->version_common
<
1522 VCHIQ_VERSION_SYNCHRONOUS_MODE
)
1525 /* Acknowledge the OPEN */
1526 if (service
->sync
&&
1527 (state
->version_common
>=
1528 VCHIQ_VERSION_SYNCHRONOUS_MODE
)) {
1529 if (queue_message_sync(state
, NULL
,
1534 &body
, 1, sizeof(ack_payload
),
1536 goto bail_not_ready
;
1538 if (queue_message(state
, NULL
,
1543 &body
, 1, sizeof(ack_payload
),
1545 goto bail_not_ready
;
1548 /* The service is now open */
1549 vchiq_set_service_state(service
,
1550 service
->sync
? VCHIQ_SRVSTATE_OPENSYNC
1551 : VCHIQ_SRVSTATE_OPEN
);
1554 service
->remoteport
= remoteport
;
1555 service
->client_id
= ((int *)header
->data
)[1];
1556 if (make_service_callback(service
, VCHIQ_SERVICE_OPENED
,
1557 NULL
, NULL
) == VCHIQ_RETRY
) {
1558 /* Bail out if not ready */
1559 service
->remoteport
= VCHIQ_PORT_FREE
;
1560 goto bail_not_ready
;
1563 /* Success - the message has been dealt with */
1564 unlock_service(service
);
1570 /* No available service, or an invalid request - send a CLOSE */
1571 if (queue_message(state
, NULL
,
1572 VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE
, 0, VCHIQ_MSG_SRCPORT(msgid
)),
1573 NULL
, 0, 0, 0) == VCHIQ_RETRY
)
1574 goto bail_not_ready
;
1580 unlock_service(service
);
1585 /* Called by the slot handler thread */
1587 parse_rx_slots(VCHIQ_STATE_T
*state
)
1589 VCHIQ_SHARED_STATE_T
*remote
= state
->remote
;
1590 VCHIQ_SERVICE_T
*service
= NULL
;
1592 DEBUG_INITIALISE(state
->local
)
1594 tx_pos
= remote
->tx_pos
;
1596 while (state
->rx_pos
!= tx_pos
) {
1597 VCHIQ_HEADER_T
*header
;
1600 unsigned int localport
, remoteport
;
1602 DEBUG_TRACE(PARSE_LINE
);
1603 if (!state
->rx_data
) {
1605 WARN_ON(!((state
->rx_pos
& VCHIQ_SLOT_MASK
) == 0));
1606 rx_index
= remote
->slot_queue
[
1607 SLOT_QUEUE_INDEX_FROM_POS(state
->rx_pos
) &
1608 VCHIQ_SLOT_QUEUE_MASK
];
1609 state
->rx_data
= (char *)SLOT_DATA_FROM_INDEX(state
,
1611 state
->rx_info
= SLOT_INFO_FROM_INDEX(state
, rx_index
);
1613 /* Initialise use_count to one, and increment
1614 ** release_count at the end of the slot to avoid
1615 ** releasing the slot prematurely. */
1616 state
->rx_info
->use_count
= 1;
1617 state
->rx_info
->release_count
= 0;
1620 header
= (VCHIQ_HEADER_T
*)(state
->rx_data
+
1621 (state
->rx_pos
& VCHIQ_SLOT_MASK
));
1622 DEBUG_VALUE(PARSE_HEADER
, (int)(long)header
);
1623 msgid
= header
->msgid
;
1624 DEBUG_VALUE(PARSE_MSGID
, msgid
);
1625 size
= header
->size
;
1626 type
= VCHIQ_MSG_TYPE(msgid
);
1627 localport
= VCHIQ_MSG_DSTPORT(msgid
);
1628 remoteport
= VCHIQ_MSG_SRCPORT(msgid
);
1630 if (type
!= VCHIQ_MSG_DATA
)
1631 VCHIQ_STATS_INC(state
, ctrl_rx_count
);
1634 case VCHIQ_MSG_OPENACK
:
1635 case VCHIQ_MSG_CLOSE
:
1636 case VCHIQ_MSG_DATA
:
1637 case VCHIQ_MSG_BULK_RX
:
1638 case VCHIQ_MSG_BULK_TX
:
1639 case VCHIQ_MSG_BULK_RX_DONE
:
1640 case VCHIQ_MSG_BULK_TX_DONE
:
1641 service
= find_service_by_port(state
, localport
);
1643 ((service
->remoteport
!= remoteport
) &&
1644 (service
->remoteport
!= VCHIQ_PORT_FREE
))) &&
1646 (type
== VCHIQ_MSG_CLOSE
)) {
1647 /* This could be a CLOSE from a client which
1648 hadn't yet received the OPENACK - look for
1649 the connected service */
1651 unlock_service(service
);
1652 service
= get_connected_service(state
,
1655 vchiq_log_warning(vchiq_core_log_level
,
1656 "%d: prs %s@%pK (%d->%d) - found connected service %d",
1657 state
->id
, msg_type_str(type
),
1658 header
, remoteport
, localport
,
1659 service
->localport
);
1663 vchiq_log_error(vchiq_core_log_level
,
1664 "%d: prs %s@%pK (%d->%d) - invalid/closed service %d",
1665 state
->id
, msg_type_str(type
),
1666 header
, remoteport
, localport
,
1675 if (SRVTRACE_ENABLED(service
, VCHIQ_LOG_INFO
)) {
1678 svc_fourcc
= service
1679 ? service
->base
.fourcc
1680 : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
1681 vchiq_log_info(SRVTRACE_LEVEL(service
),
1682 "Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d "
1684 msg_type_str(type
), type
,
1685 VCHIQ_FOURCC_AS_4CHARS(svc_fourcc
),
1686 remoteport
, localport
, size
);
1688 vchiq_log_dump_mem("Rcvd", 0, header
->data
,
1692 if (((unsigned long)header
& VCHIQ_SLOT_MASK
) +
1693 calc_stride(size
) > VCHIQ_SLOT_SIZE
) {
1694 vchiq_log_error(vchiq_core_log_level
,
1695 "header %pK (msgid %x) - size %x too big for slot",
1696 header
, (unsigned int)msgid
,
1697 (unsigned int)size
);
1698 WARN(1, "oversized for slot\n");
1702 case VCHIQ_MSG_OPEN
:
1703 WARN_ON(!(VCHIQ_MSG_DSTPORT(msgid
) == 0));
1704 if (!parse_open(state
, header
))
1705 goto bail_not_ready
;
1707 case VCHIQ_MSG_OPENACK
:
1708 if (size
>= sizeof(struct vchiq_openack_payload
)) {
1709 const struct vchiq_openack_payload
*payload
=
1710 (struct vchiq_openack_payload
*)
1712 service
->peer_version
= payload
->version
;
1714 vchiq_log_info(vchiq_core_log_level
,
1715 "%d: prs OPENACK@%pK,%x (%d->%d) v:%d",
1716 state
->id
, header
, size
, remoteport
, localport
,
1717 service
->peer_version
);
1718 if (service
->srvstate
==
1719 VCHIQ_SRVSTATE_OPENING
) {
1720 service
->remoteport
= remoteport
;
1721 vchiq_set_service_state(service
,
1722 VCHIQ_SRVSTATE_OPEN
);
1723 up(&service
->remove_event
);
1725 vchiq_log_error(vchiq_core_log_level
,
1726 "OPENACK received in state %s",
1727 srvstate_names
[service
->srvstate
]);
1729 case VCHIQ_MSG_CLOSE
:
1730 WARN_ON(size
!= 0); /* There should be no data */
1732 vchiq_log_info(vchiq_core_log_level
,
1733 "%d: prs CLOSE@%pK (%d->%d)",
1734 state
->id
, header
, remoteport
, localport
);
1736 mark_service_closing_internal(service
, 1);
1738 if (vchiq_close_service_internal(service
,
1739 1/*close_recvd*/) == VCHIQ_RETRY
)
1740 goto bail_not_ready
;
1742 vchiq_log_info(vchiq_core_log_level
,
1743 "Close Service %c%c%c%c s:%u d:%d",
1744 VCHIQ_FOURCC_AS_4CHARS(service
->base
.fourcc
),
1746 service
->remoteport
);
1748 case VCHIQ_MSG_DATA
:
1749 vchiq_log_info(vchiq_core_log_level
,
1750 "%d: prs DATA@%pK,%x (%d->%d)",
1751 state
->id
, header
, size
, remoteport
, localport
);
1753 if ((service
->remoteport
== remoteport
)
1754 && (service
->srvstate
==
1755 VCHIQ_SRVSTATE_OPEN
)) {
1756 header
->msgid
= msgid
| VCHIQ_MSGID_CLAIMED
;
1757 claim_slot(state
->rx_info
);
1758 DEBUG_TRACE(PARSE_LINE
);
1759 if (make_service_callback(service
,
1760 VCHIQ_MESSAGE_AVAILABLE
, header
,
1761 NULL
) == VCHIQ_RETRY
) {
1762 DEBUG_TRACE(PARSE_LINE
);
1763 goto bail_not_ready
;
1765 VCHIQ_SERVICE_STATS_INC(service
, ctrl_rx_count
);
1766 VCHIQ_SERVICE_STATS_ADD(service
, ctrl_rx_bytes
,
1769 VCHIQ_STATS_INC(state
, error_count
);
1772 case VCHIQ_MSG_CONNECT
:
1773 vchiq_log_info(vchiq_core_log_level
,
1774 "%d: prs CONNECT@%pK", state
->id
, header
);
1775 state
->version_common
= ((VCHIQ_SLOT_ZERO_T
*)
1776 state
->slot_data
)->version
;
1777 up(&state
->connect
);
1779 case VCHIQ_MSG_BULK_RX
:
1780 case VCHIQ_MSG_BULK_TX
: {
1781 VCHIQ_BULK_QUEUE_T
*queue
;
1782 WARN_ON(!state
->is_master
);
1783 queue
= (type
== VCHIQ_MSG_BULK_RX
) ?
1784 &service
->bulk_tx
: &service
->bulk_rx
;
1785 if ((service
->remoteport
== remoteport
)
1786 && (service
->srvstate
==
1787 VCHIQ_SRVSTATE_OPEN
)) {
1791 DEBUG_TRACE(PARSE_LINE
);
1792 if (mutex_lock_killable(
1793 &service
->bulk_mutex
) != 0) {
1794 DEBUG_TRACE(PARSE_LINE
);
1795 goto bail_not_ready
;
1798 WARN_ON(!(queue
->remote_insert
< queue
->remove
+
1799 VCHIQ_NUM_SERVICE_BULKS
));
1800 bulk
= &queue
->bulks
[
1801 BULK_INDEX(queue
->remote_insert
)];
1803 (void *)(long)((int *)header
->data
)[0];
1804 bulk
->remote_size
= ((int *)header
->data
)[1];
1807 vchiq_log_info(vchiq_core_log_level
,
1808 "%d: prs %s@%pK (%d->%d) %x@%pK",
1809 state
->id
, msg_type_str(type
),
1810 header
, remoteport
, localport
,
1811 bulk
->remote_size
, bulk
->remote_data
);
1813 queue
->remote_insert
++;
1815 if (atomic_read(&pause_bulks_count
)) {
1816 state
->deferred_bulks
++;
1817 vchiq_log_info(vchiq_core_log_level
,
1818 "%s: deferring bulk (%d)",
1820 state
->deferred_bulks
);
1821 if (state
->conn_state
!=
1822 VCHIQ_CONNSTATE_PAUSE_SENT
)
1824 vchiq_core_log_level
,
1825 "%s: bulks paused in "
1826 "unexpected state %s",
1829 state
->conn_state
]);
1830 } else if (state
->conn_state
==
1831 VCHIQ_CONNSTATE_CONNECTED
) {
1832 DEBUG_TRACE(PARSE_LINE
);
1833 resolved
= resolve_bulks(service
,
1837 mutex_unlock(&service
->bulk_mutex
);
1839 notify_bulks(service
, queue
,
1843 case VCHIQ_MSG_BULK_RX_DONE
:
1844 case VCHIQ_MSG_BULK_TX_DONE
:
1845 WARN_ON(state
->is_master
);
1846 if ((service
->remoteport
== remoteport
)
1847 && (service
->srvstate
!=
1848 VCHIQ_SRVSTATE_FREE
)) {
1849 VCHIQ_BULK_QUEUE_T
*queue
;
1852 queue
= (type
== VCHIQ_MSG_BULK_RX_DONE
) ?
1853 &service
->bulk_rx
: &service
->bulk_tx
;
1855 DEBUG_TRACE(PARSE_LINE
);
1856 if (mutex_lock_killable(
1857 &service
->bulk_mutex
) != 0) {
1858 DEBUG_TRACE(PARSE_LINE
);
1859 goto bail_not_ready
;
1861 if ((int)(queue
->remote_insert
-
1862 queue
->local_insert
) >= 0) {
1863 vchiq_log_error(vchiq_core_log_level
,
1864 "%d: prs %s@%pK (%d->%d) "
1865 "unexpected (ri=%d,li=%d)",
1866 state
->id
, msg_type_str(type
),
1867 header
, remoteport
, localport
,
1868 queue
->remote_insert
,
1869 queue
->local_insert
);
1870 mutex_unlock(&service
->bulk_mutex
);
1874 BUG_ON(queue
->process
== queue
->local_insert
);
1875 BUG_ON(queue
->process
!= queue
->remote_insert
);
1877 bulk
= &queue
->bulks
[
1878 BULK_INDEX(queue
->remote_insert
)];
1879 bulk
->actual
= *(int *)header
->data
;
1880 queue
->remote_insert
++;
1882 vchiq_log_info(vchiq_core_log_level
,
1883 "%d: prs %s@%pK (%d->%d) %x@%pK",
1884 state
->id
, msg_type_str(type
),
1885 header
, remoteport
, localport
,
1886 bulk
->actual
, bulk
->data
);
1888 vchiq_log_trace(vchiq_core_log_level
,
1889 "%d: prs:%d %cx li=%x ri=%x p=%x",
1890 state
->id
, localport
,
1891 (type
== VCHIQ_MSG_BULK_RX_DONE
) ?
1893 queue
->local_insert
,
1894 queue
->remote_insert
, queue
->process
);
1896 DEBUG_TRACE(PARSE_LINE
);
1897 WARN_ON(queue
->process
== queue
->local_insert
);
1898 vchiq_complete_bulk(bulk
);
1900 mutex_unlock(&service
->bulk_mutex
);
1901 DEBUG_TRACE(PARSE_LINE
);
1902 notify_bulks(service
, queue
, 1/*retry_poll*/);
1903 DEBUG_TRACE(PARSE_LINE
);
1906 case VCHIQ_MSG_PADDING
:
1907 vchiq_log_trace(vchiq_core_log_level
,
1908 "%d: prs PADDING@%pK,%x",
1909 state
->id
, header
, size
);
1911 case VCHIQ_MSG_PAUSE
:
1912 /* If initiated, signal the application thread */
1913 vchiq_log_trace(vchiq_core_log_level
,
1914 "%d: prs PAUSE@%pK,%x",
1915 state
->id
, header
, size
);
1916 if (state
->conn_state
== VCHIQ_CONNSTATE_PAUSED
) {
1917 vchiq_log_error(vchiq_core_log_level
,
1918 "%d: PAUSE received in state PAUSED",
1922 if (state
->conn_state
!= VCHIQ_CONNSTATE_PAUSE_SENT
) {
1923 /* Send a PAUSE in response */
1924 if (queue_message(state
, NULL
,
1925 VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE
, 0, 0),
1926 NULL
, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK
)
1928 goto bail_not_ready
;
1929 if (state
->is_master
)
1932 /* At this point slot_mutex is held */
1933 vchiq_set_conn_state(state
, VCHIQ_CONNSTATE_PAUSED
);
1934 vchiq_platform_paused(state
);
1936 case VCHIQ_MSG_RESUME
:
1937 vchiq_log_trace(vchiq_core_log_level
,
1938 "%d: prs RESUME@%pK,%x",
1939 state
->id
, header
, size
);
1940 /* Release the slot mutex */
1941 mutex_unlock(&state
->slot_mutex
);
1942 if (state
->is_master
)
1943 resume_bulks(state
);
1944 vchiq_set_conn_state(state
, VCHIQ_CONNSTATE_CONNECTED
);
1945 vchiq_platform_resumed(state
);
1948 case VCHIQ_MSG_REMOTE_USE
:
1949 vchiq_on_remote_use(state
);
1951 case VCHIQ_MSG_REMOTE_RELEASE
:
1952 vchiq_on_remote_release(state
);
1954 case VCHIQ_MSG_REMOTE_USE_ACTIVE
:
1955 vchiq_on_remote_use_active(state
);
1959 vchiq_log_error(vchiq_core_log_level
,
1960 "%d: prs invalid msgid %x@%pK,%x",
1961 state
->id
, msgid
, header
, size
);
1962 WARN(1, "invalid message\n");
1968 unlock_service(service
);
1972 state
->rx_pos
+= calc_stride(size
);
1974 DEBUG_TRACE(PARSE_LINE
);
1975 /* Perform some housekeeping when the end of the slot is
1977 if ((state
->rx_pos
& VCHIQ_SLOT_MASK
) == 0) {
1978 /* Remove the extra reference count. */
1979 release_slot(state
, state
->rx_info
, NULL
, NULL
);
1980 state
->rx_data
= NULL
;
1986 unlock_service(service
);
1989 /* Called by the slot handler thread */
1991 slot_handler_func(void *v
)
1993 VCHIQ_STATE_T
*state
= (VCHIQ_STATE_T
*) v
;
1994 VCHIQ_SHARED_STATE_T
*local
= state
->local
;
1995 DEBUG_INITIALISE(local
)
1998 DEBUG_COUNT(SLOT_HANDLER_COUNT
);
1999 DEBUG_TRACE(SLOT_HANDLER_LINE
);
2000 remote_event_wait(state
, &local
->trigger
);
2004 DEBUG_TRACE(SLOT_HANDLER_LINE
);
2005 if (state
->poll_needed
) {
2006 /* Check if we need to suspend - may change our
2008 vchiq_platform_check_suspend(state
);
2010 state
->poll_needed
= 0;
2012 /* Handle service polling and other rare conditions here
2013 ** out of the mainline code */
2014 switch (state
->conn_state
) {
2015 case VCHIQ_CONNSTATE_CONNECTED
:
2016 /* Poll the services as requested */
2017 poll_services(state
);
2020 case VCHIQ_CONNSTATE_PAUSING
:
2021 if (state
->is_master
)
2023 if (queue_message(state
, NULL
,
2024 VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE
, 0, 0),
2026 QMFLAGS_NO_MUTEX_UNLOCK
)
2028 vchiq_set_conn_state(state
,
2029 VCHIQ_CONNSTATE_PAUSE_SENT
);
2031 if (state
->is_master
)
2032 resume_bulks(state
);
2034 state
->poll_needed
= 1;
2038 case VCHIQ_CONNSTATE_PAUSED
:
2039 vchiq_platform_resume(state
);
2042 case VCHIQ_CONNSTATE_RESUMING
:
2043 if (queue_message(state
, NULL
,
2044 VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME
, 0, 0),
2045 NULL
, 0, 0, QMFLAGS_NO_MUTEX_LOCK
)
2047 if (state
->is_master
)
2048 resume_bulks(state
);
2049 vchiq_set_conn_state(state
,
2050 VCHIQ_CONNSTATE_CONNECTED
);
2051 vchiq_platform_resumed(state
);
2053 /* This should really be impossible,
2054 ** since the PAUSE should have flushed
2055 ** through outstanding messages. */
2056 vchiq_log_error(vchiq_core_log_level
,
2057 "Failed to send RESUME "
2063 case VCHIQ_CONNSTATE_PAUSE_TIMEOUT
:
2064 case VCHIQ_CONNSTATE_RESUME_TIMEOUT
:
2065 vchiq_platform_handle_timeout(state
);
2074 DEBUG_TRACE(SLOT_HANDLER_LINE
);
2075 parse_rx_slots(state
);
2081 /* Called by the recycle thread */
2083 recycle_func(void *v
)
2085 VCHIQ_STATE_T
*state
= (VCHIQ_STATE_T
*) v
;
2086 VCHIQ_SHARED_STATE_T
*local
= state
->local
;
2089 remote_event_wait(state
, &local
->recycle
);
2091 process_free_queue(state
);
2097 /* Called by the sync thread */
2101 VCHIQ_STATE_T
*state
= (VCHIQ_STATE_T
*) v
;
2102 VCHIQ_SHARED_STATE_T
*local
= state
->local
;
2103 VCHIQ_HEADER_T
*header
= (VCHIQ_HEADER_T
*)SLOT_DATA_FROM_INDEX(state
,
2104 state
->remote
->slot_sync
);
2107 VCHIQ_SERVICE_T
*service
;
2110 unsigned int localport
, remoteport
;
2112 remote_event_wait(state
, &local
->sync_trigger
);
2116 msgid
= header
->msgid
;
2117 size
= header
->size
;
2118 type
= VCHIQ_MSG_TYPE(msgid
);
2119 localport
= VCHIQ_MSG_DSTPORT(msgid
);
2120 remoteport
= VCHIQ_MSG_SRCPORT(msgid
);
2122 service
= find_service_by_port(state
, localport
);
2125 vchiq_log_error(vchiq_sync_log_level
,
2126 "%d: sf %s@%pK (%d->%d) - invalid/closed service %d",
2127 state
->id
, msg_type_str(type
),
2128 header
, remoteport
, localport
, localport
);
2129 release_message_sync(state
, header
);
2133 if (vchiq_sync_log_level
>= VCHIQ_LOG_TRACE
) {
2136 svc_fourcc
= service
2137 ? service
->base
.fourcc
2138 : VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
2139 vchiq_log_trace(vchiq_sync_log_level
,
2140 "Rcvd Msg %s from %c%c%c%c s:%d d:%d len:%d",
2142 VCHIQ_FOURCC_AS_4CHARS(svc_fourcc
),
2143 remoteport
, localport
, size
);
2145 vchiq_log_dump_mem("Rcvd", 0, header
->data
,
2150 case VCHIQ_MSG_OPENACK
:
2151 if (size
>= sizeof(struct vchiq_openack_payload
)) {
2152 const struct vchiq_openack_payload
*payload
=
2153 (struct vchiq_openack_payload
*)
2155 service
->peer_version
= payload
->version
;
2157 vchiq_log_info(vchiq_sync_log_level
,
2158 "%d: sf OPENACK@%pK,%x (%d->%d) v:%d",
2159 state
->id
, header
, size
, remoteport
, localport
,
2160 service
->peer_version
);
2161 if (service
->srvstate
== VCHIQ_SRVSTATE_OPENING
) {
2162 service
->remoteport
= remoteport
;
2163 vchiq_set_service_state(service
,
2164 VCHIQ_SRVSTATE_OPENSYNC
);
2166 up(&service
->remove_event
);
2168 release_message_sync(state
, header
);
2171 case VCHIQ_MSG_DATA
:
2172 vchiq_log_trace(vchiq_sync_log_level
,
2173 "%d: sf DATA@%pK,%x (%d->%d)",
2174 state
->id
, header
, size
, remoteport
, localport
);
2176 if ((service
->remoteport
== remoteport
) &&
2177 (service
->srvstate
==
2178 VCHIQ_SRVSTATE_OPENSYNC
)) {
2179 if (make_service_callback(service
,
2180 VCHIQ_MESSAGE_AVAILABLE
, header
,
2181 NULL
) == VCHIQ_RETRY
)
2182 vchiq_log_error(vchiq_sync_log_level
,
2183 "synchronous callback to "
2184 "service %d returns "
2191 vchiq_log_error(vchiq_sync_log_level
,
2192 "%d: sf unexpected msgid %x@%pK,%x",
2193 state
->id
, msgid
, header
, size
);
2194 release_message_sync(state
, header
);
2198 unlock_service(service
);
2206 init_bulk_queue(VCHIQ_BULK_QUEUE_T
*queue
)
2208 queue
->local_insert
= 0;
2209 queue
->remote_insert
= 0;
2211 queue
->remote_notify
= 0;
2217 get_conn_state_name(VCHIQ_CONNSTATE_T conn_state
)
2219 return conn_state_names
[conn_state
];
2224 vchiq_init_slots(void *mem_base
, int mem_size
)
2227 (int)((VCHIQ_SLOT_SIZE
- (long)mem_base
) & VCHIQ_SLOT_MASK
);
2228 VCHIQ_SLOT_ZERO_T
*slot_zero
=
2229 (VCHIQ_SLOT_ZERO_T
*)((char *)mem_base
+ mem_align
);
2230 int num_slots
= (mem_size
- mem_align
)/VCHIQ_SLOT_SIZE
;
2231 int first_data_slot
= VCHIQ_SLOT_ZERO_SLOTS
;
2233 /* Ensure there is enough memory to run an absolutely minimum system */
2234 num_slots
-= first_data_slot
;
2236 if (num_slots
< 4) {
2237 vchiq_log_error(vchiq_core_log_level
,
2238 "vchiq_init_slots - insufficient memory %x bytes",
2243 memset(slot_zero
, 0, sizeof(VCHIQ_SLOT_ZERO_T
));
2245 slot_zero
->magic
= VCHIQ_MAGIC
;
2246 slot_zero
->version
= VCHIQ_VERSION
;
2247 slot_zero
->version_min
= VCHIQ_VERSION_MIN
;
2248 slot_zero
->slot_zero_size
= sizeof(VCHIQ_SLOT_ZERO_T
);
2249 slot_zero
->slot_size
= VCHIQ_SLOT_SIZE
;
2250 slot_zero
->max_slots
= VCHIQ_MAX_SLOTS
;
2251 slot_zero
->max_slots_per_side
= VCHIQ_MAX_SLOTS_PER_SIDE
;
2253 slot_zero
->master
.slot_sync
= first_data_slot
;
2254 slot_zero
->master
.slot_first
= first_data_slot
+ 1;
2255 slot_zero
->master
.slot_last
= first_data_slot
+ (num_slots
/2) - 1;
2256 slot_zero
->slave
.slot_sync
= first_data_slot
+ (num_slots
/2);
2257 slot_zero
->slave
.slot_first
= first_data_slot
+ (num_slots
/2) + 1;
2258 slot_zero
->slave
.slot_last
= first_data_slot
+ num_slots
- 1;
2264 vchiq_init_state(VCHIQ_STATE_T
*state
, VCHIQ_SLOT_ZERO_T
*slot_zero
,
2267 VCHIQ_SHARED_STATE_T
*local
;
2268 VCHIQ_SHARED_STATE_T
*remote
;
2269 VCHIQ_STATUS_T status
;
2270 char threadname
[10];
2274 vchiq_log_warning(vchiq_core_log_level
,
2275 "%s: slot_zero = %pK, is_master = %d",
2276 __func__
, slot_zero
, is_master
);
2278 /* Check the input configuration */
2280 if (slot_zero
->magic
!= VCHIQ_MAGIC
) {
2281 vchiq_loud_error_header();
2282 vchiq_loud_error("Invalid VCHIQ magic value found.");
2283 vchiq_loud_error("slot_zero=%pK: magic=%x (expected %x)",
2284 slot_zero
, slot_zero
->magic
, VCHIQ_MAGIC
);
2285 vchiq_loud_error_footer();
2289 if (slot_zero
->version
< VCHIQ_VERSION_MIN
) {
2290 vchiq_loud_error_header();
2291 vchiq_loud_error("Incompatible VCHIQ versions found.");
2292 vchiq_loud_error("slot_zero=%pK: VideoCore version=%d (minimum %d)",
2293 slot_zero
, slot_zero
->version
, VCHIQ_VERSION_MIN
);
2294 vchiq_loud_error("Restart with a newer VideoCore image.");
2295 vchiq_loud_error_footer();
2299 if (VCHIQ_VERSION
< slot_zero
->version_min
) {
2300 vchiq_loud_error_header();
2301 vchiq_loud_error("Incompatible VCHIQ versions found.");
2302 vchiq_loud_error("slot_zero=%pK: version=%d (VideoCore minimum %d)",
2303 slot_zero
, VCHIQ_VERSION
, slot_zero
->version_min
);
2304 vchiq_loud_error("Restart with a newer kernel.");
2305 vchiq_loud_error_footer();
2309 if ((slot_zero
->slot_zero_size
!= sizeof(VCHIQ_SLOT_ZERO_T
)) ||
2310 (slot_zero
->slot_size
!= VCHIQ_SLOT_SIZE
) ||
2311 (slot_zero
->max_slots
!= VCHIQ_MAX_SLOTS
) ||
2312 (slot_zero
->max_slots_per_side
!= VCHIQ_MAX_SLOTS_PER_SIDE
)) {
2313 vchiq_loud_error_header();
2314 if (slot_zero
->slot_zero_size
!= sizeof(VCHIQ_SLOT_ZERO_T
))
2315 vchiq_loud_error("slot_zero=%pK: slot_zero_size=%d (expected %d)",
2316 slot_zero
, slot_zero
->slot_zero_size
,
2317 (int)sizeof(VCHIQ_SLOT_ZERO_T
));
2318 if (slot_zero
->slot_size
!= VCHIQ_SLOT_SIZE
)
2319 vchiq_loud_error("slot_zero=%pK: slot_size=%d (expected %d)",
2320 slot_zero
, slot_zero
->slot_size
,
2322 if (slot_zero
->max_slots
!= VCHIQ_MAX_SLOTS
)
2323 vchiq_loud_error("slot_zero=%pK: max_slots=%d (expected %d)",
2324 slot_zero
, slot_zero
->max_slots
,
2326 if (slot_zero
->max_slots_per_side
!= VCHIQ_MAX_SLOTS_PER_SIDE
)
2327 vchiq_loud_error("slot_zero=%pK: max_slots_per_side=%d (expected %d)",
2328 slot_zero
, slot_zero
->max_slots_per_side
,
2329 VCHIQ_MAX_SLOTS_PER_SIDE
);
2330 vchiq_loud_error_footer();
2334 if (VCHIQ_VERSION
< slot_zero
->version
)
2335 slot_zero
->version
= VCHIQ_VERSION
;
2338 local
= &slot_zero
->master
;
2339 remote
= &slot_zero
->slave
;
2341 local
= &slot_zero
->slave
;
2342 remote
= &slot_zero
->master
;
2345 if (local
->initialised
) {
2346 vchiq_loud_error_header();
2347 if (remote
->initialised
)
2348 vchiq_loud_error("local state has already been "
2351 vchiq_loud_error("master/slave mismatch - two %ss",
2352 is_master
? "master" : "slave");
2353 vchiq_loud_error_footer();
2357 memset(state
, 0, sizeof(VCHIQ_STATE_T
));
2360 state
->is_master
= is_master
;
2363 initialize shared state pointers
2366 state
->local
= local
;
2367 state
->remote
= remote
;
2368 state
->slot_data
= (VCHIQ_SLOT_T
*)slot_zero
;
2371 initialize events and mutexes
2374 sema_init(&state
->connect
, 0);
2375 mutex_init(&state
->mutex
);
2376 sema_init(&state
->trigger_event
, 0);
2377 sema_init(&state
->recycle_event
, 0);
2378 sema_init(&state
->sync_trigger_event
, 0);
2379 sema_init(&state
->sync_release_event
, 0);
2381 mutex_init(&state
->slot_mutex
);
2382 mutex_init(&state
->recycle_mutex
);
2383 mutex_init(&state
->sync_mutex
);
2384 mutex_init(&state
->bulk_transfer_mutex
);
2386 sema_init(&state
->slot_available_event
, 0);
2387 sema_init(&state
->slot_remove_event
, 0);
2388 sema_init(&state
->data_quota_event
, 0);
2390 state
->slot_queue_available
= 0;
2392 for (i
= 0; i
< VCHIQ_MAX_SERVICES
; i
++) {
2393 VCHIQ_SERVICE_QUOTA_T
*service_quota
=
2394 &state
->service_quotas
[i
];
2395 sema_init(&service_quota
->quota_event
, 0);
2398 for (i
= local
->slot_first
; i
<= local
->slot_last
; i
++) {
2399 local
->slot_queue
[state
->slot_queue_available
++] = i
;
2400 up(&state
->slot_available_event
);
2403 state
->default_slot_quota
= state
->slot_queue_available
/2;
2404 state
->default_message_quota
=
2405 min((unsigned short)(state
->default_slot_quota
* 256),
2406 (unsigned short)~0);
2408 state
->previous_data_index
= -1;
2409 state
->data_use_count
= 0;
2410 state
->data_quota
= state
->slot_queue_available
- 1;
2412 local
->trigger
.event
= offsetof(VCHIQ_STATE_T
, trigger_event
);
2413 remote_event_create(state
, &local
->trigger
);
2416 local
->recycle
.event
= offsetof(VCHIQ_STATE_T
, recycle_event
);
2417 remote_event_create(state
, &local
->recycle
);
2418 local
->slot_queue_recycle
= state
->slot_queue_available
;
2420 local
->sync_trigger
.event
= offsetof(VCHIQ_STATE_T
, sync_trigger_event
);
2421 remote_event_create(state
, &local
->sync_trigger
);
2423 local
->sync_release
.event
= offsetof(VCHIQ_STATE_T
, sync_release_event
);
2424 remote_event_create(state
, &local
->sync_release
);
2426 /* At start-of-day, the slot is empty and available */
2427 ((VCHIQ_HEADER_T
*)SLOT_DATA_FROM_INDEX(state
, local
->slot_sync
))->msgid
2428 = VCHIQ_MSGID_PADDING
;
2429 remote_event_signal_local(state
, &local
->sync_release
);
2431 local
->debug
[DEBUG_ENTRIES
] = DEBUG_MAX
;
2433 status
= vchiq_platform_init_state(state
);
2436 bring up slot handler thread
2438 snprintf(threadname
, sizeof(threadname
), "VCHIQ-%d", state
->id
);
2439 state
->slot_handler_thread
= kthread_create(&slot_handler_func
,
2443 if (IS_ERR(state
->slot_handler_thread
)) {
2444 vchiq_loud_error_header();
2445 vchiq_loud_error("couldn't create thread %s", threadname
);
2446 vchiq_loud_error_footer();
2449 set_user_nice(state
->slot_handler_thread
, -19);
2450 wake_up_process(state
->slot_handler_thread
);
2452 snprintf(threadname
, sizeof(threadname
), "VCHIQr-%d", state
->id
);
2453 state
->recycle_thread
= kthread_create(&recycle_func
,
2456 if (IS_ERR(state
->recycle_thread
)) {
2457 vchiq_loud_error_header();
2458 vchiq_loud_error("couldn't create thread %s", threadname
);
2459 vchiq_loud_error_footer();
2462 set_user_nice(state
->recycle_thread
, -19);
2463 wake_up_process(state
->recycle_thread
);
2465 snprintf(threadname
, sizeof(threadname
), "VCHIQs-%d", state
->id
);
2466 state
->sync_thread
= kthread_create(&sync_func
,
2469 if (IS_ERR(state
->sync_thread
)) {
2470 vchiq_loud_error_header();
2471 vchiq_loud_error("couldn't create thread %s", threadname
);
2472 vchiq_loud_error_footer();
2475 set_user_nice(state
->sync_thread
, -20);
2476 wake_up_process(state
->sync_thread
);
2478 BUG_ON(state
->id
>= VCHIQ_MAX_STATES
);
2479 vchiq_states
[state
->id
] = state
;
2481 /* Indicate readiness to the other side */
2482 local
->initialised
= 1;
2487 /* Called from application thread when a client or server service is created. */
2489 vchiq_add_service_internal(VCHIQ_STATE_T
*state
,
2490 const VCHIQ_SERVICE_PARAMS_T
*params
, int srvstate
,
2491 VCHIQ_INSTANCE_T instance
, VCHIQ_USERDATA_TERM_T userdata_term
)
2493 VCHIQ_SERVICE_T
*service
;
2495 service
= kmalloc(sizeof(VCHIQ_SERVICE_T
), GFP_KERNEL
);
2497 service
->base
.fourcc
= params
->fourcc
;
2498 service
->base
.callback
= params
->callback
;
2499 service
->base
.userdata
= params
->userdata
;
2500 service
->handle
= VCHIQ_SERVICE_HANDLE_INVALID
;
2501 service
->ref_count
= 1;
2502 service
->srvstate
= VCHIQ_SRVSTATE_FREE
;
2503 service
->userdata_term
= userdata_term
;
2504 service
->localport
= VCHIQ_PORT_FREE
;
2505 service
->remoteport
= VCHIQ_PORT_FREE
;
2507 service
->public_fourcc
= (srvstate
== VCHIQ_SRVSTATE_OPENING
) ?
2508 VCHIQ_FOURCC_INVALID
: params
->fourcc
;
2509 service
->client_id
= 0;
2510 service
->auto_close
= 1;
2512 service
->closing
= 0;
2514 atomic_set(&service
->poll_flags
, 0);
2515 service
->version
= params
->version
;
2516 service
->version_min
= params
->version_min
;
2517 service
->state
= state
;
2518 service
->instance
= instance
;
2519 service
->service_use_count
= 0;
2520 init_bulk_queue(&service
->bulk_tx
);
2521 init_bulk_queue(&service
->bulk_rx
);
2522 sema_init(&service
->remove_event
, 0);
2523 sema_init(&service
->bulk_remove_event
, 0);
2524 mutex_init(&service
->bulk_mutex
);
2525 memset(&service
->stats
, 0, sizeof(service
->stats
));
2527 vchiq_log_error(vchiq_core_log_level
,
2532 VCHIQ_SERVICE_T
**pservice
= NULL
;
2535 /* Although it is perfectly possible to use service_spinlock
2536 ** to protect the creation of services, it is overkill as it
2537 ** disables interrupts while the array is searched.
2538 ** The only danger is of another thread trying to create a
2539 ** service - service deletion is safe.
2540 ** Therefore it is preferable to use state->mutex which,
2541 ** although slower to claim, doesn't block interrupts while
2545 mutex_lock(&state
->mutex
);
2547 /* Prepare to use a previously unused service */
2548 if (state
->unused_service
< VCHIQ_MAX_SERVICES
)
2549 pservice
= &state
->services
[state
->unused_service
];
2551 if (srvstate
== VCHIQ_SRVSTATE_OPENING
) {
2552 for (i
= 0; i
< state
->unused_service
; i
++) {
2553 VCHIQ_SERVICE_T
*srv
= state
->services
[i
];
2555 pservice
= &state
->services
[i
];
2560 for (i
= (state
->unused_service
- 1); i
>= 0; i
--) {
2561 VCHIQ_SERVICE_T
*srv
= state
->services
[i
];
2563 pservice
= &state
->services
[i
];
2564 else if ((srv
->public_fourcc
== params
->fourcc
)
2565 && ((srv
->instance
!= instance
) ||
2566 (srv
->base
.callback
!=
2567 params
->callback
))) {
2568 /* There is another server using this
2569 ** fourcc which doesn't match. */
2577 service
->localport
= (pservice
- state
->services
);
2579 handle_seq
= VCHIQ_MAX_STATES
*
2581 service
->handle
= handle_seq
|
2582 (state
->id
* VCHIQ_MAX_SERVICES
) |
2584 handle_seq
+= VCHIQ_MAX_STATES
* VCHIQ_MAX_SERVICES
;
2585 *pservice
= service
;
2586 if (pservice
== &state
->services
[state
->unused_service
])
2587 state
->unused_service
++;
2590 mutex_unlock(&state
->mutex
);
2599 VCHIQ_SERVICE_QUOTA_T
*service_quota
=
2600 &state
->service_quotas
[service
->localport
];
2601 service_quota
->slot_quota
= state
->default_slot_quota
;
2602 service_quota
->message_quota
= state
->default_message_quota
;
2603 if (service_quota
->slot_use_count
== 0)
2604 service_quota
->previous_tx_index
=
2605 SLOT_QUEUE_INDEX_FROM_POS(state
->local_tx_pos
)
2608 /* Bring this service online */
2609 vchiq_set_service_state(service
, srvstate
);
2611 vchiq_log_info(vchiq_core_msg_log_level
,
2612 "%s Service %c%c%c%c SrcPort:%d",
2613 (srvstate
== VCHIQ_SRVSTATE_OPENING
)
2615 VCHIQ_FOURCC_AS_4CHARS(params
->fourcc
),
2616 service
->localport
);
2619 /* Don't unlock the service - leave it with a ref_count of 1. */
2625 vchiq_open_service_internal(VCHIQ_SERVICE_T
*service
, int client_id
)
2627 struct vchiq_open_payload payload
= {
2628 service
->base
.fourcc
,
2631 service
->version_min
2633 VCHIQ_ELEMENT_T body
= { &payload
, sizeof(payload
) };
2634 VCHIQ_STATUS_T status
= VCHIQ_SUCCESS
;
2636 service
->client_id
= client_id
;
2637 vchiq_use_service_internal(service
);
2638 status
= queue_message(service
->state
, NULL
,
2639 VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN
, service
->localport
, 0),
2640 &body
, 1, sizeof(payload
), QMFLAGS_IS_BLOCKING
);
2641 if (status
== VCHIQ_SUCCESS
) {
2642 /* Wait for the ACK/NAK */
2643 if (down_interruptible(&service
->remove_event
) != 0) {
2644 status
= VCHIQ_RETRY
;
2645 vchiq_release_service_internal(service
);
2646 } else if ((service
->srvstate
!= VCHIQ_SRVSTATE_OPEN
) &&
2647 (service
->srvstate
!= VCHIQ_SRVSTATE_OPENSYNC
)) {
2648 if (service
->srvstate
!= VCHIQ_SRVSTATE_CLOSEWAIT
)
2649 vchiq_log_error(vchiq_core_log_level
,
2650 "%d: osi - srvstate = %s (ref %d)",
2652 srvstate_names
[service
->srvstate
],
2653 service
->ref_count
);
2654 status
= VCHIQ_ERROR
;
2655 VCHIQ_SERVICE_STATS_INC(service
, error_count
);
2656 vchiq_release_service_internal(service
);
2663 release_service_messages(VCHIQ_SERVICE_T
*service
)
2665 VCHIQ_STATE_T
*state
= service
->state
;
2666 int slot_last
= state
->remote
->slot_last
;
2669 /* Release any claimed messages aimed at this service */
2671 if (service
->sync
) {
2672 VCHIQ_HEADER_T
*header
=
2673 (VCHIQ_HEADER_T
*)SLOT_DATA_FROM_INDEX(state
,
2674 state
->remote
->slot_sync
);
2675 if (VCHIQ_MSG_DSTPORT(header
->msgid
) == service
->localport
)
2676 release_message_sync(state
, header
);
2681 for (i
= state
->remote
->slot_first
; i
<= slot_last
; i
++) {
2682 VCHIQ_SLOT_INFO_T
*slot_info
=
2683 SLOT_INFO_FROM_INDEX(state
, i
);
2684 if (slot_info
->release_count
!= slot_info
->use_count
) {
2686 (char *)SLOT_DATA_FROM_INDEX(state
, i
);
2687 unsigned int pos
, end
;
2689 end
= VCHIQ_SLOT_SIZE
;
2690 if (data
== state
->rx_data
)
2691 /* This buffer is still being read from - stop
2692 ** at the current read position */
2693 end
= state
->rx_pos
& VCHIQ_SLOT_MASK
;
2698 VCHIQ_HEADER_T
*header
=
2699 (VCHIQ_HEADER_T
*)(data
+ pos
);
2700 int msgid
= header
->msgid
;
2701 int port
= VCHIQ_MSG_DSTPORT(msgid
);
2702 if ((port
== service
->localport
) &&
2703 (msgid
& VCHIQ_MSGID_CLAIMED
)) {
2704 vchiq_log_info(vchiq_core_log_level
,
2705 " fsi - hdr %pK", header
);
2706 release_slot(state
, slot_info
, header
,
2709 pos
+= calc_stride(header
->size
);
2710 if (pos
> VCHIQ_SLOT_SIZE
) {
2711 vchiq_log_error(vchiq_core_log_level
,
2712 "fsi - pos %x: header %pK, msgid %x, header->msgid %x, header->size %x",
2714 header
->msgid
, header
->size
);
2715 WARN(1, "invalid slot position\n");
2723 do_abort_bulks(VCHIQ_SERVICE_T
*service
)
2725 VCHIQ_STATUS_T status
;
2727 /* Abort any outstanding bulk transfers */
2728 if (mutex_lock_killable(&service
->bulk_mutex
) != 0)
2730 abort_outstanding_bulks(service
, &service
->bulk_tx
);
2731 abort_outstanding_bulks(service
, &service
->bulk_rx
);
2732 mutex_unlock(&service
->bulk_mutex
);
2734 status
= notify_bulks(service
, &service
->bulk_tx
, 0/*!retry_poll*/);
2735 if (status
== VCHIQ_SUCCESS
)
2736 status
= notify_bulks(service
, &service
->bulk_rx
,
2738 return (status
== VCHIQ_SUCCESS
);
2741 static VCHIQ_STATUS_T
2742 close_service_complete(VCHIQ_SERVICE_T
*service
, int failstate
)
2744 VCHIQ_STATUS_T status
;
2745 int is_server
= (service
->public_fourcc
!= VCHIQ_FOURCC_INVALID
);
2748 switch (service
->srvstate
) {
2749 case VCHIQ_SRVSTATE_OPEN
:
2750 case VCHIQ_SRVSTATE_CLOSESENT
:
2751 case VCHIQ_SRVSTATE_CLOSERECVD
:
2753 if (service
->auto_close
) {
2754 service
->client_id
= 0;
2755 service
->remoteport
= VCHIQ_PORT_FREE
;
2756 newstate
= VCHIQ_SRVSTATE_LISTENING
;
2758 newstate
= VCHIQ_SRVSTATE_CLOSEWAIT
;
2760 newstate
= VCHIQ_SRVSTATE_CLOSED
;
2761 vchiq_set_service_state(service
, newstate
);
2763 case VCHIQ_SRVSTATE_LISTENING
:
2766 vchiq_log_error(vchiq_core_log_level
,
2767 "close_service_complete(%x) called in state %s",
2768 service
->handle
, srvstate_names
[service
->srvstate
]);
2769 WARN(1, "close_service_complete in unexpected state\n");
2773 status
= make_service_callback(service
,
2774 VCHIQ_SERVICE_CLOSED
, NULL
, NULL
);
2776 if (status
!= VCHIQ_RETRY
) {
2777 int uc
= service
->service_use_count
;
2779 /* Complete the close process */
2780 for (i
= 0; i
< uc
; i
++)
2781 /* cater for cases where close is forced and the
2782 ** client may not close all it's handles */
2783 vchiq_release_service_internal(service
);
2785 service
->client_id
= 0;
2786 service
->remoteport
= VCHIQ_PORT_FREE
;
2788 if (service
->srvstate
== VCHIQ_SRVSTATE_CLOSED
)
2789 vchiq_free_service_internal(service
);
2790 else if (service
->srvstate
!= VCHIQ_SRVSTATE_CLOSEWAIT
) {
2792 service
->closing
= 0;
2794 up(&service
->remove_event
);
2797 vchiq_set_service_state(service
, failstate
);
2802 /* Called by the slot handler */
2804 vchiq_close_service_internal(VCHIQ_SERVICE_T
*service
, int close_recvd
)
2806 VCHIQ_STATE_T
*state
= service
->state
;
2807 VCHIQ_STATUS_T status
= VCHIQ_SUCCESS
;
2808 int is_server
= (service
->public_fourcc
!= VCHIQ_FOURCC_INVALID
);
2810 vchiq_log_info(vchiq_core_log_level
, "%d: csi:%d,%d (%s)",
2811 service
->state
->id
, service
->localport
, close_recvd
,
2812 srvstate_names
[service
->srvstate
]);
2814 switch (service
->srvstate
) {
2815 case VCHIQ_SRVSTATE_CLOSED
:
2816 case VCHIQ_SRVSTATE_HIDDEN
:
2817 case VCHIQ_SRVSTATE_LISTENING
:
2818 case VCHIQ_SRVSTATE_CLOSEWAIT
:
2820 vchiq_log_error(vchiq_core_log_level
,
2821 "vchiq_close_service_internal(1) called "
2823 srvstate_names
[service
->srvstate
]);
2824 else if (is_server
) {
2825 if (service
->srvstate
== VCHIQ_SRVSTATE_LISTENING
) {
2826 status
= VCHIQ_ERROR
;
2828 service
->client_id
= 0;
2829 service
->remoteport
= VCHIQ_PORT_FREE
;
2830 if (service
->srvstate
==
2831 VCHIQ_SRVSTATE_CLOSEWAIT
)
2832 vchiq_set_service_state(service
,
2833 VCHIQ_SRVSTATE_LISTENING
);
2835 up(&service
->remove_event
);
2837 vchiq_free_service_internal(service
);
2839 case VCHIQ_SRVSTATE_OPENING
:
2841 /* The open was rejected - tell the user */
2842 vchiq_set_service_state(service
,
2843 VCHIQ_SRVSTATE_CLOSEWAIT
);
2844 up(&service
->remove_event
);
2846 /* Shutdown mid-open - let the other side know */
2847 status
= queue_message(state
, service
,
2851 VCHIQ_MSG_DSTPORT(service
->remoteport
)),
2856 case VCHIQ_SRVSTATE_OPENSYNC
:
2857 mutex_lock(&state
->sync_mutex
);
2860 case VCHIQ_SRVSTATE_OPEN
:
2861 if (state
->is_master
|| close_recvd
) {
2862 if (!do_abort_bulks(service
))
2863 status
= VCHIQ_RETRY
;
2866 release_service_messages(service
);
2868 if (status
== VCHIQ_SUCCESS
)
2869 status
= queue_message(state
, service
,
2873 VCHIQ_MSG_DSTPORT(service
->remoteport
)),
2874 NULL
, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK
);
2876 if (status
== VCHIQ_SUCCESS
) {
2878 /* Change the state while the mutex is
2880 vchiq_set_service_state(service
,
2881 VCHIQ_SRVSTATE_CLOSESENT
);
2882 mutex_unlock(&state
->slot_mutex
);
2884 mutex_unlock(&state
->sync_mutex
);
2887 } else if (service
->srvstate
== VCHIQ_SRVSTATE_OPENSYNC
) {
2888 mutex_unlock(&state
->sync_mutex
);
2893 /* Change the state while the mutex is still held */
2894 vchiq_set_service_state(service
, VCHIQ_SRVSTATE_CLOSERECVD
);
2895 mutex_unlock(&state
->slot_mutex
);
2897 mutex_unlock(&state
->sync_mutex
);
2899 status
= close_service_complete(service
,
2900 VCHIQ_SRVSTATE_CLOSERECVD
);
2903 case VCHIQ_SRVSTATE_CLOSESENT
:
2905 /* This happens when a process is killed mid-close */
2908 if (!state
->is_master
) {
2909 if (!do_abort_bulks(service
)) {
2910 status
= VCHIQ_RETRY
;
2915 if (status
== VCHIQ_SUCCESS
)
2916 status
= close_service_complete(service
,
2917 VCHIQ_SRVSTATE_CLOSERECVD
);
2920 case VCHIQ_SRVSTATE_CLOSERECVD
:
2921 if (!close_recvd
&& is_server
)
2922 /* Force into LISTENING mode */
2923 vchiq_set_service_state(service
,
2924 VCHIQ_SRVSTATE_LISTENING
);
2925 status
= close_service_complete(service
,
2926 VCHIQ_SRVSTATE_CLOSERECVD
);
2930 vchiq_log_error(vchiq_core_log_level
,
2931 "vchiq_close_service_internal(%d) called in state %s",
2932 close_recvd
, srvstate_names
[service
->srvstate
]);
2939 /* Called from the application process upon process death */
2941 vchiq_terminate_service_internal(VCHIQ_SERVICE_T
*service
)
2943 VCHIQ_STATE_T
*state
= service
->state
;
2945 vchiq_log_info(vchiq_core_log_level
, "%d: tsi - (%d<->%d)",
2946 state
->id
, service
->localport
, service
->remoteport
);
2948 mark_service_closing(service
);
2950 /* Mark the service for removal by the slot handler */
2951 request_poll(state
, service
, VCHIQ_POLL_REMOVE
);
2954 /* Called from the slot handler */
2956 vchiq_free_service_internal(VCHIQ_SERVICE_T
*service
)
2958 VCHIQ_STATE_T
*state
= service
->state
;
2960 vchiq_log_info(vchiq_core_log_level
, "%d: fsi - (%d)",
2961 state
->id
, service
->localport
);
2963 switch (service
->srvstate
) {
2964 case VCHIQ_SRVSTATE_OPENING
:
2965 case VCHIQ_SRVSTATE_CLOSED
:
2966 case VCHIQ_SRVSTATE_HIDDEN
:
2967 case VCHIQ_SRVSTATE_LISTENING
:
2968 case VCHIQ_SRVSTATE_CLOSEWAIT
:
2971 vchiq_log_error(vchiq_core_log_level
,
2972 "%d: fsi - (%d) in state %s",
2973 state
->id
, service
->localport
,
2974 srvstate_names
[service
->srvstate
]);
2978 vchiq_set_service_state(service
, VCHIQ_SRVSTATE_FREE
);
2980 up(&service
->remove_event
);
2982 /* Release the initial lock */
2983 unlock_service(service
);
2987 vchiq_connect_internal(VCHIQ_STATE_T
*state
, VCHIQ_INSTANCE_T instance
)
2989 VCHIQ_SERVICE_T
*service
;
2992 /* Find all services registered to this client and enable them. */
2994 while ((service
= next_service_by_instance(state
, instance
,
2996 if (service
->srvstate
== VCHIQ_SRVSTATE_HIDDEN
)
2997 vchiq_set_service_state(service
,
2998 VCHIQ_SRVSTATE_LISTENING
);
2999 unlock_service(service
);
3002 if (state
->conn_state
== VCHIQ_CONNSTATE_DISCONNECTED
) {
3003 if (queue_message(state
, NULL
,
3004 VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT
, 0, 0), NULL
, 0,
3005 0, QMFLAGS_IS_BLOCKING
) == VCHIQ_RETRY
)
3008 vchiq_set_conn_state(state
, VCHIQ_CONNSTATE_CONNECTING
);
3011 if (state
->conn_state
== VCHIQ_CONNSTATE_CONNECTING
) {
3012 if (down_interruptible(&state
->connect
) != 0)
3015 vchiq_set_conn_state(state
, VCHIQ_CONNSTATE_CONNECTED
);
3016 up(&state
->connect
);
3019 return VCHIQ_SUCCESS
;
3023 vchiq_shutdown_internal(VCHIQ_STATE_T
*state
, VCHIQ_INSTANCE_T instance
)
3025 VCHIQ_SERVICE_T
*service
;
3028 /* Find all services registered to this client and enable them. */
3030 while ((service
= next_service_by_instance(state
, instance
,
3032 (void)vchiq_remove_service(service
->handle
);
3033 unlock_service(service
);
3036 return VCHIQ_SUCCESS
;
3040 vchiq_pause_internal(VCHIQ_STATE_T
*state
)
3042 VCHIQ_STATUS_T status
= VCHIQ_SUCCESS
;
3044 switch (state
->conn_state
) {
3045 case VCHIQ_CONNSTATE_CONNECTED
:
3046 /* Request a pause */
3047 vchiq_set_conn_state(state
, VCHIQ_CONNSTATE_PAUSING
);
3048 request_poll(state
, NULL
, 0);
3051 vchiq_log_error(vchiq_core_log_level
,
3052 "vchiq_pause_internal in state %s\n",
3053 conn_state_names
[state
->conn_state
]);
3054 status
= VCHIQ_ERROR
;
3055 VCHIQ_STATS_INC(state
, error_count
);
3063 vchiq_resume_internal(VCHIQ_STATE_T
*state
)
3065 VCHIQ_STATUS_T status
= VCHIQ_SUCCESS
;
3067 if (state
->conn_state
== VCHIQ_CONNSTATE_PAUSED
) {
3068 vchiq_set_conn_state(state
, VCHIQ_CONNSTATE_RESUMING
);
3069 request_poll(state
, NULL
, 0);
3071 status
= VCHIQ_ERROR
;
3072 VCHIQ_STATS_INC(state
, error_count
);
3079 vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle
)
3081 /* Unregister the service */
3082 VCHIQ_SERVICE_T
*service
= find_service_by_handle(handle
);
3083 VCHIQ_STATUS_T status
= VCHIQ_SUCCESS
;
3088 vchiq_log_info(vchiq_core_log_level
,
3089 "%d: close_service:%d",
3090 service
->state
->id
, service
->localport
);
3092 if ((service
->srvstate
== VCHIQ_SRVSTATE_FREE
) ||
3093 (service
->srvstate
== VCHIQ_SRVSTATE_LISTENING
) ||
3094 (service
->srvstate
== VCHIQ_SRVSTATE_HIDDEN
)) {
3095 unlock_service(service
);
3099 mark_service_closing(service
);
3101 if (current
== service
->state
->slot_handler_thread
) {
3102 status
= vchiq_close_service_internal(service
,
3104 BUG_ON(status
== VCHIQ_RETRY
);
3106 /* Mark the service for termination by the slot handler */
3107 request_poll(service
->state
, service
, VCHIQ_POLL_TERMINATE
);
3111 if (down_interruptible(&service
->remove_event
) != 0) {
3112 status
= VCHIQ_RETRY
;
3116 if ((service
->srvstate
== VCHIQ_SRVSTATE_FREE
) ||
3117 (service
->srvstate
== VCHIQ_SRVSTATE_LISTENING
) ||
3118 (service
->srvstate
== VCHIQ_SRVSTATE_OPEN
))
3121 vchiq_log_warning(vchiq_core_log_level
,
3122 "%d: close_service:%d - waiting in state %s",
3123 service
->state
->id
, service
->localport
,
3124 srvstate_names
[service
->srvstate
]);
3127 if ((status
== VCHIQ_SUCCESS
) &&
3128 (service
->srvstate
!= VCHIQ_SRVSTATE_FREE
) &&
3129 (service
->srvstate
!= VCHIQ_SRVSTATE_LISTENING
))
3130 status
= VCHIQ_ERROR
;
3132 unlock_service(service
);
3138 vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle
)
3140 /* Unregister the service */
3141 VCHIQ_SERVICE_T
*service
= find_service_by_handle(handle
);
3142 VCHIQ_STATUS_T status
= VCHIQ_SUCCESS
;
3147 vchiq_log_info(vchiq_core_log_level
,
3148 "%d: remove_service:%d",
3149 service
->state
->id
, service
->localport
);
3151 if (service
->srvstate
== VCHIQ_SRVSTATE_FREE
) {
3152 unlock_service(service
);
3156 mark_service_closing(service
);
3158 if ((service
->srvstate
== VCHIQ_SRVSTATE_HIDDEN
) ||
3159 (current
== service
->state
->slot_handler_thread
)) {
3160 /* Make it look like a client, because it must be removed and
3161 not left in the LISTENING state. */
3162 service
->public_fourcc
= VCHIQ_FOURCC_INVALID
;
3164 status
= vchiq_close_service_internal(service
,
3166 BUG_ON(status
== VCHIQ_RETRY
);
3168 /* Mark the service for removal by the slot handler */
3169 request_poll(service
->state
, service
, VCHIQ_POLL_REMOVE
);
3172 if (down_interruptible(&service
->remove_event
) != 0) {
3173 status
= VCHIQ_RETRY
;
3177 if ((service
->srvstate
== VCHIQ_SRVSTATE_FREE
) ||
3178 (service
->srvstate
== VCHIQ_SRVSTATE_OPEN
))
3181 vchiq_log_warning(vchiq_core_log_level
,
3182 "%d: remove_service:%d - waiting in state %s",
3183 service
->state
->id
, service
->localport
,
3184 srvstate_names
[service
->srvstate
]);
3187 if ((status
== VCHIQ_SUCCESS
) &&
3188 (service
->srvstate
!= VCHIQ_SRVSTATE_FREE
))
3189 status
= VCHIQ_ERROR
;
3191 unlock_service(service
);
3197 /* This function may be called by kernel threads or user threads.
3198 * User threads may receive VCHIQ_RETRY to indicate that a signal has been
3199 * received and the call should be retried after being returned to user
3201 * When called in blocking mode, the userdata field points to a bulk_waiter
3205 vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle
,
3206 VCHI_MEM_HANDLE_T memhandle
, void *offset
, int size
, void *userdata
,
3207 VCHIQ_BULK_MODE_T mode
, VCHIQ_BULK_DIR_T dir
)
3209 VCHIQ_SERVICE_T
*service
= find_service_by_handle(handle
);
3210 VCHIQ_BULK_QUEUE_T
*queue
;
3212 VCHIQ_STATE_T
*state
;
3213 struct bulk_waiter
*bulk_waiter
= NULL
;
3214 const char dir_char
= (dir
== VCHIQ_BULK_TRANSMIT
) ? 't' : 'r';
3215 const int dir_msgtype
= (dir
== VCHIQ_BULK_TRANSMIT
) ?
3216 VCHIQ_MSG_BULK_TX
: VCHIQ_MSG_BULK_RX
;
3217 VCHIQ_STATUS_T status
= VCHIQ_ERROR
;
3220 (service
->srvstate
!= VCHIQ_SRVSTATE_OPEN
) ||
3221 ((memhandle
== VCHI_MEM_HANDLE_INVALID
) && (offset
== NULL
)) ||
3222 (vchiq_check_service(service
) != VCHIQ_SUCCESS
))
3226 case VCHIQ_BULK_MODE_NOCALLBACK
:
3227 case VCHIQ_BULK_MODE_CALLBACK
:
3229 case VCHIQ_BULK_MODE_BLOCKING
:
3230 bulk_waiter
= (struct bulk_waiter
*)userdata
;
3231 sema_init(&bulk_waiter
->event
, 0);
3232 bulk_waiter
->actual
= 0;
3233 bulk_waiter
->bulk
= NULL
;
3235 case VCHIQ_BULK_MODE_WAITING
:
3236 bulk_waiter
= (struct bulk_waiter
*)userdata
;
3237 bulk
= bulk_waiter
->bulk
;
3243 state
= service
->state
;
3245 queue
= (dir
== VCHIQ_BULK_TRANSMIT
) ?
3246 &service
->bulk_tx
: &service
->bulk_rx
;
3248 if (mutex_lock_killable(&service
->bulk_mutex
) != 0) {
3249 status
= VCHIQ_RETRY
;
3253 if (queue
->local_insert
== queue
->remove
+ VCHIQ_NUM_SERVICE_BULKS
) {
3254 VCHIQ_SERVICE_STATS_INC(service
, bulk_stalls
);
3256 mutex_unlock(&service
->bulk_mutex
);
3257 if (down_interruptible(&service
->bulk_remove_event
)
3259 status
= VCHIQ_RETRY
;
3262 if (mutex_lock_killable(&service
->bulk_mutex
)
3264 status
= VCHIQ_RETRY
;
3267 } while (queue
->local_insert
== queue
->remove
+
3268 VCHIQ_NUM_SERVICE_BULKS
);
3271 bulk
= &queue
->bulks
[BULK_INDEX(queue
->local_insert
)];
3275 bulk
->userdata
= userdata
;
3277 bulk
->actual
= VCHIQ_BULK_ACTUAL_ABORTED
;
3279 if (vchiq_prepare_bulk_data(bulk
, memhandle
, offset
, size
, dir
) !=
3281 goto unlock_error_exit
;
3285 vchiq_log_info(vchiq_core_log_level
,
3286 "%d: bt (%d->%d) %cx %x@%pK %pK",
3287 state
->id
, service
->localport
, service
->remoteport
, dir_char
,
3288 size
, bulk
->data
, userdata
);
3290 /* The slot mutex must be held when the service is being closed, so
3291 claim it here to ensure that isn't happening */
3292 if (mutex_lock_killable(&state
->slot_mutex
) != 0) {
3293 status
= VCHIQ_RETRY
;
3294 goto cancel_bulk_error_exit
;
3297 if (service
->srvstate
!= VCHIQ_SRVSTATE_OPEN
)
3298 goto unlock_both_error_exit
;
3300 if (state
->is_master
) {
3301 queue
->local_insert
++;
3302 if (resolve_bulks(service
, queue
))
3303 request_poll(state
, service
,
3304 (dir
== VCHIQ_BULK_TRANSMIT
) ?
3305 VCHIQ_POLL_TXNOTIFY
: VCHIQ_POLL_RXNOTIFY
);
3307 int payload
[2] = { (int)(long)bulk
->data
, bulk
->size
};
3308 VCHIQ_ELEMENT_T element
= { payload
, sizeof(payload
) };
3310 status
= queue_message(state
, NULL
,
3311 VCHIQ_MAKE_MSG(dir_msgtype
,
3312 service
->localport
, service
->remoteport
),
3313 &element
, 1, sizeof(payload
),
3314 QMFLAGS_IS_BLOCKING
|
3315 QMFLAGS_NO_MUTEX_LOCK
|
3316 QMFLAGS_NO_MUTEX_UNLOCK
);
3317 if (status
!= VCHIQ_SUCCESS
) {
3318 goto unlock_both_error_exit
;
3320 queue
->local_insert
++;
3323 mutex_unlock(&state
->slot_mutex
);
3324 mutex_unlock(&service
->bulk_mutex
);
3326 vchiq_log_trace(vchiq_core_log_level
,
3327 "%d: bt:%d %cx li=%x ri=%x p=%x",
3329 service
->localport
, dir_char
,
3330 queue
->local_insert
, queue
->remote_insert
, queue
->process
);
3333 unlock_service(service
);
3335 status
= VCHIQ_SUCCESS
;
3338 bulk_waiter
->bulk
= bulk
;
3339 if (down_interruptible(&bulk_waiter
->event
) != 0)
3340 status
= VCHIQ_RETRY
;
3341 else if (bulk_waiter
->actual
== VCHIQ_BULK_ACTUAL_ABORTED
)
3342 status
= VCHIQ_ERROR
;
3347 unlock_both_error_exit
:
3348 mutex_unlock(&state
->slot_mutex
);
3349 cancel_bulk_error_exit
:
3350 vchiq_complete_bulk(bulk
);
3352 mutex_unlock(&service
->bulk_mutex
);
3356 unlock_service(service
);
3361 vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle
,
3362 const VCHIQ_ELEMENT_T
*elements
, unsigned int count
)
3364 VCHIQ_SERVICE_T
*service
= find_service_by_handle(handle
);
3365 VCHIQ_STATUS_T status
= VCHIQ_ERROR
;
3367 unsigned int size
= 0;
3371 (vchiq_check_service(service
) != VCHIQ_SUCCESS
))
3374 for (i
= 0; i
< (unsigned int)count
; i
++) {
3375 if (elements
[i
].size
) {
3376 if (elements
[i
].data
== NULL
) {
3377 VCHIQ_SERVICE_STATS_INC(service
, error_count
);
3380 size
+= elements
[i
].size
;
3384 if (size
> VCHIQ_MAX_MSG_SIZE
) {
3385 VCHIQ_SERVICE_STATS_INC(service
, error_count
);
3389 switch (service
->srvstate
) {
3390 case VCHIQ_SRVSTATE_OPEN
:
3391 status
= queue_message(service
->state
, service
,
3392 VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA
,
3394 service
->remoteport
),
3395 elements
, count
, size
, 1);
3397 case VCHIQ_SRVSTATE_OPENSYNC
:
3398 status
= queue_message_sync(service
->state
, service
,
3399 VCHIQ_MAKE_MSG(VCHIQ_MSG_DATA
,
3401 service
->remoteport
),
3402 elements
, count
, size
, 1);
3405 status
= VCHIQ_ERROR
;
3411 unlock_service(service
);
3417 vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle
, VCHIQ_HEADER_T
*header
)
3419 VCHIQ_SERVICE_T
*service
= find_service_by_handle(handle
);
3420 VCHIQ_SHARED_STATE_T
*remote
;
3421 VCHIQ_STATE_T
*state
;
3427 state
= service
->state
;
3428 remote
= state
->remote
;
3430 slot_index
= SLOT_INDEX_FROM_DATA(state
, (void *)header
);
3432 if ((slot_index
>= remote
->slot_first
) &&
3433 (slot_index
<= remote
->slot_last
)) {
3434 int msgid
= header
->msgid
;
3435 if (msgid
& VCHIQ_MSGID_CLAIMED
) {
3436 VCHIQ_SLOT_INFO_T
*slot_info
=
3437 SLOT_INFO_FROM_INDEX(state
, slot_index
);
3439 release_slot(state
, slot_info
, header
, service
);
3441 } else if (slot_index
== remote
->slot_sync
)
3442 release_message_sync(state
, header
);
3444 unlock_service(service
);
3448 release_message_sync(VCHIQ_STATE_T
*state
, VCHIQ_HEADER_T
*header
)
3450 header
->msgid
= VCHIQ_MSGID_PADDING
;
3452 remote_event_signal(&state
->remote
->sync_release
);
3456 vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle
, short *peer_version
)
3458 VCHIQ_STATUS_T status
= VCHIQ_ERROR
;
3459 VCHIQ_SERVICE_T
*service
= find_service_by_handle(handle
);
3462 (vchiq_check_service(service
) != VCHIQ_SUCCESS
) ||
3465 *peer_version
= service
->peer_version
;
3466 status
= VCHIQ_SUCCESS
;
3470 unlock_service(service
);
3475 vchiq_get_config(VCHIQ_INSTANCE_T instance
,
3476 int config_size
, VCHIQ_CONFIG_T
*pconfig
)
3478 VCHIQ_CONFIG_T config
;
3482 config
.max_msg_size
= VCHIQ_MAX_MSG_SIZE
;
3483 config
.bulk_threshold
= VCHIQ_MAX_MSG_SIZE
;
3484 config
.max_outstanding_bulks
= VCHIQ_NUM_SERVICE_BULKS
;
3485 config
.max_services
= VCHIQ_MAX_SERVICES
;
3486 config
.version
= VCHIQ_VERSION
;
3487 config
.version_min
= VCHIQ_VERSION_MIN
;
3489 if (config_size
> sizeof(VCHIQ_CONFIG_T
))
3492 memcpy(pconfig
, &config
,
3493 min(config_size
, (int)(sizeof(VCHIQ_CONFIG_T
))));
3495 return VCHIQ_SUCCESS
;
3499 vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle
,
3500 VCHIQ_SERVICE_OPTION_T option
, int value
)
3502 VCHIQ_SERVICE_T
*service
= find_service_by_handle(handle
);
3503 VCHIQ_STATUS_T status
= VCHIQ_ERROR
;
3507 case VCHIQ_SERVICE_OPTION_AUTOCLOSE
:
3508 service
->auto_close
= value
;
3509 status
= VCHIQ_SUCCESS
;
3512 case VCHIQ_SERVICE_OPTION_SLOT_QUOTA
: {
3513 VCHIQ_SERVICE_QUOTA_T
*service_quota
=
3514 &service
->state
->service_quotas
[
3515 service
->localport
];
3517 value
= service
->state
->default_slot_quota
;
3518 if ((value
>= service_quota
->slot_use_count
) &&
3519 (value
< (unsigned short)~0)) {
3520 service_quota
->slot_quota
= value
;
3521 if ((value
>= service_quota
->slot_use_count
) &&
3522 (service_quota
->message_quota
>=
3523 service_quota
->message_use_count
)) {
3524 /* Signal the service that it may have
3525 ** dropped below its quota */
3526 up(&service_quota
->quota_event
);
3528 status
= VCHIQ_SUCCESS
;
3532 case VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA
: {
3533 VCHIQ_SERVICE_QUOTA_T
*service_quota
=
3534 &service
->state
->service_quotas
[
3535 service
->localport
];
3537 value
= service
->state
->default_message_quota
;
3538 if ((value
>= service_quota
->message_use_count
) &&
3539 (value
< (unsigned short)~0)) {
3540 service_quota
->message_quota
= value
;
3542 service_quota
->message_use_count
) &&
3543 (service_quota
->slot_quota
>=
3544 service_quota
->slot_use_count
))
3545 /* Signal the service that it may have
3546 ** dropped below its quota */
3547 up(&service_quota
->quota_event
);
3548 status
= VCHIQ_SUCCESS
;
3552 case VCHIQ_SERVICE_OPTION_SYNCHRONOUS
:
3553 if ((service
->srvstate
== VCHIQ_SRVSTATE_HIDDEN
) ||
3554 (service
->srvstate
==
3555 VCHIQ_SRVSTATE_LISTENING
)) {
3556 service
->sync
= value
;
3557 status
= VCHIQ_SUCCESS
;
3561 case VCHIQ_SERVICE_OPTION_TRACE
:
3562 service
->trace
= value
;
3563 status
= VCHIQ_SUCCESS
;
3569 unlock_service(service
);
3576 vchiq_dump_shared_state(void *dump_context
, VCHIQ_STATE_T
*state
,
3577 VCHIQ_SHARED_STATE_T
*shared
, const char *label
)
3579 static const char *const debug_names
[] = {
3581 "SLOT_HANDLER_COUNT",
3582 "SLOT_HANDLER_LINE",
3586 "AWAIT_COMPLETION_LINE",
3587 "DEQUEUE_MESSAGE_LINE",
3588 "SERVICE_CALLBACK_LINE",
3589 "MSG_QUEUE_FULL_COUNT",
3590 "COMPLETION_QUEUE_FULL_COUNT"
3596 len
= snprintf(buf
, sizeof(buf
),
3597 " %s: slots %d-%d tx_pos=%x recycle=%x",
3598 label
, shared
->slot_first
, shared
->slot_last
,
3599 shared
->tx_pos
, shared
->slot_queue_recycle
);
3600 vchiq_dump(dump_context
, buf
, len
+ 1);
3602 len
= snprintf(buf
, sizeof(buf
),
3604 vchiq_dump(dump_context
, buf
, len
+ 1);
3606 for (i
= shared
->slot_first
; i
<= shared
->slot_last
; i
++) {
3607 VCHIQ_SLOT_INFO_T slot_info
= *SLOT_INFO_FROM_INDEX(state
, i
);
3608 if (slot_info
.use_count
!= slot_info
.release_count
) {
3609 len
= snprintf(buf
, sizeof(buf
),
3610 " %d: %d/%d", i
, slot_info
.use_count
,
3611 slot_info
.release_count
);
3612 vchiq_dump(dump_context
, buf
, len
+ 1);
3616 for (i
= 1; i
< shared
->debug
[DEBUG_ENTRIES
]; i
++) {
3617 len
= snprintf(buf
, sizeof(buf
), " DEBUG: %s = %d(%x)",
3618 debug_names
[i
], shared
->debug
[i
], shared
->debug
[i
]);
3619 vchiq_dump(dump_context
, buf
, len
+ 1);
3624 vchiq_dump_state(void *dump_context
, VCHIQ_STATE_T
*state
)
3630 len
= snprintf(buf
, sizeof(buf
), "State %d: %s", state
->id
,
3631 conn_state_names
[state
->conn_state
]);
3632 vchiq_dump(dump_context
, buf
, len
+ 1);
3634 len
= snprintf(buf
, sizeof(buf
),
3635 " tx_pos=%x(@%pK), rx_pos=%x(@%pK)",
3636 state
->local
->tx_pos
,
3637 state
->tx_data
+ (state
->local_tx_pos
& VCHIQ_SLOT_MASK
),
3639 state
->rx_data
+ (state
->rx_pos
& VCHIQ_SLOT_MASK
));
3640 vchiq_dump(dump_context
, buf
, len
+ 1);
3642 len
= snprintf(buf
, sizeof(buf
),
3643 " Version: %d (min %d)",
3644 VCHIQ_VERSION
, VCHIQ_VERSION_MIN
);
3645 vchiq_dump(dump_context
, buf
, len
+ 1);
3647 if (VCHIQ_ENABLE_STATS
) {
3648 len
= snprintf(buf
, sizeof(buf
),
3649 " Stats: ctrl_tx_count=%d, ctrl_rx_count=%d, "
3651 state
->stats
.ctrl_tx_count
, state
->stats
.ctrl_rx_count
,
3652 state
->stats
.error_count
);
3653 vchiq_dump(dump_context
, buf
, len
+ 1);
3656 len
= snprintf(buf
, sizeof(buf
),
3657 " Slots: %d available (%d data), %d recyclable, %d stalls "
3659 ((state
->slot_queue_available
* VCHIQ_SLOT_SIZE
) -
3660 state
->local_tx_pos
) / VCHIQ_SLOT_SIZE
,
3661 state
->data_quota
- state
->data_use_count
,
3662 state
->local
->slot_queue_recycle
- state
->slot_queue_available
,
3663 state
->stats
.slot_stalls
, state
->stats
.data_stalls
);
3664 vchiq_dump(dump_context
, buf
, len
+ 1);
3666 vchiq_dump_platform_state(dump_context
);
3668 vchiq_dump_shared_state(dump_context
, state
, state
->local
, "Local");
3669 vchiq_dump_shared_state(dump_context
, state
, state
->remote
, "Remote");
3671 vchiq_dump_platform_instances(dump_context
);
3673 for (i
= 0; i
< state
->unused_service
; i
++) {
3674 VCHIQ_SERVICE_T
*service
= find_service_by_port(state
, i
);
3677 vchiq_dump_service_state(dump_context
, service
);
3678 unlock_service(service
);
3684 vchiq_dump_service_state(void *dump_context
, VCHIQ_SERVICE_T
*service
)
3689 len
= snprintf(buf
, sizeof(buf
), "Service %u: %s (ref %u)",
3690 service
->localport
, srvstate_names
[service
->srvstate
],
3691 service
->ref_count
- 1); /*Don't include the lock just taken*/
3693 if (service
->srvstate
!= VCHIQ_SRVSTATE_FREE
) {
3694 char remoteport
[30];
3695 VCHIQ_SERVICE_QUOTA_T
*service_quota
=
3696 &service
->state
->service_quotas
[service
->localport
];
3697 int fourcc
= service
->base
.fourcc
;
3698 int tx_pending
, rx_pending
;
3699 if (service
->remoteport
!= VCHIQ_PORT_FREE
) {
3700 int len2
= snprintf(remoteport
, sizeof(remoteport
),
3701 "%u", service
->remoteport
);
3702 if (service
->public_fourcc
!= VCHIQ_FOURCC_INVALID
)
3703 snprintf(remoteport
+ len2
,
3704 sizeof(remoteport
) - len2
,
3705 " (client %x)", service
->client_id
);
3707 strcpy(remoteport
, "n/a");
3709 len
+= snprintf(buf
+ len
, sizeof(buf
) - len
,
3710 " '%c%c%c%c' remote %s (msg use %d/%d, slot use %d/%d)",
3711 VCHIQ_FOURCC_AS_4CHARS(fourcc
),
3713 service_quota
->message_use_count
,
3714 service_quota
->message_quota
,
3715 service_quota
->slot_use_count
,
3716 service_quota
->slot_quota
);
3718 vchiq_dump(dump_context
, buf
, len
+ 1);
3720 tx_pending
= service
->bulk_tx
.local_insert
-
3721 service
->bulk_tx
.remote_insert
;
3723 rx_pending
= service
->bulk_rx
.local_insert
-
3724 service
->bulk_rx
.remote_insert
;
3726 len
= snprintf(buf
, sizeof(buf
),
3727 " Bulk: tx_pending=%d (size %d),"
3728 " rx_pending=%d (size %d)",
3730 tx_pending
? service
->bulk_tx
.bulks
[
3731 BULK_INDEX(service
->bulk_tx
.remove
)].size
: 0,
3733 rx_pending
? service
->bulk_rx
.bulks
[
3734 BULK_INDEX(service
->bulk_rx
.remove
)].size
: 0);
3736 if (VCHIQ_ENABLE_STATS
) {
3737 vchiq_dump(dump_context
, buf
, len
+ 1);
3739 len
= snprintf(buf
, sizeof(buf
),
3740 " Ctrl: tx_count=%d, tx_bytes=%llu, "
3741 "rx_count=%d, rx_bytes=%llu",
3742 service
->stats
.ctrl_tx_count
,
3743 service
->stats
.ctrl_tx_bytes
,
3744 service
->stats
.ctrl_rx_count
,
3745 service
->stats
.ctrl_rx_bytes
);
3746 vchiq_dump(dump_context
, buf
, len
+ 1);
3748 len
= snprintf(buf
, sizeof(buf
),
3749 " Bulk: tx_count=%d, tx_bytes=%llu, "
3750 "rx_count=%d, rx_bytes=%llu",
3751 service
->stats
.bulk_tx_count
,
3752 service
->stats
.bulk_tx_bytes
,
3753 service
->stats
.bulk_rx_count
,
3754 service
->stats
.bulk_rx_bytes
);
3755 vchiq_dump(dump_context
, buf
, len
+ 1);
3757 len
= snprintf(buf
, sizeof(buf
),
3758 " %d quota stalls, %d slot stalls, "
3759 "%d bulk stalls, %d aborted, %d errors",
3760 service
->stats
.quota_stalls
,
3761 service
->stats
.slot_stalls
,
3762 service
->stats
.bulk_stalls
,
3763 service
->stats
.bulk_aborted_count
,
3764 service
->stats
.error_count
);
3768 vchiq_dump(dump_context
, buf
, len
+ 1);
3770 if (service
->srvstate
!= VCHIQ_SRVSTATE_FREE
)
3771 vchiq_dump_platform_service_state(dump_context
, service
);
3776 vchiq_loud_error_header(void)
3778 vchiq_log_error(vchiq_core_log_level
,
3779 "============================================================"
3780 "================");
3781 vchiq_log_error(vchiq_core_log_level
,
3782 "============================================================"
3783 "================");
3784 vchiq_log_error(vchiq_core_log_level
, "=====");
3788 vchiq_loud_error_footer(void)
3790 vchiq_log_error(vchiq_core_log_level
, "=====");
3791 vchiq_log_error(vchiq_core_log_level
,
3792 "============================================================"
3793 "================");
3794 vchiq_log_error(vchiq_core_log_level
,
3795 "============================================================"
3796 "================");
3800 VCHIQ_STATUS_T
vchiq_send_remote_use(VCHIQ_STATE_T
*state
)
3802 VCHIQ_STATUS_T status
= VCHIQ_RETRY
;
3803 if (state
->conn_state
!= VCHIQ_CONNSTATE_DISCONNECTED
)
3804 status
= queue_message(state
, NULL
,
3805 VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE
, 0, 0),
3810 VCHIQ_STATUS_T
vchiq_send_remote_release(VCHIQ_STATE_T
*state
)
3812 VCHIQ_STATUS_T status
= VCHIQ_RETRY
;
3813 if (state
->conn_state
!= VCHIQ_CONNSTATE_DISCONNECTED
)
3814 status
= queue_message(state
, NULL
,
3815 VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE
, 0, 0),
3820 VCHIQ_STATUS_T
vchiq_send_remote_use_active(VCHIQ_STATE_T
*state
)
3822 VCHIQ_STATUS_T status
= VCHIQ_RETRY
;
3823 if (state
->conn_state
!= VCHIQ_CONNSTATE_DISCONNECTED
)
3824 status
= queue_message(state
, NULL
,
3825 VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE
, 0, 0),
3830 void vchiq_log_dump_mem(const char *label
, uint32_t addr
, const void *void_mem
,
3833 const uint8_t *mem
= (const uint8_t *)void_mem
;
3838 while (num_bytes
> 0) {
3841 for (offset
= 0; offset
< 16; offset
++) {
3842 if (offset
< num_bytes
)
3843 s
+= snprintf(s
, 4, "%02x ", mem
[offset
]);
3845 s
+= snprintf(s
, 4, " ");
3848 for (offset
= 0; offset
< 16; offset
++) {
3849 if (offset
< num_bytes
) {
3850 uint8_t ch
= mem
[offset
];
3852 if ((ch
< ' ') || (ch
> '~'))
3859 if ((label
!= NULL
) && (*label
!= '\0'))
3860 vchiq_log_trace(VCHIQ_LOG_TRACE
,
3861 "%s: %08x: %s", label
, addr
, line_buf
);
3863 vchiq_log_trace(VCHIQ_LOG_TRACE
,
3864 "%08x: %s", addr
, line_buf
);