101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2016-2018 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg * 2301e04c3fSmrg */ 2401e04c3fSmrg 2501e04c3fSmrg#include <stdio.h> 2601e04c3fSmrg#include <stdlib.h> 2701e04c3fSmrg#include <string.h> 2801e04c3fSmrg#include <stdarg.h> 2901e04c3fSmrg 307ec681f3Smrg#include "common/intel_gem.h" 3101e04c3fSmrg#include "util/macros.h" 3201e04c3fSmrg 3301e04c3fSmrg#include "aub_read.h" 347ec681f3Smrg#include "intel_context.h" 3501e04c3fSmrg#include "intel_aub.h" 3601e04c3fSmrg 3701e04c3fSmrg#define TYPE(dw) (((dw) >> 29) & 7) 3801e04c3fSmrg#define OPCODE(dw) (((dw) >> 23) & 0x3f) 3901e04c3fSmrg#define SUBOPCODE(dw) (((dw) >> 16) & 0x7f) 4001e04c3fSmrg 4101e04c3fSmrg#define MAKE_HEADER(type, opcode, subopcode) \ 427ec681f3Smrg ((((unsigned) (type)) << 29) | ((opcode) << 23) | ((subopcode) << 16)) 4301e04c3fSmrg 4401e04c3fSmrg#define TYPE_AUB 0x7 4501e04c3fSmrg 4601e04c3fSmrg/* Classic AUB opcodes */ 4701e04c3fSmrg#define OPCODE_AUB 0x01 4801e04c3fSmrg#define SUBOPCODE_HEADER 0x05 4901e04c3fSmrg#define SUBOPCODE_BLOCK 0x41 5001e04c3fSmrg#define SUBOPCODE_BMP 0x1e 5101e04c3fSmrg 5201e04c3fSmrg/* Newer version AUB opcode */ 5301e04c3fSmrg#define OPCODE_NEW_AUB 0x2e 5401e04c3fSmrg#define SUBOPCODE_REG_POLL 0x02 5501e04c3fSmrg#define SUBOPCODE_REG_WRITE 0x03 5601e04c3fSmrg#define SUBOPCODE_MEM_POLL 0x05 5701e04c3fSmrg#define SUBOPCODE_MEM_WRITE 0x06 5801e04c3fSmrg#define SUBOPCODE_VERSION 0x0e 5901e04c3fSmrg 607ec681f3Smrgstatic PRINTFLIKE(3, 4) void 6101e04c3fSmrgparse_error(struct aub_read *read, const uint32_t *p, const char *fmt, ...) 6201e04c3fSmrg{ 6301e04c3fSmrg if (!read->error) 6401e04c3fSmrg return; 6501e04c3fSmrg 6601e04c3fSmrg va_list ap; 6701e04c3fSmrg va_start(ap, fmt); 6801e04c3fSmrg 6901e04c3fSmrg char msg[80]; 7001e04c3fSmrg vsnprintf(msg, sizeof(msg), fmt, ap); 7101e04c3fSmrg read->error(read->user_data, p, msg); 7201e04c3fSmrg 7301e04c3fSmrg va_end(ap); 7401e04c3fSmrg} 7501e04c3fSmrg 7601e04c3fSmrgstatic bool 7701e04c3fSmrghandle_trace_header(struct aub_read *read, const uint32_t *p) 7801e04c3fSmrg{ 7901e04c3fSmrg /* The intel_aubdump tool from IGT is kind enough to put a PCI-ID= tag in 8001e04c3fSmrg * the AUB header comment. If the user hasn't specified a hardware 8101e04c3fSmrg * generation, try to use the one from the AUB file. 8201e04c3fSmrg */ 8301e04c3fSmrg const uint32_t *end = p + (p[0] & 0xffff) + 2; 8401e04c3fSmrg int aub_pci_id = 0; 8501e04c3fSmrg 8601e04c3fSmrg if (end > &p[12] && p[12] > 0) { 8701e04c3fSmrg if (sscanf((char *)&p[13], "PCI-ID=%i", &aub_pci_id) > 0) { 887ec681f3Smrg if (!intel_get_device_info_from_pci_id(aub_pci_id, &read->devinfo)) { 8901e04c3fSmrg parse_error(read, p, 9001e04c3fSmrg "can't find device information: pci_id=0x%x\n", aub_pci_id); 9101e04c3fSmrg return false; 9201e04c3fSmrg } 9301e04c3fSmrg } 9401e04c3fSmrg } 9501e04c3fSmrg 9601e04c3fSmrg char app_name[33]; 9701e04c3fSmrg strncpy(app_name, (const char *)&p[2], 32); 9801e04c3fSmrg app_name[32] = 0; 9901e04c3fSmrg 10001e04c3fSmrg if (read->info) 10101e04c3fSmrg read->info(read->user_data, aub_pci_id, app_name); 10201e04c3fSmrg 10301e04c3fSmrg return true; 10401e04c3fSmrg} 10501e04c3fSmrg 10601e04c3fSmrgstatic bool 10701e04c3fSmrghandle_memtrace_version(struct aub_read *read, const uint32_t *p) 10801e04c3fSmrg{ 10901e04c3fSmrg int header_length = p[0] & 0xffff; 11001e04c3fSmrg char app_name[64]; 11101e04c3fSmrg int app_name_len = MIN2(4 * (header_length + 1 - 5), ARRAY_SIZE(app_name) - 1); 11201e04c3fSmrg int pci_id_len = 0; 11301e04c3fSmrg int aub_pci_id = 0; 11401e04c3fSmrg 11501e04c3fSmrg strncpy(app_name, (const char *)&p[5], app_name_len); 11601e04c3fSmrg app_name[app_name_len] = 0; 11701e04c3fSmrg 11801e04c3fSmrg if (sscanf(app_name, "PCI-ID=%i %n", &aub_pci_id, &pci_id_len) > 0) { 1197ec681f3Smrg if (!intel_get_device_info_from_pci_id(aub_pci_id, &read->devinfo)) { 12001e04c3fSmrg parse_error(read, p, "can't find device information: pci_id=0x%x\n", aub_pci_id); 12101e04c3fSmrg return false; 12201e04c3fSmrg } 12301e04c3fSmrg 12401e04c3fSmrg if (read->info) 12501e04c3fSmrg read->info(read->user_data, aub_pci_id, app_name + pci_id_len); 12601e04c3fSmrg } 12701e04c3fSmrg 12801e04c3fSmrg return true; 12901e04c3fSmrg} 13001e04c3fSmrg 13101e04c3fSmrgstatic bool 13201e04c3fSmrghandle_trace_block(struct aub_read *read, const uint32_t *p) 13301e04c3fSmrg{ 13401e04c3fSmrg int operation = p[1] & AUB_TRACE_OPERATION_MASK; 13501e04c3fSmrg int type = p[1] & AUB_TRACE_TYPE_MASK; 13601e04c3fSmrg int address_space = p[1] & AUB_TRACE_ADDRESS_SPACE_MASK; 13701e04c3fSmrg int header_length = p[0] & 0xffff; 1389f464c52Smaya enum drm_i915_gem_engine_class engine = I915_ENGINE_CLASS_RENDER; 13901e04c3fSmrg const void *data = p + header_length + 2; 1407ec681f3Smrg uint64_t address = intel_48b_address((read->devinfo.ver >= 8 ? ((uint64_t) p[5] << 32) : 0) | 1417ec681f3Smrg ((uint64_t) p[3])); 14201e04c3fSmrg uint32_t size = p[4]; 14301e04c3fSmrg 14401e04c3fSmrg switch (operation) { 14501e04c3fSmrg case AUB_TRACE_OP_DATA_WRITE: 14601e04c3fSmrg if (address_space == AUB_TRACE_MEMTYPE_GTT) { 14701e04c3fSmrg if (read->local_write) 14801e04c3fSmrg read->local_write(read->user_data, address, data, size); 14901e04c3fSmrg break; 15001e04c3fSmrg case AUB_TRACE_OP_COMMAND_WRITE: 15101e04c3fSmrg switch (type) { 15201e04c3fSmrg case AUB_TRACE_TYPE_RING_PRB0: 1539f464c52Smaya engine = I915_ENGINE_CLASS_RENDER; 15401e04c3fSmrg break; 15501e04c3fSmrg case AUB_TRACE_TYPE_RING_PRB1: 1569f464c52Smaya engine = I915_ENGINE_CLASS_VIDEO; 15701e04c3fSmrg break; 15801e04c3fSmrg case AUB_TRACE_TYPE_RING_PRB2: 1599f464c52Smaya engine = I915_ENGINE_CLASS_COPY; 16001e04c3fSmrg break; 16101e04c3fSmrg default: 16201e04c3fSmrg parse_error(read, p, "command write to unknown ring %d\n", type); 16301e04c3fSmrg return false; 16401e04c3fSmrg } 16501e04c3fSmrg 16601e04c3fSmrg if (read->ring_write) 16701e04c3fSmrg read->ring_write(read->user_data, engine, data, size); 16801e04c3fSmrg break; 16901e04c3fSmrg } 17001e04c3fSmrg } 17101e04c3fSmrg 17201e04c3fSmrg return true; 17301e04c3fSmrg} 17401e04c3fSmrg 17501e04c3fSmrgstatic void 17601e04c3fSmrghandle_memtrace_reg_write(struct aub_read *read, const uint32_t *p) 17701e04c3fSmrg{ 17801e04c3fSmrg uint32_t offset = p[1]; 17901e04c3fSmrg uint32_t value = p[5]; 18001e04c3fSmrg 18101e04c3fSmrg if (read->reg_write) 18201e04c3fSmrg read->reg_write(read->user_data, offset, value); 18301e04c3fSmrg 1849f464c52Smaya enum drm_i915_gem_engine_class engine; 18501e04c3fSmrg uint64_t context_descriptor; 18601e04c3fSmrg 18701e04c3fSmrg switch (offset) { 1889f464c52Smaya case EXECLIST_SUBMITPORT_RCSUNIT: /* render elsp */ 18901e04c3fSmrg read->render_elsp[read->render_elsp_index++] = value; 19001e04c3fSmrg if (read->render_elsp_index < 4) 19101e04c3fSmrg return; 19201e04c3fSmrg 19301e04c3fSmrg read->render_elsp_index = 0; 1949f464c52Smaya engine = I915_ENGINE_CLASS_RENDER; 19501e04c3fSmrg context_descriptor = (uint64_t)read->render_elsp[2] << 32 | 19601e04c3fSmrg read->render_elsp[3]; 19701e04c3fSmrg break; 1989f464c52Smaya case EXECLIST_SUBMITPORT_VCSUNIT0: /* video elsp */ 19901e04c3fSmrg read->video_elsp[read->video_elsp_index++] = value; 20001e04c3fSmrg if (read->video_elsp_index < 4) 20101e04c3fSmrg return; 20201e04c3fSmrg 20301e04c3fSmrg read->video_elsp_index = 0; 2049f464c52Smaya engine = I915_ENGINE_CLASS_VIDEO; 20501e04c3fSmrg context_descriptor = (uint64_t)read->video_elsp[2] << 32 | 20601e04c3fSmrg read->video_elsp[3]; 20701e04c3fSmrg break; 2089f464c52Smaya case EXECLIST_SUBMITPORT_BCSUNIT: /* blitter elsp */ 20901e04c3fSmrg read->blitter_elsp[read->blitter_elsp_index++] = value; 21001e04c3fSmrg if (read->blitter_elsp_index < 4) 21101e04c3fSmrg return; 21201e04c3fSmrg 21301e04c3fSmrg read->blitter_elsp_index = 0; 2149f464c52Smaya engine = I915_ENGINE_CLASS_COPY; 21501e04c3fSmrg context_descriptor = (uint64_t)read->blitter_elsp[2] << 32 | 21601e04c3fSmrg read->blitter_elsp[3]; 21701e04c3fSmrg break; 2189f464c52Smaya case EXECLIST_SQ_CONTENTS0_RCSUNIT: /* render elsq0 lo */ 21901e04c3fSmrg read->render_elsp[3] = value; 22001e04c3fSmrg return; 2219f464c52Smaya case (EXECLIST_SQ_CONTENTS0_RCSUNIT + 4): /* render elsq0 hi */ 22201e04c3fSmrg read->render_elsp[2] = value; 22301e04c3fSmrg return; 2249f464c52Smaya case EXECLIST_SQ_CONTENTS0_VCSUNIT0: /* video elsq0 lo */ 22501e04c3fSmrg read->video_elsp[3] = value; 22601e04c3fSmrg return; 2279f464c52Smaya case EXECLIST_SQ_CONTENTS0_VCSUNIT0 + 4: /* video elsq0 hi */ 22801e04c3fSmrg read->video_elsp[2] = value; 22901e04c3fSmrg return; 2309f464c52Smaya case EXECLIST_SQ_CONTENTS0_BCSUNIT: /* blitter elsq0 lo */ 23101e04c3fSmrg read->blitter_elsp[3] = value; 23201e04c3fSmrg return; 2339f464c52Smaya case (EXECLIST_SQ_CONTENTS0_BCSUNIT + 4): /* blitter elsq0 hi */ 23401e04c3fSmrg read->blitter_elsp[2] = value; 23501e04c3fSmrg return; 2369f464c52Smaya case EXECLIST_CONTROL_RCSUNIT: /* render elsc */ 2379f464c52Smaya engine = I915_ENGINE_CLASS_RENDER; 23801e04c3fSmrg context_descriptor = (uint64_t)read->render_elsp[2] << 32 | 23901e04c3fSmrg read->render_elsp[3]; 24001e04c3fSmrg break; 2419f464c52Smaya case EXECLIST_CONTROL_VCSUNIT0: /* video_elsc */ 2429f464c52Smaya engine = I915_ENGINE_CLASS_VIDEO; 24301e04c3fSmrg context_descriptor = (uint64_t)read->video_elsp[2] << 32 | 24401e04c3fSmrg read->video_elsp[3]; 24501e04c3fSmrg break; 2469f464c52Smaya case EXECLIST_CONTROL_BCSUNIT: /* blitter elsc */ 2479f464c52Smaya engine = I915_ENGINE_CLASS_COPY; 24801e04c3fSmrg context_descriptor = (uint64_t)read->blitter_elsp[2] << 32 | 24901e04c3fSmrg read->blitter_elsp[3]; 25001e04c3fSmrg break; 25101e04c3fSmrg default: 25201e04c3fSmrg return; 25301e04c3fSmrg } 25401e04c3fSmrg 25501e04c3fSmrg if (read->execlist_write) 25601e04c3fSmrg read->execlist_write(read->user_data, engine, context_descriptor); 25701e04c3fSmrg} 25801e04c3fSmrg 25901e04c3fSmrgstatic void 26001e04c3fSmrghandle_memtrace_mem_write(struct aub_read *read, const uint32_t *p) 26101e04c3fSmrg{ 26201e04c3fSmrg const void *data = p + 5; 2637ec681f3Smrg uint64_t addr = intel_48b_address(*(uint64_t*)&p[1]); 26401e04c3fSmrg uint32_t size = p[4]; 26501e04c3fSmrg uint32_t address_space = p[3] >> 28; 26601e04c3fSmrg 26701e04c3fSmrg switch (address_space) { 26801e04c3fSmrg case 0: /* GGTT */ 26901e04c3fSmrg if (read->ggtt_write) 27001e04c3fSmrg read->ggtt_write(read->user_data, addr, data, size); 27101e04c3fSmrg break; 27201e04c3fSmrg case 1: /* Local */ 27301e04c3fSmrg if (read->local_write) 27401e04c3fSmrg read->local_write(read->user_data, addr, data, size); 27501e04c3fSmrg break; 27601e04c3fSmrg case 2: /* Physical */ 27701e04c3fSmrg if (read->phys_write) 27801e04c3fSmrg read->phys_write(read->user_data, addr, data, size); 27901e04c3fSmrg break; 28001e04c3fSmrg case 4: /* GGTT Entry */ 28101e04c3fSmrg if (read->ggtt_entry_write) 28201e04c3fSmrg read->ggtt_entry_write(read->user_data, addr, data, size); 28301e04c3fSmrg break; 28401e04c3fSmrg } 28501e04c3fSmrg} 28601e04c3fSmrg 28701e04c3fSmrgint 28801e04c3fSmrgaub_read_command(struct aub_read *read, const void *data, uint32_t data_len) 28901e04c3fSmrg{ 2909f464c52Smaya const uint32_t *p = data, *next; 2917ec681f3Smrg ASSERTED const uint32_t *end = data + data_len; 29201e04c3fSmrg uint32_t h, header_length, bias; 29301e04c3fSmrg 29401e04c3fSmrg assert(data_len >= 4); 29501e04c3fSmrg 29601e04c3fSmrg h = *p; 29701e04c3fSmrg header_length = h & 0xffff; 29801e04c3fSmrg 29901e04c3fSmrg switch (OPCODE(h)) { 30001e04c3fSmrg case OPCODE_AUB: 30101e04c3fSmrg bias = 2; 30201e04c3fSmrg break; 30301e04c3fSmrg case OPCODE_NEW_AUB: 30401e04c3fSmrg bias = 1; 30501e04c3fSmrg break; 30601e04c3fSmrg default: 30701e04c3fSmrg parse_error(read, data, "unknown opcode %d\n", OPCODE(h)); 30801e04c3fSmrg return -1; 30901e04c3fSmrg } 31001e04c3fSmrg 31101e04c3fSmrg next = p + header_length + bias; 31201e04c3fSmrg if ((h & 0xffff0000) == MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK)) { 31301e04c3fSmrg assert(end - p >= 4); 31401e04c3fSmrg next += p[4] / 4; 31501e04c3fSmrg } 31601e04c3fSmrg 3177ec681f3Smrg if (next > end) { 3187ec681f3Smrg parse_error(read, data, 3197ec681f3Smrg "input ends unexpectedly (command length: %zu, remaining bytes: %zu)\n", 3207ec681f3Smrg (uintptr_t)next - (uintptr_t)data, 3217ec681f3Smrg (uintptr_t)end - (uintptr_t)data); 3227ec681f3Smrg return -1; 3237ec681f3Smrg } 32401e04c3fSmrg 32501e04c3fSmrg switch (h & 0xffff0000) { 32601e04c3fSmrg case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_HEADER): 32701e04c3fSmrg if (!handle_trace_header(read, p)) 32801e04c3fSmrg return -1; 32901e04c3fSmrg break; 33001e04c3fSmrg case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK): 33101e04c3fSmrg if (!handle_trace_block(read, p)) 33201e04c3fSmrg return -1; 33301e04c3fSmrg break; 33401e04c3fSmrg case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BMP): 33501e04c3fSmrg break; 33601e04c3fSmrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_VERSION): 33701e04c3fSmrg if (!handle_memtrace_version(read, p)) 33801e04c3fSmrg return -1; 33901e04c3fSmrg break; 34001e04c3fSmrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_WRITE): 34101e04c3fSmrg handle_memtrace_reg_write(read, p); 34201e04c3fSmrg break; 34301e04c3fSmrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE): 34401e04c3fSmrg handle_memtrace_mem_write(read, p); 34501e04c3fSmrg break; 34601e04c3fSmrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_POLL): 34701e04c3fSmrg /* fprintf(outfile, "memory poll block (dwords %d):\n", h & 0xffff); */ 34801e04c3fSmrg break; 34901e04c3fSmrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_POLL): 35001e04c3fSmrg break; 35101e04c3fSmrg default: 35201e04c3fSmrg parse_error(read, p, 35301e04c3fSmrg "unknown block type=0x%x, opcode=0x%x, subopcode=0x%x (%08x)\n", 35401e04c3fSmrg TYPE(h), OPCODE(h), SUBOPCODE(h), h); 35501e04c3fSmrg return -1; 35601e04c3fSmrg } 35701e04c3fSmrg 35801e04c3fSmrg return (next - p) * sizeof(*p); 35901e04c3fSmrg} 360