linux-pwm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] pwm: imx27: fix race condition .apply,.get_state
@ 2023-01-25 16:01 Leif Middelschulte
  2023-01-25 16:43 ` Uwe Kleine-König
  0 siblings, 1 reply; 3+ messages in thread
From: Leif Middelschulte @ 2023-01-25 16:01 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team
  Cc: Leif Middelschulte, linux-pwm, linux-arm-kernel, linux-kernel

From: Leif Middelschulte <Leif.Middelschulte@klsmartin.com>

A race condition might occur, ultimately leading to switching off the
PWM that is supposed to be turned on.
The condition is more likely, if `CONFIG_PWM_DEBUG` is set and the PWM
has been enabled before Linux is booted.

After writing some value to the register linked to the duty cycle
(`MX3_PWMSAR`), the related debug function
(`core.c:pwm_apply_state_debug`) reads back (`.get_state`)
a wrong value (`0`) as the configured duty cycle. This value is stored
as part of a temporary state variable that it subsequently reapplies
to the PWM for testing purposes. Which, effectively, turns off the PWM.

This patch postpones the return of the `.apply` function until either
the written value can be read back as expected or the operation times
out.

Signed-off-by: Leif Middelschulte <Leif.Middelschulte@klsmartin.com>
---
 drivers/pwm/pwm-imx27.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c
index 29a3089c534c..9b473fe10cb9 100644
--- a/drivers/pwm/pwm-imx27.c
+++ b/drivers/pwm/pwm-imx27.c
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -223,7 +224,7 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	unsigned long long c;
 	unsigned long long clkrate;
 	int ret;
-	u32 cr;
+	u32 cr, val;
 
 	pwm_get_state(pwm, &cstate);
 
@@ -290,6 +291,18 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 	if (!state->enabled)
 		pwm_imx27_clk_disable_unprepare(imx);
 
+	/*
+	 * According to imx pwm RM the value can be:
+	 * - written at any time
+	 * - only be read, if the pwm is enabled
+	 * Yet it returns a wrong value (i.e. within `pwm_imx27_get_state`) if it is subsequently read (while enabled).
+	 * Apparently it takes the value some cycles to propagate.
+	 * Wait a bit to make sure the right value can be read by other functions, before returning.
+	 */
+	ret = readl_relaxed_poll_timeout(imx->mmio_base + MX3_PWMSAR, val, val == duty_cycles, 20000, 300000);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
2.39.1


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

* Re: [PATCH] pwm: imx27: fix race condition .apply,.get_state
  2023-01-25 16:01 [PATCH] pwm: imx27: fix race condition .apply,.get_state Leif Middelschulte
@ 2023-01-25 16:43 ` Uwe Kleine-König
  2023-01-26 15:18   ` Leif Middelschulte
  0 siblings, 1 reply; 3+ messages in thread
From: Uwe Kleine-König @ 2023-01-25 16:43 UTC (permalink / raw)
  To: Leif Middelschulte
  Cc: Thierry Reding, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Leif Middelschulte, linux-pwm,
	linux-arm-kernel, linux-kernel

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

Hello Leif,

first of all thanks for the patch.

On Wed, Jan 25, 2023 at 05:01:42PM +0100, Leif Middelschulte wrote:
> From: Leif Middelschulte <Leif.Middelschulte@klsmartin.com>
> 
> A race condition might occur, ultimately leading to switching off the
> PWM that is supposed to be turned on.
> The condition is more likely, if `CONFIG_PWM_DEBUG` is set and the PWM
> has been enabled before Linux is booted.

As I understand it there is no problem if PWM_DEBUG is off, isn't it?

> After writing some value to the register linked to the duty cycle
> (`MX3_PWMSAR`), the related debug function
> (`core.c:pwm_apply_state_debug`) reads back (`.get_state`)
> a wrong value (`0`) as the configured duty cycle. This value is stored
> as part of a temporary state variable that it subsequently reapplies
> to the PWM for testing purposes. Which, effectively, turns off the PWM.

I thought the thing is: Reading PWMSAR yields the duty_cycle that is
currently in use. Now if .apply() is called with a new value for PWMSAR
and immediately after that .get_state() reads out PWMSAR the previous
period (with the previous duty_cycle) probably isn't completed yet and
so the old value is read.

In this case it wouldn't always be 0 which is read. (Hmm, but with the
conversion we had about this issue, my theory sounds wrong?!)

Maybe instead of waiting in .apply() (which hurts active consumers),
only wait in .get_state() until MX3_PWMSR_FIFOAV drops to zero?

Apart from that, the markdown(?) style you use is unusual for kernel
commit logs and comments. I'd write:

	With CONFIG_PWM_DEBUG=y after writing a value to the PWMSAR
	register in .apply(), the register is read in .get_state().
	Unless a period completed in the meantime, this read yields the
	previously used duty cycle configuration. As the PWM_DEBUG code
	applies the read out configuration for testing purposes this
	effectively undoes the intended effect by rewriting the previous
	hardware state.

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] 3+ messages in thread

* Re: [PATCH] pwm: imx27: fix race condition .apply,.get_state
  2023-01-25 16:43 ` Uwe Kleine-König
