]> Git Repo - J-linux.git/commitdiff
Merge tag 'regulator-fix-v5.9-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Fri, 11 Sep 2020 18:25:55 +0000 (11:25 -0700)
committerLinus Torvalds <[email protected]>
Fri, 11 Sep 2020 18:25:55 +0000 (11:25 -0700)
Pull regulator fixes from Mark Brown:
 "The biggest set of fixes here is those from Michał Mirosław fixing
  some locking issues with coupled regulators that are triggered in
  cases where a coupled regulator is used by a device involved in
  fs_reclaim like eMMC storage.

  These are relatively serious for the affected systems, though the
  circumstances where they trigger are very rare"

* tag 'regulator-fix-v5.9-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator:
  regulator: pwm: Fix machine constraints application
  regulator: core: Fix slab-out-of-bounds in regulator_unlock_recursive()
  regulator: remove superfluous lock in regulator_resolve_coupling()
  regulator: cleanup regulator_ena_gpio_free()
  regulator: plug of_node leak in regulator_register()'s error path
  regulator: push allocation in set_consumer_device_supply() out of lock
  regulator: push allocations in create_regulator() outside of lock
  regulator: push allocation in regulator_ena_gpio_request() out of lock
  regulator: push allocation in regulator_init_coupling() outside of lock
  regulator: fix spelling mistake "Cant" -> "Can't"
  regulator: cros-ec-regulator: Add NULL test for devm_kmemdup call

1  2 
drivers/regulator/core.c

diff --combined drivers/regulator/core.c
index 3fd359914690610f32e5f739936a6f63a0ef070d,0e764596b0c08d3da54d936d487950a0d467d243..7ff507ec875a85a8d904f30f947191091b1ccbfb
@@@ -236,8 -236,8 +236,8 @@@ static bool regulator_supply_is_couple(
  static void regulator_unlock_recursive(struct regulator_dev *rdev,
                                       unsigned int n_coupled)
  {
-       struct regulator_dev *c_rdev;
-       int i;
+       struct regulator_dev *c_rdev, *supply_rdev;
+       int i, supply_n_coupled;
  
        for (i = n_coupled; i > 0; i--) {
                c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1];
                if (!c_rdev)
                        continue;
  
-               if (c_rdev->supply && !regulator_supply_is_couple(c_rdev))
-                       regulator_unlock_recursive(
-                                       c_rdev->supply->rdev,
-                                       c_rdev->coupling_desc.n_coupled);
+               if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) {
+                       supply_rdev = c_rdev->supply->rdev;
+                       supply_n_coupled = supply_rdev->coupling_desc.n_coupled;
+                       regulator_unlock_recursive(supply_rdev,
+                                                  supply_n_coupled);
+               }
  
                regulator_unlock(c_rdev);
        }
@@@ -1461,7 -1464,7 +1464,7 @@@ static int set_consumer_device_supply(s
                                      const char *consumer_dev_name,
                                      const char *supply)
  {
-       struct regulator_map *node;
+       struct regulator_map *node, *new_node;
        int has_dev;
  
        if (supply == NULL)
        else
                has_dev = 0;
  
+       new_node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
+       if (new_node == NULL)
+               return -ENOMEM;
+       new_node->regulator = rdev;
+       new_node->supply = supply;
+       if (has_dev) {
+               new_node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
+               if (new_node->dev_name == NULL) {
+                       kfree(new_node);
+                       return -ENOMEM;
+               }
+       }
+       mutex_lock(&regulator_list_mutex);
        list_for_each_entry(node, &regulator_map_list, list) {
                if (node->dev_name && consumer_dev_name) {
                        if (strcmp(node->dev_name, consumer_dev_name) != 0)
                         node->regulator->desc->name,
                         supply,
                         dev_name(&rdev->dev), rdev_get_name(rdev));
-               return -EBUSY;
+               goto fail;
        }
  
-       node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL);
-       if (node == NULL)
-               return -ENOMEM;
-       node->regulator = rdev;
-       node->supply = supply;
-       if (has_dev) {
-               node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL);
-               if (node->dev_name == NULL) {
-                       kfree(node);
-                       return -ENOMEM;
-               }
-       }
+       list_add(&new_node->list, &regulator_map_list);
+       mutex_unlock(&regulator_list_mutex);
  
-       list_add(&node->list, &regulator_map_list);
        return 0;
+ fail:
+       mutex_unlock(&regulator_list_mutex);
+       kfree(new_node->dev_name);
+       kfree(new_node);
+       return -EBUSY;
  }
  
  static void unset_regulator_supplies(struct regulator_dev *rdev)
