diff options
author | Patrice Chotard <patrice.chotard@st.com> | 2013-04-11 05:01:27 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2013-04-26 11:01:35 -0400 |
commit | 42fed7ba44e4e8c1fb27b28ad14490cb1daff3c7 (patch) | |
tree | 3caafd69ed9807e9a15f14d6c482fa1f1a697a8b /drivers/pinctrl/pinconf.c | |
parent | cb6d315dc36ce56bc017051befa9ac9391300eb9 (diff) |
pinctrl: move subsystem mutex to pinctrl_dev struct
This mutex avoids deadlock in case of use of multiple pin
controllers. Before this modification, by using a global
mutex, deadlock appeared when, for example, a call to
pinctrl_pins_show() locked the pinctrl_mutex, called the
ops->pin_dbg_show of a particular pin controller. If this
pin controller needs I2C access to retrieve configuration
information and I2C driver is using pinctrl to drive its
pins, a call to pinctrl_select_state() try to lock again
pinctrl_mutex which leads to a deadlock.
Notice that the mutex grab from the two direction functions
was moved into pinctrl_gpio_direction().
For several cases, we can't replace pinctrl_mutex by
pctldev->mutex, because at this stage, pctldev is
not accessible :
- pinctrl_get()/pinctrl_put()
- pinctrl_register_maps()
So add respectively pinctrl_list_mutex and
pinctrl_maps_mutex in order to protect
pinctrl_list and pinctrl_maps list instead.
Reintroduce pinctrldev_list_mutex in
find_pinctrl_by_of_node(),
pinctrl_find_and_add_gpio_range()
pinctrl_request_gpio(), pinctrl_free_gpio(),
pinctrl_gpio_direction(), pinctrl_devices_show(),
pinctrl_register() and pinctrl_unregister() to
protect pinctrldev_list.
Changes v2->v3:
- Fix a missing EXPORT_SYMBOL_GPL() for pinctrl_select_state().
Changes v1->v2:
- pinctrl_select_state_locked() is removed, all lock mechanism
is located inside pinctrl_select_state(). When parsing
the state->setting list, take the per-pin-controller driver
lock. (Patrice).
- Introduce pinctrldev_list_mutex to protect pinctrldev_list
in all functions which parse or modify pictrldev_list.
(Patrice).
- move find_pinctrl_by_of_node() from pinctrl/devicetree.c to
pinctrl/core.c in order to protect pinctrldev_list.
(Patrice).
- Sink mutex:es into some functions and remove some _locked
variants down to where the lists are actually accessed to
make things simpler. (Linus)
- Drop *all* mutexes completely from pinctrl_lookup_state()
and pinctrl_select_state() - no relevant mutex was taken
and it was unclear what this was protecting against. (Linus)
Reported by : Seraphin Bonnaffe <seraphin.bonnaffe@stericsson.com>
Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl/pinconf.c')
-rw-r--r-- | drivers/pinctrl/pinconf.c | 46 |
1 files changed, 24 insertions, 22 deletions
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 32f96808202a..c67c37e23dd7 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c | |||
@@ -89,14 +89,14 @@ int pin_config_get(const char *dev_name, const char *name, | |||
89 | struct pinctrl_dev *pctldev; | 89 | struct pinctrl_dev *pctldev; |
90 | int pin; | 90 | int pin; |
91 | 91 | ||
92 | mutex_lock(&pinctrl_mutex); | ||
93 | |||
94 | pctldev = get_pinctrl_dev_from_devname(dev_name); | 92 | pctldev = get_pinctrl_dev_from_devname(dev_name); |
95 | if (!pctldev) { | 93 | if (!pctldev) { |
96 | pin = -EINVAL; | 94 | pin = -EINVAL; |
97 | goto unlock; | 95 | return pin; |
98 | } | 96 | } |
99 | 97 | ||
98 | mutex_lock(&pctldev->mutex); | ||
99 | |||
100 | pin = pin_get_from_name(pctldev, name); | 100 | pin = pin_get_from_name(pctldev, name); |
101 | if (pin < 0) | 101 | if (pin < 0) |
102 | goto unlock; | 102 | goto unlock; |
@@ -104,7 +104,7 @@ int pin_config_get(const char *dev_name, const char *name, | |||
104 | pin = pin_config_get_for_pin(pctldev, pin, config); | 104 | pin = pin_config_get_for_pin(pctldev, pin, config); |
105 | 105 | ||
106 | unlock: | 106 | unlock: |
107 | mutex_unlock(&pinctrl_mutex); | 107 | mutex_unlock(&pctldev->mutex); |
108 | return pin; | 108 | return pin; |
109 | } | 109 | } |
110 | EXPORT_SYMBOL(pin_config_get); | 110 | EXPORT_SYMBOL(pin_config_get); |
@@ -145,14 +145,14 @@ int pin_config_set(const char *dev_name, const char *name, | |||
145 | struct pinctrl_dev *pctldev; | 145 | struct pinctrl_dev *pctldev; |
146 | int pin, ret; | 146 | int pin, ret; |
147 | 147 | ||
148 | mutex_lock(&pinctrl_mutex); | ||
149 | |||
150 | pctldev = get_pinctrl_dev_from_devname(dev_name); | 148 | pctldev = get_pinctrl_dev_from_devname(dev_name); |
151 | if (!pctldev) { | 149 | if (!pctldev) { |
152 | ret = -EINVAL; | 150 | ret = -EINVAL; |
153 | goto unlock; | 151 | return ret; |
154 | } | 152 | } |
155 | 153 | ||
154 | mutex_lock(&pctldev->mutex); | ||
155 | |||
156 | pin = pin_get_from_name(pctldev, name); | 156 | pin = pin_get_from_name(pctldev, name); |
157 | if (pin < 0) { | 157 | if (pin < 0) { |
158 | ret = pin; | 158 | ret = pin; |
@@ -162,7 +162,7 @@ int pin_config_set(const char *dev_name, const char *name, | |||
162 | ret = pin_config_set_for_pin(pctldev, pin, config); | 162 | ret = pin_config_set_for_pin(pctldev, pin, config); |
163 | 163 | ||
164 | unlock: | 164 | unlock: |
165 | mutex_unlock(&pinctrl_mutex); | 165 | mutex_unlock(&pctldev->mutex); |
166 | return ret; | 166 | return ret; |
167 | } | 167 | } |
168 | EXPORT_SYMBOL(pin_config_set); | 168 | EXPORT_SYMBOL(pin_config_set); |
@@ -174,13 +174,14 @@ int pin_config_group_get(const char *dev_name, const char *pin_group, | |||
174 | const struct pinconf_ops *ops; | 174 | const struct pinconf_ops *ops; |
175 | int selector, ret; | 175 | int selector, ret; |
176 | 176 | ||
177 | mutex_lock(&pinctrl_mutex); | ||
178 | |||
179 | pctldev = get_pinctrl_dev_from_devname(dev_name); | 177 | pctldev = get_pinctrl_dev_from_devname(dev_name); |
180 | if (!pctldev) { | 178 | if (!pctldev) { |
181 | ret = -EINVAL; | 179 | ret = -EINVAL; |
182 | goto unlock; | 180 | return ret; |
183 | } | 181 | } |
182 | |||
183 | mutex_lock(&pctldev->mutex); | ||
184 | |||
184 | ops = pctldev->desc->confops; | 185 | ops = pctldev->desc->confops; |
185 | 186 | ||
186 | if (!ops || !ops->pin_config_group_get) { | 187 | if (!ops || !ops->pin_config_group_get) { |
@@ -200,7 +201,7 @@ int pin_config_group_get(const char *dev_name, const char *pin_group, | |||
200 | ret = ops->pin_config_group_get(pctldev, selector, config); | 201 | ret = ops->pin_config_group_get(pctldev, selector, config); |
201 | 202 | ||
202 | unlock: | 203 | unlock: |
203 | mutex_unlock(&pinctrl_mutex); | 204 | mutex_unlock(&pctldev->mutex); |
204 | return ret; | 205 | return ret; |
205 | } | 206 | } |
206 | EXPORT_SYMBOL(pin_config_group_get); | 207 | EXPORT_SYMBOL(pin_config_group_get); |
@@ -217,13 +218,14 @@ int pin_config_group_set(const char *dev_name, const char *pin_group, | |||
217 | int ret; | 218 | int ret; |
218 | int i; | 219 | int i; |
219 | 220 | ||
220 | mutex_lock(&pinctrl_mutex); | ||
221 | |||
222 | pctldev = get_pinctrl_dev_from_devname(dev_name); | 221 | pctldev = get_pinctrl_dev_from_devname(dev_name); |
223 | if (!pctldev) { | 222 | if (!pctldev) { |
224 | ret = -EINVAL; | 223 | ret = -EINVAL; |
225 | goto unlock; | 224 | return ret; |
226 | } | 225 | } |
226 | |||
227 | mutex_lock(&pctldev->mutex); | ||
228 | |||
227 | ops = pctldev->desc->confops; | 229 | ops = pctldev->desc->confops; |
228 | pctlops = pctldev->desc->pctlops; | 230 | pctlops = pctldev->desc->pctlops; |
229 | 231 | ||
@@ -279,7 +281,7 @@ int pin_config_group_set(const char *dev_name, const char *pin_group, | |||
279 | ret = 0; | 281 | ret = 0; |
280 | 282 | ||
281 | unlock: | 283 | unlock: |
282 | mutex_unlock(&pinctrl_mutex); | 284 | mutex_unlock(&pctldev->mutex); |
283 | 285 | ||
284 | return ret; | 286 | return ret; |
285 | } | 287 | } |
@@ -487,7 +489,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what) | |||
487 | seq_puts(s, "Pin config settings per pin\n"); | 489 | seq_puts(s, "Pin config settings per pin\n"); |
488 | seq_puts(s, "Format: pin (name): configs\n"); | 490 | seq_puts(s, "Format: pin (name): configs\n"); |
489 | 491 | ||
490 | mutex_lock(&pinctrl_mutex); | 492 | mutex_lock(&pctldev->mutex); |
491 | 493 | ||
492 | /* The pin number can be retrived from the pin controller descriptor */ | 494 | /* The pin number can be retrived from the pin controller descriptor */ |
493 | for (i = 0; i < pctldev->desc->npins; i++) { | 495 | for (i = 0; i < pctldev->desc->npins; i++) { |
@@ -507,7 +509,7 @@ static int pinconf_pins_show(struct seq_file *s, void *what) | |||
507 | seq_printf(s, "\n"); | 509 | seq_printf(s, "\n"); |
508 | } | 510 | } |
509 | 511 | ||
510 | mutex_unlock(&pinctrl_mutex); | 512 | mutex_unlock(&pctldev->mutex); |
511 | 513 | ||
512 | return 0; | 514 | return 0; |
513 | } | 515 | } |
@@ -608,7 +610,7 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) | |||
608 | bool found = false; | 610 | bool found = false; |
609 | unsigned long config; | 611 | unsigned long config; |
610 | 612 | ||
611 | mutex_lock(&pinctrl_mutex); | 613 | mutex_lock(&pctldev->mutex); |
612 | 614 | ||
613 | /* Parse the pinctrl map and look for the elected pin/state */ | 615 | /* Parse the pinctrl map and look for the elected pin/state */ |
614 | for_each_maps(maps_node, i, map) { | 616 | for_each_maps(maps_node, i, map) { |
@@ -657,7 +659,7 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) | |||
657 | confops->pin_config_config_dbg_show(pctldev, s, config); | 659 | confops->pin_config_config_dbg_show(pctldev, s, config); |
658 | 660 | ||
659 | exit: | 661 | exit: |
660 | mutex_unlock(&pinctrl_mutex); | 662 | mutex_unlock(&pctldev->mutex); |
661 | 663 | ||
662 | return 0; | 664 | return 0; |
663 | } | 665 | } |
@@ -747,7 +749,7 @@ static int pinconf_dbg_config_write(struct file *file, | |||
747 | return -EINVAL; | 749 | return -EINVAL; |
748 | strncpy(config, token, MAX_NAME_LEN); | 750 | strncpy(config, token, MAX_NAME_LEN); |
749 | 751 | ||
750 | mutex_lock(&pinctrl_mutex); | 752 | mutex_lock(&pinctrl_maps_mutex); |
751 | 753 | ||
752 | /* Parse the pinctrl map and look for the selected dev/state/pin */ | 754 | /* Parse the pinctrl map and look for the selected dev/state/pin */ |
753 | for_each_maps(maps_node, i, map) { | 755 | for_each_maps(maps_node, i, map) { |
@@ -785,7 +787,7 @@ static int pinconf_dbg_config_write(struct file *file, | |||
785 | } | 787 | } |
786 | 788 | ||
787 | exit: | 789 | exit: |
788 | mutex_unlock(&pinctrl_mutex); | 790 | mutex_unlock(&pinctrl_maps_mutex); |
789 | 791 | ||
790 | return count; | 792 | return count; |
791 | } | 793 | } |