Re: [PATCH v4 3/3] i3c: master: Validate GET CCC payload length and retry Direct GET once

Frank Li <[email protected]>
Newsgroups org.infradead.lists.linux-i3c,dev.linux.lists.imx,org.kernel.vger.linux-kernel
Message-ID <akQPfmc-9p88Un7z@lizhi-Precision-Tower-5810>
On Tue, Jun 30, 2026 at 06:20:27AM -0700, [email protected] wrote:
> From: Adrian Ng Ho Yin <[email protected]>
>
> Add optional_bytes to struct i3c_ccc_cmd_payload so callers describe
> variable-length GET CCC responses. GETMRL and GETMXDS set optional_bytes
> at the call site.
>
> Validate GET payload length in i3c_master_send_ccc_cmd_locked() using
> actual_len and optional_bytes. Retry failed Direct GET CCCs up to
> cmd->retries times (default I3C_CCC_RETRIES) on any error; SET CCCs are
> not retried by default.
>
> Add i3c_ccc_cmd_init_retries() and set actual_len in I3C master drivers
> on successful GET transfers.
>
> Signed-off-by: Adrian Ng Ho Yin <[email protected]>
> Signed-off-by: Tze Yee Ng <[email protected]>
> ---
>  drivers/i3c/master.c                   | 92 ++++++++++++++++++++++----
>  drivers/i3c/master/adi-i3c-master.c    |  2 +
>  drivers/i3c/master/i3c-master-cdns.c   |  2 +
>  drivers/i3c/master/mipi-i3c-hci/core.c |  5 +-
>  drivers/i3c/master/renesas-i3c.c       |  2 +
>  drivers/i3c/master/svc-i3c-master.c    |  4 +-
>  include/linux/i3c/ccc.h                |  7 ++

Can you spit ccc.h and master.c to one patch, other driver change to
anthoer patche.

>  7 files changed, 98 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index 5cd4e5da2233..29dc0793a5a4 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -901,6 +901,8 @@ static void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr,
>  {
>  	dest->addr = addr;
>  	dest->payload.len = payloadlen;
> +	dest->payload.actual_len = 0;
> +	dest->payload.optional_bytes = 0;
>  	if (payloadlen)
>  		dest->payload.data = kzalloc(payloadlen, GFP_KERNEL);
>  	else
> @@ -914,17 +916,55 @@ static void i3c_ccc_cmd_dest_cleanup(struct i3c_ccc_cmd_dest *dest)
>  	kfree(dest->payload.data);
>  }
>
...
>
> +static void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id,
> +			     struct i3c_ccc_cmd_dest *dests,
> +			     unsigned int ndests)
> +{
> +	i3c_ccc_cmd_init_retries(cmd, rnw, id, dests, ndests,
> +				 rnw ? I3C_CCC_RETRIES : 0);

why only read need retry?

> +}
> +
...
>
> @@ -953,7 +996,24 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master,
>  	    !master->ops->supports_ccc_cmd(master, cmd))
>  		return -EOPNOTSUPP;
>
> -	return master->ops->send_ccc_cmd(master, cmd);
> +	max_attempts = cmd->retries + 1;
> +	ret = -EIO;
> +	for (attempt = 0; attempt < max_attempts; attempt++) {
> +		unsigned int i;
> +
> +		if (cmd->rnw)
> +			for (i = 0; i < cmd->ndests; i++)
> +				cmd->dests[i].payload.actual_len = 0;
> +
> +		cmd->err = I3C_ERROR_UNKNOWN;
> +		ret = master->ops->send_ccc_cmd(master, cmd);
> +		if (!ret && cmd->rnw)

i3c_ccc_validate_payload_len() already checked cmd->rnw, needn't check here
again.

> +			ret = i3c_ccc_validate_payload_len(cmd);
> +		if (!ret && cmd->err == I3C_ERROR_UNKNOWN)
> +			break;

if i3c_ccc_validate_payload_len() return failure, why need try here.
suppose only need retry when target NACK request.

> +	}
> +
> +	return ret;
>  }
>
>  static struct i2c_dev_desc *
...
> @@ -1363,6 +1427,8 @@ static int i3c_master_getmxds_locked(struct i3c_master_controller *master,
>  	if (!getmaxds)
>  		return -ENOMEM;
>
> +	dest.payload.optional_bytes = 3;
> +

move these set optional_bytes to new patch

>  	i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMXDS, &dest, 1);
>  	ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
>  	if (ret) {
...
> diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
> index f39c449922ca..fec614700843 100644
> --- a/drivers/i3c/master/renesas-i3c.c
> +++ b/drivers/i3c/master/renesas-i3c.c
> @@ -805,6 +805,8 @@ static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
>  	ret = xfer->ret;
>  	if (ret)
>  		ccc->err = I3C_ERROR_M2;
> +	else if (ccc->rnw)
> +		ccc->dests[0].payload.actual_len = cmd->rx_count;

update actual_len's patch should just flow add field actual_len's patch

>
>  	return ret;
>  }
...
> +
>  /**
>   * struct i3c_ccc_cmd_payload - CCC payload
>   *
>   * @len: requested payload length
>   * @actual_len: number of bytes received on a GET CCC (filled by the driver)
> + * @optional_bytes: GET CCCs may return up to this many fewer bytes than @len

					   up to @len - @optional_bytes

Frank
>   * @data: payload data. This buffer must be DMA-able
>   */
>  struct i3c_ccc_cmd_payload {
>  	u16 len;
>  	u16 actual_len;
> +	u16 optional_bytes;
>  	void *data;
>  };
>
> @@ -374,12 +378,15 @@ struct i3c_ccc_cmd_dest {
>   * @ndests: number of destinations. Should always be one for broadcast commands
>   * @dests: array of destinations and associated payload for this CCC. Most of
>   *	   the time, only one destination is provided
> + * @retries: number of times to retry a failed Direct GET CCC (see
> + *	     &I3C_CCC_RETRIES)
>   * @err: I3C error code
>   */
>  struct i3c_ccc_cmd {
>  	u8 rnw;
>  	u8 id;
>  	unsigned int ndests;
> +	unsigned int retries;
>  	struct i3c_ccc_cmd_dest *dests;
>  	enum i3c_error_code err;
>  };
> --
> 2.43.7
>

-- 
linux-i3c mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-i3c
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.