diff mbox series

[v2,5/8] mtd: maps: gpio-addr-flash: Replace array with an integer

Message ID 20180905143643.9871-6-ricardo.ribalda@gmail.com
State Superseded
Delegated to: Boris Brezillon
Headers show
Series gpio-addr-flash: Support for device-tree and cleanup | expand

Commit Message

Ricardo Ribalda Delgado Sept. 5, 2018, 2:36 p.m. UTC
By replacing the array with an integer we can avoid completely
the bit comparison loop if the value has not changed (by far
the most common case).

Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
---
 drivers/mtd/maps/gpio-addr-flash.c | 31 +++++++++++++++---------------
 1 file changed, 16 insertions(+), 15 deletions(-)

Comments

Boris Brezillon Sept. 27, 2018, 11:42 a.m. UTC | #1
On Wed,  5 Sep 2018 16:36:40 +0200
Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> wrote:

> By replacing the array with an integer we can avoid completely
> the bit comparison loop if the value has not changed (by far
> the most common case).
> 
> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
> ---
>  drivers/mtd/maps/gpio-addr-flash.c | 31 +++++++++++++++---------------
>  1 file changed, 16 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
> index 22e100f07112..8f5e3dce9be3 100644
> --- a/drivers/mtd/maps/gpio-addr-flash.c
> +++ b/drivers/mtd/maps/gpio-addr-flash.c
> @@ -43,7 +43,7 @@ struct async_state {
>  	struct map_info map;
>  	size_t gpio_count;
>  	unsigned *gpio_addrs;
> -	int *gpio_values;
> +	unsigned int gpio_values;
>  	unsigned int win_order;
>  };
>  #define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
> @@ -55,22 +55,25 @@ struct async_state {
>   *
>   * Rather than call the GPIO framework every time, cache the last-programmed
>   * value.  This speeds up sequential accesses (which are by far the most common
> - * type).  We rely on the GPIO framework to treat non-zero value as high so
> - * that we don't have to normalize the bits.
> + * type).
>   */
>  static void gf_set_gpios(struct async_state *state, unsigned long ofs)
>  {
> -	size_t i = 0;
> -	int value;
> +	int i;
>  
>  	ofs >>= state->win_order;
> -	do {
> -		value = ofs & (1 << i);
> -		if (state->gpio_values[i] != value) {
> -			gpio_set_value(state->gpio_addrs[i], value);
> -			state->gpio_values[i] = value;
> -		}
> -	} while (++i < state->gpio_count);
> +
> +	if (ofs == state->gpio_values)
> +		return;
> +
> +	for (i = 0; i < state->gpio_count; i++) {
> +		if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))

Parens around the xx & BIT(i) operations are unneeded.

> +			continue;
> +
> +		gpio_set_value(state->gpio_addrs[i], !!(ofs & BIT(i)));
> +	}
> +
> +	state->gpio_values = ofs;
>  }
>  
>  /**
> @@ -215,7 +218,7 @@ static int gpio_flash_probe(struct platform_device *pdev)
>  	if (!memory || !gpios || !gpios->end)
>  		return -EINVAL;
>  
> -	arr_size = sizeof(int) * gpios->end;
> +	arr_size = sizeof(state->gpio_addrs[0]) * gpios->end;
>  	state = devm_kzalloc(&pdev->dev, sizeof(*state) + arr_size, GFP_KERNEL);
>  	if (!state)
>  		return -ENOMEM;
> @@ -226,9 +229,7 @@ static int gpio_flash_probe(struct platform_device *pdev)
>  	 */
>  	state->gpio_count     = gpios->end;
>  	state->gpio_addrs     = (void *)(unsigned long)gpios->start;
> -	state->gpio_values    = (void *)(state + 1);
>  	state->win_order      = get_bitmask_order(resource_size(memory)) - 1;
> -	memset(state->gpio_values, 0xff, arr_size);
>  
>  	state->map.name       = DRIVER_NAME;
>  	state->map.read       = gf_read;
Ricardo Ribalda Delgado Oct. 1, 2018, 12:10 p.m. UTC | #2
Hi Boris

