Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpiolib: use gpio_chips list in gpiochip_find_base

Re-implement gpiochip_find_base using the list of chips instead of the
global gpio_desc[] array. This makes it both simpler and more efficient,
and is needed to remove the global descriptors array.

The new code should preserve the exact same GPIO number assignment
policy as the code it is replacing. There shouldn't be any visible
change to the assigned GPIO numbers.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
[grant.likely: Added comment about assignment policy]
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

authored by

Alexandre Courbot and committed by
Grant Likely
83cabe33 cb1650d4

+15 -20
+15 -20
drivers/gpio/gpiolib.c
··· 126 126 /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ 127 127 static int gpiochip_find_base(int ngpio) 128 128 { 129 - int i; 130 - int spare = 0; 131 - int base = -ENOSPC; 129 + struct gpio_chip *chip; 130 + int base = ARCH_NR_GPIOS - ngpio; 132 131 133 - for (i = ARCH_NR_GPIOS - 1; i >= 0 ; i--) { 134 - struct gpio_desc *desc = &gpio_desc[i]; 135 - struct gpio_chip *chip = desc->chip; 136 - 137 - if (!chip) { 138 - spare++; 139 - if (spare == ngpio) { 140 - base = i; 141 - break; 142 - } 143 - } else { 144 - spare = 0; 145 - if (chip) 146 - i -= chip->ngpio - 1; 147 - } 132 + list_for_each_entry_reverse(chip, &gpio_chips, list) { 133 + /* found a free space? */ 134 + if (chip->base + chip->ngpio <= base) 135 + break; 136 + else 137 + /* nope, check the space right before the chip */ 138 + base = chip->base - ngpio; 148 139 } 149 140 150 - if (gpio_is_valid(base)) 141 + if (gpio_is_valid(base)) { 151 142 pr_debug("%s: found new base at %d\n", __func__, base); 152 - return base; 143 + return base; 144 + } else { 145 + pr_err("%s: cannot find free range\n", __func__); 146 + return -ENOSPC; 147 + } 153 148 } 154 149 155 150 /* caller ensures gpio is valid and requested, chip->get_direction may sleep */