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 *instanceOut)
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 *instanceOut = 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_interruptible(&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;
150 list_for_each_safe(pos, next,
151 &instance->bulk_waiter_list) {
152 struct bulk_waiter_node *waiter;
153 waiter = list_entry(pos,
154 struct bulk_waiter_node,
157 vchiq_log_info(vchiq_arm_log_level,
158 "bulk_waiter - cleaned up %x "
160 (unsigned int)waiter, waiter->pid);
168 EXPORT_SYMBOL(vchiq_shutdown);
170 /****************************************************************************
174 ***************************************************************************/
176 int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
178 return instance->connected;
181 /****************************************************************************
185 ***************************************************************************/
187 VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
189 VCHIQ_STATUS_T status;
190 VCHIQ_STATE_T *state = instance->state;
192 vchiq_log_trace(vchiq_core_log_level,
193 "%s(%p) called", __func__, instance);
195 if (mutex_lock_interruptible(&state->mutex) != 0) {
196 vchiq_log_trace(vchiq_core_log_level,
197 "%s: call to mutex_lock failed", __func__);
198 status = VCHIQ_RETRY;
201 status = vchiq_connect_internal(state, instance);
203 if (status == VCHIQ_SUCCESS)
204 instance->connected = 1;
206 mutex_unlock(&state->mutex);
209 vchiq_log_trace(vchiq_core_log_level,
210 "%s(%p): returning %d", __func__, instance, status);
214 EXPORT_SYMBOL(vchiq_connect);
216 /****************************************************************************
220 ***************************************************************************/
222 VCHIQ_STATUS_T vchiq_add_service(
223 VCHIQ_INSTANCE_T instance,
224 const VCHIQ_SERVICE_PARAMS_T *params,
225 VCHIQ_SERVICE_HANDLE_T *phandle)
227 VCHIQ_STATUS_T status;
228 VCHIQ_STATE_T *state = instance->state;
229 VCHIQ_SERVICE_T *service = NULL;
232 vchiq_log_trace(vchiq_core_log_level,
233 "%s(%p) called", __func__, instance);
235 *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
237 srvstate = vchiq_is_connected(instance)
238 ? VCHIQ_SRVSTATE_LISTENING
239 : VCHIQ_SRVSTATE_HIDDEN;
241 service = vchiq_add_service_internal(
249 *phandle = service->handle;
250 status = VCHIQ_SUCCESS;
252 status = VCHIQ_ERROR;
254 vchiq_log_trace(vchiq_core_log_level,
255 "%s(%p): returning %d", __func__, instance, status);
259 EXPORT_SYMBOL(vchiq_add_service);
261 /****************************************************************************
265 ***************************************************************************/
267 VCHIQ_STATUS_T vchiq_open_service(
268 VCHIQ_INSTANCE_T instance,
269 const VCHIQ_SERVICE_PARAMS_T *params,
270 VCHIQ_SERVICE_HANDLE_T *phandle)
272 VCHIQ_STATUS_T status = VCHIQ_ERROR;
273 VCHIQ_STATE_T *state = instance->state;
274 VCHIQ_SERVICE_T *service = NULL;
276 vchiq_log_trace(vchiq_core_log_level,
277 "%s(%p) called", __func__, instance);
279 *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
281 if (!vchiq_is_connected(instance))
284 service = vchiq_add_service_internal(state,
286 VCHIQ_SRVSTATE_OPENING,
291 *phandle = service->handle;
292 status = vchiq_open_service_internal(service, current->pid);
293 if (status != VCHIQ_SUCCESS) {
294 vchiq_remove_service(service->handle);
295 *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
300 vchiq_log_trace(vchiq_core_log_level,
301 "%s(%p): returning %d", __func__, instance, status);
305 EXPORT_SYMBOL(vchiq_open_service);
308 vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
309 const void *data, unsigned int size, void *userdata)
311 return vchiq_bulk_transfer(handle,
312 VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
313 VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
315 EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
318 vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
319 unsigned int size, void *userdata)
321 return vchiq_bulk_transfer(handle,
322 VCHI_MEM_HANDLE_INVALID, data, size, userdata,
323 VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
325 EXPORT_SYMBOL(vchiq_queue_bulk_receive);
328 vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data,
329 unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
331 VCHIQ_STATUS_T status;
334 case VCHIQ_BULK_MODE_NOCALLBACK:
335 case VCHIQ_BULK_MODE_CALLBACK:
336 status = vchiq_bulk_transfer(handle,
337 VCHI_MEM_HANDLE_INVALID, (void *)data, size, userdata,
338 mode, VCHIQ_BULK_TRANSMIT);
340 case VCHIQ_BULK_MODE_BLOCKING:
341 status = vchiq_blocking_bulk_transfer(handle,
342 (void *)data, size, VCHIQ_BULK_TRANSMIT);
350 EXPORT_SYMBOL(vchiq_bulk_transmit);
353 vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
354 unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
356 VCHIQ_STATUS_T status;
359 case VCHIQ_BULK_MODE_NOCALLBACK:
360 case VCHIQ_BULK_MODE_CALLBACK:
361 status = vchiq_bulk_transfer(handle,
362 VCHI_MEM_HANDLE_INVALID, data, size, userdata,
363 mode, VCHIQ_BULK_RECEIVE);
365 case VCHIQ_BULK_MODE_BLOCKING:
366 status = vchiq_blocking_bulk_transfer(handle,
367 (void *)data, size, VCHIQ_BULK_RECEIVE);
375 EXPORT_SYMBOL(vchiq_bulk_receive);
377 static VCHIQ_STATUS_T
378 vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
379 unsigned int size, VCHIQ_BULK_DIR_T dir)
381 VCHIQ_INSTANCE_T instance;
382 VCHIQ_SERVICE_T *service;
383 VCHIQ_STATUS_T status;
384 struct bulk_waiter_node *waiter = NULL;
385 struct list_head *pos;
387 service = find_service_by_handle(handle);
391 instance = service->instance;
393 unlock_service(service);
395 mutex_lock(&instance->bulk_waiter_list_mutex);
396 list_for_each(pos, &instance->bulk_waiter_list) {
397 if (list_entry(pos, struct bulk_waiter_node,
398 list)->pid == current->pid) {
399 waiter = list_entry(pos,
400 struct bulk_waiter_node,
406 mutex_unlock(&instance->bulk_waiter_list_mutex);
409 VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
411 /* This thread has an outstanding bulk transfer. */
412 if ((bulk->data != data) ||
413 (bulk->size != size)) {
414 /* This is not a retry of the previous one.
415 ** Cancel the signal when the transfer
417 spin_lock(&bulk_waiter_spinlock);
418 bulk->userdata = NULL;
419 spin_unlock(&bulk_waiter_spinlock);
425 waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
427 vchiq_log_error(vchiq_core_log_level,
428 "%s - out of memory", __func__);
433 status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
434 data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
436 if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
437 !waiter->bulk_waiter.bulk) {
438 VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
440 /* Cancel the signal when the transfer
442 spin_lock(&bulk_waiter_spinlock);
443 bulk->userdata = NULL;
444 spin_unlock(&bulk_waiter_spinlock);
448 waiter->pid = current->pid;
449 mutex_lock(&instance->bulk_waiter_list_mutex);
450 list_add(&waiter->list, &instance->bulk_waiter_list);
451 mutex_unlock(&instance->bulk_waiter_list_mutex);
452 vchiq_log_info(vchiq_arm_log_level,
453 "saved bulk_waiter %x for pid %d",
454 (unsigned int)waiter, current->pid);