summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2014-04-16 14:57:34 +0530
committerSeema Khowala <seemaj@nvidia.com>2014-04-23 14:05:26 -0700
commite8f37ec9c24b4ff3a1331237702c51918bd67c2c (patch)
tree9f063f795aa2b9a5ccb407218f4abd33ac04556b /drivers/gpio
parenta7d310f5cfcd6e59dc6cc8ee04e3cdbbfc474e1f (diff)
gpiolib: avoid sleeping lock from atomic context in gpiochip_add
If GPIO device is added from device tree then gpiochip_add() try to find the aliased base for that device on atomic context. The of_alias_get_id() is sleeping calls, so it dumps warning of sleeping calls from atomic context as: -- [ 6.320139] BUG: sleeping function called from invalid context at kernel/kernel/mutex.c:413 [ 6.332406] in_atomic(): 1, irqs_disabled(): 128, pid: 1, name: swapper/0 [ 6.339157] INFO: lockdep is turned off. [ 6.343058] irq event stamp: 106315 [ 6.346523] hardirqs last enabled at (106315): [<ffffffc0000a6724>] vprintk_emit+0x1ac/0x57c [ 6.355017] hardirqs last disabled at (106314): [<ffffffc0000a65c8>] vprintk_emit+0x50/0x57c [ 6.363423] softirqs last enabled at (105022): [<ffffffc0000ac730>] __do_softirq+0x1b8/0x2c0 [ 6.371917] softirqs last disabled at (105017): [<ffffffc0000ac91c>] do_softirq+0x6c/0x84 [ 6.380074] CPU: 0 PID: 1 Comm: swapper/0 Tainted: G W 3.10.33-g60742c9-dirty #47 [ 6.388385] Call trace: [ 6.390818] [<ffffffc0000885f4>] dump_backtrace+0x0/0x16c [ 6.396192] [<ffffffc000088770>] show_stack+0x10/0x1c [ 6.401218] [<ffffffc000956a30>] dump_stack+0x1c/0x28 [ 6.406243] [<ffffffc0000d604c>] __might_sleep+0x118/0x120 [ 6.411703] [<ffffffc00095b788>] mutex_lock_nested+0x40/0x350 [ 6.417424] [<ffffffc0006d05f8>] of_alias_get_id+0x2c/0x94 [ 6.422891] [<ffffffc000350170>] gpiochip_add+0x1b8/0x3f0 [ 6.428255] [<ffffffc0003531dc>] pca953x_probe+0x214/0x4fc ---- Rewrite this piece of code such that of_alias_get_id() will get called from non-atomic context to avoid above bug. Change-Id: I0c003f9fbec9661acaa3c5e41c4bc90f6d50729f Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-on: http://git-master/r/396957 Reviewed-by: Thomas Cherry <tcherry@nvidia.com> GVS: Gerrit_Virtual_Submit
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpiolib.c44
1 files changed, 22 insertions, 22 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 0e6c9bd34f53..92e03d478dd5 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -184,37 +184,31 @@ struct gpio_chip *gpio_to_chip(unsigned gpio)
}
/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
-static int gpiochip_find_base(struct gpio_chip *req_chip)
+static int gpiochip_find_base(struct gpio_chip *req_chip, int aliased_base)
{
struct gpio_chip *chip;
int ngpio = req_chip->ngpio;
int base = -1;
-#ifdef CONFIG_OF
- if (req_chip->of_node) {
- int gpio_nr;
+ if (aliased_base >= 0) {
+ int start_gpio = aliased_base;
+ int end_gpio = aliased_base + req_chip->ngpio;
- gpio_nr = of_alias_get_id(req_chip->of_node, "gpio");
- if (gpio_nr >= 0) {
- int start_gpio = gpio_nr;
- int end_gpio = gpio_nr + req_chip->ngpio;
+ /* Check if aliased base is not already allocated */
+ list_for_each_entry(chip, &gpio_chips, list) {
+ if (chip->base > end_gpio)
+ continue;
- list_for_each_entry(chip, &gpio_chips, list) {
- if (chip->base > end_gpio)
+ if ((chip->base < start_gpio) &&
+ ((chip->base + chip->ngpio) < start_gpio))
continue;
-
- if ((chip->base < start_gpio) &&
- ((chip->base + chip->ngpio) < start_gpio))
- continue;
- pr_err("GPIO %d to %d is already allocated\n",
- start_gpio, end_gpio);
- gpio_nr = -1;
- break;
- }
+ pr_err("GPIO %d to %d is already allocated\n",
+ start_gpio, end_gpio);
+ aliased_base = -1;
+ break;
}
- base = gpio_nr;
+ base = aliased_base;
}
-#endif
if (base >= 0)
goto found;
@@ -1206,6 +1200,7 @@ int gpiochip_add(struct gpio_chip *chip)
int status = 0;
unsigned id;
int base = chip->base;
+ int aliased_base = -1;
if ((!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))
&& base >= 0) {
@@ -1213,10 +1208,15 @@ int gpiochip_add(struct gpio_chip *chip)
goto fail;
}
+#ifdef CONFIG_OF
+ if (chip->of_node)
+ aliased_base = of_alias_get_id(chip->of_node, "gpio");
+#endif
+
spin_lock_irqsave(&gpio_lock, flags);
if (base < 0) {
- base = gpiochip_find_base(chip);
+ base = gpiochip_find_base(chip, aliased_base);
if (base < 0) {
status = base;
goto unlock;