aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-11-04 10:52:28 -0500
committerMark Brown <broonie@kernel.org>2014-11-04 12:18:32 -0500
commitea9d0d771fcd32cd56070819749477d511ec9117 (patch)
tree6471b62340c799e9604b92fdabdd3c0a97671182
parentf114040e3ea6e07372334ade75d1ee0775c355e1 (diff)
ASoC: dpcm: Fix race between FE/BE updates and trigger
DPCM can update the FE/BE connection states totally asynchronously from the FE's PCM state. Most of FE/BE state changes are protected by mutex, so that they won't race, but there are still some actions that are uncovered. For example, suppose to switch a BE while a FE's stream is running. This would call soc_dpcm_runtime_update(), which sets FE's runtime_update flag, then sets up and starts BEs, and clears FE's runtime_update flag again. When a device emits XRUN during this operation, the PCM core triggers snd_pcm_stop(XRUN). Since the trigger action is an atomic ops, this isn't blocked by the mutex, thus it kicks off DPCM's trigger action. It eventually updates and clears FE's runtime_update flag while soc_dpcm_runtime_update() is running concurrently, and it results in confusion. Usually, for avoiding such a race, we take a lock. There is a PCM stream lock for that purpose. However, as already mentioned, the trigger action is atomic, and we can't take the lock for the whole soc_dpcm_runtime_update() or other operations that include the lengthy jobs like hw_params or prepare. This patch provides an alternative solution. This adds a way to defer the conflicting trigger callback to be executed at the end of FE/BE state changes. For doing it, two things are introduced: - Each runtime_update state change of FEs is protected via PCM stream lock. - The FE's trigger callback checks the runtime_update flag. If it's not set, the trigger action is executed there. If set, mark the pending trigger action and returns immediately. - At the exit of runtime_update state change, it checks whether the pending trigger is present. If yes, it executes the trigger action at this point. Reported-and-tested-by: Qiao Zhou <zhouqiao@marvell.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Acked-by: Liam Girdwood <liam.r.girdwood@linux.intel.com> Signed-off-by: Mark Brown <broonie@kernel.org> Cc: stable@vger.kernel.org
-rw-r--r--include/sound/soc-dpcm.h2
-rw-r--r--sound/soc/soc-pcm.c72
2 files changed, 58 insertions, 16 deletions
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
index 2883a7a6f9f3..98f2ade0266e 100644
--- a/include/sound/soc-dpcm.h
+++ b/include/sound/soc-dpcm.h
@@ -102,6 +102,8 @@ struct snd_soc_dpcm_runtime {
102 /* state and update */ 102 /* state and update */
103 enum snd_soc_dpcm_update runtime_update; 103 enum snd_soc_dpcm_update runtime_update;
104 enum snd_soc_dpcm_state state; 104 enum snd_soc_dpcm_state state;
105
106 int trigger_pending; /* trigger cmd + 1 if pending, 0 if not */
105}; 107};
106 108
107/* can this BE stop and free */ 109/* can this BE stop and free */
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 002311afdeaa..57277dd79e11 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1522,13 +1522,36 @@ static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
1522 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture); 1522 dpcm_init_runtime_hw(runtime, &cpu_dai_drv->capture);
1523} 1523}
1524 1524
1525static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd);
1526
1527/* Set FE's runtime_update state; the state is protected via PCM stream lock
1528 * for avoiding the race with trigger callback.
1529 * If the state is unset and a trigger is pending while the previous operation,
1530 * process the pending trigger action here.
1531 */
1532static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe,
1533 int stream, enum snd_soc_dpcm_update state)
1534{
1535 struct snd_pcm_substream *substream =
1536 snd_soc_dpcm_get_substream(fe, stream);
1537
1538 snd_pcm_stream_lock_irq(substream);
1539 if (state == SND_SOC_DPCM_UPDATE_NO && fe->dpcm[stream].trigger_pending) {
1540 dpcm_fe_dai_do_trigger(substream,
1541 fe->dpcm[stream].trigger_pending - 1);
1542 fe->dpcm[stream].trigger_pending = 0;
1543 }
1544 fe->dpcm[stream].runtime_update = state;
1545 snd_pcm_stream_unlock_irq(substream);
1546}
1547
1525static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) 1548static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1526{ 1549{
1527 struct snd_soc_pcm_runtime *fe = fe_substream->private_data; 1550 struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
1528 struct snd_pcm_runtime *runtime = fe_substream->runtime; 1551 struct snd_pcm_runtime *runtime = fe_substream->runtime;
1529 int stream = fe_substream->stream, ret = 0; 1552 int stream = fe_substream->stream, ret = 0;
1530 1553
1531 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 1554 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
1532 1555
1533 ret = dpcm_be_dai_startup(fe, fe_substream->stream); 1556 ret = dpcm_be_dai_startup(fe, fe_substream->stream);
1534 if (ret < 0) { 1557 if (ret < 0) {
@@ -1550,13 +1573,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
1550 dpcm_set_fe_runtime(fe_substream); 1573 dpcm_set_fe_runtime(fe_substream);
1551 snd_pcm_limit_hw_rates(runtime); 1574 snd_pcm_limit_hw_rates(runtime);
1552 1575
1553 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 1576 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
1554 return 0; 1577 return 0;
1555 1578
1556unwind: 1579unwind:
1557 dpcm_be_dai_startup_unwind(fe, fe_substream->stream); 1580 dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
1558be_err: 1581be_err:
1559 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 1582 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
1560 return ret; 1583 return ret;
1561} 1584}
1562 1585
@@ -1603,7 +1626,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1603 struct snd_soc_pcm_runtime *fe = substream->private_data; 1626 struct snd_soc_pcm_runtime *fe = substream->private_data;
1604 int stream = substream->stream; 1627 int stream = substream->stream;
1605 1628
1606 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 1629 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
1607 1630
1608 /* shutdown the BEs */ 1631 /* shutdown the BEs */
1609 dpcm_be_dai_shutdown(fe, substream->stream); 1632 dpcm_be_dai_shutdown(fe, substream->stream);
@@ -1617,7 +1640,7 @@ static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
1617 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); 1640 dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
1618 1641
1619 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; 1642 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
1620 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 1643 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
1621 return 0; 1644 return 0;
1622} 1645}
1623 1646
@@ -1665,7 +1688,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
1665 int err, stream = substream->stream; 1688 int err, stream = substream->stream;
1666 1689
1667 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 1690 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
1668 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 1691 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
1669 1692
1670 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name); 1693 dev_dbg(fe->dev, "ASoC: hw_free FE %s\n", fe->dai_link->name);
1671 1694
@@ -1680,7 +1703,7 @@ static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
1680 err = dpcm_be_dai_hw_free(fe, stream); 1703 err = dpcm_be_dai_hw_free(fe, stream);
1681 1704
1682 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE; 1705 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
1683 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 1706 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
1684 1707
1685 mutex_unlock(&fe->card->mutex); 1708 mutex_unlock(&fe->card->mutex);
1686 return 0; 1709 return 0;
@@ -1773,7 +1796,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
1773 int ret, stream = substream->stream; 1796 int ret, stream = substream->stream;
1774 1797
1775 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); 1798 mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
1776 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 1799 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
1777 1800
1778 memcpy(&fe->dpcm[substream->stream].hw_params, params, 1801 memcpy(&fe->dpcm[substream->stream].hw_params, params,
1779 sizeof(struct snd_pcm_hw_params)); 1802 sizeof(struct snd_pcm_hw_params));
@@ -1796,7 +1819,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
1796 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS; 1819 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
1797 1820
1798out: 1821out:
1799 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 1822 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
1800 mutex_unlock(&fe->card->mutex); 1823 mutex_unlock(&fe->card->mutex);
1801 return ret; 1824 return ret;
1802} 1825}
@@ -1910,7 +1933,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
1910} 1933}
1911EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger); 1934EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
1912 1935
1913static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd) 1936static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
1914{ 1937{
1915 struct snd_soc_pcm_runtime *fe = substream->private_data; 1938 struct snd_soc_pcm_runtime *fe = substream->private_data;
1916 int stream = substream->stream, ret; 1939 int stream = substream->stream, ret;
@@ -1984,6 +2007,23 @@ out:
1984 return ret; 2007 return ret;
1985} 2008}
1986 2009
2010static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
2011{
2012 struct snd_soc_pcm_runtime *fe = substream->private_data;
2013 int stream = substream->stream;
2014
2015 /* if FE's runtime_update is already set, we're in race;
2016 * process this trigger later at exit
2017 */
2018 if (fe->dpcm[stream].runtime_update != SND_SOC_DPCM_UPDATE_NO) {
2019 fe->dpcm[stream].trigger_pending = cmd + 1;
2020 return 0; /* delayed, assuming it's successful */
2021 }
2022
2023 /* we're alone, let's trigger */
2024 return dpcm_fe_dai_do_trigger(substream, cmd);
2025}
2026
1987int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) 2027int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
1988{ 2028{
1989 struct snd_soc_dpcm *dpcm; 2029 struct snd_soc_dpcm *dpcm;
@@ -2027,7 +2067,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
2027 2067
2028 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name); 2068 dev_dbg(fe->dev, "ASoC: prepare FE %s\n", fe->dai_link->name);
2029 2069
2030 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; 2070 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
2031 2071
2032 /* there is no point preparing this FE if there are no BEs */ 2072 /* there is no point preparing this FE if there are no BEs */
2033 if (list_empty(&fe->dpcm[stream].be_clients)) { 2073 if (list_empty(&fe->dpcm[stream].be_clients)) {
@@ -2054,7 +2094,7 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
2054 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; 2094 fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
2055 2095
2056out: 2096out:
2057 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 2097 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
2058 mutex_unlock(&fe->card->mutex); 2098 mutex_unlock(&fe->card->mutex);
2059 2099
2060 return ret; 2100 return ret;
@@ -2201,11 +2241,11 @@ static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
2201{ 2241{
2202 int ret; 2242 int ret;
2203 2243
2204 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; 2244 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
2205 ret = dpcm_run_update_startup(fe, stream); 2245 ret = dpcm_run_update_startup(fe, stream);
2206 if (ret < 0) 2246 if (ret < 0)
2207 dev_err(fe->dev, "ASoC: failed to startup some BEs\n"); 2247 dev_err(fe->dev, "ASoC: failed to startup some BEs\n");
2208 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 2248 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
2209 2249
2210 return ret; 2250 return ret;
2211} 2251}
@@ -2214,11 +2254,11 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
2214{ 2254{
2215 int ret; 2255 int ret;
2216 2256
2217 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE; 2257 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
2218 ret = dpcm_run_update_shutdown(fe, stream); 2258 ret = dpcm_run_update_shutdown(fe, stream);
2219 if (ret < 0) 2259 if (ret < 0)
2220 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n"); 2260 dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
2221 fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; 2261 dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
2222 2262
2223 return ret; 2263 return ret;
2224} 2264}