blob: f61c74fd991407f2e3c57d7ef07691aa625cfe60 [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
Jordan Crouse9610b6b2012-03-16 14:53:42 -060025/* Placeholder for the list of memory objects frozen after a hang */
26
27struct kgsl_snapshot_object {
28 unsigned int gpuaddr;
29 unsigned int ptbase;
30 unsigned int size;
Jordan Crouse233b2092012-04-18 09:31:09 -060031 unsigned int offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -060032 int type;
33 struct kgsl_mem_entry *entry;
34 struct list_head node;
35};
36
Jordan Crouse156cfbc2012-01-24 09:32:04 -070037/* idr_for_each function to count the number of contexts */
38
39static int snapshot_context_count(int id, void *ptr, void *data)
40{
41 int *count = data;
42 *count = *count + 1;
43
44 return 0;
45}
46
47/*
48 * To simplify the iterator loop use a global pointer instead of trying
49 * to pass around double star references to the snapshot data
50 */
51
52static void *_ctxtptr;
53
54static int snapshot_context_info(int id, void *ptr, void *data)
55{
56 struct kgsl_snapshot_linux_context *header = _ctxtptr;
57 struct kgsl_context *context = ptr;
58 struct kgsl_device *device = context->dev_priv->device;
59
60 header->id = id;
61
62 /* Future-proof for per-context timestamps - for now, just
63 * return the global timestamp for all contexts
64 */
65
Jordan Crousecafb63a2012-04-16 15:22:03 -060066 header->timestamp_queued = device->ftbl->readtimestamp(device,
67 context, KGSL_TIMESTAMP_QUEUED);
Jordan Crouse156cfbc2012-01-24 09:32:04 -070068 header->timestamp_retired = device->ftbl->readtimestamp(device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -070069 context, KGSL_TIMESTAMP_RETIRED);
Jordan Crouse156cfbc2012-01-24 09:32:04 -070070
71 _ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
72
73 return 0;
74}
75
76/* Snapshot the Linux specific information */
77static int snapshot_os(struct kgsl_device *device,
78 void *snapshot, int remain, void *priv)
79{
80 struct kgsl_snapshot_linux *header = snapshot;
81 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
82 struct task_struct *task;
83 pid_t pid;
84 int hang = (int) priv;
85 int ctxtcount = 0;
86 int size = sizeof(*header);
87
88 /* Figure out how many active contexts there are - these will
89 * be appended on the end of the structure */
90
91 idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
92
93 size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);
94
95 /* Make sure there is enough room for the data */
96 if (remain < size) {
97 SNAPSHOT_ERR_NOMEM(device, "OS");
98 return 0;
99 }
100
101 memset(header, 0, sizeof(*header));
102
103 header->osid = KGSL_SNAPSHOT_OS_LINUX;
104
105 header->state = hang ? SNAPSHOT_STATE_HUNG : SNAPSHOT_STATE_RUNNING;
106
107 /* Get the kernel build information */
108 strlcpy(header->release, utsname()->release, sizeof(header->release));
109 strlcpy(header->version, utsname()->version, sizeof(header->version));
110
111 /* Get the Unix time for the timestamp */
112 header->seconds = get_seconds();
113
114 /* Remember the power information */
115 header->power_flags = pwr->power_flags;
116 header->power_level = pwr->active_pwrlevel;
117 header->power_interval_timeout = pwr->interval_timeout;
118 header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
119 header->busclk = kgsl_get_clkrate(pwr->ebi1_clk);
120
121 /* Future proof for per-context timestamps */
122 header->current_context = -1;
123
124 /* Get the current PT base */
Shubhraprakash Das79447952012-04-26 18:12:23 -0600125 header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700126 /* And the PID for the task leader */
127 pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
128
129 task = find_task_by_vpid(pid);
130
131 if (task)
132 get_task_comm(header->comm, task);
133
134 header->ctxtcount = ctxtcount;
135
136 /* append information for each context */
137 _ctxtptr = snapshot + sizeof(*header);
138 idr_for_each(&device->context_idr, snapshot_context_info, NULL);
139
140 /* Return the size of the data segment */
141 return size;
142}
143/*
144 * kgsl_snapshot_dump_indexed_regs - helper function to dump indexed registers
145 * @device - the device to dump registers from
146 * @snapshot - pointer to the start of the region of memory for the snapshot
147 * @remain - a pointer to the number of bytes remaining in the snapshot
148 * @priv - A pointer to the kgsl_snapshot_indexed_registers data
149 *
150 * Given a indexed register cmd/data pair and a count, dump each indexed
151 * register
152 */
153
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700154static int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700155 void *snapshot, int remain, void *priv)
156{
157 struct kgsl_snapshot_indexed_registers *iregs = priv;
158 struct kgsl_snapshot_indexed_regs *header = snapshot;
159 unsigned int *data = snapshot + sizeof(*header);
160 int i;
161
162 if (remain < (iregs->count * 4) + sizeof(*header)) {
163 SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
164 return 0;
165 }
166
167 header->index_reg = iregs->index;
168 header->data_reg = iregs->data;
169 header->count = iregs->count;
170 header->start = iregs->start;
171
172 for (i = 0; i < iregs->count; i++) {
173 kgsl_regwrite(device, iregs->index, iregs->start + i);
174 kgsl_regread(device, iregs->data, &data[i]);
175 }
176
177 return (iregs->count * 4) + sizeof(*header);
178}
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700179
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600180#define GPU_OBJ_HEADER_SZ \
181 (sizeof(struct kgsl_snapshot_section_header) + \
182 sizeof(struct kgsl_snapshot_gpu_object))
183
184#define GPU_OBJ_SECTION_SIZE(_o) \
185 (GPU_OBJ_HEADER_SZ + ((_o)->size))
186
187static int kgsl_snapshot_dump_object(struct kgsl_device *device,
188 struct kgsl_snapshot_object *obj, void *buf,
189 unsigned int off, unsigned int count)
190{
191 unsigned char headers[GPU_OBJ_HEADER_SZ];
192 struct kgsl_snapshot_section_header *sect =
193 (struct kgsl_snapshot_section_header *) headers;
194 struct kgsl_snapshot_gpu_object *header =
195 (struct kgsl_snapshot_gpu_object *) (headers + sizeof(*sect));
196 int ret = 0;
197
198 /* Construct a local copy of the headers */
199
200 sect->magic = SNAPSHOT_SECTION_MAGIC;
201 sect->id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
202 sect->size = GPU_OBJ_SECTION_SIZE(obj);
203
204 header->type = obj->type;
205
206 /* Header size is in dwords, object size is in bytes */
207 header->size = obj->size >> 2;
208 header->gpuaddr = obj->gpuaddr;
209 header->ptbase = obj->ptbase;
210
211 /* Copy out any part of the header block that is needed */
212
213 if (off < GPU_OBJ_HEADER_SZ) {
214 int size = count < GPU_OBJ_HEADER_SZ - off ?
215 count : GPU_OBJ_HEADER_SZ - off;
216
217 memcpy(buf, headers + off, size);
218
219 count -= size;
220 ret += size;
221 }
222
223 /* Now copy whatever part of the data is needed */
224
225 if (off < (GPU_OBJ_HEADER_SZ + obj->size)) {
226 int offset;
227 int size = count < obj->size ? count : obj->size;
228
229 /*
230 * If the desired gpuaddr isn't at the beginning of the region,
231 * then offset the source pointer
232 */
233
Jordan Crouse233b2092012-04-18 09:31:09 -0600234 offset = obj->offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600235
236 /*
237 * Then adjust it to account for the offset for the output
238 * buffer.
239 */
240
241 if (off > GPU_OBJ_HEADER_SZ) {
242 int loff = (off - GPU_OBJ_HEADER_SZ);
243
244 /* Adjust the size so we don't walk off the end */
245
246 if ((loff + size) > obj->size)
247 size = obj->size - loff;
248
249 offset += loff;
250 }
251
252 memcpy(buf + ret, obj->entry->memdesc.hostptr + offset, size);
253 ret += size;
254 }
255
256 return ret;
257}
258
259static void kgsl_snapshot_put_object(struct kgsl_device *device,
260 struct kgsl_snapshot_object *obj)
261{
262 list_del(&obj->node);
263
264 obj->entry->flags &= ~KGSL_MEM_ENTRY_FROZEN;
265 kgsl_mem_entry_put(obj->entry);
266
267 kfree(obj);
268}
269
270/* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
271 * @device - the device that is being snapshotted
272 * @ptbase - the pagetable base of the object to freeze
273 * @gpuaddr - The gpu address of the object to freeze
274 * @size - the size of the object (may not always be the size of the region)
275 * @type - the type of object being saved (shader, vbo, etc)
276 *
277 * Mark and freeze a GPU buffer object. This will prevent it from being
278 * freed until it can be copied out as part of the snapshot dump. Returns the
279 * size of the object being frozen
280 */
281
282int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
283 unsigned int gpuaddr, unsigned int size, unsigned int type)
284{
285 struct kgsl_mem_entry *entry;
286 struct kgsl_snapshot_object *obj;
287 int offset;
288
289 entry = kgsl_get_mem_entry(ptbase, gpuaddr, size);
290
291 if (entry == NULL) {
292 KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
293 gpuaddr);
294 return 0;
295 }
296
297 /* We can't freeze external memory, because we don't own it */
298 if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
299 KGSL_DRV_ERR(device,
300 "Only internal GPU buffers can be frozen\n");
301 return 0;
302 }
303
304 /*
305 * size indicates the number of bytes in the region to save. This might
306 * not always be the entire size of the region because some buffers are
307 * sub-allocated from a larger region. However, if size 0 was passed
308 * thats a flag that the caller wants to capture the entire buffer
309 */
310
311 if (size == 0) {
312 size = entry->memdesc.size;
313 offset = 0;
314
315 /* Adjust the gpuaddr to the start of the object */
316 gpuaddr = entry->memdesc.gpuaddr;
317 } else {
318 offset = gpuaddr - entry->memdesc.gpuaddr;
319 }
320
321 if (size + offset > entry->memdesc.size) {
322 KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
323 gpuaddr);
324 return 0;
325 }
326
327 /* If the buffer is already on the list, skip it */
328 list_for_each_entry(obj, &device->snapshot_obj_list, node) {
329 if (obj->gpuaddr == gpuaddr && obj->ptbase == ptbase) {
330 /* If the size is different, use the new size */
331 if (obj->size != size)
332 obj->size = size;
333
334 return 0;
335 }
336 }
337
Jordan Crouse17d6d8b2012-04-18 09:31:09 -0600338 if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
339 KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
340 gpuaddr);
341 return 0;
342 }
343
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600344 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
345
346 if (obj == NULL) {
347 KGSL_DRV_ERR(device, "Unable to allocate memory\n");
348 return 0;
349 }
350
351 /* Ref count the mem entry */
352 kgsl_mem_entry_get(entry);
353
354 obj->type = type;
355 obj->entry = entry;
356 obj->gpuaddr = gpuaddr;
357 obj->ptbase = ptbase;
358 obj->size = size;
Jordan Crouse233b2092012-04-18 09:31:09 -0600359 obj->offset = offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600360
361 list_add(&obj->node, &device->snapshot_obj_list);
362
363 /*
364 * Return the size of the entire mem entry that was frozen - this gets
365 * used for tracking how much memory is frozen for a hang. Also, mark
366 * the memory entry as frozen. If the entry was already marked as
367 * frozen, then another buffer already got to it. In that case, return
368 * 0 so it doesn't get counted twice
369 */
370
371 if (entry->flags & KGSL_MEM_ENTRY_FROZEN)
372 return 0;
373
374 entry->flags |= KGSL_MEM_ENTRY_FROZEN;
375
376 return entry->memdesc.size;
377}
378EXPORT_SYMBOL(kgsl_snapshot_get_object);
379
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700380/*
381 * kgsl_snapshot_dump_regs - helper function to dump device registers
382 * @device - the device to dump registers from
383 * @snapshot - pointer to the start of the region of memory for the snapshot
384 * @remain - a pointer to the number of bytes remaining in the snapshot
385 * @priv - A pointer to the kgsl_snapshot_registers data
386 *
387 * Given an array of register ranges pairs (start,end [inclusive]), dump the
388 * registers into a snapshot register section. The snapshot region stores a
389 * part of dwords for each register - the word address of the register, and
390 * the value.
391 */
392int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
393 int remain, void *priv)
394{
395 struct kgsl_snapshot_regs *header = snapshot;
396 struct kgsl_snapshot_registers *regs = priv;
397 unsigned int *data = snapshot + sizeof(*header);
398 int count = 0, i, j;
399
400 /* Figure out how many registers we are going to dump */
401
402 for (i = 0; i < regs->count; i++) {
403 int start = regs->regs[i * 2];
404 int end = regs->regs[i * 2 + 1];
405
406 count += (end - start + 1);
407 }
408
409 if (remain < (count * 8) + sizeof(*header)) {
410 SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
411 return 0;
412 }
413
414 for (i = 0; i < regs->count; i++) {
415 unsigned int start = regs->regs[i * 2];
416 unsigned int end = regs->regs[i * 2 + 1];
417
418 for (j = start; j <= end; j++) {
419 unsigned int val;
420
421 kgsl_regread(device, j, &val);
422 *data++ = j;
423 *data++ = val;
424 }
425 }
426
427 header->count = count;
428
429 /* Return the size of the section */
430 return (count * 8) + sizeof(*header);
431}
432EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
433
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700434void *kgsl_snapshot_indexed_registers(struct kgsl_device *device,
435 void *snapshot, int *remain,
436 unsigned int index, unsigned int data, unsigned int start,
437 unsigned int count)
438{
439 struct kgsl_snapshot_indexed_registers iregs;
440 iregs.index = index;
441 iregs.data = data;
442 iregs.start = start;
443 iregs.count = count;
444
445 return kgsl_snapshot_add_section(device,
446 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
447 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
448}
449EXPORT_SYMBOL(kgsl_snapshot_indexed_registers);
450
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700451/*
452 * kgsl_snapshot - construct a device snapshot
453 * @device - device to snapshot
454 * @hang - set to 1 if the snapshot was triggered following a hnag
455 * Given a device, construct a binary snapshot dump of the current device state
456 * and store it in the device snapshot memory.
457 */
458int kgsl_device_snapshot(struct kgsl_device *device, int hang)
459{
460 struct kgsl_snapshot_header *header = device->snapshot;
461 int remain = device->snapshot_maxsize - sizeof(*header);
462 void *snapshot;
463
464 /*
465 * The first hang is always the one we are interested in. To
466 * avoid a subsequent hang blowing away the first, the snapshot
467 * is frozen until it is dumped via sysfs.
468 *
469 * Note that triggered snapshots are always taken regardless
470 * of the state and never frozen.
471 */
472
473 if (hang && device->snapshot_frozen == 1)
474 return 0;
475
476 if (device->snapshot == NULL) {
477 KGSL_DRV_ERR(device,
478 "snapshot: No snapshot memory available\n");
479 return -ENOMEM;
480 }
481
482 if (remain < sizeof(*header)) {
483 KGSL_DRV_ERR(device,
484 "snapshot: Not enough memory for the header\n");
485 return -ENOMEM;
486 }
487
488 header->magic = SNAPSHOT_MAGIC;
489
490 header->gpuid = kgsl_gpuid(device);
491
492 /* Get a pointer to the first section (right after the header) */
493 snapshot = ((void *) device->snapshot) + sizeof(*header);
494
495 /* Build the Linux specific header */
496 snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
497 snapshot, &remain, snapshot_os, (void *) hang);
498
499 /* Get the device specific sections */
500 if (device->ftbl->snapshot)
501 snapshot = device->ftbl->snapshot(device, snapshot, &remain,
502 hang);
503
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700504 device->snapshot_timestamp = get_seconds();
505 device->snapshot_size = (int) (snapshot - device->snapshot);
506
507 /* Freeze the snapshot on a hang until it gets read */
508 device->snapshot_frozen = (hang) ? 1 : 0;
509
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700510 /* log buffer info to aid in ramdump recovery */
511 KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
512 device->snapshot, __pa(device->snapshot),
513 device->snapshot_size);
Jeremy Gebben90812c82012-03-08 12:46:01 -0700514 if (hang)
515 sysfs_notify(&device->snapshot_kobj, NULL, "timestamp");
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700516 return 0;
517}
518EXPORT_SYMBOL(kgsl_device_snapshot);
519
520/* An attribute for showing snapshot details */
521struct kgsl_snapshot_attribute {
522 struct attribute attr;
523 ssize_t (*show)(struct kgsl_device *device, char *buf);
524 ssize_t (*store)(struct kgsl_device *device, const char *buf,
525 size_t count);
526};
527
528#define to_snapshot_attr(a) \
529container_of(a, struct kgsl_snapshot_attribute, attr)
530
531#define kobj_to_device(a) \
532container_of(a, struct kgsl_device, snapshot_kobj)
533
534/* Dump the sysfs binary data to the user */
535static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
536 struct bin_attribute *attr, char *buf, loff_t off,
537 size_t count)
538{
539 struct kgsl_device *device = kobj_to_device(kobj);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600540 struct kgsl_snapshot_object *obj, *tmp;
541 unsigned int size, src, dst = 0;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700542
543 if (device == NULL)
544 return 0;
545
546 /* Return nothing if we haven't taken a snapshot yet */
547 if (device->snapshot_timestamp == 0)
548 return 0;
549
550 /* Get the mutex to keep things from changing while we are dumping */
551 mutex_lock(&device->mutex);
552
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600553 if (off < device->snapshot_size) {
554 size = count < (device->snapshot_size - off) ?
555 count : device->snapshot_size - off;
556
557 memcpy(buf, device->snapshot + off, size);
558
559 count -= size;
560 dst += size;
561 }
562
563 if (count == 0)
564 goto done;
565
566 src = device->snapshot_size;
567
568 list_for_each_entry(obj, &device->snapshot_obj_list, node) {
569
570 int objsize = GPU_OBJ_SECTION_SIZE(obj);
571 int offset;
572
573 /* If the offset is beyond this object, then move on */
574
575 if (off >= (src + objsize)) {
576 src += objsize;
577 continue;
578 }
579
580 /* Adjust the offset to be relative to the object */
581 offset = (off >= src) ? (off - src) : 0;
582
583 size = kgsl_snapshot_dump_object(device, obj, buf + dst,
584 offset, count);
585
586 count -= size;
587 dst += size;
588
589 if (count == 0)
590 goto done;
591
592 /* Move on to the next object - update src accordingly */
593 src += objsize;
594 }
595
596 /* Add the end section */
597
598 if (off < (src + sizeof(struct kgsl_snapshot_section_header))) {
599 if (count >= sizeof(struct kgsl_snapshot_section_header)) {
600 struct kgsl_snapshot_section_header *head =
601 (void *) (buf + dst);
602
603 head->magic = SNAPSHOT_SECTION_MAGIC;
604 head->id = KGSL_SNAPSHOT_SECTION_END;
605 head->size = sizeof(*head);
606
607 dst += sizeof(*head);
608 } else {
609 goto done;
610 }
611 }
612
613 /* Release the buffers and unfreeze the snapshot */
614
615 list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list, node)
616 kgsl_snapshot_put_object(device, obj);
617
618 if (device->snapshot_frozen)
619 KGSL_DRV_ERR(device, "Snapshot objects released\n");
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700620
621 device->snapshot_frozen = 0;
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
626 return dst;
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);