| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* i810_dma.c -- DMA support for the i810 -*- linux-c -*- | 
|  | 2 | * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com | 
|  | 3 | * | 
|  | 4 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. | 
|  | 5 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | 
|  | 6 | * All Rights Reserved. | 
|  | 7 | * | 
|  | 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: | 
|  | 14 | * | 
|  | 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 | 
|  | 17 | * Software. | 
|  | 18 | * | 
|  | 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. | 
|  | 26 | * | 
|  | 27 | * Authors: Rickard E. (Rik) Faith <faith@valinux.com> | 
|  | 28 | *	    Jeff Hartmann <jhartmann@valinux.com> | 
|  | 29 | *          Keith Whitwell <keith@tungstengraphics.com> | 
|  | 30 | * | 
|  | 31 | */ | 
|  | 32 |  | 
|  | 33 | #include "drmP.h" | 
|  | 34 | #include "drm.h" | 
|  | 35 | #include "i810_drm.h" | 
|  | 36 | #include "i810_drv.h" | 
|  | 37 | #include <linux/interrupt.h>	/* For task queue support */ | 
|  | 38 | #include <linux/delay.h> | 
|  | 39 | #include <linux/pagemap.h> | 
|  | 40 |  | 
|  | 41 | #define I810_BUF_FREE		2 | 
|  | 42 | #define I810_BUF_CLIENT		1 | 
|  | 43 | #define I810_BUF_HARDWARE      	0 | 
|  | 44 |  | 
|  | 45 | #define I810_BUF_UNMAPPED 0 | 
|  | 46 | #define I810_BUF_MAPPED   1 | 
|  | 47 |  | 
|  | 48 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2) | 
|  | 49 | #define down_write down | 
|  | 50 | #define up_write up | 
|  | 51 | #endif | 
|  | 52 |  | 
|  | 53 | static drm_buf_t *i810_freelist_get(drm_device_t *dev) | 
|  | 54 | { | 
|  | 55 | drm_device_dma_t *dma = dev->dma; | 
|  | 56 | int		 i; | 
|  | 57 | int 		 used; | 
|  | 58 |  | 
|  | 59 | /* Linear search might not be the best solution */ | 
|  | 60 |  | 
|  | 61 | for (i = 0; i < dma->buf_count; i++) { | 
|  | 62 | drm_buf_t *buf = dma->buflist[ i ]; | 
|  | 63 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 64 | /* In use is already a pointer */ | 
|  | 65 | used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, | 
|  | 66 | I810_BUF_CLIENT); | 
|  | 67 | if (used == I810_BUF_FREE) { | 
|  | 68 | return buf; | 
|  | 69 | } | 
|  | 70 | } | 
|  | 71 | return NULL; | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | /* This should only be called if the buffer is not sent to the hardware | 
|  | 75 | * yet, the hardware updates in use for us once its on the ring buffer. | 
|  | 76 | */ | 
|  | 77 |  | 
|  | 78 | static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf) | 
|  | 79 | { | 
|  | 80 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 81 | int used; | 
|  | 82 |  | 
|  | 83 | /* In use is already a pointer */ | 
|  | 84 | used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); | 
|  | 85 | if (used != I810_BUF_CLIENT) { | 
|  | 86 | DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); | 
|  | 87 | return -EINVAL; | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | return 0; | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | static struct file_operations i810_buffer_fops = { | 
|  | 94 | .open	 = drm_open, | 
|  | 95 | .flush	 = drm_flush, | 
|  | 96 | .release = drm_release, | 
|  | 97 | .ioctl	 = drm_ioctl, | 
|  | 98 | .mmap	 = i810_mmap_buffers, | 
|  | 99 | .fasync  = drm_fasync, | 
|  | 100 | }; | 
|  | 101 |  | 
|  | 102 | int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) | 
|  | 103 | { | 
|  | 104 | drm_file_t	    *priv	  = filp->private_data; | 
|  | 105 | drm_device_t	    *dev; | 
|  | 106 | drm_i810_private_t  *dev_priv; | 
|  | 107 | drm_buf_t           *buf; | 
|  | 108 | drm_i810_buf_priv_t *buf_priv; | 
|  | 109 |  | 
|  | 110 | lock_kernel(); | 
|  | 111 | dev	 = priv->head->dev; | 
|  | 112 | dev_priv = dev->dev_private; | 
|  | 113 | buf      = dev_priv->mmap_buffer; | 
|  | 114 | buf_priv = buf->dev_private; | 
|  | 115 |  | 
|  | 116 | vma->vm_flags |= (VM_IO | VM_DONTCOPY); | 
|  | 117 | vma->vm_file = filp; | 
|  | 118 |  | 
|  | 119 | buf_priv->currently_mapped = I810_BUF_MAPPED; | 
|  | 120 | unlock_kernel(); | 
|  | 121 |  | 
|  | 122 | if (io_remap_pfn_range(vma, vma->vm_start, | 
|  | 123 | VM_OFFSET(vma) >> PAGE_SHIFT, | 
|  | 124 | vma->vm_end - vma->vm_start, | 
|  | 125 | vma->vm_page_prot)) return -EAGAIN; | 
|  | 126 | return 0; | 
|  | 127 | } | 
|  | 128 |  | 
|  | 129 | static int i810_map_buffer(drm_buf_t *buf, struct file *filp) | 
|  | 130 | { | 
|  | 131 | drm_file_t	  *priv	  = filp->private_data; | 
|  | 132 | drm_device_t	  *dev	  = priv->head->dev; | 
|  | 133 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 134 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 135 | struct file_operations *old_fops; | 
|  | 136 | int retcode = 0; | 
|  | 137 |  | 
|  | 138 | if (buf_priv->currently_mapped == I810_BUF_MAPPED) | 
|  | 139 | return -EINVAL; | 
|  | 140 |  | 
|  | 141 | down_write( ¤t->mm->mmap_sem ); | 
|  | 142 | old_fops = filp->f_op; | 
|  | 143 | filp->f_op = &i810_buffer_fops; | 
|  | 144 | dev_priv->mmap_buffer = buf; | 
|  | 145 | buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, | 
|  | 146 | PROT_READ|PROT_WRITE, | 
|  | 147 | MAP_SHARED, | 
|  | 148 | buf->bus_address); | 
|  | 149 | dev_priv->mmap_buffer = NULL; | 
|  | 150 | filp->f_op = old_fops; | 
|  | 151 | if ((unsigned long)buf_priv->virtual > -1024UL) { | 
|  | 152 | /* Real error */ | 
|  | 153 | DRM_ERROR("mmap error\n"); | 
|  | 154 | retcode = (signed int)buf_priv->virtual; | 
|  | 155 | buf_priv->virtual = NULL; | 
|  | 156 | } | 
|  | 157 | up_write( ¤t->mm->mmap_sem ); | 
|  | 158 |  | 
|  | 159 | return retcode; | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | static int i810_unmap_buffer(drm_buf_t *buf) | 
|  | 163 | { | 
|  | 164 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 165 | int retcode = 0; | 
|  | 166 |  | 
|  | 167 | if (buf_priv->currently_mapped != I810_BUF_MAPPED) | 
|  | 168 | return -EINVAL; | 
|  | 169 |  | 
|  | 170 | down_write(¤t->mm->mmap_sem); | 
|  | 171 | retcode = do_munmap(current->mm, | 
|  | 172 | (unsigned long)buf_priv->virtual, | 
|  | 173 | (size_t) buf->total); | 
|  | 174 | up_write(¤t->mm->mmap_sem); | 
|  | 175 |  | 
|  | 176 | buf_priv->currently_mapped = I810_BUF_UNMAPPED; | 
|  | 177 | buf_priv->virtual = NULL; | 
|  | 178 |  | 
|  | 179 | return retcode; | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d, | 
|  | 183 | struct file *filp) | 
|  | 184 | { | 
|  | 185 | drm_buf_t	  *buf; | 
|  | 186 | drm_i810_buf_priv_t *buf_priv; | 
|  | 187 | int retcode = 0; | 
|  | 188 |  | 
|  | 189 | buf = i810_freelist_get(dev); | 
|  | 190 | if (!buf) { | 
|  | 191 | retcode = -ENOMEM; | 
|  | 192 | DRM_DEBUG("retcode=%d\n", retcode); | 
|  | 193 | return retcode; | 
|  | 194 | } | 
|  | 195 |  | 
|  | 196 | retcode = i810_map_buffer(buf, filp); | 
|  | 197 | if (retcode) { | 
|  | 198 | i810_freelist_put(dev, buf); | 
|  | 199 | DRM_ERROR("mapbuf failed, retcode %d\n", retcode); | 
|  | 200 | return retcode; | 
|  | 201 | } | 
|  | 202 | buf->filp = filp; | 
|  | 203 | buf_priv = buf->dev_private; | 
|  | 204 | d->granted = 1; | 
|  | 205 | d->request_idx = buf->idx; | 
|  | 206 | d->request_size = buf->total; | 
|  | 207 | d->virtual = buf_priv->virtual; | 
|  | 208 |  | 
|  | 209 | return retcode; | 
|  | 210 | } | 
|  | 211 |  | 
|  | 212 | static int i810_dma_cleanup(drm_device_t *dev) | 
|  | 213 | { | 
|  | 214 | drm_device_dma_t *dma = dev->dma; | 
|  | 215 |  | 
|  | 216 | /* Make sure interrupts are disabled here because the uninstall ioctl | 
|  | 217 | * may not have been called from userspace and after dev_private | 
|  | 218 | * is freed, it's too late. | 
|  | 219 | */ | 
|  | 220 | if (drm_core_check_feature(dev, DRIVER_HAVE_IRQ) && dev->irq_enabled) | 
|  | 221 | drm_irq_uninstall(dev); | 
|  | 222 |  | 
|  | 223 | if (dev->dev_private) { | 
|  | 224 | int i; | 
|  | 225 | drm_i810_private_t *dev_priv = | 
|  | 226 | (drm_i810_private_t *) dev->dev_private; | 
|  | 227 |  | 
|  | 228 | if (dev_priv->ring.virtual_start) { | 
|  | 229 | drm_ioremapfree((void *) dev_priv->ring.virtual_start, | 
|  | 230 | dev_priv->ring.Size, dev); | 
|  | 231 | } | 
|  | 232 | if (dev_priv->hw_status_page) { | 
|  | 233 | pci_free_consistent(dev->pdev, PAGE_SIZE, | 
|  | 234 | dev_priv->hw_status_page, | 
|  | 235 | dev_priv->dma_status_page); | 
|  | 236 | /* Need to rewrite hardware status page */ | 
|  | 237 | I810_WRITE(0x02080, 0x1ffff000); | 
|  | 238 | } | 
|  | 239 | drm_free(dev->dev_private, sizeof(drm_i810_private_t), | 
|  | 240 | DRM_MEM_DRIVER); | 
|  | 241 | dev->dev_private = NULL; | 
|  | 242 |  | 
|  | 243 | for (i = 0; i < dma->buf_count; i++) { | 
|  | 244 | drm_buf_t *buf = dma->buflist[ i ]; | 
|  | 245 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 246 | if ( buf_priv->kernel_virtual && buf->total ) | 
|  | 247 | drm_ioremapfree(buf_priv->kernel_virtual, buf->total, dev); | 
|  | 248 | } | 
|  | 249 | } | 
|  | 250 | return 0; | 
|  | 251 | } | 
|  | 252 |  | 
|  | 253 | static int i810_wait_ring(drm_device_t *dev, int n) | 
|  | 254 | { | 
|  | 255 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 256 | drm_i810_ring_buffer_t *ring = &(dev_priv->ring); | 
|  | 257 | int iters = 0; | 
|  | 258 | unsigned long end; | 
|  | 259 | unsigned int last_head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; | 
|  | 260 |  | 
|  | 261 | end = jiffies + (HZ*3); | 
|  | 262 | while (ring->space < n) { | 
|  | 263 | ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; | 
|  | 264 | ring->space = ring->head - (ring->tail+8); | 
|  | 265 | if (ring->space < 0) ring->space += ring->Size; | 
|  | 266 |  | 
|  | 267 | if (ring->head != last_head) { | 
|  | 268 | end = jiffies + (HZ*3); | 
|  | 269 | last_head = ring->head; | 
|  | 270 | } | 
|  | 271 |  | 
|  | 272 | iters++; | 
|  | 273 | if (time_before(end, jiffies)) { | 
|  | 274 | DRM_ERROR("space: %d wanted %d\n", ring->space, n); | 
|  | 275 | DRM_ERROR("lockup\n"); | 
|  | 276 | goto out_wait_ring; | 
|  | 277 | } | 
|  | 278 | udelay(1); | 
|  | 279 | } | 
|  | 280 |  | 
|  | 281 | out_wait_ring: | 
|  | 282 | return iters; | 
|  | 283 | } | 
|  | 284 |  | 
|  | 285 | static void i810_kernel_lost_context(drm_device_t *dev) | 
|  | 286 | { | 
|  | 287 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 288 | drm_i810_ring_buffer_t *ring = &(dev_priv->ring); | 
|  | 289 |  | 
|  | 290 | ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; | 
|  | 291 | ring->tail = I810_READ(LP_RING + RING_TAIL); | 
|  | 292 | ring->space = ring->head - (ring->tail+8); | 
|  | 293 | if (ring->space < 0) ring->space += ring->Size; | 
|  | 294 | } | 
|  | 295 |  | 
|  | 296 | static int i810_freelist_init(drm_device_t *dev, drm_i810_private_t *dev_priv) | 
|  | 297 | { | 
|  | 298 | drm_device_dma_t *dma = dev->dma; | 
|  | 299 | int my_idx = 24; | 
|  | 300 | u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx); | 
|  | 301 | int i; | 
|  | 302 |  | 
|  | 303 | if (dma->buf_count > 1019) { | 
|  | 304 | /* Not enough space in the status page for the freelist */ | 
|  | 305 | return -EINVAL; | 
|  | 306 | } | 
|  | 307 |  | 
|  | 308 | for (i = 0; i < dma->buf_count; i++) { | 
|  | 309 | drm_buf_t *buf = dma->buflist[ i ]; | 
|  | 310 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 311 |  | 
|  | 312 | buf_priv->in_use = hw_status++; | 
|  | 313 | buf_priv->my_use_idx = my_idx; | 
|  | 314 | my_idx += 4; | 
|  | 315 |  | 
|  | 316 | *buf_priv->in_use = I810_BUF_FREE; | 
|  | 317 |  | 
|  | 318 | buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, | 
|  | 319 | buf->total, dev); | 
|  | 320 | } | 
|  | 321 | return 0; | 
|  | 322 | } | 
|  | 323 |  | 
|  | 324 | static int i810_dma_initialize(drm_device_t *dev, | 
|  | 325 | drm_i810_private_t *dev_priv, | 
|  | 326 | drm_i810_init_t *init) | 
|  | 327 | { | 
|  | 328 | struct list_head *list; | 
|  | 329 |  | 
|  | 330 | memset(dev_priv, 0, sizeof(drm_i810_private_t)); | 
|  | 331 |  | 
|  | 332 | list_for_each(list, &dev->maplist->head) { | 
|  | 333 | drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); | 
|  | 334 | if (r_list->map && | 
|  | 335 | r_list->map->type == _DRM_SHM && | 
|  | 336 | r_list->map->flags & _DRM_CONTAINS_LOCK ) { | 
|  | 337 | dev_priv->sarea_map = r_list->map; | 
|  | 338 | break; | 
|  | 339 | } | 
|  | 340 | } | 
|  | 341 | if (!dev_priv->sarea_map) { | 
|  | 342 | dev->dev_private = (void *)dev_priv; | 
|  | 343 | i810_dma_cleanup(dev); | 
|  | 344 | DRM_ERROR("can not find sarea!\n"); | 
|  | 345 | return -EINVAL; | 
|  | 346 | } | 
|  | 347 | dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset); | 
|  | 348 | if (!dev_priv->mmio_map) { | 
|  | 349 | dev->dev_private = (void *)dev_priv; | 
|  | 350 | i810_dma_cleanup(dev); | 
|  | 351 | DRM_ERROR("can not find mmio map!\n"); | 
|  | 352 | return -EINVAL; | 
|  | 353 | } | 
|  | 354 | dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); | 
|  | 355 | if (!dev->agp_buffer_map) { | 
|  | 356 | dev->dev_private = (void *)dev_priv; | 
|  | 357 | i810_dma_cleanup(dev); | 
|  | 358 | DRM_ERROR("can not find dma buffer map!\n"); | 
|  | 359 | return -EINVAL; | 
|  | 360 | } | 
|  | 361 |  | 
|  | 362 | dev_priv->sarea_priv = (drm_i810_sarea_t *) | 
|  | 363 | ((u8 *)dev_priv->sarea_map->handle + | 
|  | 364 | init->sarea_priv_offset); | 
|  | 365 |  | 
|  | 366 | dev_priv->ring.Start = init->ring_start; | 
|  | 367 | dev_priv->ring.End = init->ring_end; | 
|  | 368 | dev_priv->ring.Size = init->ring_size; | 
|  | 369 |  | 
|  | 370 | dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + | 
|  | 371 | init->ring_start, | 
|  | 372 | init->ring_size, dev); | 
|  | 373 |  | 
|  | 374 | if (dev_priv->ring.virtual_start == NULL) { | 
|  | 375 | dev->dev_private = (void *) dev_priv; | 
|  | 376 | i810_dma_cleanup(dev); | 
|  | 377 | DRM_ERROR("can not ioremap virtual address for" | 
|  | 378 | " ring buffer\n"); | 
|  | 379 | return -ENOMEM; | 
|  | 380 | } | 
|  | 381 |  | 
|  | 382 | dev_priv->ring.tail_mask = dev_priv->ring.Size - 1; | 
|  | 383 |  | 
|  | 384 | dev_priv->w = init->w; | 
|  | 385 | dev_priv->h = init->h; | 
|  | 386 | dev_priv->pitch = init->pitch; | 
|  | 387 | dev_priv->back_offset = init->back_offset; | 
|  | 388 | dev_priv->depth_offset = init->depth_offset; | 
|  | 389 | dev_priv->front_offset = init->front_offset; | 
|  | 390 |  | 
|  | 391 | dev_priv->overlay_offset = init->overlay_offset; | 
|  | 392 | dev_priv->overlay_physical = init->overlay_physical; | 
|  | 393 |  | 
|  | 394 | dev_priv->front_di1 = init->front_offset | init->pitch_bits; | 
|  | 395 | dev_priv->back_di1 = init->back_offset | init->pitch_bits; | 
|  | 396 | dev_priv->zi1 = init->depth_offset | init->pitch_bits; | 
|  | 397 |  | 
|  | 398 | /* Program Hardware Status Page */ | 
|  | 399 | dev_priv->hw_status_page = | 
|  | 400 | pci_alloc_consistent(dev->pdev, PAGE_SIZE, | 
|  | 401 | &dev_priv->dma_status_page); | 
|  | 402 | if (!dev_priv->hw_status_page) { | 
|  | 403 | dev->dev_private = (void *)dev_priv; | 
|  | 404 | i810_dma_cleanup(dev); | 
|  | 405 | DRM_ERROR("Can not allocate hardware status page\n"); | 
|  | 406 | return -ENOMEM; | 
|  | 407 | } | 
|  | 408 | memset(dev_priv->hw_status_page, 0, PAGE_SIZE); | 
|  | 409 | DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); | 
|  | 410 |  | 
|  | 411 | I810_WRITE(0x02080, dev_priv->dma_status_page); | 
|  | 412 | DRM_DEBUG("Enabled hardware status page\n"); | 
|  | 413 |  | 
|  | 414 | /* Now we need to init our freelist */ | 
|  | 415 | if (i810_freelist_init(dev, dev_priv) != 0) { | 
|  | 416 | dev->dev_private = (void *)dev_priv; | 
|  | 417 | i810_dma_cleanup(dev); | 
|  | 418 | DRM_ERROR("Not enough space in the status page for" | 
|  | 419 | " the freelist\n"); | 
|  | 420 | return -ENOMEM; | 
|  | 421 | } | 
|  | 422 | dev->dev_private = (void *)dev_priv; | 
|  | 423 |  | 
|  | 424 | return 0; | 
|  | 425 | } | 
|  | 426 |  | 
|  | 427 | /* i810 DRM version 1.1 used a smaller init structure with different | 
|  | 428 | * ordering of values than is currently used (drm >= 1.2). There is | 
|  | 429 | * no defined way to detect the XFree version to correct this problem, | 
|  | 430 | * however by checking using this procedure we can detect the correct | 
|  | 431 | * thing to do. | 
|  | 432 | * | 
|  | 433 | * #1 Read the Smaller init structure from user-space | 
|  | 434 | * #2 Verify the overlay_physical is a valid physical address, or NULL | 
|  | 435 | *    If it isn't then we have a v1.1 client. Fix up params. | 
|  | 436 | *    If it is, then we have a 1.2 client... get the rest of the data. | 
|  | 437 | */ | 
|  | 438 | static int i810_dma_init_compat(drm_i810_init_t *init, unsigned long arg) | 
|  | 439 | { | 
|  | 440 |  | 
|  | 441 | /* Get v1.1 init data */ | 
|  | 442 | if (copy_from_user(init, (drm_i810_pre12_init_t __user *)arg, | 
|  | 443 | sizeof(drm_i810_pre12_init_t))) { | 
|  | 444 | return -EFAULT; | 
|  | 445 | } | 
|  | 446 |  | 
|  | 447 | if ((!init->overlay_physical) || (init->overlay_physical > 4096)) { | 
|  | 448 |  | 
|  | 449 | /* This is a v1.2 client, just get the v1.2 init data */ | 
|  | 450 | DRM_INFO("Using POST v1.2 init.\n"); | 
|  | 451 | if (copy_from_user(init, (drm_i810_init_t __user *)arg, | 
|  | 452 | sizeof(drm_i810_init_t))) { | 
|  | 453 | return -EFAULT; | 
|  | 454 | } | 
|  | 455 | } else { | 
|  | 456 |  | 
|  | 457 | /* This is a v1.1 client, fix the params */ | 
|  | 458 | DRM_INFO("Using PRE v1.2 init.\n"); | 
|  | 459 | init->pitch_bits = init->h; | 
|  | 460 | init->pitch = init->w; | 
|  | 461 | init->h = init->overlay_physical; | 
|  | 462 | init->w = init->overlay_offset; | 
|  | 463 | init->overlay_physical = 0; | 
|  | 464 | init->overlay_offset = 0; | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | return 0; | 
|  | 468 | } | 
|  | 469 |  | 
|  | 470 | static int i810_dma_init(struct inode *inode, struct file *filp, | 
|  | 471 | unsigned int cmd, unsigned long arg) | 
|  | 472 | { | 
|  | 473 | drm_file_t *priv = filp->private_data; | 
|  | 474 | drm_device_t *dev = priv->head->dev; | 
|  | 475 | drm_i810_private_t *dev_priv; | 
|  | 476 | drm_i810_init_t init; | 
|  | 477 | int retcode = 0; | 
|  | 478 |  | 
|  | 479 | /* Get only the init func */ | 
|  | 480 | if (copy_from_user(&init, (void __user *)arg, sizeof(drm_i810_init_func_t))) | 
|  | 481 | return -EFAULT; | 
|  | 482 |  | 
|  | 483 | switch(init.func) { | 
|  | 484 | case I810_INIT_DMA: | 
|  | 485 | /* This case is for backward compatibility. It | 
|  | 486 | * handles XFree 4.1.0 and 4.2.0, and has to | 
|  | 487 | * do some parameter checking as described below. | 
|  | 488 | * It will someday go away. | 
|  | 489 | */ | 
|  | 490 | retcode = i810_dma_init_compat(&init, arg); | 
|  | 491 | if (retcode) | 
|  | 492 | return retcode; | 
|  | 493 |  | 
|  | 494 | dev_priv = drm_alloc(sizeof(drm_i810_private_t), | 
|  | 495 | DRM_MEM_DRIVER); | 
|  | 496 | if (dev_priv == NULL) | 
|  | 497 | return -ENOMEM; | 
|  | 498 | retcode = i810_dma_initialize(dev, dev_priv, &init); | 
|  | 499 | break; | 
|  | 500 |  | 
|  | 501 | default: | 
|  | 502 | case I810_INIT_DMA_1_4: | 
|  | 503 | DRM_INFO("Using v1.4 init.\n"); | 
|  | 504 | if (copy_from_user(&init, (drm_i810_init_t __user *)arg, | 
|  | 505 | sizeof(drm_i810_init_t))) { | 
|  | 506 | return -EFAULT; | 
|  | 507 | } | 
|  | 508 | dev_priv = drm_alloc(sizeof(drm_i810_private_t), | 
|  | 509 | DRM_MEM_DRIVER); | 
|  | 510 | if (dev_priv == NULL) | 
|  | 511 | return -ENOMEM; | 
|  | 512 | retcode = i810_dma_initialize(dev, dev_priv, &init); | 
|  | 513 | break; | 
|  | 514 |  | 
|  | 515 | case I810_CLEANUP_DMA: | 
|  | 516 | DRM_INFO("DMA Cleanup\n"); | 
|  | 517 | retcode = i810_dma_cleanup(dev); | 
|  | 518 | break; | 
|  | 519 | } | 
|  | 520 |  | 
|  | 521 | return retcode; | 
|  | 522 | } | 
|  | 523 |  | 
|  | 524 |  | 
|  | 525 |  | 
|  | 526 | /* Most efficient way to verify state for the i810 is as it is | 
|  | 527 | * emitted.  Non-conformant state is silently dropped. | 
|  | 528 | * | 
|  | 529 | * Use 'volatile' & local var tmp to force the emitted values to be | 
|  | 530 | * identical to the verified ones. | 
|  | 531 | */ | 
|  | 532 | static void i810EmitContextVerified( drm_device_t *dev, | 
|  | 533 | volatile unsigned int *code ) | 
|  | 534 | { | 
|  | 535 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 536 | int i, j = 0; | 
|  | 537 | unsigned int tmp; | 
|  | 538 | RING_LOCALS; | 
|  | 539 |  | 
|  | 540 | BEGIN_LP_RING( I810_CTX_SETUP_SIZE ); | 
|  | 541 |  | 
|  | 542 | OUT_RING( GFX_OP_COLOR_FACTOR ); | 
|  | 543 | OUT_RING( code[I810_CTXREG_CF1] ); | 
|  | 544 |  | 
|  | 545 | OUT_RING( GFX_OP_STIPPLE ); | 
|  | 546 | OUT_RING( code[I810_CTXREG_ST1] ); | 
|  | 547 |  | 
|  | 548 | for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) { | 
|  | 549 | tmp = code[i]; | 
|  | 550 |  | 
|  | 551 | if ((tmp & (7<<29)) == (3<<29) && | 
|  | 552 | (tmp & (0x1f<<24)) < (0x1d<<24)) | 
|  | 553 | { | 
|  | 554 | OUT_RING( tmp ); | 
|  | 555 | j++; | 
|  | 556 | } | 
|  | 557 | else printk("constext state dropped!!!\n"); | 
|  | 558 | } | 
|  | 559 |  | 
|  | 560 | if (j & 1) | 
|  | 561 | OUT_RING( 0 ); | 
|  | 562 |  | 
|  | 563 | ADVANCE_LP_RING(); | 
|  | 564 | } | 
|  | 565 |  | 
|  | 566 | static void i810EmitTexVerified( drm_device_t *dev, | 
|  | 567 | volatile unsigned int *code ) | 
|  | 568 | { | 
|  | 569 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 570 | int i, j = 0; | 
|  | 571 | unsigned int tmp; | 
|  | 572 | RING_LOCALS; | 
|  | 573 |  | 
|  | 574 | BEGIN_LP_RING( I810_TEX_SETUP_SIZE ); | 
|  | 575 |  | 
|  | 576 | OUT_RING( GFX_OP_MAP_INFO ); | 
|  | 577 | OUT_RING( code[I810_TEXREG_MI1] ); | 
|  | 578 | OUT_RING( code[I810_TEXREG_MI2] ); | 
|  | 579 | OUT_RING( code[I810_TEXREG_MI3] ); | 
|  | 580 |  | 
|  | 581 | for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) { | 
|  | 582 | tmp = code[i]; | 
|  | 583 |  | 
|  | 584 | if ((tmp & (7<<29)) == (3<<29) && | 
|  | 585 | (tmp & (0x1f<<24)) < (0x1d<<24)) | 
|  | 586 | { | 
|  | 587 | OUT_RING( tmp ); | 
|  | 588 | j++; | 
|  | 589 | } | 
|  | 590 | else printk("texture state dropped!!!\n"); | 
|  | 591 | } | 
|  | 592 |  | 
|  | 593 | if (j & 1) | 
|  | 594 | OUT_RING( 0 ); | 
|  | 595 |  | 
|  | 596 | ADVANCE_LP_RING(); | 
|  | 597 | } | 
|  | 598 |  | 
|  | 599 |  | 
|  | 600 | /* Need to do some additional checking when setting the dest buffer. | 
|  | 601 | */ | 
|  | 602 | static void i810EmitDestVerified( drm_device_t *dev, | 
|  | 603 | volatile unsigned int *code ) | 
|  | 604 | { | 
|  | 605 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 606 | unsigned int tmp; | 
|  | 607 | RING_LOCALS; | 
|  | 608 |  | 
|  | 609 | BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 ); | 
|  | 610 |  | 
|  | 611 | tmp = code[I810_DESTREG_DI1]; | 
|  | 612 | if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) { | 
|  | 613 | OUT_RING( CMD_OP_DESTBUFFER_INFO ); | 
|  | 614 | OUT_RING( tmp ); | 
|  | 615 | } else | 
|  | 616 | DRM_DEBUG("bad di1 %x (allow %x or %x)\n", | 
|  | 617 | tmp, dev_priv->front_di1, dev_priv->back_di1); | 
|  | 618 |  | 
|  | 619 | /* invarient: | 
|  | 620 | */ | 
|  | 621 | OUT_RING( CMD_OP_Z_BUFFER_INFO ); | 
|  | 622 | OUT_RING( dev_priv->zi1 ); | 
|  | 623 |  | 
|  | 624 | OUT_RING( GFX_OP_DESTBUFFER_VARS ); | 
|  | 625 | OUT_RING( code[I810_DESTREG_DV1] ); | 
|  | 626 |  | 
|  | 627 | OUT_RING( GFX_OP_DRAWRECT_INFO ); | 
|  | 628 | OUT_RING( code[I810_DESTREG_DR1] ); | 
|  | 629 | OUT_RING( code[I810_DESTREG_DR2] ); | 
|  | 630 | OUT_RING( code[I810_DESTREG_DR3] ); | 
|  | 631 | OUT_RING( code[I810_DESTREG_DR4] ); | 
|  | 632 | OUT_RING( 0 ); | 
|  | 633 |  | 
|  | 634 | ADVANCE_LP_RING(); | 
|  | 635 | } | 
|  | 636 |  | 
|  | 637 |  | 
|  | 638 |  | 
|  | 639 | static void i810EmitState( drm_device_t *dev ) | 
|  | 640 | { | 
|  | 641 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 642 | drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; | 
|  | 643 | unsigned int dirty = sarea_priv->dirty; | 
|  | 644 |  | 
|  | 645 | DRM_DEBUG("%s %x\n", __FUNCTION__, dirty); | 
|  | 646 |  | 
|  | 647 | if (dirty & I810_UPLOAD_BUFFERS) { | 
|  | 648 | i810EmitDestVerified( dev, sarea_priv->BufferState ); | 
|  | 649 | sarea_priv->dirty &= ~I810_UPLOAD_BUFFERS; | 
|  | 650 | } | 
|  | 651 |  | 
|  | 652 | if (dirty & I810_UPLOAD_CTX) { | 
|  | 653 | i810EmitContextVerified( dev, sarea_priv->ContextState ); | 
|  | 654 | sarea_priv->dirty &= ~I810_UPLOAD_CTX; | 
|  | 655 | } | 
|  | 656 |  | 
|  | 657 | if (dirty & I810_UPLOAD_TEX0) { | 
|  | 658 | i810EmitTexVerified( dev, sarea_priv->TexState[0] ); | 
|  | 659 | sarea_priv->dirty &= ~I810_UPLOAD_TEX0; | 
|  | 660 | } | 
|  | 661 |  | 
|  | 662 | if (dirty & I810_UPLOAD_TEX1) { | 
|  | 663 | i810EmitTexVerified( dev, sarea_priv->TexState[1] ); | 
|  | 664 | sarea_priv->dirty &= ~I810_UPLOAD_TEX1; | 
|  | 665 | } | 
|  | 666 | } | 
|  | 667 |  | 
|  | 668 |  | 
|  | 669 |  | 
|  | 670 | /* need to verify | 
|  | 671 | */ | 
|  | 672 | static void i810_dma_dispatch_clear( drm_device_t *dev, int flags, | 
|  | 673 | unsigned int clear_color, | 
|  | 674 | unsigned int clear_zval ) | 
|  | 675 | { | 
|  | 676 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 677 | drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; | 
|  | 678 | int nbox = sarea_priv->nbox; | 
|  | 679 | drm_clip_rect_t *pbox = sarea_priv->boxes; | 
|  | 680 | int pitch = dev_priv->pitch; | 
|  | 681 | int cpp = 2; | 
|  | 682 | int i; | 
|  | 683 | RING_LOCALS; | 
|  | 684 |  | 
|  | 685 | if ( dev_priv->current_page == 1 ) { | 
|  | 686 | unsigned int tmp = flags; | 
|  | 687 |  | 
|  | 688 | flags &= ~(I810_FRONT | I810_BACK); | 
|  | 689 | if (tmp & I810_FRONT) flags |= I810_BACK; | 
|  | 690 | if (tmp & I810_BACK) flags |= I810_FRONT; | 
|  | 691 | } | 
|  | 692 |  | 
|  | 693 | i810_kernel_lost_context(dev); | 
|  | 694 |  | 
|  | 695 | if (nbox > I810_NR_SAREA_CLIPRECTS) | 
|  | 696 | nbox = I810_NR_SAREA_CLIPRECTS; | 
|  | 697 |  | 
|  | 698 | for (i = 0 ; i < nbox ; i++, pbox++) { | 
|  | 699 | unsigned int x = pbox->x1; | 
|  | 700 | unsigned int y = pbox->y1; | 
|  | 701 | unsigned int width = (pbox->x2 - x) * cpp; | 
|  | 702 | unsigned int height = pbox->y2 - y; | 
|  | 703 | unsigned int start = y * pitch + x * cpp; | 
|  | 704 |  | 
|  | 705 | if (pbox->x1 > pbox->x2 || | 
|  | 706 | pbox->y1 > pbox->y2 || | 
|  | 707 | pbox->x2 > dev_priv->w || | 
|  | 708 | pbox->y2 > dev_priv->h) | 
|  | 709 | continue; | 
|  | 710 |  | 
|  | 711 | if ( flags & I810_FRONT ) { | 
|  | 712 | BEGIN_LP_RING( 6 ); | 
|  | 713 | OUT_RING( BR00_BITBLT_CLIENT | | 
|  | 714 | BR00_OP_COLOR_BLT | 0x3 ); | 
|  | 715 | OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); | 
|  | 716 | OUT_RING( (height << 16) | width ); | 
|  | 717 | OUT_RING( start ); | 
|  | 718 | OUT_RING( clear_color ); | 
|  | 719 | OUT_RING( 0 ); | 
|  | 720 | ADVANCE_LP_RING(); | 
|  | 721 | } | 
|  | 722 |  | 
|  | 723 | if ( flags & I810_BACK ) { | 
|  | 724 | BEGIN_LP_RING( 6 ); | 
|  | 725 | OUT_RING( BR00_BITBLT_CLIENT | | 
|  | 726 | BR00_OP_COLOR_BLT | 0x3 ); | 
|  | 727 | OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); | 
|  | 728 | OUT_RING( (height << 16) | width ); | 
|  | 729 | OUT_RING( dev_priv->back_offset + start ); | 
|  | 730 | OUT_RING( clear_color ); | 
|  | 731 | OUT_RING( 0 ); | 
|  | 732 | ADVANCE_LP_RING(); | 
|  | 733 | } | 
|  | 734 |  | 
|  | 735 | if ( flags & I810_DEPTH ) { | 
|  | 736 | BEGIN_LP_RING( 6 ); | 
|  | 737 | OUT_RING( BR00_BITBLT_CLIENT | | 
|  | 738 | BR00_OP_COLOR_BLT | 0x3 ); | 
|  | 739 | OUT_RING( BR13_SOLID_PATTERN | (0xF0 << 16) | pitch ); | 
|  | 740 | OUT_RING( (height << 16) | width ); | 
|  | 741 | OUT_RING( dev_priv->depth_offset + start ); | 
|  | 742 | OUT_RING( clear_zval ); | 
|  | 743 | OUT_RING( 0 ); | 
|  | 744 | ADVANCE_LP_RING(); | 
|  | 745 | } | 
|  | 746 | } | 
|  | 747 | } | 
|  | 748 |  | 
|  | 749 | static void i810_dma_dispatch_swap( drm_device_t *dev ) | 
|  | 750 | { | 
|  | 751 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 752 | drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; | 
|  | 753 | int nbox = sarea_priv->nbox; | 
|  | 754 | drm_clip_rect_t *pbox = sarea_priv->boxes; | 
|  | 755 | int pitch = dev_priv->pitch; | 
|  | 756 | int cpp = 2; | 
|  | 757 | int i; | 
|  | 758 | RING_LOCALS; | 
|  | 759 |  | 
|  | 760 | DRM_DEBUG("swapbuffers\n"); | 
|  | 761 |  | 
|  | 762 | i810_kernel_lost_context(dev); | 
|  | 763 |  | 
|  | 764 | if (nbox > I810_NR_SAREA_CLIPRECTS) | 
|  | 765 | nbox = I810_NR_SAREA_CLIPRECTS; | 
|  | 766 |  | 
|  | 767 | for (i = 0 ; i < nbox; i++, pbox++) | 
|  | 768 | { | 
|  | 769 | unsigned int w = pbox->x2 - pbox->x1; | 
|  | 770 | unsigned int h = pbox->y2 - pbox->y1; | 
|  | 771 | unsigned int dst = pbox->x1*cpp + pbox->y1*pitch; | 
|  | 772 | unsigned int start = dst; | 
|  | 773 |  | 
|  | 774 | if (pbox->x1 > pbox->x2 || | 
|  | 775 | pbox->y1 > pbox->y2 || | 
|  | 776 | pbox->x2 > dev_priv->w || | 
|  | 777 | pbox->y2 > dev_priv->h) | 
|  | 778 | continue; | 
|  | 779 |  | 
|  | 780 | BEGIN_LP_RING( 6 ); | 
|  | 781 | OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 ); | 
|  | 782 | OUT_RING( pitch | (0xCC << 16)); | 
|  | 783 | OUT_RING( (h << 16) | (w * cpp)); | 
|  | 784 | if (dev_priv->current_page == 0) | 
|  | 785 | OUT_RING(dev_priv->front_offset + start); | 
|  | 786 | else | 
|  | 787 | OUT_RING(dev_priv->back_offset + start); | 
|  | 788 | OUT_RING( pitch ); | 
|  | 789 | if (dev_priv->current_page == 0) | 
|  | 790 | OUT_RING(dev_priv->back_offset + start); | 
|  | 791 | else | 
|  | 792 | OUT_RING(dev_priv->front_offset + start); | 
|  | 793 | ADVANCE_LP_RING(); | 
|  | 794 | } | 
|  | 795 | } | 
|  | 796 |  | 
|  | 797 |  | 
|  | 798 | static void i810_dma_dispatch_vertex(drm_device_t *dev, | 
|  | 799 | drm_buf_t *buf, | 
|  | 800 | int discard, | 
|  | 801 | int used) | 
|  | 802 | { | 
|  | 803 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 804 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 805 | drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; | 
|  | 806 | drm_clip_rect_t *box = sarea_priv->boxes; | 
|  | 807 | int nbox = sarea_priv->nbox; | 
|  | 808 | unsigned long address = (unsigned long)buf->bus_address; | 
|  | 809 | unsigned long start = address - dev->agp->base; | 
|  | 810 | int i = 0; | 
|  | 811 | RING_LOCALS; | 
|  | 812 |  | 
|  | 813 | i810_kernel_lost_context(dev); | 
|  | 814 |  | 
|  | 815 | if (nbox > I810_NR_SAREA_CLIPRECTS) | 
|  | 816 | nbox = I810_NR_SAREA_CLIPRECTS; | 
|  | 817 |  | 
|  | 818 | if (used > 4*1024) | 
|  | 819 | used = 0; | 
|  | 820 |  | 
|  | 821 | if (sarea_priv->dirty) | 
|  | 822 | i810EmitState( dev ); | 
|  | 823 |  | 
|  | 824 | if (buf_priv->currently_mapped == I810_BUF_MAPPED) { | 
|  | 825 | unsigned int prim = (sarea_priv->vertex_prim & PR_MASK); | 
|  | 826 |  | 
|  | 827 | *(u32 *)buf_priv->kernel_virtual = ((GFX_OP_PRIMITIVE | prim | ((used/4)-2))); | 
|  | 828 |  | 
|  | 829 | if (used & 4) { | 
|  | 830 | *(u32 *)((u32)buf_priv->kernel_virtual + used) = 0; | 
|  | 831 | used += 4; | 
|  | 832 | } | 
|  | 833 |  | 
|  | 834 | i810_unmap_buffer(buf); | 
|  | 835 | } | 
|  | 836 |  | 
|  | 837 | if (used) { | 
|  | 838 | do { | 
|  | 839 | if (i < nbox) { | 
|  | 840 | BEGIN_LP_RING(4); | 
|  | 841 | OUT_RING( GFX_OP_SCISSOR | SC_UPDATE_SCISSOR | | 
|  | 842 | SC_ENABLE ); | 
|  | 843 | OUT_RING( GFX_OP_SCISSOR_INFO ); | 
|  | 844 | OUT_RING( box[i].x1 | (box[i].y1<<16) ); | 
|  | 845 | OUT_RING( (box[i].x2-1) | ((box[i].y2-1)<<16) ); | 
|  | 846 | ADVANCE_LP_RING(); | 
|  | 847 | } | 
|  | 848 |  | 
|  | 849 | BEGIN_LP_RING(4); | 
|  | 850 | OUT_RING( CMD_OP_BATCH_BUFFER ); | 
|  | 851 | OUT_RING( start | BB1_PROTECTED ); | 
|  | 852 | OUT_RING( start + used - 4 ); | 
|  | 853 | OUT_RING( 0 ); | 
|  | 854 | ADVANCE_LP_RING(); | 
|  | 855 |  | 
|  | 856 | } while (++i < nbox); | 
|  | 857 | } | 
|  | 858 |  | 
|  | 859 | if (discard) { | 
|  | 860 | dev_priv->counter++; | 
|  | 861 |  | 
|  | 862 | (void) cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, | 
|  | 863 | I810_BUF_HARDWARE); | 
|  | 864 |  | 
|  | 865 | BEGIN_LP_RING(8); | 
|  | 866 | OUT_RING( CMD_STORE_DWORD_IDX ); | 
|  | 867 | OUT_RING( 20 ); | 
|  | 868 | OUT_RING( dev_priv->counter ); | 
|  | 869 | OUT_RING( CMD_STORE_DWORD_IDX ); | 
|  | 870 | OUT_RING( buf_priv->my_use_idx ); | 
|  | 871 | OUT_RING( I810_BUF_FREE ); | 
|  | 872 | OUT_RING( CMD_REPORT_HEAD ); | 
|  | 873 | OUT_RING( 0 ); | 
|  | 874 | ADVANCE_LP_RING(); | 
|  | 875 | } | 
|  | 876 | } | 
|  | 877 |  | 
|  | 878 | static void i810_dma_dispatch_flip( drm_device_t *dev ) | 
|  | 879 | { | 
|  | 880 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 881 | int pitch = dev_priv->pitch; | 
|  | 882 | RING_LOCALS; | 
|  | 883 |  | 
|  | 884 | DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", | 
|  | 885 | __FUNCTION__, | 
|  | 886 | dev_priv->current_page, | 
|  | 887 | dev_priv->sarea_priv->pf_current_page); | 
|  | 888 |  | 
|  | 889 | i810_kernel_lost_context(dev); | 
|  | 890 |  | 
|  | 891 | BEGIN_LP_RING( 2 ); | 
|  | 892 | OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); | 
|  | 893 | OUT_RING( 0 ); | 
|  | 894 | ADVANCE_LP_RING(); | 
|  | 895 |  | 
|  | 896 | BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 ); | 
|  | 897 | /* On i815 at least ASYNC is buggy */ | 
|  | 898 | /* pitch<<5 is from 11.2.8 p158, | 
|  | 899 | its the pitch / 8 then left shifted 8, | 
|  | 900 | so (pitch >> 3) << 8 */ | 
|  | 901 | OUT_RING( CMD_OP_FRONTBUFFER_INFO | (pitch<<5) /*| ASYNC_FLIP */ ); | 
|  | 902 | if ( dev_priv->current_page == 0 ) { | 
|  | 903 | OUT_RING( dev_priv->back_offset ); | 
|  | 904 | dev_priv->current_page = 1; | 
|  | 905 | } else { | 
|  | 906 | OUT_RING( dev_priv->front_offset ); | 
|  | 907 | dev_priv->current_page = 0; | 
|  | 908 | } | 
|  | 909 | OUT_RING(0); | 
|  | 910 | ADVANCE_LP_RING(); | 
|  | 911 |  | 
|  | 912 | BEGIN_LP_RING(2); | 
|  | 913 | OUT_RING( CMD_OP_WAIT_FOR_EVENT | WAIT_FOR_PLANE_A_FLIP ); | 
|  | 914 | OUT_RING( 0 ); | 
|  | 915 | ADVANCE_LP_RING(); | 
|  | 916 |  | 
|  | 917 | /* Increment the frame counter.  The client-side 3D driver must | 
|  | 918 | * throttle the framerate by waiting for this value before | 
|  | 919 | * performing the swapbuffer ioctl. | 
|  | 920 | */ | 
|  | 921 | dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; | 
|  | 922 |  | 
|  | 923 | } | 
|  | 924 |  | 
|  | 925 | static void i810_dma_quiescent(drm_device_t *dev) | 
|  | 926 | { | 
|  | 927 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 928 | RING_LOCALS; | 
|  | 929 |  | 
|  | 930 | /*  	printk("%s\n", __FUNCTION__); */ | 
|  | 931 |  | 
|  | 932 | i810_kernel_lost_context(dev); | 
|  | 933 |  | 
|  | 934 | BEGIN_LP_RING(4); | 
|  | 935 | OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); | 
|  | 936 | OUT_RING( CMD_REPORT_HEAD ); | 
|  | 937 | OUT_RING( 0 ); | 
|  | 938 | OUT_RING( 0 ); | 
|  | 939 | ADVANCE_LP_RING(); | 
|  | 940 |  | 
|  | 941 | i810_wait_ring( dev, dev_priv->ring.Size - 8 ); | 
|  | 942 | } | 
|  | 943 |  | 
|  | 944 | static int i810_flush_queue(drm_device_t *dev) | 
|  | 945 | { | 
|  | 946 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 947 | drm_device_dma_t *dma = dev->dma; | 
|  | 948 | int i, ret = 0; | 
|  | 949 | RING_LOCALS; | 
|  | 950 |  | 
|  | 951 | /*  	printk("%s\n", __FUNCTION__); */ | 
|  | 952 |  | 
|  | 953 | i810_kernel_lost_context(dev); | 
|  | 954 |  | 
|  | 955 | BEGIN_LP_RING(2); | 
|  | 956 | OUT_RING( CMD_REPORT_HEAD ); | 
|  | 957 | OUT_RING( 0 ); | 
|  | 958 | ADVANCE_LP_RING(); | 
|  | 959 |  | 
|  | 960 | i810_wait_ring( dev, dev_priv->ring.Size - 8 ); | 
|  | 961 |  | 
|  | 962 | for (i = 0; i < dma->buf_count; i++) { | 
|  | 963 | drm_buf_t *buf = dma->buflist[ i ]; | 
|  | 964 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 965 |  | 
|  | 966 | int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE, | 
|  | 967 | I810_BUF_FREE); | 
|  | 968 |  | 
|  | 969 | if (used == I810_BUF_HARDWARE) | 
|  | 970 | DRM_DEBUG("reclaimed from HARDWARE\n"); | 
|  | 971 | if (used == I810_BUF_CLIENT) | 
|  | 972 | DRM_DEBUG("still on client\n"); | 
|  | 973 | } | 
|  | 974 |  | 
|  | 975 | return ret; | 
|  | 976 | } | 
|  | 977 |  | 
|  | 978 | /* Must be called with the lock held */ | 
|  | 979 | void i810_reclaim_buffers(drm_device_t *dev, struct file *filp) | 
|  | 980 | { | 
|  | 981 | drm_device_dma_t *dma = dev->dma; | 
|  | 982 | int		 i; | 
|  | 983 |  | 
|  | 984 | if (!dma) return; | 
|  | 985 | if (!dev->dev_private) return; | 
|  | 986 | if (!dma->buflist) return; | 
|  | 987 |  | 
|  | 988 | i810_flush_queue(dev); | 
|  | 989 |  | 
|  | 990 | for (i = 0; i < dma->buf_count; i++) { | 
|  | 991 | drm_buf_t *buf = dma->buflist[ i ]; | 
|  | 992 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 993 |  | 
|  | 994 | if (buf->filp == filp && buf_priv) { | 
|  | 995 | int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, | 
|  | 996 | I810_BUF_FREE); | 
|  | 997 |  | 
|  | 998 | if (used == I810_BUF_CLIENT) | 
|  | 999 | DRM_DEBUG("reclaimed from client\n"); | 
|  | 1000 | if (buf_priv->currently_mapped == I810_BUF_MAPPED) | 
|  | 1001 | buf_priv->currently_mapped = I810_BUF_UNMAPPED; | 
|  | 1002 | } | 
|  | 1003 | } | 
|  | 1004 | } | 
|  | 1005 |  | 
|  | 1006 | int i810_flush_ioctl(struct inode *inode, struct file *filp, | 
|  | 1007 | unsigned int cmd, unsigned long arg) | 
|  | 1008 | { | 
|  | 1009 | drm_file_t	  *priv	  = filp->private_data; | 
|  | 1010 | drm_device_t	  *dev	  = priv->head->dev; | 
|  | 1011 |  | 
|  | 1012 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1013 |  | 
|  | 1014 | i810_flush_queue(dev); | 
|  | 1015 | return 0; | 
|  | 1016 | } | 
|  | 1017 |  | 
|  | 1018 |  | 
|  | 1019 | static int i810_dma_vertex(struct inode *inode, struct file *filp, | 
|  | 1020 | unsigned int cmd, unsigned long arg) | 
|  | 1021 | { | 
|  | 1022 | drm_file_t *priv = filp->private_data; | 
|  | 1023 | drm_device_t *dev = priv->head->dev; | 
|  | 1024 | drm_device_dma_t *dma = dev->dma; | 
|  | 1025 | drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; | 
|  | 1026 | u32 *hw_status = dev_priv->hw_status_page; | 
|  | 1027 | drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) | 
|  | 1028 | dev_priv->sarea_priv; | 
|  | 1029 | drm_i810_vertex_t vertex; | 
|  | 1030 |  | 
|  | 1031 | if (copy_from_user(&vertex, (drm_i810_vertex_t __user *)arg, sizeof(vertex))) | 
|  | 1032 | return -EFAULT; | 
|  | 1033 |  | 
|  | 1034 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1035 |  | 
|  | 1036 | DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", | 
|  | 1037 | vertex.idx, vertex.used, vertex.discard); | 
|  | 1038 |  | 
|  | 1039 | if (vertex.idx < 0 || vertex.idx > dma->buf_count) | 
|  | 1040 | return -EINVAL; | 
|  | 1041 |  | 
|  | 1042 | i810_dma_dispatch_vertex( dev, | 
|  | 1043 | dma->buflist[ vertex.idx ], | 
|  | 1044 | vertex.discard, vertex.used ); | 
|  | 1045 |  | 
|  | 1046 | atomic_add(vertex.used, &dev->counts[_DRM_STAT_SECONDARY]); | 
|  | 1047 | atomic_inc(&dev->counts[_DRM_STAT_DMA]); | 
|  | 1048 | sarea_priv->last_enqueue = dev_priv->counter-1; | 
|  | 1049 | sarea_priv->last_dispatch = (int) hw_status[5]; | 
|  | 1050 |  | 
|  | 1051 | return 0; | 
|  | 1052 | } | 
|  | 1053 |  | 
|  | 1054 |  | 
|  | 1055 |  | 
|  | 1056 | static int i810_clear_bufs(struct inode *inode, struct file *filp, | 
|  | 1057 | unsigned int cmd, unsigned long arg) | 
|  | 1058 | { | 
|  | 1059 | drm_file_t *priv = filp->private_data; | 
|  | 1060 | drm_device_t *dev = priv->head->dev; | 
|  | 1061 | drm_i810_clear_t clear; | 
|  | 1062 |  | 
|  | 1063 | if (copy_from_user(&clear, (drm_i810_clear_t __user *)arg, sizeof(clear))) | 
|  | 1064 | return -EFAULT; | 
|  | 1065 |  | 
|  | 1066 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1067 |  | 
|  | 1068 | /* GH: Someone's doing nasty things... */ | 
|  | 1069 | if (!dev->dev_private) { | 
|  | 1070 | return -EINVAL; | 
|  | 1071 | } | 
|  | 1072 |  | 
|  | 1073 | i810_dma_dispatch_clear( dev, clear.flags, | 
|  | 1074 | clear.clear_color, | 
|  | 1075 | clear.clear_depth ); | 
|  | 1076 | return 0; | 
|  | 1077 | } | 
|  | 1078 |  | 
|  | 1079 | static int i810_swap_bufs(struct inode *inode, struct file *filp, | 
|  | 1080 | unsigned int cmd, unsigned long arg) | 
|  | 1081 | { | 
|  | 1082 | drm_file_t *priv = filp->private_data; | 
|  | 1083 | drm_device_t *dev = priv->head->dev; | 
|  | 1084 |  | 
|  | 1085 | DRM_DEBUG("i810_swap_bufs\n"); | 
|  | 1086 |  | 
|  | 1087 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1088 |  | 
|  | 1089 | i810_dma_dispatch_swap( dev ); | 
|  | 1090 | return 0; | 
|  | 1091 | } | 
|  | 1092 |  | 
|  | 1093 | static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, | 
|  | 1094 | unsigned long arg) | 
|  | 1095 | { | 
|  | 1096 | drm_file_t	  *priv	    = filp->private_data; | 
|  | 1097 | drm_device_t	  *dev	    = priv->head->dev; | 
|  | 1098 | drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; | 
|  | 1099 | u32 *hw_status = dev_priv->hw_status_page; | 
|  | 1100 | drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) | 
|  | 1101 | dev_priv->sarea_priv; | 
|  | 1102 |  | 
|  | 1103 | sarea_priv->last_dispatch = (int) hw_status[5]; | 
|  | 1104 | return 0; | 
|  | 1105 | } | 
|  | 1106 |  | 
|  | 1107 | static int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd, | 
|  | 1108 | unsigned long arg) | 
|  | 1109 | { | 
|  | 1110 | drm_file_t	  *priv	    = filp->private_data; | 
|  | 1111 | drm_device_t	  *dev	    = priv->head->dev; | 
|  | 1112 | int		  retcode   = 0; | 
|  | 1113 | drm_i810_dma_t	  d; | 
|  | 1114 | drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; | 
|  | 1115 | u32 *hw_status = dev_priv->hw_status_page; | 
|  | 1116 | drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) | 
|  | 1117 | dev_priv->sarea_priv; | 
|  | 1118 |  | 
|  | 1119 | if (copy_from_user(&d, (drm_i810_dma_t __user *)arg, sizeof(d))) | 
|  | 1120 | return -EFAULT; | 
|  | 1121 |  | 
|  | 1122 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1123 |  | 
|  | 1124 | d.granted = 0; | 
|  | 1125 |  | 
|  | 1126 | retcode = i810_dma_get_buffer(dev, &d, filp); | 
|  | 1127 |  | 
|  | 1128 | DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n", | 
|  | 1129 | current->pid, retcode, d.granted); | 
|  | 1130 |  | 
|  | 1131 | if (copy_to_user((drm_dma_t __user *)arg, &d, sizeof(d))) | 
|  | 1132 | return -EFAULT; | 
|  | 1133 | sarea_priv->last_dispatch = (int) hw_status[5]; | 
|  | 1134 |  | 
|  | 1135 | return retcode; | 
|  | 1136 | } | 
|  | 1137 |  | 
|  | 1138 | static int i810_copybuf(struct inode *inode, | 
|  | 1139 | struct file *filp, unsigned int cmd, unsigned long arg) | 
|  | 1140 | { | 
|  | 1141 | /* Never copy - 2.4.x doesn't need it */ | 
|  | 1142 | return 0; | 
|  | 1143 | } | 
|  | 1144 |  | 
|  | 1145 | static int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd, | 
|  | 1146 | unsigned long arg) | 
|  | 1147 | { | 
|  | 1148 | /* Never copy - 2.4.x doesn't need it */ | 
|  | 1149 | return 0; | 
|  | 1150 | } | 
|  | 1151 |  | 
|  | 1152 | static void i810_dma_dispatch_mc(drm_device_t *dev, drm_buf_t *buf, int used, | 
|  | 1153 | unsigned int last_render) | 
|  | 1154 | { | 
|  | 1155 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 1156 | drm_i810_buf_priv_t *buf_priv = buf->dev_private; | 
|  | 1157 | drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; | 
|  | 1158 | unsigned long address = (unsigned long)buf->bus_address; | 
|  | 1159 | unsigned long start = address - dev->agp->base; | 
|  | 1160 | int u; | 
|  | 1161 | RING_LOCALS; | 
|  | 1162 |  | 
|  | 1163 | i810_kernel_lost_context(dev); | 
|  | 1164 |  | 
|  | 1165 | u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, | 
|  | 1166 | I810_BUF_HARDWARE); | 
|  | 1167 | if (u != I810_BUF_CLIENT) { | 
|  | 1168 | DRM_DEBUG("MC found buffer that isn't mine!\n"); | 
|  | 1169 | } | 
|  | 1170 |  | 
|  | 1171 | if (used > 4*1024) | 
|  | 1172 | used = 0; | 
|  | 1173 |  | 
|  | 1174 | sarea_priv->dirty = 0x7f; | 
|  | 1175 |  | 
|  | 1176 | DRM_DEBUG("dispatch mc addr 0x%lx, used 0x%x\n", | 
|  | 1177 | address, used); | 
|  | 1178 |  | 
|  | 1179 | dev_priv->counter++; | 
|  | 1180 | DRM_DEBUG("dispatch counter : %ld\n", dev_priv->counter); | 
|  | 1181 | DRM_DEBUG("i810_dma_dispatch_mc\n"); | 
|  | 1182 | DRM_DEBUG("start : %lx\n", start); | 
|  | 1183 | DRM_DEBUG("used : %d\n", used); | 
|  | 1184 | DRM_DEBUG("start + used - 4 : %ld\n", start + used - 4); | 
|  | 1185 |  | 
|  | 1186 | if (buf_priv->currently_mapped == I810_BUF_MAPPED) { | 
|  | 1187 | if (used & 4) { | 
|  | 1188 | *(u32 *)((u32)buf_priv->virtual + used) = 0; | 
|  | 1189 | used += 4; | 
|  | 1190 | } | 
|  | 1191 |  | 
|  | 1192 | i810_unmap_buffer(buf); | 
|  | 1193 | } | 
|  | 1194 | BEGIN_LP_RING(4); | 
|  | 1195 | OUT_RING( CMD_OP_BATCH_BUFFER ); | 
|  | 1196 | OUT_RING( start | BB1_PROTECTED ); | 
|  | 1197 | OUT_RING( start + used - 4 ); | 
|  | 1198 | OUT_RING( 0 ); | 
|  | 1199 | ADVANCE_LP_RING(); | 
|  | 1200 |  | 
|  | 1201 |  | 
|  | 1202 | BEGIN_LP_RING(8); | 
|  | 1203 | OUT_RING( CMD_STORE_DWORD_IDX ); | 
|  | 1204 | OUT_RING( buf_priv->my_use_idx ); | 
|  | 1205 | OUT_RING( I810_BUF_FREE ); | 
|  | 1206 | OUT_RING( 0 ); | 
|  | 1207 |  | 
|  | 1208 | OUT_RING( CMD_STORE_DWORD_IDX ); | 
|  | 1209 | OUT_RING( 16 ); | 
|  | 1210 | OUT_RING( last_render ); | 
|  | 1211 | OUT_RING( 0 ); | 
|  | 1212 | ADVANCE_LP_RING(); | 
|  | 1213 | } | 
|  | 1214 |  | 
|  | 1215 | static int i810_dma_mc(struct inode *inode, struct file *filp, | 
|  | 1216 | unsigned int cmd, unsigned long arg) | 
|  | 1217 | { | 
|  | 1218 | drm_file_t *priv = filp->private_data; | 
|  | 1219 | drm_device_t *dev = priv->head->dev; | 
|  | 1220 | drm_device_dma_t *dma = dev->dma; | 
|  | 1221 | drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; | 
|  | 1222 | u32 *hw_status = dev_priv->hw_status_page; | 
|  | 1223 | drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) | 
|  | 1224 | dev_priv->sarea_priv; | 
|  | 1225 | drm_i810_mc_t mc; | 
|  | 1226 |  | 
|  | 1227 | if (copy_from_user(&mc, (drm_i810_mc_t __user *)arg, sizeof(mc))) | 
|  | 1228 | return -EFAULT; | 
|  | 1229 |  | 
|  | 1230 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1231 |  | 
|  | 1232 | if (mc.idx >= dma->buf_count || mc.idx < 0) | 
|  | 1233 | return -EINVAL; | 
|  | 1234 |  | 
|  | 1235 | i810_dma_dispatch_mc(dev, dma->buflist[mc.idx], mc.used, | 
|  | 1236 | mc.last_render ); | 
|  | 1237 |  | 
|  | 1238 | atomic_add(mc.used, &dev->counts[_DRM_STAT_SECONDARY]); | 
|  | 1239 | atomic_inc(&dev->counts[_DRM_STAT_DMA]); | 
|  | 1240 | sarea_priv->last_enqueue = dev_priv->counter-1; | 
|  | 1241 | sarea_priv->last_dispatch = (int) hw_status[5]; | 
|  | 1242 |  | 
|  | 1243 | return 0; | 
|  | 1244 | } | 
|  | 1245 |  | 
|  | 1246 | static int i810_rstatus(struct inode *inode, struct file *filp, | 
|  | 1247 | unsigned int cmd, unsigned long arg) | 
|  | 1248 | { | 
|  | 1249 | drm_file_t *priv = filp->private_data; | 
|  | 1250 | drm_device_t *dev = priv->head->dev; | 
|  | 1251 | drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; | 
|  | 1252 |  | 
|  | 1253 | return (int)(((u32 *)(dev_priv->hw_status_page))[4]); | 
|  | 1254 | } | 
|  | 1255 |  | 
|  | 1256 | static int i810_ov0_info(struct inode *inode, struct file *filp, | 
|  | 1257 | unsigned int cmd, unsigned long arg) | 
|  | 1258 | { | 
|  | 1259 | drm_file_t *priv = filp->private_data; | 
|  | 1260 | drm_device_t *dev = priv->head->dev; | 
|  | 1261 | drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; | 
|  | 1262 | drm_i810_overlay_t data; | 
|  | 1263 |  | 
|  | 1264 | data.offset = dev_priv->overlay_offset; | 
|  | 1265 | data.physical = dev_priv->overlay_physical; | 
|  | 1266 | if (copy_to_user((drm_i810_overlay_t __user *)arg,&data,sizeof(data))) | 
|  | 1267 | return -EFAULT; | 
|  | 1268 | return 0; | 
|  | 1269 | } | 
|  | 1270 |  | 
|  | 1271 | static int i810_fstatus(struct inode *inode, struct file *filp, | 
|  | 1272 | unsigned int cmd, unsigned long arg) | 
|  | 1273 | { | 
|  | 1274 | drm_file_t *priv = filp->private_data; | 
|  | 1275 | drm_device_t *dev = priv->head->dev; | 
|  | 1276 | drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; | 
|  | 1277 |  | 
|  | 1278 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1279 |  | 
|  | 1280 | return I810_READ(0x30008); | 
|  | 1281 | } | 
|  | 1282 |  | 
|  | 1283 | static int i810_ov0_flip(struct inode *inode, struct file *filp, | 
|  | 1284 | unsigned int cmd, unsigned long arg) | 
|  | 1285 | { | 
|  | 1286 | drm_file_t *priv = filp->private_data; | 
|  | 1287 | drm_device_t *dev = priv->head->dev; | 
|  | 1288 | drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; | 
|  | 1289 |  | 
|  | 1290 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1291 |  | 
|  | 1292 | //Tell the overlay to update | 
|  | 1293 | I810_WRITE(0x30000,dev_priv->overlay_physical | 0x80000000); | 
|  | 1294 |  | 
|  | 1295 | return 0; | 
|  | 1296 | } | 
|  | 1297 |  | 
|  | 1298 |  | 
|  | 1299 | /* Not sure why this isn't set all the time: | 
|  | 1300 | */ | 
|  | 1301 | static void i810_do_init_pageflip( drm_device_t *dev ) | 
|  | 1302 | { | 
|  | 1303 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 1304 |  | 
|  | 1305 | DRM_DEBUG("%s\n", __FUNCTION__); | 
|  | 1306 | dev_priv->page_flipping = 1; | 
|  | 1307 | dev_priv->current_page = 0; | 
|  | 1308 | dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; | 
|  | 1309 | } | 
|  | 1310 |  | 
|  | 1311 | static int i810_do_cleanup_pageflip( drm_device_t *dev ) | 
|  | 1312 | { | 
|  | 1313 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 1314 |  | 
|  | 1315 | DRM_DEBUG("%s\n", __FUNCTION__); | 
|  | 1316 | if (dev_priv->current_page != 0) | 
|  | 1317 | i810_dma_dispatch_flip( dev ); | 
|  | 1318 |  | 
|  | 1319 | dev_priv->page_flipping = 0; | 
|  | 1320 | return 0; | 
|  | 1321 | } | 
|  | 1322 |  | 
|  | 1323 | static int i810_flip_bufs(struct inode *inode, struct file *filp, | 
|  | 1324 | unsigned int cmd, unsigned long arg) | 
|  | 1325 | { | 
|  | 1326 | drm_file_t *priv = filp->private_data; | 
|  | 1327 | drm_device_t *dev = priv->head->dev; | 
|  | 1328 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 1329 |  | 
|  | 1330 | DRM_DEBUG("%s\n", __FUNCTION__); | 
|  | 1331 |  | 
|  | 1332 | LOCK_TEST_WITH_RETURN(dev, filp); | 
|  | 1333 |  | 
|  | 1334 | if (!dev_priv->page_flipping) | 
|  | 1335 | i810_do_init_pageflip( dev ); | 
|  | 1336 |  | 
|  | 1337 | i810_dma_dispatch_flip( dev ); | 
|  | 1338 | return 0; | 
|  | 1339 | } | 
|  | 1340 |  | 
|  | 1341 | void i810_driver_pretakedown(drm_device_t *dev) | 
|  | 1342 | { | 
|  | 1343 | i810_dma_cleanup( dev ); | 
|  | 1344 | } | 
|  | 1345 |  | 
|  | 1346 | void i810_driver_prerelease(drm_device_t *dev, DRMFILE filp) | 
|  | 1347 | { | 
|  | 1348 | if (dev->dev_private) { | 
|  | 1349 | drm_i810_private_t *dev_priv = dev->dev_private; | 
|  | 1350 | if (dev_priv->page_flipping) { | 
|  | 1351 | i810_do_cleanup_pageflip(dev); | 
|  | 1352 | } | 
|  | 1353 | } | 
|  | 1354 | } | 
|  | 1355 |  | 
|  | 1356 | void i810_driver_release(drm_device_t *dev, struct file *filp) | 
|  | 1357 | { | 
|  | 1358 | i810_reclaim_buffers(dev, filp); | 
|  | 1359 | } | 
|  | 1360 |  | 
|  | 1361 | int i810_driver_dma_quiescent(drm_device_t *dev) | 
|  | 1362 | { | 
|  | 1363 | i810_dma_quiescent( dev ); | 
|  | 1364 | return 0; | 
|  | 1365 | } | 
|  | 1366 |  | 
|  | 1367 | drm_ioctl_desc_t i810_ioctls[] = { | 
|  | 1368 | [DRM_IOCTL_NR(DRM_I810_INIT)]    = { i810_dma_init,    1, 1 }, | 
|  | 1369 | [DRM_IOCTL_NR(DRM_I810_VERTEX)]  = { i810_dma_vertex,  1, 0 }, | 
|  | 1370 | [DRM_IOCTL_NR(DRM_I810_CLEAR)]   = { i810_clear_bufs,  1, 0 }, | 
|  | 1371 | [DRM_IOCTL_NR(DRM_I810_FLUSH)]   = { i810_flush_ioctl, 1, 0 }, | 
|  | 1372 | [DRM_IOCTL_NR(DRM_I810_GETAGE)]  = { i810_getage,      1, 0 }, | 
|  | 1373 | [DRM_IOCTL_NR(DRM_I810_GETBUF)]  = { i810_getbuf,      1, 0 }, | 
|  | 1374 | [DRM_IOCTL_NR(DRM_I810_SWAP)]    = { i810_swap_bufs,   1, 0 }, | 
|  | 1375 | [DRM_IOCTL_NR(DRM_I810_COPY)]    = { i810_copybuf,     1, 0 }, | 
|  | 1376 | [DRM_IOCTL_NR(DRM_I810_DOCOPY)]  = { i810_docopy,      1, 0 }, | 
|  | 1377 | [DRM_IOCTL_NR(DRM_I810_OV0INFO)] = { i810_ov0_info,    1, 0 }, | 
|  | 1378 | [DRM_IOCTL_NR(DRM_I810_FSTATUS)] = { i810_fstatus,     1, 0 }, | 
|  | 1379 | [DRM_IOCTL_NR(DRM_I810_OV0FLIP)] = { i810_ov0_flip,    1, 0 }, | 
|  | 1380 | [DRM_IOCTL_NR(DRM_I810_MC)]      = { i810_dma_mc,      1, 1 }, | 
|  | 1381 | [DRM_IOCTL_NR(DRM_I810_RSTATUS)] = { i810_rstatus,     1, 0 }, | 
|  | 1382 | [DRM_IOCTL_NR(DRM_I810_FLIP)]    = { i810_flip_bufs,   1, 0 } | 
|  | 1383 | }; | 
|  | 1384 |  | 
|  | 1385 | int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); |