37ebd8b673286e794b3b0a1102911224f82df48d
[oweals/openwrt.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)