blob: 8935b29ec8116b086cb1b3a2e8e55d2ba80f8f6b [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 Crouse156cfbc2012-01-24 09:32:04 -070038/* idr_for_each function to count the number of contexts */
39
40static int snapshot_context_count(int id, void *ptr, void *data)
41{
42 int *count = data;
43 *count = *count + 1;
44
45 return 0;
46}
47
48/*
49 * To simplify the iterator loop use a global pointer instead of trying
50 * to pass around double star references to the snapshot data
51 */
52
53static void *_ctxtptr;
54
55static int snapshot_context_info(int id, void *ptr, void *data)
56{
57 struct kgsl_snapshot_linux_context *header = _ctxtptr;
58 struct kgsl_context *context = ptr;
59 struct kgsl_device *device = context->dev_priv->device;
60
61 header->id = id;
62
63 /* Future-proof for per-context timestamps - for now, just
64 * return the global timestamp for all contexts
65 */
66
Jeremy Gebben731dac52012-05-10 11:13:42 -060067 header->timestamp_queued = kgsl_readtimestamp(device, context,
68 KGSL_TIMESTAMP_QUEUED);
69 header->timestamp_retired = kgsl_readtimestamp(device, context,
70 KGSL_TIMESTAMP_RETIRED);
Jordan Crouse156cfbc2012-01-24 09:32:04 -070071
72 _ctxtptr += sizeof(struct kgsl_snapshot_linux_context);
73
74 return 0;
75}
76
77/* Snapshot the Linux specific information */
78static int snapshot_os(struct kgsl_device *device,
79 void *snapshot, int remain, void *priv)
80{
81 struct kgsl_snapshot_linux *header = snapshot;
82 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
83 struct task_struct *task;
84 pid_t pid;
85 int hang = (int) priv;
86 int ctxtcount = 0;
87 int size = sizeof(*header);
88
89 /* Figure out how many active contexts there are - these will
90 * be appended on the end of the structure */
91
92 idr_for_each(&device->context_idr, snapshot_context_count, &ctxtcount);
93
94 size += ctxtcount * sizeof(struct kgsl_snapshot_linux_context);
95
96 /* Make sure there is enough room for the data */
97 if (remain < size) {
98 SNAPSHOT_ERR_NOMEM(device, "OS");
99 return 0;
100 }
101
102 memset(header, 0, sizeof(*header));
103
104 header->osid = KGSL_SNAPSHOT_OS_LINUX;
105
106 header->state = hang ? SNAPSHOT_STATE_HUNG : SNAPSHOT_STATE_RUNNING;
107
108 /* Get the kernel build information */
109 strlcpy(header->release, utsname()->release, sizeof(header->release));
110 strlcpy(header->version, utsname()->version, sizeof(header->version));
111
112 /* Get the Unix time for the timestamp */
113 header->seconds = get_seconds();
114
115 /* Remember the power information */
116 header->power_flags = pwr->power_flags;
117 header->power_level = pwr->active_pwrlevel;
118 header->power_interval_timeout = pwr->interval_timeout;
119 header->grpclk = kgsl_get_clkrate(pwr->grp_clks[0]);
120 header->busclk = kgsl_get_clkrate(pwr->ebi1_clk);
121
122 /* Future proof for per-context timestamps */
123 header->current_context = -1;
124
125 /* Get the current PT base */
Shubhraprakash Das79447952012-04-26 18:12:23 -0600126 header->ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700127 /* And the PID for the task leader */
128 pid = header->pid = kgsl_mmu_get_ptname_from_ptbase(header->ptbase);
129
130 task = find_task_by_vpid(pid);
131
132 if (task)
133 get_task_comm(header->comm, task);
134
135 header->ctxtcount = ctxtcount;
136
137 /* append information for each context */
138 _ctxtptr = snapshot + sizeof(*header);
139 idr_for_each(&device->context_idr, snapshot_context_info, NULL);
140
141 /* Return the size of the data segment */
142 return size;
143}
144/*
145 * kgsl_snapshot_dump_indexed_regs - helper function to dump indexed registers
146 * @device - the device to dump registers from
147 * @snapshot - pointer to the start of the region of memory for the snapshot
148 * @remain - a pointer to the number of bytes remaining in the snapshot
149 * @priv - A pointer to the kgsl_snapshot_indexed_registers data
150 *
151 * Given a indexed register cmd/data pair and a count, dump each indexed
152 * register
153 */
154
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700155static int kgsl_snapshot_dump_indexed_regs(struct kgsl_device *device,
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700156 void *snapshot, int remain, void *priv)
157{
158 struct kgsl_snapshot_indexed_registers *iregs = priv;
159 struct kgsl_snapshot_indexed_regs *header = snapshot;
160 unsigned int *data = snapshot + sizeof(*header);
161 int i;
162
163 if (remain < (iregs->count * 4) + sizeof(*header)) {
164 SNAPSHOT_ERR_NOMEM(device, "INDEXED REGS");
165 return 0;
166 }
167
168 header->index_reg = iregs->index;
169 header->data_reg = iregs->data;
170 header->count = iregs->count;
171 header->start = iregs->start;
172
173 for (i = 0; i < iregs->count; i++) {
174 kgsl_regwrite(device, iregs->index, iregs->start + i);
175 kgsl_regread(device, iregs->data, &data[i]);
176 }
177
178 return (iregs->count * 4) + sizeof(*header);
179}
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700180
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600181#define GPU_OBJ_HEADER_SZ \
182 (sizeof(struct kgsl_snapshot_section_header) + \
183 sizeof(struct kgsl_snapshot_gpu_object))
184
185#define GPU_OBJ_SECTION_SIZE(_o) \
186 (GPU_OBJ_HEADER_SZ + ((_o)->size))
187
188static int kgsl_snapshot_dump_object(struct kgsl_device *device,
189 struct kgsl_snapshot_object *obj, void *buf,
190 unsigned int off, unsigned int count)
191{
192 unsigned char headers[GPU_OBJ_HEADER_SZ];
193 struct kgsl_snapshot_section_header *sect =
194 (struct kgsl_snapshot_section_header *) headers;
195 struct kgsl_snapshot_gpu_object *header =
196 (struct kgsl_snapshot_gpu_object *) (headers + sizeof(*sect));
197 int ret = 0;
198
199 /* Construct a local copy of the headers */
200
201 sect->magic = SNAPSHOT_SECTION_MAGIC;
202 sect->id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
203 sect->size = GPU_OBJ_SECTION_SIZE(obj);
204
205 header->type = obj->type;
206
207 /* Header size is in dwords, object size is in bytes */
208 header->size = obj->size >> 2;
209 header->gpuaddr = obj->gpuaddr;
210 header->ptbase = obj->ptbase;
211
212 /* Copy out any part of the header block that is needed */
213
214 if (off < GPU_OBJ_HEADER_SZ) {
215 int size = count < GPU_OBJ_HEADER_SZ - off ?
216 count : GPU_OBJ_HEADER_SZ - off;
217
218 memcpy(buf, headers + off, size);
219
220 count -= size;
221 ret += size;
222 }
223
224 /* Now copy whatever part of the data is needed */
225
226 if (off < (GPU_OBJ_HEADER_SZ + obj->size)) {
227 int offset;
228 int size = count < obj->size ? count : obj->size;
229
230 /*
231 * If the desired gpuaddr isn't at the beginning of the region,
232 * then offset the source pointer
233 */
234
Jordan Crouse233b2092012-04-18 09:31:09 -0600235 offset = obj->offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600236
237 /*
238 * Then adjust it to account for the offset for the output
239 * buffer.
240 */
241
242 if (off > GPU_OBJ_HEADER_SZ) {
243 int loff = (off - GPU_OBJ_HEADER_SZ);
244
245 /* Adjust the size so we don't walk off the end */
246
247 if ((loff + size) > obj->size)
248 size = obj->size - loff;
249
250 offset += loff;
251 }
252
253 memcpy(buf + ret, obj->entry->memdesc.hostptr + offset, size);
254 ret += size;
255 }
256
257 return ret;
258}
259
260static void kgsl_snapshot_put_object(struct kgsl_device *device,
261 struct kgsl_snapshot_object *obj)
262{
263 list_del(&obj->node);
264
265 obj->entry->flags &= ~KGSL_MEM_ENTRY_FROZEN;
266 kgsl_mem_entry_put(obj->entry);
267
268 kfree(obj);
269}
270
271/* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
272 * @device - the device that is being snapshotted
273 * @ptbase - the pagetable base of the object to freeze
274 * @gpuaddr - The gpu address of the object to freeze
275 * @size - the size of the object (may not always be the size of the region)
276 * @type - the type of object being saved (shader, vbo, etc)
277 *
278 * Mark and freeze a GPU buffer object. This will prevent it from being
279 * freed until it can be copied out as part of the snapshot dump. Returns the
280 * size of the object being frozen
281 */
282
283int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
284 unsigned int gpuaddr, unsigned int size, unsigned int type)
285{
286 struct kgsl_mem_entry *entry;
287 struct kgsl_snapshot_object *obj;
288 int offset;
289
290 entry = kgsl_get_mem_entry(ptbase, gpuaddr, size);
291
292 if (entry == NULL) {
293 KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
294 gpuaddr);
295 return 0;
296 }
297
298 /* We can't freeze external memory, because we don't own it */
299 if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
300 KGSL_DRV_ERR(device,
301 "Only internal GPU buffers can be frozen\n");
302 return 0;
303 }
304
305 /*
306 * size indicates the number of bytes in the region to save. This might
307 * not always be the entire size of the region because some buffers are
308 * sub-allocated from a larger region. However, if size 0 was passed
309 * thats a flag that the caller wants to capture the entire buffer
310 */
311
312 if (size == 0) {
313 size = entry->memdesc.size;
314 offset = 0;
315
316 /* Adjust the gpuaddr to the start of the object */
317 gpuaddr = entry->memdesc.gpuaddr;
318 } else {
319 offset = gpuaddr - entry->memdesc.gpuaddr;
320 }
321
322 if (size + offset > entry->memdesc.size) {
323 KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
324 gpuaddr);
325 return 0;
326 }
327
328 /* If the buffer is already on the list, skip it */
329 list_for_each_entry(obj, &device->snapshot_obj_list, node) {
330 if (obj->gpuaddr == gpuaddr && obj->ptbase == ptbase) {
331 /* If the size is different, use the new size */
332 if (obj->size != size)
333 obj->size = size;
334
335 return 0;
336 }
337 }
338
Jordan Crouse17d6d8b2012-04-18 09:31:09 -0600339 if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
340 KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
341 gpuaddr);
342 return 0;
343 }
344
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600345 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
346
347 if (obj == NULL) {
348 KGSL_DRV_ERR(device, "Unable to allocate memory\n");
349 return 0;
350 }
351
352 /* Ref count the mem entry */
353 kgsl_mem_entry_get(entry);
354
355 obj->type = type;
356 obj->entry = entry;
357 obj->gpuaddr = gpuaddr;
358 obj->ptbase = ptbase;
359 obj->size = size;
Jordan Crouse233b2092012-04-18 09:31:09 -0600360 obj->offset = offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600361
362 list_add(&obj->node, &device->snapshot_obj_list);
363
364 /*
365 * Return the size of the entire mem entry that was frozen - this gets
366 * used for tracking how much memory is frozen for a hang. Also, mark
367 * the memory entry as frozen. If the entry was already marked as
368 * frozen, then another buffer already got to it. In that case, return
369 * 0 so it doesn't get counted twice
370 */
371
372 if (entry->flags & KGSL_MEM_ENTRY_FROZEN)
373 return 0;
374
375 entry->flags |= KGSL_MEM_ENTRY_FROZEN;
376
377 return entry->memdesc.size;
378}
379EXPORT_SYMBOL(kgsl_snapshot_get_object);
380
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700381/*
382 * kgsl_snapshot_dump_regs - helper function to dump device registers
383 * @device - the device to dump registers from
384 * @snapshot - pointer to the start of the region of memory for the snapshot
385 * @remain - a pointer to the number of bytes remaining in the snapshot
386 * @priv - A pointer to the kgsl_snapshot_registers data
387 *
388 * Given an array of register ranges pairs (start,end [inclusive]), dump the
389 * registers into a snapshot register section. The snapshot region stores a
390 * part of dwords for each register - the word address of the register, and
391 * the value.
392 */
393int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
394 int remain, void *priv)
395{
396 struct kgsl_snapshot_regs *header = snapshot;
397 struct kgsl_snapshot_registers *regs = priv;
398 unsigned int *data = snapshot + sizeof(*header);
399 int count = 0, i, j;
400
401 /* Figure out how many registers we are going to dump */
402
403 for (i = 0; i < regs->count; i++) {
404 int start = regs->regs[i * 2];
405 int end = regs->regs[i * 2 + 1];
406
407 count += (end - start + 1);
408 }
409
410 if (remain < (count * 8) + sizeof(*header)) {
411 SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
412 return 0;
413 }
414
415 for (i = 0; i < regs->count; i++) {
416 unsigned int start = regs->regs[i * 2];
417 unsigned int end = regs->regs[i * 2 + 1];
418
419 for (j = start; j <= end; j++) {
420 unsigned int val;
421
422 kgsl_regread(device, j, &val);
423 *data++ = j;
424 *data++ = val;
425 }
426 }
427
428 header->count = count;
429
430 /* Return the size of the section */
431 return (count * 8) + sizeof(*header);
432}
433EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
434
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700435void *kgsl_snapshot_indexed_registers(struct kgsl_device *device,
436 void *snapshot, int *remain,
437 unsigned int index, unsigned int data, unsigned int start,
438 unsigned int count)
439{
440 struct kgsl_snapshot_indexed_registers iregs;
441 iregs.index = index;
442 iregs.data = data;
443 iregs.start = start;
444 iregs.count = count;
445
446 return kgsl_snapshot_add_section(device,
447 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
448 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
449}
450EXPORT_SYMBOL(kgsl_snapshot_indexed_registers);
451
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700452/*
453 * kgsl_snapshot - construct a device snapshot
454 * @device - device to snapshot
455 * @hang - set to 1 if the snapshot was triggered following a hnag
456 * Given a device, construct a binary snapshot dump of the current device state
457 * and store it in the device snapshot memory.
458 */
459int kgsl_device_snapshot(struct kgsl_device *device, int hang)
460{
461 struct kgsl_snapshot_header *header = device->snapshot;
462 int remain = device->snapshot_maxsize - sizeof(*header);
463 void *snapshot;
464
465 /*
466 * The first hang is always the one we are interested in. To
467 * avoid a subsequent hang blowing away the first, the snapshot
468 * is frozen until it is dumped via sysfs.
469 *
470 * Note that triggered snapshots are always taken regardless
471 * of the state and never frozen.
472 */
473
474 if (hang && device->snapshot_frozen == 1)
475 return 0;
476
477 if (device->snapshot == NULL) {
478 KGSL_DRV_ERR(device,
479 "snapshot: No snapshot memory available\n");
480 return -ENOMEM;
481 }
482
483 if (remain < sizeof(*header)) {
484 KGSL_DRV_ERR(device,
485 "snapshot: Not enough memory for the header\n");
486 return -ENOMEM;
487 }
488
489 header->magic = SNAPSHOT_MAGIC;
490
491 header->gpuid = kgsl_gpuid(device);
492
493 /* Get a pointer to the first section (right after the header) */
494 snapshot = ((void *) device->snapshot) + sizeof(*header);
495
496 /* Build the Linux specific header */
497 snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
498 snapshot, &remain, snapshot_os, (void *) hang);
499
500 /* Get the device specific sections */
501 if (device->ftbl->snapshot)
502 snapshot = device->ftbl->snapshot(device, snapshot, &remain,
503 hang);
504
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700505 device->snapshot_timestamp = get_seconds();
506 device->snapshot_size = (int) (snapshot - device->snapshot);
507
508 /* Freeze the snapshot on a hang until it gets read */
509 device->snapshot_frozen = (hang) ? 1 : 0;
510
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700511 /* log buffer info to aid in ramdump recovery */
512 KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
513 device->snapshot, __pa(device->snapshot),
514 device->snapshot_size);
Jeremy Gebben90812c82012-03-08 12:46:01 -0700515 if (hang)
516 sysfs_notify(&device->snapshot_kobj, NULL, "timestamp");
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700517 return 0;
518}
519EXPORT_SYMBOL(kgsl_device_snapshot);
520
521/* An attribute for showing snapshot details */
522struct kgsl_snapshot_attribute {
523 struct attribute attr;
524 ssize_t (*show)(struct kgsl_device *device, char *buf);
525 ssize_t (*store)(struct kgsl_device *device, const char *buf,
526 size_t count);
527};
528
529#define to_snapshot_attr(a) \
530container_of(a, struct kgsl_snapshot_attribute, attr)
531
532#define kobj_to_device(a) \
533container_of(a, struct kgsl_device, snapshot_kobj)
534
535/* Dump the sysfs binary data to the user */
536static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
537 struct bin_attribute *attr, char *buf, loff_t off,
538 size_t count)
539{
540 struct kgsl_device *device = kobj_to_device(kobj);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600541 struct kgsl_snapshot_object *obj, *tmp;
542 unsigned int size, src, dst = 0;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700543
544 if (device == NULL)
545 return 0;
546
547 /* Return nothing if we haven't taken a snapshot yet */
548 if (device->snapshot_timestamp == 0)
549 return 0;
550
551 /* Get the mutex to keep things from changing while we are dumping */
552 mutex_lock(&device->mutex);
553
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600554 if (off < device->snapshot_size) {
555 size = count < (device->snapshot_size - off) ?
556 count : device->snapshot_size - off;
557
558 memcpy(buf, device->snapshot + off, size);
559
560 count -= size;
561 dst += size;
562 }
563
564 if (count == 0)
565 goto done;
566
567 src = device->snapshot_size;
568
569 list_for_each_entry(obj, &device->snapshot_obj_list, node) {
570
571 int objsize = GPU_OBJ_SECTION_SIZE(obj);
572 int offset;
573
574 /* If the offset is beyond this object, then move on */
575
576 if (off >= (src + objsize)) {
577 src += objsize;
578 continue;
579 }
580
581 /* Adjust the offset to be relative to the object */
582 offset = (off >= src) ? (off - src) : 0;
583
584 size = kgsl_snapshot_dump_object(device, obj, buf + dst,
585 offset, count);
586
587 count -= size;
588 dst += size;
589
590 if (count == 0)
591 goto done;
592
593 /* Move on to the next object - update src accordingly */
594 src += objsize;
595 }
596
597 /* Add the end section */
598
599 if (off < (src + sizeof(struct kgsl_snapshot_section_header))) {
600 if (count >= sizeof(struct kgsl_snapshot_section_header)) {
601 struct kgsl_snapshot_section_header *head =
602 (void *) (buf + dst);
603
604 head->magic = SNAPSHOT_SECTION_MAGIC;
605 head->id = KGSL_SNAPSHOT_SECTION_END;
606 head->size = sizeof(*head);
607
608 dst += sizeof(*head);
609 } else {
610 goto done;
611 }
612 }
613
614 /* Release the buffers and unfreeze the snapshot */
615
616 list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list, node)
617 kgsl_snapshot_put_object(device, obj);
618
619 if (device->snapshot_frozen)
620 KGSL_DRV_ERR(device, "Snapshot objects released\n");
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700621
622 device->snapshot_frozen = 0;
623
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600624done:
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700625 mutex_unlock(&device->mutex);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600626
627 return dst;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700628}
629
630/* Show the timestamp of the last collected snapshot */
631static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
632{
633 return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
634}
635
636/* manually trigger a new snapshot to be collected */
637static ssize_t trigger_store(struct kgsl_device *device, const char *buf,
638 size_t count)
639{
640 if (device && count > 0) {
641 mutex_lock(&device->mutex);
642 kgsl_device_snapshot(device, 0);
643 mutex_unlock(&device->mutex);
644 }
645
646 return count;
647}
648
649static struct bin_attribute snapshot_attr = {
650 .attr.name = "dump",
651 .attr.mode = 0444,
652 .size = 0,
653 .read = snapshot_show
654};
655
656#define SNAPSHOT_ATTR(_name, _mode, _show, _store) \
657struct kgsl_snapshot_attribute attr_##_name = { \
658 .attr = { .name = __stringify(_name), .mode = _mode }, \
659 .show = _show, \
660 .store = _store, \
661}
662
663SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
664SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
665
666static void snapshot_sysfs_release(struct kobject *kobj)
667{
668}
669
670static ssize_t snapshot_sysfs_show(struct kobject *kobj,
671 struct attribute *attr, char *buf)
672{
673 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
674 struct kgsl_device *device = kobj_to_device(kobj);
675 ssize_t ret;
676
677 if (device && pattr->show)
678 ret = pattr->show(device, buf);
679 else
680 ret = -EIO;
681
682 return ret;
683}
684
685static ssize_t snapshot_sysfs_store(struct kobject *kobj,
686 struct attribute *attr, const char *buf, size_t count)
687{
688 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
689 struct kgsl_device *device = kobj_to_device(kobj);
690 ssize_t ret;
691
692 if (device && pattr->store)
693 ret = pattr->store(device, buf, count);
694 else
695 ret = -EIO;
696
697 return ret;
698}
699
700static const struct sysfs_ops snapshot_sysfs_ops = {
701 .show = snapshot_sysfs_show,
702 .store = snapshot_sysfs_store,
703};
704
705static struct kobj_type ktype_snapshot = {
706 .sysfs_ops = &snapshot_sysfs_ops,
707 .default_attrs = NULL,
708 .release = snapshot_sysfs_release,
709};
710
711/* kgsl_device_snapshot_init - Add resources for the device GPU snapshot
712 * @device - The device to initalize
713 *
714 * Allocate memory for a GPU snapshot for the specified device,
715 * and create the sysfs files to manage it
716 */
717
718int kgsl_device_snapshot_init(struct kgsl_device *device)
719{
720 int ret;
721
722 if (device->snapshot == NULL)
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700723 device->snapshot = kzalloc(KGSL_SNAPSHOT_MEMSIZE, GFP_KERNEL);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700724
725 if (device->snapshot == NULL)
726 return -ENOMEM;
727
728 device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
729 device->snapshot_timestamp = 0;
730
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600731 INIT_LIST_HEAD(&device->snapshot_obj_list);
732
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700733 ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
734 &device->dev->kobj, "snapshot");
735 if (ret)
736 goto done;
737
738 ret = sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr);
739 if (ret)
740 goto done;
741
742 ret = sysfs_create_file(&device->snapshot_kobj, &attr_trigger.attr);
743 if (ret)
744 goto done;
745
746 ret = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
747
748done:
749 return ret;
750}
751EXPORT_SYMBOL(kgsl_device_snapshot_init);
752
753/* kgsl_device_snapshot_close - Take down snapshot memory for a device
754 * @device - Pointer to the kgsl_device
755 *
756 * Remove the sysfs files and free the memory allocated for the GPU
757 * snapshot
758 */
759
760void kgsl_device_snapshot_close(struct kgsl_device *device)
761{
762 sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr);
763 sysfs_remove_file(&device->snapshot_kobj, &attr_trigger.attr);
764 sysfs_remove_file(&device->snapshot_kobj, &attr_timestamp.attr);
765
766 kobject_put(&device->snapshot_kobj);
767
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700768 kfree(device->snapshot);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700769
770 device->snapshot = NULL;
771 device->snapshot_maxsize = 0;
772 device->snapshot_timestamp = 0;
773}
774EXPORT_SYMBOL(kgsl_device_snapshot_close);