1 /* i830_dma.c -- DMA support for the I830 -*- linux-c -*-
2 * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
27 * Authors: Rickard E. (Rik) Faith <faith@valinux.com>
28 * Jeff Hartmann <jhartmann@valinux.com>
29 * Keith Whitwell <keith@tungstengraphics.com>
30 * Abraham vd Merwe <abraham@2d3d.co.za>
39 #include <linux/interrupt.h> /* For task queue support */
40 #include <linux/pagemap.h> /* For FASTCALL on unlock_page() */
41 #include <linux/delay.h>
42 #include <asm/uaccess.h>
44 #define I830_BUF_FREE 2
45 #define I830_BUF_CLIENT 1
46 #define I830_BUF_HARDWARE 0
48 #define I830_BUF_UNMAPPED 0
49 #define I830_BUF_MAPPED 1
51 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2)
52 #define down_write down
56 static inline void i830_print_status_page(drm_device_t *dev)
58 drm_device_dma_t *dma = dev->dma;
59 drm_i830_private_t *dev_priv = dev->dev_private;
60 u32 *temp = dev_priv->hw_status_page;
63 DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]);
64 DRM_DEBUG( "hw_status: LpRing Head ptr : %x\n", temp[1]);
65 DRM_DEBUG( "hw_status: IRing Head ptr : %x\n", temp[2]);
66 DRM_DEBUG( "hw_status: Reserved : %x\n", temp[3]);
67 DRM_DEBUG( "hw_status: Driver Counter : %d\n", temp[5]);
68 for(i = 9; i < dma->buf_count + 9; i++) {
69 DRM_DEBUG( "buffer status idx : %d used: %d\n", i - 9, temp[i]);
73 static drm_buf_t *i830_freelist_get(drm_device_t *dev)
75 drm_device_dma_t *dma = dev->dma;
79 /* Linear search might not be the best solution */
81 for (i = 0; i < dma->buf_count; i++) {
82 drm_buf_t *buf = dma->buflist[ i ];
83 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
84 /* In use is already a pointer */
85 used = cmpxchg(buf_priv->in_use, I830_BUF_FREE,
87 if(used == I830_BUF_FREE) {
94 /* This should only be called if the buffer is not sent to the hardware
95 * yet, the hardware updates in use for us once its on the ring buffer.
98 static int i830_freelist_put(drm_device_t *dev, drm_buf_t *buf)
100 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
103 /* In use is already a pointer */
104 used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE);
105 if(used != I830_BUF_CLIENT) {
106 DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx);
113 static struct file_operations i830_buffer_fops = {
116 .release = DRM(release),
118 .mmap = i830_mmap_buffers,
119 .fasync = DRM(fasync),
122 int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
124 drm_file_t *priv = filp->private_data;
126 drm_i830_private_t *dev_priv;
128 drm_i830_buf_priv_t *buf_priv;
132 dev_priv = dev->dev_private;
133 buf = dev_priv->mmap_buffer;
134 buf_priv = buf->dev_private;
136 vma->vm_flags |= (VM_IO | VM_DONTCOPY);
139 buf_priv->currently_mapped = I830_BUF_MAPPED;
142 if (remap_page_range(DRM_RPR_ARG(vma) vma->vm_start,
144 vma->vm_end - vma->vm_start,
145 vma->vm_page_prot)) return -EAGAIN;
149 static int i830_map_buffer(drm_buf_t *buf, struct file *filp)
151 drm_file_t *priv = filp->private_data;
152 drm_device_t *dev = priv->dev;
153 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
154 drm_i830_private_t *dev_priv = dev->dev_private;
155 struct file_operations *old_fops;
156 unsigned long virtual;
159 if(buf_priv->currently_mapped == I830_BUF_MAPPED) return -EINVAL;
161 down_write( ¤t->mm->mmap_sem );
162 old_fops = filp->f_op;
163 filp->f_op = &i830_buffer_fops;
164 dev_priv->mmap_buffer = buf;
165 virtual = do_mmap(filp, 0, buf->total, PROT_READ|PROT_WRITE,
166 MAP_SHARED, buf->bus_address);
167 dev_priv->mmap_buffer = NULL;
168 filp->f_op = old_fops;
169 if (IS_ERR((void *)virtual)) { /* ugh */
171 DRM_ERROR("mmap error\n");
173 buf_priv->virtual = NULL;
175 buf_priv->virtual = (void __user *)virtual;
177 up_write( ¤t->mm->mmap_sem );
182 static int i830_unmap_buffer(drm_buf_t *buf)
184 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
187 if(buf_priv->currently_mapped != I830_BUF_MAPPED)
190 down_write(¤t->mm->mmap_sem);
191 retcode = do_munmap(current->mm,
192 (unsigned long)buf_priv->virtual,
193 (size_t) buf->total);
194 up_write(¤t->mm->mmap_sem);
196 buf_priv->currently_mapped = I830_BUF_UNMAPPED;
197 buf_priv->virtual = NULL;
202 static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d,
206 drm_i830_buf_priv_t *buf_priv;
209 buf = i830_freelist_get(dev);
212 DRM_DEBUG("retcode=%d\n", retcode);
216 retcode = i830_map_buffer(buf, filp);
218 i830_freelist_put(dev, buf);
219 DRM_ERROR("mapbuf failed, retcode %d\n", retcode);
223 buf_priv = buf->dev_private;
225 d->request_idx = buf->idx;
226 d->request_size = buf->total;
227 d->virtual = buf_priv->virtual;
232 int i830_dma_cleanup(drm_device_t *dev)
234 drm_device_dma_t *dma = dev->dma;
237 /* Make sure interrupts are disabled here because the uninstall ioctl
238 * may not have been called from userspace and after dev_private
239 * is freed, it's too late.
241 if ( dev->irq_enabled ) DRM(irq_uninstall)(dev);
244 if (dev->dev_private) {
246 drm_i830_private_t *dev_priv =
247 (drm_i830_private_t *) dev->dev_private;
249 if (dev_priv->ring.virtual_start) {
250 DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
251 dev_priv->ring.Size, dev);
253 if (dev_priv->hw_status_page) {
254 pci_free_consistent(dev->pdev, PAGE_SIZE,
255 dev_priv->hw_status_page,
256 dev_priv->dma_status_page);
257 /* Need to rewrite hardware status page */
258 I830_WRITE(0x02080, 0x1ffff000);
261 DRM(free)(dev->dev_private, sizeof(drm_i830_private_t),
263 dev->dev_private = NULL;
265 for (i = 0; i < dma->buf_count; i++) {
266 drm_buf_t *buf = dma->buflist[ i ];
267 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
268 if ( buf_priv->kernel_virtual && buf->total )
269 DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev);
275 int i830_wait_ring(drm_device_t *dev, int n, const char *caller)
277 drm_i830_private_t *dev_priv = dev->dev_private;
278 drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
281 unsigned int last_head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
283 end = jiffies + (HZ*3);
284 while (ring->space < n) {
285 ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
286 ring->space = ring->head - (ring->tail+8);
287 if (ring->space < 0) ring->space += ring->Size;
289 if (ring->head != last_head) {
290 end = jiffies + (HZ*3);
291 last_head = ring->head;
295 if(time_before(end, jiffies)) {
296 DRM_ERROR("space: %d wanted %d\n", ring->space, n);
297 DRM_ERROR("lockup\n");
301 dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT;
308 static void i830_kernel_lost_context(drm_device_t *dev)
310 drm_i830_private_t *dev_priv = dev->dev_private;
311 drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
313 ring->head = I830_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
314 ring->tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
315 ring->space = ring->head - (ring->tail+8);
316 if (ring->space < 0) ring->space += ring->Size;
318 if (ring->head == ring->tail)
319 dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY;
322 static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv)
324 drm_device_dma_t *dma = dev->dma;
326 u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx);
329 if(dma->buf_count > 1019) {
330 /* Not enough space in the status page for the freelist */
334 for (i = 0; i < dma->buf_count; i++) {
335 drm_buf_t *buf = dma->buflist[ i ];
336 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
338 buf_priv->in_use = hw_status++;
339 buf_priv->my_use_idx = my_idx;
342 *buf_priv->in_use = I830_BUF_FREE;
344 buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address,
350 static int i830_dma_initialize(drm_device_t *dev,
351 drm_i830_private_t *dev_priv,
352 drm_i830_init_t *init)
354 struct list_head *list;
356 memset(dev_priv, 0, sizeof(drm_i830_private_t));
358 list_for_each(list, &dev->maplist->head) {
359 drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
361 r_list->map->type == _DRM_SHM &&
362 r_list->map->flags & _DRM_CONTAINS_LOCK ) {
363 dev_priv->sarea_map = r_list->map;
368 if(!dev_priv->sarea_map) {
369 dev->dev_private = (void *)dev_priv;
370 i830_dma_cleanup(dev);
371 DRM_ERROR("can not find sarea!\n");
374 DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset );
375 if(!dev_priv->mmio_map) {
376 dev->dev_private = (void *)dev_priv;
377 i830_dma_cleanup(dev);
378 DRM_ERROR("can not find mmio map!\n");
381 DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset );
382 if(!dev_priv->buffer_map) {
383 dev->dev_private = (void *)dev_priv;
384 i830_dma_cleanup(dev);
385 DRM_ERROR("can not find dma buffer map!\n");
389 dev_priv->sarea_priv = (drm_i830_sarea_t *)
390 ((u8 *)dev_priv->sarea_map->handle +
391 init->sarea_priv_offset);
393 dev_priv->ring.Start = init->ring_start;
394 dev_priv->ring.End = init->ring_end;
395 dev_priv->ring.Size = init->ring_size;
397 dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
399 init->ring_size, dev);
401 if (dev_priv->ring.virtual_start == NULL) {
402 dev->dev_private = (void *) dev_priv;
403 i830_dma_cleanup(dev);
404 DRM_ERROR("can not ioremap virtual address for"
409 dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
411 dev_priv->w = init->w;
412 dev_priv->h = init->h;
413 dev_priv->pitch = init->pitch;
414 dev_priv->back_offset = init->back_offset;
415 dev_priv->depth_offset = init->depth_offset;
416 dev_priv->front_offset = init->front_offset;
418 dev_priv->front_di1 = init->front_offset | init->pitch_bits;
419 dev_priv->back_di1 = init->back_offset | init->pitch_bits;
420 dev_priv->zi1 = init->depth_offset | init->pitch_bits;
422 DRM_DEBUG("front_di1 %x\n", dev_priv->front_di1);
423 DRM_DEBUG("back_offset %x\n", dev_priv->back_offset);
424 DRM_DEBUG("back_di1 %x\n", dev_priv->back_di1);
425 DRM_DEBUG("pitch_bits %x\n", init->pitch_bits);
427 dev_priv->cpp = init->cpp;
428 /* We are using separate values as placeholders for mechanisms for
429 * private backbuffer/depthbuffer usage.
432 dev_priv->back_pitch = init->back_pitch;
433 dev_priv->depth_pitch = init->depth_pitch;
434 dev_priv->do_boxes = 0;
435 dev_priv->use_mi_batchbuffer_start = 0;
437 /* Program Hardware Status Page */
438 dev_priv->hw_status_page =
439 pci_alloc_consistent(dev->pdev, PAGE_SIZE,
440 &dev_priv->dma_status_page);
441 if (!dev_priv->hw_status_page) {
442 dev->dev_private = (void *)dev_priv;
443 i830_dma_cleanup(dev);
444 DRM_ERROR("Can not allocate hardware status page\n");
447 memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
448 DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page);
450 I830_WRITE(0x02080, dev_priv->dma_status_page);
451 DRM_DEBUG("Enabled hardware status page\n");
453 /* Now we need to init our freelist */
454 if(i830_freelist_init(dev, dev_priv) != 0) {
455 dev->dev_private = (void *)dev_priv;
456 i830_dma_cleanup(dev);
457 DRM_ERROR("Not enough space in the status page for"
461 dev->dev_private = (void *)dev_priv;
466 int i830_dma_init(struct inode *inode, struct file *filp,
467 unsigned int cmd, unsigned long arg)
469 drm_file_t *priv = filp->private_data;
470 drm_device_t *dev = priv->dev;
471 drm_i830_private_t *dev_priv;
472 drm_i830_init_t init;
475 if (copy_from_user(&init, (void * __user) arg, sizeof(init)))
480 dev_priv = DRM(alloc)(sizeof(drm_i830_private_t),
482 if(dev_priv == NULL) return -ENOMEM;
483 retcode = i830_dma_initialize(dev, dev_priv, &init);
485 case I830_CLEANUP_DMA:
486 retcode = i830_dma_cleanup(dev);
496 #define GFX_OP_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16))
497 #define ST1_ENABLE (1<<16)
498 #define ST1_MASK (0xffff)
500 /* Most efficient way to verify state for the i830 is as it is
501 * emitted. Non-conformant state is silently dropped.
503 static void i830EmitContextVerified( drm_device_t *dev,
506 drm_i830_private_t *dev_priv = dev->dev_private;
511 BEGIN_LP_RING( I830_CTX_SETUP_SIZE + 4 );
513 for ( i = 0 ; i < I830_CTXREG_BLENDCOLR0 ; i++ ) {
515 if ((tmp & (7<<29)) == CMD_3D &&
516 (tmp & (0x1f<<24)) < (0x1d<<24)) {
520 DRM_ERROR("Skipping %d\n", i);
524 OUT_RING( STATE3D_CONST_BLEND_COLOR_CMD );
525 OUT_RING( code[I830_CTXREG_BLENDCOLR] );
528 for ( i = I830_CTXREG_VF ; i < I830_CTXREG_MCSB0 ; i++ ) {
530 if ((tmp & (7<<29)) == CMD_3D &&
531 (tmp & (0x1f<<24)) < (0x1d<<24)) {
535 DRM_ERROR("Skipping %d\n", i);
539 OUT_RING( STATE3D_MAP_COORD_SETBIND_CMD );
540 OUT_RING( code[I830_CTXREG_MCSB1] );
549 static void i830EmitTexVerified( drm_device_t *dev, unsigned int *code )
551 drm_i830_private_t *dev_priv = dev->dev_private;
556 if (code[I830_TEXREG_MI0] == GFX_OP_MAP_INFO ||
557 (code[I830_TEXREG_MI0] & ~(0xf*LOAD_TEXTURE_MAP0)) ==
558 (STATE3D_LOAD_STATE_IMMEDIATE_2|4)) {
560 BEGIN_LP_RING( I830_TEX_SETUP_SIZE );
562 OUT_RING( code[I830_TEXREG_MI0] ); /* TM0LI */
563 OUT_RING( code[I830_TEXREG_MI1] ); /* TM0S0 */
564 OUT_RING( code[I830_TEXREG_MI2] ); /* TM0S1 */
565 OUT_RING( code[I830_TEXREG_MI3] ); /* TM0S2 */
566 OUT_RING( code[I830_TEXREG_MI4] ); /* TM0S3 */
567 OUT_RING( code[I830_TEXREG_MI5] ); /* TM0S4 */
569 for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) {
581 printk("rejected packet %x\n", code[0]);
584 static void i830EmitTexBlendVerified( drm_device_t *dev,
588 drm_i830_private_t *dev_priv = dev->dev_private;
596 BEGIN_LP_RING( num + 1 );
598 for ( i = 0 ; i < num ; i++ ) {
610 static void i830EmitTexPalette( drm_device_t *dev,
611 unsigned int *palette,
615 drm_i830_private_t *dev_priv = dev->dev_private;
621 BEGIN_LP_RING( 258 );
624 OUT_RING(CMD_OP_MAP_PALETTE_LOAD |
628 OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number));
630 for(i = 0; i < 256; i++) {
631 OUT_RING(palette[i]);
634 /* KW: WHERE IS THE ADVANCE_LP_RING? This is effectively a noop!
638 /* Need to do some additional checking when setting the dest buffer.
640 static void i830EmitDestVerified( drm_device_t *dev,
643 drm_i830_private_t *dev_priv = dev->dev_private;
647 BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 10 );
650 tmp = code[I830_DESTREG_CBUFADDR];
651 if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) {
652 if (((int)outring) & 8) {
657 OUT_RING( CMD_OP_DESTBUFFER_INFO );
658 OUT_RING( BUF_3D_ID_COLOR_BACK |
659 BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) |
664 OUT_RING( CMD_OP_DESTBUFFER_INFO );
665 OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE |
666 BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp));
667 OUT_RING( dev_priv->zi1 );
670 DRM_ERROR("bad di1 %x (allow %x or %x)\n",
671 tmp, dev_priv->front_di1, dev_priv->back_di1);
678 OUT_RING( GFX_OP_DESTBUFFER_VARS );
679 OUT_RING( code[I830_DESTREG_DV1] );
681 OUT_RING( GFX_OP_DRAWRECT_INFO );
682 OUT_RING( code[I830_DESTREG_DR1] );
683 OUT_RING( code[I830_DESTREG_DR2] );
684 OUT_RING( code[I830_DESTREG_DR3] );
685 OUT_RING( code[I830_DESTREG_DR4] );
687 /* Need to verify this */
688 tmp = code[I830_DESTREG_SENABLE];
689 if((tmp & ~0x3) == GFX_OP_SCISSOR_ENABLE) {
692 DRM_ERROR("bad scissor enable\n");
696 OUT_RING( GFX_OP_SCISSOR_RECT );
697 OUT_RING( code[I830_DESTREG_SR1] );
698 OUT_RING( code[I830_DESTREG_SR2] );
704 static void i830EmitStippleVerified( drm_device_t *dev,
707 drm_i830_private_t *dev_priv = dev->dev_private;
711 OUT_RING( GFX_OP_STIPPLE );
717 static void i830EmitState( drm_device_t *dev )
719 drm_i830_private_t *dev_priv = dev->dev_private;
720 drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
721 unsigned int dirty = sarea_priv->dirty;
723 DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
725 if (dirty & I830_UPLOAD_BUFFERS) {
726 i830EmitDestVerified( dev, sarea_priv->BufferState );
727 sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS;
730 if (dirty & I830_UPLOAD_CTX) {
731 i830EmitContextVerified( dev, sarea_priv->ContextState );
732 sarea_priv->dirty &= ~I830_UPLOAD_CTX;
735 if (dirty & I830_UPLOAD_TEX0) {
736 i830EmitTexVerified( dev, sarea_priv->TexState[0] );
737 sarea_priv->dirty &= ~I830_UPLOAD_TEX0;
740 if (dirty & I830_UPLOAD_TEX1) {
741 i830EmitTexVerified( dev, sarea_priv->TexState[1] );
742 sarea_priv->dirty &= ~I830_UPLOAD_TEX1;
745 if (dirty & I830_UPLOAD_TEXBLEND0) {
746 i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[0],
747 sarea_priv->TexBlendStateWordsUsed[0]);
748 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND0;
751 if (dirty & I830_UPLOAD_TEXBLEND1) {
752 i830EmitTexBlendVerified( dev, sarea_priv->TexBlendState[1],
753 sarea_priv->TexBlendStateWordsUsed[1]);
754 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND1;
757 if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) {
758 i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1);
760 if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) {
761 i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0);
762 sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0);
764 if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) {
765 i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0);
766 sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1);
772 if (dirty & I830_UPLOAD_TEX_PALETTE_N(2)) {
773 i830EmitTexPalette(dev, sarea_priv->Palette2[0], 0, 0);
774 sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
776 if (dirty & I830_UPLOAD_TEX_PALETTE_N(3)) {
777 i830EmitTexPalette(dev, sarea_priv->Palette2[1], 1, 0);
778 sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2);
785 if (dirty & I830_UPLOAD_STIPPLE) {
786 i830EmitStippleVerified( dev,
787 sarea_priv->StippleState);
788 sarea_priv->dirty &= ~I830_UPLOAD_STIPPLE;
791 if (dirty & I830_UPLOAD_TEX2) {
792 i830EmitTexVerified( dev, sarea_priv->TexState2 );
793 sarea_priv->dirty &= ~I830_UPLOAD_TEX2;
796 if (dirty & I830_UPLOAD_TEX3) {
797 i830EmitTexVerified( dev, sarea_priv->TexState3 );
798 sarea_priv->dirty &= ~I830_UPLOAD_TEX3;
802 if (dirty & I830_UPLOAD_TEXBLEND2) {
803 i830EmitTexBlendVerified(
805 sarea_priv->TexBlendState2,
806 sarea_priv->TexBlendStateWordsUsed2);
808 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND2;
811 if (dirty & I830_UPLOAD_TEXBLEND3) {
812 i830EmitTexBlendVerified(
814 sarea_priv->TexBlendState3,
815 sarea_priv->TexBlendStateWordsUsed3);
816 sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND3;
820 /* ================================================================
821 * Performance monitoring functions
824 static void i830_fill_box( drm_device_t *dev,
825 int x, int y, int w, int h,
826 int r, int g, int b )
828 drm_i830_private_t *dev_priv = dev->dev_private;
830 unsigned int BR13, CMD;
833 BR13 = (0xF0 << 16) | (dev_priv->pitch * dev_priv->cpp) | (1<<24);
834 CMD = XY_COLOR_BLT_CMD;
835 x += dev_priv->sarea_priv->boxes[0].x1;
836 y += dev_priv->sarea_priv->boxes[0].y1;
838 if (dev_priv->cpp == 4) {
840 CMD |= (XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
841 color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
843 color = (((r & 0xf8) << 8) |
851 OUT_RING( (y << 16) | x );
852 OUT_RING( ((y+h) << 16) | (x+w) );
854 if ( dev_priv->current_page == 1 ) {
855 OUT_RING( dev_priv->front_offset );
857 OUT_RING( dev_priv->back_offset );
864 static void i830_cp_performance_boxes( drm_device_t *dev )
866 drm_i830_private_t *dev_priv = dev->dev_private;
868 /* Purple box for page flipping
870 if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_FLIP )
871 i830_fill_box( dev, 4, 4, 8, 8, 255, 0, 255 );
873 /* Red box if we have to wait for idle at any point
875 if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_WAIT )
876 i830_fill_box( dev, 16, 4, 8, 8, 255, 0, 0 );
878 /* Blue box: lost context?
880 if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_LOST_CONTEXT )
881 i830_fill_box( dev, 28, 4, 8, 8, 0, 0, 255 );
883 /* Yellow box for texture swaps
885 if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_TEXTURE_LOAD )
886 i830_fill_box( dev, 40, 4, 8, 8, 255, 255, 0 );
888 /* Green box if hardware never idles (as far as we can tell)
890 if ( !(dev_priv->sarea_priv->perf_boxes & I830_BOX_RING_EMPTY) )
891 i830_fill_box( dev, 64, 4, 8, 8, 0, 255, 0 );
894 /* Draw bars indicating number of buffers allocated
895 * (not a great measure, easily confused)
897 if (dev_priv->dma_used) {
898 int bar = dev_priv->dma_used / 10240;
899 if (bar > 100) bar = 100;
900 if (bar < 1) bar = 1;
901 i830_fill_box( dev, 4, 16, bar, 4, 196, 128, 128 );
902 dev_priv->dma_used = 0;
905 dev_priv->sarea_priv->perf_boxes = 0;
908 static void i830_dma_dispatch_clear( drm_device_t *dev, int flags,
909 unsigned int clear_color,
910 unsigned int clear_zval,
911 unsigned int clear_depthmask)
913 drm_i830_private_t *dev_priv = dev->dev_private;
914 drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
915 int nbox = sarea_priv->nbox;
916 drm_clip_rect_t *pbox = sarea_priv->boxes;
917 int pitch = dev_priv->pitch;
918 int cpp = dev_priv->cpp;
920 unsigned int BR13, CMD, D_CMD;
924 if ( dev_priv->current_page == 1 ) {
925 unsigned int tmp = flags;
927 flags &= ~(I830_FRONT | I830_BACK);
928 if ( tmp & I830_FRONT ) flags |= I830_BACK;
929 if ( tmp & I830_BACK ) flags |= I830_FRONT;
932 i830_kernel_lost_context(dev);
936 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
937 D_CMD = CMD = XY_COLOR_BLT_CMD;
940 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25);
941 CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA |
942 XY_COLOR_BLT_WRITE_RGB);
943 D_CMD = XY_COLOR_BLT_CMD;
944 if(clear_depthmask & 0x00ffffff)
945 D_CMD |= XY_COLOR_BLT_WRITE_RGB;
946 if(clear_depthmask & 0xff000000)
947 D_CMD |= XY_COLOR_BLT_WRITE_ALPHA;
950 BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24);
951 D_CMD = CMD = XY_COLOR_BLT_CMD;
955 if (nbox > I830_NR_SAREA_CLIPRECTS)
956 nbox = I830_NR_SAREA_CLIPRECTS;
958 for (i = 0 ; i < nbox ; i++, pbox++) {
959 if (pbox->x1 > pbox->x2 ||
960 pbox->y1 > pbox->y2 ||
961 pbox->x2 > dev_priv->w ||
962 pbox->y2 > dev_priv->h)
965 if ( flags & I830_FRONT ) {
966 DRM_DEBUG("clear front\n");
970 OUT_RING( (pbox->y1 << 16) | pbox->x1 );
971 OUT_RING( (pbox->y2 << 16) | pbox->x2 );
972 OUT_RING( dev_priv->front_offset );
973 OUT_RING( clear_color );
977 if ( flags & I830_BACK ) {
978 DRM_DEBUG("clear back\n");
982 OUT_RING( (pbox->y1 << 16) | pbox->x1 );
983 OUT_RING( (pbox->y2 << 16) | pbox->x2 );
984 OUT_RING( dev_priv->back_offset );
985 OUT_RING( clear_color );
989 if ( flags & I830_DEPTH ) {
990 DRM_DEBUG("clear depth\n");
994 OUT_RING( (pbox->y1 << 16) | pbox->x1 );
995 OUT_RING( (pbox->y2 << 16) | pbox->x2 );
996 OUT_RING( dev_priv->depth_offset );
997 OUT_RING( clear_zval );
1003 static void i830_dma_dispatch_swap( drm_device_t *dev )
1005 drm_i830_private_t *dev_priv = dev->dev_private;
1006 drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
1007 int nbox = sarea_priv->nbox;
1008 drm_clip_rect_t *pbox = sarea_priv->boxes;
1009 int pitch = dev_priv->pitch;
1010 int cpp = dev_priv->cpp;
1012 unsigned int CMD, BR13;
1015 DRM_DEBUG("swapbuffers\n");
1017 i830_kernel_lost_context(dev);
1019 if (dev_priv->do_boxes)
1020 i830_cp_performance_boxes( dev );
1024 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
1025 CMD = XY_SRC_COPY_BLT_CMD;
1028 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25);
1029 CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA |
1030 XY_SRC_COPY_BLT_WRITE_RGB);
1033 BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24);
1034 CMD = XY_SRC_COPY_BLT_CMD;
1039 if (nbox > I830_NR_SAREA_CLIPRECTS)
1040 nbox = I830_NR_SAREA_CLIPRECTS;
1042 for (i = 0 ; i < nbox; i++, pbox++)
1044 if (pbox->x1 > pbox->x2 ||
1045 pbox->y1 > pbox->y2 ||
1046 pbox->x2 > dev_priv->w ||
1047 pbox->y2 > dev_priv->h)
1050 DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
1052 pbox->x2, pbox->y2);
1057 OUT_RING( (pbox->y1 << 16) | pbox->x1 );
1058 OUT_RING( (pbox->y2 << 16) | pbox->x2 );
1060 if (dev_priv->current_page == 0)
1061 OUT_RING( dev_priv->front_offset );
1063 OUT_RING( dev_priv->back_offset );
1065 OUT_RING( (pbox->y1 << 16) | pbox->x1 );
1066 OUT_RING( BR13 & 0xffff );
1068 if (dev_priv->current_page == 0)
1069 OUT_RING( dev_priv->back_offset );
1071 OUT_RING( dev_priv->front_offset );
1077 static void i830_dma_dispatch_flip( drm_device_t *dev )
1079 drm_i830_private_t *dev_priv = dev->dev_private;
1082 DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n",
1084 dev_priv->current_page,
1085 dev_priv->sarea_priv->pf_current_page);
1087 i830_kernel_lost_context(dev);
1089 if (dev_priv->do_boxes) {
1090 dev_priv->sarea_priv->perf_boxes |= I830_BOX_FLIP;
1091 i830_cp_performance_boxes( dev );
1096 OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
1101 OUT_RING( CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP );
1103 if ( dev_priv->current_page == 0 ) {
1104 OUT_RING( dev_priv->back_offset );
1105 dev_priv->current_page = 1;
1107 OUT_RING( dev_priv->front_offset );
1108 dev_priv->current_page = 0;
1115 OUT_RING( MI_WAIT_FOR_EVENT |
1116 MI_WAIT_FOR_PLANE_A_FLIP );
1121 dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
1124 static void i830_dma_dispatch_vertex(drm_device_t *dev,
1129 drm_i830_private_t *dev_priv = dev->dev_private;
1130 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1131 drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
1132 drm_clip_rect_t *box = sarea_priv->boxes;
1133 int nbox = sarea_priv->nbox;
1134 unsigned long address = (unsigned long)buf->bus_address;
1135 unsigned long start = address - dev->agp->base;
1139 i830_kernel_lost_context(dev);
1141 if (nbox > I830_NR_SAREA_CLIPRECTS)
1142 nbox = I830_NR_SAREA_CLIPRECTS;
1145 u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
1147 if(u != I830_BUF_CLIENT) {
1148 DRM_DEBUG("xxxx 2\n");
1155 if (sarea_priv->dirty)
1156 i830EmitState( dev );
1158 DRM_DEBUG("dispatch vertex addr 0x%lx, used 0x%x nbox %d\n",
1159 address, used, nbox);
1161 dev_priv->counter++;
1162 DRM_DEBUG( "dispatch counter : %ld\n", dev_priv->counter);
1163 DRM_DEBUG( "i830_dma_dispatch\n");
1164 DRM_DEBUG( "start : %lx\n", start);
1165 DRM_DEBUG( "used : %d\n", used);
1166 DRM_DEBUG( "start + used - 4 : %ld\n", start + used - 4);
1168 if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
1169 u32 __user *vp = buf_priv->virtual;
1171 put_user( (GFX_OP_PRIMITIVE |
1172 sarea_priv->vertex_prim |
1173 ((used/4)-2)), &vp[0]);
1175 if (dev_priv->use_mi_batchbuffer_start) {
1176 put_user(MI_BATCH_BUFFER_END, &vp[used/4]);
1181 put_user(0, &vp[used/4]);
1185 i830_unmap_buffer(buf);
1192 OUT_RING( GFX_OP_DRAWRECT_INFO );
1193 OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR1] );
1194 OUT_RING( box[i].x1 | (box[i].y1<<16) );
1195 OUT_RING( box[i].x2 | (box[i].y2<<16) );
1196 OUT_RING( sarea_priv->BufferState[I830_DESTREG_DR4] );
1201 if (dev_priv->use_mi_batchbuffer_start) {
1203 OUT_RING( MI_BATCH_BUFFER_START | (2<<6) );
1204 OUT_RING( start | MI_BATCH_NON_SECURE );
1209 OUT_RING( MI_BATCH_BUFFER );
1210 OUT_RING( start | MI_BATCH_NON_SECURE );
1211 OUT_RING( start + used - 4 );
1216 } while (++i < nbox);
1220 dev_priv->counter++;
1222 (void) cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
1226 OUT_RING( CMD_STORE_DWORD_IDX );
1228 OUT_RING( dev_priv->counter );
1229 OUT_RING( CMD_STORE_DWORD_IDX );
1230 OUT_RING( buf_priv->my_use_idx );
1231 OUT_RING( I830_BUF_FREE );
1232 OUT_RING( CMD_REPORT_HEAD );
1239 void i830_dma_quiescent(drm_device_t *dev)
1241 drm_i830_private_t *dev_priv = dev->dev_private;
1244 i830_kernel_lost_context(dev);
1247 OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE );
1248 OUT_RING( CMD_REPORT_HEAD );
1253 i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
1256 static int i830_flush_queue(drm_device_t *dev)
1258 drm_i830_private_t *dev_priv = dev->dev_private;
1259 drm_device_dma_t *dma = dev->dma;
1263 i830_kernel_lost_context(dev);
1266 OUT_RING( CMD_REPORT_HEAD );
1270 i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ );
1272 for (i = 0; i < dma->buf_count; i++) {
1273 drm_buf_t *buf = dma->buflist[ i ];
1274 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1276 int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE,
1279 if (used == I830_BUF_HARDWARE)
1280 DRM_DEBUG("reclaimed from HARDWARE\n");
1281 if (used == I830_BUF_CLIENT)
1282 DRM_DEBUG("still on client\n");
1288 /* Must be called with the lock held */
1289 void i830_reclaim_buffers( struct file *filp )
1291 drm_file_t *priv = filp->private_data;
1292 drm_device_t *dev = priv->dev;
1293 drm_device_dma_t *dma = dev->dma;
1297 if (!dev->dev_private) return;
1298 if (!dma->buflist) return;
1300 i830_flush_queue(dev);
1302 for (i = 0; i < dma->buf_count; i++) {
1303 drm_buf_t *buf = dma->buflist[ i ];
1304 drm_i830_buf_priv_t *buf_priv = buf->dev_private;
1306 if (buf->filp == filp && buf_priv) {
1307 int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT,
1310 if (used == I830_BUF_CLIENT)
1311 DRM_DEBUG("reclaimed from client\n");
1312 if(buf_priv->currently_mapped == I830_BUF_MAPPED)
1313 buf_priv->currently_mapped = I830_BUF_UNMAPPED;
1318 int i830_flush_ioctl(struct inode *inode, struct file *filp,
1319 unsigned int cmd, unsigned long arg)
1321 drm_file_t *priv = filp->private_data;
1322 drm_device_t *dev = priv->dev;
1324 if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
1325 DRM_ERROR("i830_flush_ioctl called without lock held\n");
1329 i830_flush_queue(dev);
1333 int i830_dma_vertex(struct inode *inode, struct file *filp,
1334 unsigned int cmd, unsigned long arg)
1336 drm_file_t *priv = filp->private_data;
1337 drm_device_t *dev = priv->dev;
1338 drm_device_dma_t *dma = dev->dma;
1339 drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
1340 u32 *hw_status = dev_priv->hw_status_page;
1341 drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
1342 dev_priv->sarea_priv;
1343 drm_i830_vertex_t vertex;
1345 if (copy_from_user(&vertex, (drm_i830_vertex_t __user *)arg, sizeof(vertex)))
1348 if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
1349 DRM_ERROR("i830_dma_vertex called without lock held\n");
1353 DRM_DEBUG("i830 dma vertex, idx %d used %d discard %d\n",
1354 vertex.idx, vertex.used, vertex.discard);
1356 if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL;
1358 i830_dma_dispatch_vertex( dev,
1359 dma->buflist[ vertex.idx ],
1360 vertex.discard, vertex.used );
1362 sarea_priv->last_enqueue = dev_priv->counter-1;
1363 sarea_priv->last_dispatch = (int) hw_status[5];
1368 int i830_clear_bufs(struct inode *inode, struct file *filp,
1369 unsigned int cmd, unsigned long arg)
1371 drm_file_t *priv = filp->private_data;
1372 drm_device_t *dev = priv->dev;
1373 drm_i830_clear_t clear;
1375 if (copy_from_user(&clear, (drm_i830_clear_t __user *)arg, sizeof(clear)))
1378 if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
1379 DRM_ERROR("i830_clear_bufs called without lock held\n");
1383 /* GH: Someone's doing nasty things... */
1384 if (!dev->dev_private) {
1388 i830_dma_dispatch_clear( dev, clear.flags,
1391 clear.clear_depthmask);
1395 int i830_swap_bufs(struct inode *inode, struct file *filp,
1396 unsigned int cmd, unsigned long arg)
1398 drm_file_t *priv = filp->private_data;
1399 drm_device_t *dev = priv->dev;
1401 DRM_DEBUG("i830_swap_bufs\n");
1403 if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
1404 DRM_ERROR("i830_swap_buf called without lock held\n");
1408 i830_dma_dispatch_swap( dev );
1414 /* Not sure why this isn't set all the time:
1416 static void i830_do_init_pageflip( drm_device_t *dev )
1418 drm_i830_private_t *dev_priv = dev->dev_private;
1420 DRM_DEBUG("%s\n", __FUNCTION__);
1421 dev_priv->page_flipping = 1;
1422 dev_priv->current_page = 0;
1423 dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
1426 int i830_do_cleanup_pageflip( drm_device_t *dev )
1428 drm_i830_private_t *dev_priv = dev->dev_private;
1430 DRM_DEBUG("%s\n", __FUNCTION__);
1431 if (dev_priv->current_page != 0)
1432 i830_dma_dispatch_flip( dev );
1434 dev_priv->page_flipping = 0;
1438 int i830_flip_bufs(struct inode *inode, struct file *filp,
1439 unsigned int cmd, unsigned long arg)
1441 drm_file_t *priv = filp->private_data;
1442 drm_device_t *dev = priv->dev;
1443 drm_i830_private_t *dev_priv = dev->dev_private;
1445 DRM_DEBUG("%s\n", __FUNCTION__);
1447 if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
1448 DRM_ERROR("i830_flip_buf called without lock held\n");
1452 if (!dev_priv->page_flipping)
1453 i830_do_init_pageflip( dev );
1455 i830_dma_dispatch_flip( dev );
1459 int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
1462 drm_file_t *priv = filp->private_data;
1463 drm_device_t *dev = priv->dev;
1464 drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
1465 u32 *hw_status = dev_priv->hw_status_page;
1466 drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
1467 dev_priv->sarea_priv;
1469 sarea_priv->last_dispatch = (int) hw_status[5];
1473 int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
1476 drm_file_t *priv = filp->private_data;
1477 drm_device_t *dev = priv->dev;
1480 drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private;
1481 u32 *hw_status = dev_priv->hw_status_page;
1482 drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
1483 dev_priv->sarea_priv;
1485 DRM_DEBUG("getbuf\n");
1486 if (copy_from_user(&d, (drm_i830_dma_t __user *)arg, sizeof(d)))
1489 if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
1490 DRM_ERROR("i830_dma called without lock held\n");
1496 retcode = i830_dma_get_buffer(dev, &d, filp);
1498 DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
1499 current->pid, retcode, d.granted);
1501 if (copy_to_user((drm_dma_t __user *)arg, &d, sizeof(d)))
1503 sarea_priv->last_dispatch = (int) hw_status[5];
1508 int i830_copybuf(struct inode *inode,
1513 /* Never copy - 2.4.x doesn't need it */
1517 int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
1525 int i830_getparam( struct inode *inode, struct file *filp, unsigned int cmd,
1528 drm_file_t *priv = filp->private_data;
1529 drm_device_t *dev = priv->dev;
1530 drm_i830_private_t *dev_priv = dev->dev_private;
1531 drm_i830_getparam_t param;
1535 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
1539 if (copy_from_user(¶m, (drm_i830_getparam_t __user *)arg, sizeof(param) ))
1542 switch( param.param ) {
1543 case I830_PARAM_IRQ_ACTIVE:
1544 value = dev->irq_enabled;
1550 if ( copy_to_user( param.value, &value, sizeof(int) ) ) {
1551 DRM_ERROR( "copy_to_user\n" );
1559 int i830_setparam( struct inode *inode, struct file *filp, unsigned int cmd,
1562 drm_file_t *priv = filp->private_data;
1563 drm_device_t *dev = priv->dev;
1564 drm_i830_private_t *dev_priv = dev->dev_private;
1565 drm_i830_setparam_t param;
1568 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
1572 if (copy_from_user(¶m, (drm_i830_setparam_t __user *)arg, sizeof(param) ))
1575 switch( param.param ) {
1576 case I830_SETPARAM_USE_MI_BATCHBUFFER_START:
1577 dev_priv->use_mi_batchbuffer_start = param.value;