staging: vchi: Use struct vchiq_service_params
[linux-2.6-microblaze.git] / drivers / staging / vc04_services / interface / vchiq_arm / vchiq_shim.c
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */
3 #include <linux/module.h>
4 #include <linux/types.h>
5 #include <linux/slab.h>
6 #include <linux/delay.h>
7
8 #include "vchiq_if.h"
9 #include "../vchi/vchi.h"
10 #include "vchiq.h"
11 #include "vchiq_core.h"
12
13 int vchi_queue_kernel_message(struct vchi_service *service, void *data,
14                               unsigned int size)
15 {
16         enum vchiq_status status;
17
18         while (1) {
19                 status = vchiq_queue_kernel_message(service->handle, data,
20                                                     size);
21
22                 /*
23                  * vchiq_queue_message() may return VCHIQ_RETRY, so we need to
24                  * implement a retry mechanism since this function is supposed
25                  * to block until queued
26                  */
27                 if (status != VCHIQ_RETRY)
28                         break;
29
30                 msleep(1);
31         }
32
33         return status;
34 }
35 EXPORT_SYMBOL(vchi_queue_kernel_message);
36
37 /***********************************************************
38  * Name: vchi_bulk_queue_receive
39  *
40  * Arguments:  VCHI_BULK_HANDLE_T handle,
41  *             void *data_dst,
42  *             const uint32_t data_size,
43  *             enum vchi_flags flags
44  *             void *bulk_handle
45  *
46  * Description: Routine to setup a rcv buffer
47  *
48  * Returns: int32_t - success == 0
49  *
50  ***********************************************************/
51 int32_t vchi_bulk_queue_receive(struct vchi_service *service, void *data_dst,
52                                 uint32_t data_size, enum vchiq_bulk_mode mode,
53                                 void *bulk_handle)
54 {
55         enum vchiq_status status;
56
57         while (1) {
58                 status = vchiq_bulk_receive(service->handle, data_dst,
59                         data_size, bulk_handle, mode);
60                 /*
61                  * vchiq_bulk_receive() may return VCHIQ_RETRY, so we need to
62                  * implement a retry mechanism since this function is supposed
63                  * to block until queued
64                  */
65                 if (status != VCHIQ_RETRY)
66                         break;
67
68                 msleep(1);
69         }
70
71         return status;
72 }
73 EXPORT_SYMBOL(vchi_bulk_queue_receive);
74
75 /***********************************************************
76  * Name: vchi_bulk_queue_transmit
77  *
78  * Arguments:  VCHI_BULK_HANDLE_T handle,
79  *             const void *data_src,
80  *             uint32_t data_size,
81  *             enum vchi_flags flags,
82  *             void *bulk_handle
83  *
84  * Description: Routine to transmit some data
85  *
86  * Returns: int32_t - success == 0
87  *
88  ***********************************************************/
89 int32_t vchi_bulk_queue_transmit(struct vchi_service *service,
90                                  const void *data_src,
91                                  uint32_t data_size,
92                                  enum vchiq_bulk_mode mode,
93                                  void *bulk_handle)
94 {
95         enum vchiq_status status;
96
97         while (1) {
98                 status = vchiq_bulk_transmit(service->handle, data_src,
99                         data_size, bulk_handle, mode);
100
101                 /*
102                  * vchiq_bulk_transmit() may return VCHIQ_RETRY, so we need to
103                  * implement a retry mechanism since this function is supposed
104                  * to block until queued
105                  */
106                 if (status != VCHIQ_RETRY)
107                         break;
108
109                 msleep(1);
110         }
111
112         return status;
113 }
114 EXPORT_SYMBOL(vchi_bulk_queue_transmit);
115
116
117 /***********************************************************
118  * Name: vchi_held_msg_release
119  *
120  * Arguments:  struct vchi_held_msg *message
121  *
122  * Description: Routine to release a held message (after it has been read with
123  *              vchi_msg_hold)
124  *
125  * Returns: int32_t - success == 0
126  *
127  ***********************************************************/
128 int32_t vchi_held_msg_release(struct vchi_held_msg *message)
129 {
130         /*
131          * Convert the service field pointer back to an
132          * unsigned int which is an int.
133          * This pointer is opaque to everything except
134          * vchi_msg_hold which simply upcasted the int
135          * to a pointer.
136          */
137
138         vchiq_release_message((unsigned int)(long)message->service,
139                               (struct vchiq_header *)message->message);
140
141         return 0;
142 }
143 EXPORT_SYMBOL(vchi_held_msg_release);
144
145 /***********************************************************
146  * Name: vchi_msg_hold
147  *
148  * Arguments:  struct vchi_service *service,
149  *             void **data,
150  *             uint32_t *msg_size,
151  *             struct vchi_held_msg *message_handle
152  *
153  * Description: Routine to return a pointer to the current message (to allow
154  *              in place processing). The message is dequeued - don't forget
155  *              to release the message using vchi_held_msg_release when you're
156  *              finished.
157  *
158  * Returns: int32_t - success == 0
159  *
160  ***********************************************************/
161 int32_t vchi_msg_hold(unsigned handle, void **data, uint32_t *msg_size,
162                       struct vchi_held_msg *message_handle)
163 {
164         struct vchiq_header *header;
165
166         header = vchiq_msg_hold(handle);
167         if (!header)
168                 return -ENOENT;
169
170         *data = header->data;
171         *msg_size = header->size;
172
173         /*
174          * upcast the unsigned int which is an int
175          * to a pointer and stuff it in the held message.
176          * This pointer is opaque to everything except
177          * vchi_held_msg_release which simply downcasts it back
178          * to an int.
179          */
180
181         message_handle->service =
182                 (struct opaque_vchi_service_t *)(long)handle;
183         message_handle->message = header;
184
185         return 0;
186 }
187 EXPORT_SYMBOL(vchi_msg_hold);
188
189 /***********************************************************
190  * Name: vchi_initialise
191  *
192  * Arguments: struct vchiq_instance **instance
193  *
194  * Description: Initialises the hardware but does not transmit anything
195  *              When run as a Host App this will be called twice hence the need
196  *              to malloc the state information
197  *
198  * Returns: 0 if successful, failure otherwise
199  *
200  ***********************************************************/
201
202 int32_t vchi_initialise(struct vchiq_instance **instance)
203 {
204         return vchiq_initialise(instance);
205 }
206 EXPORT_SYMBOL(vchi_initialise);
207
208 /***********************************************************
209  * Name: vchi_connect
210  *
211  * Arguments: struct vchiq_instance *instance
212  *
213  * Description: Starts the command service on each connection,
214  *              causing INIT messages to be pinged back and forth
215  *
216  * Returns: 0 if successful, failure otherwise
217  *
218  ***********************************************************/
219 int32_t vchi_connect(struct vchiq_instance *instance)
220 {
221         return vchiq_connect(instance);
222 }
223 EXPORT_SYMBOL(vchi_connect);
224
225 /***********************************************************
226  * Name: vchi_disconnect
227  *
228  * Arguments: struct vchiq_instance *instance
229  *
230  * Description: Stops the command service on each connection,
231  *              causing DE-INIT messages to be pinged back and forth
232  *
233  * Returns: 0 if successful, failure otherwise
234  *
235  ***********************************************************/
236 int32_t vchi_disconnect(struct vchiq_instance *instance)
237 {
238         return vchiq_shutdown(instance);
239 }
240 EXPORT_SYMBOL(vchi_disconnect);
241
242 /***********************************************************
243  * Name: vchi_service_open
244  * Name: vchi_service_create
245  *
246  * Arguments: struct vchiq_instance *instance
247  *            struct service_creation *setup,
248  *            struct vchi_service **service
249  *
250  * Description: Routine to open a service
251  *
252  * Returns: int32_t - success == 0
253  *
254  ***********************************************************/
255
256 static struct vchi_service *service_alloc(void)
257 {
258         return kzalloc(sizeof(struct vchi_service), GFP_KERNEL);
259 }
260
261 static void service_free(struct vchi_service *service)
262 {
263         if (service)
264                 kfree(service);
265 }
266
267 int32_t vchi_service_open(struct vchiq_instance *instance,
268         struct vchiq_service_params *params,
269         struct vchi_service **service)
270 {
271
272         *service = service_alloc();
273         if (*service) {
274                 enum vchiq_status status;
275
276                 status = vchiq_open_service(instance, params,
277                         &((*service)->handle));
278                 if (status != VCHIQ_SUCCESS) {
279                         service_free(*service);
280                         *service = NULL;
281                 }
282         }
283
284         return *service ? 0 : -1;
285 }
286 EXPORT_SYMBOL(vchi_service_open);
287
288 int32_t vchi_service_close(struct vchi_service *service)
289 {
290         int32_t ret = -1;
291
292         if (service) {
293                 enum vchiq_status status = vchiq_close_service(service->handle);
294                 if (status == VCHIQ_SUCCESS)
295                         service_free(service);
296
297                 ret = status;
298         }
299         return ret;
300 }
301 EXPORT_SYMBOL(vchi_service_close);
302
303 int32_t vchi_get_peer_version(struct vchi_service *service, short *peer_version)
304 {
305         int32_t ret = -1;
306
307         if (service) {
308                 enum vchiq_status status;
309
310                 status = vchiq_get_peer_version(service->handle, peer_version);
311                 ret = status;
312         }
313         return ret;
314 }
315 EXPORT_SYMBOL(vchi_get_peer_version);
316
317 /***********************************************************
318  * Name: vchi_service_use
319  *
320  * Arguments: struct vchi_service *service
321  *
322  * Description: Routine to increment refcount on a service
323  *
324  * Returns: void
325  *
326  ***********************************************************/
327 int32_t vchi_service_use(struct vchi_service *service)
328 {
329         int32_t ret = -1;
330
331         if (service)
332                 ret = vchiq_use_service(service->handle);
333         return ret;
334 }
335 EXPORT_SYMBOL(vchi_service_use);
336
337 /***********************************************************
338  * Name: vchi_service_release
339  *
340  * Arguments: struct vchi_service *service
341  *
342  * Description: Routine to decrement refcount on a service
343  *
344  * Returns: void
345  *
346  ***********************************************************/
347 int32_t vchi_service_release(struct vchi_service *service)
348 {
349         int32_t ret = -1;
350
351         if (service)
352                 ret = vchiq_release_service(service->handle);
353         return ret;
354 }
355 EXPORT_SYMBOL(vchi_service_release);