diff options
author | Vaibhav Agarwal | 2016-01-28 16:45:40 +0100 |
---|---|---|
committer | Greg Kroah-Hartman | 2016-02-03 06:46:54 +0100 |
commit | 3994e0b139c709047cdeb44b6c28cfb39f89f3f2 (patch) | |
tree | 6cd7caf1fd59c104d0c0431adb80ef657d0eb973 /drivers/staging/greybus/audio_codec.c | |
parent | greybus: audio: codec driver cleanup (diff) | |
download | kernel-qcow2-linux-3994e0b139c709047cdeb44b6c28cfb39f89f3f2.tar.gz kernel-qcow2-linux-3994e0b139c709047cdeb44b6c28cfb39f89f3f2.tar.xz kernel-qcow2-linux-3994e0b139c709047cdeb44b6c28cfb39f89f3f2.zip |
greybus: audio: use variable 'is_connected' to maintain module state
there is race condition between _disconnect() request &
stop_trigger() in case of abrupt module removal.
And sometimes this can lead to deadlock while acquiring
codec_info->lock.
To avoid such situation, atomic variable is used to maintain
codec connected state.
During dai operations (trigger, shutdown, etc.), 'is_connected'
variable is validated to avoid unnecessary lock acquire in
case module already removed.
Signed-off-by: Vaibhav Agarwal <vaibhav.agarwal@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/audio_codec.c')
-rw-r--r-- | drivers/staging/greybus/audio_codec.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c index ad28c10fa154..c05ab4fb8754 100644 --- a/drivers/staging/greybus/audio_codec.c +++ b/drivers/staging/greybus/audio_codec.c @@ -44,6 +44,9 @@ static int gbcodec_startup(struct snd_pcm_substream *substream, struct gbaudio_dai *gb_dai; struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev); + if (!atomic_read(&gb->is_connected)) + return -ENODEV; + /* find the dai */ mutex_lock(&gb->lock); gb_dai = gbaudio_find_dai(gb, -1, dai->name); @@ -77,6 +80,9 @@ static void gbcodec_shutdown(struct snd_pcm_substream *substream, struct gbaudio_dai *gb_dai; struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev); + if (!atomic_read(&gb->is_connected)) + return; + /* find the dai */ mutex_lock(&gb->lock); gb_dai = gbaudio_find_dai(gb, -1, dai->name); @@ -129,6 +135,9 @@ static int gbcodec_hw_params(struct snd_pcm_substream *substream, struct gbaudio_dai *gb_dai; struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev); + if (!atomic_read(&gb->is_connected)) + return -ENODEV; + /* find the dai */ mutex_lock(&gb->lock); gb_dai = gbaudio_find_dai(gb, -1, dai->name); @@ -204,6 +213,9 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream, struct gbaudio_dai *gb_dai; struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev); + if (!atomic_read(&gb->is_connected)) + return -ENODEV; + /* find the dai */ mutex_lock(&gb->lock); gb_dai = gbaudio_find_dai(gb, -1, dai->name); @@ -278,6 +290,9 @@ static int gbcodec_trigger(struct snd_pcm_substream *substream, int cmd, struct gbaudio_dai *gb_dai; struct gbaudio_codec_info *gb = dev_get_drvdata(dai->dev); + if (!atomic_read(&gb->is_connected)) + return -ENODEV; + /* find the dai */ mutex_lock(&gb->lock); gb_dai = gbaudio_find_dai(gb, -1, dai->name); @@ -776,6 +791,7 @@ static int gb_audio_probe(struct gb_bundle *bundle, desc.devices = 0x2; /* todo */ gbcodec->manager_id = gb_audio_manager_add(&desc); + atomic_set(&gbcodec->is_connected, 1); list_add(&gbcodec->list, &gb_codec_list); dev_dbg(dev, "Add GB Audio device:%s\n", gbcodec->name); mutex_unlock(&gb_codec_list_lock); @@ -809,6 +825,7 @@ static void gb_audio_disconnect(struct gb_bundle *bundle) struct gbaudio_dai *dai, *_dai; mutex_lock(&gb_codec_list_lock); + atomic_set(&gbcodec->is_connected, 0); list_del(&gbcodec->list); /* inform uevent to above layers */ gb_audio_manager_remove(gbcodec->manager_id); |