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/devicetree.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/devicetree.c')
-rw-r--r-- | drivers/pinctrl/devicetree.c | 15 |
1 files changed, 2 insertions, 13 deletions
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index c7b7cb477129..340fb4e6c600 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c | |||
@@ -95,22 +95,11 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename, | |||
95 | return pinctrl_register_map(map, num_maps, false, true); | 95 | return pinctrl_register_map(map, num_maps, false, true); |
96 | } | 96 | } |
97 | 97 | ||
98 | static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) | ||
99 | { | ||
100 | struct pinctrl_dev *pctldev; | ||
101 | |||
102 | list_for_each_entry(pctldev, &pinctrldev_list, node) | ||
103 | if (pctldev->dev->of_node == np) | ||
104 | return pctldev; | ||
105 | |||
106 | return NULL; | ||
107 | } | ||
108 | |||
109 | struct pinctrl_dev *of_pinctrl_get(struct device_node *np) | 98 | struct pinctrl_dev *of_pinctrl_get(struct device_node *np) |
110 | { | 99 | { |
111 | struct pinctrl_dev *pctldev; | 100 | struct pinctrl_dev *pctldev; |
112 | 101 | ||
113 | pctldev = find_pinctrl_by_of_node(np); | 102 | pctldev = get_pinctrl_dev_from_of_node(np); |
114 | if (!pctldev) | 103 | if (!pctldev) |
115 | return NULL; | 104 | return NULL; |
116 | 105 | ||
@@ -138,7 +127,7 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename, | |||
138 | /* OK let's just assume this will appear later then */ | 127 | /* OK let's just assume this will appear later then */ |
139 | return -EPROBE_DEFER; | 128 | return -EPROBE_DEFER; |
140 | } | 129 | } |
141 | pctldev = find_pinctrl_by_of_node(np_pctldev); | 130 | pctldev = get_pinctrl_dev_from_of_node(np_pctldev); |
142 | if (pctldev) | 131 | if (pctldev) |
143 | break; | 132 | break; |
144 | /* Do not defer probing of hogs (circular loop) */ | 133 | /* Do not defer probing of hogs (circular loop) */ |