Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpiolib: Fix array members of same chip processed separately

New code introduced by commit bf9346f5d47b ("gpiolib: Identify arrays
matching GPIO hardware") forcibly tries to find an array member which
has its array index number equal to its hardware pin number and set
up an array info for possible fast bitmap processing of all arrray
pins belonging to that chip which also satisfy that numbering rule.

Depending on array content, it may happen that consecutive array
members which belong to the same chip but don't have array indexes
equal to their pin hardware numbers will be split into groups, some of
them processed together via the fast bitmap path, and rest of them
separetely. However, applications may expect all those pins being
processed together with a single call to .set_multiple() chip callback,
like that was done before the change.

Limit applicability of fast bitmap processing path to cases where all
pins of consecutive array members starting from 0 which belong to the
same chip have their hardware numbers equal to their corresponding
array indexes. That should still speed up processing of applications
using whole GPIO banks as I/O ports, while not breaking simultaneous
manipulation of consecutive pins of the same chip which don't follow
the equal numbering rule.

Cc: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Janusz Krzysztofik and committed by
Linus Walleij
c4c958aa 35ae7f96

+38 -14
+13 -4
Documentation/driver-api/gpio/board.rst
··· 202 202 processing. If yes, a bitmap is passed over get/set array functions directly 203 203 between a caller and a respective .get/set_multiple() callback of a GPIO chip. 204 204 205 - In order to qualify for fast bitmap processing, the pin mapping must meet the 205 + In order to qualify for fast bitmap processing, the array must meet the 206 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. 207 + - pin hardware number of array member 0 must also be 0, 208 + - pin hardware numbers of consecutive array members which belong to the same 209 + chip as member 0 does must also match their array indexes. 209 210 210 - Open drain and open source pins are excluded from fast bitmap output processing. 211 + Otherwise fast bitmap processing path is not used in order to avoid consecutive 212 + pins which belong to the same chip but are not in hardware order being processed 213 + separately. 214 + 215 + If the array applies for fast bitmap processing path, pins which belong to 216 + different chips than member 0 does, as well as those with indexes different from 217 + their hardware pin numbers, are excluded from the fast path, both input and 218 + output. Moreover, open drain and open source pins are excluded from fast bitmap 219 + output processing.
+25 -10
drivers/gpio/gpiolib.c
··· 4376 4376 4377 4377 chip = gpiod_to_chip(desc); 4378 4378 /* 4379 - * Select a chip of first array member 4380 - * whose index matches its pin hardware number 4381 - * as a candidate for fast bitmap processing. 4379 + * If pin hardware number of array member 0 is also 0, select 4380 + * its chip as a candidate for fast bitmap processing path. 4382 4381 */ 4383 - if (!array_info && gpio_chip_hwgpio(desc) == descs->ndescs) { 4382 + if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) { 4384 4383 struct gpio_descs *array; 4385 4384 4386 4385 bitmap_size = BITS_TO_LONGS(chip->ngpio > count ? ··· 4413 4414 count - descs->ndescs); 4414 4415 descs->info = array_info; 4415 4416 } 4416 - /* 4417 - * Unmark members which don't qualify for fast bitmap 4418 - * processing (different chip, not in hardware order) 4419 - */ 4420 - if (array_info && (chip != array_info->chip || 4421 - gpio_chip_hwgpio(desc) != descs->ndescs)) { 4417 + /* Unmark array members which don't belong to the 'fast' chip */ 4418 + if (array_info && array_info->chip != chip) { 4422 4419 __clear_bit(descs->ndescs, array_info->get_mask); 4423 4420 __clear_bit(descs->ndescs, array_info->set_mask); 4421 + } 4422 + /* 4423 + * Detect array members which belong to the 'fast' chip 4424 + * but their pins are not in hardware order. 4425 + */ 4426 + else if (array_info && 4427 + gpio_chip_hwgpio(desc) != descs->ndescs) { 4428 + /* 4429 + * Don't use fast path if all array members processed so 4430 + * far belong to the same chip as this one but its pin 4431 + * hardware number is different from its array index. 4432 + */ 4433 + if (bitmap_full(array_info->get_mask, descs->ndescs)) { 4434 + array_info = NULL; 4435 + } else { 4436 + __clear_bit(descs->ndescs, 4437 + array_info->get_mask); 4438 + __clear_bit(descs->ndescs, 4439 + array_info->set_mask); 4440 + } 4424 4441 } else if (array_info) { 4425 4442 /* Exclude open drain or open source from fast output */ 4426 4443 if (gpiochip_line_is_open_drain(chip, descs->ndescs) ||