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

gpiolib: use a single SRCU struct for all GPIO descriptors

We used a per-descriptor SRCU struct in order to not impose a wait with
synchronize_srcu() for descriptor X on read-only operations of
descriptor Y. Now that we no longer call synchronize_srcu() on
descriptor label change but only when releasing descriptor resources, we
can use a single SRCU structure for all GPIO descriptors in a given chip.

Suggested-by: "Paul E. McKenney" <paulmck@kernel.org>
Acked-by: "Paul E. McKenney" <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20240507172414.28513-1-brgl@bgdev.pl
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

+25 -28
+1 -1
drivers/gpio/gpiolib-cdev.c
··· 2351 2351 2352 2352 dflags = READ_ONCE(desc->flags); 2353 2353 2354 - scoped_guard(srcu, &desc->srcu) { 2354 + scoped_guard(srcu, &desc->gdev->desc_srcu) { 2355 2355 label = gpiod_get_label(desc); 2356 2356 if (label && test_bit(FLAG_REQUESTED, &dflags)) 2357 2357 strscpy(info->consumer, label,
+19 -22
drivers/gpio/gpiolib.c
··· 112 112 if (!test_bit(FLAG_REQUESTED, &flags)) 113 113 return NULL; 114 114 115 - label = srcu_dereference_check(desc->label, &desc->srcu, 116 - srcu_read_lock_held(&desc->srcu)); 115 + label = srcu_dereference_check(desc->label, &desc->gdev->desc_srcu, 116 + srcu_read_lock_held(&desc->gdev->desc_srcu)); 117 117 118 118 return label->str; 119 119 } ··· 138 138 139 139 old = rcu_replace_pointer(desc->label, new, 1); 140 140 if (old) 141 - call_srcu(&desc->srcu, &old->rh, desc_free_label); 141 + call_srcu(&desc->gdev->desc_srcu, &old->rh, desc_free_label); 142 142 143 143 return 0; 144 144 } ··· 709 709 static void gpiodev_release(struct device *dev) 710 710 { 711 711 struct gpio_device *gdev = to_gpio_device(dev); 712 - unsigned int i; 713 712 714 - for (i = 0; i < gdev->ngpio; i++) { 715 - /* Free pending label. */ 716 - synchronize_srcu(&gdev->descs[i].srcu); 717 - cleanup_srcu_struct(&gdev->descs[i].srcu); 718 - } 713 + /* Call pending kfree()s for descriptor labels. */ 714 + synchronize_srcu(&gdev->desc_srcu); 715 + cleanup_srcu_struct(&gdev->desc_srcu); 719 716 720 717 ida_free(&gpio_ida, gdev->id); 721 718 kfree_const(gdev->label); ··· 989 992 if (ret) 990 993 goto err_remove_from_list; 991 994 995 + ret = init_srcu_struct(&gdev->desc_srcu); 996 + if (ret) 997 + goto err_cleanup_gdev_srcu; 998 + 992 999 #ifdef CONFIG_PINCTRL 993 1000 INIT_LIST_HEAD(&gdev->pin_ranges); 994 1001 #endif ··· 1000 999 if (gc->names) { 1001 1000 ret = gpiochip_set_desc_names(gc); 1002 1001 if (ret) 1003 - goto err_cleanup_gdev_srcu; 1002 + goto err_cleanup_desc_srcu; 1004 1003 } 1005 1004 ret = gpiochip_set_names(gc); 1006 1005 if (ret) 1007 - goto err_cleanup_gdev_srcu; 1006 + goto err_cleanup_desc_srcu; 1008 1007 1009 1008 ret = gpiochip_init_valid_mask(gc); 1010 1009 if (ret) 1011 - goto err_cleanup_gdev_srcu; 1010 + goto err_cleanup_desc_srcu; 1012 1011 1013 1012 for (desc_index = 0; desc_index < gc->ngpio; desc_index++) { 1014 1013 struct gpio_desc *desc = &gdev->descs[desc_index]; 1015 - 1016 - ret = init_srcu_struct(&desc->srcu); 1017 - if (ret) 1018 - goto err_cleanup_desc_srcu; 1019 1014 1020 1015 if (gc->get_direction && gpiochip_line_is_valid(gc, desc_index)) { 1021 1016 assign_bit(FLAG_IS_OUT, ··· 1024 1027 1025 1028 ret = of_gpiochip_add(gc); 1026 1029 if (ret) 1027 - goto err_cleanup_desc_srcu; 1030 + goto err_free_valid_mask; 1028 1031 1029 1032 ret = gpiochip_add_pin_ranges(gc); 1030 1033 if (ret) ··· 1071 1074 gpiochip_remove_pin_ranges(gc); 1072 1075 err_remove_of_chip: 1073 1076 of_gpiochip_remove(gc); 1074 - err_cleanup_desc_srcu: 1075 - while (desc_index--) 1076 - cleanup_srcu_struct(&gdev->descs[desc_index].srcu); 1077 + err_free_valid_mask: 1077 1078 gpiochip_free_valid_mask(gc); 1079 + err_cleanup_desc_srcu: 1080 + cleanup_srcu_struct(&gdev->desc_srcu); 1078 1081 err_cleanup_gdev_srcu: 1079 1082 cleanup_srcu_struct(&gdev->srcu); 1080 1083 err_remove_from_list: ··· 2404 2407 if (!test_bit(FLAG_REQUESTED, &desc->flags)) 2405 2408 return NULL; 2406 2409 2407 - guard(srcu)(&desc->srcu); 2410 + guard(srcu)(&desc->gdev->desc_srcu); 2408 2411 2409 2412 label = kstrdup(gpiod_get_label(desc), GFP_KERNEL); 2410 2413 if (!label) ··· 4795 4798 } 4796 4799 4797 4800 for_each_gpio_desc(gc, desc) { 4798 - guard(srcu)(&desc->srcu); 4801 + guard(srcu)(&desc->gdev->desc_srcu); 4799 4802 if (test_bit(FLAG_REQUESTED, &desc->flags)) { 4800 4803 gpiod_get_direction(desc); 4801 4804 is_out = test_bit(FLAG_IS_OUT, &desc->flags);
+5 -5
drivers/gpio/gpiolib.h
··· 31 31 * @chip: pointer to the corresponding gpiochip, holding static 32 32 * data for this device 33 33 * @descs: array of ngpio descriptors. 34 + * @desc_srcu: ensures consistent state of GPIO descriptors exposed to users 34 35 * @ngpio: the number of GPIO lines on this GPIO device, equal to the size 35 36 * of the @descs array. 36 37 * @can_sleep: indicate whether the GPIO chip driver's callbacks can sleep ··· 62 61 struct module *owner; 63 62 struct gpio_chip __rcu *chip; 64 63 struct gpio_desc *descs; 64 + struct srcu_struct desc_srcu; 65 65 int base; 66 66 u16 ngpio; 67 67 bool can_sleep; ··· 152 150 * @label: Name of the consumer 153 151 * @name: Line name 154 152 * @hog: Pointer to the device node that hogs this line (if any) 155 - * @srcu: SRCU struct protecting the label pointer. 156 153 * 157 154 * These are obtained using gpiod_get() and are preferable to the old 158 155 * integer-based handles. ··· 189 188 #ifdef CONFIG_OF_DYNAMIC 190 189 struct device_node *hog; 191 190 #endif 192 - struct srcu_struct srcu; 193 191 }; 194 192 195 193 #define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) ··· 256 256 257 257 #define gpiod_err(desc, fmt, ...) \ 258 258 do { \ 259 - scoped_guard(srcu, &desc->srcu) { \ 259 + scoped_guard(srcu, &desc->gdev->desc_srcu) { \ 260 260 pr_err("gpio-%d (%s): " fmt, desc_to_gpio(desc), \ 261 261 gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \ 262 262 } \ ··· 264 264 265 265 #define gpiod_warn(desc, fmt, ...) \ 266 266 do { \ 267 - scoped_guard(srcu, &desc->srcu) { \ 267 + scoped_guard(srcu, &desc->gdev->desc_srcu) { \ 268 268 pr_warn("gpio-%d (%s): " fmt, desc_to_gpio(desc), \ 269 269 gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \ 270 270 } \ ··· 272 272 273 273 #define gpiod_dbg(desc, fmt, ...) \ 274 274 do { \ 275 - scoped_guard(srcu, &desc->srcu) { \ 275 + scoped_guard(srcu, &desc->gdev->desc_srcu) { \ 276 276 pr_debug("gpio-%d (%s): " fmt, desc_to_gpio(desc), \ 277 277 gpiod_get_label(desc) ? : "?", ##__VA_ARGS__); \ 278 278 } \