diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/Makefile.kernel | 4 | ||||
-rw-r--r-- | linux/ati_pcigart.h | 95 | ||||
-rw-r--r-- | linux/drmP.h | 12 | ||||
-rw-r--r-- | linux/drm_ioctl.h | 4 | ||||
-rw-r--r-- | linux/drm_scatter.h | 42 | ||||
-rw-r--r-- | linux/drm_vm.h | 71 | ||||
-rw-r--r-- | linux/mga_drv.h | 18 | ||||
-rw-r--r-- | linux/r128_cce.c | 20 | ||||
-rw-r--r-- | linux/r128_drv.h | 1 | ||||
-rw-r--r-- | linux/radeon_cp.c | 21 | ||||
-rw-r--r-- | linux/radeon_drv.h | 1 |
11 files changed, 249 insertions, 40 deletions
diff --git a/linux/Makefile.kernel b/linux/Makefile.kernel index 97b507ee..e2630989 100644 --- a/linux/Makefile.kernel +++ b/linux/Makefile.kernel @@ -3,9 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. O_TARGET := drm.o -export-objs := gamma_drv.o tdfx_drv.o r128_drv.o mga_drv.o i810_drv.o \ - ffb_drv.o -list-multi := gamma.o tdfx.o r128.o mga.o i810.o ffb.o +list-multi := gamma.o tdfx.o r128.o mga.o i810.o ffb.o radeon.o gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o diff --git a/linux/ati_pcigart.h b/linux/ati_pcigart.h index 93c5148f..99d17ee7 100644 --- a/linux/ati_pcigart.h +++ b/linux/ati_pcigart.h @@ -72,8 +72,6 @@ static void DRM(ati_free_pcigart_table)( unsigned long address ) int i; DRM_DEBUG( "%s\n", __FUNCTION__ ); - if ( !address ) return; - page = virt_to_page( address ); for ( i = 0 ; i <= ATI_PCIGART_TABLE_PAGES ; i++, page++ ) { @@ -84,24 +82,45 @@ static void DRM(ati_free_pcigart_table)( unsigned long address ) free_pages( address, ATI_PCIGART_TABLE_ORDER ); } -unsigned long DRM(ati_pcigart_init)( drm_device_t *dev ) +int DRM(ati_pcigart_init)( drm_device_t *dev, + unsigned long *addr, + dma_addr_t *bus_addr) { drm_sg_mem_t *entry = dev->sg; - unsigned long address; + unsigned long address = 0; unsigned long pages; - u32 *pci_gart, page_base; - int i, j; + u32 *pci_gart, page_base, bus_address = 0; + int i, j, ret = 0; if ( !entry ) { DRM_ERROR( "no scatter/gather memory!\n" ); - return 0; + goto done; } address = DRM(ati_alloc_pcigart_table)(); if ( !address ) { DRM_ERROR( "cannot allocate PCI GART page!\n" ); - return 0; + goto done; + } + +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + if ( !dev->pdev ) { + DRM_ERROR( "PCI device unknown!\n" ); + goto done; + } + + bus_address = pci_map_single(dev->pdev, (void *)address, + ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, + PCI_DMA_TODEVICE); + if (bus_address == 0) { + DRM_ERROR( "unable to map PCIGART pages!\n" ); + DRM(ati_free_pcigart_table)( address ); + address = 0; + goto done; } +#else + bus_address = virt_to_bus( (void *)address ); +#endif pci_gart = (u32 *)address; @@ -111,28 +130,78 @@ unsigned long DRM(ati_pcigart_init)( drm_device_t *dev ) memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) ); for ( i = 0 ; i < pages ; i++ ) { +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + /* we need to support large memory configurations */ + entry->busaddr[i] = pci_map_single(dev->pdev, + entry->pagelist[i]->virtual, + PAGE_SIZE, + PCI_DMA_TODEVICE); + if (entry->busaddr[i] == 0) { + DRM_ERROR( "unable to map PCIGART pages!\n" ); + DRM(ati_pcigart_cleanup)( dev, address, bus_address ); + address = 0; + bus_address = 0; + goto done; + } + page_base = (u32) entry->busaddr[i]; +#else page_base = virt_to_bus( entry->pagelist[i]->virtual ); +#endif for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { *pci_gart++ = cpu_to_le32( page_base ); page_base += ATI_PCIGART_PAGE_SIZE; } } + ret = 1; + #if __i386__ asm volatile ( "wbinvd" ::: "memory" ); #else mb(); #endif - return address; +done: + *addr = address; + *bus_addr = bus_address; + return ret; } -int DRM(ati_pcigart_cleanup)( unsigned long address ) +int DRM(ati_pcigart_cleanup)( drm_device_t *dev, + unsigned long addr, + dma_addr_t bus_addr) { +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + drm_sg_mem_t *entry = dev->sg; + unsigned long pages; + int i; - if ( address ) { - DRM(ati_free_pcigart_table)( address ); + /* we need to support large memory configurations */ + if ( !entry ) { + DRM_ERROR( "no scatter/gather memory!\n" ); + return 0; + } + + if ( bus_addr ) { + pci_unmap_single(dev->pdev, bus_addr, + ATI_PCIGART_TABLE_PAGES * PAGE_SIZE, + PCI_DMA_TODEVICE); + + pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES ) + ? entry->pages : ATI_MAX_PCIGART_PAGES; + + for ( i = 0 ; i < pages ; i++ ) { + if ( !entry->busaddr[i] ) break; + pci_unmap_single(dev->pdev, entry->busaddr[i], + PAGE_SIZE, PCI_DMA_TODEVICE); + } + } + +#endif + + if ( addr ) { + DRM(ati_free_pcigart_table)( addr ); } - return 0; + return 1; } diff --git a/linux/drmP.h b/linux/drmP.h index 3b282685..8e2ecd16 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -624,6 +624,9 @@ typedef struct drm_sg_mem { void *virtual; int pages; struct page **pagelist; +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + dma_addr_t *busaddr; +#endif } drm_sg_mem_t; typedef struct drm_sigdata { @@ -715,6 +718,7 @@ typedef struct drm_device { drm_agp_head_t *agp; #endif #ifdef __alpha__ + struct pci_dev *pdev; #if LINUX_VERSION_CODE < 0x020403 struct pci_controler *hose; #else @@ -1018,8 +1022,12 @@ extern int DRM(sg_free)(struct inode *inode, struct file *filp, #endif /* ATI PCIGART support (ati_pcigart.h) */ -extern unsigned long DRM(ati_pcigart_init)(drm_device_t *dev); -extern int DRM(ati_pcigart_cleanup)(unsigned long address); +extern int DRM(ati_pcigart_init)(drm_device_t *dev, + unsigned long *addr, + dma_addr_t *bus_addr); +extern int DRM(ati_pcigart_cleanup)(drm_device_t *dev, + unsigned long addr, + dma_addr_t bus_addr); #endif /* __KERNEL__ */ #endif diff --git a/linux/drm_ioctl.h b/linux/drm_ioctl.h index 4712cbd3..e0c87d2d 100644 --- a/linux/drm_ioctl.h +++ b/linux/drm_ioctl.h @@ -114,8 +114,10 @@ int DRM(setunique)(struct inode *inode, struct file *filp, if (*p) break; pci_dev = pci_find_slot(b, PCI_DEVFN(d,f)); - if (pci_dev) + if (pci_dev) { + dev->pdev = pci_dev; dev->hose = pci_dev->sysdata; + } } while(0); #endif diff --git a/linux/drm_scatter.h b/linux/drm_scatter.h index c1c9f7e8..5654c8cb 100644 --- a/linux/drm_scatter.h +++ b/linux/drm_scatter.h @@ -47,12 +47,17 @@ void DRM(sg_cleanup)( drm_sg_mem_t *entry ) vfree( entry->virtual ); +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + DRM(free)( entry->busaddr, + entry->pages * sizeof(*entry->busaddr), + DRM_MEM_PAGES ); +#endif DRM(free)( entry->pagelist, - entry->pages * sizeof(*entry->pagelist), - DRM_MEM_PAGES ); + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); DRM(free)( entry, - sizeof(*entry), - DRM_MEM_SGLISTS ); + sizeof(*entry), + DRM_MEM_SGLISTS ); } int DRM(sg_alloc)( struct inode *inode, struct file *filp, @@ -93,16 +98,35 @@ int DRM(sg_alloc)( struct inode *inode, struct file *filp, DRM(free)( entry, sizeof(*entry), DRM_MEM_SGLISTS ); return -ENOMEM; } - memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist)); + +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr), + DRM_MEM_PAGES ); + if ( !entry->busaddr ) { + DRM(free)( entry->pagelist, + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + DRM(free)( entry, + sizeof(*entry), + DRM_MEM_SGLISTS ); + return -ENOMEM; + } + memset( (void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr) ); +#endif entry->virtual = vmalloc_32( pages << PAGE_SHIFT ); if ( !entry->virtual ) { +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + DRM(free)( entry->busaddr, + entry->pages * sizeof(*entry->busaddr), + DRM_MEM_PAGES ); +#endif DRM(free)( entry->pagelist, - entry->pages * sizeof(*entry->pagelist), - DRM_MEM_PAGES ); + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); DRM(free)( entry, - sizeof(*entry), - DRM_MEM_SGLISTS ); + sizeof(*entry), + DRM_MEM_SGLISTS ); return -ENOMEM; } diff --git a/linux/drm_vm.h b/linux/drm_vm.h index d8e77f79..2a5ee146 100644 --- a/linux/drm_vm.h +++ b/linux/drm_vm.h @@ -67,6 +67,64 @@ struct page *DRM(vm_nopage)(struct vm_area_struct *vma, int write_access) #endif { +#if defined(__alpha__) && __REALLY_HAVE_AGP + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; + drm_map_t *map = NULL; + drm_map_list_t *r_list; + struct list_head *list; + + /* + * Find the right map + */ + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *)list; + map = r_list->map; + if (!map) continue; + if (map->offset == VM_OFFSET(vma)) break; + } + + if (map && map->type == _DRM_AGP) { + unsigned long offset = address - vma->vm_start; + unsigned long baddr = VM_OFFSET(vma) + offset; + struct drm_agp_mem *agpmem; + struct page *page; + + /* + * Make it a bus-relative address + */ + baddr -= dev->hose->mem_space->start; + + /* + * It's AGP memory - find the real physical page to map + */ + for(agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) { + if (agpmem->bound <= baddr && + agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) + break; + } + + if (!agpmem) { + /* + * Oops - no memory found + */ + return NOPAGE_SIGBUS; /* couldn't find it */ + } + + /* + * Get the page, inc the use count, and return it + */ + offset = (baddr - agpmem->bound) >> PAGE_SHIFT; + agpmem->memory->memory[offset] &= ~1UL; /* HACK */ + page = virt_to_page(__va(agpmem->memory->memory[offset])); +#if 0 +DRM_ERROR("baddr = 0x%lx page = 0x%lx, offset = 0x%lx\n", + baddr, __va(agpmem->memory->memory[offset]), offset); +#endif + get_page(page); + return page; + } +#endif return NOPAGE_SIGBUS; /* Disallow mremap */ } @@ -434,9 +492,20 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) } switch (map->type) { + case _DRM_AGP: +#if defined(__alpha__) + /* + * On Alpha we can't talk to bus dma address from the + * CPU, so for memory of type DRM_AGP, we'll deal with + * sorting out the real physical pages and mappings + * in nopage() + */ + vma->vm_ops = &DRM(vm_ops); + break; +#endif + /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: - case _DRM_AGP: if (VM_OFFSET(vma) >= __pa(high_memory)) { #if defined(__i386__) if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { diff --git a/linux/mga_drv.h b/linux/mga_drv.h index bb3d21b4..ba2602e7 100644 --- a/linux/mga_drv.h +++ b/linux/mga_drv.h @@ -145,14 +145,28 @@ extern int mga_warp_init( drm_mga_private_t *dev_priv ); #define mga_flush_write_combine() mb() -#define MGA_BASE( reg ) ((u32)(dev_priv->mmio->handle)) +#define MGA_BASE( reg ) ((unsigned long)(dev_priv->mmio->handle)) #define MGA_ADDR( reg ) (MGA_BASE(reg) + reg) #define MGA_DEREF( reg ) *(volatile u32 *)MGA_ADDR( reg ) +#define MGA_DEREF8( reg ) *(volatile u8 *)MGA_ADDR( reg ) + +#ifdef __alpha__ +#define MGA_READ( reg ) (_MGA_READ((u32 *)MGA_ADDR(reg))) +#define MGA_WRITE( reg, val ) do { wmb(); MGA_DEREF( reg ) = val; } while (0) +#define MGA_WRITE8( reg, val ) do { wmb(); MGA_DEREF8( reg ) = val; } while (0) + +static inline u32 _MGA_READ(u32 *addr) +{ + mb(); + return *(volatile u32 *)addr; +} + +#else #define MGA_READ( reg ) MGA_DEREF( reg ) #define MGA_WRITE( reg, val ) do { MGA_DEREF( reg ) = val; } while (0) -#define MGA_DEREF8( reg ) *(volatile u8 *)MGA_ADDR( reg ) #define MGA_WRITE8( reg, val ) do { MGA_DEREF8( reg ) = val; } while (0) +#endif #define DWGREG0 0x1c00 #define DWGREG0_END 0x1dff diff --git a/linux/r128_cce.c b/linux/r128_cce.c index d04473b9..24b6de8d 100644 --- a/linux/r128_cce.c +++ b/linux/r128_cce.c @@ -350,12 +350,20 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev, tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; page_ofs = tmp_ofs >> PAGE_SHIFT; +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, + entry->busaddr[page_ofs]); + DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n", + entry->busaddr[page_ofs], + entry->handle + tmp_ofs ); +#else R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, virt_to_bus(entry->pagelist[page_ofs]->virtual)); DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n", virt_to_bus(entry->pagelist[page_ofs]->virtual), entry->handle + tmp_ofs ); +#endif } /* Set watermark control */ @@ -599,15 +607,14 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) dev_priv->sarea_priv->last_dispatch ); if ( dev_priv->is_pci ) { - dev_priv->phys_pci_gart = DRM(ati_pcigart_init)( dev ); - if ( !dev_priv->phys_pci_gart ) { + if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, + &dev_priv->bus_pci_gart) ) { DRM_ERROR( "failed to init PCI GART!\n" ); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); return -ENOMEM; } - R128_WRITE( R128_PCI_GART_PAGE, - virt_to_bus( (void *)dev_priv->phys_pci_gart ) ); + R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart ); } r128_cce_init_ring_buffer( dev, dev_priv ); @@ -629,6 +636,11 @@ int r128_do_cleanup_cce( drm_device_t *dev ) DRM_IOREMAPFREE( dev_priv->cce_ring ); DRM_IOREMAPFREE( dev_priv->ring_rptr ); DRM_IOREMAPFREE( dev_priv->buffers ); + } else { + if (!DRM(ati_pcigart_cleanup)( dev, + dev_priv->phys_pci_gart, + dev_priv->bus_pci_gart )) + DRM_ERROR( "failed to cleanup PCI GART!\n" ); } DRM(free)( dev->dev_private, sizeof(drm_r128_private_t), diff --git a/linux/r128_drv.h b/linux/r128_drv.h index 0ef94e45..4b46db08 100644 --- a/linux/r128_drv.h +++ b/linux/r128_drv.h @@ -72,6 +72,7 @@ typedef struct drm_r128_private { int usec_timeout; int is_pci; unsigned long phys_pci_gart; + dma_addr_t bus_pci_gart; unsigned long cce_buffers_offset; atomic_t idle_count; diff --git a/linux/radeon_cp.c b/linux/radeon_cp.c index a7127b2b..51596c7b 100644 --- a/linux/radeon_cp.c +++ b/linux/radeon_cp.c @@ -622,13 +622,20 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; page_ofs = tmp_ofs >> PAGE_SHIFT; - +#if defined(__alpha__) && (LINUX_VERSION_CODE >= 0x020400) + RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, + entry->busaddr[page_ofs]); + DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n", + entry->busaddr[page_ofs], + entry->handle + tmp_ofs ); +#else RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, virt_to_bus(entry->pagelist[page_ofs]->virtual)); DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n", virt_to_bus(entry->pagelist[page_ofs]->virtual), entry->handle + tmp_ofs ); +#endif } /* Set ring buffer size */ @@ -929,8 +936,8 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->sarea_priv->last_clear ); if ( dev_priv->is_pci ) { - dev_priv->phys_pci_gart = DRM(ati_pcigart_init)( dev ); - if ( !dev_priv->phys_pci_gart ) { + if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, + &dev_priv->bus_pci_gart)) { DRM_ERROR( "failed to init PCI GART!\n" ); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); @@ -944,8 +951,7 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) /* set PCI GART page-table base address */ - RADEON_WRITE( RADEON_AIC_PT_BASE, - virt_to_bus( (void *)dev_priv->phys_pci_gart ) ); + RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart ); /* set address range for PCI address translate */ @@ -990,6 +996,11 @@ int radeon_do_cleanup_cp( drm_device_t *dev ) DRM_IOREMAPFREE( dev_priv->cp_ring ); DRM_IOREMAPFREE( dev_priv->ring_rptr ); DRM_IOREMAPFREE( dev_priv->buffers ); + } else { + if (!DRM(ati_pcigart_cleanup)( dev, + dev_priv->phys_pci_gart, + dev_priv->bus_pci_gart )) + DRM_ERROR( "failed to cleanup PCI GART!\n" ); } DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t), diff --git a/linux/radeon_drv.h b/linux/radeon_drv.h index 4217beee..5afea7d1 100644 --- a/linux/radeon_drv.h +++ b/linux/radeon_drv.h @@ -84,6 +84,7 @@ typedef struct drm_radeon_private { int usec_timeout; int is_pci; unsigned long phys_pci_gart; + dma_addr_t bus_pci_gart; atomic_t idle_count; |