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
7 commit 769a8e9bf5cf39813f52962fdafdf7e4d52ad585 upstream.
9 This is a cleanup and code refactoring in bcm2835-vchiq.c.
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.
15 Also, the max packet is set at opening the stream, not at each time
16 when the write gets called.
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>
22 .../bcm2835-audio/bcm2835-vchiq.c | 440 ++++++------------
23 1 file changed, 142 insertions(+), 298 deletions(-)
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;
31 + unsigned int max_packet;
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);
39 -// Routine to send a message across a service
40 +static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
42 + mutex_lock(&instance->vchi_mutex);
43 + vchi_service_use(instance->vchi_handle);
46 +static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
48 + vchi_service_release(instance->vchi_handle);
49 + mutex_unlock(&instance->vchi_mutex);
52 +static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
53 + struct vc_audio_msg *m, bool wait)
58 + instance->result = -1;
59 + init_completion(&instance->msg_avail_comp);
62 + status = vchi_queue_kernel_message(instance->vchi_handle,
65 + LOG_ERR("vchi message queue failed: %d, msg=%d\n",
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);
75 + } else if (instance->result) {
76 + LOG_ERR("vchi message response error:%d, msg=%d\n",
77 + instance->result, m->type);
86 -bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
90 - return vchi_queue_kernel_message(handle,
93 +static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
94 + struct vc_audio_msg *m, bool wait)
98 + bcm2835_audio_lock(instance);
99 + err = bcm2835_audio_send_msg_locked(instance, m, wait);
100 + bcm2835_audio_unlock(instance);
104 +static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
105 + int type, bool wait)
107 + struct vc_audio_msg m = { .type = type };
109 + return bcm2835_audio_send_msg(instance, &m, wait);
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
116 mutex_lock(&instance->vchi_mutex);
118 - /* Close all VCHI service connections */
119 vchi_service_use(instance->vchi_handle);
121 + /* Close all VCHI service connections */
122 status = vchi_service_close(instance->vchi_handle);
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);
129 - if (IS_ERR(instance)) {
130 - LOG_ERR("%s: failed to initialize audio service\n", __func__);
132 - /* vchi_instance is retained for use the next time. */
133 + if (IS_ERR(instance))
134 return PTR_ERR(instance);
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)
142 struct bcm2835_audio_instance *instance;
143 - struct vc_audio_msg m;
148 alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
149 if (!alsa_stream->my_wq)
152 - ret = bcm2835_audio_open_connection(alsa_stream);
154 + err = bcm2835_audio_open_connection(alsa_stream);
158 instance = alsa_stream->instance;
159 - LOG_DBG(" instance (%p)\n", instance);
161 - mutex_lock(&instance->vchi_mutex);
162 - vchi_service_use(instance->vchi_handle);
164 - m.type = VC_AUDIO_MSG_TYPE_OPEN;
166 - /* Send the message to the videocore */
167 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
171 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
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,
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 */
194 + instance->max_packet = 4000;
198 - destroy_workqueue(alsa_stream->my_wq);
203 + vc_vchi_audio_deinit(instance);
205 + destroy_workqueue(alsa_stream->my_wq);
209 int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
211 - struct vc_audio_msg m;
212 - struct bcm2835_audio_instance *instance = alsa_stream->instance;
213 struct bcm2835_chip *chip = alsa_stream->chip;
217 - LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
218 - chip->dest, chip->volume);
220 - mutex_lock(&instance->vchi_mutex);
221 - vchi_service_use(instance->vchi_handle);
223 - instance->result = -1;
224 + struct vc_audio_msg m = {};
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
230 m.u.control.volume = alsa2chip(chip->volume);
232 - /* Create the message available completion */
233 - init_completion(&instance->msg_avail_comp);
235 - /* Send the message to the videocore */
236 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
240 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
247 - /* We are expecting a reply from the videocore */
248 - wait_for_completion(&instance->msg_avail_comp);
250 - if (instance->result) {
251 - LOG_ERR("%s: result=%d\n", __func__, instance->result);
260 - vchi_service_release(instance->vchi_handle);
261 - mutex_unlock(&instance->vchi_mutex);
264 + return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
267 int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
268 unsigned int channels, unsigned int samplerate,
271 - struct vc_audio_msg m;
272 - struct bcm2835_audio_instance *instance = alsa_stream->instance;
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,
286 /* resend ctls - alsa_stream may not have been open when first send */
287 - ret = bcm2835_audio_set_ctls(alsa_stream);
289 - LOG_ERR(" Alsa controls not supported\n");
292 + err = bcm2835_audio_set_ctls(alsa_stream);
296 - mutex_lock(&instance->vchi_mutex);
297 - vchi_service_use(instance->vchi_handle);
299 - instance->result = -1;
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;
306 - /* Create the message available completion */
307 - init_completion(&instance->msg_avail_comp);
309 - /* Send the message to the videocore */
310 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
314 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
321 - /* We are expecting a reply from the videocore */
322 - wait_for_completion(&instance->msg_avail_comp);
324 - if (instance->result) {
325 - LOG_ERR("%s: result=%d", __func__, instance->result);
334 - vchi_service_release(instance->vchi_handle);
335 - mutex_unlock(&instance->vchi_mutex);
338 + return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
341 static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
343 - struct vc_audio_msg m;
344 - struct bcm2835_audio_instance *instance = alsa_stream->instance;
348 - mutex_lock(&instance->vchi_mutex);
349 - vchi_service_use(instance->vchi_handle);
351 - m.type = VC_AUDIO_MSG_TYPE_START;
353 - /* Send the message to the videocore */
354 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
358 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
368 - vchi_service_release(instance->vchi_handle);
369 - mutex_unlock(&instance->vchi_mutex);
371 + return bcm2835_audio_send_simple(alsa_stream->instance,
372 + VC_AUDIO_MSG_TYPE_START, false);
375 static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
377 - struct vc_audio_msg m;
378 - struct bcm2835_audio_instance *instance = alsa_stream->instance;
382 - mutex_lock(&instance->vchi_mutex);
383 - vchi_service_use(instance->vchi_handle);
385 - m.type = VC_AUDIO_MSG_TYPE_STOP;
386 - m.u.stop.draining = alsa_stream->draining;
388 - /* Send the message to the videocore */
389 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
393 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
403 - vchi_service_release(instance->vchi_handle);
404 - mutex_unlock(&instance->vchi_mutex);
406 + return bcm2835_audio_send_simple(alsa_stream->instance,
407 + VC_AUDIO_MSG_TYPE_STOP, false);
410 int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
412 - struct vc_audio_msg m;
413 struct bcm2835_audio_instance *instance = alsa_stream->instance;
418 my_workqueue_quit(alsa_stream);
420 - mutex_lock(&instance->vchi_mutex);
421 - vchi_service_use(instance->vchi_handle);
423 - m.type = VC_AUDIO_MSG_TYPE_CLOSE;
425 - /* Create the message available completion */
426 - init_completion(&instance->msg_avail_comp);
428 - /* Send the message to the videocore */
429 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
433 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
439 - /* We are expecting a reply from the videocore */
440 - wait_for_completion(&instance->msg_avail_comp);
442 - if (instance->result) {
443 - LOG_ERR("%s: failed result (result=%d)\n",
444 - __func__, instance->result);
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);
458 /* Stop the audio service */
459 vc_vchi_audio_deinit(instance);
460 alsa_stream->instance = NULL;
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)
470 - struct vc_audio_msg m;
471 struct bcm2835_audio_instance *instance = alsa_stream->instance;
475 - LOG_INFO(" Writing %d bytes from %p\n", count, src);
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,
486 + unsigned int count;
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);
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;
501 - /* Send the message to the videocore */
502 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
508 - LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
512 + bcm2835_audio_lock(instance);
513 + err = bcm2835_audio_send_msg_locked(instance, &m, false);
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,
522 - 0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
524 - 1 * VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
527 - while (count > 0) {
528 - int bytes = min_t(int, m.u.write.max_packet, count);
530 - status = bcm2835_vchi_msg_queue(instance->vchi_handle,
532 - src = (char *)src + bytes;
537 - LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
540 + if (!instance->max_packet) {
541 + /* Send the message to the videocore */
542 + status = vchi_bulk_queue_transmit(instance->vchi_handle,
544 + VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
547 + while (count > 0) {
548 + int bytes = min(instance->max_packet, count);
552 + status = vchi_queue_kernel_message(instance->vchi_handle,
561 - vchi_service_release(instance->vchi_handle);
562 - mutex_unlock(&instance->vchi_mutex);
565 + LOG_ERR("failed on %d bytes transfer (status=%d)\n",
571 + bcm2835_audio_unlock(instance);
575 unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)