summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorJanusz Krzysztofik <jmkrzyszt@gmail.com>2018-09-24 01:53:36 +0200
committerLinus Walleij <linus.walleij@linaro.org>2018-09-24 13:47:05 +0200
commitc4c958aa64f31a962ddfdfb2ea628a25c774df25 (patch)
tree6ba8ca87ceb9b96541f1a91a5a86ff2158e9a514 /drivers/gpio
parent35ae7f9694e3c059a9d6a6049c7c171c8233c0c9 (diff)
downloadlinux-c4c958aa64f31a962ddfdfb2ea628a25c774df25.tar.gz
linux-c4c958aa64f31a962ddfdfb2ea628a25c774df25.tar.bz2
linux-c4c958aa64f31a962ddfdfb2ea628a25c774df25.zip
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>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpiolib.c35
1 files changed, 25 insertions, 10 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index aa0b4b46fccc..03d15d84bdd8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -4376,11 +4376,10 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
chip = gpiod_to_chip(desc);
/*
- * Select a chip of first array member
- * whose index matches its pin hardware number
- * as a candidate for fast bitmap processing.
+ * If pin hardware number of array member 0 is also 0, select
+ * its chip as a candidate for fast bitmap processing path.
*/
- if (!array_info && gpio_chip_hwgpio(desc) == descs->ndescs) {
+ if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) {
struct gpio_descs *array;
bitmap_size = BITS_TO_LONGS(chip->ngpio > count ?
@@ -4414,14 +4413,30 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
count - descs->ndescs);
descs->info = array_info;
}
- /*
- * Unmark members which don't qualify for fast bitmap
- * processing (different chip, not in hardware order)
- */
- if (array_info && (chip != array_info->chip ||
- gpio_chip_hwgpio(desc) != descs->ndescs)) {
+ /* Unmark array members which don't belong to the 'fast' chip */
+ if (array_info && array_info->chip != chip) {
__clear_bit(descs->ndescs, array_info->get_mask);
__clear_bit(descs->ndescs, array_info->set_mask);
+ }
+ /*
+ * Detect array members which belong to the 'fast' chip
+ * but their pins are not in hardware order.
+ */
+ else if (array_info &&
+ gpio_chip_hwgpio(desc) != descs->ndescs) {
+ /*
+ * Don't use fast path if all array members processed so
+ * far belong to the same chip as this one but its pin
+ * hardware number is different from its array index.
+ */
+ if (bitmap_full(array_info->get_mask, descs->ndescs)) {
+ array_info = NULL;
+ } else {
+ __clear_bit(descs->ndescs,
+ array_info->get_mask);
+ __clear_bit(descs->ndescs,
+ array_info->set_mask);
+ }
} else if (array_info) {
/* Exclude open drain or open source from fast output */
if (gpiochip_line_is_open_drain(chip, descs->ndescs) ||