diff options
author | Alexandre Courbot <acourbot@nvidia.com> | 2014-11-19 02:51:27 -0500 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2014-11-28 05:28:23 -0500 |
commit | 14e85c0e69d5c7fdbd963edbbec1dc5cdd385200 (patch) | |
tree | 1cd91d3c5bf4fd27c9e2c08290832e3c5cf2ce8a | |
parent | c8aaa1bf068f76c84111671a7c13ad7b06b21997 (diff) |
gpio: remove gpio_descs global array
Replace the ARCH_NR_GPIOS-sized static array of GPIO descriptors by
dynamically-allocated arrays for each GPIO chip.
This change makes gpio_to_desc() perform in O(n) (where n is the number
of GPIO chips registered) instead of O(1), however since n is rarely
bigger than 1 or 2 no noticeable performance issue is expected.
Besides this provides more incentive for GPIO consumers to move to the
gpiod interface. One could use a O(log(n)) structure to link the GPIO
chips together, but considering the low limit of n the hypothetical
performance benefit is probably not worth the added complexity.
This patch uses kcalloc() in gpiochip_add(), which removes the ability
to add a chip before kcalloc() can operate. I am not aware of such
cases, but if someone bisects up to this patch then I will be proven
wrong...
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r-- | drivers/gpio/gpiolib.c | 47 |
1 files changed, 31 insertions, 16 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 12d981a5be66..5619922ebf44 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c | |||
@@ -47,8 +47,6 @@ | |||
47 | */ | 47 | */ |
48 | DEFINE_SPINLOCK(gpio_lock); | 48 | DEFINE_SPINLOCK(gpio_lock); |
49 | 49 | ||
50 | static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; | ||
51 | |||
52 | #define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) | 50 | #define GPIO_OFFSET_VALID(chip, offset) (offset >= 0 && offset < chip->ngpio) |
53 | 51 | ||
54 | static DEFINE_MUTEX(gpio_lookup_lock); | 52 | static DEFINE_MUTEX(gpio_lookup_lock); |
@@ -65,10 +63,22 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label) | |||
65 | */ | 63 | */ |
66 | struct gpio_desc *gpio_to_desc(unsigned gpio) | 64 | struct gpio_desc *gpio_to_desc(unsigned gpio) |
67 | { | 65 | { |
68 | if (WARN(!gpio_is_valid(gpio), "invalid GPIO %d\n", gpio)) | 66 | struct gpio_chip *chip; |
69 | return NULL; | 67 | unsigned long flags; |
70 | else | 68 | |
71 | return &gpio_desc[gpio]; | 69 | spin_lock_irqsave(&gpio_lock, flags); |
70 | |||
71 | list_for_each_entry(chip, &gpio_chips, list) { | ||
72 | if (chip->base <= gpio && chip->base + chip->ngpio > gpio) { | ||
73 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
74 | return &chip->desc[gpio - chip->base]; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
79 | |||
80 | WARN(1, "invalid GPIO %d\n", gpio); | ||
81 | return NULL; | ||
72 | } | 82 | } |
73 | EXPORT_SYMBOL_GPL(gpio_to_desc); | 83 | EXPORT_SYMBOL_GPL(gpio_to_desc); |
74 | 84 | ||
@@ -91,7 +101,7 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, | |||
91 | */ | 101 | */ |
92 | int desc_to_gpio(const struct gpio_desc *desc) | 102 | int desc_to_gpio(const struct gpio_desc *desc) |
93 | { | 103 | { |
94 | return desc - &gpio_desc[0]; | 104 | return desc->chip->base + (desc - &desc->chip->desc[0]); |
95 | } | 105 | } |
96 | EXPORT_SYMBOL_GPL(desc_to_gpio); | 106 | EXPORT_SYMBOL_GPL(desc_to_gpio); |
97 | 107 | ||
@@ -206,7 +216,7 @@ static int gpiochip_add_to_list(struct gpio_chip *chip) | |||
206 | /** | 216 | /** |
207 | * gpiochip_add() - register a gpio_chip | 217 | * gpiochip_add() - register a gpio_chip |
208 | * @chip: the chip to register, with chip->base initialized | 218 | * @chip: the chip to register, with chip->base initialized |
209 | * Context: potentially before irqs or kmalloc will work | 219 | * Context: potentially before irqs will work |
210 | * | 220 | * |
211 | * Returns a negative errno if the chip can't be registered, such as | 221 | * Returns a negative errno if the chip can't be registered, such as |
212 | * because the chip->base is invalid or already associated with a | 222 | * because the chip->base is invalid or already associated with a |
@@ -226,12 +236,11 @@ int gpiochip_add(struct gpio_chip *chip) | |||
226 | int status = 0; | 236 | int status = 0; |
227 | unsigned id; | 237 | unsigned id; |
228 | int base = chip->base; | 238 | int base = chip->base; |
239 | struct gpio_desc *descs; | ||
229 | 240 | ||
230 | if (base >= 0 && | 241 | descs = kcalloc(chip->ngpio, sizeof(descs[0]), GFP_KERNEL); |
231 | (!gpio_is_valid(base) || !gpio_is_valid(base + chip->ngpio - 1))) { | 242 | if (!descs) |
232 | status = -EINVAL; | 243 | return -ENOMEM; |
233 | goto fail; | ||
234 | } | ||
235 | 244 | ||
236 | spin_lock_irqsave(&gpio_lock, flags); | 245 | spin_lock_irqsave(&gpio_lock, flags); |
237 | 246 | ||
@@ -247,10 +256,8 @@ int gpiochip_add(struct gpio_chip *chip) | |||
247 | status = gpiochip_add_to_list(chip); | 256 | status = gpiochip_add_to_list(chip); |
248 | 257 | ||
249 | if (status == 0) { | 258 | if (status == 0) { |
250 | chip->desc = &gpio_desc[chip->base]; | ||
251 | |||
252 | for (id = 0; id < chip->ngpio; id++) { | 259 | for (id = 0; id < chip->ngpio; id++) { |
253 | struct gpio_desc *desc = &chip->desc[id]; | 260 | struct gpio_desc *desc = &descs[id]; |
254 | desc->chip = chip; | 261 | desc->chip = chip; |
255 | 262 | ||
256 | /* REVISIT: most hardware initializes GPIOs as | 263 | /* REVISIT: most hardware initializes GPIOs as |
@@ -266,6 +273,8 @@ int gpiochip_add(struct gpio_chip *chip) | |||
266 | } | 273 | } |
267 | } | 274 | } |
268 | 275 | ||
276 | chip->desc = descs; | ||
277 | |||
269 | spin_unlock_irqrestore(&gpio_lock, flags); | 278 | spin_unlock_irqrestore(&gpio_lock, flags); |
270 | 279 | ||
271 | #ifdef CONFIG_PINCTRL | 280 | #ifdef CONFIG_PINCTRL |
@@ -291,6 +300,9 @@ int gpiochip_add(struct gpio_chip *chip) | |||
291 | unlock: | 300 | unlock: |
292 | spin_unlock_irqrestore(&gpio_lock, flags); | 301 | spin_unlock_irqrestore(&gpio_lock, flags); |
293 | fail: | 302 | fail: |
303 | kfree(descs); | ||
304 | chip->desc = NULL; | ||
305 | |||
294 | /* failures here can mean systems won't boot... */ | 306 | /* failures here can mean systems won't boot... */ |
295 | pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, | 307 | pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__, |
296 | chip->base, chip->base + chip->ngpio - 1, | 308 | chip->base, chip->base + chip->ngpio - 1, |
@@ -331,6 +343,9 @@ void gpiochip_remove(struct gpio_chip *chip) | |||
331 | list_del(&chip->list); | 343 | list_del(&chip->list); |
332 | spin_unlock_irqrestore(&gpio_lock, flags); | 344 | spin_unlock_irqrestore(&gpio_lock, flags); |
333 | gpiochip_unexport(chip); | 345 | gpiochip_unexport(chip); |
346 | |||
347 | kfree(chip->desc); | ||
348 | chip->desc = NULL; | ||
334 | } | 349 | } |
335 | EXPORT_SYMBOL_GPL(gpiochip_remove); | 350 | EXPORT_SYMBOL_GPL(gpiochip_remove); |
336 | 351 | ||