|
2 | 2 |
|
3 | 3 | #include <linux/acpi.h>
|
4 | 4 | #include <linux/bitmap.h>
|
5 |
| -#include <linux/cleanup.h> |
6 | 5 | #include <linux/compat.h>
|
7 | 6 | #include <linux/debugfs.h>
|
8 | 7 | #include <linux/device.h>
|
|
16 | 15 | #include <linux/kernel.h>
|
17 | 16 | #include <linux/list.h>
|
18 | 17 | #include <linux/module.h>
|
19 |
| -#include <linux/mutex.h> |
20 | 18 | #include <linux/of.h>
|
21 | 19 | #include <linux/pinctrl/consumer.h>
|
22 | 20 | #include <linux/seq_file.h>
|
@@ -83,9 +81,7 @@ DEFINE_SPINLOCK(gpio_lock);
|
83 | 81 |
|
84 | 82 | static DEFINE_MUTEX(gpio_lookup_lock);
|
85 | 83 | static LIST_HEAD(gpio_lookup_list);
|
86 |
| - |
87 | 84 | LIST_HEAD(gpio_devices);
|
88 |
| -DECLARE_RWSEM(gpio_devices_sem); |
89 | 85 |
|
90 | 86 | static DEFINE_MUTEX(gpio_machine_hogs_mutex);
|
91 | 87 | static LIST_HEAD(gpio_machine_hogs);
|
@@ -117,15 +113,20 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
|
117 | 113 | struct gpio_desc *gpio_to_desc(unsigned gpio)
|
118 | 114 | {
|
119 | 115 | struct gpio_device *gdev;
|
| 116 | + unsigned long flags; |
| 117 | + |
| 118 | + spin_lock_irqsave(&gpio_lock, flags); |
120 | 119 |
|
121 |
| - scoped_guard(rwsem_read, &gpio_devices_sem) { |
122 |
| - list_for_each_entry(gdev, &gpio_devices, list) { |
123 |
| - if (gdev->base <= gpio && |
124 |
| - gdev->base + gdev->ngpio > gpio) |
125 |
| - return &gdev->descs[gpio - gdev->base]; |
| 120 | + list_for_each_entry(gdev, &gpio_devices, list) { |
| 121 | + if (gdev->base <= gpio && |
| 122 | + gdev->base + gdev->ngpio > gpio) { |
| 123 | + spin_unlock_irqrestore(&gpio_lock, flags); |
| 124 | + return &gdev->descs[gpio - gdev->base]; |
126 | 125 | }
|
127 | 126 | }
|
128 | 127 |
|
| 128 | + spin_unlock_irqrestore(&gpio_lock, flags); |
| 129 | + |
129 | 130 | if (!gpio_is_valid(gpio))
|
130 | 131 | pr_warn("invalid GPIO %d\n", gpio);
|
131 | 132 |
|
@@ -398,21 +399,26 @@ static int gpiodev_add_to_list_unlocked(struct gpio_device *gdev)
|
398 | 399 | static struct gpio_desc *gpio_name_to_desc(const char * const name)
|
399 | 400 | {
|
400 | 401 | struct gpio_device *gdev;
|
| 402 | + unsigned long flags; |
401 | 403 |
|
402 | 404 | if (!name)
|
403 | 405 | return NULL;
|
404 | 406 |
|
405 |
| - guard(rwsem_read)(&gpio_devices_sem); |
| 407 | + spin_lock_irqsave(&gpio_lock, flags); |
406 | 408 |
|
407 | 409 | list_for_each_entry(gdev, &gpio_devices, list) {
|
408 | 410 | struct gpio_desc *desc;
|
409 | 411 |
|
410 | 412 | for_each_gpio_desc(gdev->chip, desc) {
|
411 |
| - if (desc->name && !strcmp(desc->name, name)) |
| 413 | + if (desc->name && !strcmp(desc->name, name)) { |
| 414 | + spin_unlock_irqrestore(&gpio_lock, flags); |
412 | 415 | return desc;
|
| 416 | + } |
413 | 417 | }
|
414 | 418 | }
|
415 | 419 |
|
| 420 | + spin_unlock_irqrestore(&gpio_lock, flags); |
| 421 | + |
416 | 422 | return NULL;
|
417 | 423 | }
|
418 | 424 |
|
@@ -807,6 +813,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
807 | 813 | struct lock_class_key *request_key)
|
808 | 814 | {
|
809 | 815 | struct gpio_device *gdev;
|
| 816 | + unsigned long flags; |
810 | 817 | unsigned int i;
|
811 | 818 | int base = 0;
|
812 | 819 | int ret = 0;
|
@@ -871,46 +878,49 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
871 | 878 |
|
872 | 879 | gdev->ngpio = gc->ngpio;
|
873 | 880 |
|
874 |
| - scoped_guard(rwsem_write, &gpio_devices_sem) { |
875 |
| - /* |
876 |
| - * TODO: this allocates a Linux GPIO number base in the global |
877 |
| - * GPIO numberspace for this chip. In the long run we want to |
878 |
| - * get *rid* of this numberspace and use only descriptors, but |
879 |
| - * it may be a pipe dream. It will not happen before we get rid |
880 |
| - * of the sysfs interface anyways. |
881 |
| - */ |
882 |
| - base = gc->base; |
| 881 | + spin_lock_irqsave(&gpio_lock, flags); |
883 | 882 |
|
| 883 | + /* |
| 884 | + * TODO: this allocates a Linux GPIO number base in the global |
| 885 | + * GPIO numberspace for this chip. In the long run we want to |
| 886 | + * get *rid* of this numberspace and use only descriptors, but |
| 887 | + * it may be a pipe dream. It will not happen before we get rid |
| 888 | + * of the sysfs interface anyways. |
| 889 | + */ |
| 890 | + base = gc->base; |
| 891 | + if (base < 0) { |
| 892 | + base = gpiochip_find_base_unlocked(gc->ngpio); |
884 | 893 | if (base < 0) {
|
885 |
| - base = gpiochip_find_base_unlocked(gc->ngpio); |
886 |
| - if (base < 0) { |
887 |
| - ret = base; |
888 |
| - base = 0; |
889 |
| - goto err_free_label; |
890 |
| - } |
891 |
| - /* |
892 |
| - * TODO: it should not be necessary to reflect the assigned |
893 |
| - * base outside of the GPIO subsystem. Go over drivers and |
894 |
| - * see if anyone makes use of this, else drop this and assign |
895 |
| - * a poison instead. |
896 |
| - */ |
897 |
| - gc->base = base; |
898 |
| - } else { |
899 |
| - dev_warn(&gdev->dev, |
900 |
| - "Static allocation of GPIO base is deprecated, use dynamic allocation.\n"); |
901 |
| - } |
902 |
| - gdev->base = base; |
903 |
| - |
904 |
| - ret = gpiodev_add_to_list_unlocked(gdev); |
905 |
| - if (ret) { |
906 |
| - chip_err(gc, "GPIO integer space overlap, cannot add chip\n"); |
| 894 | + spin_unlock_irqrestore(&gpio_lock, flags); |
| 895 | + ret = base; |
| 896 | + base = 0; |
907 | 897 | goto err_free_label;
|
908 | 898 | }
|
| 899 | + /* |
| 900 | + * TODO: it should not be necessary to reflect the assigned |
| 901 | + * base outside of the GPIO subsystem. Go over drivers and |
| 902 | + * see if anyone makes use of this, else drop this and assign |
| 903 | + * a poison instead. |
| 904 | + */ |
| 905 | + gc->base = base; |
| 906 | + } else { |
| 907 | + dev_warn(&gdev->dev, |
| 908 | + "Static allocation of GPIO base is deprecated, use dynamic allocation.\n"); |
| 909 | + } |
| 910 | + gdev->base = base; |
909 | 911 |
|
910 |
| - for (i = 0; i < gc->ngpio; i++) |
911 |
| - gdev->descs[i].gdev = gdev; |
| 912 | + ret = gpiodev_add_to_list_unlocked(gdev); |
| 913 | + if (ret) { |
| 914 | + spin_unlock_irqrestore(&gpio_lock, flags); |
| 915 | + chip_err(gc, "GPIO integer space overlap, cannot add chip\n"); |
| 916 | + goto err_free_label; |
912 | 917 | }
|
913 | 918 |
|
| 919 | + for (i = 0; i < gc->ngpio; i++) |
| 920 | + gdev->descs[i].gdev = gdev; |
| 921 | + |
| 922 | + spin_unlock_irqrestore(&gpio_lock, flags); |
| 923 | + |
914 | 924 | BLOCKING_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier);
|
915 | 925 | BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier);
|
916 | 926 | init_rwsem(&gdev->sem);
|
@@ -1001,8 +1011,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
1001 | 1011 | goto err_print_message;
|
1002 | 1012 | }
|
1003 | 1013 | err_remove_from_list:
|
1004 |
| - scoped_guard(rwsem_write, &gpio_devices_sem) |
1005 |
| - list_del(&gdev->list); |
| 1014 | + spin_lock_irqsave(&gpio_lock, flags); |
| 1015 | + list_del(&gdev->list); |
| 1016 | + spin_unlock_irqrestore(&gpio_lock, flags); |
1006 | 1017 | err_free_label:
|
1007 | 1018 | kfree_const(gdev->label);
|
1008 | 1019 | err_free_descs:
|
@@ -1065,7 +1076,7 @@ void gpiochip_remove(struct gpio_chip *gc)
|
1065 | 1076 | dev_crit(&gdev->dev,
|
1066 | 1077 | "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
|
1067 | 1078 |
|
1068 |
| - scoped_guard(rwsem_write, &gpio_devices_sem) |
| 1079 | + scoped_guard(spinlock_irqsave, &gpio_lock) |
1069 | 1080 | list_del(&gdev->list);
|
1070 | 1081 |
|
1071 | 1082 | /*
|
@@ -1114,7 +1125,7 @@ struct gpio_device *gpio_device_find(void *data,
|
1114 | 1125 | */
|
1115 | 1126 | might_sleep();
|
1116 | 1127 |
|
1117 |
| - guard(rwsem_read)(&gpio_devices_sem); |
| 1128 | + guard(spinlock_irqsave)(&gpio_lock); |
1118 | 1129 |
|
1119 | 1130 | list_for_each_entry(gdev, &gpio_devices, list) {
|
1120 | 1131 | if (gdev->chip && match(gdev->chip, data))
|
@@ -4725,33 +4736,35 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
|
4725 | 4736 |
|
4726 | 4737 | static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
|
4727 | 4738 | {
|
| 4739 | + unsigned long flags; |
4728 | 4740 | struct gpio_device *gdev = NULL;
|
4729 | 4741 | loff_t index = *pos;
|
4730 | 4742 |
|
4731 | 4743 | s->private = "";
|
4732 | 4744 |
|
4733 |
| - guard(rwsem_read)(&gpio_devices_sem); |
4734 |
| - |
4735 |
| - list_for_each_entry(gdev, &gpio_devices, list) { |
4736 |
| - if (index-- == 0) |
| 4745 | + spin_lock_irqsave(&gpio_lock, flags); |
| 4746 | + list_for_each_entry(gdev, &gpio_devices, list) |
| 4747 | + if (index-- == 0) { |
| 4748 | + spin_unlock_irqrestore(&gpio_lock, flags); |
4737 | 4749 | return gdev;
|
4738 |
| - } |
| 4750 | + } |
| 4751 | + spin_unlock_irqrestore(&gpio_lock, flags); |
4739 | 4752 |
|
4740 | 4753 | return NULL;
|
4741 | 4754 | }
|
4742 | 4755 |
|
4743 | 4756 | static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
4744 | 4757 | {
|
| 4758 | + unsigned long flags; |
4745 | 4759 | struct gpio_device *gdev = v;
|
4746 | 4760 | void *ret = NULL;
|
4747 | 4761 |
|
4748 |
| - scoped_guard(rwsem_read, &gpio_devices_sem) { |
4749 |
| - if (list_is_last(&gdev->list, &gpio_devices)) |
4750 |
| - ret = NULL; |
4751 |
| - else |
4752 |
| - ret = list_first_entry(&gdev->list, struct gpio_device, |
4753 |
| - list); |
4754 |
| - } |
| 4762 | + spin_lock_irqsave(&gpio_lock, flags); |
| 4763 | + if (list_is_last(&gdev->list, &gpio_devices)) |
| 4764 | + ret = NULL; |
| 4765 | + else |
| 4766 | + ret = list_first_entry(&gdev->list, struct gpio_device, list); |
| 4767 | + spin_unlock_irqrestore(&gpio_lock, flags); |
4755 | 4768 |
|
4756 | 4769 | s->private = "\n";
|
4757 | 4770 | ++*pos;
|
|
0 commit comments