Skip to content

Commit 5549611

Browse files
ahunter6gregkh
authored andcommitted
i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue
commit b795e68 upstream. The logic used to abort the DMA ring contains several flaws: 1. The driver unconditionally issues a ring abort even when the ring has already stopped. 2. The completion used to wait for abort completion is never re-initialized, resulting in incorrect wait behavior. 3. The abort sequence unintentionally clears RING_CTRL_ENABLE, which resets hardware ring pointers and disrupts the controller state. 4. If the ring is already stopped, the abort operation should be considered successful without attempting further action. Fix the abort handling by checking whether the ring is running before issuing an abort, re-initializing the completion when needed, ensuring that RING_CTRL_ENABLE remains asserted during abort, and treating an already stopped ring as a successful condition. Fixes: 9ad9a52 ("i3c/master: introduce the mipi-i3c-hci driver") 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-9-adrian.hunter@intel.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 4faa1e9 commit 5549611

1 file changed

Lines changed: 16 additions & 9 deletions

File tree

  • drivers/i3c/master/mipi-i3c-hci

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -485,18 +485,25 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci,
485485
struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number];
486486
unsigned int i;
487487
bool did_unqueue = false;
488+
u32 ring_status;
488489

489490
guard(mutex)(&hci->control_mutex);
490491

491-
/* stop the ring */
492-
rh_reg_write(RING_CONTROL, RING_CTRL_ABORT);
493-
if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) {
494-
/*
495-
* We're deep in it if ever this condition is ever met.
496-
* Hardware might still be writing to memory, etc.
497-
*/
498-
dev_crit(&hci->master.dev, "unable to abort the ring\n");
499-
WARN_ON(1);
492+
ring_status = rh_reg_read(RING_STATUS);
493+
if (ring_status & RING_STATUS_RUNNING) {
494+
/* stop the ring */
495+
reinit_completion(&rh->op_done);
496+
rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT);
497+
wait_for_completion_timeout(&rh->op_done, HZ);
498+
ring_status = rh_reg_read(RING_STATUS);
499+
if (ring_status & RING_STATUS_RUNNING) {
500+
/*
501+
* We're deep in it if ever this condition is ever met.
502+
* Hardware might still be writing to memory, etc.
503+
*/
504+
dev_crit(&hci->master.dev, "unable to abort the ring\n");
505+
WARN_ON(1);
506+
}
500507
}
501508

502509
for (i = 0; i < n; i++) {

0 commit comments

Comments
 (0)