* Re: [PATCH V3 00/16] i3c: mipi-i3c-hci: DMA abort, recovery and related improvements [not found] <20260504113352.38490-1-adrian.hunter@intel.com> @ 2026-05-12 12:35 ` Adrian Hunter [not found] ` <20260504113352.38490-4-adrian.hunter@intel.com> ` (10 subsequent siblings) 11 siblings, 0 replies; 12+ messages in thread From: Adrian Hunter @ 2026-05-12 12:35 UTC (permalink / raw) To: alexandre.belloni; +Cc: Frank.Li, linux-i3c, linux-kernel On 04/05/2026 14:33, Adrian Hunter wrote: > Hi > > This series improves the robustness of the MIPI I3C HCI DMA mode driver, > addressing issues observed during error handling and recovery. Any comments on this? > > Patch 1 ensures suspend always invokes io->suspend. > > Patches 2-4 fix issues in the existing DMA abort path: preserving the RUN > bit during abort per the MIPI specification, blocking enqueue during > abort/error, and waiting for ring restart completion. > > Patches 5-8 improve how partially completed transfer lists are handled > during dequeue: moving hci_dma_xfer_done() earlier so completed > responses are processed before NoOp replacement, completing transfer > lists immediately on error rather than deferring, and detecting when an > abort races with transfer completion to avoid restarting the wrong > transfer list. > > Patches 9-10 add Intel-specific quirks for DMA ring abort: a PIO queue > reset after abort, and an HC_CONTROL ABORT before the ring-level abort. > > Patch 11 factors out a reset-and-restore helper from the suspend path > for reuse. > > Patch 12 adds a full DMA recovery path for internal controller errors. > When the hardware reports a TID mismatch or the ring becomes stuck, the > driver now resets and restores the controller, terminating all in-flight > transfers with an error status. > > Patch 13 makes NoOp command handling observable: instead of discarding > NoOp responses, the driver now waits for them to complete and triggers > recovery if they fail. > > Patch 14 adjusts transfer timeout accounting to start from when a > transfer actually begins execution rather than when it was queued, > preventing premature timeouts behind slow predecessors. > > Patches 15-16 are minor optimizations: consolidating the DMA command and > response ring into a single coherent allocation, and increasing the ring > size to the maximum 255 entries to avoid ring-space exhaustion. > > > Changes in V3: > > i3c: mipi-i3c-hci: Fix suspend behavior when bus disable falls back to software reset > i3c: mipi-i3c-hci: Preserve RUN bit when aborting DMA ring > Add Frank's rev'd-by > > i3c: mipi-i3c-hci: Add DMA-mode recovery for internal controller errors > When erroring out transfers, ensure the final transfer of a > transfer list is processed last > > > Changes in V2: > > i3c: mipi-i3c-hci: Fix suspend behavior when bus disable falls back to software reset > Always return 0 from suspend callback > Amend commit message > > i3c: mipi-i3c-hci: Preserve RUN bit when aborting DMA ring > Improve commit message > > i3c: mipi-i3c-hci: Prevent DMA enqueue while ring is aborting or in error > Improve commit message > > i3c: mipi-i3c-hci: Wait for DMA ring restart to complete > None > > i3c: mipi-i3c-hci: Move hci_dma_xfer_done() definition > Add Frank's Rev'd-by > > i3c: mipi-i3c-hci: Call hci_dma_xfer_done() from dequeue path > Add Frank's Rev'd-by > > i3c: mipi-i3c-hci: Complete transfer lists immediately on error > Rename completing_xfer to final_xfer > > i3c: mipi-i3c-hci: Avoid restarting DMA ring after aborting wrong transfer > Rename completing_xfer to final_xfer > > i3c: mipi-i3c-hci: Add DMA ring abort/reset quirk for Intel controllers > None > > i3c: mipi-i3c-hci: Add DMA ring abort quirk for Intel controllers > None > > i3c: mipi-i3c-hci: Factor out reset-and-restore helper > Drop redundant i3c_hci_sync_irq_inactive(hci) > from i3c_hci_reset_and_restore() because it is called by > hci->io->suspend() anyway > > i3c: mipi-i3c-hci: Add DMA-mode recovery for internal controller errors > Rename completing_xfer to final_xfer > Add hci_dma_xfer_done() before checking for an already complete > transfer > Improve commit message > > i3c: mipi-i3c-hci: Wait for NoOp commands to complete > Rename completing_xfer to final_xfer > Add missing reinit_completion() > > i3c: mipi-i3c-hci: Base timeouts on actual transfer start time > Do not flag the next transfer as started when there is an error > which halts the controller > Instead flag it started at the end of hci_dma_dequeue_xfer() > Use hci_start_xfer() in pio.c > > i3c: mipi-i3c-hci: Consolidate DMA ring allocation > Check for failed allocation before assignments to avoid doing > arithmetic with NULL pointers > > i3c: mipi-i3c-hci: Increase DMA transfer ring size to maximum > None > > > Adrian Hunter (16): > i3c: mipi-i3c-hci: Fix suspend behavior when bus disable falls back to software reset > i3c: mipi-i3c-hci: Preserve RUN bit when aborting DMA ring > i3c: mipi-i3c-hci: Prevent DMA enqueue while ring is aborting or in error > i3c: mipi-i3c-hci: Wait for DMA ring restart to complete > i3c: mipi-i3c-hci: Move hci_dma_xfer_done() definition > i3c: mipi-i3c-hci: Call hci_dma_xfer_done() from dequeue path > i3c: mipi-i3c-hci: Complete transfer lists immediately on error > i3c: mipi-i3c-hci: Avoid restarting DMA ring after aborting wrong transfer > i3c: mipi-i3c-hci: Add DMA ring abort/reset quirk for Intel controllers > i3c: mipi-i3c-hci: Add DMA ring abort quirk for Intel controllers > i3c: mipi-i3c-hci: Factor out reset-and-restore helper > i3c: mipi-i3c-hci: Add DMA-mode recovery for internal controller errors > i3c: mipi-i3c-hci: Wait for NoOp commands to complete > i3c: mipi-i3c-hci: Base timeouts on actual transfer start time > i3c: mipi-i3c-hci: Consolidate DMA ring allocation > i3c: mipi-i3c-hci: Increase DMA transfer ring size to maximum > > drivers/i3c/master/mipi-i3c-hci/cmd.h | 6 + > drivers/i3c/master/mipi-i3c-hci/core.c | 82 ++++++-- > drivers/i3c/master/mipi-i3c-hci/dma.c | 344 +++++++++++++++++++++++++-------- > drivers/i3c/master/mipi-i3c-hci/hci.h | 22 +++ > drivers/i3c/master/mipi-i3c-hci/pio.c | 1 + > 5 files changed, 365 insertions(+), 90 deletions(-) > > > Regards > Adrian ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-4-adrian.hunter@intel.com>]
* Re: [PATCH V3 03/16] i3c: mipi-i3c-hci: Prevent DMA enqueue while ring is aborting or in error [not found] ` <20260504113352.38490-4-adrian.hunter@intel.com> @ 2026-05-12 16:44 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 16:44 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:39PM +0300, Adrian Hunter wrote: > Block the DMA enqueue path while a Ring abort is in progress or after an > error condition has been detected. > > Previously, new transfers could be enqueued while the DMA Ring was being > aborted or while error handling was underway. This allowed enqueue and > error-recovery paths to run concurrently, potentially interfering with > each other and corrupting Ring state. > > Introduce explicit enqueue blocking and a wait queue to serialize access: > enqueue operations now wait until abort or error handling has completed > before proceeding. Enqueue is unblocked once the Ring is safely restarted. > > Note, there is only 1 ring bundle configured, and a transfer error causes > the controller to halt ring (bundle) operation, so there is only ever 1 > outstanding error at a time. Furthermore, a later patch ensures that only > the currently active transfer list can time out. Consequently, the DMA > queue will not be unblocked while there are outstanding transfer errors or > timeouts. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- Reviewed-by: Frank Li <Frank.Li@nxp.com> > > > Changes in V3: > > None > > Changes in V2: > > Improve commit message > > > drivers/i3c/master/mipi-i3c-hci/core.c | 1 + > drivers/i3c/master/mipi-i3c-hci/dma.c | 25 +++++++++++++++++++++++-- > drivers/i3c/master/mipi-i3c-hci/hci.h | 2 ++ > 3 files changed, 26 insertions(+), 2 deletions(-) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c > index afb0764b5e1f..44617eb3a3f1 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/core.c > +++ b/drivers/i3c/master/mipi-i3c-hci/core.c > @@ -973,6 +973,7 @@ static int i3c_hci_probe(struct platform_device *pdev) > > spin_lock_init(&hci->lock); > mutex_init(&hci->control_mutex); > + init_waitqueue_head(&hci->enqueue_wait_queue); > > /* > * Multi-bus instances share the same MMIO address range, but not > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 4cd32e3afa7b..314635e6e190 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -484,6 +484,12 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci, > > spin_lock_irq(&hci->lock); > > + while (unlikely(hci->enqueue_blocked)) { > + spin_unlock_irq(&hci->lock); > + wait_event(hci->enqueue_wait_queue, !READ_ONCE(hci->enqueue_blocked)); > + spin_lock_irq(&hci->lock); > + } > + > if (n > rh->xfer_space) { > spin_unlock_irq(&hci->lock); > hci_dma_unmap_xfer(hci, xfer_list, n); > @@ -539,6 +545,14 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci, > return 0; > } > > +static void hci_dma_unblock_enqueue(struct i3c_hci *hci) > +{ > + if (hci->enqueue_blocked) { > + hci->enqueue_blocked = false; > + wake_up_all(&hci->enqueue_wait_queue); > + } > +} > + > static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > struct hci_xfer *xfer_list, int n) > { > @@ -550,12 +564,17 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > > guard(mutex)(&hci->control_mutex); > > + spin_lock_irq(&hci->lock); > + > ring_status = rh_reg_read(RING_STATUS); > if (ring_status & RING_STATUS_RUNNING) { > + hci->enqueue_blocked = true; > + spin_unlock_irq(&hci->lock); > /* stop the ring */ > reinit_completion(&rh->op_done); > rh_reg_write(RING_CONTROL, rh_reg_read(RING_CONTROL) | RING_CTRL_ABORT); > wait_for_completion_timeout(&rh->op_done, HZ); > + spin_lock_irq(&hci->lock); > ring_status = rh_reg_read(RING_STATUS); > if (ring_status & RING_STATUS_RUNNING) { > /* > @@ -567,8 +586,6 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > } > } > > - spin_lock_irq(&hci->lock); > - > for (i = 0; i < n; i++) { > struct hci_xfer *xfer = xfer_list + i; > int idx = xfer->ring_entry; > @@ -604,6 +621,8 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE); > rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_RUN_STOP); > > + hci_dma_unblock_enqueue(hci); > + > spin_unlock_irq(&hci->lock); > > return did_unqueue; > @@ -647,6 +666,8 @@ static void hci_dma_xfer_done(struct i3c_hci *hci, struct hci_rh_data *rh) > } > if (xfer->completion) > complete(xfer->completion); > + if (RESP_STATUS(resp)) > + hci->enqueue_blocked = true; > } > > done_ptr = (done_ptr + 1) % rh->xfer_entries; > diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h > index f17f43494c1b..d630400ec945 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/hci.h > +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h > @@ -54,6 +54,8 @@ struct i3c_hci { > struct mutex control_mutex; > atomic_t next_cmd_tid; > bool irq_inactive; > + bool enqueue_blocked; > + wait_queue_head_t enqueue_wait_queue; > u32 caps; > unsigned int quirks; > unsigned int DAT_entries; > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-5-adrian.hunter@intel.com>]
* Re: [PATCH V3 04/16] i3c: mipi-i3c-hci: Wait for DMA ring restart to complete [not found] ` <20260504113352.38490-5-adrian.hunter@intel.com> @ 2026-05-12 16:45 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 16:45 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:40PM +0300, Adrian Hunter wrote: > Although hci_dma_dequeue_xfer() is serialized against itself via > control_mutex, this does not guarantee that a DMA ring restart > triggered by a previous invocation has fully completed. > > When the function is called again in rapid succession, the DMA ring may > still be transitioning back to the running state, which may confound or > disrupt further state changes. > > Address this by waiting for the DMA ring restart to complete before > continuing. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- Reviewed-by: Frank Li <Frank.Li@nxp.com> > > > Changes in V2 and V3: > > None > > > drivers/i3c/master/mipi-i3c-hci/dma.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 314635e6e190..28614fdbf558 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -617,6 +617,7 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > } > > /* restart the ring */ > + reinit_completion(&rh->op_done); > mipi_i3c_hci_resume(hci); > rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE); > rh_reg_write(RING_CONTROL, RING_CTRL_ENABLE | RING_CTRL_RUN_STOP); > @@ -625,6 +626,8 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > > spin_unlock_irq(&hci->lock); > > + wait_for_completion_timeout(&rh->op_done, HZ); > + > return did_unqueue; > } > > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-8-adrian.hunter@intel.com>]
* Re: [PATCH V3 07/16] i3c: mipi-i3c-hci: Complete transfer lists immediately on error [not found] ` <20260504113352.38490-8-adrian.hunter@intel.com> @ 2026-05-12 16:46 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 16:46 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:43PM +0300, Adrian Hunter wrote: > In DMA mode, transfer lists are currently completed only when the final > transfer in the list completes. If an earlier transfer fails, the list is > left incomplete and callers wait until timeout. > > There is no need to wait for a timeout, as the completion path in > i3c_hci_process_xfer() already checks for error status. Complete the > transfer list as soon as any transfer in the list reports an error. > > This avoids unnecessary delays and spurious timeouts on error. > > Complete a transfer list completion immediately there is an error. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- Reviewed-by: Frank Li <Frank.Li@nxp.com> > > > Changes in V3: > > None > > Changes in V2: > > Renamed completing_xfer to final_xfer > > > drivers/i3c/master/mipi-i3c-hci/dma.c | 6 ++++-- > drivers/i3c/master/mipi-i3c-hci/hci.h | 1 + > 2 files changed, 5 insertions(+), 2 deletions(-) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 28e4d38f55d3..899fdf6555a8 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -502,6 +502,8 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci, > struct hci_xfer *xfer = xfer_list + i; > u32 *ring_data = rh->xfer + rh->xfer_struct_sz * enqueue_ptr; > > + xfer->final_xfer = xfer_list + n - 1; > + > /* store cmd descriptor */ > *ring_data++ = xfer->cmd_desc[0]; > *ring_data++ = xfer->cmd_desc[1]; > @@ -576,8 +578,8 @@ static void hci_dma_xfer_done(struct i3c_hci *hci, struct hci_rh_data *rh) > tid, xfer->cmd_tid); > /* TODO: do something about it? */ > } > - if (xfer->completion) > - complete(xfer->completion); > + if (xfer == xfer->final_xfer || RESP_STATUS(resp)) > + complete(xfer->final_xfer->completion); > if (RESP_STATUS(resp)) > hci->enqueue_blocked = true; > } > diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h > index d630400ec945..f07fc627d4d2 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/hci.h > +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h > @@ -104,6 +104,7 @@ struct hci_xfer { > struct { > /* DMA specific */ > struct i3c_dma *dma; > + struct hci_xfer *final_xfer; > int ring_number; > int ring_entry; > }; > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-9-adrian.hunter@intel.com>]
* Re: [PATCH V3 08/16] i3c: mipi-i3c-hci: Avoid restarting DMA ring after aborting wrong transfer [not found] ` <20260504113352.38490-9-adrian.hunter@intel.com> @ 2026-05-12 16:50 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 16:50 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:44PM +0300, Adrian Hunter wrote: > Software ABORT of the DMA ring is used to recover from transfer list > timeouts, but it is inherently racy. The intended transfer list may > complete just before the ABORT takes effect, causing the subsequent > transfer list to be aborted instead. > > In this case, an incomplete transfer list may remain in the ring and has > not yet been processed by hci_dma_dequeue_xfer(). Restarting the DMA > ring at that point can lead to unpredictable results. > > Detect when the next queued transfer is not the first entry of a transfer > list and does not belong to the list currently being dequeued. In that > case, skip restarting the DMA ring and defer recovery until a subsequent > call to hci_dma_dequeue_xfer(), which will safely restart the ring once > the incomplete list is handled. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- > > > Changes in V3: > > None > > Changes in V2: > > Renamed completing_xfer to final_xfer > > > drivers/i3c/master/mipi-i3c-hci/dma.c | 15 +++++++++++++++ > drivers/i3c/master/mipi-i3c-hci/hci.h | 1 + > 2 files changed, 16 insertions(+) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 899fdf6555a8..268f54b32101 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -503,6 +503,7 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci, > u32 *ring_data = rh->xfer + rh->xfer_struct_sz * enqueue_ptr; > > xfer->final_xfer = xfer_list + n - 1; > + xfer->xfer_list_pos = i; > > /* store cmd descriptor */ > *ring_data++ = xfer->cmd_desc[0]; > @@ -669,6 +670,20 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > } > } > > + /* > + * A software ABORT may race with transfer completion and abort the next > + * transfer list instead. Detect that case, and do not restart the ring. > + * It will be handled by a subsequent dequeue. > + */ > + if (!did_unqueue) { > + struct hci_xfer *xfer = rh->src_xfers[rh->done_ptr]; > + > + if (xfer && xfer->xfer_list_pos && xfer->final_xfer != xfer_list->final_xfer) { > + spin_unlock_irq(&hci->lock); Is it possible to use auto cleanup to handle lock()? Frank > + return false; > + } > + } > + > /* restart the ring */ > reinit_completion(&rh->op_done); > mipi_i3c_hci_resume(hci); > diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h > index f07fc627d4d2..83d4f13a68a3 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/hci.h > +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h > @@ -107,6 +107,7 @@ struct hci_xfer { > struct hci_xfer *final_xfer; > int ring_number; > int ring_entry; > + int xfer_list_pos; > }; > }; > }; > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-10-adrian.hunter@intel.com>]
* Re: [PATCH V3 09/16] i3c: mipi-i3c-hci: Add DMA ring abort/reset quirk for Intel controllers [not found] ` <20260504113352.38490-10-adrian.hunter@intel.com> @ 2026-05-12 16:53 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 16:53 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:45PM +0300, Adrian Hunter wrote: > Some Intel I3C HCI controllers cannot reliably restart a DMA ring after an > ABORT. Additional queue resets are required to recover, and must be > performed using PIO reset bits even while operating in DMA mode. > > This behavior is non-standard. Introduce a controller quirk to opt into > the required PIO queue resets after a DMA ring abort, and enable it for > Intel LPSS I3C controllers. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- > > > Changes in V2 and V3: > > None > > > drivers/i3c/master/mipi-i3c-hci/core.c | 15 ++++++++++++++- > drivers/i3c/master/mipi-i3c-hci/dma.c | 9 +++++++++ > drivers/i3c/master/mipi-i3c-hci/hci.h | 2 ++ > 3 files changed, 25 insertions(+), 1 deletion(-) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c > index 44617eb3a3f1..770235ad6b25 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/core.c > +++ b/drivers/i3c/master/mipi-i3c-hci/core.c > @@ -240,6 +240,18 @@ void mipi_i3c_hci_pio_reset(struct i3c_hci *hci) > reg_write(RESET_CONTROL, RX_FIFO_RST | TX_FIFO_RST | RESP_QUEUE_RST); > } > > +#define ALL_QUEUES_RST (CMD_QUEUE_RST | RESP_QUEUE_RST | RX_FIFO_RST | TX_FIFO_RST | IBI_QUEUE_RST) > + > +void mipi_i3c_hci_pio_reset_all_queues(struct i3c_hci *hci) > +{ > + u32 regval; > + > + reg_write(RESET_CONTROL, ALL_QUEUES_RST); > + if (readx_poll_timeout_atomic(reg_read, RESET_CONTROL, regval, > + !(regval & ALL_QUEUES_RST), 0, 20)) > + dev_err(&hci->master.dev, "%s: Reset queues failed\n", __func__); > +} > + > /* located here rather than dct.c because needed bits are in core reg space */ > void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci) > { > @@ -1040,7 +1052,8 @@ MODULE_DEVICE_TABLE(acpi, i3c_hci_acpi_match); > static const struct platform_device_id i3c_hci_driver_ids[] = { > { .name = "intel-lpss-i3c", HCI_QUIRK_RPM_ALLOWED | > HCI_QUIRK_RPM_IBI_ALLOWED | > - HCI_QUIRK_RPM_PARENT_MANAGED }, > + HCI_QUIRK_RPM_PARENT_MANAGED | > + HCI_QUIRK_DMA_ABORT_REQUIRES_PIO_RESET }, > { /* sentinel */ } > }; > MODULE_DEVICE_TABLE(platform, i3c_hci_driver_ids); > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 268f54b32101..699c6d523eed 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -597,6 +597,13 @@ static void hci_dma_xfer_done(struct i3c_hci *hci, struct hci_rh_data *rh) > rh_reg_write(RING_OPERATION1, op1_val); > } > > +static void hci_dma_abort_requires_pio_reset_quirk(struct i3c_hci *hci, struct hci_rh_data *rh) > +{ > + if ((hci->quirks & HCI_QUIRK_DMA_ABORT_REQUIRES_PIO_RESET) && > + (rh_reg_read(RING_STATUS) & RING_STATUS_ABORTED)) > + mipi_i3c_hci_pio_reset_all_queues(hci); > +} > + > static void hci_dma_unblock_enqueue(struct i3c_hci *hci) > { > if (hci->enqueue_blocked) { > @@ -638,6 +645,8 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > } > } > > + hci_dma_abort_requires_pio_reset_quirk(hci, rh); > + If only use once, needn't helper function since this helper function is simple Frank > hci_dma_xfer_done(hci, rh); > > for (i = 0; i < n; i++) { > diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h > index 83d4f13a68a3..01237b12d32e 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/hci.h > +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h > @@ -156,10 +156,12 @@ struct i3c_hci_dev_data { > #define HCI_QUIRK_RPM_ALLOWED BIT(5) /* Runtime PM allowed */ > #define HCI_QUIRK_RPM_IBI_ALLOWED BIT(6) /* IBI and Hot-Join allowed while runtime suspended */ > #define HCI_QUIRK_RPM_PARENT_MANAGED BIT(7) /* Runtime PM managed by parent device */ > +#define HCI_QUIRK_DMA_ABORT_REQUIRES_PIO_RESET BIT(8) /* Do PIO queue SW resets after DMA abort */ > > /* global functions */ > void mipi_i3c_hci_resume(struct i3c_hci *hci); > void mipi_i3c_hci_pio_reset(struct i3c_hci *hci); > +void mipi_i3c_hci_pio_reset_all_queues(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); > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-11-adrian.hunter@intel.com>]
* Re: [PATCH V3 10/16] i3c: mipi-i3c-hci: Add DMA ring abort quirk for Intel controllers [not found] ` <20260504113352.38490-11-adrian.hunter@intel.com> @ 2026-05-12 17:01 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 17:01 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:46PM +0300, Adrian Hunter wrote: > DMA rings can be aborted either per-ring via RING_CONTROL or globally > via HC_CONTROL_ABORT. The driver currently relies on the per-ring > mechanism. > > Some Intel I3C HCI controllers require HC_CONTROL_ABORT to be asserted > before a DMA ring abort is effective. This behavior is non-standard. > Introduce a controller quirk to select the required abort method and > enable it for Intel LPSS I3C controllers. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- > > > Changes in V2 and V3: > > None > > > drivers/i3c/master/mipi-i3c-hci/core.c | 18 +++++++++++++++-- > drivers/i3c/master/mipi-i3c-hci/dma.c | 27 +++++++++++++++++++++++--- > drivers/i3c/master/mipi-i3c-hci/hci.h | 2 ++ > 3 files changed, 42 insertions(+), 5 deletions(-) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c > index 770235ad6b25..8274c84b16be 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/core.c > +++ b/drivers/i3c/master/mipi-i3c-hci/core.c > @@ -231,7 +231,20 @@ static void i3c_hci_bus_cleanup(struct i3c_master_controller *m) > > void mipi_i3c_hci_resume(struct i3c_hci *hci) > { > - reg_set(HC_CONTROL, HC_CONTROL_RESUME); > + u32 reg = reg_read(HC_CONTROL); > + > + reg |= HC_CONTROL_RESUME; > + reg &= ~HC_CONTROL_ABORT; > + reg_write(HC_CONTROL, reg); > +} > + > +void mipi_i3c_hci_abort(struct i3c_hci *hci) > +{ > + u32 reg = reg_read(HC_CONTROL); > + > + reg &= ~HC_CONTROL_RESUME; /* Do not set resume */ > + reg |= HC_CONTROL_ABORT; > + reg_write(HC_CONTROL, reg); > } > > /* located here rather than pio.c because needed bits are in core reg space */ > @@ -1053,7 +1066,8 @@ static const struct platform_device_id i3c_hci_driver_ids[] = { > { .name = "intel-lpss-i3c", HCI_QUIRK_RPM_ALLOWED | > HCI_QUIRK_RPM_IBI_ALLOWED | > HCI_QUIRK_RPM_PARENT_MANAGED | > - HCI_QUIRK_DMA_ABORT_REQUIRES_PIO_RESET }, > + HCI_QUIRK_DMA_ABORT_REQUIRES_PIO_RESET | > + HCI_QUIRK_DMA_REQUIRES_HC_ABORT }, > { /* sentinel */ } > }; > MODULE_DEVICE_TABLE(platform, i3c_hci_driver_ids); > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 699c6d523eed..41bbd912df7f 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -597,6 +597,29 @@ static void hci_dma_xfer_done(struct i3c_hci *hci, struct hci_rh_data *rh) > rh_reg_write(RING_OPERATION1, op1_val); > } > > +static bool hci_dma_requires_hc_abort_quirk(struct i3c_hci *hci, struct hci_rh_data *rh) > +{ > + if (!(hci->quirks & HCI_QUIRK_DMA_REQUIRES_HC_ABORT)) > + return false; > + > + reinit_completion(&rh->op_done); > + mipi_i3c_hci_abort(hci); > + wait_for_completion_timeout(&rh->op_done, HZ); > + rh_reg_write(RING_CONTROL, rh_reg_read(RING_CONTROL) | RING_CTRL_ABORT); > + > + return true; > +} > + > +static void hci_dma_abort(struct i3c_hci *hci, struct hci_rh_data *rh) > +{ > + if (hci_dma_requires_hc_abort_quirk(hci, rh)) > + return; Move check logic here to make overall logic simple if (hci->quirks & HCI_QUIRK_DMA_REQUIRES_HC_ABORT) { hci_dma_requires_hc_abort_quirk() return; } > + > + reinit_completion(&rh->op_done); > + rh_reg_write(RING_CONTROL, rh_reg_read(RING_CONTROL) | RING_CTRL_ABORT); > + wait_for_completion_timeout(&rh->op_done, HZ); move these codes reorg into new patch. Frank > +} > + > static void hci_dma_abort_requires_pio_reset_quirk(struct i3c_hci *hci, struct hci_rh_data *rh) > { > if ((hci->quirks & HCI_QUIRK_DMA_ABORT_REQUIRES_PIO_RESET) && > @@ -630,9 +653,7 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > hci->enqueue_blocked = true; > spin_unlock_irq(&hci->lock); > /* stop the ring */ > - reinit_completion(&rh->op_done); > - rh_reg_write(RING_CONTROL, rh_reg_read(RING_CONTROL) | RING_CTRL_ABORT); > - wait_for_completion_timeout(&rh->op_done, HZ); > + hci_dma_abort(hci, rh); > spin_lock_irq(&hci->lock); > ring_status = rh_reg_read(RING_STATUS); > if (ring_status & RING_STATUS_RUNNING) { > diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h > index 01237b12d32e..97c31a315a6e 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/hci.h > +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h > @@ -157,9 +157,11 @@ struct i3c_hci_dev_data { > #define HCI_QUIRK_RPM_IBI_ALLOWED BIT(6) /* IBI and Hot-Join allowed while runtime suspended */ > #define HCI_QUIRK_RPM_PARENT_MANAGED BIT(7) /* Runtime PM managed by parent device */ > #define HCI_QUIRK_DMA_ABORT_REQUIRES_PIO_RESET BIT(8) /* Do PIO queue SW resets after DMA abort */ > +#define HCI_QUIRK_DMA_REQUIRES_HC_ABORT BIT(9) /* Use HC_CONTROL ABORT to abort DMA */ > > /* global functions */ > void mipi_i3c_hci_resume(struct i3c_hci *hci); > +void mipi_i3c_hci_abort(struct i3c_hci *hci); > void mipi_i3c_hci_pio_reset(struct i3c_hci *hci); > void mipi_i3c_hci_pio_reset_all_queues(struct i3c_hci *hci); > void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci); > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-12-adrian.hunter@intel.com>]
* Re: [PATCH V3 11/16] i3c: mipi-i3c-hci: Factor out reset-and-restore helper [not found] ` <20260504113352.38490-12-adrian.hunter@intel.com> @ 2026-05-12 17:03 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 17:03 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:47PM +0300, Adrian Hunter wrote: > Factor the reset-and-restore sequence out of i3c_hci_rpm_resume() into > a separate helper. > > This allows the same logic to be reused for recovery paths in subsequent > changes without duplicating suspend/resume handling. > > No functional change. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- Reviewed-by: Frank Li <Frank.Li@nxp.com> > > > Changes in V3: > > None > > Changes in V2: > > Drop redundant i3c_hci_sync_irq_inactive(hci) > from i3c_hci_reset_and_restore() because it is called by > hci->io->suspend() anyway > > > drivers/i3c/master/mipi-i3c-hci/core.c | 19 +++++++++++++++++-- > drivers/i3c/master/mipi-i3c-hci/hci.h | 2 ++ > 2 files changed, 19 insertions(+), 2 deletions(-) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c > index 8274c84b16be..12a0122fb709 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/core.c > +++ b/drivers/i3c/master/mipi-i3c-hci/core.c > @@ -798,9 +798,8 @@ int i3c_hci_rpm_suspend(struct device *dev) > } > EXPORT_SYMBOL_GPL(i3c_hci_rpm_suspend); > > -int i3c_hci_rpm_resume(struct device *dev) > +static int i3c_hci_do_reset_and_restore(struct i3c_hci *hci) > { > - struct i3c_hci *hci = dev_get_drvdata(dev); > int ret; > > ret = i3c_hci_reset_and_init(hci); > @@ -821,6 +820,22 @@ int i3c_hci_rpm_resume(struct device *dev) > > return 0; > } > + > +int i3c_hci_reset_and_restore(struct i3c_hci *hci) > +{ > + i3c_hci_bus_disable(hci); > + > + hci->io->suspend(hci); > + > + return i3c_hci_do_reset_and_restore(hci); > +} > + > +int i3c_hci_rpm_resume(struct device *dev) > +{ > + struct i3c_hci *hci = dev_get_drvdata(dev); > + > + return i3c_hci_do_reset_and_restore(hci); > +} > EXPORT_SYMBOL_GPL(i3c_hci_rpm_resume); > > static int i3c_hci_runtime_suspend(struct device *dev) > diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h > index 97c31a315a6e..a3151c26827e 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/hci.h > +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h > @@ -175,4 +175,6 @@ int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n); > int i3c_hci_rpm_suspend(struct device *dev); > int i3c_hci_rpm_resume(struct device *dev); > > +int i3c_hci_reset_and_restore(struct i3c_hci *hci); > + > #endif > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-14-adrian.hunter@intel.com>]
* Re: [PATCH V3 13/16] i3c: mipi-i3c-hci: Wait for NoOp commands to complete [not found] ` <20260504113352.38490-14-adrian.hunter@intel.com> @ 2026-05-12 18:05 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 18:05 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:49PM +0300, Adrian Hunter wrote: > When a transfer list is only partially completed due to an error, > hci_dma_dequeue_xfer() overwrites the remaining DMA ring entries with > NoOp commands and restarts the ring to flush them out. > > While NoOp commands are expected to complete successfully, they may still > fail to complete if the DMA ring is stuck. Explicitly wait for the NoOp > commands to finish, and trigger controller recovery if they do not > complete or report an error. > > This ensures that partially completed transfer lists are reliably > resolved and that a stuck ring is recovered promptly. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- Reviewed-by: Frank Li <Frank.Li@nxp.com> > > > Changes in V3: > > None > > Changes in V2: > > Rename completing_xfer to final_xfer > Add missing reinit_completion() > > > drivers/i3c/master/mipi-i3c-hci/dma.c | 39 ++++++++++++++++++++++----- > 1 file changed, 33 insertions(+), 6 deletions(-) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 376062c0fcbf..90fa621c9d56 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -696,11 +696,33 @@ static void hci_dma_recovery(struct i3c_hci *hci) > dev_err(&hci->master.dev, "Recovery %s\n", ret ? "failed!" : "done"); > } > > +static bool hci_dma_wait_for_noop(struct i3c_hci *hci, struct hci_xfer *xfer_list, int n, > + int noop_pos) > +{ > + struct completion *done = xfer_list->final_xfer->completion; > + bool timeout = !wait_for_completion_timeout(done, HZ); > + u32 error = timeout; > + > + for (int i = noop_pos; i < n && !error; i++) > + error = RESP_STATUS(xfer_list[i].response); > + > + if (!error) > + return true; > + > + if (timeout) > + dev_err(&hci->master.dev, "NoOp timeout error\n"); > + else > + dev_err(&hci->master.dev, "NoOp error %u\n", error); > + > + return false; > +} > + > static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > struct hci_xfer *xfer_list, int n) > { > struct hci_rings_data *rings = hci->io_data; > struct hci_rh_data *rh = &rings->headers[xfer_list[0].ring_number]; > + int noop_pos = -1; > unsigned int i; > bool did_unqueue = false; > u32 ring_status; > @@ -708,7 +730,7 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > guard(mutex)(&hci->control_mutex); > > spin_lock_irq(&hci->lock); > - > +restart: > ring_status = rh_reg_read(RING_STATUS); > if (ring_status & RING_STATUS_RUNNING) { > /* > @@ -765,11 +787,10 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > *ring_data++ = 0; > } > > - /* disassociate this xfer struct */ > - rh->src_xfers[idx] = NULL; > - > - /* and unmap it */ > - hci_dma_unmap_xfer(hci, xfer, 1); > + if (noop_pos < 0) { > + reinit_completion(xfer->final_xfer->completion); > + noop_pos = i; > + } > > did_unqueue = true; > } > @@ -801,6 +822,12 @@ static bool hci_dma_dequeue_xfer(struct i3c_hci *hci, > > wait_for_completion_timeout(&rh->op_done, HZ); > > + if (did_unqueue && !hci_dma_wait_for_noop(hci, xfer_list, n, noop_pos)) { > + spin_lock_irq(&hci->lock); > + hci->recovery_needed = true; > + goto restart; > + } > + > return did_unqueue; > } > > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-15-adrian.hunter@intel.com>]
* Re: [PATCH V3 14/16] i3c: mipi-i3c-hci: Base timeouts on actual transfer start time [not found] ` <20260504113352.38490-15-adrian.hunter@intel.com> @ 2026-05-12 18:11 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 18:11 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:50PM +0300, Adrian Hunter wrote: > Transfer timeouts are currently measured from the point where a transfer > list is queued to the controller. This can cause transfers to time out > before they have actually started, if earlier queued transfers consume > the timeout interval. > > Fix this by recording when a transfer reaches the head of the queue and > adjusting the timeout calculation to start from that point. The existing > low-overhead completion-based timeout mechanism is preserved, but care is > taken to ensure the transfer start time is consistently recorded for both > PIO and DMA paths. > > This prevents premature timeouts while retaining efficient timeout > handling. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- > > > Changes in V3: > > None > > Changes in V2: > Do not flag the next transfer as started when there is an error > which halts the controller > Instead flag it started at the end of hci_dma_dequeue_xfer() > Use hci_start_xfer() in pio.c > > > drivers/i3c/master/mipi-i3c-hci/core.c | 19 ++++++++++++++++++- > drivers/i3c/master/mipi-i3c-hci/dma.c | 19 ++++++++++++++++++- > drivers/i3c/master/mipi-i3c-hci/hci.h | 11 +++++++++++ > drivers/i3c/master/mipi-i3c-hci/pio.c | 1 + > 4 files changed, 48 insertions(+), 2 deletions(-) > ... > > #include <linux/io.h> > +#include <linux/jiffies.h> > > /* 32-bit word aware bit and mask macros */ > #define W0_MASK(h, l) GENMASK((h) - 0, (l) - 0) > @@ -88,11 +89,13 @@ struct hci_xfer { > u32 cmd_desc[4]; > u32 response; > bool rnw; > + bool started; > void *data; > unsigned int data_len; > unsigned int cmd_tid; > struct completion *completion; > unsigned long timeout; > + unsigned long start_time; it'd better to add unit for start_time Frank > union { > struct { > /* PIO specific */ > @@ -123,6 +126,14 @@ static inline void hci_free_xfer(struct hci_xfer *xfer, unsigned int n) > kfree(xfer); > } > > +static inline void hci_start_xfer(struct hci_xfer *xfer) > +{ > + if (!xfer->started) { > + xfer->started = true; > + xfer->start_time = jiffies; > + } > +} > + > /* This abstracts PIO vs DMA operations */ > struct hci_io_ops { > bool (*irq_handler)(struct i3c_hci *hci); > diff --git a/drivers/i3c/master/mipi-i3c-hci/pio.c b/drivers/i3c/master/mipi-i3c-hci/pio.c > index 8f48a81e65ab..6b8cc5f2b4d2 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/pio.c > +++ b/drivers/i3c/master/mipi-i3c-hci/pio.c > @@ -605,6 +605,7 @@ static bool hci_pio_process_cmd(struct i3c_hci *hci, struct hci_pio_data *pio) > * Finally send the command. > */ > hci_pio_write_cmd(hci, pio->curr_xfer); > + hci_start_xfer(pio->curr_xfer); > /* > * And move on. > */ > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-16-adrian.hunter@intel.com>]
* Re: [PATCH V3 15/16] i3c: mipi-i3c-hci: Consolidate DMA ring allocation [not found] ` <20260504113352.38490-16-adrian.hunter@intel.com> @ 2026-05-12 18:15 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 18:15 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:51PM +0300, Adrian Hunter wrote: > dma_alloc_coherent() allocates memory in whole pages, which can waste > space when command and response queues are allocated separately. > > Allocate the DMA command and response queues from a single coherent > allocation instead, while preserving the required 4-byte alignment. > > This reduces memory overhead without changing behavior. > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- > > > Changes in V3: > > None > > Changes in V2: > > Check for failed allocation before assignments to avoid doing > arithmetic with NULL pointers > > > drivers/i3c/master/mipi-i3c-hci/dma.c | 24 +++++++++++------------- > 1 file changed, 11 insertions(+), 13 deletions(-) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 6440302c63ca..4029d4d9e784 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -186,14 +186,12 @@ static void hci_dma_free(void *data) > for (int i = 0; i < rings->total; i++) { > rh = &rings->headers[i]; > > - if (rh->xfer) > - dma_free_coherent(rings->sysdev, > - rh->xfer_struct_sz * rh->xfer_entries, > - rh->xfer, rh->xfer_dma); > - if (rh->resp) > - dma_free_coherent(rings->sysdev, > - rh->resp_struct_sz * rh->xfer_entries, > - rh->resp, rh->resp_dma); > + if (rh->xfer) { > + size_t sz = round_up(rh->xfer_struct_sz * rh->xfer_entries, 4); > + > + sz += rh->resp_struct_sz * rh->xfer_entries; > + dma_free_coherent(rings->sysdev, sz, rh->xfer, rh->xfer_dma); Good cleanup. can you save sz into rh when alloc it? Frank > + } > kfree(rh->src_xfers); > if (rh->ibi_status) > dma_free_coherent(rings->sysdev, > @@ -359,18 +357,18 @@ static int hci_dma_init(struct i3c_hci *hci) > dev_dbg(&hci->master.dev, > "xfer_struct_sz = %d, resp_struct_sz = %d", > rh->xfer_struct_sz, rh->resp_struct_sz); > - xfers_sz = rh->xfer_struct_sz * rh->xfer_entries; > + xfers_sz = round_up(rh->xfer_struct_sz * rh->xfer_entries, 4); > resps_sz = rh->resp_struct_sz * rh->xfer_entries; > > - rh->xfer = dma_alloc_coherent(rings->sysdev, xfers_sz, > + rh->xfer = dma_alloc_coherent(rings->sysdev, xfers_sz + resps_sz, > &rh->xfer_dma, GFP_KERNEL); > - rh->resp = dma_alloc_coherent(rings->sysdev, resps_sz, > - &rh->resp_dma, GFP_KERNEL); > rh->src_xfers = > kzalloc_objs(*rh->src_xfers, rh->xfer_entries); > ret = -ENOMEM; > - if (!rh->xfer || !rh->resp || !rh->src_xfers) > + if (!rh->xfer || !rh->src_xfers) > goto err_out; > + rh->resp = rh->xfer + xfers_sz; > + rh->resp_dma = rh->xfer_dma + xfers_sz; > > /* IBIs */ > > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20260504113352.38490-17-adrian.hunter@intel.com>]
* Re: [PATCH V3 16/16] i3c: mipi-i3c-hci: Increase DMA transfer ring size to maximum [not found] ` <20260504113352.38490-17-adrian.hunter@intel.com> @ 2026-05-12 18:15 ` Frank Li 0 siblings, 0 replies; 12+ messages in thread From: Frank Li @ 2026-05-12 18:15 UTC (permalink / raw) To: Adrian Hunter; +Cc: alexandre.belloni, linux-i3c, linux-kernel On Mon, May 04, 2026 at 02:33:52PM +0300, Adrian Hunter wrote: > The DMA transfer ring is currently limited to 16 entries, despite the > MIPI I3C HCI supporting up to 32 devices. When the ring lacks space for a > new transfer list, the driver returns -EBUSY, which can be unexpected > for clients. > > Increase the DMA transfer ring size to the maximum supported value of > 255 entries. This effectively eliminates ring-space exhaustion in > practice and avoids the complexity of adding secondary queuing > mechanisms. > > Even at the maximum size, the memory overhead remains small > (approximately 24 bytes per entry by default). > > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> > --- Reviewed-by: Frank Li <Frank.Li@nxp.com> > > > Changes in V2 and V3: > > None > > > drivers/i3c/master/mipi-i3c-hci/dma.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c > index 4029d4d9e784..9549d98add4b 100644 > --- a/drivers/i3c/master/mipi-i3c-hci/dma.c > +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c > @@ -27,7 +27,7 @@ > */ > > #define XFER_RINGS 1 /* max: 8 */ > -#define XFER_RING_ENTRIES 16 /* max: 255 */ > +#define XFER_RING_ENTRIES 255 /* max: 255 */ > > #define IBI_RINGS 1 /* max: 8 */ > #define IBI_STATUS_RING_ENTRIES 32 /* max: 255 */ > -- > 2.51.0 > ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-05-12 18:15 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260504113352.38490-1-adrian.hunter@intel.com>
2026-05-12 12:35 ` [PATCH V3 00/16] i3c: mipi-i3c-hci: DMA abort, recovery and related improvements Adrian Hunter
[not found] ` <20260504113352.38490-4-adrian.hunter@intel.com>
2026-05-12 16:44 ` [PATCH V3 03/16] i3c: mipi-i3c-hci: Prevent DMA enqueue while ring is aborting or in error Frank Li
[not found] ` <20260504113352.38490-5-adrian.hunter@intel.com>
2026-05-12 16:45 ` [PATCH V3 04/16] i3c: mipi-i3c-hci: Wait for DMA ring restart to complete Frank Li
[not found] ` <20260504113352.38490-8-adrian.hunter@intel.com>
2026-05-12 16:46 ` [PATCH V3 07/16] i3c: mipi-i3c-hci: Complete transfer lists immediately on error Frank Li
[not found] ` <20260504113352.38490-9-adrian.hunter@intel.com>
2026-05-12 16:50 ` [PATCH V3 08/16] i3c: mipi-i3c-hci: Avoid restarting DMA ring after aborting wrong transfer Frank Li
[not found] ` <20260504113352.38490-10-adrian.hunter@intel.com>
2026-05-12 16:53 ` [PATCH V3 09/16] i3c: mipi-i3c-hci: Add DMA ring abort/reset quirk for Intel controllers Frank Li
[not found] ` <20260504113352.38490-11-adrian.hunter@intel.com>
2026-05-12 17:01 ` [PATCH V3 10/16] i3c: mipi-i3c-hci: Add DMA ring abort " Frank Li
[not found] ` <20260504113352.38490-12-adrian.hunter@intel.com>
2026-05-12 17:03 ` [PATCH V3 11/16] i3c: mipi-i3c-hci: Factor out reset-and-restore helper Frank Li
[not found] ` <20260504113352.38490-14-adrian.hunter@intel.com>
2026-05-12 18:05 ` [PATCH V3 13/16] i3c: mipi-i3c-hci: Wait for NoOp commands to complete Frank Li
[not found] ` <20260504113352.38490-15-adrian.hunter@intel.com>
2026-05-12 18:11 ` [PATCH V3 14/16] i3c: mipi-i3c-hci: Base timeouts on actual transfer start time Frank Li
[not found] ` <20260504113352.38490-16-adrian.hunter@intel.com>
2026-05-12 18:15 ` [PATCH V3 15/16] i3c: mipi-i3c-hci: Consolidate DMA ring allocation Frank Li
[not found] ` <20260504113352.38490-17-adrian.hunter@intel.com>
2026-05-12 18:15 ` [PATCH V3 16/16] i3c: mipi-i3c-hci: Increase DMA transfer ring size to maximum Frank Li
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox