]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
power: supply: charger-manager: fix race-condition in sysfs registration
authorSebastian Reichel <sebastian.reichel@collabora.com>
Fri, 28 Sep 2018 15:35:37 +0000 (17:35 +0200)
committerSebastian Reichel <sre@kernel.org>
Wed, 12 Dec 2018 23:16:20 +0000 (00:16 +0100)
This registers custom sysfs properties using the native functionality
of the power-supply framework, which cleans up the code a bit and
fixes a race-condition. Before this patch the sysfs attributes were
not properly registered to udev.

Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
drivers/power/supply/charger-manager.c
include/linux/power/charger-manager.h

index 2e579da5c0b99b00d39c28df156a0635e2a63f27..38be91f21cc433b6f4179aefa6cf5ce60f5b7b01 100644 (file)
@@ -1351,7 +1351,7 @@ static ssize_t charger_externally_control_store(struct device *dev,
 }
 
 /**
- * charger_manager_register_sysfs - Register sysfs entry for each charger
+ * charger_manager_prepare_sysfs - Prepare sysfs entry for each charger
  * @cm: the Charger Manager representing the battery.
  *
  * This function add sysfs entry for charger(regulator) to control charger from
@@ -1363,13 +1363,12 @@ static ssize_t charger_externally_control_store(struct device *dev,
  * externally_control, this charger isn't controlled from charger-manager and
  * always stay off state of regulator.
  */
-static int charger_manager_register_sysfs(struct charger_manager *cm)
+static int charger_manager_prepare_sysfs(struct charger_manager *cm)
 {
        struct charger_desc *desc = cm->desc;
        struct charger_regulator *charger;
        int chargers_externally_control = 1;
        char *name;
-       int ret;
        int i;
 
        /* Create sysfs entry to control charger(regulator) */
@@ -1384,8 +1383,10 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
                charger->attrs[1] = &charger->attr_state.attr;
                charger->attrs[2] = &charger->attr_externally_control.attr;
                charger->attrs[3] = NULL;
-               charger->attr_g.name = name;
-               charger->attr_g.attrs = charger->attrs;
+
+               charger->attr_grp.name = name;
+               charger->attr_grp.attrs = charger->attrs;
+               desc->sysfs_groups[i] = &charger->attr_grp;
 
                sysfs_attr_init(&charger->attr_name.attr);
                charger->attr_name.attr.name = "name";
@@ -1412,14 +1413,6 @@ static int charger_manager_register_sysfs(struct charger_manager *cm)
 
                dev_info(cm->dev, "'%s' regulator's externally_control is %d\n",
                         charger->regulator_name, charger->externally_control);
-
-               ret = sysfs_create_group(&cm->charger_psy->dev.kobj,
-                                       &charger->attr_g);
-               if (ret < 0) {
-                       dev_err(cm->dev, "Cannot create sysfs entry of %s regulator\n",
-                               charger->regulator_name);
-                       return ret;
-               }
        }
 
        if (chargers_externally_control) {
@@ -1560,6 +1553,13 @@ static struct charger_desc *of_cm_parse_desc(struct device *dev)
 
                desc->charger_regulators = chg_regs;
 
+               desc->sysfs_groups = devm_kcalloc(dev,
+                                       desc->num_charger_regulators + 1,
+                                       sizeof(*desc->sysfs_groups),
+                                       GFP_KERNEL);
+               if (!desc->sysfs_groups)
+                       return ERR_PTR(-ENOMEM);
+
                for_each_child_of_node(np, child) {
                        struct charger_cable *cables;
                        struct device_node *_child;
@@ -1762,6 +1762,15 @@ static int charger_manager_probe(struct platform_device *pdev)
 
        INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk);
 
+       /* Register sysfs entry for charger(regulator) */
+       ret = charger_manager_prepare_sysfs(cm);
+       if (ret < 0) {
+               dev_err(&pdev->dev,
+                       "Cannot prepare sysfs entry of regulators\n");
+               return ret;
+       }
+       psy_cfg.attr_grp = desc->sysfs_groups;
+
        cm->charger_psy = power_supply_register(&pdev->dev,
                                                &cm->charger_psy_desc,
                                                &psy_cfg);
@@ -1778,14 +1787,6 @@ static int charger_manager_probe(struct platform_device *pdev)
                goto err_reg_extcon;
        }
 
-       /* Register sysfs entry for charger(regulator) */
-       ret = charger_manager_register_sysfs(cm);
-       if (ret < 0) {
-               dev_err(&pdev->dev,
-                       "Cannot initialize sysfs entry of regulator\n");
-               goto err_reg_sysfs;
-       }
-
        /* Add to the list */
        mutex_lock(&cm_list_mtx);
        list_add(&cm->entry, &cm_list);
@@ -1809,14 +1810,6 @@ static int charger_manager_probe(struct platform_device *pdev)
 
        return 0;
 
-err_reg_sysfs:
-       for (i = 0; i < desc->num_charger_regulators; i++) {
-               struct charger_regulator *charger;
-
-               charger = &desc->charger_regulators[i];
-               sysfs_remove_group(&cm->charger_psy->dev.kobj,
-                               &charger->attr_g);
-       }
 err_reg_extcon:
        for (i = 0; i < desc->num_charger_regulators; i++) {
                struct charger_regulator *charger;
index c4fa907c8f148abb08657827850fdc093110dd43..2ce8d00c20dea251737233c17fedcdcd8ad22e4c 100644 (file)
@@ -119,7 +119,7 @@ struct charger_regulator {
        struct charger_cable *cables;
        int num_cables;
 
-       struct attribute_group attr_g;
+       struct attribute_group attr_grp;
        struct device_attribute attr_name;
        struct device_attribute attr_state;
        struct device_attribute attr_externally_control;
@@ -186,6 +186,7 @@ struct charger_desc {
 
        int num_charger_regulators;
        struct charger_regulator *charger_regulators;
+       const struct attribute_group **sysfs_groups;
 
        const char *psy_fuel_gauge;