aboutsummaryrefslogtreecommitdiff
path: root/clocks.c
diff options
context:
space:
mode:
Diffstat (limited to 'clocks.c')
-rw-r--r--clocks.c760
1 files changed, 295 insertions, 465 deletions
diff --git a/clocks.c b/clocks.c
index 9a76c19..2611a0d 100644
--- a/clocks.c
+++ b/clocks.c
@@ -11,565 +11,395 @@
* Contributors:
* Amit Arora <amit.arora@linaro.org> (IBM Corporation)
* - initial API and implementation
+ *
+ * Daniel Lezcano <daniel.lezcano@linaro.org> (IBM Corporation)
+ * - Rewrote code and API
+ *
*******************************************************************************/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+#endif
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <mntent.h>
+#include <sys/stat.h>
+
#include "powerdebug.h"
+#include "display.h"
#include "clocks.h"
+#include "tree.h"
+#include "utils.h"
+
+struct clock_info {
+ int flags;
+ int rate;
+ int usecount;
+ bool expanded;
+ char *prefix;
+} *clocks_info;
-static char clk_dir_path[PATH_MAX];
-static char clk_name[NAME_MAX];
-static int bold[MAX_LINES];
+static struct tree *clock_tree = NULL;
-int init_clock_details(void)
+static int locate_debugfs(char *clk_path)
{
- char *path = debugfs_locate_mpoint();
- struct stat buf;
-
- if (path)
- strcpy(clk_dir_path, path);
- else {
- if (!dump) {
- create_selectedwindow();
- sprintf(clock_lines[0], "Unable to locate debugfs "
- "mount point. Mount debugfs "
- "and try again..\n");
- print_one_clock(0, clock_lines[0], 1, 0);
- old_clock_line_no = 1;
- return(1);
- } else {
- fprintf(stderr, "powerdebug: Unable to locate debugfs "
- "mount point. Mount debugfs and try "
- "again..\n");
- exit(1);
- }
- }
- sprintf(clk_dir_path, "%s/clock", clk_dir_path);
- //strcpy(clk_dir_path, "/debug/clock"); // Hardcoded for testing..
- if (stat(clk_dir_path, &buf)) {
- if (!dump) {
- create_selectedwindow();
- sprintf(clock_lines[0], "Unable to find clock tree"
- " information at %s.\n", clk_dir_path);
- print_one_clock(0, clock_lines[0], 1, 0);
- old_clock_line_no = 1;
- return(1);
- } else {
- fprintf(stderr, "powerdebug: Unable to find clock tree"
- " information at %s.\n", clk_dir_path);
- exit(1);
- }
- }
- strcpy(clk_name, "");
- return(0);
+ strcpy(clk_path, "/sys/kernel/debug");
+ return 0;
}
-int get_int_from(char *file)
+static struct clock_info *clock_alloc(void)
{
- FILE *filep;
- char result[NAME_MAX];
- int ret;
-
- filep = fopen(file, "r");
+ struct clock_info *ci;
- if (!filep)
- return -1; //TBD : What should we return on failure, here ?
+ ci = malloc(sizeof(*ci));
+ if (ci)
+ memset(ci, 0, sizeof(*ci));
- ret = fscanf(filep, "%s", result);
- fclose(filep);
-
- return atoi(result);
+ return ci;
}
-void find_parents_for_clock(char *clkname, int complete)
+static inline const char *clock_rate(int *rate)
{
- char name[256];
-
- name[0] = '\0';
- if (!complete) {
- char str[256];
-
- strcat(name, clkname);
- sprintf(str, "Enter Clock Name : %s\n", name);
- print_one_clock(2, str, 1, 0);
- return;
- }
- sprintf(name, "Parents for \"%s\" Clock : \n", clkname);
- print_one_clock(0, name, 1, 1);
- dump_all_parents(clkname);
+ int r;
+
+ /* GHZ */
+ r = *rate >> 30;
+ if (r) {
+ *rate = r;
+ return "GHZ";
+ }
+
+ /* MHZ */
+ r = *rate >> 20;
+ if (r) {
+ *rate = r;
+ return "MHZ";
+ }
+
+ /* KHZ */
+ r = *rate >> 10;
+ if (r) {
+ *rate = r;
+ return "KHZ";
+ }
+
+ return "";
}
-int read_and_print_clock_info(int verbose, int hrow, int selected)
+static int dump_clock_cb(struct tree *t, void *data)
{
- print_one_clock(0, "Reading Clock Tree ...", 1, 1);
+ struct clock_info *clk = t->private;
+ struct clock_info *pclk;
+ const char *unit;
+ int ret = 0;
+ int rate = clk->rate;
- if (!old_clock_line_no || selected == REFRESH_WINDOW) {
- destroy_clocks_info();
- read_clock_info(clk_dir_path);
+ if (!t->parent) {
+ printf("/\n");
+ clk->prefix = "";
+ return 0;
}
- if (!clocks_info->num_children) {
- fprintf(stderr, "powerdebug: No clocks found. Exiting..\n");
- exit(1);
- }
+ pclk = t->parent->private;
- if (selected == CLOCK_SELECTED)
- selected = 1;
- else
- selected = 0;
+ if (!clk->prefix)
+ ret = asprintf(&clk->prefix, "%s%s%s", pclk->prefix,
+ t->depth > 1 ? " ": "", t->next ? "|" : " ");
+ if (ret < 0)
+ return -1;
- print_clock_info(verbose, hrow, selected);
- hrow = (hrow < old_clock_line_no) ? hrow : old_clock_line_no - 1;
+ unit = clock_rate(&rate);
- return hrow;
-}
-
-int calc_delta_screen_size(int hrow)
-{
- if (hrow >= (maxy - 3))
- return hrow - (maxy - 4);
+ printf("%s%s-- %s (flags:0x%x, usecount:%d, rate: %d %s)\n",
+ clk->prefix, !t->next ? "`" : "", t->name, clk->flags,
+ clk->usecount, rate, unit);
return 0;
}
-void print_clock_info(int verbose, int hrow, int selected)
+int dump_clock_info(void)
{
- int i, count = 0, delta;
+ return tree_for_each(clock_tree, dump_clock_cb, NULL);
+}
- (void)verbose;
+static int dump_all_parents(char *clkarg)
+{
+ struct tree *tree;
- print_clock_header();
+ tree = tree_find(clock_tree, clkarg);
+ if (!tree) {
+ printf("Clock NOT found!\n");
+ return -1;
+ }
- for (i = 0; i < clocks_info->num_children; i++)
- add_clock_details_recur(clocks_info->children[i],
- hrow, selected);
+ return tree_for_each_parent(tree, dump_clock_cb, NULL);
+}
- delta = calc_delta_screen_size(hrow);
+static inline int read_clock_cb(struct tree *t, void *data)
+{
+ struct clock_info *clk = t->private;
- while (clock_lines[count + delta] &&
- strcmp(clock_lines[count + delta], "")) {
- if (count < delta) {
- count++;
- continue;
- }
- print_one_clock(count - delta, clock_lines[count + delta],
- bold[count + delta], (hrow == (count + delta)));
- count++;
- }
+ file_read_value(t->path, "flags", "%x", &clk->flags);
+ file_read_value(t->path, "rate", "%d", &clk->rate);
+ file_read_value(t->path, "usecount", "%d", &clk->usecount);
- old_clock_line_no = clock_line_no;
- clock_line_no = 0;
+ return 0;
}
-void prepare_name_str(char *namestr, struct clock_info *clock)
+static int read_clock_info(struct tree *tree)
{
- int i;
-
- strcpy(namestr, "");
- if (clock->level > 1)
- for (i = 0; i < (clock->level - 1); i++)
- strcat(namestr, " ");
- strcat(namestr, clock->name);
+ return tree_for_each(tree, read_clock_cb, NULL);
}
-void add_clock_details_recur(struct clock_info *clock, int hrow, int selected)
+static int fill_clock_cb(struct tree *t, void *data)
{
- int i;
- char *unit = " Hz";
- char rate_str[64];
- char name_str[256];
- double drate = (double)clock->rate;
-
- if (drate > 1000 && drate < 1000000) {
- unit = "KHz";
- drate /= 1000;
- }
- if (drate > 1000000) {
- unit = "MHz";
- drate /= 1000000;
- }
- if (clock->usecount)
- bold[clock_line_no] = 1;
- else
- bold[clock_line_no] = 0;
-
- sprintf(rate_str, "%.2f %s", drate, unit);
- prepare_name_str(name_str, clock);
- sprintf(clock_lines[clock_line_no++], "%-55s %-4d %-12s %-12d %-12d",
- name_str, clock->flags, rate_str, clock->usecount,
- clock->num_children);
-
- if (selected && (hrow == (clock_line_no - 1))) {
- if (clock->expanded)
- collapse_all_subclocks(clock);
- else
- clock->expanded = 1;
- selected = 0;
+ struct clock_info *clk;
+
+ clk = clock_alloc();
+ if (!clk)
+ return -1;
+ t->private = clk;
+
+ /* we skip the root node but we set it expanded for its children */
+ if (!t->parent) {
+ clk->expanded = true;
+ return 0;
}
- if (clock->expanded && clock->num_children)
- for (i = 0; i < clock->num_children; i++)
- add_clock_details_recur(clock->children[i],
- hrow, selected);
- strcpy(clock_lines[clock_line_no], "");
+ return read_clock_cb(t, data);
}
-void collapse_all_subclocks(struct clock_info *clock)
+static int fill_clock_tree(void)
{
- int i;
-
- clock->expanded = 0;
- if (clock->num_children)
- for (i = 0; i < clock->num_children; i++)
- collapse_all_subclocks(clock->children[i]);
+ return tree_for_each(clock_tree, fill_clock_cb, NULL);
}
-void destroy_clocks_info(void)
+static int is_collapsed(struct tree *t, void *data)
{
- int i;
-
- if (!clocks_info)
- return;
-
- if (clocks_info->num_children) {
- for (i = (clocks_info->num_children - 1); i >= 0 ; i--) {
- destroy_clocks_info_recur(clocks_info->children[i]);
- if (!i) {
- free(clocks_info->children);
- clocks_info->children = NULL;
- }
- }
- }
- clocks_info->num_children = 0;
- free(clocks_info);
- clocks_info = NULL;
+ struct clock_info *clk = t->private;
+
+ if (!clk->expanded)
+ return 1;
+
+ return 0;
}
-void destroy_clocks_info_recur(struct clock_info *clock)
+static char *clock_line(struct tree *t)
{
- int i;
-
- if (clock && clock->num_children) {
- for (i = (clock->num_children - 1); i >= 0; i--) {
- fflush(stdin);
- destroy_clocks_info_recur(clock->children[i]);
- if (!i) {
- free(clock->children);
- clock->children = NULL;
- clock->num_children = 0;
- }
- }
- }
+ struct clock_info *clk;
+ int rate;
+ const char *clkunit;
+ char *clkrate, *clkname, *clkline = NULL;
+
+ clk = t->private;
+ rate = clk->rate;
+ clkunit = clock_rate(&rate);
+
+ if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0)
+ return NULL;
+
+ if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0)
+ goto free_clkname;
+
+ if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d", clkname,
+ clk->flags, clkrate, clk->usecount, t->nrchild) < 0)
+ goto free_clkrate;
+
+free_clkrate:
+ free(clkrate);
+free_clkname:
+ free(clkname);
+
+ return clkline;
}
-void read_and_dump_clock_info_one(char *clk)
+static int _clock_print_info_cb(struct tree *t, void *data)
{
- printf("\nParents for \"%s\" Clock :\n\n", clk);
- read_clock_info(clk_dir_path);
- dump_all_parents(clk);
- printf("\n\n");
+ struct clock_info *clock = t->private;
+ int *line = data;
+ char *buffer;
+
+ /* we skip the root node of the tree */
+ if (!t->parent)
+ return 0;
+
+ buffer = clock_line(t);
+ if (!buffer)
+ return -1;
+
+ display_print_line(CLOCK, *line, buffer, clock->usecount, t);
+
+ (*line)++;
+
+ free(buffer);
+
+ return 0;
}
-void read_and_dump_clock_info(int verbose)
+static int clock_print_info_cb(struct tree *t, void *data)
{
- (void)verbose;
- printf("\nClock Tree :\n");
- printf("**********\n");
- read_clock_info(clk_dir_path);
- dump_clock_info(clocks_info, 1, 1);
- printf("\n\n");
+ /* we skip the root node of the tree */
+ if (!t->parent)
+ return 0;
+
+ /* show the clock when *all* its parent is expanded */
+ if (tree_for_each_parent(t->parent, is_collapsed, NULL))
+ return 0;
+
+ return _clock_print_info_cb(t, data);
}
-void read_clock_info(char *clkpath)
+static int clock_print_header(void)
{
- DIR *dir;
- struct dirent *item;
- char filename[NAME_MAX], clockname[NAME_MAX];
- struct clock_info *child;
- struct clock_info *cur;
-
- dir = opendir(clkpath);
- if (!dir)
- return;
-
- clocks_info = (struct clock_info *)malloc(sizeof(struct clock_info));
- memset(clocks_info, 0, sizeof(clocks_info));
- strcpy(clocks_info->name, "/");
- clocks_info->level = 0;
-
- while ((item = readdir(dir))) {
- /* skip hidden dirs except ".." */
- if (item->d_name[0] == '.')
- continue;
-
- strcpy(clockname, item->d_name);
- sprintf(filename, "%s/%s", clkpath, item->d_name);
- cur = (struct clock_info *)malloc(sizeof(struct clock_info));
- memset(cur, 0, sizeof(struct clock_info));
- strcpy(cur->name, clockname);
- cur->parent = clocks_info;
- cur->num_children = 0;
- cur->expanded = 0;
- cur->level = 1;
- insert_children(&clocks_info, cur);
- child = read_clock_info_recur(filename, 2, cur);
- }
- closedir(dir);
+ char *buf;
+ int ret;
+
+ if (asprintf(&buf, "%-55s %-16s %-12s %-9s %-8s",
+ "Name", "Flags", "Rate", "Usecount", "Children") < 0)
+ return -1;
+
+ ret = display_column_name(buf);
+
+ free(buf);
+
+ return ret;
}
-struct clock_info *read_clock_info_recur(char *clkpath, int level,
- struct clock_info *parent)
+static int clock_print_info(struct tree *tree)
{
- int ret = 0;
- DIR *dir;
- char filename[PATH_MAX];
- struct dirent *item;
- struct clock_info *cur = NULL;
- struct stat buf;
-
- dir = opendir(clkpath);
- if (!dir)
- return NULL;
+ int ret, line = 0;
- while ((item = readdir(dir))) {
- struct clock_info *child;
- /* skip hidden dirs except ".." */
- if (item->d_name[0] == '.' )
- continue;
-
- sprintf(filename, "%s/%s", clkpath, item->d_name);
-
- ret = stat(filename, &buf);
-
- if (ret < 0) {
- printf("Error doing a stat on %s\n", filename);
- exit(1);
- }
-
- if (S_ISREG(buf.st_mode)) {
- if (!strcmp(item->d_name, "flags"))
- parent->flags = get_int_from(filename);
- if (!strcmp(item->d_name, "rate"))
- parent->rate = get_int_from(filename);
- if (!strcmp(item->d_name, "usecount"))
- parent->usecount = get_int_from(filename);
- continue;
- }
-
- if (!S_ISDIR(buf.st_mode))
- continue;
-
- cur = (struct clock_info *)malloc(sizeof(struct clock_info));
- memset(cur, 0, sizeof(cur));
- strcpy(cur->name, item->d_name);
- cur->children = NULL;
- cur->parent = NULL;
- cur->num_children = 0;
- cur->expanded = 0;
- cur->level = level;
- child = read_clock_info_recur(filename, level + 1, cur);
- insert_children(&parent, cur);
- cur->parent = parent;
- }
- closedir(dir);
+ display_reset_cursor(CLOCK);
+
+ clock_print_header();
+
+ ret = tree_for_each(tree, clock_print_info_cb, &line);
+
+ display_refresh_pad(CLOCK);
- return cur;
+ return ret;
}
-void insert_children(struct clock_info **parent, struct clock_info *clk)
+static int clock_select(void)
{
- if (!(*parent)->num_children || (*parent)->children == NULL) {
- (*parent)->children = (struct clock_info **)
- malloc(sizeof(struct clock_info *)*2);
- (*parent)->num_children = 0;
- } else
- (*parent)->children = (struct clock_info **)
- realloc((*parent)->children,
- sizeof(struct clock_info *) *
- ((*parent)->num_children + 2));
- if ((*parent)->num_children > 0)
- (*parent)->children[(*parent)->num_children - 1]->last_child
- = 0;
- clk->last_child = 1;
- (*parent)->children[(*parent)->num_children] = clk;
- (*parent)->children[(*parent)->num_children + 1] = NULL;
- (*parent)->num_children++;
+ struct tree *t = display_get_row_data(CLOCK);
+ struct clock_info *clk = t->private;
+
+ clk->expanded = !clk->expanded;
+
+ return 0;
}
-void dump_parent(struct clock_info *clk, int line)
+/*
+ * Read the clock information and fill the tree with the information
+ * found in the files. Then print the result to the text based interface
+ * Return 0 on success, < 0 otherwise
+ */
+static int clock_display(bool refresh)
{
- char *unit = "Hz";
- double drate;
- static char spaces[64];
- char str[256];
- static int maxline;
-
- if (maxline < line)
- maxline = line;
-
- if (clk && clk->parent)
- dump_parent(clk->parent, ++line);
-
- drate = (double)clk->rate;
- if (drate > 1000 && drate < 1000000) {
- unit = "KHz";
- drate /= 1000;
- }
- if (drate > 1000000) {
- unit = "MHz";
- drate /= 1000000;
- }
- if (clk == clocks_info) {
- line++;
- strcpy(spaces, "");
- sprintf(str, "%s%s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
- spaces, clk->name, clk->flags, clk->usecount, drate,
- unit);
- } else {
- if (!(clk->parent == clocks_info))
- strcat(spaces, " ");
- sprintf(str, "%s`- %s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
- spaces, clk->name, clk->flags, clk->usecount, drate,
- unit);
- }
- if (dump)
- //printf("line=%d:m%d:l%d %s", maxline - line + 2, maxline, line, str);
- printf("%s", str);
- else
- print_one_clock(maxline - line + 2, str, 1, 0);
+ if (refresh && read_clock_info(clock_tree))
+ return -1;
+
+ return clock_print_info(clock_tree);
}
-void dump_all_parents(char *clkarg)
+static int clock_find(const char *name)
{
- struct clock_info *clk;
- char spaces[1024];
+ struct tree **ptree = NULL;
+ int i, nr, line = 0, ret = 0;
- strcpy(spaces, "");
+ nr = tree_finds(clock_tree, name, &ptree);
- clk = find_clock(clocks_info, clkarg);
+ display_reset_cursor(CLOCK);
+
+ for (i = 0; i < nr; i++) {
+
+ ret = _clock_print_info_cb(ptree[i], &line);
+ if (ret)
+ break;
- if (!clk)
- printf("Clock NOT found!\n");
- else {
-// while(clk && clk != clocks_info) {
-// printf("%s\n", clk->name);
-// strcat(spaces, " ");
-// clk = clk->parent;
-// printf("%s <-- ", spaces);
-// }
-// printf(" /\n");
- dump_parent(clk, 1);
}
+
+ display_refresh_pad(CLOCK);
+
+ free(ptree);
+
+ return ret;
}
-struct clock_info *find_clock(struct clock_info *clk, char *clkarg)
+static int clock_selectf(void)
{
- int i;
- struct clock_info *ret = clk;
-
- if (!strcmp(clk->name, clkarg))
- return ret;
-
- if (clk->children) {
- for (i = 0; i < clk->num_children; i++) {
- if (!strcmp(clk->children[i]->name, clkarg))
- return clk->children[i];
- }
- for (i = 0; i < clk->num_children; i++) {
- ret = find_clock(clk->children[i], clkarg);
- if (ret)
- return ret;
- }
- }
+ struct tree *t = display_get_row_data(CLOCK);
+ int line = 0;
- return NULL;
-}
+ display_reset_cursor(CLOCK);
+ if (tree_for_each_parent(t, _clock_print_info_cb, &line))
+ return -1;
-void dump_clock_info(struct clock_info *clk, int level, int bmp)
+ return display_refresh_pad(CLOCK);
+}
+
+/*
+ * Read the clock information and fill the tree with the information
+ * found in the files. Then dump to stdout a formatted result.
+ * @clk : a name for a specific clock we want to show
+ * Return 0 on success, < 0 otherwise
+ */
+int clock_dump(char *clk)
{
- int i, j;
+ int ret;
- if (!clk)
- return;
-
- for (i = 1, j = 0; i < level; i++, j = (i - 1)) {
- if (i == (level - 1)) {
- if (clk->last_child)
- printf("`-- ");
- else
- printf("|-- ");
- } else {
- if ((1<<j) & bmp)
- printf("| ");
- else
- printf(" ");
- }
- }
+ if (read_clock_info(clock_tree))
+ return -1;
- if (clk == clocks_info)
- printf("%s\n", clk->name);
- else {
- char *unit = "Hz";
- double drate = (double)clk->rate;
-
- if (drate > 1000 && drate < 1000000) {
- unit = "KHz";
- drate /= 1000;
- }
- if (drate > 1000000) {
- unit = "MHz";
- drate /= 1000000;
- }
- printf("%s (flags:%d,usecount:%d,rate:%5.2f %s)\n",
- clk->name, clk->flags, clk->usecount, drate, unit);
- }
- if (clk->children) {
- int tbmp = bmp;
- int xbmp = -1;
-
- if (clk->last_child) {
- xbmp ^= 1 << (level - 2);
-
- xbmp = tbmp & xbmp;
- } else
- xbmp = bmp;
- for (i = 0; i < clk->num_children; i++) {
- tbmp = xbmp | (1 << level);
- dump_clock_info(clk->children[i], level + 1, tbmp);
- }
+ if (clk) {
+ printf("\nParents for \"%s\" Clock :\n\n", clk);
+ ret = dump_all_parents(clk);
+ printf("\n\n");
+ } else {
+ printf("\nClock Tree :\n");
+ printf("**********\n");
+ ret = dump_clock_info();
+ printf("\n\n");
}
+
+ return ret;
}
-char *debugfs_locate_mpoint(void)
+static struct display_ops clock_ops = {
+ .display = clock_display,
+ .select = clock_select,
+ .find = clock_find,
+ .selectf = clock_selectf,
+};
+
+/*
+ * Initialize the clock framework
+ */
+int clock_init(void)
{
- int ret;
- FILE *filep;
- char **path;
- char fsname[64];
- struct statfs sfs;
-
- path = likely_mpoints;
- while (*path) {
- ret = statfs(*path, &sfs);
- if (ret >= 0 && sfs.f_type == (long)DEBUGFS_MAGIC)
- return *path;
- path++;
- }
+ char clk_dir_path[PATH_MAX];
- filep = fopen("/proc/mounts", "r");
- if (filep == NULL) {
- fprintf(stderr, "powerdebug: Error opening /proc/mounts.");
- exit(1);
- }
+ if (locate_debugfs(clk_dir_path))
+ return -1;
- while (fscanf(filep, "%*s %s %s %*s %*d %*d\n",
- debugfs_mntpoint, fsname) == 2)
- if (!strcmp(fsname, "debugfs"))
- break;
- fclose(filep);
+ sprintf(clk_dir_path, "%s/clock", clk_dir_path);
- if (strcmp(fsname, "debugfs"))
- return NULL;
+ if (access(clk_dir_path, F_OK))
+ return -1;
+
+ clock_tree = tree_load(clk_dir_path, NULL, false);
+ if (!clock_tree)
+ return -1;
+
+ if (fill_clock_tree())
+ return -1;
- return debugfs_mntpoint;
+ return display_register(CLOCK, &clock_ops);
}