From: Lijun Fang fanglijun3@huawei.com
--- drivers/gpio/gpiolib.c | 45 +++++++++++++++++++++++++++++++++----- include/asm-generic/gpio.h | 13 +++++++++++ include/linux/kernel.h | 6 +++++ 3 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 00526fdd7691..12b005e24ae8 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -176,11 +176,34 @@ struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc) } EXPORT_SYMBOL_GPL(gpiod_to_chip);
+#ifdef CONFIG_ACPI +int ascend_resize_ngpio __read_mostly; + +static int __init ascend_enable_resize_ngpio(char *s) +{ + ascend_resize_ngpio = 1; + + pr_info("Ascend enable resize ngpio features\n"); + + return 1; +} + +__setup("enable_resize_ngpio", ascend_enable_resize_ngpio); +#endif + +static int set_gpio_base(int ngpio) +{ + if (ascend_resize_ngpio) + return RESIZE_NR_GPIOS - ngpio; + + return ARCH_NR_GPIOS - ngpio; +} + /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ static int gpiochip_find_base(int ngpio) { struct gpio_device *gdev; - int base = ARCH_NR_GPIOS - ngpio; + int base = set_gpio_base(ngpio);
list_for_each_entry_reverse(gdev, &gpio_devices, list) { /* found a free space? */ @@ -191,12 +214,22 @@ static int gpiochip_find_base(int ngpio) base = gdev->base - ngpio; }
- if (gpio_is_valid(base)) { - pr_debug("%s: found new base at %d\n", __func__, base); - return base; + if (ascend_resize_ngpio) { + if (resize_gpio_is_valid(base)) { + pr_debug("%s: found resize new base at %d\n", __func__, base); + return base; + } else { + pr_err("%s: cannot find resize free range\n", __func__); + return -ENOSPC; + } } else { - pr_err("%s: cannot find free range\n", __func__); - return -ENOSPC; + if (gpio_is_valid(base)) { + pr_debug("%s: found new base at %d\n", __func__, base); + return base; + } else { + pr_err("%s: cannot find free range\n", __func__); + return -ENOSPC; + } } }
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index aea9aee1f3e9..5a9319dfe917 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -32,6 +32,8 @@ #endif #endif
+#define RESIZE_NR_GPIOS 1024 + /* * "valid" GPIO numbers are nonnegative and may be passed to * setup routines like gpio_request(). only some valid numbers @@ -46,6 +48,11 @@ static inline bool gpio_is_valid(int number) return number >= 0 && number < ARCH_NR_GPIOS; }
+static inline bool resize_gpio_is_valid(int number) +{ + return number >= 0 && number < RESIZE_NR_GPIOS; +} + struct device; struct gpio; struct seq_file; @@ -146,6 +153,12 @@ static inline bool gpio_is_valid(int number) return number >= 0; }
+static inline bool resize_gpio_is_valid(int number) +{ + /* only non-negative numbers are valid */ + return number >= 0; +} + /* platforms that don't directly support access to GPIOs through I2C, SPI, * or other blocking infrastructure can use these wrappers. */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 78a0907f0b04..d2c4a87c012a 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -216,6 +216,12 @@ static __always_inline void might_resched(void)
#endif /* CONFIG_PREEMPT_* */
+#ifdef CONFIG_ACPI +extern int ascend_resize_ngpio; +#else +#define ascend_resize_ngpio 0 +#endif + #ifdef CONFIG_DEBUG_ATOMIC_SLEEP extern void ___might_sleep(const char *file, int line, int preempt_offset); extern void __might_sleep(const char *file, int line, int preempt_offset);