|
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