savage_state.c revision 152909
123353Sdfr/* savage_state.c -- State and drawing support for Savage
223353Sdfr *
323353Sdfr * Copyright 2004  Felix Kuehling
423353Sdfr * All Rights Reserved.
523353Sdfr *
623353Sdfr * Permission is hereby granted, free of charge, to any person obtaining a
723353Sdfr * copy of this software and associated documentation files (the "Software"),
823353Sdfr * to deal in the Software without restriction, including without limitation
923353Sdfr * the rights to use, copy, modify, merge, publish, distribute, sub license,
1023353Sdfr * and/or sell copies of the Software, and to permit persons to whom the
1123353Sdfr * Software is furnished to do so, subject to the following conditions:
1223353Sdfr *
1323353Sdfr * The above copyright notice and this permission notice (including the
1423353Sdfr * next paragraph) shall be included in all copies or substantial portions
1523353Sdfr * of the Software.
1623353Sdfr *
1723353Sdfr * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1823353Sdfr * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1923353Sdfr * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2023353Sdfr * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
2123353Sdfr * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
2223353Sdfr * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2323353Sdfr * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2423353Sdfr */
2523353Sdfr
2623353Sdfr#include <sys/cdefs.h>
2723353Sdfr__FBSDID("$FreeBSD: head/sys/dev/drm/savage_state.c 152909 2005-11-28 23:13:57Z anholt $");
2823353Sdfr#include "dev/drm/drmP.h"
2950476Speter#include "dev/drm/savage_drm.h"
3023353Sdfr#include "dev/drm/savage_drv.h"
3123353Sdfr
32206622Suqsvoid savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv,
3323353Sdfr			       const drm_clip_rect_t *pbox)
3423353Sdfr{
3523353Sdfr	uint32_t scstart = dev_priv->state.s3d.new_scstart;
3623353Sdfr	uint32_t scend   = dev_priv->state.s3d.new_scend;
3723353Sdfr	scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) |
3823353Sdfr		((uint32_t)pbox->x1 & 0x000007ff) |
3984306Sru		(((uint32_t)pbox->y1 << 16) & 0x07ff0000);
4084306Sru	scend   = (scend   & ~SAVAGE_SCISSOR_MASK_S3D) |
4184306Sru		(((uint32_t)pbox->x2-1) & 0x000007ff) |
4223353Sdfr		((((uint32_t)pbox->y2-1) << 16) & 0x07ff0000);
4323353Sdfr	if (scstart != dev_priv->state.s3d.scstart ||
4423353Sdfr	    scend   != dev_priv->state.s3d.scend) {
4523353Sdfr		DMA_LOCALS;
4623353Sdfr		BEGIN_DMA(4);
4723353Sdfr		DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D);
4823353Sdfr		DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2);
4923353Sdfr		DMA_WRITE(scstart);
5023353Sdfr		DMA_WRITE(scend);
51115440Shmp		dev_priv->state.s3d.scstart = scstart;
52140931Sru		dev_priv->state.s3d.scend   = scend;
53115440Shmp		dev_priv->waiting = 1;
54140931Sru		DMA_COMMIT();
55115440Shmp	}
56140931Sru}
57115440Shmp
58140931Sruvoid savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv,
5923353Sdfr			      const drm_clip_rect_t *pbox)
6023353Sdfr{
6123353Sdfr	uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0;
6223353Sdfr	uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1;
63107788Sru	drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) |
6454533Salfred		((uint32_t)pbox->x1 & 0x000007ff) |
65107788Sru		(((uint32_t)pbox->y1 << 12) & 0x00fff000);
66121382Shmp	drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) |
67121382Shmp		(((uint32_t)pbox->x2-1) & 0x000007ff) |
6854533Salfred		((((uint32_t)pbox->y2-1) << 12) & 0x00fff000);
69140931Sru	if (drawctrl0 != dev_priv->state.s4.drawctrl0 ||
7023353Sdfr	    drawctrl1 != dev_priv->state.s4.drawctrl1) {
71140931Sru		DMA_LOCALS;
7223353Sdfr		BEGIN_DMA(4);
73140931Sru		DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D);
7423353Sdfr		DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2);
75140931Sru		DMA_WRITE(drawctrl0);
7623353Sdfr		DMA_WRITE(drawctrl1);
77140931Sru		dev_priv->state.s4.drawctrl0 = drawctrl0;
7823353Sdfr		dev_priv->state.s4.drawctrl1 = drawctrl1;
7923353Sdfr		dev_priv->waiting = 1;
80140931Sru		DMA_COMMIT();
8123353Sdfr	}
82140931Sru}
8323353Sdfr
8423353Sdfrstatic int savage_verify_texaddr(drm_savage_private_t *dev_priv, int unit,
8523353Sdfr				 uint32_t addr)
8623353Sdfr{
8723353Sdfr	if ((addr & 6) != 2) { /* reserved bits */
8823353Sdfr		DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
8923467Smpp		return DRM_ERR(EINVAL);
9078278Srwatson	}
9178278Srwatson	if (!(addr & 1)) { /* local */
9278278Srwatson		addr &= ~7;
9323353Sdfr		if (addr <  dev_priv->texture_offset ||
94107788Sru		    addr >= dev_priv->texture_offset+dev_priv->texture_size) {
9578278Srwatson			DRM_ERROR("bad texAddr%d %08x (local addr out of range)\n",
9678278Srwatson				  unit, addr);
9778278Srwatson			return DRM_ERR(EINVAL);
9823353Sdfr		}
9923353Sdfr	} else { /* AGP */
10029966Swosch		if (!dev_priv->agp_textures) {
10129966Swosch			DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
10223353Sdfr				  unit, addr);
103147647Shmp			return DRM_ERR(EINVAL);
10434504Scharnier		}
105		addr &= ~7;
106		if (addr < dev_priv->agp_textures->offset ||
107		    addr >= (dev_priv->agp_textures->offset +
108			     dev_priv->agp_textures->size)) {
109			DRM_ERROR("bad texAddr%d %08x (AGP addr out of range)\n",
110				  unit, addr);
111			return DRM_ERR(EINVAL);
112		}
113	}
114	return 0;
115}
116
117#define SAVE_STATE(reg,where)			\
118	if(start <= reg && start+count > reg)	\
119		dev_priv->state.where = regs[reg - start]
120#define SAVE_STATE_MASK(reg,where,mask) do {			\
121	if(start <= reg && start+count > reg) {			\
122		uint32_t tmp;					\
123		tmp = regs[reg - start];			\
124		dev_priv->state.where = (tmp & (mask)) |	\
125			(dev_priv->state.where & ~(mask));	\
126	}							\
127} while (0)
128static int savage_verify_state_s3d(drm_savage_private_t *dev_priv,
129				   unsigned int start, unsigned int count,
130				   const uint32_t *regs)
131{
132	if (start < SAVAGE_TEXPALADDR_S3D ||
133	    start+count-1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
134		DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
135			  start, start+count-1);
136		return DRM_ERR(EINVAL);
137	}
138
139	SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
140			~SAVAGE_SCISSOR_MASK_S3D);
141	SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend,
142			~SAVAGE_SCISSOR_MASK_S3D);
143
144	/* if any texture regs were changed ... */
145	if (start <= SAVAGE_TEXCTRL_S3D &&
146	    start+count > SAVAGE_TEXPALADDR_S3D) {
147		/* ... check texture state */
148		SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl);
149		SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr);
150		if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK)
151			return savage_verify_texaddr(
152				dev_priv, 0, dev_priv->state.s3d.texaddr);
153	}
154
155	return 0;
156}
157
158static int savage_verify_state_s4(drm_savage_private_t *dev_priv,
159				  unsigned int start, unsigned int count,
160				  const uint32_t *regs)
161{
162	int ret = 0;
163
164	if (start < SAVAGE_DRAWLOCALCTRL_S4 ||
165	    start+count-1 > SAVAGE_TEXBLENDCOLOR_S4) {
166		DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
167			  start, start+count-1);
168		return DRM_ERR(EINVAL);
169	}
170
171	SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
172			~SAVAGE_SCISSOR_MASK_S4);
173	SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1,
174			~SAVAGE_SCISSOR_MASK_S4);
175
176	/* if any texture regs were changed ... */
177	if (start <= SAVAGE_TEXDESCR_S4 &&
178	    start+count > SAVAGE_TEXPALADDR_S4) {
179		/* ... check texture state */
180		SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr);
181		SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0);
182		SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1);
183		if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK)
184			ret |= savage_verify_texaddr(
185				dev_priv, 0, dev_priv->state.s4.texaddr0);
186		if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK)
187			ret |= savage_verify_texaddr(
188				dev_priv, 1, dev_priv->state.s4.texaddr1);
189	}
190
191	return ret;
192}
193#undef SAVE_STATE
194#undef SAVE_STATE_MASK
195
196static int savage_dispatch_state(drm_savage_private_t *dev_priv,
197				 const drm_savage_cmd_header_t *cmd_header,
198				 const uint32_t *regs)
199{
200	unsigned int count = cmd_header->state.count;
201	unsigned int start = cmd_header->state.start;
202	unsigned int count2 = 0;
203	unsigned int bci_size;
204	int ret;
205	DMA_LOCALS;
206
207	if (!count)
208		return 0;
209
210	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
211		ret = savage_verify_state_s3d(dev_priv, start, count, regs);
212		if (ret != 0)
213			return ret;
214		/* scissor regs are emitted in savage_dispatch_draw */
215		if (start < SAVAGE_SCSTART_S3D) {
216			if (start+count > SAVAGE_SCEND_S3D+1)
217				count2 = count - (SAVAGE_SCEND_S3D+1 - start);
218			if (start+count > SAVAGE_SCSTART_S3D)
219				count = SAVAGE_SCSTART_S3D - start;
220		} else if (start <= SAVAGE_SCEND_S3D) {
221			if (start+count > SAVAGE_SCEND_S3D+1) {
222				count -= SAVAGE_SCEND_S3D+1 - start;
223				start = SAVAGE_SCEND_S3D+1;
224			} else
225				return 0;
226		}
227	} else {
228		ret = savage_verify_state_s4(dev_priv, start, count, regs);
229		if (ret != 0)
230			return ret;
231		/* scissor regs are emitted in savage_dispatch_draw */
232		if (start < SAVAGE_DRAWCTRL0_S4) {
233			if (start+count > SAVAGE_DRAWCTRL1_S4+1)
234				count2 = count - (SAVAGE_DRAWCTRL1_S4+1 - start);
235			if (start+count > SAVAGE_DRAWCTRL0_S4)
236				count = SAVAGE_DRAWCTRL0_S4 - start;
237		} else if (start <= SAVAGE_DRAWCTRL1_S4) {
238			if (start+count > SAVAGE_DRAWCTRL1_S4+1) {
239				count -= SAVAGE_DRAWCTRL1_S4+1 - start;
240				start = SAVAGE_DRAWCTRL1_S4+1;
241			} else
242				return 0;
243		}
244	}
245
246	bci_size = count + (count+254)/255 + count2 + (count2+254)/255;
247
248	if (cmd_header->state.global) {
249		BEGIN_DMA(bci_size+1);
250		DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
251		dev_priv->waiting = 1;
252	} else {
253		BEGIN_DMA(bci_size);
254	}
255
256	do {
257		while (count > 0) {
258			unsigned int n = count < 255 ? count : 255;
259			DMA_SET_REGISTERS(start, n);
260			DMA_COPY(regs, n);
261			count -= n;
262			start += n;
263			regs += n;
264		}
265		start += 2;
266		regs += 2;
267		count = count2;
268		count2 = 0;
269	} while (count);
270
271	DMA_COMMIT();
272
273	return 0;
274}
275
276static int savage_dispatch_dma_prim(drm_savage_private_t *dev_priv,
277				    const drm_savage_cmd_header_t *cmd_header,
278				    const drm_buf_t *dmabuf)
279{
280	unsigned char reorder = 0;
281	unsigned int prim = cmd_header->prim.prim;
282	unsigned int skip = cmd_header->prim.skip;
283	unsigned int n = cmd_header->prim.count;
284	unsigned int start = cmd_header->prim.start;
285	unsigned int i;
286	BCI_LOCALS;
287
288	if (!dmabuf) {
289	    DRM_ERROR("called without dma buffers!\n");
290	    return DRM_ERR(EINVAL);
291	}
292
293	if (!n)
294		return 0;
295
296	switch (prim) {
297	case SAVAGE_PRIM_TRILIST_201:
298		reorder = 1;
299		prim = SAVAGE_PRIM_TRILIST;
300	case SAVAGE_PRIM_TRILIST:
301		if (n % 3 != 0) {
302			DRM_ERROR("wrong number of vertices %u in TRILIST\n",
303				  n);
304			return DRM_ERR(EINVAL);
305		}
306		break;
307	case SAVAGE_PRIM_TRISTRIP:
308	case SAVAGE_PRIM_TRIFAN:
309		if (n < 3) {
310			DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",
311				  n);
312			return DRM_ERR(EINVAL);
313		}
314		break;
315	default:
316		DRM_ERROR("invalid primitive type %u\n", prim);
317		return DRM_ERR(EINVAL);
318	}
319
320	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
321		if (skip != 0) {
322			DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
323				  skip);
324			return DRM_ERR(EINVAL);
325		}
326	} else {
327		unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
328			(skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
329			(skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
330		if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
331			DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
332				  skip);
333			return DRM_ERR(EINVAL);
334		}
335		if (reorder) {
336			DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
337			return DRM_ERR(EINVAL);
338		}
339	}
340
341	if (start + n > dmabuf->total/32) {
342		DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
343			  start, start + n - 1, dmabuf->total/32);
344		return DRM_ERR(EINVAL);
345	}
346
347	/* Vertex DMA doesn't work with command DMA at the same time,
348	 * so we use BCI_... to submit commands here. Flush buffered
349	 * faked DMA first. */
350	DMA_FLUSH();
351
352	if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
353		BEGIN_BCI(2);
354		BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
355		BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
356		dev_priv->state.common.vbaddr = dmabuf->bus_address;
357	}
358	if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
359		/* Workaround for what looks like a hardware bug. If a
360		 * WAIT_3D_IDLE was emitted some time before the
361		 * indexed drawing command then the engine will lock
362		 * up. There are two known workarounds:
363		 * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
364		BEGIN_BCI(63);
365		for (i = 0; i < 63; ++i)
366			BCI_WRITE(BCI_CMD_WAIT);
367		dev_priv->waiting = 0;
368	}
369
370	prim <<= 25;
371	while (n != 0) {
372		/* Can emit up to 255 indices (85 triangles) at once. */
373		unsigned int count = n > 255 ? 255 : n;
374		if (reorder) {
375			/* Need to reorder indices for correct flat
376			 * shading while preserving the clock sense
377			 * for correct culling. Only on Savage3D. */
378			int reorder[3] = {-1, -1, -1};
379			reorder[start%3] = 2;
380
381			BEGIN_BCI((count+1+1)/2);
382			BCI_DRAW_INDICES_S3D(count, prim, start+2);
383
384			for (i = start+1; i+1 < start+count; i += 2)
385				BCI_WRITE((i + reorder[i % 3]) |
386					  ((i+1 + reorder[(i+1) % 3]) << 16));
387			if (i < start+count)
388				BCI_WRITE(i + reorder[i%3]);
389		} else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
390			BEGIN_BCI((count+1+1)/2);
391			BCI_DRAW_INDICES_S3D(count, prim, start);
392
393			for (i = start+1; i+1 < start+count; i += 2)
394				BCI_WRITE(i | ((i+1) << 16));
395			if (i < start+count)
396				BCI_WRITE(i);
397		} else {
398			BEGIN_BCI((count+2+1)/2);
399			BCI_DRAW_INDICES_S4(count, prim, skip);
400
401			for (i = start; i+1 < start+count; i += 2)
402				BCI_WRITE(i | ((i+1) << 16));
403			if (i < start+count)
404				BCI_WRITE(i);
405		}
406
407		start += count;
408		n -= count;
409
410		prim |= BCI_CMD_DRAW_CONT;
411	}
412
413	return 0;
414}
415
416static int savage_dispatch_vb_prim(drm_savage_private_t *dev_priv,
417				   const drm_savage_cmd_header_t *cmd_header,
418				   const uint32_t *vtxbuf, unsigned int vb_size,
419				   unsigned int vb_stride)
420{
421	unsigned char reorder = 0;
422	unsigned int prim = cmd_header->prim.prim;
423	unsigned int skip = cmd_header->prim.skip;
424	unsigned int n = cmd_header->prim.count;
425	unsigned int start = cmd_header->prim.start;
426	unsigned int vtx_size;
427	unsigned int i;
428	DMA_LOCALS;
429
430	if (!n)
431		return 0;
432
433	switch (prim) {
434	case SAVAGE_PRIM_TRILIST_201:
435		reorder = 1;
436		prim = SAVAGE_PRIM_TRILIST;
437	case SAVAGE_PRIM_TRILIST:
438		if (n % 3 != 0) {
439			DRM_ERROR("wrong number of vertices %u in TRILIST\n",
440				  n);
441			return DRM_ERR(EINVAL);
442		}
443		break;
444	case SAVAGE_PRIM_TRISTRIP:
445	case SAVAGE_PRIM_TRIFAN:
446		if (n < 3) {
447			DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",
448				  n);
449			return DRM_ERR(EINVAL);
450		}
451		break;
452	default:
453		DRM_ERROR("invalid primitive type %u\n", prim);
454		return DRM_ERR(EINVAL);
455	}
456
457	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
458		if (skip > SAVAGE_SKIP_ALL_S3D) {
459			DRM_ERROR("invalid skip flags 0x%04x\n", skip);
460			return DRM_ERR(EINVAL);
461		}
462		vtx_size = 8; /* full vertex */
463	} else {
464		if (skip > SAVAGE_SKIP_ALL_S4) {
465			DRM_ERROR("invalid skip flags 0x%04x\n", skip);
466			return DRM_ERR(EINVAL);
467		}
468		vtx_size = 10; /* full vertex */
469	}
470
471	vtx_size -= (skip & 1) + (skip >> 1 & 1) +
472		(skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
473		(skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
474
475	if (vtx_size > vb_stride) {
476		DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
477			  vtx_size, vb_stride);
478		return DRM_ERR(EINVAL);
479	}
480
481	if (start + n > vb_size / (vb_stride*4)) {
482		DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
483			  start, start + n - 1, vb_size / (vb_stride*4));
484		return DRM_ERR(EINVAL);
485	}
486
487	prim <<= 25;
488	while (n != 0) {
489		/* Can emit up to 255 vertices (85 triangles) at once. */
490		unsigned int count = n > 255 ? 255 : n;
491		if (reorder) {
492			/* Need to reorder vertices for correct flat
493			 * shading while preserving the clock sense
494			 * for correct culling. Only on Savage3D. */
495			int reorder[3] = {-1, -1, -1};
496			reorder[start%3] = 2;
497
498			BEGIN_DMA(count*vtx_size+1);
499			DMA_DRAW_PRIMITIVE(count, prim, skip);
500
501			for (i = start; i < start+count; ++i) {
502				unsigned int j = i + reorder[i % 3];
503				DMA_COPY(&vtxbuf[vb_stride*j], vtx_size);
504			}
505
506			DMA_COMMIT();
507		} else {
508			BEGIN_DMA(count*vtx_size+1);
509			DMA_DRAW_PRIMITIVE(count, prim, skip);
510
511			if (vb_stride == vtx_size) {
512				DMA_COPY(&vtxbuf[vb_stride*start],
513					 vtx_size*count);
514			} else {
515				for (i = start; i < start+count; ++i) {
516					DMA_COPY(&vtxbuf[vb_stride*i],
517						 vtx_size);
518				}
519			}
520
521			DMA_COMMIT();
522		}
523
524		start += count;
525		n -= count;
526
527		prim |= BCI_CMD_DRAW_CONT;
528	}
529
530	return 0;
531}
532
533static int savage_dispatch_dma_idx(drm_savage_private_t *dev_priv,
534				   const drm_savage_cmd_header_t *cmd_header,
535				   const uint16_t *idx,
536				   const drm_buf_t *dmabuf)
537{
538	unsigned char reorder = 0;
539	unsigned int prim = cmd_header->idx.prim;
540	unsigned int skip = cmd_header->idx.skip;
541	unsigned int n = cmd_header->idx.count;
542	unsigned int i;
543	BCI_LOCALS;
544
545	if (!dmabuf) {
546	    DRM_ERROR("called without dma buffers!\n");
547	    return DRM_ERR(EINVAL);
548	}
549
550	if (!n)
551		return 0;
552
553	switch (prim) {
554	case SAVAGE_PRIM_TRILIST_201:
555		reorder = 1;
556		prim = SAVAGE_PRIM_TRILIST;
557	case SAVAGE_PRIM_TRILIST:
558		if (n % 3 != 0) {
559			DRM_ERROR("wrong number of indices %u in TRILIST\n",
560				  n);
561			return DRM_ERR(EINVAL);
562		}
563		break;
564	case SAVAGE_PRIM_TRISTRIP:
565	case SAVAGE_PRIM_TRIFAN:
566		if (n < 3) {
567			DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",
568				  n);
569			return DRM_ERR(EINVAL);
570		}
571		break;
572	default:
573		DRM_ERROR("invalid primitive type %u\n", prim);
574		return DRM_ERR(EINVAL);
575	}
576
577	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
578		if (skip != 0) {
579			DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
580				  skip);
581			return DRM_ERR(EINVAL);
582		}
583	} else {
584		unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
585			(skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
586			(skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
587		if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
588			DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
589				  skip);
590			return DRM_ERR(EINVAL);
591		}
592		if (reorder) {
593			DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
594			return DRM_ERR(EINVAL);
595		}
596	}
597
598	/* Vertex DMA doesn't work with command DMA at the same time,
599	 * so we use BCI_... to submit commands here. Flush buffered
600	 * faked DMA first. */
601	DMA_FLUSH();
602
603	if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
604		BEGIN_BCI(2);
605		BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
606		BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
607		dev_priv->state.common.vbaddr = dmabuf->bus_address;
608	}
609	if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
610		/* Workaround for what looks like a hardware bug. If a
611		 * WAIT_3D_IDLE was emitted some time before the
612		 * indexed drawing command then the engine will lock
613		 * up. There are two known workarounds:
614		 * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
615		BEGIN_BCI(63);
616		for (i = 0; i < 63; ++i)
617			BCI_WRITE(BCI_CMD_WAIT);
618		dev_priv->waiting = 0;
619	}
620
621	prim <<= 25;
622	while (n != 0) {
623		/* Can emit up to 255 indices (85 triangles) at once. */
624		unsigned int count = n > 255 ? 255 : n;
625
626		/* check indices */
627		for (i = 0; i < count; ++i) {
628			if (idx[i] > dmabuf->total/32) {
629				DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
630					  i, idx[i], dmabuf->total/32);
631				return DRM_ERR(EINVAL);
632			}
633		}
634
635		if (reorder) {
636			/* Need to reorder indices for correct flat
637			 * shading while preserving the clock sense
638			 * for correct culling. Only on Savage3D. */
639			int reorder[3] = {2, -1, -1};
640
641			BEGIN_BCI((count+1+1)/2);
642			BCI_DRAW_INDICES_S3D(count, prim, idx[2]);
643
644			for (i = 1; i+1 < count; i += 2)
645				BCI_WRITE(idx[i + reorder[i % 3]] |
646					  (idx[i+1 + reorder[(i+1) % 3]] << 16));
647			if (i < count)
648				BCI_WRITE(idx[i + reorder[i%3]]);
649		} else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
650			BEGIN_BCI((count+1+1)/2);
651			BCI_DRAW_INDICES_S3D(count, prim, idx[0]);
652
653			for (i = 1; i+1 < count; i += 2)
654				BCI_WRITE(idx[i] | (idx[i+1] << 16));
655			if (i < count)
656				BCI_WRITE(idx[i]);
657		} else {
658			BEGIN_BCI((count+2+1)/2);
659			BCI_DRAW_INDICES_S4(count, prim, skip);
660
661			for (i = 0; i+1 < count; i += 2)
662				BCI_WRITE(idx[i] | (idx[i+1] << 16));
663			if (i < count)
664				BCI_WRITE(idx[i]);
665		}
666
667		idx += count;
668		n -= count;
669
670		prim |= BCI_CMD_DRAW_CONT;
671	}
672
673	return 0;
674}
675
676static int savage_dispatch_vb_idx(drm_savage_private_t *dev_priv,
677				  const drm_savage_cmd_header_t *cmd_header,
678				  const uint16_t *idx,
679				  const uint32_t *vtxbuf,
680				  unsigned int vb_size,
681				  unsigned int vb_stride)
682{
683	unsigned char reorder = 0;
684	unsigned int prim = cmd_header->idx.prim;
685	unsigned int skip = cmd_header->idx.skip;
686	unsigned int n = cmd_header->idx.count;
687	unsigned int vtx_size;
688	unsigned int i;
689	DMA_LOCALS;
690
691	if (!n)
692		return 0;
693
694	switch (prim) {
695	case SAVAGE_PRIM_TRILIST_201:
696		reorder = 1;
697		prim = SAVAGE_PRIM_TRILIST;
698	case SAVAGE_PRIM_TRILIST:
699		if (n % 3 != 0) {
700			DRM_ERROR("wrong number of indices %u in TRILIST\n",
701				  n);
702			return DRM_ERR(EINVAL);
703		}
704		break;
705	case SAVAGE_PRIM_TRISTRIP:
706	case SAVAGE_PRIM_TRIFAN:
707		if (n < 3) {
708			DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",
709				  n);
710			return DRM_ERR(EINVAL);
711		}
712		break;
713	default:
714		DRM_ERROR("invalid primitive type %u\n", prim);
715		return DRM_ERR(EINVAL);
716	}
717
718	if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
719		if (skip > SAVAGE_SKIP_ALL_S3D) {
720			DRM_ERROR("invalid skip flags 0x%04x\n", skip);
721			return DRM_ERR(EINVAL);
722		}
723		vtx_size = 8; /* full vertex */
724	} else {
725		if (skip > SAVAGE_SKIP_ALL_S4) {
726			DRM_ERROR("invalid skip flags 0x%04x\n", skip);
727			return DRM_ERR(EINVAL);
728		}
729		vtx_size = 10; /* full vertex */
730	}
731
732	vtx_size -= (skip & 1) + (skip >> 1 & 1) +
733		(skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
734		(skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
735
736	if (vtx_size > vb_stride) {
737		DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
738			  vtx_size, vb_stride);
739		return DRM_ERR(EINVAL);
740	}
741
742	prim <<= 25;
743	while (n != 0) {
744		/* Can emit up to 255 vertices (85 triangles) at once. */
745		unsigned int count = n > 255 ? 255 : n;
746
747		/* Check indices */
748		for (i = 0; i < count; ++i) {
749			if (idx[i] > vb_size / (vb_stride*4)) {
750				DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
751					  i, idx[i],  vb_size / (vb_stride*4));
752				return DRM_ERR(EINVAL);
753			}
754		}
755
756		if (reorder) {
757			/* Need to reorder vertices for correct flat
758			 * shading while preserving the clock sense
759			 * for correct culling. Only on Savage3D. */
760			int reorder[3] = {2, -1, -1};
761
762			BEGIN_DMA(count*vtx_size+1);
763			DMA_DRAW_PRIMITIVE(count, prim, skip);
764
765			for (i = 0; i < count; ++i) {
766				unsigned int j = idx[i + reorder[i % 3]];
767				DMA_COPY(&vtxbuf[vb_stride*j], vtx_size);
768			}
769
770			DMA_COMMIT();
771		} else {
772			BEGIN_DMA(count*vtx_size+1);
773			DMA_DRAW_PRIMITIVE(count, prim, skip);
774
775			for (i = 0; i < count; ++i) {
776				unsigned int j = idx[i];
777				DMA_COPY(&vtxbuf[vb_stride*j], vtx_size);
778			}
779
780			DMA_COMMIT();
781		}
782
783		idx += count;
784		n -= count;
785
786		prim |= BCI_CMD_DRAW_CONT;
787	}
788
789	return 0;
790}
791
792static int savage_dispatch_clear(drm_savage_private_t *dev_priv,
793				 const drm_savage_cmd_header_t *cmd_header,
794				 const drm_savage_cmd_header_t *data,
795				 unsigned int nbox,
796				 const drm_clip_rect_t *boxes)
797{
798	unsigned int flags = cmd_header->clear0.flags;
799	unsigned int clear_cmd;
800	unsigned int i, nbufs;
801	DMA_LOCALS;
802
803	if (nbox == 0)
804		return 0;
805
806	clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
807		BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW;
808	BCI_CMD_SET_ROP(clear_cmd,0xCC);
809
810	nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) +
811		((flags & SAVAGE_BACK) ? 1 : 0) +
812		((flags & SAVAGE_DEPTH) ? 1 : 0);
813	if (nbufs == 0)
814		return 0;
815
816	if (data->clear1.mask != 0xffffffff) {
817		/* set mask */
818		BEGIN_DMA(2);
819		DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
820		DMA_WRITE(data->clear1.mask);
821		DMA_COMMIT();
822	}
823	for (i = 0; i < nbox; ++i) {
824		unsigned int x, y, w, h;
825		unsigned int buf;
826
827		x = boxes[i].x1, y = boxes[i].y1;
828		w = boxes[i].x2 - boxes[i].x1;
829		h = boxes[i].y2 - boxes[i].y1;
830		BEGIN_DMA(nbufs*6);
831		for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) {
832			if (!(flags & buf))
833				continue;
834			DMA_WRITE(clear_cmd);
835			switch(buf) {
836			case SAVAGE_FRONT:
837				DMA_WRITE(dev_priv->front_offset);
838				DMA_WRITE(dev_priv->front_bd);
839				break;
840			case SAVAGE_BACK:
841				DMA_WRITE(dev_priv->back_offset);
842				DMA_WRITE(dev_priv->back_bd);
843				break;
844			case SAVAGE_DEPTH:
845				DMA_WRITE(dev_priv->depth_offset);
846				DMA_WRITE(dev_priv->depth_bd);
847				break;
848			}
849			DMA_WRITE(data->clear1.value);
850			DMA_WRITE(BCI_X_Y(x, y));
851			DMA_WRITE(BCI_W_H(w, h));
852		}
853		DMA_COMMIT();
854	}
855	if (data->clear1.mask != 0xffffffff) {
856		/* reset mask */
857		BEGIN_DMA(2);
858		DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
859		DMA_WRITE(0xffffffff);
860		DMA_COMMIT();
861	}
862
863	return 0;
864}
865
866static int savage_dispatch_swap(drm_savage_private_t *dev_priv,
867				unsigned int nbox, const drm_clip_rect_t *boxes)
868{
869	unsigned int swap_cmd;
870	unsigned int i;
871	DMA_LOCALS;
872
873	if (nbox == 0)
874		return 0;
875
876	swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
877		BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD;
878	BCI_CMD_SET_ROP(swap_cmd,0xCC);
879
880	for (i = 0; i < nbox; ++i) {
881		BEGIN_DMA(6);
882		DMA_WRITE(swap_cmd);
883		DMA_WRITE(dev_priv->back_offset);
884		DMA_WRITE(dev_priv->back_bd);
885		DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1));
886		DMA_WRITE(BCI_X_Y(boxes[i].x1, boxes[i].y1));
887		DMA_WRITE(BCI_W_H(boxes[i].x2-boxes[i].x1,
888				  boxes[i].y2-boxes[i].y1));
889		DMA_COMMIT();
890	}
891
892	return 0;
893}
894
895static int savage_dispatch_draw(drm_savage_private_t *dev_priv,
896				const drm_savage_cmd_header_t *start,
897				const drm_savage_cmd_header_t *end,
898				const drm_buf_t *dmabuf,
899				const unsigned int *vtxbuf,
900				unsigned int vb_size, unsigned int vb_stride,
901				unsigned int nbox,
902				const drm_clip_rect_t *boxes)
903{
904	unsigned int i, j;
905	int ret;
906
907	for (i = 0; i < nbox; ++i) {
908		const drm_savage_cmd_header_t *cmdbuf;
909		dev_priv->emit_clip_rect(dev_priv, &boxes[i]);
910
911		cmdbuf = start;
912		while (cmdbuf < end) {
913			drm_savage_cmd_header_t cmd_header;
914			cmd_header = *cmdbuf;
915			cmdbuf++;
916			switch (cmd_header.cmd.cmd) {
917			case SAVAGE_CMD_DMA_PRIM:
918				ret = savage_dispatch_dma_prim(
919					dev_priv, &cmd_header, dmabuf);
920				break;
921			case SAVAGE_CMD_VB_PRIM:
922				ret = savage_dispatch_vb_prim(
923					dev_priv, &cmd_header,
924					vtxbuf, vb_size, vb_stride);
925				break;
926			case SAVAGE_CMD_DMA_IDX:
927				j = (cmd_header.idx.count + 3) / 4;
928				/* j was check in savage_bci_cmdbuf */
929				ret = savage_dispatch_dma_idx(dev_priv,
930					&cmd_header, (const uint16_t *)cmdbuf,
931					dmabuf);
932				cmdbuf += j;
933				break;
934			case SAVAGE_CMD_VB_IDX:
935				j = (cmd_header.idx.count + 3) / 4;
936				/* j was check in savage_bci_cmdbuf */
937				ret = savage_dispatch_vb_idx(dev_priv,
938					&cmd_header, (const uint16_t *)cmdbuf,
939					(const uint32_t *)vtxbuf, vb_size,
940					vb_stride);
941				cmdbuf += j;
942				break;
943			default:
944				/* What's the best return code? EFAULT? */
945				DRM_ERROR("IMPLEMENTATION ERROR: "
946					  "non-drawing-command %d\n",
947					  cmd_header.cmd.cmd);
948				return DRM_ERR(EINVAL);
949			}
950
951			if (ret != 0)
952				return ret;
953		}
954	}
955
956	return 0;
957}
958
959int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
960{
961	DRM_DEVICE;
962	drm_savage_private_t *dev_priv = dev->dev_private;
963	drm_device_dma_t *dma = dev->dma;
964	drm_buf_t *dmabuf;
965	drm_savage_cmdbuf_t cmdbuf;
966	drm_savage_cmd_header_t *kcmd_addr = NULL;
967	drm_savage_cmd_header_t *first_draw_cmd;
968	unsigned int *kvb_addr = NULL;
969	drm_clip_rect_t *kbox_addr = NULL;
970	unsigned int i, j;
971	int ret = 0;
972
973	DRM_DEBUG("\n");
974
975	LOCK_TEST_WITH_RETURN(dev, filp);
976
977	DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *)data,
978				 sizeof(cmdbuf));
979
980	if (dma && dma->buflist) {
981		if (cmdbuf.dma_idx > dma->buf_count) {
982			DRM_ERROR("vertex buffer index %u out of range (0-%u)\n",
983				  cmdbuf.dma_idx, dma->buf_count-1);
984			return DRM_ERR(EINVAL);
985		}
986		dmabuf = dma->buflist[cmdbuf.dma_idx];
987	} else {
988		dmabuf = NULL;
989	}
990
991	/* Copy the user buffers into kernel temporary areas.  This hasn't been
992	 * a performance loss compared to VERIFYAREA_READ/
993	 * COPY_FROM_USER_UNCHECKED when done in other drivers, and is correct
994	 * for locking on FreeBSD.
995	 */
996	if (cmdbuf.size) {
997		kcmd_addr = drm_alloc(cmdbuf.size * 8, DRM_MEM_DRIVER);
998		if (kcmd_addr == NULL)
999			return ENOMEM;
1000
1001		if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf.cmd_addr,
1002				       cmdbuf.size * 8))
1003		{
1004			drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
1005			return DRM_ERR(EFAULT);
1006		}
1007		cmdbuf.cmd_addr = kcmd_addr;
1008	}
1009	if (cmdbuf.vb_size) {
1010		kvb_addr = drm_alloc(cmdbuf.vb_size, DRM_MEM_DRIVER);
1011		if (kvb_addr == NULL) {
1012			ret = DRM_ERR(ENOMEM);
1013			goto done;
1014		}
1015
1016		if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf.vb_addr,
1017				       cmdbuf.vb_size)) {
1018			ret = DRM_ERR(EFAULT);
1019			goto done;
1020		}
1021		cmdbuf.vb_addr = kvb_addr;
1022	}
1023	if (cmdbuf.nbox) {
1024		kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(drm_clip_rect_t),
1025				       DRM_MEM_DRIVER);
1026		if (kbox_addr == NULL) {
1027			ret = DRM_ERR(ENOMEM);
1028			goto done;
1029		}
1030
1031		if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr,
1032				       cmdbuf.nbox * sizeof(drm_clip_rect_t))) {
1033			ret = DRM_ERR(EFAULT);
1034			goto done;
1035		}
1036		cmdbuf.box_addr = kbox_addr;
1037	}
1038
1039	/* Make sure writes to DMA buffers are finished before sending
1040	 * DMA commands to the graphics hardware. */
1041	DRM_MEMORYBARRIER();
1042
1043	/* Coming from user space. Don't know if the Xserver has
1044	 * emitted wait commands. Assuming the worst. */
1045	dev_priv->waiting = 1;
1046
1047	i = 0;
1048	first_draw_cmd = NULL;
1049	while (i < cmdbuf.size) {
1050		drm_savage_cmd_header_t cmd_header;
1051		cmd_header = *(drm_savage_cmd_header_t *)cmdbuf.cmd_addr;
1052		cmdbuf.cmd_addr++;
1053		i++;
1054
1055		/* Group drawing commands with same state to minimize
1056		 * iterations over clip rects. */
1057		j = 0;
1058		switch (cmd_header.cmd.cmd) {
1059		case SAVAGE_CMD_DMA_IDX:
1060		case SAVAGE_CMD_VB_IDX:
1061			j = (cmd_header.idx.count + 3) / 4;
1062			if (i + j > cmdbuf.size) {
1063				DRM_ERROR("indexed drawing command extends "
1064					  "beyond end of command buffer\n");
1065				DMA_FLUSH();
1066				return DRM_ERR(EINVAL);
1067			}
1068			/* fall through */
1069		case SAVAGE_CMD_DMA_PRIM:
1070		case SAVAGE_CMD_VB_PRIM:
1071			if (!first_draw_cmd)
1072				first_draw_cmd = cmdbuf.cmd_addr-1;
1073			cmdbuf.cmd_addr += j;
1074			i += j;
1075			break;
1076		default:
1077			if (first_draw_cmd) {
1078				ret = savage_dispatch_draw (
1079					dev_priv, first_draw_cmd,
1080					cmdbuf.cmd_addr-1,
1081					dmabuf, cmdbuf.vb_addr, cmdbuf.vb_size,
1082					cmdbuf.vb_stride,
1083					cmdbuf.nbox, cmdbuf.box_addr);
1084				if (ret != 0)
1085					return ret;
1086				first_draw_cmd = NULL;
1087			}
1088		}
1089		if (first_draw_cmd)
1090			continue;
1091
1092		switch (cmd_header.cmd.cmd) {
1093		case SAVAGE_CMD_STATE:
1094			j = (cmd_header.state.count + 1) / 2;
1095			if (i + j > cmdbuf.size) {
1096				DRM_ERROR("command SAVAGE_CMD_STATE extends "
1097					  "beyond end of command buffer\n");
1098				DMA_FLUSH();
1099				ret = DRM_ERR(EINVAL);
1100				goto done;
1101			}
1102			ret = savage_dispatch_state(dev_priv, &cmd_header,
1103				(const uint32_t *)cmdbuf.cmd_addr);
1104			cmdbuf.cmd_addr += j;
1105			i += j;
1106			break;
1107		case SAVAGE_CMD_CLEAR:
1108			if (i + 1 > cmdbuf.size) {
1109				DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
1110					  "beyond end of command buffer\n");
1111				DMA_FLUSH();
1112				ret = DRM_ERR(EINVAL);
1113				goto done;
1114			}
1115			ret = savage_dispatch_clear(dev_priv, &cmd_header,
1116						    cmdbuf.cmd_addr,
1117						    cmdbuf.nbox, cmdbuf.box_addr);
1118			cmdbuf.cmd_addr++;
1119			i++;
1120			break;
1121		case SAVAGE_CMD_SWAP:
1122			ret = savage_dispatch_swap(dev_priv, cmdbuf.nbox,
1123						   cmdbuf.box_addr);
1124			break;
1125		default:
1126			DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd);
1127			DMA_FLUSH();
1128			ret = DRM_ERR(EINVAL);
1129			goto done;
1130		}
1131
1132		if (ret != 0) {
1133			DMA_FLUSH();
1134			goto done;
1135		}
1136	}
1137
1138	if (first_draw_cmd) {
1139		ret = savage_dispatch_draw (
1140			dev_priv, first_draw_cmd, cmdbuf.cmd_addr, dmabuf,
1141			cmdbuf.vb_addr, cmdbuf.vb_size, cmdbuf.vb_stride,
1142			cmdbuf.nbox, cmdbuf.box_addr);
1143		if (ret != 0) {
1144			DMA_FLUSH();
1145			goto done;
1146		}
1147	}
1148
1149	DMA_FLUSH();
1150
1151	if (dmabuf && cmdbuf.discard) {
1152		drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
1153		uint16_t event;
1154		event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
1155		SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
1156		savage_freelist_put(dev, dmabuf);
1157	}
1158
1159done:
1160	/* If we didn't need to allocate them, these'll be NULL */
1161	drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
1162	drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER);
1163	drm_free(kbox_addr, cmdbuf.nbox * sizeof(drm_clip_rect_t),
1164		 DRM_MEM_DRIVER);
1165
1166	return ret;
1167}
1168