Skip to content

Commit 81570d6

Browse files
author
Bartosz Golaszewski
committed
gpiolib: protect gpio_chip with SRCU in array_info paths in multi get/set
During the locking rework in GPIOLIB, we omitted one important use-case, namely: setting and getting values for GPIO descriptor arrays with array_info present. This patch does two things: first it makes struct gpio_array store the address of the underlying GPIO device and not chip. Next: it protects the chip with SRCU from removal in gpiod_get_array_value_complex() and gpiod_set_array_value_complex(). Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20250215095655.23152-1-brgl@bgdev.pl Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
1 parent 4e667a1 commit 81570d6

File tree

2 files changed

+35
-17
lines changed

2 files changed

+35
-17
lines changed

drivers/gpio/gpiolib.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3143,6 +3143,8 @@ static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
31433143
static int gpio_chip_get_multiple(struct gpio_chip *gc,
31443144
unsigned long *mask, unsigned long *bits)
31453145
{
3146+
lockdep_assert_held(&gc->gpiodev->srcu);
3147+
31463148
if (gc->get_multiple)
31473149
return gc->get_multiple(gc, mask, bits);
31483150
if (gc->get) {
@@ -3173,6 +3175,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
31733175
struct gpio_array *array_info,
31743176
unsigned long *value_bitmap)
31753177
{
3178+
struct gpio_chip *gc;
31763179
int ret, i = 0;
31773180

31783181
/*
@@ -3184,10 +3187,15 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
31843187
array_size <= array_info->size &&
31853188
(void *)array_info == desc_array + array_info->size) {
31863189
if (!can_sleep)
3187-
WARN_ON(array_info->chip->can_sleep);
3190+
WARN_ON(array_info->gdev->can_sleep);
3191+
3192+
guard(srcu)(&array_info->gdev->srcu);
3193+
gc = srcu_dereference(array_info->gdev->chip,
3194+
&array_info->gdev->srcu);
3195+
if (!gc)
3196+
return -ENODEV;
31883197

3189-
ret = gpio_chip_get_multiple(array_info->chip,
3190-
array_info->get_mask,
3198+
ret = gpio_chip_get_multiple(gc, array_info->get_mask,
31913199
value_bitmap);
31923200
if (ret)
31933201
return ret;
@@ -3468,6 +3476,8 @@ static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value)
34683476
static void gpio_chip_set_multiple(struct gpio_chip *gc,
34693477
unsigned long *mask, unsigned long *bits)
34703478
{
3479+
lockdep_assert_held(&gc->gpiodev->srcu);
3480+
34713481
if (gc->set_multiple) {
34723482
gc->set_multiple(gc, mask, bits);
34733483
} else {
@@ -3485,6 +3495,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
34853495
struct gpio_array *array_info,
34863496
unsigned long *value_bitmap)
34873497
{
3498+
struct gpio_chip *gc;
34883499
int i = 0;
34893500

34903501
/*
@@ -3496,14 +3507,19 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
34963507
array_size <= array_info->size &&
34973508
(void *)array_info == desc_array + array_info->size) {
34983509
if (!can_sleep)
3499-
WARN_ON(array_info->chip->can_sleep);
3510+
WARN_ON(array_info->gdev->can_sleep);
3511+
3512+
guard(srcu)(&array_info->gdev->srcu);
3513+
gc = srcu_dereference(array_info->gdev->chip,
3514+
&array_info->gdev->srcu);
3515+
if (!gc)
3516+
return -ENODEV;
35003517

35013518
if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
35023519
bitmap_xor(value_bitmap, value_bitmap,
35033520
array_info->invert_mask, array_size);
35043521

3505-
gpio_chip_set_multiple(array_info->chip, array_info->set_mask,
3506-
value_bitmap);
3522+
gpio_chip_set_multiple(gc, array_info->set_mask, value_bitmap);
35073523

35083524
i = find_first_zero_bit(array_info->set_mask, array_size);
35093525
if (i == array_size)
@@ -4765,9 +4781,10 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
47654781
{
47664782
struct gpio_desc *desc;
47674783
struct gpio_descs *descs;
4784+
struct gpio_device *gdev;
47684785
struct gpio_array *array_info = NULL;
4769-
struct gpio_chip *gc;
47704786
int count, bitmap_size;
4787+
unsigned long dflags;
47714788
size_t descs_size;
47724789

47734790
count = gpiod_count(dev, con_id);
@@ -4788,16 +4805,16 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
47884805

47894806
descs->desc[descs->ndescs] = desc;
47904807

4791-
gc = gpiod_to_chip(desc);
4808+
gdev = gpiod_to_gpio_device(desc);
47924809
/*
47934810
* If pin hardware number of array member 0 is also 0, select
47944811
* its chip as a candidate for fast bitmap processing path.
47954812
*/
47964813
if (descs->ndescs == 0 && gpio_chip_hwgpio(desc) == 0) {
47974814
struct gpio_descs *array;
47984815

4799-
bitmap_size = BITS_TO_LONGS(gc->ngpio > count ?
4800-
gc->ngpio : count);
4816+
bitmap_size = BITS_TO_LONGS(gdev->ngpio > count ?
4817+
gdev->ngpio : count);
48014818

48024819
array = krealloc(descs, descs_size +
48034820
struct_size(array_info, invert_mask, 3 * bitmap_size),
@@ -4817,7 +4834,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
48174834

48184835
array_info->desc = descs->desc;
48194836
array_info->size = count;
4820-
array_info->chip = gc;
4837+
array_info->gdev = gdev;
48214838
bitmap_set(array_info->get_mask, descs->ndescs,
48224839
count - descs->ndescs);
48234840
bitmap_set(array_info->set_mask, descs->ndescs,
@@ -4830,7 +4847,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
48304847
continue;
48314848

48324849
/* Unmark array members which don't belong to the 'fast' chip */
4833-
if (array_info->chip != gc) {
4850+
if (array_info->gdev != gdev) {
48344851
__clear_bit(descs->ndescs, array_info->get_mask);
48354852
__clear_bit(descs->ndescs, array_info->set_mask);
48364853
}
@@ -4853,9 +4870,10 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
48534870
array_info->set_mask);
48544871
}
48554872
} else {
4873+
dflags = READ_ONCE(desc->flags);
48564874
/* Exclude open drain or open source from fast output */
4857-
if (gpiochip_line_is_open_drain(gc, descs->ndescs) ||
4858-
gpiochip_line_is_open_source(gc, descs->ndescs))
4875+
if (test_bit(FLAG_OPEN_DRAIN, &dflags) ||
4876+
test_bit(FLAG_OPEN_SOURCE, &dflags))
48594877
__clear_bit(descs->ndescs,
48604878
array_info->set_mask);
48614879
/* Identify 'fast' pins which require invertion */
@@ -4867,7 +4885,7 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
48674885
if (array_info)
48684886
dev_dbg(dev,
48694887
"GPIO array info: chip=%s, size=%d, get_mask=%lx, set_mask=%lx, invert_mask=%lx\n",
4870-
array_info->chip->label, array_info->size,
4888+
array_info->gdev->label, array_info->size,
48714889
*array_info->get_mask, *array_info->set_mask,
48724890
*array_info->invert_mask);
48734891
return descs;

drivers/gpio/gpiolib.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ extern const char *const gpio_suffixes[];
114114
*
115115
* @desc: Array of pointers to the GPIO descriptors
116116
* @size: Number of elements in desc
117-
* @chip: Parent GPIO chip
117+
* @gdev: Parent GPIO device
118118
* @get_mask: Get mask used in fastpath
119119
* @set_mask: Set mask used in fastpath
120120
* @invert_mask: Invert mask used in fastpath
@@ -126,7 +126,7 @@ extern const char *const gpio_suffixes[];
126126
struct gpio_array {
127127
struct gpio_desc **desc;
128128
unsigned int size;
129-
struct gpio_chip *chip;
129+
struct gpio_device *gdev;
130130
unsigned long *get_mask;
131131
unsigned long *set_mask;
132132
unsigned long invert_mask[];

0 commit comments

Comments
 (0)