Commit 4065f0b2 authored by Martin Povišer's avatar Martin Povišer Committed by Mark Brown

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: default avatarMartin Povišer <povik+lin@cutebit.org>
Link: https://lore.kernel.org/r/20220824160715.95779-5-povik+lin@cutebit.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 3df5d0d9
...@@ -158,6 +158,9 @@ struct mca_data { ...@@ -158,6 +158,9 @@ struct mca_data {
struct reset_control *rstc; struct reset_control *rstc;
struct device_link *pd_link; struct device_link *pd_link;
/* Mutex for accessing port_driver of foreign clusters */
struct mutex port_mutex;
int nclusters; int nclusters;
struct mca_cluster clusters[]; struct mca_cluster clusters[];
}; };
...@@ -296,16 +299,21 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl) ...@@ -296,16 +299,21 @@ static bool mca_fe_clocks_in_use(struct mca_cluster *cl)
struct mca_cluster *be_cl; struct mca_cluster *be_cl;
int stream, i; int stream, i;
mutex_lock(&mca->port_mutex);
for (i = 0; i < mca->nclusters; i++) { for (i = 0; i < mca->nclusters; i++) {
be_cl = &mca->clusters[i]; be_cl = &mca->clusters[i];
if (be_cl->port_driver != cl->no) if (be_cl->port_driver != cl->no)
continue; continue;
for_each_pcm_streams(stream) for_each_pcm_streams(stream) {
if (be_cl->clocks_in_use[stream]) if (be_cl->clocks_in_use[stream]) {
mutex_unlock(&mca->port_mutex);
return true; return true;
}
}
} }
mutex_unlock(&mca->port_mutex);
return false; return false;
} }
...@@ -349,6 +357,11 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream, ...@@ -349,6 +357,11 @@ static int mca_be_hw_free(struct snd_pcm_substream *substream,
if (cl->port_driver < 0) if (cl->port_driver < 0)
return -EINVAL; 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]; fe_cl = &mca->clusters[cl->port_driver];
if (!mca_fe_clocks_in_use(fe_cl)) if (!mca_fe_clocks_in_use(fe_cl))
return 0; /* Nothing to do */ return 0; /* Nothing to do */
...@@ -721,7 +734,9 @@ static int mca_be_startup(struct snd_pcm_substream *substream, ...@@ -721,7 +734,9 @@ static int mca_be_startup(struct snd_pcm_substream *substream,
cl->base + REG_PORT_CLOCK_SEL); cl->base + REG_PORT_CLOCK_SEL);
writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no), writel_relaxed(PORT_DATA_SEL_TXA(fe_cl->no),
cl->base + REG_PORT_DATA_SEL); cl->base + REG_PORT_DATA_SEL);
mutex_lock(&mca->port_mutex);
cl->port_driver = fe_cl->no; cl->port_driver = fe_cl->no;
mutex_unlock(&mca->port_mutex);
cl->port_started[substream->stream] = true; cl->port_started[substream->stream] = true;
return 0; return 0;
...@@ -731,6 +746,7 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream, ...@@ -731,6 +746,7 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct mca_cluster *cl = mca_dai_to_cluster(dai); struct mca_cluster *cl = mca_dai_to_cluster(dai);
struct mca_data *mca = cl->host;
cl->port_started[substream->stream] = false; cl->port_started[substream->stream] = false;
...@@ -741,7 +757,9 @@ static void mca_be_shutdown(struct snd_pcm_substream *substream, ...@@ -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_ENABLES);
writel_relaxed(0, cl->base + REG_PORT_DATA_SEL); writel_relaxed(0, cl->base + REG_PORT_DATA_SEL);
mutex_lock(&mca->port_mutex);
cl->port_driver = -1; cl->port_driver = -1;
mutex_unlock(&mca->port_mutex);
} }
} }
...@@ -962,6 +980,7 @@ static int apple_mca_probe(struct platform_device *pdev) ...@@ -962,6 +980,7 @@ static int apple_mca_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
mca->dev = &pdev->dev; mca->dev = &pdev->dev;
mca->nclusters = nclusters; mca->nclusters = nclusters;
mutex_init(&mca->port_mutex);
platform_set_drvdata(pdev, mca); platform_set_drvdata(pdev, mca);
clusters = mca->clusters; clusters = mca->clusters;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment