Commit c6396b83 authored by Adrian Hunter's avatar Adrian Hunter Committed by Alexandre Belloni
Browse files

i3c: mipi-i3c-hci: Fix handling of shared IRQs during early initialization



Shared interrupts may fire unexpectedly, including during periods when the
controller is not yet fully initialized. Commit b9a15012
("i3c: mipi-i3c-hci: Add optional Runtime PM support") addressed this issue
for the runtime-suspended state, but the same problem can also occur before
the bus is enabled for the first time.

Ensure the IRQ handler ignores interrupts until initialization is complete
by making consistent use of the existing irq_inactive flag.  The flag is
now set to false immediately before enabling the bus.

To guarantee correct ordering with respect to the IRQ handler, protect
all transitions of irq_inactive with the same spinlock used inside the
handler.

Fixes: b8460480 ("i3c: mipi-i3c-hci: Allow for Multi-Bus Instances")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Reviewed-by: default avatarFrank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260306072451.11131-14-adrian.hunter@intel.com


Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
parent e44d2719
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -152,6 +152,9 @@ static int i3c_hci_bus_init(struct i3c_master_controller *m)
	if (hci->quirks & HCI_QUIRK_RESP_BUF_THLD)
		amd_set_resp_buf_thld(hci);

	scoped_guard(spinlock_irqsave, &hci->lock)
		hci->irq_inactive = false;

	/* Enable bus with Hot-Join disabled */
	reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE | HC_CONTROL_HOT_JOIN_CTRL);
	dev_dbg(&hci->master.dev, "HC_CONTROL = %#x", reg_read(HC_CONTROL));
@@ -184,8 +187,9 @@ void i3c_hci_sync_irq_inactive(struct i3c_hci *hci)
	int irq = platform_get_irq(pdev, 0);

	reg_write(INTR_SIGNAL_ENABLE, 0x0);
	hci->irq_inactive = true;
	synchronize_irq(irq);
	scoped_guard(spinlock_irqsave, &hci->lock)
		hci->irq_inactive = true;
}

static void i3c_hci_bus_cleanup(struct i3c_master_controller *m)
@@ -781,10 +785,11 @@ static int i3c_hci_runtime_resume(struct device *dev)

	mipi_i3c_hci_dat_v1.restore(hci);

	hci->irq_inactive = false;

	hci->io->resume(hci);

	scoped_guard(spinlock_irqsave, &hci->lock)
		hci->irq_inactive = false;

	/* Enable bus with Hot-Join disabled */
	reg_set(HC_CONTROL, HC_CONTROL_BUS_ENABLE | HC_CONTROL_HOT_JOIN_CTRL);

@@ -975,6 +980,8 @@ static int i3c_hci_probe(struct platform_device *pdev)
	if (ret)
		return ret;

	hci->irq_inactive = true;

	irq = platform_get_irq(pdev, 0);
	ret = devm_request_irq(&pdev->dev, irq, i3c_hci_irq_handler,
			       IRQF_SHARED, NULL, hci);