diff options
author | Alexandre Courbot <acourbot@nvidia.com> | 2013-02-02 11:29:24 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2013-02-09 04:20:12 -0500 |
commit | 1a989d0f1de8f5a150b35e1e8181cc1abc139162 (patch) | |
tree | 5d1a3b1009d2ec1ee84abf3d2a120a46b4748f87 | |
parent | 0fa2fd9a0d4f1305a54a396d44975894e90eed7b (diff) |
gpiolib: link all gpio_chips using a list
Add a list member to gpio_chip that allows all chips to be parsed
quickly. The current method requires parsing the entire GPIO integer
space, which is painfully slow. Using a list makes many chip operations
that involve lookup or parsing faster, and also simplifies the code. It
is also necessary to eventually get rid of the global gpio_desc[] array.
The list of gpio_chips is always ordered by base GPIO number to ensure
chips traversal is done in the right order.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
-rw-r--r-- | drivers/gpio/gpiolib.c | 51 | ||||
-rw-r--r-- | include/asm-generic/gpio.h | 2 |
2 files changed, 46 insertions, 7 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e14eb88bbe8d..453ac77771ca 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/interrupt.h> | 3 | #include <linux/interrupt.h> |
4 | #include <linux/irq.h> | 4 | #include <linux/irq.h> |
5 | #include <linux/spinlock.h> | 5 | #include <linux/spinlock.h> |
6 | #include <linux/list.h> | ||
6 | #include <linux/device.h> | 7 | #include <linux/device.h> |
7 | #include <linux/err.h> | 8 | #include <linux/err.h> |
8 | #include <linux/debugfs.h> | 9 | #include <linux/debugfs.h> |
@@ -71,6 +72,8 @@ struct gpio_desc { | |||
71 | }; | 72 | }; |
72 | static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; | 73 | static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; |
73 | 74 | ||
75 | static LIST_HEAD(gpio_chips); | ||
76 | |||
74 | #ifdef CONFIG_GPIO_SYSFS | 77 | #ifdef CONFIG_GPIO_SYSFS |
75 | static DEFINE_IDR(dirent_idr); | 78 | static DEFINE_IDR(dirent_idr); |
76 | #endif | 79 | #endif |
@@ -1014,6 +1017,43 @@ static inline void gpiochip_unexport(struct gpio_chip *chip) | |||
1014 | 1017 | ||
1015 | #endif /* CONFIG_GPIO_SYSFS */ | 1018 | #endif /* CONFIG_GPIO_SYSFS */ |
1016 | 1019 | ||
1020 | /* | ||
1021 | * Add a new chip to the global chips list, keeping the list of chips sorted | ||
1022 | * by base order. | ||
1023 | * | ||
1024 | * Return -EBUSY if the new chip overlaps with some other chip's integer | ||
1025 | * space. | ||
1026 | */ | ||
1027 | static int gpiochip_add_to_list(struct gpio_chip *chip) | ||
1028 | { | ||
1029 | struct list_head *pos = &gpio_chips; | ||
1030 | struct gpio_chip *_chip; | ||
1031 | int err = 0; | ||
1032 | |||
1033 | /* find where to insert our chip */ | ||
1034 | list_for_each(pos, &gpio_chips) { | ||
1035 | _chip = list_entry(pos, struct gpio_chip, list); | ||
1036 | /* shall we insert before _chip? */ | ||
1037 | if (_chip->base >= chip->base + chip->ngpio) | ||
1038 | break; | ||
1039 | } | ||
1040 | |||
1041 | /* are we stepping on the chip right before? */ | ||
1042 | if (pos != &gpio_chips && pos->prev != &gpio_chips) { | ||
1043 | _chip = list_entry(pos->prev, struct gpio_chip, list); | ||
1044 | if (_chip->base + _chip->ngpio > chip->base) { | ||
1045 | dev_err(chip->dev, | ||
1046 | "GPIO integer space overlap, cannot add chip\n"); | ||
1047 | err = -EBUSY; | ||
1048 | } | ||
1049 | } | ||
1050 | |||
1051 | if (!err) | ||
1052 | list_add_tail(&chip->list, pos); | ||
1053 | |||
1054 | return err; | ||
1055 | } | ||
1056 | |||
1017 | /** | 1057 | /** |
1018 | * gpiochip_add() - register a gpio_chip | 1058 | * gpiochip_add() - register a gpio_chip |
1019 | * @chip: the chip to register, with chip->base initialized | 1059 | * @chip: the chip to register, with chip->base initialized |
@@ -1055,13 +1095,8 @@ int gpiochip_add(struct gpio_chip *chip) | |||
1055 | chip->base = base; | 1095 | chip->base = base; |
1056 | } | 1096 | } |
1057 | 1097 | ||
1058 | /* these GPIO numbers must not be managed by another gpio_chip */ | 1098 | status = gpiochip_add_to_list(chip); |
1059 | for (id = base; id < base + chip->ngpio; id++) { | 1099 | |
1060 | if (gpio_desc[id].chip != NULL) { | ||
1061 | status = -EBUSY; | ||
1062 | break; | ||
1063 | } | ||
1064 | } | ||
1065 | if (status == 0) { | 1100 | if (status == 0) { |
1066 | for (id = base; id < base + chip->ngpio; id++) { | 1101 | for (id = base; id < base + chip->ngpio; id++) { |
1067 | gpio_desc[id].chip = chip; | 1102 | gpio_desc[id].chip = chip; |
@@ -1135,6 +1170,8 @@ int gpiochip_remove(struct gpio_chip *chip) | |||
1135 | if (status == 0) { | 1170 | if (status == 0) { |
1136 | for (id = chip->base; id < chip->base + chip->ngpio; id++) | 1171 | for (id = chip->base; id < chip->base + chip->ngpio; id++) |
1137 | gpio_desc[id].chip = NULL; | 1172 | gpio_desc[id].chip = NULL; |
1173 | |||
1174 | list_del(&chip->list); | ||
1138 | } | 1175 | } |
1139 | 1176 | ||
1140 | spin_unlock_irqrestore(&gpio_lock, flags); | 1177 | spin_unlock_irqrestore(&gpio_lock, flags); |
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 2034e691c7ab..b562f95cdc2f 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h | |||
@@ -53,6 +53,7 @@ struct device_node; | |||
53 | * @label: for diagnostics | 53 | * @label: for diagnostics |
54 | * @dev: optional device providing the GPIOs | 54 | * @dev: optional device providing the GPIOs |
55 | * @owner: helps prevent removal of modules exporting active GPIOs | 55 | * @owner: helps prevent removal of modules exporting active GPIOs |
56 | * @list: links gpio_chips together for traversal | ||
56 | * @request: optional hook for chip-specific activation, such as | 57 | * @request: optional hook for chip-specific activation, such as |
57 | * enabling module power and clock; may sleep | 58 | * enabling module power and clock; may sleep |
58 | * @free: optional hook for chip-specific deactivation, such as | 59 | * @free: optional hook for chip-specific deactivation, such as |
@@ -98,6 +99,7 @@ struct gpio_chip { | |||
98 | const char *label; | 99 | const char *label; |
99 | struct device *dev; | 100 | struct device *dev; |
100 | struct module *owner; | 101 | struct module *owner; |
102 | struct list_head list; | ||
101 | 103 | ||
102 | int (*request)(struct gpio_chip *chip, | 104 | int (*request)(struct gpio_chip *chip, |
103 | unsigned offset); | 105 | unsigned offset); |