Module Name: src Committed By: jmcneill Date: Sat Apr 28 15:20:33 UTC 2018
Modified Files: src/sys/dev/clk: clk.c clk_backend.h Log Message: Create private sysctl nodes for inspecting clock trees. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/sys/dev/clk/clk.c src/sys/dev/clk/clk_backend.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/clk/clk.c diff -u src/sys/dev/clk/clk.c:1.3 src/sys/dev/clk/clk.c:1.4 --- src/sys/dev/clk/clk.c:1.3 Sun Apr 1 21:11:01 2018 +++ src/sys/dev/clk/clk.c Sat Apr 28 15:20:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: clk.c,v 1.3 2018/04/01 21:11:01 bouyer Exp $ */ +/* $NetBSD: clk.c,v 1.4 2018/04/28 15:20:33 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -27,13 +27,166 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: clk.c,v 1.3 2018/04/01 21:11:01 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: clk.c,v 1.4 2018/04/28 15:20:33 jmcneill Exp $"); #include <sys/param.h> +#include <sys/sysctl.h> #include <dev/clk/clk.h> #include <dev/clk/clk_backend.h> +static struct sysctllog *clk_log; +static const struct sysctlnode *clk_node; + +static int +create_clk_node(void) +{ + const struct sysctlnode *hw_node; + int error; + + if (clk_node) + return 0; + + error = sysctl_createv(&clk_log, 0, NULL, &hw_node, + CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL, + NULL, 0, NULL, 0, CTL_HW, CTL_EOL); + if (error) + return error; + + error = sysctl_createv(&clk_log, 0, &hw_node, &clk_node, + CTLFLAG_PERMANENT, CTLTYPE_NODE, "clk", NULL, + NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); + if (error) + return error; + + return 0; +} + +static int +create_domain_node(struct clk_domain *domain) +{ + int error; + + if (domain->node) + return 0; + + error = create_clk_node(); + if (error) + return error; + + error = sysctl_createv(&clk_log, 0, &clk_node, &domain->node, + 0, CTLTYPE_NODE, domain->name, NULL, + NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); + if (error) + return error; + + return 0; +} + +static int +clk_sysctl_rate_helper(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct clk *clk; + uint64_t rate; + + node = *rnode; + clk = node.sysctl_data; + node.sysctl_data = &rate; + + rate = clk_get_rate(clk); + + return sysctl_lookup(SYSCTLFN_CALL(&node)); +} + +static int +clk_sysctl_parent_helper(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct clk *clk, *clk_parent; + + node = *rnode; + clk = node.sysctl_data; + + clk_parent = clk_get_parent(clk); + if (clk_parent && clk_parent->name) + node.sysctl_data = __UNCONST(clk_parent->name); + else + node.sysctl_data = __UNCONST("?"); + + return sysctl_lookup(SYSCTLFN_CALL(&node)); +} + +static int +clk_sysctl_parent_domain_helper(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct clk *clk, *clk_parent; + + node = *rnode; + clk = node.sysctl_data; + + clk_parent = clk_get_parent(clk); + if (clk_parent && clk_parent->domain && clk_parent->domain->name) + node.sysctl_data = __UNCONST(clk_parent->domain->name); + else + node.sysctl_data = __UNCONST("?"); + + return sysctl_lookup(SYSCTLFN_CALL(&node)); +} + +int +clk_attach(struct clk *clk) +{ + const struct sysctlnode *node; + struct clk_domain *domain = clk->domain; + int error; + + KASSERT(domain != NULL); + + if (!domain->name || !clk->name) { + /* Names are required to create sysctl nodes */ + return 0; + } + + error = create_domain_node(domain); + if (error != 0) + goto sysctl_failed; + + error = sysctl_createv(&clk_log, 0, &domain->node, &node, + CTLFLAG_PRIVATE, CTLTYPE_NODE, clk->name, NULL, + NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); + if (error) + goto sysctl_failed; + + error = sysctl_createv(&clk_log, 0, &node, NULL, + CTLFLAG_PRIVATE, CTLTYPE_QUAD, "rate", NULL, + clk_sysctl_rate_helper, 0, (void *)clk, 0, + CTL_CREATE, CTL_EOL); + if (error) + goto sysctl_failed; + + error = sysctl_createv(&clk_log, 0, &node, NULL, + CTLFLAG_PRIVATE, CTLTYPE_STRING, "parent", NULL, + clk_sysctl_parent_helper, 0, (void *)clk, 0, + CTL_CREATE, CTL_EOL); + if (error) + goto sysctl_failed; + + error = sysctl_createv(&clk_log, 0, &node, NULL, + CTLFLAG_PRIVATE, CTLTYPE_STRING, "parent_domain", NULL, + clk_sysctl_parent_domain_helper, 0, (void *)clk, 0, + CTL_CREATE, CTL_EOL); + if (error) + goto sysctl_failed; + +sysctl_failed: + if (error) + aprint_error("%s: failed to create sysctl node for %s: %d\n", + domain->name, clk->name, error); + return error; +} + struct clk * clk_get(struct clk_domain *domain, const char *name) { @@ -106,5 +259,8 @@ clk_set_parent(struct clk *clk, struct c struct clk * clk_get_parent(struct clk *clk) { - return clk->domain->funcs->get_parent(clk->domain->priv, clk); + if (clk->domain->funcs->get_parent) + return clk->domain->funcs->get_parent(clk->domain->priv, clk); + else + return NULL; } Index: src/sys/dev/clk/clk_backend.h diff -u src/sys/dev/clk/clk_backend.h:1.3 src/sys/dev/clk/clk_backend.h:1.4 --- src/sys/dev/clk/clk_backend.h:1.3 Sun Apr 1 21:11:01 2018 +++ src/sys/dev/clk/clk_backend.h Sat Apr 28 15:20:33 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: clk_backend.h,v 1.3 2018/04/01 21:11:01 bouyer Exp $ */ +/* $NetBSD: clk_backend.h,v 1.4 2018/04/28 15:20:33 jmcneill Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill <jmcne...@invisible.ca> @@ -29,9 +29,13 @@ #ifndef _DEV_CLK_CLK_BACKEND_H #define _DEV_CLK_CLK_BACKEND_H +#include <sys/sysctl.h> + #include <dev/clk/clk.h> struct clk_domain { + const char *name; + const struct sysctlnode *node; const struct clk_funcs *funcs; void *priv; }; @@ -56,4 +60,6 @@ struct clk_funcs { struct clk *(*get_parent)(void *, struct clk *); }; +int clk_attach(struct clk *); + #endif /* _DEV_CLK_CLK_BACKEND_H */