1262f27b2SOleksandr Tymoshenko /**
2262f27b2SOleksandr Tymoshenko * Copyright (c) 2010-2012 Broadcom. All rights reserved.
3262f27b2SOleksandr Tymoshenko *
4262f27b2SOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without
5262f27b2SOleksandr Tymoshenko * modification, are permitted provided that the following conditions
6262f27b2SOleksandr Tymoshenko * are met:
7262f27b2SOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright
8262f27b2SOleksandr Tymoshenko * notice, this list of conditions, and the following disclaimer,
9262f27b2SOleksandr Tymoshenko * without modification.
10262f27b2SOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright
11262f27b2SOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the
12262f27b2SOleksandr Tymoshenko * documentation and/or other materials provided with the distribution.
13262f27b2SOleksandr Tymoshenko * 3. The names of the above-listed copyright holders may not be used
14262f27b2SOleksandr Tymoshenko * to endorse or promote products derived from this software without
15262f27b2SOleksandr Tymoshenko * specific prior written permission.
16262f27b2SOleksandr Tymoshenko *
17262f27b2SOleksandr Tymoshenko * ALTERNATIVELY, this software may be distributed under the terms of the
18262f27b2SOleksandr Tymoshenko * GNU General Public License ("GPL") version 2, as published by the Free
19262f27b2SOleksandr Tymoshenko * Software Foundation.
20262f27b2SOleksandr Tymoshenko *
21262f27b2SOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22262f27b2SOleksandr Tymoshenko * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23262f27b2SOleksandr Tymoshenko * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24262f27b2SOleksandr Tymoshenko * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25262f27b2SOleksandr Tymoshenko * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26262f27b2SOleksandr Tymoshenko * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27262f27b2SOleksandr Tymoshenko * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28262f27b2SOleksandr Tymoshenko * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29262f27b2SOleksandr Tymoshenko * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30262f27b2SOleksandr Tymoshenko * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31262f27b2SOleksandr Tymoshenko * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32262f27b2SOleksandr Tymoshenko */
33262f27b2SOleksandr Tymoshenko
34262f27b2SOleksandr Tymoshenko /* ---- Include Files ---------------------------------------------------- */
35262f27b2SOleksandr Tymoshenko
36262f27b2SOleksandr Tymoshenko #include "vchiq_core.h"
37262f27b2SOleksandr Tymoshenko #include "vchiq_arm.h"
38*a0b87461SOleksandr Tymoshenko #include "vchiq_killable.h"
39262f27b2SOleksandr Tymoshenko
40262f27b2SOleksandr Tymoshenko /* ---- Public Variables ------------------------------------------------- */
41262f27b2SOleksandr Tymoshenko
42262f27b2SOleksandr Tymoshenko /* ---- Private Constants and Types -------------------------------------- */
43262f27b2SOleksandr Tymoshenko
44262f27b2SOleksandr Tymoshenko struct bulk_waiter_node {
45262f27b2SOleksandr Tymoshenko struct bulk_waiter bulk_waiter;
46262f27b2SOleksandr Tymoshenko int pid;
47262f27b2SOleksandr Tymoshenko struct list_head list;
48262f27b2SOleksandr Tymoshenko };
49262f27b2SOleksandr Tymoshenko
50262f27b2SOleksandr Tymoshenko struct vchiq_instance_struct {
51262f27b2SOleksandr Tymoshenko VCHIQ_STATE_T *state;
52262f27b2SOleksandr Tymoshenko
53262f27b2SOleksandr Tymoshenko int connected;
54262f27b2SOleksandr Tymoshenko
55262f27b2SOleksandr Tymoshenko struct list_head bulk_waiter_list;
56262f27b2SOleksandr Tymoshenko struct mutex bulk_waiter_list_mutex;
57262f27b2SOleksandr Tymoshenko };
58262f27b2SOleksandr Tymoshenko
59262f27b2SOleksandr Tymoshenko static VCHIQ_STATUS_T
60262f27b2SOleksandr Tymoshenko vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
61262f27b2SOleksandr Tymoshenko unsigned int size, VCHIQ_BULK_DIR_T dir);
62262f27b2SOleksandr Tymoshenko
63262f27b2SOleksandr Tymoshenko /****************************************************************************
64262f27b2SOleksandr Tymoshenko *
65262f27b2SOleksandr Tymoshenko * vchiq_initialise
66262f27b2SOleksandr Tymoshenko *
67262f27b2SOleksandr Tymoshenko ***************************************************************************/
68262f27b2SOleksandr Tymoshenko #define VCHIQ_INIT_RETRIES 10
vchiq_initialise(VCHIQ_INSTANCE_T * instanceOut)69262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instanceOut)
70262f27b2SOleksandr Tymoshenko {
71262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T status = VCHIQ_ERROR;
72262f27b2SOleksandr Tymoshenko VCHIQ_STATE_T *state;
73262f27b2SOleksandr Tymoshenko VCHIQ_INSTANCE_T instance = NULL;
74262f27b2SOleksandr Tymoshenko int i;
75262f27b2SOleksandr Tymoshenko
76262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
77262f27b2SOleksandr Tymoshenko
78262f27b2SOleksandr Tymoshenko /* VideoCore may not be ready due to boot up timing.
79262f27b2SOleksandr Tymoshenko It may never be ready if kernel and firmware are mismatched, so don't block forever. */
80262f27b2SOleksandr Tymoshenko for (i=0; i<VCHIQ_INIT_RETRIES; i++) {
81262f27b2SOleksandr Tymoshenko state = vchiq_get_state();
82262f27b2SOleksandr Tymoshenko if (state)
83262f27b2SOleksandr Tymoshenko break;
84262f27b2SOleksandr Tymoshenko udelay(500);
85262f27b2SOleksandr Tymoshenko }
86262f27b2SOleksandr Tymoshenko if (i==VCHIQ_INIT_RETRIES) {
87262f27b2SOleksandr Tymoshenko vchiq_log_error(vchiq_core_log_level,
88262f27b2SOleksandr Tymoshenko "%s: videocore not initialized\n", __func__);
89262f27b2SOleksandr Tymoshenko goto failed;
90262f27b2SOleksandr Tymoshenko } else if (i>0) {
91262f27b2SOleksandr Tymoshenko vchiq_log_warning(vchiq_core_log_level,
92262f27b2SOleksandr Tymoshenko "%s: videocore initialized after %d retries\n", __func__, i);
93262f27b2SOleksandr Tymoshenko }
94262f27b2SOleksandr Tymoshenko
95262f27b2SOleksandr Tymoshenko instance = kzalloc(sizeof(*instance), GFP_KERNEL);
96262f27b2SOleksandr Tymoshenko if (!instance) {
97262f27b2SOleksandr Tymoshenko vchiq_log_error(vchiq_core_log_level,
98262f27b2SOleksandr Tymoshenko "%s: error allocating vchiq instance\n", __func__);
99262f27b2SOleksandr Tymoshenko goto failed;
100262f27b2SOleksandr Tymoshenko }
101262f27b2SOleksandr Tymoshenko
102262f27b2SOleksandr Tymoshenko instance->connected = 0;
103262f27b2SOleksandr Tymoshenko instance->state = state;
104262f27b2SOleksandr Tymoshenko lmutex_init(&instance->bulk_waiter_list_mutex);
105262f27b2SOleksandr Tymoshenko INIT_LIST_HEAD(&instance->bulk_waiter_list);
106262f27b2SOleksandr Tymoshenko
107262f27b2SOleksandr Tymoshenko *instanceOut = instance;
108262f27b2SOleksandr Tymoshenko
109262f27b2SOleksandr Tymoshenko status = VCHIQ_SUCCESS;
110262f27b2SOleksandr Tymoshenko
111262f27b2SOleksandr Tymoshenko failed:
112262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
113262f27b2SOleksandr Tymoshenko "%s(%p): returning %d", __func__, instance, status);
114262f27b2SOleksandr Tymoshenko
115262f27b2SOleksandr Tymoshenko return status;
116262f27b2SOleksandr Tymoshenko }
117262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_initialise);
118262f27b2SOleksandr Tymoshenko
119262f27b2SOleksandr Tymoshenko /****************************************************************************
120262f27b2SOleksandr Tymoshenko *
121262f27b2SOleksandr Tymoshenko * vchiq_shutdown
122262f27b2SOleksandr Tymoshenko *
123262f27b2SOleksandr Tymoshenko ***************************************************************************/
124262f27b2SOleksandr Tymoshenko
vchiq_shutdown(VCHIQ_INSTANCE_T instance)125262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance)
126262f27b2SOleksandr Tymoshenko {
127262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T status;
128262f27b2SOleksandr Tymoshenko VCHIQ_STATE_T *state = instance->state;
129262f27b2SOleksandr Tymoshenko
130262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
131262f27b2SOleksandr Tymoshenko "%s(%p) called", __func__, instance);
132262f27b2SOleksandr Tymoshenko
133262f27b2SOleksandr Tymoshenko if (lmutex_lock_interruptible(&state->mutex) != 0)
134262f27b2SOleksandr Tymoshenko return VCHIQ_RETRY;
135262f27b2SOleksandr Tymoshenko
136262f27b2SOleksandr Tymoshenko /* Remove all services */
137262f27b2SOleksandr Tymoshenko status = vchiq_shutdown_internal(state, instance);
138262f27b2SOleksandr Tymoshenko
139262f27b2SOleksandr Tymoshenko lmutex_unlock(&state->mutex);
140262f27b2SOleksandr Tymoshenko
141262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
142262f27b2SOleksandr Tymoshenko "%s(%p): returning %d", __func__, instance, status);
143262f27b2SOleksandr Tymoshenko
144262f27b2SOleksandr Tymoshenko if (status == VCHIQ_SUCCESS) {
145262f27b2SOleksandr Tymoshenko struct list_head *pos, *next;
146262f27b2SOleksandr Tymoshenko list_for_each_safe(pos, next,
147262f27b2SOleksandr Tymoshenko &instance->bulk_waiter_list) {
148262f27b2SOleksandr Tymoshenko struct bulk_waiter_node *waiter;
149262f27b2SOleksandr Tymoshenko waiter = list_entry(pos,
150262f27b2SOleksandr Tymoshenko struct bulk_waiter_node,
151262f27b2SOleksandr Tymoshenko list);
152262f27b2SOleksandr Tymoshenko list_del(pos);
153262f27b2SOleksandr Tymoshenko vchiq_log_info(vchiq_arm_log_level,
154262f27b2SOleksandr Tymoshenko "bulk_waiter - cleaned up %x "
155262f27b2SOleksandr Tymoshenko "for pid %d",
156262f27b2SOleksandr Tymoshenko (unsigned int)waiter, waiter->pid);
157262f27b2SOleksandr Tymoshenko _sema_destroy(&waiter->bulk_waiter.event);
158262f27b2SOleksandr Tymoshenko
159262f27b2SOleksandr Tymoshenko kfree(waiter);
160262f27b2SOleksandr Tymoshenko }
161262f27b2SOleksandr Tymoshenko
162262f27b2SOleksandr Tymoshenko lmutex_destroy(&instance->bulk_waiter_list_mutex);
163262f27b2SOleksandr Tymoshenko
164262f27b2SOleksandr Tymoshenko kfree(instance);
165262f27b2SOleksandr Tymoshenko }
166262f27b2SOleksandr Tymoshenko
167262f27b2SOleksandr Tymoshenko return status;
168262f27b2SOleksandr Tymoshenko }
169262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_shutdown);
170262f27b2SOleksandr Tymoshenko
171262f27b2SOleksandr Tymoshenko /****************************************************************************
172262f27b2SOleksandr Tymoshenko *
173262f27b2SOleksandr Tymoshenko * vchiq_is_connected
174262f27b2SOleksandr Tymoshenko *
175262f27b2SOleksandr Tymoshenko ***************************************************************************/
176262f27b2SOleksandr Tymoshenko
vchiq_is_connected(VCHIQ_INSTANCE_T instance)177262f27b2SOleksandr Tymoshenko static int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
178262f27b2SOleksandr Tymoshenko {
179262f27b2SOleksandr Tymoshenko return instance->connected;
180262f27b2SOleksandr Tymoshenko }
181262f27b2SOleksandr Tymoshenko
182262f27b2SOleksandr Tymoshenko /****************************************************************************
183262f27b2SOleksandr Tymoshenko *
184262f27b2SOleksandr Tymoshenko * vchiq_connect
185262f27b2SOleksandr Tymoshenko *
186262f27b2SOleksandr Tymoshenko ***************************************************************************/
187262f27b2SOleksandr Tymoshenko
vchiq_connect(VCHIQ_INSTANCE_T instance)188262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance)
189262f27b2SOleksandr Tymoshenko {
190262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T status;
191262f27b2SOleksandr Tymoshenko VCHIQ_STATE_T *state = instance->state;
192262f27b2SOleksandr Tymoshenko
193262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
194262f27b2SOleksandr Tymoshenko "%s(%p) called", __func__, instance);
195262f27b2SOleksandr Tymoshenko
196262f27b2SOleksandr Tymoshenko if (lmutex_lock_interruptible(&state->mutex) != 0) {
197262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
198262f27b2SOleksandr Tymoshenko "%s: call to lmutex_lock failed", __func__);
199262f27b2SOleksandr Tymoshenko status = VCHIQ_RETRY;
200262f27b2SOleksandr Tymoshenko goto failed;
201262f27b2SOleksandr Tymoshenko }
202262f27b2SOleksandr Tymoshenko status = vchiq_connect_internal(state, instance);
203262f27b2SOleksandr Tymoshenko
204262f27b2SOleksandr Tymoshenko if (status == VCHIQ_SUCCESS)
205262f27b2SOleksandr Tymoshenko instance->connected = 1;
206262f27b2SOleksandr Tymoshenko
207262f27b2SOleksandr Tymoshenko lmutex_unlock(&state->mutex);
208262f27b2SOleksandr Tymoshenko
209262f27b2SOleksandr Tymoshenko failed:
210262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
211262f27b2SOleksandr Tymoshenko "%s(%p): returning %d", __func__, instance, status);
212262f27b2SOleksandr Tymoshenko
213262f27b2SOleksandr Tymoshenko return status;
214262f27b2SOleksandr Tymoshenko }
215262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_connect);
216262f27b2SOleksandr Tymoshenko
217262f27b2SOleksandr Tymoshenko /****************************************************************************
218262f27b2SOleksandr Tymoshenko *
219262f27b2SOleksandr Tymoshenko * vchiq_add_service
220262f27b2SOleksandr Tymoshenko *
221262f27b2SOleksandr Tymoshenko ***************************************************************************/
222262f27b2SOleksandr Tymoshenko
vchiq_add_service(VCHIQ_INSTANCE_T instance,const VCHIQ_SERVICE_PARAMS_T * params,VCHIQ_SERVICE_HANDLE_T * phandle)223262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T vchiq_add_service(
224262f27b2SOleksandr Tymoshenko VCHIQ_INSTANCE_T instance,
225262f27b2SOleksandr Tymoshenko const VCHIQ_SERVICE_PARAMS_T *params,
226262f27b2SOleksandr Tymoshenko VCHIQ_SERVICE_HANDLE_T *phandle)
227262f27b2SOleksandr Tymoshenko {
228262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T status;
229262f27b2SOleksandr Tymoshenko VCHIQ_STATE_T *state = instance->state;
230262f27b2SOleksandr Tymoshenko VCHIQ_SERVICE_T *service = NULL;
231262f27b2SOleksandr Tymoshenko int srvstate;
232262f27b2SOleksandr Tymoshenko
233262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
234262f27b2SOleksandr Tymoshenko "%s(%p) called", __func__, instance);
235262f27b2SOleksandr Tymoshenko
236262f27b2SOleksandr Tymoshenko *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
237262f27b2SOleksandr Tymoshenko
238262f27b2SOleksandr Tymoshenko srvstate = vchiq_is_connected(instance)
239262f27b2SOleksandr Tymoshenko ? VCHIQ_SRVSTATE_LISTENING
240262f27b2SOleksandr Tymoshenko : VCHIQ_SRVSTATE_HIDDEN;
241262f27b2SOleksandr Tymoshenko
242262f27b2SOleksandr Tymoshenko service = vchiq_add_service_internal(
243262f27b2SOleksandr Tymoshenko state,
244262f27b2SOleksandr Tymoshenko params,
245262f27b2SOleksandr Tymoshenko srvstate,
246262f27b2SOleksandr Tymoshenko instance,
247262f27b2SOleksandr Tymoshenko NULL);
248262f27b2SOleksandr Tymoshenko
249262f27b2SOleksandr Tymoshenko if (service) {
250262f27b2SOleksandr Tymoshenko *phandle = service->handle;
251262f27b2SOleksandr Tymoshenko status = VCHIQ_SUCCESS;
252262f27b2SOleksandr Tymoshenko } else
253262f27b2SOleksandr Tymoshenko status = VCHIQ_ERROR;
254262f27b2SOleksandr Tymoshenko
255262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
256262f27b2SOleksandr Tymoshenko "%s(%p): returning %d", __func__, instance, status);
257262f27b2SOleksandr Tymoshenko
258262f27b2SOleksandr Tymoshenko return status;
259262f27b2SOleksandr Tymoshenko }
260262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_add_service);
261262f27b2SOleksandr Tymoshenko
262262f27b2SOleksandr Tymoshenko /****************************************************************************
263262f27b2SOleksandr Tymoshenko *
264262f27b2SOleksandr Tymoshenko * vchiq_open_service
265262f27b2SOleksandr Tymoshenko *
266262f27b2SOleksandr Tymoshenko ***************************************************************************/
267262f27b2SOleksandr Tymoshenko
vchiq_open_service(VCHIQ_INSTANCE_T instance,const VCHIQ_SERVICE_PARAMS_T * params,VCHIQ_SERVICE_HANDLE_T * phandle)268262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T vchiq_open_service(
269262f27b2SOleksandr Tymoshenko VCHIQ_INSTANCE_T instance,
270262f27b2SOleksandr Tymoshenko const VCHIQ_SERVICE_PARAMS_T *params,
271262f27b2SOleksandr Tymoshenko VCHIQ_SERVICE_HANDLE_T *phandle)
272262f27b2SOleksandr Tymoshenko {
273262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T status = VCHIQ_ERROR;
274262f27b2SOleksandr Tymoshenko VCHIQ_STATE_T *state = instance->state;
275262f27b2SOleksandr Tymoshenko VCHIQ_SERVICE_T *service = NULL;
276262f27b2SOleksandr Tymoshenko
277262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
278262f27b2SOleksandr Tymoshenko "%s(%p) called", __func__, instance);
279262f27b2SOleksandr Tymoshenko
280262f27b2SOleksandr Tymoshenko *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
281262f27b2SOleksandr Tymoshenko
282262f27b2SOleksandr Tymoshenko if (!vchiq_is_connected(instance))
283262f27b2SOleksandr Tymoshenko goto failed;
284262f27b2SOleksandr Tymoshenko
285262f27b2SOleksandr Tymoshenko service = vchiq_add_service_internal(state,
286262f27b2SOleksandr Tymoshenko params,
287262f27b2SOleksandr Tymoshenko VCHIQ_SRVSTATE_OPENING,
288262f27b2SOleksandr Tymoshenko instance,
289262f27b2SOleksandr Tymoshenko NULL);
290262f27b2SOleksandr Tymoshenko
291262f27b2SOleksandr Tymoshenko if (service) {
292262f27b2SOleksandr Tymoshenko *phandle = service->handle;
293262f27b2SOleksandr Tymoshenko status = vchiq_open_service_internal(service,
294262f27b2SOleksandr Tymoshenko (uintptr_t)current);
295262f27b2SOleksandr Tymoshenko if (status != VCHIQ_SUCCESS) {
296262f27b2SOleksandr Tymoshenko vchiq_remove_service(service->handle);
297262f27b2SOleksandr Tymoshenko *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
298262f27b2SOleksandr Tymoshenko }
299262f27b2SOleksandr Tymoshenko }
300262f27b2SOleksandr Tymoshenko
301262f27b2SOleksandr Tymoshenko failed:
302262f27b2SOleksandr Tymoshenko vchiq_log_trace(vchiq_core_log_level,
303262f27b2SOleksandr Tymoshenko "%s(%p): returning %d", __func__, instance, status);
304262f27b2SOleksandr Tymoshenko
305262f27b2SOleksandr Tymoshenko return status;
306262f27b2SOleksandr Tymoshenko }
307262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_open_service);
308262f27b2SOleksandr Tymoshenko
309262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T
vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,void * data,unsigned int size,void * userdata)310262f27b2SOleksandr Tymoshenko vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
311262f27b2SOleksandr Tymoshenko void *data, unsigned int size, void *userdata)
312262f27b2SOleksandr Tymoshenko {
313262f27b2SOleksandr Tymoshenko return vchiq_bulk_transfer(handle,
314262f27b2SOleksandr Tymoshenko VCHI_MEM_HANDLE_INVALID, data, size, userdata,
315262f27b2SOleksandr Tymoshenko VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_TRANSMIT);
316262f27b2SOleksandr Tymoshenko }
317262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_queue_bulk_transmit);
318262f27b2SOleksandr Tymoshenko
319262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T
vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,void * data,unsigned int size,void * userdata)320262f27b2SOleksandr Tymoshenko vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
321262f27b2SOleksandr Tymoshenko unsigned int size, void *userdata)
322262f27b2SOleksandr Tymoshenko {
323262f27b2SOleksandr Tymoshenko return vchiq_bulk_transfer(handle,
324262f27b2SOleksandr Tymoshenko VCHI_MEM_HANDLE_INVALID, data, size, userdata,
325262f27b2SOleksandr Tymoshenko VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_RECEIVE);
326262f27b2SOleksandr Tymoshenko }
327262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_queue_bulk_receive);
328262f27b2SOleksandr Tymoshenko
329262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T
vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,void * data,unsigned int size,void * userdata,VCHIQ_BULK_MODE_T mode)330262f27b2SOleksandr Tymoshenko vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, void *data,
331262f27b2SOleksandr Tymoshenko unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
332262f27b2SOleksandr Tymoshenko {
333262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T status;
334262f27b2SOleksandr Tymoshenko
335262f27b2SOleksandr Tymoshenko switch (mode) {
336262f27b2SOleksandr Tymoshenko case VCHIQ_BULK_MODE_NOCALLBACK:
337262f27b2SOleksandr Tymoshenko case VCHIQ_BULK_MODE_CALLBACK:
338262f27b2SOleksandr Tymoshenko status = vchiq_bulk_transfer(handle,
339262f27b2SOleksandr Tymoshenko VCHI_MEM_HANDLE_INVALID, data, size, userdata,
340262f27b2SOleksandr Tymoshenko mode, VCHIQ_BULK_TRANSMIT);
341262f27b2SOleksandr Tymoshenko break;
342262f27b2SOleksandr Tymoshenko case VCHIQ_BULK_MODE_BLOCKING:
343262f27b2SOleksandr Tymoshenko status = vchiq_blocking_bulk_transfer(handle,
344262f27b2SOleksandr Tymoshenko data, size, VCHIQ_BULK_TRANSMIT);
345262f27b2SOleksandr Tymoshenko break;
346262f27b2SOleksandr Tymoshenko default:
347262f27b2SOleksandr Tymoshenko return VCHIQ_ERROR;
348262f27b2SOleksandr Tymoshenko }
349262f27b2SOleksandr Tymoshenko
350262f27b2SOleksandr Tymoshenko return status;
351262f27b2SOleksandr Tymoshenko }
352262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_bulk_transmit);
353262f27b2SOleksandr Tymoshenko
354262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T
vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,void * data,unsigned int size,void * userdata,VCHIQ_BULK_MODE_T mode)355262f27b2SOleksandr Tymoshenko vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data,
356262f27b2SOleksandr Tymoshenko unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode)
357262f27b2SOleksandr Tymoshenko {
358262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T status;
359262f27b2SOleksandr Tymoshenko
360262f27b2SOleksandr Tymoshenko switch (mode) {
361262f27b2SOleksandr Tymoshenko case VCHIQ_BULK_MODE_NOCALLBACK:
362262f27b2SOleksandr Tymoshenko case VCHIQ_BULK_MODE_CALLBACK:
363262f27b2SOleksandr Tymoshenko status = vchiq_bulk_transfer(handle,
364262f27b2SOleksandr Tymoshenko VCHI_MEM_HANDLE_INVALID, data, size, userdata,
365262f27b2SOleksandr Tymoshenko mode, VCHIQ_BULK_RECEIVE);
366262f27b2SOleksandr Tymoshenko break;
367262f27b2SOleksandr Tymoshenko case VCHIQ_BULK_MODE_BLOCKING:
368262f27b2SOleksandr Tymoshenko status = vchiq_blocking_bulk_transfer(handle,
369262f27b2SOleksandr Tymoshenko data, size, VCHIQ_BULK_RECEIVE);
370262f27b2SOleksandr Tymoshenko break;
371262f27b2SOleksandr Tymoshenko default:
372262f27b2SOleksandr Tymoshenko return VCHIQ_ERROR;
373262f27b2SOleksandr Tymoshenko }
374262f27b2SOleksandr Tymoshenko
375262f27b2SOleksandr Tymoshenko return status;
376262f27b2SOleksandr Tymoshenko }
377262f27b2SOleksandr Tymoshenko EXPORT_SYMBOL(vchiq_bulk_receive);
378262f27b2SOleksandr Tymoshenko
379262f27b2SOleksandr Tymoshenko static VCHIQ_STATUS_T
vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,void * data,unsigned int size,VCHIQ_BULK_DIR_T dir)380262f27b2SOleksandr Tymoshenko vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data,
381262f27b2SOleksandr Tymoshenko unsigned int size, VCHIQ_BULK_DIR_T dir)
382262f27b2SOleksandr Tymoshenko {
383262f27b2SOleksandr Tymoshenko VCHIQ_INSTANCE_T instance;
384262f27b2SOleksandr Tymoshenko VCHIQ_SERVICE_T *service;
385262f27b2SOleksandr Tymoshenko VCHIQ_STATUS_T status;
386262f27b2SOleksandr Tymoshenko struct bulk_waiter_node *waiter = NULL;
387262f27b2SOleksandr Tymoshenko struct list_head *pos;
388262f27b2SOleksandr Tymoshenko
389262f27b2SOleksandr Tymoshenko service = find_service_by_handle(handle);
390262f27b2SOleksandr Tymoshenko if (!service)
391262f27b2SOleksandr Tymoshenko return VCHIQ_ERROR;
392262f27b2SOleksandr Tymoshenko
393262f27b2SOleksandr Tymoshenko instance = service->instance;
394262f27b2SOleksandr Tymoshenko
395262f27b2SOleksandr Tymoshenko unlock_service(service);
396262f27b2SOleksandr Tymoshenko
397262f27b2SOleksandr Tymoshenko lmutex_lock(&instance->bulk_waiter_list_mutex);
398262f27b2SOleksandr Tymoshenko list_for_each(pos, &instance->bulk_waiter_list) {
399262f27b2SOleksandr Tymoshenko if (list_entry(pos, struct bulk_waiter_node,
400262f27b2SOleksandr Tymoshenko list)->pid == current->p_pid) {
401262f27b2SOleksandr Tymoshenko waiter = list_entry(pos,
402262f27b2SOleksandr Tymoshenko struct bulk_waiter_node,
403262f27b2SOleksandr Tymoshenko list);
404262f27b2SOleksandr Tymoshenko list_del(pos);
405262f27b2SOleksandr Tymoshenko break;
406262f27b2SOleksandr Tymoshenko }
407262f27b2SOleksandr Tymoshenko }
408262f27b2SOleksandr Tymoshenko lmutex_unlock(&instance->bulk_waiter_list_mutex);
409262f27b2SOleksandr Tymoshenko
410262f27b2SOleksandr Tymoshenko if (waiter) {
411262f27b2SOleksandr Tymoshenko VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
412262f27b2SOleksandr Tymoshenko if (bulk) {
413262f27b2SOleksandr Tymoshenko /* This thread has an outstanding bulk transfer. */
414262f27b2SOleksandr Tymoshenko if ((bulk->data != data) ||
415262f27b2SOleksandr Tymoshenko (bulk->size != size)) {
416262f27b2SOleksandr Tymoshenko /* This is not a retry of the previous one.
417262f27b2SOleksandr Tymoshenko ** Cancel the signal when the transfer
418262f27b2SOleksandr Tymoshenko ** completes. */
419262f27b2SOleksandr Tymoshenko spin_lock(&bulk_waiter_spinlock);
420262f27b2SOleksandr Tymoshenko bulk->userdata = NULL;
421262f27b2SOleksandr Tymoshenko spin_unlock(&bulk_waiter_spinlock);
422262f27b2SOleksandr Tymoshenko }
423262f27b2SOleksandr Tymoshenko }
424262f27b2SOleksandr Tymoshenko }
425262f27b2SOleksandr Tymoshenko
426262f27b2SOleksandr Tymoshenko if (!waiter) {
427262f27b2SOleksandr Tymoshenko waiter = kzalloc(sizeof(struct bulk_waiter_node), GFP_KERNEL);
428262f27b2SOleksandr Tymoshenko if (!waiter) {
429262f27b2SOleksandr Tymoshenko vchiq_log_error(vchiq_core_log_level,
430262f27b2SOleksandr Tymoshenko "%s - out of memory", __func__);
431262f27b2SOleksandr Tymoshenko return VCHIQ_ERROR;
432262f27b2SOleksandr Tymoshenko }
433262f27b2SOleksandr Tymoshenko }
434262f27b2SOleksandr Tymoshenko
435262f27b2SOleksandr Tymoshenko status = vchiq_bulk_transfer(handle, VCHI_MEM_HANDLE_INVALID,
436262f27b2SOleksandr Tymoshenko data, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING,
437262f27b2SOleksandr Tymoshenko dir);
438262f27b2SOleksandr Tymoshenko if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) ||
439262f27b2SOleksandr Tymoshenko !waiter->bulk_waiter.bulk) {
440262f27b2SOleksandr Tymoshenko VCHIQ_BULK_T *bulk = waiter->bulk_waiter.bulk;
441262f27b2SOleksandr Tymoshenko if (bulk) {
442262f27b2SOleksandr Tymoshenko /* Cancel the signal when the transfer
443262f27b2SOleksandr Tymoshenko ** completes. */
444262f27b2SOleksandr Tymoshenko spin_lock(&bulk_waiter_spinlock);
445262f27b2SOleksandr Tymoshenko bulk->userdata = NULL;
446262f27b2SOleksandr Tymoshenko spin_unlock(&bulk_waiter_spinlock);
447262f27b2SOleksandr Tymoshenko }
448262f27b2SOleksandr Tymoshenko _sema_destroy(&waiter->bulk_waiter.event);
449262f27b2SOleksandr Tymoshenko
450262f27b2SOleksandr Tymoshenko kfree(waiter);
451262f27b2SOleksandr Tymoshenko } else {
452262f27b2SOleksandr Tymoshenko waiter->pid = current->p_pid;
453262f27b2SOleksandr Tymoshenko lmutex_lock(&instance->bulk_waiter_list_mutex);
454262f27b2SOleksandr Tymoshenko list_add(&waiter->list, &instance->bulk_waiter_list);
455262f27b2SOleksandr Tymoshenko lmutex_unlock(&instance->bulk_waiter_list_mutex);
456262f27b2SOleksandr Tymoshenko vchiq_log_info(vchiq_arm_log_level,
457262f27b2SOleksandr Tymoshenko "saved bulk_waiter %x for pid %d",
458262f27b2SOleksandr Tymoshenko (unsigned int)waiter, current->p_pid);
459262f27b2SOleksandr Tymoshenko }
460262f27b2SOleksandr Tymoshenko
461262f27b2SOleksandr Tymoshenko return status;
462262f27b2SOleksandr Tymoshenko }
463