aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2015-05-04 11:10:44 -0400
committerLinus Walleij <linus.walleij@linaro.org>2015-05-12 04:47:39 -0400
commit6ffcb7971486ea4f1eb14f07f8efb0b6f829a23c (patch)
treecf2c8ed5ec678cc8698cd62774c211ac30ea765d /drivers/gpio
parent56d30ec14c13303eb9e7c34358ba6549fc7b0121 (diff)
gpio: sysfs: use per-gpio locking
Add a per-gpio mutex to serialise attribute operations rather than use one global mutex for all gpios and chips. Having a single global lock for all gpios in a system adds unnecessary latency to the sysfs interface, and especially when having gpio controllers connected over slow buses. Now that the global gpio-sysfs interrupt table is gone and with per-gpio data in place, we can easily switch to using a more fine-grained locking scheme. Keep the global mutex to serialise the global (class) operations of gpio export and unexport and chip removal. Also document the locking assumptions made. Note that this is also needed to fix a race between gpiod_export and gpiod_unexport. Signed-off-by: Johan Hovold <johan@kernel.org> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpiolib-sysfs.c52
1 files changed, 34 insertions, 18 deletions
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index 682e4d34999c..1bb05aa33a84 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -12,12 +12,15 @@
12 12
13struct gpiod_data { 13struct gpiod_data {
14 struct gpio_desc *desc; 14 struct gpio_desc *desc;
15
16 struct mutex mutex;
15 struct kernfs_node *value_kn; 17 struct kernfs_node *value_kn;
16 int irq; 18 int irq;
17}; 19};
18 20
19/* lock protects against unexport_gpio() being called while 21/*
20 * sysfs files are active. 22 * Lock to serialise gpiod export and unexport, and prevent re-export of
23 * gpiod whose chip is being unregistered.
21 */ 24 */
22static DEFINE_MUTEX(sysfs_lock); 25static DEFINE_MUTEX(sysfs_lock);
23 26
@@ -49,14 +52,15 @@ static ssize_t direction_show(struct device *dev,
49 struct gpio_desc *desc = data->desc; 52 struct gpio_desc *desc = data->desc;
50 ssize_t status; 53 ssize_t status;
51 54
52 mutex_lock(&sysfs_lock); 55 mutex_lock(&data->mutex);
53 56
54 gpiod_get_direction(desc); 57 gpiod_get_direction(desc);
55 status = sprintf(buf, "%s\n", 58 status = sprintf(buf, "%s\n",
56 test_bit(FLAG_IS_OUT, &desc->flags) 59 test_bit(FLAG_IS_OUT, &desc->flags)
57 ? "out" : "in"); 60 ? "out" : "in");
58 61
59 mutex_unlock(&sysfs_lock); 62 mutex_unlock(&data->mutex);
63
60 return status; 64 return status;
61} 65}
62 66
@@ -67,7 +71,7 @@ static ssize_t direction_store(struct device *dev,
67 struct gpio_desc *desc = data->desc; 71 struct gpio_desc *desc = data->desc;
68 ssize_t status; 72 ssize_t status;
69 73
70 mutex_lock(&sysfs_lock); 74 mutex_lock(&data->mutex);
71 75
72 if (sysfs_streq(buf, "high")) 76 if (sysfs_streq(buf, "high"))
73 status = gpiod_direction_output_raw(desc, 1); 77 status = gpiod_direction_output_raw(desc, 1);
@@ -78,7 +82,8 @@ static ssize_t direction_store(struct device *dev,
78 else 82 else
79 status = -EINVAL; 83 status = -EINVAL;
80 84
81 mutex_unlock(&sysfs_lock); 85 mutex_unlock(&data->mutex);
86
82 return status ? : size; 87 return status ? : size;
83} 88}
84static DEVICE_ATTR_RW(direction); 89static DEVICE_ATTR_RW(direction);
@@ -90,11 +95,12 @@ static ssize_t value_show(struct device *dev,
90 struct gpio_desc *desc = data->desc; 95 struct gpio_desc *desc = data->desc;
91 ssize_t status; 96 ssize_t status;
92 97
93 mutex_lock(&sysfs_lock); 98 mutex_lock(&data->mutex);
94 99
95 status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc)); 100 status = sprintf(buf, "%d\n", gpiod_get_value_cansleep(desc));
96 101
97 mutex_unlock(&sysfs_lock); 102 mutex_unlock(&data->mutex);
103
98 return status; 104 return status;
99} 105}
100 106
@@ -105,7 +111,7 @@ static ssize_t value_store(struct device *dev,
105 struct gpio_desc *desc = data->desc; 111 struct gpio_desc *desc = data->desc;
106 ssize_t status; 112 ssize_t status;
107 113
108 mutex_lock(&sysfs_lock); 114 mutex_lock(&data->mutex);
109 115
110 if (!test_bit(FLAG_IS_OUT, &desc->flags)) { 116 if (!test_bit(FLAG_IS_OUT, &desc->flags)) {
111 status = -EPERM; 117 status = -EPERM;
@@ -119,7 +125,8 @@ static ssize_t value_store(struct device *dev,
119 } 125 }
120 } 126 }
121 127
122 mutex_unlock(&sysfs_lock); 128 mutex_unlock(&data->mutex);
129
123 return status; 130 return status;
124} 131}
125static DEVICE_ATTR_RW(value); 132static DEVICE_ATTR_RW(value);
@@ -133,6 +140,7 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
133 return IRQ_HANDLED; 140 return IRQ_HANDLED;
134} 141}
135 142
143/* Caller holds gpiod-data mutex. */
136static int gpio_sysfs_request_irq(struct device *dev, unsigned long gpio_flags) 144static int gpio_sysfs_request_irq(struct device *dev, unsigned long gpio_flags)
137{ 145{
138 struct gpiod_data *data = dev_get_drvdata(dev); 146 struct gpiod_data *data = dev_get_drvdata(dev);
@@ -185,6 +193,10 @@ err_put_kn:
185 return ret; 193 return ret;
186} 194}
187 195
196/*
197 * Caller holds gpiod-data mutex (unless called after class-device
198 * deregistration).
199 */
188static void gpio_sysfs_free_irq(struct device *dev) 200static void gpio_sysfs_free_irq(struct device *dev)
189{ 201{
190 struct gpiod_data *data = dev_get_drvdata(dev); 202 struct gpiod_data *data = dev_get_drvdata(dev);
@@ -215,7 +227,7 @@ static ssize_t edge_show(struct device *dev,
215 ssize_t status = 0; 227 ssize_t status = 0;
216 int i; 228 int i;
217 229
218 mutex_lock(&sysfs_lock); 230 mutex_lock(&data->mutex);
219 231
220 for (i = 0; i < ARRAY_SIZE(trigger_types); i++) { 232 for (i = 0; i < ARRAY_SIZE(trigger_types); i++) {
221 mask = desc->flags & GPIO_TRIGGER_MASK; 233 mask = desc->flags & GPIO_TRIGGER_MASK;
@@ -225,7 +237,8 @@ static ssize_t edge_show(struct device *dev,
225 } 237 }
226 } 238 }
227 239
228 mutex_unlock(&sysfs_lock); 240 mutex_unlock(&data->mutex);
241
229 return status; 242 return status;
230} 243}
231 244
@@ -248,7 +261,7 @@ static ssize_t edge_store(struct device *dev,
248 261
249 flags = trigger_types[i].flags; 262 flags = trigger_types[i].flags;
250 263
251 mutex_lock(&sysfs_lock); 264 mutex_lock(&data->mutex);
252 265
253 if ((desc->flags & GPIO_TRIGGER_MASK) == flags) { 266 if ((desc->flags & GPIO_TRIGGER_MASK) == flags) {
254 status = size; 267 status = size;
@@ -265,12 +278,13 @@ static ssize_t edge_store(struct device *dev,
265 } 278 }
266 279
267out_unlock: 280out_unlock:
268 mutex_unlock(&sysfs_lock); 281 mutex_unlock(&data->mutex);
269 282
270 return status; 283 return status;
271} 284}
272static DEVICE_ATTR_RW(edge); 285static DEVICE_ATTR_RW(edge);
273 286
287/* Caller holds gpiod-data mutex. */
274static int sysfs_set_active_low(struct device *dev, int value) 288static int sysfs_set_active_low(struct device *dev, int value)
275{ 289{
276 struct gpiod_data *data = dev_get_drvdata(dev); 290 struct gpiod_data *data = dev_get_drvdata(dev);
@@ -304,12 +318,12 @@ static ssize_t active_low_show(struct device *dev,
304 struct gpio_desc *desc = data->desc; 318 struct gpio_desc *desc = data->desc;
305 ssize_t status; 319 ssize_t status;
306 320
307 mutex_lock(&sysfs_lock); 321 mutex_lock(&data->mutex);
308 322
309 status = sprintf(buf, "%d\n", 323 status = sprintf(buf, "%d\n",
310 !!test_bit(FLAG_ACTIVE_LOW, &desc->flags)); 324 !!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
311 325
312 mutex_unlock(&sysfs_lock); 326 mutex_unlock(&data->mutex);
313 327
314 return status; 328 return status;
315} 329}
@@ -317,16 +331,17 @@ static ssize_t active_low_show(struct device *dev,
317static ssize_t active_low_store(struct device *dev, 331static ssize_t active_low_store(struct device *dev,
318 struct device_attribute *attr, const char *buf, size_t size) 332 struct device_attribute *attr, const char *buf, size_t size)
319{ 333{
334 struct gpiod_data *data = dev_get_drvdata(dev);
320 ssize_t status; 335 ssize_t status;
321 long value; 336 long value;
322 337
323 mutex_lock(&sysfs_lock); 338 mutex_lock(&data->mutex);
324 339
325 status = kstrtol(buf, 0, &value); 340 status = kstrtol(buf, 0, &value);
326 if (status == 0) 341 if (status == 0)
327 status = sysfs_set_active_low(dev, value != 0); 342 status = sysfs_set_active_low(dev, value != 0);
328 343
329 mutex_unlock(&sysfs_lock); 344 mutex_unlock(&data->mutex);
330 345
331 return status ? : size; 346 return status ? : size;
332} 347}
@@ -583,6 +598,7 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
583 } 598 }
584 599
585 data->desc = desc; 600 data->desc = desc;
601 mutex_init(&data->mutex);
586 602
587 offset = gpio_chip_hwgpio(desc); 603 offset = gpio_chip_hwgpio(desc);
588 if (chip->names && chip->names[offset]) 604 if (chip->names && chip->names[offset])