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