[PATCH 02/17] i3c: mipi-i3c-hci: Ensure proper bus clean-up
Frank Li
Frank.li at nxp.com
Fri Dec 19 08:22:08 PST 2025
On Fri, Dec 19, 2025 at 04:45:19PM +0200, Adrian Hunter wrote:
> 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 <adrian.hunter at intel.com>
> ---
Reviewed-by: Frank Li <Frank.Li at nxp.com>
> drivers/i3c/master/mipi-i3c-hci/core.c | 32 +++++++++++++++++++++++---
> drivers/i3c/master/mipi-i3c-hci/dma.c | 7 ++++++
> drivers/i3c/master/mipi-i3c-hci/hci.h | 1 +
> drivers/i3c/master/mipi-i3c-hci/pio.c | 2 ++
> 4 files changed, 39 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index 6da5daf18166..0d3ec674878d 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 5515ed740ca4..54849aa98fad 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 3f88b67bc5cc..fd08b701d094 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 109c6c5d83d6..90dca56fc0c5 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));
> --
> 2.51.0
>
>
> --
> linux-i3c mailing list
> linux-i3c at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-i3c
More information about the linux-i3c
mailing list