Commit 0c7242c21ab652451d68830f08d5b86d45ab1135
Committed by
Afzal Mohammed
1 parent
e3c57087ce
Exists in
master
OMAP2+: DVFS: add debugfs support for visualizing
Ability to show the dependency table helps debug some of the quirky issues associated with dvfs when multiple device requests are present [nm@ti.com: log beautification, few fixes] Signed-off-by: Nishanth Menon <nm@ti.com> Signed-off-by: Todd Poynor <toddpoynor@google.com> [vaibhav.bedia@ti.com: Pull in for AM33xx] Signed-off-by: Vaibhav Bedia <vaibhav.bedia@ti.com>
Showing 1 changed file with 174 additions and 0 deletions Side-by-side Diff
arch/arm/mach-omap2/dvfs.c
... | ... | @@ -17,6 +17,8 @@ |
17 | 17 | #include <linux/slab.h> |
18 | 18 | #include <linux/opp.h> |
19 | 19 | #include <linux/clk.h> |
20 | +#include <linux/debugfs.h> | |
21 | +#include <linux/seq_file.h> | |
20 | 22 | #include <plat/common.h> |
21 | 23 | #include <plat/omap_device.h> |
22 | 24 | #include <plat/omap_hwmod.h> |
... | ... | @@ -880,6 +882,176 @@ |
880 | 882 | } |
881 | 883 | EXPORT_SYMBOL(omap_device_scale); |
882 | 884 | |
885 | +#ifdef CONFIG_PM_DEBUG | |
886 | +static int dvfs_dump_vdd(struct seq_file *sf, void *unused) | |
887 | +{ | |
888 | + int k; | |
889 | + struct omap_vdd_dvfs_info *dvfs_info; | |
890 | + struct omap_vdd_dev_list *tdev; | |
891 | + struct omap_dev_user_list *duser; | |
892 | + struct omap_vdd_user_list *vuser; | |
893 | + struct omap_vdd_info *vdd; | |
894 | + struct omap_vdd_dep_info *dep_info; | |
895 | + struct voltagedomain *voltdm; | |
896 | + struct omap_volt_data *volt_data; | |
897 | + int anyreq; | |
898 | + int anyreq2; | |
899 | + | |
900 | + dvfs_info = (struct omap_vdd_dvfs_info *)sf->private; | |
901 | + if (IS_ERR_OR_NULL(dvfs_info)) { | |
902 | + pr_err("%s: NO DVFS?\n", __func__); | |
903 | + return -EINVAL; | |
904 | + } | |
905 | + | |
906 | + voltdm = dvfs_info->voltdm; | |
907 | + if (IS_ERR_OR_NULL(voltdm)) { | |
908 | + pr_err("%s: NO voltdm?\n", __func__); | |
909 | + return -EINVAL; | |
910 | + } | |
911 | + | |
912 | + vdd = voltdm->vdd; | |
913 | + if (IS_ERR_OR_NULL(vdd)) { | |
914 | + pr_err("%s: NO vdd data?\n", __func__); | |
915 | + return -EINVAL; | |
916 | + } | |
917 | + | |
918 | + seq_printf(sf, "vdd_%s\n", voltdm->name); | |
919 | + mutex_lock(&omap_dvfs_lock); | |
920 | + spin_lock(&dvfs_info->user_lock); | |
921 | + | |
922 | + seq_printf(sf, "|- voltage requests\n| |\n"); | |
923 | + anyreq = 0; | |
924 | + plist_for_each_entry(vuser, &dvfs_info->vdd_user_list, node) { | |
925 | + seq_printf(sf, "| |-%d: %s:%s\n", | |
926 | + vuser->node.prio, | |
927 | + dev_driver_string(vuser->dev), dev_name(vuser->dev)); | |
928 | + anyreq = 1; | |
929 | + } | |
930 | + | |
931 | + spin_unlock(&dvfs_info->user_lock); | |
932 | + | |
933 | + if (!anyreq) | |
934 | + seq_printf(sf, "| `-none\n"); | |
935 | + else | |
936 | + seq_printf(sf, "| X\n"); | |
937 | + seq_printf(sf, "|\n"); | |
938 | + | |
939 | + seq_printf(sf, "|- frequency requests\n| |\n"); | |
940 | + anyreq2 = 0; | |
941 | + list_for_each_entry(tdev, &dvfs_info->dev_list, node) { | |
942 | + anyreq = 0; | |
943 | + seq_printf(sf, "| |- %s:%s\n", | |
944 | + dev_driver_string(tdev->dev), dev_name(tdev->dev)); | |
945 | + spin_lock(&tdev->user_lock); | |
946 | + plist_for_each_entry(duser, &tdev->freq_user_list, node) { | |
947 | + seq_printf(sf, "| | |-%d: %s:%s\n", | |
948 | + duser->node.prio, | |
949 | + dev_driver_string(duser->dev), | |
950 | + dev_name(duser->dev)); | |
951 | + anyreq = 1; | |
952 | + } | |
953 | + | |
954 | + spin_unlock(&tdev->user_lock); | |
955 | + | |
956 | + if (!anyreq) | |
957 | + seq_printf(sf, "| | `-none\n"); | |
958 | + else | |
959 | + seq_printf(sf, "| | X\n"); | |
960 | + anyreq2 = 1; | |
961 | + } | |
962 | + if (!anyreq2) | |
963 | + seq_printf(sf, "| `-none\n"); | |
964 | + else | |
965 | + seq_printf(sf, "| X\n"); | |
966 | + | |
967 | + volt_data = vdd->volt_data; | |
968 | + seq_printf(sf, "|- Supported voltages\n| |\n"); | |
969 | + anyreq = 0; | |
970 | + while (volt_data && volt_data->volt_nominal) { | |
971 | + seq_printf(sf, "| |-%d\n", volt_data->volt_nominal); | |
972 | + anyreq = 1; | |
973 | + volt_data++; | |
974 | + } | |
975 | + if (!anyreq) | |
976 | + seq_printf(sf, "| `-none\n"); | |
977 | + else | |
978 | + seq_printf(sf, "| X\n"); | |
979 | + | |
980 | + dep_info = vdd->dep_vdd_info; | |
981 | + seq_printf(sf, "`- voltage dependencies\n |\n"); | |
982 | + anyreq = 0; | |
983 | + while (dep_info && dep_info->nr_dep_entries) { | |
984 | + struct omap_vdd_dep_volt *dep_table = dep_info->dep_table; | |
985 | + | |
986 | + seq_printf(sf, " |-on vdd_%s\n", dep_info->name); | |
987 | + | |
988 | + for (k = 0; k < dep_info->nr_dep_entries; k++) { | |
989 | + seq_printf(sf, " | |- %d => %d\n", | |
990 | + dep_table[k].main_vdd_volt, | |
991 | + dep_table[k].dep_vdd_volt); | |
992 | + } | |
993 | + | |
994 | + anyreq = 1; | |
995 | + dep_info++; | |
996 | + } | |
997 | + | |
998 | + if (!anyreq) | |
999 | + seq_printf(sf, " `- none\n"); | |
1000 | + else | |
1001 | + seq_printf(sf, " X X\n"); | |
1002 | + | |
1003 | + mutex_unlock(&omap_dvfs_lock); | |
1004 | + return 0; | |
1005 | +} | |
1006 | + | |
1007 | +static int dvfs_dbg_open(struct inode *inode, struct file *file) | |
1008 | +{ | |
1009 | + return single_open(file, dvfs_dump_vdd, inode->i_private); | |
1010 | +} | |
1011 | + | |
1012 | +static struct file_operations debugdvfs_fops = { | |
1013 | + .open = dvfs_dbg_open, | |
1014 | + .read = seq_read, | |
1015 | + .llseek = seq_lseek, | |
1016 | + .release = single_release, | |
1017 | +}; | |
1018 | + | |
1019 | +static struct dentry __initdata *dvfsdebugfs_dir; | |
1020 | + | |
1021 | +static void __init dvfs_dbg_init(struct omap_vdd_dvfs_info *dvfs_info) | |
1022 | +{ | |
1023 | + struct dentry *ddir; | |
1024 | + | |
1025 | + /* create a base dir */ | |
1026 | + if (!dvfsdebugfs_dir) | |
1027 | + dvfsdebugfs_dir = debugfs_create_dir("dvfs", NULL); | |
1028 | + if (IS_ERR_OR_NULL(dvfsdebugfs_dir)) { | |
1029 | + WARN_ONCE("%s: Unable to create base DVFS dir\n", __func__); | |
1030 | + return; | |
1031 | + } | |
1032 | + | |
1033 | + if (IS_ERR_OR_NULL(dvfs_info->voltdm)) { | |
1034 | + pr_err("%s: no voltdm\n", __func__); | |
1035 | + return; | |
1036 | + } | |
1037 | + | |
1038 | + ddir = debugfs_create_dir(dvfs_info->voltdm->name, dvfsdebugfs_dir); | |
1039 | + if (IS_ERR_OR_NULL(ddir)) { | |
1040 | + pr_warning("%s: unable to create subdir %s\n", __func__, | |
1041 | + dvfs_info->voltdm->name); | |
1042 | + return; | |
1043 | + } | |
1044 | + | |
1045 | + debugfs_create_file("info", S_IRUGO, ddir, | |
1046 | + (void *)dvfs_info, &debugdvfs_fops); | |
1047 | +} | |
1048 | +#else /* CONFIG_PM_DEBUG */ | |
1049 | +static inline void dvfs_dbg_init(struct omap_vdd_dvfs_info *dvfs_info) | |
1050 | +{ | |
1051 | + return; | |
1052 | +} | |
1053 | +#endif /* CONFIG_PM_DEBUG */ | |
1054 | + | |
883 | 1055 | /** |
884 | 1056 | * omap_dvfs_register_device - Add a parent device into dvfs managed list |
885 | 1057 | * @dev: Device to be added |
... | ... | @@ -940,6 +1112,8 @@ |
940 | 1112 | INIT_LIST_HEAD(&dvfs_info->dev_list); |
941 | 1113 | |
942 | 1114 | list_add(&dvfs_info->node, &omap_dvfs_info_list); |
1115 | + | |
1116 | + dvfs_dbg_init(dvfs_info); | |
943 | 1117 | } |
944 | 1118 | |
945 | 1119 | /* If device already added, we dont need to do more.. */ |