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