Skip to content

Commit fcb0ee6

Browse files
author
Sylwester Nawrocki
committed
clk: Implement clk_unregister
clk_unregister() is currently not implemented and it is required when a clock provider module needs to be unloaded. Normally the clock supplier module is prevented to be unloaded by taking reference on the module in clk_get(). For cases when the clock supplier module deinitializes despite the consumers of its clocks holding a reference on the module, e.g. when the driver is unbound through "unbind" sysfs attribute, there are empty clock ops added. These ops are assigned temporarily to struct clk and used until all consumers release the clock, to avoid invoking callbacks from the module which just got removed. Signed-off-by: Jiada Wang <[email protected]> Signed-off-by: Sylwester Nawrocki <[email protected]> Signed-off-by: Kyungmin Park <[email protected]>
1 parent ac2df52 commit fcb0ee6

File tree

2 files changed

+120
-3
lines changed

2 files changed

+120
-3
lines changed

drivers/clk/clk.c

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,21 @@ static int clk_debug_register(struct clk *clk)
345345
return ret;
346346
}
347347

348+
/**
349+
* clk_debug_unregister - remove a clk node from the debugfs clk tree
350+
* @clk: the clk being removed from the debugfs clk tree
351+
*
352+
* Dynamically removes a clk and all it's children clk nodes from the
353+
* debugfs clk tree if clk->dentry points to debugfs created by
354+
* clk_debug_register in __clk_init.
355+
*
356+
* Caller must hold prepare_lock.
357+
*/
358+
static void clk_debug_unregister(struct clk *clk)
359+
{
360+
debugfs_remove_recursive(clk->dentry);
361+
}
362+
348363
/**
349364
* clk_debug_reparent - reparent clk node in the debugfs clk tree
350365
* @clk: the clk being reparented
@@ -435,6 +450,9 @@ static inline int clk_debug_register(struct clk *clk) { return 0; }
435450
static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
436451
{
437452
}
453+
static inline void clk_debug_unregister(struct clk *clk)
454+
{
455+
}
438456
#endif
439457

440458
/* caller must hold prepare_lock */
@@ -1778,6 +1796,7 @@ int __clk_init(struct device *dev, struct clk *clk)
17781796

17791797
clk_debug_register(clk);
17801798

1799+
kref_init(&clk->ref);
17811800
out:
17821801
clk_prepare_unlock();
17831802

@@ -1913,13 +1932,104 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
19131932
}
19141933
EXPORT_SYMBOL_GPL(clk_register);
19151934

1935+
/*
1936+
* Free memory allocated for a clock.
1937+
* Caller must hold prepare_lock.
1938+
*/
1939+
static void __clk_release(struct kref *ref)
1940+
{
1941+
struct clk *clk = container_of(ref, struct clk, ref);
1942+
int i = clk->num_parents;
1943+
1944+
kfree(clk->parents);
1945+
while (--i >= 0)
1946+
kfree(clk->parent_names[i]);
1947+
1948+
kfree(clk->parent_names);
1949+
kfree(clk->name);
1950+
kfree(clk);
1951+
}
1952+
1953+
/*
1954+
* Empty clk_ops for unregistered clocks. These are used temporarily
1955+
* after clk_unregister() was called on a clock and until last clock
1956+
* consumer calls clk_put() and the struct clk object is freed.
1957+
*/
1958+
static int clk_nodrv_prepare_enable(struct clk_hw *hw)
1959+
{
1960+
return -ENXIO;
1961+
}
1962+
1963+
static void clk_nodrv_disable_unprepare(struct clk_hw *hw)
1964+
{
1965+
WARN_ON_ONCE(1);
1966+
}
1967+
1968+
static int clk_nodrv_set_rate(struct clk_hw *hw, unsigned long rate,
1969+
unsigned long parent_rate)
1970+
{
1971+
return -ENXIO;
1972+
}
1973+
1974+
static int clk_nodrv_set_parent(struct clk_hw *hw, u8 index)
1975+
{
1976+
return -ENXIO;
1977+
}
1978+
1979+
static const struct clk_ops clk_nodrv_ops = {
1980+
.enable = clk_nodrv_prepare_enable,
1981+
.disable = clk_nodrv_disable_unprepare,
1982+
.prepare = clk_nodrv_prepare_enable,
1983+
.unprepare = clk_nodrv_disable_unprepare,
1984+
.set_rate = clk_nodrv_set_rate,
1985+
.set_parent = clk_nodrv_set_parent,
1986+
};
1987+
19161988
/**
19171989
* clk_unregister - unregister a currently registered clock
19181990
* @clk: clock to unregister
1919-
*
1920-
* Currently unimplemented.
19211991
*/
1922-
void clk_unregister(struct clk *clk) {}
1992+
void clk_unregister(struct clk *clk)
1993+
{
1994+
unsigned long flags;
1995+
1996+
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
1997+
return;
1998+
1999+
clk_prepare_lock();
2000+
2001+
if (clk->ops == &clk_nodrv_ops) {
2002+
pr_err("%s: unregistered clock: %s\n", __func__, clk->name);
2003+
goto out;
2004+
}
2005+
/*
2006+
* Assign empty clock ops for consumers that might still hold
2007+
* a reference to this clock.
2008+
*/
2009+
flags = clk_enable_lock();
2010+
clk->ops = &clk_nodrv_ops;
2011+
clk_enable_unlock(flags);
2012+
2013+
if (!hlist_empty(&clk->children)) {
2014+
struct clk *child;
2015+
2016+
/* Reparent all children to the orphan list. */
2017+
hlist_for_each_entry(child, &clk->children, child_node)
2018+
clk_set_parent(child, NULL);
2019+
}
2020+
2021+
clk_debug_unregister(clk);
2022+
2023+
hlist_del_init(&clk->child_node);
2024+
2025+
if (clk->prepare_count)
2026+
pr_warn("%s: unregistering prepared clock: %s\n",
2027+
__func__, clk->name);
2028+
2029+
kref_put(&clk->ref, __clk_release);
2030+
out:
2031+
clk_prepare_unlock();
2032+
}
19232033
EXPORT_SYMBOL_GPL(clk_unregister);
19242034

19252035
static void devm_clk_release(struct device *dev, void *res)
@@ -1987,6 +2097,7 @@ int __clk_get(struct clk *clk)
19872097
if (clk && !try_module_get(clk->owner))
19882098
return 0;
19892099

2100+
kref_get(&clk->ref);
19902101
return 1;
19912102
}
19922103

@@ -1995,6 +2106,10 @@ void __clk_put(struct clk *clk)
19952106
if (WARN_ON_ONCE(IS_ERR(clk)))
19962107
return;
19972108

2109+
clk_prepare_lock();
2110+
kref_put(&clk->ref, __clk_release);
2111+
clk_prepare_unlock();
2112+
19982113
if (clk)
19992114
module_put(clk->owner);
20002115
}

include/linux/clk-private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define __LINUX_CLK_PRIVATE_H
1313

1414
#include <linux/clk-provider.h>
15+
#include <linux/kref.h>
1516
#include <linux/list.h>
1617

1718
/*
@@ -50,6 +51,7 @@ struct clk {
5051
#ifdef CONFIG_COMMON_CLK_DEBUG
5152
struct dentry *dentry;
5253
#endif
54+
struct kref ref;
5355
};
5456

5557
/*

0 commit comments

Comments
 (0)