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(-)
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; }