From eebb7a7a35c39b4ccea2795b99dfd5cb6538320f Mon Sep 17 00:00:00 2001 From: Li Yifan Date: Wed, 14 Oct 2026 09:45:19 +0800 Subject: [PATCH] ASoC: SOF: Intel: hda: stop CORB/RIRB DMA in hda_dsp_remove() If the deferred probe fails after hda_dsp_probe(), e.g. because the SOF firmware is not installed, the IOMMU reports a continuous stream of DMA write faults from the audio controller: [ 13.155983] sof-audio-pci-intel-nvl 0000:80:1f.3: error: sof_probe_work failed err: -2 [ 15.056446] DMAR: DRHD: handling fault status reg 2 [ 15.056457] DMAR: [DMA Write NO_PASID] Request device [0000:80:1f.3] fault addr 0xffffe000 [fault reason 0x71] SM: Present bit in first-level paging entry is clear hda_dsp_remove() frees the CORB/RIRB ring buffer in hda_dsp_stream_free() without stopping the controller, so RIRB DMA and unsolicited responses stay enabled. sof_pci_probe() has already returned success at this point, so the PCI device stays bound with bus mastering enabled, and every unsolicited response from the codec is written to the freed buffer. Without an IOMMU these writes would go to memory that may already have been reused. This was masked until commit 9e6966f70404 ("ASoC: SOF: Intel: hda: Keep non-alt mlinks powered at probe on ACE2+"): hda_bus_ml_put_all() at the end of hda_init_caps() dropped the last link reference, and snd_hdac_ext_bus_link_put() then stopped CORB/RIRB DMA as a side effect. Call hda_codec_stop_cmd_io() before the buffers are freed, to disable CORB/RIRB DMA and unsolicited responses. Fixes: 9e6966f70404 ("ASoC: SOF: Intel: hda: Keep non-alt mlinks powered at probe on ACE2+") Suggested-by: Bard Liao Assisted-by: LLM Signed-off-by: Li Yifan --- sound/soc/sof/intel/hda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index e1815bfe358b5d..16a30613aa1280 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1006,6 +1006,9 @@ void hda_dsp_remove(struct snd_sof_dev *sdev) snd_dma_free_pages(&hda->iccmax_dmab); skip_disable_dsp: + /* stop CORB/RIRB DMA before the ring buffers are freed below */ + hda_codec_stop_cmd_io(sdev); + free_irq(sdev->ipc_irq, sdev); if (sdev->msi_enabled) pci_free_irq_vectors(pci);