From: Adrian Hunter Date: Tue, 13 Jan 2026 07:26:43 +0000 (+0200) Subject: i3c: mipi-i3c-hci: Ensure proper bus clean-up X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8bb96575883d3b201ce37046b3903ea1d2d50bbc;p=thirdparty%2Fkernel%2Flinux.git i3c: mipi-i3c-hci: Ensure proper bus clean-up Wait for the bus to fully disable before proceeding, ensuring that no operations are still in progress. Synchronize the IRQ handler only after interrupt signals have been disabled. This approach also handles cases where bus disable might fail, preventing race conditions and ensuring a consistent shutdown sequence. Signed-off-by: Adrian Hunter Reviewed-by: Frank Li Link: https://patch.msgid.link/20260113072702.16268-3-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni --- diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c index 6da5daf18166f..0d3ec674878d7 100644 --- a/drivers/i3c/master/mipi-i3c-hci/core.c +++ b/drivers/i3c/master/mipi-i3c-hci/core.c @@ -151,13 +151,39 @@ static int i3c_hci_bus_init(struct i3c_master_controller *m) return 0; } +/* Bus disable should never fail, so be generous with the timeout */ +#define BUS_DISABLE_TIMEOUT_US (500 * USEC_PER_MSEC) + +static int i3c_hci_bus_disable(struct i3c_hci *hci) +{ + u32 regval; + int ret; + + reg_clear(HC_CONTROL, HC_CONTROL_BUS_ENABLE); + + /* Ensure controller is disabled */ + ret = readx_poll_timeout(reg_read, HC_CONTROL, regval, + !(regval & HC_CONTROL_BUS_ENABLE), 0, BUS_DISABLE_TIMEOUT_US); + if (ret) + dev_err(&hci->master.dev, "%s: Failed to disable bus\n", __func__); + + return ret; +} + +void i3c_hci_sync_irq_inactive(struct i3c_hci *hci) +{ + struct platform_device *pdev = to_platform_device(hci->master.dev.parent); + int irq = platform_get_irq(pdev, 0); + + reg_write(INTR_SIGNAL_ENABLE, 0x0); + synchronize_irq(irq); +} + static void i3c_hci_bus_cleanup(struct i3c_master_controller *m) { struct i3c_hci *hci = to_i3c_hci(m); - struct platform_device *pdev = to_platform_device(m->dev.parent); - reg_clear(HC_CONTROL, HC_CONTROL_BUS_ENABLE); - synchronize_irq(platform_get_irq(pdev, 0)); + i3c_hci_bus_disable(hci); hci->io->cleanup(hci); if (hci->cmd == &mipi_i3c_hci_cmd_v1) mipi_i3c_hci_dat_v1.cleanup(hci); diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c index 5515ed740ca4b..54849aa98fad1 100644 --- a/drivers/i3c/master/mipi-i3c-hci/dma.c +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c @@ -160,6 +160,13 @@ static void hci_dma_cleanup(struct i3c_hci *hci) rh_reg_write(INTR_SIGNAL_ENABLE, 0); rh_reg_write(RING_CONTROL, 0); + } + + i3c_hci_sync_irq_inactive(hci); + + for (i = 0; i < rings->total; i++) { + rh = &rings->headers[i]; + rh_reg_write(CR_SETUP, 0); rh_reg_write(IBI_SETUP, 0); diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h index 3f88b67bc5cc2..fd08b701d094f 100644 --- a/drivers/i3c/master/mipi-i3c-hci/hci.h +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h @@ -142,5 +142,6 @@ void mipi_i3c_hci_pio_reset(struct i3c_hci *hci); void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci); void amd_set_od_pp_timing(struct i3c_hci *hci); void amd_set_resp_buf_thld(struct i3c_hci *hci); +void i3c_hci_sync_irq_inactive(struct i3c_hci *hci); #endif diff --git a/drivers/i3c/master/mipi-i3c-hci/pio.c b/drivers/i3c/master/mipi-i3c-hci/pio.c index 109c6c5d83d6b..90dca56fc0c53 100644 --- a/drivers/i3c/master/mipi-i3c-hci/pio.c +++ b/drivers/i3c/master/mipi-i3c-hci/pio.c @@ -211,6 +211,8 @@ static void hci_pio_cleanup(struct i3c_hci *hci) pio_reg_write(INTR_SIGNAL_ENABLE, 0x0); + i3c_hci_sync_irq_inactive(hci); + if (pio) { dev_dbg(&hci->master.dev, "status = %#x/%#x", pio_reg_read(INTR_STATUS), pio_reg_read(INTR_SIGNAL_ENABLE));