ASoC: amd: fix IRQ handler races in AMD SoundWire drivers
Subsystems (4)
Vijendar Mukunda
maintainercover ASoC: amd: fix IRQ handler races in AMD SoundWire drivers
These four patches fix two related race conditions in the AMD SoundWire IRQ handlers for the PS (ACP63) and SOF platforms.
Patches 1 and 2 guard against a NULL dereference in the ACP external IRQ handler. The handler is registered before sdw_amd_probe() assigns adata->sdw, so a stray interrupt in the probe window, or one that fires after sdw_amd_exit() frees the context, can reach the adata->sdw->pdev[i] dereference with adata->sdw still NULL.
Patches 3 and 4 guard schedule_work() calls with the interrupt_enabled flag so that an in-flight IRQ arriving while the SoundWire manager is being torn down does not queue new work after amd_disable_sdw_interrupts() has cleared the flag.
NOTE: Patches 3 and 4 depend on the following patch which introduces the interrupt_enabled field in the AMD SoundWire manager:
https://lore.kernel.org/linux-sound/[email protected]/
Until that patch is merged, patches 3 and 4 should not be picked up independently.
Vijendar Mukunda (4):
ASoC: amd: ps: guard adata->sdw dereferences with NULL check in IRQ
handler
ASoC: SOF: amd: guard adata->sdw dereferences with NULL check in IRQ
handler
ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled
flag
ASoC: amd: ps: guard SDW IRQ work scheduling with interrupt_enabled
flag
sound/soc/amd/ps/pci-ps.c | 32 ++++++++++++++++++++------------ sound/soc/sof/amd/acp.c | 32 ++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 24 deletions(-)
--
2.53.0
Vijendar Mukunda
maintainerPATCH 1/4 ASoC: amd: ps: guard adata->sdw dereferences with NULL check in IRQ handler
The ACP external IRQ handler is registered before sdw_amd_probe() assigns adata->sdw, so a stray interrupt in the probe window could reach the adata->sdw->pdev[i] dereference with adata->sdw still NULL.
The same window exists on the teardown side: after sdw_amd_exit() frees the context but before adata->sdw is cleared by the caller.
Add NULL checks for adata->sdw in acp63_irq_handler() before dereferencing ->pdev[0] and ->pdev[1], and in handle_acp70_sdw_wake_event() for the same reason. The interrupt-status register write that acknowledges the IRQ is kept outside the guard so the hardware bit is always cleared regardless of whether the SoundWire context is live.
--- sound/soc/amd/ps/pci-ps.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
sound/soc/amd/ps/pci-ps.c +20 -12
@@ -26,16 +26,20 @@ static void handle_acp70_sdw_wake_event(struct acp63_dev_data *adata)struct amd_sdw_manager *amd_manager;if (adata->acp70_sdw0_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw0_wake_event =0 ; }if (adata->acp70_sdw1_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw1_wake_event =0 ; } }
@@ -209,18 +213,22 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) ext_intr_stat =readl (adata->acp63_base +ACP_EXTERNAL_INTR_STAT );if (ext_intr_stat &ACP_SDW0_STAT ) {writel (ACP_SDW0_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT ); - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; } ext_intr_stat1 =readl (adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 );if (ext_intr_stat1 &ACP_SDW1_STAT ) {writel (ACP_SDW1_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 ); - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; }
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH 1/4] ASoC: amd: ps: guard adata->sdw dereferences with NULL check in IRQ handler
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider: - [Medium] ASoC: amd: ps: NULL deref of adata->sdw->pdev[i] on single-link SDW configs - [Low] ASoC: amd: ps…
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [Medium] ASoC: amd: ps: NULL deref of adata->sdw->pdev[i] on single-link SDW configs
- [Low] ASoC: amd: ps: inaccurate commit message teardown claim and Fixes tag
It also noticed 1 related pre-existing issue this patch does not introduce:
- [Critical] soundwire: amd: use-after-free in amd_sdw_manager_remove()
[1]
--
commit 929ea19624010c51ae72f2eb65f2e1a41edc5971
Author: Vijendar Mukunda <[email protected]>
Quoted 9 lines
ASoC: amd: ps: guard
adata->sdwdereferences with NULL check in IRQ handlerThe ACP external IRQ handler is registered before
sdw_amd_probe()assignsadata->sdw, so a stray interrupt in the probe window could reach the adata->sdw->pdev[i] dereference withadata->sdwstill NULL.The same window exists on the teardown side: after
sdw_amd_exit()frees the context but beforeadata->sdwis cleared by the caller.
Quoted 8 lines
Add NULL checks for
adata->sdwinacp63_irq_handler()before dereferencing ->pdev[0] and ->pdev[1], and inhandle_acp70_sdw_wake_event()for the same reason. The interrupt-status register write that acknowledges the IRQ is kept outside the guard so the hardware bit is always cleared regardless of whether the SoundWire context is live.Fixes e1cb350610ce ("ASoC: amd: ps: handle SoundWire interrupts in acp pci driver")Signed-off-by Vijendar Mukunda <[email protected]>
[Severity: Low]
Is the teardown description and Fixes tag accurate here?
In amd_sdw_exit(), sdw_amd_exit(acp_data->sdw) frees the context while acp_data->sdw is still non-NULL, and acp_data->sdw = NULL only runs after sdw_amd_exit() returns, so an if (adata->sdw) check in that window would see a dangling non-NULL pointer rather than NULL (snd_acp63_remove() instead avoids this by calling acp_hw_disable_interrupts() and devm_free_irq() before amd_sdw_exit()).
Also, e1cb350610ce ("ASoC: amd: ps: handle SoundWire interrupts in acp pci driver") predates adata->sdw. The adata->sdw dereferences in acp63_irq_handler() were introduced by eaf825037d6d ("ASoC: amd: ps:
refactor acp child platform device creation code"), and handle_acp70_sdw_wake_event() was added by 3898b189079c ("ASoC: amd: ps:
add soundwire wake interrupt handling").
Quoted 49 lines
sound/soc/amd/ps/pci-ps.c +15
-9@@ -26,16 +26,20 @@ static void handle_acp70_sdw_wake_event(struct acp63_dev_data *adata)struct amd_sdw_manager *amd_manager;if (adata->acp70_sdw0_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw0_wake_event =0 ; }if (adata->acp70_sdw1_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw1_wake_event =0 ; } }@@ -209,18 +213,22 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) ext_intr_stat =readl (adata->acp63_base +ACP_EXTERNAL_INTR_STAT );if (ext_intr_stat &ACP_SDW0_STAT ) {writel (ACP_SDW0_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT ); - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; } ext_intr_stat1 =readl (adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 );if (ext_intr_stat1 &ACP_SDW1_STAT ) {writel (ACP_SDW1_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 );
sound/soc/amd/ps/pci-ps.c static irqreturn_t acp63_irq_handler(int irq, void *dev_id) · line 233
Quoted 10 lines
sound/soc/amd/ps/pci-ps.c +5
-3- amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; }
[Severity: Medium]
Can adata->sdw->pdev[0] or adata->sdw->pdev[1] still be NULL when adata->sdw is non-NULL?
In sdw_amd_probe_controller(), ctx->pdev[index] is only registered for links set in link_mask:
drivers/soundwire/amd_init.c:sdw_amd_probe_controller() {
...
for (index = 0; index < count; index++) {
if (!(link_mask & BIT(index)))
continue;
...
ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]);
}On single-link configurations (where link_mask is BIT(0) or BIT(1)), adata->sdw is non-NULL while the unused link's pdev[i] remains NULL. A stray interrupt or wake event for that link in acp63_irq_handler() or handle_acp70_sdw_wake_event() will then pass &adata->sdw->pdev[i]->dev to dev_get_drvdata() and cause a NULL pointer dereference, as acp70_enable_sdw_host_wake_interrupts() unmasks ACP70_SDW_HOST_WAKE_MASK for both links whenever either link enables host wake.
Should these checks also verify adata->sdw->pdev[0] and adata->sdw->pdev[1] (like handle_acp63_sdw_pme_event() does)?
[Severity: Critical]
This problem wasn't introduced by this patch, but can unbinding the child SoundWire manager device race with acp63_irq_handler() and cause a use-after-free of amd_manager [1]?
CPU0 CPU1acp63_irq_handler()
amd_manager = dev_get_drvdata()
amd_sdw_manager_remove()
cancel_work_sync(...) amd_disable_sdw_interrupts()
<driver core frees amd_manager>
if (amd_manager)
schedule_work(&amd_manager->amd_sdw_irq_thread); <-- use-after-free
amd_sdw_manager_remove() masks SoundWire interrupts and cancels amd_sdw_work, but does not synchronize with the parent ACP IRQ handler or cancel amd_sdw_irq_thread before devres frees amd_manager. If acp63_irq_handler() reads amd_manager before removal finishes and calls schedule_work() afterwards, it queues work on the freed amd_manager.
[1] https://sashiko.dev/#/bug/linux-ab458b2e-f505-4a41-8238-a93ceb5d9c77
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Mukunda,Vijendar
maintainerRe: [PATCH 1/4] ASoC: amd: ps: guard adata->sdw dereferences with NULL check in IRQ handler
Quoted 30 lines · On 11/7/26 23:42, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [Medium] ASoC: amd: ps: NULL deref of adata->sdw->pdev[i] on single-link SDW configs
- [Low] ASoC: amd: ps: inaccurate commit message teardown claim and Fixes tag
It also noticed 1 related pre-existing issue this patch does not introduce:
- [Critical] soundwire: amd: use-after-free inamd_sdw_manager_remove()
[1]
--commit
929ea19624010c51ae72f2eb65f2e1a41edc5971
Author: Vijendar Mukunda <[email protected]>Quoted 15 lines
ASoC: amd: ps: guard
adata->sdwdereferences with NULL check in IRQ handlerThe ACP external IRQ handler is registered before
sdw_amd_probe()assignsadata->sdw, so a stray interrupt in the probe window could reach the adata->sdw->pdev[i] dereference withadata->sdwstill NULL.The same window exists on the teardown side: after
sdw_amd_exit()frees the context but beforeadata->sdwis cleared by the caller.Add NULL checks for
adata->sdwinacp63_irq_handler()before dereferencing ->pdev[0] and ->pdev[1], and inhandle_acp70_sdw_wake_event()for the same reason. The interrupt-status register write that acknowledges the IRQ is kept outside the guard so the hardware bit is always cleared regardless of whether the SoundWire context is live.
Quoted 4 lines
Quoted 2 lines
Fixes e1cb350610ce ("ASoC: amd: ps: handle SoundWire interrupts in acp pci driver")Signed-off-by Vijendar Mukunda <[email protected]>[Severity: Low]
Is the teardown description and Fixes tag accurate here?
you are correct. During teardown adata->sdw
is non-NULL while sdw_amd_exit() runs and is set to NULL only afterwards, so the if (adata->sdw) guard sees a dangling pointer rather than NULL in that window. snd_acp63_remove() avoids the race by calling acp_hw_disable_interrupts() and devm_free_irq() before amd_sdw_exit(). The teardown sentence will be removed from the commit message in v2.
Quoted 8 lines
In
amd_sdw_exit(),sdw_amd_exit(acp_data->sdw)frees the context whileacp_data->sdwis still non-NULL, andacp_data->sdw= NULL only runs aftersdw_amd_exit()returns, so an if (adata->sdw) check in that window would see a dangling non-NULL pointer rather than NULL (snd_acp63_remove()instead avoids this by callingacp_hw_disable_interrupts()anddevm_free_irq()beforeamd_sdw_exit()).
Quoted 6 lines
Also,
e1cb350610ce("ASoC: amd: ps: handle SoundWire interrupts in acp pci driver") predatesadata->sdw. Theadata->sdwdereferences inacp63_irq_handler()were introduced byeaf825037d6d("ASoC: amd: ps:
refactor acp child platform device creation code"), andhandle_acp70_sdw_wake_event()was added by3898b189079c("ASoC: amd: ps:
add soundwire wake interrupt handling").
Will use correct Fixes tag
Quoted 47 lines
Quoted 47 lines
sound/soc/amd/ps/pci-ps.c +15
-9@@ -26,16 +26,20 @@ static void handle_acp70_sdw_wake_event(struct acp63_dev_data *adata)struct amd_sdw_manager *amd_manager;if (adata->acp70_sdw0_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw0_wake_event =0 ; }if (adata->acp70_sdw1_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw1_wake_event =0 ; } }@@ -209,18 +213,22 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) ext_intr_stat =readl (adata->acp63_base +ACP_EXTERNAL_INTR_STAT );if (ext_intr_stat &ACP_SDW0_STAT ) {writel (ACP_SDW0_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT ); - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; }
Quoted 16 lines
sound/soc/amd/ps/pci-ps.c static irqreturn_t acp63_irq_handler(int irq, void *dev_id) · line 233
Quoted 13 lines
sound/soc/amd/ps/pci-ps.c +5
-3ext_intr_stat1 =readl (adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 );if (ext_intr_stat1 &ACP_SDW1_STAT ) {writel (ACP_SDW1_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 ); - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; }[Severity: Medium]
Can adata->sdw->pdev[0] or adata->sdw->pdev[1] still be NULL whenadata->sdwis non-NULL?
for ACP6.3/7.0/7.1/7.2, all link platform
devices are probed and registered during sdw_amd_probe_controller(). The AMD-specific enable mask only controls whether the start sequence is invoked for a given link, not whether its pdev is registered. So pdev[0] and pdev[1] are always non-NULL when adata->sdw is non-NULL. No additional pdev[i] NULL checks are needed.
Quoted 20 lines
In
sdw_amd_probe_controller(), ctx->pdev[index] is only registered for links set inlink_mask:drivers/soundwire/amd_init.c:sdw_amd_probe_controller() { ... for (index = 0; index < count; index++) { if (!(link_mask & BIT(index))) continue; ... ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]); }On single-link configurations (where
link_maskis BIT(0) or BIT(1)),adata->sdwis non-NULL while the unused link's pdev[i] remains NULL. A stray interrupt or wake event for that link inacp63_irq_handler()orhandle_acp70_sdw_wake_event()will then pass &adata->sdw->pdev[i]->dev todev_get_drvdata()and cause a NULL pointer dereference, asacp70_enable_sdw_host_wake_interrupts()unmasksACP70_SDW_HOST_WAKE_MASKfor both links whenever either link enables host wake.
Quoted 7 lines
Should these checks also verify adata->sdw->pdev[0] and adata->sdw->pdev[1] (like
handle_acp63_sdw_pme_event()does)?[Severity: Critical]
This problem wasn't introduced by this patch, but can unbinding the child SoundWire manager device race withacp63_irq_handler()and cause a use-after-free ofamd_manager[1]?
The IRQ related fixes including this gap are addressed in the following series:
https://lore.kernel.org/linux-sound/[email protected]/
Quoted 19 lines
CPU0 CPU1
acp63_irq_handler()
amd_manager=dev_get_drvdata()
amd_sdw_manager_remove()
cancel_work_sync(...)amd_disable_sdw_interrupts()
<driver core freesamd_manager>
if (amd_manager)schedule_work(&amd_manager->amd_sdw_irq_thread); <-- use-after-free
amd_sdw_manager_remove()masks SoundWire interrupts and cancelsamd_sdw_work, but does not synchronize with the parent ACP IRQ handler or cancelamd_sdw_irq_threadbefore devres freesamd_manager. Ifacp63_irq_handler()readsamd_managerbefore removal finishes and callsschedule_work()afterwards, it queues work on the freedamd_manager.[1] https://sashiko.dev/#/bug/linux-ab458b2e-f505-4a41-8238-a93ceb5d9c77
Vijendar Mukunda
maintainerPATCH 2/4 ASoC: SOF: amd: guard adata->sdw dereferences with NULL check in IRQ handler
In reply to Vijendar MukundaThe ACP external IRQ handler is registered before sdw_amd_probe() assigns adata->sdw, so a stray interrupt in the probe window could reach the adata->sdw->pdev[i] dereference with adata->sdw still NULL.
The same window exists on the teardown side: after sdw_amd_exit() frees the context but before adata->sdw is cleared by the caller.
Add NULL checks for adata->sdw in acp_irq_handler() before dereferencing ->pdev[0] and ->pdev[1], and in amd_sof_handle_acp70_sdw_wake_event() for the same reason. The interrupt-status register write that acknowledges the IRQ is kept outside the guard so the hardware bit is always cleared regardless of whether the SoundWire context is live.
--- sound/soc/sof/amd/acp.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-)
sound/soc/sof/amd/acp.c +20 -12
@@ -478,16 +478,20 @@ static void amd_sof_handle_acp70_sdw_wake_event(struct acp_dev_data *adata)struct amd_sdw_manager *amd_manager;if (adata->acp70_sdw0_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw0_wake_event =0 ; }if (adata->acp70_sdw1_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw1_wake_event =0 ; } }
@@ -579,10 +583,12 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) val =snd_sof_dsp_read (sdev,ACP_DSP_BAR , desc->ext_intr_stat);if (val &ACP_SDW0_IRQ_MASK ) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev);snd_sof_dsp_write (sdev,ACP_DSP_BAR , desc->ext_intr_stat,ACP_SDW0_IRQ_MASK ); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; }
@@ -608,11 +614,13 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)if (desc->ext_intr_stat1) { val =snd_sof_dsp_read (sdev,ACP_DSP_BAR , desc->ext_intr_stat1);if (val &ACP_SDW1_IRQ_MASK ) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev);snd_sof_dsp_write (sdev,ACP_DSP_BAR , desc->ext_intr_stat1,ACP_SDW1_IRQ_MASK ); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; }switch (adata->pci_rev) {
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH 2/4] ASoC: SOF: amd: guard adata->sdw dereferences with NULL check in IRQ handler
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider: - [Medium] ASoC: SOF: amd: NULL dereference of adata->sdw->pdev[i] in acp_irq_handler() - [Low] ASoC: SOF…
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [Medium] ASoC: SOF: amd: NULL dereference of adata->sdw->pdev[i] in acp_irq_handler()
- [Low] ASoC: SOF: amd: inaccurate teardown claim and missing Fixes tag It also noticed 1 related pre-existing issue this patch does not introduce:
- [Medium] soundwire: amd: memory and platform device leaks in sdw_amd_probe() [1]
--
commit 920e1ff1deb60367eb67bae9d4d4b5880a64d07f
Author: Vijendar Mukunda <[email protected]>
Quoted 9 lines
ASoC: SOF: amd: guard
adata->sdwdereferences with NULL check in IRQ handlerThe ACP external IRQ handler is registered before
sdw_amd_probe()assignsadata->sdw, so a stray interrupt in the probe window could reach the adata->sdw->pdev[i] dereference withadata->sdwstill NULL.The same window exists on the teardown side: after
sdw_amd_exit()frees the context but beforeadata->sdwis cleared by the caller.
Quoted 8 lines
Add NULL checks for
adata->sdwinacp_irq_handler()before dereferencing ->pdev[0] and ->pdev[1], and inamd_sof_handle_acp70_sdw_wake_event()for the same reason. The interrupt-status register write that acknowledges the IRQ is kept outside the guard so the hardware bit is always cleared regardless of whether the SoundWire context is live.Fixes 96eb81851012 ("ASoC: SOF: amd: add interrupt handling for SoundWire manager devices")Signed-off-by Vijendar Mukunda <[email protected]>
[Severity: Low]
Is the teardown window description in the second paragraph accurate? In amd_sof_sdw_exit(), sdw_amd_exit(acp_data->sdw) frees the context before acp_data->sdw = NULL runs, so adata->sdw is still non-NULL during that interval and an if (adata->sdw) check cannot guard it; teardown is safe instead because callers invoke free_irq(sdev->ipc_irq, sdev) before calling amd_sof_sdw_exit().
Also, since the unguarded adata->sdw dereferences in amd_sof_handle_acp70_sdw_wake_event() were introduced by a later commit, should this include:
Quoted 53 lines
sound/soc/sof/amd/acp.c +15
-10@@ -478,16 +478,20 @@ static void amd_sof_handle_acp70_sdw_wake_event(struct acp_dev_data *adata)struct amd_sdw_manager *amd_manager;if (adata->acp70_sdw0_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw0_wake_event =0 ; }if (adata->acp70_sdw1_wake_event) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) -pm_request_resume (amd_manager->dev); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +pm_request_resume (amd_manager->dev); + } adata->acp70_sdw1_wake_event =0 ; } }@@ -579,10 +583,12 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) val =snd_sof_dsp_read (sdev,ACP_DSP_BAR , desc->ext_intr_stat);if (val &ACP_SDW0_IRQ_MASK ) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev);snd_sof_dsp_write (sdev,ACP_DSP_BAR , desc->ext_intr_stat,ACP_SDW0_IRQ_MASK ); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; }@@ -608,11 +614,13 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)if (desc->ext_intr_stat1) { val =snd_sof_dsp_read (sdev,ACP_DSP_BAR , desc->ext_intr_stat1);if (val &ACP_SDW1_IRQ_MASK ) { - amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
sound/soc/sof/amd/acp.c static irqreturn_t acp_irq_handler(int irq, void *dev_id) · line 625
Quoted 10 lines
sound/soc/sof/amd/acp.c +5
-2ACP_SDW1_IRQ_MASK); -if (amd_manager) -schedule_work (&amd_manager->amd_sdw_irq_thread); +if (adata->sdw) { + amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); +if (amd_manager) +schedule_work (&amd_manager->amd_sdw_irq_thread); + } irq_flag =1 ; }
[Severity: Medium]
Can adata->sdw->pdev[0] or adata->sdw->pdev[1] still be NULL here when adata->sdw is non-NULL?
In sdw_amd_probe_controller(), ctx->pdev[index] is only populated for links set in link_mask:
drivers/soundwire/amd_init.c:sdw_amd_probe_controller() {
...
for (index = 0; index < count; index++) {
if (!(link_mask & BIT(index)))
continue;
...
ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]);
...
}On single-link configurations where only one SoundWire manager is active, the unused link's pdev[i] remains NULL while adata->sdw is non-NULL. Passing &adata->sdw->pdev[i]->dev to dev_get_drvdata() on a stray interrupt or wake event for the unpopulated link will cause a NULL pointer dereference in hard IRQ context, unlike the sibling ACP7x handlers in this file (such as sof_acp7x_handle_sdw_manager_irq()) which check adata->sdw->pdev[instance] before calling dev_get_drvdata().
[Severity: Medium]
This problem wasn't introduced by this patch, but in the same SoundWire probe path [1], does a failure in sdw_amd_startup() leak the sdw_amd_ctx memory and platform devices allocated by sdw_amd_probe_controller(), as well as adata->dmic_dev in amd_sof_acp_probe()?
drivers/soundwire/amd_init.c:sdw_amd_probe() {
*sdw_ctx = sdw_amd_probe_controller(res);
if (!*sdw_ctx)
return -ENODEV;
return sdw_amd_startup(*sdw_ctx);
}sound/soc/sof/amd/acp.c:amd_sof_acp_probe() {
...
adata->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec",
PLATFORM_DEVID_NONE, NULL, 0);
...
ret = amd_sof_sdw_probe(sdev);
if (ret < 0) {
dev_err(sdev->dev, "error: SoundWire probe error\n");
free_irq(sdev->ipc_irq, sdev);
return ret;
}
...
unregister_dev:
platform_device_unregister(adata->dmic_dev);
return ret;
}When sdw_amd_startup() fails, sdw_amd_probe() returns without unregistering the ctx->pdev[index] devices or freeing ctx, and amd_sof_acp_probe() returns directly after free_irq() instead of jumping to unregister_dev to unregister adata->dmic_dev.
[1] https://sashiko.dev/#/bug/linux-3af16781-2451-4877-8594-c12800a7bba5
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Vijendar Mukunda
maintainerPATCH 3/4 ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag
In reply to Vijendar Mukundaacp_irq_handler() in sound/soc/sof/amd/acp.c called schedule_work() for the SoundWire manager workqueue guarded only by a NULL check on amd_manager, the same gap fixed in the PS platform IRQ handler.
Add the interrupt_enabled check so that an in-flight IRQ arriving while the SoundWire manager is being torn down does not queue new work after amd_disable_sdw_interrupts() has cleared the flag.
--- sound/soc/sof/amd/acp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/sof/amd/acp.c +2 -2
@@ -586,7 +586,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)snd_sof_dsp_write (sdev,ACP_DSP_BAR , desc->ext_intr_stat,ACP_SDW0_IRQ_MASK );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;
@@ -618,7 +618,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) ACP_SDW1_IRQ_MASK);if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider: - [High] ASoC: SOF: amd: build failure in acp_irq_handler() on missing struct member - [Medium] ASoC: SOF…
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [High] ASoC: SOF: amd: build failure in acp_irq_handler() on missing struct member
- [Medium] ASoC: SOF: amd: unguarded work queue in sof_acp7x_handle_sdw_manager_irq()
--
commit 84b5998c660c53c97f1f81d73a850a90f66dfb5d
Author: Vijendar Mukunda <[email protected]>
ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag
This commit checks amd_manager->interrupt_enabled before calling schedule_work(&amd_manager->amd_sdw_irq_thread) in acp_irq_handler().
Quoted 14 lines
sound/soc/sof/amd/acp.c +1
-1@@ -586,7 +586,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)snd_sof_dsp_write (sdev,ACP_DSP_BAR , desc->ext_intr_stat,ACP_SDW0_IRQ_MASK );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;
sound/soc/sof/amd/acp.c static irqreturn_t acp_irq_handler(int irq, void *dev_id) · line 624
Quoted 8 lines
sound/soc/sof/amd/acp.c +1
-1@@ -618,7 +618,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) ACP_SDW1_IRQ_MASK);if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;
[Severity: High]
Does this break the build when CONFIG_SND_SOC_SOF_AMD_COMMON is enabled? struct amd_sdw_manager in include/linux/soundwire/sdw_amd.h has no interrupt_enabled member, and amd_enable_sdw_interrupts() and amd_disable_sdw_interrupts() in drivers/soundwire/amd_manager.c only update hardware interrupt mask registers without setting or clearing any software flag.
[Severity: Medium]
Assuming interrupt_enabled is added to struct amd_sdw_manager, should sof_acp7x_handle_sdw_manager_irq() also check amd_manager->interrupt_enabled before queuing amd_sdw_irq_thread?
sound/soc/sof/amd/acp.c:sof_acp7x_handle_sdw_manager_irq() {
...
amd_manager = dev_get_drvdata(&adata->sdw->pdev[instance]->dev);
if (amd_manager)
schedule_work(&amd_manager->amd_sdw_irq_thread);
}On ACP7x platforms, an in-flight IRQ in acp7x_irq_handler() racing with amd_sdw_manager_remove() or amd_deinit_sdw_manager() can still queue amd_sdw_irq_thread after interrupts are disabled and pending work is cancelled, leading to a use-after-free on amd_manager or register accesses to a disabled manager.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Mukunda,Vijendar
maintainerRe: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag
Quoted 46 lines · On 11/7/26 23:38, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [High] ASoC: SOF: amd: build failure inacp_irq_handler()on missing struct member
- [Medium] ASoC: SOF: amd: unguarded work queue insof_acp7x_handle_sdw_manager_irq()
--commit
84b5998c660c53c97f1f81d73a850a90f66dfb5d
Author: Vijendar Mukunda <[email protected]>ASoC: SOF: amd: guard SDW IRQ work scheduling with
interrupt_enabledflagThis commit checks
amd_manager->interrupt_enabledbefore callingschedule_work(&amd_manager->amd_sdw_irq_thread)inacp_irq_handler().Quoted 14 lines
sound/soc/sof/amd/acp.c +1
-1@@ -586,7 +586,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id)snd_sof_dsp_write (sdev,ACP_DSP_BAR , desc->ext_intr_stat,ACP_SDW0_IRQ_MASK );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;sound/soc/sof/amd/acp.c static irqreturn_t acp_irq_handler(int irq, void *dev_id) · line 624
Quoted 8 lines
sound/soc/sof/amd/acp.c +1
-1@@ -618,7 +618,7 @@ static irqreturn_t acp_irq_handler(int irq, void *dev_id) ACP_SDW1_IRQ_MASK);if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;[Severity: High]
Does this break the build whenCONFIG_SND_SOC_SOF_AMD_COMMONis enabled? structamd_sdw_managerininclude/linux/soundwire/sdw_amd.hhas nointerrupt_enabledmember, andamd_enable_sdw_interrupts()andamd_disable_sdw_interrupts()indrivers/soundwire/amd_manager.conly update hardware interrupt mask registers without setting or clearing any software flag.
Quoted 4 lines
[Severity: Medium]
Assuminginterrupt_enabledis added to structamd_sdw_manager, shouldsof_acp7x_handle_sdw_manager_irq()also checkamd_manager->interrupt_enabledbefore queuingamd_sdw_irq_thread?
The interrupt_enabled field is introduced by a prerequisite patch in the AMD SoundWire manager series:
https://lore.kernel.org/linux-sound/[email protected]/
The cover letter for this series explicitly notes that patches 3 and 4 depend on that patch and should not be picked up independently until it is merged. There is no build failure when the series is applied in the correct order.
Quoted 7 lines
sound/soc/sof/amd/acp.c:sof_acp7x_handle_sdw_manager_irq() {
...
amd_manager = dev_get_drvdata(&adata->sdw->pdev[instance]->dev);
if (amd_manager)
schedule_work(&amd_manager->amd_sdw_irq_thread);
}Quoted 5 lines
On ACP7x platforms, an in-flight IRQ in
acp7x_irq_handler()racing withamd_sdw_manager_remove()oramd_deinit_sdw_manager()can still queueamd_sdw_irq_threadafter interrupts are disabled and pending work is cancelled, leading to a use-after-free onamd_manageror register accesses to a disabled manager.
ACP7.B/7.F SoundWire manager support has not yet been added to the SoundWire driver, so adata->sdw is never assigned on ACP7x platforms and this branch is never entered. The interrupt_enabled guard for sof_acp7x_handle_sdw_manager_irq() will be addressed as part of the upcoming ACP7.B/7.F SoundWire support series.
Quoted 1 line
kernel test robot
build botRe: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag
In reply to Vijendar Mukundakernel test robot noticed the following build errors:
Hi Vijendar,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-sound/for-next]
[also build test ERROR on vkoul-dmaengine/next linus/master v7.4-rc1 next-20261105] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Vijendar-Mukunda/ASoC-amd-ps-guard-adata-sdw-dereferences-with-NULL-check-in-IRQ-handler/20261107-232226 base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next patch link: https://lore.kernel.org/r/20261107175339.3547918-4-Vijendar.Mukunda%40amd.com patch subject: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag config: x86_64-rhel-9.4-ltp (https://download.01.org/0day-ci/archive/20261108/[email protected]/config) compiler: gcc-14 (Debian 14.2.0-19) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261108/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
sound/soc/sof/amd/acp.c: In function 'acp_irq_handler':
>> sound/soc/sof/amd/acp.c:589:55: error: 'struct amd_sdw_manager' has no member named 'interrupt_enabled'
589 | if (amd_manager && amd_manager->interrupt_enabled)
| ^~
sound/soc/sof/amd/acp.c:621:63: error: 'struct amd_sdw_manager' has no member named 'interrupt_enabled'
621 | if (amd_manager && amd_manager->interrupt_enabled)
| ^~vim +589 sound/soc/sof/amd/acp.c
566
567 static irqreturn_t acp_irq_handler(int irq, void *dev_id)
568 {
569 struct amd_sdw_manager *amd_manager;
570 struct snd_sof_dev *sdev = dev_id;
571 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
572 struct acp_dev_data *adata = sdev->pdata->hw_pdata;
573 unsigned int base = desc->dsp_intr_base;
574 unsigned int val;
575 int irq_flag = 0, wake_irq_flag = 0;
576
577 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
578 if (val & ACP_DSP_TO_HOST_IRQ) {
579 snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET,
580 ACP_DSP_TO_HOST_IRQ);
581 return IRQ_WAKE_THREAD;
582 }
583
584 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
585 if (val & ACP_SDW0_IRQ_MASK) {
586 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_SDW0_IRQ_MASK);
587 if (adata->sdw) {
588 amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
> 589 if (amd_manager && amd_manager->interrupt_enabled)
590 schedule_work(&amd_manager->amd_sdw_irq_thread);
591 }
592 irq_flag = 1;
593 }
594
595 if (val & ACP_ERROR_IRQ_MASK) {
596 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
597 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0);
598 /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */
599 switch (adata->pci_rev) {
600 case ACP_RMB_PCI_ID:
601 case ACP63_PCI_ID:
602 case ACP70_PCI_ID:
603 case ACP71_PCI_ID:
604 case ACP72_PCI_ID:
605 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0);
606 break;
607 default:
608 break;
609 }
610 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0);
611 irq_flag = 1;
612 }
613
614 if (desc->ext_intr_stat1) {
615 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1);
616 if (val & ACP_SDW1_IRQ_MASK) {
617 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
618 ACP_SDW1_IRQ_MASK);
619 if (adata->sdw) {
620 amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
621 if (amd_manager && amd_manager->interrupt_enabled)
622 schedule_work(&amd_manager->amd_sdw_irq_thread);
623 }
624 irq_flag = 1;
625 }
626 switch (adata->pci_rev) {
627 case ACP70_PCI_ID:
628 case ACP71_PCI_ID:
629 case ACP72_PCI_ID:
630 wake_irq_flag = amd_sof_check_and_handle_acp70_sdw_wake_irq(sdev);
631 break;
632 }
633 }
634 if (irq_flag || wake_irq_flag)
635 return IRQ_HANDLED;
636 else
637 return IRQ_NONE;
638 }
639
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Mukunda,Vijendar
maintainerRe: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag
Quoted 18 lines · kernel test robot
Hi Vijendar,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-sound/for-next]
[also build test ERROR on vkoul-dmaengine/next linus/master v7.4-rc1 next-20261105] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]url: https://github.com/intel-lab-lkp/linux/commits/Vijendar-Mukunda/ASoC-amd-ps-guard-adata-sdw-dereferences-with-NULL-check-in-IRQ-handler/20261107-232226 base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next patch link: https://lore.kernel.org/r/20261107175339.3547918-4-Vijendar.Mukunda%40amd.com patch subject: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag config: x86_64-rhel-9.4-ltp (https://download.01.org/0day-ci/archive/20261108/[email protected]/config) compiler: gcc-14 (Debian 14.2.0-19) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261108/[email protected]/reproduce)
Quoted 9 lines
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/All errors (new ones prefixed by >>):
sound/soc/sof/amd/acp.c: In function 'acp_irq_handler':Quoted 1 line
Quoted 1 line
sound/soc/sof/amd/acp.c:589:55: error: 'structamd_sdw_manager' has no member named 'interrupt_enabled'
As mentioned in cover letter, Patch 3/4 & 4/4 has dependency on below patch which introduces the interrupt_enabled field in the AMD SoundWire manager:
https://lore.kernel.org/linux-sound/[email protected]/
Quoted 87 lines
589 | if (amd_manager && amd_manager->interrupt_enabled) | ^~ sound/soc/sof/amd/acp.c:621:63: error: 'struct amd_sdw_manager' has no member named 'interrupt_enabled' 621 | if (amd_manager && amd_manager->interrupt_enabled) | ^~vim +589
sound/soc/sof/amd/acp.c566 567 static irqreturn_t acp_irq_handler(int irq, void *dev_id) 568 { 569 struct amd_sdw_manager *amd_manager; 570 struct snd_sof_dev *sdev = dev_id; 571 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); 572 struct acp_dev_data *adata = sdev->pdata->hw_pdata; 573 unsigned int base = desc->dsp_intr_base; 574 unsigned int val; 575 int irq_flag = 0, wake_irq_flag = 0; 576 577 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); 578 if (val & ACP_DSP_TO_HOST_IRQ) { 579 snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, 580 ACP_DSP_TO_HOST_IRQ); 581 return IRQ_WAKE_THREAD; 582 } 583 584 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); 585 if (val & ACP_SDW0_IRQ_MASK) { 586 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_SDW0_IRQ_MASK); 587 if (adata->sdw) { 588 amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);Quoted 1 line
589 if (
amd_manager&&amd_manager->interrupt_enabled)590 schedule_work(&amd_manager->amd_sdw_irq_thread); 591 } 592 irq_flag = 1; 593 } 594 595 if (val & ACP_ERROR_IRQ_MASK) { 596 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); 597 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0); 598 /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */ 599 switch (adata->pci_rev) { 600 case ACP_RMB_PCI_ID: 601 case ACP63_PCI_ID: 602 case ACP70_PCI_ID: 603 case ACP71_PCI_ID: 604 case ACP72_PCI_ID: 605 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0); 606 break; 607 default: 608 break; 609 } 610 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); 611 irq_flag = 1; 612 } 613 614 if (desc->ext_intr_stat1) { 615 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1); 616 if (val & ACP_SDW1_IRQ_MASK) { 617 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1, 618 ACP_SDW1_IRQ_MASK); 619 if (adata->sdw) { 620 amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev); 621 if (amd_manager && amd_manager->interrupt_enabled) 622 schedule_work(&amd_manager->amd_sdw_irq_thread); 623 } 624 irq_flag = 1; 625 } 626 switch (adata->pci_rev) { 627 case ACP70_PCI_ID: 628 case ACP71_PCI_ID: 629 case ACP72_PCI_ID: 630 wake_irq_flag = amd_sof_check_and_handle_acp70_sdw_wake_irq(sdev); 631 break; 632 } 633 } 634 if (irq_flag || wake_irq_flag) 635 return IRQ_HANDLED; 636 else 637 return IRQ_NONE; 638 } 639--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag
In reply to Vijendar Mukundakernel test robot noticed the following build errors:
Hi Vijendar,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-sound/for-next]
[also build test ERROR on vkoul-dmaengine/next linus/master v7.4-rc1 next-20261105] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Vijendar-Mukunda/ASoC-amd-ps-guard-adata-sdw-dereferences-with-NULL-check-in-IRQ-handler/20261107-232226 base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next patch link: https://lore.kernel.org/r/20261107175339.3547918-4-Vijendar.Mukunda%40amd.com patch subject: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20261108/[email protected]/config) compiler: clang version 22.1.8 (https://github.com/llvm/llvm-project ca7933e47d3a3451d81e72ac174dcb5aa28b59d1) rustc: rustc 1.96.0 (ac68faa20 2026-05-25) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261108/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
>> sound/soc/sof/amd/acp.c:589:36: error: no member named 'interrupt_enabled' in 'struct amd_sdw_manager'
589 | if (amd_manager && amd_manager->interrupt_enabled)
| ~~~~~~~~~~~ ^
sound/soc/sof/amd/acp.c:621:37: error: no member named 'interrupt_enabled' in 'struct amd_sdw_manager'
621 | if (amd_manager && amd_manager->interrupt_enabled)
| ~~~~~~~~~~~ ^
2 errors generated.
vim +589 sound/soc/sof/amd/acp.c
566
567 static irqreturn_t acp_irq_handler(int irq, void *dev_id)
568 {
569 struct amd_sdw_manager *amd_manager;
570 struct snd_sof_dev *sdev = dev_id;
571 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
572 struct acp_dev_data *adata = sdev->pdata->hw_pdata;
573 unsigned int base = desc->dsp_intr_base;
574 unsigned int val;
575 int irq_flag = 0, wake_irq_flag = 0;
576
577 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET);
578 if (val & ACP_DSP_TO_HOST_IRQ) {
579 snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET,
580 ACP_DSP_TO_HOST_IRQ);
581 return IRQ_WAKE_THREAD;
582 }
583
584 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat);
585 if (val & ACP_SDW0_IRQ_MASK) {
586 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_SDW0_IRQ_MASK);
587 if (adata->sdw) {
588 amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
> 589 if (amd_manager && amd_manager->interrupt_enabled)
590 schedule_work(&amd_manager->amd_sdw_irq_thread);
591 }
592 irq_flag = 1;
593 }
594
595 if (val & ACP_ERROR_IRQ_MASK) {
596 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK);
597 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0);
598 /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */
599 switch (adata->pci_rev) {
600 case ACP_RMB_PCI_ID:
601 case ACP63_PCI_ID:
602 case ACP70_PCI_ID:
603 case ACP71_PCI_ID:
604 case ACP72_PCI_ID:
605 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0);
606 break;
607 default:
608 break;
609 }
610 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0);
611 irq_flag = 1;
612 }
613
614 if (desc->ext_intr_stat1) {
615 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1);
616 if (val & ACP_SDW1_IRQ_MASK) {
617 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1,
618 ACP_SDW1_IRQ_MASK);
619 if (adata->sdw) {
620 amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
621 if (amd_manager && amd_manager->interrupt_enabled)
622 schedule_work(&amd_manager->amd_sdw_irq_thread);
623 }
624 irq_flag = 1;
625 }
626 switch (adata->pci_rev) {
627 case ACP70_PCI_ID:
628 case ACP71_PCI_ID:
629 case ACP72_PCI_ID:
630 wake_irq_flag = amd_sof_check_and_handle_acp70_sdw_wake_irq(sdev);
631 break;
632 }
633 }
634 if (irq_flag || wake_irq_flag)
635 return IRQ_HANDLED;
636 else
637 return IRQ_NONE;
638 }
639
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Mukunda,Vijendar
maintainerRe: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag
Quoted 19 lines · kernel test robot
Hi Vijendar,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-sound/for-next]
[also build test ERROR on vkoul-dmaengine/next linus/master v7.4-rc1 next-20261105] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]url: https://github.com/intel-lab-lkp/linux/commits/Vijendar-Mukunda/ASoC-amd-ps-guard-adata-sdw-dereferences-with-NULL-check-in-IRQ-handler/20261107-232226 base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next patch link: https://lore.kernel.org/r/20261107175339.3547918-4-Vijendar.Mukunda%40amd.com patch subject: [PATCH 3/4] ASoC: SOF: amd: guard SDW IRQ work scheduling with interrupt_enabled flag config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20261108/[email protected]/config) compiler: clang version 22.1.8 (https://github.com/llvm/llvm-project ca7933e47d3a3451d81e72ac174dcb5aa28b59d1) rustc: rustc 1.96.0 (ac68faa20 2026-05-25) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261108/[email protected]/reproduce)
Quoted 8 lines
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/All errors (new ones prefixed by >>):
Quoted 1 line
Quoted 1 line
sound/soc/sof/amd/acp.c:589:36: error: no member named 'interrupt_enabled' in 'structamd_sdw_manager'
As mentioned in cover letter, Patch 3/4 & 4/4 has dependency on below patch which introduces the interrupt_enabled field in the AMD SoundWire manager:
https://lore.kernel.org/linux-sound/[email protected]/
This patch series was prepared based on ASoC tree.
Will combine these asoc patches along with Soundwire patches and will re spin the patch series.
Quoted 88 lines
589 | if (
amd_manager&&amd_manager->interrupt_enabled)
| ~~~~~~~~~~~ ^
sound/soc/sof/amd/acp.c:621:37: error: no member named 'interrupt_enabled' in 'structamd_sdw_manager'
621 | if (amd_manager&&amd_manager->interrupt_enabled)
| ~~~~~~~~~~~ ^
2 errors generated.vim +589
sound/soc/sof/amd/acp.c566 567 static irqreturn_t acp_irq_handler(int irq, void *dev_id) 568 { 569 struct amd_sdw_manager *amd_manager; 570 struct snd_sof_dev *sdev = dev_id; 571 const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata); 572 struct acp_dev_data *adata = sdev->pdata->hw_pdata; 573 unsigned int base = desc->dsp_intr_base; 574 unsigned int val; 575 int irq_flag = 0, wake_irq_flag = 0; 576 577 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET); 578 if (val & ACP_DSP_TO_HOST_IRQ) { 579 snd_sof_dsp_write(sdev, ACP_DSP_BAR, base + DSP_SW_INTR_STAT_OFFSET, 580 ACP_DSP_TO_HOST_IRQ); 581 return IRQ_WAKE_THREAD; 582 } 583 584 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat); 585 if (val & ACP_SDW0_IRQ_MASK) { 586 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_SDW0_IRQ_MASK); 587 if (adata->sdw) { 588 amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);Quoted 1 line
589 if (
amd_manager&&amd_manager->interrupt_enabled)590 schedule_work(&amd_manager->amd_sdw_irq_thread); 591 } 592 irq_flag = 1; 593 } 594 595 if (val & ACP_ERROR_IRQ_MASK) { 596 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat, ACP_ERROR_IRQ_MASK); 597 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_sw0_i2s_err_reason, 0); 598 /* ACP_SW1_I2S_ERROR_REASON is newly added register from rmb platform onwards */ 599 switch (adata->pci_rev) { 600 case ACP_RMB_PCI_ID: 601 case ACP63_PCI_ID: 602 case ACP70_PCI_ID: 603 case ACP71_PCI_ID: 604 case ACP72_PCI_ID: 605 snd_sof_dsp_write(sdev, ACP_DSP_BAR, ACP_SW1_I2S_ERROR_REASON, 0); 606 break; 607 default: 608 break; 609 } 610 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->acp_error_stat, 0); 611 irq_flag = 1; 612 } 613 614 if (desc->ext_intr_stat1) { 615 val = snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->ext_intr_stat1); 616 if (val & ACP_SDW1_IRQ_MASK) { 617 snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->ext_intr_stat1, 618 ACP_SDW1_IRQ_MASK); 619 if (adata->sdw) { 620 amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev); 621 if (amd_manager && amd_manager->interrupt_enabled) 622 schedule_work(&amd_manager->amd_sdw_irq_thread); 623 } 624 irq_flag = 1; 625 } 626 switch (adata->pci_rev) { 627 case ACP70_PCI_ID: 628 case ACP71_PCI_ID: 629 case ACP72_PCI_ID: 630 wake_irq_flag = amd_sof_check_and_handle_acp70_sdw_wake_irq(sdev); 631 break; 632 } 633 } 634 if (irq_flag || wake_irq_flag) 635 return IRQ_HANDLED; 636 else 637 return IRQ_NONE; 638 } 639--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Vijendar Mukunda
maintainerPATCH 4/4 ASoC: amd: ps: guard SDW IRQ work scheduling with interrupt_enabled flag
In reply to Vijendar Mukundaacp63_irq_handler() called schedule_work() for the SoundWire manager workqueue guarded only by a NULL pointer check on amd_manager. Add a check for amd_manager->interrupt_enabled so that an in-flight interrupt that fires while the SoundWire manager is being torn down does not queue new work after amd_disable_sdw_interrupts() has cleared the flag.
--- sound/soc/amd/ps/pci-ps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
sound/soc/amd/ps/pci-ps.c +2 -2
@@ -215,7 +215,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)writel (ACP_SDW0_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;
@@ -226,7 +226,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)writel (ACP_SDW1_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;
Signature · 1 line
2.53.0
[email protected]
AI reviewRe: [PATCH 4/4] ASoC: amd: ps: guard SDW IRQ work scheduling with interrupt_enabled flag
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider: - [High] ASoC: amd: ps: build failure in acp63_irq_handler() due to missing struct member - [Medium] ASoC…
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [High] ASoC: amd: ps: build failure in acp63_irq_handler() due to missing struct member
- [Medium] ASoC: amd: ps: TOCTOU race on interrupt_enabled in acp63_irq_handler()
--
commit 371c40e74acce37765aa0469d9b4a4ac8ef4b3eb
Author: Vijendar Mukunda <[email protected]>
ASoC: amd: ps: guard SDW IRQ work scheduling with interrupt_enabled flag
This commit guards SoundWire manager work scheduling in acp63_irq_handler() with an amd_manager->interrupt_enabled check for both SoundWire instances.
Quoted 14 lines
sound/soc/amd/ps/pci-ps.c +1
-1@@ -215,7 +215,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)writel (ACP_SDW0_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;
sound/soc/amd/ps/pci-ps.c static irqreturn_t acp63_irq_handler(int irq, void *dev_id) · line 232
Quoted 8 lines
sound/soc/amd/ps/pci-ps.c +1
-1@@ -226,7 +226,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)writel (ACP_SDW1_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;
[Severity: High]
Does this break the build when CONFIG_SND_SOC_AMD_PS is enabled? struct amd_sdw_manager in include/linux/soundwire/sdw_amd.h has no interrupt_enabled member, and neither amd_enable_sdw_interrupts() nor amd_disable_sdw_interrupts() in drivers/soundwire/amd_manager.c sets or clears such a flag.
[Severity: Medium]
Even with interrupt_enabled added and cleared in amd_disable_sdw_interrupts(), can acp63_irq_handler() still race with SoundWire manager teardown and cause a use-after-free of amd_manager?
CPU0 CPU1 (<hardirq>)amd_sdw_manager_remove()
cancel_work_sync(&amd_sdw_work)
acp63_irq_handler()
amd_manager = dev_get_drvdata(...)
if (amd_manager->interrupt_enabled) amd_disable_sdw_interrupts()
interrupt_enabled = false
schedule_work(&amd_sdw_irq_thread)device_unbind_cleanup()
devres_release_all() /* frees amd_manager */ dev_set_drvdata(dev, NULL)
amd_sdw_irq_thread()
/* dereferences freed amd_manager */
<-- use-after-freeacp63_irq_handler() checks dev_get_drvdata() and interrupt_enabled locklessly in hardirq context on the parent PCI device, while amd_sdw_manager_remove() never cancels amd_sdw_irq_thread or synchronizes with the parent IRQ before devres frees amd_manager.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
Mukunda,Vijendar
maintainerRe: [PATCH 4/4] ASoC: amd: ps: guard SDW IRQ work scheduling with interrupt_enabled flag
Quoted 36 lines · On 11/7/26 23:42, [email protected] wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issues to consider:
- [High] ASoC: amd: ps: build failure inacp63_irq_handler()due to missing struct member
- [Medium] ASoC: amd: ps: TOCTOU race oninterrupt_enabledinacp63_irq_handler()
--commit
371c40e74acce37765aa0469d9b4a4ac8ef4b3eb
Author: Vijendar Mukunda <[email protected]>ASoC: amd: ps: guard SDW IRQ work scheduling with
interrupt_enabledflagThis commit guards SoundWire manager work scheduling in
acp63_irq_handler()with anamd_manager->interrupt_enabledcheck for both SoundWire instances.Quoted 20 lines
sound/soc/amd/ps/pci-ps.c +2
-2@@ -215,7 +215,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)writel (ACP_SDW0_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[0 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread); } irq_flag =1 ;@@ -226,7 +226,7 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id)writel (ACP_SDW1_STAT , adata->acp63_base +ACP_EXTERNAL_INTR_STAT1 );if (adata->sdw) { amd_manager =dev_get_drvdata (&adata->sdw->pdev[1 ]->dev); -if (amd_manager) +if (amd_manager && amd_manager->interrupt_enabled)schedule_work (&amd_manager->amd_sdw_irq_thread);
Quoted 8 lines
sound/soc/amd/ps/pci-ps.c static irqreturn_t acp63_irq_handler(int irq, void *dev_id) · line 232
Quoted 2 lines
sound/soc/amd/ps/pci-ps.c +0
-0} irq_flag =1 ;[Severity: High]
Does this break the build whenCONFIG_SND_SOC_AMD_PSis enabled? structamd_sdw_managerininclude/linux/soundwire/sdw_amd.hhas nointerrupt_enabledmember, and neitheramd_enable_sdw_interrupts()noramd_disable_sdw_interrupts()indrivers/soundwire/amd_manager.csets or clears such a flag.
The interrupt_enabled member is added by patch 17/25 of the AMD SoundWire fix series which this ASoC series depends on. The dependency is stated in the cover letter of this series. When both series are applied together the build is clean.
Dependency:
https://lore.kernel.org/linux-sound/[email protected]/
Quoted 17 lines
[Severity: Medium]
Even withinterrupt_enabledadded and cleared inamd_disable_sdw_interrupts(), canacp63_irq_handler()still race with SoundWire manager teardown and cause a use-after-free ofamd_manager?CPU0 CPU1 (<hardirq>)
amd_sdw_manager_remove()
cancel_work_sync(&amd_sdw_work)acp63_irq_handler() amd_manager = dev_get_drvdata(...) if (amd_manager->interrupt_enabled)
amd_disable_sdw_interrupts()
interrupt_enabled= false
schedule_work(&amd_sdw_irq_thread)device_unbind_cleanup()
devres_release_all()/* freesamd_manager*/dev_set_drvdata(dev, NULL)
Quoted 8 lines
amd_sdw_irq_thread() /* dereferences freed amd_manager */ <-- use-after-free
acp63_irq_handler()checksdev_get_drvdata()andinterrupt_enabledlocklessly in hardirq context on the parent PCI device, whileamd_sdw_manager_remove()never cancelsamd_sdw_irq_threador synchronizes with the parent IRQ before devres freesamd_manager.
The remove ordering shown above is the state before the fix series. Patch 14/25 of the AMD SoundWire fix series corrects the remove sequence to:
amd_disable_sdw_interrupts() /* clears interrupt_enabled, masks hardware IRQ source */ cancel_work_sync(&amd_sdw_irq_thread) cancel_work_sync(&amd_sdw_work)
Once SoundWire interrupts are masked at the hardware level, no new IRQ deliveries can occur. An IRQ handler already in flight before the mask took effect may still queue amd_sdw_irq_thread, and cancel_work_sync() drains both amd_sdw_irq_thread and any amd_sdw_work items it may have re-queued. synchronize_irq() is therefore not required: the hardware mask bounds the window, and cancel_work_sync() covers any work queued by the in-flight handler.
Quoted 1 line
kernel test robot
build botRe: [PATCH 4/4] ASoC: amd: ps: guard SDW IRQ work scheduling with interrupt_enabled flag
In reply to Vijendar Mukundakernel test robot noticed the following build errors:
Hi Vijendar,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-sound/for-next]
[also build test ERROR on vkoul-dmaengine/next linus/master v7.4-rc1 next-20261105] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Vijendar-Mukunda/ASoC-amd-ps-guard-adata-sdw-dereferences-with-NULL-check-in-IRQ-handler/20261107-232226 base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next patch link: https://lore.kernel.org/r/20261107175339.3547918-5-Vijendar.Mukunda%40amd.com patch subject: [PATCH 4/4] ASoC: amd: ps: guard SDW IRQ work scheduling with interrupt_enabled flag config: x86_64-rhel-9.4-ltp (https://download.01.org/0day-ci/archive/20261108/[email protected]/config) compiler: gcc-14 (Debian 14.2.0-19) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261108/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
sound/soc/amd/ps/pci-ps.c: In function 'acp63_irq_handler':
>> sound/soc/amd/ps/pci-ps.c:218:55: error: 'struct amd_sdw_manager' has no member named 'interrupt_enabled'
218 | if (amd_manager && amd_manager->interrupt_enabled)
| ^~
sound/soc/amd/ps/pci-ps.c:229:55: error: 'struct amd_sdw_manager' has no member named 'interrupt_enabled'
229 | if (amd_manager && amd_manager->interrupt_enabled)
| ^~vim +218 sound/soc/amd/ps/pci-ps.c
194
195 static irqreturn_t acp63_irq_handler(int irq, void *dev_id)
196 {
197 struct acp63_dev_data *adata;
198 struct pdm_dev_data *ps_pdm_data;
199 struct amd_sdw_manager *amd_manager;
200 u32 ext_intr_stat, ext_intr_stat1;
201 u16 irq_flag = 0;
202 u16 wake_irq_flag = 0;
203 u16 sdw_dma_irq_flag = 0;
204
205 adata = dev_id;
206 if (!adata)
207 return IRQ_NONE;
208 /* ACP interrupts will be cleared by reading particular bit and writing
209 * same value to the status register. writing zero's doesn't have any
210 * effect.
211 * Bit by bit checking of IRQ field is implemented.
212 */
213 ext_intr_stat = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
214 if (ext_intr_stat & ACP_SDW0_STAT) {
215 writel(ACP_SDW0_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
216 if (adata->sdw) {
217 amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev);
> 218 if (amd_manager && amd_manager->interrupt_enabled)
219 schedule_work(&amd_manager->amd_sdw_irq_thread);
220 }
221 irq_flag = 1;
222 }
223
224 ext_intr_stat1 = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
225 if (ext_intr_stat1 & ACP_SDW1_STAT) {
226 writel(ACP_SDW1_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1);
227 if (adata->sdw) {
228 amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev);
229 if (amd_manager && amd_manager->interrupt_enabled)
230 schedule_work(&amd_manager->amd_sdw_irq_thread);
231 }
232 irq_flag = 1;
233 }
234
235 if (ext_intr_stat & ACP_ERROR_IRQ) {
236 writel(ACP_ERROR_IRQ, adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
237 /* TODO: Report SoundWire Manager instance errors */
238 writel(0, adata->acp63_base + ACP_SW0_I2S_ERROR_REASON);
239 writel(0, adata->acp63_base + ACP_SW1_I2S_ERROR_REASON);
240 writel(0, adata->acp63_base + ACP_ERROR_STATUS);
241 irq_flag = 1;
242 }
243
244 if (adata->acp_rev >= ACP70_PCI_REV)
245 wake_irq_flag = check_and_handle_acp70_sdw_wake_irq(adata);
246
247 if (ext_intr_stat & BIT(PDM_DMA_STAT)) {
248 ps_pdm_data = dev_get_drvdata(&adata->pdm_dev->dev);
249 writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT);
250 if (ps_pdm_data->capture_stream)
251 snd_pcm_period_elapsed(ps_pdm_data->capture_stream);
252 irq_flag = 1;
253 }
254
255 sdw_dma_irq_flag = check_and_handle_sdw_dma_irq(adata, ext_intr_stat, ext_intr_stat1);
256 if (sdw_dma_irq_flag)
257 return IRQ_WAKE_THREAD;
258
259 if (irq_flag || wake_irq_flag)
260 return IRQ_HANDLED;
261 else
262 return IRQ_NONE;
263 }
264
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Mukunda,Vijendar
maintainerQuoted 14 lines · Vijendar Mukunda
These four patches fix two related race conditions in the AMD SoundWire IRQ handlers for the PS (ACP63) and SOF platforms.
Patches 1 and 2 guard against a NULL dereference in the ACP external IRQ handler. The handler is registered before
sdw_amd_probe()assignsadata->sdw, so a stray interrupt in the probe window, or one that fires aftersdw_amd_exit()frees the context, can reach the adata->sdw->pdev[i] dereference withadata->sdwstill NULL.Patches 3 and 4 guard
schedule_work()calls with theinterrupt_enabledflag so that an in-flight IRQ arriving while the SoundWire manager is being torn down does not queue new work afteramd_disable_sdw_interrupts()has cleared the flag.
Quoted 7 lines
NOTE: Patches 3 and 4 depend on the following patch which introduces the
interrupt_enabledfield in the AMD SoundWire manager:https://lore.kernel.org/linux-sound/[email protected]/
Until that patch is merged, patches 3 and 4 should not be picked up independently.
Hi Mark, Vinod,
The following two series have a build and correctness dependency on each other:
SoundWire fix series (25 patches):
https://lore.kernel.org/linux-sound/[email protected]/
Companion ASoC series (4 patches):
https://lore.kernel.org/alsa-devel/[email protected]/
ASoC patches 1/4 and 2/4 reference the interrupt_enabled member of struct amd_sdw_manager introduced by SoundWire patch 17/25, so the ASoC patches will not build without the SoundWire series. SoundWire patch 18/25 delays *sdw_ctx publication until after startup succeeds, opening a probe-window race in acp63_irq_handler() and acp_irq_handler() that ASoC patches 3/4 and 4/4 close with adata->sdw NULL checks.
Because the two series are split across trees, the Sashiko AI review tool sees each series in isolation and raises the cross-tree dependency as unresolved races:
https://sashiko.dev/#/patchset/20261107154659.3358223-1-Vijendar.Mukunda%40amd.com
https://sashiko.dev/#/patchset/20261107175339.3547918-1-Vijendar.Mukunda%40amd.com
When both series were combined and run through Sashiko as a single patch set, none of these cross-dependency issues were reported, confirming that the concerns are an artifact of the split rather than real bugs. Reposting as a single combined series would give Sashiko the full context and make the review cycle easier. Please let us know if that is the preferred approach.
Thanks,
Vijendar
Quoted 16 lines
Vijendar Mukunda (4):
ASoC: amd: ps: guardadata->sdwdereferences with NULL check in IRQ
handler
ASoC: SOF: amd: guardadata->sdwdereferences with NULL check in IRQ
handler
ASoC: SOF: amd: guard SDW IRQ work scheduling withinterrupt_enabled
flag
ASoC: amd: ps: guard SDW IRQ work scheduling withinterrupt_enabled
flagsound/soc/amd/ps/pci-ps.c | 32 ++++++++++++++++++++------------ sound/soc/sof/amd/acp.c | 32 ++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 24 deletions(-)--
2.53.0
Mukunda,Vijendar
maintainerQuoted 22 lines · Mukunda,Vijendar
Quoted 14 lines · Vijendar Mukunda
These four patches fix two related race conditions in the AMD SoundWire IRQ handlers for the PS (ACP63) and SOF platforms.
Patches 1 and 2 guard against a NULL dereference in the ACP external IRQ handler. The handler is registered before
sdw_amd_probe()assignsadata->sdw, so a stray interrupt in the probe window, or one that fires aftersdw_amd_exit()frees the context, can reach the adata->sdw->pdev[i] dereference withadata->sdwstill NULL.Patches 3 and 4 guard
schedule_work()calls with theinterrupt_enabledflag so that an in-flight IRQ arriving while the SoundWire manager is being torn down does not queue new work afteramd_disable_sdw_interrupts()has cleared the flag.Quoted 7 lines
NOTE: Patches 3 and 4 depend on the following patch which introduces the
interrupt_enabledfield in the AMD SoundWire manager:https://lore.kernel.org/linux-sound/[email protected]/
Until that patch is merged, patches 3 and 4 should not be picked up independently.
Quoted 12 lines
Hi Mark, Vinod,
The following two series have a build and correctness dependency on each other:
SoundWire fix series (25 patches):
https://lore.kernel.org/linux-sound/[email protected]/
Companion ASoC series (4 patches):
https://lore.kernel.org/alsa-devel/[email protected]/
ASoC patches 1/4 and 2/4 reference theinterrupt_enabledmember of
I was referring to the patch ordering in my local copy, which differs from the series that was posted. In the posted series, the correct references are 3/4 and 4/4 for the |interrupt_enabled| dependency, and 1/4 and 2/4 for the |adata->sdw| NULL checks.
Quoted 6 lines
struct
amd_sdw_managerintroduced by SoundWire patch 17/25, so the ASoC patches will not build without the SoundWire series. SoundWire patch 18/25 delays*sdw_ctxpublication until after startup succeeds, opening a probe-window race inacp63_irq_handler()andacp_irq_handler()that ASoC patches 3/4 and 4/4 close withadata->sdwNULL checks.
Correction to my previous reply: I quoted the wrong patch numbers.
In the posted series, patches 3/4 and 4/4 have the interrupt_enabled dependency, while patches 1/4 and 2/4 contain the adata->sdw NULL checks.
Sorry for the confusion.
Quoted 35 lines
Because the two series are split across trees, the Sashiko AI review tool sees each series in isolation and raises the cross-tree dependency as unresolved races:
https://sashiko.dev/#/patchset/20261107154659.3358223-1-Vijendar.Mukunda%40amd.com
https://sashiko.dev/#/patchset/20261107175339.3547918-1-Vijendar.Mukunda%40amd.com
When both series were combined and run through Sashiko as a single patch set, none of these cross-dependency issues were reported, confirming that the concerns are an artifact of the split rather than real bugs. Reposting as a single combined series would give Sashiko the full context and make the review cycle easier. Please let us know if that is the preferred approach.
Thanks,
VijendarQuoted 16 lines
Vijendar Mukunda (4):
ASoC: amd: ps: guardadata->sdwdereferences with NULL check in IRQ
handler
ASoC: SOF: amd: guardadata->sdwdereferences with NULL check in IRQ
handler
ASoC: SOF: amd: guard SDW IRQ work scheduling withinterrupt_enabled
flag
ASoC: amd: ps: guard SDW IRQ work scheduling withinterrupt_enabled
flagsound/soc/amd/ps/pci-ps.c | 32 ++++++++++++++++++++------------ sound/soc/sof/amd/acp.c | 32 ++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 24 deletions(-)--
2.53.0
Mark Brown
maintainerQuoted 5 lines
Patches 3 and 4 guard
schedule_work()calls with theinterrupt_enabledflag so that an in-flight IRQ arriving while the SoundWire manager is being torn down does not queue new work afteramd_disable_sdw_interrupts()has cleared the flag.
Quoted 7 lines
NOTE: Patches 3 and 4 depend on the following patch which introduces the
interrupt_enabledfield in the AMD SoundWire manager:https://lore.kernel.org/linux-sound/[email protected]/
Until that patch is merged, patches 3 and 4 should not be picked up independently.
Please try to avoid mixing in things with differing dependencies into a single series, it makes things much harder to track.
Signature · 1 line
Mark Brown <[email protected]>