1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2016-2018 Intel Corporation 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21b8e80941Smrg * IN THE SOFTWARE. 22b8e80941Smrg * 23b8e80941Smrg */ 24b8e80941Smrg 25b8e80941Smrg#include <stdio.h> 26b8e80941Smrg#include <stdlib.h> 27b8e80941Smrg#include <string.h> 28b8e80941Smrg#include <stdarg.h> 29b8e80941Smrg 30b8e80941Smrg#include "common/gen_gem.h" 31b8e80941Smrg#include "util/macros.h" 32b8e80941Smrg 33b8e80941Smrg#include "aub_read.h" 34b8e80941Smrg#include "gen_context.h" 35b8e80941Smrg#include "intel_aub.h" 36b8e80941Smrg 37b8e80941Smrg#define TYPE(dw) (((dw) >> 29) & 7) 38b8e80941Smrg#define OPCODE(dw) (((dw) >> 23) & 0x3f) 39b8e80941Smrg#define SUBOPCODE(dw) (((dw) >> 16) & 0x7f) 40b8e80941Smrg 41b8e80941Smrg#define MAKE_HEADER(type, opcode, subopcode) \ 42b8e80941Smrg (((type) << 29) | ((opcode) << 23) | ((subopcode) << 16)) 43b8e80941Smrg 44b8e80941Smrg#define TYPE_AUB 0x7 45b8e80941Smrg 46b8e80941Smrg/* Classic AUB opcodes */ 47b8e80941Smrg#define OPCODE_AUB 0x01 48b8e80941Smrg#define SUBOPCODE_HEADER 0x05 49b8e80941Smrg#define SUBOPCODE_BLOCK 0x41 50b8e80941Smrg#define SUBOPCODE_BMP 0x1e 51b8e80941Smrg 52b8e80941Smrg/* Newer version AUB opcode */ 53b8e80941Smrg#define OPCODE_NEW_AUB 0x2e 54b8e80941Smrg#define SUBOPCODE_REG_POLL 0x02 55b8e80941Smrg#define SUBOPCODE_REG_WRITE 0x03 56b8e80941Smrg#define SUBOPCODE_MEM_POLL 0x05 57b8e80941Smrg#define SUBOPCODE_MEM_WRITE 0x06 58b8e80941Smrg#define SUBOPCODE_VERSION 0x0e 59b8e80941Smrg 60b8e80941Smrg#define MAKE_GEN(major, minor) (((major) << 8) | (minor)) 61b8e80941Smrg 62b8e80941Smrgstatic void 63b8e80941Smrgparse_error(struct aub_read *read, const uint32_t *p, const char *fmt, ...) 64b8e80941Smrg{ 65b8e80941Smrg if (!read->error) 66b8e80941Smrg return; 67b8e80941Smrg 68b8e80941Smrg va_list ap; 69b8e80941Smrg va_start(ap, fmt); 70b8e80941Smrg 71b8e80941Smrg char msg[80]; 72b8e80941Smrg vsnprintf(msg, sizeof(msg), fmt, ap); 73b8e80941Smrg read->error(read->user_data, p, msg); 74b8e80941Smrg 75b8e80941Smrg va_end(ap); 76b8e80941Smrg} 77b8e80941Smrg 78b8e80941Smrgstatic bool 79b8e80941Smrghandle_trace_header(struct aub_read *read, const uint32_t *p) 80b8e80941Smrg{ 81b8e80941Smrg /* The intel_aubdump tool from IGT is kind enough to put a PCI-ID= tag in 82b8e80941Smrg * the AUB header comment. If the user hasn't specified a hardware 83b8e80941Smrg * generation, try to use the one from the AUB file. 84b8e80941Smrg */ 85b8e80941Smrg const uint32_t *end = p + (p[0] & 0xffff) + 2; 86b8e80941Smrg int aub_pci_id = 0; 87b8e80941Smrg 88b8e80941Smrg if (end > &p[12] && p[12] > 0) { 89b8e80941Smrg if (sscanf((char *)&p[13], "PCI-ID=%i", &aub_pci_id) > 0) { 90b8e80941Smrg if (!gen_get_device_info(aub_pci_id, &read->devinfo)) { 91b8e80941Smrg parse_error(read, p, 92b8e80941Smrg "can't find device information: pci_id=0x%x\n", aub_pci_id); 93b8e80941Smrg return false; 94b8e80941Smrg } 95b8e80941Smrg } 96b8e80941Smrg } 97b8e80941Smrg 98b8e80941Smrg char app_name[33]; 99b8e80941Smrg strncpy(app_name, (const char *)&p[2], 32); 100b8e80941Smrg app_name[32] = 0; 101b8e80941Smrg 102b8e80941Smrg if (read->info) 103b8e80941Smrg read->info(read->user_data, aub_pci_id, app_name); 104b8e80941Smrg 105b8e80941Smrg return true; 106b8e80941Smrg} 107b8e80941Smrg 108b8e80941Smrgstatic bool 109b8e80941Smrghandle_memtrace_version(struct aub_read *read, const uint32_t *p) 110b8e80941Smrg{ 111b8e80941Smrg int header_length = p[0] & 0xffff; 112b8e80941Smrg char app_name[64]; 113b8e80941Smrg int app_name_len = MIN2(4 * (header_length + 1 - 5), ARRAY_SIZE(app_name) - 1); 114b8e80941Smrg int pci_id_len = 0; 115b8e80941Smrg int aub_pci_id = 0; 116b8e80941Smrg 117b8e80941Smrg strncpy(app_name, (const char *)&p[5], app_name_len); 118b8e80941Smrg app_name[app_name_len] = 0; 119b8e80941Smrg 120b8e80941Smrg if (sscanf(app_name, "PCI-ID=%i %n", &aub_pci_id, &pci_id_len) > 0) { 121b8e80941Smrg if (!gen_get_device_info(aub_pci_id, &read->devinfo)) { 122b8e80941Smrg parse_error(read, p, "can't find device information: pci_id=0x%x\n", aub_pci_id); 123b8e80941Smrg return false; 124b8e80941Smrg } 125b8e80941Smrg 126b8e80941Smrg if (read->info) 127b8e80941Smrg read->info(read->user_data, aub_pci_id, app_name + pci_id_len); 128b8e80941Smrg } 129b8e80941Smrg 130b8e80941Smrg return true; 131b8e80941Smrg} 132b8e80941Smrg 133b8e80941Smrgstatic bool 134b8e80941Smrghandle_trace_block(struct aub_read *read, const uint32_t *p) 135b8e80941Smrg{ 136b8e80941Smrg int operation = p[1] & AUB_TRACE_OPERATION_MASK; 137b8e80941Smrg int type = p[1] & AUB_TRACE_TYPE_MASK; 138b8e80941Smrg int address_space = p[1] & AUB_TRACE_ADDRESS_SPACE_MASK; 139b8e80941Smrg int header_length = p[0] & 0xffff; 140b8e80941Smrg enum drm_i915_gem_engine_class engine = I915_ENGINE_CLASS_RENDER; 141b8e80941Smrg const void *data = p + header_length + 2; 142b8e80941Smrg uint64_t address = gen_48b_address((read->devinfo.gen >= 8 ? ((uint64_t) p[5] << 32) : 0) | 143b8e80941Smrg ((uint64_t) p[3])); 144b8e80941Smrg uint32_t size = p[4]; 145b8e80941Smrg 146b8e80941Smrg switch (operation) { 147b8e80941Smrg case AUB_TRACE_OP_DATA_WRITE: 148b8e80941Smrg if (address_space == AUB_TRACE_MEMTYPE_GTT) { 149b8e80941Smrg if (read->local_write) 150b8e80941Smrg read->local_write(read->user_data, address, data, size); 151b8e80941Smrg break; 152b8e80941Smrg case AUB_TRACE_OP_COMMAND_WRITE: 153b8e80941Smrg switch (type) { 154b8e80941Smrg case AUB_TRACE_TYPE_RING_PRB0: 155b8e80941Smrg engine = I915_ENGINE_CLASS_RENDER; 156b8e80941Smrg break; 157b8e80941Smrg case AUB_TRACE_TYPE_RING_PRB1: 158b8e80941Smrg engine = I915_ENGINE_CLASS_VIDEO; 159b8e80941Smrg break; 160b8e80941Smrg case AUB_TRACE_TYPE_RING_PRB2: 161b8e80941Smrg engine = I915_ENGINE_CLASS_COPY; 162b8e80941Smrg break; 163b8e80941Smrg default: 164b8e80941Smrg parse_error(read, p, "command write to unknown ring %d\n", type); 165b8e80941Smrg return false; 166b8e80941Smrg } 167b8e80941Smrg 168b8e80941Smrg if (read->ring_write) 169b8e80941Smrg read->ring_write(read->user_data, engine, data, size); 170b8e80941Smrg break; 171b8e80941Smrg } 172b8e80941Smrg } 173b8e80941Smrg 174b8e80941Smrg return true; 175b8e80941Smrg} 176b8e80941Smrg 177b8e80941Smrgstatic void 178b8e80941Smrghandle_memtrace_reg_write(struct aub_read *read, const uint32_t *p) 179b8e80941Smrg{ 180b8e80941Smrg uint32_t offset = p[1]; 181b8e80941Smrg uint32_t value = p[5]; 182b8e80941Smrg 183b8e80941Smrg if (read->reg_write) 184b8e80941Smrg read->reg_write(read->user_data, offset, value); 185b8e80941Smrg 186b8e80941Smrg enum drm_i915_gem_engine_class engine; 187b8e80941Smrg uint64_t context_descriptor; 188b8e80941Smrg 189b8e80941Smrg switch (offset) { 190b8e80941Smrg case EXECLIST_SUBMITPORT_RCSUNIT: /* render elsp */ 191b8e80941Smrg read->render_elsp[read->render_elsp_index++] = value; 192b8e80941Smrg if (read->render_elsp_index < 4) 193b8e80941Smrg return; 194b8e80941Smrg 195b8e80941Smrg read->render_elsp_index = 0; 196b8e80941Smrg engine = I915_ENGINE_CLASS_RENDER; 197b8e80941Smrg context_descriptor = (uint64_t)read->render_elsp[2] << 32 | 198b8e80941Smrg read->render_elsp[3]; 199b8e80941Smrg break; 200b8e80941Smrg case EXECLIST_SUBMITPORT_VCSUNIT0: /* video elsp */ 201b8e80941Smrg read->video_elsp[read->video_elsp_index++] = value; 202b8e80941Smrg if (read->video_elsp_index < 4) 203b8e80941Smrg return; 204b8e80941Smrg 205b8e80941Smrg read->video_elsp_index = 0; 206b8e80941Smrg engine = I915_ENGINE_CLASS_VIDEO; 207b8e80941Smrg context_descriptor = (uint64_t)read->video_elsp[2] << 32 | 208b8e80941Smrg read->video_elsp[3]; 209b8e80941Smrg break; 210b8e80941Smrg case EXECLIST_SUBMITPORT_BCSUNIT: /* blitter elsp */ 211b8e80941Smrg read->blitter_elsp[read->blitter_elsp_index++] = value; 212b8e80941Smrg if (read->blitter_elsp_index < 4) 213b8e80941Smrg return; 214b8e80941Smrg 215b8e80941Smrg read->blitter_elsp_index = 0; 216b8e80941Smrg engine = I915_ENGINE_CLASS_COPY; 217b8e80941Smrg context_descriptor = (uint64_t)read->blitter_elsp[2] << 32 | 218b8e80941Smrg read->blitter_elsp[3]; 219b8e80941Smrg break; 220b8e80941Smrg case EXECLIST_SQ_CONTENTS0_RCSUNIT: /* render elsq0 lo */ 221b8e80941Smrg read->render_elsp[3] = value; 222b8e80941Smrg return; 223b8e80941Smrg case (EXECLIST_SQ_CONTENTS0_RCSUNIT + 4): /* render elsq0 hi */ 224b8e80941Smrg read->render_elsp[2] = value; 225b8e80941Smrg return; 226b8e80941Smrg case EXECLIST_SQ_CONTENTS0_VCSUNIT0: /* video elsq0 lo */ 227b8e80941Smrg read->video_elsp[3] = value; 228b8e80941Smrg return; 229b8e80941Smrg case EXECLIST_SQ_CONTENTS0_VCSUNIT0 + 4: /* video elsq0 hi */ 230b8e80941Smrg read->video_elsp[2] = value; 231b8e80941Smrg return; 232b8e80941Smrg case EXECLIST_SQ_CONTENTS0_BCSUNIT: /* blitter elsq0 lo */ 233b8e80941Smrg read->blitter_elsp[3] = value; 234b8e80941Smrg return; 235b8e80941Smrg case (EXECLIST_SQ_CONTENTS0_BCSUNIT + 4): /* blitter elsq0 hi */ 236b8e80941Smrg read->blitter_elsp[2] = value; 237b8e80941Smrg return; 238b8e80941Smrg case EXECLIST_CONTROL_RCSUNIT: /* render elsc */ 239b8e80941Smrg engine = I915_ENGINE_CLASS_RENDER; 240b8e80941Smrg context_descriptor = (uint64_t)read->render_elsp[2] << 32 | 241b8e80941Smrg read->render_elsp[3]; 242b8e80941Smrg break; 243b8e80941Smrg case EXECLIST_CONTROL_VCSUNIT0: /* video_elsc */ 244b8e80941Smrg engine = I915_ENGINE_CLASS_VIDEO; 245b8e80941Smrg context_descriptor = (uint64_t)read->video_elsp[2] << 32 | 246b8e80941Smrg read->video_elsp[3]; 247b8e80941Smrg break; 248b8e80941Smrg case EXECLIST_CONTROL_BCSUNIT: /* blitter elsc */ 249b8e80941Smrg engine = I915_ENGINE_CLASS_COPY; 250b8e80941Smrg context_descriptor = (uint64_t)read->blitter_elsp[2] << 32 | 251b8e80941Smrg read->blitter_elsp[3]; 252b8e80941Smrg break; 253b8e80941Smrg default: 254b8e80941Smrg return; 255b8e80941Smrg } 256b8e80941Smrg 257b8e80941Smrg if (read->execlist_write) 258b8e80941Smrg read->execlist_write(read->user_data, engine, context_descriptor); 259b8e80941Smrg} 260b8e80941Smrg 261b8e80941Smrgstatic void 262b8e80941Smrghandle_memtrace_mem_write(struct aub_read *read, const uint32_t *p) 263b8e80941Smrg{ 264b8e80941Smrg const void *data = p + 5; 265b8e80941Smrg uint64_t addr = gen_48b_address(*(uint64_t*)&p[1]); 266b8e80941Smrg uint32_t size = p[4]; 267b8e80941Smrg uint32_t address_space = p[3] >> 28; 268b8e80941Smrg 269b8e80941Smrg switch (address_space) { 270b8e80941Smrg case 0: /* GGTT */ 271b8e80941Smrg if (read->ggtt_write) 272b8e80941Smrg read->ggtt_write(read->user_data, addr, data, size); 273b8e80941Smrg break; 274b8e80941Smrg case 1: /* Local */ 275b8e80941Smrg if (read->local_write) 276b8e80941Smrg read->local_write(read->user_data, addr, data, size); 277b8e80941Smrg break; 278b8e80941Smrg case 2: /* Physical */ 279b8e80941Smrg if (read->phys_write) 280b8e80941Smrg read->phys_write(read->user_data, addr, data, size); 281b8e80941Smrg break; 282b8e80941Smrg case 4: /* GGTT Entry */ 283b8e80941Smrg if (read->ggtt_entry_write) 284b8e80941Smrg read->ggtt_entry_write(read->user_data, addr, data, size); 285b8e80941Smrg break; 286b8e80941Smrg } 287b8e80941Smrg} 288b8e80941Smrg 289b8e80941Smrgint 290b8e80941Smrgaub_read_command(struct aub_read *read, const void *data, uint32_t data_len) 291b8e80941Smrg{ 292b8e80941Smrg const uint32_t *p = data, *next; 293b8e80941Smrg MAYBE_UNUSED const uint32_t *end = data + data_len; 294b8e80941Smrg uint32_t h, header_length, bias; 295b8e80941Smrg 296b8e80941Smrg assert(data_len >= 4); 297b8e80941Smrg 298b8e80941Smrg h = *p; 299b8e80941Smrg header_length = h & 0xffff; 300b8e80941Smrg 301b8e80941Smrg switch (OPCODE(h)) { 302b8e80941Smrg case OPCODE_AUB: 303b8e80941Smrg bias = 2; 304b8e80941Smrg break; 305b8e80941Smrg case OPCODE_NEW_AUB: 306b8e80941Smrg bias = 1; 307b8e80941Smrg break; 308b8e80941Smrg default: 309b8e80941Smrg parse_error(read, data, "unknown opcode %d\n", OPCODE(h)); 310b8e80941Smrg return -1; 311b8e80941Smrg } 312b8e80941Smrg 313b8e80941Smrg next = p + header_length + bias; 314b8e80941Smrg if ((h & 0xffff0000) == MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK)) { 315b8e80941Smrg assert(end - p >= 4); 316b8e80941Smrg next += p[4] / 4; 317b8e80941Smrg } 318b8e80941Smrg 319b8e80941Smrg assert(next <= end); 320b8e80941Smrg 321b8e80941Smrg switch (h & 0xffff0000) { 322b8e80941Smrg case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_HEADER): 323b8e80941Smrg if (!handle_trace_header(read, p)) 324b8e80941Smrg return -1; 325b8e80941Smrg break; 326b8e80941Smrg case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK): 327b8e80941Smrg if (!handle_trace_block(read, p)) 328b8e80941Smrg return -1; 329b8e80941Smrg break; 330b8e80941Smrg case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BMP): 331b8e80941Smrg break; 332b8e80941Smrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_VERSION): 333b8e80941Smrg if (!handle_memtrace_version(read, p)) 334b8e80941Smrg return -1; 335b8e80941Smrg break; 336b8e80941Smrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_WRITE): 337b8e80941Smrg handle_memtrace_reg_write(read, p); 338b8e80941Smrg break; 339b8e80941Smrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE): 340b8e80941Smrg handle_memtrace_mem_write(read, p); 341b8e80941Smrg break; 342b8e80941Smrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_POLL): 343b8e80941Smrg /* fprintf(outfile, "memory poll block (dwords %d):\n", h & 0xffff); */ 344b8e80941Smrg break; 345b8e80941Smrg case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_POLL): 346b8e80941Smrg break; 347b8e80941Smrg default: 348b8e80941Smrg parse_error(read, p, 349b8e80941Smrg "unknown block type=0x%x, opcode=0x%x, subopcode=0x%x (%08x)\n", 350b8e80941Smrg TYPE(h), OPCODE(h), SUBOPCODE(h), h); 351b8e80941Smrg return -1; 352b8e80941Smrg } 353b8e80941Smrg 354b8e80941Smrg return (next - p) * sizeof(*p); 355b8e80941Smrg} 356