Hi Jeremy,
bash-2.05b# /powerdebug -vcd
Clock Tree :
**********
/
|-- kpp_clk.clk <flags=0x0:rate=0:usecount=0>
|-- pll2_sw_clk.clk <flags=0x0:rate=665000000:usecount=0>
| |-- main_bus_clk.clk <flags=0x0:rate=665000000:usecount=0>
| | |-- ahb_clk.clk <flags=0x0:rate=133000000:usecount=0>
| |-- usboh3_clk.clk <flags=0x0:rate=166250000:usecount=0>
|-- hsi2c_clk.clk <flags=0x0:rate=66500000:usecount=0>
|-- i2c2_clk.clk <flags=0x0:rate=66500000:usecount=0>
|-- i2c1_clk.clk <flags=0x0:rate=66500000:usecount=0>
|-- fec_clk.clk <flags=0x0:rate=66500000:usecount=0>
|-- gpt_clk.clk <flags=0x0:rate=66500000:usecount=0>
|-- uart3_clk.clk <flags=0x0:rate=66500000:usecount=0>
|-- uart2_clk.clk <flags=0x0:rate=66500000:usecount=0>
|-- uart1_clk.clk <flags=0x0:rate=66500000:usecount=0>
Hi Yong,
Sure; if you want the extended functionality, I think your tree approach is
> Yes, it's also nice to have a file containing all the clock information
> which you have implemented in the email.
> Since we expect more features like enable/disable clocks in the debugfs, we
> also like to have tree-like debugfs for clock information.
best.
A couple of comments inline...
> Below is my draft implementation. Original implementation is from omap
> platform clock code, and I adopted to common clock device.
Minor nitpick: no need to put this #inlude on its own.
> diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c
> index 9e4c4d9..e7a629a 100644
> --- a/arch/arm/common/clkdev.c
> +++ b/arch/arm/common/clkdev.c
> @@ -19,6 +19,7 @@
>
> #include <linux/mutex.h>
> #include <linux/clk.h>
> #include <linux/slab.h>
>
> +#include <linux/debugfs.h>
Might be good to add CONFIG_CLK_DEBUG (which would depend on CONFIG_PM_DEBUG
>
> #include <asm/clkdev.h>
>
> @@ -186,3 +187,128 @@ void clkdev_drop(struct clk_lookup *cl)
>
> kfree(cl);
>
> }
> EXPORT_SYMBOL(clkdev_drop);
>
> +
> +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
and CONFIG_DEBUG_FS), so we can enable/disable it separately.
I think you can replace this (and read_file, and rate_fops) with something
> +/*
> + * debugfs support to trace clock tree hierarchy and attributes
> + */
> +
> +static int open_file(struct inode *inode, struct file *file)
like:
static int clk_debug_rate_get(void *data, u64 *val)
{
struct clk *clk = data
*val = (u64)clk_get_rate(clk);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(clk_debug_rate_fops, clk_debug_rate_get,
NULL, "%lu\n");
and then in clk_debugfs_register_one:
clk, &clk_debug_rate_fops);
debugfs_create_file("rate", S_IRUGO, clk->dentry,
I'd suggest:
> +static struct dentry *clk_debugfs_root;
> +
> +static int clk_debugfs_register_one(struct clk *clk)
> +{
> + int err;
> + struct dentry *d, *child, *child_tmp;
> + struct clk *pa = clk_get_parent(clk);
> +
> + if ((pa != ERR_PTR(-ENOSYS)) && pa)
if (pa && !IS_ERR(pa))
Why do you need to check for clk == NULL here? We probably don't want 'null'
> + d = debugfs_create_dir(clk ? clk->name : "null", pa->dentry);
> + else
> + d = debugfs_create_dir(clk ? clk->name : "null", clk_debugfs_root);
directories hanging around.
> +
> + if (!d) {
Do we need these checks?> + return -ENOMEM;
> + }
> +
> + clk->dentry = d;
> + d = debugfs_create_u32("enable_count", S_IRUGO, clk->dentry, (u32
> *)&clk->enable_count);
> + if (!d) {
> + err = -ENOMEM;
> + goto err_out;
> + }
> +
> + d = debugfs_create_file("rate", S_IRUGO, clk->dentry, (void *)clk,
> &rate_fops);
> + if (!d) {
> + err = -ENOMEM;
> + goto err_out;
> + }
> +
> + return 0;
> +
> +err_out:
> + d = clk->dentry;
> + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
> + debugfs_remove(child);
> + debugfs_remove(clk->dentry);
> + return err;
> +}
> +
> +static int clk_debugfs_register(struct clk *clk)
> +{
> + int err;
> + struct clk *pa;
> +
> + if (clk == ERR_PTR(-ENOSYS))
> + return -1;
> +
> + if (!clk)
> + return -1;
Again, this might be better:
> +
> + pa = clk_get_parent(clk);
> +
> + if ((pa != ERR_PTR(-ENOSYS)) && pa && !pa->dentry) {
if (pa && !IS_ERR(pa) && !pa->dentry)
.. but this makes me think we should probably drop the -ENOSYS return code
from clk_get_parent, but that's a patch for another time.. :)
I'd suggest "clocks" instead of "clock", but this is fairly minor.
> + err = clk_debugfs_register(pa);
> + if (err)
> + return err;
> + }
> +
> + if (!clk->dentry) {
> + err = clk_debugfs_register_one(clk);
> + if (err)
> + return err;
> + }
> + return 0;
> +}
> +
> +static int __init clk_debugfs_init(void)
> +{
> + struct clk_lookup *cl;
> + struct dentry *d;
> + int err;
> +
> + d = debugfs_create_dir("clock", NULL);
I see you found this oops too :)
> diff --git a/arch/arm/plat-mxc/clock-common.c
> b/arch/arm/plat-mxc/clock-common.c
> index 8911813..96e19a4 100644
> --- a/arch/arm/plat-mxc/clock-common.c
> +++ b/arch/arm/plat-mxc/clock-common.c
> @@ -93,11 +93,14 @@ void clk_mxc_disable(struct clk *_clk)
>
> unsigned long clk_mxc_get_rate(struct clk *_clk)
> {
>
> struct clk_mxc *clk = to_clk_mxc(_clk);
>
> -
> +
>
> if (clk->get_rate)
> return clk->get_rate(clk);
>
> - return clk_get_rate(clk->parent);
> + if (clk->parent)
> + return clk_get_rate(clk->parent);
> +
> + return 0;
Probably best to put 'name' into the CLK_DEBUG case; then you'll just need to
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 56416b7..0dc3443 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -44,16 +44,22 @@ struct device;
>
> * registered with the arch-specific clock management code; the clock
>
> driver
>
> * code does not need to handle these.
> */
>
> +#define CLK_NAME_LEN 16
>
> struct clk {
>
> const struct clk_ops *ops;
> unsigned int enable_count;
> struct mutex mutex;
>
> + char name[CLK_NAME_LEN];
> +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
> + struct dentry *dentry;
> +#endif
use the __INIT_CLK_DEBUG macros in my previous patch.
BTW, the spacing in the patch seems to be a little off; not sure if this is
due to your mailer or the patch itself. If it's the latter, you might want to
clean this up before submitting.
Cheers,
Jeremy