clk: Combine __clk_get() and __clk_create_clk()

The __clk_get() function is practically a private clk implementation
detail now. No architecture defines it, and given that new code should
be using the common clk framework there isn't a need for it to keep
existing just to serve clkdev purposes. Let's fold it into the
__clk_create_clk() function and make that a little more generic by
renaming it to clk_hw_create_clk(). This will allow the framework to
create a struct clk handle to a particular clk_hw pointer and link it up
as a consumer wherever that's needed.

Doing this also lets us get rid of the __clk_free_clk() API that had to
be kept in sync with __clk_put(). Splitting that API up into the "link
and unlink from consumer list" phase and "free the clk pointer" phase
allows us to reuse that logic in a couple places, simplifying the code.

Cc: Miquel Raynal <miquel.raynal@bootlin.com>
Cc: Jerome Brunet <jbrunet@baylibre.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Jeffrey Hugo <jhugo@codeaurora.org>
Cc: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
This commit is contained in:
Stephen Boyd 2018-12-11 08:32:04 -08:00
parent d13937116f
commit 1df4046a93
3 changed files with 98 additions and 61 deletions

View File

@ -3209,42 +3209,103 @@ unlock:
return ret;
}
struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
/**
* clk_core_link_consumer - Add a clk consumer to the list of consumers in a clk_core
* @core: clk to add consumer to
* @clk: consumer to link to a clk
*/
static void clk_core_link_consumer(struct clk_core *core, struct clk *clk)
{
clk_prepare_lock();
hlist_add_head(&clk->clks_node, &core->clks);
clk_prepare_unlock();
}
/**
* clk_core_unlink_consumer - Remove a clk consumer from the list of consumers in a clk_core
* @clk: consumer to unlink
*/
static void clk_core_unlink_consumer(struct clk *clk)
{
lockdep_assert_held(&prepare_lock);
hlist_del(&clk->clks_node);
}
/**
* alloc_clk - Allocate a clk consumer, but leave it unlinked to the clk_core
* @core: clk to allocate a consumer for
* @dev_id: string describing device name
* @con_id: connection ID string on device
*
* Returns: clk consumer left unlinked from the consumer list
*/
static struct clk *alloc_clk(struct clk_core *core, const char *dev_id,
const char *con_id)
{
struct clk *clk;
/* This is to allow this function to be chained to others */
if (IS_ERR_OR_NULL(hw))
return ERR_CAST(hw);
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk)
return ERR_PTR(-ENOMEM);
clk->core = hw->core;
clk->core = core;
clk->dev_id = dev_id;
clk->con_id = kstrdup_const(con_id, GFP_KERNEL);
clk->max_rate = ULONG_MAX;
clk_prepare_lock();
hlist_add_head(&clk->clks_node, &hw->core->clks);
clk_prepare_unlock();
return clk;
}
/* keep in sync with __clk_put */
void __clk_free_clk(struct clk *clk)
/**
* free_clk - Free a clk consumer
* @clk: clk consumer to free
*
* Note, this assumes the clk has been unlinked from the clk_core consumer
* list.
*/
static void free_clk(struct clk *clk)
{
clk_prepare_lock();
hlist_del(&clk->clks_node);
clk_prepare_unlock();
kfree_const(clk->con_id);
kfree(clk);
}
/**
* clk_hw_create_clk: Allocate and link a clk consumer to a clk_core given
* a clk_hw
* @hw: clk_hw associated with the clk being consumed
* @dev_id: string describing device name
* @con_id: connection ID string on device
*
* This is the main function used to create a clk pointer for use by clk
* consumers. It connects a consumer to the clk_core and clk_hw structures
* used by the framework and clk provider respectively.
*/
struct clk *clk_hw_create_clk(struct clk_hw *hw,
const char *dev_id, const char *con_id)
{
struct clk *clk;
struct clk_core *core;
/* This is to allow this function to be chained to others */
if (IS_ERR_OR_NULL(hw))
return ERR_CAST(hw);
core = hw->core;
clk = alloc_clk(core, dev_id, con_id);
if (IS_ERR(clk))
return clk;
if (!try_module_get(core->owner)) {
free_clk(clk);
return ERR_PTR(-ENOENT);
}
kref_get(&core->ref);
clk_core_link_consumer(core, clk);
return clk;
}
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock
@ -3320,17 +3381,27 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
INIT_HLIST_HEAD(&core->clks);
hw->clk = __clk_create_clk(hw, NULL, NULL);
/*
* Don't call clk_hw_create_clk() here because that would pin the
* provider module to itself and prevent it from ever being removed.
*/
hw->clk = alloc_clk(core, NULL, NULL);
if (IS_ERR(hw->clk)) {
ret = PTR_ERR(hw->clk);
goto fail_parents;
}
clk_core_link_consumer(hw->core, hw->clk);
ret = __clk_core_init(core);
if (!ret)
return hw->clk;
__clk_free_clk(hw->clk);
clk_prepare_lock();
clk_core_unlink_consumer(hw->clk);
clk_prepare_unlock();
free_clk(hw->clk);
hw->clk = NULL;
fail_parents:
@ -3601,20 +3672,7 @@ EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
/*
* clkdev helpers
*/
int __clk_get(struct clk *clk)
{
struct clk_core *core = !clk ? NULL : clk->core;
if (core) {
if (!try_module_get(core->owner))
return 0;
kref_get(&core->ref);
}
return 1;
}
/* keep in sync with __clk_free_clk */
void __clk_put(struct clk *clk)
{
struct module *owner;
@ -3648,8 +3706,7 @@ void __clk_put(struct clk *clk)
module_put(owner);
kfree_const(clk->con_id);
kfree(clk);
free_clk(clk);
}
/*** clk rate change notifiers ***/
@ -4025,8 +4082,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
const char *dev_id, const char *con_id)
{
struct of_clk_provider *provider;
struct clk *clk = ERR_PTR(-EPROBE_DEFER);
struct clk_hw *hw;
struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
if (!clkspec)
return ERR_PTR(-EINVAL);
@ -4036,21 +4092,13 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == clkspec->np) {
hw = __of_clk_get_hw_from_provider(provider, clkspec);
clk = __clk_create_clk(hw, dev_id, con_id);
}
if (!IS_ERR(clk)) {
if (!__clk_get(clk)) {
__clk_free_clk(clk);
clk = ERR_PTR(-ENOENT);
}
break;
if (!IS_ERR(hw))
break;
}
}
mutex_unlock(&of_clk_mutex);
return clk;
return clk_hw_create_clk(hw, dev_id, con_id);
}
/**

View File

@ -12,24 +12,20 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
#endif
#ifdef CONFIG_COMMON_CLK
struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
const char *con_id);
void __clk_free_clk(struct clk *clk);
int __clk_get(struct clk *clk);
struct clk *clk_hw_create_clk(struct clk_hw *hw,
const char *dev_id, const char *con_id);
void __clk_put(struct clk *clk);
#else
/* All these casts to avoid ifdefs in clkdev... */
static inline struct clk *
__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id)
clk_hw_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id)
{
return (struct clk *)hw;
}
static inline void __clk_free_clk(struct clk *clk) { }
static struct clk_hw *__clk_get_hw(struct clk *clk)
{
return (struct clk_hw *)clk;
}
static inline int __clk_get(struct clk *clk) { return 1; }
static inline void __clk_put(struct clk *clk) { }
#endif

View File

@ -174,16 +174,9 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id)
if (!cl)
goto out;
clk = __clk_create_clk(cl->clk_hw, dev_id, con_id);
clk = clk_hw_create_clk(cl->clk_hw, dev_id, con_id);
if (IS_ERR(clk))
goto out;
if (!__clk_get(clk)) {
__clk_free_clk(clk);
cl = NULL;
goto out;
}
out:
mutex_unlock(&clocks_mutex);