ASoC: apple: mca: Add locking
In DAI ops, accesses to the native cluster (of the DAI), and to data of clusters related to it by a DPCM frontend-backend link, should have been synchronized by the 'pcm_mutex' lock at ASoC level. What is not covered are the 'port_driver' accesses on foreign clusters to which the current cluster has no a priori relation, so fill in locking for that. (This should only matter in bizarre configurations of sharing one MCA peripheral between ASoC cards.) Signed-off-by: Martin Povišer <povik+lin@cutebit.org> Link: https://lore.kernel.org/r/20220824160715.95779-5-povik+lin@cutebit.org Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Родитель
3df5d0d972
Коммит
4065f0b25b
|
@ -158,6 +158,9 @@ struct mca_data {
|
|||
struct reset_control *rstc;
|
||||
struct device_link *pd_link;
|
||||
|
||||
/* Mutex for accessing port_driver of foreign clusters */
|
||||
struct mutex port_mutex;
|
||||
|
||||
int nclusters;
|
||||
struct mca_cluster clusters[];
|
||||
};
|
||||
|
@ -296,16 +299,21 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl)
|
|||
struct mca_cluster *be_cl;
|
||||
int stream, i;
|
||||
|
||||
mutex_lock(&mca->port_mutex);
|
||||
for (i = 0; i < mca->nclusters; i++) {
|
||||
be_cl = &mca->clusters[i];
|
||||
|
||||
if (be_cl->port_driver != cl->no)
|
||||
continue;
|
||||
|
||||
for_each_pcm_streams(stream)
|
||||
if (be_cl->clocks_in_use[stream])
|
||||
for_each_pcm_streams(stream) {
|
||||
if (be_cl->clocks_in_use[stream]) {
|
||||
mutex_unlock(&mca->port_mutex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mca->port_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -349,6 +357,11 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream,
|
|||
if (cl->port_driver < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* We are operating on a foreign cluster here, but since we
|
||||
* belong to the same PCM, accesses should have been
|
||||
* synchronized at ASoC level.
|
||||
*/
|
||||
fe_cl = &mca->clusters[cl->port_driver];
|
||||
if (!mca_fe_clocks_in_use(fe_cl))
|
||||
return 0; /* Nothing to do */
|
||||
|
@ -721,7 +734,9 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
|
|||
cl->base + REG_PORT_CLOCK_SEL);
|
||||
writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),
|
||||
cl->base + REG_PORT_DATA_SEL);
|
||||
mutex_lock(&mca->port_mutex);
|
||||
cl->port_driver = fe_cl->no;
|
||||
mutex_unlock(&mca->port_mutex);
|
||||
cl->port_started[substream->stream] = true;
|
||||
|
||||
return 0;
|
||||
|
@ -731,6 +746,7 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct mca_cluster *cl = mca_dai_to_cluster(dai);
|
||||
struct mca_data *mca = cl->host;
|
||||
|
||||
cl->port_started[substream->stream] = false;
|
||||
|
||||
|
@ -741,7 +757,9 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
|
|||
*/
|
||||
writel_relaxed(0, cl->base + REG_PORT_ENABLES);
|
||||
writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
|
||||
mutex_lock(&mca->port_mutex);
|
||||
cl->port_driver = -1;
|
||||
mutex_unlock(&mca->port_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -962,6 +980,7 @@ static int apple_mca_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
mca->dev = &pdev->dev;
|
||||
mca->nclusters = nclusters;
|
||||
mutex_init(&mca->port_mutex);
|
||||
platform_set_drvdata(pdev, mca);
|
||||
clusters = mca->clusters;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче