145 lines
4.6 KiB
Diff
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 4efda25..642a1c0 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 f49977e..4b8e09e 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 */
|
|
--
|
|
2.21.0
|
|
|