mga_dma.c revision 113995
1/* mga_dma.c -- DMA support for mga g200/g400 -*- 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: 28 * Rickard E. (Rik) Faith <faith@valinux.com> 29 * Jeff Hartmann <jhartmann@valinux.com> 30 * Keith Whitwell <keith@tungstengraphics.com> 31 * 32 * Rewritten by: 33 * Gareth Hughes <gareth@valinux.com> 34 * 35 * $FreeBSD: head/sys/dev/drm/mga_dma.c 113995 2003-04-25 01:18:47Z anholt $ 36 */ 37 38#include "dev/drm/mga.h" 39#include "dev/drm/drmP.h" 40#include "dev/drm/drm.h" 41#include "dev/drm/mga_drm.h" 42#include "dev/drm/mga_drv.h" 43 44#define MGA_DEFAULT_USEC_TIMEOUT 10000 45#define MGA_FREELIST_DEBUG 0 46 47 48/* ================================================================ 49 * Engine control 50 */ 51 52int mga_do_wait_for_idle( drm_mga_private_t *dev_priv ) 53{ 54 u32 status = 0; 55 int i; 56 DRM_DEBUG( "\n" ); 57 58 for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { 59 status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; 60 if ( status == MGA_ENDPRDMASTS ) { 61 MGA_WRITE8( MGA_CRTC_INDEX, 0 ); 62 return 0; 63 } 64 DRM_UDELAY( 1 ); 65 } 66 67#if MGA_DMA_DEBUG 68 DRM_ERROR( "failed!\n" ); 69 DRM_INFO( " status=0x%08x\n", status ); 70#endif 71 return DRM_ERR(EBUSY); 72} 73 74int mga_do_dma_idle( drm_mga_private_t *dev_priv ) 75{ 76 u32 status = 0; 77 int i; 78 DRM_DEBUG( "\n" ); 79 80 for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { 81 status = MGA_READ( MGA_STATUS ) & MGA_DMA_IDLE_MASK; 82 if ( status == MGA_ENDPRDMASTS ) return 0; 83 DRM_UDELAY( 1 ); 84 } 85 86#if MGA_DMA_DEBUG 87 DRM_ERROR( "failed! status=0x%08x\n", status ); 88#endif 89 return DRM_ERR(EBUSY); 90} 91 92int mga_do_dma_reset( drm_mga_private_t *dev_priv ) 93{ 94 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 95 drm_mga_primary_buffer_t *primary = &dev_priv->prim; 96 97 DRM_DEBUG( "\n" ); 98 99 /* The primary DMA stream should look like new right about now. 100 */ 101 primary->tail = 0; 102 primary->space = primary->size; 103 primary->last_flush = 0; 104 105 sarea_priv->last_wrap = 0; 106 107 /* FIXME: Reset counters, buffer ages etc... 108 */ 109 110 /* FIXME: What else do we need to reinitialize? WARP stuff? 111 */ 112 113 return 0; 114} 115 116int mga_do_engine_reset( drm_mga_private_t *dev_priv ) 117{ 118 DRM_DEBUG( "\n" ); 119 120 /* Okay, so we've completely screwed up and locked the engine. 121 * How about we clean up after ourselves? 122 */ 123 MGA_WRITE( MGA_RST, MGA_SOFTRESET ); 124 DRM_UDELAY( 15 ); /* Wait at least 10 usecs */ 125 MGA_WRITE( MGA_RST, 0 ); 126 127 /* Initialize the registers that get clobbered by the soft 128 * reset. Many of the core register values survive a reset, 129 * but the drawing registers are basically all gone. 130 * 131 * 3D clients should probably die after calling this. The X 132 * server should reset the engine state to known values. 133 */ 134#if 0 135 MGA_WRITE( MGA_PRIMPTR, 136 virt_to_bus((void *)dev_priv->prim.status_page) | 137 MGA_PRIMPTREN0 | 138 MGA_PRIMPTREN1 ); 139#endif 140 141 MGA_WRITE( MGA_ICLEAR, MGA_SOFTRAPICLR ); 142 MGA_WRITE( MGA_IEN, MGA_SOFTRAPIEN ); 143 144 /* The primary DMA stream should look like new right about now. 145 */ 146 mga_do_dma_reset( dev_priv ); 147 148 /* This bad boy will never fail. 149 */ 150 return 0; 151} 152 153 154/* ================================================================ 155 * Primary DMA stream 156 */ 157 158void mga_do_dma_flush( drm_mga_private_t *dev_priv ) 159{ 160 drm_mga_primary_buffer_t *primary = &dev_priv->prim; 161 u32 head, tail; 162 u32 status = 0; 163 int i; 164 DMA_LOCALS; 165 DRM_DEBUG( "\n" ); 166 167 /* We need to wait so that we can do an safe flush */ 168 for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { 169 status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; 170 if ( status == MGA_ENDPRDMASTS ) break; 171 DRM_UDELAY( 1 ); 172 } 173 174 if ( primary->tail == primary->last_flush ) { 175 DRM_DEBUG( " bailing out...\n" ); 176 return; 177 } 178 179 tail = primary->tail + dev_priv->primary->offset; 180 181 /* We need to pad the stream between flushes, as the card 182 * actually (partially?) reads the first of these commands. 183 * See page 4-16 in the G400 manual, middle of the page or so. 184 */ 185 BEGIN_DMA( 1 ); 186 187 DMA_BLOCK( MGA_DMAPAD, 0x00000000, 188 MGA_DMAPAD, 0x00000000, 189 MGA_DMAPAD, 0x00000000, 190 MGA_DMAPAD, 0x00000000 ); 191 192 ADVANCE_DMA(); 193 194 primary->last_flush = primary->tail; 195 196 head = MGA_READ( MGA_PRIMADDRESS ); 197 198 if ( head <= tail ) { 199 primary->space = primary->size - primary->tail; 200 } else { 201 primary->space = head - tail; 202 } 203 204 DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset ); 205 DRM_DEBUG( " tail = 0x%06lx\n", tail - dev_priv->primary->offset ); 206 DRM_DEBUG( " space = 0x%06x\n", primary->space ); 207 208 mga_flush_write_combine(); 209 MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); 210 211 DRM_DEBUG( "done.\n" ); 212} 213 214void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv ) 215{ 216 drm_mga_primary_buffer_t *primary = &dev_priv->prim; 217 u32 head, tail; 218 DMA_LOCALS; 219 DRM_DEBUG( "\n" ); 220 221 BEGIN_DMA_WRAP(); 222 223 DMA_BLOCK( MGA_DMAPAD, 0x00000000, 224 MGA_DMAPAD, 0x00000000, 225 MGA_DMAPAD, 0x00000000, 226 MGA_DMAPAD, 0x00000000 ); 227 228 ADVANCE_DMA(); 229 230 tail = primary->tail + dev_priv->primary->offset; 231 232 primary->tail = 0; 233 primary->last_flush = 0; 234 primary->last_wrap++; 235 236 head = MGA_READ( MGA_PRIMADDRESS ); 237 238 if ( head == dev_priv->primary->offset ) { 239 primary->space = primary->size; 240 } else { 241 primary->space = head - dev_priv->primary->offset; 242 } 243 244 DRM_DEBUG( " head = 0x%06lx\n", 245 head - dev_priv->primary->offset ); 246 DRM_DEBUG( " tail = 0x%06x\n", primary->tail ); 247 DRM_DEBUG( " wrap = %d\n", primary->last_wrap ); 248 DRM_DEBUG( " space = 0x%06x\n", primary->space ); 249 250 mga_flush_write_combine(); 251 MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); 252 253 set_bit( 0, &primary->wrapped ); 254 DRM_DEBUG( "done.\n" ); 255} 256 257void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv ) 258{ 259 drm_mga_primary_buffer_t *primary = &dev_priv->prim; 260 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 261 u32 head = dev_priv->primary->offset; 262 DRM_DEBUG( "\n" ); 263 264 sarea_priv->last_wrap++; 265 DRM_DEBUG( " wrap = %d\n", sarea_priv->last_wrap ); 266 267 mga_flush_write_combine(); 268 MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL ); 269 270 clear_bit( 0, &primary->wrapped ); 271 DRM_DEBUG( "done.\n" ); 272} 273 274 275/* ================================================================ 276 * Freelist management 277 */ 278 279#define MGA_BUFFER_USED ~0 280#define MGA_BUFFER_FREE 0 281 282#if MGA_FREELIST_DEBUG 283static void mga_freelist_print( drm_device_t *dev ) 284{ 285 drm_mga_private_t *dev_priv = dev->dev_private; 286 drm_mga_freelist_t *entry; 287 288 DRM_INFO( "\n" ); 289 DRM_INFO( "current dispatch: last=0x%x done=0x%x\n", 290 dev_priv->sarea_priv->last_dispatch, 291 (unsigned int)(MGA_READ( MGA_PRIMADDRESS ) - 292 dev_priv->primary->offset) ); 293 DRM_INFO( "current freelist:\n" ); 294 295 for ( entry = dev_priv->head->next ; entry ; entry = entry->next ) { 296 DRM_INFO( " %p idx=%2d age=0x%x 0x%06lx\n", 297 entry, entry->buf->idx, entry->age.head, 298 entry->age.head - dev_priv->primary->offset ); 299 } 300 DRM_INFO( "\n" ); 301} 302#endif 303 304static int mga_freelist_init( drm_device_t *dev, drm_mga_private_t *dev_priv ) 305{ 306 drm_device_dma_t *dma = dev->dma; 307 drm_buf_t *buf; 308 drm_mga_buf_priv_t *buf_priv; 309 drm_mga_freelist_t *entry; 310 int i; 311 DRM_DEBUG( "count=%d\n", dma->buf_count ); 312 313 dev_priv->head = DRM(alloc)( sizeof(drm_mga_freelist_t), 314 DRM_MEM_DRIVER ); 315 if ( dev_priv->head == NULL ) 316 return DRM_ERR(ENOMEM); 317 318 memset( dev_priv->head, 0, sizeof(drm_mga_freelist_t) ); 319 SET_AGE( &dev_priv->head->age, MGA_BUFFER_USED, 0 ); 320 321 for ( i = 0 ; i < dma->buf_count ; i++ ) { 322 buf = dma->buflist[i]; 323 buf_priv = buf->dev_private; 324 325 entry = DRM(alloc)( sizeof(drm_mga_freelist_t), 326 DRM_MEM_DRIVER ); 327 if ( entry == NULL ) 328 return DRM_ERR(ENOMEM); 329 330 memset( entry, 0, sizeof(drm_mga_freelist_t) ); 331 332 entry->next = dev_priv->head->next; 333 entry->prev = dev_priv->head; 334 SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 ); 335 entry->buf = buf; 336 337 if ( dev_priv->head->next != NULL ) 338 dev_priv->head->next->prev = entry; 339 if ( entry->next == NULL ) 340 dev_priv->tail = entry; 341 342 buf_priv->list_entry = entry; 343 buf_priv->discard = 0; 344 buf_priv->dispatched = 0; 345 346 dev_priv->head->next = entry; 347 } 348 349 return 0; 350} 351 352static void mga_freelist_cleanup( drm_device_t *dev ) 353{ 354 drm_mga_private_t *dev_priv = dev->dev_private; 355 drm_mga_freelist_t *entry; 356 drm_mga_freelist_t *next; 357 DRM_DEBUG( "\n" ); 358 359 entry = dev_priv->head; 360 while ( entry ) { 361 next = entry->next; 362 DRM(free)( entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER ); 363 entry = next; 364 } 365 366 dev_priv->head = dev_priv->tail = NULL; 367} 368 369#if 0 370/* FIXME: Still needed? 371 */ 372static void mga_freelist_reset( drm_device_t *dev ) 373{ 374 drm_device_dma_t *dma = dev->dma; 375 drm_buf_t *buf; 376 drm_mga_buf_priv_t *buf_priv; 377 int i; 378 379 for ( i = 0 ; i < dma->buf_count ; i++ ) { 380 buf = dma->buflist[i]; 381 buf_priv = buf->dev_private; 382 SET_AGE( &buf_priv->list_entry->age, 383 MGA_BUFFER_FREE, 0 ); 384 } 385} 386#endif 387 388static drm_buf_t *mga_freelist_get( drm_device_t *dev ) 389{ 390 drm_mga_private_t *dev_priv = dev->dev_private; 391 drm_mga_freelist_t *next; 392 drm_mga_freelist_t *prev; 393 drm_mga_freelist_t *tail = dev_priv->tail; 394 u32 head, wrap; 395 DRM_DEBUG( "\n" ); 396 397 head = MGA_READ( MGA_PRIMADDRESS ); 398 wrap = dev_priv->sarea_priv->last_wrap; 399 400 DRM_DEBUG( " tail=0x%06lx %d\n", 401 tail->age.head ? 402 tail->age.head - dev_priv->primary->offset : 0, 403 tail->age.wrap ); 404 DRM_DEBUG( " head=0x%06lx %d\n", 405 head - dev_priv->primary->offset, wrap ); 406 407 if ( TEST_AGE( &tail->age, head, wrap ) ) { 408 prev = dev_priv->tail->prev; 409 next = dev_priv->tail; 410 prev->next = NULL; 411 next->prev = next->next = NULL; 412 dev_priv->tail = prev; 413 SET_AGE( &next->age, MGA_BUFFER_USED, 0 ); 414 return next->buf; 415 } 416 417 DRM_DEBUG( "returning NULL!\n" ); 418 return NULL; 419} 420 421int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf ) 422{ 423 drm_mga_private_t *dev_priv = dev->dev_private; 424 drm_mga_buf_priv_t *buf_priv = buf->dev_private; 425 drm_mga_freelist_t *head, *entry, *prev; 426 427 DRM_DEBUG( "age=0x%06lx wrap=%d\n", 428 buf_priv->list_entry->age.head - 429 dev_priv->primary->offset, 430 buf_priv->list_entry->age.wrap ); 431 432 entry = buf_priv->list_entry; 433 head = dev_priv->head; 434 435 if ( buf_priv->list_entry->age.head == MGA_BUFFER_USED ) { 436 SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 ); 437 prev = dev_priv->tail; 438 prev->next = entry; 439 entry->prev = prev; 440 entry->next = NULL; 441 } else { 442 prev = head->next; 443 head->next = entry; 444 prev->prev = entry; 445 entry->prev = head; 446 entry->next = prev; 447 } 448 449 return 0; 450} 451 452 453/* ================================================================ 454 * DMA initialization, cleanup 455 */ 456 457static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) 458{ 459 drm_mga_private_t *dev_priv; 460 int ret; 461 DRM_DEBUG( "\n" ); 462 463 dev_priv = DRM(alloc)( sizeof(drm_mga_private_t), DRM_MEM_DRIVER ); 464 if ( !dev_priv ) 465 return DRM_ERR(ENOMEM); 466 467 memset( dev_priv, 0, sizeof(drm_mga_private_t) ); 468 469 dev_priv->chipset = init->chipset; 470 471 dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; 472 473 if ( init->sgram ) { 474 dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; 475 } else { 476 dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; 477 } 478 dev_priv->maccess = init->maccess; 479 480 dev_priv->fb_cpp = init->fb_cpp; 481 dev_priv->front_offset = init->front_offset; 482 dev_priv->front_pitch = init->front_pitch; 483 dev_priv->back_offset = init->back_offset; 484 dev_priv->back_pitch = init->back_pitch; 485 486 dev_priv->depth_cpp = init->depth_cpp; 487 dev_priv->depth_offset = init->depth_offset; 488 dev_priv->depth_pitch = init->depth_pitch; 489 490 /* FIXME: Need to support AGP textures... 491 */ 492 dev_priv->texture_offset = init->texture_offset[0]; 493 dev_priv->texture_size = init->texture_size[0]; 494 495 DRM_GETSAREA(); 496 497 if(!dev_priv->sarea) { 498 DRM_ERROR( "failed to find sarea!\n" ); 499 /* Assign dev_private so we can do cleanup. */ 500 dev->dev_private = (void *)dev_priv; 501 mga_do_cleanup_dma( dev ); 502 return DRM_ERR(EINVAL); 503 } 504 505 DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); 506 if(!dev_priv->fb) { 507 DRM_ERROR( "failed to find framebuffer!\n" ); 508 /* Assign dev_private so we can do cleanup. */ 509 dev->dev_private = (void *)dev_priv; 510 mga_do_cleanup_dma( dev ); 511 return DRM_ERR(EINVAL); 512 } 513 DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); 514 if(!dev_priv->mmio) { 515 DRM_ERROR( "failed to find mmio region!\n" ); 516 /* Assign dev_private so we can do cleanup. */ 517 dev->dev_private = (void *)dev_priv; 518 mga_do_cleanup_dma( dev ); 519 return DRM_ERR(EINVAL); 520 } 521 DRM_FIND_MAP( dev_priv->status, init->status_offset ); 522 if(!dev_priv->status) { 523 DRM_ERROR( "failed to find status page!\n" ); 524 /* Assign dev_private so we can do cleanup. */ 525 dev->dev_private = (void *)dev_priv; 526 mga_do_cleanup_dma( dev ); 527 return DRM_ERR(EINVAL); 528 } 529 530 DRM_FIND_MAP( dev_priv->warp, init->warp_offset ); 531 if(!dev_priv->warp) { 532 DRM_ERROR( "failed to find warp microcode region!\n" ); 533 /* Assign dev_private so we can do cleanup. */ 534 dev->dev_private = (void *)dev_priv; 535 mga_do_cleanup_dma( dev ); 536 return DRM_ERR(EINVAL); 537 } 538 DRM_FIND_MAP( dev_priv->primary, init->primary_offset ); 539 if(!dev_priv->primary) { 540 DRM_ERROR( "failed to find primary dma region!\n" ); 541 /* Assign dev_private so we can do cleanup. */ 542 dev->dev_private = (void *)dev_priv; 543 mga_do_cleanup_dma( dev ); 544 return DRM_ERR(EINVAL); 545 } 546 DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); 547 if(!dev_priv->buffers) { 548 DRM_ERROR( "failed to find dma buffer region!\n" ); 549 /* Assign dev_private so we can do cleanup. */ 550 dev->dev_private = (void *)dev_priv; 551 mga_do_cleanup_dma( dev ); 552 return DRM_ERR(EINVAL); 553 } 554 555 dev_priv->sarea_priv = 556 (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + 557 init->sarea_priv_offset); 558 559 DRM_IOREMAP( dev_priv->warp ); 560 DRM_IOREMAP( dev_priv->primary ); 561 DRM_IOREMAP( dev_priv->buffers ); 562 563 if(!dev_priv->warp->handle || 564 !dev_priv->primary->handle || 565 !dev_priv->buffers->handle ) { 566 DRM_ERROR( "failed to ioremap agp regions!\n" ); 567 /* Assign dev_private so we can do cleanup. */ 568 dev->dev_private = (void *)dev_priv; 569 mga_do_cleanup_dma( dev ); 570 return DRM_ERR(ENOMEM); 571 } 572 573 ret = mga_warp_install_microcode( dev_priv ); 574 if ( ret < 0 ) { 575 DRM_ERROR( "failed to install WARP ucode!\n" ); 576 /* Assign dev_private so we can do cleanup. */ 577 dev->dev_private = (void *)dev_priv; 578 mga_do_cleanup_dma( dev ); 579 return ret; 580 } 581 582 ret = mga_warp_init( dev_priv ); 583 if ( ret < 0 ) { 584 DRM_ERROR( "failed to init WARP engine!\n" ); 585 /* Assign dev_private so we can do cleanup. */ 586 dev->dev_private = (void *)dev_priv; 587 mga_do_cleanup_dma( dev ); 588 return ret; 589 } 590 591 dev_priv->prim.status = (u32 *)dev_priv->status->handle; 592 593 mga_do_wait_for_idle( dev_priv ); 594 595 /* Init the primary DMA registers. 596 */ 597 MGA_WRITE( MGA_PRIMADDRESS, 598 dev_priv->primary->offset | MGA_DMA_GENERAL ); 599#if 0 600 MGA_WRITE( MGA_PRIMPTR, 601 virt_to_bus((void *)dev_priv->prim.status) | 602 MGA_PRIMPTREN0 | /* Soft trap, SECEND, SETUPEND */ 603 MGA_PRIMPTREN1 ); /* DWGSYNC */ 604#endif 605 606 dev_priv->prim.start = (u8 *)dev_priv->primary->handle; 607 dev_priv->prim.end = ((u8 *)dev_priv->primary->handle 608 + dev_priv->primary->size); 609 dev_priv->prim.size = dev_priv->primary->size; 610 611 dev_priv->prim.tail = 0; 612 dev_priv->prim.space = dev_priv->prim.size; 613 dev_priv->prim.wrapped = 0; 614 615 dev_priv->prim.last_flush = 0; 616 dev_priv->prim.last_wrap = 0; 617 618 dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE; 619 620 dev_priv->prim.status[0] = dev_priv->primary->offset; 621 dev_priv->prim.status[1] = 0; 622 623 dev_priv->sarea_priv->last_wrap = 0; 624 dev_priv->sarea_priv->last_frame.head = 0; 625 dev_priv->sarea_priv->last_frame.wrap = 0; 626 627 if ( mga_freelist_init( dev, dev_priv ) < 0 ) { 628 DRM_ERROR( "could not initialize freelist\n" ); 629 /* Assign dev_private so we can do cleanup. */ 630 dev->dev_private = (void *)dev_priv; 631 mga_do_cleanup_dma( dev ); 632 return DRM_ERR(ENOMEM); 633 } 634 635 /* Make dev_private visable to others. */ 636 dev->dev_private = (void *)dev_priv; 637 return 0; 638} 639 640int mga_do_cleanup_dma( drm_device_t *dev ) 641{ 642 DRM_DEBUG( "\n" ); 643 644 if ( dev->dev_private ) { 645 drm_mga_private_t *dev_priv = dev->dev_private; 646 647 if ( dev_priv->warp != NULL ) 648 DRM_IOREMAPFREE( dev_priv->warp ); 649 if ( dev_priv->primary != NULL ) 650 DRM_IOREMAPFREE( dev_priv->primary ); 651 if ( dev_priv->buffers != NULL ) 652 DRM_IOREMAPFREE( dev_priv->buffers ); 653 654 if ( dev_priv->head != NULL ) { 655 mga_freelist_cleanup( dev ); 656 } 657 658 DRM(free)( dev->dev_private, sizeof(drm_mga_private_t), 659 DRM_MEM_DRIVER ); 660 dev->dev_private = NULL; 661 } 662 663 return 0; 664} 665 666int mga_dma_init( DRM_IOCTL_ARGS ) 667{ 668 DRM_DEVICE; 669 drm_mga_init_t init; 670 671 DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t *)data, sizeof(init) ); 672 673 switch ( init.func ) { 674 case MGA_INIT_DMA: 675 return mga_do_init_dma( dev, &init ); 676 case MGA_CLEANUP_DMA: 677 return mga_do_cleanup_dma( dev ); 678 } 679 680 return DRM_ERR(EINVAL); 681} 682 683 684/* ================================================================ 685 * Primary DMA stream management 686 */ 687 688int mga_dma_flush( DRM_IOCTL_ARGS ) 689{ 690 DRM_DEVICE; 691 drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; 692 drm_lock_t lock; 693 694 LOCK_TEST_WITH_RETURN( dev, filp ); 695 696 DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t *)data, sizeof(lock) ); 697 698 DRM_DEBUG( "%s%s%s\n", 699 (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "", 700 (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "", 701 (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "" ); 702 703 WRAP_WAIT_WITH_RETURN( dev_priv ); 704 705 if ( lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL) ) { 706 mga_do_dma_flush( dev_priv ); 707 } 708 709 if ( lock.flags & _DRM_LOCK_QUIESCENT ) { 710#if MGA_DMA_DEBUG 711 int ret = mga_do_wait_for_idle( dev_priv ); 712 if ( ret < 0 ) 713 DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ ); 714 return ret; 715#else 716 return mga_do_wait_for_idle( dev_priv ); 717#endif 718 } else { 719 return 0; 720 } 721} 722 723int mga_dma_reset( DRM_IOCTL_ARGS ) 724{ 725 DRM_DEVICE; 726 drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; 727 728 LOCK_TEST_WITH_RETURN( dev, filp ); 729 730 return mga_do_dma_reset( dev_priv ); 731} 732 733 734/* ================================================================ 735 * DMA buffer management 736 */ 737 738static int mga_dma_get_buffers( DRMFILE filp, 739 drm_device_t *dev, drm_dma_t *d ) 740{ 741 drm_buf_t *buf; 742 int i; 743 744 for ( i = d->granted_count ; i < d->request_count ; i++ ) { 745 buf = mga_freelist_get( dev ); 746 if ( !buf ) return DRM_ERR(EAGAIN); 747 748 buf->filp = filp; 749 750 if ( DRM_COPY_TO_USER( &d->request_indices[i], 751 &buf->idx, sizeof(buf->idx) ) ) 752 return DRM_ERR(EFAULT); 753 if ( DRM_COPY_TO_USER( &d->request_sizes[i], 754 &buf->total, sizeof(buf->total) ) ) 755 return DRM_ERR(EFAULT); 756 757 d->granted_count++; 758 } 759 return 0; 760} 761 762int mga_dma_buffers( DRM_IOCTL_ARGS ) 763{ 764 DRM_DEVICE; 765 drm_device_dma_t *dma = dev->dma; 766 drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; 767 drm_dma_t d; 768 int ret = 0; 769 770 LOCK_TEST_WITH_RETURN( dev, filp ); 771 772 DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) ); 773 774 /* Please don't send us buffers. 775 */ 776 if ( d.send_count != 0 ) { 777 DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", 778 DRM_CURRENTPID, d.send_count ); 779 return DRM_ERR(EINVAL); 780 } 781 782 /* We'll send you buffers. 783 */ 784 if ( d.request_count < 0 || d.request_count > dma->buf_count ) { 785 DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", 786 DRM_CURRENTPID, d.request_count, dma->buf_count ); 787 return DRM_ERR(EINVAL); 788 } 789 790 WRAP_TEST_WITH_RETURN( dev_priv ); 791 792 d.granted_count = 0; 793 794 if ( d.request_count ) { 795 ret = mga_dma_get_buffers( filp, dev, &d ); 796 } 797 798 DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) ); 799 800 return ret; 801} 802