aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl/pinmux.c
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-03-02 15:05:44 -0500
committerLinus Walleij <linus.walleij@linaro.org>2012-03-05 05:19:49 -0500
commit57b676f9c1b7cd84397fe5a86c9bd2788ac4bd32 (patch)
treee07d87bba28678aa80d9325a9c48eac0f57a7fe2 /drivers/pinctrl/pinmux.c
parent962bcbc57aa244eeb1176fa2e9f65ac865cca68a (diff)
pinctrl: fix and simplify locking
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>
Diffstat (limited to 'drivers/pinctrl/pinmux.c')
-rw-r--r--drivers/pinctrl/pinmux.c21
1 files changed, 9 insertions, 12 deletions
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index f409f161ea1d..7342c26f4246 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -19,8 +19,6 @@
19#include <linux/radix-tree.h> 19#include <linux/radix-tree.h>
20#include <linux/err.h> 20#include <linux/err.h>
21#include <linux/list.h> 21#include <linux/list.h>
22#include <linux/mutex.h>
23#include <linux/spinlock.h>
24#include <linux/string.h> 22#include <linux/string.h>
25#include <linux/sysfs.h> 23#include <linux/sysfs.h>
26#include <linux/debugfs.h> 24#include <linux/debugfs.h>
@@ -96,15 +94,12 @@ static int pin_request(struct pinctrl_dev *pctldev,
96 goto out; 94 goto out;
97 } 95 }
98 96
99 spin_lock(&desc->lock);
100 if (desc->owner && strcmp(desc->owner, owner)) { 97 if (desc->owner && strcmp(desc->owner, owner)) {
101 spin_unlock(&desc->lock);
102 dev_err(pctldev->dev, 98 dev_err(pctldev->dev,
103 "pin already requested\n"); 99 "pin already requested\n");
104 goto out; 100 goto out;
105 } 101 }
106 desc->owner = owner; 102 desc->owner = owner;
107 spin_unlock(&desc->lock);
108 103
109 /* Let each pin increase references to this module */ 104 /* Let each pin increase references to this module */
110 if (!try_module_get(pctldev->owner)) { 105 if (!try_module_get(pctldev->owner)) {
@@ -131,11 +126,8 @@ static int pin_request(struct pinctrl_dev *pctldev,
131 dev_err(pctldev->dev, "->request on device %s failed for pin %d\n", 126 dev_err(pctldev->dev, "->request on device %s failed for pin %d\n",
132 pctldev->desc->name, pin); 127 pctldev->desc->name, pin);
133out_free_pin: 128out_free_pin:
134 if (status) { 129 if (status)
135 spin_lock(&desc->lock);
136 desc->owner = NULL; 130 desc->owner = NULL;
137 spin_unlock(&desc->lock);
138 }
139out: 131out:
140 if (status) 132 if (status)
141 dev_err(pctldev->dev, "pin-%d (%s) status %d\n", 133 dev_err(pctldev->dev, "pin-%d (%s) status %d\n",
@@ -178,10 +170,8 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
178 else if (ops->free) 170 else if (ops->free)
179 ops->free(pctldev, pin); 171 ops->free(pctldev, pin);
180 172
181 spin_lock(&desc->lock);
182 owner = desc->owner; 173 owner = desc->owner;
183 desc->owner = NULL; 174 desc->owner = NULL;
184 spin_unlock(&desc->lock);
185 module_put(pctldev->owner); 175 module_put(pctldev->owner);
186 176
187 return owner; 177 return owner;
@@ -580,6 +570,8 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
580 const struct pinmux_ops *pmxops = pctldev->desc->pmxops; 570 const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
581 unsigned func_selector = 0; 571 unsigned func_selector = 0;
582 572
573 mutex_lock(&pinctrl_mutex);
574
583 while (pmxops->list_functions(pctldev, func_selector) >= 0) { 575 while (pmxops->list_functions(pctldev, func_selector) >= 0) {
584 const char *func = pmxops->get_function_name(pctldev, 576 const char *func = pmxops->get_function_name(pctldev,
585 func_selector); 577 func_selector);
@@ -600,9 +592,10 @@ static int pinmux_functions_show(struct seq_file *s, void *what)
600 seq_puts(s, "]\n"); 592 seq_puts(s, "]\n");
601 593
602 func_selector++; 594 func_selector++;
603
604 } 595 }
605 596
597 mutex_unlock(&pinctrl_mutex);
598
606 return 0; 599 return 0;
607} 600}
608 601
@@ -614,6 +607,8 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
614 seq_puts(s, "Pinmux settings per pin\n"); 607 seq_puts(s, "Pinmux settings per pin\n");
615 seq_puts(s, "Format: pin (name): owner\n"); 608 seq_puts(s, "Format: pin (name): owner\n");
616 609
610 mutex_lock(&pinctrl_mutex);
611
617 /* The pin number can be retrived from the pin controller descriptor */ 612 /* The pin number can be retrived from the pin controller descriptor */
618 for (i = 0; i < pctldev->desc->npins; i++) { 613 for (i = 0; i < pctldev->desc->npins; i++) {
619 struct pin_desc *desc; 614 struct pin_desc *desc;
@@ -635,6 +630,8 @@ static int pinmux_pins_show(struct seq_file *s, void *what)
635 is_hog ? " (HOG)" : ""); 630 is_hog ? " (HOG)" : "");
636 } 631 }
637 632
633 mutex_unlock(&pinctrl_mutex);
634
638 return 0; 635 return 0;
639} 636}
640 637