public inbox for linux-i2c@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/1] i2c: lpi2c: Avoid calling clk_get_rate during transfer
@ 2024-01-18  7:43 Alexander Stein
  2024-01-18 10:22 ` Uwe Kleine-König
  0 siblings, 1 reply; 5+ messages in thread
From: Alexander Stein @ 2024-01-18  7:43 UTC (permalink / raw)
  To: Dong Aisheng, Andi Shyti, Shawn Guo, Sascha Hauer, Fabio Estevam
  Cc: Alexander Stein, Pengutronix Kernel Team, NXP Linux Team,
	linux-i2c, linux-arm-kernel, Uwe Kleine-König

Instead of repeatedly calling clk_get_rate for each transfer, lock
the clock rate and cache the value.
A deadlock has been observed while adding tlv320aic32x4 audio codec to
the system. When this clock provider adds its clock, the clk mutex is
locked already, it needs to access i2c, which in return needs the mutex
for clk_get_rate as well.

Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
---
This is an alternative, lightweight approach replacing the patch [1] and
depends on [2].
The issue to address is still removing the call to clk_get_rate() during each
transfer, which might reuslt in a deadlock. lockdep also complains about this
call chain.

Instead of adding a clock notifier, lock the peripheral clock rate and cache
the peripheral clock rate.
Currently LPI2C is available in the following SoC:
* i.MX7ULP
* i.MX8ULP
* i.MX8DXL
* i.MX8X
* i.MX8
* i.MX93

Additionally I expect both i.MX91 and i.MX95 to also use this driver.

This patch assumes the parent clock rate never changes. This is apparently true
for i.MX93 as each I2C has it's own lpi2c*_root clock. On i.MX8 and i.MX8X
clocks are managed by SCU with it's own dedicated firmware. I can't say if the
clock never changes though. I have no idea about the other SoC.

Best regards,
Alexander

[1] https://lore.kernel.org/all/20240110120556.519800-1-alexander.stein@ew.tq-group.com/
[2] https://lore.kernel.org/all/20240104225512.1124519-2-u.kleine-koenig@pengutronix.de/

 drivers/i2c/busses/i2c-imx-lpi2c.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
index 678b30e90492a..6cbcb27a3b280 100644
--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
+++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
@@ -99,6 +99,7 @@ struct lpi2c_imx_struct {
 	__u8			*rx_buf;
 	__u8			*tx_buf;
 	struct completion	complete;
+	unsigned long		rate_per;
 	unsigned int		msglen;
 	unsigned int		delivered;
 	unsigned int		block_data;
@@ -207,7 +208,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
 
 	lpi2c_imx_set_mode(lpi2c_imx);
 
-	clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
+	clk_rate = lpi2c_imx->rate_per;
 	if (!clk_rate)
 		return -EINVAL;
 
@@ -590,6 +591,20 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	/*
+	 * Lock the parent clock rate to avoid getting parent clock upon
+	 * each transfer
+	 */
+	ret = devm_clk_rate_exclusive_get(&pdev->dev, lpi2c_imx->clks[0].clk);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "can't lock I2C peripheral clock rate\n");
+
+	lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk);
+	if (!lpi2c_imx->rate_per)
+		return dev_err_probe(&pdev->dev, -EINVAL,
+				     "can't get I2C peripheral clock rate\n");
+
 	pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_get_noresume(&pdev->dev);
-- 
2.34.1


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

* Re: [PATCH 1/1] i2c: lpi2c: Avoid calling clk_get_rate during transfer
  2024-01-18  7:43 [PATCH 1/1] i2c: lpi2c: Avoid calling clk_get_rate during transfer Alexander Stein
@ 2024-01-18 10:22 ` Uwe Kleine-König
  2024-01-18 11:26   ` Alexander Stein
  2024-01-19  0:08   ` Andi Shyti
  0 siblings, 2 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2024-01-18 10:22 UTC (permalink / raw)
  To: Alexander Stein
  Cc: Dong Aisheng, Andi Shyti, Shawn Guo, Sascha Hauer, Fabio Estevam,
	NXP Linux Team, Pengutronix Kernel Team, linux-arm-kernel,
	linux-i2c

