blob: 00f60bb29c00ab1d7daafebdb51de04f81825956 [file] [log] [blame]
Shrenuj Bansala419c792016-10-20 14:05:11 -07001/* Copyright (c) 2002,2008-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/debugfs.h>
16
17#include "kgsl.h"
18#include "kgsl_device.h"
19#include "kgsl_sharedmem.h"
20#include "kgsl_debugfs.h"
21
22/*default log levels is error for everything*/
23#define KGSL_LOG_LEVEL_MAX 7
24
25struct dentry *kgsl_debugfs_dir;
26static struct dentry *proc_d_debugfs;
27
28static inline int kgsl_log_set(unsigned int *log_val, void *data, u64 val)
29{
30 *log_val = min_t(unsigned int, val, KGSL_LOG_LEVEL_MAX);
31 return 0;
32}
33
34#define KGSL_DEBUGFS_LOG(__log) \
35static int __log ## _set(void *data, u64 val) \
36{ \
37 struct kgsl_device *device = data; \
38 return kgsl_log_set(&device->__log, data, val); \
39} \
40static int __log ## _get(void *data, u64 *val) \
41{ \
42 struct kgsl_device *device = data; \
43 *val = device->__log; \
44 return 0; \
45} \
46DEFINE_SIMPLE_ATTRIBUTE(__log ## _fops, \
47__log ## _get, __log ## _set, "%llu\n") \
48
49KGSL_DEBUGFS_LOG(drv_log);
50KGSL_DEBUGFS_LOG(cmd_log);
51KGSL_DEBUGFS_LOG(ctxt_log);
52KGSL_DEBUGFS_LOG(mem_log);
53KGSL_DEBUGFS_LOG(pwr_log);
54
55static int _strict_set(void *data, u64 val)
56{
57 kgsl_sharedmem_set_noretry(val ? true : false);
58 return 0;
59}
60
61static int _strict_get(void *data, u64 *val)
62{
63 *val = kgsl_sharedmem_get_noretry();
64 return 0;
65}
66
67DEFINE_SIMPLE_ATTRIBUTE(_strict_fops, _strict_get, _strict_set, "%llu\n");
68
69void kgsl_device_debugfs_init(struct kgsl_device *device)
70{
71 if (kgsl_debugfs_dir && !IS_ERR(kgsl_debugfs_dir))
72 device->d_debugfs = debugfs_create_dir(device->name,
73 kgsl_debugfs_dir);
74
75 if (!device->d_debugfs || IS_ERR(device->d_debugfs))
76 return;
77
78 debugfs_create_file("log_level_cmd", 0644, device->d_debugfs, device,
79 &cmd_log_fops);
80 debugfs_create_file("log_level_ctxt", 0644, device->d_debugfs, device,
81 &ctxt_log_fops);
82 debugfs_create_file("log_level_drv", 0644, device->d_debugfs, device,
83 &drv_log_fops);
84 debugfs_create_file("log_level_mem", 0644, device->d_debugfs, device,
85 &mem_log_fops);
86 debugfs_create_file("log_level_pwr", 0644, device->d_debugfs, device,
87 &pwr_log_fops);
88}
89
Lynus Vaz519dacfd2017-02-14 12:17:37 +053090void kgsl_device_debugfs_close(struct kgsl_device *device)
91{
92 debugfs_remove_recursive(device->d_debugfs);
93}
94
Shrenuj Bansala419c792016-10-20 14:05:11 -070095struct type_entry {
96 int type;
97 const char *str;
98};
99
100static const struct type_entry memtypes[] = { KGSL_MEM_TYPES };
101
102static const char *memtype_str(int memtype)
103{
104 int i;
105
106 for (i = 0; i < ARRAY_SIZE(memtypes); i++)
107 if (memtypes[i].type == memtype)
108 return memtypes[i].str;
109 return "unknown";
110}
111
112static char get_alignflag(const struct kgsl_memdesc *m)
113{
114 int align = kgsl_memdesc_get_align(m);
115
116 if (align >= ilog2(SZ_1M))
117 return 'L';
118 else if (align >= ilog2(SZ_64K))
119 return 'l';
120 return '-';
121}
122
123static char get_cacheflag(const struct kgsl_memdesc *m)
124{
125 static const char table[] = {
126 [KGSL_CACHEMODE_WRITECOMBINE] = '-',
127 [KGSL_CACHEMODE_UNCACHED] = 'u',
128 [KGSL_CACHEMODE_WRITEBACK] = 'b',
129 [KGSL_CACHEMODE_WRITETHROUGH] = 't',
130 };
131
132 return table[kgsl_memdesc_get_cachemode(m)];
133}
134
135
136static int print_mem_entry(void *data, void *ptr)
137{
138 struct seq_file *s = data;
139 struct kgsl_mem_entry *entry = ptr;
140 char flags[10];
141 char usage[16];
142 struct kgsl_memdesc *m = &entry->memdesc;
143 unsigned int usermem_type = kgsl_memdesc_usermem_type(m);
144 int egl_surface_count = 0, egl_image_count = 0;
145
146 if (m->flags & KGSL_MEMFLAGS_SPARSE_VIRT)
147 return 0;
148
149 flags[0] = kgsl_memdesc_is_global(m) ? 'g' : '-';
150 flags[1] = '-';
151 flags[2] = !(m->flags & KGSL_MEMFLAGS_GPUREADONLY) ? 'w' : '-';
152 flags[3] = get_alignflag(m);
153 flags[4] = get_cacheflag(m);
154 flags[5] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-';
Jordan Crouse6bce65c2020-12-28 16:06:42 +0530155 /*
156 * Show Y if at least one vma has this entry
157 * mapped (could be multiple)
158 */
159 flags[6] = atomic_read(&entry->map_count) ? 'Y' : 'N';
Shrenuj Bansala419c792016-10-20 14:05:11 -0700160 flags[7] = kgsl_memdesc_is_secured(m) ? 's' : '-';
161 flags[8] = m->flags & KGSL_MEMFLAGS_SPARSE_PHYS ? 'P' : '-';
162 flags[9] = '\0';
163
164 kgsl_get_memory_usage(usage, sizeof(usage), m->flags);
165
166 if (usermem_type == KGSL_MEM_ENTRY_ION)
167 kgsl_get_egl_counts(entry, &egl_surface_count,
168 &egl_image_count);
169
Jordan Crouse6bce65c2020-12-28 16:06:42 +0530170 seq_printf(s, "%pK %d %16llu %5d %9s %10s %16s %5d %16d %6d %6d",
Shrenuj Bansala419c792016-10-20 14:05:11 -0700171 (uint64_t *)(uintptr_t) m->gpuaddr,
Jordan Crouse6bce65c2020-12-28 16:06:42 +0530172 /*
173 * Show zero for the useraddr - we can't reliably track
174 * that value for multiple vmas anyway
175 */
176 0, m->size, entry->id, flags,
Shrenuj Bansala419c792016-10-20 14:05:11 -0700177 memtype_str(usermem_type),
Jordan Crouse6bce65c2020-12-28 16:06:42 +0530178 usage, (m->sgt ? m->sgt->nents : 0),
179 atomic_read(&entry->map_count),
Shrenuj Bansala419c792016-10-20 14:05:11 -0700180 egl_surface_count, egl_image_count);
181
182 if (entry->metadata[0] != 0)
183 seq_printf(s, " %s", entry->metadata);
184
185 seq_putc(s, '\n');
186
187 return 0;
188}
189
190static struct kgsl_mem_entry *process_mem_seq_find(struct seq_file *s,
191 void *ptr, loff_t pos)
192{
193 struct kgsl_mem_entry *entry = ptr;
194 struct kgsl_process_private *private = s->private;
195 int id = 0;
196
197 loff_t temp_pos = 1;
198
199 if (entry != SEQ_START_TOKEN)
200 id = entry->id + 1;
201
202 spin_lock(&private->mem_lock);
203 for (entry = idr_get_next(&private->mem_idr, &id); entry;
204 id++, entry = idr_get_next(&private->mem_idr, &id),
205 temp_pos++) {
206 if (temp_pos == pos && kgsl_mem_entry_get(entry)) {
207 spin_unlock(&private->mem_lock);
208 goto found;
209 }
210 }
211 spin_unlock(&private->mem_lock);
212
213 entry = NULL;
214found:
215 if (ptr != SEQ_START_TOKEN)
216 kgsl_mem_entry_put(ptr);
217
218 return entry;
219}
220
221static void *process_mem_seq_start(struct seq_file *s, loff_t *pos)
222{
223 loff_t seq_file_offset = *pos;
224
225 if (seq_file_offset == 0)
226 return SEQ_START_TOKEN;
227 else
228 return process_mem_seq_find(s, SEQ_START_TOKEN,
229 seq_file_offset);
230}
231
232static void process_mem_seq_stop(struct seq_file *s, void *ptr)
233{
234 if (ptr && ptr != SEQ_START_TOKEN)
235 kgsl_mem_entry_put(ptr);
236}
237
238static void *process_mem_seq_next(struct seq_file *s, void *ptr,
239 loff_t *pos)
240{
241 ++*pos;
242 return process_mem_seq_find(s, ptr, 1);
243}
244
245static int process_mem_seq_show(struct seq_file *s, void *ptr)
246{
247 if (ptr == SEQ_START_TOKEN) {
248 seq_printf(s, "%16s %16s %16s %5s %9s %10s %16s %5s %16s %6s %6s\n",
249 "gpuaddr", "useraddr", "size", "id", "flags", "type",
Jordan Crouse6bce65c2020-12-28 16:06:42 +0530250 "usage", "sglen", "mapcount", "eglsrf", "eglimg");
Shrenuj Bansala419c792016-10-20 14:05:11 -0700251 return 0;
252 } else
253 return print_mem_entry(s, ptr);
254}
255
256static const struct seq_operations process_mem_seq_fops = {
257 .start = process_mem_seq_start,
258 .stop = process_mem_seq_stop,
259 .next = process_mem_seq_next,
260 .show = process_mem_seq_show,
261};
262
263static int process_mem_open(struct inode *inode, struct file *file)
264{
265 int ret;
266 pid_t pid = (pid_t) (unsigned long) inode->i_private;
267 struct seq_file *s = NULL;
268 struct kgsl_process_private *private = NULL;
269
270 private = kgsl_process_private_find(pid);
271
272 if (!private)
273 return -ENODEV;
274
275 ret = seq_open(file, &process_mem_seq_fops);
276 if (ret)
277 kgsl_process_private_put(private);
278 else {
279 s = file->private_data;
280 s->private = private;
281 }
282
283 return ret;
284}
285
286static int process_mem_release(struct inode *inode, struct file *file)
287{
288 struct kgsl_process_private *private =
289 ((struct seq_file *)file->private_data)->private;
290
291 if (private)
292 kgsl_process_private_put(private);
293
294 return seq_release(inode, file);
295}
296
297static const struct file_operations process_mem_fops = {
298 .open = process_mem_open,
299 .read = seq_read,
300 .llseek = seq_lseek,
301 .release = process_mem_release,
302};
303
304static int print_sparse_mem_entry(int id, void *ptr, void *data)
305{
306 struct seq_file *s = data;
307 struct kgsl_mem_entry *entry = ptr;
308 struct kgsl_memdesc *m = &entry->memdesc;
309 struct rb_node *node;
310
311 if (!(m->flags & KGSL_MEMFLAGS_SPARSE_VIRT))
312 return 0;
313
Lynus Vazdb41c9c2017-10-30 17:50:43 +0530314 spin_lock(&entry->bind_lock);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700315 node = rb_first(&entry->bind_tree);
316
317 while (node != NULL) {
318 struct sparse_bind_object *obj = rb_entry(node,
319 struct sparse_bind_object, node);
320 seq_printf(s, "%5d %16llx %16llx %16llx %16llx\n",
321 entry->id, entry->memdesc.gpuaddr,
322 obj->v_off, obj->size, obj->p_off);
323 node = rb_next(node);
324 }
Lynus Vazdb41c9c2017-10-30 17:50:43 +0530325 spin_unlock(&entry->bind_lock);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700326
327 seq_putc(s, '\n');
328
329 return 0;
330}
331
332static int process_sparse_mem_print(struct seq_file *s, void *unused)
333{
334 struct kgsl_process_private *private = s->private;
335
336 seq_printf(s, "%5s %16s %16s %16s %16s\n",
337 "v_id", "gpuaddr", "v_offset", "v_size", "p_offset");
338
339 spin_lock(&private->mem_lock);
340 idr_for_each(&private->mem_idr, print_sparse_mem_entry, s);
341 spin_unlock(&private->mem_lock);
342
343 return 0;
344}
345
346static int process_sparse_mem_open(struct inode *inode, struct file *file)
347{
348 int ret;
349 pid_t pid = (pid_t) (unsigned long) inode->i_private;
350 struct kgsl_process_private *private = NULL;
351
352 private = kgsl_process_private_find(pid);
353
354 if (!private)
355 return -ENODEV;
356
357 ret = single_open(file, process_sparse_mem_print, private);
358 if (ret)
359 kgsl_process_private_put(private);
360
361 return ret;
362}
363
364static const struct file_operations process_sparse_mem_fops = {
365 .open = process_sparse_mem_open,
366 .read = seq_read,
367 .llseek = seq_lseek,
368 .release = process_mem_release,
369};
370
371static int globals_print(struct seq_file *s, void *unused)
372{
373 kgsl_print_global_pt_entries(s);
374 return 0;
375}
376
377static int globals_open(struct inode *inode, struct file *file)
378{
379 return single_open(file, globals_print, NULL);
380}
381
382static int globals_release(struct inode *inode, struct file *file)
383{
384 return single_release(inode, file);
385}
386
387static const struct file_operations global_fops = {
388 .open = globals_open,
389 .read = seq_read,
390 .llseek = seq_lseek,
391 .release = globals_release,
392};
393
394/**
395 * kgsl_process_init_debugfs() - Initialize debugfs for a process
396 * @private: Pointer to process private structure created for the process
397 *
398 * kgsl_process_init_debugfs() is called at the time of creating the
399 * process struct when a process opens kgsl device for the first time.
400 * This function is not fatal - all we do is print a warning message if
401 * the files can't be created
402 */
403void kgsl_process_init_debugfs(struct kgsl_process_private *private)
404{
405 unsigned char name[16];
406 struct dentry *dentry;
407
408 snprintf(name, sizeof(name), "%d", private->pid);
409
410 private->debug_root = debugfs_create_dir(name, proc_d_debugfs);
411
412 /*
413 * Both debugfs_create_dir() and debugfs_create_file() return
414 * ERR_PTR(-ENODEV) if debugfs is disabled in the kernel but return
415 * NULL on error when it is enabled. For both usages we need to check
416 * for ERROR or NULL and only print a warning on an actual failure
417 * (i.e. - when the return value is NULL)
418 */
419
420 if (IS_ERR_OR_NULL(private->debug_root)) {
421 WARN((private->debug_root == NULL),
422 "Unable to create debugfs dir for %s\n", name);
423 private->debug_root = NULL;
424 return;
425 }
426
427 dentry = debugfs_create_file("mem", 0444, private->debug_root,
428 (void *) ((unsigned long) private->pid), &process_mem_fops);
429
430 if (IS_ERR_OR_NULL(dentry))
431 WARN((dentry == NULL),
432 "Unable to create 'mem' file for %s\n", name);
433
434 dentry = debugfs_create_file("sparse_mem", 0444, private->debug_root,
435 (void *) ((unsigned long) private->pid),
436 &process_sparse_mem_fops);
437
438 if (IS_ERR_OR_NULL(dentry))
439 WARN((dentry == NULL),
440 "Unable to create 'sparse_mem' file for %s\n", name);
441
442}
443
444void kgsl_core_debugfs_init(void)
445{
446 struct dentry *debug_dir;
447
448 kgsl_debugfs_dir = debugfs_create_dir("kgsl", NULL);
449
450 debugfs_create_file("globals", 0444, kgsl_debugfs_dir, NULL,
451 &global_fops);
452
453 debug_dir = debugfs_create_dir("debug", kgsl_debugfs_dir);
454
455 debugfs_create_file("strict_memory", 0644, debug_dir, NULL,
456 &_strict_fops);
457
458 proc_d_debugfs = debugfs_create_dir("proc", kgsl_debugfs_dir);
459}
460
461void kgsl_core_debugfs_close(void)
462{
463 debugfs_remove_recursive(kgsl_debugfs_dir);
464}