From 5d6ddbca26d695561fb1d08d798a0cc254b805e7 Mon Sep 17 00:00:00 2001 From: Kevin E Martin Date: Thu, 5 Apr 2001 22:16:12 +0000 Subject: Merged ati-pcigart-1-0-0 --- linux-core/ati_pcigart.c | 138 ++++++++++++++++++++++++++++ linux-core/drmP.h | 77 ++++++++++++++-- linux-core/drm_agpsupport.c | 21 +++-- linux-core/drm_bufs.c | 182 +++++++++++++++++++++++++++++++++++- linux-core/drm_drv.c | 14 +++ linux-core/drm_fops.c | 15 +++ linux-core/drm_init.c | 4 + linux-core/drm_ioctl.c | 21 +++++ linux-core/drm_memory.h | 1 + linux-core/drm_scatter.c | 218 ++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_vm.c | 74 ++++++++++++++- linux-core/r128_drv.c | 6 +- linux-core/radeon_drv.c | 6 +- 13 files changed, 752 insertions(+), 25 deletions(-) create mode 100644 linux-core/ati_pcigart.c create mode 100644 linux-core/drm_scatter.c (limited to 'linux-core') diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c new file mode 100644 index 00000000..93c5148f --- /dev/null +++ b/linux-core/ati_pcigart.c @@ -0,0 +1,138 @@ +/* ati_pcigart.h -- ATI PCI GART support -*- linux-c -*- + * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com + * + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Gareth Hughes + */ + +#define __NO_VERSION__ +#include "drmP.h" + +#if PAGE_SIZE == 8192 +# define ATI_PCIGART_TABLE_ORDER 2 +# define ATI_PCIGART_TABLE_PAGES (1 << 2) +#elif PAGE_SIZE == 4096 +# define ATI_PCIGART_TABLE_ORDER 3 +# define ATI_PCIGART_TABLE_PAGES (1 << 3) +#elif +# error - PAGE_SIZE not 8K or 4K +#endif + +# define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture, 4K pages */ +# define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */ + +static unsigned long DRM(ati_alloc_pcigart_table)( void ) +{ + unsigned long address; + struct page *page; + int i; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + address = __get_free_pages( GFP_KERNEL, ATI_PCIGART_TABLE_ORDER ); + if ( address == 0UL ) { + return 0; + } + + page = virt_to_page( address ); + + for ( i = 0 ; i <= ATI_PCIGART_TABLE_PAGES ; i++, page++ ) { + atomic_inc( &page->count ); + SetPageReserved( page ); + } + + DRM_DEBUG( "%s: returning 0x%08lx\n", __FUNCTION__, address ); + return address; +} + +static void DRM(ati_free_pcigart_table)( unsigned long address ) +{ + struct page *page; + 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++ ) { + atomic_dec( &page->count ); + ClearPageReserved( page ); + } + + free_pages( address, ATI_PCIGART_TABLE_ORDER ); +} + +unsigned long DRM(ati_pcigart_init)( drm_device_t *dev ) +{ + drm_sg_mem_t *entry = dev->sg; + unsigned long address; + unsigned long pages; + u32 *pci_gart, page_base; + int i, j; + + if ( !entry ) { + DRM_ERROR( "no scatter/gather memory!\n" ); + return 0; + } + + address = DRM(ati_alloc_pcigart_table)(); + if ( !address ) { + DRM_ERROR( "cannot allocate PCI GART page!\n" ); + return 0; + } + + pci_gart = (u32 *)address; + + pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES ) + ? entry->pages : ATI_MAX_PCIGART_PAGES; + + memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) ); + + for ( i = 0 ; i < pages ; i++ ) { + page_base = virt_to_bus( entry->pagelist[i]->virtual ); + for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { + *pci_gart++ = cpu_to_le32( page_base ); + page_base += ATI_PCIGART_PAGE_SIZE; + } + } + +#if __i386__ + asm volatile ( "wbinvd" ::: "memory" ); +#else + mb(); +#endif + + return address; +} + +int DRM(ati_pcigart_cleanup)( unsigned long address ) +{ + + if ( address ) { + DRM(ati_free_pcigart_table)( address ); + } + + return 0; +} diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 274e318a..085d1cb8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -53,7 +53,7 @@ #include #include /* For (un)lock_kernel */ #include -#ifdef __alpha__ +#if defined(__alpha__) || defined(__powerpc__) #include /* For pte_wrprotect */ #endif #include @@ -145,6 +145,7 @@ #define DRM_MEM_BOUNDAGP 17 #define DRM_MEM_CTXBITMAP 18 #define DRM_MEM_STUB 19 +#define DRM_MEM_SGLISTS 20 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) @@ -199,7 +200,7 @@ __cmpxchg_u32(volatile int *m, int old, int new) unsigned long prev, cmp; __asm__ __volatile__( - "1: ldl_l %0,%2\n" + "1: ldl_l %0,%5\n" " cmpeq %0,%3,%1\n" " beq %1,2f\n" " mov %4,%1\n" @@ -210,7 +211,8 @@ __cmpxchg_u32(volatile int *m, int old, int new) "3: br 1b\n" ".previous" : "=&r"(prev), "=&r"(cmp), "=m"(*m) - : "r"((long) old), "r"(new), "m"(*m)); + : "r"((long) old), "r"(new), "m"(*m) + : "memory" ); return prev; } @@ -221,7 +223,7 @@ __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) unsigned long prev, cmp; __asm__ __volatile__( - "1: ldq_l %0,%2\n" + "1: ldq_l %0,%5\n" " cmpeq %0,%3,%1\n" " beq %1,2f\n" " mov %4,%1\n" @@ -232,7 +234,8 @@ __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) "3: br 1b\n" ".previous" : "=&r"(prev), "=&r"(cmp), "=m"(*m) - : "r"((long) old), "r"(new), "m"(*m)); + : "r"((long) old), "r"(new), "m"(*m) + : "memory" ); return prev; } @@ -284,12 +287,43 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, return old; } +#elif defined(__powerpc__) +extern void __cmpxchg_called_with_bad_pointer(void); +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, + unsigned long new, int size) +{ + unsigned long prev; + + switch (size) { + case 4: + __asm__ __volatile__( + "sync;" + "0: lwarx %0,0,%1 ;" + " cmpl 0,%0,%3;" + " bne 1f;" + " stwcx. %2,0,%1;" + " bne- 0b;" + "1: " + "sync;" + : "=&r"(prev) + : "r"(ptr), "r"(new), "r"(old) + : "cr0", "memory"); + return prev; + } + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#endif /* i386, powerpc & alpha */ + +#ifndef __alpha__ #define cmpxchg(ptr,o,n) \ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \ (unsigned long)(n),sizeof(*(ptr)))) -#endif /* i386 & alpha */ #endif +#endif /* !__HAVE_ARCH_CMPXCHG */ + /* Macros to make printk easier */ #define DRM_ERROR(fmt, arg...) \ printk(KERN_ERR "[" DRM_NAME ":" __FUNCTION__ "] *ERROR* " fmt , ##arg) @@ -547,7 +581,8 @@ typedef struct drm_device_dma { unsigned long *pagelist; unsigned long byte_count; enum { - _DRM_DMA_USE_AGP = 0x01 + _DRM_DMA_USE_AGP = 0x01, + _DRM_DMA_USE_SG = 0x02 } flags; /* DMA support */ @@ -579,6 +614,13 @@ typedef struct drm_agp_head { } drm_agp_head_t; #endif +typedef struct drm_sg_mem { + unsigned long handle; + void *virtual; + int pages; + struct page **pagelist; +} drm_sg_mem_t; + typedef struct drm_sigdata { int context; drm_hw_lock_t *lock; @@ -667,6 +709,10 @@ typedef struct drm_device { #if __REALLY_HAVE_AGP drm_agp_head_t *agp; #endif +#ifdef __alpha__ + struct pci_controler *hose; +#endif + drm_sg_mem_t *sg; /* Scatter gather memory */ unsigned long *ctx_bitmap; void *dev_private; drm_sigdata_t sigdata; /* For block_all_signals */ @@ -718,6 +764,9 @@ extern unsigned long DRM(vm_shm_nopage)(struct vm_area_struct *vma, extern unsigned long DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access); +extern unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma, + unsigned long address, + int write_access); #else /* Return type changed in 2.3.23 */ extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma, @@ -729,6 +778,9 @@ extern struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, extern struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access); +extern struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma, + unsigned long address, + int write_access); #endif extern void DRM(vm_open)(struct vm_area_struct *vma); extern void DRM(vm_close)(struct vm_area_struct *vma); @@ -947,5 +999,16 @@ extern int DRM(proc_cleanup)(int minor, struct proc_dir_entry *root, struct proc_dir_entry *dev_root); + /* Scatter Gather Support (drm_scatter.h) */ +extern void DRM(sg_cleanup)(drm_sg_mem_t *entry); +extern int DRM(sg_alloc)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(sg_free)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + + /* 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); + #endif /* __KERNEL__ */ #endif diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index dfd0d8fc..9b056c75 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -52,7 +52,8 @@ int DRM(agp_info)(struct inode *inode, struct file *filp, agp_kern_info *kern; drm_agp_info_t info; - if (!dev->agp->acquired || !drm_agp->copy_info) return -EINVAL; + if (!dev->agp || !dev->agp->acquired || !drm_agp->copy_info) + return -EINVAL; kern = &dev->agp->agp_info; info.agp_version_major = kern->version.major; @@ -77,7 +78,8 @@ int DRM(agp_acquire)(struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; int retcode; - if (!dev->agp|| dev->agp->acquired || !drm_agp->acquire) return -EINVAL; + if (!dev->agp || dev->agp->acquired || !drm_agp->acquire) + return -EINVAL; if ((retcode = drm_agp->acquire())) return retcode; dev->agp->acquired = 1; return 0; @@ -89,7 +91,8 @@ int DRM(agp_release)(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; - if (!dev->agp->acquired || !drm_agp->release) return -EINVAL; + if (!dev->agp || !dev->agp->acquired || !drm_agp->release) + return -EINVAL; drm_agp->release(); dev->agp->acquired = 0; return 0; @@ -108,7 +111,8 @@ int DRM(agp_enable)(struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_agp_mode_t mode; - if (!dev->agp->acquired || !drm_agp->enable) return -EINVAL; + if (!dev->agp || !dev->agp->acquired || !drm_agp->enable) + return -EINVAL; if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode))) return -EFAULT; @@ -131,7 +135,7 @@ int DRM(agp_alloc)(struct inode *inode, struct file *filp, unsigned long pages; u32 type; - if (!dev->agp->acquired) return -EINVAL; + if (!dev->agp || !dev->agp->acquired) return -EINVAL; if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) return -EFAULT; if (!(entry = DRM(alloc)(sizeof(*entry), DRM_MEM_AGPLISTS))) @@ -188,7 +192,7 @@ int DRM(agp_unbind)(struct inode *inode, struct file *filp, drm_agp_binding_t request; drm_agp_mem_t *entry; - if (!dev->agp->acquired) return -EINVAL; + if (!dev->agp || !dev->agp->acquired) return -EINVAL; if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) return -EFAULT; if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) @@ -207,7 +211,8 @@ int DRM(agp_bind)(struct inode *inode, struct file *filp, int retcode; int page; - if (!dev->agp->acquired || !drm_agp->bind_memory) return -EINVAL; + if (!dev->agp || !dev->agp->acquired || !drm_agp->bind_memory) + return -EINVAL; if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) return -EFAULT; if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) @@ -229,7 +234,7 @@ int DRM(agp_free)(struct inode *inode, struct file *filp, drm_agp_buffer_t request; drm_agp_mem_t *entry; - if (!dev->agp->acquired) return -EINVAL; + if (!dev->agp || !dev->agp->acquired) return -EINVAL; if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) return -EFAULT; if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index b1111048..16af7bd5 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -37,6 +37,10 @@ #define __HAVE_PCI_DMA 0 #endif +#ifndef __HAVE_SG +#define __HAVE_SG 0 +#endif + #ifndef DRIVER_BUF_PRIV_T #define DRIVER_BUF_PRIV_T u32 #endif @@ -103,13 +107,16 @@ int DRM(addmap)( struct inode *inode, struct file *filp, switch ( map->type ) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#ifndef __sparc__ +#if !defined(__sparc__) && !defined(__alpha__) if ( map->offset + map->size < map->offset || map->offset < virt_to_phys(high_memory) ) { DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); return -EINVAL; } #endif +#ifdef __alpha__ + map->offset += dev->hose->mem_space->start; +#endif #if __REALLY_HAVE_MTRR if ( map->type == _DRM_FRAME_BUFFER || (map->flags & _DRM_WRITE_COMBINING) ) { @@ -135,10 +142,21 @@ int DRM(addmap)( struct inode *inode, struct file *filp, break; #if __REALLY_HAVE_AGP case _DRM_AGP: +#ifdef __alpha__ + map->offset += dev->hose->mem_space->start; +#endif map->offset = map->offset + dev->agp->base; map->mtrr = dev->agp->agp_mtrr; /* for getmap */ break; #endif + case _DRM_SCATTER_GATHER: + if (!dev->sg) { + DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + return -EINVAL; + } + map->offset = map->offset + dev->sg->handle; + break; + default: DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); return -EINVAL; @@ -237,6 +255,7 @@ int DRM(rmmap)(struct inode *inode, struct file *filp, vfree(map->handle); break; case _DRM_AGP: + case _DRM_SCATTER_GATHER: break; } DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); @@ -565,6 +584,159 @@ int DRM(addbufs_pci)( struct inode *inode, struct file *filp, } #endif /* __HAVE_PCI_DMA */ +#ifdef __HAVE_SG +int DRM(addbufs_sg)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + drm_buf_desc_t request; + drm_buf_entry_t *entry; + drm_buf_t *buf; + unsigned long offset; + unsigned long agp_offset; + int count; + int order; + int size; + int alignment; + int page_order; + int total; + int byte_count; + int i; + + if ( !dma ) return -EINVAL; + + if ( copy_from_user( &request, (drm_buf_desc_t *)arg, + sizeof(request) ) ) + return -EFAULT; + + count = request.count; + order = DRM(order)( request.size ); + size = 1 << order; + + alignment = (request.flags & _DRM_PAGE_ALIGN) + ? PAGE_ALIGN(size) : size; + page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; + total = PAGE_SIZE << page_order; + + byte_count = 0; + agp_offset = request.agp_start; + + DRM_DEBUG( "count: %d\n", count ); + DRM_DEBUG( "order: %d\n", order ); + DRM_DEBUG( "size: %d\n", size ); + DRM_DEBUG( "agp_offset: %ld\n", agp_offset ); + DRM_DEBUG( "alignment: %d\n", alignment ); + DRM_DEBUG( "page_order: %d\n", page_order ); + DRM_DEBUG( "total: %d\n", total ); + + if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL; + if ( dev->queue_count ) return -EBUSY; /* Not while in use */ + + spin_lock( &dev->count_lock ); + if ( dev->buf_use ) { + spin_unlock( &dev->count_lock ); + return -EBUSY; + } + atomic_inc( &dev->buf_alloc ); + spin_unlock( &dev->count_lock ); + + down( &dev->struct_sem ); + entry = &dma->bufs[order]; + if ( entry->buf_count ) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; /* May only call once for each order */ + } + + entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist), + DRM_MEM_BUFS ); + if ( !entry->buflist ) { + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memset( entry->buflist, 0, count * sizeof(*entry->buflist) ); + + entry->buf_size = size; + entry->page_order = page_order; + + offset = 0; + + while ( entry->buf_count < count ) { + buf = &entry->buflist[entry->buf_count]; + buf->idx = dma->buf_count + entry->buf_count; + buf->total = alignment; + buf->order = order; + buf->used = 0; + + buf->offset = (dma->byte_count + offset); + buf->bus_address = agp_offset + offset; + buf->address = (void *)(agp_offset + offset + dev->sg->handle); + buf->next = NULL; + buf->waiting = 0; + buf->pending = 0; + init_waitqueue_head( &buf->dma_wait ); + buf->pid = 0; + + buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); + buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), + DRM_MEM_BUFS ); + memset( buf->dev_private, 0, buf->dev_priv_size ); + +#if __HAVE_DMA_HISTOGRAM + buf->time_queued = 0; + buf->time_dispatched = 0; + buf->time_completed = 0; + buf->time_freed = 0; +#endif + DRM_DEBUG( "buffer %d @ %p\n", + entry->buf_count, buf->address ); + + offset += alignment; + entry->buf_count++; + byte_count += PAGE_SIZE << page_order; + } + + DRM_DEBUG( "byte_count: %d\n", byte_count ); + + dma->buflist = DRM(realloc)( dma->buflist, + dma->buf_count * sizeof(*dma->buflist), + (dma->buf_count + entry->buf_count) + * sizeof(*dma->buflist), + DRM_MEM_BUFS ); + for ( i = 0 ; i < entry->buf_count ; i++ ) { + dma->buflist[i + dma->buf_count] = &entry->buflist[i]; + } + + dma->buf_count += entry->buf_count; + dma->byte_count += byte_count; + + DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count ); + DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count ); + +#if __HAVE_DMA_FREELIST + DRM(freelist_create)( &entry->freelist, entry->buf_count ); + for ( i = 0 ; i < entry->buf_count ; i++ ) { + DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] ); + } +#endif + up( &dev->struct_sem ); + + request.count = entry->buf_count; + request.size = size; + + if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) ) + return -EFAULT; + + dma->flags = _DRM_DMA_USE_SG; + + atomic_dec( &dev->buf_alloc ); + return 0; +} +#endif /* __HAVE_SG */ + int DRM(addbufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -579,6 +751,11 @@ int DRM(addbufs)( struct inode *inode, struct file *filp, return DRM(addbufs_agp)( inode, filp, cmd, arg ); else #endif +#if __HAVE_SG + if ( request.flags & _DRM_SG_BUFFER ) + return DRM(addbufs_sg)( inode, filp, cmd, arg ); + else +#endif #if __HAVE_PCI_DMA return DRM(addbufs_pci)( inode, filp, cmd, arg ); #else @@ -760,7 +937,8 @@ int DRM(mapbufs)( struct inode *inode, struct file *filp, return -EFAULT; if ( request.count >= dma->buf_count ) { - if ( __HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP) ) { + if ( (__HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP)) || + (__HAVE_SG && (dma->flags & _DRM_DMA_USE_SG)) ) { drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev ); if ( !map ) { diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 7447ca6d..3791d7a8 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -81,6 +81,9 @@ #ifndef __HAVE_COUNTERS #define __HAVE_COUNTERS 0 #endif +#ifndef __HAVE_SG +#define __HAVE_SG 0 +#endif #ifndef DRIVER_PREINIT #define DRIVER_PREINIT() @@ -178,6 +181,11 @@ static drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND)] = { DRM(agp_unbind), 1, 1 }, #endif +#if __HAVE_SG + [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC)] = { DRM(sg_alloc), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = { DRM(sg_free), 1, 1 }, +#endif + DRIVER_IOCTLS }; @@ -415,6 +423,12 @@ static int DRM(takedown)( drm_device_t *dev ) * handled in the AGP/GART driver. */ break; + case _DRM_SCATTER_GATHER: + if(dev->sg) { + DRM(sg_cleanup)(dev->sg); + dev->sg = NULL; + } + break; } DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); } diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index dd574766..75752b3a 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -70,6 +70,21 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) } up(&dev->struct_sem); +#ifdef __alpha__ + /* + * Default the hose + */ + if (!dev->hose) { + struct pci_dev *pci_dev; + pci_dev = pci_find_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); + if (pci_dev) dev->hose = pci_dev->sysdata; + if (!dev->hose) { + struct pci_bus *b = pci_bus_b(pci_root_buses.next); + if (b) dev->hose = b->sysdata; + } + } +#endif + return 0; } diff --git a/linux-core/drm_init.c b/linux-core/drm_init.c index 9ae98414..d9d8e3a2 100644 --- a/linux-core/drm_init.c +++ b/linux-core/drm_init.c @@ -32,7 +32,11 @@ #define __NO_VERSION__ #include "drmP.h" +#if 0 +int DRM(flags) = DRM_FLAG_DEBUG; +#else int DRM(flags) = 0; +#endif /* drm_parse_option parses a single option. See description for * drm_parse_options for details. diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c index 2fba6b0c..1cc8f31f 100644 --- a/linux-core/drm_ioctl.c +++ b/linux-core/drm_ioctl.c @@ -95,6 +95,27 @@ int DRM(setunique)(struct inode *inode, struct file *filp, DRM_MEM_DRIVER); sprintf(dev->devname, "%s@%s", dev->name, dev->unique); +#ifdef __alpha__ + do { + struct pci_dev *pci_dev; + int b, d, f; + char *p; + + for(p = dev->unique; p && *p && *p != ':'; p++); + if (!p || !*p) break; + b = (int)simple_strtoul(p+1, &p, 10); + if (*p != ':') break; + d = (int)simple_strtoul(p+1, &p, 10); + if (*p != ':') break; + f = (int)simple_strtoul(p+1, &p, 10); + if (*p) break; + + pci_dev = pci_find_slot(b, PCI_DEVFN(d,f)); + if (pci_dev) + dev->hose = pci_dev->sysdata; + } while(0); +#endif + return 0; } diff --git a/linux-core/drm_memory.h b/linux-core/drm_memory.h index 1763d9b4..498937d4 100644 --- a/linux-core/drm_memory.h +++ b/linux-core/drm_memory.h @@ -63,6 +63,7 @@ static drm_mem_stats_t DRM(mem_stats)[] = { [DRM_MEM_MAPPINGS] = { "mappings" }, [DRM_MEM_BUFLISTS] = { "buflists" }, [DRM_MEM_AGPLISTS] = { "agplist" }, + [DRM_MEM_SGLISTS] = { "sglist" }, [DRM_MEM_TOTALAGP] = { "totalagp" }, [DRM_MEM_BOUNDAGP] = { "boundagp" }, [DRM_MEM_CTXBITMAP] = { "ctxbitmap"}, diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c new file mode 100644 index 00000000..a0371074 --- /dev/null +++ b/linux-core/drm_scatter.c @@ -0,0 +1,218 @@ +/* drm_scatter.h -- IOCTLs to manage scatter/gather memory -*- linux-c -*- + * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com + * + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Gareth Hughes + */ + +#define __NO_VERSION__ +#include +#include +#include "drmP.h" + +#define DEBUG_SCATTER 0 + +void DRM(sg_cleanup)( drm_sg_mem_t *entry ) +{ + struct page *page; + int i; + + for ( i = 0 ; i < entry->pages ; i++ ) { + page = entry->pagelist[i]; + if ( page ) + ClearPageReserved( page ); + } + + vfree( entry->virtual ); + + DRM(free)( entry->pagelist, + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + DRM(free)( entry, + sizeof(*entry), + DRM_MEM_SGLISTS ); +} + +int DRM(sg_alloc)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_scatter_gather_t request; + drm_sg_mem_t *entry; + unsigned long pages, i, j; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( dev->sg ) + return -EINVAL; + + if ( copy_from_user( &request, + (drm_scatter_gather_t *)arg, + sizeof(request) ) ) + return -EFAULT; + + entry = DRM(alloc)( sizeof(*entry), DRM_MEM_SGLISTS ); + if ( !entry ) + return -ENOMEM; + + memset( entry, 0, sizeof(*entry) ); + + pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE; + DRM_DEBUG( "sg size=%ld pages=%ld\n", request.size, pages ); + + entry->pages = pages; + entry->pagelist = DRM(alloc)( pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + if ( !entry->pagelist ) { + DRM(free)( entry, sizeof(*entry), DRM_MEM_SGLISTS ); + return -ENOMEM; + } + + entry->virtual = vmalloc_32( pages << PAGE_SHIFT ); + if ( !entry->virtual ) { + DRM(free)( entry->pagelist, + entry->pages * sizeof(*entry->pagelist), + DRM_MEM_PAGES ); + DRM(free)( entry, + sizeof(*entry), + DRM_MEM_SGLISTS ); + return -ENOMEM; + } + + /* This also forces the mapping of COW pages, so our page list + * will be valid. Please don't remove it... + */ + memset( entry->virtual, 0, pages << PAGE_SHIFT ); + + entry->handle = (unsigned long)entry->virtual; + + DRM_DEBUG( "sg alloc handle = %08lx\n", entry->handle ); + DRM_DEBUG( "sg alloc virtual = %p\n", entry->virtual ); + + for ( i = entry->handle, j = 0 ; j < pages ; i += PAGE_SIZE, j++ ) { + pgd = pgd_offset_k( i ); + if ( !pgd_present( *pgd ) ) + goto failed; + + pmd = pmd_offset( pgd, i ); + if ( !pmd_present( *pmd ) ) + goto failed; + + pte = pte_offset( pmd, i ); + if ( !pte_present( *pte ) ) + goto failed; + + entry->pagelist[j] = pte_page( *pte ); + + SetPageReserved( entry->pagelist[j] ); + } + + request.handle = entry->handle; + + if ( copy_to_user( (drm_scatter_gather_t *)arg, + &request, + sizeof(request) ) ) { + DRM(sg_cleanup)( entry ); + return -EFAULT; + } + + dev->sg = entry; + +#if DEBUG_SCATTER + /* Verify that each page points to its virtual address, and vice + * versa. + */ + { + int error = 0; + + for ( i = 0 ; i < pages ; i++ ) { + unsigned long *tmp; + + tmp = (unsigned long *)entry->pagelist[i]->virtual; + for ( j = 0 ; + j < PAGE_SIZE / sizeof(unsigned long) ; + j++, tmp++ ) { + *tmp = 0xcafebabe; + } + tmp = (unsigned long *)((u8 *)entry->virtual + + (PAGE_SIZE * i)); + for( j = 0 ; + j < PAGE_SIZE / sizeof(unsigned long) ; + j++, tmp++ ) { + if ( *tmp != 0xcafebabe && error == 0 ) { + error = 1; + DRM_ERROR( "Scatter allocation error, " + "pagelist does not match " + "virtual mapping\n" ); + } + } + tmp = (unsigned long *)entry->pagelist[i]->virtual; + for(j = 0 ; + j < PAGE_SIZE / sizeof(unsigned long) ; + j++, tmp++) { + *tmp = 0; + } + } + if (error == 0) + DRM_ERROR( "Scatter allocation matches pagelist\n" ); + } +#endif + + return 0; + + failed: + DRM(sg_cleanup)( entry ); + return -ENOMEM; +} + +int DRM(sg_free)( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_scatter_gather_t request; + drm_sg_mem_t *entry; + + if ( copy_from_user( &request, + (drm_scatter_gather_t *)arg, + sizeof(request) ) ) + return -EFAULT; + + entry = dev->sg; + dev->sg = NULL; + + if ( !entry || entry->handle != request.handle ) + return -EINVAL; + + DRM_DEBUG( "sg free virtual = %p\n", entry->virtual ); + + DRM(sg_cleanup)( entry ); + + return 0; +} diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index fb51926b..771c11bd 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -50,6 +50,12 @@ struct vm_operations_struct drm_vm_dma_ops = { close: DRM(vm_close), }; +struct vm_operations_struct drm_vm_sg_ops = { + nopage: DRM(vm_sg_nopage), + open: DRM(vm_open), + close: DRM(vm_close), +}; + #if LINUX_VERSION_CODE < 0x020317 unsigned long DRM(vm_nopage)(struct vm_area_struct *vma, unsigned long address, @@ -93,7 +99,7 @@ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, offset = address - vma->vm_start; i = (unsigned long)map->handle + offset; /* We have to walk page tables here because we need large SAREA's, and - * they need to be virtually contigious in kernel space. + * they need to be virtually contiguous in kernel space. */ pgd = pgd_offset_k( i ); if( !pgd_present( *pgd ) ) return NOPAGE_OOM; @@ -187,6 +193,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma) vfree(map->handle); break; case _DRM_AGP: + case _DRM_SCATTER_GATHER: break; } DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); @@ -230,6 +237,48 @@ struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, #endif } +#if LINUX_VERSION_CODE < 0x020317 +unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#else + /* Return type changed in 2.3.23 */ +struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma, + unsigned long address, + int write_access) +#endif +{ +#if LINUX_VERSION_CODE >= 0x020300 + drm_map_t *map = (drm_map_t *)vma->vm_private_data; +#else + drm_map_t *map = (drm_map_t *)vma->vm_pte; +#endif + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->dev; + drm_sg_mem_t *entry = dev->sg; + unsigned long offset; + unsigned long map_offset; + unsigned long page_offset; + struct page *page; + + if (!entry) return NOPAGE_SIGBUS; /* Error */ + if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!entry->pagelist) return NOPAGE_OOM ; /* Nothing allocated */ + + + offset = address - vma->vm_start; + map_offset = map->offset - dev->sg->handle; + page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT); + page = entry->pagelist[page_offset]; + atomic_inc(&page->count); /* Dec. by kernel */ + +#if LINUX_VERSION_CODE < 0x020317 + return (unsigned long)virt_to_phys(page->virtual); +#else + return page; +#endif +} + void DRM(vm_open)(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; @@ -322,6 +371,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) drm_device_t *dev = priv->dev; drm_map_t *map = NULL; drm_map_list_t *r_list; + unsigned long offset = 0; struct list_head *list; DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", @@ -374,19 +424,26 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) } #elif defined(__ia64__) if (map->type != _DRM_AGP) - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + vma->vm_page_prot = + pgprot_writecombine(vma->vm_page_prot); +#elif defined(__powerpc__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED; #endif vma->vm_flags |= VM_IO; /* not in core dump */ } +#ifdef __alpha__ + offset = dev->hose->dense_mem_base - + dev->hose->mem_space->start; +#endif if (remap_page_range(vma->vm_start, - VM_OFFSET(vma), + VM_OFFSET(vma) + offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," " offset = 0x%lx\n", map->type, - vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + vma->vm_start, vma->vm_end, VM_OFFSET(vma) + offset); vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: @@ -400,6 +457,15 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) DRM_KERNEL advisory is supported. */ vma->vm_flags |= VM_LOCKED; break; + case _DRM_SCATTER_GATHER: + vma->vm_ops = &drm_vm_sg_ops; +#if LINUX_VERSION_CODE >= 0x020300 + vma->vm_private_data = (void *)map; +#else + vma->vm_pte = (unsigned long)map; +#endif + vma->vm_flags |= VM_LOCKED; + break; default: return -EINVAL; /* This should never happen. */ } diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index daae0f87..584cb29c 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -33,16 +33,17 @@ #include "r128.h" #include "drmP.h" #include "r128_drv.h" +#include "ati_pcigart.h" #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." #define DRIVER_NAME "r128" #define DRIVER_DESC "ATI Rage 128" -#define DRIVER_DATE "20010308" +#define DRIVER_DATE "20010405" #define DRIVER_MAJOR 2 #define DRIVER_MINOR 1 -#define DRIVER_PATCHLEVEL 5 +#define DRIVER_PATCHLEVEL 6 #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { r128_cce_buffers, 1, 0 }, \ @@ -88,3 +89,4 @@ #include "drm_proc.h" #include "drm_vm.h" #include "drm_stub.h" +#include "drm_scatter.h" diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index b022c3bb..d7632667 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -31,16 +31,17 @@ #include "radeon.h" #include "drmP.h" #include "radeon_drv.h" +#include "ati_pcigart.h" #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." #define DRIVER_NAME "radeon" #define DRIVER_DESC "ATI Radeon" -#define DRIVER_DATE "20010402" +#define DRIVER_DATE "20010405" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 1 -#define DRIVER_PATCHLEVEL 0 +#define DRIVER_PATCHLEVEL 1 #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -85,3 +86,4 @@ #include "drm_proc.h" #include "drm_vm.h" #include "drm_stub.h" +#include "drm_scatter.h" -- cgit v1.2.3