Skip to content

Commit

Permalink
opp: Defer acquiring the clk until OPPs are added
Browse files Browse the repository at this point in the history
We acquire the clk at the time the OPP table is allocated, though it
works fine, it is not the best place to do so. One of the main reason
being we may need to acquire it again from dev_pm_opp_set_clkname() if
the platform wants another clock to be acquired instead.

There is also requirement from some of the platforms where they do not
want the OPP core to manage the clock at all.

This patch hence defers acquiring the clk until the time we are certain
about which clk we need to acquire and if we really need to acquire one.
With this commit, the clk will get acquired either from
dev_pm_opp_set_clkname() or while we initialize the OPPs within the
table.

Signed-off-by: Viresh Kumar <[email protected]>
Tested-by: Dmitry Osipenko <[email protected]>
  • Loading branch information
vireshk committed Feb 2, 2021
1 parent 406e476 commit 32439ac
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 33 deletions.
73 changes: 45 additions & 28 deletions drivers/opp/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,21 +1158,11 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)

_of_init_opp_table(opp_table, dev, index);

/* Find clk for the device */
opp_table->clk = clk_get(dev, NULL);
if (IS_ERR(opp_table->clk)) {
ret = PTR_ERR(opp_table->clk);
if (ret == -EPROBE_DEFER)
goto remove_opp_dev;

dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
}

/* Find interconnect path(s) for the device */
ret = dev_pm_opp_of_find_icc_paths(dev, opp_table);
if (ret) {
if (ret == -EPROBE_DEFER)
goto put_clk;
goto remove_opp_dev;

dev_warn(dev, "%s: Error finding interconnect paths: %d\n",
__func__, ret);
Expand All @@ -1184,9 +1174,6 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)

return opp_table;

put_clk:
if (!IS_ERR(opp_table->clk))
clk_put(opp_table->clk);
remove_opp_dev:
_remove_opp_dev(opp_dev, opp_table);
err:
Expand All @@ -1199,6 +1186,33 @@ void _get_opp_table_kref(struct opp_table *opp_table)
kref_get(&opp_table->kref);
}

static struct opp_table *_update_opp_table_clk(struct device *dev,
struct opp_table *opp_table,
bool getclk)
{
/*
* Return early if we don't need to get clk or we have already tried it
* earlier.
*/
if (!getclk || IS_ERR(opp_table) || opp_table->clk)
return opp_table;

/* Find clk for the device */
opp_table->clk = clk_get(dev, NULL);
if (IS_ERR(opp_table->clk)) {
int ret = PTR_ERR(opp_table->clk);

if (ret == -EPROBE_DEFER) {
dev_pm_opp_put_opp_table(opp_table);
return ERR_PTR(ret);
}

dev_dbg(dev, "%s: Couldn't find clock: %d\n", __func__, ret);
}

return opp_table;
}

/*
* We need to make sure that the OPP table for a device doesn't get added twice,
* if this routine gets called in parallel with the same device pointer.
Expand All @@ -1214,7 +1228,8 @@ void _get_opp_table_kref(struct opp_table *opp_table)
* uses the opp_tables_busy flag to indicate if another creator is in the middle
* of adding an OPP table and others should wait for it to finish.
*/
struct opp_table *_add_opp_table_indexed(struct device *dev, int index)
struct opp_table *_add_opp_table_indexed(struct device *dev, int index,
bool getclk)
{
struct opp_table *opp_table;

Expand Down Expand Up @@ -1261,12 +1276,12 @@ struct opp_table *_add_opp_table_indexed(struct device *dev, int index)
unlock:
mutex_unlock(&opp_table_lock);

return opp_table;
return _update_opp_table_clk(dev, opp_table, getclk);
}

static struct opp_table *_add_opp_table(struct device *dev)
static struct opp_table *_add_opp_table(struct device *dev, bool getclk)
{
return _add_opp_table_indexed(dev, 0);
return _add_opp_table_indexed(dev, 0, getclk);
}

