blob: 2a1d352a2f510dd455175f24ab627705d1ef5916 [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/export.h>
15#include <linux/delay.h>
16#include <linux/debugfs.h>
17#include <linux/uaccess.h>
18#include <linux/io.h>
19
20#include "kgsl.h"
21#include "adreno.h"
22#include "kgsl_sync.h"
23
24static int _isdb_set(void *data, u64 val)
25{
26 struct kgsl_device *device = data;
27 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
28
29 /* Once ISDB goes enabled it stays enabled */
30 if (test_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv))
31 return 0;
32
33 mutex_lock(&device->mutex);
34
35 /*
36 * Bring down the GPU so we can bring it back up with the correct power
37 * and clock settings
38 */
39 kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
40 set_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv);
41 kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
42
43 mutex_unlock(&device->mutex);
44
45 return 0;
46}
47
48static int _isdb_get(void *data, u64 *val)
49{
50 struct kgsl_device *device = data;
51 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
52
53 *val = (u64) test_bit(ADRENO_DEVICE_ISDB_ENABLED, &adreno_dev->priv);
54 return 0;
55}
56
57DEFINE_SIMPLE_ATTRIBUTE(_isdb_fops, _isdb_get, _isdb_set, "%llu\n");
58
59static int _lm_limit_set(void *data, u64 val)
60{
61 struct kgsl_device *device = data;
62 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
63
64 if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM))
65 return 0;
66
67 /* assure value is between 3A and 10A */
68 if (val > 10000)
69 val = 10000;
70 else if (val < 3000)
71 val = 3000;
72
73 adreno_dev->lm_limit = val;
74
75 if (test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) {
76 mutex_lock(&device->mutex);
77 kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND);
78 kgsl_pwrctrl_change_state(device, KGSL_STATE_SLUMBER);
79 mutex_unlock(&device->mutex);
80 }
81
82 return 0;
83}
84
85static int _lm_limit_get(void *data, u64 *val)
86{
87 struct kgsl_device *device = data;
88 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
89
90 if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM))
91 *val = 0;
92
93 *val = (u64) adreno_dev->lm_limit;
94 return 0;
95}
96
97DEFINE_SIMPLE_ATTRIBUTE(_lm_limit_fops, _lm_limit_get, _lm_limit_set, "%llu\n");
98
99static int _lm_threshold_count_get(void *data, u64 *val)
100{
101 struct kgsl_device *device = data;
102 struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
103
104 if (!ADRENO_FEATURE(adreno_dev, ADRENO_LM))
105 *val = 0;
106 else
107 *val = (u64) adreno_dev->lm_threshold_cross;
108 return 0;
109}
110
111DEFINE_SIMPLE_ATTRIBUTE(_lm_threshold_fops, _lm_threshold_count_get,
112 NULL, "%llu\n");
113
114static int _active_count_get(void *data, u64 *val)
115{
116 struct kgsl_device *device = data;
117 unsigned int i = atomic_read(&device->active_cnt);
118
119 *val = (u64) i;
120 return 0;
121}
122
123DEFINE_SIMPLE_ATTRIBUTE(_active_count_fops, _active_count_get, NULL, "%llu\n");
124
125typedef void (*reg_read_init_t)(struct kgsl_device *device);
126typedef void (*reg_read_fill_t)(struct kgsl_device *device, int i,
127 unsigned int *vals, int linec);
128
129
130static void sync_event_print(struct seq_file *s,
131 struct kgsl_drawobj_sync_event *sync_event)
132{
133 switch (sync_event->type) {
134 case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP: {
135 seq_printf(s, "sync: ctx: %d ts: %d",
136 sync_event->context->id, sync_event->timestamp);
137 break;
138 }
Lynus Vazc031a9b2017-01-25 13:00:13 +0530139 case KGSL_CMD_SYNCPOINT_TYPE_FENCE: {
Lynus Vaze99b92b2017-04-24 18:04:54 +0530140 seq_printf(s, "sync: [%pK] %s", sync_event->handle,
141 sync_event->fence_name);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700142 break;
Lynus Vazc031a9b2017-01-25 13:00:13 +0530143 }
Shrenuj Bansala419c792016-10-20 14:05:11 -0700144 default:
145 seq_printf(s, "sync: type: %d", sync_event->type);
146 break;
147 }
148}
149
150struct flag_entry {
151 unsigned long mask;
152 const char *str;
153};
154
155static const struct flag_entry drawobj_flags[] = {KGSL_DRAWOBJ_FLAGS};
156
157static const struct flag_entry cmdobj_priv[] = {
158 { CMDOBJ_SKIP, "skip"},
159 { CMDOBJ_FORCE_PREAMBLE, "force_preamble"},
160 { CMDOBJ_WFI, "wait_for_idle" },
161};
162
163static const struct flag_entry context_flags[] = {KGSL_CONTEXT_FLAGS};
164
165/*
166 * Note that the ADRENO_CONTEXT_* flags start at
167 * KGSL_CONTEXT_PRIV_DEVICE_SPECIFIC so it is ok to cross the streams here.
168 */
169static const struct flag_entry context_priv[] = {
Hareesh Gundu7d5a8f22017-02-21 13:23:46 +0530170 { KGSL_CONTEXT_PRIV_SUBMITTED, "submitted"},
Shrenuj Bansala419c792016-10-20 14:05:11 -0700171 { KGSL_CONTEXT_PRIV_DETACHED, "detached"},
172 { KGSL_CONTEXT_PRIV_INVALID, "invalid"},
173 { KGSL_CONTEXT_PRIV_PAGEFAULT, "pagefault"},
174 { ADRENO_CONTEXT_FAULT, "fault"},
175 { ADRENO_CONTEXT_GPU_HANG, "gpu_hang"},
176 { ADRENO_CONTEXT_GPU_HANG_FT, "gpu_hang_ft"},
177 { ADRENO_CONTEXT_SKIP_EOF, "skip_end_of_frame" },
178 { ADRENO_CONTEXT_FORCE_PREAMBLE, "force_preamble"},
179};
180
181static void print_flags(struct seq_file *s, const struct flag_entry *table,
182 size_t table_size, unsigned long flags)
183{
184 int i;
185 int first = 1;
186
187 for (i = 0; i < table_size; i++) {
188 if (flags & table[i].mask) {
189 seq_printf(s, "%c%s", first ? '\0' : '|', table[i].str);
190 flags &= ~(table[i].mask);
191 first = 0;
192 }
193 }
194 if (flags) {
195 seq_printf(s, "%c0x%lx", first ? '\0' : '|', flags);
196 first = 0;
197 }
198 if (first)
199 seq_puts(s, "None");
200}
201
202static void syncobj_print(struct seq_file *s,
203 struct kgsl_drawobj_sync *syncobj)
204{
205 struct kgsl_drawobj_sync_event *event;
206 unsigned int i;
207
208 seq_puts(s, " syncobj ");
209
210 for (i = 0; i < syncobj->numsyncs; i++) {
211 event = &syncobj->synclist[i];
212
213 if (!kgsl_drawobj_event_pending(syncobj, i))
214 continue;
215
216 sync_event_print(s, event);
217 seq_puts(s, "\n");
218 }
219}
220
221static void cmdobj_print(struct seq_file *s,
222 struct kgsl_drawobj_cmd *cmdobj)
223{
224 struct kgsl_drawobj *drawobj = DRAWOBJ(cmdobj);
225
226 if (drawobj->type == CMDOBJ_TYPE)
227 seq_puts(s, " cmdobj ");
228 else
229 seq_puts(s, " markerobj ");
230
231 seq_printf(s, "\t %d ", drawobj->timestamp);
232
233 seq_puts(s, " priv: ");
234 print_flags(s, cmdobj_priv, ARRAY_SIZE(cmdobj_priv),
235 cmdobj->priv);
236}
237
238static void drawobj_print(struct seq_file *s,
239 struct kgsl_drawobj *drawobj)
240{
Lynus Vaze99b92b2017-04-24 18:04:54 +0530241 if (!kref_get_unless_zero(&drawobj->refcount))
242 return;
243
Shrenuj Bansala419c792016-10-20 14:05:11 -0700244 if (drawobj->type == SYNCOBJ_TYPE)
245 syncobj_print(s, SYNCOBJ(drawobj));
246 else if ((drawobj->type == CMDOBJ_TYPE) ||
247 (drawobj->type == MARKEROBJ_TYPE))
248 cmdobj_print(s, CMDOBJ(drawobj));
249
250 seq_puts(s, " flags: ");
251 print_flags(s, drawobj_flags, ARRAY_SIZE(drawobj_flags),
252 drawobj->flags);
253
Lynus Vaze99b92b2017-04-24 18:04:54 +0530254 kgsl_drawobj_put(drawobj);
Shrenuj Bansala419c792016-10-20 14:05:11 -0700255 seq_puts(s, "\n");
256}
257
258static const char *ctx_type_str(unsigned int type)
259{
260 int i;
261 struct flag_entry table[] = {KGSL_CONTEXT_TYPES};
262
263 for (i = 0; i < ARRAY_SIZE(table); i++)
264 if (type == table[i].mask)
265 return table[i].str;
266 return "UNKNOWN";
267}
268
269static int ctx_print(struct seq_file *s, void *unused)
270{
271 struct adreno_context *drawctxt = s->private;
272 unsigned int i;
273 struct kgsl_event *event;
274 unsigned int queued = 0, consumed = 0, retired = 0;
275
276 seq_printf(s, "id: %d type: %s priority: %d process: %s (%d) tid: %d\n",
277 drawctxt->base.id,
278 ctx_type_str(drawctxt->type),
279 drawctxt->base.priority,
280 drawctxt->base.proc_priv->comm,
281 drawctxt->base.proc_priv->pid,
282 drawctxt->base.tid);
283
284 seq_puts(s, "flags: ");
285 print_flags(s, context_flags, ARRAY_SIZE(context_flags),
286 drawctxt->base.flags & ~(KGSL_CONTEXT_PRIORITY_MASK
287 | KGSL_CONTEXT_TYPE_MASK));
288 seq_puts(s, " priv: ");
289 print_flags(s, context_priv, ARRAY_SIZE(context_priv),
290 drawctxt->base.priv);
291 seq_puts(s, "\n");
292
293 seq_puts(s, "timestamps: ");
294 kgsl_readtimestamp(drawctxt->base.device, &drawctxt->base,
295 KGSL_TIMESTAMP_QUEUED, &queued);
296 kgsl_readtimestamp(drawctxt->base.device, &drawctxt->base,
297 KGSL_TIMESTAMP_CONSUMED, &consumed);
298 kgsl_readtimestamp(drawctxt->base.device, &drawctxt->base,
299 KGSL_TIMESTAMP_RETIRED, &retired);
300 seq_printf(s, "queued: %u consumed: %u retired: %u global:%u\n",
301 queued, consumed, retired,
302 drawctxt->internal_timestamp);
303
304 seq_puts(s, "drawqueue:\n");
305
306 spin_lock(&drawctxt->lock);
307 for (i = drawctxt->drawqueue_head;
308 i != drawctxt->drawqueue_tail;
309 i = DRAWQUEUE_NEXT(i, ADRENO_CONTEXT_DRAWQUEUE_SIZE))
310 drawobj_print(s, drawctxt->drawqueue[i]);
311 spin_unlock(&drawctxt->lock);
312
313 seq_puts(s, "events:\n");
314 spin_lock(&drawctxt->base.events.lock);
315 list_for_each_entry(event, &drawctxt->base.events.events, node)
316 seq_printf(s, "\t%d: %pF created: %u\n", event->timestamp,
317 event->func, event->created);
318 spin_unlock(&drawctxt->base.events.lock);
319
320 return 0;
321}
322
323static int ctx_open(struct inode *inode, struct file *file)
324{
325 int ret;
326 unsigned int id = (unsigned int)(unsigned long)inode->i_private;
327 struct kgsl_context *context;
328
329 context = kgsl_context_get(kgsl_get_device(KGSL_DEVICE_3D0), id);
330 if (context == NULL)
331 return -ENODEV;
332
333 ret = single_open(file, ctx_print, context);
334 if (ret)
335 kgsl_context_put(context);
336 return ret;
337}
338
339static int ctx_release(struct inode *inode, struct file *file)
340{
341 struct kgsl_context *context;
342
343 context = ((struct seq_file *)file->private_data)->private;
344
345 kgsl_context_put(context);
346
347 return single_release(inode, file);
348}
349
350static const struct file_operations ctx_fops = {
351 .open = ctx_open,
352 .read = seq_read,
353 .llseek = seq_lseek,
354 .release = ctx_release,
355};
356
357
358void
359adreno_context_debugfs_init(struct adreno_device *adreno_dev,
360 struct adreno_context *ctx)
361{
362 unsigned char name[16];
363
364 snprintf(name, sizeof(name), "%d", ctx->base.id);
365
366 ctx->debug_root = debugfs_create_file(name, 0444,
367 adreno_dev->ctx_d_debugfs,
368 (void *)(unsigned long)ctx->base.id, &ctx_fops);
369}
370
371void adreno_debugfs_init(struct adreno_device *adreno_dev)
372{
373 struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
374
375 if (!device->d_debugfs || IS_ERR(device->d_debugfs))
376 return;
377
378 debugfs_create_file("active_cnt", 0444, device->d_debugfs, device,
379 &_active_count_fops);
380 adreno_dev->ctx_d_debugfs = debugfs_create_dir("ctx",
381 device->d_debugfs);
382
383 if (ADRENO_FEATURE(adreno_dev, ADRENO_LM)) {
384 debugfs_create_file("lm_limit", 0644, device->d_debugfs, device,
385 &_lm_limit_fops);
386 debugfs_create_file("lm_threshold_count", 0444,
387 device->d_debugfs, device, &_lm_threshold_fops);
388 }
389
390 if (adreno_is_a5xx(adreno_dev))
391 debugfs_create_file("isdb", 0644, device->d_debugfs,
392 device, &_isdb_fops);
393}