blob: 3b8512909e48d97f64bef09c14da909e468e2221 [file] [log] [blame]
Rajesh Kemisettic05883a2018-09-17 11:34:08 +05301/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
Shrenuj Bansala419c792016-10-20 14:05:11 -07002 *
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#include <linux/fs.h>
14#include <linux/kernel.h>
15#include <linux/ctype.h>
16#include <linux/slab.h>
17#include <linux/delay.h>
18#include <linux/uaccess.h>
19#include <linux/vmalloc.h>
20#include <linux/debugfs.h>
21
22#include "adreno.h"
23#include "adreno_profile.h"
24#include "kgsl_sharedmem.h"
25#include "adreno_pm4types.h"
26
27#define ASSIGNS_STR_FORMAT "%.8s:%u "
28
29/*
30 * Raw Data for processing later:
31 * : 3 - timestamp, count, context id
32 * [per counter] - data for each counter
33 * : 1 - Register offset
34 * : 2 - Pre IB register hi/lo value
35 * : 2 - Post IB register hi/lo value
36 * [per counter end]
37 */
38#define SIZE_DATA(cnt) (6 + (cnt) * 5)
39
40/*
41 * Pre-IB command size (in dwords):
42 * : 2 - NOP start identifier
43 * : 4 - timestamp
44 * : 4 - count
45 * : 4 - context id
46 * : 4 - pid
47 * : 4 - tid
48 * : 4 - type
49 * [loop count start] - for each counter to watch
50 * : 4 - Register offset
51 * : 4 - Register read lo
52 * : 4 - Register read high
53 * [loop end]
54 * : 2 - NOP end identifier
55 */
56#define SIZE_PREIB(cnt) (28 + (cnt) * 12)
57
58/*
59 * Post-IB command size (in dwords):
60 * : 2 - NOP start identifier
61 * [loop count start] - for each counter to watch
62 * : 4 - Register read lo
63 * : 4 - Register read high
64 * [loop end]
65 * : 2 - NOP end identifier
66 */
67#define SIZE_POSTIB(cnt) (4 + (cnt) * 8)
68
69/* Counter data + Pre size + post size = total size */
70#define SIZE_SHARED_ENTRY(cnt) (SIZE_DATA(cnt) + SIZE_PREIB(cnt) \
71 + SIZE_POSTIB(cnt))
72
73/*
74 * Space for following string :"%u %u %u %.5s %u "
75 * [count iterations]: "%.8s:%u %llu %llu%c"
76 */
77#define SIZE_PIPE_ENTRY(cnt) (50 + (cnt) * 62)
78#define SIZE_LOG_ENTRY(cnt) (6 + (cnt) * 5)
79
Shrenuj Bansala419c792016-10-20 14:05:11 -070080static inline uint _ib_start(struct adreno_device *adreno_dev,
81 unsigned int *cmds)
82{
83 unsigned int *start = cmds;
84
85 *cmds++ = cp_packet(adreno_dev, CP_NOP, 1);
86 *cmds++ = KGSL_START_OF_PROFILE_IDENTIFIER;
87
88 return cmds - start;
89}
90
91static inline uint _ib_end(struct adreno_device *adreno_dev,
92 unsigned int *cmds)
93{
94 unsigned int *start = cmds;
95
96 *cmds++ = cp_packet(adreno_dev, CP_NOP, 1);
97 *cmds++ = KGSL_END_OF_PROFILE_IDENTIFIER;
98
99 return cmds - start;
100}
101
102static inline uint _ib_cmd_mem_write(struct adreno_device *adreno_dev,
103 uint *cmds, uint64_t gpuaddr, uint val, uint *off)
104{
105 unsigned int *start = cmds;
106
107 *cmds++ = cp_mem_packet(adreno_dev, CP_MEM_WRITE, 2, 1);
108 cmds += cp_gpuaddr(adreno_dev, cmds, gpuaddr);
109 *cmds++ = val;
110
111 *off += sizeof(unsigned int);
112 return cmds - start;
113}
114
115static inline uint _ib_cmd_reg_to_mem(struct adreno_device *adreno_dev,
116 uint *cmds, uint64_t gpuaddr, uint val, uint *off)
117{
118 unsigned int *start = cmds;
119
120 *cmds++ = cp_mem_packet(adreno_dev, CP_REG_TO_MEM, 2, 1);
121 *cmds++ = val;
122 cmds += cp_gpuaddr(adreno_dev, cmds, gpuaddr);
123
124 *off += sizeof(unsigned int);
125 return cmds - start;
126}
127
128static inline int _create_ib_ref(struct adreno_device *adreno_dev,
129 struct kgsl_memdesc *memdesc, unsigned int *cmd,
130 unsigned int cnt, unsigned int off)
131{
132 unsigned int *start = cmd;
133
134 *cmd++ = cp_mem_packet(adreno_dev, CP_INDIRECT_BUFFER_PFE, 2, 1);
135 cmd += cp_gpuaddr(adreno_dev, cmd, (memdesc->gpuaddr + off));
136 *cmd++ = cnt;
137
138 return cmd - start;
139}
140
141static int _build_pre_ib_cmds(struct adreno_device *adreno_dev,
142 struct adreno_profile *profile,
143 unsigned int *rbcmds, unsigned int head,
144 unsigned int timestamp, struct adreno_context *drawctxt)
145{
146 struct adreno_profile_assigns_list *entry;
147 unsigned int *start, *ibcmds;
148 unsigned int count = profile->assignment_count;
149 uint64_t gpuaddr = profile->shared_buffer.gpuaddr;
150 unsigned int ib_offset = head + SIZE_DATA(count);
151 unsigned int data_offset = head * sizeof(unsigned int);
152
153 ibcmds = ib_offset + ((unsigned int *) profile->shared_buffer.hostptr);
154 start = ibcmds;
155
156 /* start of profile identifier */
157 ibcmds += _ib_start(adreno_dev, ibcmds);
158
159 /*
160 * Write ringbuffer commands to save the following to memory:
161 * timestamp, count, context_id, pid, tid, context type
162 */
163 ibcmds += _ib_cmd_mem_write(adreno_dev, ibcmds, gpuaddr + data_offset,
164 timestamp, &data_offset);
165 ibcmds += _ib_cmd_mem_write(adreno_dev, ibcmds, gpuaddr + data_offset,
166 profile->assignment_count, &data_offset);
167 ibcmds += _ib_cmd_mem_write(adreno_dev, ibcmds, gpuaddr + data_offset,
168 drawctxt->base.id, &data_offset);
169 ibcmds += _ib_cmd_mem_write(adreno_dev, ibcmds, gpuaddr + data_offset,
170 drawctxt->base.proc_priv->pid, &data_offset);
171 ibcmds += _ib_cmd_mem_write(adreno_dev, ibcmds, gpuaddr + data_offset,
172 drawctxt->base.tid, &data_offset);
173 ibcmds += _ib_cmd_mem_write(adreno_dev, ibcmds, gpuaddr + data_offset,
174 drawctxt->type, &data_offset);
175
176 /* loop for each countable assigned */
177 list_for_each_entry(entry, &profile->assignments_list, list) {
178 ibcmds += _ib_cmd_mem_write(adreno_dev, ibcmds,
179 gpuaddr + data_offset, entry->offset,
180 &data_offset);
181 ibcmds += _ib_cmd_reg_to_mem(adreno_dev, ibcmds,
182 gpuaddr + data_offset, entry->offset,
183 &data_offset);
184 ibcmds += _ib_cmd_reg_to_mem(adreno_dev, ibcmds,
185 gpuaddr + data_offset, entry->offset_hi,
186 &data_offset);
187
188 /* skip over post_ib counter data */
189 data_offset += sizeof(unsigned int) * 2;
190 }
191
192 /* end of profile identifier */
193 ibcmds += _ib_end(adreno_dev, ibcmds);
194
195 return _create_ib_ref(adreno_dev, &profile->shared_buffer, rbcmds,
196 ibcmds - start, ib_offset * sizeof(unsigned int));
197}
198
199static int _build_post_ib_cmds(struct adreno_device *adreno_dev,
200 struct adreno_profile *profile,
201 unsigned int *rbcmds, unsigned int head)
202{
203 struct adreno_profile_assigns_list *entry;
204 unsigned int *start, *ibcmds;
205 unsigned int count = profile->assignment_count;
206 uint64_t gpuaddr = profile->shared_buffer.gpuaddr;
207 unsigned int ib_offset = head + SIZE_DATA(count) + SIZE_PREIB(count);
208 unsigned int data_offset = head * sizeof(unsigned int);
209
210 ibcmds = ib_offset + ((unsigned int *) profile->shared_buffer.hostptr);
211 start = ibcmds;
212 /* start of profile identifier */
213 ibcmds += _ib_start(adreno_dev, ibcmds);
214
215 /* skip over pre_ib preamble */
216 data_offset += sizeof(unsigned int) * 6;
217
218 /* loop for each countable assigned */
219 list_for_each_entry(entry, &profile->assignments_list, list) {
220 /* skip over pre_ib counter data */
221 data_offset += sizeof(unsigned int) * 3;
222 ibcmds += _ib_cmd_reg_to_mem(adreno_dev, ibcmds,
223 gpuaddr + data_offset, entry->offset,
224 &data_offset);
225 ibcmds += _ib_cmd_reg_to_mem(adreno_dev, ibcmds,
226 gpuaddr + data_offset, entry->offset_hi,
227 &data_offset);
228 }
229
230 /* end of profile identifier */
231 ibcmds += _ib_end(adreno_dev, ibcmds);
232
233 return _create_ib_ref(adreno_dev, &profile->shared_buffer, rbcmds,
234 ibcmds - start, ib_offset * sizeof(unsigned int));
235}
236
237static bool shared_buf_empty(struct adreno_profile *profile)
238{
239 if (profile->shared_buffer.hostptr == NULL ||
240 profile->shared_buffer.size == 0)
241 return true;
242
243 if (profile->shared_head == profile->shared_tail)
244 return true;
245
246 return false;
247}
248
249static inline void shared_buf_inc(unsigned int max_size,
250 unsigned int *offset, size_t inc)
251{
252 *offset = (*offset + inc) % max_size;
253}
254
255static inline void log_buf_wrapcnt(unsigned int cnt, uintptr_t *off)
256{
257 *off = (*off + cnt) % ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS;
258}
259
260static inline void log_buf_wrapinc_len(unsigned int *profile_log_buffer,
261 unsigned int **ptr, unsigned int len)
262{
263 *ptr += len;
264 if (*ptr >= (profile_log_buffer +
265 ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS))
266 *ptr -= ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS;
267}
268
269static inline void log_buf_wrapinc(unsigned int *profile_log_buffer,
270 unsigned int **ptr)
271{
272 log_buf_wrapinc_len(profile_log_buffer, ptr, 1);
273}
274
275static inline unsigned int log_buf_available(struct adreno_profile *profile,
276 unsigned int *head_ptr)
277{
278 uintptr_t tail, head;
279
280 tail = (uintptr_t) profile->log_tail -
281 (uintptr_t) profile->log_buffer;
282 head = (uintptr_t)head_ptr - (uintptr_t) profile->log_buffer;
283 if (tail > head)
284 return (tail - head) / sizeof(uintptr_t);
285 else
286 return ADRENO_PROFILE_LOG_BUF_SIZE_DWORDS - ((head - tail) /
287 sizeof(uintptr_t));
288}
289
290static inline unsigned int shared_buf_available(struct adreno_profile *profile)
291{
292 if (profile->shared_tail > profile->shared_head)
293 return profile->shared_tail - profile->shared_head;
294 else
295 return profile->shared_size -
296 (profile->shared_head - profile->shared_tail);
297}
298
299static struct adreno_profile_assigns_list *_find_assignment_by_offset(
300 struct adreno_profile *profile, unsigned int offset)
301{
302 struct adreno_profile_assigns_list *entry;
303
304 list_for_each_entry(entry, &profile->assignments_list, list) {
305 if (entry->offset == offset)
306 return entry;
307 }
308
309 return NULL;
310}
311
312static bool _in_assignments_list(struct adreno_profile *profile,
313 unsigned int groupid, unsigned int countable)
314{
315 struct adreno_profile_assigns_list *entry;
316
317 list_for_each_entry(entry, &profile->assignments_list, list) {
318 if (entry->groupid == groupid && entry->countable ==
319 countable)
320 return true;
321 }
322
323 return false;
324}
325
326static bool _add_to_assignments_list(struct adreno_profile *profile,
327 const char *str, unsigned int groupid, unsigned int countable,
328 unsigned int offset, unsigned int offset_hi)
329{
330 struct adreno_profile_assigns_list *entry;
331
332 /* first make sure we can alloc memory */
333 entry = kmalloc(sizeof(struct adreno_profile_assigns_list), GFP_KERNEL);
334 if (!entry)
335 return false;
336
337 list_add_tail(&entry->list, &profile->assignments_list);
338
339 entry->countable = countable;
340 entry->groupid = groupid;
341 entry->offset = offset;
342 entry->offset_hi = offset_hi;
343
344 strlcpy(entry->name, str, sizeof(entry->name));
345
346 profile->assignment_count++;
347
348 return true;
349}
350
351static bool results_available(struct adreno_device *adreno_dev,
352 struct adreno_profile *profile, unsigned int *shared_buf_tail)
353{
354 unsigned int global_eop;
355 unsigned int off = profile->shared_tail;
356 unsigned int *shared_ptr = (unsigned int *)
357 profile->shared_buffer.hostptr;
358 unsigned int ts, cnt;
359 int ts_cmp;
360
361 /*
362 * If shared_buffer empty or Memstore EOP timestamp is less than
363 * outstanding counter buffer timestamps then no results available
364 */
365 if (shared_buf_empty(profile))
366 return false;
367
368 if (adreno_rb_readtimestamp(adreno_dev,
369 adreno_dev->cur_rb,
370 KGSL_TIMESTAMP_RETIRED, &global_eop))
371 return false;
372 do {
373 cnt = *(shared_ptr + off + 1);
374 if (cnt == 0)
375 return false;
376
377 ts = *(shared_ptr + off);
378 ts_cmp = timestamp_cmp(ts, global_eop);
379 if (ts_cmp >= 0) {
380 *shared_buf_tail = off;
381 if (off == profile->shared_tail)
382 return false;
383 else
384 return true;
385 }
386 shared_buf_inc(profile->shared_size, &off,
387 SIZE_SHARED_ENTRY(cnt));
388 } while (off != profile->shared_head);
389
390 *shared_buf_tail = profile->shared_head;
391
392 return true;
393}
394
395static void transfer_results(struct adreno_profile *profile,
396 unsigned int shared_buf_tail)
397{
398 unsigned int buf_off;
399 unsigned int ts, cnt, ctxt_id, pid, tid, client_type;
400 unsigned int *ptr = (unsigned int *) profile->shared_buffer.hostptr;
401 unsigned int *log_ptr, *log_base;
402 struct adreno_profile_assigns_list *assigns_list;
403 int i, tmp_tail;
404
405 log_ptr = profile->log_head;
406 log_base = profile->log_buffer;
407 if (log_ptr == NULL)
408 return;
409
410 /*
411 * go through counter buffers and format for write into log_buffer
412 * if log buffer doesn't have space just overwrite it circularly
413 * shared_buf is guaranteed to not wrap within an entry so can use
414 * ptr increment
415 */
416 while (profile->shared_tail != shared_buf_tail) {
417 buf_off = profile->shared_tail;
418 /*
419 * format: timestamp, count, context_id
420 * count entries: pc_off, pc_start, pc_end
421 */
422 ts = *(ptr + buf_off++);
423 cnt = *(ptr + buf_off++);
424 ctxt_id = *(ptr + buf_off++);
425 pid = *(ptr + buf_off++);
426 tid = *(ptr + buf_off++);
427 client_type = *(ptr + buf_off++);
428
429 /*
430 * if entry overwrites the tail of log_buffer then adjust tail
431 * ptr to make room for the new entry, discarding old entry
432 */
433 while (log_buf_available(profile, log_ptr) <=
434 SIZE_LOG_ENTRY(cnt)) {
435 unsigned int size_tail;
436 uintptr_t boff;
437
438 size_tail = SIZE_LOG_ENTRY(0xffff &
439 *(profile->log_tail));
440 boff = ((uintptr_t) profile->log_tail -
441 (uintptr_t) log_base) / sizeof(uintptr_t);
442 log_buf_wrapcnt(size_tail, &boff);
443 profile->log_tail = log_base + boff;
444 }
445
446 *log_ptr = cnt;
447 log_buf_wrapinc(log_base, &log_ptr);
448 *log_ptr = client_type;
449 log_buf_wrapinc(log_base, &log_ptr);
450 *log_ptr = pid;
451 log_buf_wrapinc(log_base, &log_ptr);
452 *log_ptr = tid;
453 log_buf_wrapinc(log_base, &log_ptr);
454 *log_ptr = ctxt_id;
455 log_buf_wrapinc(log_base, &log_ptr);
456 *log_ptr = ts;
457 log_buf_wrapinc(log_base, &log_ptr);
458
459 for (i = 0; i < cnt; i++) {
460 assigns_list = _find_assignment_by_offset(
461 profile, *(ptr + buf_off++));
462 if (assigns_list == NULL) {
463 *log_ptr = (unsigned int) -1;
464
465 shared_buf_inc(profile->shared_size,
466 &profile->shared_tail,
467 SIZE_SHARED_ENTRY(cnt));
468 goto err;
469 } else {
470 *log_ptr = assigns_list->groupid << 16 |
471 (assigns_list->countable & 0xffff);
472 }
473 log_buf_wrapinc(log_base, &log_ptr);
474 *log_ptr = *(ptr + buf_off++); /* perf cntr start hi */
475 log_buf_wrapinc(log_base, &log_ptr);
476 *log_ptr = *(ptr + buf_off++); /* perf cntr start lo */
477 log_buf_wrapinc(log_base, &log_ptr);
478 *log_ptr = *(ptr + buf_off++); /* perf cntr end hi */
479 log_buf_wrapinc(log_base, &log_ptr);
480 *log_ptr = *(ptr + buf_off++); /* perf cntr end lo */
481 log_buf_wrapinc(log_base, &log_ptr);
482
483 }
484
485 tmp_tail = profile->shared_tail;
486 shared_buf_inc(profile->shared_size,
487 &profile->shared_tail,
488 SIZE_SHARED_ENTRY(cnt));
489 /*
490 * Possibly lost some room as we cycled around, so it's safe to
491 * reset the max size
492 */
493 if (profile->shared_tail < tmp_tail)
494 profile->shared_size =
495 ADRENO_PROFILE_SHARED_BUF_SIZE_DWORDS;
496
497 }
498 profile->log_head = log_ptr;
499 return;
500err:
501 /* reset head/tail to same on error in hopes we work correctly later */
502 profile->log_head = profile->log_tail;
503}
504
505static int profile_enable_get(void *data, u64 *val)
506{
507 struct kgsl_device *device = data;
508 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
509
510 mutex_lock(&device->mutex);
511 *val = adreno_profile_enabled(&adreno_dev->profile);
512 mutex_unlock(&device->mutex);
513
514 return 0;
515}
516
517static int profile_enable_set(void *data, u64 val)
518{
519 struct kgsl_device *device = data;
520 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
521 struct adreno_profile *profile = &adreno_dev->profile;
522
523 mutex_lock(&device->mutex);
524
525 if (val && profile->log_buffer == NULL) {
526 /* allocate profile_log_buffer the first time enabled */
527 profile->log_buffer = vmalloc(ADRENO_PROFILE_LOG_BUF_SIZE);
528 if (profile->log_buffer == NULL) {
529 mutex_unlock(&device->mutex);
530 return -ENOMEM;
531 }
532 profile->log_tail = profile->log_buffer;
533 profile->log_head = profile->log_buffer;
534 }
535
536 profile->enabled = val;
537
538 mutex_unlock(&device->mutex);
539
540 return 0;
541}
542
543static ssize_t profile_assignments_read(struct file *filep,
544 char __user *ubuf, size_t max, loff_t *ppos)
545{
546 struct kgsl_device *device = (struct kgsl_device *) filep->private_data;
547 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
548 struct adreno_profile *profile = &adreno_dev->profile;
549 struct adreno_profile_assigns_list *entry;
550 int len = 0, max_size = PAGE_SIZE;
551 char *buf, *pos;
552 ssize_t size = 0;
553
554 mutex_lock(&device->mutex);
555
556 if (profile->assignment_count == 0) {
557 mutex_unlock(&device->mutex);
558 return 0;
559 }
560
561 buf = kmalloc(max_size, GFP_KERNEL);
562 if (!buf) {
563 mutex_unlock(&device->mutex);
564 return -ENOMEM;
565 }
566
567 pos = buf;
568
569 /* copy all assingments from list to str */
570 list_for_each_entry(entry, &profile->assignments_list, list) {
571 len = snprintf(pos, max_size, ASSIGNS_STR_FORMAT,
572 entry->name, entry->countable);
573
574 max_size -= len;
575 pos += len;
576 }
577
578 size = simple_read_from_buffer(ubuf, max, ppos, buf,
579 strlen(buf));
580
581 kfree(buf);
582
583 mutex_unlock(&device->mutex);
584 return size;
585}
586
587static void _remove_assignment(struct adreno_device *adreno_dev,
588 unsigned int groupid, unsigned int countable)
589{
590 struct adreno_profile *profile = &adreno_dev->profile;
591 struct adreno_profile_assigns_list *entry, *tmp;
592
593 list_for_each_entry_safe(entry, tmp, &profile->assignments_list, list) {
594 if (entry->groupid == groupid &&
595 entry->countable == countable) {
596 list_del(&entry->list);
597
598 profile->assignment_count--;
599
600 kfree(entry);
601
602 /* remove from perf counter allocation */
603 adreno_perfcounter_put(adreno_dev, groupid, countable,
604 PERFCOUNTER_FLAG_KERNEL);
605 }
606 }
607}
608
609static void _add_assignment(struct adreno_device *adreno_dev,
610 unsigned int groupid, unsigned int countable)
611{
612 struct adreno_profile *profile = &adreno_dev->profile;
613 unsigned int offset, offset_hi;
614 const char *name = NULL;
615
616 name = adreno_perfcounter_get_name(adreno_dev, groupid);
617 if (!name)
618 return;
619
620 /* if already in assigned list skip it */
621 if (_in_assignments_list(profile, groupid, countable))
622 return;
623
624 /* add to perf counter allocation, if fail skip it */
625 if (adreno_perfcounter_get(adreno_dev, groupid, countable,
626 &offset, &offset_hi, PERFCOUNTER_FLAG_NONE))
627 return;
628
629 /* add to assignments list, put counter back if error */
630 if (!_add_to_assignments_list(profile, name, groupid,
631 countable, offset, offset_hi))
632 adreno_perfcounter_put(adreno_dev, groupid,
633 countable, PERFCOUNTER_FLAG_KERNEL);
634}
635
636static char *_parse_next_assignment(struct adreno_device *adreno_dev,
637 char *str, int *groupid, int *countable, bool *remove)
638{
639 char *groupid_str, *countable_str, *next_str = NULL;
640 int ret;
641
642 *groupid = -EINVAL;
643 *countable = -EINVAL;
644 *remove = false;
645
646 /* remove spaces */
647 while (*str == ' ')
648 str++;
649
650 /* check if it's a remove assignment */
651 if (*str == '-') {
652 *remove = true;
653 str++;
654 }
655
656 /* get the groupid string */
657 groupid_str = str;
658 while (*str != ':') {
659 if (*str == '\0')
660 return NULL;
661 *str = tolower(*str);
662 str++;
663 }
664 if (groupid_str == str)
665 return NULL;
666
667 *str = '\0';
668 str++;
669
670 /* get the countable string */
671 countable_str = str;
672 while (*str != ' ' && *str != '\0')
673 str++;
674 if (countable_str == str)
675 return NULL;
676
677 /*
678 * If we have reached the end of the original string then make sure we
679 * return NULL from this function or we could accidently overrun
680 */
681
682 if (*str != '\0') {
683 *str = '\0';
684 next_str = str + 1;
685 }
686
687 /* set results */
688 *groupid = adreno_perfcounter_get_groupid(adreno_dev,
689 groupid_str);
690 if (*groupid < 0)
691 return NULL;
692 ret = kstrtou32(countable_str, 10, countable);
693 if (ret)
694 return NULL;
695
696 return next_str;
697}
698
699static ssize_t profile_assignments_write(struct file *filep,
700 const char __user *user_buf, size_t len, loff_t *off)
701{
702 struct kgsl_device *device = (struct kgsl_device *) filep->private_data;
703 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
704 struct adreno_profile *profile = &adreno_dev->profile;
705 size_t size = 0;
706 char *buf, *pbuf;
707 bool remove_assignment = false;
708 int groupid, countable, ret;
709
710 if (len >= PAGE_SIZE || len == 0)
711 return -EINVAL;
712
713 buf = kmalloc(len + 1, GFP_KERNEL);
714 if (buf == NULL)
715 return -ENOMEM;
716
717 if (copy_from_user(buf, user_buf, len)) {
718 size = -EFAULT;
719 goto error_free;
720 }
721
722 mutex_lock(&device->mutex);
723
724 if (adreno_profile_enabled(profile)) {
725 size = -EINVAL;
726 goto error_unlock;
727 }
728
Carter Cooper05f2a6b2017-03-20 11:43:11 -0600729 ret = adreno_perfcntr_active_oob_get(adreno_dev);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700730 if (ret) {
731 size = ret;
732 goto error_unlock;
733 }
734
735 /*
736 * When adding/removing assignments, ensure that the GPU is done with
737 * all it's work. This helps to synchronize the work flow to the
738 * GPU and avoid racey conditions.
739 */
740 if (adreno_idle(device)) {
741 size = -ETIMEDOUT;
742 goto error_put;
743 }
744
745 /* clear all shared buffer results */
746 adreno_profile_process_results(adreno_dev);
747
748 pbuf = buf;
749
750 /* clear the log buffer */
751 if (profile->log_buffer != NULL) {
752 profile->log_head = profile->log_buffer;
753 profile->log_tail = profile->log_buffer;
754 }
755
756
757 /* for sanity and parsing, ensure it is null terminated */
758 buf[len] = '\0';
759
760 /* parse file buf and add(remove) to(from) appropriate lists */
761 while (pbuf) {
762 pbuf = _parse_next_assignment(adreno_dev, pbuf, &groupid,
763 &countable, &remove_assignment);
764 if (groupid < 0 || countable < 0)
765 break;
766
767 if (remove_assignment)
768 _remove_assignment(adreno_dev, groupid, countable);
769 else
770 _add_assignment(adreno_dev, groupid, countable);
771 }
772
773 size = len;
774
775error_put:
Carter Cooper05f2a6b2017-03-20 11:43:11 -0600776 adreno_perfcntr_active_oob_put(adreno_dev);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700777error_unlock:
778 mutex_unlock(&device->mutex);
779error_free:
780 kfree(buf);
781 return size;
782}
783
784static int _pipe_print_pending(char __user *ubuf, size_t max)
785{
786 loff_t unused = 0;
787 char str[] = "Operation Would Block!";
788
789 return simple_read_from_buffer(ubuf, max,
790 &unused, str, strlen(str));
791}
792
793static int _pipe_print_results(struct adreno_device *adreno_dev,
794 char __user *ubuf, size_t max)
795{
796 struct adreno_profile *profile = &adreno_dev->profile;
797 const char *grp_name;
798 char __user *usr_buf = ubuf;
799 unsigned int *log_ptr = NULL, *tmp_log_ptr = NULL;
800 int len, i;
801 int status = 0;
802 ssize_t size, total_size = 0;
803 unsigned int cnt, api_type, ctxt_id, pid, tid, ts, cnt_reg;
804 unsigned long long pc_start, pc_end;
805 const char *api_str;
806 char format_space;
807 loff_t unused = 0;
808 char pipe_hdr_buf[51]; /* 4 uint32 + 5 space + 5 API type + '\0' */
809 char pipe_cntr_buf[63]; /* 2 uint64 + 1 uint32 + 4 spaces + 8 group */
810
811 /* convert unread entries to ASCII, copy to user-space */
812 log_ptr = profile->log_tail;
813
814 do {
815 /* store the tmp var for error cases so we can skip */
816 tmp_log_ptr = log_ptr;
817
818 /* Too many to output to pipe, so skip this data */
819 cnt = *log_ptr;
820 log_buf_wrapinc(profile->log_buffer, &log_ptr);
821
822 if (SIZE_PIPE_ENTRY(cnt) > max) {
823 log_buf_wrapinc_len(profile->log_buffer,
824 &tmp_log_ptr, SIZE_PIPE_ENTRY(cnt));
825 log_ptr = tmp_log_ptr;
826 goto done;
827 }
828
829 /*
830 * Not enough space left in pipe, return without doing
831 * anything
832 */
833 if ((max - (usr_buf - ubuf)) < SIZE_PIPE_ENTRY(cnt)) {
834 log_ptr = tmp_log_ptr;
835 goto done;
836 }
837
838 api_type = *log_ptr;
839 api_str = get_api_type_str(api_type);
840 log_buf_wrapinc(profile->log_buffer, &log_ptr);
841 pid = *log_ptr;
842 log_buf_wrapinc(profile->log_buffer, &log_ptr);
843 tid = *log_ptr;
844 log_buf_wrapinc(profile->log_buffer, &log_ptr);
845 ctxt_id = *log_ptr;
846 log_buf_wrapinc(profile->log_buffer, &log_ptr);
847 ts = *log_ptr;
848 log_buf_wrapinc(profile->log_buffer, &log_ptr);
849 len = snprintf(pipe_hdr_buf, sizeof(pipe_hdr_buf) - 1,
850 "%u %u %u %.5s %u ",
851 pid, tid, ctxt_id, api_str, ts);
852 size = simple_read_from_buffer(usr_buf,
853 max - (usr_buf - ubuf),
854 &unused, pipe_hdr_buf, len);
855
856 /* non-fatal error, so skip rest of entry and return */
857 if (size < 0) {
858 log_buf_wrapinc_len(profile->log_buffer,
859 &tmp_log_ptr, SIZE_PIPE_ENTRY(cnt));
860 log_ptr = tmp_log_ptr;
861 goto done;
862 }
863
864 unused = 0;
865 usr_buf += size;
866 total_size += size;
867
868 for (i = 0; i < cnt; i++) {
869 unsigned int start_lo, start_hi;
870 unsigned int end_lo, end_hi;
871
872 grp_name = adreno_perfcounter_get_name(
873 adreno_dev, (*log_ptr >> 16) & 0xffff);
874
875 /* non-fatal error, so skip rest of entry and return */
876 if (grp_name == NULL) {
877 log_buf_wrapinc_len(profile->log_buffer,
878 &tmp_log_ptr, SIZE_PIPE_ENTRY(cnt));
879 log_ptr = tmp_log_ptr;
880 goto done;
881 }
882
883 if (i == cnt - 1)
884 format_space = '\n';
885 else
886 format_space = ' ';
887
888 cnt_reg = *log_ptr & 0xffff;
889 log_buf_wrapinc(profile->log_buffer, &log_ptr);
890 start_lo = *log_ptr;
891 log_buf_wrapinc(profile->log_buffer, &log_ptr);
892 start_hi = *log_ptr;
893 log_buf_wrapinc(profile->log_buffer, &log_ptr);
894 end_lo = *log_ptr;
895 log_buf_wrapinc(profile->log_buffer, &log_ptr);
896 end_hi = *log_ptr;
897 log_buf_wrapinc(profile->log_buffer, &log_ptr);
898
899 pc_start = (((uint64_t) start_hi) << 32) | start_lo;
900 pc_end = (((uint64_t) end_hi) << 32) | end_lo;
901
902 len = snprintf(pipe_cntr_buf,
903 sizeof(pipe_cntr_buf) - 1,
904 "%.8s:%u %llu %llu%c",
905 grp_name, cnt_reg, pc_start,
906 pc_end, format_space);
907
908 size = simple_read_from_buffer(usr_buf,
909 max - (usr_buf - ubuf),
910 &unused, pipe_cntr_buf, len);
911
912 /* non-fatal error, so skip rest of entry and return */
913 if (size < 0) {
914 log_buf_wrapinc_len(profile->log_buffer,
915 &tmp_log_ptr, SIZE_PIPE_ENTRY(cnt));
916 log_ptr = tmp_log_ptr;
917 goto done;
918 }
919 unused = 0;
920 usr_buf += size;
921 total_size += size;
922 }
923 } while (log_ptr != profile->log_head);
924
925done:
926 status = total_size;
927 profile->log_tail = log_ptr;
928
929 return status;
930}
931
932static ssize_t profile_pipe_print(struct file *filep, char __user *ubuf,
933 size_t max, loff_t *ppos)
934{
935 struct kgsl_device *device = (struct kgsl_device *) filep->private_data;
936 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
937 struct adreno_profile *profile = &adreno_dev->profile;
938 char __user *usr_buf = ubuf;
939 int status = 0;
940
941 /*
942 * this file not seekable since it only supports streaming, ignore
943 * ppos <> 0
944 */
945 /*
946 * format <pid> <tid> <context id> <cnt<<16 | client type> <timestamp>
947 * for each perf counter <cntr_reg_off> <start hi & lo> <end hi & low>
948 */
949
950 mutex_lock(&device->mutex);
951
952 while (1) {
953 /* process any results that are available into the log_buffer */
954 status = adreno_profile_process_results(adreno_dev);
955 if (status > 0) {
956 /* if we have results, print them and exit */
957 status = _pipe_print_results(adreno_dev, usr_buf, max);
958 break;
959 }
960
961 /* there are no unread results, act accordingly */
962 if (filep->f_flags & O_NONBLOCK) {
963 if (profile->shared_tail != profile->shared_head) {
964 status = _pipe_print_pending(usr_buf, max);
965 break;
966 }
967
968 status = 0;
969 break;
970 }
971
972 mutex_unlock(&device->mutex);
973 set_current_state(TASK_INTERRUPTIBLE);
974 schedule_timeout(msecs_to_jiffies(100));
975 mutex_lock(&device->mutex);
976
977 if (signal_pending(current)) {
978 status = 0;
979 break;
980 }
981 }
982
983 mutex_unlock(&device->mutex);
984
985 return status;
986}
987
988static int profile_groups_print(struct seq_file *s, void *unused)
989{
990 struct kgsl_device *device = (struct kgsl_device *) s->private;
991 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
992 struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
993 struct adreno_perfcounters *counters = gpudev->perfcounters;
994 struct adreno_perfcount_group *group;
995 int i, j, used;
996
997 mutex_lock(&device->mutex);
998
999 for (i = 0; i < counters->group_count; ++i) {
1000 group = &(counters->groups[i]);
1001 /* get number of counters used for this group */
1002 used = 0;
1003 for (j = 0; j < group->reg_count; j++) {
1004 if (group->regs[j].countable !=
1005 KGSL_PERFCOUNTER_NOT_USED)
1006 used++;
1007 }
1008
1009 seq_printf(s, "%s %d %d\n", group->name,
1010 group->reg_count, used);
1011 }
1012
1013 mutex_unlock(&device->mutex);
1014
1015 return 0;
1016}
1017
1018static int profile_groups_open(struct inode *inode, struct file *file)
1019{
1020 return single_open(file, profile_groups_print, inode->i_private);
1021}
1022
1023static const struct file_operations profile_groups_fops = {
1024 .owner = THIS_MODULE,
1025 .open = profile_groups_open,
1026 .read = seq_read,
1027 .llseek = noop_llseek,
1028 .release = single_release,
1029};
1030
1031static const struct file_operations profile_pipe_fops = {
1032 .owner = THIS_MODULE,
1033 .open = simple_open,
1034 .read = profile_pipe_print,
1035 .llseek = noop_llseek,
1036};
1037
1038static const struct file_operations profile_assignments_fops = {
1039 .owner = THIS_MODULE,
1040 .open = simple_open,
1041 .read = profile_assignments_read,
1042 .write = profile_assignments_write,
1043 .llseek = noop_llseek,
1044};
1045
1046DEFINE_SIMPLE_ATTRIBUTE(profile_enable_fops,
1047 profile_enable_get,
1048 profile_enable_set, "%llu\n");
1049
1050void adreno_profile_init(struct adreno_device *adreno_dev)
1051{
1052 struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
1053 struct adreno_profile *profile = &adreno_dev->profile;
1054 struct dentry *profile_dir;
1055 int ret;
1056
1057 profile->enabled = false;
1058
1059 /* allocate shared_buffer, which includes pre_ib and post_ib */
1060 profile->shared_size = ADRENO_PROFILE_SHARED_BUF_SIZE_DWORDS;
1061 ret = kgsl_allocate_global(device, &profile->shared_buffer,
1062 profile->shared_size * sizeof(unsigned int),
1063 0, 0, "profile");
1064
1065 if (ret) {
1066 profile->shared_size = 0;
1067 return;
1068 }
1069
1070 INIT_LIST_HEAD(&profile->assignments_list);
1071
1072 /* Create perf counter debugfs */
1073 profile_dir = debugfs_create_dir("profiling", device->d_debugfs);
1074 if (IS_ERR(profile_dir))
1075 return;
1076
1077 debugfs_create_file("enable", 0644, profile_dir, device,
1078 &profile_enable_fops);
1079 debugfs_create_file("blocks", 0444, profile_dir, device,
1080 &profile_groups_fops);
1081 debugfs_create_file("pipe", 0444, profile_dir, device,
1082 &profile_pipe_fops);
1083 debugfs_create_file("assignments", 0644, profile_dir, device,
1084 &profile_assignments_fops);
1085}
1086
1087void adreno_profile_close(struct adreno_device *adreno_dev)
1088{
1089 struct adreno_profile *profile = &adreno_dev->profile;
1090 struct adreno_profile_assigns_list *entry, *tmp;
1091
1092 profile->enabled = false;
1093 vfree(profile->log_buffer);
1094 profile->log_buffer = NULL;
1095 profile->log_head = NULL;
1096 profile->log_tail = NULL;
1097 profile->shared_head = 0;
1098 profile->shared_tail = 0;
1099 kgsl_free_global(KGSL_DEVICE(adreno_dev), &profile->shared_buffer);
1100 profile->shared_size = 0;
1101
1102 profile->assignment_count = 0;
1103
1104 list_for_each_entry_safe(entry, tmp, &profile->assignments_list, list) {
1105 list_del(&entry->list);
1106 kfree(entry);
1107 }
1108}
1109
1110int adreno_profile_process_results(struct adreno_device *adreno_dev)
1111{
1112 struct adreno_profile *profile = &adreno_dev->profile;
1113 unsigned int shared_buf_tail = profile->shared_tail;
1114
1115 if (!results_available(adreno_dev, profile, &shared_buf_tail))
1116 return 0;
1117
1118 /*
1119 * transfer retired results to log_buffer
1120 * update shared_buffer tail ptr
1121 */
1122 transfer_results(profile, shared_buf_tail);
1123
1124 return 1;
1125}
1126
1127void adreno_profile_preib_processing(struct adreno_device *adreno_dev,
1128 struct adreno_context *drawctxt, unsigned int *cmd_flags,
1129 unsigned int **rbptr)
1130{
1131 struct adreno_profile *profile = &adreno_dev->profile;
1132 int count = profile->assignment_count;
1133 unsigned int entry_head = profile->shared_head;
1134 unsigned int *shared_ptr;
1135 struct adreno_ringbuffer *rb = ADRENO_CURRENT_RINGBUFFER(adreno_dev);
1136 unsigned int rbcmds[4];
1137 unsigned int *ptr = *rbptr;
1138 unsigned int i, ret = 0;
1139
1140 *cmd_flags &= ~KGSL_CMD_FLAGS_PROFILE;
1141
1142 if (!adreno_profile_assignments_ready(profile))
1143 goto done;
1144
1145 /*
1146 * check if space available, include the post_ib in space available
1147 * check so don't have to handle trying to undo the pre_ib insertion in
1148 * ringbuffer in the case where only the post_ib fails enough space
1149 */
1150 if (SIZE_SHARED_ENTRY(count) >= shared_buf_available(profile))
1151 goto done;
1152
1153 if (entry_head + SIZE_SHARED_ENTRY(count) >= profile->shared_size) {
1154 /* entry_head would wrap, start entry_head at 0 in buffer */
1155 entry_head = 0;
1156 profile->shared_size = profile->shared_head;
1157 profile->shared_head = 0;
1158
1159 /* recheck space available */
1160 if (SIZE_SHARED_ENTRY(count) >= shared_buf_available(profile))
1161 goto done;
1162 }
1163
1164 /* zero out the counter area of shared_buffer entry_head */
1165 shared_ptr = entry_head + ((unsigned int *)
1166 profile->shared_buffer.hostptr);
1167 memset(shared_ptr, 0, SIZE_SHARED_ENTRY(count) * sizeof(unsigned int));
1168
1169 /* reserve space for the pre ib shared buffer */
1170 shared_buf_inc(profile->shared_size, &profile->shared_head,
1171 SIZE_SHARED_ENTRY(count));
1172
1173 /* create the shared ibdesc */
1174 ret = _build_pre_ib_cmds(adreno_dev, profile, rbcmds, entry_head,
1175 rb->timestamp + 1, drawctxt);
1176
1177 /* set flag to sync with post ib commands */
1178 *cmd_flags |= KGSL_CMD_FLAGS_PROFILE;
1179
1180done:
1181 /* write the ibdesc to the ringbuffer */
1182 for (i = 0; i < ret; i++)
1183 *ptr++ = rbcmds[i];
1184
1185 *rbptr = ptr;
1186}
1187
1188void adreno_profile_postib_processing(struct adreno_device *adreno_dev,
1189 unsigned int *cmd_flags, unsigned int **rbptr)
1190{
1191 struct adreno_profile *profile = &adreno_dev->profile;
1192 int count = profile->assignment_count;
1193 unsigned int entry_head = profile->shared_head -
1194 SIZE_SHARED_ENTRY(count);
1195 unsigned int *ptr = *rbptr;
1196 unsigned int rbcmds[4];
1197 int ret = 0, i;
1198
1199 if (!adreno_profile_assignments_ready(profile))
1200 goto done;
1201
1202 if (!(*cmd_flags & KGSL_CMD_FLAGS_PROFILE))
1203 goto done;
1204
1205 /* create the shared ibdesc */
1206 ret = _build_post_ib_cmds(adreno_dev, profile, rbcmds, entry_head);
1207
1208done:
1209 /* write the ibdesc to the ringbuffer */
1210 for (i = 0; i < ret; i++)
1211 *ptr++ = rbcmds[i];
1212
1213 *rbptr = ptr;
1214
1215 /* reset the sync flag */
1216 *cmd_flags &= ~KGSL_CMD_FLAGS_PROFILE;
1217}
1218