2023-10-16 15:47:30

by Frank Li

[permalink] [raw]
Subject: [PATCH 0/5] i3c: master: some improvment for i3c master

These are dependent on bugs fixed serial: https://lore.kernel.org/imx/[email protected]/T/#t
There are two major improment

1. Add actual size in i3c_transfer because i3c allow target early termiate
transfer.
2. Add API for i3c_dev_gettstatus_format1 for i3c comand GET_STATUS.
3. svc master enable hotjoin default

Frank Li (5):
i3c: master: svc: enable hotjoin default
i3c: add actual in i3c_priv_xfer
i3c: svc: rename read_len as actual_len
i3c: master: svc return actual transfer data len
i3c: add API i3c_dev_gettstatus_format1() to get target device status

drivers/i3c/device.c | 24 ++++++++++++++++
drivers/i3c/internals.h | 1 +
drivers/i3c/master.c | 27 ++++++++++++++++++
drivers/i3c/master/svc-i3c-master.c | 44 +++++++++++++++++++----------
include/linux/i3c/device.h | 2 ++
5 files changed, 83 insertions(+), 15 deletions(-)

--
2.34.1


2023-10-16 15:47:39

by Frank Li

[permalink] [raw]
Subject: [PATCH 5/5] i3c: add API i3c_dev_gettstatus_format1() to get target device status

I3C standard 5.1.9.3.15 Get Device Status (GETSTATUS):
Get request for one I3C Target Device to return its current status.

Add API to fetch it with format1.

Signed-off-by: Frank Li <[email protected]>
---
drivers/i3c/device.c | 24 ++++++++++++++++++++++++
drivers/i3c/internals.h | 1 +
drivers/i3c/master.c | 27 +++++++++++++++++++++++++++
include/linux/i3c/device.h | 1 +
4 files changed, 53 insertions(+)

diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
index 1a6a8703dbc3..0566ab9f1498 100644
--- a/drivers/i3c/device.c
+++ b/drivers/i3c/device.c
@@ -196,6 +196,30 @@ void i3c_device_free_ibi(struct i3c_device *dev)
}
EXPORT_SYMBOL_GPL(i3c_device_free_ibi);

+/**
+ * i3c_device_getstatus_format1() - Get device status with format 1.
+ * @dev: device for which you want to get status.
+ * @status: I3C status format 1
+ *
+ * Return: 0 in case of success, a negative error core otherwise.
+ */
+int i3c_device_getstatus_format1(struct i3c_device *dev, u16 *status)
+{
+ int ret = -EINVAL;
+
+ if (!status)
+ return -EINVAL;
+
+ i3c_bus_normaluse_lock(dev->bus);
+ if (dev->desc) {
+ ret = i3c_dev_getstatus_format1_locked(dev->desc, status);
+ }
+ i3c_bus_normaluse_unlock(dev->bus);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i3c_device_getstatus_format1);
+
/**
* i3cdev_to_dev() - Returns the device embedded in @i3cdev
* @i3cdev: I3C device
diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
index 908a807badaf..976ad26ca79c 100644
--- a/drivers/i3c/internals.h
+++ b/drivers/i3c/internals.h
@@ -24,4 +24,5 @@ int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev);
int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
const struct i3c_ibi_setup *req);
void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev);
+int i3c_dev_getstatus_format1_locked(struct i3c_dev_desc *dev, u16 *status);
#endif /* I3C_INTERNAL_H */
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 08aeb69a7800..fa831721f305 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -2840,6 +2840,33 @@ void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev)
dev->ibi = NULL;
}

+int i3c_dev_getstatus_format1_locked(struct i3c_dev_desc *dev, u16 *status)
+{
+ struct i3c_master_controller *master = i3c_dev_get_master(dev);
+ struct i3c_ccc_getstatus *format1;
+ struct i3c_ccc_cmd_dest dest;
+ struct i3c_ccc_cmd cmd;
+ int ret;
+
+ format1 = i3c_ccc_cmd_dest_init(&dest, dev->info.dyn_addr,
+ sizeof(*format1));
+ if (!format1)
+ return -ENOMEM;
+
+ i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETSTATUS, &dest, 1);
+
+ ret = i3c_master_send_ccc_cmd_locked(master, &cmd);
+ if (ret)
+ goto out;
+
+ *status = be16_to_cpu(format1->status);
+
+out:
+ i3c_ccc_cmd_dest_cleanup(&dest);
+
+ return ret;
+}
+
static int __init i3c_init(void)
{
int res;
diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h
index f2fa7ee5d96d..212cdcd17179 100644
--- a/include/linux/i3c/device.h
+++ b/include/linux/i3c/device.h
@@ -344,4 +344,5 @@ void i3c_device_free_ibi(struct i3c_device *dev);
int i3c_device_enable_ibi(struct i3c_device *dev);
int i3c_device_disable_ibi(struct i3c_device *dev);

+int i3c_device_getstatus_format1(struct i3c_device *dev, u16 *status);
#endif /* I3C_DEV_H */
--
2.34.1

2023-10-16 15:47:43

by Frank Li

[permalink] [raw]
Subject: [PATCH 4/5] i3c: master: svc return actual transfer data len

I3C allow devices early terminate data transfer. So set "actual" to
indicate how much data get by i3c_priv_xfer.

Signed-off-by: Frank Li <[email protected]>
---
drivers/i3c/master/svc-i3c-master.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 3570b709cf60..444825aafa6f 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -138,6 +138,7 @@ struct svc_i3c_cmd {
const void *out;
unsigned int len;
unsigned int actual_len;
+ struct i3c_priv_xfer *xfer;
bool continued;
};

@@ -1045,6 +1046,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,

if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
ret = -ENXIO;
+ *actual_len = 0;
goto emit_stop;
}

@@ -1062,6 +1064,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
*/
if (SVC_I3C_MSTATUS_IBIWON(reg)) {
ret = -ENXIO;
+ *actual_len = 0;
goto emit_stop;
}

@@ -1157,6 +1160,9 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
cmd->addr, cmd->in, cmd->out,
cmd->len, &cmd->actual_len,
cmd->continued);
+ if (cmd->xfer)
+ cmd->xfer->actual = cmd->actual_len;
+
if (ret)
break;
}
@@ -1344,6 +1350,7 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
for (i = 0; i < nxfers; i++) {
struct svc_i3c_cmd *cmd = &xfer->cmds[i];

+ cmd->xfer = xfers + i;
cmd->addr = master->addrs[data->index];
cmd->rnw = xfers[i].rnw;
cmd->in = xfers[i].rnw ? xfers[i].data.in : NULL;
--
2.34.1

2023-10-17 08:33:42

by Jarkko Nikula

[permalink] [raw]
Subject: Re: [PATCH 4/5] i3c: master: svc return actual transfer data len

Hi

On 10/16/23 18:46, Frank Li wrote:
> I3C allow devices early terminate data transfer. So set "actual" to
> indicate how much data get by i3c_priv_xfer.
>
> Signed-off-by: Frank Li <[email protected]>
> ---
> drivers/i3c/master/svc-i3c-master.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
> index 3570b709cf60..444825aafa6f 100644
> --- a/drivers/i3c/master/svc-i3c-master.c
> +++ b/drivers/i3c/master/svc-i3c-master.c
> @@ -138,6 +138,7 @@ struct svc_i3c_cmd {
> const void *out;
> unsigned int len;
> unsigned int actual_len;
> + struct i3c_priv_xfer *xfer;
> bool continued;
> };
>
I'm thinking would it make sense to combine this and previous patch by
removing the read_len/actual_len variable from this structure and use
the added one (by the patch 2/5) from "struct i3c_priv_xfer" directly?

2023-10-17 14:10:49

by Miquel Raynal

[permalink] [raw]
Subject: Re: [PATCH 4/5] i3c: master: svc return actual transfer data len

Hi Frank,

[email protected] wrote on Mon, 16 Oct 2023 11:46:31 -0400:

> I3C allow devices early terminate data transfer. So set "actual" to
> indicate how much data get by i3c_priv_xfer.
>
> Signed-off-by: Frank Li <[email protected]>
> ---
> drivers/i3c/master/svc-i3c-master.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
> index 3570b709cf60..444825aafa6f 100644
> --- a/drivers/i3c/master/svc-i3c-master.c
> +++ b/drivers/i3c/master/svc-i3c-master.c
> @@ -138,6 +138,7 @@ struct svc_i3c_cmd {
> const void *out;
> unsigned int len;
> unsigned int actual_len;
> + struct i3c_priv_xfer *xfer;
> bool continued;
> };
>
> @@ -1045,6 +1046,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
>
> if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
> ret = -ENXIO;
> + *actual_len = 0;
> goto emit_stop;
> }
>
> @@ -1062,6 +1064,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
> */
> if (SVC_I3C_MSTATUS_IBIWON(reg)) {
> ret = -ENXIO;
> + *actual_len = 0;
> goto emit_stop;
> }
>
> @@ -1157,6 +1160,9 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
> cmd->addr, cmd->in, cmd->out,
> cmd->len, &cmd->actual_len,
> cmd->continued);
> + if (cmd->xfer)
> + cmd->xfer->actual = cmd->actual_len;

