From 42fed7ba44e4e8c1fb27b28ad14490cb1daff3c7 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Thu, 11 Apr 2013 11:01:27 +0200 Subject: 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 Signed-off-by: Patrice Chotard Signed-off-by: Linus Walleij --- drivers/pinctrl/core.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/pinctrl/core.h') diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 6d3d40036d1b..75476b3d87da 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -33,6 +33,7 @@ struct pinctrl_gpio_range; * @p: result of pinctrl_get() for this device * @hog_default: default state for pins hogged by this device * @hog_sleep: sleep state for pins hogged by this device + * @mutex: mutex taken on each pin controller specific action * @device_root: debugfs root for this device */ struct pinctrl_dev { @@ -46,6 +47,7 @@ struct pinctrl_dev { struct pinctrl *p; struct pinctrl_state *hog_default; struct pinctrl_state *hog_sleep; + struct mutex mutex; #ifdef CONFIG_DEBUG_FS struct dentry *device_root; #endif @@ -168,6 +170,7 @@ struct pinctrl_maps { }; struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name); +struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np); int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name); const char *pin_get_name(struct pinctrl_dev *pctldev, const unsigned pin); int pinctrl_get_group_selector(struct pinctrl_dev *pctldev, @@ -186,8 +189,7 @@ void pinctrl_unregister_map(struct pinctrl_map const *map); extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev); extern int pinctrl_force_default(struct pinctrl_dev *pctldev); -extern struct mutex pinctrl_mutex; -extern struct list_head pinctrldev_list; +extern struct mutex pinctrl_maps_mutex; extern struct list_head pinctrl_maps; #define for_each_maps(_maps_node_, _i_, _map_) \ -- cgit v1.2.3