diff options
42 files changed, 2275 insertions, 560 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 82675881..bb719edb 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -67,11 +67,6 @@ extern int xf86RemoveSIGIOHandler(int fd); # endif #endif -#ifdef __alpha__ -extern unsigned long _bus_base(void); -#define BUS_BASE _bus_base() -#endif - /* Not all systems have MAP_FAILED defined */ #ifndef MAP_FAILED #define MAP_FAILED ((void *)-1) @@ -490,11 +485,6 @@ int drmAddMap(int fd, drm_map_t map; map.offset = offset; -#ifdef __alpha__ - /* Make sure we add the bus_base to all but shm */ - if (type != DRM_SHM) - map.offset += BUS_BASE; -#endif map.size = size; map.handle = 0; map.type = type; @@ -998,6 +988,28 @@ unsigned int drmAgpDeviceId(int fd) return i.id_device; } +int drmScatterGatherAlloc(int fd, unsigned long size, unsigned long *handle) +{ + drm_scatter_gather_t sg; + + *handle = 0; + sg.size = size; + sg.handle = 0; + if (ioctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) return -errno; + *handle = sg.handle; + return 0; +} + +int drmScatterGatherFree(int fd, unsigned long handle) +{ + drm_scatter_gather_t sg; + + sg.size = 0; + sg.handle = handle; + if (ioctl(fd, DRM_IOCTL_SG_FREE, &sg)) return -errno; + return 0; +} + int drmError(int err, const char *label) { switch (err) { 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 <gareth@valinux.com> + */ + +#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 <linux/sched.h> #include <linux/smp_lock.h> /* For (un)lock_kernel */ #include <linux/mm.h> -#ifdef __alpha__ +#if defined(__alpha__) || defined(__powerpc__) #include <asm/pgtable.h> /* For pte_wrprotect */ #endif #include <asm/io.h> @@ -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 <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include <linux/config.h> +#include <linux/vmalloc.h> +#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" diff --git a/linux/Makefile.linux b/linux/Makefile.linux index 470c25b3..702fca0d 100644 --- a/linux/Makefile.linux +++ b/linux/Makefile.linux @@ -47,7 +47,7 @@ # **** End of SMP/MODVERSIONS detection -MODS = gamma.o tdfx.o +MODS = gamma.o tdfx.o r128.o radeon.o LIBS = DRMTEMPLATES = drm_auth.h drm_bufs.h drm_context.h drm_dma.h drm_drawable.h \ @@ -61,6 +61,13 @@ GAMMAHEADERS = gamma_drv.h $(DRMHEADERS) $(DRMTEMPLATES) TDFXOBJS = tdfx_drv.o TDFXHEADERS = tdfx.h $(DRMHEADERS) +R128OBJS = r128_drv.o r128_cce.o r128_state.o +R128HEADERS = r128.h r128_drv.h r128_drm.h $(DRMHEADERS) $(DRMTEMPLATES) + +RADEONOBJS = radeon_drv.o radeon_cp.o radeon_state.o +RADEONHEADERS = radeon.h radeon_drv.h radeon_drm.h $(DRMHEADERS) \ + $(DRMTEMPLATES) + INC = /usr/include CFLAGS = -O2 $(WARNINGS) @@ -132,7 +139,7 @@ ifeq ($(AGP),1) MODCFLAGS += -DCONFIG_AGP -DCONFIG_AGP_MODULE DRMTEMPLATES += drm_agpsupport.h DRMHEADERS += agpsupport-pre24.h -MODS += mga.o r128.o radeon.o +MODS += mga.o ifeq ($(MACHINE),i386) MODS += i810.o endif @@ -140,19 +147,16 @@ ifeq ($(MACHINE),i686) MODS += i810.o endif - MGAOBJS = mga_drv.o mga_dma.o mga_state.o mga_warp.o MGAHEADERS = mga.h mga_drv.h mga_drm.h $(DRMHEADERS) $(DRMTEMPLATES) I810OBJS = i810_drv.o i810_dma.o I810HEADERS = i810.h i810_drv.h i810_drm.h $(DRMHEADERS) $(DRMTEMPLATES) -R128OBJS = r128_drv.o r128_cce.o r128_state.o -R128HEADERS = r128.h r128_drv.h r128_drm.h $(DRMHEADERS) $(DRMTEMPLATES) +endif -RADEONOBJS = radeon_drv.o radeon_cp.o radeon_state.o -RADEONHEADERS = radeon.h radeon_drv.h radeon_drm.h $(DRMHEADERS) \ - $(DRMTEMPLATES) +ifeq ($(MACHINE),alpha) +MODCFLAGS+= -ffixed-8 -mno-fp-regs -mcpu=ev56 -Wa,-mev6 endif ifeq ($(SIS),1) @@ -218,26 +222,27 @@ tdfx.o: $(TDFXOBJS) $(LIBS) sis.o: $(SISOBJS) $(LIBS) $(LD) -r $^ -o $@ -ifeq ($(AGP),1) -mga_drv.o: mga_drv.c +r128_drv.o: r128_drv.c $(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@ -mga.o: $(MGAOBJS) +r128.o: $(R128OBJS) $(LIBS) $(LD) -r $^ -o $@ -i810_drv.o: i810_drv.c +radeon_drv.o: radeon_drv.c $(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@ -i810.o: $(I810OBJS) $(LIBS) +radeon.o: $(RADEONOBJS) $(LIBS) $(LD) -r $^ -o $@ -r128_drv.o: r128_drv.c +ifeq ($(AGP),1) +mga_drv.o: mga_drv.c $(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@ -r128.o: $(R128OBJS) $(LIBS) +mga.o: $(MGAOBJS) $(LD) -r $^ -o $@ -radeon_drv.o: radeon_drv.c +i810_drv.o: i810_drv.c $(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@ -radeon.o: $(RADEONOBJS) $(LIBS) +i810.o: $(I810OBJS) $(LIBS) $(LD) -r $^ -o $@ + endif .PHONY: ChangeLog diff --git a/linux/ati_pcigart.h b/linux/ati_pcigart.h new file mode 100644 index 00000000..93c5148f --- /dev/null +++ b/linux/ati_pcigart.h @@ -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 <gareth@valinux.com> + */ + +#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/drm.h b/linux/drm.h index f1abaabf..3def97f7 100644 --- a/linux/drm.h +++ b/linux/drm.h @@ -126,10 +126,11 @@ typedef struct drm_control { } drm_control_t; typedef enum drm_map_type { - _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ - _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2, /* shared, cached */ - _DRM_AGP = 3 /* AGP/GART */ + _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /* no caching, no core dump */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3, /* AGP/GART */ + _DRM_SCATTER_GATHER = 4 /* Scatter/gather memory for PCI DMA */ } drm_map_type_t; typedef enum drm_map_flags { @@ -238,7 +239,8 @@ typedef struct drm_buf_desc { int high_mark; /* High water mark */ enum { _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ - _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ + _DRM_AGP_BUFFER = 0x02, /* Buffer is in agp space */ + _DRM_SG_BUFFER = 0x04 /* Scatter/gather memory buffer */ } flags; unsigned long agp_start; /* Start address of where the agp buffers * are in the agp aperture */ @@ -344,6 +346,11 @@ typedef struct drm_agp_info { unsigned short id_device; } drm_agp_info_t; +typedef struct drm_scatter_gather { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for mapping / unmapping */ +} drm_scatter_gather_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) @@ -399,6 +406,9 @@ typedef struct drm_agp_info { #define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) #define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) +#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t) +#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t) + /* MGA specific ioctls */ #define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x41, drm_lock_t) diff --git a/linux/drmP.h b/linux/drmP.h index 274e318a..085d1cb8 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -53,7 +53,7 @@ #include <linux/sched.h> #include <linux/smp_lock.h> /* For (un)lock_kernel */ #include <linux/mm.h> -#ifdef __alpha__ +#if defined(__alpha__) || defined(__powerpc__) #include <asm/pgtable.h> /* For pte_wrprotect */ #endif #include <asm/io.h> @@ -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/drm_agpsupport.h b/linux/drm_agpsupport.h index dfd0d8fc..9b056c75 100644 --- a/linux/drm_agpsupport.h +++ b/linux/drm_agpsupport.h @@ -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/drm_bufs.h b/linux/drm_bufs.h index b1111048..16af7bd5 100644 --- a/linux/drm_bufs.h +++ b/linux/drm_bufs.h @@ -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/drm_drv.h b/linux/drm_drv.h index 7447ca6d..3791d7a8 100644 --- a/linux/drm_drv.h +++ b/linux/drm_drv.h @@ -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/drm_fops.h b/linux/drm_fops.h index dd574766..75752b3a 100644 --- a/linux/drm_fops.h +++ b/linux/drm_fops.h @@ -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/drm_init.h b/linux/drm_init.h index 9ae98414..d9d8e3a2 100644 --- a/linux/drm_init.h +++ b/linux/drm_init.h @@ -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/drm_ioctl.h b/linux/drm_ioctl.h index 2fba6b0c..1cc8f31f 100644 --- a/linux/drm_ioctl.h +++ b/linux/drm_ioctl.h @@ -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/drm_memory.h b/linux/drm_memory.h index 1763d9b4..498937d4 100644 --- a/linux/drm_memory.h +++ b/linux/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/drm_scatter.h b/linux/drm_scatter.h new file mode 100644 index 00000000..a0371074 --- /dev/null +++ b/linux/drm_scatter.h @@ -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 <gareth@valinux.com> + */ + +#define __NO_VERSION__ +#include <linux/config.h> +#include <linux/vmalloc.h> +#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/drm_vm.h b/linux/drm_vm.h index fb51926b..771c11bd 100644 --- a/linux/drm_vm.h +++ b/linux/drm_vm.h @@ -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/mga_drm.h b/linux/mga_drm.h index 066b4e48..4af2ca2e 100644 --- a/linux/mga_drm.h +++ b/linux/mga_drm.h @@ -237,7 +237,7 @@ typedef struct drm_mga_init { MGA_CLEANUP_DMA = 0x02 } func; - int sarea_priv_offset; + unsigned long sarea_priv_offset; int chipset; int sgram; @@ -254,12 +254,12 @@ typedef struct drm_mga_init { unsigned int texture_offset[MGA_NR_TEX_HEAPS]; unsigned int texture_size[MGA_NR_TEX_HEAPS]; - unsigned int fb_offset; - unsigned int mmio_offset; - unsigned int status_offset; - unsigned int warp_offset; - unsigned int primary_offset; - unsigned int buffers_offset; + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long status_offset; + unsigned long warp_offset; + unsigned long primary_offset; + unsigned long buffers_offset; } drm_mga_init_t; typedef struct drm_mga_fullscreen { diff --git a/linux/r128.h b/linux/r128.h index 83e002af..926b4bfd 100644 --- a/linux/r128.h +++ b/linux/r128.h @@ -37,9 +37,11 @@ /* General customization: */ #define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 +#define __MUST_HAVE_AGP 0 #define __HAVE_MTRR 1 #define __HAVE_CTX_BITMAP 1 +#define __HAVE_SG 1 +#define __HAVE_PCI_DMA 1 /* Driver customization: */ diff --git a/linux/r128_cce.c b/linux/r128_cce.c index c0e20c21..1ced05fe 100644 --- a/linux/r128_cce.c +++ b/linux/r128_cce.c @@ -178,6 +178,8 @@ static void r128_cce_load_microcode( drm_r128_private_t *dev_priv ) { int i; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + r128_do_wait_for_idle( dev_priv ); R128_WRITE( R128_PM4_MICROCODE_ADDR, 0 ); @@ -208,7 +210,7 @@ int r128_do_cce_idle( drm_r128_private_t *dev_priv ) int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - if ( *dev_priv->ring.head == dev_priv->ring.tail ) { + if ( GET_RING_HEAD( &dev_priv->ring ) == dev_priv->ring.tail ) { int pm4stat = R128_READ( R128_PM4_STAT ); if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size ) && @@ -249,7 +251,7 @@ static void r128_do_cce_reset( drm_r128_private_t *dev_priv ) { R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); - *dev_priv->ring.head = 0; + SET_RING_HEAD( &dev_priv->ring, 0 ); dev_priv->ring.tail = 0; } @@ -312,19 +314,43 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev ) u32 ring_start; u32 tmp; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + /* The manual (p. 2) says this address is in "VM space". This * means it's an offset from the start of AGP space. */ - ring_start = dev_priv->cce_ring->offset - dev->agp->base; +#if __REALLY_HAVE_AGP + if ( !dev_priv->is_pci ) + ring_start = dev_priv->cce_ring->offset - dev->agp->base; + else +#endif + ring_start = dev_priv->cce_ring->offset - dev->sg->handle; + R128_WRITE( R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET ); R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); /* DL_RPTR_ADDR is a physical address in AGP space. */ - *dev_priv->ring.head = 0; - R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, - dev_priv->ring_rptr->offset ); + SET_RING_HEAD( &dev_priv->ring, 0 ); + + if ( !dev_priv->is_pci ) { + R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, + dev_priv->ring_rptr->offset ); + } else { + drm_sg_mem_t *entry = dev->sg; + unsigned long tmp_ofs, page_ofs; + + tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; + page_ofs = tmp_ofs >> PAGE_SHIFT; + + 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 ); + } /* Set watermark control */ R128_WRITE( R128_PM4_BUFFER_WM_CNTL, @@ -346,6 +372,8 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) drm_r128_private_t *dev_priv; struct list_head *list; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + dev_priv = DRM(alloc)( sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); if ( dev_priv == NULL ) return -ENOMEM; @@ -355,11 +383,9 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) dev_priv->is_pci = init->is_pci; - /* GH: We don't support PCI cards until PCI GART is implemented. - * Fail here so we can remove all checks for PCI cards around - * the CCE ring code. - */ - if ( dev_priv->is_pci ) { + if ( dev_priv->is_pci && !dev->sg ) { + DRM_DEBUG( "PCI GART memory not allocated!\n" ); + DRM_ERROR( "PCI GART memory not allocated!\n" ); DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; return -EINVAL; @@ -368,6 +394,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) dev_priv->usec_timeout = init->usec_timeout; if ( dev_priv->usec_timeout < 1 || dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT ) { + DRM_DEBUG( "TIMEOUT problem!\n" ); DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; return -EINVAL; @@ -387,6 +414,7 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) ( init->cce_mode != R128_PM4_128BM_64INDBM ) && ( init->cce_mode != R128_PM4_64BM_128INDBM ) && ( init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM ) ) { + DRM_DEBUG( "Bad cce_mode!\n" ); DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; return -EINVAL; @@ -476,9 +504,24 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DRM_IOREMAP( dev_priv->cce_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + if ( !dev_priv->is_pci ) { + DRM_IOREMAP( dev_priv->cce_ring ); + DRM_IOREMAP( dev_priv->ring_rptr ); + DRM_IOREMAP( dev_priv->buffers ); + } else { + dev_priv->cce_ring->handle = + (void *)dev_priv->cce_ring->offset; + dev_priv->ring_rptr->handle = + (void *)dev_priv->ring_rptr->offset; + dev_priv->buffers->handle = (void *)dev_priv->buffers->offset; + } + +#if __REALLY_HAVE_AGP + if ( !dev_priv->is_pci ) + dev_priv->cce_buffers_offset = dev->agp->base; + else +#endif + dev_priv->cce_buffers_offset = dev->sg->handle; dev_priv->ring.head = ((__volatile__ u32 *) dev_priv->ring_rptr->handle); @@ -501,6 +544,20 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) R128_WRITE( R128_LAST_DISPATCH_REG, 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 ) { + DRM_DEBUG( "failed to init PCI GART!\n" ); + DRM_ERROR( "failed to init PCI GART!\n" ); + DRM(free)( dev_priv, sizeof(*dev_priv), + DRM_MEM_DRIVER ); + dev->dev_private = NULL; + return -EINVAL; + } + R128_WRITE( R128_PCI_GART_PAGE, + virt_to_bus( (void *)dev_priv->phys_pci_gart ) ); + } + r128_cce_init_ring_buffer( dev ); r128_cce_load_microcode( dev_priv ); r128_do_engine_reset( dev ); @@ -513,9 +570,11 @@ int r128_do_cleanup_cce( drm_device_t *dev ) if ( dev->dev_private ) { drm_r128_private_t *dev_priv = dev->dev_private; - DRM_IOREMAPFREE( dev_priv->cce_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); + if ( !dev_priv->is_pci ) { + DRM_IOREMAPFREE( dev_priv->cce_ring ); + DRM_IOREMAPFREE( dev_priv->ring_rptr ); + DRM_IOREMAPFREE( dev_priv->buffers ); + } DRM(free)( dev->dev_private, sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); @@ -532,6 +591,8 @@ int r128_cce_init( struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_r128_init_t init; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + if ( copy_from_user( &init, (drm_r128_init_t *)arg, sizeof(init) ) ) return -EFAULT; diff --git a/linux/r128_drm.h b/linux/r128_drm.h index 86aba175..fc1261ea 100644 --- a/linux/r128_drm.h +++ b/linux/r128_drm.h @@ -175,7 +175,7 @@ typedef struct drm_r128_init { R128_INIT_CCE = 0x01, R128_CLEANUP_CCE = 0x02 } func; - int sarea_priv_offset; + unsigned long sarea_priv_offset; int is_pci; int cce_mode; int cce_secure; @@ -189,12 +189,12 @@ typedef struct drm_r128_init { unsigned int depth_offset, depth_pitch; unsigned int span_offset; - unsigned int fb_offset; - unsigned int mmio_offset; - unsigned int ring_offset; - unsigned int ring_rptr_offset; - unsigned int buffers_offset; - unsigned int agp_textures_offset; + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; } drm_r128_init_t; typedef struct drm_r128_cce_stop { diff --git a/linux/r128_drv.c b/linux/r128_drv.c index daae0f87..584cb29c 100644 --- a/linux/r128_drv.c +++ b/linux/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/r128_drv.h b/linux/r128_drv.h index 6216b9a1..fbc69229 100644 --- a/linux/r128_drv.h +++ b/linux/r128_drv.h @@ -28,11 +28,15 @@ * Rickard E. (Rik) Faith <faith@valinux.com> * Kevin E. Martin <martin@valinux.com> * Gareth Hughes <gareth@valinux.com> + * Michel Dänzer <daenzerm@student.ethz.ch> */ #ifndef __R128_DRV_H__ #define __R128_DRV_H__ +#define GET_RING_HEAD( ring ) le32_to_cpu( *(ring)->head ) +#define SET_RING_HEAD( ring, val ) *(ring)->head = cpu_to_le32( val ) + typedef struct drm_r128_freelist { unsigned int age; drm_buf_t *buf; @@ -67,6 +71,8 @@ typedef struct drm_r128_private { int usec_timeout; int is_pci; + unsigned long phys_pci_gart; + unsigned long cce_buffers_offset; atomic_t idle_count; @@ -134,7 +140,7 @@ extern int r128_wait_ring( drm_r128_private_t *dev_priv, int n ); static inline void r128_update_ring_snapshot( drm_r128_ring_buffer_t *ring ) { - ring->space = (*(volatile int *)ring->head - ring->tail) * sizeof(u32); + ring->space = (GET_RING_HEAD( ring ) - ring->tail) * sizeof(u32); if ( ring->space <= 0 ) ring->space += ring->size; } @@ -248,6 +254,7 @@ extern int r128_cce_indirect( struct inode *inode, struct file *filp, # define R128_PC_FLUSH_ALL 0x00ff # define R128_PC_BUSY (1 << 31) +#define R128_PCI_GART_PAGE 0x017c #define R128_PRIM_TEX_CNTL_C 0x1cb0 #define R128_SCALE_3D_CNTL 0x1a00 @@ -365,7 +372,7 @@ extern int r128_cce_indirect( struct inode *inode, struct file *filp, #define R128_LAST_FRAME_REG R128_GUI_SCRATCH_REG0 #define R128_LAST_DISPATCH_REG R128_GUI_SCRATCH_REG1 -#define R128_MAX_VB_AGE 0xffffffff +#define R128_MAX_VB_AGE 0x7fffffff #define R128_MAX_VB_VERTS (0xffff) #define R128_RING_HIGH_MARK 128 @@ -373,17 +380,36 @@ extern int r128_cce_indirect( struct inode *inode, struct file *filp, #define R128_PERFORMANCE_BOXES 0 -#define R128_BASE(reg) ((u32)(dev_priv->mmio->handle)) +#define R128_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) #define R128_ADDR(reg) (R128_BASE( reg ) + reg) #define R128_DEREF(reg) *(volatile u32 *)R128_ADDR( reg ) -#define R128_READ(reg) R128_DEREF( reg ) -#define R128_WRITE(reg,val) do { R128_DEREF( reg ) = val; } while (0) +#ifdef __alpha__ +#define R128_READ(reg) (_R128_READ((u32 *)R128_ADDR(reg))) +static inline u32 _R128_READ(u32 *addr) { + mb(); + return *(volatile u32 *)addr; +} +#define R128_WRITE(reg,val) \ + do { wmb(); R128_DEREF(reg) = val; } while (0) +#else +#define R128_READ(reg) le32_to_cpu( R128_DEREF( reg ) ) +#define R128_WRITE(reg,val) do { R128_DEREF( reg ) = cpu_to_le32( val ); } while (0) +#endif #define R128_DEREF8(reg) *(volatile u8 *)R128_ADDR( reg ) +#ifdef __alpha__ +#define R128_READ8(reg) _R128_READ8((u8 *)R128_ADDR(reg)) +static inline u8 _R128_READ8(u8 *addr) { + mb(); + return *(volatile u8 *)addr; +} +#define R128_WRITE8(reg,val) \ + do { wmb(); R128_DEREF8(reg) = val; } while (0) +#else #define R128_READ8(reg) R128_DEREF8( reg ) #define R128_WRITE8(reg,val) do { R128_DEREF8( reg ) = val; } while (0) - +#endif #define R128_WRITE_PLL(addr,val) \ do { \ @@ -485,7 +511,7 @@ do { \ #define ADVANCE_RING() do { \ if ( R128_VERBOSE ) { \ - DRM_INFO( "ADVANCE_RING() tail=0x%06x wr=0x%06x\n", \ + DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ write, dev_priv->ring.tail ); \ } \ if ( R128_BROKEN_CCE && write < 32 ) { \ @@ -503,7 +529,7 @@ do { \ DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \ (unsigned int)(x), write ); \ } \ - ring[write++] = (x); \ + ring[write++] = cpu_to_le32( x ); \ write &= tail_mask; \ } while (0) diff --git a/linux/r128_state.c b/linux/r128_state.c index 9fc6b485..7eafd72d 100644 --- a/linux/r128_state.c +++ b/linux/r128_state.c @@ -660,7 +660,7 @@ static void r128_cce_dispatch_indirect( drm_device_t *dev, u32 *data = (u32 *) ((char *)dev_priv->buffers->handle + buf->offset + start); - data[dwords++] = R128_CCE_PACKET2; + data[dwords++] = cpu_to_le32( R128_CCE_PACKET2 ); } buf_priv->dispatched = 1; @@ -704,7 +704,7 @@ static void r128_cce_dispatch_indices( drm_device_t *dev, drm_r128_buf_priv_t *buf_priv = buf->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; int format = sarea_priv->vc_format; - int offset = dev_priv->buffers->offset - dev->agp->base; + int offset = dev_priv->buffers->offset - dev_priv->cce_buffers_offset; int prim = buf_priv->prim; u32 *data; int dwords; @@ -727,16 +727,21 @@ static void r128_cce_dispatch_indices( drm_device_t *dev, data = (u32 *)((char *)dev_priv->buffers->handle + buf->offset + start); - data[0] = CCE_PACKET3( R128_3D_RNDR_GEN_INDX_PRIM, dwords-2 ); + data[0] = cpu_to_le32( CCE_PACKET3( R128_3D_RNDR_GEN_INDX_PRIM, + dwords-2 ) ); - data[1] = offset; - data[2] = R128_MAX_VB_VERTS; - data[3] = format; - data[4] = (prim | R128_CCE_VC_CNTL_PRIM_WALK_IND | - (count << 16)); + data[1] = cpu_to_le32( offset ); + data[2] = cpu_to_le32( R128_MAX_VB_VERTS ); + data[3] = cpu_to_le32( format ); + data[4] = cpu_to_le32( (prim | R128_CCE_VC_CNTL_PRIM_WALK_IND | + (count << 16)) ); if ( count & 0x1 ) { +#ifdef __LITTLE_ENDIAN data[dwords-1] &= 0x0000ffff; +#else + data[dwords-1] &= 0xffff0000; +#endif } do { @@ -842,23 +847,23 @@ static int r128_cce_dispatch_blit( drm_device_t *dev, data = (u32 *)((char *)dev_priv->buffers->handle + buf->offset); - data[0] = CCE_PACKET3( R128_CNTL_HOSTDATA_BLT, dwords + 6 ); - data[1] = (R128_GMC_DST_PITCH_OFFSET_CNTL | - R128_GMC_BRUSH_NONE | - (blit->format << 8) | - R128_GMC_SRC_DATATYPE_COLOR | - R128_ROP3_S | - R128_DP_SRC_SOURCE_HOST_DATA | - R128_GMC_CLR_CMP_CNTL_DIS | - R128_GMC_AUX_CLIP_DIS | - R128_GMC_WR_MSK_DIS); - - data[2] = (blit->pitch << 21) | (blit->offset >> 5); - data[3] = 0xffffffff; - data[4] = 0xffffffff; - data[5] = (blit->y << 16) | blit->x; - data[6] = (blit->height << 16) | blit->width; - data[7] = dwords; + data[0] = cpu_to_le32( CCE_PACKET3( R128_CNTL_HOSTDATA_BLT, dwords + 6 ) ); + data[1] = cpu_to_le32( (R128_GMC_DST_PITCH_OFFSET_CNTL | + R128_GMC_BRUSH_NONE | + (blit->format << 8) | + R128_GMC_SRC_DATATYPE_COLOR | + R128_ROP3_S | + R128_DP_SRC_SOURCE_HOST_DATA | + R128_GMC_CLR_CMP_CNTL_DIS | + R128_GMC_AUX_CLIP_DIS | + R128_GMC_WR_MSK_DIS) ); + + data[2] = cpu_to_le32( (blit->pitch << 21) | (blit->offset >> 5) ); + data[3] = cpu_to_le32( 0xffffffff ); + data[4] = cpu_to_le32( 0xffffffff ); + data[5] = cpu_to_le32( (blit->y << 16) | blit->x ); + data[6] = cpu_to_le32( (blit->height << 16) | blit->width ); + data[7] = cpu_to_le32( dwords ); buf->used = (dwords + 8) * sizeof(u32); @@ -1299,8 +1304,8 @@ int r128_cce_vertex( struct inode *inode, struct file *filp, LOCK_TEST_WITH_RETURN( dev ); - if ( !dev_priv || dev_priv->is_pci ) { - DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return -EINVAL; } @@ -1362,8 +1367,8 @@ int r128_cce_indices( struct inode *inode, struct file *filp, LOCK_TEST_WITH_RETURN( dev ); - if ( !dev_priv || dev_priv->is_pci ) { - DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return -EINVAL; } diff --git a/linux/radeon.h b/linux/radeon.h index db238b1b..0fdeb82a 100644 --- a/linux/radeon.h +++ b/linux/radeon.h @@ -37,9 +37,11 @@ /* General customization: */ #define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 +#define __MUST_HAVE_AGP 0 #define __HAVE_MTRR 1 #define __HAVE_CTX_BITMAP 1 +#define __HAVE_SG 1 +#define __HAVE_PCI_DMA 1 /* Driver customization: */ diff --git a/linux/radeon_cp.c b/linux/radeon_cp.c index 5d662bc0..c255a3e0 100644 --- a/linux/radeon_cp.c +++ b/linux/radeon_cp.c @@ -24,12 +24,12 @@ * DEALINGS IN THE SOFTWARE. * * Authors: - * Kevin E. Martin <martin@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> */ #define __NO_VERSION__ +#include "radeon.h" #include "drmP.h" #include "radeon_drv.h" @@ -300,26 +300,6 @@ static u32 radeon_cp_microcode[][2] = { }; -#define DO_IOREMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) - -#define DO_IOREMAPFREE(_m) \ - do { \ - if ((_m)->handle && (_m)->size) \ - drm_ioremapfree((_m)->handle, (_m)->size); \ - } while (0) - -#define DO_FIND_MAP(_m, _o) \ - do { \ - int _i; \ - for (_i = 0; _i < dev->map_count; _i++) { \ - if (dev->maplist[_i]->offset == _o) { \ - _m = dev->maplist[_i]; \ - break; \ - } \ - } \ - } while (0) - - int RADEON_READ_PLL(drm_device_t *dev, int addr) { drm_radeon_private_t *dev_priv = dev->dev_private; @@ -338,6 +318,16 @@ static void radeon_status( drm_radeon_private_t *dev_priv ) (unsigned int)RADEON_READ( RADEON_CP_RB_RPTR ) ); printk( "CP_RB_WTPR = 0x%08x\n", (unsigned int)RADEON_READ( RADEON_CP_RB_WPTR ) ); + printk( "AIC_CNTL = 0x%08x\n", + (unsigned int)RADEON_READ( RADEON_AIC_CNTL ) ); + printk( "AIC_STAT = 0x%08x\n", + (unsigned int)RADEON_READ( RADEON_AIC_STAT ) ); + printk( "AIC_PT_BASE = 0x%08x\n", + (unsigned int)RADEON_READ( RADEON_AIC_PT_BASE ) ); + printk( "TLB_ADDR = 0x%08x\n", + (unsigned int)RADEON_READ( RADEON_AIC_TLB_ADDR ) ); + printk( "TLB_DATA = 0x%08x\n", + (unsigned int)RADEON_READ( RADEON_AIC_TLB_DATA ) ); } #endif @@ -421,6 +411,7 @@ static int radeon_do_wait_for_idle( drm_radeon_private_t *dev_priv ) static void radeon_cp_load_microcode( drm_radeon_private_t *dev_priv ) { int i; + DRM_DEBUG( "%s\n", __FUNCTION__ ); radeon_do_wait_for_idle( dev_priv ); @@ -439,6 +430,7 @@ static void radeon_cp_load_microcode( drm_radeon_private_t *dev_priv ) */ static void radeon_do_cp_flush( drm_radeon_private_t *dev_priv ) { + DRM_DEBUG( "%s\n", __FUNCTION__ ); #if 0 u32 tmp; @@ -452,6 +444,7 @@ static void radeon_do_cp_flush( drm_radeon_private_t *dev_priv ) int radeon_do_cp_idle( drm_radeon_private_t *dev_priv ) { RING_LOCALS; + DRM_DEBUG( "%s\n", __FUNCTION__ ); BEGIN_RING( 6 ); @@ -469,6 +462,7 @@ int radeon_do_cp_idle( drm_radeon_private_t *dev_priv ) static void radeon_do_cp_start( drm_radeon_private_t *dev_priv ) { RING_LOCALS; + DRM_DEBUG( "%s\n", __FUNCTION__ ); radeon_do_wait_for_idle( dev_priv ); @@ -492,6 +486,7 @@ static void radeon_do_cp_start( drm_radeon_private_t *dev_priv ) static void radeon_do_cp_reset( drm_radeon_private_t *dev_priv ) { u32 cur_read_ptr; + DRM_DEBUG( "%s\n", __FUNCTION__ ); cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR ); RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr ); @@ -505,6 +500,8 @@ static void radeon_do_cp_reset( drm_radeon_private_t *dev_priv ) */ static void radeon_do_cp_stop( drm_radeon_private_t *dev_priv ) { + DRM_DEBUG( "%s\n", __FUNCTION__ ); + RADEON_WRITE( RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS ); dev_priv->cp_running = 0; @@ -571,18 +568,29 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev ) drm_radeon_private_t *dev_priv = dev->dev_private; u32 ring_start, cur_read_ptr; u32 tmp; + DRM_DEBUG( "%s\n", __FUNCTION__ ); /* Initialize the memory controller */ RADEON_WRITE( RADEON_MC_FB_LOCATION, (dev_priv->agp_vm_start - 1) & 0xffff0000 ); - RADEON_WRITE( RADEON_MC_AGP_LOCATION, - (((dev_priv->agp_vm_start - 1 + - dev_priv->agp_size) & 0xffff0000) | - (dev_priv->agp_vm_start >> 16)) ); - ring_start = (dev_priv->cp_ring->offset - - dev->agp->base - + dev_priv->agp_vm_start); + if ( !dev_priv->is_pci ) { + RADEON_WRITE( RADEON_MC_AGP_LOCATION, + (((dev_priv->agp_vm_start - 1 + + dev_priv->agp_size) & 0xffff0000) | + (dev_priv->agp_vm_start >> 16)) ); + } + +#if __REALLY_HAVE_AGP + if ( !dev_priv->is_pci ) + ring_start = (dev_priv->cp_ring->offset + - dev->agp->base + + dev_priv->agp_vm_start); + else +#endif + ring_start = (dev_priv->cp_ring->offset + - dev->sg->handle + + dev_priv->agp_vm_start); RADEON_WRITE( RADEON_CP_RB_BASE, ring_start ); @@ -595,17 +603,29 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev ) *dev_priv->ring.head = cur_read_ptr; dev_priv->ring.tail = cur_read_ptr; - RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset ); + if ( !dev_priv->is_pci ) { + RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, + dev_priv->ring_rptr->offset ); + } else { + drm_sg_mem_t *entry = dev->sg; + unsigned long tmp_ofs, page_ofs; + + tmp_ofs = dev_priv->ring_rptr->offset - dev->sg->handle; + page_ofs = tmp_ofs >> PAGE_SHIFT; + + 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 ); + } /* Set ring buffer size */ RADEON_WRITE( RADEON_CP_RB_CNTL, dev_priv->ring.size_l2qw ); radeon_do_wait_for_idle( dev_priv ); - /* Turn off PCI GART */ - tmp = RADEON_READ( RADEON_AIC_CNTL ) & ~RADEON_PCIGART_TRANSLATE_EN; - RADEON_WRITE( RADEON_AIC_CNTL, tmp ); - /* Turn on bus mastering */ tmp = RADEON_READ( RADEON_BUS_CNTL ) & ~RADEON_BUS_MASTER_DIS; RADEON_WRITE( RADEON_BUS_CNTL, tmp ); @@ -621,9 +641,11 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev ) static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) { drm_radeon_private_t *dev_priv; - int i; + struct list_head *list; + u32 tmp; + DRM_DEBUG( "%s\n", __FUNCTION__ ); - dev_priv = drm_alloc( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); + dev_priv = DRM(alloc)( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); if ( dev_priv == NULL ) return -ENOMEM; dev->dev_private = (void *)dev_priv; @@ -632,12 +654,21 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->is_pci = init->is_pci; - /* We don't support PCI cards until PCI GART is implemented. - * Fail here so we can remove all checks for PCI cards around - * the CP ring code. +#if 1 + /* PCI support is not 100% working, so we disable it here. */ if ( dev_priv->is_pci ) { - drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); + DRM_ERROR( "PCI GART not yet supported for Radeon!\n" ); + DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); + dev->dev_private = NULL; + return -EINVAL; + } +#endif + + if ( dev_priv->is_pci && !dev->sg ) { + DRM_DEBUG( "PCI GART memory not allocated!\n" ); + DRM_ERROR( "PCI GART memory not allocated!\n" ); + DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; return -EINVAL; } @@ -645,7 +676,8 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->usec_timeout = init->usec_timeout; if ( dev_priv->usec_timeout < 1 || dev_priv->usec_timeout > RADEON_MAX_USEC_TIMEOUT ) { - drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); + DRM_DEBUG( "TIMEOUT problem!\n" ); + DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; return -EINVAL; } @@ -662,7 +694,8 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) */ if ( ( init->cp_mode != RADEON_CSQ_PRIBM_INDDIS ) && ( init->cp_mode != RADEON_CSQ_PRIBM_INDBM ) ) { - drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); + DRM_DEBUG( "BAD cp_mode (%x)!\n", init->cp_mode ); + DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; return -EINVAL; } @@ -722,55 +755,78 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) RADEON_BFACE_SOLID | RADEON_FFACE_SOLID | RADEON_FLAT_SHADE_VTX_LAST | - RADEON_DIFFUSE_SHADE_FLAT | RADEON_ALPHA_SHADE_FLAT | RADEON_SPECULAR_SHADE_FLAT | RADEON_FOG_SHADE_FLAT | - RADEON_VTX_PIX_CENTER_OGL | RADEON_ROUND_MODE_TRUNC | RADEON_ROUND_PREC_8TH_PIX); - /* FIXME: We want multiple shared areas, including one shared - * only by the X Server and kernel module. - */ - for ( i = 0 ; i < dev->map_count ; i++ ) { - if ( dev->maplist[i]->type == _DRM_SHM ) { - dev_priv->sarea = dev->maplist[i]; - break; - } - } - - DO_FIND_MAP( dev_priv->fb, init->fb_offset ); - DO_FIND_MAP( dev_priv->mmio, init->mmio_offset ); - DO_FIND_MAP( dev_priv->cp_ring, init->ring_offset ); - DO_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); - DO_FIND_MAP( dev_priv->buffers, init->buffers_offset ); + list_for_each(list, &dev->maplist->head) { + drm_map_list_t *r_list = (drm_map_list_t *)list; + if( r_list->map && + r_list->map->type == _DRM_SHM && + r_list->map->flags & _DRM_CONTAINS_LOCK ) { + dev_priv->sarea = r_list->map; + break; + } + } + + DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); + DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + DRM_FIND_MAP( dev_priv->cp_ring, init->ring_offset ); + DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); + DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); if ( !dev_priv->is_pci ) { - DO_FIND_MAP( dev_priv->agp_textures, - init->agp_textures_offset ); + DRM_FIND_MAP( dev_priv->agp_textures, + init->agp_textures_offset ); } dev_priv->sarea_priv = (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DO_IOREMAP( dev_priv->cp_ring ); - DO_IOREMAP( dev_priv->ring_rptr ); - DO_IOREMAP( dev_priv->buffers ); -#if 0 if ( !dev_priv->is_pci ) { - DO_IOREMAP( dev_priv->agp_textures ); + DRM_IOREMAP( dev_priv->cp_ring ); + DRM_IOREMAP( dev_priv->ring_rptr ); + DRM_IOREMAP( dev_priv->buffers ); + } else { + dev_priv->cp_ring->handle = + (void *)dev_priv->cp_ring->offset; + dev_priv->ring_rptr->handle = + (void *)dev_priv->ring_rptr->offset; + dev_priv->buffers->handle = (void *)dev_priv->buffers->offset; + + DRM_DEBUG( "dev_priv->cp_ring->handle %p\n", + dev_priv->cp_ring->handle ); + DRM_DEBUG( "dev_priv->ring_rptr->handle %p\n", + dev_priv->ring_rptr->handle ); + DRM_DEBUG( "dev_priv->buffers->handle %p\n", + dev_priv->buffers->handle ); } -#endif + dev_priv->agp_size = init->agp_size; dev_priv->agp_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE ); - dev_priv->agp_buffers_offset = (dev_priv->buffers->offset - - dev->agp->base - + dev_priv->agp_vm_start); +#if __REALLY_HAVE_AGP + if ( !dev_priv->is_pci ) + dev_priv->agp_buffers_offset = (dev_priv->buffers->offset + - dev->agp->base + + dev_priv->agp_vm_start); + else +#endif + dev_priv->agp_buffers_offset = (dev_priv->buffers->offset + - dev->sg->handle + + dev_priv->agp_vm_start); + + DRM_DEBUG( "dev_priv->agp_size %d\n", + dev_priv->agp_size ); + DRM_DEBUG( "dev_priv->agp_vm_start 0x%x\n", + dev_priv->agp_vm_start ); + DRM_DEBUG( "dev_priv->agp_buffers_offset 0x%lx\n", + dev_priv->agp_buffers_offset ); dev_priv->ring.head = ((__volatile__ u32 *) dev_priv->ring_rptr->handle); @@ -779,11 +835,13 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->ring.end = ((u32 *)dev_priv->cp_ring->handle + init->ring_size / sizeof(u32)); dev_priv->ring.size = init->ring_size; - dev_priv->ring.size_l2qw = drm_order( init->ring_size / 8 ); + dev_priv->ring.size_l2qw = DRM(order)( init->ring_size / 8 ); dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; + dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; + #if 0 /* Initialize the scratch register pointer. This will cause * the scratch register values to be written out to memory @@ -812,6 +870,44 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) RADEON_WRITE( RADEON_LAST_CLEAR_REG, 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 ) { + DRM_DEBUG( "failed to init PCI GART!\n" ); + DRM_ERROR( "failed to init PCI GART!\n" ); + DRM(free)( dev_priv, sizeof(*dev_priv), + DRM_MEM_DRIVER ); + dev->dev_private = NULL; + return -EINVAL; + } + /* Turn on PCI GART + */ + tmp = RADEON_READ( RADEON_AIC_CNTL ) + | RADEON_PCIGART_TRANSLATE_EN; + RADEON_WRITE( RADEON_AIC_CNTL, tmp ); + + /* set PCI GART page-table base address + */ + RADEON_WRITE( RADEON_AIC_PT_BASE, + virt_to_bus( (void *)dev_priv->phys_pci_gart ) ); + + /* set address range for PCI address translate + */ + RADEON_WRITE( RADEON_AIC_LO_ADDR, dev_priv->agp_vm_start ); + RADEON_WRITE( RADEON_AIC_HI_ADDR, dev_priv->agp_vm_start + + dev_priv->agp_size - 1); + + /* Turn off AGP aperture -- is this required for PCIGART? + */ + RADEON_WRITE( RADEON_MC_AGP_LOCATION, 0 ); + } else { + /* Turn off PCI GART + */ + tmp = RADEON_READ( RADEON_AIC_CNTL ) + & ~RADEON_PCIGART_TRANSLATE_EN; + RADEON_WRITE( RADEON_AIC_CNTL, tmp ); + } + radeon_cp_load_microcode( dev_priv ); radeon_cp_init_ring_buffer( dev ); radeon_do_engine_reset( dev ); @@ -823,22 +919,21 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) return 0; } -static int radeon_do_cleanup_cp( drm_device_t *dev ) +int radeon_do_cleanup_cp( drm_device_t *dev ) { + DRM_DEBUG( "%s\n", __FUNCTION__ ); + if ( dev->dev_private ) { drm_radeon_private_t *dev_priv = dev->dev_private; - DO_IOREMAPFREE( dev_priv->cp_ring ); - DO_IOREMAPFREE( dev_priv->ring_rptr ); - DO_IOREMAPFREE( dev_priv->buffers ); -#if 0 if ( !dev_priv->is_pci ) { - DO_IOREMAPFREE( dev_priv->agp_textures ); + DRM_IOREMAPFREE( dev_priv->cp_ring ); + DRM_IOREMAPFREE( dev_priv->ring_rptr ); + DRM_IOREMAPFREE( dev_priv->buffers ); } -#endif - drm_free( dev->dev_private, sizeof(drm_radeon_private_t), - DRM_MEM_DRIVER ); + DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t), + DRM_MEM_DRIVER ); dev->dev_private = NULL; } @@ -873,11 +968,8 @@ int radeon_cp_start( struct inode *inode, struct file *filp, drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "%s\n", __FUNCTION__ ); - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); + if ( dev_priv->cp_running ) { DRM_DEBUG( "%s while CP running\n", __FUNCTION__ ); return 0; @@ -906,11 +998,7 @@ int radeon_cp_stop( struct inode *inode, struct file *filp, int ret; DRM_DEBUG( "%s\n", __FUNCTION__ ); - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); if ( copy_from_user( &stop, (drm_radeon_init_t *)arg, sizeof(stop) ) ) return -EFAULT; @@ -952,11 +1040,8 @@ int radeon_cp_reset( struct inode *inode, struct file *filp, drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "%s\n", __FUNCTION__ ); - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); + if ( !dev_priv ) { DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); return -EINVAL; @@ -978,11 +1063,7 @@ int radeon_cp_idle( struct inode *inode, struct file *filp, drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "%s\n", __FUNCTION__ ); - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); return radeon_do_cp_idle( dev_priv ); } @@ -994,11 +1075,7 @@ int radeon_engine_reset( struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; DRM_DEBUG( "%s\n", __FUNCTION__ ); - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); return radeon_do_engine_reset( dev ); } @@ -1048,11 +1125,7 @@ int radeon_fullscreen( struct inode *inode, struct file *filp, drm_device_t *dev = priv->dev; drm_radeon_fullscreen_t fs; - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); if ( copy_from_user( &fs, (drm_radeon_fullscreen_t *)arg, sizeof(fs) ) ) @@ -1085,8 +1158,8 @@ static int radeon_freelist_init( drm_device_t *dev ) drm_radeon_freelist_t *entry; int i; - dev_priv->head = drm_alloc( sizeof(drm_radeon_freelist_t), - DRM_MEM_DRIVER ); + dev_priv->head = DRM(alloc)( sizeof(drm_radeon_freelist_t), + DRM_MEM_DRIVER ); if ( dev_priv->head == NULL ) return -ENOMEM; @@ -1097,8 +1170,8 @@ static int radeon_freelist_init( drm_device_t *dev ) buf = dma->buflist[i]; buf_priv = buf->dev_private; - entry = drm_alloc( sizeof(drm_radeon_freelist_t), - DRM_MEM_DRIVER ); + entry = DRM(alloc)( sizeof(drm_radeon_freelist_t), + DRM_MEM_DRIVER ); if ( !entry ) return -ENOMEM; entry->age = RADEON_BUFFER_FREE; @@ -1218,32 +1291,20 @@ int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n ) int i; for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - ring->space = *ring->head - ring->tail; - if ( ring->space <= 0 ) - ring->space += ring->size; - - if ( ring->space >= n ) + radeon_update_ring_snapshot( ring ); + if ( ring->space > n ) return 0; - udelay( 1 ); } /* FIXME: This return value is ignored in the BEGIN_RING macro! */ +#if RADEON_FIFO_DEBUG + radeon_status( dev_priv ); DRM_ERROR( "failed!\n" ); +#endif return -EBUSY; } -void radeon_update_ring_snapshot( drm_radeon_private_t *dev_priv ) -{ - drm_radeon_ring_buffer_t *ring = &dev_priv->ring; - - ring->space = *ring->head - ring->tail; - if ( ring->space == 0 ) - atomic_inc( &dev_priv->idle_count ); - if ( ring->space <= 0 ) - ring->space += ring->size; -} - static int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d ) { int i; @@ -1276,14 +1337,10 @@ int radeon_cp_buffers( struct inode *inode, struct file *filp, int ret = 0; drm_dma_t d; - if ( copy_from_user( &d, (drm_dma_t *) arg, sizeof(d) ) ) - return -EFAULT; + LOCK_TEST_WITH_RETURN( dev ); - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + if ( copy_from_user( &d, (drm_dma_t *)arg, sizeof(d) ) ) + return -EFAULT; /* Please don't send us buffers. */ @@ -1307,7 +1364,7 @@ int radeon_cp_buffers( struct inode *inode, struct file *filp, ret = radeon_cp_get_buffers( dev, &d ); } - if ( copy_to_user( (drm_dma_t *) arg, &d, sizeof(d) ) ) + if ( copy_to_user( (drm_dma_t *)arg, &d, sizeof(d) ) ) return -EFAULT; return ret; diff --git a/linux/radeon_drm.h b/linux/radeon_drm.h index c5f9f66d..4ae387ff 100644 --- a/linux/radeon_drm.h +++ b/linux/radeon_drm.h @@ -26,7 +26,6 @@ * Authors: * Kevin E. Martin <martin@valinux.com> * Gareth Hughes <gareth@valinux.com> - * */ #ifndef __RADEON_DRM_H__ @@ -74,7 +73,7 @@ /* Vertex/indirect buffer size */ -#define RADEON_BUFFER_SIZE 16384 +#define RADEON_BUFFER_SIZE 65536 /* Byte offsets for indirect buffer data */ @@ -237,7 +236,7 @@ typedef struct drm_radeon_init { RADEON_INIT_CP = 0x01, RADEON_CLEANUP_CP = 0x02 } func; - int sarea_priv_offset; + unsigned long sarea_priv_offset; int is_pci; int cp_mode; int agp_size; @@ -250,12 +249,12 @@ typedef struct drm_radeon_init { unsigned int depth_bpp; unsigned int depth_offset, depth_pitch; - unsigned int fb_offset; - unsigned int mmio_offset; - unsigned int ring_offset; - unsigned int ring_rptr_offset; - unsigned int buffers_offset; - unsigned int agp_textures_offset; + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; } drm_radeon_init_t; typedef struct drm_radeon_cp_stop { @@ -276,15 +275,18 @@ typedef struct drm_radeon_fullscreen { #define CLEAR_Y2 3 #define CLEAR_DEPTH 4 +typedef union drm_radeon_clear_rect { + float f[5]; + unsigned int ui[5]; +} drm_radeon_clear_rect_t; + typedef struct drm_radeon_clear { unsigned int flags; - int x, y, w, h; unsigned int clear_color; unsigned int clear_depth; - union { - float f[5]; - unsigned int ui[5]; - } rect; + unsigned int color_mask; + unsigned int depth_mask; + drm_radeon_clear_rect_t *depth_boxes; } drm_radeon_clear_t; typedef struct drm_radeon_vertex { @@ -302,14 +304,20 @@ typedef struct drm_radeon_indices { int discard; /* Client finished with buffer? */ } drm_radeon_indices_t; -typedef struct drm_radeon_blit { - int idx; - int pitch; +typedef struct drm_radeon_tex_image { + unsigned int x, y; /* Blit coordinates */ + unsigned int width, height; + const void *data; +} drm_radeon_tex_image_t; + +typedef struct drm_radeon_texture { int offset; + int pitch; int format; - unsigned short x, y; - unsigned short width, height; -} drm_radeon_blit_t; + int width; /* Texture image coordinates */ + int height; + drm_radeon_tex_image_t *image; +} drm_radeon_texture_t; typedef struct drm_radeon_stipple { unsigned int *mask; diff --git a/linux/radeon_drv.c b/linux/radeon_drv.c index b022c3bb..d7632667 100644 --- a/linux/radeon_drv.c +++ b/linux/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" diff --git a/linux/radeon_drv.h b/linux/radeon_drv.h index 06b54199..24935847 100644 --- a/linux/radeon_drv.h +++ b/linux/radeon_drv.h @@ -24,10 +24,8 @@ * DEALINGS IN THE SOFTWARE. * * Authors: - * Rickard E. (Rik) Faith <faith@valinux.com> - * Kevin E. Martin <martin@valinux.com> - * Gareth Hughes <gareth@valinux.com> - * + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> */ #ifndef __RADEON_DRV_H__ @@ -50,6 +48,8 @@ typedef struct drm_radeon_ring_buffer { u32 tail; u32 tail_mask; int space; + + int high_mark; } drm_radeon_ring_buffer_t; typedef struct drm_radeon_depth_clear_t { @@ -64,7 +64,7 @@ typedef struct drm_radeon_private { int agp_size; u32 agp_vm_start; - u32 agp_buffers_offset; + unsigned long agp_buffers_offset; int cp_mode; int cp_running; @@ -83,6 +83,7 @@ typedef struct drm_radeon_private { int usec_timeout; int is_pci; + unsigned long phys_pci_gart; atomic_t idle_count; @@ -91,13 +92,13 @@ typedef struct drm_radeon_private { u32 crtc_offset; u32 crtc_offset_cntl; - unsigned int color_fmt; + u32 color_fmt; unsigned int front_offset; unsigned int front_pitch; unsigned int back_offset; unsigned int back_pitch; - unsigned int depth_fmt; + u32 depth_fmt; unsigned int depth_offset; unsigned int depth_pitch; @@ -124,18 +125,6 @@ typedef struct drm_radeon_buf_priv { drm_radeon_freelist_t *list_entry; } drm_radeon_buf_priv_t; - /* radeon_drv.c */ -extern int radeon_version( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_open( struct inode *inode, struct file *filp ); -extern int radeon_release( struct inode *inode, struct file *filp ); -extern int radeon_ioctl( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_lock( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_unlock( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); - /* radeon_cp.c */ extern int radeon_cp_init( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -158,9 +147,17 @@ extern void radeon_freelist_reset( drm_device_t *dev ); extern drm_buf_t *radeon_freelist_get( drm_device_t *dev ); extern int radeon_wait_ring( drm_radeon_private_t *dev_priv, int n ); -extern void radeon_update_ring_snapshot( drm_radeon_private_t *dev_priv ); + +static inline void +radeon_update_ring_snapshot( drm_radeon_ring_buffer_t *ring ) +{ + ring->space = (*(volatile int *)ring->head - ring->tail) * sizeof(u32); + if ( ring->space <= 0 ) + ring->space += ring->size; +} extern int radeon_do_cp_idle( drm_radeon_private_t *dev_priv ); +extern int radeon_do_cleanup_cp( drm_device_t *dev ); extern int radeon_do_cleanup_pageflip( drm_device_t *dev ); /* radeon_state.c */ @@ -172,38 +169,13 @@ extern int radeon_cp_vertex( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); extern int radeon_cp_indices( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); -extern int radeon_cp_blit( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); +extern int radeon_cp_texture( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); extern int radeon_cp_stipple( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); extern int radeon_cp_indirect( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); - /* radeon_bufs.c */ -extern int radeon_addbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int radeon_mapbufs(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); - - /* radeon_context.c */ -extern int radeon_resctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int radeon_addctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int radeon_modctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int radeon_getctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int radeon_switchctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int radeon_newctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int radeon_rmctx(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); - -extern int radeon_context_switch(drm_device_t *dev, int old, int new); -extern int radeon_context_switch_complete(drm_device_t *dev, int new); - /* Register definitions, register access macros and drmAddMap constants * for Radeon kernel driver. @@ -462,6 +434,12 @@ extern int radeon_context_switch_complete(drm_device_t *dev, int new); #define RADEON_AIC_CNTL 0x01d0 # define RADEON_PCIGART_TRANSLATE_EN (1 << 0) +#define RADEON_AIC_STAT 0x01d4 +#define RADEON_AIC_PT_BASE 0x01d8 +#define RADEON_AIC_LO_ADDR 0x01dc +#define RADEON_AIC_HI_ADDR 0x01e0 +#define RADEON_AIC_TLB_ADDR 0x01e4 +#define RADEON_AIC_TLB_DATA 0x01e8 /* CP command packets */ #define RADEON_CP_PACKET0 0x00000000 @@ -514,14 +492,14 @@ extern int radeon_context_switch_complete(drm_device_t *dev, int new); #define RADEON_COLOR_FORMAT_RGB8 9 #define RADEON_COLOR_FORMAT_ARGB4444 15 -#define RADEON_TXF_8BPP_I 0 -#define RADEON_TXF_16BPP_AI88 1 -#define RADEON_TXF_8BPP_RGB332 2 -#define RADEON_TXF_16BPP_ARGB1555 3 -#define RADEON_TXF_16BPP_RGB565 4 -#define RADEON_TXF_16BPP_ARGB4444 5 -#define RADEON_TXF_32BPP_ARGB8888 6 -#define RADEON_TXF_32BPP_RGBA8888 7 +#define RADEON_TXFORMAT_I8 0 +#define RADEON_TXFORMAT_AI88 1 +#define RADEON_TXFORMAT_RGB332 2 +#define RADEON_TXFORMAT_ARGB1555 3 +#define RADEON_TXFORMAT_RGB565 4 +#define RADEON_TXFORMAT_ARGB4444 5 +#define RADEON_TXFORMAT_ARGB8888 6 +#define RADEON_TXFORMAT_RGBA8888 7 /* Constants */ #define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */ @@ -534,27 +512,51 @@ extern int radeon_context_switch_complete(drm_device_t *dev, int new); #define RADEON_MAX_VB_AGE 0x7fffffff #define RADEON_MAX_VB_VERTS (0xffff) +#define RADEON_RING_HIGH_MARK 128 -#define RADEON_BASE(reg) ((u32)(dev_priv->mmio->handle)) -#define RADEON_ADDR(reg) (RADEON_BASE(reg) + reg) -#define RADEON_DEREF(reg) *(__volatile__ u32 *)RADEON_ADDR(reg) -#define RADEON_READ(reg) RADEON_DEREF(reg) -#define RADEON_WRITE(reg,val) do { RADEON_DEREF(reg) = val; } while (0) +#define RADEON_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) +#define RADEON_ADDR(reg) (RADEON_BASE( reg ) + reg) -#define RADEON_DEREF8(reg) *(__volatile__ u8 *)RADEON_ADDR(reg) -#define RADEON_READ8(reg) RADEON_DEREF8(reg) -#define RADEON_WRITE8(reg,val) do { RADEON_DEREF8(reg) = val; } while (0) +#define RADEON_DEREF(reg) *(volatile u32 *)RADEON_ADDR( reg ) +#ifdef __alpha__ +#define RADEON_READ(reg) (_RADEON_READ((u32 *)RADEON_ADDR( reg ))) +static inline u32 _RADEON_READ(u32 *addr) { + mb(); + return *(volatile u32 *)addr; +} +#define RADEON_WRITE(reg,val) do { \ + wmb(); + RADEON_DEREF(reg) = val; +} while (0) +#else +#define RADEON_READ(reg) RADEON_DEREF( reg ) +#define RADEON_WRITE(reg, val) do { RADEON_DEREF( reg ) = val; } while (0) +#endif -#define RADEON_WRITE_PLL(addr,val) \ -do { \ - RADEON_WRITE8(RADEON_CLOCK_CNTL_INDEX, \ - ((addr) & 0x1f) | RADEON_PLL_WR_EN); \ - RADEON_WRITE(RADEON_CLOCK_CNTL_DATA, (val)); \ +#define RADEON_DEREF8(reg) *(volatile u8 *)RADEON_ADDR( reg ) +#ifdef __alpha__ +#define RADEON_READ8(reg) _RADEON_READ8((u8 *)RADEON_ADDR( reg )) +static inline u8 _RADEON_READ8(u8 *addr) { + mb(); + return *(volatile u8 *)addr; +} +#define RADEON_WRITE8(reg,val) do { \ + wmb(); + RADEON_DEREF8( reg ) = val; } while (0) +#else +#define RADEON_READ8(reg) RADEON_DEREF8( reg ) +#define RADEON_WRITE8(reg, val) do { RADEON_DEREF8( reg ) = val; } while (0) +#endif -extern int RADEON_READ_PLL(drm_device_t *dev, int addr); +#define RADEON_WRITE_PLL( addr, val ) do { \ + RADEON_WRITE8( RADEON_CLOCK_CNTL_INDEX, \ + ((addr) & 0x1f) | RADEON_PLL_WR_EN ); \ + RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \ +} while (0) +extern int RADEON_READ_PLL( drm_device_t *dev, int addr ); #define CP_PACKET0( reg, n ) \ @@ -573,54 +575,46 @@ extern int RADEON_READ_PLL(drm_device_t *dev, int addr); * Engine control helper macros */ -#define RADEON_WAIT_UNTIL_2D_IDLE() \ -do { \ +#define RADEON_WAIT_UNTIL_2D_IDLE() do { \ OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ OUT_RING( (RADEON_WAIT_2D_IDLECLEAN | \ RADEON_WAIT_HOST_IDLECLEAN) ); \ } while (0) -#define RADEON_WAIT_UNTIL_3D_IDLE() \ -do { \ +#define RADEON_WAIT_UNTIL_3D_IDLE() do { \ OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ OUT_RING( (RADEON_WAIT_3D_IDLECLEAN | \ RADEON_WAIT_HOST_IDLECLEAN) ); \ } while (0) -#define RADEON_WAIT_UNTIL_IDLE() \ -do { \ +#define RADEON_WAIT_UNTIL_IDLE() do { \ OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ OUT_RING( (RADEON_WAIT_2D_IDLECLEAN | \ RADEON_WAIT_3D_IDLECLEAN | \ RADEON_WAIT_HOST_IDLECLEAN) ); \ } while (0) -#define RADEON_WAIT_UNTIL_PAGE_FLIPPED() \ -do { \ +#define RADEON_WAIT_UNTIL_PAGE_FLIPPED() do { \ OUT_RING( CP_PACKET0( RADEON_WAIT_UNTIL, 0 ) ); \ OUT_RING( RADEON_WAIT_CRTC_PFLIP ); \ } while (0) -#define RADEON_FLUSH_CACHE() \ -do { \ +#define RADEON_FLUSH_CACHE() do { \ OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \ OUT_RING( RADEON_RB2D_DC_FLUSH ); \ } while (0) -#define RADEON_PURGE_CACHE() \ -do { \ +#define RADEON_PURGE_CACHE() do { \ OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \ OUT_RING( RADEON_RB2D_DC_FLUSH_ALL ); \ } while (0) -#define RADEON_FLUSH_ZCACHE() \ -do { \ +#define RADEON_FLUSH_ZCACHE() do { \ OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ OUT_RING( RADEON_RB3D_ZC_FLUSH ); \ } while (0) -#define RADEON_PURGE_ZCACHE() \ -do { \ +#define RADEON_PURGE_ZCACHE() do { \ OUT_RING( CP_PACKET0( RADEON_RB3D_ZCACHE_CTLSTAT, 0 ) ); \ OUT_RING( RADEON_RB3D_ZC_FLUSH_ALL ); \ } while (0) @@ -630,7 +624,33 @@ do { \ * Misc helper macros */ -#define VB_AGE_CHECK_WITH_RET( dev_priv ) \ +#define LOCK_TEST_WITH_RETURN( dev ) \ +do { \ + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ + dev->lock.pid != current->pid ) { \ + DRM_ERROR( "%s called without lock held\n", \ + __FUNCTION__ ); \ + return -EINVAL; \ + } \ +} while (0) + +#define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ +do { \ + drm_radeon_ring_buffer_t *ring = &dev_priv->ring; int i; \ + if ( ring->space < ring->high_mark ) { \ + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { \ + radeon_update_ring_snapshot( ring ); \ + if ( ring->space >= ring->high_mark ) \ + goto __ring_space_done; \ + udelay( 1 ); \ + } \ + DRM_ERROR( "ring space check failed!\n" ); \ + return -EBUSY; \ + } \ + __ring_space_done: \ +} while (0) + +#define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ do { \ drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; \ if ( sarea_priv->last_dispatch >= RADEON_MAX_VB_AGE ) { \ @@ -641,20 +661,17 @@ do { \ } \ } while (0) -#define RADEON_DISPATCH_AGE( age ) \ -do { \ +#define RADEON_DISPATCH_AGE( age ) do { \ OUT_RING( CP_PACKET0( RADEON_LAST_DISPATCH_REG, 0 ) ); \ OUT_RING( age ); \ } while (0) -#define RADEON_FRAME_AGE( age ) \ -do { \ +#define RADEON_FRAME_AGE( age ) do { \ OUT_RING( CP_PACKET0( RADEON_LAST_FRAME_REG, 0 ) ); \ OUT_RING( age ); \ } while (0) -#define RADEON_CLEAR_AGE( age ) \ -do { \ +#define RADEON_CLEAR_AGE( age ) do { \ OUT_RING( CP_PACKET0( RADEON_LAST_CLEAR_REG, 0 ) ); \ OUT_RING( age ); \ } while (0) @@ -676,7 +693,7 @@ do { \ DRM_INFO( "BEGIN_RING( %d ) in %s\n", \ n, __FUNCTION__ ); \ } \ - if ( dev_priv->ring.space < (n) * sizeof(u32) ) { \ + if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ radeon_wait_ring( dev_priv, (n) * sizeof(u32) ); \ } \ dev_priv->ring.space -= (n) * sizeof(u32); \ @@ -687,7 +704,7 @@ do { \ #define ADVANCE_RING() do { \ if ( RADEON_VERBOSE ) { \ - DRM_INFO( "ADVANCE_RING() tail=0x%06x wr=0x%06x\n", \ + DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ write, dev_priv->ring.tail ); \ } \ radeon_flush_write_combine(); \ diff --git a/linux/radeon_state.c b/linux/radeon_state.c index 7bfefb2c..0a209245 100644 --- a/linux/radeon_state.c +++ b/linux/radeon_state.c @@ -23,12 +23,12 @@ * DEALINGS IN THE SOFTWARE. * * Authors: - * Kevin E. Martin <martin@valinux.com> * Gareth Hughes <gareth@valinux.com> - * + * Kevin E. Martin <martin@valinux.com> */ #define __NO_VERSION__ +#include "radeon.h" #include "drmP.h" #include "radeon_drv.h" #include "drm.h" @@ -486,7 +486,8 @@ static void radeon_print_dirty( const char *msg, unsigned int flags ) } static void radeon_cp_dispatch_clear( drm_device_t *dev, - drm_radeon_clear_t *clear ) + drm_radeon_clear_t *clear, + drm_radeon_clear_rect_t *depth_boxes ) { drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -497,8 +498,6 @@ static void radeon_cp_dispatch_clear( drm_device_t *dev, RING_LOCALS; DRM_DEBUG( "%s\n", __FUNCTION__ ); - radeon_update_ring_snapshot( dev_priv ); - if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) { unsigned int tmp = flags; @@ -525,7 +524,7 @@ static void radeon_cp_dispatch_clear( drm_device_t *dev, RADEON_WAIT_UNTIL_3D_IDLE(); OUT_RING( CP_PACKET0( RADEON_DP_WRITE_MASK, 0 ) ); - OUT_RING( sarea_priv->context_state.rb3d_planemask ); + OUT_RING( clear->color_mask ); ADVANCE_RING(); @@ -609,17 +608,17 @@ static void radeon_cp_dispatch_clear( drm_device_t *dev, RADEON_VTX_FMT_RADEON_MODE | (3 << RADEON_NUM_VERTICES_SHIFT)) ); - OUT_RING( clear->rect.ui[CLEAR_X1] ); - OUT_RING( clear->rect.ui[CLEAR_Y1] ); - OUT_RING( clear->rect.ui[CLEAR_DEPTH] ); + OUT_RING( depth_boxes[i].ui[CLEAR_X1] ); + OUT_RING( depth_boxes[i].ui[CLEAR_Y1] ); + OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] ); - OUT_RING( clear->rect.ui[CLEAR_X1] ); - OUT_RING( clear->rect.ui[CLEAR_Y2] ); - OUT_RING( clear->rect.ui[CLEAR_DEPTH] ); + OUT_RING( depth_boxes[i].ui[CLEAR_X1] ); + OUT_RING( depth_boxes[i].ui[CLEAR_Y2] ); + OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] ); - OUT_RING( clear->rect.ui[CLEAR_X2] ); - OUT_RING( clear->rect.ui[CLEAR_Y2] ); - OUT_RING( clear->rect.ui[CLEAR_DEPTH] ); + OUT_RING( depth_boxes[i].ui[CLEAR_X2] ); + OUT_RING( depth_boxes[i].ui[CLEAR_Y2] ); + OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] ); ADVANCE_RING(); @@ -655,8 +654,6 @@ static void radeon_cp_dispatch_swap( drm_device_t *dev ) RING_LOCALS; DRM_DEBUG( "%s\n", __FUNCTION__ ); - radeon_update_ring_snapshot( dev_priv ); - #if RADEON_PERFORMANCE_BOXES /* Do some trivial performance monitoring... */ @@ -724,8 +721,6 @@ static void radeon_cp_dispatch_flip( drm_device_t *dev ) RING_LOCALS; DRM_DEBUG( "%s: page=%d\n", __FUNCTION__, dev_priv->current_page ); - radeon_update_ring_snapshot( dev_priv ); - #if RADEON_PERFORMANCE_BOXES /* Do some trivial performance monitoring... */ @@ -776,9 +771,7 @@ static void radeon_cp_dispatch_vertex( drm_device_t *dev, RING_LOCALS; DRM_DEBUG( "%s: nbox=%d\n", __FUNCTION__, sarea_priv->nbox ); - radeon_update_ring_snapshot( dev_priv ); - - if ( 1 ) + if ( 0 ) radeon_print_dirty( "dispatch_vertex", sarea_priv->dirty ); if ( buf->used ) { @@ -844,8 +837,6 @@ static void radeon_cp_dispatch_indirect( drm_device_t *dev, DRM_DEBUG( "indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end ); - radeon_update_ring_snapshot( dev_priv ); - if ( start != end ) { int offset = (dev_priv->agp_buffers_offset + buf->offset + start); @@ -908,8 +899,6 @@ static void radeon_cp_dispatch_indices( drm_device_t *dev, RING_LOCALS; DRM_DEBUG( "indices: s=%d e=%d c=%d\n", start, end, count ); - radeon_update_ring_snapshot( dev_priv ); - if ( 0 ) radeon_print_dirty( "dispatch_indices", sarea_priv->dirty ); @@ -971,50 +960,67 @@ static void radeon_cp_dispatch_indices( drm_device_t *dev, sarea_priv->nbox = 0; } -static int radeon_cp_dispatch_blit( drm_device_t *dev, - drm_radeon_blit_t *blit ) +#define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32)) + +static int radeon_cp_dispatch_texture( drm_device_t *dev, + drm_radeon_texture_t *tex, + drm_radeon_tex_image_t *image ) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; drm_radeon_buf_priv_t *buf_priv; u32 format; - u32 *data; - int dword_shift, dwords; + u32 *buffer; + u8 *data; + int size, dwords, tex_width, blit_width; + u32 y, height; + int ret = 0, i; RING_LOCALS; - DRM_DEBUG( "blit: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n", - blit->offset >> 10, blit->pitch, blit->format, - blit->x, blit->y, blit->width, blit->height ); - radeon_update_ring_snapshot( dev_priv ); + /* FIXME: Be smarter about this... + */ + buf = radeon_freelist_get( dev ); + if ( !buf ) return -EAGAIN; + + DRM_DEBUG( "tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n", + tex->offset >> 10, tex->pitch, tex->format, + image->x, image->y, image->width, image->height ); + + buf_priv = buf->dev_private; /* The compiler won't optimize away a division by a variable, * even if the only legal values are powers of two. Thus, we'll * use a shift instead. */ - switch ( blit->format ) { - case RADEON_TXF_32BPP_ARGB8888: - case RADEON_TXF_32BPP_RGBA8888: + switch ( tex->format ) { + case RADEON_TXFORMAT_ARGB8888: + case RADEON_TXFORMAT_RGBA8888: format = RADEON_COLOR_FORMAT_ARGB8888; - dword_shift = 0; + tex_width = tex->width * 4; + blit_width = image->width * 4; break; - case RADEON_TXF_16BPP_AI88: - case RADEON_TXF_16BPP_ARGB1555: - case RADEON_TXF_16BPP_RGB565: - case RADEON_TXF_16BPP_ARGB4444: + case RADEON_TXFORMAT_AI88: + case RADEON_TXFORMAT_ARGB1555: + case RADEON_TXFORMAT_RGB565: + case RADEON_TXFORMAT_ARGB4444: format = RADEON_COLOR_FORMAT_RGB565; - dword_shift = 1; + tex_width = tex->width * 2; + blit_width = image->width * 2; break; - case RADEON_TXF_8BPP_I: - case RADEON_TXF_8BPP_RGB332: + case RADEON_TXFORMAT_I8: + case RADEON_TXFORMAT_RGB332: format = RADEON_COLOR_FORMAT_CI8; - dword_shift = 2; + tex_width = tex->width * 1; + blit_width = image->width * 1; break; default: - DRM_ERROR( "invalid blit format %d\n", blit->format ); + DRM_ERROR( "invalid texture format %d\n", tex->format ); return -EINVAL; } + DRM_DEBUG( " tex=%dx%d blit=%d\n", + tex_width, tex->height, blit_width ); + /* Flush the pixel cache. This ensures no pixel data gets mixed * up with the texture data from the host data blit, otherwise * part of the texture image may be corrupted. @@ -1026,46 +1032,88 @@ static int radeon_cp_dispatch_blit( drm_device_t *dev, ADVANCE_RING(); - /* Dispatch the indirect buffer. + /* Make a copy of the parameters in case we have to update them + * for a multi-pass texture blit. */ - buf = dma->buflist[blit->idx]; - buf_priv = buf->dev_private; + y = image->y; + height = image->height; + data = (u8 *)image->data; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; - } - if ( buf->pending ) { - DRM_ERROR( "sending pending buffer %d\n", blit->idx ); - return -EINVAL; - } + size = height * blit_width; - buf_priv->discard = 1; + if ( size > RADEON_MAX_TEXTURE_SIZE ) { + /* Texture image is too large, do a multipass upload */ + ret = -EAGAIN; - dwords = (blit->width * blit->height) >> dword_shift; - if ( !dwords ) dwords = 1; + /* Adjust the blit size to fit the indirect buffer */ + height = RADEON_MAX_TEXTURE_SIZE / blit_width; + size = height * blit_width; - data = (u32 *)((char *)dev_priv->buffers->handle + buf->offset); + /* Update the input parameters for next time */ + image->y += height; + image->height -= height; + image->data = (char *)image->data + size; - data[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); - data[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | - RADEON_GMC_BRUSH_NONE | - (format << 8) | - RADEON_GMC_SRC_DATATYPE_COLOR | - RADEON_ROP3_S | - RADEON_DP_SRC_SOURCE_HOST_DATA | - RADEON_GMC_CLR_CMP_CNTL_DIS | - RADEON_GMC_WR_MSK_DIS); + if ( copy_to_user( tex->image, image, sizeof(*image) ) ) { + DRM_ERROR( "EFAULT on tex->image\n" ); + return -EFAULT; + } + } else if ( size < 4 ) { + size = 4; + } - data[2] = (blit->pitch << 22) | (blit->offset >> 10); - data[3] = 0xffffffff; - data[4] = 0xffffffff; - data[5] = (blit->y << 16) | blit->x; - data[6] = (blit->height << 16) | blit->width; - data[7] = dwords; + dwords = size / 4; + /* Dispatch the indirect buffer. + */ + buffer = (u32 *)((char *)dev_priv->buffers->handle + buf->offset); + + buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); + buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_NONE | + (format << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_HOST_DATA | + RADEON_GMC_CLR_CMP_CNTL_DIS | + RADEON_GMC_WR_MSK_DIS); + + buffer[2] = (tex->pitch << 22) | (tex->offset >> 10); + buffer[3] = 0xffffffff; + buffer[4] = 0xffffffff; + buffer[5] = (y << 16) | image->x; + buffer[6] = (height << 16) | image->width; + buffer[7] = dwords; + + buffer += 8; + + if ( tex_width >= 32 ) { + /* Texture image width is larger than the minimum, so we + * can upload it directly. + */ + if ( copy_from_user( buffer, data, dwords * sizeof(u32) ) ) { + DRM_ERROR( "EFAULT on data, %d dwords\n", dwords ); + return -EFAULT; + } + } else { + /* Texture image width is less than the minimum, so we + * need to pad out each image scanline to the minimum + * width. + */ + for ( i = 0 ; i < tex->height ; i++ ) { + if ( copy_from_user( buffer, data, tex_width ) ) { + DRM_ERROR( "EFAULT on pad, %d bytes\n", + tex_width ); + return -EFAULT; + } + buffer += 8; + data += tex_width; + } + } + + buf->pid = current->pid; buf->used = (dwords + 8) * sizeof(u32); + buf_priv->discard = 1; radeon_cp_dispatch_indirect( dev, buf, 0, buf->used ); @@ -1080,7 +1128,7 @@ static int radeon_cp_dispatch_blit( drm_device_t *dev, ADVANCE_RING(); - return 0; + return ret; } static void radeon_cp_dispatch_stipple( drm_device_t *dev, u32 *stipple ) @@ -1090,8 +1138,6 @@ static void radeon_cp_dispatch_stipple( drm_device_t *dev, u32 *stipple ) RING_LOCALS; DRM_DEBUG( "%s\n", __FUNCTION__ ); - radeon_update_ring_snapshot( dev_priv ); - BEGIN_RING( 35 ); OUT_RING( CP_PACKET0( RADEON_RE_STIPPLE_ADDR, 0 ) ); @@ -1118,22 +1164,25 @@ int radeon_cp_clear( struct inode *inode, struct file *filp, drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_radeon_clear_t clear; + drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; DRM_DEBUG( "%s\n", __FUNCTION__ ); - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); - if ( copy_from_user( &clear, (drm_radeon_clear_t *) arg, + if ( copy_from_user( &clear, (drm_radeon_clear_t *)arg, sizeof(clear) ) ) return -EFAULT; + RING_SPACE_TEST_WITH_RETURN( dev_priv ); + if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS ) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; - radeon_cp_dispatch_clear( dev, &clear ); + if ( copy_from_user( &depth_boxes, clear.depth_boxes, + sarea_priv->nbox * sizeof(depth_boxes[0]) ) ) + return -EFAULT; + + radeon_cp_dispatch_clear( dev, &clear, depth_boxes ); return 0; } @@ -1147,11 +1196,9 @@ int radeon_cp_swap( struct inode *inode, struct file *filp, drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; DRM_DEBUG( "%s\n", __FUNCTION__ ); - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); + + RING_SPACE_TEST_WITH_RETURN( dev_priv ); if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS ) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; @@ -1178,13 +1225,10 @@ int radeon_cp_vertex( struct inode *inode, struct file *filp, drm_radeon_buf_priv_t *buf_priv; drm_radeon_vertex_t vertex; - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } - if ( !dev_priv || dev_priv->is_pci ) { - DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); + LOCK_TEST_WITH_RETURN( dev ); + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return -EINVAL; } @@ -1207,7 +1251,8 @@ int radeon_cp_vertex( struct inode *inode, struct file *filp, return -EINVAL; } - VB_AGE_CHECK_WITH_RET( dev_priv ); + RING_SPACE_TEST_WITH_RETURN( dev_priv ); + VB_AGE_TEST_WITH_RETURN( dev_priv ); buf = dma->buflist[vertex.idx]; buf_priv = buf->dev_private; @@ -1243,13 +1288,10 @@ int radeon_cp_indices( struct inode *inode, struct file *filp, drm_radeon_indices_t elts; int count; - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } - if ( !dev_priv || dev_priv->is_pci ) { - DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); + LOCK_TEST_WITH_RETURN( dev ); + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return -EINVAL; } @@ -1272,7 +1314,8 @@ int radeon_cp_indices( struct inode *inode, struct file *filp, return -EINVAL; } - VB_AGE_CHECK_WITH_RET( dev_priv ); + RING_SPACE_TEST_WITH_RETURN( dev_priv ); + VB_AGE_TEST_WITH_RETURN( dev_priv ); buf = dma->buflist[elts.idx]; buf_priv = buf->dev_private; @@ -1308,37 +1351,34 @@ int radeon_cp_indices( struct inode *inode, struct file *filp, return 0; } -int radeon_cp_blit( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_texture( 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_radeon_private_t *dev_priv = dev->dev_private; - drm_device_dma_t *dma = dev->dma; - drm_radeon_blit_t blit; + drm_radeon_texture_t tex; + drm_radeon_tex_image_t image; - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); - if ( copy_from_user( &blit, (drm_radeon_blit_t *)arg, - sizeof(blit) ) ) + if ( copy_from_user( &tex, (drm_radeon_texture_t *)arg, sizeof(tex) ) ) return -EFAULT; - DRM_DEBUG( "%s: pid=%d index=%d\n", - __FUNCTION__, current->pid, blit.idx ); - - if ( blit.idx < 0 || blit.idx > dma->buf_count ) { - DRM_ERROR( "sending %d buffers (of %d max)\n", - blit.idx, dma->buf_count ); + if ( tex.image == NULL ) { + DRM_ERROR( "null texture image!\n" ); return -EINVAL; } - VB_AGE_CHECK_WITH_RET( dev_priv ); + if ( copy_from_user( &image, + (drm_radeon_tex_image_t *)tex.image, + sizeof(image) ) ) + return -EFAULT; + + RING_SPACE_TEST_WITH_RETURN( dev_priv ); + VB_AGE_TEST_WITH_RETURN( dev_priv ); - return radeon_cp_dispatch_blit( dev, &blit ); + return radeon_cp_dispatch_texture( dev, &tex, &image ); } int radeon_cp_stipple( struct inode *inode, struct file *filp, @@ -1346,23 +1386,21 @@ int radeon_cp_stipple( struct inode *inode, struct file *filp, { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; + drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_stipple_t stipple; u32 mask[32]; - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } + LOCK_TEST_WITH_RETURN( dev ); if ( copy_from_user( &stipple, (drm_radeon_stipple_t *)arg, sizeof(stipple) ) ) return -EFAULT; - if ( copy_from_user( &mask, stipple.mask, - 32 * sizeof(u32) ) ) + if ( copy_from_user( &mask, stipple.mask, 32 * sizeof(u32) ) ) return -EFAULT; + RING_SPACE_TEST_WITH_RETURN( dev_priv ); + radeon_cp_dispatch_stipple( dev, mask ); return 0; @@ -1380,13 +1418,10 @@ int radeon_cp_indirect( struct inode *inode, struct file *filp, drm_radeon_indirect_t indirect; RING_LOCALS; - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } - if ( !dev_priv || dev_priv->is_pci ) { - DRM_ERROR( "%s called with a PCI card\n", __FUNCTION__ ); + LOCK_TEST_WITH_RETURN( dev ); + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); return -EINVAL; } @@ -1423,7 +1458,8 @@ int radeon_cp_indirect( struct inode *inode, struct file *filp, return -EINVAL; } - VB_AGE_CHECK_WITH_RET( dev_priv ); + RING_SPACE_TEST_WITH_RETURN( dev_priv ); + VB_AGE_TEST_WITH_RETURN( dev_priv ); buf->used = indirect.end; buf_priv->discard = indirect.discard; diff --git a/shared-core/drm.h b/shared-core/drm.h index f1abaabf..3def97f7 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -126,10 +126,11 @@ typedef struct drm_control { } drm_control_t; typedef enum drm_map_type { - _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ - _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2, /* shared, cached */ - _DRM_AGP = 3 /* AGP/GART */ + _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /* no caching, no core dump */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3, /* AGP/GART */ + _DRM_SCATTER_GATHER = 4 /* Scatter/gather memory for PCI DMA */ } drm_map_type_t; typedef enum drm_map_flags { @@ -238,7 +239,8 @@ typedef struct drm_buf_desc { int high_mark; /* High water mark */ enum { _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ - _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ + _DRM_AGP_BUFFER = 0x02, /* Buffer is in agp space */ + _DRM_SG_BUFFER = 0x04 /* Scatter/gather memory buffer */ } flags; unsigned long agp_start; /* Start address of where the agp buffers * are in the agp aperture */ @@ -344,6 +346,11 @@ typedef struct drm_agp_info { unsigned short id_device; } drm_agp_info_t; +typedef struct drm_scatter_gather { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for mapping / unmapping */ +} drm_scatter_gather_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) @@ -399,6 +406,9 @@ typedef struct drm_agp_info { #define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) #define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) +#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t) +#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t) + /* MGA specific ioctls */ #define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x41, drm_lock_t) diff --git a/shared/drm.h b/shared/drm.h index f1abaabf..3def97f7 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -126,10 +126,11 @@ typedef struct drm_control { } drm_control_t; typedef enum drm_map_type { - _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ - _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2, /* shared, cached */ - _DRM_AGP = 3 /* AGP/GART */ + _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /* no caching, no core dump */ + _DRM_SHM = 2, /* shared, cached */ + _DRM_AGP = 3, /* AGP/GART */ + _DRM_SCATTER_GATHER = 4 /* Scatter/gather memory for PCI DMA */ } drm_map_type_t; typedef enum drm_map_flags { @@ -238,7 +239,8 @@ typedef struct drm_buf_desc { int high_mark; /* High water mark */ enum { _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ - _DRM_AGP_BUFFER = 0x02 /* Buffer is in agp space */ + _DRM_AGP_BUFFER = 0x02, /* Buffer is in agp space */ + _DRM_SG_BUFFER = 0x04 /* Scatter/gather memory buffer */ } flags; unsigned long agp_start; /* Start address of where the agp buffers * are in the agp aperture */ @@ -344,6 +346,11 @@ typedef struct drm_agp_info { unsigned short id_device; } drm_agp_info_t; +typedef struct drm_scatter_gather { + unsigned long size; /* In bytes -- will round to page boundary */ + unsigned long handle; /* Used for mapping / unmapping */ +} drm_scatter_gather_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) @@ -399,6 +406,9 @@ typedef struct drm_agp_info { #define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t) #define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t) +#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t) +#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t) + /* MGA specific ioctls */ #define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( 0x41, drm_lock_t) |