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

144 lines
4.8 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Pawel Furtak <pawel.furtak@intel.com>
Date: Tue, 15 Jan 2019 17:11:49 +0100
Subject: [PATCH] ASoC: Skl: Virt: Add locks to substreams list
Protect substream list access with additional locks
to prevent concurrency issues.
Change-Id: Id1f488e7f1553d2ce3b8fe5cad7b37532f30e200
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 | 27 ++++++++++++++++---
.../soc/intel/skylake/virtio/skl-virtio-fe.h | 2 ++
2 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-fe.c b/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
index 642a1c05113b..66a57d548ab0 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-fe.c
@@ -351,6 +351,7 @@ static void vfe_not_handle_rx(struct virtqueue *vq)
static void vfe_posn_update(struct work_struct *work)
{
+ struct snd_pcm_substream *substream;
struct vfe_hw_pos_request *pos_req;
struct virtqueue *vq;
unsigned long irq_flags;
@@ -369,15 +370,22 @@ static void vfe_posn_update(struct work_struct *work)
if (pos_req == NULL)
break;
+ spin_lock_irqsave(&vfe->substream_info_lock, irq_flags);
substr_info = vfe_find_substream_info_by_pcm(vfe,
pos_req->pcm_id, pos_req->stream_dir);
// substream may be already closed on FE side
- if (!substr_info)
+ if (!substr_info) {
+ spin_unlock_irqrestore(&vfe->substream_info_lock,
+ irq_flags);
goto send_back_msg;
+ }
substr_info->hw_ptr = pos_req->stream_pos;
- snd_pcm_period_elapsed(substr_info->substream);
+ substream = substr_info->substream;
+ spin_unlock_irqrestore(&vfe->substream_info_lock, irq_flags);
+
+ snd_pcm_period_elapsed(substream);
send_back_msg:
vfe_send_pos_request(vfe, pos_req);
@@ -418,7 +426,8 @@ int vfe_pcm_open(struct snd_pcm_substream *substream)
{
struct vfe_substream_info *substr_info;
struct vfe_msg_header msg_header;
- struct vfe_pcm_result vbe_result;
+ struct vfe_pcm_result vbe_result = { .ret = -EIO };
+ unsigned long irq_flags;
int ret;
struct snd_skl_vfe *vfe = get_virtio_audio_fe();
@@ -438,6 +447,9 @@ int vfe_pcm_open(struct snd_pcm_substream *substream)
if (ret < 0)
return ret;
+ if (vbe_result.ret < 0)
+ return vbe_result.ret;
+
substr_info = kzalloc(sizeof(*substr_info), GFP_KERNEL);
if (!substr_info)
return -ENOMEM;
@@ -446,7 +458,9 @@ int vfe_pcm_open(struct snd_pcm_substream *substream)
substr_info->substream = substream;
substr_info->direction = substream->stream;
+ spin_lock_irqsave(&vfe->substream_info_lock, irq_flags);
list_add(&substr_info->list, &vfe->substr_info_list);
+ spin_unlock_irqrestore(&vfe->substream_info_lock, irq_flags);
return vbe_result.ret;
}
@@ -456,6 +470,7 @@ int vfe_pcm_close(struct snd_pcm_substream *substream)
struct vfe_substream_info *sstream_info;
struct vfe_msg_header msg_header;
struct vfe_pcm_result vbe_result;
+ unsigned long irq_flags;
int ret;
struct snd_skl_vfe *vfe = get_virtio_audio_fe();
@@ -463,12 +478,14 @@ int vfe_pcm_close(struct snd_pcm_substream *substream)
if (ret)
return 0;
+ spin_lock_irqsave(&vfe->substream_info_lock, irq_flags);
sstream_info = vfe_find_substream_info(vfe, substream);
if (sstream_info) {
list_del(&sstream_info->list);
kfree(sstream_info);
}
+ spin_unlock_irqrestore(&vfe->substream_info_lock, irq_flags);
msg_header = vfe_get_pcm_msg_header(VFE_MSG_PCM_CLOSE, substream);
@@ -573,7 +590,7 @@ snd_pcm_uframes_t vfe_pcm_pointer(struct snd_pcm_substream *substream)
struct vfe_substream_info *substr_info =
vfe_find_substream_info(vfe, substream);
- return substr_info->hw_ptr;
+ return substr_info ? substr_info->hw_ptr : 0;
}
static const char *const vfe_skl_vq_names[SKL_VIRTIO_NUM_OF_VQS] = {
@@ -866,6 +883,8 @@ static int vfe_init(struct virtio_device *vdev)
vdev->priv = vfe;
INIT_LIST_HEAD(&vfe->kcontrols_list);
+
+ spin_lock_init(&vfe->substream_info_lock);
INIT_LIST_HEAD(&vfe->substr_info_list);
/* find virt queue for vfe to send/receive IPC message. */
diff --git a/sound/soc/intel/skylake/virtio/skl-virtio-fe.h b/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
index 4b8e09e2c09a..5656d0b6a6ab 100644
--- a/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
+++ b/sound/soc/intel/skylake/virtio/skl-virtio-fe.h
@@ -51,6 +51,8 @@ struct snd_skl_vfe {
struct virtqueue *ipc_not_tx_vq;
struct list_head kcontrols_list;
+
+ spinlock_t substream_info_lock;
struct list_head substr_info_list;
int (*send_dsp_ipc_msg)(struct snd_skl_vfe *vfe,
--
https://clearlinux.org