diff options
Diffstat (limited to 'drivers/char/drm/mga_dma.c')
-rw-r--r-- | drivers/char/drm/mga_dma.c | 612 |
1 files changed, 503 insertions, 109 deletions
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c index 832eaf8a5068..fc7d4a594bca 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,390 @@ 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 | #if __OS_HAS_AGP | ||
421 | /** | ||
422 | * Bootstrap the driver for AGP DMA. | ||
423 | * | ||
424 | * \todo | ||
425 | * Investigate whether there is any benifit to storing the WARP microcode in | ||
426 | * AGP memory. If not, the microcode may as well always be put in PCI | ||
427 | * memory. | ||
428 | * | ||
429 | * \todo | ||
430 | * This routine needs to set dma_bs->agp_mode to the mode actually configured | ||
431 | * in the hardware. Looking just at the Linux AGP driver code, I don't see | ||
432 | * an easy way to determine this. | ||
433 | * | ||
434 | * \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap | ||
435 | */ | ||
436 | static int mga_do_agp_dma_bootstrap(drm_device_t * dev, | ||
437 | drm_mga_dma_bootstrap_t * dma_bs) | ||
438 | { | ||
439 | drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private; | ||
440 | const unsigned int warp_size = mga_warp_microcode_size(dev_priv); | ||
441 | int err; | ||
442 | unsigned offset; | ||
443 | const unsigned secondary_size = dma_bs->secondary_bin_count | ||
444 | * dma_bs->secondary_bin_size; | ||
445 | const unsigned agp_size = (dma_bs->agp_size << 20); | ||
446 | drm_buf_desc_t req; | ||
447 | drm_agp_mode_t mode; | ||
448 | drm_agp_info_t info; | ||
449 | |||
450 | |||
451 | /* Acquire AGP. */ | ||
452 | err = drm_agp_acquire(dev); | ||
453 | if (err) { | ||
454 | DRM_ERROR("Unable to acquire AGP\n"); | ||
455 | return err; | ||
456 | } | ||
457 | |||
458 | err = drm_agp_info(dev, &info); | ||
459 | if (err) { | ||
460 | DRM_ERROR("Unable to get AGP info\n"); | ||
461 | return err; | ||
462 | } | ||
463 | |||
464 | mode.mode = (info.mode & ~0x07) | dma_bs->agp_mode; | ||
465 | err = drm_agp_enable(dev, mode); | ||
466 | if (err) { | ||
467 | DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode); | ||
468 | return err; | ||
469 | } | ||
470 | |||
471 | |||
472 | /* In addition to the usual AGP mode configuration, the G200 AGP cards | ||
473 | * need to have the AGP mode "manually" set. | ||
474 | */ | ||
475 | |||
476 | if (dev_priv->chipset == MGA_CARD_TYPE_G200) { | ||
477 | if (mode.mode & 0x02) { | ||
478 | MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_ENABLE); | ||
479 | } | ||
480 | else { | ||
481 | MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_DISABLE); | ||
482 | } | ||
483 | } | ||
484 | |||
485 | |||
486 | /* Allocate and bind AGP memory. */ | ||
487 | dev_priv->agp_pages = agp_size / PAGE_SIZE; | ||
488 | dev_priv->agp_mem = drm_alloc_agp( dev, dev_priv->agp_pages, 0 ); | ||
489 | if (dev_priv->agp_mem == NULL) { | ||
490 | dev_priv->agp_pages = 0; | ||
491 | DRM_ERROR("Unable to allocate %uMB AGP memory\n", | ||
492 | dma_bs->agp_size); | ||
493 | return DRM_ERR(ENOMEM); | ||
494 | } | ||
495 | |||
496 | err = drm_bind_agp( dev_priv->agp_mem, 0 ); | ||
497 | if (err) { | ||
498 | DRM_ERROR("Unable to bind AGP memory\n"); | ||
499 | return err; | ||
500 | } | ||
501 | |||
502 | offset = 0; | ||
503 | err = drm_addmap( dev, offset, warp_size, | ||
504 | _DRM_AGP, _DRM_READ_ONLY, & dev_priv->warp ); | ||
505 | if (err) { | ||
506 | DRM_ERROR("Unable to map WARP microcode\n"); | ||
507 | return err; | ||
508 | } | ||
509 | |||
510 | offset += warp_size; | ||
511 | err = drm_addmap( dev, offset, dma_bs->primary_size, | ||
512 | _DRM_AGP, _DRM_READ_ONLY, & dev_priv->primary ); | ||
513 | if (err) { | ||
514 | DRM_ERROR("Unable to map primary DMA region\n"); | ||
515 | return err; | ||
516 | } | ||
517 | |||
518 | offset += dma_bs->primary_size; | ||
519 | err = drm_addmap( dev, offset, secondary_size, | ||
520 | _DRM_AGP, 0, & dev->agp_buffer_map ); | ||
521 | if (err) { | ||
522 | DRM_ERROR("Unable to map secondary DMA region\n"); | ||
523 | return err; | ||
524 | } | ||
525 | |||
526 | (void) memset( &req, 0, sizeof(req) ); | ||
527 | req.count = dma_bs->secondary_bin_count; | ||
528 | req.size = dma_bs->secondary_bin_size; | ||
529 | req.flags = _DRM_AGP_BUFFER; | ||
530 | req.agp_start = offset; | ||
531 | |||
532 | err = drm_addbufs_agp( dev, & req ); | ||
533 | if (err) { | ||
534 | DRM_ERROR("Unable to add secondary DMA buffers\n"); | ||
535 | return err; | ||
536 | } | ||
537 | |||
538 | offset += secondary_size; | ||
539 | err = drm_addmap( dev, offset, agp_size - offset, | ||
540 | _DRM_AGP, 0, & dev_priv->agp_textures ); | ||
541 | if (err) { | ||
542 | DRM_ERROR("Unable to map AGP texture region\n"); | ||
543 | return err; | ||
544 | } | ||
545 | |||
546 | drm_core_ioremap(dev_priv->warp, dev); | ||
547 | drm_core_ioremap(dev_priv->primary, dev); | ||
548 | drm_core_ioremap(dev->agp_buffer_map, dev); | ||
549 | |||
550 | if (!dev_priv->warp->handle || | ||
551 | !dev_priv->primary->handle || !dev->agp_buffer_map->handle) { | ||
552 | DRM_ERROR("failed to ioremap agp regions! (%p, %p, %p)\n", | ||
553 | dev_priv->warp->handle, dev_priv->primary->handle, | ||
554 | dev->agp_buffer_map->handle); | ||
555 | return DRM_ERR(ENOMEM); | ||
556 | } | ||
557 | |||
558 | dev_priv->dma_access = MGA_PAGPXFER; | ||
559 | dev_priv->wagp_enable = MGA_WAGP_ENABLE; | ||
560 | |||
561 | DRM_INFO("Initialized card for AGP DMA.\n"); | ||
562 | return 0; | ||
563 | } | ||
564 | #else | ||
565 | static int mga_do_agp_dma_bootstrap(drm_device_t * dev, | ||
566 | drm_mga_dma_bootstrap_t * dma_bs) | ||
567 | { | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | #endif | ||
571 | |||
572 | /** | ||
573 | * Bootstrap the driver for PCI DMA. | ||
574 | * | ||
575 | * \todo | ||
576 | * The algorithm for decreasing the size of the primary DMA buffer could be | ||
577 | * better. The size should be rounded up to the nearest page size, then | ||
578 | * decrease the request size by a single page each pass through the loop. | ||
579 | * | ||
580 | * \todo | ||
581 | * Determine whether the maximum address passed to drm_pci_alloc is correct. | ||
582 | * The same goes for drm_addbufs_pci. | ||
583 | * | ||
584 | * \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap | ||
585 | */ | ||
586 | static int mga_do_pci_dma_bootstrap(drm_device_t * dev, | ||
587 | drm_mga_dma_bootstrap_t * dma_bs) | ||
588 | { | ||
589 | drm_mga_private_t * const dev_priv = (drm_mga_private_t *) dev->dev_private; | ||
590 | const unsigned int warp_size = mga_warp_microcode_size(dev_priv); | ||
591 | unsigned int primary_size; | ||
592 | unsigned int bin_count; | ||
593 | int err; | ||
594 | drm_buf_desc_t req; | ||
595 | |||
596 | |||
597 | if (dev->dma == NULL) { | ||
598 | DRM_ERROR("dev->dma is NULL\n"); | ||
599 | return DRM_ERR(EFAULT); | ||
600 | } | ||
601 | |||
602 | /* The proper alignment is 0x100 for this mapping */ | ||
603 | err = drm_addmap(dev, 0, warp_size, _DRM_CONSISTENT, | ||
604 | _DRM_READ_ONLY, &dev_priv->warp); | ||
605 | if (err != 0) { | ||
606 | DRM_ERROR("Unable to create mapping for WARP microcode\n"); | ||
607 | return err; | ||
608 | } | ||
609 | |||
610 | /* Other than the bottom two bits being used to encode other | ||
611 | * information, there don't appear to be any restrictions on the | ||
612 | * alignment of the primary or secondary DMA buffers. | ||
613 | */ | ||
614 | |||
615 | for ( primary_size = dma_bs->primary_size | ||
616 | ; primary_size != 0 | ||
617 | ; primary_size >>= 1 ) { | ||
618 | /* The proper alignment for this mapping is 0x04 */ | ||
619 | err = drm_addmap(dev, 0, primary_size, _DRM_CONSISTENT, | ||
620 | _DRM_READ_ONLY, &dev_priv->primary); | ||
621 | if (!err) | ||
622 | break; | ||
623 | } | ||
624 | |||
625 | if (err != 0) { | ||
626 | DRM_ERROR("Unable to allocate primary DMA region\n"); | ||
627 | return DRM_ERR(ENOMEM); | ||
628 | } | ||
629 | |||
630 | if (dev_priv->primary->size != dma_bs->primary_size) { | ||
631 | DRM_INFO("Primary DMA buffer size reduced from %u to %u.\n", | ||
632 | dma_bs->primary_size, | ||
633 | (unsigned) dev_priv->primary->size); | ||
634 | dma_bs->primary_size = dev_priv->primary->size; | ||
635 | } | ||
636 | |||
637 | for ( bin_count = dma_bs->secondary_bin_count | ||
638 | ; bin_count > 0 | ||
639 | ; bin_count-- ) { | ||
640 | (void) memset( &req, 0, sizeof(req) ); | ||
641 | req.count = bin_count; | ||
642 | req.size = dma_bs->secondary_bin_size; | ||
643 | |||
644 | err = drm_addbufs_pci( dev, & req ); | ||
645 | if (!err) { | ||
646 | break; | ||
647 | } | ||
648 | } | ||
649 | |||
650 | if (bin_count == 0) { | ||
651 | DRM_ERROR("Unable to add secondary DMA buffers\n"); | ||
652 | return err; | ||
653 | } | ||
654 | |||
655 | if (bin_count != dma_bs->secondary_bin_count) { | ||
656 | DRM_INFO("Secondary PCI DMA buffer bin count reduced from %u " | ||
657 | "to %u.\n", dma_bs->secondary_bin_count, bin_count); | ||
658 | |||
659 | dma_bs->secondary_bin_count = bin_count; | ||
660 | } | ||
661 | |||
662 | dev_priv->dma_access = 0; | ||
663 | dev_priv->wagp_enable = 0; | ||
664 | |||
665 | dma_bs->agp_mode = 0; | ||
666 | |||
667 | DRM_INFO("Initialized card for PCI DMA.\n"); | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | |||
672 | static int mga_do_dma_bootstrap(drm_device_t * dev, | ||
673 | drm_mga_dma_bootstrap_t * dma_bs) | ||
674 | { | ||
675 | const int is_agp = (dma_bs->agp_mode != 0) && drm_device_is_agp(dev); | ||
676 | int err; | ||
677 | drm_mga_private_t * const dev_priv = | ||
678 | (drm_mga_private_t *) dev->dev_private; | ||
679 | |||
680 | |||
681 | dev_priv->used_new_dma_init = 1; | ||
682 | |||
683 | /* The first steps are the same for both PCI and AGP based DMA. Map | ||
684 | * the cards MMIO registers and map a status page. | ||
685 | */ | ||
686 | err = drm_addmap( dev, dev_priv->mmio_base, dev_priv->mmio_size, | ||
687 | _DRM_REGISTERS, _DRM_READ_ONLY, & dev_priv->mmio ); | ||
688 | if (err) { | ||
689 | DRM_ERROR("Unable to map MMIO region\n"); | ||
690 | return err; | ||
691 | } | ||
692 | |||
693 | |||
694 | err = drm_addmap( dev, 0, SAREA_MAX, _DRM_SHM, | ||
695 | _DRM_READ_ONLY | _DRM_LOCKED | _DRM_KERNEL, | ||
696 | & dev_priv->status ); | ||
697 | if (err) { | ||
698 | DRM_ERROR("Unable to map status region\n"); | ||
699 | return err; | ||
700 | } | ||
701 | |||
702 | |||
703 | /* The DMA initialization procedure is slightly different for PCI and | ||
704 | * AGP cards. AGP cards just allocate a large block of AGP memory and | ||
705 | * carve off portions of it for internal uses. The remaining memory | ||
706 | * is returned to user-mode to be used for AGP textures. | ||
707 | */ | ||
708 | if (is_agp) { | ||
709 | err = mga_do_agp_dma_bootstrap(dev, dma_bs); | ||
710 | } | ||
711 | |||
712 | /* If we attempted to initialize the card for AGP DMA but failed, | ||
713 | * clean-up any mess that may have been created. | ||
714 | */ | ||
715 | |||
716 | if (err) { | ||
717 | mga_do_cleanup_dma(dev); | ||
718 | } | ||
719 | |||
720 | |||
721 | /* Not only do we want to try and initialized PCI cards for PCI DMA, | ||
722 | * but we also try to initialized AGP cards that could not be | ||
723 | * initialized for AGP DMA. This covers the case where we have an AGP | ||
724 | * card in a system with an unsupported AGP chipset. In that case the | ||
725 | * card will be detected as AGP, but we won't be able to allocate any | ||
726 | * AGP memory, etc. | ||
727 | */ | ||
728 | |||
729 | if (!is_agp || err) { | ||
730 | err = mga_do_pci_dma_bootstrap(dev, dma_bs); | ||
731 | } | ||
732 | |||
733 | |||
734 | return err; | ||
735 | } | ||
736 | |||
737 | int mga_dma_bootstrap(DRM_IOCTL_ARGS) | ||
738 | { | ||
739 | DRM_DEVICE; | ||
740 | drm_mga_dma_bootstrap_t bootstrap; | ||
741 | int err; | ||
742 | |||
743 | |||
744 | DRM_COPY_FROM_USER_IOCTL(bootstrap, | ||
745 | (drm_mga_dma_bootstrap_t __user *) data, | ||
746 | sizeof(bootstrap)); | ||
747 | |||
748 | err = mga_do_dma_bootstrap(dev, & bootstrap); | ||
749 | if (! err) { | ||
750 | static const int modes[] = { 0, 1, 2, 2, 4, 4, 4, 4 }; | ||
751 | const drm_mga_private_t * const dev_priv = | ||
752 | (drm_mga_private_t *) dev->dev_private; | ||
753 | |||
754 | if (dev_priv->agp_textures != NULL) { | ||
755 | bootstrap.texture_handle = dev_priv->agp_textures->offset; | ||
756 | bootstrap.texture_size = dev_priv->agp_textures->size; | ||
757 | } | ||
758 | else { | ||
759 | bootstrap.texture_handle = 0; | ||
760 | bootstrap.texture_size = 0; | ||
761 | } | ||
762 | |||
763 | bootstrap.agp_mode = modes[ bootstrap.agp_mode & 0x07 ]; | ||
764 | if (DRM_COPY_TO_USER( (void __user *) data, & bootstrap, | ||
765 | sizeof(bootstrap))) { | ||
766 | err = DRM_ERR(EFAULT); | ||
767 | } | ||
768 | } | ||
769 | else { | ||
770 | mga_do_cleanup_dma(dev); | ||
771 | } | ||
772 | |||
773 | return err; | ||
774 | } | ||
775 | |||
399 | static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) | 776 | static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) |
400 | { | 777 | { |
401 | drm_mga_private_t *dev_priv; | 778 | drm_mga_private_t *dev_priv; |
402 | int ret; | 779 | int ret; |
403 | DRM_DEBUG( "\n" ); | 780 | DRM_DEBUG( "\n" ); |
404 | 781 | ||
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 | 782 | ||
411 | dev_priv->chipset = init->chipset; | 783 | dev_priv = dev->dev_private; |
412 | 784 | ||
413 | dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; | 785 | if (init->sgram) { |
414 | |||
415 | if ( init->sgram ) { | ||
416 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; | 786 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; |
417 | } else { | 787 | } else { |
418 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; | 788 | dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; |
@@ -436,88 +806,66 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) | |||
436 | 806 | ||
437 | DRM_GETSAREA(); | 807 | DRM_GETSAREA(); |
438 | 808 | ||
439 | if(!dev_priv->sarea) { | 809 | if (!dev_priv->sarea) { |
440 | DRM_ERROR( "failed to find sarea!\n" ); | 810 | 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); | 811 | return DRM_ERR(EINVAL); |
445 | } | 812 | } |
446 | 813 | ||
447 | dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); | 814 | if (! dev_priv->used_new_dma_init) { |
448 | if(!dev_priv->mmio) { | 815 | dev_priv->status = drm_core_findmap(dev, init->status_offset); |
449 | DRM_ERROR( "failed to find mmio region!\n" ); | 816 | if (!dev_priv->status) { |
450 | /* Assign dev_private so we can do cleanup. */ | 817 | DRM_ERROR("failed to find status page!\n"); |
451 | dev->dev_private = (void *)dev_priv; | 818 | return DRM_ERR(EINVAL); |
452 | mga_do_cleanup_dma( dev ); | 819 | } |
453 | return DRM_ERR(EINVAL); | 820 | dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); |
454 | } | 821 | if (!dev_priv->mmio) { |
455 | dev_priv->status = drm_core_findmap(dev, init->status_offset); | 822 | DRM_ERROR("failed to find mmio region!\n"); |
456 | if(!dev_priv->status) { | 823 | return DRM_ERR(EINVAL); |
457 | DRM_ERROR( "failed to find status page!\n" ); | 824 | } |
458 | /* Assign dev_private so we can do cleanup. */ | 825 | dev_priv->warp = drm_core_findmap(dev, init->warp_offset); |
459 | dev->dev_private = (void *)dev_priv; | 826 | if (!dev_priv->warp) { |
460 | mga_do_cleanup_dma( dev ); | 827 | DRM_ERROR("failed to find warp microcode region!\n"); |
461 | return DRM_ERR(EINVAL); | 828 | return DRM_ERR(EINVAL); |
462 | } | 829 | } |
463 | dev_priv->warp = drm_core_findmap(dev, init->warp_offset); | 830 | dev_priv->primary = drm_core_findmap(dev, init->primary_offset); |
464 | if(!dev_priv->warp) { | 831 | if (!dev_priv->primary) { |
465 | DRM_ERROR( "failed to find warp microcode region!\n" ); | 832 | DRM_ERROR("failed to find primary dma region!\n"); |
466 | /* Assign dev_private so we can do cleanup. */ | 833 | return DRM_ERR(EINVAL); |
467 | dev->dev_private = (void *)dev_priv; | 834 | } |
468 | mga_do_cleanup_dma( dev ); | 835 | dev->agp_buffer_token = init->buffers_offset; |
469 | return DRM_ERR(EINVAL); | 836 | dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); |
470 | } | 837 | if (!dev->agp_buffer_map) { |
471 | dev_priv->primary = drm_core_findmap(dev, init->primary_offset); | 838 | DRM_ERROR("failed to find dma buffer region!\n"); |
472 | if(!dev_priv->primary) { | 839 | return DRM_ERR(EINVAL); |
473 | DRM_ERROR( "failed to find primary dma region!\n" ); | 840 | } |
474 | /* Assign dev_private so we can do cleanup. */ | 841 | |
475 | dev->dev_private = (void *)dev_priv; | 842 | drm_core_ioremap(dev_priv->warp, dev); |
476 | mga_do_cleanup_dma( dev ); | 843 | drm_core_ioremap(dev_priv->primary, dev); |
477 | return DRM_ERR(EINVAL); | 844 | drm_core_ioremap(dev->agp_buffer_map, dev); |
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 | } | 845 | } |
487 | 846 | ||
488 | dev_priv->sarea_priv = | 847 | dev_priv->sarea_priv = |
489 | (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + | 848 | (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + |
490 | init->sarea_priv_offset); | 849 | init->sarea_priv_offset); |
491 | 850 | ||
492 | drm_core_ioremap( dev_priv->warp, dev ); | 851 | if (!dev_priv->warp->handle || |
493 | drm_core_ioremap( dev_priv->primary, dev ); | 852 | !dev_priv->primary->handle || |
494 | drm_core_ioremap( dev->agp_buffer_map, dev ); | 853 | ((dev_priv->dma_access != 0) && |
495 | 854 | ((dev->agp_buffer_map == NULL) || | |
496 | if(!dev_priv->warp->handle || | 855 | (dev->agp_buffer_map->handle == NULL)))) { |
497 | !dev_priv->primary->handle || | 856 | 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); | 857 | return DRM_ERR(ENOMEM); |
504 | } | 858 | } |
505 | 859 | ||
506 | ret = mga_warp_install_microcode( dev_priv ); | 860 | ret = mga_warp_install_microcode(dev_priv); |
507 | if ( ret < 0 ) { | 861 | if (ret < 0) { |
508 | DRM_ERROR( "failed to install WARP ucode!\n" ); | 862 | 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; | 863 | return ret; |
513 | } | 864 | } |
514 | 865 | ||
515 | ret = mga_warp_init( dev_priv ); | 866 | ret = mga_warp_init(dev_priv); |
516 | if ( ret < 0 ) { | 867 | if (ret < 0) { |
517 | DRM_ERROR( "failed to init WARP engine!\n" ); | 868 | 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; | 869 | return ret; |
522 | } | 870 | } |
523 | 871 | ||
@@ -557,22 +905,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; | 905 | dev_priv->sarea_priv->last_frame.head = 0; |
558 | dev_priv->sarea_priv->last_frame.wrap = 0; | 906 | dev_priv->sarea_priv->last_frame.wrap = 0; |
559 | 907 | ||
560 | if ( mga_freelist_init( dev, dev_priv ) < 0 ) { | 908 | if (mga_freelist_init(dev, dev_priv) < 0) { |
561 | DRM_ERROR( "could not initialize freelist\n" ); | 909 | 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); | 910 | return DRM_ERR(ENOMEM); |
566 | } | 911 | } |
567 | 912 | ||
568 | /* Make dev_private visable to others. */ | ||
569 | dev->dev_private = (void *)dev_priv; | ||
570 | return 0; | 913 | return 0; |
571 | } | 914 | } |
572 | 915 | ||
573 | static int mga_do_cleanup_dma( drm_device_t *dev ) | 916 | static int mga_do_cleanup_dma( drm_device_t *dev ) |
574 | { | 917 | { |
575 | DRM_DEBUG( "\n" ); | 918 | int err = 0; |
919 | DRM_DEBUG("\n"); | ||
576 | 920 | ||
577 | /* Make sure interrupts are disabled here because the uninstall ioctl | 921 | /* Make sure interrupts are disabled here because the uninstall ioctl |
578 | * may not have been called from userspace and after dev_private | 922 | * may not have been called from userspace and after dev_private |
@@ -583,37 +927,73 @@ static int mga_do_cleanup_dma( drm_device_t *dev ) | |||
583 | if ( dev->dev_private ) { | 927 | if ( dev->dev_private ) { |
584 | drm_mga_private_t *dev_priv = dev->dev_private; | 928 | drm_mga_private_t *dev_priv = dev->dev_private; |
585 | 929 | ||
586 | if ( dev_priv->warp != NULL ) | 930 | if ((dev_priv->warp != NULL) |
587 | drm_core_ioremapfree( dev_priv->warp, dev ); | 931 | && (dev_priv->mmio->type != _DRM_CONSISTENT)) |
588 | if ( dev_priv->primary != NULL ) | 932 | drm_core_ioremapfree(dev_priv->warp, dev); |
589 | drm_core_ioremapfree( dev_priv->primary, dev ); | 933 | |
590 | if ( dev->agp_buffer_map != NULL ) | 934 | if ((dev_priv->primary != NULL) |
591 | drm_core_ioremapfree( dev->agp_buffer_map, dev ); | 935 | && (dev_priv->primary->type != _DRM_CONSISTENT)) |
936 | drm_core_ioremapfree(dev_priv->primary, dev); | ||
937 | |||
938 | if (dev->agp_buffer_map != NULL) | ||
939 | drm_core_ioremapfree(dev->agp_buffer_map, dev); | ||
592 | 940 | ||
593 | if ( dev_priv->head != NULL ) { | 941 | if (dev_priv->used_new_dma_init) { |
594 | mga_freelist_cleanup( dev ); | 942 | #if __OS_HAS_AGP |
943 | if (dev_priv->agp_mem != NULL) { | ||
944 | dev_priv->agp_textures = NULL; | ||
945 | drm_unbind_agp(dev_priv->agp_mem); | ||
946 | |||
947 | drm_free_agp(dev_priv->agp_mem, dev_priv->agp_pages); | ||
948 | dev_priv->agp_pages = 0; | ||
949 | dev_priv->agp_mem = NULL; | ||
950 | } | ||
951 | |||
952 | if ((dev->agp != NULL) && dev->agp->acquired) { | ||
953 | err = drm_agp_release(dev); | ||
954 | } | ||
955 | #endif | ||
956 | dev_priv->used_new_dma_init = 0; | ||
595 | } | 957 | } |
596 | 958 | ||
597 | drm_free( dev->dev_private, sizeof(drm_mga_private_t), | 959 | dev_priv->warp = NULL; |
598 | DRM_MEM_DRIVER ); | 960 | dev_priv->primary = NULL; |
599 | dev->dev_private = NULL; | 961 | dev_priv->mmio = NULL; |
962 | dev_priv->status = NULL; | ||
963 | dev_priv->sarea = NULL; | ||
964 | dev_priv->sarea_priv = NULL; | ||
965 | dev->agp_buffer_map = NULL; | ||
966 | |||
967 | memset(&dev_priv->prim, 0, sizeof(dev_priv->prim)); | ||
968 | dev_priv->warp_pipe = 0; | ||
969 | memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys)); | ||
970 | |||
971 | if (dev_priv->head != NULL) { | ||
972 | mga_freelist_cleanup(dev); | ||
973 | } | ||
600 | } | 974 | } |
601 | 975 | ||
602 | return 0; | 976 | return err; |
603 | } | 977 | } |
604 | 978 | ||
605 | int mga_dma_init( DRM_IOCTL_ARGS ) | 979 | int mga_dma_init( DRM_IOCTL_ARGS ) |
606 | { | 980 | { |
607 | DRM_DEVICE; | 981 | DRM_DEVICE; |
608 | drm_mga_init_t init; | 982 | drm_mga_init_t init; |
983 | int err; | ||
609 | 984 | ||
610 | LOCK_TEST_WITH_RETURN( dev, filp ); | 985 | LOCK_TEST_WITH_RETURN( dev, filp ); |
611 | 986 | ||
612 | DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t __user *)data, sizeof(init) ); | 987 | DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data, |
988 | sizeof(init)); | ||
613 | 989 | ||
614 | switch ( init.func ) { | 990 | switch ( init.func ) { |
615 | case MGA_INIT_DMA: | 991 | case MGA_INIT_DMA: |
616 | return mga_do_init_dma( dev, &init ); | 992 | err = mga_do_init_dma(dev, &init); |
993 | if (err) { | ||
994 | (void) mga_do_cleanup_dma(dev); | ||
995 | } | ||
996 | return err; | ||
617 | case MGA_CLEANUP_DMA: | 997 | case MGA_CLEANUP_DMA: |
618 | return mga_do_cleanup_dma( dev ); | 998 | return mga_do_cleanup_dma( dev ); |
619 | } | 999 | } |
@@ -742,7 +1122,21 @@ int mga_dma_buffers( DRM_IOCTL_ARGS ) | |||
742 | return ret; | 1122 | return ret; |
743 | } | 1123 | } |
744 | 1124 | ||
745 | void mga_driver_pretakedown(drm_device_t *dev) | 1125 | /** |
1126 | * Called just before the module is unloaded. | ||
1127 | */ | ||
1128 | int mga_driver_postcleanup(drm_device_t * dev) | ||
1129 | { | ||
1130 | drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER); | ||
1131 | dev->dev_private = NULL; | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | /** | ||
1137 | * Called when the last opener of the device is closed. | ||
1138 | */ | ||
1139 | void mga_driver_pretakedown(drm_device_t * dev) | ||
746 | { | 1140 | { |
747 | mga_do_cleanup_dma( dev ); | 1141 | mga_do_cleanup_dma( dev ); |
748 | } | 1142 | } |