kgem_debug.c revision 42542f5f
1/*
2 * Copyright © 2007-2011 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Eric Anholt <eric@anholt.net>
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <sys/mman.h>
33#include <assert.h>
34
35#include "sna.h"
36#include "sna_reg.h"
37
38#include "kgem_debug.h"
39
40struct drm_i915_gem_relocation_entry *
41kgem_debug_get_reloc_entry(struct kgem *kgem, uint32_t offset)
42{
43	int i;
44
45	offset *= sizeof(uint32_t);
46
47	for (i = 0; i < kgem->nreloc; i++)
48		if (kgem->reloc[i].offset == offset)
49			return kgem->reloc+i;
50
51	assert(!"valid relocation entry, unknown batch offset");
52	return NULL;
53}
54
55struct kgem_bo *
56kgem_debug_get_bo_for_reloc_entry(struct kgem *kgem,
57				  struct drm_i915_gem_relocation_entry *reloc)
58{
59	struct kgem_bo *bo;
60
61	if (reloc == NULL)
62		return NULL;
63
64	list_for_each_entry(bo, &kgem->next_request->buffers, request)
65		if (bo->target_handle == reloc->target_handle && bo->proxy == NULL)
66			break;
67
68	assert(&bo->request != &kgem->next_request->buffers);
69
70	return bo;
71}
72
73static int kgem_debug_handle_is_fenced(struct kgem *kgem, uint32_t handle)
74{
75	int i;
76
77	if (kgem->has_handle_lut)
78		return kgem->exec[handle].flags & EXEC_OBJECT_NEEDS_FENCE;
79
80	for (i = 0; i < kgem->nexec; i++)
81		if (kgem->exec[i].handle == handle)
82			return kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE;
83
84	return 0;
85}
86
87static int kgem_debug_handle_tiling(struct kgem *kgem, uint32_t handle)
88{
89	struct kgem_bo *bo;
90
91	list_for_each_entry(bo, &kgem->next_request->buffers, request)
92		if (bo->target_handle == handle)
93			return bo->tiling;
94
95	return 0;
96}
97
98void
99kgem_debug_print(const uint32_t *data,
100		 uint32_t offset, unsigned int index,
101		 const char *fmt, ...)
102{
103	va_list va;
104	char buf[240];
105	int len;
106
107	len = snprintf(buf, sizeof(buf),
108		       "0x%08x: 0x%08x: %s",
109		       (offset + index) * 4,
110		       data[index],
111		       index == 0 ? "" : "   ");
112
113	va_start(va, fmt);
114	vsnprintf(buf + len, sizeof(buf) - len, fmt, va);
115	va_end(va);
116
117	ErrorF("%s", buf);
118}
119
120static int
121decode_nop(struct kgem *kgem, uint32_t offset)
122{
123	uint32_t *data = kgem->batch + offset;
124	kgem_debug_print(data, offset, 0, "UNKNOWN\n");
125	assert(0);
126	return 1;
127}
128
129static int
130decode_mi(struct kgem *kgem, uint32_t offset)
131{
132	static const struct {
133		uint32_t opcode;
134		int len_mask;
135		int min_len;
136		int max_len;
137		const char *name;
138	} opcodes[] = {
139		{ 0x08, 0, 1, 1, "MI_ARB_ON_OFF" },
140		{ 0x0a, 0, 1, 1, "MI_BATCH_BUFFER_END" },
141		{ 0x30, 0x3f, 3, 3, "MI_BATCH_BUFFER" },
142		{ 0x31, 0x3f, 2, 2, "MI_BATCH_BUFFER_START" },
143		{ 0x14, 0x3f, 3, 3, "MI_DISPLAY_BUFFER_INFO" },
144		{ 0x04, 0, 1, 1, "MI_FLUSH" },
145		{ 0x22, 0x1f, 3, 3, "MI_LOAD_REGISTER_IMM" },
146		{ 0x13, 0x3f, 2, 2, "MI_LOAD_SCAN_LINES_EXCL" },
147		{ 0x12, 0x3f, 2, 2, "MI_LOAD_SCAN_LINES_INCL" },
148		{ 0x00, 0, 1, 1, "MI_NOOP" },
149		{ 0x11, 0x3f, 2, 2, "MI_OVERLAY_FLIP" },
150		{ 0x07, 0, 1, 1, "MI_REPORT_HEAD" },
151		{ 0x18, 0x3f, 2, 2, "MI_SET_CONTEXT" },
152		{ 0x20, 0x3f, 3, 4, "MI_STORE_DATA_IMM" },
153		{ 0x21, 0x3f, 3, 4, "MI_STORE_DATA_INDEX" },
154		{ 0x24, 0x3f, 3, 3, "MI_STORE_REGISTER_MEM" },
155		{ 0x02, 0, 1, 1, "MI_USER_INTERRUPT" },
156		{ 0x03, 0, 1, 1, "MI_WAIT_FOR_EVENT" },
157		{ 0x16, 0x7f, 3, 3, "MI_SEMAPHORE_MBOX" },
158		{ 0x26, 0x1f, 3, 4, "MI_FLUSH_DW" },
159		{ 0x0b, 0, 1, 1, "MI_SUSPEND_FLUSH" },
160	};
161	uint32_t *data = kgem->batch + offset;
162	int op;
163
164	for (op = 0; op < ARRAY_SIZE(opcodes); op++) {
165		if ((data[0] & 0x1f800000) >> 23 == opcodes[op].opcode) {
166			unsigned int len = 1, i;
167
168			kgem_debug_print(data, offset, 0, "%s\n", opcodes[op].name);
169			if (opcodes[op].max_len > 1) {
170				len = (data[0] & opcodes[op].len_mask) + 2;
171				if (len < opcodes[op].min_len ||
172				    len > opcodes[op].max_len)
173				{
174					ErrorF("Bad length (%d) in %s, [%d, %d]\n",
175					       len, opcodes[op].name,
176					       opcodes[op].min_len,
177					       opcodes[op].max_len);
178					assert(0);
179				}
180			}
181
182			for (i = 1; i < len; i++)
183				kgem_debug_print(data, offset, i, "dword %d\n", i);
184
185			return len;
186		}
187	}
188
189	kgem_debug_print(data, offset, 0, "MI UNKNOWN\n");
190	assert(0);
191	return 1;
192}
193
194static int
195__decode_2d(struct kgem *kgem, uint32_t offset)
196{
197	static const struct {
198		uint32_t opcode;
199		int min_len;
200		int max_len;
201		const char *name;
202	} opcodes[] = {
203		{ 0x40, 5, 5, "COLOR_BLT" },
204		{ 0x43, 6, 6, "SRC_COPY_BLT" },
205		{ 0x01, 8, 8, "XY_SETUP_BLT" },
206		{ 0x11, 9, 9, "XY_SETUP_MONO_PATTERN_SL_BLT" },
207		{ 0x03, 3, 3, "XY_SETUP_CLIP_BLT" },
208		{ 0x24, 2, 2, "XY_PIXEL_BLT" },
209		{ 0x25, 3, 3, "XY_SCANLINES_BLT" },
210		{ 0x26, 4, 4, "Y_TEXT_BLT" },
211		{ 0x31, 5, 134, "XY_TEXT_IMMEDIATE_BLT" },
212		{ 0x50, 6, 6, "XY_COLOR_BLT" },
213		{ 0x51, 6, 6, "XY_PAT_BLT" },
214		{ 0x76, 8, 8, "XY_PAT_CHROMA_BLT" },
215		{ 0x72, 7, 135, "XY_PAT_BLT_IMMEDIATE" },
216		{ 0x77, 9, 137, "XY_PAT_CHROMA_BLT_IMMEDIATE" },
217		{ 0x52, 9, 9, "XY_MONO_PAT_BLT" },
218		{ 0x59, 7, 7, "XY_MONO_PAT_FIXED_BLT" },
219		{ 0x53, 8, 8, "XY_SRC_COPY_BLT" },
220		{ 0x54, 8, 8, "XY_MONO_SRC_COPY_BLT" },
221		{ 0x71, 9, 137, "XY_MONO_SRC_COPY_IMMEDIATE_BLT" },
222		{ 0x55, 9, 9, "XY_FULL_BLT" },
223		{ 0x55, 9, 137, "XY_FULL_IMMEDIATE_PATTERN_BLT" },
224		{ 0x56, 9, 9, "XY_FULL_MONO_SRC_BLT" },
225		{ 0x75, 10, 138, "XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT" },
226		{ 0x57, 12, 12, "XY_FULL_MONO_PATTERN_BLT" },
227		{ 0x58, 12, 12, "XY_FULL_MONO_PATTERN_MONO_SRC_BLT" },
228	};
229
230	unsigned int op, len;
231	const char *format = NULL;
232	uint32_t *data = kgem->batch + offset;
233	struct drm_i915_gem_relocation_entry *reloc;
234
235	/* Special case the two most common ops that we detail in full */
236	switch ((data[0] & 0x1fc00000) >> 22) {
237	case 0x50:
238		kgem_debug_print(data, offset, 0,
239			  "XY_COLOR_BLT (rgb %sabled, alpha %sabled, dst tile %d)\n",
240			  (data[0] & (1 << 20)) ? "en" : "dis",
241			  (data[0] & (1 << 21)) ? "en" : "dis",
242			  (data[0] >> 11) & 1);
243
244		len = (data[0] & 0x000000ff) + 2;
245		assert(len == 6);
246
247		switch ((data[1] >> 24) & 0x3) {
248		case 0:
249			format="8";
250			break;
251		case 1:
252			format="565";
253			break;
254		case 2:
255			format="1555";
256			break;
257		case 3:
258			format="8888";
259			break;
260		}
261
262		kgem_debug_print(data, offset, 1, "format %s, rop %x, pitch %d, "
263			  "clipping %sabled\n", format,
264			  (data[1] >> 16) & 0xff,
265			  (short)(data[1] & 0xffff),
266			  data[1] & (1 << 30) ? "en" : "dis");
267		kgem_debug_print(data, offset, 2, "(%d,%d)\n",
268			  data[2] & 0xffff, data[2] >> 16);
269		kgem_debug_print(data, offset, 3, "(%d,%d)\n",
270			  data[3] & 0xffff, data[3] >> 16);
271		reloc = kgem_debug_get_reloc_entry(kgem, offset+4);
272		kgem_debug_print(data, offset, 4, "dst offset 0x%08x [handle=%d, delta=%d, read=%x, write=%x (fenced? %d, tiling? %d)]\n",
273				 data[4],
274				 reloc->target_handle, reloc->delta,
275				 reloc->read_domains, reloc->write_domain,
276				 kgem_debug_handle_is_fenced(kgem, reloc->target_handle),
277				 kgem_debug_handle_tiling(kgem, reloc->target_handle));
278		kgem_debug_print(data, offset, 5, "color\n");
279		assert(kgem->gen >= 040 ||
280		       kgem_debug_handle_is_fenced(kgem, reloc->target_handle));
281		return len;
282
283	case 0x53:
284		kgem_debug_print(data, offset, 0,
285			  "XY_SRC_COPY_BLT (rgb %sabled, alpha %sabled, "
286			  "src tile %d, dst tile %d)\n",
287			  (data[0] & (1 << 20)) ? "en" : "dis",
288			  (data[0] & (1 << 21)) ? "en" : "dis",
289			  (data[0] >> 15) & 1,
290			  (data[0] >> 11) & 1);
291
292		len = (data[0] & 0x000000ff) + 2;
293		assert(len == 8);
294
295		switch ((data[1] >> 24) & 0x3) {
296		case 0:
297			format="8";
298			break;
299		case 1:
300			format="565";
301			break;
302		case 2:
303			format="1555";
304			break;
305		case 3:
306			format="8888";
307			break;
308		}
309
310		kgem_debug_print(data, offset, 1, "format %s, rop %x, dst pitch %d, "
311				 "clipping %sabled\n", format,
312				 (data[1] >> 16) & 0xff,
313				 (short)(data[1] & 0xffff),
314				 data[1] & (1 << 30) ? "en" : "dis");
315		kgem_debug_print(data, offset, 2, "dst (%d,%d)\n",
316				 data[2] & 0xffff, data[2] >> 16);
317		kgem_debug_print(data, offset, 3, "dst (%d,%d)\n",
318				 data[3] & 0xffff, data[3] >> 16);
319		reloc = kgem_debug_get_reloc_entry(kgem, offset+4);
320		assert(reloc);
321		kgem_debug_print(data, offset, 4, "dst offset 0x%08x [handle=%d, delta=%d, read=%x, write=%x, (fenced? %d, tiling? %d)]\n",
322				 data[4],
323				 reloc->target_handle, reloc->delta,
324				 reloc->read_domains, reloc->write_domain,
325				 kgem_debug_handle_is_fenced(kgem, reloc->target_handle),
326				 kgem_debug_handle_tiling(kgem, reloc->target_handle));
327		assert(kgem->gen >= 040 ||
328		       kgem_debug_handle_is_fenced(kgem, reloc->target_handle));
329
330		kgem_debug_print(data, offset, 5, "src (%d,%d)\n",
331				 data[5] & 0xffff, data[5] >> 16);
332		kgem_debug_print(data, offset, 6, "src pitch %d\n",
333				 (short)(data[6] & 0xffff));
334		reloc = kgem_debug_get_reloc_entry(kgem, offset+7);
335		assert(reloc);
336		kgem_debug_print(data, offset, 7, "src offset 0x%08x [handle=%d, delta=%d, read=%x, write=%x (fenced? %d, tiling? %d)]\n",
337				 data[7],
338				 reloc->target_handle, reloc->delta,
339				 reloc->read_domains, reloc->write_domain,
340				 kgem_debug_handle_is_fenced(kgem, reloc->target_handle),
341				 kgem_debug_handle_tiling(kgem, reloc->target_handle));
342		assert(kgem->gen >= 040 ||
343		       kgem_debug_handle_is_fenced(kgem, reloc->target_handle));
344
345		return len;
346	}
347
348	for (op = 0; op < ARRAY_SIZE(opcodes); op++) {
349		if ((data[0] & 0x1fc00000) >> 22 == opcodes[op].opcode) {
350			unsigned int i;
351
352			len = 1;
353			kgem_debug_print(data, offset, 0, "%s\n", opcodes[op].name);
354			if (opcodes[op].max_len > 1) {
355				len = (data[0] & 0x000000ff) + 2;
356				assert(len >= opcodes[op].min_len &&
357				       len <= opcodes[op].max_len);
358			}
359
360			for (i = 1; i < len; i++)
361				kgem_debug_print(data, offset, i, "dword %d\n", i);
362
363			return len;
364		}
365	}
366
367	kgem_debug_print(data, offset, 0, "2D UNKNOWN\n");
368	assert(0);
369	return 1;
370}
371
372static int
373__decode_2d_gen8(struct kgem *kgem, uint32_t offset)
374{
375	static const struct {
376		uint32_t opcode;
377		int min_len;
378		int max_len;
379		const char *name;
380	} opcodes[] = {
381		{ 0x43, 8, 8, "SRC_COPY_BLT" },
382		{ 0x01, 8, 8, "XY_SETUP_BLT" },
383		{ 0x11, 10, 10, "XY_SETUP_MONO_PATTERN_SL_BLT" },
384		{ 0x03, 3, 3, "XY_SETUP_CLIP_BLT" },
385		{ 0x24, 2, 2, "XY_PIXEL_BLT" },
386		{ 0x25, 3, 3, "XY_SCANLINES_BLT" },
387		{ 0x26, 4, 4, "Y_TEXT_BLT" },
388		{ 0x31, 5, 134, "XY_TEXT_IMMEDIATE_BLT" },
389		{ 0x50, 7, 7, "XY_COLOR_BLT" },
390		{ 0x51, 6, 6, "XY_PAT_BLT" },
391		{ 0x76, 8, 8, "XY_PAT_CHROMA_BLT" },
392		{ 0x72, 7, 135, "XY_PAT_BLT_IMMEDIATE" },
393		{ 0x77, 9, 137, "XY_PAT_CHROMA_BLT_IMMEDIATE" },
394		{ 0x52, 9, 9, "XY_MONO_PAT_BLT" },
395		{ 0x59, 7, 7, "XY_MONO_PAT_FIXED_BLT" },
396		{ 0x53, 8, 8, "XY_SRC_COPY_BLT" },
397		{ 0x54, 8, 8, "XY_MONO_SRC_COPY_BLT" },
398		{ 0x71, 9, 137, "XY_MONO_SRC_COPY_IMMEDIATE_BLT" },
399		{ 0x55, 9, 9, "XY_FULL_BLT" },
400		{ 0x55, 9, 137, "XY_FULL_IMMEDIATE_PATTERN_BLT" },
401		{ 0x56, 9, 9, "XY_FULL_MONO_SRC_BLT" },
402		{ 0x75, 10, 138, "XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT" },
403		{ 0x57, 12, 12, "XY_FULL_MONO_PATTERN_BLT" },
404		{ 0x58, 12, 12, "XY_FULL_MONO_PATTERN_MONO_SRC_BLT" },
405	};
406
407	unsigned int op, len;
408	const char *format = NULL;
409	uint32_t *data = kgem->batch + offset;
410	struct drm_i915_gem_relocation_entry *reloc;
411
412	/* Special case the two most common ops that we detail in full */
413	switch ((data[0] & 0x1fc00000) >> 22) {
414	case 0x50:
415		kgem_debug_print(data, offset, 0,
416			  "XY_COLOR_BLT (rgb %sabled, alpha %sabled, dst tile %d)\n",
417			  (data[0] & (1 << 20)) ? "en" : "dis",
418			  (data[0] & (1 << 21)) ? "en" : "dis",
419			  (data[0] >> 11) & 1);
420
421		len = (data[0] & 0x000000ff) + 2;
422		assert(len == 7);
423
424		switch ((data[1] >> 24) & 0x3) {
425		case 0:
426			format="8";
427			break;
428		case 1:
429			format="565";
430			break;
431		case 2:
432			format="1555";
433			break;
434		case 3:
435			format="8888";
436			break;
437		}
438
439		kgem_debug_print(data, offset, 1, "format %s, rop %x, pitch %d, "
440			  "clipping %sabled\n", format,
441			  (data[1] >> 16) & 0xff,
442			  (short)(data[1] & 0xffff),
443			  data[1] & (1 << 30) ? "en" : "dis");
444		kgem_debug_print(data, offset, 2, "(%d,%d)\n",
445			  data[2] & 0xffff, data[2] >> 16);
446		kgem_debug_print(data, offset, 3, "(%d,%d)\n",
447			  data[3] & 0xffff, data[3] >> 16);
448		reloc = kgem_debug_get_reloc_entry(kgem, offset+4);
449		kgem_debug_print(data, offset, 4, "dst offset 0x%016llx [handle=%d, delta=%d, read=%x, write=%x (fenced? %d, tiling? %d)]\n",
450				(long long)*(uint64_t *)&data[4],
451				reloc->target_handle, reloc->delta,
452				reloc->read_domains, reloc->write_domain,
453				kgem_debug_handle_is_fenced(kgem, reloc->target_handle),
454				kgem_debug_handle_tiling(kgem, reloc->target_handle));
455		kgem_debug_print(data, offset, 6, "color\n");
456		return len;
457
458	case 0x53:
459		kgem_debug_print(data, offset, 0,
460			  "XY_SRC_COPY_BLT (rgb %sabled, alpha %sabled, "
461			  "src tile %d, dst tile %d)\n",
462			  (data[0] & (1 << 20)) ? "en" : "dis",
463			  (data[0] & (1 << 21)) ? "en" : "dis",
464			  (data[0] >> 15) & 1,
465			  (data[0] >> 11) & 1);
466
467		len = (data[0] & 0x000000ff) + 2;
468		assert(len == 10);
469
470		switch ((data[1] >> 24) & 0x3) {
471		case 0:
472			format="8";
473			break;
474		case 1:
475			format="565";
476			break;
477		case 2:
478			format="1555";
479			break;
480		case 3:
481			format="8888";
482			break;
483		}
484
485		kgem_debug_print(data, offset, 1, "format %s, rop %x, dst pitch %d, "
486				 "clipping %sabled\n", format,
487				 (data[1] >> 16) & 0xff,
488				 (short)(data[1] & 0xffff),
489				 data[1] & (1 << 30) ? "en" : "dis");
490		kgem_debug_print(data, offset, 2, "dst (%d,%d)\n",
491				 data[2] & 0xffff, data[2] >> 16);
492		kgem_debug_print(data, offset, 3, "dst (%d,%d)\n",
493				 data[3] & 0xffff, data[3] >> 16);
494		reloc = kgem_debug_get_reloc_entry(kgem, offset+4);
495		assert(reloc);
496		kgem_debug_print(data, offset, 4, "dst offset 0x%016llx [handle=%d, delta=%d, read=%x, write=%x, (fenced? %d, tiling? %d)]\n",
497				(long long)*(uint64_t *)&data[4],
498				reloc->target_handle, reloc->delta,
499				reloc->read_domains, reloc->write_domain,
500				kgem_debug_handle_is_fenced(kgem, reloc->target_handle),
501				kgem_debug_handle_tiling(kgem, reloc->target_handle));
502
503		kgem_debug_print(data, offset, 6, "src (%d,%d)\n",
504				 data[6] & 0xffff, data[6] >> 16);
505		kgem_debug_print(data, offset, 7, "src pitch %d\n",
506				 (short)(data[7] & 0xffff));
507		reloc = kgem_debug_get_reloc_entry(kgem, offset+8);
508		assert(reloc);
509		kgem_debug_print(data, offset, 8, "src offset 0x%016llx [handle=%d, delta=%d, read=%x, write=%x (fenced? %d, tiling? %d)]\n",
510				(long long)*(uint64_t *)&data[8],
511				reloc->target_handle, reloc->delta,
512				reloc->read_domains, reloc->write_domain,
513				kgem_debug_handle_is_fenced(kgem, reloc->target_handle),
514				kgem_debug_handle_tiling(kgem, reloc->target_handle));
515
516		return len;
517	}
518
519	for (op = 0; op < ARRAY_SIZE(opcodes); op++) {
520		if ((data[0] & 0x1fc00000) >> 22 == opcodes[op].opcode) {
521			unsigned int i;
522
523			len = 1;
524			kgem_debug_print(data, offset, 0, "%s\n", opcodes[op].name);
525			if (opcodes[op].max_len > 1) {
526				len = (data[0] & 0x000000ff) + 2;
527				assert(len >= opcodes[op].min_len &&
528				       len <= opcodes[op].max_len);
529			}
530
531			for (i = 1; i < len; i++)
532				kgem_debug_print(data, offset, i, "dword %d\n", i);
533
534			return len;
535		}
536	}
537
538	kgem_debug_print(data, offset, 0, "2D UNKNOWN\n");
539	assert(0);
540	return 1;
541}
542
543static int (*decode_2d(int gen))(struct kgem*, uint32_t)
544{
545	if (gen >= 0100)
546		return __decode_2d_gen8;
547	else
548		return __decode_2d;
549}
550
551static int kgem_nop_decode_3d(struct kgem *kgem, uint32_t offset)
552{
553    uint32_t *data = kgem->batch + offset;
554    return (data[0] & 0xf) + 2;
555}
556
557static void kgem_nop_finish_state(struct kgem *kgem)
558{
559}
560
561static int (*decode_3d(int gen))(struct kgem*, uint32_t)
562{
563	if (gen >= 0100) {
564		return kgem_nop_decode_3d;
565	} else if (gen >= 070) {
566		return kgem_gen7_decode_3d;
567	} else if (gen >= 060) {
568		return kgem_gen6_decode_3d;
569	} else if (gen >= 050) {
570		return kgem_gen5_decode_3d;
571	} else if (gen >= 040) {
572		return kgem_gen4_decode_3d;
573	} else if (gen >= 030) {
574		return kgem_gen3_decode_3d;
575	} else if (gen >= 020) {
576		return kgem_gen2_decode_3d;
577	}
578	assert(0);
579}
580
581static void (*finish_state(int gen))(struct kgem*)
582{
583	if (gen >= 0100) {
584		return kgem_nop_finish_state;
585	} else if (gen >= 070) {
586		return kgem_gen7_finish_state;
587	} else if (gen >= 060) {
588		return kgem_gen6_finish_state;
589	} else if (gen >= 050) {
590		return kgem_gen5_finish_state;
591	} else if (gen >= 040) {
592		return kgem_gen4_finish_state;
593	} else if (gen >= 030) {
594		return kgem_gen3_finish_state;
595	} else if (gen >= 020) {
596		return kgem_gen2_finish_state;
597	}
598	assert(0);
599}
600
601void __kgem_batch_debug(struct kgem *kgem, uint32_t nbatch)
602{
603	int (*const decode[])(struct kgem *, uint32_t) = {
604		decode_mi,
605		decode_nop,
606		decode_2d(kgem->gen),
607		decode_3d(kgem->gen),
608	};
609	uint32_t offset = 0;
610
611	while (offset < nbatch) {
612		int class = (kgem->batch[offset] & 0xe0000000) >> 29;
613		assert(class < ARRAY_SIZE(decode));
614		offset += decode[class](kgem, offset);
615	}
616
617	finish_state(kgem->gen)(kgem);
618}
619