On Thu, Sep 27, 2018 at 1:42 PM Boris Brezillon
<boris.brezillon@bootlin.com> wrote:
>
> On Wed,  5 Sep 2018 16:36:40 +0200
> Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> wrote:
>
> > By replacing the array with an integer we can avoid completely
> > the bit comparison loop if the value has not changed (by far
> > the most common case).
> >
> > Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
> > ---
> >  drivers/mtd/maps/gpio-addr-flash.c | 31 +++++++++++++++---------------
> >  1 file changed, 16 insertions(+), 15 deletions(-)
> >
> > diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
> > index 22e100f07112..8f5e3dce9be3 100644
> > --- a/drivers/mtd/maps/gpio-addr-flash.c
> > +++ b/drivers/mtd/maps/gpio-addr-flash.c
> > @@ -43,7 +43,7 @@ struct async_state {
> >       struct map_info map;
> >       size_t gpio_count;
> >       unsigned *gpio_addrs;
> > -     int *gpio_values;
> > +     unsigned int gpio_values;
> >       unsigned int win_order;
> >  };
> >  #define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
> > @@ -55,22 +55,25 @@ struct async_state {
> >   *
> >   * Rather than call the GPIO framework every time, cache the last-programmed
> >   * value.  This speeds up sequential accesses (which are by far the most common
> > - * type).  We rely on the GPIO framework to treat non-zero value as high so
> > - * that we don't have to normalize the bits.
> > + * type).
> >   */
> >  static void gf_set_gpios(struct async_state *state, unsigned long ofs)
> >  {
> > -     size_t i = 0;
> > -     int value;
> > +     int i;
> >
> >       ofs >>= state->win_order;
> > -     do {
> > -             value = ofs & (1 << i);
> > -             if (state->gpio_values[i] != value) {
> > -                     gpio_set_value(state->gpio_addrs[i], value);
> > -                     state->gpio_values[i] = value;
> > -             }
> > -     } while (++i < state->gpio_count);
> > +
> > +     if (ofs == state->gpio_values)
> > +             return;
> > +
> > +     for (i = 0; i < state->gpio_count; i++) {
> > +             if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))
>
> Parens around the xx & BIT(i) operations are unneeded.

If I remove it:


ricardo@neopili:~/curro/kernel-upstream$ make drivers/mtd/maps/gpio-addr-flash.o
  CALL    scripts/checksyscalls.sh
  DESCEND  objtool
  CC      drivers/mtd/maps/gpio-addr-flash.o
drivers/mtd/maps/gpio-addr-flash.c: In function ‘gf_set_gpios’:
drivers/mtd/maps/gpio-addr-flash.c:70:20: warning: suggest parentheses
around comparison in operand of ‘&’ [-Wparentheses]
   if (ofs & BIT(i) == (state->gpio_values & BIT(i)))


>
> > +                     continue;
> > +
> > +             gpio_set_value(state->gpio_addrs[i], !!(ofs & BIT(i)));
> > +     }
> > +
> > +     state->gpio_values = ofs;
> >  }
> >
> >  /**
> > @@ -215,7 +218,7 @@ static int gpio_flash_probe(struct platform_device *pdev)
> >       if (!memory || !gpios || !gpios->end)
> >               return -EINVAL;
> >
> > -     arr_size = sizeof(int) * gpios->end;
> > +     arr_size = sizeof(state->gpio_addrs[0]) * gpios->end;
> >       state = devm_kzalloc(&pdev->dev, sizeof(*state) + arr_size, GFP_KERNEL);
> >       if (!state)
> >               return -ENOMEM;
> > @@ -226,9 +229,7 @@ static int gpio_flash_probe(struct platform_device *pdev)
> >        */
> >       state->gpio_count     = gpios->end;
> >       state->gpio_addrs     = (void *)(unsigned long)gpios->start;
> > -     state->gpio_values    = (void *)(state + 1);
> >       state->win_order      = get_bitmask_order(resource_size(memory)) - 1;
> > -     memset(state->gpio_values, 0xff, arr_size);
> >
> >       state->map.name       = DRIVER_NAME;
> >       state->map.read       = gf_read;
>
Boris Brezillon Oct. 1, 2018, 12:32 p.m. UTC | #3
On Mon, 1 Oct 2018 14:10:03 +0200
Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> wrote:

