Skip to content

Commit b17566a

Browse files
jkrzysztlinusw
authored andcommitted
gpiolib: Implement fast processing path in get/set array
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 <corbet@lwn.net> Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
1 parent 77588c1 commit b17566a

File tree

3 files changed

+105
-5
lines changed

3 files changed

+105
-5
lines changed

Documentation/driver-api/gpio/board.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,18 @@ And the table can be added to the board code as follows::
193193

194194
The line will be hogged as soon as the gpiochip is created or - in case the
195195
chip was created earlier - when the hog table is registered.
196+
197+
Arrays of pins
198+
--------------
199+
In addition to requesting pins belonging to a function one by one, a device may
200+
also request an array of pins assigned to the function. The way those pins are
201+
mapped to the device determines if the array qualifies for fast bitmap
202+
processing. If yes, a bitmap is passed over get/set array functions directly
203+
between a caller and a respective .get/set_multiple() callback of a GPIO chip.
204+
205+
In order to qualify for fast bitmap processing, the pin mapping must meet the
206+
following requirements:
207+
- it must belong to the same chip as other 'fast' pins of the function,
208+
- its index within the function must match its hardware number within the chip.
209+
210+
Open drain and open source pins are excluded from fast bitmap output processing.

Documentation/driver-api/gpio/consumer.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,14 @@ array_info should be set to NULL.
388388
Note that for optimal performance GPIOs belonging to the same chip should be
389389
contiguous within the array of descriptors.
390390

391+
Still better performance may be achieved if array indexes of the descriptors
392+
match hardware pin numbers of a single chip. If an array passed to a get/set
393+
array function matches the one obtained from gpiod_get_array() and array_info
394+
associated with the array is also passed, the function may take a fast bitmap
395+
processing path, passing the value_bitmap argument directly to the respective
396+
.get/set_multiple() callback of the chip. That allows for utilization of GPIO
397+
banks as data I/O ports without much loss of performance.
398+
391399
The return value of gpiod_get_array_value() and its variants is 0 on success
392400
or negative on error. Note the difference to gpiod_get_value(), which returns
393401
0 or 1 on success to convey the GPIO value. With the array functions, the GPIO

drivers/gpio/gpiolib.c

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2789,7 +2789,36 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
27892789
struct gpio_array *array_info,
27902790
unsigned long *value_bitmap)
27912791
{
2792-
int i = 0;
2792+
int err, i = 0;
2793+
2794+
/*
2795+
* Validate array_info against desc_array and its size.
2796+
* It should immediately follow desc_array if both
2797+
* have been obtained from the same gpiod_get_array() call.
2798+
*/
2799+
if (array_info && array_info->desc == desc_array &&
2800+
array_size <= array_info->size &&
2801+
(void *)array_info == desc_array + array_info->size) {
2802+
if (!can_sleep)
2803+
WARN_ON(array_info->chip->can_sleep);
2804+
2805+
err = gpio_chip_get_multiple(array_info->chip,
2806+
array_info->get_mask,
2807+
value_bitmap);
2808+
if (err)
2809+
return err;
2810+
2811+
if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
2812+
bitmap_xor(value_bitmap, value_bitmap,
2813+
array_info->invert_mask, array_size);
2814+
2815+
if (bitmap_full(array_info->get_mask, array_size))
2816+
return 0;
2817+
2818+
i = find_first_zero_bit(array_info->get_mask, array_size);
2819+
} else {
2820+
array_info = NULL;
2821+
}
27932822

27942823
while (i < array_size) {
27952824
struct gpio_chip *chip = desc_array[i]->gdev->chip;
@@ -2820,7 +2849,12 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
28202849
int hwgpio = gpio_chip_hwgpio(desc);
28212850

28222851
__set_bit(hwgpio, mask);
2823-
i++;
2852+
2853+
if (array_info)
2854+
find_next_zero_bit(array_info->get_mask,
2855+
array_size, i);
2856+
else
2857+
i++;
28242858
} while ((i < array_size) &&
28252859
(desc_array[i]->gdev->chip == chip));
28262860

@@ -2831,7 +2865,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
28312865
return ret;
28322866
}
28332867

2834-
for (j = first; j < i; j++) {
2868+
for (j = first; j < i; ) {
28352869
const struct gpio_desc *desc = desc_array[j];
28362870
int hwgpio = gpio_chip_hwgpio(desc);
28372871
int value = test_bit(hwgpio, bits);
@@ -2840,6 +2874,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
28402874
value = !value;
28412875
__assign_bit(j, value_bitmap, value);
28422876
trace_gpio_value(desc_to_gpio(desc), 1, value);
2877+
2878+
if (array_info)
2879+
find_next_zero_bit(array_info->get_mask, i, j);
2880+
else
2881+
j++;
28432882
}
28442883

28452884
if (mask != fastpath)
@@ -3043,6 +3082,32 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
30433082
{
30443083
int i = 0;
30453084

3085+
/*
3086+
* Validate array_info against desc_array and its size.
3087+
* It should immediately follow desc_array if both
3088+
* have been obtained from the same gpiod_get_array() call.
3089+
*/
3090+
if (array_info && array_info->desc == desc_array &&
3091+
array_size <= array_info->size &&
3092+
(void *)array_info == desc_array + array_info->size) {
3093+
if (!can_sleep)
3094+
WARN_ON(array_info->chip->can_sleep);
3095+
3096+
if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
3097+
bitmap_xor(value_bitmap, value_bitmap,
3098+
array_info->invert_mask, array_size);
3099+
3100+
gpio_chip_set_multiple(array_info->chip, array_info->set_mask,
3101+
value_bitmap);
3102+
3103+
if (bitmap_full(array_info->set_mask, array_size))
3104+
return 0;
3105+
3106+
i = find_first_zero_bit(array_info->set_mask, array_size);
3107+
} else {
3108+
array_info = NULL;
3109+
}
3110+
30463111
while (i < array_size) {
30473112
struct gpio_chip *chip = desc_array[i]->gdev->chip;
30483113
unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
@@ -3070,7 +3135,14 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
30703135
int hwgpio = gpio_chip_hwgpio(desc);
30713136
int value = test_bit(i, value_bitmap);
30723137

3073-
if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags))
3138+
/*
3139+
* Pins applicable for fast input but not for
3140+
* fast output processing may have been already
3141+
* inverted inside the fast path, skip them.
3142+
*/
3143+
if (!raw && !(array_info &&
3144+
test_bit(i, array_info->invert_mask)) &&
3145+
test_bit(FLAG_ACTIVE_LOW, &desc->flags))
30743146
value = !value;
30753147
trace_gpio_value(desc_to_gpio(desc), 0, value);
30763148
/*
@@ -3089,7 +3161,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
30893161
__clear_bit(hwgpio, bits);
30903162
count++;
30913163
}
3092-
i++;
3164+
3165+
if (array_info)
3166+
find_next_zero_bit(array_info->set_mask,
3167+
array_size, i);
3168+
else
3169+
i++;
30933170
} while ((i < array_size) &&
30943171
(desc_array[i]->gdev->chip == chip));
30953172
/* push collected bits to outputs */

0 commit comments

Comments
 (0)