opp: Don't decrement uninitialized list_kref
The list_kref was added for static OPPs and to track their users. The
kref is initialized while the static OPPs are added, but removed
unconditionally even if the static OPPs were never added. This causes
refcount mismatch warnings currently.
Fix that by always initializing the kref when the OPP table is first
initialized. The refcount is later incremented only for the second user
onwards.
Fixes: d0e8ae6c26
("OPP: Create separate kref for static OPPs list")
Reported-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
This commit is contained in:
Родитель
71419d84c2
Коммит
11e1a16482
|
@ -988,6 +988,7 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
|
||||||
BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
|
BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
|
||||||
INIT_LIST_HEAD(&opp_table->opp_list);
|
INIT_LIST_HEAD(&opp_table->opp_list);
|
||||||
kref_init(&opp_table->kref);
|
kref_init(&opp_table->kref);
|
||||||
|
kref_init(&opp_table->list_kref);
|
||||||
|
|
||||||
/* Secure the device table modification */
|
/* Secure the device table modification */
|
||||||
list_add(&opp_table->node, &opp_tables);
|
list_add(&opp_table->node, &opp_tables);
|
||||||
|
|
|
@ -662,8 +662,6 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
kref_init(&opp_table->list_kref);
|
|
||||||
|
|
||||||
/* We have opp-table node now, iterate over it and add OPPs */
|
/* We have opp-table node now, iterate over it and add OPPs */
|
||||||
for_each_available_child_of_node(opp_table->np, np) {
|
for_each_available_child_of_node(opp_table->np, np) {
|
||||||
opp = _opp_add_static_v2(opp_table, dev, np);
|
opp = _opp_add_static_v2(opp_table, dev, np);
|
||||||
|
@ -672,17 +670,15 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
|
||||||
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
|
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
|
||||||
ret);
|
ret);
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
goto put_list_kref;
|
return ret;
|
||||||
} else if (opp) {
|
} else if (opp) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There should be one of more OPP defined */
|
/* There should be one of more OPP defined */
|
||||||
if (WARN_ON(!count)) {
|
if (WARN_ON(!count))
|
||||||
ret = -ENOENT;
|
return -ENOENT;
|
||||||
goto put_list_kref;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(opp, &opp_table->opp_list, node)
|
list_for_each_entry(opp, &opp_table->opp_list, node)
|
||||||
pstate_count += !!opp->pstate;
|
pstate_count += !!opp->pstate;
|
||||||
|
@ -691,8 +687,7 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
|
||||||
if (pstate_count && pstate_count != count) {
|
if (pstate_count && pstate_count != count) {
|
||||||
dev_err(dev, "Not all nodes have performance state set (%d: %d)\n",
|
dev_err(dev, "Not all nodes have performance state set (%d: %d)\n",
|
||||||
count, pstate_count);
|
count, pstate_count);
|
||||||
ret = -ENOENT;
|
return -ENOENT;
|
||||||
goto put_list_kref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pstate_count)
|
if (pstate_count)
|
||||||
|
@ -701,11 +696,6 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
|
||||||
opp_table->parsed_static_opps = true;
|
opp_table->parsed_static_opps = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
put_list_kref:
|
|
||||||
_put_opp_list_kref(opp_table);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initializes OPP tables based on old-deprecated bindings */
|
/* Initializes OPP tables based on old-deprecated bindings */
|
||||||
|
@ -731,8 +721,6 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
kref_init(&opp_table->list_kref);
|
|
||||||
|
|
||||||
val = prop->value;
|
val = prop->value;
|
||||||
while (nr) {
|
while (nr) {
|
||||||
unsigned long freq = be32_to_cpup(val++) * 1000;
|
unsigned long freq = be32_to_cpup(val++) * 1000;
|
||||||
|
@ -742,7 +730,6 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
|
dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
|
||||||
__func__, freq, ret);
|
__func__, freq, ret);
|
||||||
_put_opp_list_kref(opp_table);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
nr -= 2;
|
nr -= 2;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче