mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/4] Fix rockchip I2C bus
@ 2023-09-08 10:16 Gerald Loacker
  2023-09-08 10:16 ` [PATCH 1/4] i2c: rockchip: fix i2c stop condition Gerald Loacker
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Gerald Loacker @ 2023-09-08 10:16 UTC (permalink / raw)
  To: barebox; +Cc: Gerald Loacker

The rockchip I2C driver does not send a stop condition, this violates the
timing on the SCL line. iThe first patch fixes this and puts all related
functions on the same level.

Furthermore, we have seen nested calls to the rockchip_i2c_xfer function.
The second patch adds a check of pending interrupts and avoids
interrupting an ongoing transfer.

The last two patches propagate I2C errors from the KSZ9477 driver to the
DSA subsystem to react accordingly.

To: barebox@lists.infradead.org

Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
---
Gerald Loacker (4):
      i2c: rockchip: fix i2c stop condition
      i2c: rockchip: ignore i2c transfers when another transfer is running
      net: ksz9477: propagate phy read error
      net: ksz9477: propagate phy write error

 drivers/i2c/busses/i2c-rockchip.c | 35 +++++++++++++++++++++--------------
 drivers/net/ksz9477.c             | 15 +++++++--------
 2 files changed, 28 insertions(+), 22 deletions(-)
---
base-commit: 4411b931680e4fb15d6f80e5543ef9f81aef092b
change-id: 20230908-bugfix-i2c-rockchip-f8874bd640e5

Best regards,
-- 
Gerald Loacker <gerald.loacker@wolfvision.net>




^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/4] i2c: rockchip: fix i2c stop condition
  2023-09-08 10:16 [PATCH 0/4] Fix rockchip I2C bus Gerald Loacker
@ 2023-09-08 10:16 ` Gerald Loacker
  2023-09-08 13:53   ` Sascha Hauer
  2023-09-08 10:16 ` [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running Gerald Loacker
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 14+ messages in thread
From: Gerald Loacker @ 2023-09-08 10:16 UTC (permalink / raw)
  To: barebox; +Cc: Gerald Loacker

The i2c bus gets disabled without sending a stop condition. This violates
i2c timing on the clock line. Fix this and include all related functions
(rk_i2c_send_start_bit, rk_i2c_send_stop_bit, rk_i2c_disable) onto the same
level.

Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
---
 drivers/i2c/busses/i2c-rockchip.c | 21 ++++++++-------------
 1 file changed, 8 insertions(+), 13 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
index 23bf4a55d7..1bca3e9913 100644
--- a/drivers/i2c/busses/i2c-rockchip.c
+++ b/drivers/i2c/busses/i2c-rockchip.c
@@ -222,10 +222,6 @@ static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
 	dev_dbg(dev, "rk_i2c_read: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
 	      chip, reg, r_len, b_len);
 
-	err = rk_i2c_send_start_bit(i2c);
-	if (err)
-		return err;
-
 	writel(I2C_MRXADDR_SET(1, chip << 1 | 1), &regs->mrxaddr);
 	if (r_len == 0) {
 		writel(0, &regs->mrxraddr);
@@ -294,8 +290,6 @@ static int rk_i2c_read(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
 i2c_exit:
 	if (err)
 		rk_i2c_show_regs(i2c);
-	rk_i2c_disable(i2c);
-
 	return err;
 }
 
@@ -315,9 +309,6 @@ static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
 
 	dev_dbg(dev, "rk_i2c_write: chip = %d, reg = %d, r_len = %d, b_len = %d\n",
 	      chip, reg, r_len, b_len);
-	err = rk_i2c_send_start_bit(i2c);
-	if (err)
-		return err;
 
 	while (bytes_remain_len) {
 		if (bytes_remain_len > RK_I2C_FIFO_SIZE)
@@ -370,8 +361,6 @@ static int rk_i2c_write(struct rk_i2c *i2c, uchar chip, uint reg, uint r_len,
 i2c_exit:
 	if (err)
 		rk_i2c_show_regs(i2c);
-	rk_i2c_disable(i2c);
-
 	return err;
 }
 
@@ -387,6 +376,11 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 		struct i2c_msg *msg = &msgs[i];
 
 		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+
+		ret = rk_i2c_send_start_bit(i2c);
+		if (ret)
+			break;
+
 		if (msg->flags & I2C_M_RD) {
 			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
 					  msg->len);
@@ -394,6 +388,9 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
 					   msg->len);
 		}
+
+		rk_i2c_send_stop_bit(i2c);
+
 		if (ret) {
 			dev_dbg(dev, "i2c_write: error sending: %pe\n",
 				ERR_PTR(ret));
@@ -402,9 +399,7 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 		}
 	}
 
-	rk_i2c_send_stop_bit(i2c);
 	rk_i2c_disable(i2c);
-
 	return ret < 0 ? ret : nmsgs;
 }
 

-- 
2.37.2




^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running
  2023-09-08 10:16 [PATCH 0/4] Fix rockchip I2C bus Gerald Loacker
  2023-09-08 10:16 ` [PATCH 1/4] i2c: rockchip: fix i2c stop condition Gerald Loacker
@ 2023-09-08 10:16 ` Gerald Loacker
  2023-09-08 11:51   ` Sascha Hauer
  2023-09-08 10:16 ` [PATCH 3/4] net: ksz9477: propagate phy read error Gerald Loacker
  2023-09-08 10:16 ` [PATCH 4/4] net: ksz9477: propagate phy write error Gerald Loacker
  3 siblings, 1 reply; 14+ messages in thread
From: Gerald Loacker @ 2023-09-08 10:16 UTC (permalink / raw)
  To: barebox; +Cc: Gerald Loacker

It may happen that an i2c transfer is requested by a callback although
there is an other i2c transfer running. In this case do not interrupt the
transfer and return with an error.

Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
---
 drivers/i2c/busses/i2c-rockchip.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
index 1bca3e9913..a869b9d0b7 100644
--- a/drivers/i2c/busses/i2c-rockchip.c
+++ b/drivers/i2c/busses/i2c-rockchip.c
@@ -369,7 +369,19 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
 {
 	struct rk_i2c *i2c = to_rk_i2c(adapter);
 	struct device *dev = &adapter->dev;
-	int i, ret = 0;
+	struct i2c_regs *regs = i2c->regs;
+	int i, ret = 0, val;
+
+	val = readl(&regs->con);
+	if (val & I2C_CON_EN) {
+		val = readl(&regs->con);
+		if (val & I2C_IPD_ALL_CLEAN) {
+			dev_dbg(dev,
+				"i2c_xfer: %d messages dropped due to pending interrupts\n",
+				nmsgs);
+			return -EAGAIN;
+		}
+	}
 
 	dev_dbg(dev, "i2c_xfer: %d messages\n", nmsgs);
 	for (i = 0; i < nmsgs; i++) {

-- 
2.37.2




^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 3/4] net: ksz9477: propagate phy read error
  2023-09-08 10:16 [PATCH 0/4] Fix rockchip I2C bus Gerald Loacker
  2023-09-08 10:16 ` [PATCH 1/4] i2c: rockchip: fix i2c stop condition Gerald Loacker
  2023-09-08 10:16 ` [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running Gerald Loacker
@ 2023-09-08 10:16 ` Gerald Loacker
  2023-09-08 11:59   ` Ahmad Fatoum
  2023-09-08 10:16 ` [PATCH 4/4] net: ksz9477: propagate phy write error Gerald Loacker
  3 siblings, 1 reply; 14+ messages in thread
From: Gerald Loacker @ 2023-09-08 10:16 UTC (permalink / raw)
  To: barebox; +Cc: Gerald Loacker

In case of an error we should not return an arbitrary value, propagate the
error code instead.
Fix return value in case of address error.

Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
---
 drivers/net/ksz9477.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c
