1 /*
2 *
3 * (C) COPYRIGHT 2017 ARM Limited. All rights reserved.
4 *
5 * This program is free software and is provided to you under the terms of the
6 * GNU General Public License version 2 as published by the Free Software
7 * Foundation, and any use by you of this program is subject to the terms
8 * of such GNU licence.
9 *
10 * A copy of the licence is included with the program, and can also be obtained
11 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
12 * Boston, MA 02110-1301, USA.
13 *
14 */
15
16
17
18 #include <linux/debugfs.h>
19 #include <linux/list.h>
20 #include <linux/mutex.h>
21
22 #include "mali_kbase.h"
23 #include "mali_kbase_ipa.h"
24 #include "mali_kbase_ipa_debugfs.h"
25
26 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0))
27 #define DEFINE_DEBUGFS_ATTRIBUTE DEFINE_SIMPLE_ATTRIBUTE
28 #endif
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 int err = 0;
60
61 if (sval < S32_MIN || sval > S32_MAX)
62 return -ERANGE;
63
64 mutex_lock(¶m->model->kbdev->ipa.lock);
65 *param->addr.s32p = val;
66 err = kbase_ipa_model_recalculate(model);
67 mutex_unlock(¶m->model->kbdev->ipa.lock);
68
69 return err;
70 }
71
72 DEFINE_DEBUGFS_ATTRIBUTE(fops_s32, param_int_get, param_int_set, "%lld\n");
73
param_string_get(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)74 static ssize_t param_string_get(struct file *file, char __user *user_buf,
75 size_t count, loff_t *ppos)
76 {
77 struct kbase_ipa_model_param *param = file->private_data;
78 ssize_t ret;
79 size_t len;
80
81 mutex_lock(¶m->model->kbdev->ipa.lock);
82 len = strnlen(param->addr.str, param->size - 1) + 1;
83 ret = simple_read_from_buffer(user_buf, count, ppos,
84 param->addr.str, len);
85 mutex_unlock(¶m->model->kbdev->ipa.lock);
86
87 return ret;
88 }
89
param_string_set(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)90 static ssize_t param_string_set(struct file *file, const char __user *user_buf,
91 size_t count, loff_t *ppos)
92 {
93 struct kbase_ipa_model_param *param = file->private_data;
94 struct kbase_ipa_model *model = param->model;
95 ssize_t ret = count;
96 size_t buf_size;
97 int err;
98
99 mutex_lock(&model->kbdev->ipa.lock);
100
101 if (count > param->size) {
102 ret = -EINVAL;
103 goto end;
104 }
105
106 buf_size = min(param->size - 1, count);
107 if (copy_from_user(param->addr.str, user_buf, buf_size)) {
108 ret = -EFAULT;
109 goto end;
110 }
111
112 param->addr.str[buf_size] = '\0';
113
114 err = kbase_ipa_model_recalculate(model);
115 if (err < 0)
116 ret = err;
117
118 end:
119 mutex_unlock(&model->kbdev->ipa.lock);
120
121 return ret;
122 }
123
124 static const struct file_operations fops_string = {
125 .read = param_string_get,
126 .write = param_string_set,
127 .open = simple_open,
128 .llseek = default_llseek,
129 };
130
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)131 int kbase_ipa_model_param_add(struct kbase_ipa_model *model, const char *name,
132 void *addr, size_t size,
133 enum kbase_ipa_model_param_type type)
134 {
135 struct kbase_ipa_model_param *param;
136
137 param = kzalloc(sizeof(*param), GFP_KERNEL);
138
139 if (!param)
140 return -ENOMEM;
141
142 /* 'name' is stack-allocated for array elements, so copy it into
143 * heap-allocated storage */
144 param->name = kstrdup(name, GFP_KERNEL);
145 param->addr.voidp = addr;
146 param->size = size;
147 param->type = type;
148 param->model = model;
149
150 list_add(¶m->link, &model->params);
151
152 return 0;
153 }
154
kbase_ipa_model_param_free_all(struct kbase_ipa_model * model)155 void kbase_ipa_model_param_free_all(struct kbase_ipa_model *model)
156 {
157 struct kbase_ipa_model_param *param_p, *param_n;
158
159 list_for_each_entry_safe(param_p, param_n, &model->params, link) {
160 list_del(¶m_p->link);
161 kfree(param_p->name);
162 kfree(param_p);
163 }
164 }
165
kbase_ipa_model_debugfs_init(struct kbase_ipa_model * model)166 static void kbase_ipa_model_debugfs_init(struct kbase_ipa_model *model)
167 {
168 struct list_head *it;
169 struct dentry *dir;
170
171 lockdep_assert_held(&model->kbdev->ipa.lock);
172
173 dir = debugfs_create_dir(model->ops->name,
174 model->kbdev->mali_debugfs_directory);
175
176 if (!dir) {
177 dev_err(model->kbdev->dev,
178 "Couldn't create mali debugfs %s directory",
179 model->ops->name);
180 return;
181 }
182
183 list_for_each(it, &model->params) {
184 struct kbase_ipa_model_param *param =
185 list_entry(it,
186 struct kbase_ipa_model_param,
187 link);
188 const struct file_operations *fops = NULL;
189
190 switch (param->type) {
191 case PARAM_TYPE_S32:
192 fops = &fops_s32;
193 break;
194 case PARAM_TYPE_STRING:
195 fops = &fops_string;
196 break;
197 }
198
199 if (unlikely(!fops)) {
200 dev_err(model->kbdev->dev,
201 "Type not set for %s parameter %s\n",
202 model->ops->name, param->name);
203 } else {
204 debugfs_create_file(param->name, S_IRUGO | S_IWUSR,
205 dir, param, fops);
206 }
207 }
208 }
209
kbase_ipa_debugfs_init(struct kbase_device * kbdev)210 void kbase_ipa_debugfs_init(struct kbase_device *kbdev)
211 {
212 mutex_lock(&kbdev->ipa.lock);
213
214 if (kbdev->ipa.configured_model != kbdev->ipa.fallback_model)
215 kbase_ipa_model_debugfs_init(kbdev->ipa.configured_model);
216 kbase_ipa_model_debugfs_init(kbdev->ipa.fallback_model);
217
218 mutex_unlock(&kbdev->ipa.lock);
219 }
220