mga_dma.c revision 95746
1139749Simp/* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*- 223925Sgibbs * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com 323925Sgibbs * 423925Sgibbs * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 5102668Sgibbs * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 623925Sgibbs * All Rights Reserved. 723925Sgibbs * 823925Sgibbs * Permission is hereby granted, free of charge, to any person obtaining a 923925Sgibbs * copy of this software and associated documentation files (the "Software"), 1023925Sgibbs * to deal in the Software without restriction, including without limitation 1123925Sgibbs * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1226997Sgibbs * and/or sell copies of the Software, and to permit persons to whom the 1354211Sgibbs * Software is furnished to do so, subject to the following conditions: 1495376Sgibbs * 1595376Sgibbs * The above copyright notice and this permission notice (including the next 1695376Sgibbs * paragraph) shall be included in all copies or substantial portions of the 1795376Sgibbs * Software. 1895376Sgibbs * 1995376Sgibbs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2095376Sgibbs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2195376Sgibbs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2223925Sgibbs * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2363457Sgibbs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2495376Sgibbs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2595376Sgibbs * DEALINGS IN THE SOFTWARE. 2663457Sgibbs * 2795376Sgibbs * Authors: 2895376Sgibbs * Rickard E. (Rik) Faith <faith@valinux.com> 2995376Sgibbs * Jeff Hartmann <jhartmann@valinux.com> 3095376Sgibbs * Keith Whitwell <keithw@valinux.com> 3195376Sgibbs * 3295376Sgibbs * Rewritten by: 3323925Sgibbs * Gareth Hughes <gareth@valinux.com> 3423925Sgibbs * 3595376Sgibbs * $FreeBSD: head/sys/dev/drm/mga_dma.c 95746 2002-04-29 18:18:42Z anholt $ 3695376Sgibbs */ 3795376Sgibbs 3895376Sgibbs#define __NO_VERSION__ 3923925Sgibbs#include "dev/drm/mga.h" 40102668Sgibbs#include "dev/drm/drmP.h" 4165943Sgibbs#include "dev/drm/mga_drm.h" 4250477Speter#include "dev/drm/mga_drv.h" 4323925Sgibbs 4423925Sgibbs#ifdef __linux__ 4565943Sgibbs#include <linux/interrupt.h> /* For task queue support */ 4665943Sgibbs#include <linux/delay.h> 4765943Sgibbs#endif /* __linux__ */ 4823925Sgibbs 4965943Sgibbs#define MGA_DEFAULT_USEC_TIMEOUT 10000 5023925Sgibbs#define MGA_FREELIST_DEBUG 0 5123925Sgibbs 5223925Sgibbs 5323925Sgibbs/* ================================================================ 5423925Sgibbs * Engine control 5523925Sgibbs */ 5623925Sgibbs 57102668Sgibbsint mga_do_wait_for_idle( drm_mga_private_t *dev_priv ) 58102668Sgibbs{ 5923925Sgibbs u32 status = 0; 60102668Sgibbs int i; 6123925Sgibbs DRM_DEBUG( "%s\n", __FUNCTION__ ); 6229897Sgibbs 6323925Sgibbs for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { 6495376Sgibbs status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; 6595376Sgibbs if ( status == MGA_ENDPRDMASTS ) { 6695376Sgibbs MGA_WRITE8( MGA_CRTC_INDEX, 0 ); 6723925Sgibbs return 0; 6823925Sgibbs } 6923925Sgibbs DRM_OS_DELAY( 1 ); 7023925Sgibbs } 7123925Sgibbs 7223925Sgibbs#if MGA_DMA_DEBUG 7323925Sgibbs DRM_ERROR( "failed!\n" ); 74102668Sgibbs DRM_INFO( " status=0x%08x\n", status ); 75102668Sgibbs#endif 7623925Sgibbs return DRM_OS_ERR(EBUSY); 77102668Sgibbs} 78102668Sgibbs 79102668Sgibbsint mga_do_dma_idle( drm_mga_private_t *dev_priv ) 80102668Sgibbs{ 81102668Sgibbs u32 status = 0; 82102668Sgibbs int i; 83102668Sgibbs DRM_DEBUG( "%s\n", __FUNCTION__ ); 8423925Sgibbs 8523925Sgibbs for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { 86102668Sgibbs status = MGA_READ( MGA_STATUS ) & MGA_DMA_IDLE_MASK; 8723925Sgibbs if ( status == MGA_ENDPRDMASTS ) return 0; 88102668Sgibbs DRM_OS_DELAY( 1 ); 89102668Sgibbs } 9023925Sgibbs 9123925Sgibbs#if MGA_DMA_DEBUG 9223925Sgibbs DRM_ERROR( "failed! status=0x%08x\n", status ); 9395376Sgibbs#endif 9495376Sgibbs return DRM_OS_ERR(EBUSY); 9523925Sgibbs} 9623925Sgibbs 9723925Sgibbsint mga_do_dma_reset( drm_mga_private_t *dev_priv ) 9823925Sgibbs{ 9923925Sgibbs drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 10023925Sgibbs drm_mga_primary_buffer_t *primary = &dev_priv->prim; 10123925Sgibbs 10223925Sgibbs DRM_DEBUG( "%s\n", __FUNCTION__ ); 10395376Sgibbs 10423925Sgibbs /* The primary DMA stream should look like new right about now. 10523925Sgibbs */ 10623925Sgibbs primary->tail = 0; 10739220Sgibbs primary->space = primary->size; 10823925Sgibbs primary->last_flush = 0; 10923925Sgibbs 11095376Sgibbs sarea_priv->last_wrap = 0; 11195376Sgibbs 11295376Sgibbs /* FIXME: Reset counters, buffer ages etc... 11395376Sgibbs */ 11495376Sgibbs 11595376Sgibbs /* FIXME: What else do we need to reinitialize? WARP stuff? 11695376Sgibbs */ 11795376Sgibbs 11895376Sgibbs return 0; 11995376Sgibbs} 12095376Sgibbs 12195376Sgibbsint mga_do_engine_reset( drm_mga_private_t *dev_priv ) 12295376Sgibbs{ 12323925Sgibbs DRM_DEBUG( "%s\n", __FUNCTION__ ); 12423925Sgibbs 12523925Sgibbs /* Okay, so we've completely screwed up and locked the engine. 12623925Sgibbs * How about we clean up after ourselves? 12723925Sgibbs */ 12823925Sgibbs MGA_WRITE( MGA_RST, MGA_SOFTRESET ); 12923925Sgibbs DRM_OS_DELAY( 15 ); /* Wait at least 10 usecs */ 13023925Sgibbs MGA_WRITE( MGA_RST, 0 ); 13123925Sgibbs 13295376Sgibbs /* Initialize the registers that get clobbered by the soft 133102668Sgibbs * reset. Many of the core register values survive a reset, 13423925Sgibbs * but the drawing registers are basically all gone. 13523925Sgibbs * 13623925Sgibbs * 3D clients should probably die after calling this. The X 13795376Sgibbs * server should reset the engine state to known values. 13895376Sgibbs */ 13923925Sgibbs#if 0 14023925Sgibbs MGA_WRITE( MGA_PRIMPTR, 14123925Sgibbs virt_to_bus((void *)dev_priv->prim.status_page) | 14223925Sgibbs MGA_PRIMPTREN0 | 14323925Sgibbs MGA_PRIMPTREN1 ); 14423925Sgibbs#endif 14523925Sgibbs 14623925Sgibbs MGA_WRITE( MGA_ICLEAR, MGA_SOFTRAPICLR ); 14723925Sgibbs MGA_WRITE( MGA_IEN, MGA_SOFTRAPIEN ); 14860938Sjake 14923925Sgibbs /* The primary DMA stream should look like new right about now. 15066270Sgibbs */ 15123925Sgibbs mga_do_dma_reset( dev_priv ); 15266270Sgibbs 15366270Sgibbs /* This bad boy will never fail. 15466270Sgibbs */ 15566270Sgibbs return 0; 15666270Sgibbs} 15766270Sgibbs 15839220Sgibbs 15939220Sgibbs/* ================================================================ 16039220Sgibbs * Primary DMA stream 16139220Sgibbs */ 16239220Sgibbs 16339220Sgibbsvoid mga_do_dma_flush( drm_mga_private_t *dev_priv ) 16423925Sgibbs{ 16539220Sgibbs drm_mga_primary_buffer_t *primary = &dev_priv->prim; 16639220Sgibbs u32 head, tail; 16739220Sgibbs DMA_LOCALS; 16839220Sgibbs DRM_DEBUG( "%s:\n", __FUNCTION__ ); 16939220Sgibbs 17039220Sgibbs if ( primary->tail == primary->last_flush ) { 17160938Sjake DRM_DEBUG( " bailing out...\n" ); 17260938Sjake return; 17360938Sjake } 17439220Sgibbs 17539220Sgibbs tail = primary->tail + dev_priv->primary->offset; 17639220Sgibbs 17739220Sgibbs /* We need to pad the stream between flushes, as the card 17839220Sgibbs * actually (partially?) reads the first of these commands. 17939220Sgibbs * See page 4-16 in the G400 manual, middle of the page or so. 18039220Sgibbs */ 18139220Sgibbs BEGIN_DMA( 1 ); 18266270Sgibbs 18360938Sjake DMA_BLOCK( MGA_DMAPAD, 0x00000000, 18460938Sjake MGA_DMAPAD, 0x00000000, 18539220Sgibbs MGA_DMAPAD, 0x00000000, 186102668Sgibbs MGA_DMAPAD, 0x00000000 ); 18723925Sgibbs 188102668Sgibbs ADVANCE_DMA(); 18923925Sgibbs 190102668Sgibbs primary->last_flush = primary->tail; 19123925Sgibbs 19223925Sgibbs head = MGA_READ( MGA_PRIMADDRESS ); 193193244Sdelphij 19423925Sgibbs if ( head <= tail ) { 19523925Sgibbs primary->space = primary->size - primary->tail; 196102668Sgibbs } else { 19723925Sgibbs primary->space = head - tail; 19823925Sgibbs } 199102668Sgibbs 20023925Sgibbs DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset ); 20123925Sgibbs DRM_DEBUG( " tail = 0x%06lx\n", tail - dev_priv->primary->offset ); 20223925Sgibbs DRM_DEBUG( " space = 0x%06x\n", primary->space ); 203102668Sgibbs 20423925Sgibbs mga_flush_write_combine(); 205102668Sgibbs MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); 206102668Sgibbs 207102668Sgibbs 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