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