blob: a2ab5b136a98731b2335887aad11b3febbcb54a8 [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
Steve Mucklef132c6c2012-06-06 18:30:57 -070013#include <linux/export.h>
Jordan Crouse156cfbc2012-01-24 09:32:04 -070014#include <linux/time.h>
15#include <linux/sysfs.h>
16#include <linux/utsname.h>
17#include <linux/sched.h>
18#include <linux/idr.h>
19
20#include "kgsl.h"
21#include "kgsl_log.h"
22#include "kgsl_device.h"
23#include "kgsl_sharedmem.h"
24#include "kgsl_snapshot.h"
25
Jordan Crouse9610b6b2012-03-16 14:53:42 -060026/* Placeholder for the list of memory objects frozen after a hang */
27
28struct kgsl_snapshot_object {
29 unsigned int gpuaddr;
30 unsigned int ptbase;
31 unsigned int size;
Jordan Crouse233b2092012-04-18 09:31:09 -060032 unsigned int offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -060033 int type;
34 struct kgsl_mem_entry *entry;
35 struct list_head node;
36};
37
Jordan Crouse7c325702012-06-20 08:22:16 -060038struct snapshot_obj_itr {
39 void *buf; /* Buffer pointer to write to */
40 int pos; /* Current position in the sequence */
41 loff_t offset; /* file offset to start writing from */
42 size_t remain; /* Bytes remaining in buffer */
43 size_t write; /* Bytes written so far */
44};
45
46static void obj_itr_init(struct snapshot_obj_itr *itr, void *buf,
47 loff_t offset, size_t remain)
48{
49 itr->buf = buf;
50 itr->offset = offset;
51 itr->remain = remain;
52 itr->pos = 0;
53 itr->write = 0;
54}
55
56static int obj_itr_out(struct snapshot_obj_itr *itr, void *src, int size)
57{
58 if (itr->remain == 0)
59 return 0;
60
61 if ((itr->pos + size) <= itr->offset)
62 goto done;
63
64 /* Handle the case that offset is in the middle of the buffer */
65
66 if (itr->offset > itr->pos) {
67 src += (itr->offset - itr->pos);
68 size -= (itr->offset - itr->pos);
69
70 /* Advance pos to the offset start */
71 itr->pos = itr->offset;
72 }
73
74 if (size > itr->remain)
75 size = itr->remain;
76
77 memcpy(itr->buf, src, size);
78
79 itr->buf += size;
80 itr->write += size;
81 itr->remain -= size;
82
83done:
84 itr->pos += size;
85 return size;
86}
87
Jordan Crouse156cfbc2012-01-24 09:32:04 -070088/* idr_for_each function to count the number of contexts */
89
90static int snapshot_context_count(int id, void *ptr, void *data)
91{
92 int *count = data;
93 *count = *count + 1;
94
95 return 0;
96}
97
98/*
99 * To simplify the iterator loop use a global pointer instead of trying
100 * to pass around double star references to the snapshot data
101 */
102
103static void *_ctxtptr;
104
105static int snapshot_context_info(int id, void *ptr, void *data)
106{
107 struct kgsl_snapshot_linux_context *header = _ctxtptr;
108 struct kgsl_context *context = ptr;
109 struct kgsl_device *device = context->dev_priv->device;
110
111 header->id = id;
112
113 /* Future-proof for per-context timestamps - for now, just
114 * return the global timestamp for all contexts
115 */
116
Jeremy Gebben731dac52012-05-10 11:13:42 -0600117 header->timestamp_queued = kgsl_readtimestamp(device, context,
118 KGSL_TIMESTAMP_QUEUED);
119 header->timestamp_retired = kgsl_readtimestamp(device, context,
120 KGSL_TIMESTAMP_RETIRED);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700121
122 _ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
123
124 return 0;
125}
126
127/* Snapshot the Linux specific information */
128static int snapshot_os(struct kgsl_device *device,
129 void *snapshot, int remain, void *priv)
130{
131 struct kgsl_snapshot_linux *header = snapshot;
132 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
133 struct task_struct *task;
134 pid_t pid;
135 int hang = (int) priv;
136 int ctxtcount = 0;
137 int size = sizeof(*header);
138
139 /* Figure out how many active contexts there are - these will
140 * be appended on the end of the structure */
141
142 idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
143
144 size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);
145
146 /* Make sure there is enough room for the data */
147 if (remain < size) {
148 SNAPSHOT_ERR_NOMEM(device, "OS");
149 return 0;
150 }
151
152 memset(header, 0, sizeof(*header));
153
154 header->osid = KGSL_SNAPSHOT_OS_LINUX;
155
156 header->state = hang ? SNAPSHOT_STATE_HUNG : SNAPSHOT_STATE_RUNNING;
157
158 /* Get the kernel build information */
159 strlcpy(header->release, utsname()->release, sizeof(header->release));
160 strlcpy(header->version, utsname()->version, sizeof(header->version));
161
162 /* Get the Unix time for the timestamp */
163 header->seconds = get_seconds();
164
165 /* Remember the power information */
166 header->power_flags = pwr->power_flags;
167 header->power_level = pwr->active_pwrlevel;
168 header->power_interval_timeout = pwr->interval_timeout;
169 header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
170 header->busclk = kgsl_get_clkrate(pwr->ebi1_clk);
171
172 /* Future proof for per-context timestamps */
173 header->current_context = -1;
174
175 /* Get the current PT base */
Shubhraprakash Das79447952012-04-26 18:12:23 -0600176 header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700177 /* And the PID for the task leader */
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700178 pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(&device->mmu,
179 header->ptbase);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700180
181 task = find_task_by_vpid(pid);
182
183 if (task)
184 get_task_comm(header->comm, task);
185
186 header->ctxtcount = ctxtcount;
187
188 /* append information for each context */
189 _ctxtptr = snapshot + sizeof(*header);
190 idr_for_each(&device->context_idr, snapshot_context_info, NULL);
191
192 /* Return the size of the data segment */
193 return size;
194}
195/*
196 * kgsl_snapshot_dump_indexed_regs - helper function to dump indexed registers
197 * @device - the device to dump registers from
198 * @snapshot - pointer to the start of the region of memory for the snapshot
199 * @remain - a pointer to the number of bytes remaining in the snapshot
200 * @priv - A pointer to the kgsl_snapshot_indexed_registers data
201 *
202 * Given a indexed register cmd/data pair and a count, dump each indexed
203 * register
204 */
205
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700206static int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700207 void *snapshot, int remain, void *priv)
208{
209 struct kgsl_snapshot_indexed_registers *iregs = priv;
210 struct kgsl_snapshot_indexed_regs *header = snapshot;
211 unsigned int *data = snapshot + sizeof(*header);
212 int i;
213
214 if (remain < (iregs->count * 4) + sizeof(*header)) {
215 SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
216 return 0;
217 }
218
219 header->index_reg = iregs->index;
220 header->data_reg = iregs->data;
221 header->count = iregs->count;
222 header->start = iregs->start;
223
224 for (i = 0; i < iregs->count; i++) {
225 kgsl_regwrite(device, iregs->index, iregs->start + i);
226 kgsl_regread(device, iregs->data, &data[i]);
227 }
228
229 return (iregs->count * 4) + sizeof(*header);
230}
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700231
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600232#define GPU_OBJ_HEADER_SZ \
233 (sizeof(struct kgsl_snapshot_section_header) + \
234 sizeof(struct kgsl_snapshot_gpu_object))
235
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600236static int kgsl_snapshot_dump_object(struct kgsl_device *device,
Jordan Crouse7c325702012-06-20 08:22:16 -0600237 struct kgsl_snapshot_object *obj, struct snapshot_obj_itr *itr)
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600238{
Jordan Crouse7c325702012-06-20 08:22:16 -0600239 struct kgsl_snapshot_section_header sect;
240 struct kgsl_snapshot_gpu_object header;
241 int ret;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600242
Jordan Crouse7c325702012-06-20 08:22:16 -0600243 sect.magic = SNAPSHOT_SECTION_MAGIC;
244 sect.id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600245
Jordan Crouse7c325702012-06-20 08:22:16 -0600246 /*
247 * Header size is in dwords, object size is in bytes -
248 * round up if the object size isn't dword aligned
249 */
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600250
Jordan Crouse7c325702012-06-20 08:22:16 -0600251 sect.size = GPU_OBJ_HEADER_SZ + ALIGN(obj->size, 4);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600252
Jordan Crouse7c325702012-06-20 08:22:16 -0600253 ret = obj_itr_out(itr, &sect, sizeof(sect));
254 if (ret == 0)
255 return 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600256
Jordan Crouse7c325702012-06-20 08:22:16 -0600257 header.size = ALIGN(obj->size, 4) >> 2;
258 header.gpuaddr = obj->gpuaddr;
259 header.ptbase = obj->ptbase;
260 header.type = obj->type;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600261
Jordan Crouse7c325702012-06-20 08:22:16 -0600262 ret = obj_itr_out(itr, &header, sizeof(header));
263 if (ret == 0)
264 return 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600265
Jordan Crouse7c325702012-06-20 08:22:16 -0600266 ret = obj_itr_out(itr, obj->entry->memdesc.hostptr + obj->offset,
267 obj->size);
268 if (ret == 0)
269 return 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600270
Jordan Crouse7c325702012-06-20 08:22:16 -0600271 /* Pad the end to a dword boundary if we need to */
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600272
Jordan Crouse7c325702012-06-20 08:22:16 -0600273 if (obj->size % 4) {
274 unsigned int dummy = 0;
275 ret = obj_itr_out(itr, &dummy, obj->size % 4);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600276 }
277
278 return ret;
279}
280
281static void kgsl_snapshot_put_object(struct kgsl_device *device,
282 struct kgsl_snapshot_object *obj)
283{
284 list_del(&obj->node);
285
286 obj->entry->flags &= ~KGSL_MEM_ENTRY_FROZEN;
287 kgsl_mem_entry_put(obj->entry);
288
289 kfree(obj);
290}
291
292/* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
293 * @device - the device that is being snapshotted
294 * @ptbase - the pagetable base of the object to freeze
295 * @gpuaddr - The gpu address of the object to freeze
296 * @size - the size of the object (may not always be the size of the region)
297 * @type - the type of object being saved (shader, vbo, etc)
298 *
299 * Mark and freeze a GPU buffer object. This will prevent it from being
300 * freed until it can be copied out as part of the snapshot dump. Returns the
301 * size of the object being frozen
302 */
303
304int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
305 unsigned int gpuaddr, unsigned int size, unsigned int type)
306{
307 struct kgsl_mem_entry *entry;
308 struct kgsl_snapshot_object *obj;
309 int offset;
310
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700311 entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600312
313 if (entry == NULL) {
314 KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
315 gpuaddr);
316 return 0;
317 }
318
319 /* We can't freeze external memory, because we don't own it */
320 if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
321 KGSL_DRV_ERR(device,
322 "Only internal GPU buffers can be frozen\n");
323 return 0;
324 }
325
326 /*
327 * size indicates the number of bytes in the region to save. This might
328 * not always be the entire size of the region because some buffers are
329 * sub-allocated from a larger region. However, if size 0 was passed
330 * thats a flag that the caller wants to capture the entire buffer
331 */
332
333 if (size == 0) {
334 size = entry->memdesc.size;
335 offset = 0;
336
337 /* Adjust the gpuaddr to the start of the object */
338 gpuaddr = entry->memdesc.gpuaddr;
339 } else {
340 offset = gpuaddr - entry->memdesc.gpuaddr;
341 }
342
343 if (size + offset > entry->memdesc.size) {
344 KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
345 gpuaddr);
346 return 0;
347 }
348
349 /* If the buffer is already on the list, skip it */
350 list_for_each_entry(obj, &device->snapshot_obj_list, node) {
351 if (obj->gpuaddr == gpuaddr && obj->ptbase == ptbase) {
352 /* If the size is different, use the new size */
353 if (obj->size != size)
354 obj->size = size;
355
356 return 0;
357 }
358 }
359
Jordan Crouse17d6d8b2012-04-18 09:31:09 -0600360 if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
361 KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
362 gpuaddr);
363 return 0;
364 }
365
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600366 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
367
368 if (obj == NULL) {
369 KGSL_DRV_ERR(device, "Unable to allocate memory\n");
370 return 0;
371 }
372
373 /* Ref count the mem entry */
374 kgsl_mem_entry_get(entry);
375
376 obj->type = type;
377 obj->entry = entry;
378 obj->gpuaddr = gpuaddr;
379 obj->ptbase = ptbase;
380 obj->size = size;
Jordan Crouse233b2092012-04-18 09:31:09 -0600381 obj->offset = offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600382
383 list_add(&obj->node, &device->snapshot_obj_list);
384
385 /*
386 * Return the size of the entire mem entry that was frozen - this gets
387 * used for tracking how much memory is frozen for a hang. Also, mark
388 * the memory entry as frozen. If the entry was already marked as
389 * frozen, then another buffer already got to it. In that case, return
390 * 0 so it doesn't get counted twice
391 */
392
393 if (entry->flags & KGSL_MEM_ENTRY_FROZEN)
394 return 0;
395
396 entry->flags |= KGSL_MEM_ENTRY_FROZEN;
397
398 return entry->memdesc.size;
399}
400EXPORT_SYMBOL(kgsl_snapshot_get_object);
401
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700402/*
403 * kgsl_snapshot_dump_regs - helper function to dump device registers
404 * @device - the device to dump registers from
405 * @snapshot - pointer to the start of the region of memory for the snapshot
406 * @remain - a pointer to the number of bytes remaining in the snapshot
407 * @priv - A pointer to the kgsl_snapshot_registers data
408 *
409 * Given an array of register ranges pairs (start,end [inclusive]), dump the
410 * registers into a snapshot register section. The snapshot region stores a
411 * part of dwords for each register - the word address of the register, and
412 * the value.
413 */
414int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
415 int remain, void *priv)
416{
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600417 struct kgsl_snapshot_registers_list *list = priv;
418
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700419 struct kgsl_snapshot_regs *header = snapshot;
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600420 struct kgsl_snapshot_registers *regs;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700421 unsigned int *data = snapshot + sizeof(*header);
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600422 int count = 0, i, j, k;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700423
424 /* Figure out how many registers we are going to dump */
425
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600426 for (i = 0; i < list->count; i++) {
427 regs = &(list->registers[i]);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700428
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600429 for (j = 0; j < regs->count; j++) {
430 int start = regs->regs[j * 2];
431 int end = regs->regs[j * 2 + 1];
432
433 count += (end - start + 1);
434 }
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700435 }
436
437 if (remain < (count * 8) + sizeof(*header)) {
438 SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
439 return 0;
440 }
441
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700442
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600443 for (i = 0; i < list->count; i++) {
444 regs = &(list->registers[i]);
445 for (j = 0; j < regs->count; j++) {
446 unsigned int start = regs->regs[j * 2];
447 unsigned int end = regs->regs[j * 2 + 1];
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700448
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600449 for (k = start; k <= end; k++) {
450 unsigned int val;
451
452 kgsl_regread(device, k, &val);
453 *data++ = k;
454 *data++ = val;
455 }
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700456 }
457 }
458
459 header->count = count;
460
461 /* Return the size of the section */
462 return (count * 8) + sizeof(*header);
463}
464EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
465
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700466void *kgsl_snapshot_indexed_registers(struct kgsl_device *device,
467 void *snapshot, int *remain,
468 unsigned int index, unsigned int data, unsigned int start,
469 unsigned int count)
470{
471 struct kgsl_snapshot_indexed_registers iregs;
472 iregs.index = index;
473 iregs.data = data;
474 iregs.start = start;
475 iregs.count = count;
476
477 return kgsl_snapshot_add_section(device,
478 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
479 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
480}
481EXPORT_SYMBOL(kgsl_snapshot_indexed_registers);
482
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700483/*
484 * kgsl_snapshot - construct a device snapshot
485 * @device - device to snapshot
486 * @hang - set to 1 if the snapshot was triggered following a hnag
487 * Given a device, construct a binary snapshot dump of the current device state
488 * and store it in the device snapshot memory.
489 */
490int kgsl_device_snapshot(struct kgsl_device *device, int hang)
491{
492 struct kgsl_snapshot_header *header = device->snapshot;
493 int remain = device->snapshot_maxsize - sizeof(*header);
494 void *snapshot;
495
496 /*
497 * The first hang is always the one we are interested in. To
498 * avoid a subsequent hang blowing away the first, the snapshot
499 * is frozen until it is dumped via sysfs.
500 *
501 * Note that triggered snapshots are always taken regardless
502 * of the state and never frozen.
503 */
504
505 if (hang && device->snapshot_frozen == 1)
506 return 0;
507
508 if (device->snapshot == NULL) {
509 KGSL_DRV_ERR(device,
510 "snapshot: No snapshot memory available\n");
511 return -ENOMEM;
512 }
513
514 if (remain < sizeof(*header)) {
515 KGSL_DRV_ERR(device,
516 "snapshot: Not enough memory for the header\n");
517 return -ENOMEM;
518 }
519
520 header->magic = SNAPSHOT_MAGIC;
521
Jordan Crouse70829d32012-06-20 08:22:17 -0600522 header->gpuid = kgsl_gpuid(device, &header->chipid);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700523
524 /* Get a pointer to the first section (right after the header) */
525 snapshot = ((void *) device->snapshot) + sizeof(*header);
526
527 /* Build the Linux specific header */
528 snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
529 snapshot, &remain, snapshot_os, (void *) hang);
530
531 /* Get the device specific sections */
532 if (device->ftbl->snapshot)
533 snapshot = device->ftbl->snapshot(device, snapshot, &remain,
534 hang);
535
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700536 device->snapshot_timestamp = get_seconds();
537 device->snapshot_size = (int) (snapshot - device->snapshot);
538
539 /* Freeze the snapshot on a hang until it gets read */
540 device->snapshot_frozen = (hang) ? 1 : 0;
541
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700542 /* log buffer info to aid in ramdump recovery */
543 KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
544 device->snapshot, __pa(device->snapshot),
545 device->snapshot_size);
Jeremy Gebben90812c82012-03-08 12:46:01 -0700546 if (hang)
547 sysfs_notify(&device->snapshot_kobj, NULL, "timestamp");
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700548 return 0;
549}
550EXPORT_SYMBOL(kgsl_device_snapshot);
551
552/* An attribute for showing snapshot details */
553struct kgsl_snapshot_attribute {
554 struct attribute attr;
555 ssize_t (*show)(struct kgsl_device *device, char *buf);
556 ssize_t (*store)(struct kgsl_device *device, const char *buf,
557 size_t count);
558};
559
560#define to_snapshot_attr(a) \
561container_of(a, struct kgsl_snapshot_attribute, attr)
562
563#define kobj_to_device(a) \
564container_of(a, struct kgsl_device, snapshot_kobj)
565
566/* Dump the sysfs binary data to the user */
567static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
568 struct bin_attribute *attr, char *buf, loff_t off,
569 size_t count)
570{
571 struct kgsl_device *device = kobj_to_device(kobj);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600572 struct kgsl_snapshot_object *obj, *tmp;
Jordan Crouse7c325702012-06-20 08:22:16 -0600573 struct kgsl_snapshot_section_header head;
574 struct snapshot_obj_itr itr;
575 int ret;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700576
577 if (device == NULL)
578 return 0;
579
580 /* Return nothing if we haven't taken a snapshot yet */
581 if (device->snapshot_timestamp == 0)
582 return 0;
583
584 /* Get the mutex to keep things from changing while we are dumping */
585 mutex_lock(&device->mutex);
586
Jordan Crouse7c325702012-06-20 08:22:16 -0600587 obj_itr_init(&itr, buf, off, count);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600588
Jordan Crouse7c325702012-06-20 08:22:16 -0600589 ret = obj_itr_out(&itr, device->snapshot, device->snapshot_size);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600590
Jordan Crouse7c325702012-06-20 08:22:16 -0600591 if (ret == 0)
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600592 goto done;
593
Jordan Crouse7c325702012-06-20 08:22:16 -0600594 list_for_each_entry(obj, &device->snapshot_obj_list, node)
595 kgsl_snapshot_dump_object(device, obj, &itr);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600596
Jordan Crouse7c325702012-06-20 08:22:16 -0600597 {
598 head.magic = SNAPSHOT_SECTION_MAGIC;
599 head.id = KGSL_SNAPSHOT_SECTION_END;
600 head.size = sizeof(head);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600601
Jordan Crouse7c325702012-06-20 08:22:16 -0600602 obj_itr_out(&itr, &head, sizeof(head));
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600603 }
604
Jordan Crouse7c325702012-06-20 08:22:16 -0600605 /*
606 * Make sure everything has been written out before destroying things.
607 * The best way to confirm this is to go all the way through without
608 * writing any bytes - so only release if we get this far and
609 * itr->write is 0
610 */
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600611
Jordan Crouse7c325702012-06-20 08:22:16 -0600612 if (itr.write == 0) {
613 list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list,
614 node)
615 kgsl_snapshot_put_object(device, obj);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600616
Jordan Crouse7c325702012-06-20 08:22:16 -0600617 if (device->snapshot_frozen)
618 KGSL_DRV_ERR(device, "Snapshot objects released\n");
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600619
Jordan Crouse7c325702012-06-20 08:22:16 -0600620 device->snapshot_frozen = 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600621 }
622
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600623done:
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700624 mutex_unlock(&device->mutex);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600625
Jordan Crouse7c325702012-06-20 08:22:16 -0600626 return itr.write;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700627}
628
629/* Show the timestamp of the last collected snapshot */
630static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
631{
632 return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
633}
634
635/* manually trigger a new snapshot to be collected */
636static ssize_t trigger_store(struct kgsl_device *device, const char *buf,
637 size_t count)
638{
639 if (device && count > 0) {
640 mutex_lock(&device->mutex);
641 kgsl_device_snapshot(device, 0);
642 mutex_unlock(&device->mutex);
643 }
644
645 return count;
646}
647
648static struct bin_attribute snapshot_attr = {
649 .attr.name = "dump",
650 .attr.mode = 0444,
651 .size = 0,
652 .read = snapshot_show
653};
654
655#define SNAPSHOT_ATTR(_name, _mode, _show, _store) \
656struct kgsl_snapshot_attribute attr_##_name = { \
657 .attr = { .name = __stringify(_name), .mode = _mode }, \
658 .show = _show, \
659 .store = _store, \
660}
661
662SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
663SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
664
665static void snapshot_sysfs_release(struct kobject *kobj)
666{
667}
668
669static ssize_t snapshot_sysfs_show(struct kobject *kobj,
670 struct attribute *attr, char *buf)
671{
672 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
673 struct kgsl_device *device = kobj_to_device(kobj);
674 ssize_t ret;
675
676 if (device && pattr->show)
677 ret = pattr->show(device, buf);
678 else
679 ret = -EIO;
680
681 return ret;
682}
683
684static ssize_t snapshot_sysfs_store(struct kobject *kobj,
685 struct attribute *attr, const char *buf, size_t count)
686{
687 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
688 struct kgsl_device *device = kobj_to_device(kobj);
689 ssize_t ret;
690
691 if (device && pattr->store)
692 ret = pattr->store(device, buf, count);
693 else
694 ret = -EIO;
695
696 return ret;
697}
698
699static const struct sysfs_ops snapshot_sysfs_ops = {
700 .show = snapshot_sysfs_show,
701 .store = snapshot_sysfs_store,
702};
703
704static struct kobj_type ktype_snapshot = {
705 .sysfs_ops = &snapshot_sysfs_ops,
706 .default_attrs = NULL,
707 .release = snapshot_sysfs_release,
708};
709
710/* kgsl_device_snapshot_init - Add resources for the device GPU snapshot
711 * @device - The device to initalize
712 *
713 * Allocate memory for a GPU snapshot for the specified device,
714 * and create the sysfs files to manage it
715 */
716
717int kgsl_device_snapshot_init(struct kgsl_device *device)
718{
719 int ret;
720
721 if (device->snapshot == NULL)
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700722 device->snapshot = kzalloc(KGSL_SNAPSHOT_MEMSIZE, GFP_KERNEL);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700723
724 if (device->snapshot == NULL)
725 return -ENOMEM;
726
727 device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
728 device->snapshot_timestamp = 0;
729
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600730 INIT_LIST_HEAD(&device->snapshot_obj_list);
731
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700732 ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
733 &device->dev->kobj, "snapshot");
734 if (ret)
735 goto done;
736
737 ret = sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr);
738 if (ret)
739 goto done;
740
741 ret = sysfs_create_file(&device->snapshot_kobj, &attr_trigger.attr);
742 if (ret)
743 goto done;
744
745 ret = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
746
747done:
748 return ret;
749}
750EXPORT_SYMBOL(kgsl_device_snapshot_init);
751
752/* kgsl_device_snapshot_close - Take down snapshot memory for a device
753 * @device - Pointer to the kgsl_device
754 *
755 * Remove the sysfs files and free the memory allocated for the GPU
756 * snapshot
757 */
758
759void kgsl_device_snapshot_close(struct kgsl_device *device)
760{
761 sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr);
762 sysfs_remove_file(&device->snapshot_kobj, &attr_trigger.attr);
763 sysfs_remove_file(&device->snapshot_kobj, &attr_timestamp.attr);
764
765 kobject_put(&device->snapshot_kobj);
766
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700767 kfree(device->snapshot);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700768
769 device->snapshot = NULL;
770 device->snapshot_maxsize = 0;
771 device->snapshot_timestamp = 0;
772}
773EXPORT_SYMBOL(kgsl_device_snapshot_close);