blob: c058e95736645a5f3875f8ef6582f2a96b60da8d [file] [log] [blame]
Duy Truonge833aca2013-02-12 13:35:08 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jordan Crouse156cfbc2012-01-24 09:32:04 -07002 *
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
Jordan Crouse21aaadf2012-09-11 16:38:15 -0600292/* ksgl_snapshot_have_object - Return 1 if the object has been processed
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 *
298 * Return 1 if the object is already in the list - this can save us from
299 * having to parse the sme thing over again.
300*/
301int kgsl_snapshot_have_object(struct kgsl_device *device, unsigned int ptbase,
302 unsigned int gpuaddr, unsigned int size)
303{
304 struct kgsl_snapshot_object *obj;
305
306 list_for_each_entry(obj, &device->snapshot_obj_list, node) {
307 if (obj->ptbase != ptbase)
308 continue;
309
310 if ((gpuaddr >= obj->gpuaddr) &&
311 ((gpuaddr + size) <= (obj->gpuaddr + obj->size)))
312 return 1;
313 }
314
315 return 0;
316}
317
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600318/* kgsl_snapshot_get_object - Mark a GPU buffer to be frozen
319 * @device - the device that is being snapshotted
320 * @ptbase - the pagetable base of the object to freeze
321 * @gpuaddr - The gpu address of the object to freeze
322 * @size - the size of the object (may not always be the size of the region)
323 * @type - the type of object being saved (shader, vbo, etc)
324 *
325 * Mark and freeze a GPU buffer object. This will prevent it from being
326 * freed until it can be copied out as part of the snapshot dump. Returns the
327 * size of the object being frozen
328 */
329
330int kgsl_snapshot_get_object(struct kgsl_device *device, unsigned int ptbase,
331 unsigned int gpuaddr, unsigned int size, unsigned int type)
332{
333 struct kgsl_mem_entry *entry;
334 struct kgsl_snapshot_object *obj;
335 int offset;
336
Shubhraprakash Das3cf33be2012-08-16 22:42:55 -0700337 entry = kgsl_get_mem_entry(device, ptbase, gpuaddr, size);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600338
339 if (entry == NULL) {
340 KGSL_DRV_ERR(device, "Unable to find GPU buffer %8.8X\n",
341 gpuaddr);
342 return 0;
343 }
344
345 /* We can't freeze external memory, because we don't own it */
346 if (entry->memtype != KGSL_MEM_ENTRY_KERNEL) {
347 KGSL_DRV_ERR(device,
348 "Only internal GPU buffers can be frozen\n");
349 return 0;
350 }
351
352 /*
353 * size indicates the number of bytes in the region to save. This might
354 * not always be the entire size of the region because some buffers are
355 * sub-allocated from a larger region. However, if size 0 was passed
356 * thats a flag that the caller wants to capture the entire buffer
357 */
358
359 if (size == 0) {
360 size = entry->memdesc.size;
361 offset = 0;
362
363 /* Adjust the gpuaddr to the start of the object */
364 gpuaddr = entry->memdesc.gpuaddr;
365 } else {
366 offset = gpuaddr - entry->memdesc.gpuaddr;
367 }
368
369 if (size + offset > entry->memdesc.size) {
370 KGSL_DRV_ERR(device, "Invalid size for GPU buffer %8.8X\n",
371 gpuaddr);
372 return 0;
373 }
374
375 /* If the buffer is already on the list, skip it */
376 list_for_each_entry(obj, &device->snapshot_obj_list, node) {
377 if (obj->gpuaddr == gpuaddr && obj->ptbase == ptbase) {
378 /* If the size is different, use the new size */
379 if (obj->size != size)
380 obj->size = size;
381
382 return 0;
383 }
384 }
385
Jordan Crouse17d6d8b2012-04-18 09:31:09 -0600386 if (kgsl_memdesc_map(&entry->memdesc) == NULL) {
387 KGSL_DRV_ERR(device, "Unable to map GPU buffer %X\n",
388 gpuaddr);
389 return 0;
390 }
391
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600392 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
393
394 if (obj == NULL) {
395 KGSL_DRV_ERR(device, "Unable to allocate memory\n");
396 return 0;
397 }
398
399 /* Ref count the mem entry */
400 kgsl_mem_entry_get(entry);
401
402 obj->type = type;
403 obj->entry = entry;
404 obj->gpuaddr = gpuaddr;
405 obj->ptbase = ptbase;
406 obj->size = size;
Jordan Crouse233b2092012-04-18 09:31:09 -0600407 obj->offset = offset;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600408
409 list_add(&obj->node, &device->snapshot_obj_list);
410
411 /*
412 * Return the size of the entire mem entry that was frozen - this gets
413 * used for tracking how much memory is frozen for a hang. Also, mark
414 * the memory entry as frozen. If the entry was already marked as
415 * frozen, then another buffer already got to it. In that case, return
416 * 0 so it doesn't get counted twice
417 */
418
419 if (entry->flags & KGSL_MEM_ENTRY_FROZEN)
420 return 0;
421
422 entry->flags |= KGSL_MEM_ENTRY_FROZEN;
423
424 return entry->memdesc.size;
425}
426EXPORT_SYMBOL(kgsl_snapshot_get_object);
427
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700428/*
429 * kgsl_snapshot_dump_regs - helper function to dump device registers
430 * @device - the device to dump registers from
431 * @snapshot - pointer to the start of the region of memory for the snapshot
432 * @remain - a pointer to the number of bytes remaining in the snapshot
433 * @priv - A pointer to the kgsl_snapshot_registers data
434 *
435 * Given an array of register ranges pairs (start,end [inclusive]), dump the
436 * registers into a snapshot register section. The snapshot region stores a
437 * part of dwords for each register - the word address of the register, and
438 * the value.
439 */
440int kgsl_snapshot_dump_regs(struct kgsl_device *device, void *snapshot,
441 int remain, void *priv)
442{
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600443 struct kgsl_snapshot_registers_list *list = priv;
444
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700445 struct kgsl_snapshot_regs *header = snapshot;
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600446 struct kgsl_snapshot_registers *regs;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700447 unsigned int *data = snapshot + sizeof(*header);
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600448 int count = 0, i, j, k;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700449
450 /* Figure out how many registers we are going to dump */
451
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600452 for (i = 0; i < list->count; i++) {
453 regs = &(list->registers[i]);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700454
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600455 for (j = 0; j < regs->count; j++) {
456 int start = regs->regs[j * 2];
457 int end = regs->regs[j * 2 + 1];
458
459 count += (end - start + 1);
460 }
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700461 }
462
463 if (remain < (count * 8) + sizeof(*header)) {
464 SNAPSHOT_ERR_NOMEM(device, "REGISTERS");
465 return 0;
466 }
467
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700468
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600469 for (i = 0; i < list->count; i++) {
470 regs = &(list->registers[i]);
471 for (j = 0; j < regs->count; j++) {
472 unsigned int start = regs->regs[j * 2];
473 unsigned int end = regs->regs[j * 2 + 1];
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700474
Jordan Crouseea4f8b82012-08-14 14:38:46 -0600475 for (k = start; k <= end; k++) {
476 unsigned int val;
477
478 kgsl_regread(device, k, &val);
479 *data++ = k;
480 *data++ = val;
481 }
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700482 }
483 }
484
485 header->count = count;
486
487 /* Return the size of the section */
488 return (count * 8) + sizeof(*header);
489}
490EXPORT_SYMBOL(kgsl_snapshot_dump_regs);
491
Jordan Crouse0c2761a2012-02-01 22:11:12 -0700492void *kgsl_snapshot_indexed_registers(struct kgsl_device *device,
493 void *snapshot, int *remain,
494 unsigned int index, unsigned int data, unsigned int start,
495 unsigned int count)
496{
497 struct kgsl_snapshot_indexed_registers iregs;
498 iregs.index = index;
499 iregs.data = data;
500 iregs.start = start;
501 iregs.count = count;
502
503 return kgsl_snapshot_add_section(device,
504 KGSL_SNAPSHOT_SECTION_INDEXED_REGS, snapshot,
505 remain, kgsl_snapshot_dump_indexed_regs, &iregs);
506}
507EXPORT_SYMBOL(kgsl_snapshot_indexed_registers);
508
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700509/*
510 * kgsl_snapshot - construct a device snapshot
511 * @device - device to snapshot
512 * @hang - set to 1 if the snapshot was triggered following a hnag
513 * Given a device, construct a binary snapshot dump of the current device state
514 * and store it in the device snapshot memory.
515 */
516int kgsl_device_snapshot(struct kgsl_device *device, int hang)
517{
518 struct kgsl_snapshot_header *header = device->snapshot;
519 int remain = device->snapshot_maxsize - sizeof(*header);
520 void *snapshot;
521
522 /*
523 * The first hang is always the one we are interested in. To
524 * avoid a subsequent hang blowing away the first, the snapshot
525 * is frozen until it is dumped via sysfs.
526 *
527 * Note that triggered snapshots are always taken regardless
528 * of the state and never frozen.
529 */
530
531 if (hang && device->snapshot_frozen == 1)
532 return 0;
533
534 if (device->snapshot == NULL) {
535 KGSL_DRV_ERR(device,
536 "snapshot: No snapshot memory available\n");
537 return -ENOMEM;
538 }
539
540 if (remain < sizeof(*header)) {
541 KGSL_DRV_ERR(device,
542 "snapshot: Not enough memory for the header\n");
543 return -ENOMEM;
544 }
545
546 header->magic = SNAPSHOT_MAGIC;
547
Jordan Crouse70829d32012-06-20 08:22:17 -0600548 header->gpuid = kgsl_gpuid(device, &header->chipid);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700549
550 /* Get a pointer to the first section (right after the header) */
551 snapshot = ((void *) device->snapshot) + sizeof(*header);
552
553 /* Build the Linux specific header */
554 snapshot = kgsl_snapshot_add_section(device, KGSL_SNAPSHOT_SECTION_OS,
555 snapshot, &remain, snapshot_os, (void *) hang);
556
557 /* Get the device specific sections */
558 if (device->ftbl->snapshot)
559 snapshot = device->ftbl->snapshot(device, snapshot, &remain,
560 hang);
561
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700562 device->snapshot_timestamp = get_seconds();
563 device->snapshot_size = (int) (snapshot - device->snapshot);
564
565 /* Freeze the snapshot on a hang until it gets read */
566 device->snapshot_frozen = (hang) ? 1 : 0;
567
Tarun Karrad20d71a2013-01-25 15:38:57 -0800568 /* log buffer info to aid in ramdump fault tolerance */
Tarun Karra45a50d62013-01-28 21:47:37 -0800569 KGSL_DRV_ERR(device, "snapshot created at pa %lx size %d\n",
570 __pa(device->snapshot), device->snapshot_size);
Jeremy Gebben90812c82012-03-08 12:46:01 -0700571 if (hang)
572 sysfs_notify(&device->snapshot_kobj, NULL, "timestamp");
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700573 return 0;
574}
575EXPORT_SYMBOL(kgsl_device_snapshot);
576
577/* An attribute for showing snapshot details */
578struct kgsl_snapshot_attribute {
579 struct attribute attr;
580 ssize_t (*show)(struct kgsl_device *device, char *buf);
581 ssize_t (*store)(struct kgsl_device *device, const char *buf,
582 size_t count);
583};
584
585#define to_snapshot_attr(a) \
586container_of(a, struct kgsl_snapshot_attribute, attr)
587
588#define kobj_to_device(a) \
589container_of(a, struct kgsl_device, snapshot_kobj)
590
591/* Dump the sysfs binary data to the user */
592static ssize_t snapshot_show(struct file *filep, struct kobject *kobj,
593 struct bin_attribute *attr, char *buf, loff_t off,
594 size_t count)
595{
596 struct kgsl_device *device = kobj_to_device(kobj);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600597 struct kgsl_snapshot_object *obj, *tmp;
Jordan Crouse7c325702012-06-20 08:22:16 -0600598 struct kgsl_snapshot_section_header head;
599 struct snapshot_obj_itr itr;
600 int ret;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700601
602 if (device == NULL)
603 return 0;
604
605 /* Return nothing if we haven't taken a snapshot yet */
606 if (device->snapshot_timestamp == 0)
607 return 0;
608
609 /* Get the mutex to keep things from changing while we are dumping */
610 mutex_lock(&device->mutex);
611
Jordan Crouse7c325702012-06-20 08:22:16 -0600612 obj_itr_init(&itr, buf, off, count);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600613
Jordan Crouse7c325702012-06-20 08:22:16 -0600614 ret = obj_itr_out(&itr, device->snapshot, device->snapshot_size);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600615
Jordan Crouse7c325702012-06-20 08:22:16 -0600616 if (ret == 0)
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600617 goto done;
618
Jordan Crouse7c325702012-06-20 08:22:16 -0600619 list_for_each_entry(obj, &device->snapshot_obj_list, node)
620 kgsl_snapshot_dump_object(device, obj, &itr);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600621
Jordan Crouse7c325702012-06-20 08:22:16 -0600622 {
623 head.magic = SNAPSHOT_SECTION_MAGIC;
624 head.id = KGSL_SNAPSHOT_SECTION_END;
625 head.size = sizeof(head);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600626
Jordan Crouse7c325702012-06-20 08:22:16 -0600627 obj_itr_out(&itr, &head, sizeof(head));
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600628 }
629
Jordan Crouse7c325702012-06-20 08:22:16 -0600630 /*
631 * Make sure everything has been written out before destroying things.
632 * The best way to confirm this is to go all the way through without
633 * writing any bytes - so only release if we get this far and
634 * itr->write is 0
635 */
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600636
Jordan Crouse7c325702012-06-20 08:22:16 -0600637 if (itr.write == 0) {
638 list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list,
639 node)
640 kgsl_snapshot_put_object(device, obj);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600641
Jordan Crouse7c325702012-06-20 08:22:16 -0600642 if (device->snapshot_frozen)
643 KGSL_DRV_ERR(device, "Snapshot objects released\n");
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600644
Jordan Crouse7c325702012-06-20 08:22:16 -0600645 device->snapshot_frozen = 0;
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600646 }
647
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600648done:
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700649 mutex_unlock(&device->mutex);
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600650
Jordan Crouse7c325702012-06-20 08:22:16 -0600651 return itr.write;
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700652}
653
654/* Show the timestamp of the last collected snapshot */
655static ssize_t timestamp_show(struct kgsl_device *device, char *buf)
656{
657 return snprintf(buf, PAGE_SIZE, "%x\n", device->snapshot_timestamp);
658}
659
660/* manually trigger a new snapshot to be collected */
661static ssize_t trigger_store(struct kgsl_device *device, const char *buf,
662 size_t count)
663{
664 if (device && count > 0) {
665 mutex_lock(&device->mutex);
666 kgsl_device_snapshot(device, 0);
667 mutex_unlock(&device->mutex);
668 }
669
670 return count;
671}
672
673static struct bin_attribute snapshot_attr = {
674 .attr.name = "dump",
675 .attr.mode = 0444,
676 .size = 0,
677 .read = snapshot_show
678};
679
680#define SNAPSHOT_ATTR(_name, _mode, _show, _store) \
681struct kgsl_snapshot_attribute attr_##_name = { \
682 .attr = { .name = __stringify(_name), .mode = _mode }, \
683 .show = _show, \
684 .store = _store, \
685}
686
687SNAPSHOT_ATTR(trigger, 0600, NULL, trigger_store);
688SNAPSHOT_ATTR(timestamp, 0444, timestamp_show, NULL);
689
690static void snapshot_sysfs_release(struct kobject *kobj)
691{
692}
693
694static ssize_t snapshot_sysfs_show(struct kobject *kobj,
695 struct attribute *attr, char *buf)
696{
697 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
698 struct kgsl_device *device = kobj_to_device(kobj);
699 ssize_t ret;
700
701 if (device && pattr->show)
702 ret = pattr->show(device, buf);
703 else
704 ret = -EIO;
705
706 return ret;
707}
708
709static ssize_t snapshot_sysfs_store(struct kobject *kobj,
710 struct attribute *attr, const char *buf, size_t count)
711{
712 struct kgsl_snapshot_attribute *pattr = to_snapshot_attr(attr);
713 struct kgsl_device *device = kobj_to_device(kobj);
714 ssize_t ret;
715
716 if (device && pattr->store)
717 ret = pattr->store(device, buf, count);
718 else
719 ret = -EIO;
720
721 return ret;
722}
723
724static const struct sysfs_ops snapshot_sysfs_ops = {
725 .show = snapshot_sysfs_show,
726 .store = snapshot_sysfs_store,
727};
728
729static struct kobj_type ktype_snapshot = {
730 .sysfs_ops = &snapshot_sysfs_ops,
731 .default_attrs = NULL,
732 .release = snapshot_sysfs_release,
733};
734
735/* kgsl_device_snapshot_init - Add resources for the device GPU snapshot
736 * @device - The device to initalize
737 *
738 * Allocate memory for a GPU snapshot for the specified device,
739 * and create the sysfs files to manage it
740 */
741
742int kgsl_device_snapshot_init(struct kgsl_device *device)
743{
744 int ret;
745
746 if (device->snapshot == NULL)
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700747 device->snapshot = kzalloc(KGSL_SNAPSHOT_MEMSIZE, GFP_KERNEL);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700748
749 if (device->snapshot == NULL)
750 return -ENOMEM;
751
752 device->snapshot_maxsize = KGSL_SNAPSHOT_MEMSIZE;
753 device->snapshot_timestamp = 0;
754
Jordan Crouse9610b6b2012-03-16 14:53:42 -0600755 INIT_LIST_HEAD(&device->snapshot_obj_list);
756
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700757 ret = kobject_init_and_add(&device->snapshot_kobj, &ktype_snapshot,
758 &device->dev->kobj, "snapshot");
759 if (ret)
760 goto done;
761
762 ret = sysfs_create_bin_file(&device->snapshot_kobj, &snapshot_attr);
763 if (ret)
764 goto done;
765
766 ret = sysfs_create_file(&device->snapshot_kobj, &attr_trigger.attr);
767 if (ret)
768 goto done;
769
770 ret = sysfs_create_file(&device->snapshot_kobj, &attr_timestamp.attr);
771
772done:
773 return ret;
774}
775EXPORT_SYMBOL(kgsl_device_snapshot_init);
776
777/* kgsl_device_snapshot_close - Take down snapshot memory for a device
778 * @device - Pointer to the kgsl_device
779 *
780 * Remove the sysfs files and free the memory allocated for the GPU
781 * snapshot
782 */
783
784void kgsl_device_snapshot_close(struct kgsl_device *device)
785{
786 sysfs_remove_bin_file(&device->snapshot_kobj, &snapshot_attr);
787 sysfs_remove_file(&device->snapshot_kobj, &attr_trigger.attr);
788 sysfs_remove_file(&device->snapshot_kobj, &attr_timestamp.attr);
789
790 kobject_put(&device->snapshot_kobj);
791
Jeremy Gebben9d15ae42012-02-29 16:50:27 -0700792 kfree(device->snapshot);
Jordan Crouse156cfbc2012-01-24 09:32:04 -0700793
794 device->snapshot = NULL;
795 device->snapshot_maxsize = 0;
796 device->snapshot_timestamp = 0;
797}
798EXPORT_SYMBOL(kgsl_device_snapshot_close);