blob: 93fdc08775aa7f5cf3c041c47fd990552e7ff52c [file] [log] [blame]
Jordan Crouse156cfbc2012-01-24 09:32:04 -07001/* Copyright (c) 2012, Code Aurora Forum. 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
Jordan Crouse156cfbc2012-01-24 09:32:04 -070013#include <linux/time.h>
14#include <linux/sysfs.h>
15#include <linux/utsname.h>
16#include <linux/sched.h>
17#include <linux/idr.h>
18
19#include "kgsl.h"
20#include "kgsl_log.h"
21#include "kgsl_device.h"
22#include "kgsl_sharedmem.h"
23#include "kgsl_snapshot.h"
24
25/* idr_for_each function to count the number of contexts */
26
27static int snapshot_context_count(int id, void *ptr, void *data)
28{
29 int *count = data;
30 *count = *count + 1;
31
32 return 0;
33}
34
35/*
36 * To simplify the iterator loop use a global pointer instead of trying
37 * to pass around double star references to the snapshot data
38 */
39
40static void *_ctxtptr;
41
42static int snapshot_context_info(int id, void *ptr, void *data)
43{
44 struct kgsl_snapshot_linux_context *header = _ctxtptr;
45 struct kgsl_context *context = ptr;
46 struct kgsl_device *device = context->dev_priv->device;
47
48 header->id = id;
49
50 /* Future-proof for per-context timestamps - for now, just
51 * return the global timestamp for all contexts
52 */
53
54 header->timestamp_queued = -1;
55 header->timestamp_retired = device->ftbl->readtimestamp(device,
56 KGSL_TIMESTAMP_RETIRED);
57
58 _ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
59
60 return 0;
61}
62
63/* Snapshot the Linux specific information */
64static int snapshot_os(struct kgsl_device *device,
65 void *snapshot, int remain, void *priv)
66{
67 struct kgsl_snapshot_linux *header = snapshot;
68 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
69 struct task_struct *task;
70 pid_t pid;
71 int hang = (int) priv;
72 int ctxtcount = 0;
73 int size = sizeof(*header);
74
75 /* Figure out how many active contexts there are - these will
76 * be appended on the end of the structure */
77
78 idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
79
80 size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);
81
82 /* Make sure there is enough room for the data */
83 if (remain < size) {
84 SNAPSHOT_ERR_NOMEM(device, "OS");
85 return 0;
86 }
87
88 memset(header, 0, sizeof(*header));
89
90 header->osid = KGSL_SNAPSHOT_OS_LINUX;
91
92 header->state = hang ? SNAPSHOT_STATE_HUNG : SNAPSHOT_STATE_RUNNING;
93
94 /* Get the kernel build information */
95 strlcpy(header->release, utsname()->release, sizeof(header->release));
96 strlcpy(header->version, utsname()->version, sizeof(header->version));
97
98 /* Get the Unix time for the timestamp */
99 header->seconds = get_seconds();
100
101 /* Remember the power information */
102 header->power_flags = pwr->power_flags;
103 header->power_level = pwr->active_pwrlevel;
104 header->power_interval_timeout = pwr->interval_timeout;
105 header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
106 header->busclk = kgsl_get_clkrate(pwr->ebi1_clk);
107
108 /* Future proof for per-context timestamps */
109 header->current_context = -1;
110
111 /* Get the current PT base */
112 header->ptbase = kgsl_mmu_get_current_ptbase(device);
113 /* And the PID for the task leader */
114 pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
115
116 task = find_task_by_vpid(pid);
117
118 if (task)
119 get_task_comm(header->comm, task);
120
121 header->ctxtcount = ctxtcount;
122
123 /* append information for each context */
124 _ctxtptr = snapshot + sizeof(*header);
125 idr_for_each(&device->context_idr, snapshot_context_info, NULL);
126
127 /* Return the size of the data segment */
128 return size;
129}
130/*
131 * kgsl_snapshot_dump_indexed_regs - helper function to dump indexed registers
132 * @device - the device to dump registers from
133 * @snapshot - pointer to the start of the region of memory for the snapshot
134 * @remain - a pointer to the number of bytes remaining in the snapshot
135 * @priv - A pointer to the kgsl_snapshot_indexed_registers data
136 *
137 * Given a indexed register cmd/data pair and a count, dump each indexed
138 * register
139 */
140
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700141static int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700142 void *snapshot, int remain, void *priv)
143{
144 struct kgsl_snapshot_indexed_registers *iregs = priv;
145 struct kgsl_snapshot_indexed_regs *header = snapshot;
146 unsigned int *data = snapshot + sizeof(*header);
147 int i;
148
149 if (remain < (iregs->count * 4) + sizeof(*header)) {
150 SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
151 return 0;
152 }
153
154 header->index_reg = iregs->index;
155 header->data_reg = iregs->data;
156 header->count = iregs->count;
157 header->start = iregs->start;
158
159 for (i = 0; i < iregs->count; i++) {
160 kgsl_regwrite(device, iregs->index, iregs->start + i);
161 kgsl_regread(device, iregs->data, &data[i]);
162 }
163
164 return (iregs->count * 4) + sizeof(*header);
165}
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700166
167/*
168 * kgsl_snapshot_dump_regs - helper function to dump device registers
169 * @device - the device to dump registers from
170 * @snapshot - pointer to the start of the region of memory for the snapshot
171 * @remain - a pointer to the number of bytes remaining in the snapshot
172 * @priv - A pointer to the kgsl_snapshot_registers data
173 *
174 * Given an array of register ranges pairs (start,end [inclusive]), dump the
175 * registers into a snapshot register section. The snapshot region stores a
176 * part of dwords for each register - the word address of the register, and
177 * the value.
178 */
179int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
180 int remain, void *priv)
181{
182 struct kgsl_snapshot_regs *header = snapshot;
183 struct kgsl_snapshot_registers *regs = priv;
184 unsigned int *data = snapshot + sizeof(*header);
185 int count = 0, i, j;
186
187 /* Figure out how many registers we are going to dump */
188
189 for (i = 0; i < regs->count; i++) {
190 int start = regs->regs[i * 2];
191 int end = regs->regs[i * 2 + 1];
192
193 count += (end - start + 1);
194 }
195
196 if (remain < (count * 8) + sizeof(*header)) {
197 SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
198 return 0;
199 }
200
201 for (i = 0; i < regs->count; i++) {
202 unsigned int start = regs->regs[i * 2];
203 unsigned int end = regs->regs[i * 2 + 1];
204
205 for (j = start; j <= end; j++) {
206 unsigned int val;
207
208 kgsl_regread(device, j, &val);
209 *data++ = j;
210 *data++ = val;
211 }
212 }
213
214 header->count = count;
215
216 /* Return the size of the section */
217 return (count * 8) + sizeof(*header);
218}
219EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
220
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700221void *kgsl_snapshot_indexed_registers(struct kgsl_device *device,
222 void *snapshot, int *remain,
223 unsigned int index, unsigned int data, unsigned int start,
224 unsigned int count)
225{
226 struct kgsl_snapshot_indexed_registers iregs;
227 iregs.index = index;
228 iregs.data = data;
229 iregs.start = start;
230 iregs.count = count;
231
232 return kgsl_snapshot_add_section(device,
233 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
234 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
235}
236EXPORT_SYMBOL(kgsl_snapshot_indexed_registers);
237
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700238/*
239 * kgsl_snapshot - construct a device snapshot
240 * @device - device to snapshot
241 * @hang - set to 1 if the snapshot was triggered following a hnag
242 * Given a device, construct a binary snapshot dump of the current device state
243 * and store it in the device snapshot memory.
244 */
245int kgsl_device_snapshot(struct kgsl_device *device, int hang)
246{
247 struct kgsl_snapshot_header *header = device->snapshot;
248 int remain = device->snapshot_maxsize - sizeof(*header);
249 void *snapshot;
250
251 /*
252 * The first hang is always the one we are interested in. To
253 * avoid a subsequent hang blowing away the first, the snapshot
254 * is frozen until it is dumped via sysfs.
255 *
256 * Note that triggered snapshots are always taken regardless
257 * of the state and never frozen.
258 */
259
260 if (hang && device->snapshot_frozen == 1)
261 return 0;
262
263 if (device->snapshot == NULL) {
264 KGSL_DRV_ERR(device,
265 "snapshot: No snapshot memory available\n");
266 return -ENOMEM;
267 }
268
269 if (remain < sizeof(*header)) {
270 KGSL_DRV_ERR(device,
271 "snapshot: Not enough memory for the header\n");
272 return -ENOMEM;
273 }
274
275 header->magic = SNAPSHOT_MAGIC;
276
277 header->gpuid = kgsl_gpuid(device);
278
279 /* Get a pointer to the first section (right after the header) */
280 snapshot = ((void *) device->snapshot) + sizeof(*header);
281
282 /* Build the Linux specific header */
283 snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
284 snapshot, &remain, snapshot_os, (void *) hang);
285
286 /* Get the device specific sections */
287 if (device->ftbl->snapshot)
288 snapshot = device->ftbl->snapshot(device, snapshot, &remain,
289 hang);
290
291 /* Add the empty end section to let the parser know we are done */
292 snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_END,
293 snapshot, &remain, NULL, NULL);
294
295 device->snapshot_timestamp = get_seconds();
296 device->snapshot_size = (int) (snapshot - device->snapshot);
297
298 /* Freeze the snapshot on a hang until it gets read */
299 device->snapshot_frozen = (hang) ? 1 : 0;
300
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700301 /* log buffer info to aid in ramdump recovery */
302 KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
303 device->snapshot, __pa(device->snapshot),
304 device->snapshot_size);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700305 return 0;
306}
307EXPORT_SYMBOL(kgsl_device_snapshot);
308
309/* An attribute for showing snapshot details */
310struct kgsl_snapshot_attribute {
311 struct attribute attr;
312 ssize_t (*show)(struct kgsl_device *device, char *buf);
313 ssize_t (*store)(struct kgsl_device *device, const char *buf,
314 size_t count);
315};
316
317#define to_snapshot_attr(a) \
318container_of(a, struct kgsl_snapshot_attribute, attr)
319
320#define kobj_to_device(a) \
321container_of(a, struct kgsl_device, snapshot_kobj)
322
323/* Dump the sysfs binary data to the user */
324static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
325 struct bin_attribute *attr, char *buf, loff_t off,
326 size_t count)
327{
328 struct kgsl_device *device = kobj_to_device(kobj);
329
330 if (device == NULL)
331 return 0;
332
333 /* Return nothing if we haven't taken a snapshot yet */
334 if (device->snapshot_timestamp == 0)
335 return 0;
336
337 /* Get the mutex to keep things from changing while we are dumping */
338 mutex_lock(&device->mutex);
339
340 /*
341 * Release the freeze on the snapshot the first time the buffer is read
342 */
343
344 device->snapshot_frozen = 0;
345
346 if (off >= device->snapshot_size) {
347 count = 0;
348 goto exit;
349 }
350
351 if (off + count > device->snapshot_size)
352 count = device->snapshot_size - off;
353
354 memcpy(buf, device->snapshot + off, count);
355
356exit:
357 mutex_unlock(&device->mutex);
358 return count;
359}
360
361/* Show the timestamp of the last collected snapshot */
362static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
363{
364 return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
365}
366
367/* manually trigger a new snapshot to be collected */
368static ssize_t trigger_store(struct kgsl_device *device, const char *buf,
369 size_t count)
370{
371 if (device && count > 0) {
372 mutex_lock(&device->mutex);
373 kgsl_device_snapshot(device, 0);
374 mutex_unlock(&device->mutex);
375 }
376
377 return count;
378}
379
380static struct bin_attribute snapshot_attr = {
381 .attr.name = "dump",
382 .attr.mode = 0444,
383 .size = 0,
384 .read = snapshot_show
385};
386
387#define SNAPSHOT_ATTR(_name, _mode, _show, _store) \
388struct kgsl_snapshot_attribute attr_##_name = { \
389 .attr = { .name = __stringify(_name), .mode = _mode }, \
390 .show = _show, \
391 .store = _store, \
392}
393
394SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
395SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
396
397static void snapshot_sysfs_release(struct kobject *kobj)
398{
399}
400
401static ssize_t snapshot_sysfs_show(struct kobject *kobj,
402 struct attribute *attr, char *buf)
403{
404 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
405 struct kgsl_device *device = kobj_to_device(kobj);
406 ssize_t ret;
407
408 if (device && pattr->show)
409 ret = pattr->show(device, buf);
410 else
411 ret = -EIO;
412
413 return ret;
414}
415
416static ssize_t snapshot_sysfs_store(struct kobject *kobj,
417 struct attribute *attr, const char *buf, size_t count)
418{
419 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
420 struct kgsl_device *device = kobj_to_device(kobj);
421 ssize_t ret;
422
423 if (device && pattr->store)
424 ret = pattr->store(device, buf, count);
425 else
426 ret = -EIO;
427
428 return ret;
429}
430
431static const struct sysfs_ops snapshot_sysfs_ops = {
432 .show = snapshot_sysfs_show,
433 .store = snapshot_sysfs_store,
434};
435
436static struct kobj_type ktype_snapshot = {
437 .sysfs_ops = &snapshot_sysfs_ops,
438 .default_attrs = NULL,
439 .release = snapshot_sysfs_release,
440};
441
442/* kgsl_device_snapshot_init - Add resources for the device GPU snapshot
443 * @device - The device to initalize
444 *
445 * Allocate memory for a GPU snapshot for the specified device,
446 * and create the sysfs files to manage it
447 */
448
449int kgsl_device_snapshot_init(struct kgsl_device *device)
450{
451 int ret;
452
453 if (device->snapshot == NULL)
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700454 device->snapshot = kzalloc(KGSL_SNAPSHOT_MEMSIZE, GFP_KERNEL);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700455
456 if (device->snapshot == NULL)
457 return -ENOMEM;
458
459 device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
460 device->snapshot_timestamp = 0;
461
462 ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
463 &device->dev->kobj, "snapshot");
464 if (ret)
465 goto done;
466
467 ret = sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr);
468 if (ret)
469 goto done;
470
471 ret = sysfs_create_file(&device->snapshot_kobj, &attr_trigger.attr);
472 if (ret)
473 goto done;
474
475 ret = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
476
477done:
478 return ret;
479}
480EXPORT_SYMBOL(kgsl_device_snapshot_init);
481
482/* kgsl_device_snapshot_close - Take down snapshot memory for a device
483 * @device - Pointer to the kgsl_device
484 *
485 * Remove the sysfs files and free the memory allocated for the GPU
486 * snapshot
487 */
488
489void kgsl_device_snapshot_close(struct kgsl_device *device)
490{
491 sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr);
492 sysfs_remove_file(&device->snapshot_kobj, &attr_trigger.attr);
493 sysfs_remove_file(&device->snapshot_kobj, &attr_timestamp.attr);
494
495 kobject_put(&device->snapshot_kobj);
496
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700497 kfree(device->snapshot);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700498
499 device->snapshot = NULL;
500 device->snapshot_maxsize = 0;
501 device->snapshot_timestamp = 0;
502}
503EXPORT_SYMBOL(kgsl_device_snapshot_close);