clear-pkgs-linux-iot-lts2018/0873-ASoC-Skl-Virt-Add-lock...

145 lines
4.6 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Pawel Furtak <pawel.furtak@intel.com>
Date: Mon, 14 Jan 2019 16:10:29 +0100
Subject: [PATCH] ASoC: Skl: Virt: Add locks to virtqueue related operations
According to virtqueue documentation, caller shall guarantee
that no other virtqueue operations will be called during
execution of given method. This patch adds spinlocks to protect
agains such situations.
Change-Id: I6e2c0a78a0ea58b7d8b52f8f5d80ea8558e188c6
Tracked-On: OAM-74848
Signed-off-by: Pawel Furtak <pawel.furtak@intel.com>
Reviewed-by: Janca, Grzegorz <grzegorz.janca@intel.com>
Reviewed-by: Rojewski, Cezary <cezary.rojewski@intel.com>
Tested-by: Rojewski, Cezary <cezary.rojewski@intel.com>
---
.../soc/intel/skylake/virtio/skl-virtio-fe.c | 40 ++++++++++++++++---
.../soc/intel/skylake/virtio/skl-virtio-fe.h | 1 +
2 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-fe.c b/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
index 4efda251cf36..642a1c05113b 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
@@ -100,15 +100,19 @@ static int vfe_send_virtio_msg(struct snd_skl_vfe *vfe,
struct virtqueue *vq, struct scatterlist *sgs, int sg_count,
void *data, bool out)
{
+ unsigned long irq_flags;
int ret;
if (!vq)
return -EINVAL;
+
+ spin_lock_irqsave(&vfe->ipc_vq_lock, irq_flags);
if (out)
ret = virtqueue_add_outbuf(vq, sgs, sg_count, data, GFP_KERNEL);
else
ret = virtqueue_add_inbuf(vq, sgs, sg_count, data, GFP_KERNEL);
+ spin_unlock_irqrestore(&vfe->ipc_vq_lock, irq_flags);
if (ret < 0) {
dev_err(&vfe->vdev->dev,
@@ -117,7 +121,10 @@ static int vfe_send_virtio_msg(struct snd_skl_vfe *vfe,
return ret;
}
+ spin_lock_irqsave(&vfe->ipc_vq_lock, irq_flags);
virtqueue_kick(vq);
+ spin_unlock_irqrestore(&vfe->ipc_vq_lock, irq_flags);
+
return 0;
}
@@ -270,10 +277,17 @@ static void vfe_cmd_tx_done(struct virtqueue *vq)
{
struct snd_skl_vfe *vfe = vq->vdev->priv;
struct vfe_dsp_ipc_msg *msg;
+ unsigned long irq_flags;
unsigned int buflen = 0;
- while ((msg = virtqueue_get_buf(vfe->ipc_cmd_tx_vq, &buflen))
- != NULL) {
+ while (true) {
+ spin_lock_irqsave(&vfe->ipc_vq_lock, irq_flags);
+ msg = virtqueue_get_buf(vfe->ipc_cmd_tx_vq, &buflen);
+ spin_unlock_irqrestore(&vfe->ipc_vq_lock, irq_flags);
+
+ if (msg == NULL)
+ break;
+
msg->ipc->complete = true;
list_del(&msg->ipc->list);
sst_ipc_tx_msg_reply_complete(&vfe->sdev.skl_sst->ipc,
@@ -290,11 +304,18 @@ static void vfe_not_tx_done(struct virtqueue *vq)
{
struct snd_skl_vfe *vfe = vq->vdev->priv;
enum vfe_ipc_msg_status msg_status;
+ unsigned long irq_flags;
struct vfe_ipc_msg *msg;
unsigned int buflen = 0;
- while ((msg = virtqueue_get_buf(vfe->ipc_not_tx_vq, &buflen))
- != NULL) {
+
+ while (true) {
+ spin_lock_irqsave(&vfe->ipc_vq_lock, irq_flags);
+ msg = virtqueue_get_buf(vfe->ipc_not_tx_vq, &buflen);
+ spin_unlock_irqrestore(&vfe->ipc_vq_lock, irq_flags);
+
+ if (msg == NULL)
+ break;
msg_status = atomic_read(&msg->status);
if (msg_status != VFE_MSG_PENDING)
@@ -332,6 +353,7 @@ static void vfe_posn_update(struct work_struct *work)
{
struct vfe_hw_pos_request *pos_req;
struct virtqueue *vq;
+ unsigned long irq_flags;
unsigned int buflen = 0;
struct vfe_substream_info *substr_info;
struct snd_skl_vfe *vfe =
@@ -339,7 +361,14 @@ static void vfe_posn_update(struct work_struct *work)
vq = vfe->ipc_not_rx_vq;
- while ((pos_req = virtqueue_get_buf(vq, &buflen)) != NULL) {
+ while (true) {
+ spin_lock_irqsave(&vfe->ipc_vq_lock, irq_flags);
+ pos_req = virtqueue_get_buf(vq, &buflen);
+ spin_unlock_irqrestore(&vfe->ipc_vq_lock, irq_flags);
+
+ if (pos_req == NULL)
+ break;
+
substr_info = vfe_find_substream_info_by_pcm(vfe,
pos_req->pcm_id, pos_req->stream_dir);
@@ -847,6 +876,7 @@ static int vfe_init(struct virtio_device *vdev)
return ret;
}
+ spin_lock_init(&vfe->ipc_vq_lock);
/* virtques */
vfe->ipc_cmd_tx_vq = vqs[SKL_VIRTIO_IPC_CMD_TX_VQ];
vfe->ipc_cmd_rx_vq = vqs[SKL_VIRTIO_IPC_CMD_RX_VQ];
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-fe.h b/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
index f49977e9ce33..4b8e09e2c09a 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
@@ -40,6 +40,7 @@ struct snd_skl_vfe {
/* position update work */
struct work_struct posn_update_work;
+ spinlock_t ipc_vq_lock;
/* IPC cmd from frontend to backend */
struct virtqueue *ipc_cmd_tx_vq;
/* IPC cmd reply from backend to frontend */
--
https://clearlinux.org