aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2014-11-19 02:51:27 -0500
committerLinus Walleij <linus.walleij@linaro.org>2014-11-28 05:28:23 -0500
commit14e85c0e69d5c7fdbd963edbbec1dc5cdd385200 (patch)
tree1cd91d3c5bf4fd27c9e2c08290832e3c5cf2ce8a
parentc8aaa1bf068f76c84111671a7c13ad7b06b21997 (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.c47
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 */
48DEFINE_SPINLOCK(gpio_lock); 48DEFINE_SPINLOCK(gpio_lock);
49 49
50static 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
54static DEFINE_MUTEX(gpio_lookup_lock); 52static DEFINE_MUTEX(gpio_lookup_lock);
@@ -65,10 +63,22 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
65 */ 63 */
66struct gpio_desc *gpio_to_desc(unsigned gpio) 64struct 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}
73EXPORT_SYMBOL_GPL(gpio_to_desc); 83EXPORT_SYMBOL_GPL(gpio_to_desc);
74 84
@@ -91,7 +101,7 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
91 */ 101 */
92int desc_to_gpio(const struct gpio_desc *desc) 102int 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}
96EXPORT_SYMBOL_GPL(desc_to_gpio); 106EXPORT_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)
291unlock: 300unlock:
292 spin_unlock_irqrestore(&gpio_lock, flags); 301 spin_unlock_irqrestore(&gpio_lock, flags);
293fail: 302fail:
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}
335EXPORT_SYMBOL_GPL(gpiochip_remove); 350EXPORT_SYMBOL_GPL(gpiochip_remove);
336 351