.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Generic OPP debugfs interface |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2015-2016 Viresh Kumar <viresh.kumar@linaro.org> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 as |
---|
8 | | - * published by the Free Software Foundation. |
---|
9 | 6 | */ |
---|
10 | 7 | |
---|
11 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
.. | .. |
---|
35 | 32 | debugfs_remove_recursive(opp->dentry); |
---|
36 | 33 | } |
---|
37 | 34 | |
---|
38 | | -static bool opp_debug_create_supplies(struct dev_pm_opp *opp, |
---|
| 35 | +static ssize_t bw_name_read(struct file *fp, char __user *userbuf, |
---|
| 36 | + size_t count, loff_t *ppos) |
---|
| 37 | +{ |
---|
| 38 | + struct icc_path *path = fp->private_data; |
---|
| 39 | + char buf[64]; |
---|
| 40 | + int i; |
---|
| 41 | + |
---|
| 42 | + i = scnprintf(buf, sizeof(buf), "%.62s\n", icc_get_name(path)); |
---|
| 43 | + |
---|
| 44 | + return simple_read_from_buffer(userbuf, count, ppos, buf, i); |
---|
| 45 | +} |
---|
| 46 | + |
---|
| 47 | +static const struct file_operations bw_name_fops = { |
---|
| 48 | + .open = simple_open, |
---|
| 49 | + .read = bw_name_read, |
---|
| 50 | + .llseek = default_llseek, |
---|
| 51 | +}; |
---|
| 52 | + |
---|
| 53 | +static void opp_debug_create_bw(struct dev_pm_opp *opp, |
---|
| 54 | + struct opp_table *opp_table, |
---|
| 55 | + struct dentry *pdentry) |
---|
| 56 | +{ |
---|
| 57 | + struct dentry *d; |
---|
| 58 | + char name[11]; |
---|
| 59 | + int i; |
---|
| 60 | + |
---|
| 61 | + for (i = 0; i < opp_table->path_count; i++) { |
---|
| 62 | + snprintf(name, sizeof(name), "icc-path-%.1d", i); |
---|
| 63 | + |
---|
| 64 | + /* Create per-path directory */ |
---|
| 65 | + d = debugfs_create_dir(name, pdentry); |
---|
| 66 | + |
---|
| 67 | + debugfs_create_file("name", S_IRUGO, d, opp_table->paths[i], |
---|
| 68 | + &bw_name_fops); |
---|
| 69 | + debugfs_create_u32("peak_bw", S_IRUGO, d, |
---|
| 70 | + &opp->bandwidth[i].peak); |
---|
| 71 | + debugfs_create_u32("avg_bw", S_IRUGO, d, |
---|
| 72 | + &opp->bandwidth[i].avg); |
---|
| 73 | + } |
---|
| 74 | +} |
---|
| 75 | + |
---|
| 76 | +static void opp_debug_create_supplies(struct dev_pm_opp *opp, |
---|
39 | 77 | struct opp_table *opp_table, |
---|
40 | 78 | struct dentry *pdentry) |
---|
41 | 79 | { |
---|
.. | .. |
---|
50 | 88 | /* Create per-opp directory */ |
---|
51 | 89 | d = debugfs_create_dir(name, pdentry); |
---|
52 | 90 | |
---|
53 | | - if (!d) |
---|
54 | | - return false; |
---|
| 91 | + debugfs_create_ulong("u_volt_target", S_IRUGO, d, |
---|
| 92 | + &opp->supplies[i].u_volt); |
---|
55 | 93 | |
---|
56 | | - if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, |
---|
57 | | - &opp->supplies[i].u_volt)) |
---|
58 | | - return false; |
---|
| 94 | + debugfs_create_ulong("u_volt_min", S_IRUGO, d, |
---|
| 95 | + &opp->supplies[i].u_volt_min); |
---|
59 | 96 | |
---|
60 | | - if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, |
---|
61 | | - &opp->supplies[i].u_volt_min)) |
---|
62 | | - return false; |
---|
| 97 | + debugfs_create_ulong("u_volt_max", S_IRUGO, d, |
---|
| 98 | + &opp->supplies[i].u_volt_max); |
---|
63 | 99 | |
---|
64 | | - if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, |
---|
65 | | - &opp->supplies[i].u_volt_max)) |
---|
66 | | - return false; |
---|
67 | | - |
---|
68 | | - if (!debugfs_create_ulong("u_amp", S_IRUGO, d, |
---|
69 | | - &opp->supplies[i].u_amp)) |
---|
70 | | - return false; |
---|
| 100 | + debugfs_create_ulong("u_amp", S_IRUGO, d, |
---|
| 101 | + &opp->supplies[i].u_amp); |
---|
71 | 102 | } |
---|
72 | | - |
---|
73 | | - return true; |
---|
74 | 103 | } |
---|
75 | 104 | |
---|
76 | | -int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) |
---|
| 105 | +void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table) |
---|
77 | 106 | { |
---|
78 | 107 | struct dentry *pdentry = opp_table->dentry; |
---|
79 | 108 | struct dentry *d; |
---|
.. | .. |
---|
95 | 124 | |
---|
96 | 125 | /* Create per-opp directory */ |
---|
97 | 126 | d = debugfs_create_dir(name, pdentry); |
---|
98 | | - if (!d) |
---|
99 | | - return -ENOMEM; |
---|
100 | 127 | |
---|
101 | | - if (!debugfs_create_bool("available", S_IRUGO, d, &opp->available)) |
---|
102 | | - return -ENOMEM; |
---|
| 128 | + debugfs_create_bool("available", S_IRUGO, d, &opp->available); |
---|
| 129 | + debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic); |
---|
| 130 | + debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo); |
---|
| 131 | + debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend); |
---|
| 132 | + debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate); |
---|
| 133 | + debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate); |
---|
| 134 | + debugfs_create_ulong("clock_latency_ns", S_IRUGO, d, |
---|
| 135 | + &opp->clock_latency_ns); |
---|
103 | 136 | |
---|
104 | | - if (!debugfs_create_bool("dynamic", S_IRUGO, d, &opp->dynamic)) |
---|
105 | | - return -ENOMEM; |
---|
106 | | - |
---|
107 | | - if (!debugfs_create_bool("turbo", S_IRUGO, d, &opp->turbo)) |
---|
108 | | - return -ENOMEM; |
---|
109 | | - |
---|
110 | | - if (!debugfs_create_bool("suspend", S_IRUGO, d, &opp->suspend)) |
---|
111 | | - return -ENOMEM; |
---|
112 | | - |
---|
113 | | - if (!debugfs_create_u32("performance_state", S_IRUGO, d, &opp->pstate)) |
---|
114 | | - return -ENOMEM; |
---|
115 | | - |
---|
116 | | - if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate)) |
---|
117 | | - return -ENOMEM; |
---|
118 | | - |
---|
119 | | - if (!opp_debug_create_supplies(opp, opp_table, d)) |
---|
120 | | - return -ENOMEM; |
---|
121 | | - |
---|
122 | | - if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d, |
---|
123 | | - &opp->clock_latency_ns)) |
---|
124 | | - return -ENOMEM; |
---|
| 137 | + opp_debug_create_supplies(opp, opp_table, d); |
---|
| 138 | + opp_debug_create_bw(opp, opp_table, d); |
---|
125 | 139 | |
---|
126 | 140 | opp->dentry = d; |
---|
127 | | - return 0; |
---|
128 | 141 | } |
---|
129 | 142 | |
---|
130 | | -static int opp_list_debug_create_dir(struct opp_device *opp_dev, |
---|
131 | | - struct opp_table *opp_table) |
---|
| 143 | +static void opp_list_debug_create_dir(struct opp_device *opp_dev, |
---|
| 144 | + struct opp_table *opp_table) |
---|
132 | 145 | { |
---|
133 | 146 | const struct device *dev = opp_dev->dev; |
---|
134 | 147 | struct dentry *d; |
---|
.. | .. |
---|
137 | 150 | |
---|
138 | 151 | /* Create device specific directory */ |
---|
139 | 152 | d = debugfs_create_dir(opp_table->dentry_name, rootdir); |
---|
140 | | - if (!d) { |
---|
141 | | - dev_err(dev, "%s: Failed to create debugfs dir\n", __func__); |
---|
142 | | - return -ENOMEM; |
---|
143 | | - } |
---|
144 | 153 | |
---|
145 | 154 | opp_dev->dentry = d; |
---|
146 | 155 | opp_table->dentry = d; |
---|
147 | | - |
---|
148 | | - return 0; |
---|
149 | 156 | } |
---|
150 | 157 | |
---|
151 | | -static int opp_list_debug_create_link(struct opp_device *opp_dev, |
---|
152 | | - struct opp_table *opp_table) |
---|
| 158 | +static void opp_list_debug_create_link(struct opp_device *opp_dev, |
---|
| 159 | + struct opp_table *opp_table) |
---|
153 | 160 | { |
---|
154 | | - const struct device *dev = opp_dev->dev; |
---|
155 | 161 | char name[NAME_MAX]; |
---|
156 | | - struct dentry *d; |
---|
157 | 162 | |
---|
158 | 163 | opp_set_dev_name(opp_dev->dev, name); |
---|
159 | 164 | |
---|
160 | 165 | /* Create device specific directory link */ |
---|
161 | | - d = debugfs_create_symlink(name, rootdir, opp_table->dentry_name); |
---|
162 | | - if (!d) { |
---|
163 | | - dev_err(dev, "%s: Failed to create link\n", __func__); |
---|
164 | | - return -ENOMEM; |
---|
165 | | - } |
---|
166 | | - |
---|
167 | | - opp_dev->dentry = d; |
---|
168 | | - |
---|
169 | | - return 0; |
---|
| 166 | + opp_dev->dentry = debugfs_create_symlink(name, rootdir, |
---|
| 167 | + opp_table->dentry_name); |
---|
170 | 168 | } |
---|
171 | 169 | |
---|
172 | 170 | /** |
---|
.. | .. |
---|
177 | 175 | * Dynamically adds device specific directory in debugfs 'opp' directory. If the |
---|
178 | 176 | * device-opp is shared with other devices, then links will be created for all |
---|
179 | 177 | * devices except the first. |
---|
180 | | - * |
---|
181 | | - * Return: 0 on success, otherwise negative error. |
---|
182 | 178 | */ |
---|
183 | | -int opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table) |
---|
| 179 | +void opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table) |
---|
184 | 180 | { |
---|
185 | | - if (!rootdir) { |
---|
186 | | - pr_debug("%s: Uninitialized rootdir\n", __func__); |
---|
187 | | - return -EINVAL; |
---|
188 | | - } |
---|
189 | | - |
---|
190 | 181 | if (opp_table->dentry) |
---|
191 | | - return opp_list_debug_create_link(opp_dev, opp_table); |
---|
192 | | - |
---|
193 | | - return opp_list_debug_create_dir(opp_dev, opp_table); |
---|
| 182 | + opp_list_debug_create_link(opp_dev, opp_table); |
---|
| 183 | + else |
---|
| 184 | + opp_list_debug_create_dir(opp_dev, opp_table); |
---|
194 | 185 | } |
---|
195 | 186 | |
---|
196 | 187 | static void opp_migrate_dentry(struct opp_device *opp_dev, |
---|
.. | .. |
---|
213 | 204 | |
---|
214 | 205 | dentry = debugfs_rename(rootdir, opp_dev->dentry, rootdir, |
---|
215 | 206 | opp_table->dentry_name); |
---|
216 | | - if (!dentry) { |
---|
| 207 | + if (IS_ERR(dentry)) { |
---|
217 | 208 | dev_err(dev, "%s: Failed to rename link from: %s to %s\n", |
---|
218 | 209 | __func__, dev_name(opp_dev->dev), dev_name(dev)); |
---|
219 | 210 | return; |
---|
.. | .. |
---|
248 | 239 | opp_dev->dentry = NULL; |
---|
249 | 240 | } |
---|
250 | 241 | |
---|
| 242 | +static int opp_summary_show(struct seq_file *s, void *data) |
---|
| 243 | +{ |
---|
| 244 | + struct list_head *lists = (struct list_head *)s->private; |
---|
| 245 | + struct opp_table *opp_table; |
---|
| 246 | + struct dev_pm_opp *opp; |
---|
| 247 | + |
---|
| 248 | + mutex_lock(&opp_table_lock); |
---|
| 249 | + |
---|
| 250 | + seq_puts(s, " device rate(Hz) target(uV) min(uV) max(uV)\n"); |
---|
| 251 | + seq_puts(s, "-------------------------------------------------------------------\n"); |
---|
| 252 | + |
---|
| 253 | + list_for_each_entry(opp_table, lists, node) { |
---|
| 254 | + seq_printf(s, " %s\n", opp_table->dentry_name); |
---|
| 255 | + mutex_lock(&opp_table->lock); |
---|
| 256 | + list_for_each_entry(opp, &opp_table->opp_list, node) { |
---|
| 257 | + if (!opp->available) |
---|
| 258 | + continue; |
---|
| 259 | + seq_printf(s, "%31lu %12lu %11lu %11lu\n", |
---|
| 260 | + opp->rate, |
---|
| 261 | + opp->supplies[0].u_volt, |
---|
| 262 | + opp->supplies[0].u_volt_min, |
---|
| 263 | + opp->supplies[0].u_volt_max); |
---|
| 264 | + if (opp_table->regulator_count > 1) |
---|
| 265 | + seq_printf(s, "%44lu %11lu %11lu\n", |
---|
| 266 | + opp->supplies[1].u_volt, |
---|
| 267 | + opp->supplies[1].u_volt_min, |
---|
| 268 | + opp->supplies[1].u_volt_max); |
---|
| 269 | + } |
---|
| 270 | + mutex_unlock(&opp_table->lock); |
---|
| 271 | + } |
---|
| 272 | + |
---|
| 273 | + mutex_unlock(&opp_table_lock); |
---|
| 274 | + |
---|
| 275 | + return 0; |
---|
| 276 | +} |
---|
| 277 | + |
---|
| 278 | +static int opp_summary_open(struct inode *inode, struct file *file) |
---|
| 279 | +{ |
---|
| 280 | + return single_open(file, opp_summary_show, inode->i_private); |
---|
| 281 | +} |
---|
| 282 | + |
---|
| 283 | +static const struct file_operations opp_summary_fops = { |
---|
| 284 | + .open = opp_summary_open, |
---|
| 285 | + .read = seq_read, |
---|
| 286 | + .llseek = seq_lseek, |
---|
| 287 | + .release = single_release, |
---|
| 288 | +}; |
---|
| 289 | + |
---|
251 | 290 | static int __init opp_debug_init(void) |
---|
252 | 291 | { |
---|
253 | 292 | /* Create /sys/kernel/debug/opp directory */ |
---|
254 | 293 | rootdir = debugfs_create_dir("opp", NULL); |
---|
255 | | - if (!rootdir) { |
---|
256 | | - pr_err("%s: Failed to create root directory\n", __func__); |
---|
257 | | - return -ENOMEM; |
---|
258 | | - } |
---|
| 294 | + |
---|
| 295 | + debugfs_create_file("opp_summary", 0444, rootdir, &opp_tables, |
---|
| 296 | + &opp_summary_fops); |
---|
259 | 297 | |
---|
260 | 298 | return 0; |
---|
261 | 299 | } |
---|
262 | | -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT |
---|
263 | | -core_initcall_sync(opp_debug_init); |
---|
264 | | -#else |
---|
265 | 300 | core_initcall(opp_debug_init); |
---|
266 | | -#endif |
---|