@@@ -1580,44 -1592,53 +1592,53 @@@ static struct regulator *create_regulat
                                          const char *supply_name)
  {
        struct regulator *regulator;
-       char buf[REG_STR_SIZE];
-       int err, size;
+       int err;
+       if (dev) {
+               char buf[REG_STR_SIZE];
+               int size;
+               size = snprintf(buf, REG_STR_SIZE, "%s-%s",
+                               dev->kobj.name, supply_name);
+               if (size >= REG_STR_SIZE)
+                       return NULL;
+               supply_name = kstrdup(buf, GFP_KERNEL);
+               if (supply_name == NULL)
+                       return NULL;
+       } else {
+               supply_name = kstrdup_const(supply_name, GFP_KERNEL);
+               if (supply_name == NULL)
+                       return NULL;
+       }
  
        regulator = kzalloc(sizeof(*regulator), GFP_KERNEL);
-       if (regulator == NULL)
+       if (regulator == NULL) {
+               kfree(supply_name);
                return NULL;
+       }
  
-       regulator_lock(rdev);
        regulator->rdev = rdev;
+       regulator->supply_name = supply_name;
+       regulator_lock(rdev);
        list_add(&regulator->list, &rdev->consumer_list);
+       regulator_unlock(rdev);
  
        if (dev) {
                regulator->dev = dev;
  
                /* Add a link to the device sysfs entry */
-               size = snprintf(buf, REG_STR_SIZE, "%s-%s",
-                               dev->kobj.name, supply_name);
-               if (size >= REG_STR_SIZE)
-                       goto overflow_err;
-               regulator->supply_name = kstrdup(buf, GFP_KERNEL);
-               if (regulator->supply_name == NULL)
-                       goto overflow_err;
                err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj,
-                                       buf);
+                                              supply_name);
                if (err) {
                        rdev_dbg(rdev, "could not add device link %s err %d\n",
                                  dev->kobj.name, err);
                        /* non-fatal */
                }
-       } else {
-               regulator->supply_name = kstrdup_const(supply_name, GFP_KERNEL);
-               if (regulator->supply_name == NULL)
-                       goto overflow_err;
        }
  
-       regulator->debugfs = debugfs_create_dir(regulator->supply_name,
+       regulator->debugfs = debugfs_create_dir(supply_name,
                                                rdev->debugfs);
        if (!regulator->debugfs) {
                rdev_dbg(rdev, "Failed to create debugfs directory\n");
            _regulator_is_enabled(rdev))
                regulator->always_on = true;
  
-       regulator_unlock(rdev);
        return regulator;
- overflow_err:
-       list_del(&regulator->list);
-       kfree(regulator);
-       regulator_unlock(rdev);
-       return NULL;
  }
  
  static int _regulator_get_enable_time(struct regulator_dev *rdev)
