1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
2 /*
3 *
4 * (C) COPYRIGHT 2017-2022 ARM Limited. All rights reserved.
5 *
6 * This program is free software and is provided to you under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation, and any use by you of this program is subject to the terms
9 * of such GNU license.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can access it online at
18 * http://www.gnu.org/licenses/gpl-2.0.html.
19 *
20 */
21
22 #include <linux/debugfs.h>
23 #include <linux/list.h>
24 #include <linux/mutex.h>
25
26 #include "mali_kbase.h"
27 #include "mali_kbase_ipa.h"
28 #include "mali_kbase_ipa_debugfs.h"
29
30 struct kbase_ipa_model_param {
31 char *name;
32 union {
33 void *voidp;
34 s32 *s32p;
35 char *str;
36 } addr;
37 size_t size;
38 enum kbase_ipa_model_param_type type;
39 struct kbase_ipa_model *model;
40 struct list_head link;
41 };
42
param_int_get(void * data,u64 * val)43 static int param_int_get(void *data, u64 *val)
44 {
45 struct kbase_ipa_model_param *param = data;
46
47 mutex_lock(¶m->model->kbdev->ipa.lock);
48 *(s64 *) val = *param->addr.s32p;
49 mutex_unlock(¶m->model->kbdev->ipa.lock);
50
51 return 0;
52 }
53
param_int_set(void * data,u64 val)54 static int param_int_set(void *data, u64 val)
55 {
56 struct kbase_ipa_model_param *param = data;
57 struct kbase_ipa_model *model = param->model;
58 s64 sval = (s64) val;
59 s32 old_val;
60 int err = 0;
61
62 if (sval < S32_MIN || sval > S32_MAX)
63 return -ERANGE;
64
65 mutex_lock(¶m->model->kbdev->ipa.lock);
66 old_val = *param->addr.s32p;
67 *param->addr.s32p = val;
68 err = kbase_ipa_model_recalculate(model);
69 if (err < 0)
70 *param->addr.s32p = old_val;
71 mutex_unlock(¶m->model->kbdev->ipa.lock);
72
73 return err;
74 }
75
76 DEFINE_DEBUGFS_ATTRIBUTE(fops_s32, param_int_get, param_int_set, "%lld\n");
77
param_string_get(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)78 static ssize_t param_string_get(struct file *file, char __user *user_buf,
79 size_t count, loff_t *ppos)
80 {
81 struct kbase_ipa_model_param *param = file->private_data;
82 ssize_t ret;
83 size_t len;
84
85 mutex_lock(¶m->model->kbdev->ipa.lock);
86 len = strnlen(param->addr.str, param->size - 1) + 1;
87 ret = simple_read_from_buffer(user_buf, count, ppos,
88 param->addr.str, len);
89 mutex_unlock(¶m->model->kbdev->ipa.lock);
90
91 return ret;
92 }
93
param_string_set(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)94 static ssize_t param_string_set(struct file *file, const char __user *user_buf,
95 size_t count, loff_t *ppos)
96 {
97 struct kbase_ipa_model_param *param = file->private_data;
98 struct kbase_ipa_model *model = param->model;
99 char *old_str = NULL;
100 ssize_t ret = count;
101 size_t buf_size;
102 int err;
103
104 mutex_lock(&model->kbdev->ipa.lock);
105
106 if (count > param->size) {
107 ret = -EINVAL;
108 goto end;
109 }
110
111 old_str = kstrndup(param->addr.str, param->size, GFP_KERNEL);
112 if (!old_str) {
113 ret = -ENOMEM;
114 goto end;
115 }
116
117 buf_size = min(param->size - 1, count);
118 if (copy_from_user(param->addr.str, user_buf, buf_size)) {
119 ret = -EFAULT;
120 goto end;
121 }
122
123 param->addr.str[buf_size] = '\0';
124
125 err = kbase_ipa_model_recalculate(model);
126 if (err < 0) {
127 u32 string_len = strscpy(param->addr.str, old_str, param->size);
128
129 string_len += sizeof(char);
130 /* Make sure that the source string fit into the buffer. */
131 KBASE_DEBUG_ASSERT(string_len <= param->size);
132 CSTD_UNUSED(string_len);
133
134 ret = err;
135 }
136
137 end:
138 kfree(old_str);
139 mutex_unlock(&model->kbdev->ipa.lock);
140
141 return ret;
142 }
143
144 static const struct file_operations fops_string = {
145 .owner = THIS_MODULE,
146 .read = param_string_get,
147 .write = param_string_set,
148 .open = simple_open,
149 .llseek = default_llseek,
150 };
151
kbase_ipa_model_param_add(struct kbase_ipa_model * model,const char * name,void * addr,size_t size,enum kbase_ipa_model_param_type type)152 int kbase_ipa_model_param_add(struct kbase_ipa_model *model, const char *name,
153 void *addr, size_t size,
154 enum kbase_ipa_model_param_type type)
155 {
156 struct kbase_ipa_model_param *param;
157
158 param = kzalloc(sizeof(*param), GFP_KERNEL);
159
160 if (!param)
161 return -ENOMEM;
162
163 /* 'name' is stack-allocated for array elements, so copy it into
164 * heap-allocated storage
165 */
166 param->name = kstrdup(name, GFP_KERNEL);
167
168 if (!param->name) {
169 kfree(param);
170 return -ENOMEM;
171 }
172
173 param->addr.voidp = addr;
174 param->size = size;
175 param->type = type;
176 param->model = model;
177
178 list_add(¶m->link, &model->params);
179
180 return 0;
181 }
182
kbase_ipa_model_param_free_all(struct kbase_ipa_model * model)183 void kbase_ipa_model_param_free_all(struct kbase_ipa_model *model)
184 {
185 struct kbase_ipa_model_param *param_p, *param_n;
186
187 list_for_each_entry_safe(param_p, param_n, &model->params, link) {
188 list_del(¶m_p->link);
189 kfree(param_p->name);
190 kfree(param_p);
191 }
192 }
193
force_fallback_model_get(void * data,u64 * val)194 static int force_fallback_model_get(void *data, u64 *val)
195 {
196 struct kbase_device *kbdev = data;
197
198 mutex_lock(&kbdev->ipa.lock);
199 *val = kbdev->ipa.force_fallback_model;
200 mutex_unlock(&kbdev->ipa.lock);
201
202 return 0;
203 }
204
force_fallback_model_set(void * data,u64 val)205 static int force_fallback_model_set(void *data, u64 val)
206 {
207 struct kbase_device *kbdev = data;
208
209 mutex_lock(&kbdev->ipa.lock);
210 kbdev->ipa.force_fallback_model = (val ? true : false);
211 mutex_unlock(&kbdev->ipa.lock);
212
213 return 0;
214 }
215
216 DEFINE_DEBUGFS_ATTRIBUTE(force_fallback_model,
217 force_fallback_model_get,
218 force_fallback_model_set,
219 "%llu\n");
220
current_power_get(void * data,u64 * val)221 static int current_power_get(void *data, u64 *val)
222 {
223 struct kbase_device *kbdev = data;
224 struct devfreq *df = kbdev->devfreq;
225 u32 power;
226
227 kbase_pm_context_active(kbdev);
228 /* The current model assumes that there's no more than one voltage
229 * regulator currently available in the system.
230 */
231 kbase_get_real_power(df, &power,
232 kbdev->current_nominal_freq,
233 (kbdev->current_voltages[0] / 1000));
234 kbase_pm_context_idle(kbdev);
235
236 *val = power;
237
238 return 0;
239 }
240 DEFINE_DEBUGFS_ATTRIBUTE(current_power, current_power_get, NULL, "%llu\n");
241
kbase_ipa_model_debugfs_init(struct kbase_ipa_model * model)242 static void kbase_ipa_model_debugfs_init(struct kbase_ipa_model *model)
243 {
244 struct list_head *it;
245 struct dentry *dir;
246
247 lockdep_assert_held(&model->kbdev->ipa.lock);
248
249 dir = debugfs_create_dir(model->ops->name,
250 model->kbdev->mali_debugfs_directory);
251
252 if (IS_ERR_OR_NULL(dir)) {
253 dev_err(model->kbdev->dev,
254 "Couldn't create mali debugfs %s directory",
255 model->ops->name);
256 return;
257 }
258
259 list_for_each(it, &model->params) {
260 struct kbase_ipa_model_param *param =
261 list_entry(it,
262 struct kbase_ipa_model_param,
263 link);
264 const struct file_operations *fops = NULL;
265
266 switch (param->type) {
267 case PARAM_TYPE_S32:
268 fops = &fops_s32;
269 break;
270 case PARAM_TYPE_STRING:
271 fops = &fops_string;
272 break;
273 }
274
275 if (unlikely(!fops)) {
276 dev_err(model->kbdev->dev,
277 "Type not set for %s parameter %s\n",
278 model->ops->name, param->name);
279 } else {
280 debugfs_create_file(param->name, 0644,
281 dir, param, fops);
282 }
283 }
284 }
285
kbase_ipa_model_param_set_s32(struct kbase_ipa_model * model,const char * name,s32 val)286 void kbase_ipa_model_param_set_s32(struct kbase_ipa_model *model,
287 const char *name, s32 val)
288 {
289 struct kbase_ipa_model_param *param;
290
291 mutex_lock(&model->kbdev->ipa.lock);
292
293 list_for_each_entry(param, &model->params, link) {
294 if (!strcmp(param->name, name)) {
295 if (param->type == PARAM_TYPE_S32) {
296 *param->addr.s32p = val;
297 } else {
298 dev_err(model->kbdev->dev,
299 "Wrong type for %s parameter %s\n",
300 model->ops->name, param->name);
301 }
302 break;
303 }
304 }
305
306 mutex_unlock(&model->kbdev->ipa.lock);
307 }
308 KBASE_EXPORT_TEST_API(kbase_ipa_model_param_set_s32);
309
kbase_ipa_debugfs_init(struct kbase_device * kbdev)310 void kbase_ipa_debugfs_init(struct kbase_device *kbdev)
311 {
312 mutex_lock(&kbdev->ipa.lock);
313
314 if (kbdev->ipa.configured_model != kbdev->ipa.fallback_model)
315 kbase_ipa_model_debugfs_init(kbdev->ipa.configured_model);
316 kbase_ipa_model_debugfs_init(kbdev->ipa.fallback_model);
317
318 debugfs_create_file("ipa_current_power", 0444,
319 kbdev->mali_debugfs_directory, kbdev, ¤t_power);
320 debugfs_create_file("ipa_force_fallback_model", 0644,
321 kbdev->mali_debugfs_directory, kbdev, &force_fallback_model);
322
323 mutex_unlock(&kbdev->ipa.lock);
324 }
325