blob: 6f0eaebc780a2176d4d61986a70e9bef96562239 [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 */
178 pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
179
180 task = find_task_by_vpid(pid);
181
182 if (task)
183 get_task_comm(header->comm, task);
184
185 header->ctxtcount = ctxtcount;
186
187 /* append information for each context */
188 _ctxtptr = snapshot + sizeof(*header);
189 idr_for_each(&device->context_idr, snapshot_context_info, NULL);
190
191 /* Return the size of the data segment */
192 return size;
193}
194/*
195 * kgsl_snapshot_dump_indexed_regs - helper function to dump indexed registers
196 * @device - the device to dump registers from
197 * @snapshot - pointer to the start of the region of memory for the snapshot
198 * @remain - a pointer to the number of bytes remaining in the snapshot
199 * @priv - A pointer to the kgsl_snapshot_indexed_registers data
200 *
201 * Given a indexed register cmd/data pair and a count, dump each indexed
202 * register
203 */
204
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700205static int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700206 void *snapshot, int remain, void *priv)
207{
208 struct kgsl_snapshot_indexed_registers *iregs = priv;
209 struct kgsl_snapshot_indexed_regs *header = snapshot;
210 unsigned int *data = snapshot + sizeof(*header);
211 int i;
212
213 if (remain < (iregs->count * 4) + sizeof(*header)) {
214 SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
215 return 0;
216 }
217
218 header->index_reg = iregs->index;
219 header->data_reg = iregs->data;
220 header->count = iregs->count;
221 header->start = iregs->start;
222
223 for (i = 0; i < iregs->count; i++) {
224 kgsl_regwrite(device, iregs->index, iregs->start + i);
225 kgsl_regread(device, iregs->data, &data[i]);
226 }
227
228 return (iregs->count * 4) + sizeof(*header);
229}
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700230
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600231#define GPU_OBJ_HEADER_SZ \
232 (sizeof(struct kgsl_snapshot_section_header) + \
233 sizeof(struct kgsl_snapshot_gpu_object))
234
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600235static int kgsl_snapshot_dump_object(struct kgsl_device *device,
Jordan Crouse7c325702012-06-20 08:22:16 -0600236 struct kgsl_snapshot_object *obj, struct snapshot_obj_itr *itr)
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600237{
Jordan Crouse7c325702012-06-20 08:22:16 -0600238 struct kgsl_snapshot_section_header sect;
239 struct kgsl_snapshot_gpu_object header;
240 int ret;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600241
Jordan Crouse7c325702012-06-20 08:22:16 -0600242 sect.magic = SNAPSHOT_SECTION_MAGIC;
243 sect.id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600244
Jordan Crouse7c325702012-06-20 08:22:16 -0600245 /*
246 * Header size is in dwords, object size is in bytes -
247 * round up if the object size isn't dword aligned
248 */
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600249
Jordan Crouse7c325702012-06-20 08:22:16 -0600250 sect.size = GPU_OBJ_HEADER_SZ + ALIGN(obj->size, 4);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600251
Jordan Crouse7c325702012-06-20 08:22:16 -0600252 ret = obj_itr_out(itr, &sect, sizeof(sect));
253 if (ret == 0)
254 return 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600255
Jordan Crouse7c325702012-06-20 08:22:16 -0600256 header.size = ALIGN(obj->size, 4) >> 2;
257 header.gpuaddr = obj->gpuaddr;
258 header.ptbase = obj->ptbase;
259 header.type = obj->type;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600260
Jordan Crouse7c325702012-06-20 08:22:16 -0600261 ret = obj_itr_out(itr, &header, sizeof(header));
262 if (ret == 0)
263 return 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600264
Jordan Crouse7c325702012-06-20 08:22:16 -0600265 ret = obj_itr_out(itr, obj->entry->memdesc.hostptr + obj->offset,
266 obj->size);
267 if (ret == 0)
268 return 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600269
Jordan Crouse7c325702012-06-20 08:22:16 -0600270 /* Pad the end to a dword boundary if we need to */
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600271
Jordan Crouse7c325702012-06-20 08:22:16 -0600272 if (obj->size % 4) {
273 unsigned int dummy = 0;
274 ret = obj_itr_out(itr, &dummy, obj->size % 4);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600275 }
276
277 return ret;
278}
279
280static void kgsl_snapshot_put_object(struct kgsl_device *device,
281 struct kgsl_snapshot_object *obj)
282{
283 list_del(&obj->node);
284
285 obj->entry->flags &= ~KGSL_MEM_ENTRY_FROZEN;
286 kgsl_mem_entry_put(obj->entry);
287
288 kfree(obj);
289}
290
291/* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
292 * @device - the device that is being snapshotted
293 * @ptbase - the pagetable base of the object to freeze
294 * @gpuaddr - The gpu address of the object to freeze
295 * @size - the size of the object (may not always be the size of the region)
296 * @type - the type of object being saved (shader, vbo, etc)
297 *
298 * Mark and freeze a GPU buffer object. This will prevent it from being
299 * freed until it can be copied out as part of the snapshot dump. Returns the
300 * size of the object being frozen
301 */
302
303int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
304 unsigned int gpuaddr, unsigned int size, unsigned int type)
305{
306 struct kgsl_mem_entry *entry;
307 struct kgsl_snapshot_object *obj;
308 int offset;
309
310 entry = kgsl_get_mem_entry(ptbase, gpuaddr, size);
311
312 if (entry == NULL) {
313 KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
314 gpuaddr);
315 return 0;
316 }
317
318 /* We can't freeze external memory, because we don't own it */
319 if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
320 KGSL_DRV_ERR(device,
321 "Only internal GPU buffers can be frozen\n");
322 return 0;
323 }
324
325 /*
326 * size indicates the number of bytes in the region to save. This might
327 * not always be the entire size of the region because some buffers are
328 * sub-allocated from a larger region. However, if size 0 was passed
329 * thats a flag that the caller wants to capture the entire buffer
330 */
331
332 if (size == 0) {
333 size = entry->memdesc.size;
334 offset = 0;
335
336 /* Adjust the gpuaddr to the start of the object */
337 gpuaddr = entry->memdesc.gpuaddr;
338 } else {
339 offset = gpuaddr - entry->memdesc.gpuaddr;
340 }
341
342 if (size + offset > entry->memdesc.size) {
343 KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
344 gpuaddr);
345 return 0;
346 }
347
348 /* If the buffer is already on the list, skip it */
349 list_for_each_entry(obj, &device->snapshot_obj_list, node) {
350 if (obj->gpuaddr == gpuaddr && obj->ptbase == ptbase) {
351 /* If the size is different, use the new size */
352 if (obj->size != size)
353 obj->size = size;
354
355 return 0;
356 }
357 }
358
Jordan Crouse17d6d8b2012-04-18 09:31:09 -0600359 if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
360 KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
361 gpuaddr);
362 return 0;
363 }
364
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600365 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
366
367 if (obj == NULL) {
368 KGSL_DRV_ERR(device, "Unable to allocate memory\n");
369 return 0;
370 }
371
372 /* Ref count the mem entry */
373 kgsl_mem_entry_get(entry);
374
375 obj->type = type;
376 obj->entry = entry;
377 obj->gpuaddr = gpuaddr;
378 obj->ptbase = ptbase;
379 obj->size = size;
Jordan Crouse233b2092012-04-18 09:31:09 -0600380 obj->offset = offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600381
382 list_add(&obj->node, &device->snapshot_obj_list);
383
384 /*
385 * Return the size of the entire mem entry that was frozen - this gets
386 * used for tracking how much memory is frozen for a hang. Also, mark
387 * the memory entry as frozen. If the entry was already marked as
388 * frozen, then another buffer already got to it. In that case, return
389 * 0 so it doesn't get counted twice
390 */
391
392 if (entry->flags & KGSL_MEM_ENTRY_FROZEN)
393 return 0;
394
395 entry->flags |= KGSL_MEM_ENTRY_FROZEN;
396
397 return entry->memdesc.size;
398}
399EXPORT_SYMBOL(kgsl_snapshot_get_object);
400
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700401/*
402 * kgsl_snapshot_dump_regs - helper function to dump device registers
403 * @device - the device to dump registers from
404 * @snapshot - pointer to the start of the region of memory for the snapshot
405 * @remain - a pointer to the number of bytes remaining in the snapshot
406 * @priv - A pointer to the kgsl_snapshot_registers data
407 *
408 * Given an array of register ranges pairs (start,end [inclusive]), dump the
409 * registers into a snapshot register section. The snapshot region stores a
410 * part of dwords for each register - the word address of the register, and
411 * the value.
412 */
413int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
414 int remain, void *priv)
415{
416 struct kgsl_snapshot_regs *header = snapshot;
417 struct kgsl_snapshot_registers *regs = priv;
418 unsigned int *data = snapshot + sizeof(*header);
419 int count = 0, i, j;
420
421 /* Figure out how many registers we are going to dump */
422
423 for (i = 0; i < regs->count; i++) {
424 int start = regs->regs[i * 2];
425 int end = regs->regs[i * 2 + 1];
426
427 count += (end - start + 1);
428 }
429
430 if (remain < (count * 8) + sizeof(*header)) {
431 SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
432 return 0;
433 }
434
435 for (i = 0; i < regs->count; i++) {
436 unsigned int start = regs->regs[i * 2];
437 unsigned int end = regs->regs[i * 2 + 1];
438
439 for (j = start; j <= end; j++) {
440 unsigned int val;
441
442 kgsl_regread(device, j, &val);
443 *data++ = j;
444 *data++ = val;
445 }
446 }
447
448 header->count = count;
449
450 /* Return the size of the section */
451 return (count * 8) + sizeof(*header);
452}
453EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
454
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700455void *kgsl_snapshot_indexed_registers(struct kgsl_device *device,
456 void *snapshot, int *remain,
457 unsigned int index, unsigned int data, unsigned int start,
458 unsigned int count)
459{
460 struct kgsl_snapshot_indexed_registers iregs;
461 iregs.index = index;
462 iregs.data = data;
463 iregs.start = start;
464 iregs.count = count;
465
466 return kgsl_snapshot_add_section(device,
467 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
468 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
469}
470EXPORT_SYMBOL(kgsl_snapshot_indexed_registers);
471
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700472/*
473 * kgsl_snapshot - construct a device snapshot
474 * @device - device to snapshot
475 * @hang - set to 1 if the snapshot was triggered following a hnag
476 * Given a device, construct a binary snapshot dump of the current device state
477 * and store it in the device snapshot memory.
478 */
479int kgsl_device_snapshot(struct kgsl_device *device, int hang)
480{
481 struct kgsl_snapshot_header *header = device->snapshot;
482 int remain = device->snapshot_maxsize - sizeof(*header);
483 void *snapshot;
484
485 /*
486 * The first hang is always the one we are interested in. To
487 * avoid a subsequent hang blowing away the first, the snapshot
488 * is frozen until it is dumped via sysfs.
489 *
490 * Note that triggered snapshots are always taken regardless
491 * of the state and never frozen.
492 */
493
494 if (hang && device->snapshot_frozen == 1)
495 return 0;
496
497 if (device->snapshot == NULL) {
498 KGSL_DRV_ERR(device,
499 "snapshot: No snapshot memory available\n");
500 return -ENOMEM;
501 }
502
503 if (remain < sizeof(*header)) {
504 KGSL_DRV_ERR(device,
505 "snapshot: Not enough memory for the header\n");
506 return -ENOMEM;
507 }
508
509 header->magic = SNAPSHOT_MAGIC;
510
511 header->gpuid = kgsl_gpuid(device);
512
513 /* Get a pointer to the first section (right after the header) */
514 snapshot = ((void *) device->snapshot) + sizeof(*header);
515
516 /* Build the Linux specific header */
517 snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
518 snapshot, &remain, snapshot_os, (void *) hang);
519
520 /* Get the device specific sections */
521 if (device->ftbl->snapshot)
522 snapshot = device->ftbl->snapshot(device, snapshot, &remain,
523 hang);
524
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700525 device->snapshot_timestamp = get_seconds();
526 device->snapshot_size = (int) (snapshot - device->snapshot);
527
528 /* Freeze the snapshot on a hang until it gets read */
529 device->snapshot_frozen = (hang) ? 1 : 0;
530
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700531 /* log buffer info to aid in ramdump recovery */
532 KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
533 device->snapshot, __pa(device->snapshot),
534 device->snapshot_size);
Jeremy Gebben90812c82012-03-08 12:46:01 -0700535 if (hang)
536 sysfs_notify(&device->snapshot_kobj, NULL, "timestamp");
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700537 return 0;
538}
539EXPORT_SYMBOL(kgsl_device_snapshot);
540
541/* An attribute for showing snapshot details */
542struct kgsl_snapshot_attribute {
543 struct attribute attr;
544 ssize_t (*show)(struct kgsl_device *device, char *buf);
545 ssize_t (*store)(struct kgsl_device *device, const char *buf,
546 size_t count);
547};
548
549#define to_snapshot_attr(a) \
550container_of(a, struct kgsl_snapshot_attribute, attr)
551
552#define kobj_to_device(a) \
553container_of(a, struct kgsl_device, snapshot_kobj)
554
555/* Dump the sysfs binary data to the user */
556static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
557 struct bin_attribute *attr, char *buf, loff_t off,
558 size_t count)
559{
560 struct kgsl_device *device = kobj_to_device(kobj);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600561 struct kgsl_snapshot_object *obj, *tmp;
Jordan Crouse7c325702012-06-20 08:22:16 -0600562 struct kgsl_snapshot_section_header head;
563 struct snapshot_obj_itr itr;
564 int ret;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700565
566 if (device == NULL)
567 return 0;
568
569 /* Return nothing if we haven't taken a snapshot yet */
570 if (device->snapshot_timestamp == 0)
571 return 0;
572
573 /* Get the mutex to keep things from changing while we are dumping */
574 mutex_lock(&device->mutex);
575
Jordan Crouse7c325702012-06-20 08:22:16 -0600576 obj_itr_init(&itr, buf, off, count);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600577
Jordan Crouse7c325702012-06-20 08:22:16 -0600578 ret = obj_itr_out(&itr, device->snapshot, device->snapshot_size);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600579
Jordan Crouse7c325702012-06-20 08:22:16 -0600580 if (ret == 0)
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600581 goto done;
582
Jordan Crouse7c325702012-06-20 08:22:16 -0600583 list_for_each_entry(obj, &device->snapshot_obj_list, node)
584 kgsl_snapshot_dump_object(device, obj, &itr);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600585
Jordan Crouse7c325702012-06-20 08:22:16 -0600586 {
587 head.magic = SNAPSHOT_SECTION_MAGIC;
588 head.id = KGSL_SNAPSHOT_SECTION_END;
589 head.size = sizeof(head);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600590
Jordan Crouse7c325702012-06-20 08:22:16 -0600591 obj_itr_out(&itr, &head, sizeof(head));
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600592 }
593
Jordan Crouse7c325702012-06-20 08:22:16 -0600594 /*
595 * Make sure everything has been written out before destroying things.
596 * The best way to confirm this is to go all the way through without
597 * writing any bytes - so only release if we get this far and
598 * itr->write is 0
599 */
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600600
Jordan Crouse7c325702012-06-20 08:22:16 -0600601 if (itr.write == 0) {
602 list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list,
603 node)
604 kgsl_snapshot_put_object(device, obj);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600605
Jordan Crouse7c325702012-06-20 08:22:16 -0600606 if (device->snapshot_frozen)
607 KGSL_DRV_ERR(device, "Snapshot objects released\n");
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600608
Jordan Crouse7c325702012-06-20 08:22:16 -0600609 device->snapshot_frozen = 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600610 }
611
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600612done:
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700613 mutex_unlock(&device->mutex);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600614
Jordan Crouse7c325702012-06-20 08:22:16 -0600615 return itr.write;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700616}
617
618/* Show the timestamp of the last collected snapshot */
619static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
620{
621 return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
622}
623
624/* manually trigger a new snapshot to be collected */
625static ssize_t trigger_store(struct kgsl_device *device, const char *buf,
626 size_t count)
627{
628 if (device && count > 0) {
629 mutex_lock(&device->mutex);
630 kgsl_device_snapshot(device, 0);
631 mutex_unlock(&device->mutex);
632 }
633
634 return count;
635}
636
637static struct bin_attribute snapshot_attr = {
638 .attr.name = "dump",
639 .attr.mode = 0444,
640 .size = 0,
641 .read = snapshot_show
642};
643
644#define SNAPSHOT_ATTR(_name, _mode, _show, _store) \
645struct kgsl_snapshot_attribute attr_##_name = { \
646 .attr = { .name = __stringify(_name), .mode = _mode }, \
647 .show = _show, \
648 .store = _store, \
649}
650
651SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
652SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
653
654static void snapshot_sysfs_release(struct kobject *kobj)
655{
656}
657
658static ssize_t snapshot_sysfs_show(struct kobject *kobj,
659 struct attribute *attr, char *buf)
660{
661 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
662 struct kgsl_device *device = kobj_to_device(kobj);
663 ssize_t ret;
664
665 if (device && pattr->show)
666 ret = pattr->show(device, buf);
667 else
668 ret = -EIO;
669
670 return ret;
671}
672
673static ssize_t snapshot_sysfs_store(struct kobject *kobj,
674 struct attribute *attr, const char *buf, size_t count)
675{
676 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
677 struct kgsl_device *device = kobj_to_device(kobj);
678 ssize_t ret;
679
680 if (device && pattr->store)
681 ret = pattr->store(device, buf, count);
682 else
683 ret = -EIO;
684
685 return ret;
686}
687
688static const struct sysfs_ops snapshot_sysfs_ops = {
689 .show = snapshot_sysfs_show,
690 .store = snapshot_sysfs_store,
691};
692
693static struct kobj_type ktype_snapshot = {
694 .sysfs_ops = &snapshot_sysfs_ops,
695 .default_attrs = NULL,
696 .release = snapshot_sysfs_release,
697};
698
699/* kgsl_device_snapshot_init - Add resources for the device GPU snapshot
700 * @device - The device to initalize
701 *
702 * Allocate memory for a GPU snapshot for the specified device,
703 * and create the sysfs files to manage it
704 */
705
706int kgsl_device_snapshot_init(struct kgsl_device *device)
707{
708 int ret;
709
710 if (device->snapshot == NULL)
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700711 device->snapshot = kzalloc(KGSL_SNAPSHOT_MEMSIZE, GFP_KERNEL);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700712
713 if (device->snapshot == NULL)
714 return -ENOMEM;
715
716 device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
717 device->snapshot_timestamp = 0;
718
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600719 INIT_LIST_HEAD(&device->snapshot_obj_list);
720
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700721 ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
722 &device->dev->kobj, "snapshot");
723 if (ret)
724 goto done;
725
726 ret = sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr);
727 if (ret)
728 goto done;
729
730 ret = sysfs_create_file(&device->snapshot_kobj, &attr_trigger.attr);
731 if (ret)
732 goto done;
733
734 ret = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
735
736done:
737 return ret;
738}
739EXPORT_SYMBOL(kgsl_device_snapshot_init);
740
741/* kgsl_device_snapshot_close - Take down snapshot memory for a device
742 * @device - Pointer to the kgsl_device
743 *
744 * Remove the sysfs files and free the memory allocated for the GPU
745 * snapshot
746 */
747
748void kgsl_device_snapshot_close(struct kgsl_device *device)
749{
750 sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr);
751 sysfs_remove_file(&device->snapshot_kobj, &attr_trigger.attr);
752 sysfs_remove_file(&device->snapshot_kobj, &attr_timestamp.attr);
753
754 kobject_put(&device->snapshot_kobj);
755
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700756 kfree(device->snapshot);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700757
758 device->snapshot = NULL;
759 device->snapshot_maxsize = 0;
760 device->snapshot_timestamp = 0;
761}
762EXPORT_SYMBOL(kgsl_device_snapshot_close);