[PATCH 09/12] i3c: mipi-i3c-hci: Consolidate common xfer processing logic

Frank Li Frank.li at nxp.com
Fri Feb 27 08:30:42 PST 2026


On Fri, Feb 27, 2026 at 04:11:46PM +0200, Adrian Hunter wrote:
> Several parts of the MIPI I3C HCI driver duplicate the same sequence for
> queueing a transfer, waiting for completion, and handling timeouts. This
> logic appears in five separate locations and will be affected by an
> upcoming fix.
>
> Refactor the repeated code into a new helper, i3c_hci_process_xfer(), and
> store the timeout value in the hci_xfer structure so that callers do not
> need to pass it as a separate parameter.
>
> Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver")
> Cc: stable at vger.kernel.org
> Signed-off-by: Adrian Hunter <adrian.hunter at intel.com>
> ---
Reviewed-by: Frank Li <Frank.Li at nxp.com>
>  drivers/i3c/master/mipi-i3c-hci/cmd_v1.c |  8 ++---
>  drivers/i3c/master/mipi-i3c-hci/cmd_v2.c |  8 ++---
>  drivers/i3c/master/mipi-i3c-hci/core.c   | 43 ++++++++++++++----------
>  drivers/i3c/master/mipi-i3c-hci/hci.h    |  2 ++
>  4 files changed, 33 insertions(+), 28 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
> index 831a261f6c56..75d452d7f6af 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
> @@ -331,12 +331,10 @@ static int hci_cmd_v1_daa(struct i3c_hci *hci)
>  			CMD_A0_ROC | CMD_A0_TOC;
>  		xfer->cmd_desc[1] = 0;
>  		xfer->completion = &done;
> -		hci->io->queue_xfer(hci, xfer, 1);
> -		if (!wait_for_completion_timeout(&done, HZ) &&
> -		    hci->io->dequeue_xfer(hci, xfer, 1)) {
> -			ret = -ETIMEDOUT;
> +		xfer->timeout = HZ;
> +		ret = i3c_hci_process_xfer(hci, xfer, 1);
> +		if (ret)
>  			break;
> -		}
>  		if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||
>  		     RESP_STATUS(xfer->response) == RESP_ERR_NACK) &&
>  		    RESP_DATA_LENGTH(xfer->response) == 1) {
> diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
> index 054beee36da5..39eec26a363c 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
> @@ -253,6 +253,7 @@ static int hci_cmd_v2_daa(struct i3c_hci *hci)
>  	xfer[0].rnw = true;
>  	xfer[0].cmd_desc[1] = CMD_A1_DATA_LENGTH(8);
>  	xfer[1].completion = &done;
> +	xfer[1].timeout = HZ;
>
>  	for (;;) {
>  		ret = i3c_master_get_free_addr(&hci->master, next_addr);
> @@ -272,12 +273,9 @@ static int hci_cmd_v2_daa(struct i3c_hci *hci)
>  			CMD_A0_ASSIGN_ADDRESS(next_addr) |
>  			CMD_A0_ROC |
>  			CMD_A0_TOC;
> -		hci->io->queue_xfer(hci, xfer, 2);
> -		if (!wait_for_completion_timeout(&done, HZ) &&
> -		    hci->io->dequeue_xfer(hci, xfer, 2)) {
> -			ret = -ETIMEDOUT;
> +		ret = i3c_hci_process_xfer(hci, xfer, 2);
> +		if (ret)
>  			break;
> -		}
>  		if (RESP_STATUS(xfer[0].response) != RESP_SUCCESS) {
>  			ret = 0;  /* no more devices to be assigned */
>  			break;
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index 4877a321edf9..9cfe12fb9a0e 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
> @@ -213,6 +213,25 @@ void mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci)
>  	reg_write(DCT_SECTION, FIELD_PREP(DCT_TABLE_INDEX, 0));
>  }
>
> +int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n)
> +{
> +	struct completion *done = xfer[n - 1].completion;
> +	unsigned long timeout = xfer[n - 1].timeout;
> +	int ret;
> +
> +	ret = hci->io->queue_xfer(hci, xfer, n);
> +	if (ret)
> +		return ret;
> +
> +	if (!wait_for_completion_timeout(done, timeout) &&
> +	    hci->io->dequeue_xfer(hci, xfer, n)) {
> +		dev_err(&hci->master.dev, "%s: timeout error\n", __func__);
> +		return -ETIMEDOUT;
> +	}
> +
> +	return 0;
> +}
> +
>  static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
>  				struct i3c_ccc_cmd *ccc)
>  {
> @@ -253,18 +272,14 @@ static int i3c_hci_send_ccc_cmd(struct i3c_master_controller *m,
>  	last = i - 1;
>  	xfer[last].cmd_desc[0] |= CMD_0_TOC;
>  	xfer[last].completion = &done;
> +	xfer[last].timeout = HZ;
>
>  	if (prefixed)
>  		xfer--;
>
> -	ret = hci->io->queue_xfer(hci, xfer, nxfers);
> +	ret = i3c_hci_process_xfer(hci, xfer, nxfers);
>  	if (ret)
>  		goto out;
> -	if (!wait_for_completion_timeout(&done, HZ) &&
> -	    hci->io->dequeue_xfer(hci, xfer, nxfers)) {
> -		ret = -ETIMEDOUT;
> -		goto out;
> -	}
>  	for (i = prefixed; i < nxfers; i++) {
>  		if (ccc->rnw)
>  			ccc->dests[i - prefixed].payload.len =
> @@ -335,15 +350,11 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
>  	last = i - 1;
>  	xfer[last].cmd_desc[0] |= CMD_0_TOC;
>  	xfer[last].completion = &done;
> +	xfer[last].timeout = HZ;
>
> -	ret = hci->io->queue_xfer(hci, xfer, nxfers);
> +	ret = i3c_hci_process_xfer(hci, xfer, nxfers);
>  	if (ret)
>  		goto out;
> -	if (!wait_for_completion_timeout(&done, HZ) &&
> -	    hci->io->dequeue_xfer(hci, xfer, nxfers)) {
> -		ret = -ETIMEDOUT;
> -		goto out;
> -	}
>  	for (i = 0; i < nxfers; i++) {
>  		if (i3c_xfers[i].rnw)
>  			i3c_xfers[i].len = RESP_DATA_LENGTH(xfer[i].response);
> @@ -383,15 +394,11 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
>  	last = i - 1;
>  	xfer[last].cmd_desc[0] |= CMD_0_TOC;
>  	xfer[last].completion = &done;
> +	xfer[last].timeout = m->i2c.timeout;
>
> -	ret = hci->io->queue_xfer(hci, xfer, nxfers);
> +	ret = i3c_hci_process_xfer(hci, xfer, nxfers);
>  	if (ret)
>  		goto out;
> -	if (!wait_for_completion_timeout(&done, m->i2c.timeout) &&
> -	    hci->io->dequeue_xfer(hci, xfer, nxfers)) {
> -		ret = -ETIMEDOUT;
> -		goto out;
> -	}
>  	for (i = 0; i < nxfers; i++) {
>  		if (RESP_STATUS(xfer[i].response) != RESP_SUCCESS) {
>  			ret = -EIO;
> diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
> index 337b7ab1cb06..6680b8640c5a 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/hci.h
> +++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
> @@ -87,6 +87,7 @@ struct hci_xfer {
>  	unsigned int data_len;
>  	unsigned int cmd_tid;
>  	struct completion *completion;
> +	unsigned long timeout;
>  	union {
>  		struct {
>  			/* PIO specific */
> @@ -154,5 +155,6 @@ 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);
>  void i3c_hci_sync_irq_inactive(struct i3c_hci *hci);
> +int i3c_hci_process_xfer(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
>
>  #endif
> --
> 2.51.0
>
>
> --
> linux-i3c mailing list
> linux-i3c at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-i3c



More information about the linux-i3c mailing list