struct opp_table *dev_pm_opp_get_opp_table(struct device *dev)
Expand Down Expand Up @@ -1711,7 +1726,7 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
{
struct opp_table *opp_table;

opp_table = _add_opp_table(dev);
opp_table = _add_opp_table(dev, false);
if (IS_ERR(opp_table))
return opp_table;

Expand Down Expand Up @@ -1773,7 +1788,7 @@ struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
{
struct opp_table *opp_table;

opp_table = _add_opp_table(dev);
opp_table = _add_opp_table(dev, false);
if (IS_ERR(opp_table))
return opp_table;

Expand Down Expand Up @@ -1869,7 +1884,7 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
struct regulator *reg;
int ret, i;

opp_table = _add_opp_table(dev);
opp_table = _add_opp_table(dev, false);
if (IS_ERR(opp_table))
return opp_table;

Expand Down Expand Up @@ -1980,7 +1995,7 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
struct opp_table *opp_table;
int ret;

opp_table = _add_opp_table(dev);
opp_table = _add_opp_table(dev, false);
if (IS_ERR(opp_table))
return opp_table;

Expand All @@ -1990,9 +2005,11 @@ struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
goto err;
}

/* Already have default clk set, free it */
if (!IS_ERR(opp_table->clk))
clk_put(opp_table->clk);
/* clk shouldn't be initialized at this point */
if (WARN_ON(opp_table->clk)) {
ret = -EBUSY;
goto err;
}

/* Find clk for the device */
opp_table->clk = clk_get(dev, name);
Expand Down Expand Up @@ -2051,7 +2068,7 @@ struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
if (!set_opp)
return ERR_PTR(-EINVAL);

opp_table = _add_opp_table(dev);
opp_table = _add_opp_table(dev, false);
if (IS_ERR(opp_table))
return opp_table;

Expand Down Expand Up @@ -2138,7 +2155,7 @@ struct opp_table *dev_pm_opp_attach_genpd(struct device *dev,
int index = 0, ret = -EINVAL;
const char **name = names;

opp_table = _add_opp_table(dev);
opp_table = _add_opp_table(dev, false);
if (IS_ERR(opp_table))
return opp_table;

Expand Down Expand Up @@ -2306,7 +2323,7 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
struct opp_table *opp_table;
int ret;

opp_table = _add_opp_table(dev);
opp_table = _add_opp_table(dev, true);
if (IS_ERR(opp_table))
return PTR_ERR(opp_table);

Expand Down
8 changes: 4 additions & 4 deletions drivers/opp/of.c
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
return ret;
}

static int _of_add_table_indexed(struct device *dev, int index)
static int _of_add_table_indexed(struct device *dev, int index, bool getclk)
{
struct opp_table *opp_table;
int ret, count;
Expand All @@ -972,7 +972,7 @@ static int _of_add_table_indexed(struct device *dev, int index)
index = 0;
}

opp_table = _add_opp_table_indexed(dev, index);
opp_table = _add_opp_table_indexed(dev, index, getclk);
if (IS_ERR(opp_table))
return PTR_ERR(opp_table);

Expand Down Expand Up @@ -1010,7 +1010,7 @@ static int _of_add_table_indexed(struct device *dev, int index)
*/
int dev_pm_opp_of_add_table(struct device *dev)
{
return _of_add_table_indexed(dev, 0);
return _of_add_table_indexed(dev, 0, true);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);

Expand All @@ -1026,7 +1026,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
*/
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
{
return _of_add_table_indexed(dev, index);
return _of_add_table_indexed(dev, index, true);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table_indexed);

Expand Down
2 changes: 1 addition & 1 deletion drivers/opp/opp.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ int _opp_compare_key(struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);
int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table, bool rate_not_available);
int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic);
void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);
struct opp_table *_add_opp_table_indexed(struct device *dev, int index);
struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);
void _put_opp_list_kref(struct opp_table *opp_table);

#ifdef CONFIG_OF
Expand Down

0 comments on commit 32439ac

Please sign in to comment.