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 Files ---------------------------------------------------- */
36 #include <linux/kernel.h>
37 #include <linux/module.h>
38 #include <linux/mutex.h>
40 #include "vchiq_core.h"
41 #include "vchiq_arm.h"
42 #include "vchiq_killable.h"
44 /* ---- Public Variables ------------------------------------------------- */
46 /* ---- Private Constants and Types -------------------------------------- */
48 struct bulk_waiter_node {
49 struct bulk_waiter bulk_waiter;
51 struct list_head list;
54 struct vchiq_instance_struct {
59 struct list_head bulk_waiter_list;
60 struct mutex bulk_waiter_list_mutex;
64 vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
65 unsigned int size, VCHIQ_BULK_DIR_T dir);
67 /****************************************************************************
71 ***************************************************************************/
72 #define VCHIQ_INIT_RETRIES 10
73 VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out)
75 VCHIQ_STATUS_T status = VCHIQ_ERROR;
77 VCHIQ_INSTANCE_T instance = NULL;
80 vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
82 /* VideoCore may not be ready due to boot up timing.
83 It may never be ready if kernel and firmware are mismatched, so don't block forever. */
84 for (i = 0; i < VCHIQ_INIT_RETRIES; i++) {
85 state = vchiq_get_state();
90 if (i == VCHIQ_INIT_RETRIES) {
91 vchiq_log_error(vchiq_core_log_level,
92 "%s: videocore not initialized\n", __func__);
95 vchiq_log_warning(vchiq_core_log_level,
96 "%s: videocore initialized after %d retries\n", __func__, i);
99 instance = kzalloc(sizeof(*instance), GFP_KERNEL);
101 vchiq_log_error(vchiq_core_log_level,
102 "%s: error allocating vchiq instance\n", __func__);
106 instance->connected = 0;
107 instance->state = state;
108 mutex_init(&instance->bulk_waiter_list_mutex);
109 INIT_LIST_HEAD(&instance->bulk_waiter_list);
111 *instance_out = instance;
113 status = VCHIQ_SUCCESS;
116 vchiq_log_trace(vchiq_core_log_level,
117 "%s(%p): returning %d", __func__, instance, status);
121 EXPORT_SYMBOL(vchiq_initialise);
123 /****************************************************************************
127 ***************************************************************************/
129 VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
131 VCHIQ_STATUS_T status;
132 VCHIQ_STATE_T *state = instance->state;
134 vchiq_log_trace(vchiq_core_log_level,
135 "%s(%p) called", __func__, instance);
137 if (mutex_lock_killable(&state->mutex) != 0)
140 /* Remove all services */
141 status = vchiq_shutdown_internal(state, instance);
143 mutex_unlock(&state->mutex);
145 vchiq_log_trace(vchiq_core_log_level,
146 "%s(%p): returning %d", __func__, instance, status);
148 if (status == VCHIQ_SUCCESS) {
149 struct list_head *pos, *next;
151 list_for_each_safe(pos, next,
152 &instance->bulk_waiter_list) {
153 struct bulk_waiter_node *waiter;
155 waiter = list_entry(pos,
156 struct bulk_waiter_node,
159 vchiq_log_info(vchiq_arm_log_level,
160 "bulk_waiter - cleaned up %pK for pid %d",
161 waiter, waiter->pid);
169 EXPORT_SYMBOL(vchiq_shutdown);
171 /****************************************************************************
175 ***************************************************************************/
177 static int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
179 return instance->connected;
182 /****************************************************************************
186 ***************************************************************************/
188 VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
190 VCHIQ_STATUS_T status;
191 VCHIQ_STATE_T *state = instance->state;
193 vchiq_log_trace(vchiq_core_log_level,
194 "%s(%p) called", __func__, instance);
196 if (mutex_lock_killable(&state->mutex) != 0) {
197 vchiq_log_trace(vchiq_core_log_level,
198 "%s: call to mutex_lock failed", __func__);
199 status = VCHIQ_RETRY;
202 status = vchiq_connect_internal(state, instance);
204 if (status == VCHIQ_SUCCESS)
205 instance->connected = 1;
207 mutex_unlock(&state->mutex);
210 vchiq_log_trace(vchiq_core_log_level,
211 "%s(%p): returning %d", __func__, instance, status);
215 EXPORT_SYMBOL(vchiq_connect);
217 /****************************************************************************
221 ***************************************************************************/
223 VCHIQ_STATUS_T vchiq_add_service(
224 VCHIQ_INSTANCE_T instance,
225 const VCHIQ_SERVICE_PARAMS_T *params,
226 VCHIQ_SERVICE_HANDLE_T *phandle)
228 VCHIQ_STATUS_T status;
229 VCHIQ_STATE_T *state = instance->state;
230 VCHIQ_SERVICE_T *service = NULL;
233 vchiq_log_trace(vchiq_core_log_level,
234 "%s(%p) called", __func__, instance);
236 *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
238 srvstate = vchiq_is_connected(instance)
239 ? VCHIQ_SRVSTATE_LISTENING
240 : VCHIQ_SRVSTATE_HIDDEN;
242 service = vchiq_add_service_internal(
250 *phandle = service->handle;
251 status = VCHIQ_SUCCESS;
253 status = VCHIQ_ERROR;
255 vchiq_log_trace(vchiq_core_log_level,
256 "%s(%p): returning %d", __func__, instance, status);
260 EXPORT_SYMBOL(vchiq_add_service);
262 /****************************************************************************
266 ***************************************************************************/
268 VCHIQ_STATUS_T vchiq_open_service(
269 VCHIQ_INSTANCE_T instance,
270 const VCHIQ_SERVICE_PARAMS_T *params,
271 VCHIQ_SERVICE_HANDLE_T *phandle)
273 VCHIQ_STATUS_T status = VCHIQ_ERROR;
274 VCHIQ_STATE_T *state = instance->state;
275 VCHIQ_SERVICE_T *service = NULL;
277 vchiq_log_trace(vchiq_core_log_level,
278 "%s(%p) called", __func__, instance);
280 *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
282 if (!vchiq_is_connected(instance))
285 service = vchiq_add_service_internal(state,
287 VCHIQ_SRVSTATE_OPENING,
292 *phandle = service->handle;
293 status = vchiq_open_service_internal(service, current->pid);
294 if (status != VCHIQ_SUCCESS) {
295 vchiq_remove_service(service->handle);
296 *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
301 vchiq_log_trace(vchiq_core_log_level,
302 "%s(%p): returning %d", __func__, instance, status);
306 EXPORT_SYMBOL(vchiq_open_service);
309 vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
310 const void *data, unsigned int size, void *userdata)
312 return vchiq_bulk_transfer(handle,
313 VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
314 VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
316 EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
319 vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
320 unsigned int size, void *userdata)
322 return vchiq_bulk_transfer(handle,
323 VCHI_MEM_HANDLE_INVALID, data, size, userdata,
324 VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
326 EXPORT_SYMBOL(vchiq_queue_bulk_receive);
329 vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
330 unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
332 VCHIQ_STATUS_T status;
335 case VCHIQ_BULK_MODE_NOCALLBACK:
336 case VCHIQ_BULK_MODE_CALLBACK:
337 status = vchiq_bulk_transfer(handle,
338 VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
339 mode, VCHIQ_BULK_TRANSMIT);
341 case VCHIQ_BULK_MODE_BLOCKING:
342 status = vchiq_blocking_bulk_transfer(handle,
343 (void *)data, size, VCHIQ_BULK_TRANSMIT);
351 EXPORT_SYMBOL(vchiq_bulk_transmit);
354 vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
355 unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
357 VCHIQ_STATUS_T status;
360 case VCHIQ_BULK_MODE_NOCALLBACK:
361 case VCHIQ_BULK_MODE_CALLBACK:
362 status = vchiq_bulk_transfer(handle,
363 VCHI_MEM_HANDLE_INVALID, data, size, userdata,
364 mode, VCHIQ_BULK_RECEIVE);
366 case VCHIQ_BULK_MODE_BLOCKING:
367 status = vchiq_blocking_bulk_transfer(handle,
368 (void *)data, size, VCHIQ_BULK_RECEIVE);
376 EXPORT_SYMBOL(vchiq_bulk_receive);
378 static VCHIQ_STATUS_T
379 vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
380 unsigned int size, VCHIQ_BULK_DIR_T dir)
382 VCHIQ_INSTANCE_T instance;
383 VCHIQ_SERVICE_T *service;
384 VCHIQ_STATUS_T status;
385 struct bulk_waiter_node *waiter = NULL;
386 struct list_head *pos;
388 service = find_service_by_handle(handle);
392 instance = service->instance;
394 unlock_service(service);
396 mutex_lock(&instance->bulk_waiter_list_mutex);
397 list_for_each(pos, &instance->bulk_waiter_list) {
398 if (list_entry(pos, struct bulk_waiter_node,
399 list)->pid == current->pid) {
400 waiter = list_entry(pos,
401 struct bulk_waiter_node,
407 mutex_unlock(&instance->bulk_waiter_list_mutex);
410 VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
413 /* This thread has an outstanding bulk transfer. */
414 if ((bulk->data != data) ||
415 (bulk->size != size)) {
416 /* This is not a retry of the previous one.
417 ** Cancel the signal when the transfer
419 spin_lock(&bulk_waiter_spinlock);
420 bulk->userdata = NULL;
421 spin_unlock(&bulk_waiter_spinlock);
427 waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
429 vchiq_log_error(vchiq_core_log_level,
430 "%s - out of memory", __func__);
435 status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
436 data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
438 if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
439 !waiter->bulk_waiter.bulk) {
440 VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
443 /* Cancel the signal when the transfer
445 spin_lock(&bulk_waiter_spinlock);
446 bulk->userdata = NULL;
447 spin_unlock(&bulk_waiter_spinlock);
451 waiter->pid = current->pid;
452 mutex_lock(&instance->bulk_waiter_list_mutex);
453 list_add(&waiter->list, &instance->bulk_waiter_list);
454 mutex_unlock(&instance->bulk_waiter_list_mutex);
455 vchiq_log_info(vchiq_arm_log_level,
456 "saved bulk_waiter %pK for pid %d",
457 waiter, current->pid);