- 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
This commit is contained in:
Kevin E Martin 2001-04-03 17:42:23 +00:00
parent 287caa02b5
commit a77ca07b80
42 changed files with 1787 additions and 158 deletions

View file

@ -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;

138
linux-core/ati_pcigart.c Normal file
View file

@ -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;
}

View file

@ -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

View file

@ -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)))

View file

@ -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 ) {

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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.

View file

@ -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;
}

View file

@ -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"},

210
linux-core/drm_scatter.c Normal file
View file

@ -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;
}

View file

@ -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. */
}

View file

@ -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"

View file

@ -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"

View file

@ -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,6 +222,16 @@ tdfx.o: $(TDFXOBJS) $(LIBS)
sis.o: $(SISOBJS) $(LIBS)
$(LD) -r $^ -o $@
r128_drv.o: r128_drv.c
$(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@
r128.o: $(R128OBJS) $(LIBS)
$(LD) -r $^ -o $@
radeon_drv.o: radeon_drv.c
$(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@
radeon.o: $(RADEONOBJS) $(LIBS)
$(LD) -r $^ -o $@
ifeq ($(AGP),1)
mga_drv.o: mga_drv.c
$(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@
@ -229,15 +243,6 @@ i810_drv.o: i810_drv.c
i810.o: $(I810OBJS) $(LIBS)
$(LD) -r $^ -o $@
r128_drv.o: r128_drv.c
$(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@
r128.o: $(R128OBJS) $(LIBS)
$(LD) -r $^ -o $@
radeon_drv.o: radeon_drv.c
$(CC) $(MODCFLAGS) -DEXPORT_SYMTAB -I$(TREE) -c $< -o $@
radeon.o: $(RADEONOBJS) $(LIBS)
$(LD) -r $^ -o $@
endif
.PHONY: ChangeLog

138
linux/ati_pcigart.h Normal file
View file

@ -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;
}

View file

@ -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)

View file

@ -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

View file

@ -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)))

View file

@ -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 ) {

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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.

View file

@ -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;
}

View file

@ -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"},

210
linux/drm_scatter.h Normal file
View file

@ -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;
}

View file

@ -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. */
}

View file

@ -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 {

View file

@ -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:
*/

View file

@ -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;

View file

@ -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 {

View file

@ -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"

View file

@ -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 ) { \

View file

@ -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;
}

View file

@ -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:
*/

View file

@ -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 );

View file

@ -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 {

View file

@ -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"

View file

@ -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(); \

View file

@ -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;
}

View file

@ -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)

View file

@ -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)