diff options
| author | Emmanuel Vadot <manu@FreeBSD.org> | 2017-03-05 07:13:29 +0000 |
|---|---|---|
| committer | Emmanuel Vadot <manu@FreeBSD.org> | 2017-03-05 07:13:29 +0000 |
| commit | c1b014c51c2e474046dbc1ed4839d51eb04b02c2 (patch) | |
| tree | 6996e8b83f6a156a288a11671f29204b03402ebb /sys/dev/extres | |
| parent | 9edf60b1edb5647fa51649c7233a976ea86329e3 (diff) | |
Notes
Diffstat (limited to 'sys/dev/extres')
| -rw-r--r-- | sys/dev/extres/clk/clk.c | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/sys/dev/extres/clk/clk.c b/sys/dev/extres/clk/clk.c index c6ba90c7417b..55d21698fa3a 100644 --- a/sys/dev/extres/clk/clk.c +++ b/sys/dev/extres/clk/clk.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mutex.h> #include <sys/limits.h> #include <sys/lock.h> +#include <sys/sbuf.h> #include <sys/sysctl.h> #include <sys/systm.h> #include <sys/sx.h> @@ -118,6 +119,8 @@ struct clknode { /* Cached values. */ uint64_t freq; /* Actual frequency */ + + struct sysctl_ctx_list sysctl_ctx; }; /* @@ -175,6 +178,15 @@ SX_SYSINIT(clock_topology, &clk_topo_lock, "Clock topology lock"); static void clknode_adjust_parent(struct clknode *clknode, int idx); +enum clknode_sysctl_type { + CLKNODE_SYSCTL_PARENT, + CLKNODE_SYSCTL_PARENTS_LIST, + CLKNODE_SYSCTL_CHILDREN_LIST, +}; + +static int clknode_sysctl(SYSCTL_HANDLER_ARGS); +static int clkdom_sysctl(SYSCTL_HANDLER_ARGS); + /* * Default clock methods for base class. */ @@ -382,6 +394,14 @@ clkdom_create(device_t dev) clkdom->ofw_mapper = clknode_default_ofw_map; #endif + SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "clocks", + CTLTYPE_STRING | CTLFLAG_RD, + clkdom, 0, clkdom_sysctl, + "A", + "Clock list for the domain"); + return (clkdom); } @@ -503,6 +523,7 @@ clknode_create(struct clkdom * clkdom, clknode_class_t clknode_class, const struct clknode_init_def *def) { struct clknode *clknode; + struct sysctl_oid *clknode_oid; KASSERT(def->name != NULL, ("clock name is NULL")); KASSERT(def->name[0] != '\0', ("clock name is empty")); @@ -547,6 +568,42 @@ clknode_create(struct clkdom * clkdom, clknode_class_t clknode_class, clknode->parent_idx = CLKNODE_IDX_NONE; TAILQ_INIT(&clknode->children); + sysctl_ctx_init(&clknode->sysctl_ctx); + clknode_oid = SYSCTL_ADD_NODE(&clknode->sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_clock), + OID_AUTO, clknode->name, + CTLFLAG_RD, 0, "A clock node"); + + SYSCTL_ADD_U64(&clknode->sysctl_ctx, + SYSCTL_CHILDREN(clknode_oid), + OID_AUTO, "frequency", + CTLFLAG_RD, &clknode->freq, 0, "The clock frequency"); + SYSCTL_ADD_PROC(&clknode->sysctl_ctx, + SYSCTL_CHILDREN(clknode_oid), + OID_AUTO, "parent", + CTLTYPE_STRING | CTLFLAG_RD, + clknode, CLKNODE_SYSCTL_PARENT, clknode_sysctl, + "A", + "The clock parent"); + SYSCTL_ADD_PROC(&clknode->sysctl_ctx, + SYSCTL_CHILDREN(clknode_oid), + OID_AUTO, "parents", + CTLTYPE_STRING | CTLFLAG_RD, + clknode, CLKNODE_SYSCTL_PARENTS_LIST, clknode_sysctl, + "A", + "The clock parents list"); + SYSCTL_ADD_PROC(&clknode->sysctl_ctx, + SYSCTL_CHILDREN(clknode_oid), + OID_AUTO, "childrens", + CTLTYPE_STRING | CTLFLAG_RD, + clknode, CLKNODE_SYSCTL_CHILDREN_LIST, clknode_sysctl, + "A", + "The clock childrens list"); + SYSCTL_ADD_INT(&clknode->sysctl_ctx, + SYSCTL_CHILDREN(clknode_oid), + OID_AUTO, "enable_cnt", + CTLFLAG_RD, &clknode->enable_cnt, 0, "The clock enable counter"); + return (clknode); } @@ -1385,3 +1442,64 @@ clk_parse_ofw_clk_name(device_t dev, phandle_t node, const char **name) return (0); } #endif + +static int +clkdom_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct clkdom *clkdom = arg1; + struct clknode *clknode; + struct sbuf *sb; + int ret; + + sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); + if (sb == NULL) + return (ENOMEM); + + CLK_TOPO_SLOCK(); + TAILQ_FOREACH(clknode, &clkdom->clknode_list, clkdom_link) { + sbuf_printf(sb, "%s ", clknode->name); + } + CLK_TOPO_UNLOCK(); + + ret = sbuf_finish(sb); + sbuf_delete(sb); + return (ret); +} + +static int +clknode_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct clknode *clknode, *children; + enum clknode_sysctl_type type = arg2; + struct sbuf *sb; + const char **parent_names; + int ret, i; + + clknode = arg1; + sb = sbuf_new_for_sysctl(NULL, NULL, 512, req); + if (sb == NULL) + return (ENOMEM); + + CLK_TOPO_SLOCK(); + switch (type) { + case CLKNODE_SYSCTL_PARENT: + if (clknode->parent) + sbuf_printf(sb, "%s", clknode->parent->name); + break; + case CLKNODE_SYSCTL_PARENTS_LIST: + parent_names = clknode_get_parent_names(clknode); + for (i = 0; i < clknode->parent_cnt; i++) + sbuf_printf(sb, "%s ", parent_names[i]); + break; + case CLKNODE_SYSCTL_CHILDREN_LIST: + TAILQ_FOREACH(children, &(clknode->children), sibling_link) { + sbuf_printf(sb, "%s ", children->name); + } + break; + } + CLK_TOPO_UNLOCK(); + + ret = sbuf_finish(sb); + sbuf_delete(sb); + return (ret); +} |
