17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2017-2019 Alyssa Rosenzweig
37ec681f3Smrg * Copyright (C) 2017-2019 Connor Abbott
47ec681f3Smrg * Copyright (C) 2019 Collabora, Ltd.
57ec681f3Smrg *
67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
87ec681f3Smrg * to deal in the Software without restriction, including without limitation
97ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
117ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
127ec681f3Smrg *
137ec681f3Smrg * The above copyright notice and this permission notice (including the next
147ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
157ec681f3Smrg * Software.
167ec681f3Smrg *
177ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
217ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
227ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
237ec681f3Smrg * SOFTWARE.
247ec681f3Smrg */
257ec681f3Smrg
267ec681f3Smrg#include <genxml/gen_macros.h>
277ec681f3Smrg#include <stdio.h>
287ec681f3Smrg#include <stdlib.h>
297ec681f3Smrg#include <memory.h>
307ec681f3Smrg#include <stdbool.h>
317ec681f3Smrg#include <stdarg.h>
327ec681f3Smrg#include <errno.h>
337ec681f3Smrg#include <ctype.h>
347ec681f3Smrg#include "decode.h"
357ec681f3Smrg
367ec681f3Smrg#include "midgard/disassemble.h"
377ec681f3Smrg#include "bifrost/disassemble.h"
387ec681f3Smrg
397ec681f3Smrg#define DUMP_UNPACKED(T, var, ...) { \
407ec681f3Smrg        pandecode_log(__VA_ARGS__); \
417ec681f3Smrg        pan_print(pandecode_dump_stream, T, var, (pandecode_indent + 1) * 2); \
427ec681f3Smrg}
437ec681f3Smrg
447ec681f3Smrg#define DUMP_CL(T, cl, ...) {\
457ec681f3Smrg        pan_unpack(cl, T, temp); \
467ec681f3Smrg        DUMP_UNPACKED(T, temp, __VA_ARGS__); \
477ec681f3Smrg}
487ec681f3Smrg
497ec681f3Smrg#define DUMP_SECTION(A, S, cl, ...) { \
507ec681f3Smrg        pan_section_unpack(cl, A, S, temp); \
517ec681f3Smrg        pandecode_log(__VA_ARGS__); \
527ec681f3Smrg        pan_section_print(pandecode_dump_stream, A, S, temp, (pandecode_indent + 1) * 2); \
537ec681f3Smrg}
547ec681f3Smrg
557ec681f3Smrg#define MAP_ADDR(T, addr, cl) \
567ec681f3Smrg        const uint8_t *cl = 0; \
577ec681f3Smrg        { \
587ec681f3Smrg                struct pandecode_mapped_memory *mapped_mem = pandecode_find_mapped_gpu_mem_containing(addr); \
597ec681f3Smrg                cl = pandecode_fetch_gpu_mem(mapped_mem, addr, pan_size(T)); \
607ec681f3Smrg        }
617ec681f3Smrg
627ec681f3Smrg#define DUMP_ADDR(T, addr, ...) {\
637ec681f3Smrg        MAP_ADDR(T, addr, cl) \
647ec681f3Smrg        DUMP_CL(T, cl, __VA_ARGS__); \
657ec681f3Smrg}
667ec681f3Smrg
677ec681f3Smrg/* Semantic logging type.
687ec681f3Smrg *
697ec681f3Smrg * Raw: for raw messages to be printed as is.
707ec681f3Smrg * Message: for helpful information to be commented out in replays.
717ec681f3Smrg *
727ec681f3Smrg * Use one of pandecode_log or pandecode_msg as syntax sugar.
737ec681f3Smrg */
747ec681f3Smrg
757ec681f3Smrgenum pandecode_log_type {
767ec681f3Smrg        PANDECODE_RAW,
777ec681f3Smrg        PANDECODE_MESSAGE,
787ec681f3Smrg};
797ec681f3Smrg
807ec681f3Smrg#define pandecode_log(...)  pandecode_log_typed(PANDECODE_RAW,      __VA_ARGS__)
817ec681f3Smrg#define pandecode_msg(...)  pandecode_log_typed(PANDECODE_MESSAGE,  __VA_ARGS__)
827ec681f3Smrg
837ec681f3Smrgstatic unsigned pandecode_indent = 0;
847ec681f3Smrg
857ec681f3Smrgstatic void
867ec681f3Smrgpandecode_make_indent(void)
877ec681f3Smrg{
887ec681f3Smrg        for (unsigned i = 0; i < pandecode_indent; ++i)
897ec681f3Smrg                fprintf(pandecode_dump_stream, "  ");
907ec681f3Smrg}
917ec681f3Smrg
927ec681f3Smrgstatic void PRINTFLIKE(2, 3)
937ec681f3Smrgpandecode_log_typed(enum pandecode_log_type type, const char *format, ...)
947ec681f3Smrg{
957ec681f3Smrg        va_list ap;
967ec681f3Smrg
977ec681f3Smrg        pandecode_make_indent();
987ec681f3Smrg
997ec681f3Smrg        if (type == PANDECODE_MESSAGE)
1007ec681f3Smrg                fprintf(pandecode_dump_stream, "// ");
1017ec681f3Smrg
1027ec681f3Smrg        va_start(ap, format);
1037ec681f3Smrg        vfprintf(pandecode_dump_stream, format, ap);
1047ec681f3Smrg        va_end(ap);
1057ec681f3Smrg}
1067ec681f3Smrg
1077ec681f3Smrgstatic void
1087ec681f3Smrgpandecode_log_cont(const char *format, ...)
1097ec681f3Smrg{
1107ec681f3Smrg        va_list ap;
1117ec681f3Smrg
1127ec681f3Smrg        va_start(ap, format);
1137ec681f3Smrg        vfprintf(pandecode_dump_stream, format, ap);
1147ec681f3Smrg        va_end(ap);
1157ec681f3Smrg}
1167ec681f3Smrg
1177ec681f3Smrg/* To check for memory safety issues, validates that the given pointer in GPU
1187ec681f3Smrg * memory is valid, containing at least sz bytes. The goal is to eliminate
1197ec681f3Smrg * GPU-side memory bugs (NULL pointer dereferences, buffer overflows, or buffer
1207ec681f3Smrg * overruns) by statically validating pointers.
1217ec681f3Smrg */
1227ec681f3Smrg
1237ec681f3Smrgstatic void
1247ec681f3Smrgpandecode_validate_buffer(mali_ptr addr, size_t sz)
1257ec681f3Smrg{
1267ec681f3Smrg        if (!addr) {
1277ec681f3Smrg                pandecode_msg("XXX: null pointer deref");
1287ec681f3Smrg                return;
1297ec681f3Smrg        }
1307ec681f3Smrg
1317ec681f3Smrg        /* Find a BO */
1327ec681f3Smrg
1337ec681f3Smrg        struct pandecode_mapped_memory *bo =
1347ec681f3Smrg                pandecode_find_mapped_gpu_mem_containing(addr);
1357ec681f3Smrg
1367ec681f3Smrg        if (!bo) {
1377ec681f3Smrg                pandecode_msg("XXX: invalid memory dereference\n");
1387ec681f3Smrg                return;
1397ec681f3Smrg        }
1407ec681f3Smrg
1417ec681f3Smrg        /* Bounds check */
1427ec681f3Smrg
1437ec681f3Smrg        unsigned offset = addr - bo->gpu_va;
1447ec681f3Smrg        unsigned total = offset + sz;
1457ec681f3Smrg
1467ec681f3Smrg        if (total > bo->length) {
1477ec681f3Smrg                pandecode_msg("XXX: buffer overrun. "
1487ec681f3Smrg                                "Chunk of size %zu at offset %d in buffer of size %zu. "
1497ec681f3Smrg                                "Overrun by %zu bytes. \n",
1507ec681f3Smrg                                sz, offset, bo->length, total - bo->length);
1517ec681f3Smrg                return;
1527ec681f3Smrg        }
1537ec681f3Smrg}
1547ec681f3Smrg
1557ec681f3Smrg#if PAN_ARCH <= 5
1567ec681f3Smrg/* Midgard's tiler descriptor is embedded within the
1577ec681f3Smrg * larger FBD */
1587ec681f3Smrg
1597ec681f3Smrgstatic void
1607ec681f3Smrgpandecode_midgard_tiler_descriptor(
1617ec681f3Smrg                const struct mali_tiler_context_packed *tp,
1627ec681f3Smrg                const struct mali_tiler_weights_packed *wp)
1637ec681f3Smrg{
1647ec681f3Smrg        pan_unpack(tp, TILER_CONTEXT, t);
1657ec681f3Smrg        DUMP_UNPACKED(TILER_CONTEXT, t, "Tiler:\n");
1667ec681f3Smrg
1677ec681f3Smrg        /* We've never seen weights used in practice, but they exist */
1687ec681f3Smrg        pan_unpack(wp, TILER_WEIGHTS, w);
1697ec681f3Smrg        bool nonzero_weights = false;
1707ec681f3Smrg
1717ec681f3Smrg        nonzero_weights |= w.weight0 != 0x0;
1727ec681f3Smrg        nonzero_weights |= w.weight1 != 0x0;
1737ec681f3Smrg        nonzero_weights |= w.weight2 != 0x0;
1747ec681f3Smrg        nonzero_weights |= w.weight3 != 0x0;
1757ec681f3Smrg        nonzero_weights |= w.weight4 != 0x0;
1767ec681f3Smrg        nonzero_weights |= w.weight5 != 0x0;
1777ec681f3Smrg        nonzero_weights |= w.weight6 != 0x0;
1787ec681f3Smrg        nonzero_weights |= w.weight7 != 0x0;
1797ec681f3Smrg
1807ec681f3Smrg        if (nonzero_weights)
1817ec681f3Smrg                DUMP_UNPACKED(TILER_WEIGHTS, w, "Tiler Weights:\n");
1827ec681f3Smrg}
1837ec681f3Smrg#endif
1847ec681f3Smrg
1857ec681f3Smrg/* Information about the framebuffer passed back for
1867ec681f3Smrg * additional analysis */
1877ec681f3Smrg
1887ec681f3Smrgstruct pandecode_fbd {
1897ec681f3Smrg        unsigned width;
1907ec681f3Smrg        unsigned height;
1917ec681f3Smrg        unsigned rt_count;
1927ec681f3Smrg        bool has_extra;
1937ec681f3Smrg};
1947ec681f3Smrg
1957ec681f3Smrg#if PAN_ARCH == 4
1967ec681f3Smrgstatic struct pandecode_fbd
1977ec681f3Smrgpandecode_sfbd(uint64_t gpu_va, int job_no, bool is_fragment, unsigned gpu_id)
1987ec681f3Smrg{
1997ec681f3Smrg        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
2007ec681f3Smrg        const void *PANDECODE_PTR_VAR(s, mem, (mali_ptr) gpu_va);
2017ec681f3Smrg
2027ec681f3Smrg        struct pandecode_fbd info = {
2037ec681f3Smrg                .has_extra = false,
2047ec681f3Smrg                .rt_count = 1
2057ec681f3Smrg        };
2067ec681f3Smrg
2077ec681f3Smrg        pandecode_log("Framebuffer:\n");
2087ec681f3Smrg        pandecode_indent++;
2097ec681f3Smrg
2107ec681f3Smrg        DUMP_SECTION(FRAMEBUFFER, LOCAL_STORAGE, s, "Local Storage:\n");
2117ec681f3Smrg        pan_section_unpack(s, FRAMEBUFFER, PARAMETERS, p);
2127ec681f3Smrg        DUMP_UNPACKED(FRAMEBUFFER_PARAMETERS, p, "Parameters:\n");
2137ec681f3Smrg
2147ec681f3Smrg        const void *t = pan_section_ptr(s, FRAMEBUFFER, TILER);
2157ec681f3Smrg        const void *w = pan_section_ptr(s, FRAMEBUFFER, TILER_WEIGHTS);
2167ec681f3Smrg
2177ec681f3Smrg        pandecode_midgard_tiler_descriptor(t, w);
2187ec681f3Smrg
2197ec681f3Smrg        pandecode_indent--;
2207ec681f3Smrg
2217ec681f3Smrg        /* Dummy unpack of the padding section to make sure all words are 0.
2227ec681f3Smrg         * No need to call print here since the section is supposed to be empty.
2237ec681f3Smrg         */
2247ec681f3Smrg        pan_section_unpack(s, FRAMEBUFFER, PADDING_1, padding1);
2257ec681f3Smrg        pan_section_unpack(s, FRAMEBUFFER, PADDING_2, padding2);
2267ec681f3Smrg        pandecode_log("\n");
2277ec681f3Smrg
2287ec681f3Smrg        return info;
2297ec681f3Smrg}
2307ec681f3Smrg#endif
2317ec681f3Smrg
2327ec681f3Smrg#if PAN_ARCH >= 5
2337ec681f3Smrgstatic void
2347ec681f3Smrgpandecode_local_storage(uint64_t gpu_va, int job_no)
2357ec681f3Smrg{
2367ec681f3Smrg        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
2377ec681f3Smrg        const struct mali_local_storage_packed *PANDECODE_PTR_VAR(s, mem, (mali_ptr) gpu_va);
2387ec681f3Smrg        DUMP_CL(LOCAL_STORAGE, s, "Local Storage:\n");
2397ec681f3Smrg}
2407ec681f3Smrg
2417ec681f3Smrgstatic void
2427ec681f3Smrgpandecode_render_target(uint64_t gpu_va, unsigned job_no, unsigned gpu_id,
2437ec681f3Smrg                        const struct MALI_FRAMEBUFFER_PARAMETERS *fb)
2447ec681f3Smrg{
2457ec681f3Smrg        pandecode_log("Color Render Targets:\n");
2467ec681f3Smrg        pandecode_indent++;
2477ec681f3Smrg
2487ec681f3Smrg        for (int i = 0; i < (fb->render_target_count); i++) {
2497ec681f3Smrg                mali_ptr rt_va = gpu_va + i * pan_size(RENDER_TARGET);
2507ec681f3Smrg                struct pandecode_mapped_memory *mem =
2517ec681f3Smrg                        pandecode_find_mapped_gpu_mem_containing(rt_va);
2527ec681f3Smrg                const struct mali_render_target_packed *PANDECODE_PTR_VAR(rtp, mem, (mali_ptr) rt_va);
2537ec681f3Smrg                DUMP_CL(RENDER_TARGET, rtp, "Color Render Target %d:\n", i);
2547ec681f3Smrg        }
2557ec681f3Smrg
2567ec681f3Smrg        pandecode_indent--;
2577ec681f3Smrg        pandecode_log("\n");
2587ec681f3Smrg}
2597ec681f3Smrg#endif
2607ec681f3Smrg
2617ec681f3Smrg#if PAN_ARCH >= 6
2627ec681f3Smrgstatic void
2637ec681f3Smrgpandecode_sample_locations(const void *fb, int job_no)
2647ec681f3Smrg{
2657ec681f3Smrg        pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, params);
2667ec681f3Smrg
2677ec681f3Smrg        struct pandecode_mapped_memory *smem =
2687ec681f3Smrg                pandecode_find_mapped_gpu_mem_containing(params.sample_locations);
2697ec681f3Smrg
2707ec681f3Smrg        const u16 *PANDECODE_PTR_VAR(samples, smem, params.sample_locations);
2717ec681f3Smrg
2727ec681f3Smrg        pandecode_log("Sample locations:\n");
2737ec681f3Smrg        for (int i = 0; i < 33; i++) {
2747ec681f3Smrg                pandecode_log("  (%d, %d),\n",
2757ec681f3Smrg                                samples[2 * i] - 128,
2767ec681f3Smrg                                samples[2 * i + 1] - 128);
2777ec681f3Smrg        }
2787ec681f3Smrg}
2797ec681f3Smrg#endif
2807ec681f3Smrg
2817ec681f3Smrgstatic void
2827ec681f3Smrgpandecode_dcd(const struct MALI_DRAW *p,
2837ec681f3Smrg              int job_no, enum mali_job_type job_type,
2847ec681f3Smrg              char *suffix, unsigned gpu_id);
2857ec681f3Smrg
2867ec681f3Smrg#if PAN_ARCH >= 5
2877ec681f3Smrgstatic struct pandecode_fbd
2887ec681f3Smrgpandecode_mfbd_bfr(uint64_t gpu_va, int job_no, bool is_fragment, unsigned gpu_id)
2897ec681f3Smrg{
2907ec681f3Smrg        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
2917ec681f3Smrg        const void *PANDECODE_PTR_VAR(fb, mem, (mali_ptr) gpu_va);
2927ec681f3Smrg        pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, params);
2937ec681f3Smrg
2947ec681f3Smrg        struct pandecode_fbd info;
2957ec681f3Smrg
2967ec681f3Smrg#if PAN_ARCH >= 6
2977ec681f3Smrg        pandecode_sample_locations(fb, job_no);
2987ec681f3Smrg
2997ec681f3Smrg        pan_section_unpack(fb, FRAMEBUFFER, PARAMETERS, bparams);
3007ec681f3Smrg        unsigned dcd_size = pan_size(DRAW);
3017ec681f3Smrg        struct pandecode_mapped_memory *dcdmem =
3027ec681f3Smrg                pandecode_find_mapped_gpu_mem_containing(bparams.frame_shader_dcds);
3037ec681f3Smrg
3047ec681f3Smrg        if (bparams.pre_frame_0 != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
3057ec681f3Smrg                const void *PANDECODE_PTR_VAR(dcd, dcdmem, bparams.frame_shader_dcds + (0 * dcd_size));
3067ec681f3Smrg                pan_unpack(dcd, DRAW, draw);
3077ec681f3Smrg                pandecode_log("Pre frame 0:\n");
3087ec681f3Smrg                pandecode_dcd(&draw, job_no, MALI_JOB_TYPE_FRAGMENT, "", gpu_id);
3097ec681f3Smrg        }
3107ec681f3Smrg
3117ec681f3Smrg        if (bparams.pre_frame_1 != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
3127ec681f3Smrg                const void *PANDECODE_PTR_VAR(dcd, dcdmem, bparams.frame_shader_dcds + (1 * dcd_size));
3137ec681f3Smrg                pan_unpack(dcd, DRAW, draw);
3147ec681f3Smrg                pandecode_log("Pre frame 1:\n");
3157ec681f3Smrg                pandecode_dcd(&draw, job_no, MALI_JOB_TYPE_FRAGMENT, "", gpu_id);
3167ec681f3Smrg        }
3177ec681f3Smrg
3187ec681f3Smrg        if (bparams.post_frame != MALI_PRE_POST_FRAME_SHADER_MODE_NEVER) {
3197ec681f3Smrg                const void *PANDECODE_PTR_VAR(dcd, dcdmem, bparams.frame_shader_dcds + (2 * dcd_size));
3207ec681f3Smrg                pan_unpack(dcd, DRAW, draw);
3217ec681f3Smrg                pandecode_log("Post frame:\n");
3227ec681f3Smrg                pandecode_dcd(&draw, job_no, MALI_JOB_TYPE_FRAGMENT, "", gpu_id);
3237ec681f3Smrg        }
3247ec681f3Smrg#endif
3257ec681f3Smrg
3267ec681f3Smrg        pandecode_log("Multi-Target Framebuffer:\n");
3277ec681f3Smrg        pandecode_indent++;
3287ec681f3Smrg
3297ec681f3Smrg#if PAN_ARCH <= 5
3307ec681f3Smrg        DUMP_SECTION(FRAMEBUFFER, LOCAL_STORAGE, fb, "Local Storage:\n");
3317ec681f3Smrg#endif
3327ec681f3Smrg
3337ec681f3Smrg        info.width = params.width;
3347ec681f3Smrg        info.height = params.height;
3357ec681f3Smrg        info.rt_count = params.render_target_count;
3367ec681f3Smrg        DUMP_UNPACKED(FRAMEBUFFER_PARAMETERS, params, "Parameters:\n");
3377ec681f3Smrg
3387ec681f3Smrg#if PAN_ARCH <= 5
3397ec681f3Smrg        const void *t = pan_section_ptr(fb, FRAMEBUFFER, TILER);
3407ec681f3Smrg        const void *w = pan_section_ptr(fb, FRAMEBUFFER, TILER_WEIGHTS);
3417ec681f3Smrg        pandecode_midgard_tiler_descriptor(t, w);
3427ec681f3Smrg#endif
3437ec681f3Smrg
3447ec681f3Smrg        pandecode_indent--;
3457ec681f3Smrg        pandecode_log("\n");
3467ec681f3Smrg
3477ec681f3Smrg        gpu_va += pan_size(FRAMEBUFFER);
3487ec681f3Smrg
3497ec681f3Smrg        info.has_extra = params.has_zs_crc_extension;
3507ec681f3Smrg
3517ec681f3Smrg        if (info.has_extra) {
3527ec681f3Smrg                struct pandecode_mapped_memory *mem =
3537ec681f3Smrg                        pandecode_find_mapped_gpu_mem_containing(gpu_va);
3547ec681f3Smrg                const struct mali_zs_crc_extension_packed *PANDECODE_PTR_VAR(zs_crc, mem, (mali_ptr)gpu_va);
3557ec681f3Smrg                DUMP_CL(ZS_CRC_EXTENSION, zs_crc, "ZS CRC Extension:\n");
3567ec681f3Smrg                pandecode_log("\n");
3577ec681f3Smrg
3587ec681f3Smrg                gpu_va += pan_size(ZS_CRC_EXTENSION);
3597ec681f3Smrg        }
3607ec681f3Smrg
3617ec681f3Smrg        if (is_fragment)
3627ec681f3Smrg                pandecode_render_target(gpu_va, job_no, gpu_id, &params);
3637ec681f3Smrg
3647ec681f3Smrg        return info;
3657ec681f3Smrg}
3667ec681f3Smrg#endif
3677ec681f3Smrg
3687ec681f3Smrgstatic void
3697ec681f3Smrgpandecode_attributes(const struct pandecode_mapped_memory *mem,
3707ec681f3Smrg                            mali_ptr addr, int job_no, char *suffix,
3717ec681f3Smrg                            int count, bool varying, enum mali_job_type job_type)
3727ec681f3Smrg{
3737ec681f3Smrg        char *prefix = varying ? "Varying" : "Attribute";
3747ec681f3Smrg        assert(addr);
3757ec681f3Smrg
3767ec681f3Smrg        if (!count) {
3777ec681f3Smrg                pandecode_msg("warn: No %s records\n", prefix);
3787ec681f3Smrg                return;
3797ec681f3Smrg        }
3807ec681f3Smrg
3817ec681f3Smrg        MAP_ADDR(ATTRIBUTE_BUFFER, addr, cl);
3827ec681f3Smrg
3837ec681f3Smrg        for (int i = 0; i < count; ++i) {
3847ec681f3Smrg                pan_unpack(cl + i * pan_size(ATTRIBUTE_BUFFER), ATTRIBUTE_BUFFER, temp);
3857ec681f3Smrg                DUMP_UNPACKED(ATTRIBUTE_BUFFER, temp, "%s:\n", prefix);
3867ec681f3Smrg
3877ec681f3Smrg                switch (temp.type) {
3887ec681f3Smrg                case MALI_ATTRIBUTE_TYPE_1D_NPOT_DIVISOR_WRITE_REDUCTION:
3897ec681f3Smrg                case MALI_ATTRIBUTE_TYPE_1D_NPOT_DIVISOR: {
3907ec681f3Smrg                        pan_unpack(cl + (i + 1) * pan_size(ATTRIBUTE_BUFFER),
3917ec681f3Smrg                                   ATTRIBUTE_BUFFER_CONTINUATION_NPOT, temp2);
3927ec681f3Smrg                        pan_print(pandecode_dump_stream, ATTRIBUTE_BUFFER_CONTINUATION_NPOT,
3937ec681f3Smrg                                  temp2, (pandecode_indent + 1) * 2);
3947ec681f3Smrg                        i++;
3957ec681f3Smrg                        break;
3967ec681f3Smrg                }
3977ec681f3Smrg                case MALI_ATTRIBUTE_TYPE_3D_LINEAR:
3987ec681f3Smrg                case MALI_ATTRIBUTE_TYPE_3D_INTERLEAVED: {
3997ec681f3Smrg                        pan_unpack(cl + (i + 1) * pan_size(ATTRIBUTE_BUFFER_CONTINUATION_3D),
4007ec681f3Smrg                                   ATTRIBUTE_BUFFER_CONTINUATION_3D, temp2);
4017ec681f3Smrg                        pan_print(pandecode_dump_stream, ATTRIBUTE_BUFFER_CONTINUATION_3D,
4027ec681f3Smrg                                  temp2, (pandecode_indent + 1) * 2);
4037ec681f3Smrg                        i++;
4047ec681f3Smrg                        break;
4057ec681f3Smrg                }
4067ec681f3Smrg                default:
4077ec681f3Smrg                        break;
4087ec681f3Smrg                }
4097ec681f3Smrg        }
4107ec681f3Smrg        pandecode_log("\n");
4117ec681f3Smrg}
4127ec681f3Smrg
4137ec681f3Smrg#if PAN_ARCH >= 6
4147ec681f3Smrg/* Decodes a Bifrost blend constant. See the notes in bifrost_blend_rt */
4157ec681f3Smrg
4167ec681f3Smrgstatic mali_ptr
4177ec681f3Smrgpandecode_bifrost_blend(void *descs, int job_no, int rt_no, mali_ptr frag_shader)
4187ec681f3Smrg{
4197ec681f3Smrg        pan_unpack(descs + (rt_no * pan_size(BLEND)), BLEND, b);
4207ec681f3Smrg        DUMP_UNPACKED(BLEND, b, "Blend RT %d:\n", rt_no);
4217ec681f3Smrg        if (b.internal.mode != MALI_BLEND_MODE_SHADER)
4227ec681f3Smrg                return 0;
4237ec681f3Smrg
4247ec681f3Smrg        return (frag_shader & 0xFFFFFFFF00000000ULL) | b.internal.shader.pc;
4257ec681f3Smrg}
4267ec681f3Smrg#elif PAN_ARCH == 5
4277ec681f3Smrgstatic mali_ptr
4287ec681f3Smrgpandecode_midgard_blend_mrt(void *descs, int job_no, int rt_no)
4297ec681f3Smrg{
4307ec681f3Smrg        pan_unpack(descs + (rt_no * pan_size(BLEND)), BLEND, b);
4317ec681f3Smrg        DUMP_UNPACKED(BLEND, b, "Blend RT %d:\n", rt_no);
4327ec681f3Smrg        return b.blend_shader ? (b.shader_pc & ~0xf) : 0;
4337ec681f3Smrg}
4347ec681f3Smrg#endif
4357ec681f3Smrg
4367ec681f3Smrgstatic unsigned
4377ec681f3Smrgpandecode_attribute_meta(int count, mali_ptr attribute, bool varying)
4387ec681f3Smrg{
4397ec681f3Smrg        unsigned max = 0;
4407ec681f3Smrg
4417ec681f3Smrg        for (int i = 0; i < count; ++i, attribute += pan_size(ATTRIBUTE)) {
4427ec681f3Smrg                MAP_ADDR(ATTRIBUTE, attribute, cl);
4437ec681f3Smrg                pan_unpack(cl, ATTRIBUTE, a);
4447ec681f3Smrg                DUMP_UNPACKED(ATTRIBUTE, a, "%s:\n", varying ? "Varying" : "Attribute");
4457ec681f3Smrg                max = MAX2(max, a.buffer_index);
4467ec681f3Smrg        }
4477ec681f3Smrg
4487ec681f3Smrg        pandecode_log("\n");
4497ec681f3Smrg        return MIN2(max + 1, 256);
4507ec681f3Smrg}
4517ec681f3Smrg
4527ec681f3Smrg/* return bits [lo, hi) of word */
4537ec681f3Smrgstatic u32
4547ec681f3Smrgbits(u32 word, u32 lo, u32 hi)
4557ec681f3Smrg{
4567ec681f3Smrg        if (hi - lo >= 32)
4577ec681f3Smrg                return word; // avoid undefined behavior with the shift
4587ec681f3Smrg
4597ec681f3Smrg        if (lo >= 32)
4607ec681f3Smrg                return 0;
4617ec681f3Smrg
4627ec681f3Smrg        return (word >> lo) & ((1 << (hi - lo)) - 1);
4637ec681f3Smrg}
4647ec681f3Smrg
4657ec681f3Smrgstatic void
4667ec681f3Smrgpandecode_invocation(const void *i)
4677ec681f3Smrg{
4687ec681f3Smrg        /* Decode invocation_count. See the comment before the definition of
4697ec681f3Smrg         * invocation_count for an explanation.
4707ec681f3Smrg         */
4717ec681f3Smrg        pan_unpack(i, INVOCATION, invocation);
4727ec681f3Smrg
4737ec681f3Smrg        unsigned size_x = bits(invocation.invocations, 0, invocation.size_y_shift) + 1;
4747ec681f3Smrg        unsigned size_y = bits(invocation.invocations, invocation.size_y_shift, invocation.size_z_shift) + 1;
4757ec681f3Smrg        unsigned size_z = bits(invocation.invocations, invocation.size_z_shift, invocation.workgroups_x_shift) + 1;
4767ec681f3Smrg
4777ec681f3Smrg        unsigned groups_x = bits(invocation.invocations, invocation.workgroups_x_shift, invocation.workgroups_y_shift) + 1;
4787ec681f3Smrg        unsigned groups_y = bits(invocation.invocations, invocation.workgroups_y_shift, invocation.workgroups_z_shift) + 1;
4797ec681f3Smrg        unsigned groups_z = bits(invocation.invocations, invocation.workgroups_z_shift, 32) + 1;
4807ec681f3Smrg
4817ec681f3Smrg        pandecode_log("Invocation (%d, %d, %d) x (%d, %d, %d)\n",
4827ec681f3Smrg                      size_x, size_y, size_z,
4837ec681f3Smrg                      groups_x, groups_y, groups_z);
4847ec681f3Smrg
4857ec681f3Smrg        DUMP_UNPACKED(INVOCATION, invocation, "Invocation:\n")
4867ec681f3Smrg}
4877ec681f3Smrg
4887ec681f3Smrgstatic void
4897ec681f3Smrgpandecode_primitive(const void *p)
4907ec681f3Smrg{
4917ec681f3Smrg        pan_unpack(p, PRIMITIVE, primitive);
4927ec681f3Smrg        DUMP_UNPACKED(PRIMITIVE, primitive, "Primitive:\n");
4937ec681f3Smrg
4947ec681f3Smrg        /* Validate an index buffer is present if we need one. TODO: verify
4957ec681f3Smrg         * relationship between invocation_count and index_count */
4967ec681f3Smrg
4977ec681f3Smrg        if (primitive.indices) {
4987ec681f3Smrg                /* Grab the size */
4997ec681f3Smrg                unsigned size = (primitive.index_type == MALI_INDEX_TYPE_UINT32) ?
5007ec681f3Smrg                        sizeof(uint32_t) : primitive.index_type;
5017ec681f3Smrg
5027ec681f3Smrg                /* Ensure we got a size, and if so, validate the index buffer
5037ec681f3Smrg                 * is large enough to hold a full set of indices of the given
5047ec681f3Smrg                 * size */
5057ec681f3Smrg
5067ec681f3Smrg                if (!size)
5077ec681f3Smrg                        pandecode_msg("XXX: index size missing\n");
5087ec681f3Smrg                else
5097ec681f3Smrg                        pandecode_validate_buffer(primitive.indices, primitive.index_count * size);
5107ec681f3Smrg        } else if (primitive.index_type)
5117ec681f3Smrg                pandecode_msg("XXX: unexpected index size\n");
5127ec681f3Smrg}
5137ec681f3Smrg
5147ec681f3Smrgstatic void
5157ec681f3Smrgpandecode_uniform_buffers(mali_ptr pubufs, int ubufs_count, int job_no)
5167ec681f3Smrg{
5177ec681f3Smrg        struct pandecode_mapped_memory *umem = pandecode_find_mapped_gpu_mem_containing(pubufs);
5187ec681f3Smrg        uint64_t *PANDECODE_PTR_VAR(ubufs, umem, pubufs);
5197ec681f3Smrg
5207ec681f3Smrg        for (int i = 0; i < ubufs_count; i++) {
5217ec681f3Smrg                mali_ptr addr = (ubufs[i] >> 10) << 2;
5227ec681f3Smrg                unsigned size = addr ? (((ubufs[i] & ((1 << 10) - 1)) + 1) * 16) : 0;
5237ec681f3Smrg
5247ec681f3Smrg                pandecode_validate_buffer(addr, size);
5257ec681f3Smrg
5267ec681f3Smrg                char *ptr = pointer_as_memory_reference(addr);
5277ec681f3Smrg                pandecode_log("ubuf_%d[%u] = %s;\n", i, size, ptr);
5287ec681f3Smrg                free(ptr);
5297ec681f3Smrg        }
5307ec681f3Smrg
5317ec681f3Smrg        pandecode_log("\n");
5327ec681f3Smrg}
5337ec681f3Smrg
5347ec681f3Smrgstatic void
5357ec681f3Smrgpandecode_uniforms(mali_ptr uniforms, unsigned uniform_count)
5367ec681f3Smrg{
5377ec681f3Smrg        pandecode_validate_buffer(uniforms, uniform_count * 16);
5387ec681f3Smrg
5397ec681f3Smrg        char *ptr = pointer_as_memory_reference(uniforms);
5407ec681f3Smrg        pandecode_log("vec4 uniforms[%u] = %s;\n", uniform_count, ptr);
5417ec681f3Smrg        free(ptr);
5427ec681f3Smrg        pandecode_log("\n");
5437ec681f3Smrg}
5447ec681f3Smrg
5457ec681f3Smrgstatic const char *
5467ec681f3Smrgshader_type_for_job(unsigned type)
5477ec681f3Smrg{
5487ec681f3Smrg        switch (type) {
5497ec681f3Smrg        case MALI_JOB_TYPE_VERTEX:  return "VERTEX";
5507ec681f3Smrg        case MALI_JOB_TYPE_TILER:   return "FRAGMENT";
5517ec681f3Smrg        case MALI_JOB_TYPE_FRAGMENT: return "FRAGMENT";
5527ec681f3Smrg        case MALI_JOB_TYPE_COMPUTE: return "COMPUTE";
5537ec681f3Smrg        default: return "UNKNOWN";
5547ec681f3Smrg        }
5557ec681f3Smrg}
5567ec681f3Smrg
5577ec681f3Smrgstatic unsigned shader_id = 0;
5587ec681f3Smrg
5597ec681f3Smrgstatic struct midgard_disasm_stats
5607ec681f3Smrgpandecode_shader_disassemble(mali_ptr shader_ptr, int shader_no, int type,
5617ec681f3Smrg                             unsigned gpu_id)
5627ec681f3Smrg{
5637ec681f3Smrg        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(shader_ptr);
5647ec681f3Smrg        uint8_t *PANDECODE_PTR_VAR(code, mem, shader_ptr);
5657ec681f3Smrg
5667ec681f3Smrg        /* Compute maximum possible size */
5677ec681f3Smrg        size_t sz = mem->length - (shader_ptr - mem->gpu_va);
5687ec681f3Smrg
5697ec681f3Smrg        /* Print some boilerplate to clearly denote the assembly (which doesn't
5707ec681f3Smrg         * obey indentation rules), and actually do the disassembly! */
5717ec681f3Smrg
5727ec681f3Smrg        pandecode_log_cont("\n\n");
5737ec681f3Smrg
5747ec681f3Smrg        struct midgard_disasm_stats stats;
5757ec681f3Smrg
5767ec681f3Smrg#if PAN_ARCH >= 6
5777ec681f3Smrg        disassemble_bifrost(pandecode_dump_stream, code, sz, true);
5787ec681f3Smrg
5797ec681f3Smrg        /* TODO: Extend stats to Bifrost */
5807ec681f3Smrg        stats.texture_count = -128;
5817ec681f3Smrg        stats.sampler_count = -128;
5827ec681f3Smrg        stats.attribute_count = -128;
5837ec681f3Smrg        stats.varying_count = -128;
5847ec681f3Smrg        stats.uniform_count = -128;
5857ec681f3Smrg        stats.uniform_buffer_count = -128;
5867ec681f3Smrg        stats.work_count = -128;
5877ec681f3Smrg
5887ec681f3Smrg        stats.instruction_count = 0;
5897ec681f3Smrg        stats.bundle_count = 0;
5907ec681f3Smrg        stats.quadword_count = 0;
5917ec681f3Smrg        stats.helper_invocations = false;
5927ec681f3Smrg#else
5937ec681f3Smrg	stats = disassemble_midgard(pandecode_dump_stream,
5947ec681f3Smrg                                    code, sz, gpu_id, true);
5957ec681f3Smrg#endif
5967ec681f3Smrg
5977ec681f3Smrg        unsigned nr_threads =
5987ec681f3Smrg                (stats.work_count <= 4) ? 4 :
5997ec681f3Smrg                (stats.work_count <= 8) ? 2 :
6007ec681f3Smrg                1;
6017ec681f3Smrg
6027ec681f3Smrg        pandecode_log_cont("shader%d - MESA_SHADER_%s shader: "
6037ec681f3Smrg                "%u inst, %u bundles, %u quadwords, "
6047ec681f3Smrg                "%u registers, %u threads, 0 loops, 0:0 spills:fills\n\n\n",
6057ec681f3Smrg                shader_id++,
6067ec681f3Smrg                shader_type_for_job(type),
6077ec681f3Smrg                stats.instruction_count, stats.bundle_count, stats.quadword_count,
6087ec681f3Smrg                stats.work_count, nr_threads);
6097ec681f3Smrg
6107ec681f3Smrg        return stats;
6117ec681f3Smrg}
6127ec681f3Smrg
6137ec681f3Smrgstatic void
6147ec681f3Smrgpandecode_texture_payload(mali_ptr payload,
6157ec681f3Smrg                          enum mali_texture_dimension dim,
6167ec681f3Smrg                          enum mali_texture_layout layout,
6177ec681f3Smrg                          bool manual_stride,
6187ec681f3Smrg                          uint8_t levels,
6197ec681f3Smrg                          uint16_t nr_samples,
6207ec681f3Smrg                          uint16_t array_size,
6217ec681f3Smrg                          struct pandecode_mapped_memory *tmem)
6227ec681f3Smrg{
6237ec681f3Smrg        pandecode_log(".payload = {\n");
6247ec681f3Smrg        pandecode_indent++;
6257ec681f3Smrg
6267ec681f3Smrg        /* A bunch of bitmap pointers follow.
6277ec681f3Smrg         * We work out the correct number,
6287ec681f3Smrg         * based on the mipmap/cubemap
6297ec681f3Smrg         * properties, but dump extra
6307ec681f3Smrg         * possibilities to futureproof */
6317ec681f3Smrg
6327ec681f3Smrg        int bitmap_count = levels;
6337ec681f3Smrg
6347ec681f3Smrg        /* Miptree for each face */
6357ec681f3Smrg        if (dim == MALI_TEXTURE_DIMENSION_CUBE)
6367ec681f3Smrg                bitmap_count *= 6;
6377ec681f3Smrg
6387ec681f3Smrg        /* Array of layers */
6397ec681f3Smrg        bitmap_count *= nr_samples;
6407ec681f3Smrg
6417ec681f3Smrg        /* Array of textures */
6427ec681f3Smrg        bitmap_count *= array_size;
6437ec681f3Smrg
6447ec681f3Smrg        /* Stride for each element */
6457ec681f3Smrg        if (manual_stride)
6467ec681f3Smrg                bitmap_count *= 2;
6477ec681f3Smrg
6487ec681f3Smrg        mali_ptr *pointers_and_strides = pandecode_fetch_gpu_mem(tmem,
6497ec681f3Smrg                payload, sizeof(mali_ptr) * bitmap_count);
6507ec681f3Smrg        for (int i = 0; i < bitmap_count; ++i) {
6517ec681f3Smrg                /* How we dump depends if this is a stride or a pointer */
6527ec681f3Smrg
6537ec681f3Smrg                if (manual_stride && (i & 1)) {
6547ec681f3Smrg                        /* signed 32-bit snuck in as a 64-bit pointer */
6557ec681f3Smrg                        uint64_t stride_set = pointers_and_strides[i];
6567ec681f3Smrg                        int32_t line_stride = stride_set;
6577ec681f3Smrg                        int32_t surface_stride = stride_set >> 32;
6587ec681f3Smrg                        pandecode_log("(mali_ptr) %d /* surface stride */ %d /* line stride */, \n",
6597ec681f3Smrg                                      surface_stride, line_stride);
6607ec681f3Smrg                } else {
6617ec681f3Smrg                        char *a = pointer_as_memory_reference(pointers_and_strides[i]);
6627ec681f3Smrg                        pandecode_log("%s, \n", a);
6637ec681f3Smrg                        free(a);
6647ec681f3Smrg                }
6657ec681f3Smrg        }
6667ec681f3Smrg
6677ec681f3Smrg        pandecode_indent--;
6687ec681f3Smrg        pandecode_log("},\n");
6697ec681f3Smrg}
6707ec681f3Smrg
6717ec681f3Smrg#if PAN_ARCH <= 5
6727ec681f3Smrgstatic void
6737ec681f3Smrgpandecode_texture(mali_ptr u,
6747ec681f3Smrg                struct pandecode_mapped_memory *tmem,
6757ec681f3Smrg                unsigned job_no, unsigned tex)
6767ec681f3Smrg{
6777ec681f3Smrg        struct pandecode_mapped_memory *mapped_mem = pandecode_find_mapped_gpu_mem_containing(u);
6787ec681f3Smrg        const uint8_t *cl = pandecode_fetch_gpu_mem(mapped_mem, u, pan_size(TEXTURE));
6797ec681f3Smrg
6807ec681f3Smrg        pan_unpack(cl, TEXTURE, temp);
6817ec681f3Smrg        DUMP_UNPACKED(TEXTURE, temp, "Texture:\n")
6827ec681f3Smrg
6837ec681f3Smrg        pandecode_indent++;
6847ec681f3Smrg        unsigned nr_samples = temp.dimension == MALI_TEXTURE_DIMENSION_3D ?
6857ec681f3Smrg                              1 : temp.sample_count;
6867ec681f3Smrg        pandecode_texture_payload(u + pan_size(TEXTURE),
6877ec681f3Smrg                        temp.dimension, temp.texel_ordering, temp.manual_stride,
6887ec681f3Smrg                        temp.levels, nr_samples, temp.array_size, mapped_mem);
6897ec681f3Smrg        pandecode_indent--;
6907ec681f3Smrg}
6917ec681f3Smrg#else
6927ec681f3Smrgstatic void
6937ec681f3Smrgpandecode_bifrost_texture(
6947ec681f3Smrg                const void *cl,
6957ec681f3Smrg                unsigned job_no,
6967ec681f3Smrg                unsigned tex)
6977ec681f3Smrg{
6987ec681f3Smrg        pan_unpack(cl, TEXTURE, temp);
6997ec681f3Smrg        DUMP_UNPACKED(TEXTURE, temp, "Texture:\n")
7007ec681f3Smrg
7017ec681f3Smrg        struct pandecode_mapped_memory *tmem = pandecode_find_mapped_gpu_mem_containing(temp.surfaces);
7027ec681f3Smrg        unsigned nr_samples = temp.dimension == MALI_TEXTURE_DIMENSION_3D ?
7037ec681f3Smrg                              1 : temp.sample_count;
7047ec681f3Smrg        pandecode_indent++;
7057ec681f3Smrg        pandecode_texture_payload(temp.surfaces, temp.dimension, temp.texel_ordering,
7067ec681f3Smrg                                  true, temp.levels, nr_samples, temp.array_size, tmem);
7077ec681f3Smrg        pandecode_indent--;
7087ec681f3Smrg}
7097ec681f3Smrg#endif
7107ec681f3Smrg
7117ec681f3Smrgstatic void
7127ec681f3Smrgpandecode_blend_shader_disassemble(mali_ptr shader, int job_no, int job_type,
7137ec681f3Smrg                                   unsigned gpu_id)
7147ec681f3Smrg{
7157ec681f3Smrg        struct midgard_disasm_stats stats =
7167ec681f3Smrg                pandecode_shader_disassemble(shader, job_no, job_type, gpu_id);
7177ec681f3Smrg
7187ec681f3Smrg        bool has_texture = (stats.texture_count > 0);
7197ec681f3Smrg        bool has_sampler = (stats.sampler_count > 0);
7207ec681f3Smrg        bool has_attribute = (stats.attribute_count > 0);
7217ec681f3Smrg        bool has_varying = (stats.varying_count > 0);
7227ec681f3Smrg        bool has_uniform = (stats.uniform_count > 0);
7237ec681f3Smrg        bool has_ubo = (stats.uniform_buffer_count > 0);
7247ec681f3Smrg
7257ec681f3Smrg        if (has_texture || has_sampler)
7267ec681f3Smrg                pandecode_msg("XXX: blend shader accessing textures\n");
7277ec681f3Smrg
7287ec681f3Smrg        if (has_attribute || has_varying)
7297ec681f3Smrg                pandecode_msg("XXX: blend shader accessing interstage\n");
7307ec681f3Smrg
7317ec681f3Smrg        if (has_uniform || has_ubo)
7327ec681f3Smrg                pandecode_msg("XXX: blend shader accessing uniforms\n");
7337ec681f3Smrg}
7347ec681f3Smrg
7357ec681f3Smrgstatic void
7367ec681f3Smrgpandecode_textures(mali_ptr textures, unsigned texture_count, int job_no)
7377ec681f3Smrg{
7387ec681f3Smrg        struct pandecode_mapped_memory *mmem = pandecode_find_mapped_gpu_mem_containing(textures);
7397ec681f3Smrg
7407ec681f3Smrg        if (!mmem)
7417ec681f3Smrg                return;
7427ec681f3Smrg
7437ec681f3Smrg        pandecode_log("Textures %"PRIx64"_%d:\n", textures, job_no);
7447ec681f3Smrg        pandecode_indent++;
7457ec681f3Smrg
7467ec681f3Smrg#if PAN_ARCH >= 6
7477ec681f3Smrg        const void *cl =
7487ec681f3Smrg                pandecode_fetch_gpu_mem(mmem,
7497ec681f3Smrg                                        textures,
7507ec681f3Smrg                                        pan_size(TEXTURE) *
7517ec681f3Smrg                                        texture_count);
7527ec681f3Smrg
7537ec681f3Smrg        for (unsigned tex = 0; tex < texture_count; ++tex) {
7547ec681f3Smrg                pandecode_bifrost_texture(cl + pan_size(TEXTURE) * tex,
7557ec681f3Smrg                                          job_no, tex);
7567ec681f3Smrg        }
7577ec681f3Smrg#else
7587ec681f3Smrg        mali_ptr *PANDECODE_PTR_VAR(u, mmem, textures);
7597ec681f3Smrg
7607ec681f3Smrg        for (int tex = 0; tex < texture_count; ++tex) {
7617ec681f3Smrg                mali_ptr *PANDECODE_PTR_VAR(u, mmem, textures + tex * sizeof(mali_ptr));
7627ec681f3Smrg                char *a = pointer_as_memory_reference(*u);
7637ec681f3Smrg                pandecode_log("%s,\n", a);
7647ec681f3Smrg                free(a);
7657ec681f3Smrg        }
7667ec681f3Smrg
7677ec681f3Smrg        /* Now, finally, descend down into the texture descriptor */
7687ec681f3Smrg        for (unsigned tex = 0; tex < texture_count; ++tex) {
7697ec681f3Smrg                mali_ptr *PANDECODE_PTR_VAR(u, mmem, textures + tex * sizeof(mali_ptr));
7707ec681f3Smrg                struct pandecode_mapped_memory *tmem = pandecode_find_mapped_gpu_mem_containing(*u);
7717ec681f3Smrg                if (tmem)
7727ec681f3Smrg                        pandecode_texture(*u, tmem, job_no, tex);
7737ec681f3Smrg        }
7747ec681f3Smrg#endif
7757ec681f3Smrg        pandecode_indent--;
7767ec681f3Smrg        pandecode_log("\n");
7777ec681f3Smrg}
7787ec681f3Smrg
7797ec681f3Smrgstatic void
7807ec681f3Smrgpandecode_samplers(mali_ptr samplers, unsigned sampler_count, int job_no)
7817ec681f3Smrg{
7827ec681f3Smrg        pandecode_log("Samplers %"PRIx64"_%d:\n", samplers, job_no);
7837ec681f3Smrg        pandecode_indent++;
7847ec681f3Smrg
7857ec681f3Smrg        for (int i = 0; i < sampler_count; ++i)
7867ec681f3Smrg                DUMP_ADDR(SAMPLER, samplers + (pan_size(SAMPLER) * i), "Sampler %d:\n", i);
7877ec681f3Smrg
7887ec681f3Smrg        pandecode_indent--;
7897ec681f3Smrg        pandecode_log("\n");
7907ec681f3Smrg}
7917ec681f3Smrg
7927ec681f3Smrgstatic void
7937ec681f3Smrgpandecode_dcd(const struct MALI_DRAW *p,
7947ec681f3Smrg              int job_no, enum mali_job_type job_type,
7957ec681f3Smrg              char *suffix, unsigned gpu_id)
7967ec681f3Smrg{
7977ec681f3Smrg        struct pandecode_mapped_memory *attr_mem;
7987ec681f3Smrg
7997ec681f3Smrg#if PAN_ARCH >= 5
8007ec681f3Smrg        struct pandecode_fbd fbd_info = {
8017ec681f3Smrg                /* Default for Bifrost */
8027ec681f3Smrg                .rt_count = 1
8037ec681f3Smrg        };
8047ec681f3Smrg#endif
8057ec681f3Smrg
8067ec681f3Smrg#if PAN_ARCH >= 6
8077ec681f3Smrg        pandecode_local_storage(p->thread_storage & ~1, job_no);
8087ec681f3Smrg#elif PAN_ARCH == 5
8097ec681f3Smrg        if (job_type != MALI_JOB_TYPE_TILER) {
8107ec681f3Smrg                pandecode_local_storage(p->thread_storage & ~1, job_no);
8117ec681f3Smrg	} else {
8127ec681f3Smrg                assert(p->fbd & MALI_FBD_TAG_IS_MFBD);
8137ec681f3Smrg                fbd_info = pandecode_mfbd_bfr((u64) ((uintptr_t) p->fbd) & ~MALI_FBD_TAG_MASK,
8147ec681f3Smrg                                              job_no, false, gpu_id);
8157ec681f3Smrg        }
8167ec681f3Smrg#else
8177ec681f3Smrg        pandecode_sfbd((u64) (uintptr_t) p->fbd, job_no, false, gpu_id);
8187ec681f3Smrg#endif
8197ec681f3Smrg
8207ec681f3Smrg        int varying_count = 0, attribute_count = 0, uniform_count = 0, uniform_buffer_count = 0;
8217ec681f3Smrg        int texture_count = 0, sampler_count = 0;
8227ec681f3Smrg
8237ec681f3Smrg        if (p->state) {
8247ec681f3Smrg                struct pandecode_mapped_memory *smem = pandecode_find_mapped_gpu_mem_containing(p->state);
8257ec681f3Smrg                uint32_t *cl = pandecode_fetch_gpu_mem(smem, p->state, pan_size(RENDERER_STATE));
8267ec681f3Smrg
8277ec681f3Smrg                pan_unpack(cl, RENDERER_STATE, state);
8287ec681f3Smrg
8297ec681f3Smrg                if (state.shader.shader & ~0xF)
8307ec681f3Smrg                        pandecode_shader_disassemble(state.shader.shader & ~0xF, job_no, job_type, gpu_id);
8317ec681f3Smrg
8327ec681f3Smrg#if PAN_ARCH >= 6
8337ec681f3Smrg                bool idvs = (job_type == MALI_JOB_TYPE_INDEXED_VERTEX);
8347ec681f3Smrg
8357ec681f3Smrg                if (idvs && state.secondary_shader)
8367ec681f3Smrg                        pandecode_shader_disassemble(state.secondary_shader, job_no, job_type, gpu_id);
8377ec681f3Smrg#endif
8387ec681f3Smrg                DUMP_UNPACKED(RENDERER_STATE, state, "State:\n");
8397ec681f3Smrg                pandecode_indent++;
8407ec681f3Smrg
8417ec681f3Smrg                /* Save for dumps */
8427ec681f3Smrg                attribute_count = state.shader.attribute_count;
8437ec681f3Smrg                varying_count = state.shader.varying_count;
8447ec681f3Smrg                texture_count = state.shader.texture_count;
8457ec681f3Smrg                sampler_count = state.shader.sampler_count;
8467ec681f3Smrg                uniform_buffer_count = state.properties.uniform_buffer_count;
8477ec681f3Smrg
8487ec681f3Smrg#if PAN_ARCH >= 6
8497ec681f3Smrg                uniform_count = state.preload.uniform_count;
8507ec681f3Smrg#else
8517ec681f3Smrg                uniform_count = state.properties.uniform_count;
8527ec681f3Smrg#endif
8537ec681f3Smrg
8547ec681f3Smrg#if PAN_ARCH >= 6
8557ec681f3Smrg                DUMP_UNPACKED(PRELOAD, state.preload, "Preload:\n");
8567ec681f3Smrg#elif PAN_ARCH == 4
8577ec681f3Smrg                mali_ptr shader = state.blend_shader & ~0xF;
8587ec681f3Smrg                if (state.multisample_misc.blend_shader && shader)
8597ec681f3Smrg                        pandecode_blend_shader_disassemble(shader, job_no, job_type, gpu_id);
8607ec681f3Smrg#endif
8617ec681f3Smrg                pandecode_indent--;
8627ec681f3Smrg                pandecode_log("\n");
8637ec681f3Smrg
8647ec681f3Smrg                /* MRT blend fields are used whenever MFBD is used, with
8657ec681f3Smrg                 * per-RT descriptors */
8667ec681f3Smrg
8677ec681f3Smrg#if PAN_ARCH >= 5
8687ec681f3Smrg                if ((job_type == MALI_JOB_TYPE_TILER || job_type == MALI_JOB_TYPE_FRAGMENT) &&
8697ec681f3Smrg                    (PAN_ARCH >= 6 || p->thread_storage & MALI_FBD_TAG_IS_MFBD)) {
8707ec681f3Smrg                        void* blend_base = ((void *) cl) + pan_size(RENDERER_STATE);
8717ec681f3Smrg
8727ec681f3Smrg                        for (unsigned i = 0; i < fbd_info.rt_count; i++) {
8737ec681f3Smrg                                mali_ptr shader = 0;
8747ec681f3Smrg
8757ec681f3Smrg#if PAN_ARCH >= 6
8767ec681f3Smrg                                shader = pandecode_bifrost_blend(blend_base, job_no, i,
8777ec681f3Smrg                                                                 state.shader.shader);
8787ec681f3Smrg#else
8797ec681f3Smrg                                shader = pandecode_midgard_blend_mrt(blend_base, job_no, i);
8807ec681f3Smrg#endif
8817ec681f3Smrg                                if (shader & ~0xF)
8827ec681f3Smrg                                        pandecode_blend_shader_disassemble(shader, job_no, job_type,
8837ec681f3Smrg                                                                           gpu_id);
8847ec681f3Smrg                        }
8857ec681f3Smrg                }
8867ec681f3Smrg#endif
8877ec681f3Smrg        } else
8887ec681f3Smrg                pandecode_msg("XXX: missing shader descriptor\n");
8897ec681f3Smrg
8907ec681f3Smrg        if (p->viewport) {
8917ec681f3Smrg                DUMP_ADDR(VIEWPORT, p->viewport, "Viewport:\n");
8927ec681f3Smrg                pandecode_log("\n");
8937ec681f3Smrg        }
8947ec681f3Smrg
8957ec681f3Smrg        unsigned max_attr_index = 0;
8967ec681f3Smrg
8977ec681f3Smrg        if (p->attributes)
8987ec681f3Smrg                max_attr_index = pandecode_attribute_meta(attribute_count, p->attributes, false);
8997ec681f3Smrg
9007ec681f3Smrg        if (p->attribute_buffers) {
9017ec681f3Smrg                attr_mem = pandecode_find_mapped_gpu_mem_containing(p->attribute_buffers);
9027ec681f3Smrg                pandecode_attributes(attr_mem, p->attribute_buffers, job_no, suffix, max_attr_index, false, job_type);
9037ec681f3Smrg        }
9047ec681f3Smrg
9057ec681f3Smrg        if (p->varyings) {
9067ec681f3Smrg                varying_count = pandecode_attribute_meta(varying_count, p->varyings, true);
9077ec681f3Smrg        }
9087ec681f3Smrg
9097ec681f3Smrg        if (p->varying_buffers) {
9107ec681f3Smrg                attr_mem = pandecode_find_mapped_gpu_mem_containing(p->varying_buffers);
9117ec681f3Smrg                pandecode_attributes(attr_mem, p->varying_buffers, job_no, suffix, varying_count, true, job_type);
9127ec681f3Smrg        }
9137ec681f3Smrg
9147ec681f3Smrg        if (p->uniform_buffers) {
9157ec681f3Smrg                if (uniform_buffer_count)
9167ec681f3Smrg                        pandecode_uniform_buffers(p->uniform_buffers, uniform_buffer_count, job_no);
9177ec681f3Smrg                else
9187ec681f3Smrg                        pandecode_msg("warn: UBOs specified but not referenced\n");
9197ec681f3Smrg        } else if (uniform_buffer_count)
9207ec681f3Smrg                pandecode_msg("XXX: UBOs referenced but not specified\n");
9217ec681f3Smrg
9227ec681f3Smrg        /* We don't want to actually dump uniforms, but we do need to validate
9237ec681f3Smrg         * that the counts we were given are sane */
9247ec681f3Smrg
9257ec681f3Smrg        if (p->push_uniforms) {
9267ec681f3Smrg                if (uniform_count)
9277ec681f3Smrg                        pandecode_uniforms(p->push_uniforms, uniform_count);
9287ec681f3Smrg                else
9297ec681f3Smrg                        pandecode_msg("warn: Uniforms specified but not referenced\n");
9307ec681f3Smrg        } else if (uniform_count)
9317ec681f3Smrg                pandecode_msg("XXX: Uniforms referenced but not specified\n");
9327ec681f3Smrg
9337ec681f3Smrg        if (p->textures)
9347ec681f3Smrg                pandecode_textures(p->textures, texture_count, job_no);
9357ec681f3Smrg
9367ec681f3Smrg        if (p->samplers)
9377ec681f3Smrg                pandecode_samplers(p->samplers, sampler_count, job_no);
9387ec681f3Smrg}
9397ec681f3Smrg
9407ec681f3Smrgstatic void
9417ec681f3Smrgpandecode_primitive_size(const void *s, bool constant)
9427ec681f3Smrg{
9437ec681f3Smrg        pan_unpack(s, PRIMITIVE_SIZE, ps);
9447ec681f3Smrg        if (ps.size_array == 0x0)
9457ec681f3Smrg                return;
9467ec681f3Smrg
9477ec681f3Smrg        DUMP_UNPACKED(PRIMITIVE_SIZE, ps, "Primitive Size:\n")
9487ec681f3Smrg}
9497ec681f3Smrg
9507ec681f3Smrgstatic void
9517ec681f3Smrgpandecode_vertex_compute_geometry_job(const struct MALI_JOB_HEADER *h,
9527ec681f3Smrg                                      const struct pandecode_mapped_memory *mem,
9537ec681f3Smrg                                      mali_ptr job, int job_no, unsigned gpu_id)
9547ec681f3Smrg{
9557ec681f3Smrg        struct mali_compute_job_packed *PANDECODE_PTR_VAR(p, mem, job);
9567ec681f3Smrg        pan_section_unpack(p, COMPUTE_JOB, DRAW, draw);
9577ec681f3Smrg        pandecode_dcd(&draw, job_no, h->type, "", gpu_id);
9587ec681f3Smrg
9597ec681f3Smrg        pandecode_log("Vertex Job Payload:\n");
9607ec681f3Smrg        pandecode_indent++;
9617ec681f3Smrg        pandecode_invocation(pan_section_ptr(p, COMPUTE_JOB, INVOCATION));
9627ec681f3Smrg        DUMP_SECTION(COMPUTE_JOB, PARAMETERS, p, "Vertex Job Parameters:\n");
9637ec681f3Smrg        DUMP_UNPACKED(DRAW, draw, "Draw:\n");
9647ec681f3Smrg        pandecode_indent--;
9657ec681f3Smrg        pandecode_log("\n");
9667ec681f3Smrg}
9677ec681f3Smrg
9687ec681f3Smrg#if PAN_ARCH >= 6
9697ec681f3Smrgstatic void
9707ec681f3Smrgpandecode_bifrost_tiler_heap(mali_ptr gpu_va, int job_no)
9717ec681f3Smrg{
9727ec681f3Smrg        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
9737ec681f3Smrg        pan_unpack(PANDECODE_PTR(mem, gpu_va, void), TILER_HEAP, h);
9747ec681f3Smrg        DUMP_UNPACKED(TILER_HEAP, h, "Bifrost Tiler Heap:\n");
9757ec681f3Smrg}
9767ec681f3Smrg
9777ec681f3Smrgstatic void
9787ec681f3Smrgpandecode_bifrost_tiler(mali_ptr gpu_va, int job_no)
9797ec681f3Smrg{
9807ec681f3Smrg        struct pandecode_mapped_memory *mem = pandecode_find_mapped_gpu_mem_containing(gpu_va);
9817ec681f3Smrg        pan_unpack(PANDECODE_PTR(mem, gpu_va, void), TILER_CONTEXT, t);
9827ec681f3Smrg
9837ec681f3Smrg        pandecode_bifrost_tiler_heap(t.heap, job_no);
9847ec681f3Smrg
9857ec681f3Smrg        DUMP_UNPACKED(TILER_CONTEXT, t, "Bifrost Tiler:\n");
9867ec681f3Smrg        pandecode_indent++;
9877ec681f3Smrg        if (t.hierarchy_mask != 0xa &&
9887ec681f3Smrg            t.hierarchy_mask != 0x14 &&
9897ec681f3Smrg            t.hierarchy_mask != 0x28 &&
9907ec681f3Smrg            t.hierarchy_mask != 0x50 &&
9917ec681f3Smrg            t.hierarchy_mask != 0xa0)
9927ec681f3Smrg                pandecode_msg("XXX: Unexpected hierarchy_mask (not 0xa, 0x14, 0x28, 0x50 or 0xa0)!");
9937ec681f3Smrg
9947ec681f3Smrg        pandecode_indent--;
9957ec681f3Smrg}
9967ec681f3Smrg
9977ec681f3Smrgstatic void
9987ec681f3Smrgpandecode_indexed_vertex_job(const struct MALI_JOB_HEADER *h,
9997ec681f3Smrg                             const struct pandecode_mapped_memory *mem,
10007ec681f3Smrg                             mali_ptr job, int job_no, unsigned gpu_id)
10017ec681f3Smrg{
10027ec681f3Smrg        struct mali_indexed_vertex_job_packed *PANDECODE_PTR_VAR(p, mem, job);
10037ec681f3Smrg
10047ec681f3Smrg        pandecode_log("Vertex:\n");
10057ec681f3Smrg        pan_section_unpack(p, INDEXED_VERTEX_JOB, VERTEX_DRAW, vert_draw);
10067ec681f3Smrg        pandecode_dcd(&vert_draw, job_no, h->type, "", gpu_id);
10077ec681f3Smrg        DUMP_UNPACKED(DRAW, vert_draw, "Vertex Draw:\n");
10087ec681f3Smrg
10097ec681f3Smrg        pandecode_log("Fragment:\n");
10107ec681f3Smrg        pan_section_unpack(p, INDEXED_VERTEX_JOB, FRAGMENT_DRAW, frag_draw);
10117ec681f3Smrg        pandecode_dcd(&frag_draw, job_no, MALI_JOB_TYPE_FRAGMENT, "", gpu_id);
10127ec681f3Smrg        DUMP_UNPACKED(DRAW, frag_draw, "Fragment Draw:\n");
10137ec681f3Smrg
10147ec681f3Smrg        pan_section_unpack(p, INDEXED_VERTEX_JOB, TILER, tiler_ptr);
10157ec681f3Smrg        pandecode_log("Tiler Job Payload:\n");
10167ec681f3Smrg        pandecode_indent++;
10177ec681f3Smrg        pandecode_bifrost_tiler(tiler_ptr.address, job_no);
10187ec681f3Smrg        pandecode_indent--;
10197ec681f3Smrg
10207ec681f3Smrg        pandecode_invocation(pan_section_ptr(p, INDEXED_VERTEX_JOB, INVOCATION));
10217ec681f3Smrg        pandecode_primitive(pan_section_ptr(p, INDEXED_VERTEX_JOB, PRIMITIVE));
10227ec681f3Smrg
10237ec681f3Smrg        /* TODO: gl_PointSize on Bifrost */
10247ec681f3Smrg        pandecode_primitive_size(pan_section_ptr(p, INDEXED_VERTEX_JOB, PRIMITIVE_SIZE), true);
10257ec681f3Smrg
10267ec681f3Smrg        pan_section_unpack(p, INDEXED_VERTEX_JOB, PADDING, padding);
10277ec681f3Smrg}
10287ec681f3Smrg
10297ec681f3Smrgstatic void
10307ec681f3Smrgpandecode_tiler_job_bfr(const struct MALI_JOB_HEADER *h,
10317ec681f3Smrg                        const struct pandecode_mapped_memory *mem,
10327ec681f3Smrg                        mali_ptr job, int job_no, unsigned gpu_id)
10337ec681f3Smrg{
10347ec681f3Smrg        struct mali_tiler_job_packed *PANDECODE_PTR_VAR(p, mem, job);
10357ec681f3Smrg        pan_section_unpack(p, TILER_JOB, DRAW, draw);
10367ec681f3Smrg        pan_section_unpack(p, TILER_JOB, TILER, tiler_ptr);
10377ec681f3Smrg        pandecode_dcd(&draw, job_no, h->type, "", gpu_id);
10387ec681f3Smrg
10397ec681f3Smrg        pandecode_log("Tiler Job Payload:\n");
10407ec681f3Smrg        pandecode_indent++;
10417ec681f3Smrg        pandecode_bifrost_tiler(tiler_ptr.address, job_no);
10427ec681f3Smrg
10437ec681f3Smrg        pandecode_invocation(pan_section_ptr(p, TILER_JOB, INVOCATION));
10447ec681f3Smrg        pandecode_primitive(pan_section_ptr(p, TILER_JOB, PRIMITIVE));
10457ec681f3Smrg
10467ec681f3Smrg        /* TODO: gl_PointSize on Bifrost */
10477ec681f3Smrg        pandecode_primitive_size(pan_section_ptr(p, TILER_JOB, PRIMITIVE_SIZE), true);
10487ec681f3Smrg        pan_section_unpack(p, TILER_JOB, PADDING, padding);
10497ec681f3Smrg        DUMP_UNPACKED(DRAW, draw, "Draw:\n");
10507ec681f3Smrg        pandecode_indent--;
10517ec681f3Smrg        pandecode_log("\n");
10527ec681f3Smrg}
10537ec681f3Smrg#else
10547ec681f3Smrgstatic void
10557ec681f3Smrgpandecode_tiler_job_mdg(const struct MALI_JOB_HEADER *h,
10567ec681f3Smrg                        const struct pandecode_mapped_memory *mem,
10577ec681f3Smrg                        mali_ptr job, int job_no, unsigned gpu_id)
10587ec681f3Smrg{
10597ec681f3Smrg        struct mali_tiler_job_packed *PANDECODE_PTR_VAR(p, mem, job);
10607ec681f3Smrg        pan_section_unpack(p, TILER_JOB, DRAW, draw);
10617ec681f3Smrg        pandecode_dcd(&draw, job_no, h->type, "", gpu_id);
10627ec681f3Smrg
10637ec681f3Smrg        pandecode_log("Tiler Job Payload:\n");
10647ec681f3Smrg        pandecode_indent++;
10657ec681f3Smrg        pandecode_invocation(pan_section_ptr(p, TILER_JOB, INVOCATION));
10667ec681f3Smrg        pandecode_primitive(pan_section_ptr(p, TILER_JOB, PRIMITIVE));
10677ec681f3Smrg        DUMP_UNPACKED(DRAW, draw, "Draw:\n");
10687ec681f3Smrg
10697ec681f3Smrg        pan_section_unpack(p, TILER_JOB, PRIMITIVE, primitive);
10707ec681f3Smrg        pandecode_primitive_size(pan_section_ptr(p, TILER_JOB, PRIMITIVE_SIZE),
10717ec681f3Smrg                                 primitive.point_size_array_format == MALI_POINT_SIZE_ARRAY_FORMAT_NONE);
10727ec681f3Smrg        pandecode_indent--;
10737ec681f3Smrg        pandecode_log("\n");
10747ec681f3Smrg}
10757ec681f3Smrg#endif
10767ec681f3Smrg
10777ec681f3Smrgstatic void
10787ec681f3Smrgpandecode_fragment_job(const struct pandecode_mapped_memory *mem,
10797ec681f3Smrg                       mali_ptr job, int job_no, unsigned gpu_id)
10807ec681f3Smrg{
10817ec681f3Smrg        struct mali_fragment_job_packed *PANDECODE_PTR_VAR(p, mem, job);
10827ec681f3Smrg        pan_section_unpack(p, FRAGMENT_JOB, PAYLOAD, s);
10837ec681f3Smrg
10847ec681f3Smrg
10857ec681f3Smrg#if PAN_ARCH == 4
10867ec681f3Smrg        pandecode_sfbd(s.framebuffer, job_no, true, gpu_id);
10877ec681f3Smrg#else
10887ec681f3Smrg        assert(s.framebuffer & MALI_FBD_TAG_IS_MFBD);
10897ec681f3Smrg
10907ec681f3Smrg        struct pandecode_fbd info;
10917ec681f3Smrg
10927ec681f3Smrg        info = pandecode_mfbd_bfr(s.framebuffer & ~MALI_FBD_TAG_MASK, job_no,
10937ec681f3Smrg                                  true, gpu_id);
10947ec681f3Smrg#endif
10957ec681f3Smrg
10967ec681f3Smrg#if PAN_ARCH >= 5
10977ec681f3Smrg        unsigned expected_tag = 0;
10987ec681f3Smrg
10997ec681f3Smrg        /* Compute the tag for the tagged pointer. This contains the type of
11007ec681f3Smrg         * FBD (MFBD/SFBD), and in the case of an MFBD, information about which
11017ec681f3Smrg         * additional structures follow the MFBD header (an extra payload or
11027ec681f3Smrg         * not, as well as a count of render targets) */
11037ec681f3Smrg
11047ec681f3Smrg        expected_tag = MALI_FBD_TAG_IS_MFBD;
11057ec681f3Smrg        if (info.has_extra)
11067ec681f3Smrg                expected_tag |= MALI_FBD_TAG_HAS_ZS_RT;
11077ec681f3Smrg
11087ec681f3Smrg        expected_tag |= MALI_FBD_TAG_IS_MFBD | (MALI_POSITIVE(info.rt_count) << 2);
11097ec681f3Smrg#endif
11107ec681f3Smrg
11117ec681f3Smrg        DUMP_UNPACKED(FRAGMENT_JOB_PAYLOAD, s, "Fragment Job Payload:\n");
11127ec681f3Smrg
11137ec681f3Smrg#if PAN_ARCH >= 5
11147ec681f3Smrg        /* The FBD is a tagged pointer */
11157ec681f3Smrg
11167ec681f3Smrg        unsigned tag = (s.framebuffer & MALI_FBD_TAG_MASK);
11177ec681f3Smrg
11187ec681f3Smrg        if (tag != expected_tag)
11197ec681f3Smrg                pandecode_msg("XXX: expected FBD tag %X but got %X\n", expected_tag, tag);
11207ec681f3Smrg#endif
11217ec681f3Smrg
11227ec681f3Smrg        pandecode_log("\n");
11237ec681f3Smrg}
11247ec681f3Smrg
11257ec681f3Smrgstatic void
11267ec681f3Smrgpandecode_write_value_job(const struct pandecode_mapped_memory *mem,
11277ec681f3Smrg                          mali_ptr job, int job_no)
11287ec681f3Smrg{
11297ec681f3Smrg        struct mali_write_value_job_packed *PANDECODE_PTR_VAR(p, mem, job);
11307ec681f3Smrg        pan_section_unpack(p, WRITE_VALUE_JOB, PAYLOAD, u);
11317ec681f3Smrg        DUMP_SECTION(WRITE_VALUE_JOB, PAYLOAD, p, "Write Value Payload:\n");
11327ec681f3Smrg        pandecode_log("\n");
11337ec681f3Smrg}
11347ec681f3Smrg
11357ec681f3Smrgstatic void
11367ec681f3Smrgpandecode_cache_flush_job(const struct pandecode_mapped_memory *mem,
11377ec681f3Smrg                          mali_ptr job, int job_no)
11387ec681f3Smrg{
11397ec681f3Smrg        struct mali_cache_flush_job_packed *PANDECODE_PTR_VAR(p, mem, job);
11407ec681f3Smrg        pan_section_unpack(p, CACHE_FLUSH_JOB, PAYLOAD, u);
11417ec681f3Smrg        DUMP_SECTION(CACHE_FLUSH_JOB, PAYLOAD, p, "Cache Flush Payload:\n");
11427ec681f3Smrg        pandecode_log("\n");
11437ec681f3Smrg}
11447ec681f3Smrg
11457ec681f3Smrg/* Entrypoint to start tracing. jc_gpu_va is the GPU address for the first job
11467ec681f3Smrg * in the chain; later jobs are found by walking the chain. Bifrost is, well,
11477ec681f3Smrg * if it's bifrost or not. GPU ID is the more finegrained ID (at some point, we
11487ec681f3Smrg * might wish to combine this with the bifrost parameter) because some details
11497ec681f3Smrg * are model-specific even within a particular architecture. */
11507ec681f3Smrg
11517ec681f3Smrgvoid
11527ec681f3SmrgGENX(pandecode_jc)(mali_ptr jc_gpu_va, unsigned gpu_id)
11537ec681f3Smrg{
11547ec681f3Smrg        pandecode_dump_file_open();
11557ec681f3Smrg
11567ec681f3Smrg        unsigned job_descriptor_number = 0;
11577ec681f3Smrg        mali_ptr next_job = 0;
11587ec681f3Smrg
11597ec681f3Smrg        do {
11607ec681f3Smrg                struct pandecode_mapped_memory *mem =
11617ec681f3Smrg                        pandecode_find_mapped_gpu_mem_containing(jc_gpu_va);
11627ec681f3Smrg
11637ec681f3Smrg                pan_unpack(PANDECODE_PTR(mem, jc_gpu_va, struct mali_job_header_packed),
11647ec681f3Smrg                           JOB_HEADER, h);
11657ec681f3Smrg                next_job = h.next;
11667ec681f3Smrg
11677ec681f3Smrg                int job_no = job_descriptor_number++;
11687ec681f3Smrg
11697ec681f3Smrg                DUMP_UNPACKED(JOB_HEADER, h, "Job Header:\n");
11707ec681f3Smrg                pandecode_log("\n");
11717ec681f3Smrg
11727ec681f3Smrg                switch (h.type) {
11737ec681f3Smrg                case MALI_JOB_TYPE_WRITE_VALUE:
11747ec681f3Smrg                        pandecode_write_value_job(mem, jc_gpu_va, job_no);
11757ec681f3Smrg                        break;
11767ec681f3Smrg
11777ec681f3Smrg                case MALI_JOB_TYPE_CACHE_FLUSH:
11787ec681f3Smrg                        pandecode_cache_flush_job(mem, jc_gpu_va, job_no);
11797ec681f3Smrg                        break;
11807ec681f3Smrg
11817ec681f3Smrg                case MALI_JOB_TYPE_TILER:
11827ec681f3Smrg#if PAN_ARCH >= 6
11837ec681f3Smrg                        pandecode_tiler_job_bfr(&h, mem, jc_gpu_va, job_no, gpu_id);
11847ec681f3Smrg#else
11857ec681f3Smrg                        pandecode_tiler_job_mdg(&h, mem, jc_gpu_va, job_no, gpu_id);
11867ec681f3Smrg#endif
11877ec681f3Smrg                        break;
11887ec681f3Smrg
11897ec681f3Smrg                case MALI_JOB_TYPE_VERTEX:
11907ec681f3Smrg                case MALI_JOB_TYPE_COMPUTE:
11917ec681f3Smrg                        pandecode_vertex_compute_geometry_job(&h, mem, jc_gpu_va, job_no, gpu_id);
11927ec681f3Smrg                        break;
11937ec681f3Smrg
11947ec681f3Smrg#if PAN_ARCH >= 6
11957ec681f3Smrg                case MALI_JOB_TYPE_INDEXED_VERTEX:
11967ec681f3Smrg                        pandecode_indexed_vertex_job(&h, mem, jc_gpu_va, job_no, gpu_id);
11977ec681f3Smrg                        break;
11987ec681f3Smrg#endif
11997ec681f3Smrg
12007ec681f3Smrg                case MALI_JOB_TYPE_FRAGMENT:
12017ec681f3Smrg                        pandecode_fragment_job(mem, jc_gpu_va, job_no, gpu_id);
12027ec681f3Smrg                        break;
12037ec681f3Smrg
12047ec681f3Smrg                default:
12057ec681f3Smrg                        break;
12067ec681f3Smrg                }
12077ec681f3Smrg        } while ((jc_gpu_va = next_job));
12087ec681f3Smrg
12097ec681f3Smrg        fflush(pandecode_dump_stream);
12107ec681f3Smrg        pandecode_map_read_write();
12117ec681f3Smrg}
12127ec681f3Smrg
12137ec681f3Smrgvoid
12147ec681f3SmrgGENX(pandecode_abort_on_fault)(mali_ptr jc_gpu_va)
12157ec681f3Smrg{
12167ec681f3Smrg        mali_ptr next_job = 0;
12177ec681f3Smrg
12187ec681f3Smrg        do {
12197ec681f3Smrg                struct pandecode_mapped_memory *mem =
12207ec681f3Smrg                        pandecode_find_mapped_gpu_mem_containing(jc_gpu_va);
12217ec681f3Smrg
12227ec681f3Smrg                pan_unpack(PANDECODE_PTR(mem, jc_gpu_va, struct mali_job_header_packed),
12237ec681f3Smrg                           JOB_HEADER, h);
12247ec681f3Smrg                next_job = h.next;
12257ec681f3Smrg
12267ec681f3Smrg                /* Ensure the job is marked COMPLETE */
12277ec681f3Smrg                if (h.exception_status != 0x1) {
12287ec681f3Smrg                        fprintf(stderr, "Incomplete job or timeout");
12297ec681f3Smrg                        abort();
12307ec681f3Smrg                }
12317ec681f3Smrg        } while ((jc_gpu_va = next_job));
12327ec681f3Smrg
12337ec681f3Smrg        pandecode_map_read_write();
12347ec681f3Smrg}
1235