[-- Attachment #1: Type: text/plain, Size: 2958 bytes --]

On Thu, Jan 18, 2024 at 08:43:32AM +0100, Alexander Stein wrote:
> Instead of repeatedly calling clk_get_rate for each transfer, lock
> the clock rate and cache the value.
> A deadlock has been observed while adding tlv320aic32x4 audio codec to
> the system. When this clock provider adds its clock, the clk mutex is
> locked already, it needs to access i2c, which in return needs the mutex
> for clk_get_rate as well.
> 
> Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
> ---
> This is an alternative, lightweight approach replacing the patch [1] and
> depends on [2].
> The issue to address is still removing the call to clk_get_rate() during each
> transfer, which might reuslt in a deadlock. lockdep also complains about this
> call chain.
> 
> Instead of adding a clock notifier, lock the peripheral clock rate and cache
> the peripheral clock rate.
> Currently LPI2C is available in the following SoC:
> * i.MX7ULP
> * i.MX8ULP
> * i.MX8DXL
> * i.MX8X
> * i.MX8
> * i.MX93
> 
> Additionally I expect both i.MX91 and i.MX95 to also use this driver.
> 
> This patch assumes the parent clock rate never changes. This is apparently true
> for i.MX93 as each I2C has it's own lpi2c*_root clock. On i.MX8 and i.MX8X
> clocks are managed by SCU with it's own dedicated firmware. I can't say if the
> clock never changes though. I have no idea about the other SoC.
> 
> Best regards,
> Alexander
> 
> [1] https://lore.kernel.org/all/20240110120556.519800-1-alexander.stein@ew.tq-group.com/
> [2] https://lore.kernel.org/all/20240104225512.1124519-2-u.kleine-koenig@pengutronix.de/
> 
>  drivers/i2c/busses/i2c-imx-lpi2c.c | 17 ++++++++++++++++-
>  1 file changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
> index 678b30e90492a..6cbcb27a3b280 100644
> --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> @@ -99,6 +99,7 @@ struct lpi2c_imx_struct {
>  	__u8			*rx_buf;
>  	__u8			*tx_buf;
>  	struct completion	complete;
> +	unsigned long		rate_per;
>  	unsigned int		msglen;
>  	unsigned int		delivered;
>  	unsigned int		block_data;
> @@ -207,7 +208,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
>  
>  	lpi2c_imx_set_mode(lpi2c_imx);
>  
> -	clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
> +	clk_rate = lpi2c_imx->rate_per;
>  	if (!clk_rate)
>  		return -EINVAL;

After the things you did in lpi2c_imx_probe() you can assume that
clk_rate is not zero, so you could drop the if here.

Otherwise looks good to me (if you want even if you keep the if which is
only a minor optimisation).

Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 1/1] i2c: lpi2c: Avoid calling clk_get_rate during transfer
  2024-01-18 10:22 ` Uwe Kleine-König
@ 2024-01-18 11:26   ` Alexander Stein
  2024-01-18 11:53     ` Uwe Kleine-König
  2024-01-19  0:08   ` Andi Shyti
  1 sibling, 1 reply; 5+ messages in thread
From: Alexander Stein @ 2024-01-18 11:26 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Dong Aisheng, Andi Shyti, Shawn Guo, Sascha Hauer, Fabio Estevam,
	NXP Linux Team, Pengutronix Kernel Team, linux-arm-kernel,
	linux-i2c

Hi Uwe,

Am Donnerstag, 18. Januar 2024, 11:22:35 CET schrieb Uwe Kleine-König:
> On Thu, Jan 18, 2024 at 08:43:32AM +0100, Alexander Stein wrote:
> > Instead of repeatedly calling clk_get_rate for each transfer, lock
> > the clock rate and cache the value.
> > A deadlock has been observed while adding tlv320aic32x4 audio codec to
> > the system. When this clock provider adds its clock, the clk mutex is
> > locked already, it needs to access i2c, which in return needs the mutex
> > for clk_get_rate as well.
> > 
> > Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
> > ---
> > This is an alternative, lightweight approach replacing the patch [1] and
> > depends on [2].
> > The issue to address is still removing the call to clk_get_rate() during
> > each transfer, which might reuslt in a deadlock. lockdep also complains
> > about this call chain.
> > 
> > Instead of adding a clock notifier, lock the peripheral clock rate and
> > cache the peripheral clock rate.
> > Currently LPI2C is available in the following SoC:
> > * i.MX7ULP
> > * i.MX8ULP
> > * i.MX8DXL
> > * i.MX8X
> > * i.MX8
> > * i.MX93
> > 
> > Additionally I expect both i.MX91 and i.MX95 to also use this driver.
> > 
> > This patch assumes the parent clock rate never changes. This is apparently
> > true for i.MX93 as each I2C has it's own lpi2c*_root clock. On i.MX8 and
> > i.MX8X clocks are managed by SCU with it's own dedicated firmware. I
> > can't say if the clock never changes though. I have no idea about the
> > other SoC.
> > 
> > Best regards,
> > Alexander
> > 
> > [1]
> > https://lore.kernel.org/all/20240110120556.519800-1-alexander.stein@ew.tq
> > -group.com/ [2]
> > https://lore.kernel.org/all/20240104225512.1124519-2-u.kleine-koenig@peng
> > utronix.de/> 
> >  drivers/i2c/busses/i2c-imx-lpi2c.c | 17 ++++++++++++++++-
> >  1 file changed, 16 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c
> > b/drivers/i2c/busses/i2c-imx-lpi2c.c index 678b30e90492a..6cbcb27a3b280
> > 100644
> > --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> > +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> > @@ -99,6 +99,7 @@ struct lpi2c_imx_struct {
> > 
> >  	__u8			*rx_buf;
> >  	__u8			*tx_buf;
> >  	struct completion	complete;
> > 
> > +	unsigned long		rate_per;
> > 
> >  	unsigned int		msglen;
> >  	unsigned int		delivered;
> >  	unsigned int		block_data;
> > 
> > @@ -207,7 +208,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct
> > *lpi2c_imx)> 
> >  	lpi2c_imx_set_mode(lpi2c_imx);
> > 
> > -	clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
> > +	clk_rate = lpi2c_imx->rate_per;
> > 
> >  	if (!clk_rate)
> >  	
> >  		return -EINVAL;
> 
> After the things you did in lpi2c_imx_probe() you can assume that
> clk_rate is not zero, so you could drop the if here.

As in some cases the clock is not setup by Linux, but externally, I'd rather 
keep that check to ensure it's enabled.

> Otherwise looks good to me (if you want even if you keep the if which is
> only a minor optimisation).
> 
> Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

Thanks and best regards,
Alexander

> Best regards
> Uwe


-- 
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/



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

* Re: [PATCH 1/1] i2c: lpi2c: Avoid calling clk_get_rate during transfer
  2024-01-18 11:26   ` Alexander Stein
@ 2024-01-18 11:53     ` Uwe Kleine-König
  0 siblings, 0 replies; 5+ messages in thread
From: Uwe Kleine-König @ 2024-01-18 11:53 UTC (permalink / raw)
  To: Alexander Stein
  Cc: Dong Aisheng, Andi Shyti, Shawn Guo, Sascha Hauer, NXP Linux Team,
	Pengutronix Kernel Team, Fabio Estevam, linux-arm-kernel,
	linux-i2c

[-- Attachment #1: Type: text/plain, Size: 3765 bytes --]

On Thu, Jan 18, 2024 at 12:26:39PM +0100, Alexander Stein wrote:
> Hi Uwe,
> 
> Am Donnerstag, 18. Januar 2024, 11:22:35 CET schrieb Uwe Kleine-König:
> > On Thu, Jan 18, 2024 at 08:43:32AM +0100, Alexander Stein wrote:
> > > Instead of repeatedly calling clk_get_rate for each transfer, lock
> > > the clock rate and cache the value.
> > > A deadlock has been observed while adding tlv320aic32x4 audio codec to
> > > the system. When this clock provider adds its clock, the clk mutex is
> > > locked already, it needs to access i2c, which in return needs the mutex
> > > for clk_get_rate as well.
> > > 
> > > Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
> > > ---
> > > This is an alternative, lightweight approach replacing the patch [1] and
> > > depends on [2].
> > > The issue to address is still removing the call to clk_get_rate() during
> > > each transfer, which might reuslt in a deadlock. lockdep also complains
> > > about this call chain.
> > > 
> > > Instead of adding a clock notifier, lock the peripheral clock rate and
> > > cache the peripheral clock rate.
> > > Currently LPI2C is available in the following SoC:
> > > * i.MX7ULP
> > > * i.MX8ULP
> > > * i.MX8DXL
> > > * i.MX8X
> > > * i.MX8
> > > * i.MX93
> > > 
> > > Additionally I expect both i.MX91 and i.MX95 to also use this driver.
> > > 
> > > This patch assumes the parent clock rate never changes. This is apparently
> > > true for i.MX93 as each I2C has it's own lpi2c*_root clock. On i.MX8 and
> > > i.MX8X clocks are managed by SCU with it's own dedicated firmware. I
> > > can't say if the clock never changes though. I have no idea about the
> > > other SoC.
> > > 
> > > Best regards,
> > > Alexander
> > > 
> > > [1]
> > > https://lore.kernel.org/all/20240110120556.519800-1-alexander.stein@ew.tq
> > > -group.com/ [2]
> > > https://lore.kernel.org/all/20240104225512.1124519-2-u.kleine-koenig@peng
> > > utronix.de/> 
> > >  drivers/i2c/busses/i2c-imx-lpi2c.c | 17 ++++++++++++++++-
> > >  1 file changed, 16 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c
> > > b/drivers/i2c/busses/i2c-imx-lpi2c.c index 678b30e90492a..6cbcb27a3b280
> > > 100644
> > > --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> > > +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> > > @@ -99,6 +99,7 @@ struct lpi2c_imx_struct {
> > > 
> > >  	__u8			*rx_buf;
> > >  	__u8			*tx_buf;
> > >  	struct completion	complete;
> > > 
> > > +	unsigned long		rate_per;
> > > 
> > >  	unsigned int		msglen;
> > >  	unsigned int		delivered;
> > >  	unsigned int		block_data;
> > > 
> > > @@ -207,7 +208,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct
> > > *lpi2c_imx)> 
> > >  	lpi2c_imx_set_mode(lpi2c_imx);
> > > 
> > > -	clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
> > > +	clk_rate = lpi2c_imx->rate_per;
> > > 
> > >  	if (!clk_rate)
> > >  	
> > >  		return -EINVAL;
> > 
> > After the things you did in lpi2c_imx_probe() you can assume that
> > clk_rate is not zero, so you could drop the if here.
> 
> As in some cases the clock is not setup by Linux, but externally, I'd rather 
> keep that check to ensure it's enabled.

Just to be sure we both understand this in the same way:

In .probe() you do:

	lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk);
	if (!lpi2c_imx->rate_per)
		return dev_err_probe(&pdev->dev, -EINVAL, ...);

so irrespective of how the clock is setup, I would expect that
lpi2c_imx->rate_per will never be zero in lpi2c_imx_config().

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 1/1] i2c: lpi2c: Avoid calling clk_get_rate during transfer
  2024-01-18 10:22 ` Uwe Kleine-König
  2024-01-18 11:26   ` Alexander Stein