> > > +             return;
> > > +
> > > +     for (i = 0; i < state->gpio_count; i++) {
> > > +             if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))  
> >
> > Parens around the xx & BIT(i) operations are unneeded.  
> 
> If I remove it:
> 
> 
> ricardo@neopili:~/curro/kernel-upstream$ make drivers/mtd/maps/gpio-addr-flash.o
>   CALL    scripts/checksyscalls.sh
>   DESCEND  objtool
>   CC      drivers/mtd/maps/gpio-addr-flash.o
> drivers/mtd/maps/gpio-addr-flash.c: In function ‘gf_set_gpios’:
> drivers/mtd/maps/gpio-addr-flash.c:70:20: warning: suggest parentheses
> around comparison in operand of ‘&’ [-Wparentheses]
>    if (ofs & BIT(i) == (state->gpio_values & BIT(i)))

Hm, okay. I remember having a similar discussion on one of my patch and
people suggesting to drop it because of the == precedence on x & a.
Anyway, let's just keep it like that.
diff mbox series

Patch

diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c
index 22e100f07112..8f5e3dce9be3 100644
--- a/drivers/mtd/maps/gpio-addr-flash.c
+++ b/drivers/mtd/maps/gpio-addr-flash.c
@@ -43,7 +43,7 @@  struct async_state {
 	struct map_info map;
 	size_t gpio_count;
 	unsigned *gpio_addrs;
-	int *gpio_values;
+	unsigned int gpio_values;
 	unsigned int win_order;
 };
 #define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1)
@@ -55,22 +55,25 @@  struct async_state {
  *
  * Rather than call the GPIO framework every time, cache the last-programmed
  * value.  This speeds up sequential accesses (which are by far the most common
- * type).  We rely on the GPIO framework to treat non-zero value as high so
- * that we don't have to normalize the bits.
+ * type).
  */
 static void gf_set_gpios(struct async_state *state, unsigned long ofs)
 {
-	size_t i = 0;
-	int value;
+	int i;
 
 	ofs >>= state->win_order;
-	do {
-		value = ofs & (1 << i);
-		if (state->gpio_values[i] != value) {
-			gpio_set_value(state->gpio_addrs[i], value);
-			state->gpio_values[i] = value;
-		}
-	} while (++i < state->gpio_count);
+
+	if (ofs == state->gpio_values)
+		return;
+
+	for (i = 0; i < state->gpio_count; i++) {
+		if ((ofs & BIT(i)) == (state->gpio_values & BIT(i)))
+			continue;
+
+		gpio_set_value(state->gpio_addrs[i], !!(ofs & BIT(i)));
+	}
+
+	state->gpio_values = ofs;
 }
 
 /**
@@ -215,7 +218,7 @@  static int gpio_flash_probe(struct platform_device *pdev)
 	if (!memory || !gpios || !gpios->end)
 		return -EINVAL;
 
-	arr_size = sizeof(int) * gpios->end;
+	arr_size = sizeof(state->gpio_addrs[0]) * gpios->end;
 	state = devm_kzalloc(&pdev->dev, sizeof(*state) + arr_size, GFP_KERNEL);
 	if (!state)
 		return -ENOMEM;
@@ -226,9 +229,7 @@  static int gpio_flash_probe(struct platform_device *pdev)
 	 */
 	state->gpio_count     = gpios->end;
 	state->gpio_addrs     = (void *)(unsigned long)gpios->start;
-	state->gpio_values    = (void *)(state + 1);
 	state->win_order      = get_bitmask_order(resource_size(memory)) - 1;
-	memset(state->gpio_values, 0xff, arr_size);
 
 	state->map.name       = DRIVER_NAME;
 	state->map.read       = gf_read;