Hi, Julien On 01/09/2016 11:16 PM, Bamvor Zhang Jian wrote: > Hi, Julien > > On 01/09/2016 06:56 AM, Julien Grossholtz wrote: >> Hi, >> >> The issue is in the break condition of the list_for_each_entry_safe loop. >> If there is a chip at the beginning it breaks even if there is another >> one after. You should check the next chip: >> if (chip->base > prev->base && chip->base + chip->ngpio <= next->base) > Thanks you suggestion. It indeed fix the issue you mentioned. > I will send the new version after I make sure there is no other corner case. Could you do me favor to test the following patches? It works for the following ranges: [0,31], [32,64], [-1,32], [-1, 32] and the other test cases I wrote. Regards Bamvor --- drivers/gpio/gpiolib.c | 65 ++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 3db34e7..9460f94 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -189,55 +189,46 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction); */ static int gpiochip_add_to_list(struct gpio_chip *chip) { - struct gpio_chip *iterator; - struct gpio_chip *previous = NULL; + struct gpio_chip *prev, *next; if (list_empty(&gpio_chips)) { - list_add_tail(&chip->list, &gpio_chips); + /* initial entry in list */ + list_add(&chip->list, &gpio_chips); return 0; } - list_for_each_entry(iterator, &gpio_chips, list) { - if (iterator->base >= chip->base + chip->ngpio) { - /* - * Iterator is the first GPIO chip so there is no - * previous one - */ - if (!previous) { - goto found; - } else { - /* - * We found a valid range(means - * [base, base + ngpio - 1]) between previous - * and iterator chip. - */ - if (previous->base + previous->ngpio - <= chip->base) - goto found; - } - } - previous = iterator; + next = list_entry(gpio_chips.next, struct gpio_chip, list); + if (chip->base + chip->ngpio <= next->base) { + /* add before first entry */ + list_add(&chip->list, &gpio_chips); + return 0; } - /* - * We are beyond the last chip in the list and iterator now - * points to the head. - * Let iterator point to the last chip in the list. - */ + prev = list_entry(gpio_chips.prev, struct gpio_chip, list); + if (prev->base + prev->ngpio <= chip->base) { + /* add behind last entry */ + list_add_tail(&chip->list, &gpio_chips); + return 0; + } - iterator = list_last_entry(&gpio_chips, struct gpio_chip, list); - if (iterator->base + iterator->ngpio <= chip->base) - goto found; + list_for_each_entry_safe(prev, next, &gpio_chips, list) { + /* at the end of the list */ + if (&(next->list) == &gpio_chips) + break; - dev_err(chip->parent, - "GPIO integer space overlap, cannot add chip\n"); - return -EBUSY; + /* add between prev and next */ + if ( prev->base + prev->ngpio <= chip->base + && chip->base + chip->ngpio <= next->base) { + list_add(&chip->list, &prev->list); + return 0; + } + } -found: - list_add_tail(&chip->list, &iterator->list); - return 0; + dev_err(chip->parent, "GPIO integer space overlap, cannot add chip\n"); + return -EBUSY; } + /** * Convert a GPIO name to its descriptor */ -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html