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