Just to be sure, wouldn't it be more natural to always fill cmd->xfer
rather than checking it here?

> +
> if (ret)
> break;
> }
> @@ -1344,6 +1350,7 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
> for (i = 0; i < nxfers; i++) {
> struct svc_i3c_cmd *cmd = &xfer->cmds[i];
>
> + cmd->xfer = xfers + i;

Please follow the same pattern as below: = &xfers[i]

> cmd->addr = master->addrs[data->index];
> cmd->rnw = xfers[i].rnw;
> cmd->in = xfers[i].rnw ? xfers[i].data.in : NULL;


Thanks,
Miquèl

2023-10-18 20:18:44

by Frank Li

[permalink] [raw]
Subject: Re: [PATCH 4/5] i3c: master: svc return actual transfer data len

On Tue, Oct 17, 2023 at 11:33:34AM +0300, Jarkko Nikula wrote:
> Hi
>
> On 10/16/23 18:46, Frank Li wrote:
> > I3C allow devices early terminate data transfer. So set "actual" to
> > indicate how much data get by i3c_priv_xfer.
> >
> > Signed-off-by: Frank Li <[email protected]>
> > ---
> > drivers/i3c/master/svc-i3c-master.c | 7 +++++++
> > 1 file changed, 7 insertions(+)
> >
> > diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
> > index 3570b709cf60..444825aafa6f 100644
> > --- a/drivers/i3c/master/svc-i3c-master.c
> > +++ b/drivers/i3c/master/svc-i3c-master.c
> > @@ -138,6 +138,7 @@ struct svc_i3c_cmd {
> > const void *out;
> > unsigned int len;
> > unsigned int actual_len;
> > + struct i3c_priv_xfer *xfer;
> > bool continued;
> > };
> I'm thinking would it make sense to combine this and previous patch by
> removing the read_len/actual_len variable from this structure and use the
> added one (by the patch 2/5) from "struct i3c_priv_xfer" directly?

Some I2C transfer and CCC use svc_i3c_cmd, in such case xfer is NULL. Keep
len/actual_len is more simple.

Frank

2023-10-18 20:27:24

by Frank Li

[permalink] [raw]
Subject: Re: [PATCH 4/5] i3c: master: svc return actual transfer data len

On Tue, Oct 17, 2023 at 04:10:07PM +0200, Miquel Raynal wrote:
> Hi Frank,
>
> [email protected] wrote on Mon, 16 Oct 2023 11:46:31 -0400:
>
> > I3C allow devices early terminate data transfer. So set "actual" to
> > indicate how much data get by i3c_priv_xfer.
> >
> > Signed-off-by: Frank Li <[email protected]>
> > ---
> > drivers/i3c/master/svc-i3c-master.c | 7 +++++++
> > 1 file changed, 7 insertions(+)
> >
> > diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
> > index 3570b709cf60..444825aafa6f 100644
> > --- a/drivers/i3c/master/svc-i3c-master.c
> > +++ b/drivers/i3c/master/svc-i3c-master.c
> > @@ -138,6 +138,7 @@ struct svc_i3c_cmd {
> > const void *out;
> > unsigned int len;
> > unsigned int actual_len;
> > + struct i3c_priv_xfer *xfer;
> > bool continued;
> > };
> >
> > @@ -1045,6 +1046,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
> >
> > if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
> > ret = -ENXIO;
> > + *actual_len = 0;
> > goto emit_stop;
> > }
> >
> > @@ -1062,6 +1064,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
> > */
> > if (SVC_I3C_MSTATUS_IBIWON(reg)) {
> > ret = -ENXIO;
> > + *actual_len = 0;
> > goto emit_stop;
> > }
> >
> > @@ -1157,6 +1160,9 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
> > cmd->addr, cmd->in, cmd->out,
> > cmd->len, &cmd->actual_len,
> > cmd->continued);
> > + if (cmd->xfer)
> > + cmd->xfer->actual = cmd->actual_len;
>
> Just to be sure, wouldn't it be more natural to always fill cmd->xfer
> rather than checking it here?

cmd->xfer is NULL for i2c and ccc transfer. So need check it.
I will add comments here

Frank
>
> > +
> > if (ret)
> > break;
> > }
> > @@ -1344,6 +1350,7 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
> > for (i = 0; i < nxfers; i++) {
> > struct svc_i3c_cmd *cmd = &xfer->cmds[i];
> >
> > + cmd->xfer = xfers + i;
>
> Please follow the same pattern as below: = &xfers[i]
>
> > cmd->addr = master->addrs[data->index];
> > cmd->rnw = xfers[i].rnw;
> > cmd->in = xfers[i].rnw ? xfers[i].data.in : NULL;
>
>
> Thanks,
> Miqu?l