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