index 9665e0f723..d664b7cf01 100644
--- a/drivers/net/ksz9477.c
+++ b/drivers/net/ksz9477.c
@@ -29,14 +29,15 @@ static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg)
 {
 	struct device *dev = ds->dev;
 	struct ksz_switch *priv = dev_get_priv(dev);
-	u16 val = 0xffff;
+	u16 val;
+	int ret;
 
 	if (addr >= priv->phy_port_cnt)
-		return val;
+		return -EINVAL;
 
-	ksz_pread16(priv, addr, 0x100 + (reg << 1), &val);
+	ret = ksz_pread16(priv, addr, 0x100 + (reg << 1), &val);
 
-	return val;
+	return (ret < 0) ? ret : val;
 }
 
 static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg,

-- 
2.37.2




^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 4/4] net: ksz9477: propagate phy write error
  2023-09-08 10:16 [PATCH 0/4] Fix rockchip I2C bus Gerald Loacker
                   ` (2 preceding siblings ...)
  2023-09-08 10:16 ` [PATCH 3/4] net: ksz9477: propagate phy read error Gerald Loacker
@ 2023-09-08 10:16 ` Gerald Loacker
  3 siblings, 0 replies; 14+ messages in thread
From: Gerald Loacker @ 2023-09-08 10:16 UTC (permalink / raw)
  To: barebox; +Cc: Gerald Loacker

Return -EINVAL in case of an address error, otherwise propagate error code.

Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
---
 drivers/net/ksz9477.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c
index d664b7cf01..0310e0260a 100644
--- a/drivers/net/ksz9477.c
+++ b/drivers/net/ksz9477.c
@@ -48,14 +48,12 @@ static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg,
 
 	/* No real PHY after this. */
 	if (addr >= priv->phy_port_cnt)
-		return 0;
+		return -EINVAL;
 
 	/* No gigabit support.  Do not write to this register. */
 	if (!(priv->features & GBIT_SUPPORT) && reg == MII_CTRL1000)
 		return 0;
-	ksz_pwrite16(priv, addr, 0x100 + (reg << 1), val);
-
-	return 0;
+	return ksz_pwrite16(priv, addr, 0x100 + (reg << 1), val);
 }
 
 static int ksz9477_switch_detect(struct ksz_switch *priv)

-- 
2.37.2




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running
  2023-09-08 10:16 ` [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running Gerald Loacker
@ 2023-09-08 11:51   ` Sascha Hauer
  2023-09-08 11:55     ` Sascha Hauer
  0 siblings, 1 reply; 14+ messages in thread
From: Sascha Hauer @ 2023-09-08 11:51 UTC (permalink / raw)
  To: Gerald Loacker; +Cc: barebox

On Fri, Sep 08, 2023 at 12:16:47PM +0200, Gerald Loacker wrote:
> It may happen that an i2c transfer is requested by a callback although
> there is an other i2c transfer running. In this case do not interrupt the
> transfer and return with an error.
> 
> Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
> ---
>  drivers/i2c/busses/i2c-rockchip.c | 14 +++++++++++++-
>  1 file changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
> index 1bca3e9913..a869b9d0b7 100644
> --- a/drivers/i2c/busses/i2c-rockchip.c
> +++ b/drivers/i2c/busses/i2c-rockchip.c
> @@ -369,7 +369,19 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
>  {
>  	struct rk_i2c *i2c = to_rk_i2c(adapter);
>  	struct device *dev = &adapter->dev;
> -	int i, ret = 0;
> +	struct i2c_regs *regs = i2c->regs;
> +	int i, ret = 0, val;
> +
> +	val = readl(&regs->con);
> +	if (val & I2C_CON_EN) {
> +		val = readl(&regs->con);
> +		if (val & I2C_IPD_ALL_CLEAN) {
> +			dev_dbg(dev,
> +				"i2c_xfer: %d messages dropped due to pending interrupts\n",
> +				nmsgs);
> +			return -EAGAIN;
> +		}
> +	}

Can you have a look how this can happen? Normally this should only
happen if you have a heartbeat LED behind a I2C GPIO expander or some
other unusual setup. Adding a dump_stack() next to the dev_dbg() call
might give a clue.

Let's see how this really happens, but generally I think we should find
another solution for this, either on I2C core level or by replacing
the readl_poll_timeout() with a variant that doesn't allow running in
the background, i.e. one which uses is_timeout_non_interruptible()
rather than is_timeout().

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running
  2023-09-08 11:51   ` Sascha Hauer
@ 2023-09-08 11:55     ` Sascha Hauer
  2023-09-08 13:13       ` Sascha Hauer
  0 siblings, 1 reply; 14+ messages in thread
From: Sascha Hauer @ 2023-09-08 11:55 UTC (permalink / raw)
  To: Gerald Loacker; +Cc: barebox

On Fri, Sep 08, 2023 at 01:51:32PM +0200, Sascha Hauer wrote:
> On Fri, Sep 08, 2023 at 12:16:47PM +0200, Gerald Loacker wrote:
> > It may happen that an i2c transfer is requested by a callback although
> > there is an other i2c transfer running. In this case do not interrupt the
> > transfer and return with an error.
> > 
> > Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
> > ---
> >  drivers/i2c/busses/i2c-rockchip.c | 14 +++++++++++++-
> >  1 file changed, 13 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
> > index 1bca3e9913..a869b9d0b7 100644
> > --- a/drivers/i2c/busses/i2c-rockchip.c
> > +++ b/drivers/i2c/busses/i2c-rockchip.c
> > @@ -369,7 +369,19 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
> >  {
> >  	struct rk_i2c *i2c = to_rk_i2c(adapter);
> >  	struct device *dev = &adapter->dev;
> > -	int i, ret = 0;
> > +	struct i2c_regs *regs = i2c->regs;
> > +	int i, ret = 0, val;
> > +
> > +	val = readl(&regs->con);
> > +	if (val & I2C_CON_EN) {
> > +		val = readl(&regs->con);
> > +		if (val & I2C_IPD_ALL_CLEAN) {
> > +			dev_dbg(dev,
> > +				"i2c_xfer: %d messages dropped due to pending interrupts\n",
> > +				nmsgs);
> > +			return -EAGAIN;
> > +		}
> > +	}
> 
> Can you have a look how this can happen? Normally this should only
> happen if you have a heartbeat LED behind a I2C GPIO expander or some
> other unusual setup. Adding a dump_stack() next to the dev_dbg() call
> might give a clue.

I just realized you sent some ksz9477 along with this series. Are you
using that in I2C mode? In that case it could be the periodic link check
that does I2C accesses in the background.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] net: ksz9477: propagate phy read error
  2023-09-08 10:16 ` [PATCH 3/4] net: ksz9477: propagate phy read error Gerald Loacker
@ 2023-09-08 11:59   ` Ahmad Fatoum
  2023-09-08 12:32     ` Oleksij Rempel
  0 siblings, 1 reply; 14+ messages in thread
From: Ahmad Fatoum @ 2023-09-08 11:59 UTC (permalink / raw)
  To: Gerald Loacker, barebox, Oleksij Rempel

On 08.09.23 12:16, Gerald Loacker wrote:
> In case of an error we should not return an arbitrary value, propagate the
> error code instead.
> Fix return value in case of address error.
> 
> Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
> ---
>  drivers/net/ksz9477.c | 9 +++++----
>  1 file changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c
> index 9665e0f723..d664b7cf01 100644
> --- a/drivers/net/ksz9477.c
> +++ b/drivers/net/ksz9477.c
> @@ -29,14 +29,15 @@ static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg)
>  {
>  	struct device *dev = ds->dev;
>  	struct ksz_switch *priv = dev_get_priv(dev);
> -	u16 val = 0xffff;
> +	u16 val;
> +	int ret;
>  
>  	if (addr >= priv->phy_port_cnt)
> -		return val;
> +		return -EINVAL;

Looks sensible IMO, but shouldn't we do the same in dsa_slave_phy_read
if no callback is defined?

@Oleksij, why did you decide for 0xffff instead of a negative error code?


>  
> -	ksz_pread16(priv, addr, 0x100 + (reg << 1), &val);
> +	ret = ksz_pread16(priv, addr, 0x100 + (reg << 1), &val);
>  
> -	return val;
> +	return (ret < 0) ? ret : val;
>  }
>  
>  static int ksz9477_phy_write16(struct dsa_switch *ds, int addr, int reg,
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] net: ksz9477: propagate phy read error
  2023-09-08 11:59   ` Ahmad Fatoum
@ 2023-09-08 12:32     ` Oleksij Rempel
  0 siblings, 0 replies; 14+ messages in thread
From: Oleksij Rempel @ 2023-09-08 12:32 UTC (permalink / raw)
  To: Ahmad Fatoum; +Cc: Gerald Loacker, barebox

Hi,

On Fri, Sep 08, 2023 at 01:59:05PM +0200, Ahmad Fatoum wrote:
> On 08.09.23 12:16, Gerald Loacker wrote:
> > In case of an error we should not return an arbitrary value, propagate the
> > error code instead.
> > Fix return value in case of address error.
> > 
> > Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
> > ---
> >  drivers/net/ksz9477.c | 9 +++++----
> >  1 file changed, 5 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c
> > index 9665e0f723..d664b7cf01 100644
> > --- a/drivers/net/ksz9477.c
> > +++ b/drivers/net/ksz9477.c
> > @@ -29,14 +29,15 @@ static int ksz9477_phy_read16(struct dsa_switch *ds, int addr, int reg)
> >  {
> >  	struct device *dev = ds->dev;
> >  	struct ksz_switch *priv = dev_get_priv(dev);
> > -	u16 val = 0xffff;
> > +	u16 val;
> > +	int ret;
> >  
> >  	if (addr >= priv->phy_port_cnt)
> > -		return val;
> > +		return -EINVAL;
> 
> Looks sensible IMO, but shouldn't we do the same in dsa_slave_phy_read
> if no callback is defined?
> 
> @Oleksij, why did you decide for 0xffff instead of a negative error code?

This code imitate real MDIO bus access. If you trying to read at not
existing PHY address, you will get 0xffff instead of negative error.
May be it is better to add a comment :)

Regards,
Oleksij
-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running
  2023-09-08 11:55     ` Sascha Hauer
@ 2023-09-08 13:13       ` Sascha Hauer
  2023-09-11 11:46         ` Gerald Loacker
  0 siblings, 1 reply; 14+ messages in thread
From: Sascha Hauer @ 2023-09-08 13:13 UTC (permalink / raw)
  To: Gerald Loacker; +Cc: barebox

On Fri, Sep 08, 2023 at 01:55:40PM +0200, Sascha Hauer wrote:
> On Fri, Sep 08, 2023 at 01:51:32PM +0200, Sascha Hauer wrote:
> > On Fri, Sep 08, 2023 at 12:16:47PM +0200, Gerald Loacker wrote:
> > > It may happen that an i2c transfer is requested by a callback although
> > > there is an other i2c transfer running. In this case do not interrupt the
> > > transfer and return with an error.
> > > 
> > > Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
> > > ---
> > >  drivers/i2c/busses/i2c-rockchip.c | 14 +++++++++++++-
> > >  1 file changed, 13 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
> > > index 1bca3e9913..a869b9d0b7 100644
> > > --- a/drivers/i2c/busses/i2c-rockchip.c
> > > +++ b/drivers/i2c/busses/i2c-rockchip.c
> > > @@ -369,7 +369,19 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
> > >  {
> > >  	struct rk_i2c *i2c = to_rk_i2c(adapter);
> > >  	struct device *dev = &adapter->dev;
> > > -	int i, ret = 0;
> > > +	struct i2c_regs *regs = i2c->regs;
> > > +	int i, ret = 0, val;
> > > +
> > > +	val = readl(&regs->con);
> > > +	if (val & I2C_CON_EN) {
> > > +		val = readl(&regs->con);
> > > +		if (val & I2C_IPD_ALL_CLEAN) {
> > > +			dev_dbg(dev,
> > > +				"i2c_xfer: %d messages dropped due to pending interrupts\n",
> > > +				nmsgs);
> > > +			return -EAGAIN;
> > > +		}
> > > +	}
> > 
> > Can you have a look how this can happen? Normally this should only
> > happen if you have a heartbeat LED behind a I2C GPIO expander or some
> > other unusual setup. Adding a dump_stack() next to the dev_dbg() call
> > might give a clue.
> 
> I just realized you sent some ksz9477 along with this series. Are you
> using that in I2C mode? In that case it could be the periodic link check
> that does I2C accesses in the background.

Assuming that this is indeed your problem I have just sent a series that
could fix this issue. It's untested yet, please give it a try.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/4] i2c: rockchip: fix i2c stop condition
  2023-09-08 10:16 ` [PATCH 1/4] i2c: rockchip: fix i2c stop condition Gerald Loacker
@ 2023-09-08 13:53   ` Sascha Hauer
  2023-09-12  5:45     ` Gerald Loacker
  0 siblings, 1 reply; 14+ messages in thread
From: Sascha Hauer @ 2023-09-08 13:53 UTC (permalink / raw)
  To: Gerald Loacker; +Cc: barebox

On Fri, Sep 08, 2023 at 12:16:46PM +0200, Gerald Loacker wrote:
> The i2c bus gets disabled without sending a stop condition. This violates
> i2c timing on the clock line. Fix this and include all related functions
> (rk_i2c_send_start_bit, rk_i2c_send_stop_bit, rk_i2c_disable) onto the same
> level.
> 
> Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
> ---
>  drivers/i2c/busses/i2c-rockchip.c | 21 ++++++++-------------
>  1 file changed, 8 insertions(+), 13 deletions(-)
> 
> @@ -387,6 +376,11 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
>  		struct i2c_msg *msg = &msgs[i];
>  
>  		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
> +
> +		ret = rk_i2c_send_start_bit(i2c);
> +		if (ret)
> +			break;
> +
>  		if (msg->flags & I2C_M_RD) {
>  			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
>  					  msg->len);
> @@ -394,6 +388,9 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
>  			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
>  					   msg->len);
>  		}
> +
> +		rk_i2c_send_stop_bit(i2c);
> +
>  		if (ret) {
>  			dev_dbg(dev, "i2c_write: error sending: %pe\n",
>  				ERR_PTR(ret));
> @@ -402,9 +399,7 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
>  		}
>  	}
>  
> -	rk_i2c_send_stop_bit(i2c);

