Sparse can't see locking scheme used in ->get_multiple() and ->set_multiple() callbacks. CHECK .../drivers/gpio/gpio-aggregator.c .../spinlock.h:409:9: warning: context imbalance in 'gpio_fwd_get_multiple' - unexpected unlock .../spinlock.h:409:9: warning: context imbalance in 'gpio_fwd_set_multiple' - unexpected unlock Refactor them to have better readability and make Sparse happy. Signed-off-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> --- drivers/gpio/gpio-aggregator.c | 70 +++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 424a3d25350b..5be166e73381 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -333,20 +333,14 @@ static int gpio_fwd_get(struct gpio_chip *chip, unsigned int offset) return gpiod_get_value(fwd->descs[offset]); } -static int gpio_fwd_get_multiple(struct gpio_chip *chip, unsigned long *mask, +static int gpio_fwd_get_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, unsigned long *bits) { - struct gpiochip_fwd *fwd = gpiochip_get_data(chip); - unsigned long *values, flags = 0; struct gpio_desc **descs; + unsigned long *values; unsigned int i, j = 0; int error; - if (chip->can_sleep) - mutex_lock(&fwd->mlock); - else - spin_lock_irqsave(&fwd->slock, flags); - /* Both values bitmap and desc pointers are stored in tmp[] */ values = &fwd->tmp[0]; descs = (void *)&fwd->tmp[BITS_TO_LONGS(fwd->chip.ngpio)]; @@ -356,16 +350,32 @@ static int gpio_fwd_get_multiple(struct gpio_chip *chip, unsigned long *mask, descs[j++] = fwd->descs[i]; error = gpiod_get_array_value(j, descs, NULL, values); - if (!error) { - j = 0; - for_each_set_bit(i, mask, fwd->chip.ngpio) - __assign_bit(i, bits, test_bit(j++, values)); - } + if (error) + return error; - if (chip->can_sleep) + j = 0; + for_each_set_bit(i, mask, fwd->chip.ngpio) + __assign_bit(i, bits, test_bit(j++, values)); + + return 0; +} + +static int gpio_fwd_get_multiple_locked(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + unsigned long flags; + int error; + + if (chip->can_sleep) { + mutex_lock(&fwd->mlock); + error = gpio_fwd_get_multiple(fwd, mask, bits); mutex_unlock(&fwd->mlock); - else + } else { + spin_lock_irqsave(&fwd->slock, flags); + error = gpio_fwd_get_multiple(fwd, mask, bits); spin_unlock_irqrestore(&fwd->slock, flags); + } return error; } @@ -377,19 +387,13 @@ static void gpio_fwd_set(struct gpio_chip *chip, unsigned int offset, int value) gpiod_set_value(fwd->descs[offset], value); } -static void gpio_fwd_set_multiple(struct gpio_chip *chip, unsigned long *mask, +static void gpio_fwd_set_multiple(struct gpiochip_fwd *fwd, unsigned long *mask, unsigned long *bits) { - struct gpiochip_fwd *fwd = gpiochip_get_data(chip); - unsigned long *values, flags = 0; struct gpio_desc **descs; + unsigned long *values; unsigned int i, j = 0; - if (chip->can_sleep) - mutex_lock(&fwd->mlock); - else - spin_lock_irqsave(&fwd->slock, flags); - /* Both values bitmap and desc pointers are stored in tmp[] */ values = &fwd->tmp[0]; descs = (void *)&fwd->tmp[BITS_TO_LONGS(fwd->chip.ngpio)]; @@ -400,11 +404,23 @@ static void gpio_fwd_set_multiple(struct gpio_chip *chip, unsigned long *mask, } gpiod_set_array_value(j, descs, NULL, values); +} - if (chip->can_sleep) +static void gpio_fwd_set_multiple_locked(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct gpiochip_fwd *fwd = gpiochip_get_data(chip); + unsigned long flags; + + if (chip->can_sleep) { + mutex_lock(&fwd->mlock); + gpio_fwd_set_multiple(fwd, mask, bits); mutex_unlock(&fwd->mlock); - else + } else { + spin_lock_irqsave(&fwd->slock, flags); + gpio_fwd_set_multiple(fwd, mask, bits); spin_unlock_irqrestore(&fwd->slock, flags); + } } static int gpio_fwd_set_config(struct gpio_chip *chip, unsigned int offset, @@ -470,9 +486,9 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, chip->direction_input = gpio_fwd_direction_input; chip->direction_output = gpio_fwd_direction_output; chip->get = gpio_fwd_get; - chip->get_multiple = gpio_fwd_get_multiple; + chip->get_multiple = gpio_fwd_get_multiple_locked; chip->set = gpio_fwd_set; - chip->set_multiple = gpio_fwd_set_multiple; + chip->set_multiple = gpio_fwd_set_multiple_locked; chip->base = -1; chip->ngpio = ngpios; fwd->descs = descs; -- 2.27.0