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