diff options
| -rw-r--r-- | drivers/char/drm/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/char/drm/mga_dma.c | 601 | ||||
| -rw-r--r-- | drivers/char/drm/mga_drm.h | 95 | ||||
| -rw-r--r-- | drivers/char/drm/mga_drv.h | 96 | ||||
| -rw-r--r-- | drivers/char/drm/mga_irq.c | 72 | ||||
| -rw-r--r-- | drivers/char/drm/mga_state.c | 158 | ||||
| -rw-r--r-- | drivers/char/drm/mga_warp.c | 141 |
7 files changed, 888 insertions, 277 deletions
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index 123417e43040..d6c50312aec6 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig | |||
| @@ -82,7 +82,7 @@ endchoice | |||
| 82 | 82 | ||
| 83 | config DRM_MGA | 83 | config DRM_MGA |
| 84 | tristate "Matrox g200/g400" | 84 | tristate "Matrox g200/g400" |
| 85 | depends on DRM && AGP | 85 | depends on DRM |
| 86 | help | 86 | help |
| 87 | Choose this option if you have a Matrox G200, G400 or G450 graphics | 87 | Choose this option if you have a Matrox G200, G400 or G450 graphics |
| 88 | card. If M is selected, the module will be called mga. AGP | 88 | card. If M is selected, the module will be called mga. AGP |
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index 832eaf8a5068..7899e281d062 100644 --- a/drivers/char/drm/mga_dma.c +++ b/drivers/char/drm/mga_dma.c | |||
| @@ -23,18 +23,21 @@ | |||
| 23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | 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 | 24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 25 | * DEALINGS IN THE SOFTWARE. | 25 | * DEALINGS IN THE SOFTWARE. |
| 26 | * | 26 | */ |
| 27 | * Authors: | 27 | |
| 28 | * Rickard E. (Rik) Faith <faith@valinux.com> | 28 | /** |
| 29 | * Jeff Hartmann <jhartmann@valinux.com> | 29 | * \file mga_dma.c |
| 30 | * Keith Whitwell <keith@tungstengraphics.com> | 30 | * DMA support for MGA G200 / G400. |
| 31 | * | 31 | * |
| 32 | * Rewritten by: | 32 | * \author Rickard E. (Rik) Faith <faith@valinux.com> |
| 33 | * Gareth Hughes <gareth@valinux.com> | 33 | * \author Jeff Hartmann <jhartmann@valinux.com> |
| 34 | * \author Keith Whitwell <keith@tungstengraphics.com> | ||
| 35 | * \author Gareth Hughes <gareth@valinux.com> | ||
| 34 | */ | 36 | */ |
| 35 | 37 | ||
| 36 | #include "drmP.h" | 38 | #include "drmP.h" |
| 37 | #include "drm.h" | 39 | #include "drm.h" |
| 40 | #include "drm_sarea.h" | ||
| 38 | #include "mga_drm.h" | 41 | #include "mga_drm.h" |
| 39 | #include "mga_drv.h" | 42 | #include "mga_drv.h" |
| 40 | 43 | ||
| @@ -148,7 +151,7 @@ void mga_do_dma_flush( drm_mga_private_t *dev_priv ) | |||
| 148 | DRM_DEBUG( " space = 0x%06x\n", primary->space ); | 151 | DRM_DEBUG( " space = 0x%06x\n", primary->space ); |
| 149 | 152 | ||
| 150 | mga_flush_write_combine(); | 153 | mga_flush_write_combine(); |
| 151 | MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); | 154 | MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access); |
| 152 | 155 | ||
| 153 | DRM_DEBUG( "done.\n" ); | 156 | DRM_DEBUG( "done.\n" ); |
| 154 | } | 157 | } |
| @@ -190,7 +193,7 @@ void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv ) | |||
| 190 | DRM_DEBUG( " space = 0x%06x\n", primary->space ); | 193 | DRM_DEBUG( " space = 0x%06x\n", primary->space ); |
| 191 | 194 | ||
| 192 | mga_flush_write_combine(); | 195 | mga_flush_write_combine(); |
| 193 | MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); | 196 | MGA_WRITE(MGA_PRIMEND, tail | dev_priv->dma_access); |
| 194 | 197 | ||
| 195 | set_bit( 0, &primary->wrapped ); | 198 | set_bit( 0, &primary->wrapped ); |
| 196 | DRM_DEBUG( "done.\n" ); | 199 | DRM_DEBUG( "done.\n" ); |
| @@ -396,23 +399,383 @@ int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf ) | |||
| 396 | * DMA initialization, cleanup | 399 | * DMA initialization, cleanup |
| 397 | */ | 400 | */ |
| 398 | 401 | ||
| 402 | |||
| 403 | int mga_driver_preinit(drm_device_t *dev, unsigned long flags) | ||
| 404 | { | ||
| 405 | drm_mga_private_t * dev_priv; | ||
| 406 | |||
| 407 | dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); | ||
| 408 | if (!dev_priv) | ||
| 409 | return DRM_ERR(ENOMEM); | ||
| 410 | |||
| 411 | dev->dev_private = (void *)dev_priv; | ||
| 412 | memset(dev_priv, 0, sizeof(drm_mga_private_t)); | ||
| 413 | |||
| 414 | dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; | ||
| 415 | dev_priv->chipset = flags; | ||
| 416 | |||
| 417 | return 0; | ||
| 418 | } | ||
| 419 | |||
| 420 | /** | ||
| 421 | * Bootstrap the driver for AGP DMA. | ||
| 422 | * | ||
| 423 | * \todo | ||
| 424 | * Investigate whether there is any benifit to storing the WARP microcode in | ||
| 425 | * AGP memory. If not, the microcode may as well always be put in PCI | ||
| 426 | * memory. | ||
| 427 | * | ||
| 428 | * \todo | ||
| 429 | * This routine needs to set dma_bs->agp_mode to the mode actually configured | ||
| 430 | * in the hardware. Looking just at the Linux AGP driver code, I don't see | ||
| 431 | * an easy way to determine this. | ||
| 432 | * | ||
| 433 | * \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap | ||
| 434 | */ | ||
| 435 | static int mga_do_agp_dma_bootstrap(drm_device_t * dev, | ||
| 436 | drm_mga_dma_bootstrap_t * dma_bs) | ||
| 437 | { | ||
| 438 | drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private; | ||
| 439 | const unsigned int warp_size = mga_warp_microcode_size(dev_priv); | ||
| 440 | int err; | ||
| 441 | unsigned offset; | ||
| 442 | const unsigned secondary_size = dma_bs->secondary_bin_count | ||
| 443 | * dma_bs->secondary_bin_size; | ||
| 444 | const unsigned agp_size = (dma_bs->agp_size << 20); | ||
| 445 | drm_buf_desc_t req; | ||
| 446 | drm_agp_mode_t mode; | ||
| 447 | drm_agp_info_t info; | ||
| 448 | |||
| 449 | |||
| 450 | /* Acquire AGP. */ | ||
| 451 | err = drm_agp_acquire(dev); | ||
| 452 | if (err) { | ||
| 453 | DRM_ERROR("Unable to acquire AGP\n"); | ||
| 454 | return err; | ||
| 455 | } | ||
| 456 | |||
| 457 | err = drm_agp_info(dev, &info); | ||
| 458 | if (err) { | ||
| 459 | DRM_ERROR("Unable to get AGP info\n"); | ||
| 460 | return err; | ||
| 461 | } | ||
| 462 | |||
| 463 | mode.mode = (info.mode & ~0x07) | dma_bs->agp_mode; | ||
| 464 | err = drm_agp_enable(dev, mode); | ||
| 465 | if (err) { | ||
| 466 | DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); | ||
| 467 | return err; | ||
| 468 | } | ||
| 469 | |||
| 470 | |||
| 471 | /* In addition to the usual AGP mode configuration, the G200 AGP cards | ||
| 472 | * need to have the AGP mode "manually" set. | ||
| 473 | */ | ||
| 474 | |||
| 475 | if (dev_priv->chipset == MGA_CARD_TYPE_G200) { | ||
| 476 | if (mode.mode & 0x02) { | ||
| 477 | MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_ENABLE); | ||
| 478 | } | ||
| 479 | else { | ||
| 480 | MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_DISABLE); | ||
| 481 | } | ||
| 482 | } | ||
| 483 | |||
| 484 | |||
| 485 | /* Allocate and bind AGP memory. */ | ||
| 486 | dev_priv->agp_pages = agp_size / PAGE_SIZE; | ||
| 487 | dev_priv->agp_mem = drm_alloc_agp( dev, dev_priv->agp_pages, 0 ); | ||
| 488 | if (dev_priv->agp_mem == NULL) { | ||
| 489 | dev_priv->agp_pages = 0; | ||
| 490 | DRM_ERROR("Unable to allocate %uMB AGP memory\n", | ||
| 491 | dma_bs->agp_size); | ||
| 492 | return DRM_ERR(ENOMEM); | ||
| 493 | } | ||
| 494 | |||
| 495 | err = drm_bind_agp( dev_priv->agp_mem, 0 ); | ||
| 496 | if (err) { | ||
| 497 | DRM_ERROR("Unable to bind AGP memory\n"); | ||
| 498 | return err; | ||
| 499 | } | ||
| 500 | |||
| 501 | offset = 0; | ||
| 502 | err = drm_addmap( dev, offset, warp_size, | ||
| 503 | _DRM_AGP, _DRM_READ_ONLY, & dev_priv->warp ); | ||
| 504 | if (err) { | ||
| 505 | DRM_ERROR("Unable to map WARP microcode\n"); | ||
| 506 | return err; | ||
| 507 | } | ||
| 508 | |||
| 509 | offset += warp_size; | ||
| 510 | err = drm_addmap( dev, offset, dma_bs->primary_size, | ||
| 511 | _DRM_AGP, _DRM_READ_ONLY, & dev_priv->primary ); | ||
| 512 | if (err) { | ||
| 513 | DRM_ERROR("Unable to map primary DMA region\n"); | ||
| 514 | return err; | ||
| 515 | } | ||
| 516 | |||
| 517 | offset += dma_bs->primary_size; | ||
| 518 | err = drm_addmap( dev, offset, secondary_size, | ||
| 519 | _DRM_AGP, 0, & dev->agp_buffer_map ); | ||
| 520 | if (err) { | ||
| 521 | DRM_ERROR("Unable to map secondary DMA region\n"); | ||
| 522 | return err; | ||
| 523 | } | ||
| 524 | |||
| 525 | (void) memset( &req, 0, sizeof(req) ); | ||
| 526 | req.count = dma_bs->secondary_bin_count; | ||
| 527 | req.size = dma_bs->secondary_bin_size; | ||
| 528 | req.flags = _DRM_AGP_BUFFER; | ||
| 529 | req.agp_start = offset; | ||
| 530 | |||
| 531 | err = drm_addbufs_agp( dev, & req ); | ||
| 532 | if (err) { | ||
| 533 | DRM_ERROR("Unable to add secondary DMA buffers\n"); | ||
| 534 | return err; | ||
| 535 | } | ||
| 536 | |||
| 537 | offset += secondary_size; | ||
| 538 | err = drm_addmap( dev, offset, agp_size - offset, | ||
| 539 | _DRM_AGP, 0, & dev_priv->agp_textures ); | ||
| 540 | if (err) { | ||
| 541 | DRM_ERROR("Unable to map AGP texture region\n"); | ||
| 542 | return err; | ||
| 543 | } | ||
| 544 | |||
| 545 | drm_core_ioremap(dev_priv->warp, dev); | ||
| 546 | drm_core_ioremap(dev_priv->primary, dev); | ||
| 547 | drm_core_ioremap(dev->agp_buffer_map, dev); | ||
| 548 | |||
| 549 | if (!dev_priv->warp->handle || | ||
| 550 | !dev_priv->primary->handle || !dev->agp_buffer_map->handle) { | ||
| 551 | DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n", | ||
| 552 | dev_priv->warp->handle, dev_priv->primary->handle, | ||
| 553 | dev->agp_buffer_map->handle); | ||
| 554 | return DRM_ERR(ENOMEM); | ||
| 555 | } | ||
| 556 | |||
| 557 | dev_priv->dma_access = MGA_PAGPXFER; | ||
| 558 | dev_priv->wagp_enable = MGA_WAGP_ENABLE; | ||
| 559 | |||
| 560 | DRM_INFO("Initialized card for AGP DMA.\n"); | ||
| 561 | return 0; | ||
| 562 | } | ||
| 563 | |||
| 564 | /** | ||
| 565 | * Bootstrap the driver for PCI DMA. | ||
| 566 | * | ||
| 567 | * \todo | ||
| 568 | * The algorithm for decreasing the size of the primary DMA buffer could be | ||
| 569 | * better. The size should be rounded up to the nearest page size, then | ||
| 570 | * decrease the request size by a single page each pass through the loop. | ||
| 571 | * | ||
| 572 | * \todo | ||
| 573 | * Determine whether the maximum address passed to drm_pci_alloc is correct. | ||
| 574 | * The same goes for drm_addbufs_pci. | ||
| 575 | * | ||
| 576 | * \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap | ||
| 577 | */ | ||
| 578 | static int mga_do_pci_dma_bootstrap(drm_device_t * dev, | ||
| 579 | drm_mga_dma_bootstrap_t * dma_bs) | ||
| 580 | { | ||
| 581 | drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private; | ||
| 582 | const unsigned int warp_size = mga_warp_microcode_size(dev_priv); | ||
| 583 | unsigned int primary_size; | ||
| 584 | unsigned int bin_count; | ||
| 585 | int err; | ||
| 586 | drm_buf_desc_t req; | ||
| 587 | |||
| 588 | |||
| 589 | if (dev->dma == NULL) { | ||
| 590 | DRM_ERROR("dev->dma is NULL\n"); | ||
| 591 | return DRM_ERR(EFAULT); | ||
| 592 | } | ||
| 593 | |||
| 594 | /* The proper alignment is 0x100 for this mapping */ | ||
| 595 | err = drm_addmap(dev, 0, warp_size, _DRM_CONSISTENT, | ||
| 596 | _DRM_READ_ONLY, &dev_priv->warp); | ||
| 597 | if (err != 0) { | ||
| 598 | DRM_ERROR("Unable to create mapping for WARP microcode\n"); | ||
| 599 | return err; | ||
| 600 | } | ||
| 601 | |||
| 602 | /* Other than the bottom two bits being used to encode other | ||
| 603 | * information, there don't appear to be any restrictions on the | ||
| 604 | * alignment of the primary or secondary DMA buffers. | ||
| 605 | */ | ||
| 606 | |||
| 607 | for ( primary_size = dma_bs->primary_size | ||
| 608 | ; primary_size != 0 | ||
| 609 | ; primary_size >>= 1 ) { | ||
| 610 | /* The proper alignment for this mapping is 0x04 */ | ||
| 611 | err = drm_addmap(dev, 0, primary_size, _DRM_CONSISTENT, | ||
| 612 | _DRM_READ_ONLY, &dev_priv->primary); | ||
| 613 | if (!err) | ||
| 614 | break; | ||
| 615 | } | ||
| 616 | |||
| 617 | if (err != 0) { | ||
| 618 | DRM_ERROR("Unable to allocate primary DMA region\n"); | ||
| 619 | return DRM_ERR(ENOMEM); | ||
| 620 | } | ||
| 621 | |||
| 622 | if (dev_priv->primary->size != dma_bs->primary_size) { | ||
| 623 | DRM_INFO("Primary DMA buffer size reduced from %u to %u.\n", | ||
| 624 | dma_bs->primary_size, | ||
| 625 | (unsigned) dev_priv->primary->size); | ||
| 626 | dma_bs->primary_size = dev_priv->primary->size; | ||
| 627 | } | ||
| 628 | |||
| 629 | for ( bin_count = dma_bs->secondary_bin_count | ||
| 630 | ; bin_count > 0 | ||
| 631 | ; bin_count-- ) { | ||
| 632 | (void) memset( &req, 0, sizeof(req) ); | ||
| 633 | req.count = bin_count; | ||
| 634 | req.size = dma_bs->secondary_bin_size; | ||
| 635 | |||
| 636 | err = drm_addbufs_pci( dev, & req ); | ||
| 637 | if (!err) { | ||
| 638 | break; | ||
| 639 | } | ||
| 640 | } | ||
| 641 | |||
| 642 | if (bin_count == 0) { | ||
| 643 | DRM_ERROR("Unable to add secondary DMA buffers\n"); | ||
| 644 | return err; | ||
| 645 | } | ||
| 646 | |||
| 647 | if (bin_count != dma_bs->secondary_bin_count) { | ||
| 648 | DRM_INFO("Secondary PCI DMA buffer bin count reduced from %u " | ||
| 649 | "to %u.\n", dma_bs->secondary_bin_count, bin_count); | ||
| 650 | |||
| 651 | dma_bs->secondary_bin_count = bin_count; | ||
| 652 | } | ||
| 653 | |||
| 654 | dev_priv->dma_access = 0; | ||
| 655 | dev_priv->wagp_enable = 0; | ||
| 656 | |||
| 657 | dma_bs->agp_mode = 0; | ||
| 658 | |||
| 659 | DRM_INFO("Initialized card for PCI DMA.\n"); | ||
| 660 | return 0; | ||
| 661 | } | ||
| 662 | |||
| 663 | |||
| 664 | static int mga_do_dma_bootstrap(drm_device_t * dev, | ||
| 665 | drm_mga_dma_bootstrap_t * dma_bs) | ||
| 666 | { | ||
| 667 | const int is_agp = (dma_bs->agp_mode != 0) && drm_device_is_agp(dev); | ||
| 668 | int err; | ||
| 669 | drm_mga_private_t * const dev_priv = | ||
| 670 | (drm_mga_private_t *) dev->dev_private; | ||
| 671 | |||
| 672 | |||
| 673 | dev_priv->used_new_dma_init = 1; | ||
| 674 | |||
| 675 | /* The first steps are the same for both PCI and AGP based DMA. Map | ||
| 676 | * the cards MMIO registers and map a status page. | ||
| 677 | */ | ||
| 678 | err = drm_addmap( dev, dev_priv->mmio_base, dev_priv->mmio_size, | ||
| 679 | _DRM_REGISTERS, _DRM_READ_ONLY, & dev_priv->mmio ); | ||
| 680 | if (err) { | ||
| 681 | DRM_ERROR("Unable to map MMIO region\n"); | ||
| 682 | return err; | ||
| 683 | } | ||
| 684 | |||
| 685 | |||
| 686 | err = drm_addmap( dev, 0, SAREA_MAX, _DRM_SHM, | ||
| 687 | _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL, | ||
| 688 | & dev_priv->status ); | ||
| 689 | if (err) { | ||
| 690 | DRM_ERROR("Unable to map status region\n"); | ||
| 691 | return err; | ||
| 692 | } | ||
| 693 | |||
| 694 | |||
| 695 | /* The DMA initialization procedure is slightly different for PCI and | ||
| 696 | * AGP cards. AGP cards just allocate a large block of AGP memory and | ||
| 697 | * carve off portions of it for internal uses. The remaining memory | ||
| 698 | * is returned to user-mode to be used for AGP textures. | ||
| 699 | */ | ||
| 700 | |||
| 701 | if (is_agp) { | ||
| 702 | err = mga_do_agp_dma_bootstrap(dev, dma_bs); | ||
| 703 | } | ||
| 704 | |||
| 705 | /* If we attempted to initialize the card for AGP DMA but failed, | ||
| 706 | * clean-up any mess that may have been created. | ||
| 707 | */ | ||
| 708 | |||
| 709 | if (err) { | ||
| 710 | mga_do_cleanup_dma(dev); | ||
| 711 | } | ||
| 712 | |||
| 713 | |||
| 714 | /* Not only do we want to try and initialized PCI cards for PCI DMA, | ||
| 715 | * but we also try to initialized AGP cards that could not be | ||
| 716 | * initialized for AGP DMA. This covers the case where we have an AGP | ||
| 717 | * card in a system with an unsupported AGP chipset. In that case the | ||
| 718 | * card will be detected as AGP, but we won't be able to allocate any | ||
| 719 | * AGP memory, etc. | ||
| 720 | */ | ||
| 721 | |||
| 722 | if (!is_agp || err) { | ||
| 723 | err = mga_do_pci_dma_bootstrap(dev, dma_bs); | ||
| 724 | } | ||
| 725 | |||
| 726 | |||
| 727 | return err; | ||
| 728 | } | ||
| 729 | |||
| 730 | int mga_dma_bootstrap(DRM_IOCTL_ARGS) | ||
| 731 | { | ||
| 732 | DRM_DEVICE; | ||
| 733 | drm_mga_dma_bootstrap_t bootstrap; | ||
| 734 | int err; | ||
| 735 | |||
| 736 | |||
| 737 | DRM_COPY_FROM_USER_IOCTL(bootstrap, | ||
| 738 | (drm_mga_dma_bootstrap_t __user *) data, | ||
| 739 | sizeof(bootstrap)); | ||
| 740 | |||
| 741 | err = mga_do_dma_bootstrap(dev, & bootstrap); | ||
| 742 | if (! err) { | ||
| 743 | static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 }; | ||
| 744 | const drm_mga_private_t * const dev_priv = | ||
| 745 | (drm_mga_private_t *) dev->dev_private; | ||
| 746 | |||
| 747 | if (dev_priv->agp_textures != NULL) { | ||
| 748 | bootstrap.texture_handle = dev_priv->agp_textures->offset; | ||
| 749 | bootstrap.texture_size = dev_priv->agp_textures->size; | ||
| 750 | } | ||
| 751 | else { | ||
| 752 | bootstrap.texture_handle = 0; | ||
| 753 | bootstrap.texture_size = 0; | ||
| 754 | } | ||
| 755 | |||
| 756 | bootstrap.agp_mode = modes[ bootstrap.agp_mode & 0x07 ]; | ||
| 757 | if (DRM_COPY_TO_USER( (void __user *) data, & bootstrap, | ||
| 758 | sizeof(bootstrap))) { | ||
| 759 | err = DRM_ERR(EFAULT); | ||
| 760 | } | ||
| 761 | } | ||
| 762 | else { | ||
| 763 | mga_do_cleanup_dma(dev); | ||
| 764 | } | ||
| 765 | |||
| 766 | return err; | ||
| 767 | } | ||
| 768 | |||
| 399 | static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) | 769 | static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) |
| 400 | { | 770 | { |
| 401 | drm_mga_private_t *dev_priv; | 771 | drm_mga_private_t *dev_priv; |
| 402 | int ret; | 772 | int ret; |
| 403 | DRM_DEBUG( "\n" ); | 773 | DRM_DEBUG( "\n" ); |
| 404 | 774 | ||
| 405 | dev_priv = drm_alloc( sizeof(drm_mga_private_t), DRM_MEM_DRIVER ); | ||
| 406 | if ( !dev_priv ) | ||
| 407 | return DRM_ERR(ENOMEM); | ||
| 408 | |||
| 409 | memset( dev_priv, 0, sizeof(drm_mga_private_t) ); | ||
| 410 | 775 | ||
| 411 | dev_priv->chipset = init->chipset; | 776 | dev_priv = dev->dev_private; |
| 412 | 777 | ||
| 413 | dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; | 778 | if (init->sgram) { |
| 414 | |||
| 415 | if ( init->sgram ) { | ||
| 416 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; | 779 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; |
| 417 | } else { | 780 | } else { |
| 418 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; | 781 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; |
| @@ -436,88 +799,65 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) | |||
| 436 | 799 | ||
| 437 | DRM_GETSAREA(); | 800 | DRM_GETSAREA(); |
| 438 | 801 | ||
| 439 | if(!dev_priv->sarea) { | 802 | if (!dev_priv->sarea) { |
| 440 | DRM_ERROR( "failed to find sarea!\n" ); | 803 | DRM_ERROR("failed to find sarea!\n"); |
| 441 | /* Assign dev_private so we can do cleanup. */ | ||
| 442 | dev->dev_private = (void *)dev_priv; | ||
| 443 | mga_do_cleanup_dma( dev ); | ||
| 444 | return DRM_ERR(EINVAL); | 804 | return DRM_ERR(EINVAL); |
| 445 | } | 805 | } |
| 446 | 806 | ||
| 447 | dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); | 807 | if (! dev_priv->used_new_dma_init) { |
| 448 | if(!dev_priv->mmio) { | 808 | dev_priv->status = drm_core_findmap(dev, init->status_offset); |
| 449 | DRM_ERROR( "failed to find mmio region!\n" ); | 809 | if (!dev_priv->status) { |
| 450 | /* Assign dev_private so we can do cleanup. */ | 810 | DRM_ERROR("failed to find status page!\n"); |
| 451 | dev->dev_private = (void *)dev_priv; | 811 | return DRM_ERR(EINVAL); |
| 452 | mga_do_cleanup_dma( dev ); | 812 | } |
| 453 | return DRM_ERR(EINVAL); | 813 | dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); |
| 454 | } | 814 | if (!dev_priv->mmio) { |
| 455 | dev_priv->status = drm_core_findmap(dev, init->status_offset); | 815 | DRM_ERROR("failed to find mmio region!\n"); |
| 456 | if(!dev_priv->status) { | 816 | return DRM_ERR(EINVAL); |
| 457 | DRM_ERROR( "failed to find status page!\n" ); | 817 | } |
| 458 | /* Assign dev_private so we can do cleanup. */ | 818 | dev_priv->warp = drm_core_findmap(dev, init->warp_offset); |
| 459 | dev->dev_private = (void *)dev_priv; | 819 | if (!dev_priv->warp) { |
| 460 | mga_do_cleanup_dma( dev ); | 820 | DRM_ERROR("failed to find warp microcode region!\n"); |
| 461 | return DRM_ERR(EINVAL); | 821 | return DRM_ERR(EINVAL); |
| 462 | } | 822 | } |
| 463 | dev_priv->warp = drm_core_findmap(dev, init->warp_offset); | 823 | dev_priv->primary = drm_core_findmap(dev, init->primary_offset); |
| 464 | if(!dev_priv->warp) { | 824 | if (!dev_priv->primary) { |
| 465 | DRM_ERROR( "failed to find warp microcode region!\n" ); | 825 | DRM_ERROR("failed to find primary dma region!\n"); |
| 466 | /* Assign dev_private so we can do cleanup. */ | 826 | return DRM_ERR(EINVAL); |
| 467 | dev->dev_private = (void *)dev_priv; | 827 | } |
| 468 | mga_do_cleanup_dma( dev ); | 828 | dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); |
| 469 | return DRM_ERR(EINVAL); | 829 | if (!dev->agp_buffer_map) { |
| 470 | } | 830 | DRM_ERROR("failed to find dma buffer region!\n"); |
| 471 | dev_priv->primary = drm_core_findmap(dev, init->primary_offset); | 831 | return DRM_ERR(EINVAL); |
| 472 | if(!dev_priv->primary) { | 832 | } |
| 473 | DRM_ERROR( "failed to find primary dma region!\n" ); | 833 | |
| 474 | /* Assign dev_private so we can do cleanup. */ | 834 | drm_core_ioremap(dev_priv->warp, dev); |
| 475 | dev->dev_private = (void *)dev_priv; | 835 | drm_core_ioremap(dev_priv->primary, dev); |
| 476 | mga_do_cleanup_dma( dev ); | 836 | drm_core_ioremap(dev->agp_buffer_map, dev); |
| 477 | return DRM_ERR(EINVAL); | ||
| 478 | } | ||
| 479 | dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); | ||
| 480 | if(!dev->agp_buffer_map) { | ||
| 481 | DRM_ERROR( "failed to find dma buffer region!\n" ); | ||
| 482 | /* Assign dev_private so we can do cleanup. */ | ||
| 483 | dev->dev_private = (void *)dev_priv; | ||
| 484 | mga_do_cleanup_dma( dev ); | ||
| 485 | return DRM_ERR(EINVAL); | ||
| 486 | } | 837 | } |
| 487 | 838 | ||
| 488 | dev_priv->sarea_priv = | 839 | dev_priv->sarea_priv = |
| 489 | (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + | 840 | (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + |
| 490 | init->sarea_priv_offset); | 841 | init->sarea_priv_offset); |
| 491 | 842 | ||
| 492 | drm_core_ioremap( dev_priv->warp, dev ); | 843 | if (!dev_priv->warp->handle || |
| 493 | drm_core_ioremap( dev_priv->primary, dev ); | 844 | !dev_priv->primary->handle || |
| 494 | drm_core_ioremap( dev->agp_buffer_map, dev ); | 845 | ((dev_priv->dma_access != 0) && |
| 495 | 846 | ((dev->agp_buffer_map == NULL) || | |
| 496 | if(!dev_priv->warp->handle || | 847 | (dev->agp_buffer_map->handle == NULL)))) { |
| 497 | !dev_priv->primary->handle || | 848 | DRM_ERROR("failed to ioremap agp regions!\n"); |
| 498 | !dev->agp_buffer_map->handle ) { | ||
| 499 | DRM_ERROR( "failed to ioremap agp regions!\n" ); | ||
| 500 | /* Assign dev_private so we can do cleanup. */ | ||
| 501 | dev->dev_private = (void *)dev_priv; | ||
| 502 | mga_do_cleanup_dma( dev ); | ||
| 503 | return DRM_ERR(ENOMEM); | 849 | return DRM_ERR(ENOMEM); |
| 504 | } | 850 | } |
| 505 | 851 | ||
| 506 | ret = mga_warp_install_microcode( dev_priv ); | 852 | ret = mga_warp_install_microcode(dev_priv); |
| 507 | if ( ret < 0 ) { | 853 | if (ret < 0) { |
| 508 | DRM_ERROR( "failed to install WARP ucode!\n" ); | 854 | DRM_ERROR("failed to install WARP ucode!\n"); |
| 509 | /* Assign dev_private so we can do cleanup. */ | ||
| 510 | dev->dev_private = (void *)dev_priv; | ||
| 511 | mga_do_cleanup_dma( dev ); | ||
| 512 | return ret; | 855 | return ret; |
| 513 | } | 856 | } |
| 514 | 857 | ||
| 515 | ret = mga_warp_init( dev_priv ); | 858 | ret = mga_warp_init(dev_priv); |
| 516 | if ( ret < 0 ) { | 859 | if (ret < 0) { |
| 517 | DRM_ERROR( "failed to init WARP engine!\n" ); | 860 | DRM_ERROR("failed to init WARP engine!\n"); |
| 518 | /* Assign dev_private so we can do cleanup. */ | ||
| 519 | dev->dev_private = (void *)dev_priv; | ||
| 520 | mga_do_cleanup_dma( dev ); | ||
| 521 | return ret; | 861 | return ret; |
| 522 | } | 862 | } |
| 523 | 863 | ||
| @@ -557,22 +897,18 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) | |||
| 557 | dev_priv->sarea_priv->last_frame.head = 0; | 897 | dev_priv->sarea_priv->last_frame.head = 0; |
| 558 | dev_priv->sarea_priv->last_frame.wrap = 0; | 898 | dev_priv->sarea_priv->last_frame.wrap = 0; |
| 559 | 899 | ||
| 560 | if ( mga_freelist_init( dev, dev_priv ) < 0 ) { | 900 | if (mga_freelist_init(dev, dev_priv) < 0) { |
| 561 | DRM_ERROR( "could not initialize freelist\n" ); | 901 | DRM_ERROR("could not initialize freelist\n"); |
| 562 | /* Assign dev_private so we can do cleanup. */ | ||
| 563 | dev->dev_private = (void *)dev_priv; | ||
| 564 | mga_do_cleanup_dma( dev ); | ||
| 565 | return DRM_ERR(ENOMEM); | 902 | return DRM_ERR(ENOMEM); |
| 566 | } | 903 | } |
| 567 | 904 | ||
| 568 | /* Make dev_private visable to others. */ | ||
| 569 | dev->dev_private = (void *)dev_priv; | ||
| 570 | return 0; | 905 | return 0; |
| 571 | } | 906 | } |
| 572 | 907 | ||
| 573 | static int mga_do_cleanup_dma( drm_device_t *dev ) | 908 | static int mga_do_cleanup_dma( drm_device_t *dev ) |
| 574 | { | 909 | { |
| 575 | DRM_DEBUG( "\n" ); | 910 | int err = 0; |
| 911 | DRM_DEBUG("\n"); | ||
| 576 | 912 | ||
| 577 | /* Make sure interrupts are disabled here because the uninstall ioctl | 913 | /* Make sure interrupts are disabled here because the uninstall ioctl |
| 578 | * may not have been called from userspace and after dev_private | 914 | * may not have been called from userspace and after dev_private |
| @@ -583,20 +919,49 @@ static int mga_do_cleanup_dma( drm_device_t *dev ) | |||
| 583 | if ( dev->dev_private ) { | 919 | if ( dev->dev_private ) { |
| 584 | drm_mga_private_t *dev_priv = dev->dev_private; | 920 | drm_mga_private_t *dev_priv = dev->dev_private; |
| 585 | 921 | ||
| 586 | if ( dev_priv->warp != NULL ) | 922 | if ((dev_priv->warp != NULL) |
| 587 | drm_core_ioremapfree( dev_priv->warp, dev ); | 923 | && (dev_priv->mmio->type != _DRM_CONSISTENT)) |
| 588 | if ( dev_priv->primary != NULL ) | 924 | drm_core_ioremapfree(dev_priv->warp, dev); |
| 589 | drm_core_ioremapfree( dev_priv->primary, dev ); | 925 | |
| 590 | if ( dev->agp_buffer_map != NULL ) | 926 | if ((dev_priv->primary != NULL) |
| 591 | drm_core_ioremapfree( dev->agp_buffer_map, dev ); | 927 | && (dev_priv->primary->type != _DRM_CONSISTENT)) |
| 928 | drm_core_ioremapfree(dev_priv->primary, dev); | ||
| 592 | 929 | ||
| 593 | if ( dev_priv->head != NULL ) { | 930 | if (dev->agp_buffer_map != NULL) |
| 594 | mga_freelist_cleanup( dev ); | 931 | drm_core_ioremapfree(dev->agp_buffer_map, dev); |
| 932 | |||
| 933 | if (dev_priv->used_new_dma_init) { | ||
| 934 | if (dev_priv->agp_mem != NULL) { | ||
| 935 | dev_priv->agp_textures = NULL; | ||
| 936 | drm_unbind_agp(dev_priv->agp_mem); | ||
| 937 | |||
| 938 | drm_free_agp(dev_priv->agp_mem, dev_priv->agp_pages); | ||
| 939 | dev_priv->agp_pages = 0; | ||
| 940 | dev_priv->agp_mem = NULL; | ||
| 941 | } | ||
| 942 | |||
| 943 | if ((dev->agp != NULL) && dev->agp->acquired) { | ||
| 944 | err = drm_agp_release(dev); | ||
| 945 | } | ||
| 946 | |||
| 947 | dev_priv->used_new_dma_init = 0; | ||
| 595 | } | 948 | } |
| 596 | 949 | ||
| 597 | drm_free( dev->dev_private, sizeof(drm_mga_private_t), | 950 | dev_priv->warp = NULL; |
| 598 | DRM_MEM_DRIVER ); | 951 | dev_priv->primary = NULL; |
| 599 | dev->dev_private = NULL; | 952 | dev_priv->mmio = NULL; |
| 953 | dev_priv->status = NULL; | ||
| 954 | dev_priv->sarea = NULL; | ||
| 955 | dev_priv->sarea_priv = NULL; | ||
| 956 | dev->agp_buffer_map = NULL; | ||
| 957 | |||
| 958 | memset(&dev_priv->prim, 0, sizeof(dev_priv->prim)); | ||
| 959 | dev_priv->warp_pipe = 0; | ||
| 960 | memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys)); | ||
| 961 | |||
| 962 | if (dev_priv->head != NULL) { | ||
| 963 | mga_freelist_cleanup(dev); | ||
| 964 | } | ||
| 600 | } | 965 | } |
| 601 | 966 | ||
| 602 | return 0; | 967 | return 0; |
| @@ -606,14 +971,20 @@ int mga_dma_init( DRM_IOCTL_ARGS ) | |||
| 606 | { | 971 | { |
| 607 | DRM_DEVICE; | 972 | DRM_DEVICE; |
| 608 | drm_mga_init_t init; | 973 | drm_mga_init_t init; |
| 974 | int err; | ||
| 609 | 975 | ||
| 610 | LOCK_TEST_WITH_RETURN( dev, filp ); | 976 | LOCK_TEST_WITH_RETURN( dev, filp ); |
| 611 | 977 | ||
| 612 | DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t __user *)data, sizeof(init) ); | 978 | DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data, |
| 979 | sizeof(init)); | ||
| 613 | 980 | ||
| 614 | switch ( init.func ) { | 981 | switch ( init.func ) { |
| 615 | case MGA_INIT_DMA: | 982 | case MGA_INIT_DMA: |
| 616 | return mga_do_init_dma( dev, &init ); | 983 | err = mga_do_init_dma(dev, &init); |
| 984 | if (err) { | ||
| 985 | (void) mga_do_cleanup_dma(dev); | ||
| 986 | } | ||
| 987 | return err; | ||
| 617 | case MGA_CLEANUP_DMA: | 988 | case MGA_CLEANUP_DMA: |
| 618 | return mga_do_cleanup_dma( dev ); | 989 | return mga_do_cleanup_dma( dev ); |
| 619 | } | 990 | } |
| @@ -742,7 +1113,21 @@ int mga_dma_buffers( DRM_IOCTL_ARGS ) | |||
| 742 | return ret; | 1113 | return ret; |
| 743 | } | 1114 | } |
| 744 | 1115 | ||
| 745 | void mga_driver_pretakedown(drm_device_t *dev) | 1116 | /** |
| 1117 | * Called just before the module is unloaded. | ||
| 1118 | */ | ||
| 1119 | int mga_driver_postcleanup(drm_device_t * dev) | ||
| 1120 | { | ||
| 1121 | drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER); | ||
| 1122 | dev->dev_private = NULL; | ||
| 1123 | |||
| 1124 | return 0; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | /** | ||
| 1128 | * Called when the last opener of the device is closed. | ||
| 1129 | */ | ||
| 1130 | void mga_driver_pretakedown(drm_device_t * dev) | ||
| 746 | { | 1131 | { |
| 747 | mga_do_cleanup_dma( dev ); | 1132 | mga_do_cleanup_dma( dev ); |
| 748 | } | 1133 | } |
diff --git a/drivers/char/drm/mga_drm.h b/drivers/char/drm/mga_drm.h index 4500e6e4920a..2d8aa790379e 100644 --- a/drivers/char/drm/mga_drm.h +++ b/drivers/char/drm/mga_drm.h | |||
| @@ -226,10 +226,6 @@ typedef struct _drm_mga_sarea { | |||
| 226 | } drm_mga_sarea_t; | 226 | } drm_mga_sarea_t; |
| 227 | 227 | ||
| 228 | 228 | ||
| 229 | /* WARNING: If you change any of these defines, make sure to change the | ||
| 230 | * defines in the Xserver file (xf86drmMga.h) | ||
| 231 | */ | ||
| 232 | |||
| 233 | /* MGA specific ioctls | 229 | /* MGA specific ioctls |
| 234 | * The device specific ioctl range is 0x40 to 0x79. | 230 | * The device specific ioctl range is 0x40 to 0x79. |
| 235 | */ | 231 | */ |
| @@ -244,6 +240,14 @@ typedef struct _drm_mga_sarea { | |||
| 244 | #define DRM_MGA_BLIT 0x08 | 240 | #define DRM_MGA_BLIT 0x08 |
| 245 | #define DRM_MGA_GETPARAM 0x09 | 241 | #define DRM_MGA_GETPARAM 0x09 |
| 246 | 242 | ||
| 243 | /* 3.2: | ||
| 244 | * ioctls for operating on fences. | ||
| 245 | */ | ||
| 246 | #define DRM_MGA_SET_FENCE 0x0a | ||
| 247 | #define DRM_MGA_WAIT_FENCE 0x0b | ||
| 248 | #define DRM_MGA_DMA_BOOTSTRAP 0x0c | ||
| 249 | |||
| 250 | |||
| 247 | #define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t) | 251 | #define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t) |
| 248 | #define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t) | 252 | #define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t) |
| 249 | #define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET) | 253 | #define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET) |
| @@ -254,6 +258,9 @@ typedef struct _drm_mga_sarea { | |||
| 254 | #define DRM_IOCTL_MGA_ILOAD DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t) | 258 | #define DRM_IOCTL_MGA_ILOAD DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t) |
| 255 | #define DRM_IOCTL_MGA_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t) | 259 | #define DRM_IOCTL_MGA_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t) |
| 256 | #define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t) | 260 | #define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t) |
| 261 | #define DRM_IOCTL_MGA_SET_FENCE DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_SET_FENCE, uint32_t) | ||
| 262 | #define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, uint32_t) | ||
| 263 | #define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t) | ||
| 257 | 264 | ||
| 258 | typedef struct _drm_mga_warp_index { | 265 | typedef struct _drm_mga_warp_index { |
| 259 | int installed; | 266 | int installed; |
| @@ -292,12 +299,72 @@ typedef struct drm_mga_init { | |||
| 292 | unsigned long buffers_offset; | 299 | unsigned long buffers_offset; |
| 293 | } drm_mga_init_t; | 300 | } drm_mga_init_t; |
| 294 | 301 | ||
| 295 | typedef struct drm_mga_fullscreen { | 302 | typedef struct drm_mga_dma_bootstrap { |
| 296 | enum { | 303 | /** |
| 297 | MGA_INIT_FULLSCREEN = 0x01, | 304 | * \name AGP texture region |
| 298 | MGA_CLEANUP_FULLSCREEN = 0x02 | 305 | * |
| 299 | } func; | 306 | * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, these fields will |
| 300 | } drm_mga_fullscreen_t; | 307 | * be filled in with the actual AGP texture settings. |
| 308 | * | ||
| 309 | * \warning | ||
| 310 | * If these fields are non-zero, but dma_mga_dma_bootstrap::agp_mode | ||
| 311 | * is zero, it means that PCI memory (most likely through the use of | ||
| 312 | * an IOMMU) is being used for "AGP" textures. | ||
| 313 | */ | ||
| 314 | /*@{*/ | ||
| 315 | drm_handle_t texture_handle; /**< Handle used to map AGP textures. */ | ||
| 316 | uint32_t texture_size; /**< Size of the AGP texture region. */ | ||
| 317 | /*@}*/ | ||
| 318 | |||
| 319 | |||
| 320 | /** | ||
| 321 | * Requested size of the primary DMA region. | ||
| 322 | * | ||
| 323 | * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be | ||
| 324 | * filled in with the actual AGP mode. If AGP was not available | ||
| 325 | */ | ||
| 326 | uint32_t primary_size; | ||
| 327 | |||
| 328 | |||
| 329 | /** | ||
| 330 | * Requested number of secondary DMA buffers. | ||
| 331 | * | ||
| 332 | * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be | ||
| 333 | * filled in with the actual number of secondary DMA buffers | ||
| 334 | * allocated. Particularly when PCI DMA is used, this may be | ||
| 335 | * (subtantially) less than the number requested. | ||
| 336 | */ | ||
| 337 | uint32_t secondary_bin_count; | ||
| 338 | |||
| 339 | |||
| 340 | /** | ||
| 341 | * Requested size of each secondary DMA buffer. | ||
| 342 | * | ||
| 343 | * While the kernel \b is free to reduce | ||
| 344 | * dma_mga_dma_bootstrap::secondary_bin_count, it is \b not allowed | ||
| 345 | * to reduce dma_mga_dma_bootstrap::secondary_bin_size. | ||
| 346 | */ | ||
| 347 | uint32_t secondary_bin_size; | ||
| 348 | |||
| 349 | |||
| 350 | /** | ||
| 351 | * Bit-wise mask of AGPSTAT2_* values. Currently only \c AGPSTAT2_1X, | ||
| 352 | * \c AGPSTAT2_2X, and \c AGPSTAT2_4X are supported. If this value is | ||
| 353 | * zero, it means that PCI DMA should be used, even if AGP is | ||
| 354 | * possible. | ||
| 355 | * | ||
| 356 | * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be | ||
| 357 | * filled in with the actual AGP mode. If AGP was not available | ||
| 358 | * (i.e., PCI DMA was used), this value will be zero. | ||
| 359 | */ | ||
| 360 | uint32_t agp_mode; | ||
| 361 | |||
| 362 | |||
| 363 | /** | ||
| 364 | * Desired AGP GART size, measured in megabytes. | ||
| 365 | */ | ||
| 366 | uint8_t agp_size; | ||
| 367 | } drm_mga_dma_bootstrap_t; | ||
| 301 | 368 | ||
| 302 | typedef struct drm_mga_clear { | 369 | typedef struct drm_mga_clear { |
| 303 | unsigned int flags; | 370 | unsigned int flags; |
| @@ -342,6 +409,14 @@ typedef struct _drm_mga_blit { | |||
| 342 | */ | 409 | */ |
| 343 | #define MGA_PARAM_IRQ_NR 1 | 410 | #define MGA_PARAM_IRQ_NR 1 |
| 344 | 411 | ||
| 412 | /* 3.2: Query the actual card type. The DDX only distinguishes between | ||
| 413 | * G200 chips and non-G200 chips, which it calls G400. It turns out that | ||
| 414 | * there are some very sublte differences between the G4x0 chips and the G550 | ||
| 415 | * chips. Using this parameter query, a client-side driver can detect the | ||
| 416 | * difference between a G4x0 and a G550. | ||
| 417 | */ | ||
| 418 | #define MGA_PARAM_CARD_TYPE 2 | ||
| 419 | |||
| 345 | typedef struct drm_mga_getparam { | 420 | typedef struct drm_mga_getparam { |
| 346 | int param; | 421 | int param; |
| 347 | void __user *value; | 422 | void __user *value; |
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h index 38f913905e04..b22fdbd4f830 100644 --- a/drivers/char/drm/mga_drv.h +++ b/drivers/char/drm/mga_drv.h | |||
| @@ -38,11 +38,11 @@ | |||
| 38 | 38 | ||
| 39 | #define DRIVER_NAME "mga" | 39 | #define DRIVER_NAME "mga" |
| 40 | #define DRIVER_DESC "Matrox G200/G400" | 40 | #define DRIVER_DESC "Matrox G200/G400" |
| 41 | #define DRIVER_DATE "20051013" | 41 | #define DRIVER_DATE "20050607" |
| 42 | 42 | ||
| 43 | #define DRIVER_MAJOR 3 | 43 | #define DRIVER_MAJOR 3 |
| 44 | #define DRIVER_MINOR 1 | 44 | #define DRIVER_MINOR 2 |
| 45 | #define DRIVER_PATCHLEVEL 1 | 45 | #define DRIVER_PATCHLEVEL 0 |
| 46 | 46 | ||
| 47 | typedef struct drm_mga_primary_buffer { | 47 | typedef struct drm_mga_primary_buffer { |
| 48 | u8 *start; | 48 | u8 *start; |
| @@ -87,9 +87,43 @@ typedef struct drm_mga_private { | |||
| 87 | int chipset; | 87 | int chipset; |
| 88 | int usec_timeout; | 88 | int usec_timeout; |
| 89 | 89 | ||
| 90 | /** | ||
| 91 | * If set, the new DMA initialization sequence was used. This is | ||
| 92 | * primarilly used to select how the driver should uninitialized its | ||
| 93 | * internal DMA structures. | ||
| 94 | */ | ||
| 95 | int used_new_dma_init; | ||
| 96 | |||
| 97 | /** | ||
| 98 | * If AGP memory is used for DMA buffers, this will be the value | ||
| 99 | * \c MGA_PAGPXFER. Otherwise, it will be zero (for a PCI transfer). | ||
| 100 | */ | ||
| 101 | u32 dma_access; | ||
| 102 | |||
| 103 | /** | ||
| 104 | * If AGP memory is used for DMA buffers, this will be the value | ||
| 105 | * \c MGA_WAGP_ENABLE. Otherwise, it will be zero (for a PCI | ||
| 106 | * transfer). | ||
| 107 | */ | ||
| 108 | u32 wagp_enable; | ||
| 109 | |||
| 110 | /** | ||
| 111 | * \name MMIO region parameters. | ||
| 112 | * | ||
| 113 | * \sa drm_mga_private_t::mmio | ||
| 114 | */ | ||
| 115 | /*@{*/ | ||
| 116 | u32 mmio_base; /**< Bus address of base of MMIO. */ | ||
| 117 | u32 mmio_size; /**< Size of the MMIO region. */ | ||
| 118 | /*@}*/ | ||
| 119 | |||
| 90 | u32 clear_cmd; | 120 | u32 clear_cmd; |
| 91 | u32 maccess; | 121 | u32 maccess; |
| 92 | 122 | ||
| 123 | wait_queue_head_t fence_queue; | ||
| 124 | atomic_t last_fence_retired; | ||
| 125 | u32 next_fence_to_post; | ||
| 126 | |||
| 93 | unsigned int fb_cpp; | 127 | unsigned int fb_cpp; |
| 94 | unsigned int front_offset; | 128 | unsigned int front_offset; |
| 95 | unsigned int front_pitch; | 129 | unsigned int front_pitch; |
| @@ -108,35 +142,43 @@ typedef struct drm_mga_private { | |||
| 108 | drm_local_map_t *status; | 142 | drm_local_map_t *status; |
| 109 | drm_local_map_t *warp; | 143 | drm_local_map_t *warp; |
| 110 | drm_local_map_t *primary; | 144 | drm_local_map_t *primary; |
| 111 | drm_local_map_t *buffers; | ||
| 112 | drm_local_map_t *agp_textures; | 145 | drm_local_map_t *agp_textures; |
| 146 | |||
| 147 | DRM_AGP_MEM *agp_mem; | ||
| 148 | unsigned int agp_pages; | ||
| 113 | } drm_mga_private_t; | 149 | } drm_mga_private_t; |
| 114 | 150 | ||
| 115 | /* mga_dma.c */ | 151 | /* mga_dma.c */ |
| 116 | extern int mga_dma_init( DRM_IOCTL_ARGS ); | 152 | extern int mga_driver_preinit(drm_device_t * dev, unsigned long flags); |
| 117 | extern int mga_dma_flush( DRM_IOCTL_ARGS ); | 153 | extern int mga_dma_bootstrap(DRM_IOCTL_ARGS); |
| 118 | extern int mga_dma_reset( DRM_IOCTL_ARGS ); | 154 | extern int mga_dma_init(DRM_IOCTL_ARGS); |
| 119 | extern int mga_dma_buffers( DRM_IOCTL_ARGS ); | 155 | extern int mga_dma_flush(DRM_IOCTL_ARGS); |
| 120 | extern void mga_driver_pretakedown(drm_device_t *dev); | 156 | extern int mga_dma_reset(DRM_IOCTL_ARGS); |
| 121 | extern int mga_driver_dma_quiescent(drm_device_t *dev); | 157 | extern int mga_dma_buffers(DRM_IOCTL_ARGS); |
| 122 | 158 | extern int mga_driver_postcleanup(drm_device_t * dev); | |
| 123 | extern int mga_do_wait_for_idle( drm_mga_private_t *dev_priv ); | 159 | extern void mga_driver_pretakedown(drm_device_t * dev); |
| 124 | 160 | extern int mga_driver_dma_quiescent(drm_device_t * dev); | |
| 125 | extern void mga_do_dma_flush( drm_mga_private_t *dev_priv ); | 161 | |
| 126 | extern void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv ); | 162 | extern int mga_do_wait_for_idle(drm_mga_private_t * dev_priv); |
| 127 | extern void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv ); | 163 | |
| 164 | extern void mga_do_dma_flush(drm_mga_private_t * dev_priv); | ||
| 165 | extern void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv); | ||
| 166 | extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv); | ||
| 128 | 167 | ||
| 129 | extern int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf ); | 168 | extern int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf ); |
| 130 | 169 | ||
| 131 | /* mga_warp.c */ | 170 | /* mga_warp.c */ |
| 132 | extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv ); | 171 | extern unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv); |
| 133 | extern int mga_warp_init( drm_mga_private_t *dev_priv ); | 172 | extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); |
| 134 | 173 | extern int mga_warp_init(drm_mga_private_t * dev_priv); | |
| 135 | extern int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); | 174 | |
| 136 | extern irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ); | 175 | /* mga_irq.c */ |
| 137 | extern void mga_driver_irq_preinstall( drm_device_t *dev ); | 176 | extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence); |
| 138 | extern void mga_driver_irq_postinstall( drm_device_t *dev ); | 177 | extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence); |
| 139 | extern void mga_driver_irq_uninstall( drm_device_t *dev ); | 178 | extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); |
| 179 | extern void mga_driver_irq_preinstall(drm_device_t * dev); | ||
| 180 | extern void mga_driver_irq_postinstall(drm_device_t * dev); | ||
| 181 | extern void mga_driver_irq_uninstall(drm_device_t * dev); | ||
| 140 | extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, | 182 | extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, |
| 141 | unsigned long arg); | 183 | unsigned long arg); |
| 142 | 184 | ||
| @@ -527,6 +569,12 @@ do { \ | |||
| 527 | */ | 569 | */ |
| 528 | #define MGA_EXEC 0x0100 | 570 | #define MGA_EXEC 0x0100 |
| 529 | 571 | ||
| 572 | /* AGP PLL encoding (for G200 only). | ||
| 573 | */ | ||
| 574 | #define MGA_AGP_PLL 0x1e4c | ||
| 575 | # define MGA_AGP2XPLL_DISABLE (0 << 0) | ||
| 576 | # define MGA_AGP2XPLL_ENABLE (1 << 0) | ||
| 577 | |||
| 530 | /* Warp registers | 578 | /* Warp registers |
| 531 | */ | 579 | */ |
| 532 | #define MGA_WR0 0x2d00 | 580 | #define MGA_WR0 0x2d00 |
diff --git a/drivers/char/drm/mga_irq.c b/drivers/char/drm/mga_irq.c index bc0b6b5d43a6..52eaa4e788f9 100644 --- a/drivers/char/drm/mga_irq.c +++ b/drivers/char/drm/mga_irq.c | |||
| @@ -41,15 +41,40 @@ irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ) | |||
| 41 | drm_mga_private_t *dev_priv = | 41 | drm_mga_private_t *dev_priv = |
| 42 | (drm_mga_private_t *)dev->dev_private; | 42 | (drm_mga_private_t *)dev->dev_private; |
| 43 | int status; | 43 | int status; |
| 44 | int handled = 0; | ||
| 45 | |||
| 46 | status = MGA_READ(MGA_STATUS); | ||
| 44 | 47 | ||
| 45 | status = MGA_READ( MGA_STATUS ); | ||
| 46 | |||
| 47 | /* VBLANK interrupt */ | 48 | /* VBLANK interrupt */ |
| 48 | if ( status & MGA_VLINEPEN ) { | 49 | if ( status & MGA_VLINEPEN ) { |
| 49 | MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR ); | 50 | MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR ); |
| 50 | atomic_inc(&dev->vbl_received); | 51 | atomic_inc(&dev->vbl_received); |
| 51 | DRM_WAKEUP(&dev->vbl_queue); | 52 | DRM_WAKEUP(&dev->vbl_queue); |
| 52 | drm_vbl_send_signals( dev ); | 53 | drm_vbl_send_signals(dev); |
| 54 | handled = 1; | ||
| 55 | } | ||
| 56 | |||
| 57 | /* SOFTRAP interrupt */ | ||
| 58 | if (status & MGA_SOFTRAPEN) { | ||
| 59 | const u32 prim_start = MGA_READ(MGA_PRIMADDRESS); | ||
| 60 | const u32 prim_end = MGA_READ(MGA_PRIMEND); | ||
| 61 | |||
| 62 | |||
| 63 | MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR); | ||
| 64 | |||
| 65 | /* In addition to clearing the interrupt-pending bit, we | ||
| 66 | * have to write to MGA_PRIMEND to re-start the DMA operation. | ||
| 67 | */ | ||
| 68 | if ( (prim_start & ~0x03) != (prim_end & ~0x03) ) { | ||
| 69 | MGA_WRITE(MGA_PRIMEND, prim_end); | ||
| 70 | } | ||
| 71 | |||
| 72 | atomic_inc(&dev_priv->last_fence_retired); | ||
| 73 | DRM_WAKEUP(&dev_priv->fence_queue); | ||
| 74 | handled = 1; | ||
| 75 | } | ||
| 76 | |||
| 77 | if ( handled ) { | ||
| 53 | return IRQ_HANDLED; | 78 | return IRQ_HANDLED; |
| 54 | } | 79 | } |
| 55 | return IRQ_NONE; | 80 | return IRQ_NONE; |
| @@ -73,9 +98,28 @@ int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) | |||
| 73 | return ret; | 98 | return ret; |
| 74 | } | 99 | } |
| 75 | 100 | ||
| 76 | void mga_driver_irq_preinstall( drm_device_t *dev ) { | 101 | int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence) |
| 77 | drm_mga_private_t *dev_priv = | 102 | { |
| 78 | (drm_mga_private_t *)dev->dev_private; | 103 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; |
| 104 | unsigned int cur_fence; | ||
| 105 | int ret = 0; | ||
| 106 | |||
| 107 | /* Assume that the user has missed the current sequence number | ||
| 108 | * by about a day rather than she wants to wait for years | ||
| 109 | * using fences. | ||
| 110 | */ | ||
| 111 | DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ, | ||
| 112 | (((cur_fence = atomic_read(&dev_priv->last_fence_retired)) | ||
| 113 | - *sequence) <= (1 << 23))); | ||
| 114 | |||
| 115 | *sequence = cur_fence; | ||
| 116 | |||
| 117 | return ret; | ||
| 118 | } | ||
| 119 | |||
| 120 | void mga_driver_irq_preinstall(drm_device_t * dev) | ||
| 121 | { | ||
| 122 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; | ||
| 79 | 123 | ||
| 80 | /* Disable *all* interrupts */ | 124 | /* Disable *all* interrupts */ |
| 81 | MGA_WRITE( MGA_IEN, 0 ); | 125 | MGA_WRITE( MGA_IEN, 0 ); |
| @@ -83,12 +127,14 @@ void mga_driver_irq_preinstall( drm_device_t *dev ) { | |||
| 83 | MGA_WRITE( MGA_ICLEAR, ~0 ); | 127 | MGA_WRITE( MGA_ICLEAR, ~0 ); |
| 84 | } | 128 | } |
| 85 | 129 | ||
| 86 | void mga_driver_irq_postinstall( drm_device_t *dev ) { | 130 | void mga_driver_irq_postinstall(drm_device_t * dev) |
| 87 | drm_mga_private_t *dev_priv = | 131 | { |
| 88 | (drm_mga_private_t *)dev->dev_private; | 132 | drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; |
| 133 | |||
| 134 | DRM_INIT_WAITQUEUE( &dev_priv->fence_queue ); | ||
| 89 | 135 | ||
| 90 | /* Turn on VBL interrupt */ | 136 | /* Turn on vertical blank interrupt and soft trap interrupt. */ |
| 91 | MGA_WRITE( MGA_IEN, MGA_VLINEIEN ); | 137 | MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); |
| 92 | } | 138 | } |
| 93 | 139 | ||
| 94 | void mga_driver_irq_uninstall( drm_device_t *dev ) { | 140 | void mga_driver_irq_uninstall( drm_device_t *dev ) { |
| @@ -98,5 +144,7 @@ void mga_driver_irq_uninstall( drm_device_t *dev ) { | |||
| 98 | return; | 144 | return; |
| 99 | 145 | ||
| 100 | /* Disable *all* interrupts */ | 146 | /* Disable *all* interrupts */ |
| 101 | MGA_WRITE( MGA_IEN, 0 ); | 147 | MGA_WRITE(MGA_IEN, 0); |
| 148 | |||
| 149 | dev->irq_enabled = 0; | ||
| 102 | } | 150 | } |
diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c index 3c7a8f5ba501..05bbb4719376 100644 --- a/drivers/char/drm/mga_state.c +++ b/drivers/char/drm/mga_state.c | |||
| @@ -53,16 +53,16 @@ static void mga_emit_clip_rect( drm_mga_private_t *dev_priv, | |||
| 53 | 53 | ||
| 54 | /* Force reset of DWGCTL on G400 (eliminates clip disable bit). | 54 | /* Force reset of DWGCTL on G400 (eliminates clip disable bit). |
| 55 | */ | 55 | */ |
| 56 | if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) { | 56 | if (dev_priv->chipset == MGA_CARD_TYPE_G400) { |
| 57 | DMA_BLOCK( MGA_DWGCTL, ctx->dwgctl, | 57 | DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl, |
| 58 | MGA_LEN + MGA_EXEC, 0x80000000, | 58 | MGA_LEN + MGA_EXEC, 0x80000000, |
| 59 | MGA_DWGCTL, ctx->dwgctl, | 59 | MGA_DWGCTL, ctx->dwgctl, |
| 60 | MGA_LEN + MGA_EXEC, 0x80000000 ); | 60 | MGA_LEN + MGA_EXEC, 0x80000000); |
| 61 | } | 61 | } |
| 62 | DMA_BLOCK( MGA_DMAPAD, 0x00000000, | 62 | DMA_BLOCK(MGA_DMAPAD, 0x00000000, |
| 63 | MGA_CXBNDRY, (box->x2 << 16) | box->x1, | 63 | MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1, |
| 64 | MGA_YTOP, box->y1 * pitch, | 64 | MGA_YTOP, box->y1 * pitch, |
| 65 | MGA_YBOT, box->y2 * pitch ); | 65 | MGA_YBOT, (box->y2 - 1) * pitch); |
| 66 | 66 | ||
| 67 | ADVANCE_DMA(); | 67 | ADVANCE_DMA(); |
| 68 | } | 68 | } |
| @@ -260,12 +260,11 @@ static __inline__ void mga_g200_emit_pipe( drm_mga_private_t *dev_priv ) | |||
| 260 | 260 | ||
| 261 | /* Padding required to to hardware bug. | 261 | /* Padding required to to hardware bug. |
| 262 | */ | 262 | */ |
| 263 | DMA_BLOCK( MGA_DMAPAD, 0xffffffff, | 263 | DMA_BLOCK(MGA_DMAPAD, 0xffffffff, |
| 264 | MGA_DMAPAD, 0xffffffff, | 264 | MGA_DMAPAD, 0xffffffff, |
| 265 | MGA_DMAPAD, 0xffffffff, | 265 | MGA_DMAPAD, 0xffffffff, |
| 266 | MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] | | 266 | MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] | |
| 267 | MGA_WMODE_START | | 267 | MGA_WMODE_START | dev_priv->wagp_enable)); |
| 268 | MGA_WAGP_ENABLE) ); | ||
| 269 | 268 | ||
| 270 | ADVANCE_DMA(); | 269 | ADVANCE_DMA(); |
| 271 | } | 270 | } |
| @@ -342,12 +341,11 @@ static __inline__ void mga_g400_emit_pipe( drm_mga_private_t *dev_priv ) | |||
| 342 | MGA_WR60, MGA_G400_WR_MAGIC ); /* tex1 height */ | 341 | MGA_WR60, MGA_G400_WR_MAGIC ); /* tex1 height */ |
| 343 | 342 | ||
| 344 | /* Padding required to to hardware bug */ | 343 | /* Padding required to to hardware bug */ |
| 345 | DMA_BLOCK( MGA_DMAPAD, 0xffffffff, | 344 | DMA_BLOCK(MGA_DMAPAD, 0xffffffff, |
| 346 | MGA_DMAPAD, 0xffffffff, | 345 | MGA_DMAPAD, 0xffffffff, |
| 347 | MGA_DMAPAD, 0xffffffff, | 346 | MGA_DMAPAD, 0xffffffff, |
| 348 | MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] | | 347 | MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] | |
| 349 | MGA_WMODE_START | | 348 | MGA_WMODE_START | dev_priv->wagp_enable)); |
| 350 | MGA_WAGP_ENABLE) ); | ||
| 351 | 349 | ||
| 352 | ADVANCE_DMA(); | 350 | ADVANCE_DMA(); |
| 353 | } | 351 | } |
| @@ -459,9 +457,9 @@ static int mga_verify_state( drm_mga_private_t *dev_priv ) | |||
| 459 | if ( dirty & MGA_UPLOAD_TEX0 ) | 457 | if ( dirty & MGA_UPLOAD_TEX0 ) |
| 460 | ret |= mga_verify_tex( dev_priv, 0 ); | 458 | ret |= mga_verify_tex( dev_priv, 0 ); |
| 461 | 459 | ||
| 462 | if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) { | 460 | if (dev_priv->chipset >= MGA_CARD_TYPE_G400) { |
| 463 | if ( dirty & MGA_UPLOAD_TEX1 ) | 461 | if (dirty & MGA_UPLOAD_TEX1) |
| 464 | ret |= mga_verify_tex( dev_priv, 1 ); | 462 | ret |= mga_verify_tex(dev_priv, 1); |
| 465 | 463 | ||
| 466 | if ( dirty & MGA_UPLOAD_PIPE ) | 464 | if ( dirty & MGA_UPLOAD_PIPE ) |
| 467 | ret |= ( sarea_priv->warp_pipe > MGA_MAX_G400_PIPES ); | 465 | ret |= ( sarea_priv->warp_pipe > MGA_MAX_G400_PIPES ); |
| @@ -686,12 +684,12 @@ static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf ) | |||
| 686 | 684 | ||
| 687 | BEGIN_DMA( 1 ); | 685 | BEGIN_DMA( 1 ); |
| 688 | 686 | ||
| 689 | DMA_BLOCK( MGA_DMAPAD, 0x00000000, | 687 | DMA_BLOCK(MGA_DMAPAD, 0x00000000, |
| 690 | MGA_DMAPAD, 0x00000000, | 688 | MGA_DMAPAD, 0x00000000, |
| 691 | MGA_SECADDRESS, (address | | 689 | MGA_SECADDRESS, (address | |
| 692 | MGA_DMA_VERTEX), | 690 | MGA_DMA_VERTEX), |
| 693 | MGA_SECEND, ((address + length) | | 691 | MGA_SECEND, ((address + length) | |
| 694 | MGA_PAGPXFER) ); | 692 | dev_priv->dma_access)); |
| 695 | 693 | ||
| 696 | ADVANCE_DMA(); | 694 | ADVANCE_DMA(); |
| 697 | } while ( ++i < sarea_priv->nbox ); | 695 | } while ( ++i < sarea_priv->nbox ); |
| @@ -733,11 +731,11 @@ static void mga_dma_dispatch_indices( drm_device_t *dev, drm_buf_t *buf, | |||
| 733 | 731 | ||
| 734 | BEGIN_DMA( 1 ); | 732 | BEGIN_DMA( 1 ); |
| 735 | 733 | ||
| 736 | DMA_BLOCK( MGA_DMAPAD, 0x00000000, | 734 | DMA_BLOCK(MGA_DMAPAD, 0x00000000, |
| 737 | MGA_DMAPAD, 0x00000000, | 735 | MGA_DMAPAD, 0x00000000, |
| 738 | MGA_SETUPADDRESS, address + start, | 736 | MGA_SETUPADDRESS, address + start, |
| 739 | MGA_SETUPEND, ((address + end) | | 737 | MGA_SETUPEND, ((address + end) | |
| 740 | MGA_PAGPXFER) ); | 738 | dev_priv->dma_access)); |
| 741 | 739 | ||
| 742 | ADVANCE_DMA(); | 740 | ADVANCE_DMA(); |
| 743 | } while ( ++i < sarea_priv->nbox ); | 741 | } while ( ++i < sarea_priv->nbox ); |
| @@ -764,7 +762,7 @@ static void mga_dma_dispatch_iload( drm_device_t *dev, drm_buf_t *buf, | |||
| 764 | drm_mga_private_t *dev_priv = dev->dev_private; | 762 | drm_mga_private_t *dev_priv = dev->dev_private; |
| 765 | drm_mga_buf_priv_t *buf_priv = buf->dev_private; | 763 | drm_mga_buf_priv_t *buf_priv = buf->dev_private; |
| 766 | drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state; | 764 | drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state; |
| 767 | u32 srcorg = buf->bus_address | MGA_SRCACC_AGP | MGA_SRCMAP_SYSMEM; | 765 | u32 srcorg = buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM; |
| 768 | u32 y2; | 766 | u32 y2; |
| 769 | DMA_LOCALS; | 767 | DMA_LOCALS; |
| 770 | DRM_DEBUG( "buf=%d used=%d\n", buf->idx, buf->used ); | 768 | DRM_DEBUG( "buf=%d used=%d\n", buf->idx, buf->used ); |
| @@ -1095,6 +1093,9 @@ static int mga_getparam( DRM_IOCTL_ARGS ) | |||
| 1095 | case MGA_PARAM_IRQ_NR: | 1093 | case MGA_PARAM_IRQ_NR: |
| 1096 | value = dev->irq; | 1094 | value = dev->irq; |
| 1097 | break; | 1095 | break; |
| 1096 | case MGA_PARAM_CARD_TYPE: | ||
| 1097 | value = dev_priv->chipset; | ||
| 1098 | break; | ||
| 1098 | default: | 1099 | default: |
| 1099 | return DRM_ERR(EINVAL); | 1100 | return DRM_ERR(EINVAL); |
| 1100 | } | 1101 | } |
| @@ -1107,17 +1108,82 @@ static int mga_getparam( DRM_IOCTL_ARGS ) | |||
| 1107 | return 0; | 1108 | return 0; |
| 1108 | } | 1109 | } |
| 1109 | 1110 | ||
| 1111 | static int mga_set_fence(DRM_IOCTL_ARGS) | ||
| 1112 | { | ||
| 1113 | DRM_DEVICE; | ||
| 1114 | drm_mga_private_t *dev_priv = dev->dev_private; | ||
| 1115 | u32 temp; | ||
| 1116 | DMA_LOCALS; | ||
| 1117 | |||
| 1118 | if (!dev_priv) { | ||
| 1119 | DRM_ERROR("%s called with no initialization\n", __FUNCTION__); | ||
| 1120 | return DRM_ERR(EINVAL); | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); | ||
| 1124 | |||
| 1125 | /* I would normal do this assignment in the declaration of temp, | ||
| 1126 | * but dev_priv may be NULL. | ||
| 1127 | */ | ||
| 1128 | |||
| 1129 | temp = dev_priv->next_fence_to_post; | ||
| 1130 | dev_priv->next_fence_to_post++; | ||
| 1131 | |||
| 1132 | BEGIN_DMA(1); | ||
| 1133 | DMA_BLOCK(MGA_DMAPAD, 0x00000000, | ||
| 1134 | MGA_DMAPAD, 0x00000000, | ||
| 1135 | MGA_DMAPAD, 0x00000000, | ||
| 1136 | MGA_SOFTRAP, 0x00000000); | ||
| 1137 | ADVANCE_DMA(); | ||
| 1138 | |||
| 1139 | if (DRM_COPY_TO_USER( (u32 __user *) data, & temp, sizeof(u32))) { | ||
| 1140 | DRM_ERROR("copy_to_user\n"); | ||
| 1141 | return DRM_ERR(EFAULT); | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | return 0; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | static int mga_wait_fence(DRM_IOCTL_ARGS) | ||
| 1148 | { | ||
| 1149 | DRM_DEVICE; | ||
| 1150 | drm_mga_private_t *dev_priv = dev->dev_private; | ||
| 1151 | u32 fence; | ||
| 1152 | |||
| 1153 | if (!dev_priv) { | ||
| 1154 | DRM_ERROR("%s called with no initialization\n", __FUNCTION__); | ||
| 1155 | return DRM_ERR(EINVAL); | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32)); | ||
| 1159 | |||
| 1160 | DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); | ||
| 1161 | |||
| 1162 | mga_driver_fence_wait(dev, & fence); | ||
| 1163 | |||
| 1164 | if (DRM_COPY_TO_USER( (u32 __user *) data, & fence, sizeof(u32))) { | ||
| 1165 | DRM_ERROR("copy_to_user\n"); | ||
| 1166 | return DRM_ERR(EFAULT); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | return 0; | ||
| 1170 | } | ||
| 1171 | |||
| 1110 | drm_ioctl_desc_t mga_ioctls[] = { | 1172 | drm_ioctl_desc_t mga_ioctls[] = { |
| 1111 | [DRM_IOCTL_NR(DRM_MGA_INIT)] = { mga_dma_init, 1, 1 }, | 1173 | [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, 1, 1}, |
| 1112 | [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = { mga_dma_flush, 1, 0 }, | 1174 | [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, 1, 0}, |
| 1113 | [DRM_IOCTL_NR(DRM_MGA_RESET)] = { mga_dma_reset, 1, 0 }, | 1175 | [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, 1, 0}, |
| 1114 | [DRM_IOCTL_NR(DRM_MGA_SWAP)] = { mga_dma_swap, 1, 0 }, | 1176 | [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, 1, 0}, |
| 1115 | [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = { mga_dma_clear, 1, 0 }, | 1177 | [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, 1, 0}, |
| 1116 | [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = { mga_dma_vertex, 1, 0 }, | 1178 | [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, 1, 0}, |
| 1117 | [DRM_IOCTL_NR(DRM_MGA_INDICES)] = { mga_dma_indices, 1, 0 }, | 1179 | [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, 1, 0}, |
| 1118 | [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = { mga_dma_iload, 1, 0 }, | 1180 | [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, 1, 0}, |
| 1119 | [DRM_IOCTL_NR(DRM_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, | 1181 | [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, 1, 0}, |
| 1120 | [DRM_IOCTL_NR(DRM_MGA_GETPARAM)]= { mga_getparam, 1, 0 }, | 1182 | [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, 1, 0}, |
| 1183 | [DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, 1, 0}, | ||
| 1184 | [DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, 1, 0}, | ||
| 1185 | [DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, 1, 1}, | ||
| 1186 | |||
| 1121 | }; | 1187 | }; |
| 1122 | 1188 | ||
| 1123 | int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); | 1189 | int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); |
diff --git a/drivers/char/drm/mga_warp.c b/drivers/char/drm/mga_warp.c index 0a3a0cc700dc..55ccc8a0ac29 100644 --- a/drivers/char/drm/mga_warp.c +++ b/drivers/char/drm/mga_warp.c | |||
| @@ -48,65 +48,52 @@ do { \ | |||
| 48 | vcbase += WARP_UCODE_SIZE( which ); \ | 48 | vcbase += WARP_UCODE_SIZE( which ); \ |
| 49 | } while (0) | 49 | } while (0) |
| 50 | 50 | ||
| 51 | 51 | static const unsigned int mga_warp_g400_microcode_size = | |
| 52 | static unsigned int mga_warp_g400_microcode_size( drm_mga_private_t *dev_priv ) | 52 | (WARP_UCODE_SIZE(warp_g400_tgz) + |
| 53 | { | 53 | WARP_UCODE_SIZE(warp_g400_tgza) + |
| 54 | unsigned int size; | 54 | WARP_UCODE_SIZE(warp_g400_tgzaf) + |
| 55 | 55 | WARP_UCODE_SIZE(warp_g400_tgzf) + | |
| 56 | size = ( WARP_UCODE_SIZE( warp_g400_tgz ) + | 56 | WARP_UCODE_SIZE(warp_g400_tgzs) + |
| 57 | WARP_UCODE_SIZE( warp_g400_tgza ) + | 57 | WARP_UCODE_SIZE(warp_g400_tgzsa) + |
| 58 | WARP_UCODE_SIZE( warp_g400_tgzaf ) + | 58 | WARP_UCODE_SIZE(warp_g400_tgzsaf) + |
| 59 | WARP_UCODE_SIZE( warp_g400_tgzf ) + | 59 | WARP_UCODE_SIZE(warp_g400_tgzsf) + |
| 60 | WARP_UCODE_SIZE( warp_g400_tgzs ) + | 60 | WARP_UCODE_SIZE(warp_g400_t2gz) + |
| 61 | WARP_UCODE_SIZE( warp_g400_tgzsa ) + | 61 | WARP_UCODE_SIZE(warp_g400_t2gza) + |
| 62 | WARP_UCODE_SIZE( warp_g400_tgzsaf ) + | 62 | WARP_UCODE_SIZE(warp_g400_t2gzaf) + |
| 63 | WARP_UCODE_SIZE( warp_g400_tgzsf ) + | 63 | WARP_UCODE_SIZE(warp_g400_t2gzf) + |
| 64 | WARP_UCODE_SIZE( warp_g400_t2gz ) + | 64 | WARP_UCODE_SIZE(warp_g400_t2gzs) + |
| 65 | WARP_UCODE_SIZE( warp_g400_t2gza ) + | 65 | WARP_UCODE_SIZE(warp_g400_t2gzsa) + |
| 66 | WARP_UCODE_SIZE( warp_g400_t2gzaf ) + | 66 | WARP_UCODE_SIZE(warp_g400_t2gzsaf) + |
| 67 | WARP_UCODE_SIZE( warp_g400_t2gzf ) + | 67 | WARP_UCODE_SIZE(warp_g400_t2gzsf)); |
| 68 | WARP_UCODE_SIZE( warp_g400_t2gzs ) + | 68 | |
| 69 | WARP_UCODE_SIZE( warp_g400_t2gzsa ) + | 69 | static const unsigned int mga_warp_g200_microcode_size = |
| 70 | WARP_UCODE_SIZE( warp_g400_t2gzsaf ) + | 70 | (WARP_UCODE_SIZE(warp_g200_tgz) + |
| 71 | WARP_UCODE_SIZE( warp_g400_t2gzsf ) ); | 71 | WARP_UCODE_SIZE(warp_g200_tgza) + |
| 72 | 72 | WARP_UCODE_SIZE(warp_g200_tgzaf) + | |
| 73 | size = PAGE_ALIGN( size ); | 73 | WARP_UCODE_SIZE(warp_g200_tgzf) + |
| 74 | 74 | WARP_UCODE_SIZE(warp_g200_tgzs) + | |
| 75 | DRM_DEBUG( "G400 ucode size = %d bytes\n", size ); | 75 | WARP_UCODE_SIZE(warp_g200_tgzsa) + |
| 76 | return size; | 76 | WARP_UCODE_SIZE(warp_g200_tgzsaf) + |
| 77 | } | 77 | WARP_UCODE_SIZE(warp_g200_tgzsf)); |
| 78 | 78 | ||
| 79 | static unsigned int mga_warp_g200_microcode_size( drm_mga_private_t *dev_priv ) | 79 | |
| 80 | unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv) | ||
| 80 | { | 81 | { |
| 81 | unsigned int size; | 82 | switch (dev_priv->chipset) { |
| 82 | 83 | case MGA_CARD_TYPE_G400: | |
| 83 | size = ( WARP_UCODE_SIZE( warp_g200_tgz ) + | 84 | case MGA_CARD_TYPE_G550: |
| 84 | WARP_UCODE_SIZE( warp_g200_tgza ) + | 85 | return PAGE_ALIGN(mga_warp_g400_microcode_size); |
| 85 | WARP_UCODE_SIZE( warp_g200_tgzaf ) + | 86 | case MGA_CARD_TYPE_G200: |
| 86 | WARP_UCODE_SIZE( warp_g200_tgzf ) + | 87 | return PAGE_ALIGN(mga_warp_g200_microcode_size); |
| 87 | WARP_UCODE_SIZE( warp_g200_tgzs ) + | 88 | default: |
| 88 | WARP_UCODE_SIZE( warp_g200_tgzsa ) + | 89 | return 0; |
| 89 | WARP_UCODE_SIZE( warp_g200_tgzsaf ) + | 90 | } |
| 90 | WARP_UCODE_SIZE( warp_g200_tgzsf ) ); | ||
| 91 | |||
| 92 | size = PAGE_ALIGN( size ); | ||
| 93 | |||
| 94 | DRM_DEBUG( "G200 ucode size = %d bytes\n", size ); | ||
| 95 | return size; | ||
| 96 | } | 91 | } |
| 97 | 92 | ||
| 98 | static int mga_warp_install_g400_microcode( drm_mga_private_t *dev_priv ) | 93 | static int mga_warp_install_g400_microcode( drm_mga_private_t *dev_priv ) |
| 99 | { | 94 | { |
| 100 | unsigned char *vcbase = dev_priv->warp->handle; | 95 | unsigned char *vcbase = dev_priv->warp->handle; |
| 101 | unsigned long pcbase = dev_priv->warp->offset; | 96 | unsigned long pcbase = dev_priv->warp->offset; |
| 102 | unsigned int size; | ||
| 103 | |||
| 104 | size = mga_warp_g400_microcode_size( dev_priv ); | ||
| 105 | if ( size > dev_priv->warp->size ) { | ||
| 106 | DRM_ERROR( "microcode too large! (%u > %lu)\n", | ||
| 107 | size, dev_priv->warp->size ); | ||
| 108 | return DRM_ERR(ENOMEM); | ||
| 109 | } | ||
| 110 | 97 | ||
| 111 | memset( dev_priv->warp_pipe_phys, 0, | 98 | memset( dev_priv->warp_pipe_phys, 0, |
| 112 | sizeof(dev_priv->warp_pipe_phys) ); | 99 | sizeof(dev_priv->warp_pipe_phys) ); |
| @@ -136,35 +123,36 @@ static int mga_warp_install_g200_microcode( drm_mga_private_t *dev_priv ) | |||
| 136 | { | 123 | { |
| 137 | unsigned char *vcbase = dev_priv->warp->handle; | 124 | unsigned char *vcbase = dev_priv->warp->handle; |
| 138 | unsigned long pcbase = dev_priv->warp->offset; | 125 | unsigned long pcbase = dev_priv->warp->offset; |
| 139 | unsigned int size; | ||
| 140 | |||
| 141 | size = mga_warp_g200_microcode_size( dev_priv ); | ||
| 142 | if ( size > dev_priv->warp->size ) { | ||
| 143 | DRM_ERROR( "microcode too large! (%u > %lu)\n", | ||
| 144 | size, dev_priv->warp->size ); | ||
| 145 | return DRM_ERR(ENOMEM); | ||
| 146 | } | ||
| 147 | 126 | ||
| 148 | memset( dev_priv->warp_pipe_phys, 0, | 127 | memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys)); |
| 149 | sizeof(dev_priv->warp_pipe_phys) ); | ||
| 150 | 128 | ||
| 151 | WARP_UCODE_INSTALL( warp_g200_tgz, MGA_WARP_TGZ ); | 129 | WARP_UCODE_INSTALL(warp_g200_tgz, MGA_WARP_TGZ); |
| 152 | WARP_UCODE_INSTALL( warp_g200_tgzf, MGA_WARP_TGZF ); | 130 | WARP_UCODE_INSTALL(warp_g200_tgzf, MGA_WARP_TGZF); |
| 153 | WARP_UCODE_INSTALL( warp_g200_tgza, MGA_WARP_TGZA ); | 131 | WARP_UCODE_INSTALL(warp_g200_tgza, MGA_WARP_TGZA); |
| 154 | WARP_UCODE_INSTALL( warp_g200_tgzaf, MGA_WARP_TGZAF ); | 132 | WARP_UCODE_INSTALL(warp_g200_tgzaf, MGA_WARP_TGZAF); |
| 155 | WARP_UCODE_INSTALL( warp_g200_tgzs, MGA_WARP_TGZS ); | 133 | WARP_UCODE_INSTALL(warp_g200_tgzs, MGA_WARP_TGZS); |
| 156 | WARP_UCODE_INSTALL( warp_g200_tgzsf, MGA_WARP_TGZSF ); | 134 | WARP_UCODE_INSTALL(warp_g200_tgzsf, MGA_WARP_TGZSF); |
| 157 | WARP_UCODE_INSTALL( warp_g200_tgzsa, MGA_WARP_TGZSA ); | 135 | WARP_UCODE_INSTALL(warp_g200_tgzsa, MGA_WARP_TGZSA); |
| 158 | WARP_UCODE_INSTALL( warp_g200_tgzsaf, MGA_WARP_TGZSAF ); | 136 | WARP_UCODE_INSTALL(warp_g200_tgzsaf, MGA_WARP_TGZSAF); |
| 159 | 137 | ||
| 160 | return 0; | 138 | return 0; |
| 161 | } | 139 | } |
| 162 | 140 | ||
| 163 | int mga_warp_install_microcode( drm_mga_private_t *dev_priv ) | 141 | int mga_warp_install_microcode( drm_mga_private_t *dev_priv ) |
| 164 | { | 142 | { |
| 165 | switch ( dev_priv->chipset ) { | 143 | const unsigned int size = mga_warp_microcode_size(dev_priv); |
| 144 | |||
| 145 | DRM_DEBUG("MGA ucode size = %d bytes\n", size); | ||
| 146 | if (size > dev_priv->warp->size) { | ||
| 147 | DRM_ERROR("microcode too large! (%u > %lu)\n", | ||
| 148 | size, dev_priv->warp->size); | ||
| 149 | return DRM_ERR(ENOMEM); | ||
| 150 | } | ||
| 151 | |||
| 152 | switch (dev_priv->chipset) { | ||
| 166 | case MGA_CARD_TYPE_G400: | 153 | case MGA_CARD_TYPE_G400: |
| 167 | return mga_warp_install_g400_microcode( dev_priv ); | 154 | case MGA_CARD_TYPE_G550: |
| 155 | return mga_warp_install_g400_microcode(dev_priv); | ||
| 168 | case MGA_CARD_TYPE_G200: | 156 | case MGA_CARD_TYPE_G200: |
| 169 | return mga_warp_install_g200_microcode( dev_priv ); | 157 | return mga_warp_install_g200_microcode( dev_priv ); |
| 170 | default: | 158 | default: |
| @@ -182,10 +170,11 @@ int mga_warp_init( drm_mga_private_t *dev_priv ) | |||
| 182 | */ | 170 | */ |
| 183 | switch ( dev_priv->chipset ) { | 171 | switch ( dev_priv->chipset ) { |
| 184 | case MGA_CARD_TYPE_G400: | 172 | case MGA_CARD_TYPE_G400: |
| 185 | MGA_WRITE( MGA_WIADDR2, MGA_WMODE_SUSPEND ); | 173 | case MGA_CARD_TYPE_G550: |
| 186 | MGA_WRITE( MGA_WGETMSB, 0x00000E00 ); | 174 | MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND); |
| 187 | MGA_WRITE( MGA_WVRTXSZ, 0x00001807 ); | 175 | MGA_WRITE(MGA_WGETMSB, 0x00000E00); |
| 188 | MGA_WRITE( MGA_WACCEPTSEQ, 0x18000000 ); | 176 | MGA_WRITE(MGA_WVRTXSZ, 0x00001807); |
| 177 | MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000); | ||
| 189 | break; | 178 | break; |
| 190 | case MGA_CARD_TYPE_G200: | 179 | case MGA_CARD_TYPE_G200: |
| 191 | MGA_WRITE( MGA_WIADDR, MGA_WMODE_SUSPEND ); | 180 | MGA_WRITE( MGA_WIADDR, MGA_WMODE_SUSPEND ); |
