Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

i3c: mipi-i3c-hci: Correct RING_CTRL_ABORT handling in DMA dequeue

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: 9ad9a52cce282 ("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>

authored by

Adrian Hunter and committed by
Alexandre Belloni
b795e68b f0b51596

+16 -9
+16 -9
drivers/i3c/master/mipi-i3c-hci/dma.c
··· 546 546 struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number]; 547 547 unsigned int i; 548 548 bool did_unqueue = false; 549 + u32 ring_status; 549 550 550 551 guard(mutex)(&hci->control_mutex); 551 552 552 - /* stop the ring */ 553 - rh_reg_write(RING_CONTROL, RING_CTRL_ABORT); 554 - if (wait_for_completion_timeout(&rh->op_done, HZ) == 0) { 555 - /* 556 - * We're deep in it if ever this condition is ever met. 557 - * Hardware might still be writing to memory, etc. 558 - */ 559 - dev_crit(&hci->master.dev, "unable to abort the ring\n"); 560 - WARN_ON(1); 553 + ring_status = rh_reg_read(RING_STATUS); 554 + if (ring_status & RING_STATUS_RUNNING) { 555 + /* stop the ring */ 556 + reinit_completion(&rh->op_done); 557 + rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_ABORT); 558 + wait_for_completion_timeout(&rh->op_done, HZ); 559 + ring_status = rh_reg_read(RING_STATUS); 560 + if (ring_status & RING_STATUS_RUNNING) { 561 + /* 562 + * We're deep in it if ever this condition is ever met. 563 + * Hardware might still be writing to memory, etc. 564 + */ 565 + dev_crit(&hci->master.dev, "unable to abort the ring\n"); 566 + WARN_ON(1); 567 + } 561 568 } 562 569 563 570 spin_lock_irq(&hci->lock);