brcm2708: update to latest patches from RPi foundation
[openwrt/openwrt.git] / target / linux / brcm2708 / patches-4.19 / 950-0390-staging-bcm2835-audio-Code-refactoring-of-vchiq-acce.patch
diff --git a/target/linux/brcm2708/patches-4.19/950-0390-staging-bcm2835-audio-Code-refactoring-of-vchiq-acce.patch b/target/linux/brcm2708/patches-4.19/950-0390-staging-bcm2835-audio-Code-refactoring-of-vchiq-acce.patch
new file mode 100644 (file)
index 0000000..37ebd8b
--- /dev/null
@@ -0,0 +1,575 @@
+From 43f89ac74f3f221e3036a1ec311b24016860d15e Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 4 Sep 2018 17:58:48 +0200
+Subject: [PATCH] staging: bcm2835-audio: Code refactoring of vchiq
+ accessor codes
+
+commit 769a8e9bf5cf39813f52962fdafdf7e4d52ad585 upstream.
+
+This is a cleanup and code refactoring in bcm2835-vchiq.c.
+
+The major code changes are to provide local helpers for easier use of
+lock / unlock, and message passing with/without response wait.  This
+allows us to reduce lots of open codes.
+
+Also, the max packet is set at opening the stream, not at each time
+when the write gets called.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Tested-by: Stefan Wahren <stefan.wahren@i2se.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ .../bcm2835-audio/bcm2835-vchiq.c             | 440 ++++++------------
+ 1 file changed, 142 insertions(+), 298 deletions(-)
+
+--- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
++++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c
+@@ -49,6 +49,7 @@ struct bcm2835_audio_instance {
+       struct mutex vchi_mutex;
+       struct bcm2835_alsa_stream *alsa_stream;
+       int result;
++      unsigned int max_packet;
+       short peer_version;
+ };
+@@ -65,16 +66,68 @@ static int bcm2835_audio_start_worker(st
+ static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
+                                     unsigned int count, void *src);
+-// Routine to send a message across a service
++static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance)
++{
++      mutex_lock(&instance->vchi_mutex);
++      vchi_service_use(instance->vchi_handle);
++}
++
++static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance)
++{
++      vchi_service_release(instance->vchi_handle);
++      mutex_unlock(&instance->vchi_mutex);
++}
++
++static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance,
++                                       struct vc_audio_msg *m, bool wait)
++{
++      int status;
++
++      if (wait) {
++              instance->result = -1;
++              init_completion(&instance->msg_avail_comp);
++      }
++
++      status = vchi_queue_kernel_message(instance->vchi_handle,
++                                         m, sizeof(*m));
++      if (status) {
++              LOG_ERR("vchi message queue failed: %d, msg=%d\n",
++                      status, m->type);
++              return -EIO;
++      }
++
++      if (wait) {
++              if (!wait_for_completion_timeout(&instance->msg_avail_comp,
++                                               msecs_to_jiffies(10 * 1000))) {
++                      LOG_ERR("vchi message timeout, msg=%d\n", m->type);
++                      return -ETIMEDOUT;
++              } else if (instance->result) {
++                      LOG_ERR("vchi message response error:%d, msg=%d\n",
++                              instance->result, m->type);
++                      return -EIO;
++              }
++      }
++
++      return 0;
++}
+-static int
+-bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
+-                     void *data,
+-                     unsigned int size)
+-{
+-      return vchi_queue_kernel_message(handle,
+-                                       data,
+-                                       size);
++static int bcm2835_audio_send_msg(struct bcm2835_audio_instance *instance,
++                                struct vc_audio_msg *m, bool wait)
++{
++      int err;
++
++      bcm2835_audio_lock(instance);
++      err = bcm2835_audio_send_msg_locked(instance, m, wait);
++      bcm2835_audio_unlock(instance);
++      return err;
++}
++
++static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance,
++                                   int type, bool wait)
++{
++      struct vc_audio_msg m = { .type = type };
++
++      return bcm2835_audio_send_msg(instance, &m, wait);
+ }
+ static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
+@@ -283,10 +336,9 @@ static int vc_vchi_audio_deinit(struct b
+       int status;
+       mutex_lock(&instance->vchi_mutex);
+-
+-      /* Close all VCHI service connections */
+       vchi_service_use(instance->vchi_handle);
++      /* Close all VCHI service connections */
+       status = vchi_service_close(instance->vchi_handle);
+       if (status) {
+               LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
+@@ -345,12 +397,8 @@ static int bcm2835_audio_open_connection
+       instance = vc_vchi_audio_init(vhci_ctx->vchi_instance,
+                                     vhci_ctx->vchi_connection);
+-      if (IS_ERR(instance)) {
+-              LOG_ERR("%s: failed to initialize audio service\n", __func__);
+-
+-              /* vchi_instance is retained for use the next time. */
++      if (IS_ERR(instance))
+               return PTR_ERR(instance);
+-      }
+       instance->alsa_stream = alsa_stream;
+       alsa_stream->instance = instance;
+@@ -361,66 +409,44 @@ static int bcm2835_audio_open_connection
+ int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
+ {
+       struct bcm2835_audio_instance *instance;
+-      struct vc_audio_msg m;
+-      int status;
+-      int ret;
++      int err;
+       alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
+       if (!alsa_stream->my_wq)
+               return -ENOMEM;
+-      ret = bcm2835_audio_open_connection(alsa_stream);
+-      if (ret)
++      err = bcm2835_audio_open_connection(alsa_stream);
++      if (err < 0)
+               goto free_wq;
+       instance = alsa_stream->instance;
+-      LOG_DBG(" instance (%p)\n", instance);
+-
+-      mutex_lock(&instance->vchi_mutex);
+-      vchi_service_use(instance->vchi_handle);
+-
+-      m.type = VC_AUDIO_MSG_TYPE_OPEN;
+-
+-      /* Send the message to the videocore */
+-      status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+-                                      &m, sizeof(m));
+-
+-      if (status) {
+-              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+-                      __func__, status);
+-
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      ret = 0;
+-unlock:
+-      vchi_service_release(instance->vchi_handle);
+-      mutex_unlock(&instance->vchi_mutex);
++      err = bcm2835_audio_send_simple(instance, VC_AUDIO_MSG_TYPE_OPEN,
++                                      false);
++      if (err < 0)
++              goto deinit;
++
++      bcm2835_audio_lock(instance);
++      vchi_get_peer_version(instance->vchi_handle, &instance->peer_version);
++      bcm2835_audio_unlock(instance);
++      if (instance->peer_version < 2 || force_bulk)
++              instance->max_packet = 0; /* bulk transfer */
++      else
++              instance->max_packet = 4000;
+-free_wq:
+-      if (ret)
+-              destroy_workqueue(alsa_stream->my_wq);
++      return 0;
+-      return ret;
++ deinit:
++      vc_vchi_audio_deinit(instance);
++ free_wq:
++      destroy_workqueue(alsa_stream->my_wq);
++      return err;
+ }
+ int bcm2835_audio_set_ctls(struct bcm2835_alsa_stream *alsa_stream)
+ {
+-      struct vc_audio_msg m;
+-      struct bcm2835_audio_instance *instance = alsa_stream->instance;
+       struct bcm2835_chip *chip = alsa_stream->chip;
+-      int status;
+-      int ret;
+-
+-      LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
+-               chip->dest, chip->volume);
+-
+-      mutex_lock(&instance->vchi_mutex);
+-      vchi_service_use(instance->vchi_handle);
+-
+-      instance->result = -1;
++      struct vc_audio_msg m = {};
+       m.type = VC_AUDIO_MSG_TYPE_CONTROL;
+       m.u.control.dest = chip->dest;
+@@ -429,289 +455,107 @@ int bcm2835_audio_set_ctls(struct bcm283
+       else
+               m.u.control.volume = alsa2chip(chip->volume);
+-      /* Create the message available completion */
+-      init_completion(&instance->msg_avail_comp);
+-
+-      /* Send the message to the videocore */
+-      status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+-                                      &m, sizeof(m));
+-
+-      if (status) {
+-              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+-                      __func__, status);
+-
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      /* We are expecting a reply from the videocore */
+-      wait_for_completion(&instance->msg_avail_comp);
+-
+-      if (instance->result) {
+-              LOG_ERR("%s: result=%d\n", __func__, instance->result);
+-
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      ret = 0;
+-
+-unlock:
+-      vchi_service_release(instance->vchi_handle);
+-      mutex_unlock(&instance->vchi_mutex);
+-
+-      return ret;
++      return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
+ }
+ int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
+                            unsigned int channels, unsigned int samplerate,
+                            unsigned int bps)
+ {
+-      struct vc_audio_msg m;
+-      struct bcm2835_audio_instance *instance = alsa_stream->instance;
+-      int status;
+-      int ret;
+-
+-      LOG_INFO(" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
+-               channels, samplerate, bps);
++      struct vc_audio_msg m = {
++               .type = VC_AUDIO_MSG_TYPE_CONFIG,
++               .u.config.channels = channels,
++               .u.config.samplerate = samplerate,
++               .u.config.bps = bps,
++      };
++      int err;
+       /* resend ctls - alsa_stream may not have been open when first send */
+-      ret = bcm2835_audio_set_ctls(alsa_stream);
+-      if (ret) {
+-              LOG_ERR(" Alsa controls not supported\n");
+-              return -EINVAL;
+-      }
++      err = bcm2835_audio_set_ctls(alsa_stream);
++      if (err)
++              return err;
+-      mutex_lock(&instance->vchi_mutex);
+-      vchi_service_use(instance->vchi_handle);
+-
+-      instance->result = -1;
+-
+-      m.type = VC_AUDIO_MSG_TYPE_CONFIG;
+-      m.u.config.channels = channels;
+-      m.u.config.samplerate = samplerate;
+-      m.u.config.bps = bps;
+-
+-      /* Create the message available completion */
+-      init_completion(&instance->msg_avail_comp);
+-
+-      /* Send the message to the videocore */
+-      status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+-                                      &m, sizeof(m));
+-
+-      if (status) {
+-              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+-                      __func__, status);
+-
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      /* We are expecting a reply from the videocore */
+-      wait_for_completion(&instance->msg_avail_comp);
+-
+-      if (instance->result) {
+-              LOG_ERR("%s: result=%d", __func__, instance->result);
+-
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      ret = 0;
+-
+-unlock:
+-      vchi_service_release(instance->vchi_handle);
+-      mutex_unlock(&instance->vchi_mutex);
+-
+-      return ret;
++      return bcm2835_audio_send_msg(alsa_stream->instance, &m, true);
+ }
+ static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
+ {
+-      struct vc_audio_msg m;
+-      struct bcm2835_audio_instance *instance = alsa_stream->instance;
+-      int status;
+-      int ret;
+-
+-      mutex_lock(&instance->vchi_mutex);
+-      vchi_service_use(instance->vchi_handle);
+-
+-      m.type = VC_AUDIO_MSG_TYPE_START;
+-
+-      /* Send the message to the videocore */
+-      status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+-                                      &m, sizeof(m));
+-
+-      if (status) {
+-              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+-                      __func__, status);
+-
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      ret = 0;
+-
+-unlock:
+-      vchi_service_release(instance->vchi_handle);
+-      mutex_unlock(&instance->vchi_mutex);
+-      return ret;
++      return bcm2835_audio_send_simple(alsa_stream->instance,
++                                       VC_AUDIO_MSG_TYPE_START, false);
+ }
+ static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
+ {
+-      struct vc_audio_msg m;
+-      struct bcm2835_audio_instance *instance = alsa_stream->instance;
+-      int status;
+-      int ret;
+-
+-      mutex_lock(&instance->vchi_mutex);
+-      vchi_service_use(instance->vchi_handle);
+-
+-      m.type = VC_AUDIO_MSG_TYPE_STOP;
+-      m.u.stop.draining = alsa_stream->draining;
+-
+-      /* Send the message to the videocore */
+-      status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+-                                      &m, sizeof(m));
+-
+-      if (status) {
+-              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+-                      __func__, status);
+-
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      ret = 0;
+-
+-unlock:
+-      vchi_service_release(instance->vchi_handle);
+-      mutex_unlock(&instance->vchi_mutex);
+-      return ret;
++      return bcm2835_audio_send_simple(alsa_stream->instance,
++                                       VC_AUDIO_MSG_TYPE_STOP, false);
+ }
+ int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
+ {
+-      struct vc_audio_msg m;
+       struct bcm2835_audio_instance *instance = alsa_stream->instance;
+-      int status;
+-      int ret;
++      int err;
+       my_workqueue_quit(alsa_stream);
+-      mutex_lock(&instance->vchi_mutex);
+-      vchi_service_use(instance->vchi_handle);
+-
+-      m.type = VC_AUDIO_MSG_TYPE_CLOSE;
+-
+-      /* Create the message available completion */
+-      init_completion(&instance->msg_avail_comp);
+-
+-      /* Send the message to the videocore */
+-      status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+-                                      &m, sizeof(m));
+-
+-      if (status) {
+-              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+-                      __func__, status);
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      /* We are expecting a reply from the videocore */
+-      wait_for_completion(&instance->msg_avail_comp);
+-
+-      if (instance->result) {
+-              LOG_ERR("%s: failed result (result=%d)\n",
+-                      __func__, instance->result);
+-
+-              ret = -1;
+-              goto unlock;
+-      }
+-
+-      ret = 0;
+-
+-unlock:
+-      vchi_service_release(instance->vchi_handle);
+-      mutex_unlock(&instance->vchi_mutex);
++      err = bcm2835_audio_send_simple(alsa_stream->instance,
++                                      VC_AUDIO_MSG_TYPE_CLOSE, true);
+       /* Stop the audio service */
+       vc_vchi_audio_deinit(instance);
+       alsa_stream->instance = NULL;
+-      return ret;
++      return err;
+ }
+ static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
+-                                    unsigned int count, void *src)
++                                    unsigned int size, void *src)
+ {
+-      struct vc_audio_msg m;
+       struct bcm2835_audio_instance *instance = alsa_stream->instance;
+-      int status;
+-      int ret;
+-
+-      LOG_INFO(" Writing %d bytes from %p\n", count, src);
+-
+-      mutex_lock(&instance->vchi_mutex);
+-      vchi_service_use(instance->vchi_handle);
++      struct vc_audio_msg m = {
++              .type = VC_AUDIO_MSG_TYPE_WRITE,
++              .u.write.count = size,
++              .u.write.max_packet = instance->max_packet,
++              .u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1,
++              .u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2,
++      };
++      unsigned int count;
++      int err, status;
+-      if (instance->peer_version == 0 &&
+-          vchi_get_peer_version(instance->vchi_handle, &instance->peer_version) == 0)
+-              LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
+-
+-      m.type = VC_AUDIO_MSG_TYPE_WRITE;
+-      m.u.write.count = count;
+-      // old version uses bulk, new version uses control
+-      m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
+-      m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
+-      m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
+-      m.u.write.silence = src == NULL;
+-
+-      /* Send the message to the videocore */
+-      status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+-                                      &m, sizeof(m));
++      if (!size)
++              return 0;
+-      if (status) {
+-              LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+-                      __func__, status);
+-
+-              ret = -1;
++      bcm2835_audio_lock(instance);
++      err = bcm2835_audio_send_msg_locked(instance, &m, false);
++      if (err < 0)
+               goto unlock;
+-      }
+-      if (!m.u.write.silence) {
+-              if (!m.u.write.max_packet) {
+-                      /* Send the message to the videocore */
+-                      status = vchi_bulk_queue_transmit(instance->vchi_handle,
+-                                                        src, count,
+-                                                        0 * VCHI_FLAGS_BLOCK_UNTIL_QUEUED
+-                                                        +
+-                                                        1 * VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
+-                                                        NULL);
+-              } else {
+-                      while (count > 0) {
+-                              int bytes = min_t(int, m.u.write.max_packet, count);
+-                              status = bcm2835_vchi_msg_queue(instance->vchi_handle,
+-                                                              src, bytes);
+-                              src = (char *)src + bytes;
+-                              count -= bytes;
+-                      }
+-              }
+-              if (status) {
+-                      LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
+-                              __func__, status);
++      count = size;
++      if (!instance->max_packet) {
++              /* Send the message to the videocore */
++              status = vchi_bulk_queue_transmit(instance->vchi_handle,
++                                                src, count,
++                                                VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
++                                                NULL);
++      } else {
++              while (count > 0) {
++                      int bytes = min(instance->max_packet, count);
+-                      ret = -1;
+-                      goto unlock;
++                      status = vchi_queue_kernel_message(instance->vchi_handle,
++                                                         src, bytes);
++                      src += bytes;
++                      count -= bytes;
+               }
+       }
+-      ret = 0;
+-unlock:
+-      vchi_service_release(instance->vchi_handle);
+-      mutex_unlock(&instance->vchi_mutex);
+-      return ret;
++      if (status) {
++              LOG_ERR("failed on %d bytes transfer (status=%d)\n",
++                      size, status);
++              err = -EIO;
++      }
++
++ unlock:
++      bcm2835_audio_unlock(instance);
++      return err;
+ }
+ unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)