diff options
author | Kevin E Martin <kem@kem.org> | 2001-04-03 17:42:23 +0000 |
---|---|---|
committer | Kevin E Martin <kem@kem.org> | 2001-04-03 17:42:23 +0000 |
commit | a77ca07b8055d4d881bcc37aae728502ad883891 (patch) | |
tree | 63cac0145bf8f8437e6eef3be250d88d0ae122dc | |
parent | 287caa02b5874feb1a91cab9e5f3685cdedb1b83 (diff) | |
download | drm-a77ca07b8055d4d881bcc37aae728502ad883891.tar.gz |
- Port pcigart code from old pcigart branch and add Alpha support (Jay
Estabrook, Compaq)
- Fix a few problems to allow it to work on ix86
- Rage 128 support works fine, Radeon locks up after a few seconds
- TODO: Fix Radeon pcigart, port PPC changes
42 files changed, 1787 insertions, 158 deletions
diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 8aa27fd3..404840cd 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -68,11 +68,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) @@ -499,11 +494,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; 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..0c0de04c 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.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; } @@ -547,7 +550,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 +583,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 +678,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 +733,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 +747,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 +968,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 63cfb0d4..b82d1a26 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..ec759084 --- /dev/null +++ b/linux-core/drm_scatter.c @@ -0,0 +1,210 @@ +/* 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; + printk("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) printk("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..26906aee 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", @@ -378,15 +428,19 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) #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 +454,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..7e736541 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -33,6 +33,7 @@ #include "r128.h" #include "drmP.h" #include "r128_drv.h" +#include "ati_pcigart.h" #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." @@ -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 dba2037f..3791c5ec 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -31,6 +31,7 @@ #include "radeon.h" #include "drmP.h" #include "radeon_drv.h" +#include "ati_pcigart.h" #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." @@ -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..0c0de04c 100644 --- a/linux/drmP.h +++ b/linux/drmP.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; } @@ -547,7 +550,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 +583,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 +678,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 +733,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 +747,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 +968,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 63cfb0d4..b82d1a26 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..ec759084 --- /dev/null +++ b/linux/drm_scatter.h @@ -0,0 +1,210 @@ +/* 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; + printk("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) printk("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..26906aee 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", @@ -378,15 +428,19 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) #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 +454,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..8a98aced 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 ); @@ -312,10 +314,18 @@ 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 ); @@ -323,8 +333,24 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev ) /* 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 ); + + 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 ); @@ -532,6 +589,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..7e736541 100644 --- a/linux/r128_drv.c +++ b/linux/r128_drv.c @@ -33,6 +33,7 @@ #include "r128.h" #include "drmP.h" #include "r128_drv.h" +#include "ati_pcigart.h" #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." @@ -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..bf682998 100644 --- a/linux/r128_drv.h +++ b/linux/r128_drv.h @@ -67,6 +67,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; @@ -248,6 +250,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 @@ -373,17 +376,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 ) +#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) R128_DEREF( reg ) #define R128_WRITE(reg,val) do { R128_DEREF( reg ) = 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 +507,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 ) { \ diff --git a/linux/r128_state.c b/linux/r128_state.c index 9fc6b485..1006a77c 100644 --- a/linux/r128_state.c +++ b/linux/r128_state.c @@ -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; @@ -1299,8 +1299,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 +1362,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 ed8b1bbc..a1e57bcf 100644 --- a/linux/radeon_cp.c +++ b/linux/radeon_cp.c @@ -36,7 +36,7 @@ #include <linux/interrupt.h> /* For task queue support */ #include <linux/delay.h> -#define RADEON_FIFO_DEBUG 0 +#define RADEON_FIFO_DEBUG 1 /* CP microcode (from ATI) */ @@ -318,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 @@ -363,8 +373,14 @@ static int radeon_do_wait_for_fifo( drm_radeon_private_t *dev_priv, } #if RADEON_FIFO_DEBUG - DRM_ERROR( "failed!\n" ); - radeon_status( dev_priv ); + { + static int fails = 0; + if (!fails) { + DRM_ERROR( "failed!\n" ); + radeon_status( dev_priv ); + fails++; + } + } #endif return -EBUSY; } @@ -386,8 +402,14 @@ static int radeon_do_wait_for_idle( drm_radeon_private_t *dev_priv ) } #if RADEON_FIFO_DEBUG - DRM_ERROR( "failed!\n" ); - radeon_status( dev_priv ); + { + static int fails = 0; + if (!fails) { + DRM_ERROR( "failed!\n" ); + radeon_status( dev_priv ); + fails++; + } + } #endif return -EBUSY; } @@ -401,6 +423,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 ); @@ -419,6 +442,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; @@ -432,6 +456,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 ); @@ -449,6 +474,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 ); @@ -472,6 +498,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 ); @@ -485,6 +512,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; @@ -551,18 +580,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 ); @@ -575,17 +615,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 ); @@ -602,6 +654,8 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) { drm_radeon_private_t *dev_priv; struct list_head *list; + u32 tmp; + DRM_DEBUG( "%s\n", __FUNCTION__ ); dev_priv = DRM(alloc)( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); if ( dev_priv == NULL ) @@ -612,11 +666,9 @@ 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 ( 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; @@ -625,6 +677,7 @@ 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_DEBUG( "TIMEOUT problem!\n" ); DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; return -EINVAL; @@ -642,6 +695,7 @@ 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_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; @@ -735,15 +789,46 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DRM_IOREMAP( dev_priv->cp_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + if ( !dev_priv->is_pci ) { + 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 ); + } + 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); @@ -787,6 +872,41 @@ 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); + +#if 1 + /* ??? turn off AGP aperture */ + RADEON_WRITE( RADEON_MC_AGP_LOCATION, 0 ); +#endif + } 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 ); @@ -800,6 +920,8 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) 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; @@ -871,7 +993,7 @@ int radeon_cp_stop( struct inode *inode, struct file *filp, drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_cp_stop_t stop; int ret; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); LOCK_TEST_WITH_RETURN( dev ); diff --git a/linux/radeon_drm.h b/linux/radeon_drm.h index 50a7d6ed..4ae387ff 100644 --- a/linux/radeon_drm.h +++ b/linux/radeon_drm.h @@ -236,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; @@ -249,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 { diff --git a/linux/radeon_drv.c b/linux/radeon_drv.c index dba2037f..3791c5ec 100644 --- a/linux/radeon_drv.c +++ b/linux/radeon_drv.c @@ -31,6 +31,7 @@ #include "radeon.h" #include "drmP.h" #include "radeon_drv.h" +#include "ati_pcigart.h" #define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc." @@ -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 f176bb56..39b5c133 100644 --- a/linux/radeon_drv.h +++ b/linux/radeon_drv.h @@ -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; @@ -433,6 +434,12 @@ extern int radeon_cp_indirect( struct inode *inode, struct file *filp, #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 @@ -508,16 +515,36 @@ extern int radeon_cp_indirect( struct inode *inode, struct file *filp, #define RADEON_RING_HIGH_MARK 128 -#define RADEON_BASE(reg) ((u32)(dev_priv->mmio->handle)) +#define RADEON_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) #define RADEON_ADDR(reg) (RADEON_BASE( reg ) + reg) #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_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 #define RADEON_WRITE_PLL( addr, val ) do { \ RADEON_WRITE8( RADEON_CLOCK_CNTL_INDEX, \ @@ -673,7 +700,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 9360c43b..0a209245 100644 --- a/linux/radeon_state.c +++ b/linux/radeon_state.c @@ -1227,8 +1227,8 @@ int radeon_cp_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; } @@ -1290,8 +1290,8 @@ int radeon_cp_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; } @@ -1420,8 +1420,8 @@ int radeon_cp_indirect( 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/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) |