gpio_delay_probe() requests the real GPIOs it wraps via
gpio_request_by_name_nodev(), which strdup()s a label into the real
GPIO device's own uc_priv->name[] array. The driver had no .remove
hook, so those requests, and their strdup'd labels, were never
released when the gpio-delay device was torn down.

Add gpio_delay_remove() to free each wrapped real GPIO. Guard each
free with device_active() on the real GPIO's device: generic DM
teardown (e.g. dm_leak_check_end()'s uclass-by-uclass destroy) does
not guarantee a consumer is removed before the provider it wraps, so
the real GPIO device may already be inactive with its uclass_priv
freed by the time this runs.

Fixes: c866f2f197e2 ("gpio: Add GPIO delay driver")
Signed-off-by: Pranav Sanwal <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
---
 drivers/gpio/gpio-delay.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/gpio/gpio-delay.c b/drivers/gpio/gpio-delay.c
index f6c9c7efb0b..27fc59b5ee4 100644
--- a/drivers/gpio/gpio-delay.c
+++ b/drivers/gpio/gpio-delay.c
@@ -90,6 +90,33 @@ static int gpio_delay_xlate(struct udevice *dev, struct 
gpio_desc *desc,
        return 0;
 }
 
+static void gpio_delay_free_wrapped(struct udevice *dev, int count)
+{
+       struct gpio_delay_priv *priv = dev_get_priv(dev);
+       int i;
+
+       for (i = 0; i < count; i++) {
+               /*
+                * Generic DM teardown (e.g. dm_leak_check_end()'s
+                * uclass-by-uclass destroy) does not guarantee a consumer is
+                * removed before the provider it wraps, so the real GPIO
+                * device may already be inactive with its uclass_priv freed
+                * by the time this runs.
+                */
+               if (device_active(priv->descs[i].real_gpio.dev))
+                       dm_gpio_free(dev, &priv->descs[i].real_gpio);
+       }
+}
+
+static int gpio_delay_remove(struct udevice *dev)
+{
+       struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+       gpio_delay_free_wrapped(dev, uc_priv->gpio_count);
+
+       return 0;
+}
+
 static const struct dm_gpio_ops gpio_delay_ops = {
        .direction_output = gpio_delay_direction_output,
        .direction_input = gpio_delay_direction_input,
@@ -142,4 +169,5 @@ U_BOOT_DRIVER(gpio_delay) = {
        .ops = &gpio_delay_ops,
        .priv_auto = sizeof(struct gpio_delay_priv),
        .probe = gpio_delay_probe,
+       .remove = gpio_delay_remove,
 };
-- 
2.43.7

Reply via email to