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 *    Chris Wilson <chris"chris-wilson.co.uk>
26 *
27 */
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <sys/mman.h>
34#include <assert.h>
35
36#include "sna.h"
37#include "sna_reg.h"
38#include "gen7_render.h"
39
40#include "kgem_debug.h"
41
42static struct state {
43	struct vertex_buffer {
44		int handle;
45		void *base;
46		const char *ptr;
47		int pitch;
48
49		struct kgem_bo *current;
50	} vb[33];
51	struct vertex_elements {
52		int buffer;
53		int offset;
54		bool valid;
55		uint32_t type;
56		uint8_t swizzle[4];
57	} ve[33];
58	int num_ve;
59
60	struct dynamic_state {
61		struct kgem_bo *current;
62		void *base, *ptr;
63	} dynamic_state;
64} state;
65
66static void gen7_update_vertex_buffer(struct kgem *kgem, const uint32_t *data)
67{
68	uint32_t reloc = sizeof(uint32_t) * (&data[1] - kgem->batch);
69	struct kgem_bo *bo = NULL;
70	void *base, *ptr;
71	int i;
72
73	for (i = 0; i < kgem->nreloc; i++)
74		if (kgem->reloc[i].offset == reloc)
75			break;
76	assert(i < kgem->nreloc);
77	reloc = kgem->reloc[i].target_handle;
78
79	if (reloc == 0) {
80		base = kgem->batch;
81	} else {
82		list_for_each_entry(bo, &kgem->next_request->buffers, request)
83			if (bo->handle == reloc)
84				break;
85		assert(&bo->request != &kgem->next_request->buffers);
86		base = kgem_bo_map__debug(kgem, bo);
87	}
88	ptr = (char *)base + kgem->reloc[i].delta;
89
90	i = data[0] >> 26;
91
92	state.vb[i].current = bo;
93	state.vb[i].base = base;
94	state.vb[i].ptr = ptr;
95	state.vb[i].pitch = data[0] & 0x7ff;
96}
97
98static void gen7_update_dynamic_buffer(struct kgem *kgem, const uint32_t offset)
99{
100	uint32_t reloc = sizeof(uint32_t) * offset;
101	struct kgem_bo *bo = NULL;
102	void *base, *ptr;
103	int i;
104
105	if ((kgem->batch[offset] & 1) == 0)
106		return;
107
108	for (i = 0; i < kgem->nreloc; i++)
109		if (kgem->reloc[i].offset == reloc)
110			break;
111	if(i < kgem->nreloc) {
112		reloc = kgem->reloc[i].target_handle;
113
114		if (reloc == 0) {
115			base = kgem->batch;
116		} else {
117			list_for_each_entry(bo, &kgem->next_request->buffers, request)
118				if (bo->handle == reloc)
119					break;
120			assert(&bo->request != &kgem->next_request->buffers);
121			base = kgem_bo_map__debug(kgem, bo);
122		}
123		ptr = (char *)base + (kgem->reloc[i].delta & ~1);
124	} else {
125		bo = NULL;
126		base = NULL;
127		ptr = NULL;
128	}
129
130	state.dynamic_state.current = bo;
131	state.dynamic_state.base = base;
132	state.dynamic_state.ptr = ptr;
133}
134
135static uint32_t
136get_ve_component(uint32_t data, int component)
137{
138	return (data >> (16 + (3 - component) * 4)) & 0x7;
139}
140
141static void gen7_update_vertex_elements(struct kgem *kgem, int id, const uint32_t *data)
142{
143	state.ve[id].buffer = data[0] >> 26;
144	state.ve[id].valid = !!(data[0] & (1 << 25));
145	state.ve[id].type = (data[0] >> 16) & 0x1ff;
146	state.ve[id].offset = data[0] & 0x7ff;
147	state.ve[id].swizzle[0] = get_ve_component(data[1], 0);
148	state.ve[id].swizzle[1] = get_ve_component(data[1], 1);
149	state.ve[id].swizzle[2] = get_ve_component(data[1], 2);
150	state.ve[id].swizzle[3] = get_ve_component(data[1], 3);
151}
152
153static void gen7_update_sf_state(struct kgem *kgem, uint32_t *data)
154{
155	state.num_ve = 1 + ((data[1] >> 22) & 0x3f);
156}
157
158static void vertices_sint16_out(const struct vertex_elements *ve, const int16_t *v, int max)
159{
160	int c;
161
162	ErrorF("(");
163	for (c = 0; c < max; c++) {
164		switch (ve->swizzle[c]) {
165		case 0: ErrorF("#"); break;
166		case 1: ErrorF("%d", v[c]); break;
167		case 2: ErrorF("0.0"); break;
168		case 3: ErrorF("1.0"); break;
169		case 4: ErrorF("0x1"); break;
170		case 5: break;
171		default: ErrorF("?");
172		}
173		if (c < 3)
174			ErrorF(", ");
175	}
176	for (; c < 4; c++) {
177		switch (ve->swizzle[c]) {
178		case 0: ErrorF("#"); break;
179		case 1: ErrorF("1.0"); break;
180		case 2: ErrorF("0.0"); break;
181		case 3: ErrorF("1.0"); break;
182		case 4: ErrorF("0x1"); break;
183		case 5: break;
184		default: ErrorF("?");
185		}
186		if (c < 3)
187			ErrorF(", ");
188	}
189	ErrorF(")");
190}
191
192static void vertices_float_out(const struct vertex_elements *ve, const float *f, int max)
193{
194	int c, o;
195
196	ErrorF("(");
197	for (c = o = 0; c < 4 && o < max; c++) {
198		switch (ve->swizzle[c]) {
199		case 0: ErrorF("#"); break;
200		case 1: ErrorF("%f", f[o++]); break;
201		case 2: ErrorF("0.0"); break;
202		case 3: ErrorF("1.0"); break;
203		case 4: ErrorF("0x1"); break;
204		case 5: break;
205		default: ErrorF("?");
206		}
207		if (c < 3)
208			ErrorF(", ");
209	}
210	for (; c < 4; c++) {
211		switch (ve->swizzle[c]) {
212		case 0: ErrorF("#"); break;
213		case 1: ErrorF("1.0"); break;
214		case 2: ErrorF("0.0"); break;
215		case 3: ErrorF("1.0"); break;
216		case 4: ErrorF("0x1"); break;
217		case 5: break;
218		default: ErrorF("?");
219		}
220		if (c < 3)
221			ErrorF(", ");
222	}
223	ErrorF(")");
224}
225
226static void ve_out(const struct vertex_elements *ve, const void *ptr)
227{
228	switch (ve->type) {
229	case GEN7_SURFACEFORMAT_R32_FLOAT:
230		vertices_float_out(ve, ptr, 1);
231		break;
232	case GEN7_SURFACEFORMAT_R32G32_FLOAT:
233		vertices_float_out(ve, ptr, 2);
234		break;
235	case GEN7_SURFACEFORMAT_R32G32B32_FLOAT:
236		vertices_float_out(ve, ptr, 3);
237		break;
238	case GEN7_SURFACEFORMAT_R32G32B32A32_FLOAT:
239		vertices_float_out(ve, ptr, 4);
240		break;
241	case GEN7_SURFACEFORMAT_R16_SINT:
242		vertices_sint16_out(ve, ptr, 1);
243		break;
244	case GEN7_SURFACEFORMAT_R16G16_SINT:
245		vertices_sint16_out(ve, ptr, 2);
246		break;
247	case GEN7_SURFACEFORMAT_R16G16B16A16_SINT:
248		vertices_sint16_out(ve, ptr, 4);
249		break;
250	case GEN7_SURFACEFORMAT_R16_SSCALED:
251		vertices_sint16_out(ve, ptr, 1);
252		break;
253	case GEN7_SURFACEFORMAT_R16G16_SSCALED:
254		vertices_sint16_out(ve, ptr, 2);
255		break;
256	case GEN7_SURFACEFORMAT_R16G16B16A16_SSCALED:
257		vertices_sint16_out(ve, ptr, 4);
258		break;
259	}
260}
261
262static void indirect_vertex_out(struct kgem *kgem, uint32_t v)
263{
264	int i = 1;
265
266	do {
267		const struct vertex_elements *ve = &state.ve[i];
268		const struct vertex_buffer *vb = &state.vb[ve->buffer];
269		const void *ptr = vb->ptr + v * vb->pitch + ve->offset;
270
271		if (!ve->valid)
272			continue;
273
274		ve_out(ve, ptr);
275
276		while (++i <= state.num_ve && !state.ve[i].valid)
277			;
278
279		if (i <= state.num_ve)
280			ErrorF(", ");
281	} while (i <= state.num_ve);
282}
283
284static void primitive_out(struct kgem *kgem, uint32_t *data)
285{
286	int n;
287
288	assert((data[0] & (1<<15)) == 0); /* XXX index buffers */
289
290	for (n = 0; n < data[2]; n++) {
291		int v = data[3] + n;
292		ErrorF("	[%d:%d] = ", n, v);
293		indirect_vertex_out(kgem, v);
294		ErrorF("\n");
295	}
296}
297
298static void finish_state(struct kgem *kgem)
299{
300	memset(&state, 0, sizeof(state));
301}
302
303static void
304state_base_out(uint32_t *data, uint32_t offset, unsigned int index,
305	       const char *name)
306{
307    if (data[index] & 1)
308	kgem_debug_print(data, offset, index,
309		  "%s state base address 0x%08x\n",
310		  name, data[index] & ~1);
311    else
312	kgem_debug_print(data, offset, index,
313		  "%s state base not updated\n",
314		  name);
315}
316
317static void
318state_max_out(uint32_t *data, uint32_t offset, unsigned int index,
319	      const char *name)
320{
321	if (data[index] == 1)
322		kgem_debug_print(data, offset, index,
323			  "%s state upper bound disabled\n", name);
324	else if (data[index] & 1)
325		kgem_debug_print(data, offset, index,
326			  "%s state upper bound 0x%08x\n",
327			  name, data[index] & ~1);
328	else
329		kgem_debug_print(data, offset, index,
330			  "%s state upper bound not updated\n",
331			  name);
332}
333
334static const char *
335get_965_surfacetype(unsigned int surfacetype)
336{
337	switch (surfacetype) {
338	case 0: return "1D";
339	case 1: return "2D";
340	case 2: return "3D";
341	case 3: return "CUBE";
342	case 4: return "BUFFER";
343	case 7: return "NULL";
344	default: return "unknown";
345	}
346}
347
348static const char *
349get_965_depthformat(unsigned int depthformat)
350{
351	switch (depthformat) {
352	case 0: return "s8_z24float";
353	case 1: return "z32float";
354	case 2: return "z24s8";
355	case 5: return "z16";
356	default: return "unknown";
357	}
358}
359
360static const char *
361get_element_component(uint32_t data, int component)
362{
363	uint32_t component_control = (data >> (16 + (3 - component) * 4)) & 0x7;
364
365	switch (component_control) {
366	case 0:
367		return "nostore";
368	case 1:
369		switch (component) {
370		case 0: return "X";
371		case 1: return "Y";
372		case 2: return "Z";
373		case 3: return "W";
374		default: return "fail";
375		}
376	case 2:
377		return "0.0";
378	case 3:
379		return "1.0";
380	case 4:
381		return "0x1";
382	case 5:
383		return "VID";
384	default:
385		return "fail";
386	}
387}
388
389static const char *
390get_prim_type(uint32_t data)
391{
392	uint32_t primtype = data & 0x1f;
393
394	switch (primtype) {
395	case 0x01: return "point list";
396	case 0x02: return "line list";
397	case 0x03: return "line strip";
398	case 0x04: return "tri list";
399	case 0x05: return "tri strip";
400	case 0x06: return "tri fan";
401	case 0x07: return "quad list";
402	case 0x08: return "quad strip";
403	case 0x09: return "line list adj";
404	case 0x0a: return "line strip adj";
405	case 0x0b: return "tri list adj";
406	case 0x0c: return "tri strip adj";
407	case 0x0d: return "tri strip reverse";
408	case 0x0e: return "polygon";
409	case 0x0f: return "rect list";
410	case 0x10: return "line loop";
411	case 0x11: return "point list bf";
412	case 0x12: return "line strip cont";
413	case 0x13: return "line strip bf";
414	case 0x14: return "line strip cont bf";
415	case 0x15: return "tri fan no stipple";
416	default: return "fail";
417	}
418}
419
420struct reloc {
421	struct kgem_bo *bo;
422	void *base;
423};
424
425static void *
426get_reloc(struct kgem *kgem,
427	  void *base, const uint32_t *reloc,
428	  struct reloc *r)
429{
430	uint32_t delta = *reloc;
431
432	memset(r, 0, sizeof(*r));
433
434	if (base == 0) {
435		uint32_t handle = sizeof(uint32_t) * (reloc - kgem->batch);
436		struct kgem_bo *bo = NULL;
437		int i;
438
439		for (i = 0; i < kgem->nreloc; i++)
440			if (kgem->reloc[i].offset == handle)
441				break;
442		assert(i < kgem->nreloc);
443		handle = kgem->reloc[i].target_handle;
444		delta = kgem->reloc[i].delta;
445
446		if (handle == 0) {
447			base = kgem->batch;
448		} else {
449			list_for_each_entry(bo, &kgem->next_request->buffers, request)
450				if (bo->handle == handle)
451					break;
452			assert(&bo->request != &kgem->next_request->buffers);
453			base = kgem_bo_map__debug(kgem, bo);
454			r->bo = bo;
455			r->base = base;
456		}
457	}
458
459	return (char *)base + (delta & ~3);
460}
461
462static const char *
463gen7_filter_to_string(uint32_t filter)
464{
465	switch (filter) {
466	default:
467	case GEN7_MAPFILTER_NEAREST: return "nearest";
468	case GEN7_MAPFILTER_LINEAR: return "linear";
469	}
470}
471
472static const char *
473gen7_repeat_to_string(uint32_t repeat)
474{
475	switch (repeat) {
476	default:
477	case GEN7_TEXCOORDMODE_CLAMP_BORDER: return "border";
478	case GEN7_TEXCOORDMODE_WRAP: return "wrap";
479	case GEN7_TEXCOORDMODE_CLAMP: return "clamp";
480	case GEN7_TEXCOORDMODE_MIRROR: return "mirror";
481	}
482}
483
484static void
485gen7_decode_sampler_state(struct kgem *kgem, const uint32_t *reloc)
486{
487	const struct gen7_sampler_state *ss;
488	struct reloc r;
489	const char *min, *mag;
490	const char *s_wrap, *t_wrap, *r_wrap;
491
492	ss = get_reloc(kgem, state.dynamic_state.ptr, reloc, &r);
493
494	min = gen7_filter_to_string(ss->ss0.min_filter);
495	mag = gen7_filter_to_string(ss->ss0.mag_filter);
496
497	s_wrap = gen7_repeat_to_string(ss->ss3.s_wrap_mode);
498	t_wrap = gen7_repeat_to_string(ss->ss3.t_wrap_mode);
499	r_wrap = gen7_repeat_to_string(ss->ss3.r_wrap_mode);
500
501	ErrorF("  Sampler 0:\n");
502	ErrorF("    filter: min=%s, mag=%s\n", min, mag);
503	ErrorF("    wrap: s=%s, t=%s, r=%s\n", s_wrap, t_wrap, r_wrap);
504
505	ss++;
506	min = gen7_filter_to_string(ss->ss0.min_filter);
507	mag = gen7_filter_to_string(ss->ss0.mag_filter);
508
509	s_wrap = gen7_repeat_to_string(ss->ss3.s_wrap_mode);
510	t_wrap = gen7_repeat_to_string(ss->ss3.t_wrap_mode);
511	r_wrap = gen7_repeat_to_string(ss->ss3.r_wrap_mode);
512
513	ErrorF("  Sampler 1:\n");
514	ErrorF("    filter: min=%s, mag=%s\n", min, mag);
515	ErrorF("    wrap: s=%s, t=%s, r=%s\n", s_wrap, t_wrap, r_wrap);
516}
517
518static const char *
519gen7_blend_factor_to_string(uint32_t v)
520{
521	switch (v) {
522#define C(x) case GEN7_BLENDFACTOR_##x: return #x;
523		C(ONE);
524		C(SRC_COLOR);
525		C(SRC_ALPHA);
526		C(DST_ALPHA);
527		C(DST_COLOR);
528		C(SRC_ALPHA_SATURATE);
529		C(CONST_COLOR);
530		C(CONST_ALPHA);
531		C(SRC1_COLOR);
532		C(SRC1_ALPHA);
533		C(ZERO);
534		C(INV_SRC_COLOR);
535		C(INV_SRC_ALPHA);
536		C(INV_DST_ALPHA);
537		C(INV_DST_COLOR);
538		C(INV_CONST_COLOR);
539		C(INV_CONST_ALPHA);
540		C(INV_SRC1_COLOR);
541		C(INV_SRC1_ALPHA);
542#undef C
543	default: return "???";
544	}
545}
546
547static const char *
548gen7_blend_function_to_string(uint32_t v)
549{
550	switch (v) {
551#define C(x) case GEN7_BLENDFUNCTION_##x: return #x;
552		C(ADD);
553		C(SUBTRACT);
554		C(REVERSE_SUBTRACT);
555		C(MIN);
556		C(MAX);
557#undef C
558	default: return "???";
559	}
560}
561
562static void
563gen7_decode_blend(struct kgem *kgem, const uint32_t *reloc)
564{
565	const struct gen7_blend_state *blend;
566	struct reloc r;
567	const char *dst, *src;
568	const char *func;
569
570	blend = get_reloc(kgem, state.dynamic_state.ptr, reloc, &r);
571
572	dst = gen7_blend_factor_to_string(blend->blend0.dest_blend_factor);
573	src = gen7_blend_factor_to_string(blend->blend0.source_blend_factor);
574	func = gen7_blend_function_to_string(blend->blend0.blend_func);
575
576	ErrorF("  Blend (%s): function %s, src=%s, dst=%s\n",
577	       blend->blend0.blend_enable ? "enabled" : "disabled",
578	       func, src, dst);
579}
580
581int kgem_gen7_decode_3d(struct kgem *kgem, uint32_t offset)
582{
583	static const struct {
584		uint32_t opcode;
585		int min_len;
586		int max_len;
587		const char *name;
588	} opcodes[] = {
589		{ 0x6101, 6, 6, "STATE_BASE_ADDRESS" },
590		{ 0x6102, 2, 2 , "STATE_SIP" },
591		{ 0x6104, 1, 1, "3DSTATE_PIPELINE_SELECT" },
592		{ 0x780a, 3, 3, "3DSTATE_INDEX_BUFFER" },
593		{ 0x7900, 4, 4, "3DSTATE_DRAWING_RECTANGLE" },
594	};
595	uint32_t *data = kgem->batch + offset;
596	uint32_t op;
597	unsigned int len;
598	int i;
599	const char *name;
600
601	len = (data[0] & 0xff) + 2;
602	op = (data[0] & 0xffff0000) >> 16;
603	switch (op) {
604	case 0x6101:
605		i = 0;
606		kgem_debug_print(data, offset, i++, "STATE_BASE_ADDRESS\n");
607		assert(len == 10);
608
609		state_base_out(data, offset, i++, "general");
610		state_base_out(data, offset, i++, "surface");
611		state_base_out(data, offset, i++, "dynamic");
612		state_base_out(data, offset, i++, "indirect");
613		state_base_out(data, offset, i++, "instruction");
614
615		state_max_out(data, offset, i++, "general");
616		state_max_out(data, offset, i++, "dynamic");
617		state_max_out(data, offset, i++, "indirect");
618		state_max_out(data, offset, i++, "instruction");
619
620		gen7_update_dynamic_buffer(kgem, offset + 3);
621
622		return len;
623
624	case 0x7808:
625		assert((len - 1) % 4 == 0);
626		kgem_debug_print(data, offset, 0, "3DSTATE_VERTEX_BUFFERS\n");
627
628		for (i = 1; i < len;) {
629			gen7_update_vertex_buffer(kgem, data + i);
630
631			kgem_debug_print(data, offset, i, "buffer %d: %s, pitch %db\n",
632				  data[i] >> 26,
633				  data[i] & (1 << 20) ? "random" : "sequential",
634				  data[i] & 0x07ff);
635			i++;
636			kgem_debug_print(data, offset, i++, "buffer address\n");
637			kgem_debug_print(data, offset, i++, "max index\n");
638			kgem_debug_print(data, offset, i++, "mbz\n");
639		}
640		return len;
641
642	case 0x7809:
643		assert((len + 1) % 2 == 0);
644		kgem_debug_print(data, offset, 0, "3DSTATE_VERTEX_ELEMENTS\n");
645
646		for (i = 1; i < len;) {
647			gen7_update_vertex_elements(kgem, (i - 1)/2, data + i);
648
649			kgem_debug_print(data, offset, i, "buffer %d: %svalid, type 0x%04x, "
650				  "src offset 0x%04x bytes\n",
651				  data[i] >> 26,
652				  data[i] & (1 << 25) ? "" : "in",
653				  (data[i] >> 16) & 0x1ff,
654				  data[i] & 0x07ff);
655			i++;
656			kgem_debug_print(data, offset, i, "(%s, %s, %s, %s), "
657				  "dst offset 0x%02x bytes\n",
658				  get_element_component(data[i], 0),
659				  get_element_component(data[i], 1),
660				  get_element_component(data[i], 2),
661				  get_element_component(data[i], 3),
662				  (data[i] & 0xff) * 4);
663			i++;
664		}
665		return len;
666
667	case 0x780a:
668		assert(len == 3);
669		kgem_debug_print(data, offset, 0, "3DSTATE_INDEX_BUFFER\n");
670		kgem_debug_print(data, offset, 1, "beginning buffer address\n");
671		kgem_debug_print(data, offset, 2, "ending buffer address\n");
672		return len;
673
674	case 0x7b00:
675		assert(len == 7);
676		kgem_debug_print(data, offset, 0, "3DPRIMITIVE\n");
677		kgem_debug_print(data, offset, 1, "type %s, %s\n",
678			  get_prim_type(data[1]),
679			  (data[1] & (1 << 15)) ? "random" : "sequential");
680		kgem_debug_print(data, offset, 2, "vertex count\n");
681		kgem_debug_print(data, offset, 3, "start vertex\n");
682		kgem_debug_print(data, offset, 4, "instance count\n");
683		kgem_debug_print(data, offset, 5, "start instance\n");
684		kgem_debug_print(data, offset, 6, "index bias\n");
685		primitive_out(kgem, data);
686		return len;
687	}
688
689	/* For the rest, just dump the bytes */
690	name = NULL;
691	for (i = 0; i < ARRAY_SIZE(opcodes); i++)
692		if (op == opcodes[i].opcode) {
693			name = opcodes[i].name;
694			break;
695		}
696
697	len = (data[0] & 0xff) + 2;
698	if (name == NULL) {
699		kgem_debug_print(data, offset, 0, "unknown\n");
700	} else {
701		kgem_debug_print(data, offset, 0, "%s\n", opcodes[i].name);
702		if (opcodes[i].max_len > 1) {
703			assert(len >= opcodes[i].min_len &&
704					len <= opcodes[i].max_len);
705		}
706	}
707	for (i = 1; i < len; i++)
708		kgem_debug_print(data, offset, i, "dword %d\n", i);
709
710	return len;
711}
712
713void kgem_gen7_finish_state(struct kgem *kgem)
714{
715	finish_state(kgem);
716}
717