57b676f9c1
There are many problems with the current pinctrl locking: struct pinctrl_dev's gpio_ranges_lock isn't effective; pinctrl_match_gpio_range() only holds this lock while searching for a gpio range, but the found range is return and manipulated after releading the lock. This could allow pinctrl_remove_gpio_range() for that range while it is in use, and the caller may very well delete the range after removing it, causing pinctrl code to touch the now-free range object. Solving this requires the introduction of a higher-level lock, at least a lock per pin controller, which both gpio range registration and pinctrl_get()/put() will acquire. There is missing locking on HW programming; pin controllers may pack the configuration for different pins/groups/config options/... into one register, and hence have to read-modify-write the register. This needs to be protected, but currently isn't. Related, a future change will add a "complete" op to the pin controller drivers, the idea being that each state's programming will be programmed into the pinctrl driver followed by the "complete" call, which may e.g. flush a register cache to HW. For this to work, it must not be possible to interleave the pinctrl driver calls for different devices. As above, solving this requires the introduction of a higher-level lock, at least a lock per pin controller, which will be held for the duration of any pinctrl_enable()/disable() call. However, each pinctrl mapping table entry may affect a different pin controller if necessary. Hence, with a per-pin-controller lock, almost any pinctrl API may need to acquire multiple locks, one per controller. To avoid deadlock, these would need to be acquired in the same order in all cases. This is extremely difficult to implement in the case of pinctrl_get(), which doesn't know which pin controllers to lock until it has parsed the entire mapping table, since it contains somewhat arbitrary data. The simplest solution here is to introduce a single lock that covers all pin controllers at once. This will be acquired by all pinctrl APIs. This then makes struct pinctrl's mutex irrelevant, since that single lock will always be held whenever this mutex is currently held. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
100 lines
3.0 KiB
C
100 lines
3.0 KiB
C
/*
|
|
* Core private header for the pin control subsystem
|
|
*
|
|
* Copyright (C) 2011 ST-Ericsson SA
|
|
* Written on behalf of Linaro for ST-Ericsson
|
|
*
|
|
* Author: Linus Walleij <linus.walleij@linaro.org>
|
|
*
|
|
* License terms: GNU General Public License (GPL) version 2
|
|
*/
|
|
|
|
#include <linux/mutex.h>
|
|
#include <linux/radix-tree.h>
|
|
#include <linux/pinctrl/pinconf.h>
|
|
|
|
struct pinctrl_gpio_range;
|
|
|
|
/**
|
|
* struct pinctrl_dev - pin control class device
|
|
* @node: node to include this pin controller in the global pin controller list
|
|
* @desc: the pin controller descriptor supplied when initializing this pin
|
|
* controller
|
|
* @pin_desc_tree: each pin descriptor for this pin controller is stored in
|
|
* this radix tree
|
|
* @gpio_ranges: a list of GPIO ranges that is handled by this pin controller,
|
|
* ranges are added to this list at runtime
|
|
* @dev: the device entry for this pin controller
|
|
* @owner: module providing the pin controller, used for refcounting
|
|
* @driver_data: driver data for drivers registering to the pin controller
|
|
* subsystem
|
|
* @p: result of pinctrl_get() for this device
|
|
* @device_root: debugfs root for this device
|
|
*/
|
|
struct pinctrl_dev {
|
|
struct list_head node;
|
|
struct pinctrl_desc *desc;
|
|
struct radix_tree_root pin_desc_tree;
|
|
struct list_head gpio_ranges;
|
|
struct device *dev;
|
|
struct module *owner;
|
|
void *driver_data;
|
|
struct pinctrl *p;
|
|
#ifdef CONFIG_DEBUG_FS
|
|
struct dentry *device_root;
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* struct pinctrl - per-device pin control state holder
|
|
* @node: global list node
|
|
* @dev: the device using this pin control handle
|
|
* @usecount: the number of active users of this pin controller setting, used
|
|
* to keep track of nested use cases
|
|
* @pctldev: pin control device handling this pin control handle
|
|
* @groups: the group selectors for the pinmux device and
|
|
* selector combination handling this pinmux, this is a list that
|
|
* will be traversed on all pinmux operations such as
|
|
* get/put/enable/disable
|
|
*/
|
|
struct pinctrl {
|
|
struct list_head node;
|
|
struct device *dev;
|
|
unsigned usecount;
|
|
struct pinctrl_dev *pctldev;
|
|
#ifdef CONFIG_PINMUX
|
|
struct list_head groups;
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* struct pin_desc - pin descriptor for each physical pin in the arch
|
|
* @pctldev: corresponding pin control device
|
|
* @name: a name for the pin, e.g. the name of the pin/pad/finger on a
|
|
* datasheet or such
|
|
* @dynamic_name: if the name of this pin was dynamically allocated
|
|
* @owner: the device holding this pin or NULL of no device has claimed it
|
|
*/
|
|
struct pin_desc {
|
|
struct pinctrl_dev *pctldev;
|
|
const char *name;
|
|
bool dynamic_name;
|
|
/* These fields only added when supporting pinmux drivers */
|
|
#ifdef CONFIG_PINMUX
|
|
const char *owner;
|
|
#endif
|
|
};
|
|
|
|
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
|
|
int pin_get_from_name(struct pinctrl_dev *pctldev, const char *name);
|
|
int pinctrl_get_group_selector(struct pinctrl_dev *pctldev,
|
|
const char *pin_group);
|
|
|
|
static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
|
|
unsigned int pin)
|
|
{
|
|
return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
|
|
}
|
|
|
|
extern struct mutex pinctrl_mutex;
|