@@@ -1895,7 -1910,7 +1910,7 @@@ struct regulator *_regulator_get(struc
                case EXCLUSIVE_GET:
                        dev_warn(dev,
                                 "dummy supplies not allowed for exclusive requests\n");
 -                      /* fall through */
 +                      fallthrough;
  
                default:
                        return ERR_PTR(-ENODEV);
@@@ -2230,10 -2245,13 +2245,13 @@@ EXPORT_SYMBOL_GPL(regulator_bulk_unregi
  static int regulator_ena_gpio_request(struct regulator_dev *rdev,
                                const struct regulator_config *config)
  {
-       struct regulator_enable_gpio *pin;
+       struct regulator_enable_gpio *pin, *new_pin;
        struct gpio_desc *gpiod;
  
        gpiod = config->ena_gpiod;
+       new_pin = kzalloc(sizeof(*new_pin), GFP_KERNEL);
+       mutex_lock(&regulator_list_mutex);
  
        list_for_each_entry(pin, &regulator_ena_gpio_list, list) {
                if (pin->gpiod == gpiod) {
                }
        }
  
-       pin = kzalloc(sizeof(struct regulator_enable_gpio), GFP_KERNEL);
-       if (pin == NULL)
+       if (new_pin == NULL) {
+               mutex_unlock(&regulator_list_mutex);
                return -ENOMEM;
+       }
+       pin = new_pin;
+       new_pin = NULL;
  
        pin->gpiod = gpiod;
        list_add(&pin->list, &regulator_ena_gpio_list);
  update_ena_gpio_to_rdev:
        pin->request_count++;
        rdev->ena_pin = pin;
+       mutex_unlock(&regulator_list_mutex);
+       kfree(new_pin);
        return 0;
  }
  
@@@ -2264,19 -2290,19 +2290,19 @@@ static void regulator_ena_gpio_free(str
  
        /* Free the GPIO only in case of no use */
        list_for_each_entry_safe(pin, n, &regulator_ena_gpio_list, list) {
-               if (pin->gpiod == rdev->ena_pin->gpiod) {
-                       if (pin->request_count <= 1) {
-                               pin->request_count = 0;
-                               gpiod_put(pin->gpiod);
-                               list_del(&pin->list);
-                               kfree(pin);
-                               rdev->ena_pin = NULL;
-                               return;
-                       } else {
-                               pin->request_count--;
-                       }
-               }
+               if (pin != rdev->ena_pin)
+                       continue;
+               if (--pin->request_count)
+                       break;
+               gpiod_put(pin->gpiod);
+               list_del(&pin->list);
+               kfree(pin);
+               break;
        }
+       rdev->ena_pin = NULL;
  }
  
  /**
@@@ -4949,13 -4975,9 +4975,9 @@@ static void regulator_resolve_coupling(
                        return;
                }
  
-               regulator_lock(c_rdev);
                c_desc->coupled_rdevs[i] = c_rdev;
                c_desc->n_resolved++;
  
-               regulator_unlock(c_rdev);
                regulator_resolve_coupling(c_rdev);
        }
  }
@@@ -5040,7 -5062,10 +5062,10 @@@ static int regulator_init_coupling(stru
        if (!of_check_coupling_data(rdev))
                return -EPERM;
  
+       mutex_lock(&regulator_list_mutex);
        rdev->coupling_desc.coupler = regulator_find_coupler(rdev);
+       mutex_unlock(&regulator_list_mutex);
        if (IS_ERR(rdev->coupling_desc.coupler)) {
                err = PTR_ERR(rdev->coupling_desc.coupler);
                rdev_err(rdev, "failed to get coupler: %d\n", err);
@@@ -5141,6 -5166,7 +5166,7 @@@ regulator_register(const struct regulat
                ret = -ENOMEM;
                goto rinse;
        }
+       device_initialize(&rdev->dev);
  
        /*
         * Duplicate the config so the driver could override it after
         */
        config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL);
        if (config == NULL) {
-               kfree(rdev);
                ret = -ENOMEM;
-               goto rinse;
+               goto clean;
        }
  
        init_data = regulator_of_get_init_data(dev, regulator_desc, config,
         * from a gpio extender or something else.
         */
        if (PTR_ERR(init_data) == -EPROBE_DEFER) {
-               kfree(config);
-               kfree(rdev);
                ret = -EPROBE_DEFER;
-               goto rinse;
+               goto clean;
        }
  
        /*
        }
  
        if (config->ena_gpiod) {
-               mutex_lock(&regulator_list_mutex);
                ret = regulator_ena_gpio_request(rdev, config);
-               mutex_unlock(&regulator_list_mutex);
                if (ret != 0) {
                        rdev_err(rdev, "Failed to request enable GPIO: %d\n",
                                 ret);
        }
  
        /* register with sysfs */
-       device_initialize(&rdev->dev);
        rdev->dev.class = &regulator_class;
        rdev->dev.parent = dev;
        dev_set_name(&rdev->dev, "regulator.%lu",
        if (ret < 0)
                goto wash;
  
-       mutex_lock(&regulator_list_mutex);
        ret = regulator_init_coupling(rdev);
-       mutex_unlock(&regulator_list_mutex);
        if (ret < 0)
                goto wash;
  
        /* add consumers devices */
        if (init_data) {
-               mutex_lock(&regulator_list_mutex);
                for (i = 0; i < init_data->num_consumer_supplies; i++) {
                        ret = set_consumer_device_supply(rdev,
                                init_data->consumer_supplies[i].dev_name,
                                init_data->consumer_supplies[i].supply);
                        if (ret < 0) {
-                               mutex_unlock(&regulator_list_mutex);
                                dev_err(dev, "Failed to set supply %s\n",
                                        init_data->consumer_supplies[i].supply);
                                goto unset_supplies;
                        }
                }
-               mutex_unlock(&regulator_list_mutex);
        }
  
        if (!rdev->desc->ops->get_voltage &&
@@@ -5303,13 -5318,11 +5318,11 @@@ wash
        mutex_lock(&regulator_list_mutex);
        regulator_ena_gpio_free(rdev);
        mutex_unlock(&regulator_list_mutex);
-       put_device(&rdev->dev);
-       rdev = NULL;
  clean:
        if (dangling_of_gpiod)
                gpiod_put(config->ena_gpiod);
-       kfree(rdev);
        kfree(config);
+       put_device(&rdev->dev);
  rinse:
        if (dangling_cfg_gpiod)
                gpiod_put(cfg->ena_gpiod);
This page took 0.075074 seconds and 4 git commands to generate.