* 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
* 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
* 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
* 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
* 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
* 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
* 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
* 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
* 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
* 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
* 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
* 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