diff mbox series

[3/7] ASoC: SOF: Intel: Don't disable Soundwire interrupt before the bus has shut down

Message ID 20220907101402.4685-4-rf@opensource.cirrus.com (mailing list archive)
State New, archived
Headers show
Series soundwire: Fix driver removal | expand

Commit Message

Richard Fitzgerald Sept. 7, 2022, 10:13 a.m. UTC
Until the Soundwire child drivers have been removed and the bus driver has
shut down any of them can still be actively doing something. And any of
them may need bus transactions to shut down their hardware. So the
Soundwire interrupt must not be disabled until the point that nothing can
be using it.

Normally it is up to the driver using the interrupt to ensure that it
doesn't break if there is an interrupt while it is shutting down. However,
the design of the Intel drivers means that the Soundwire bus driver doesn't
have control of its own interrupt - instead its interrupt handler is called
externally by the code in hda.c. Therefore hda.c must shutdown the bus
before disabling the interrupt and freeing the context memory.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
---
 sound/soc/sof/intel/hda.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

Comments

Mark Brown Sept. 7, 2022, 11:26 a.m. UTC | #1
On Wed, Sep 07, 2022 at 11:13:58AM +0100, Richard Fitzgerald wrote:
> Until the Soundwire child drivers have been removed and the bus driver has
> shut down any of them can still be actively doing something. And any of
> them may need bus transactions to shut down their hardware. So the
> Soundwire interrupt must not be disabled until the point that nothing can
> be using it.

Acked-by: Mark Brown <broonie@kernel.org>
diff mbox series

Patch

diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index ee67e21e739f..34f5de052bc0 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -236,17 +236,25 @@  int hda_sdw_startup(struct snd_sof_dev *sdev)
 static int hda_sdw_exit(struct snd_sof_dev *sdev)
 {
 	struct sof_intel_hda_dev *hdev;
+	void *tmp_sdw;
 
 	hdev = sdev->pdata->hw_pdata;
-
-	hda_sdw_int_enable(sdev, false);
-
-	if (hdev->sdw) {
+	if (hdev->sdw)
 		sdw_intel_exit(hdev->sdw);
-		sdw_intel_remove(hdev->sdw);
-	}
+
+	/* The bus has now stopped so the interrupt can be disabled */
+	hda_sdw_int_enable(sdev, false);
+
+	/* Wait for last run of irq handler to complete */
+	synchronize_irq(sdev->ipc_irq);
+
+	/* Stop using the pointer */
+	tmp_sdw = hdev->sdw;
 	hdev->sdw = NULL;
 
+	if (tmp_sdw)
+		sdw_intel_remove(tmp_sdw);
+
 	return 0;
 }