Skip to content

Commit e44d271

Browse files
ahunter6alexandrebelloni
authored andcommitted
i3c: mipi-i3c-hci: Fix race in DMA error handling in interrupt context
The DMA ring halts whenever a transfer encounters an error. The interrupt handler previously attempted to detect this situation and restart the ring if a transfer completed at the same time. However, this restart logic runs entirely in interrupt context and is inherently racy: it interacts with other paths manipulating the ring state, and fully serializing it within the interrupt handler is not practical. Move this error-recovery logic out of the interrupt handler and into the transfer-processing path (i3c_hci_process_xfer()), where serialization and state management are already controlled. Introduce a new optional I/O-ops callback, handle_error(), invoked when a completed transfer reports an error. For DMA operation, the implementation simply calls the existing dequeue function, which safely aborts and restarts the ring when needed. This removes the fragile ring-restart logic from the interrupt handler and centralizes error handling where proper sequencing can be ensured. Fixes: ccdb2e0 ("i3c: mipi-i3c-hci: Add Intel specific quirk to ring resuming") Cc: stable@vger.kernel.org Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Link: https://patch.msgid.link/20260306072451.11131-13-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent 7ac45bc commit e44d271

3 files changed

Lines changed: 24 additions & 27 deletions

File tree

drivers/i3c/master/mipi-i3c-hci/core.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,21 @@ int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n)
223223
if (ret)
224224
return ret;
225225

226-
if (!wait_for_completion_timeout(done, timeout) &&
227-
hci->io->dequeue_xfer(hci, xfer, n)) {
228-
dev_err(&hci->master.dev, "%s: timeout error\n", __func__);
229-
return -ETIMEDOUT;
226+
if (!wait_for_completion_timeout(done, timeout)) {
227+
if (hci->io->dequeue_xfer(hci, xfer, n)) {
228+
dev_err(&hci->master.dev, "%s: timeout error\n", __func__);
229+
return -ETIMEDOUT;
230+
}
231+
return 0;
232+
}
233+
234+
if (hci->io->handle_error) {
235+
bool error = false;
236+
237+
for (int i = 0; i < n && !error; i++)
238+
error = RESP_STATUS(xfer[i].response);
239+
if (error)
240+
return hci->io->handle_error(hci, xfer, n);
230241
}
231242

232243
return 0;

drivers/i3c/master/mipi-i3c-hci/dma.c

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,11 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
609609
return did_unqueue;
610610
}
611611

612+
static int hci_dma_handle_error(struct i3c_hci *hci, struct hci_xfer *xfer_list, int n)
613+
{
614+
return hci_dma_dequeue_xfer(hci, xfer_list, n) ? -EIO : 0;
615+
}
616+
612617
static void hci_dma_xfer_done(struct i3c_hci *hci, struct hci_rh_data *rh)
613618
{
614619
u32 op1_val, op2_val, resp, *ring_resp;
@@ -870,29 +875,8 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
870875
hci_dma_xfer_done(hci, rh);
871876
if (status & INTR_RING_OP)
872877
complete(&rh->op_done);
873-
874-
if (status & INTR_TRANSFER_ABORT) {
875-
u32 ring_status;
876-
877-
dev_notice_ratelimited(&hci->master.dev,
878-
"Ring %d: Transfer Aborted\n", i);
879-
mipi_i3c_hci_resume(hci);
880-
ring_status = rh_reg_read(RING_STATUS);
881-
if (!(ring_status & RING_STATUS_RUNNING) &&
882-
status & INTR_TRANSFER_COMPLETION &&
883-
status & INTR_TRANSFER_ERR) {
884-
/*
885-
* Ring stop followed by run is an Intel
886-
* specific required quirk after resuming the
887-
* halted controller. Do it only when the ring
888-
* is not in running state after a transfer
889-
* error.
890-
*/
891-
rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE);
892-
rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE |
893-
RING_CTRL_RUN_STOP);
894-
}
895-
}
878+
if (status & INTR_TRANSFER_ABORT)
879+
dev_dbg(&hci->master.dev, "Ring %d: Transfer Aborted\n", i);
896880
if (status & INTR_IBI_RING_FULL)
897881
dev_err_ratelimited(&hci->master.dev,
898882
"Ring %d: IBI Ring Full Condition\n", i);
@@ -908,6 +892,7 @@ const struct hci_io_ops mipi_i3c_hci_dma = {
908892
.cleanup = hci_dma_cleanup,
909893
.queue_xfer = hci_dma_queue_xfer,
910894
.dequeue_xfer = hci_dma_dequeue_xfer,
895+
.handle_error = hci_dma_handle_error,
911896
.irq_handler = hci_dma_irq_handler,
912897
.request_ibi = hci_dma_request_ibi,
913898
.free_ibi = hci_dma_free_ibi,

drivers/i3c/master/mipi-i3c-hci/hci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ struct hci_io_ops {
123123
bool (*irq_handler)(struct i3c_hci *hci);
124124
int (*queue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
125125
bool (*dequeue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
126+
int (*handle_error)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
126127
int (*request_ibi)(struct i3c_hci *hci, struct i3c_dev_desc *dev,
127128
const struct i3c_ibi_setup *req);
128129
void (*free_ibi)(struct i3c_hci *hci, struct i3c_dev_desc *dev);

0 commit comments

Comments
 (0)