xref: /freebsd-src/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c (revision b626f5a73a48f44a31a200291b141e1da408a2ff)
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