Hi All,

On 2018-09-02 14:01, Janusz Krzysztofik wrote:
> Certain GPIO descriptor arrays returned by gpio_get_array() may contain
> information on direct mapping of array members to pins of a single GPIO
> chip in hardware order.  In such cases, bitmaps of values can be passed
> directly from/to the chip's .get/set_multiple() callbacks without
> wasting time on iterations.
>
> Add respective code to gpiod_get/set_array_bitmap_complex() functions.
> Pins not applicable for fast path are processed as before, skipping
> over the 'fast' ones.
>
> Cc: Jonathan Corbet <cor...@lwn.net>
> Signed-off-by: Janusz Krzysztofik <jmkrzy...@gmail.com>

I've just noticed that this patch landed in today's linux-next. Sadly it
breaks booting of Exynos5250-based Samsung Snow Chromebook (ARM 32bit,
device-tree source arch/arm/boot/dts/exynos5250-snow.dts).

Booting hangs after detecting MMC cards. Reverting this patch fixes the
boot. I will try later to add some debugs and investigate it further what
really happens when booting hangs.

> ---
>   Documentation/driver-api/gpio/board.rst    | 15 ++++++
>   Documentation/driver-api/gpio/consumer.rst |  8 +++
>   drivers/gpio/gpiolib.c                     | 87 
> ++++++++++++++++++++++++++++--
>   3 files changed, 105 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/driver-api/gpio/board.rst 
> b/Documentation/driver-api/gpio/board.rst
> index 2c112553df84..c66821e033c2 100644
> --- a/Documentation/driver-api/gpio/board.rst
> +++ b/Documentation/driver-api/gpio/board.rst
> @@ -193,3 +193,18 @@ And the table can be added to the board code as follows::
>   
>   The line will be hogged as soon as the gpiochip is created or - in case the
>   chip was created earlier - when the hog table is registered.
> +
> +Arrays of pins
> +--------------
> +In addition to requesting pins belonging to a function one by one, a device 
> may
> +also request an array of pins assigned to the function.  The way those pins 
> are
> +mapped to the device determines if the array qualifies for fast bitmap
> +processing.  If yes, a bitmap is passed over get/set array functions directly
> +between a caller and a respective .get/set_multiple() callback of a GPIO 
> chip.
> +
> +In order to qualify for fast bitmap processing, the pin mapping must meet the
> +following requirements:
> +- it must belong to the same chip as other 'fast' pins of the function,
> +- its index within the function must match its hardware number within the 
> chip.
> +
> +Open drain and open source pins are excluded from fast bitmap output 
> processing.
> diff --git a/Documentation/driver-api/gpio/consumer.rst 
> b/Documentation/driver-api/gpio/consumer.rst
> index 0afd95a12b10..cf992e5ab976 100644
> --- a/Documentation/driver-api/gpio/consumer.rst
> +++ b/Documentation/driver-api/gpio/consumer.rst
> @@ -388,6 +388,14 @@ array_info should be set to NULL.
>   Note that for optimal performance GPIOs belonging to the same chip should be
>   contiguous within the array of descriptors.
>   
> +Still better performance may be achieved if array indexes of the descriptors
> +match hardware pin numbers of a single chip.  If an array passed to a get/set
> +array function matches the one obtained from gpiod_get_array() and array_info
> +associated with the array is also passed, the function may take a fast bitmap
> +processing path, passing the value_bitmap argument directly to the respective
> +.get/set_multiple() callback of the chip.  That allows for utilization of 
> GPIO
> +banks as data I/O ports without much loss of performance.
> +
>   The return value of gpiod_get_array_value() and its variants is 0 on success
>   or negative on error. Note the difference to gpiod_get_value(), which 
> returns
>   0 or 1 on success to convey the GPIO value. With the array functions, the 
> GPIO
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index cef6ee31fe05..b9d083fb13ee 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -2789,7 +2789,36 @@ int gpiod_get_array_value_complex(bool raw, bool 
> can_sleep,
>                                 struct gpio_array *array_info,
>                                 unsigned long *value_bitmap)
>   {
> -     int i = 0;
> +     int err, i = 0;
> +
> +     /*
> +      * Validate array_info against desc_array and its size.
> +      * It should immediately follow desc_array if both
> +      * have been obtained from the same gpiod_get_array() call.
> +      */
> +     if (array_info && array_info->desc == desc_array &&
> +         array_size <= array_info->size &&
> +         (void *)array_info == desc_array + array_info->size) {
> +             if (!can_sleep)
> +                     WARN_ON(array_info->chip->can_sleep);
> +
> +             err = gpio_chip_get_multiple(array_info->chip,
> +                                          array_info->get_mask,
> +                                          value_bitmap);
> +             if (err)
> +                     return err;
> +
> +             if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
> +                     bitmap_xor(value_bitmap, value_bitmap,
> +                                array_info->invert_mask, array_size);
> +
> +             if (bitmap_full(array_info->get_mask, array_size))
> +                     return 0;
> +
> +             i = find_first_zero_bit(array_info->get_mask, array_size);
> +     } else {
> +             array_info = NULL;
> +     }
>   
>       while (i < array_size) {
>               struct gpio_chip *chip = desc_array[i]->gdev->chip;
> @@ -2820,7 +2849,12 @@ int gpiod_get_array_value_complex(bool raw, bool 
> can_sleep,
>                       int hwgpio = gpio_chip_hwgpio(desc);
>   
>                       __set_bit(hwgpio, mask);
> -                     i++;
> +
> +                     if (array_info)
> +                             find_next_zero_bit(array_info->get_mask,
> +                                                array_size, i);
> +                     else
> +                             i++;
>               } while ((i < array_size) &&
>                        (desc_array[i]->gdev->chip == chip));
>   
> @@ -2831,7 +2865,7 @@ int gpiod_get_array_value_complex(bool raw, bool 
> can_sleep,
>                       return ret;
>               }
>   
> -             for (j = first; j < i; j++) {
> +             for (j = first; j < i; ) {
>                       const struct gpio_desc *desc = desc_array[j];
>                       int hwgpio = gpio_chip_hwgpio(desc);
>                       int value = test_bit(hwgpio, bits);
> @@ -2840,6 +2874,11 @@ int gpiod_get_array_value_complex(bool raw, bool 
> can_sleep,
>                               value = !value;
>                       __assign_bit(j, value_bitmap, value);
>                       trace_gpio_value(desc_to_gpio(desc), 1, value);
> +
> +                     if (array_info)
> +                             find_next_zero_bit(array_info->get_mask, i, j);
> +                     else
> +                             j++;
>               }
>   
>               if (mask != fastpath)
> @@ -3041,6 +3080,32 @@ int gpiod_set_array_value_complex(bool raw, bool 
> can_sleep,
>   {
>       int i = 0;
>   
> +     /*
> +      * Validate array_info against desc_array and its size.
> +      * It should immediately follow desc_array if both
> +      * have been obtained from the same gpiod_get_array() call.
> +      */
> +     if (array_info && array_info->desc == desc_array &&
> +         array_size <= array_info->size &&
> +         (void *)array_info == desc_array + array_info->size) {
> +             if (!can_sleep)
> +                     WARN_ON(array_info->chip->can_sleep);
> +
> +             if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
> +                     bitmap_xor(value_bitmap, value_bitmap,
> +                                array_info->invert_mask, array_size);
> +
> +             gpio_chip_set_multiple(array_info->chip, array_info->set_mask,
> +                                    value_bitmap);
> +
> +             if (bitmap_full(array_info->set_mask, array_size))
> +                     return 0;
> +
> +             i = find_first_zero_bit(array_info->set_mask, array_size);
> +     } else {
> +             array_info = NULL;
> +     }
> +
>       while (i < array_size) {
>               struct gpio_chip *chip = desc_array[i]->gdev->chip;
>               unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
> @@ -3068,7 +3133,14 @@ int gpiod_set_array_value_complex(bool raw, bool 
> can_sleep,
>                       int hwgpio = gpio_chip_hwgpio(desc);
>                       int value = test_bit(i, value_bitmap);
>   
> -                     if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
> +                     /*
> +                      * Pins applicable for fast input but not for
> +                      * fast output processing may have been already
> +                      * inverted inside the fast path, skip them.
> +                      */
> +                     if (!raw && !(array_info &&
> +                         test_bit(i, array_info->invert_mask)) &&
> +                         test_bit(FLAG_ACTIVE_LOW, &desc->flags))
>                               value = !value;
>                       trace_gpio_value(desc_to_gpio(desc), 0, value);
>                       /*
> @@ -3087,7 +3159,12 @@ int gpiod_set_array_value_complex(bool raw, bool 
> can_sleep,
>                                       __clear_bit(hwgpio, bits);
>                               count++;
>                       }
> -                     i++;
> +
> +                     if (array_info)
> +                             find_next_zero_bit(array_info->set_mask,
> +                                                array_size, i);
> +                     else
> +                             i++;
>               } while ((i < array_size) &&
>                        (desc_array[i]->gdev->chip == chip));
>               /* push collected bits to outputs */
>

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland

_______________________________________________
devel mailing list
de...@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

Reply via email to