37ebd8b673286e794b3b0a1102911224f82df48d
[openwrt/staging/ldir.git] /
1 From 43f89ac74f3f221e3036a1ec311b24016860d15e Mon Sep 17 00:00:00 2001
2 From: Takashi Iwai <tiwai@suse.de>
3 Date: Tue, 4 Sep 2018 17:58:48 +0200
4 Subject: [PATCH] staging: bcm2835-audio: Code refactoring of vchiq
5 accessor codes
6
7 commit 769a8e9bf5cf39813f52962fdafdf7e4d52ad585 upstream.
8
9 This is a cleanup and code refactoring in bcm2835-vchiq.c.
10
11 The major code changes are to provide local helpers for easier use of
12 lock / unlock, and message passing with/without response wait. This
13 allows us to reduce lots of open codes.
14
15 Also, the max packet is set at opening the stream, not at each time
16 when the write gets called.
17
18 Signed-off-by: Takashi Iwai <tiwai@suse.de>
19 Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
20 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
21 ---
22 .../bcm2835-audio/bcm2835-vchiq.c | 440 ++++++------------
23 1 file changed, 142 insertions(+), 298 deletions(-)
24
25 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
26 +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
27 @@ -49,6 +49,7 @@ struct bcm2835_audio_instance {
28 struct mutex vchi_mutex;
29 struct bcm2835_alsa_stream *alsa_stream;
30 int result;
31 + unsigned int max_packet;
32 short peer_version;
33 };
34
35 @@ -65,16 +66,68 @@ static int bcm2835_audio_start_worker(st
36 static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
37 unsigned int count, void *src);
38
39 -// Routine to send a message across a service
40 +static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
41 +{
42 + mutex_lock(&instance->vchi_mutex);
43 + vchi_service_use(instance->vchi_handle);
44 +}
45 +
46 +static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
47 +{
48 + vchi_service_release(instance->vchi_handle);
49 + mutex_unlock(&instance->vchi_mutex);
50 +}
51 +
52 +static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
53 + struct vc_audio_msg *m, bool wait)
54 +{
55 + int status;
56 +
57 + if (wait) {
58 + instance->result = -1;
59 + init_completion(&instance->msg_avail_comp);
60 + }
61 +
62 + status = vchi_queue_kernel_message(instance->vchi_handle,
63 + m, sizeof(*m));
64 + if (status) {
65 + LOG_ERR("vchi message queue failed: %d, msg=%d\n",
66 + status, m->type);
67 + return -EIO;
68 + }
69 +
70 + if (wait) {
71 + if (!wait_for_completion_timeout(&instance->msg_avail_comp,
72 + msecs_to_jiffies(10 * 1000))) {
73 + LOG_ERR("vchi message timeout, msg=%d\n", m->type);
74 + return -ETIMEDOUT;
75 + } else if (instance->result) {
76 + LOG_ERR("vchi message response error:%d, msg=%d\n",
77 + instance->result, m->type);
78 + return -EIO;
79 + }
80 + }
81 +
82 + return 0;
83 +}
84
85 -static int
86 -bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
87 - void *data,
88 - unsigned int size)
89 -{
90 - return vchi_queue_kernel_message(handle,
91 - data,
92 - size);
93 +static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
94 + struct vc_audio_msg *m, bool wait)
95 +{
96 + int err;
97 +
98 + bcm2835_audio_lock(instance);
99 + err = bcm2835_audio_send_msg_locked(instance, m, wait);
100 + bcm2835_audio_unlock(instance);
101 + return err;
102 +}
103 +
104 +static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
105 + int type, bool wait)
106 +{
107 + struct vc_audio_msg m = { .type = type };
108 +
109 + return bcm2835_audio_send_msg(instance, &m, wait);
110 }
111
112 static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
113 @@ -283,10 +336,9 @@ static int vc_vchi_audio_deinit(struct b
114 int status;
115
116 mutex_lock(&instance->vchi_mutex);
117 -
118 - /* Close all VCHI service connections */
119 vchi_service_use(instance->vchi_handle);
120
121 + /* Close all VCHI service connections */
122 status = vchi_service_close(instance->vchi_handle);
123 if (status) {
124 LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
125 @@ -345,12 +397,8 @@ static int bcm2835_audio_open_connection
126 instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
127 vhci_ctx->vchi_connection);
128
129 - if (IS_ERR(instance)) {
130 - LOG_ERR("%s: failed to initialize audio service\n", __func__);
131 -
132 - /* vchi_instance is retained for use the next time. */
133 + if (IS_ERR(instance))
134 return PTR_ERR(instance);
135 - }
136
137 instance->alsa_stream = alsa_stream;
138 alsa_stream->instance = instance;
139 @@ -361,66 +409,44 @@ static int bcm2835_audio_open_connection
140 int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
141 {
142 struct bcm2835_audio_instance *instance;
143 - struct vc_audio_msg m;
144 - int status;
145 - int ret;
146 + int err;
147
148 alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
149 if (!alsa_stream->my_wq)
150 return -ENOMEM;
151
152 - ret = bcm2835_audio_open_connection(alsa_stream);
153 - if (ret)
154 + err = bcm2835_audio_open_connection(alsa_stream);
155 + if (err < 0)
156 goto free_wq;
157
158 instance = alsa_stream->instance;
159 - LOG_DBG(" instance (%p)\n", instance);
160 -
161 - mutex_lock(&instance->vchi_mutex);
162 - vchi_service_use(instance->vchi_handle);
163 -
164 - m.type = VC_AUDIO_MSG_TYPE_OPEN;
165 -
166 - /* Send the message to the videocore */
167 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
168 - &m, sizeof(m));
169 -
170 - if (status) {
171 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
172 - __func__, status);
173 -
174 - ret = -1;
175 - goto unlock;
176 - }
177 -
178 - ret = 0;
179
180 -unlock:
181 - vchi_service_release(instance->vchi_handle);
182 - mutex_unlock(&instance->vchi_mutex);
183 + err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
184 + false);
185 + if (err < 0)
186 + goto deinit;
187 +
188 + bcm2835_audio_lock(instance);
189 + vchi_get_peer_version(instance->vchi_handle, &instance->peer_version);
190 + bcm2835_audio_unlock(instance);
191 + if (instance->peer_version < 2 || force_bulk)
192 + instance->max_packet = 0; /* bulk transfer */
193 + else
194 + instance->max_packet = 4000;
195
196 -free_wq:
197 - if (ret)
198 - destroy_workqueue(alsa_stream->my_wq);
199 + return 0;
200
201 - return ret;
202 + deinit:
203 + vc_vchi_audio_deinit(instance);
204 + free_wq:
205 + destroy_workqueue(alsa_stream->my_wq);
206 + return err;
207 }
208
209 int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
210 {
211 - struct vc_audio_msg m;
212 - struct bcm2835_audio_instance *instance = alsa_stream->instance;
213 struct bcm2835_chip *chip = alsa_stream->chip;
214 - int status;
215 - int ret;
216 -
217 - LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
218 - chip->dest, chip->volume);
219 -
220 - mutex_lock(&instance->vchi_mutex);
221 - vchi_service_use(instance->vchi_handle);
222 -
223 - instance->result = -1;
224 + struct vc_audio_msg m = {};
225
226 m.type = VC_AUDIO_MSG_TYPE_CONTROL;
227 m.u.control.dest = chip->dest;
228 @@ -429,289 +455,107 @@ int bcm2835_audio_set_ctls(struct bcm283
229 else
230 m.u.control.volume = alsa2chip(chip->volume);
231
232 - /* Create the message available completion */
233 - init_completion(&instance->msg_avail_comp);
234 -
235 - /* Send the message to the videocore */
236 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
237 - &m, sizeof(m));
238 -
239 - if (status) {
240 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
241 - __func__, status);
242 -
243 - ret = -1;
244 - goto unlock;
245 - }
246 -
247 - /* We are expecting a reply from the videocore */
248 - wait_for_completion(&instance->msg_avail_comp);
249 -
250 - if (instance->result) {
251 - LOG_ERR("%s: result=%d\n", __func__, instance->result);
252 -
253 - ret = -1;
254 - goto unlock;
255 - }
256 -
257 - ret = 0;
258 -
259 -unlock:
260 - vchi_service_release(instance->vchi_handle);
261 - mutex_unlock(&instance->vchi_mutex);
262 -
263 - return ret;
264 + return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
265 }
266
267 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
268 unsigned int channels, unsigned int samplerate,
269 unsigned int bps)
270 {
271 - struct vc_audio_msg m;
272 - struct bcm2835_audio_instance *instance = alsa_stream->instance;
273 - int status;
274 - int ret;
275 -
276 - LOG_INFO(" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
277 - channels, samplerate, bps);
278 + struct vc_audio_msg m = {
279 + .type = VC_AUDIO_MSG_TYPE_CONFIG,
280 + .u.config.channels = channels,
281 + .u.config.samplerate = samplerate,
282 + .u.config.bps = bps,
283 + };
284 + int err;
285
286 /* resend ctls - alsa_stream may not have been open when first send */
287 - ret = bcm2835_audio_set_ctls(alsa_stream);
288 - if (ret) {
289 - LOG_ERR(" Alsa controls not supported\n");
290 - return -EINVAL;
291 - }
292 + err = bcm2835_audio_set_ctls(alsa_stream);
293 + if (err)
294 + return err;
295
296 - mutex_lock(&instance->vchi_mutex);
297 - vchi_service_use(instance->vchi_handle);
298 -
299 - instance->result = -1;
300 -
301 - m.type = VC_AUDIO_MSG_TYPE_CONFIG;
302 - m.u.config.channels = channels;
303 - m.u.config.samplerate = samplerate;
304 - m.u.config.bps = bps;
305 -
306 - /* Create the message available completion */
307 - init_completion(&instance->msg_avail_comp);
308 -
309 - /* Send the message to the videocore */
310 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
311 - &m, sizeof(m));
312 -
313 - if (status) {
314 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
315 - __func__, status);
316 -
317 - ret = -1;
318 - goto unlock;
319 - }
320 -
321 - /* We are expecting a reply from the videocore */
322 - wait_for_completion(&instance->msg_avail_comp);
323 -
324 - if (instance->result) {
325 - LOG_ERR("%s: result=%d", __func__, instance->result);
326 -
327 - ret = -1;
328 - goto unlock;
329 - }
330 -
331 - ret = 0;
332 -
333 -unlock:
334 - vchi_service_release(instance->vchi_handle);
335 - mutex_unlock(&instance->vchi_mutex);
336 -
337 - return ret;
338 + return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
339 }
340
341 static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
342 {
343 - struct vc_audio_msg m;
344 - struct bcm2835_audio_instance *instance = alsa_stream->instance;
345 - int status;
346 - int ret;
347 -
348 - mutex_lock(&instance->vchi_mutex);
349 - vchi_service_use(instance->vchi_handle);
350 -
351 - m.type = VC_AUDIO_MSG_TYPE_START;
352 -
353 - /* Send the message to the videocore */
354 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
355 - &m, sizeof(m));
356 -
357 - if (status) {
358 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
359 - __func__, status);
360 -
361 - ret = -1;
362 - goto unlock;
363 - }
364 -
365 - ret = 0;
366 -
367 -unlock:
368 - vchi_service_release(instance->vchi_handle);
369 - mutex_unlock(&instance->vchi_mutex);
370 - return ret;
371 + return bcm2835_audio_send_simple(alsa_stream->instance,
372 + VC_AUDIO_MSG_TYPE_START, false);
373 }
374
375 static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
376 {
377 - struct vc_audio_msg m;
378 - struct bcm2835_audio_instance *instance = alsa_stream->instance;
379 - int status;
380 - int ret;
381 -
382 - mutex_lock(&instance->vchi_mutex);
383 - vchi_service_use(instance->vchi_handle);
384 -
385 - m.type = VC_AUDIO_MSG_TYPE_STOP;
386 - m.u.stop.draining = alsa_stream->draining;
387 -
388 - /* Send the message to the videocore */
389 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
390 - &m, sizeof(m));
391 -
392 - if (status) {
393 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
394 - __func__, status);
395 -
396 - ret = -1;
397 - goto unlock;
398 - }
399 -
400 - ret = 0;
401 -
402 -unlock:
403 - vchi_service_release(instance->vchi_handle);
404 - mutex_unlock(&instance->vchi_mutex);
405 - return ret;
406 + return bcm2835_audio_send_simple(alsa_stream->instance,
407 + VC_AUDIO_MSG_TYPE_STOP, false);
408 }
409
410 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
411 {
412 - struct vc_audio_msg m;
413 struct bcm2835_audio_instance *instance = alsa_stream->instance;
414 - int status;
415 - int ret;
416 + int err;
417
418 my_workqueue_quit(alsa_stream);
419
420 - mutex_lock(&instance->vchi_mutex);
421 - vchi_service_use(instance->vchi_handle);
422 -
423 - m.type = VC_AUDIO_MSG_TYPE_CLOSE;
424 -
425 - /* Create the message available completion */
426 - init_completion(&instance->msg_avail_comp);
427 -
428 - /* Send the message to the videocore */
429 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
430 - &m, sizeof(m));
431 -
432 - if (status) {
433 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
434 - __func__, status);
435 - ret = -1;
436 - goto unlock;
437 - }
438 -
439 - /* We are expecting a reply from the videocore */
440 - wait_for_completion(&instance->msg_avail_comp);
441 -
442 - if (instance->result) {
443 - LOG_ERR("%s: failed result (result=%d)\n",
444 - __func__, instance->result);
445 -
446 - ret = -1;
447 - goto unlock;
448 - }
449 -
450 - ret = 0;
451 -
452 -unlock:
453 - vchi_service_release(instance->vchi_handle);
454 - mutex_unlock(&instance->vchi_mutex);
455 + err = bcm2835_audio_send_simple(alsa_stream->instance,
456 + VC_AUDIO_MSG_TYPE_CLOSE, true);
457
458 /* Stop the audio service */
459 vc_vchi_audio_deinit(instance);
460 alsa_stream->instance = NULL;
461
462 - return ret;
463 + return err;
464 }
465
466 static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
467 - unsigned int count, void *src)
468 + unsigned int size, void *src)
469 {
470 - struct vc_audio_msg m;
471 struct bcm2835_audio_instance *instance = alsa_stream->instance;
472 - int status;
473 - int ret;
474 -
475 - LOG_INFO(" Writing %d bytes from %p\n", count, src);
476 -
477 - mutex_lock(&instance->vchi_mutex);
478 - vchi_service_use(instance->vchi_handle);
479 + struct vc_audio_msg m = {
480 + .type = VC_AUDIO_MSG_TYPE_WRITE,
481 + .u.write.count = size,
482 + .u.write.max_packet = instance->max_packet,
483 + .u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1,
484 + .u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2,
485 + };
486 + unsigned int count;
487 + int err, status;
488
489 - if (instance->peer_version == 0 &&
490 - vchi_get_peer_version(instance->vchi_handle, &instance->peer_version) == 0)
491 - LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
492 -
493 - m.type = VC_AUDIO_MSG_TYPE_WRITE;
494 - m.u.write.count = count;
495 - // old version uses bulk, new version uses control
496 - m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
497 - m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
498 - m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
499 - m.u.write.silence = src == NULL;
500 -
501 - /* Send the message to the videocore */
502 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
503 - &m, sizeof(m));
504 + if (!size)
505 + return 0;
506
507 - if (status) {
508 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
509 - __func__, status);
510 -
511 - ret = -1;
512 + bcm2835_audio_lock(instance);
513 + err = bcm2835_audio_send_msg_locked(instance, &m, false);
514 + if (err < 0)
515 goto unlock;
516 - }
517 - if (!m.u.write.silence) {
518 - if (!m.u.write.max_packet) {
519 - /* Send the message to the videocore */
520 - status = vchi_bulk_queue_transmit(instance->vchi_handle,
521 - src, count,
522 - 0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
523 - +
524 - 1 * VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
525 - NULL);
526 - } else {
527 - while (count > 0) {
528 - int bytes = min_t(int, m.u.write.max_packet, count);
529
530 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
531 - src, bytes);
532 - src = (char *)src + bytes;
533 - count -= bytes;
534 - }
535 - }
536 - if (status) {
537 - LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
538 - __func__, status);
539 + count = size;
540 + if (!instance->max_packet) {
541 + /* Send the message to the videocore */
542 + status = vchi_bulk_queue_transmit(instance->vchi_handle,
543 + src, count,
544 + VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
545 + NULL);
546 + } else {
547 + while (count > 0) {
548 + int bytes = min(instance->max_packet, count);
549
550 - ret = -1;
551 - goto unlock;
552 + status = vchi_queue_kernel_message(instance->vchi_handle,
553 + src, bytes);
554 + src += bytes;
555 + count -= bytes;
556 }
557 }
558 - ret = 0;
559
560 -unlock:
561 - vchi_service_release(instance->vchi_handle);
562 - mutex_unlock(&instance->vchi_mutex);
563 - return ret;
564 + if (status) {
565 + LOG_ERR("failed on %d bytes transfer (status=%d)\n",
566 + size, status);
567 + err = -EIO;
568 + }
569 +
570 + unlock:
571 + bcm2835_audio_unlock(instance);
572 + return err;
573 }
574
575 unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)