@ 2023-01-26 15:18   ` Leif Middelschulte
  0 siblings, 0 replies; 3+ messages in thread
From: Leif Middelschulte @ 2023-01-26 15:18 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: Thierry Reding, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Leif Middelschulte, linux-pwm,
	linux-arm-kernel, linux-kernel

Hello Uwe,

> Am 25.01.2023 um 17:43 schrieb Uwe Kleine-König <u.kleine-koenig@pengutronix.de>:
> 
> Hello Leif,
> 
> first of all thanks for the patch.

Thank you for supporting the effort.

> 
> On Wed, Jan 25, 2023 at 05:01:42PM +0100, Leif Middelschulte wrote:
>> From: Leif Middelschulte <Leif.Middelschulte@klsmartin.com>
>> 
>> A race condition might occur, ultimately leading to switching off the
>> PWM that is supposed to be turned on.
>> The condition is more likely, if `CONFIG_PWM_DEBUG` is set and the PWM
>> has been enabled before Linux is booted.
> 
> As I understand it there is no problem if PWM_DEBUG is off, isn't it?

There is „no problem“ as in: It’s not obvious at the moment/it slumbers. That’s true.

> 
>> After writing some value to the register linked to the duty cycle
>> (`MX3_PWMSAR`), the related debug function
>> (`core.c:pwm_apply_state_debug`) reads back (`.get_state`)
>> a wrong value (`0`) as the configured duty cycle. This value is stored
>> as part of a temporary state variable that it subsequently reapplies
>> to the PWM for testing purposes. Which, effectively, turns off the PWM.
> 
> I thought the thing is: Reading PWMSAR yields the duty_cycle that is
> currently in use. Now if .apply() is called with a new value for PWMSAR
> and immediately after that .get_state() reads out PWMSAR the previous
> period (with the previous duty_cycle) probably isn't completed yet and
> so the old value is read.
> 
> In this case it wouldn't always be 0 which is read. (Hmm, but with the
> conversion we had about this issue, my theory sounds wrong?!)

This is correct. The value will not always be 0, but the current and/or future
value of the sample FIFO.

The problem is that it can be quiet hard to tell exactly which value will be
read back, as the PWM features a FIFO. The read back value depends on
the timing between register read and write.

> 
> Maybe instead of waiting in .apply() (which hurts active consumers),
> only wait in .get_state() until MX3_PWMSR_FIFOAV drops to zero?

This is what I’ve implemented in v2 of this patch.

> 
> Apart from that, the markdown(?) style you use is unusual for kernel
> commit logs and comments. I'd write:
> 
> With CONFIG_PWM_DEBUG=y after writing a value to the PWMSAR
> register in .apply(), the register is read in .get_state().
> Unless a period completed in the meantime, this read yields the
> previously used duty cycle configuration. As the PWM_DEBUG code
> applies the read out configuration for testing purposes this
> effectively undoes the intended effect by rewriting the previous
> hardware state.

Thank you for pointing this out. I have adopted the suggested description
In v2 of this patch.

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

Thanks again,

Leif


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

end of thread, other threads:[~2023-01-26 15:20 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-01-25 16:01 [PATCH] pwm: imx27: fix race condition .apply,.get_state Leif Middelschulte
2023-01-25 16:43 ` Uwe Kleine-König
2023-01-26 15:18   ` Leif Middelschulte

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).