decode.c revision 7ec681f3
1/*
2 * Copyright (C) 2017-2019 Alyssa Rosenzweig
3 * Copyright (C) 2017-2019 Connor Abbott
4 * Copyright (C) 2019 Collabora, Ltd.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26#include <genxml/gen_macros.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <memory.h>
30#include <stdbool.h>
31#include <stdarg.h>
32#include <errno.h>
33#include <ctype.h>
34#include "decode.h"
35
36#include "midgard/disassemble.h"
37#include "bifrost/disassemble.h"
38
39#define DUMP_UNPACKED(T, var, ...) { \
40        pandecode_log(__VA_ARGS__); \
41        pan_print(pandecode_dump_stream, T, var, (pandecode_indent + 1) * 2); \
42}
43
44#define DUMP_CL(T, cl, ...) {\
45        pan_unpack(cl, T, temp); \
46        DUMP_UNPACKED(T, temp, __VA_ARGS__); \
47}
48
49#define DUMP_SECTION(A, S, cl, ...) { \
50        pan_section_unpack(cl, A, S, temp); \
51        pandecode_log(__VA_ARGS__); \
52        pan_section_print(pandecode_dump_stream, A, S, temp, (pandecode_indent + 1) * 2); \
53}
54
55#define MAP_ADDR(T, addr, cl) \
56        const uint8_t *cl = 0; \
57        { \
58                struct pandecode_mapped_memory *mapped_mem = pandecode_find_mapped_gpu_mem_containing(addr); \
59                cl = pandecode_fetch_gpu_mem(mapped_mem, addr, pan_size(T)); \
60        }
61
62#define DUMP_ADDR(T, addr, ...) {\
63        MAP_ADDR(T, addr, cl) \
64        DUMP_CL(T, cl, __VA_ARGS__); \
65}
66
67/* Semantic logging type.
68 *
69 * Raw: for raw messages to be printed as is.
70 * Message: for helpful information to be commented out in replays.
71 *
72 * Use one of pandecode_log or pandecode_msg as syntax sugar.
73 */
74
75enum pandecode_log_type {
76        PANDECODE_RAW,
77        PANDECODE_MESSAGE,
78};
79
80#define pandecode_log(...)  pandecode_log_typed(PANDECODE_RAW,      __VA_ARGS__)
81#define pandecode_msg(...)  pandecode_log_typed(PANDECODE_MESSAGE,  __VA_ARGS__)
82
83static unsigned pandecode_indent = 0;
84
85static void
86pandecode_make_indent(void)
87{
88        for (unsigned i = 0; i < pandecode_indent; ++i)
89                fprintf(pandecode_dump_stream, "  ");
90}
91
92static void PRINTFLIKE(2, 3)
93pandecode_log_typed(enum pandecode_log_type type, const char *format, ...)
94{
95        va_list ap;
96
97        pandecode_make_indent();
98
99        if (type == PANDECODE_MESSAGE)
100                fprintf(pandecode_dump_stream, "// ");
101
102        va_start(ap, format);
103        vfprintf(pandecode_dump_stream, format, ap);
104        va_end(ap);
105}
106
107static void
108pandecode_log_cont(const char *format, ...)
109{
110        va_list ap;
111
112        va_start(ap, format);
113        vfprintf(pandecode_dump_stream, format, ap);
114        va_end(ap);
115}
116
117/* To check for memory safety issues, validates that the given pointer in GPU
118 * memory is valid, containing at least sz bytes. The goal is to eliminate
119 * GPU-side memory bugs (NULL pointer dereferences, buffer overflows, or buffer
120 * overruns) by statically validating pointers.
121 */
122
123static void
124pandecode_validate_buffer(mali_ptr addr, size_t sz)
125{
126        if (!addr) {
127                pandecode_msg("XXX: null pointer deref");
128                return;
129        }
130
131        /* Find a BO */
132
133        struct pandecode_mapped_memory *bo =
134                pandecode_find_mapped_gpu_mem_containing(addr);
135
136        if (!bo) {
137                pandecode_msg("XXX: invalid memory dereference\n");
138                return;
139        }
140
141        /* Bounds check */
142
143        unsigned offset = addr - bo->gpu_va;
144        unsigned total = offset + sz;
145
146        if (total > bo->length) {
147                pandecode_msg("XXX: buffer overrun. "
148                                "Chunk of size %zu at offset %d in buffer of size %zu. "
149                                "Overrun by %zu bytes. \n",
150                                sz, offset, bo->length, total - bo->length);
151                return;
152        }
153}
154
155#if PAN_ARCH <= 5
156/* Midgard's tiler descriptor is embedded within the
157 * larger FBD */
158
159static void
160pandecode_midgard_tiler_descriptor(
161                const struct mali_tiler_context_packed *tp,
162                const struct mali_tiler_weights_packed *wp)
163{
164        pan_unpack(tp, TILER_CONTEXT, t);
165        DUMP_UNPACKED(TILER_CONTEXT, t, "Tiler:\n");
166
167        /* We've never seen weights used in practice, but they exist */
168        pan_unpack(wp, TILER_WEIGHTS, w);
169        bool nonzero_weights = false;
170
171        nonzero_weights |= w.weight0 != 0x0;
172        nonzero_weights |= w.weight1 != 0x0;
173        nonzero_weights |= w.weight2 != 0x0;
174        nonzero_weights |= w.weight3 != 0x0;
175        nonzero_weights |= w.weight4 != 0x0;
176        nonzero_weights |= w.weight5 != 0x0;
177        nonzero_weights |= w.weight6 != 0x0;
178        nonzero_weights |= w.weight7 != 0x0;
179
180        if (nonzero_weights)
181                DUMP_UNPACKED(TILER_WEIGHTS, w, "Tiler Weights:\n");
182}
183#endif
184
185/* Information about the framebuffer passed back for
186 * additional analysis */
187
188struct pandecode_fbd {
189        unsigned width;
190        unsigned height;
191        unsigned rt_count;
192        bool has_extra;
193};
194
195#if PAN_ARCH == 4
196static struct pandecode_fbd
197pandecode_sfbd(uint64_t gpu_va, int job_no, bool is_fragment, unsigned gpu_id)
198{
199        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
200        const void *PANDECODE_PTR_VAR(s, mem, (mali_ptr) gpu_va);
201
202        struct pandecode_fbd info = {
203                .has_extra = false,
204                .rt_count = 1
205        };
206
207        pandecode_log("Framebuffer:\n");
208        pandecode_indent++;
209
210        DUMP_SECTION(FRAMEBUFFER, LOCAL_STORAGE, s, "Local Storage:\n");
211        pan_section_unpack(s, FRAMEBUFFER, PARAMETERS, p);
212        DUMP_UNPACKED(FRAMEBUFFER_PARAMETERS, p, "Parameters:\n");
213
214        const void *t = pan_section_ptr(s, FRAMEBUFFER, TILER);
215        const void *w = pan_section_ptr(s, FRAMEBUFFER, TILER_WEIGHTS);
216
217        pandecode_midgard_tiler_descriptor(t, w);
218
219        pandecode_indent--;
220
221        /* Dummy unpack of the padding section to make sure all words are 0.
222         * No need to call print here since the section is supposed to be empty.
223         */
224        pan_section_unpack(s, FRAMEBUFFER, PADDING_1, padding1);
225        pan_section_unpack(s, FRAMEBUFFER, PADDING_2, padding2);
226        pandecode_log("\n");
227
228        return info;
229}
230#endif
231
232#if PAN_ARCH >= 5
233static void
234pandecode_local_storage(uint64_t gpu_va, int job_no)
235{
236        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
237        const struct mali_local_storage_packed *PANDECODE_PTR_VAR(s, mem, (mali_ptr) gpu_va);
238        DUMP_CL(LOCAL_STORAGE, s, "Local Storage:\n");
239}
240
241static void
242pandecode_render_target(uint64_t gpu_va, unsigned job_no, unsigned gpu_id,
243                        const struct MALI_FRAMEBUFFER_PARAMETERS *fb)
244{
245        pandecode_log("Color Render Targets:\n");
246        pandecode_indent++;
247
248        for (int i = 0; i < (fb->render_target_count); i++) {
249                mali_ptr rt_va = gpu_va + i * pan_size(RENDER_TARGET);
250                struct pandecode_mapped_memory *mem =
251                        pandecode_find_mapped_gpu_mem_containing(rt_va);
252                const struct mali_render_target_packed *PANDECODE_PTR_VAR(rtp, mem, (mali_ptr) rt_va);
253                DUMP_CL(RENDER_TARGET, rtp, "Color Render Target %d:\n", i);
254        }
255
256        pandecode_indent--;
257        pandecode_log("\n");
258}
259#endif
260
261#if PAN_ARCH >= 6
262static void
263pandecode_sample_locations(const void *fb, int job_no)
264{
265        pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, params);
266
267        struct pandecode_mapped_memory *smem =
268                pandecode_find_mapped_gpu_mem_containing(params.sample_locations);
269
270        const u16 *PANDECODE_PTR_VAR(samples, smem, params.sample_locations);
271
272        pandecode_log("Sample locations:\n");
273        for (int i = 0; i < 33; i++) {
274                pandecode_log("  (%d, %d),\n",
275                                samples[2 * i] - 128,
276                                samples[2 * i + 1] - 128);
277        }
278}
279#endif
280
281static void
282pandecode_dcd(const struct MALI_DRAW *p,
283              int job_no, enum mali_job_type job_type,
284              char *suffix, unsigned gpu_id);
285
286#if PAN_ARCH >= 5
287static struct pandecode_fbd
288pandecode_mfbd_bfr(uint64_t gpu_va, int job_no, bool is_fragment, unsigned gpu_id)
289{
290        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
291        const void *PANDECODE_PTR_VAR(fb, mem, (mali_ptr) gpu_va);
292        pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, params);
293
294        struct pandecode_fbd info;
295
296#if PAN_ARCH >= 6
297        pandecode_sample_locations(fb, job_no);
298
299        pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, bparams);
300        unsigned dcd_size = pan_size(DRAW);
301        struct pandecode_mapped_memory *dcdmem =
302                pandecode_find_mapped_gpu_mem_containing(bparams.frame_shader_dcds);
303
304        if (bparams.pre_frame_0 != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
305                const void *PANDECODE_PTR_VAR(dcd, dcdmem, bparams.frame_shader_dcds + (0 * dcd_size));
306                pan_unpack(dcd, DRAW, draw);
307                pandecode_log("Pre frame 0:\n");
308                pandecode_dcd(&draw, job_no, MALI_JOB_TYPE_FRAGMENT, "", gpu_id);
309        }
310
311        if (bparams.pre_frame_1 != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
312                const void *PANDECODE_PTR_VAR(dcd, dcdmem, bparams.frame_shader_dcds + (1 * dcd_size));
313                pan_unpack(dcd, DRAW, draw);
314                pandecode_log("Pre frame 1:\n");
315                pandecode_dcd(&draw, job_no, MALI_JOB_TYPE_FRAGMENT, "", gpu_id);
316        }
317
318        if (bparams.post_frame != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
319                const void *PANDECODE_PTR_VAR(dcd, dcdmem, bparams.frame_shader_dcds + (2 * dcd_size));
320                pan_unpack(dcd, DRAW, draw);
321                pandecode_log("Post frame:\n");
322                pandecode_dcd(&draw, job_no, MALI_JOB_TYPE_FRAGMENT, "", gpu_id);
323        }
324#endif
325
326        pandecode_log("Multi-Target Framebuffer:\n");
327        pandecode_indent++;
328
329#if PAN_ARCH <= 5
330        DUMP_SECTION(FRAMEBUFFER, LOCAL_STORAGE, fb, "Local Storage:\n");
331#endif
332
333        info.width = params.width;
334        info.height = params.height;
335        info.rt_count = params.render_target_count;
336        DUMP_UNPACKED(FRAMEBUFFER_PARAMETERS, params, "Parameters:\n");
337
338#if PAN_ARCH <= 5
339        const void *t = pan_section_ptr(fb, FRAMEBUFFER, TILER);
340        const void *w = pan_section_ptr(fb, FRAMEBUFFER, TILER_WEIGHTS);
341        pandecode_midgard_tiler_descriptor(t, w);
342#endif
343
344        pandecode_indent--;
345        pandecode_log("\n");
346
347        gpu_va += pan_size(FRAMEBUFFER);
348
349        info.has_extra = params.has_zs_crc_extension;
350
351        if (info.has_extra) {
352                struct pandecode_mapped_memory *mem =
353                        pandecode_find_mapped_gpu_mem_containing(gpu_va);
354                const struct mali_zs_crc_extension_packed *PANDECODE_PTR_VAR(zs_crc, mem, (mali_ptr)gpu_va);
355                DUMP_CL(ZS_CRC_EXTENSION, zs_crc, "ZS CRC Extension:\n");
356                pandecode_log("\n");
357
358                gpu_va += pan_size(ZS_CRC_EXTENSION);
359        }
360
361        if (is_fragment)
362                pandecode_render_target(gpu_va, job_no, gpu_id, &params);
363
364        return info;
365}
366#endif
367
368static void
369pandecode_attributes(const struct pandecode_mapped_memory *mem,
370                            mali_ptr addr, int job_no, char *suffix,
371                            int count, bool varying, enum mali_job_type job_type)
372{
373        char *prefix = varying ? "Varying" : "Attribute";
374        assert(addr);
375
376        if (!count) {
377                pandecode_msg("warn: No %s records\n", prefix);
378                return;
379        }
380
381        MAP_ADDR(ATTRIBUTE_BUFFER, addr, cl);
382
383        for (int i = 0; i < count; ++i) {
384                pan_unpack(cl + i * pan_size(ATTRIBUTE_BUFFER), ATTRIBUTE_BUFFER, temp);
385                DUMP_UNPACKED(ATTRIBUTE_BUFFER, temp, "%s:\n", prefix);
386
387                switch (temp.type) {
388                case MALI_ATTRIBUTE_TYPE_1D_NPOT_DIVISOR_WRITE_REDUCTION:
389                case MALI_ATTRIBUTE_TYPE_1D_NPOT_DIVISOR: {
390                        pan_unpack(cl + (i + 1) * pan_size(ATTRIBUTE_BUFFER),
391                                   ATTRIBUTE_BUFFER_CONTINUATION_NPOT, temp2);
392                        pan_print(pandecode_dump_stream, ATTRIBUTE_BUFFER_CONTINUATION_NPOT,
393                                  temp2, (pandecode_indent + 1) * 2);
394                        i++;
395                        break;
396                }
397                case MALI_ATTRIBUTE_TYPE_3D_LINEAR:
398                case MALI_ATTRIBUTE_TYPE_3D_INTERLEAVED: {
399                        pan_unpack(cl + (i + 1) * pan_size(ATTRIBUTE_BUFFER_CONTINUATION_3D),
400                                   ATTRIBUTE_BUFFER_CONTINUATION_3D, temp2);
401                        pan_print(pandecode_dump_stream, ATTRIBUTE_BUFFER_CONTINUATION_3D,
402                                  temp2, (pandecode_indent + 1) * 2);
403                        i++;
404                        break;
405                }
406                default:
407                        break;
408                }
409        }
410        pandecode_log("\n");
411}
412
413#if PAN_ARCH >= 6
414/* Decodes a Bifrost blend constant. See the notes in bifrost_blend_rt */
415
416static mali_ptr
417pandecode_bifrost_blend(void *descs, int job_no, int rt_no, mali_ptr frag_shader)
418{
419        pan_unpack(descs + (rt_no * pan_size(BLEND)), BLEND, b);
420        DUMP_UNPACKED(BLEND, b, "Blend RT %d:\n", rt_no);
421        if (b.internal.mode != MALI_BLEND_MODE_SHADER)
422                return 0;
423
424        return (frag_shader & 0xFFFFFFFF00000000ULL) | b.internal.shader.pc;
425}
426#elif PAN_ARCH == 5
427static mali_ptr
428pandecode_midgard_blend_mrt(void *descs, int job_no, int rt_no)
429{
430        pan_unpack(descs + (rt_no * pan_size(BLEND)), BLEND, b);
431        DUMP_UNPACKED(BLEND, b, "Blend RT %d:\n", rt_no);
432        return b.blend_shader ? (b.shader_pc & ~0xf) : 0;
433}
434#endif
435
436static unsigned
437pandecode_attribute_meta(int count, mali_ptr attribute, bool varying)
438{
439        unsigned max = 0;
440
441        for (int i = 0; i < count; ++i, attribute += pan_size(ATTRIBUTE)) {
442                MAP_ADDR(ATTRIBUTE, attribute, cl);
443                pan_unpack(cl, ATTRIBUTE, a);
444                DUMP_UNPACKED(ATTRIBUTE, a, "%s:\n", varying ? "Varying" : "Attribute");
445                max = MAX2(max, a.buffer_index);
446        }
447
448        pandecode_log("\n");
449        return MIN2(max + 1, 256);
450}
451
452/* return bits [lo, hi) of word */
453static u32
454bits(u32 word, u32 lo, u32 hi)
455{
456        if (hi - lo >= 32)
457                return word; // avoid undefined behavior with the shift
458
459        if (lo >= 32)
460                return 0;
461
462        return (word >> lo) & ((1 << (hi - lo)) - 1);
463}
464
465static void
466pandecode_invocation(const void *i)
467{
468        /* Decode invocation_count. See the comment before the definition of
469         * invocation_count for an explanation.
470         */
471        pan_unpack(i, INVOCATION, invocation);
472
473        unsigned size_x = bits(invocation.invocations, 0, invocation.size_y_shift) + 1;
474        unsigned size_y = bits(invocation.invocations, invocation.size_y_shift, invocation.size_z_shift) + 1;
475        unsigned size_z = bits(invocation.invocations, invocation.size_z_shift, invocation.workgroups_x_shift) + 1;
476
477        unsigned groups_x = bits(invocation.invocations, invocation.workgroups_x_shift, invocation.workgroups_y_shift) + 1;
478        unsigned groups_y = bits(invocation.invocations, invocation.workgroups_y_shift, invocation.workgroups_z_shift) + 1;
479        unsigned groups_z = bits(invocation.invocations, invocation.workgroups_z_shift, 32) + 1;
480
481        pandecode_log("Invocation (%d, %d, %d) x (%d, %d, %d)\n",
482                      size_x, size_y, size_z,
483                      groups_x, groups_y, groups_z);
484
485        DUMP_UNPACKED(INVOCATION, invocation, "Invocation:\n")
486}
487
488static void
489pandecode_primitive(const void *p)
490{
491        pan_unpack(p, PRIMITIVE, primitive);
492        DUMP_UNPACKED(PRIMITIVE, primitive, "Primitive:\n");
493
494        /* Validate an index buffer is present if we need one. TODO: verify
495         * relationship between invocation_count and index_count */
496
497        if (primitive.indices) {
498                /* Grab the size */
499                unsigned size = (primitive.index_type == MALI_INDEX_TYPE_UINT32) ?
500                        sizeof(uint32_t) : primitive.index_type;
501
502                /* Ensure we got a size, and if so, validate the index buffer
503                 * is large enough to hold a full set of indices of the given
504                 * size */
505
506                if (!size)
507                        pandecode_msg("XXX: index size missing\n");
508                else
509                        pandecode_validate_buffer(primitive.indices, primitive.index_count * size);
510        } else if (primitive.index_type)
511                pandecode_msg("XXX: unexpected index size\n");
512}
513
514static void
515pandecode_uniform_buffers(mali_ptr pubufs, int ubufs_count, int job_no)
516{
517        struct pandecode_mapped_memory *umem = pandecode_find_mapped_gpu_mem_containing(pubufs);
518        uint64_t *PANDECODE_PTR_VAR(ubufs, umem, pubufs);
519
520        for (int i = 0; i < ubufs_count; i++) {
521                mali_ptr addr = (ubufs[i] >> 10) << 2;
522                unsigned size = addr ? (((ubufs[i] & ((1 << 10) - 1)) + 1) * 16) : 0;
523
524                pandecode_validate_buffer(addr, size);
525
526                char *ptr = pointer_as_memory_reference(addr);
527                pandecode_log("ubuf_%d[%u] = %s;\n", i, size, ptr);
528                free(ptr);
529        }
530
531        pandecode_log("\n");
532}
533
534static void
535pandecode_uniforms(mali_ptr uniforms, unsigned uniform_count)
536{
537        pandecode_validate_buffer(uniforms, uniform_count * 16);
538
539        char *ptr = pointer_as_memory_reference(uniforms);
540        pandecode_log("vec4 uniforms[%u] = %s;\n", uniform_count, ptr);
541        free(ptr);
542        pandecode_log("\n");
543}
544
545static const char *
546shader_type_for_job(unsigned type)
547{
548        switch (type) {
549        case MALI_JOB_TYPE_VERTEX:  return "VERTEX";
550        case MALI_JOB_TYPE_TILER:   return "FRAGMENT";
551        case MALI_JOB_TYPE_FRAGMENT: return "FRAGMENT";
552        case MALI_JOB_TYPE_COMPUTE: return "COMPUTE";
553        default: return "UNKNOWN";
554        }
555}
556
557static unsigned shader_id = 0;
558
559static struct midgard_disasm_stats
560pandecode_shader_disassemble(mali_ptr shader_ptr, int shader_no, int type,
561                             unsigned gpu_id)
562{
563        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(shader_ptr);
564        uint8_t *PANDECODE_PTR_VAR(code, mem, shader_ptr);
565
566        /* Compute maximum possible size */
567        size_t sz = mem->length - (shader_ptr - mem->gpu_va);
568
569        /* Print some boilerplate to clearly denote the assembly (which doesn't
570         * obey indentation rules), and actually do the disassembly! */
571
572        pandecode_log_cont("\n\n");
573
574        struct midgard_disasm_stats stats;
575
576#if PAN_ARCH >= 6
577        disassemble_bifrost(pandecode_dump_stream, code, sz, true);
578
579        /* TODO: Extend stats to Bifrost */
580        stats.texture_count = -128;
581        stats.sampler_count = -128;
582        stats.attribute_count = -128;
583        stats.varying_count = -128;
584        stats.uniform_count = -128;
585        stats.uniform_buffer_count = -128;
586        stats.work_count = -128;
587
588        stats.instruction_count = 0;
589        stats.bundle_count = 0;
590        stats.quadword_count = 0;
591        stats.helper_invocations = false;
592#else
593	stats = disassemble_midgard(pandecode_dump_stream,
594                                    code, sz, gpu_id, true);
595#endif
596
597        unsigned nr_threads =
598                (stats.work_count <= 4) ? 4 :
599                (stats.work_count <= 8) ? 2 :
600                1;
601
602        pandecode_log_cont("shader%d - MESA_SHADER_%s shader: "
603                "%u inst, %u bundles, %u quadwords, "
604                "%u registers, %u threads, 0 loops, 0:0 spills:fills\n\n\n",
605                shader_id++,
606                shader_type_for_job(type),
607                stats.instruction_count, stats.bundle_count, stats.quadword_count,
608                stats.work_count, nr_threads);
609
610        return stats;
611}
612
613static void
614pandecode_texture_payload(mali_ptr payload,
615                          enum mali_texture_dimension dim,
616                          enum mali_texture_layout layout,
617                          bool manual_stride,
618                          uint8_t levels,
619                          uint16_t nr_samples,
620                          uint16_t array_size,
621                          struct pandecode_mapped_memory *tmem)
622{
623        pandecode_log(".payload = {\n");
624        pandecode_indent++;
625
626        /* A bunch of bitmap pointers follow.
627         * We work out the correct number,
628         * based on the mipmap/cubemap
629         * properties, but dump extra
630         * possibilities to futureproof */
631
632        int bitmap_count = levels;
633
634        /* Miptree for each face */
635        if (dim == MALI_TEXTURE_DIMENSION_CUBE)
636                bitmap_count *= 6;
637
638        /* Array of layers */
639        bitmap_count *= nr_samples;
640
641        /* Array of textures */
642        bitmap_count *= array_size;
643
644        /* Stride for each element */
645        if (manual_stride)
646                bitmap_count *= 2;
647
648        mali_ptr *pointers_and_strides = pandecode_fetch_gpu_mem(tmem,
649                payload, sizeof(mali_ptr) * bitmap_count);
650        for (int i = 0; i < bitmap_count; ++i) {
651                /* How we dump depends if this is a stride or a pointer */
652
653                if (manual_stride && (i & 1)) {
654                        /* signed 32-bit snuck in as a 64-bit pointer */
655                        uint64_t stride_set = pointers_and_strides[i];
656                        int32_t line_stride = stride_set;
657                        int32_t surface_stride = stride_set >> 32;
658                        pandecode_log("(mali_ptr) %d /* surface stride */ %d /* line stride */, \n",
659                                      surface_stride, line_stride);
660                } else {
661                        char *a = pointer_as_memory_reference(pointers_and_strides[i]);
662                        pandecode_log("%s, \n", a);
663                        free(a);
664                }
665        }
666
667        pandecode_indent--;
668        pandecode_log("},\n");
669}
670
671#if PAN_ARCH <= 5
672static void
673pandecode_texture(mali_ptr u,
674                struct pandecode_mapped_memory *tmem,
675                unsigned job_no, unsigned tex)
676{
677        struct pandecode_mapped_memory *mapped_mem = pandecode_find_mapped_gpu_mem_containing(u);
678        const uint8_t *cl = pandecode_fetch_gpu_mem(mapped_mem, u, pan_size(TEXTURE));
679
680        pan_unpack(cl, TEXTURE, temp);
681        DUMP_UNPACKED(TEXTURE, temp, "Texture:\n")
682
683        pandecode_indent++;
684        unsigned nr_samples = temp.dimension == MALI_TEXTURE_DIMENSION_3D ?
685                              1 : temp.sample_count;
686        pandecode_texture_payload(u + pan_size(TEXTURE),
687                        temp.dimension, temp.texel_ordering, temp.manual_stride,
688                        temp.levels, nr_samples, temp.array_size, mapped_mem);
689        pandecode_indent--;
690}
691#else
692static void
693pandecode_bifrost_texture(
694                const void *cl,
695                unsigned job_no,
696                unsigned tex)
697{
698        pan_unpack(cl, TEXTURE, temp);
699        DUMP_UNPACKED(TEXTURE, temp, "Texture:\n")
700
701        struct pandecode_mapped_memory *tmem = pandecode_find_mapped_gpu_mem_containing(temp.surfaces);
702        unsigned nr_samples = temp.dimension == MALI_TEXTURE_DIMENSION_3D ?
703                              1 : temp.sample_count;
704        pandecode_indent++;
705        pandecode_texture_payload(temp.surfaces, temp.dimension, temp.texel_ordering,
706                                  true, temp.levels, nr_samples, temp.array_size, tmem);
707        pandecode_indent--;
708}
709#endif
710
711static void
712pandecode_blend_shader_disassemble(mali_ptr shader, int job_no, int job_type,
713                                   unsigned gpu_id)
714{
715        struct midgard_disasm_stats stats =
716                pandecode_shader_disassemble(shader, job_no, job_type, gpu_id);
717
718        bool has_texture = (stats.texture_count > 0);
719        bool has_sampler = (stats.sampler_count > 0);
720        bool has_attribute = (stats.attribute_count > 0);
721        bool has_varying = (stats.varying_count > 0);
722        bool has_uniform = (stats.uniform_count > 0);
723        bool has_ubo = (stats.uniform_buffer_count > 0);
724
725        if (has_texture || has_sampler)
726                pandecode_msg("XXX: blend shader accessing textures\n");
727
728        if (has_attribute || has_varying)
729                pandecode_msg("XXX: blend shader accessing interstage\n");
730
731        if (has_uniform || has_ubo)
732                pandecode_msg("XXX: blend shader accessing uniforms\n");
733}
734
735static void
736pandecode_textures(mali_ptr textures, unsigned texture_count, int job_no)
737{
738        struct pandecode_mapped_memory *mmem = pandecode_find_mapped_gpu_mem_containing(textures);
739
740        if (!mmem)
741                return;
742
743        pandecode_log("Textures %"PRIx64"_%d:\n", textures, job_no);
744        pandecode_indent++;
745
746#if PAN_ARCH >= 6
747        const void *cl =
748                pandecode_fetch_gpu_mem(mmem,
749                                        textures,
750                                        pan_size(TEXTURE) *
751                                        texture_count);
752
753        for (unsigned tex = 0; tex < texture_count; ++tex) {
754                pandecode_bifrost_texture(cl + pan_size(TEXTURE) * tex,
755                                          job_no, tex);
756        }
757#else
758        mali_ptr *PANDECODE_PTR_VAR(u, mmem, textures);
759
760        for (int tex = 0; tex < texture_count; ++tex) {
761                mali_ptr *PANDECODE_PTR_VAR(u, mmem, textures + tex * sizeof(mali_ptr));
762                char *a = pointer_as_memory_reference(*u);
763                pandecode_log("%s,\n", a);
764                free(a);
765        }
766
767        /* Now, finally, descend down into the texture descriptor */
768        for (unsigned tex = 0; tex < texture_count; ++tex) {
769                mali_ptr *PANDECODE_PTR_VAR(u, mmem, textures + tex * sizeof(mali_ptr));
770                struct pandecode_mapped_memory *tmem = pandecode_find_mapped_gpu_mem_containing(*u);
771                if (tmem)
772                        pandecode_texture(*u, tmem, job_no, tex);
773        }
774#endif
775        pandecode_indent--;
776        pandecode_log("\n");
777}
778
779static void
780pandecode_samplers(mali_ptr samplers, unsigned sampler_count, int job_no)
781{
782        pandecode_log("Samplers %"PRIx64"_%d:\n", samplers, job_no);
783        pandecode_indent++;
784
785        for (int i = 0; i < sampler_count; ++i)
786                DUMP_ADDR(SAMPLER, samplers + (pan_size(SAMPLER) * i), "Sampler %d:\n", i);
787
788        pandecode_indent--;
789        pandecode_log("\n");
790}
791
792static void
793pandecode_dcd(const struct MALI_DRAW *p,
794              int job_no, enum mali_job_type job_type,
795              char *suffix, unsigned gpu_id)
796{
797        struct pandecode_mapped_memory *attr_mem;
798
799#if PAN_ARCH >= 5
800        struct pandecode_fbd fbd_info = {
801                /* Default for Bifrost */
802                .rt_count = 1
803        };
804#endif
805
806#if PAN_ARCH >= 6
807        pandecode_local_storage(p->thread_storage & ~1, job_no);
808#elif PAN_ARCH == 5
809        if (job_type != MALI_JOB_TYPE_TILER) {
810                pandecode_local_storage(p->thread_storage & ~1, job_no);
811	} else {
812                assert(p->fbd & MALI_FBD_TAG_IS_MFBD);
813                fbd_info = pandecode_mfbd_bfr((u64) ((uintptr_t) p->fbd) & ~MALI_FBD_TAG_MASK,
814                                              job_no, false, gpu_id);
815        }
816#else
817        pandecode_sfbd((u64) (uintptr_t) p->fbd, job_no, false, gpu_id);
818#endif
819
820        int varying_count = 0, attribute_count = 0, uniform_count = 0, uniform_buffer_count = 0;
821        int texture_count = 0, sampler_count = 0;
822
823        if (p->state) {
824                struct pandecode_mapped_memory *smem = pandecode_find_mapped_gpu_mem_containing(p->state);
825                uint32_t *cl = pandecode_fetch_gpu_mem(smem, p->state, pan_size(RENDERER_STATE));
826
827                pan_unpack(cl, RENDERER_STATE, state);
828
829                if (state.shader.shader & ~0xF)
830                        pandecode_shader_disassemble(state.shader.shader & ~0xF, job_no, job_type, gpu_id);
831
832#if PAN_ARCH >= 6
833                bool idvs = (job_type == MALI_JOB_TYPE_INDEXED_VERTEX);
834
835                if (idvs && state.secondary_shader)
836                        pandecode_shader_disassemble(state.secondary_shader, job_no, job_type, gpu_id);
837#endif
838                DUMP_UNPACKED(RENDERER_STATE, state, "State:\n");
839                pandecode_indent++;
840
841                /* Save for dumps */
842                attribute_count = state.shader.attribute_count;
843                varying_count = state.shader.varying_count;
844                texture_count = state.shader.texture_count;
845                sampler_count = state.shader.sampler_count;
846                uniform_buffer_count = state.properties.uniform_buffer_count;
847
848#if PAN_ARCH >= 6
849                uniform_count = state.preload.uniform_count;
850#else
851                uniform_count = state.properties.uniform_count;
852#endif
853
854#if PAN_ARCH >= 6
855                DUMP_UNPACKED(PRELOAD, state.preload, "Preload:\n");
856#elif PAN_ARCH == 4
857                mali_ptr shader = state.blend_shader & ~0xF;
858                if (state.multisample_misc.blend_shader && shader)
859                        pandecode_blend_shader_disassemble(shader, job_no, job_type, gpu_id);
860#endif
861                pandecode_indent--;
862                pandecode_log("\n");
863
864                /* MRT blend fields are used whenever MFBD is used, with
865                 * per-RT descriptors */
866
867#if PAN_ARCH >= 5
868                if ((job_type == MALI_JOB_TYPE_TILER || job_type == MALI_JOB_TYPE_FRAGMENT) &&
869                    (PAN_ARCH >= 6 || p->thread_storage & MALI_FBD_TAG_IS_MFBD)) {
870                        void* blend_base = ((void *) cl) + pan_size(RENDERER_STATE);
871
872                        for (unsigned i = 0; i < fbd_info.rt_count; i++) {
873                                mali_ptr shader = 0;
874
875#if PAN_ARCH >= 6
876                                shader = pandecode_bifrost_blend(blend_base, job_no, i,
877                                                                 state.shader.shader);
878#else
879                                shader = pandecode_midgard_blend_mrt(blend_base, job_no, i);
880#endif
881                                if (shader & ~0xF)
882                                        pandecode_blend_shader_disassemble(shader, job_no, job_type,
883                                                                           gpu_id);
884                        }
885                }
886#endif
887        } else
888                pandecode_msg("XXX: missing shader descriptor\n");
889
890        if (p->viewport) {
891                DUMP_ADDR(VIEWPORT, p->viewport, "Viewport:\n");
892                pandecode_log("\n");
893        }
894
895        unsigned max_attr_index = 0;
896
897        if (p->attributes)
898                max_attr_index = pandecode_attribute_meta(attribute_count, p->attributes, false);
899
900        if (p->attribute_buffers) {
901                attr_mem = pandecode_find_mapped_gpu_mem_containing(p->attribute_buffers);
902                pandecode_attributes(attr_mem, p->attribute_buffers, job_no, suffix, max_attr_index, false, job_type);
903        }
904
905        if (p->varyings) {
906                varying_count = pandecode_attribute_meta(varying_count, p->varyings, true);
907        }
908
909        if (p->varying_buffers) {
910                attr_mem = pandecode_find_mapped_gpu_mem_containing(p->varying_buffers);
911                pandecode_attributes(attr_mem, p->varying_buffers, job_no, suffix, varying_count, true, job_type);
912        }
913
914        if (p->uniform_buffers) {
915                if (uniform_buffer_count)
916                        pandecode_uniform_buffers(p->uniform_buffers, uniform_buffer_count, job_no);
917                else
918                        pandecode_msg("warn: UBOs specified but not referenced\n");
919        } else if (uniform_buffer_count)
920                pandecode_msg("XXX: UBOs referenced but not specified\n");
921
922        /* We don't want to actually dump uniforms, but we do need to validate
923         * that the counts we were given are sane */
924
925        if (p->push_uniforms) {
926                if (uniform_count)
927                        pandecode_uniforms(p->push_uniforms, uniform_count);
928                else
929                        pandecode_msg("warn: Uniforms specified but not referenced\n");
930        } else if (uniform_count)
931                pandecode_msg("XXX: Uniforms referenced but not specified\n");
932
933        if (p->textures)
934                pandecode_textures(p->textures, texture_count, job_no);
935
936        if (p->samplers)
937                pandecode_samplers(p->samplers, sampler_count, job_no);
938}
939
940static void
941pandecode_primitive_size(const void *s, bool constant)
942{
943        pan_unpack(s, PRIMITIVE_SIZE, ps);
944        if (ps.size_array == 0x0)
945                return;
946
947        DUMP_UNPACKED(PRIMITIVE_SIZE, ps, "Primitive Size:\n")
948}
949
950static void
951pandecode_vertex_compute_geometry_job(const struct MALI_JOB_HEADER *h,
952                                      const struct pandecode_mapped_memory *mem,
953                                      mali_ptr job, int job_no, unsigned gpu_id)
954{
955        struct mali_compute_job_packed *PANDECODE_PTR_VAR(p, mem, job);
956        pan_section_unpack(p, COMPUTE_JOB, DRAW, draw);
957        pandecode_dcd(&draw, job_no, h->type, "", gpu_id);
958
959        pandecode_log("Vertex Job Payload:\n");
960        pandecode_indent++;
961        pandecode_invocation(pan_section_ptr(p, COMPUTE_JOB, INVOCATION));
962        DUMP_SECTION(COMPUTE_JOB, PARAMETERS, p, "Vertex Job Parameters:\n");
963        DUMP_UNPACKED(DRAW, draw, "Draw:\n");
964        pandecode_indent--;
965        pandecode_log("\n");
966}
967
968#if PAN_ARCH >= 6
969static void
970pandecode_bifrost_tiler_heap(mali_ptr gpu_va, int job_no)
971{
972        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
973        pan_unpack(PANDECODE_PTR(mem, gpu_va, void), TILER_HEAP, h);
974        DUMP_UNPACKED(TILER_HEAP, h, "Bifrost Tiler Heap:\n");
975}
976
977static void
978pandecode_bifrost_tiler(mali_ptr gpu_va, int job_no)
979{
980        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
981        pan_unpack(PANDECODE_PTR(mem, gpu_va, void), TILER_CONTEXT, t);
982
983        pandecode_bifrost_tiler_heap(t.heap, job_no);
984
985        DUMP_UNPACKED(TILER_CONTEXT, t, "Bifrost Tiler:\n");
986        pandecode_indent++;
987        if (t.hierarchy_mask != 0xa &&
988            t.hierarchy_mask != 0x14 &&
989            t.hierarchy_mask != 0x28 &&
990            t.hierarchy_mask != 0x50 &&
991            t.hierarchy_mask != 0xa0)
992                pandecode_msg("XXX: Unexpected hierarchy_mask (not 0xa, 0x14, 0x28, 0x50 or 0xa0)!");
993
994        pandecode_indent--;
995}
996
997static void
998pandecode_indexed_vertex_job(const struct MALI_JOB_HEADER *h,
999                             const struct pandecode_mapped_memory *mem,
1000                             mali_ptr job, int job_no, unsigned gpu_id)
1001{
1002        struct mali_indexed_vertex_job_packed *PANDECODE_PTR_VAR(p, mem, job);
1003
1004        pandecode_log("Vertex:\n");
1005        pan_section_unpack(p, INDEXED_VERTEX_JOB, VERTEX_DRAW, vert_draw);
1006        pandecode_dcd(&vert_draw, job_no, h->type, "", gpu_id);
1007        DUMP_UNPACKED(DRAW, vert_draw, "Vertex Draw:\n");
1008
1009        pandecode_log("Fragment:\n");
1010        pan_section_unpack(p, INDEXED_VERTEX_JOB, FRAGMENT_DRAW, frag_draw);
1011        pandecode_dcd(&frag_draw, job_no, MALI_JOB_TYPE_FRAGMENT, "", gpu_id);
1012        DUMP_UNPACKED(DRAW, frag_draw, "Fragment Draw:\n");
1013
1014        pan_section_unpack(p, INDEXED_VERTEX_JOB, TILER, tiler_ptr);
1015        pandecode_log("Tiler Job Payload:\n");
1016        pandecode_indent++;
1017        pandecode_bifrost_tiler(tiler_ptr.address, job_no);
1018        pandecode_indent--;
1019
1020        pandecode_invocation(pan_section_ptr(p, INDEXED_VERTEX_JOB, INVOCATION));
1021        pandecode_primitive(pan_section_ptr(p, INDEXED_VERTEX_JOB, PRIMITIVE));
1022
1023        /* TODO: gl_PointSize on Bifrost */
1024        pandecode_primitive_size(pan_section_ptr(p, INDEXED_VERTEX_JOB, PRIMITIVE_SIZE), true);
1025
1026        pan_section_unpack(p, INDEXED_VERTEX_JOB, PADDING, padding);
1027}
1028
1029static void
1030pandecode_tiler_job_bfr(const struct MALI_JOB_HEADER *h,
1031                        const struct pandecode_mapped_memory *mem,
1032                        mali_ptr job, int job_no, unsigned gpu_id)
1033{
1034        struct mali_tiler_job_packed *PANDECODE_PTR_VAR(p, mem, job);
1035        pan_section_unpack(p, TILER_JOB, DRAW, draw);
1036        pan_section_unpack(p, TILER_JOB, TILER, tiler_ptr);
1037        pandecode_dcd(&draw, job_no, h->type, "", gpu_id);
1038
1039        pandecode_log("Tiler Job Payload:\n");
1040        pandecode_indent++;
1041        pandecode_bifrost_tiler(tiler_ptr.address, job_no);
1042
1043        pandecode_invocation(pan_section_ptr(p, TILER_JOB, INVOCATION));
1044        pandecode_primitive(pan_section_ptr(p, TILER_JOB, PRIMITIVE));
1045
1046        /* TODO: gl_PointSize on Bifrost */
1047        pandecode_primitive_size(pan_section_ptr(p, TILER_JOB, PRIMITIVE_SIZE), true);
1048        pan_section_unpack(p, TILER_JOB, PADDING, padding);
1049        DUMP_UNPACKED(DRAW, draw, "Draw:\n");
1050        pandecode_indent--;
1051        pandecode_log("\n");
1052}
1053#else
1054static void
1055pandecode_tiler_job_mdg(const struct MALI_JOB_HEADER *h,
1056                        const struct pandecode_mapped_memory *mem,
1057                        mali_ptr job, int job_no, unsigned gpu_id)
1058{
1059        struct mali_tiler_job_packed *PANDECODE_PTR_VAR(p, mem, job);
1060        pan_section_unpack(p, TILER_JOB, DRAW, draw);
1061        pandecode_dcd(&draw, job_no, h->type, "", gpu_id);
1062
1063        pandecode_log("Tiler Job Payload:\n");
1064        pandecode_indent++;
1065        pandecode_invocation(pan_section_ptr(p, TILER_JOB, INVOCATION));
1066        pandecode_primitive(pan_section_ptr(p, TILER_JOB, PRIMITIVE));
1067        DUMP_UNPACKED(DRAW, draw, "Draw:\n");
1068
1069        pan_section_unpack(p, TILER_JOB, PRIMITIVE, primitive);
1070        pandecode_primitive_size(pan_section_ptr(p, TILER_JOB, PRIMITIVE_SIZE),
1071                                 primitive.point_size_array_format == MALI_POINT_SIZE_ARRAY_FORMAT_NONE);
1072        pandecode_indent--;
1073        pandecode_log("\n");
1074}
1075#endif
1076
1077static void
1078pandecode_fragment_job(const struct pandecode_mapped_memory *mem,
1079                       mali_ptr job, int job_no, unsigned gpu_id)
1080{
1081        struct mali_fragment_job_packed *PANDECODE_PTR_VAR(p, mem, job);
1082        pan_section_unpack(p, FRAGMENT_JOB, PAYLOAD, s);
1083
1084
1085#if PAN_ARCH == 4
1086        pandecode_sfbd(s.framebuffer, job_no, true, gpu_id);
1087#else
1088        assert(s.framebuffer & MALI_FBD_TAG_IS_MFBD);
1089
1090        struct pandecode_fbd info;
1091
1092        info = pandecode_mfbd_bfr(s.framebuffer & ~MALI_FBD_TAG_MASK, job_no,
1093                                  true, gpu_id);
1094#endif
1095
1096#if PAN_ARCH >= 5
1097        unsigned expected_tag = 0;
1098
1099        /* Compute the tag for the tagged pointer. This contains the type of
1100         * FBD (MFBD/SFBD), and in the case of an MFBD, information about which
1101         * additional structures follow the MFBD header (an extra payload or
1102         * not, as well as a count of render targets) */
1103
1104        expected_tag = MALI_FBD_TAG_IS_MFBD;
1105        if (info.has_extra)
1106                expected_tag |= MALI_FBD_TAG_HAS_ZS_RT;
1107
1108        expected_tag |= MALI_FBD_TAG_IS_MFBD | (MALI_POSITIVE(info.rt_count) << 2);
1109#endif
1110
1111        DUMP_UNPACKED(FRAGMENT_JOB_PAYLOAD, s, "Fragment Job Payload:\n");
1112
1113#if PAN_ARCH >= 5
1114        /* The FBD is a tagged pointer */
1115
1116        unsigned tag = (s.framebuffer & MALI_FBD_TAG_MASK);
1117
1118        if (tag != expected_tag)
1119                pandecode_msg("XXX: expected FBD tag %X but got %X\n", expected_tag, tag);
1120#endif
1121
1122        pandecode_log("\n");
1123}
1124
1125static void
1126pandecode_write_value_job(const struct pandecode_mapped_memory *mem,
1127                          mali_ptr job, int job_no)
1128{
1129        struct mali_write_value_job_packed *PANDECODE_PTR_VAR(p, mem, job);
1130        pan_section_unpack(p, WRITE_VALUE_JOB, PAYLOAD, u);
1131        DUMP_SECTION(WRITE_VALUE_JOB, PAYLOAD, p, "Write Value Payload:\n");
1132        pandecode_log("\n");
1133}
1134
1135static void
1136pandecode_cache_flush_job(const struct pandecode_mapped_memory *mem,
1137                          mali_ptr job, int job_no)
1138{
1139        struct mali_cache_flush_job_packed *PANDECODE_PTR_VAR(p, mem, job);
1140        pan_section_unpack(p, CACHE_FLUSH_JOB, PAYLOAD, u);
1141        DUMP_SECTION(CACHE_FLUSH_JOB, PAYLOAD, p, "Cache Flush Payload:\n");
1142        pandecode_log("\n");
1143}
1144
1145/* Entrypoint to start tracing. jc_gpu_va is the GPU address for the first job
1146 * in the chain; later jobs are found by walking the chain. Bifrost is, well,
1147 * if it's bifrost or not. GPU ID is the more finegrained ID (at some point, we
1148 * might wish to combine this with the bifrost parameter) because some details
1149 * are model-specific even within a particular architecture. */
1150
1151void
1152GENX(pandecode_jc)(mali_ptr jc_gpu_va, unsigned gpu_id)
1153{
1154        pandecode_dump_file_open();
1155
1156        unsigned job_descriptor_number = 0;
1157        mali_ptr next_job = 0;
1158
1159        do {
1160                struct pandecode_mapped_memory *mem =
1161                        pandecode_find_mapped_gpu_mem_containing(jc_gpu_va);
1162
1163                pan_unpack(PANDECODE_PTR(mem, jc_gpu_va, struct mali_job_header_packed),
1164                           JOB_HEADER, h);
1165                next_job = h.next;
1166
1167                int job_no = job_descriptor_number++;
1168
1169                DUMP_UNPACKED(JOB_HEADER, h, "Job Header:\n");
1170                pandecode_log("\n");
1171
1172                switch (h.type) {
1173                case MALI_JOB_TYPE_WRITE_VALUE:
1174                        pandecode_write_value_job(mem, jc_gpu_va, job_no);
1175                        break;
1176
1177                case MALI_JOB_TYPE_CACHE_FLUSH:
1178                        pandecode_cache_flush_job(mem, jc_gpu_va, job_no);
1179                        break;
1180
1181                case MALI_JOB_TYPE_TILER:
1182#if PAN_ARCH >= 6
1183                        pandecode_tiler_job_bfr(&h, mem, jc_gpu_va, job_no, gpu_id);
1184#else
1185                        pandecode_tiler_job_mdg(&h, mem, jc_gpu_va, job_no, gpu_id);
1186#endif
1187                        break;
1188
1189                case MALI_JOB_TYPE_VERTEX:
1190                case MALI_JOB_TYPE_COMPUTE:
1191                        pandecode_vertex_compute_geometry_job(&h, mem, jc_gpu_va, job_no, gpu_id);
1192                        break;
1193
1194#if PAN_ARCH >= 6
1195                case MALI_JOB_TYPE_INDEXED_VERTEX:
1196                        pandecode_indexed_vertex_job(&h, mem, jc_gpu_va, job_no, gpu_id);
1197                        break;
1198#endif
1199
1200                case MALI_JOB_TYPE_FRAGMENT:
1201                        pandecode_fragment_job(mem, jc_gpu_va, job_no, gpu_id);
1202                        break;
1203
1204                default:
1205                        break;
1206                }
1207        } while ((jc_gpu_va = next_job));
1208
1209        fflush(pandecode_dump_stream);
1210        pandecode_map_read_write();
1211}
1212
1213void
1214GENX(pandecode_abort_on_fault)(mali_ptr jc_gpu_va)
1215{
1216        mali_ptr next_job = 0;
1217
1218        do {
1219                struct pandecode_mapped_memory *mem =
1220                        pandecode_find_mapped_gpu_mem_containing(jc_gpu_va);
1221
1222                pan_unpack(PANDECODE_PTR(mem, jc_gpu_va, struct mali_job_header_packed),
1223                           JOB_HEADER, h);
1224                next_job = h.next;
1225
1226                /* Ensure the job is marked COMPLETE */
1227                if (h.exception_status != 0x1) {
1228                        fprintf(stderr, "Incomplete job or timeout");
1229                        abort();
1230                }
1231        } while ((jc_gpu_va = next_job));
1232
1233        pandecode_map_read_write();
1234}
1235