@ 2024-01-19  0:08   ` Andi Shyti
  1 sibling, 0 replies; 5+ messages in thread
From: Andi Shyti @ 2024-01-19  0:08 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Alexander Stein, Dong Aisheng, Shawn Guo, Sascha Hauer,
	Fabio Estevam, NXP Linux Team, Pengutronix Kernel Team,
	linux-arm-kernel, linux-i2c

Hi,

> > diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
> > index 678b30e90492a..6cbcb27a3b280 100644
> > --- a/drivers/i2c/busses/i2c-imx-lpi2c.c
> > +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
> > @@ -99,6 +99,7 @@ struct lpi2c_imx_struct {
> >  	__u8			*rx_buf;
> >  	__u8			*tx_buf;
> >  	struct completion	complete;
> > +	unsigned long		rate_per;
> >  	unsigned int		msglen;
> >  	unsigned int		delivered;
> >  	unsigned int		block_data;
> > @@ -207,7 +208,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
> >  
> >  	lpi2c_imx_set_mode(lpi2c_imx);
> >  
> > -	clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk);
> > +	clk_rate = lpi2c_imx->rate_per;
> >  	if (!clk_rate)
> >  		return -EINVAL;
> 
> After the things you did in lpi2c_imx_probe() you can assume that
> clk_rate is not zero, so you could drop the if here.
> 
> Otherwise looks good to me (if you want even if you keep the if which is
> only a minor optimisation).
> 
> Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

you're finding users already... :-)

Looks better than the original version.

Reviewed-by: Andi Shyti <andi.shyti@kernel.org>

Thanks,
Andi

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

end of thread, other threads:[~2024-01-19  0:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-18  7:43 [PATCH 1/1] i2c: lpi2c: Avoid calling clk_get_rate during transfer Alexander Stein
2024-01-18 10:22 ` Uwe Kleine-König
2024-01-18 11:26   ` Alexander Stein
2024-01-18 11:53     ` Uwe Kleine-König
2024-01-19  0:08   ` Andi Shyti

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