Commit 438d8908 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Linus Torvalds

gpiolib: better rmmod infrastructure

As long as one or more GPIOs on a gpio chip are used its driver should not be
unloaded.  The existing mechanism (gpiochip_remove failure) doesn't address
that, since rmmod can no longer be made to fail by having the cleanup code
report errors.  Module usecounts are the solution.

Assuming standard "initialize struct to zero" policies, this change won't
affect SOC platform drivers.  However, drivers for external chips (on I2C and
SPI busses) should be updated if they can be built as modules.
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@pengutronix.de>
[ gpio_ensure_requested() needs to update module usecounts too ]
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 73fcdc9e
...@@ -68,6 +68,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc) ...@@ -68,6 +68,9 @@ static void gpio_ensure_requested(struct gpio_desc *desc)
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc)); pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
desc_set_label(desc, "[auto]"); desc_set_label(desc, "[auto]");
if (!try_module_get(desc->chip->owner))
pr_err("GPIO-%d: module can't be gotten \n",
(int)(desc - gpio_desc));
} }
} }
...@@ -177,6 +180,9 @@ int gpio_request(unsigned gpio, const char *label) ...@@ -177,6 +180,9 @@ int gpio_request(unsigned gpio, const char *label)
if (desc->chip == NULL) if (desc->chip == NULL)
goto done; goto done;
if (!try_module_get(desc->chip->owner))
goto done;
/* NOTE: gpio_request() can be called in early boot, /* NOTE: gpio_request() can be called in early boot,
* before IRQs are enabled. * before IRQs are enabled.
*/ */
...@@ -184,8 +190,10 @@ int gpio_request(unsigned gpio, const char *label) ...@@ -184,8 +190,10 @@ int gpio_request(unsigned gpio, const char *label)
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) { if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
desc_set_label(desc, label ? : "?"); desc_set_label(desc, label ? : "?");
status = 0; status = 0;
} else } else {
status = -EBUSY; status = -EBUSY;
module_put(desc->chip->owner);
}
done: done:
if (status) if (status)
...@@ -209,9 +217,10 @@ void gpio_free(unsigned gpio) ...@@ -209,9 +217,10 @@ void gpio_free(unsigned gpio)
spin_lock_irqsave(&gpio_lock, flags); spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio]; desc = &gpio_desc[gpio];
if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
desc_set_label(desc, NULL); desc_set_label(desc, NULL);
else module_put(desc->chip->owner);
} else
WARN_ON(extra_checks); WARN_ON(extra_checks);
spin_unlock_irqrestore(&gpio_lock, flags); spin_unlock_irqrestore(&gpio_lock, flags);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#endif #endif
struct seq_file; struct seq_file;
struct module;
/** /**
* struct gpio_chip - abstract a GPIO controller * struct gpio_chip - abstract a GPIO controller
...@@ -48,6 +49,7 @@ struct seq_file; ...@@ -48,6 +49,7 @@ struct seq_file;
*/ */
struct gpio_chip { struct gpio_chip {
char *label; char *label;
struct module *owner;
int (*direction_input)(struct gpio_chip *chip, int (*direction_input)(struct gpio_chip *chip,
unsigned offset); unsigned offset);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment