lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <200809241508.11091.david-b@pacbell.net>
Date:	Wed, 24 Sep 2008 15:08:10 -0700
From:	David Brownell <david-b@...bell.net>
To:	Andrew Morton <akpm@...ux-foundation.org>
Cc:	lkml <linux-kernel@...r.kernel.org>
Subject: [patch 2.6.27-rc7] gpiolib: request/free hooks

From: David Brownell <dbrownell@...rs.sourceforge.net>

Add a new internal mechanism to gpiolib to support low power
operations by letting gpio_chip instances see when their GPIOs
are in use.  When no GPIOs are active, chips may be able to 
enter lower powered runtime states by disabling clocks and/or
power domains.

Signed-off-by: David Brownell <dbrownell@...rs.sourceforge.net>
---
 Documentation/gpio.txt     |    4 ++++
 drivers/gpio/gpiolib.c     |   42 ++++++++++++++++++++++++++++++------------
 include/asm-generic/gpio.h |    9 +++++++++
 3 files changed, 43 insertions(+), 12 deletions(-)

--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -240,6 +240,10 @@ signal, or (b) something wrongly believe
 needed to manage a signal that's in active use.  That is, requesting a
 GPIO can serve as a kind of lock.
 
+Some platforms may also use knowledge about what GPIOs are active for
+power management, such as by powering down unused chip sectors and, more
+easily, gating off unused clocks.
+
 These two calls are optional because not not all current Linux platforms
 offer such functionality in their GPIO support; a valid implementation
 could return success for all gpio_request() calls.  Unlike the other calls,
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -69,14 +69,18 @@ static inline void desc_set_label(struct
  * those calls have no teeth) we can't avoid autorequesting.  This nag
  * message should motivate switching to explicit requests...
  */
-static void gpio_ensure_requested(struct gpio_desc *desc)
+static void gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
 {
 	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
-		pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
+		struct gpio_chip *chip = desc->chip;
+		int gpio = chip->base + offset;
+
+		pr_warning("GPIO-%d autorequested\n", gpio);
 		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));
+		if (!try_module_get(chip->owner))
+			pr_err("GPIO-%d: module can't be gotten \n", gpio);
+		if (chip->request)
+			chip->request(chip, offset);
 	}
 }
 
@@ -781,6 +785,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
 int gpio_request(unsigned gpio, const char *label)
 {
 	struct gpio_desc	*desc;
+	struct gpio_chip	*chip;
 	int			status = -EINVAL;
 	unsigned long		flags;
 
@@ -789,22 +794,31 @@ int gpio_request(unsigned gpio, const ch
 	if (!gpio_is_valid(gpio))
 		goto done;
 	desc = &gpio_desc[gpio];
-	if (desc->chip == NULL)
+	chip = desc->chip;
+	if (chip == NULL)
 		goto done;
 
-	if (!try_module_get(desc->chip->owner))
+	if (!try_module_get(chip->owner))
 		goto done;
 
 	/* NOTE:  gpio_request() can be called in early boot,
-	 * before IRQs are enabled.
+	 * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
 	 */
 
+	if (chip->request) {
+		status = chip->request(chip, gpio - chip->base);
+		if (status < 0) {
+			module_put(chip->owner);
+			goto done;
+		}
+	}
+
 	if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
 		desc_set_label(desc, label ? : "?");
 		status = 0;
 	} else {
 		status = -EBUSY;
-		module_put(desc->chip->owner);
+		module_put(chip->owner);
 	}
 
 done:
@@ -820,6 +834,7 @@ void gpio_free(unsigned gpio)
 {
 	unsigned long		flags;
 	struct gpio_desc	*desc;
+	struct gpio_chip	*chip;
 
 	if (!gpio_is_valid(gpio)) {
 		WARN_ON(extra_checks);
@@ -831,8 +846,11 @@ void gpio_free(unsigned gpio)
 	spin_lock_irqsave(&gpio_lock, flags);
 
 	desc = &gpio_desc[gpio];
-	if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
+	chip = desc->chip;
+	if (chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
 		desc_set_label(desc, NULL);
+		if (chip->free)
+			chip->free(chip, gpio - chip->base);
 		module_put(desc->chip->owner);
 	} else
 		WARN_ON(extra_checks);
@@ -898,7 +916,7 @@ int gpio_direction_input(unsigned gpio)
 	gpio -= chip->base;
 	if (gpio >= chip->ngpio)
 		goto fail;
-	gpio_ensure_requested(desc);
+	gpio_ensure_requested(desc, gpio);
 
 	/* now we know the gpio is valid and chip won't vanish */
 
@@ -936,7 +954,7 @@ int gpio_direction_output(unsigned gpio,
 	gpio -= chip->base;
 	if (gpio >= chip->ngpio)
 		goto fail;
-	gpio_ensure_requested(desc);
+	gpio_ensure_requested(desc, gpio);
 
 	/* now we know the gpio is valid and chip won't vanish */
 
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -35,6 +35,10 @@ struct module;
  * @label: for diagnostics
  * @dev: optional device providing the GPIOs
  * @owner: helps prevent removal of modules exporting active GPIOs
+ * @request: optional hook for chip-specific activation, such as
+ *	enabling module power and clock; may sleep
+ * @free: optional hook for chip-specific deactivation, such as
+ *	disabling module power and clock; may sleep
  * @direction_input: configures signal "offset" as input, or returns error
  * @get: returns value for signal "offset"; for output signals this
  *	returns either the value actually sensed, or zero
@@ -67,6 +71,11 @@ struct gpio_chip {
 	struct device		*dev;
 	struct module		*owner;
 
+	int			(*request)(struct gpio_chip *chip,
+						unsigned offset);
+	void			(*free)(struct gpio_chip *chip,
+						unsigned offset);
+
 	int			(*direction_input)(struct gpio_chip *chip,
 						unsigned offset);
 	int			(*get)(struct gpio_chip *chip,
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