I believe this is wrong. A stop bit should only be sent after the last
message, not after all messages.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running
  2023-09-08 13:13       ` Sascha Hauer
@ 2023-09-11 11:46         ` Gerald Loacker
  0 siblings, 0 replies; 14+ messages in thread
From: Gerald Loacker @ 2023-09-11 11:46 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

Hi Sascha,

Am 08.09.2023 um 15:13 schrieb Sascha Hauer:
> On Fri, Sep 08, 2023 at 01:55:40PM +0200, Sascha Hauer wrote:
>> On Fri, Sep 08, 2023 at 01:51:32PM +0200, Sascha Hauer wrote:
>>> On Fri, Sep 08, 2023 at 12:16:47PM +0200, Gerald Loacker wrote:
>>>> It may happen that an i2c transfer is requested by a callback although
>>>> there is an other i2c transfer running. In this case do not interrupt the
>>>> transfer and return with an error.
>>>>
>>>> Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
>>>> ---
>>>>  drivers/i2c/busses/i2c-rockchip.c | 14 +++++++++++++-
>>>>  1 file changed, 13 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/i2c/busses/i2c-rockchip.c b/drivers/i2c/busses/i2c-rockchip.c
>>>> index 1bca3e9913..a869b9d0b7 100644
>>>> --- a/drivers/i2c/busses/i2c-rockchip.c
>>>> +++ b/drivers/i2c/busses/i2c-rockchip.c
>>>> @@ -369,7 +369,19 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
>>>>  {
>>>>  	struct rk_i2c *i2c = to_rk_i2c(adapter);
>>>>  	struct device *dev = &adapter->dev;
>>>> -	int i, ret = 0;
>>>> +	struct i2c_regs *regs = i2c->regs;
>>>> +	int i, ret = 0, val;
>>>> +
>>>> +	val = readl(&regs->con);
>>>> +	if (val & I2C_CON_EN) {
>>>> +		val = readl(&regs->con);
>>>> +		if (val & I2C_IPD_ALL_CLEAN) {
>>>> +			dev_dbg(dev,
>>>> +				"i2c_xfer: %d messages dropped due to pending interrupts\n",
>>>> +				nmsgs);
>>>> +			return -EAGAIN;
>>>> +		}
>>>> +	}
>>>
>>> Can you have a look how this can happen? Normally this should only
>>> happen if you have a heartbeat LED behind a I2C GPIO expander or some
>>> other unusual setup. Adding a dump_stack() next to the dev_dbg() call
>>> might give a clue.
>>
>> I just realized you sent some ksz9477 along with this series. Are you
>> using that in I2C mode? In that case it could be the periodic link check
>> that does I2C accesses in the background.
> 
> Assuming that this is indeed your problem I have just sent a series that
> could fix this issue. It's untested yet, please give it a try.
> 

Yes, this solves the problem of interrupted I2C transfers from the
periodic link check and also makes the ksz9477 patches obsolete. Thanks!

Gerald

> Sascha
> 



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/4] i2c: rockchip: fix i2c stop condition
  2023-09-08 13:53   ` Sascha Hauer
@ 2023-09-12  5:45     ` Gerald Loacker
  2023-09-12  6:03       ` Sascha Hauer
  0 siblings, 1 reply; 14+ messages in thread
From: Gerald Loacker @ 2023-09-12  5:45 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox



Am 08.09.2023 um 15:53 schrieb Sascha Hauer:
> On Fri, Sep 08, 2023 at 12:16:46PM +0200, Gerald Loacker wrote:
>> The i2c bus gets disabled without sending a stop condition. This violates
>> i2c timing on the clock line. Fix this and include all related functions
>> (rk_i2c_send_start_bit, rk_i2c_send_stop_bit, rk_i2c_disable) onto the same
>> level.
>>
>> Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
>> ---
>>  drivers/i2c/busses/i2c-rockchip.c | 21 ++++++++-------------
>>  1 file changed, 8 insertions(+), 13 deletions(-)
>>
>> @@ -387,6 +376,11 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
>>  		struct i2c_msg *msg = &msgs[i];
>>  
>>  		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
>> +
>> +		ret = rk_i2c_send_start_bit(i2c);
>> +		if (ret)
>> +			break;
>> +
>>  		if (msg->flags & I2C_M_RD) {
>>  			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
>>  					  msg->len);
>> @@ -394,6 +388,9 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
>>  			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
>>  					   msg->len);
>>  		}
>> +
>> +		rk_i2c_send_stop_bit(i2c);
>> +
>>  		if (ret) {
>>  			dev_dbg(dev, "i2c_write: error sending: %pe\n",
>>  				ERR_PTR(ret));
>> @@ -402,9 +399,7 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
>>  		}
>>  	}
>>  
>> -	rk_i2c_send_stop_bit(i2c);
> 
> I believe this is wrong. A stop bit should only be sent after the last
> message, not after all messages.
> 

Your're right. This was just because the repeated start does not work
consitently in our case. I'll come up with another approach.

Gerald

> Sascha
> 



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/4] i2c: rockchip: fix i2c stop condition
  2023-09-12  5:45     ` Gerald Loacker
@ 2023-09-12  6:03       ` Sascha Hauer
  0 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2023-09-12  6:03 UTC (permalink / raw)
  To: Gerald Loacker; +Cc: barebox

On Tue, Sep 12, 2023 at 07:45:36AM +0200, Gerald Loacker wrote:
> 
> 
> Am 08.09.2023 um 15:53 schrieb Sascha Hauer:
> > On Fri, Sep 08, 2023 at 12:16:46PM +0200, Gerald Loacker wrote:
> >> The i2c bus gets disabled without sending a stop condition. This violates
> >> i2c timing on the clock line. Fix this and include all related functions
> >> (rk_i2c_send_start_bit, rk_i2c_send_stop_bit, rk_i2c_disable) onto the same
> >> level.
> >>
> >> Signed-off-by: Gerald Loacker <gerald.loacker@wolfvision.net>
> >> ---
> >>  drivers/i2c/busses/i2c-rockchip.c | 21 ++++++++-------------
> >>  1 file changed, 8 insertions(+), 13 deletions(-)
> >>
> >> @@ -387,6 +376,11 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
> >>  		struct i2c_msg *msg = &msgs[i];
> >>  
> >>  		dev_dbg(dev, "i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
> >> +
> >> +		ret = rk_i2c_send_start_bit(i2c);
> >> +		if (ret)
> >> +			break;
> >> +
> >>  		if (msg->flags & I2C_M_RD) {
> >>  			ret = rk_i2c_read(i2c, msg->addr, 0, 0, msg->buf,
> >>  					  msg->len);
> >> @@ -394,6 +388,9 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
> >>  			ret = rk_i2c_write(i2c, msg->addr, 0, 0, msg->buf,
> >>  					   msg->len);
> >>  		}
> >> +
> >> +		rk_i2c_send_stop_bit(i2c);
> >> +
> >>  		if (ret) {
> >>  			dev_dbg(dev, "i2c_write: error sending: %pe\n",
> >>  				ERR_PTR(ret));
> >> @@ -402,9 +399,7 @@ static int rockchip_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
> >>  		}
> >>  	}
> >>  
> >> -	rk_i2c_send_stop_bit(i2c);
> > 
> > I believe this is wrong. A stop bit should only be sent after the last
> > message, not after all messages.
> > 
> 
> Your're right. This was just because the repeated start does not work
> consitently in our case. I'll come up with another approach.

Might be worth to look at the kernel driver. It has a comment about
this:

	/*
	 * The HW is actually not capable of REPEATED START. But we can
	 * get the intended effect by resetting its internal state
	 * and issuing an ordinary START.
	 */
	ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
	i2c_writel(i2c, ctrl, REG_CON);

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2023-09-12  6:05 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-08 10:16 [PATCH 0/4] Fix rockchip I2C bus Gerald Loacker
2023-09-08 10:16 ` [PATCH 1/4] i2c: rockchip: fix i2c stop condition Gerald Loacker
2023-09-08 13:53   ` Sascha Hauer
2023-09-12  5:45     ` Gerald Loacker
2023-09-12  6:03       ` Sascha Hauer
2023-09-08 10:16 ` [PATCH 2/4] i2c: rockchip: ignore i2c transfers when another transfer is running Gerald Loacker
2023-09-08 11:51   ` Sascha Hauer
2023-09-08 11:55     ` Sascha Hauer
2023-09-08 13:13       ` Sascha Hauer
2023-09-11 11:46         ` Gerald Loacker
2023-09-08 10:16 ` [PATCH 3/4] net: ksz9477: propagate phy read error Gerald Loacker
2023-09-08 11:59   ` Ahmad Fatoum
2023-09-08 12:32     ` Oleksij Rempel
2023-09-08 10:16 ` [PATCH 4/4] net: ksz9477: propagate phy write error Gerald Loacker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox