summaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/devicetree.c
diff options
context:
space:
mode:
authorPatrice Chotard <patrice.chotard@st.com>2013-04-11 11:01:27 +0200
committerLinus Walleij <linus.walleij@linaro.org>2013-04-26 17:01:35 +0200
commit42fed7ba44e4e8c1fb27b28ad14490cb1daff3c7 (patch)
tree3caafd69ed9807e9a15f14d6c482fa1f1a697a8b /drivers/pinctrl/devicetree.c
parentcb6d315dc36ce56bc017051befa9ac9391300eb9 (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.c15
1 files changed, 2 insertions, 13 deletions
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index c7b7cb47712..340fb4e6c60 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,
return pinctrl_register_map(map, num_maps, false, true);
}
-static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
-{
- struct pinctrl_dev *pctldev;
-
- list_for_each_entry(pctldev, &pinctrldev_list, node)
- if (pctldev->dev->of_node == np)
- return pctldev;
-
- return NULL;
-}
-
struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
{
struct pinctrl_dev *pctldev;
- pctldev = find_pinctrl_by_of_node(np);
+ pctldev = get_pinctrl_dev_from_of_node(np);
if (!pctldev)
return NULL;
@@ -138,7 +127,7 @@ static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
/* OK let's just assume this will appear later then */
return -EPROBE_DEFER;
}
- pctldev = find_pinctrl_by_of_node(np_pctldev);
+ pctldev = get_pinctrl_dev_from_of_node(np_pctldev);
if (pctldev)
break;
/* Do not defer probing of hogs (circular loop) */