Linux-i2c Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH] i2c: rcar: avoid race when unregistering slave
@ 2020-07-26 16:16 Wolfram Sang
  2020-07-27 10:55 ` Niklas Söderlund
  2020-07-31 13:55 ` Wolfram Sang
  0 siblings, 2 replies; 3+ messages in thread
From: Wolfram Sang @ 2020-07-26 16:16 UTC (permalink / raw)
  To: linux-i2c
  Cc: linux-renesas-soc, Ray Jui, Scott Branden, Dhananjay Phadke,
	bcm-kernel-feedback-list, Rayagonda Kokatanur, Wolfram Sang

Due to the lockless design of the driver, it is theoretically possible
to access a NULL pointer, if a slave interrupt was running while we were
unregistering the slave. To make this rock solid, disable the interrupt
for a short time while we are clearing the interrupt_enable register.
This patch is purely based on code inspection. The OOPS is super-hard to
trigger because clearing SAR (the address) makes interrupts even more
unlikely to happen as well. While here, reinit SCR to SDBS because this
bit should always be set according to documentation. There is no effect,
though, because the interface is disabled.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---

Some people on CC here which encountered the same issue with the
bcm-iproc driver. Does something like this work for you, too?

 drivers/i2c/busses/i2c-rcar.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 8dd35522d95a..0f73f0681a6e 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -871,12 +871,14 @@ static int rcar_unreg_slave(struct i2c_client *slave)
 
 	WARN_ON(!priv->slave);
 
-	/* disable irqs and ensure none is running before clearing ptr */
+	/* ensure no irq is running before clearing ptr */
+	disable_irq(priv->irq);
 	rcar_i2c_write(priv, ICSIER, 0);
-	rcar_i2c_write(priv, ICSCR, 0);
+	rcar_i2c_write(priv, ICSSR, 0);
+	enable_irq(priv->irq);
+	rcar_i2c_write(priv, ICSCR, SDBS);
 	rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
 
-	synchronize_irq(priv->irq);
 	priv->slave = NULL;
 
 	pm_runtime_put(rcar_i2c_priv_to_dev(priv));
-- 
2.20.1


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

* Re: [PATCH] i2c: rcar: avoid race when unregistering slave
  2020-07-26 16:16 [PATCH] i2c: rcar: avoid race when unregistering slave Wolfram Sang
@ 2020-07-27 10:55 ` Niklas Söderlund
  2020-07-31 13:55 ` Wolfram Sang
  1 sibling, 0 replies; 3+ messages in thread
From: Niklas Söderlund @ 2020-07-27 10:55 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-i2c, linux-renesas-soc, Ray Jui, Scott Branden,
	Dhananjay Phadke, bcm-kernel-feedback-list, Rayagonda Kokatanur

Hi Wolfram,

Thanks for your patch.

On 2020-07-26 18:16:06 +0200, Wolfram Sang wrote:
> Due to the lockless design of the driver, it is theoretically possible
> to access a NULL pointer, if a slave interrupt was running while we were
> unregistering the slave. To make this rock solid, disable the interrupt
> for a short time while we are clearing the interrupt_enable register.
> This patch is purely based on code inspection. The OOPS is super-hard to
> trigger because clearing SAR (the address) makes interrupts even more
> unlikely to happen as well. While here, reinit SCR to SDBS because this
> bit should always be set according to documentation. There is no effect,
> though, because the interface is disabled.
> 
> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>

Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
> 
> Some people on CC here which encountered the same issue with the
> bcm-iproc driver. Does something like this work for you, too?
> 
>  drivers/i2c/busses/i2c-rcar.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
> index 8dd35522d95a..0f73f0681a6e 100644
> --- a/drivers/i2c/busses/i2c-rcar.c
> +++ b/drivers/i2c/busses/i2c-rcar.c
> @@ -871,12 +871,14 @@ static int rcar_unreg_slave(struct i2c_client *slave)
>  
>  	WARN_ON(!priv->slave);
>  
> -	/* disable irqs and ensure none is running before clearing ptr */
> +	/* ensure no irq is running before clearing ptr */
> +	disable_irq(priv->irq);
>  	rcar_i2c_write(priv, ICSIER, 0);
> -	rcar_i2c_write(priv, ICSCR, 0);
> +	rcar_i2c_write(priv, ICSSR, 0);
> +	enable_irq(priv->irq);
> +	rcar_i2c_write(priv, ICSCR, SDBS);
>  	rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
>  
> -	synchronize_irq(priv->irq);
>  	priv->slave = NULL;
>  
>  	pm_runtime_put(rcar_i2c_priv_to_dev(priv));
> -- 
> 2.20.1
> 

-- 
Regards,
Niklas Söderlund

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

* Re: [PATCH] i2c: rcar: avoid race when unregistering slave
  2020-07-26 16:16 [PATCH] i2c: rcar: avoid race when unregistering slave Wolfram Sang
  2020-07-27 10:55 ` Niklas Söderlund
@ 2020-07-31 13:55 ` Wolfram Sang
  1 sibling, 0 replies; 3+ messages in thread
From: Wolfram Sang @ 2020-07-31 13:55 UTC (permalink / raw)
  To: linux-i2c
  Cc: linux-renesas-soc, Ray Jui, Scott Branden, Dhananjay Phadke,
	bcm-kernel-feedback-list, Rayagonda Kokatanur


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

On Sun, Jul 26, 2020 at 06:16:06PM +0200, Wolfram Sang wrote:
> Due to the lockless design of the driver, it is theoretically possible
> to access a NULL pointer, if a slave interrupt was running while we were
> unregistering the slave. To make this rock solid, disable the interrupt
> for a short time while we are clearing the interrupt_enable register.
> This patch is purely based on code inspection. The OOPS is super-hard to
> trigger because clearing SAR (the address) makes interrupts even more
> unlikely to happen as well. While here, reinit SCR to SDBS because this
> bit should always be set according to documentation. There is no effect,
> though, because the interface is disabled.
> 
> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>

Applied to for-next, thanks!


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

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

end of thread, back to index

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-26 16:16 [PATCH] i2c: rcar: avoid race when unregistering slave Wolfram Sang
2020-07-27 10:55 ` Niklas Söderlund
2020-07-31 13:55 ` Wolfram Sang

Linux-i2c Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-i2c/0 linux-i2c/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-i2c linux-i2c/ https://lore.kernel.org/linux-i2c \
		linux-i2c@vger.kernel.org
	public-inbox-index linux-i2c

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-i2c


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git