mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 00:22:00 +02:00
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 <adrian.hunter@intel.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260113072702.16268-3-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
This commit is contained in:
parent
78f63ae4a8
commit
8bb9657588
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user