[PATCH v1] mailbox: bcm-pdc: Free the IRQ before cancelling receive work

Yibo Tan posted 1 patch 1 week, 2 days ago
drivers/mailbox/bcm-pdc-mailbox.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
[PATCH v1] mailbox: bcm-pdc: Free the IRQ before cancelling receive work
Posted by Yibo Tan 1 week, 2 days ago
pdc_irq_handler() queues rx_work to process received data.  Because the
driver requests a managed IRQ, the handler remains registered until
after probe or remove returns unless the driver frees it explicitly.

The pdc_mb_init() error path and pdc_remove() currently cancel the work
while the IRQ handler is still registered.  A later interrupt can queue
the work again.  Cleanup then destroys the DMA pools and frees struct
pdc_state, so pdc_work_cb() can access freed memory and registers.

KASAN reported an invalid access in pdc_work_cb() when an interrupt
queued the work during removal.  After this change, removal waited for
the work to finish and the same test completed without a kernel
diagnostic.

Add pdc_stop() to disable the hardware, free the managed IRQ and wait for
rx_work.  Call it in both paths before destroying either DMA pool.

Fixes: 8aef00f090bc ("mailbox: bcm-pdc: Convert from threaded IRQ to tasklet")
Cc: stable@vger.kernel.org
Assisted-by: Codex:GPT-5
Signed-off-by: Yibo Tan <lhfff@tju.edu.cn>
---
 drivers/mailbox/bcm-pdc-mailbox.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c
index 6fcc4002ad4f..aea2e5273bf0 100644
--- a/drivers/mailbox/bcm-pdc-mailbox.c
+++ b/drivers/mailbox/bcm-pdc-mailbox.c
@@ -1335,6 +1335,15 @@ static void pdc_hw_disable(struct pdc_state *pdcs)
 		  &dma_reg->dmarcv.control);
 }
 
+static void pdc_stop(struct pdc_state *pdcs)
+{
+	struct device *dev = &pdcs->pdev->dev;
+
+	pdc_hw_disable(pdcs);
+	devm_free_irq(dev, pdcs->pdc_irq, dev);
+	cancel_work_sync(&pdcs->rx_work);
+}
+
 /**
  * pdc_rx_buf_pool_create() - Pool of receive buffers used to catch the metadata
  * header returned with each response message.
@@ -1581,15 +1590,16 @@ static int pdc_probe(struct platform_device *pdev)
 	/* Initialize mailbox controller */
 	err = pdc_mb_init(pdcs);
 	if (err)
-		goto cleanup_buf_pool;
+		goto cleanup_irq;
 
 	pdc_setup_debugfs(pdcs);
 
 	dev_dbg(dev, "pdc_probe() successful");
 	return PDC_SUCCESS;
 
+cleanup_irq:
+	pdc_stop(pdcs);
 cleanup_buf_pool:
-	cancel_work_sync(&pdcs->rx_work);
 	dma_pool_destroy(pdcs->rx_buf_pool);
 
 cleanup_ring_pool:
@@ -1605,9 +1615,7 @@ static void pdc_remove(struct platform_device *pdev)
 
 	pdc_free_debugfs();
 
-	cancel_work_sync(&pdcs->rx_work);
-
-	pdc_hw_disable(pdcs);
+	pdc_stop(pdcs);
 
 	dma_pool_destroy(pdcs->rx_buf_pool);
 	dma_pool_destroy(pdcs->ring_pool);
-- 
2.39.5