From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Pawel Furtak 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 Reviewed-by: Janca, Grzegorz Reviewed-by: Rojewski, Cezary Tested-by: Rojewski, Cezary --- .../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