From 7dd3d9bd873f138675cb727eaa51a498d99f0e89 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Thu, 4 May 2023 08:04:21 +0200 Subject: gpiolib: fix allocation of mixed dynamic/static GPIOs If static allocation and dynamic allocation GPIOs are present, dynamic allocation pollutes the numberspace for static allocation, causing static allocation to fail. Enforce dynamic allocation above GPIO_DYNAMIC_BASE. Seen on a GTA04 when omap-gpio (static) and twl-gpio (dynamic) raced: [some successful registrations of omap_gpio instances] [ 2.553833] twl4030_gpio twl4030-gpio: gpio (irq 145) chaining IRQs 161..178 [ 2.561401] gpiochip_find_base: found new base at 160 [ 2.564392] gpio gpiochip5: (twl4030): added GPIO chardev (254:5) [ 2.564544] gpio gpiochip5: registered GPIOs 160 to 177 on twl4030 [...] [ 2.692169] omap-gpmc 6e000000.gpmc: GPMC revision 5.0 [ 2.697357] gpmc_mem_init: disabling cs 0 mapped at 0x0-0x1000000 [ 2.703643] gpiochip_find_base: found new base at 178 [ 2.704376] gpio gpiochip6: (omap-gpmc): added GPIO chardev (254:6) [ 2.704589] gpio gpiochip6: registered GPIOs 178 to 181 on omap-gpmc [...] [ 2.840393] gpio gpiochip7: Static allocation of GPIO base is deprecated, use dynamic allocation. [ 2.849365] gpio gpiochip7: (gpio-160-191): GPIO integer space overlap, cannot add chip [ 2.857513] gpiochip_add_data_with_key: GPIOs 160..191 (gpio-160-191) failed to register, -16 [ 2.866149] omap_gpio 48310000.gpio: error -EBUSY: Could not register gpio chip On that device it is fixed invasively by commit 92bf78b33b0b4 ("gpio: omap: use dynamic allocation of base") but let's also fix that for devices where there is still a mixture of static and dynamic allocation. Fixes: 7b61212f2a07 ("gpiolib: Get rid of ARCH_NR_GPIOS") Signed-off-by: Andreas Kemnade Reviewed-by: Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 04fb05df805b..a7220e04a93e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -209,6 +209,8 @@ static int gpiochip_find_base(int ngpio) break; /* nope, check the space right after the chip */ base = gdev->base + gdev->ngpio; + if (base < GPIO_DYNAMIC_BASE) + base = GPIO_DYNAMIC_BASE; } if (gpio_is_valid(base)) { -- cgit v1.2.3 From 05a854c565d635710bb50e19c89df87e6df971ad Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 27 May 2023 14:40:56 +0300 Subject: gpiolib: Consolidate the allocated mask freeing APIs There is a common API to allocate a mask, but more than one duplicative counterparts. Consolidate the latter into a single common API beneath. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 04fb05df805b..995a468b7a24 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -463,6 +463,12 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *gc) return p; } +static void gpiochip_free_mask(unsigned long **p) +{ + bitmap_free(*p); + *p = NULL; +} + static unsigned int gpiochip_count_reserved_ranges(struct gpio_chip *gc) { struct device *dev = &gc->gpiodev->dev; @@ -542,8 +548,7 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) static void gpiochip_free_valid_mask(struct gpio_chip *gc) { - bitmap_free(gc->valid_mask); - gc->valid_mask = NULL; + gpiochip_free_mask(&gc->valid_mask); } static int gpiochip_add_pin_ranges(struct gpio_chip *gc) @@ -1087,8 +1092,7 @@ static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gc) static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc) { - bitmap_free(gc->irq.valid_mask); - gc->irq.valid_mask = NULL; + gpiochip_free_mask(&gc->irq.valid_mask); } bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc, -- cgit v1.2.3 From 1a55fc4012d977de5f88fc7f07535783c9f8d86c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 27 May 2023 14:40:57 +0300 Subject: gpiolib: Unify allocation and initialization of GPIO valid mask Now that the of_gpiochip_add() doesn't use valid mask, we may unify GPIO valid mask allocation and initialization. With this it makes a symmetry to the similar which we done for IRQ chip. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 995a468b7a24..bb81d9427fbb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -482,18 +482,6 @@ static unsigned int gpiochip_count_reserved_ranges(struct gpio_chip *gc) return 0; } -static int gpiochip_alloc_valid_mask(struct gpio_chip *gc) -{ - if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask)) - return 0; - - gc->valid_mask = gpiochip_allocate_mask(gc); - if (!gc->valid_mask) - return -ENOMEM; - - return 0; -} - static int gpiochip_apply_reserved_ranges(struct gpio_chip *gc) { struct device *dev = &gc->gpiodev->dev; @@ -534,6 +522,13 @@ static int gpiochip_init_valid_mask(struct gpio_chip *gc) { int ret; + if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask)) + return 0; + + gc->valid_mask = gpiochip_allocate_mask(gc); + if (!gc->valid_mask) + return -ENOMEM; + ret = gpiochip_apply_reserved_ranges(gc); if (ret) return ret; @@ -860,7 +855,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, if (ret) goto err_remove_from_list; - ret = gpiochip_alloc_valid_mask(gc); + ret = gpiochip_init_valid_mask(gc); if (ret) goto err_remove_from_list; @@ -868,10 +863,6 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, if (ret) goto err_free_gpiochip_mask; - ret = gpiochip_init_valid_mask(gc); - if (ret) - goto err_remove_of_chip; - for (i = 0; i < gc->ngpio; i++) { struct gpio_desc *desc = &gdev->descs[i]; -- cgit v1.2.3 From be6736cc5423e9c153f38ca49ed9ba05a02a58f9 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 5 Jun 2023 14:52:48 +0200 Subject: gpiolib: demote the hogging log messages to debug Drivers should be silent when they work correctly. There's no reason to emit info messages when GPIO lines are hogged. Demote the message to debug. Signed-off-by: Bartosz Golaszewski Suggested-by: Kent Gibson Reviewed-by: Andy Shevchenko --- drivers/gpio/gpiolib.c | 2 +- drivers/of/unittest.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bb81d9427fbb..d5f23c2b3f30 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4236,7 +4236,7 @@ int gpiod_hog(struct gpio_desc *desc, const char *name, /* Mark GPIO as hogged so it can be identified and removed later */ set_bit(FLAG_IS_HOGGED, &desc->flags); - gpiod_info(desc, "hogged as %s%s\n", + gpiod_dbg(desc, "hogged as %s%s\n", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? "output" : "input", (dflags & GPIOD_FLAGS_BIT_DIR_OUT) ? (dflags & GPIOD_FLAGS_BIT_DIR_VAL) ? "/high" : "/low" : ""); diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 2191c0136531..0060334a98a7 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1849,19 +1849,19 @@ static void __init of_unittest_overlay_gpio(void) * driver is registered */ - EXPECT_BEGIN(KERN_INFO, + EXPECT_BEGIN(KERN_DEBUG, "gpio-<> (line-B-input): hogged as input\n"); - EXPECT_BEGIN(KERN_INFO, + EXPECT_BEGIN(KERN_DEBUG, "gpio-<> (line-A-input): hogged as input\n"); ret = platform_driver_register(&unittest_gpio_driver); if (unittest(ret == 0, "could not register unittest gpio driver\n")) return; - EXPECT_END(KERN_INFO, + EXPECT_END(KERN_DEBUG, "gpio-<> (line-A-input): hogged as input\n"); - EXPECT_END(KERN_INFO, + EXPECT_END(KERN_DEBUG, "gpio-<> (line-B-input): hogged as input\n"); unittest(probe_pass_count + 2 == unittest_gpio_probe_pass_count, @@ -1888,7 +1888,7 @@ static void __init of_unittest_overlay_gpio(void) probe_pass_count = unittest_gpio_probe_pass_count; chip_request_count = unittest_gpio_chip_request_count; - EXPECT_BEGIN(KERN_INFO, + EXPECT_BEGIN(KERN_DEBUG, "gpio-<> (line-D-input): hogged as input\n"); /* overlay_gpio_03 contains gpio node and child gpio hog node */ @@ -1896,7 +1896,7 @@ static void __init of_unittest_overlay_gpio(void) unittest(overlay_data_apply("overlay_gpio_03", NULL), "Adding overlay 'overlay_gpio_03' failed\n"); - EXPECT_END(KERN_INFO, + EXPECT_END(KERN_DEBUG, "gpio-<> (line-D-input): hogged as input\n"); unittest(probe_pass_count + 1 == unittest_gpio_probe_pass_count, @@ -1935,7 +1935,7 @@ static void __init of_unittest_overlay_gpio(void) * - processing gpio for overlay_gpio_04b */ - EXPECT_BEGIN(KERN_INFO, + EXPECT_BEGIN(KERN_DEBUG, "gpio-<> (line-C-input): hogged as input\n"); /* overlay_gpio_04b contains child gpio hog node */ @@ -1943,7 +1943,7 @@ static void __init of_unittest_overlay_gpio(void) unittest(overlay_data_apply("overlay_gpio_04b", NULL), "Adding overlay 'overlay_gpio_04b' failed\n"); - EXPECT_END(KERN_INFO, + EXPECT_END(KERN_DEBUG, "gpio-<> (line-C-input): hogged as input\n"); unittest(chip_request_count + 1 == unittest_gpio_chip_request_count, -- cgit v1.2.3 From b0ce9ce408b6cfbce6c720c7eb084e6d81a04434 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 5 Jun 2023 15:58:10 +0300 Subject: gpiolib: Do not unexport GPIO on freeing Since the legacy exporting is gone with 2f804aca4832 ("gpiolib: Kill unused GPIOF_EXPORT and Co") there is no need to unexport GPIO on freeing. Remove that call. Note, the other users of this functionality do that explicitly, except one SH and one OMAP boardfile which don't free GPIO anyways, so it is safe to drop the call. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d5f23c2b3f30..6e66e7e01992 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2117,8 +2117,6 @@ static bool gpiod_free_commit(struct gpio_desc *desc) might_sleep(); - gpiod_unexport(desc); - spin_lock_irqsave(&gpio_lock, flags); gc = desc->gdev->chip; -- cgit v1.2.3 From 8c00914e5438e3636f26b4f814b3297ae2a1b9ee Mon Sep 17 00:00:00 2001 From: Jiawen Wu Date: Wed, 7 Jun 2023 16:18:03 +0800 Subject: gpiolib: Fix GPIO chip IRQ initialization restriction In case of gpio-regmap, IRQ chip is added by regmap-irq and associated with GPIO chip by gpiochip_irqchip_add_domain(). The initialization flag was not added in gpiochip_irqchip_add_domain(), causing gpiochip_to_irq() to return -EPROBE_DEFER. Fixes: 5467801f1fcb ("gpio: Restrict usage of GPIO chip irq members before initialization") Signed-off-by: Jiawen Wu Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a7220e04a93e..9ecf93cbd801 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1792,6 +1792,14 @@ int gpiochip_irqchip_add_domain(struct gpio_chip *gc, gc->to_irq = gpiochip_to_irq; gc->irq.domain = domain; + /* + * Using barrier() here to prevent compiler from reordering + * gc->irq.initialized before adding irqdomain. + */ + barrier(); + + gc->irq.initialized = true; + return 0; } EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_domain); -- cgit v1.2.3 From ff7a1790fbf92f1bdd0966d3f0da3ea808ede876 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Mon, 19 Jun 2023 10:56:07 +0200 Subject: gpiolib: Fix irq_domain resource tracking for gpiochip_irqchip_add_domain() Up until commit 6a45b0e2589f ("gpiolib: Introduce gpiochip_irqchip_add_domain()") all irq_domains were allocated by gpiolib itself and thus gpiolib also takes care of freeing it. With gpiochip_irqchip_add_domain() a user of gpiolib can associate an irq_domain with the gpio_chip. This irq_domain is not managed by gpiolib and therefore must not be freed by gpiolib. Fixes: 6a45b0e2589f ("gpiolib: Introduce gpiochip_irqchip_add_domain()") Reported-by: Jiawen Wu Signed-off-by: Michael Walle Reviewed-by: Linus Walleij Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 3 ++- include/linux/gpio/driver.h | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9ecf93cbd801..5be8ad61523e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1745,7 +1745,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc) } /* Remove all IRQ mappings and delete the domain */ - if (gc->irq.domain) { + if (!gc->irq.domain_is_allocated_externally && gc->irq.domain) { unsigned int irq; for (offset = 0; offset < gc->ngpio; offset++) { @@ -1791,6 +1791,7 @@ int gpiochip_irqchip_add_domain(struct gpio_chip *gc, gc->to_irq = gpiochip_to_irq; gc->irq.domain = domain; + gc->irq.domain_is_allocated_externally = true; /* * Using barrier() here to prevent compiler from reordering diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 5c6db5533be6..67b8774eed8f 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -251,6 +251,14 @@ struct gpio_irq_chip { */ bool initialized; + /** + * @domain_is_allocated_externally: + * + * True it the irq_domain was allocated outside of gpiolib, in which + * case gpiolib won't free the irq_domain itself. + */ + bool domain_is_allocated_externally; + /** * @init_hw: optional routine to initialize hardware before * an IRQ chip will be added. This is quite useful when -- cgit v1.2.3 From a48b3f7be9c5e507ca07bd93d769798f4e5e68b1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 16 Jun 2023 16:53:13 +0300 Subject: gpiolib: Drop unused domain_ops memeber of GPIO IRQ chip It seems there is no driver that requires custom IRQ chip domain options. Drop the member and respective code. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Acked-by: Marc Zyngier Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 3 +-- include/linux/gpio/driver.h | 7 ------- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 6e66e7e01992..5fd518658501 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1669,11 +1669,10 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc, if (ret) return ret; } else { - /* Some drivers provide custom irqdomain ops */ gc->irq.domain = irq_domain_create_simple(fwnode, gc->ngpio, gc->irq.first, - gc->irq.domain_ops ?: &gpiochip_domain_ops, + &gpiochip_domain_ops, gc); if (!gc->irq.domain) return -EINVAL; diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 5c6db5533be6..6879b5436480 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -61,13 +61,6 @@ struct gpio_irq_chip { */ struct irq_domain *domain; - /** - * @domain_ops: - * - * Table of interrupt domain operations for this IRQ chip. - */ - const struct irq_domain_ops *domain_ops; - #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY /** * @fwnode: -- cgit v1.2.3