summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-core/drm_agpsupport.c21
-rw-r--r--linux-core/drm_bufs.c198
-rw-r--r--linux-core/drm_fops.c15
-rw-r--r--linux-core/drm_init.c4
-rw-r--r--linux-core/drm_ioctl.c21
-rw-r--r--linux-core/drm_memory.h1
-rw-r--r--linux-core/drm_vm.c74
-rw-r--r--linux/drm_agpsupport.h21
-rw-r--r--linux/drm_bufs.h198
-rw-r--r--linux/drm_fops.h15
-rw-r--r--linux/drm_init.h4
-rw-r--r--linux/drm_ioctl.h21
-rw-r--r--linux/drm_memory.h1
-rw-r--r--linux/drm_vm.h74
-rw-r--r--linux/r128.h4
-rw-r--r--linux/radeon.h4
16 files changed, 646 insertions, 30 deletions
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..16af7bd5 100644
--- a/linux-core/drm_bufs.c
+++ b/linux-core/drm_bufs.c
@@ -37,6 +37,10 @@
#define __HAVE_PCI_DMA 0
#endif
+#ifndef __HAVE_SG
+#define __HAVE_SG 0
+#endif
+
#ifndef DRIVER_BUF_PRIV_T
#define DRIVER_BUF_PRIV_T u32
#endif
@@ -103,13 +107,16 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
switch ( map->type ) {
case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER:
-#ifndef __sparc__
+#if !defined(__sparc__) && !defined(__alpha__)
if ( map->offset + map->size < map->offset ||
map->offset < virt_to_phys(high_memory) ) {
DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
return -EINVAL;
}
#endif
+#ifdef __alpha__
+ map->offset += dev->hose->mem_space->start;
+#endif
#if __REALLY_HAVE_MTRR
if ( map->type == _DRM_FRAME_BUFFER ||
(map->flags & _DRM_WRITE_COMBINING) ) {
@@ -135,10 +142,21 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
break;
#if __REALLY_HAVE_AGP
case _DRM_AGP:
+#ifdef __alpha__
+ map->offset += dev->hose->mem_space->start;
+#endif
map->offset = map->offset + dev->agp->base;
map->mtrr = dev->agp->agp_mtrr; /* for getmap */
break;
#endif
+ case _DRM_SCATTER_GATHER:
+ if (!dev->sg) {
+ DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
+ map->offset = map->offset + dev->sg->handle;
+ break;
+
default:
DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
return -EINVAL;
@@ -237,6 +255,7 @@ int DRM(rmmap)(struct inode *inode, struct file *filp,
vfree(map->handle);
break;
case _DRM_AGP:
+ case _DRM_SCATTER_GATHER:
break;
}
DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
@@ -565,6 +584,159 @@ int DRM(addbufs_pci)( struct inode *inode, struct file *filp,
}
#endif /* __HAVE_PCI_DMA */
+#ifdef __HAVE_SG
+int DRM(addbufs_sg)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_desc_t request;
+ drm_buf_entry_t *entry;
+ drm_buf_t *buf;
+ unsigned long offset;
+ unsigned long agp_offset;
+ int count;
+ int order;
+ int size;
+ int alignment;
+ int page_order;
+ int total;
+ int byte_count;
+ int i;
+
+ if ( !dma ) return -EINVAL;
+
+ if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
+ sizeof(request) ) )
+ return -EFAULT;
+
+ count = request.count;
+ order = DRM(order)( request.size );
+ size = 1 << order;
+
+ alignment = (request.flags & _DRM_PAGE_ALIGN)
+ ? PAGE_ALIGN(size) : size;
+ page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+ total = PAGE_SIZE << page_order;
+
+ byte_count = 0;
+ agp_offset = request.agp_start;
+
+ DRM_DEBUG( "count: %d\n", count );
+ DRM_DEBUG( "order: %d\n", order );
+ DRM_DEBUG( "size: %d\n", size );
+ DRM_DEBUG( "agp_offset: %ld\n", agp_offset );
+ DRM_DEBUG( "alignment: %d\n", alignment );
+ DRM_DEBUG( "page_order: %d\n", page_order );
+ DRM_DEBUG( "total: %d\n", total );
+
+ if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
+ if ( dev->queue_count ) return -EBUSY; /* Not while in use */
+
+ spin_lock( &dev->count_lock );
+ if ( dev->buf_use ) {
+ spin_unlock( &dev->count_lock );
+ return -EBUSY;
+ }
+ atomic_inc( &dev->buf_alloc );
+ spin_unlock( &dev->count_lock );
+
+ down( &dev->struct_sem );
+ entry = &dma->bufs[order];
+ if ( entry->buf_count ) {
+ up( &dev->struct_sem );
+ atomic_dec( &dev->buf_alloc );
+ return -ENOMEM; /* May only call once for each order */
+ }
+
+ entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
+ DRM_MEM_BUFS );
+ if ( !entry->buflist ) {
+ up( &dev->struct_sem );
+ atomic_dec( &dev->buf_alloc );
+ return -ENOMEM;
+ }
+ memset( entry->buflist, 0, count * sizeof(*entry->buflist) );
+
+ entry->buf_size = size;
+ entry->page_order = page_order;
+
+ offset = 0;
+
+ while ( entry->buf_count < count ) {
+ buf = &entry->buflist[entry->buf_count];
+ buf->idx = dma->buf_count + entry->buf_count;
+ buf->total = alignment;
+ buf->order = order;
+ buf->used = 0;
+
+ buf->offset = (dma->byte_count + offset);
+ buf->bus_address = agp_offset + offset;
+ buf->address = (void *)(agp_offset + offset + dev->sg->handle);
+ buf->next = NULL;
+ buf->waiting = 0;
+ buf->pending = 0;
+ init_waitqueue_head( &buf->dma_wait );
+ buf->pid = 0;
+
+ buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
+ buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
+ DRM_MEM_BUFS );
+ memset( buf->dev_private, 0, buf->dev_priv_size );
+
+#if __HAVE_DMA_HISTOGRAM
+ buf->time_queued = 0;
+ buf->time_dispatched = 0;
+ buf->time_completed = 0;
+ buf->time_freed = 0;
+#endif
+ DRM_DEBUG( "buffer %d @ %p\n",
+ entry->buf_count, buf->address );
+
+ offset += alignment;
+ entry->buf_count++;
+ byte_count += PAGE_SIZE << page_order;
+ }
+
+ DRM_DEBUG( "byte_count: %d\n", byte_count );
+
+ dma->buflist = DRM(realloc)( dma->buflist,
+ dma->buf_count * sizeof(*dma->buflist),
+ (dma->buf_count + entry->buf_count)
+ * sizeof(*dma->buflist),
+ DRM_MEM_BUFS );
+ for ( i = 0 ; i < entry->buf_count ; i++ ) {
+ dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+ }
+
+ dma->buf_count += entry->buf_count;
+ dma->byte_count += byte_count;
+
+ DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
+ DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );
+
+#if __HAVE_DMA_FREELIST
+ DRM(freelist_create)( &entry->freelist, entry->buf_count );
+ for ( i = 0 ; i < entry->buf_count ; i++ ) {
+ DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
+ }
+#endif
+ up( &dev->struct_sem );
+
+ request.count = entry->buf_count;
+ request.size = size;
+
+ if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
+ return -EFAULT;
+
+ dma->flags = _DRM_DMA_USE_SG;
+
+ atomic_dec( &dev->buf_alloc );
+ return 0;
+}
+#endif /* __HAVE_SG */
+
int DRM(addbufs)( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg )
{
@@ -579,6 +751,11 @@ int DRM(addbufs)( struct inode *inode, struct file *filp,
return DRM(addbufs_agp)( inode, filp, cmd, arg );
else
#endif
+#if __HAVE_SG
+ if ( request.flags & _DRM_SG_BUFFER )
+ return DRM(addbufs_sg)( inode, filp, cmd, arg );
+ else
+#endif
#if __HAVE_PCI_DMA
return DRM(addbufs_pci)( inode, filp, cmd, arg );
#else
@@ -760,7 +937,8 @@ int DRM(mapbufs)( struct inode *inode, struct file *filp,
return -EFAULT;
if ( request.count >= dma->buf_count ) {
- if ( __HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP) ) {
+ if ( (__HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP)) ||
+ (__HAVE_SG && (dma->flags & _DRM_DMA_USE_SG)) ) {
drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev );
if ( !map ) {
@@ -768,18 +946,34 @@ int DRM(mapbufs)( struct inode *inode, struct file *filp,
goto done;
}
+#if LINUX_VERSION_CODE <= 0x020402
down( &current->mm->mmap_sem );
+#else
+ down_write( &current->mm->mmap_sem );
+#endif
virtual = do_mmap( filp, 0, map->size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
(unsigned long)map->offset );
+#if LINUX_VERSION_CODE <= 0x020402
up( &current->mm->mmap_sem );
+#else
+ up_write( &current->mm->mmap_sem );
+#endif
} else {
+#if LINUX_VERSION_CODE <= 0x020402
down( &current->mm->mmap_sem );
+#else
+ down_write( &current->mm->mmap_sem );
+#endif
virtual = do_mmap( filp, 0, dma->byte_count,
PROT_READ | PROT_WRITE,
MAP_SHARED, 0 );
+#if LINUX_VERSION_CODE <= 0x020402
up( &current->mm->mmap_sem );
+#else
+ up_write( &current->mm->mmap_sem );
+#endif
}
if ( virtual > -1024UL ) {
/* Real error */
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_vm.c b/linux-core/drm_vm.c
index fb51926b..771c11bd 100644
--- a/linux-core/drm_vm.c
+++ b/linux-core/drm_vm.c
@@ -50,6 +50,12 @@ struct vm_operations_struct drm_vm_dma_ops = {
close: DRM(vm_close),
};
+struct vm_operations_struct drm_vm_sg_ops = {
+ nopage: DRM(vm_sg_nopage),
+ open: DRM(vm_open),
+ close: DRM(vm_close),
+};
+
#if LINUX_VERSION_CODE < 0x020317
unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address,
@@ -93,7 +99,7 @@ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
offset = address - vma->vm_start;
i = (unsigned long)map->handle + offset;
/* We have to walk page tables here because we need large SAREA's, and
- * they need to be virtually contigious in kernel space.
+ * they need to be virtually contiguous in kernel space.
*/
pgd = pgd_offset_k( i );
if( !pgd_present( *pgd ) ) return NOPAGE_OOM;
@@ -187,6 +193,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma)
vfree(map->handle);
break;
case _DRM_AGP:
+ case _DRM_SCATTER_GATHER:
break;
}
DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
@@ -230,6 +237,48 @@ struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
#endif
}
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#else
+ /* Return type changed in 2.3.23 */
+struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#endif
+{
+#if LINUX_VERSION_CODE >= 0x020300
+ drm_map_t *map = (drm_map_t *)vma->vm_private_data;
+#else
+ drm_map_t *map = (drm_map_t *)vma->vm_pte;
+#endif
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_sg_mem_t *entry = dev->sg;
+ unsigned long offset;
+ unsigned long map_offset;
+ unsigned long page_offset;
+ struct page *page;
+
+ if (!entry) return NOPAGE_SIGBUS; /* Error */
+ if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+ if (!entry->pagelist) return NOPAGE_OOM ; /* Nothing allocated */
+
+
+ offset = address - vma->vm_start;
+ map_offset = map->offset - dev->sg->handle;
+ page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
+ page = entry->pagelist[page_offset];
+ atomic_inc(&page->count); /* Dec. by kernel */
+
+#if LINUX_VERSION_CODE < 0x020317
+ return (unsigned long)virt_to_phys(page->virtual);
+#else
+ return page;
+#endif
+}
+
void DRM(vm_open)(struct vm_area_struct *vma)
{
drm_file_t *priv = vma->vm_file->private_data;
@@ -322,6 +371,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
drm_device_t *dev = priv->dev;
drm_map_t *map = NULL;
drm_map_list_t *r_list;
+ unsigned long offset = 0;
struct list_head *list;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
@@ -374,19 +424,26 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
}
#elif defined(__ia64__)
if (map->type != _DRM_AGP)
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ vma->vm_page_prot =
+ pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__powerpc__)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
#endif
vma->vm_flags |= VM_IO; /* not in core dump */
}
+#ifdef __alpha__
+ offset = dev->hose->dense_mem_base -
+ dev->hose->mem_space->start;
+#endif
if (remap_page_range(vma->vm_start,
- VM_OFFSET(vma),
+ VM_OFFSET(vma) + offset,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%lx\n",
map->type,
- vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+ vma->vm_start, vma->vm_end, VM_OFFSET(vma) + offset);
vma->vm_ops = &drm_vm_ops;
break;
case _DRM_SHM:
@@ -400,6 +457,15 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
DRM_KERNEL advisory is supported. */
vma->vm_flags |= VM_LOCKED;
break;
+ case _DRM_SCATTER_GATHER:
+ vma->vm_ops = &drm_vm_sg_ops;
+#if LINUX_VERSION_CODE >= 0x020300
+ vma->vm_private_data = (void *)map;
+#else
+ vma->vm_pte = (unsigned long)map;
+#endif
+ vma->vm_flags |= VM_LOCKED;
+ break;
default:
return -EINVAL; /* This should never happen. */
}
diff --git a/linux/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..16af7bd5 100644
--- a/linux/drm_bufs.h
+++ b/linux/drm_bufs.h
@@ -37,6 +37,10 @@
#define __HAVE_PCI_DMA 0
#endif
+#ifndef __HAVE_SG
+#define __HAVE_SG 0
+#endif
+
#ifndef DRIVER_BUF_PRIV_T
#define DRIVER_BUF_PRIV_T u32
#endif
@@ -103,13 +107,16 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
switch ( map->type ) {
case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER:
-#ifndef __sparc__
+#if !defined(__sparc__) && !defined(__alpha__)
if ( map->offset + map->size < map->offset ||
map->offset < virt_to_phys(high_memory) ) {
DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
return -EINVAL;
}
#endif
+#ifdef __alpha__
+ map->offset += dev->hose->mem_space->start;
+#endif
#if __REALLY_HAVE_MTRR
if ( map->type == _DRM_FRAME_BUFFER ||
(map->flags & _DRM_WRITE_COMBINING) ) {
@@ -135,10 +142,21 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
break;
#if __REALLY_HAVE_AGP
case _DRM_AGP:
+#ifdef __alpha__
+ map->offset += dev->hose->mem_space->start;
+#endif
map->offset = map->offset + dev->agp->base;
map->mtrr = dev->agp->agp_mtrr; /* for getmap */
break;
#endif
+ case _DRM_SCATTER_GATHER:
+ if (!dev->sg) {
+ DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
+ map->offset = map->offset + dev->sg->handle;
+ break;
+
default:
DRM(free)( map, sizeof(*map), DRM_MEM_MAPS );
return -EINVAL;
@@ -237,6 +255,7 @@ int DRM(rmmap)(struct inode *inode, struct file *filp,
vfree(map->handle);
break;
case _DRM_AGP:
+ case _DRM_SCATTER_GATHER:
break;
}
DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
@@ -565,6 +584,159 @@ int DRM(addbufs_pci)( struct inode *inode, struct file *filp,
}
#endif /* __HAVE_PCI_DMA */
+#ifdef __HAVE_SG
+int DRM(addbufs_sg)( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_device_dma_t *dma = dev->dma;
+ drm_buf_desc_t request;
+ drm_buf_entry_t *entry;
+ drm_buf_t *buf;
+ unsigned long offset;
+ unsigned long agp_offset;
+ int count;
+ int order;
+ int size;
+ int alignment;
+ int page_order;
+ int total;
+ int byte_count;
+ int i;
+
+ if ( !dma ) return -EINVAL;
+
+ if ( copy_from_user( &request, (drm_buf_desc_t *)arg,
+ sizeof(request) ) )
+ return -EFAULT;
+
+ count = request.count;
+ order = DRM(order)( request.size );
+ size = 1 << order;
+
+ alignment = (request.flags & _DRM_PAGE_ALIGN)
+ ? PAGE_ALIGN(size) : size;
+ page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
+ total = PAGE_SIZE << page_order;
+
+ byte_count = 0;
+ agp_offset = request.agp_start;
+
+ DRM_DEBUG( "count: %d\n", count );
+ DRM_DEBUG( "order: %d\n", order );
+ DRM_DEBUG( "size: %d\n", size );
+ DRM_DEBUG( "agp_offset: %ld\n", agp_offset );
+ DRM_DEBUG( "alignment: %d\n", alignment );
+ DRM_DEBUG( "page_order: %d\n", page_order );
+ DRM_DEBUG( "total: %d\n", total );
+
+ if ( order < DRM_MIN_ORDER || order > DRM_MAX_ORDER ) return -EINVAL;
+ if ( dev->queue_count ) return -EBUSY; /* Not while in use */
+
+ spin_lock( &dev->count_lock );
+ if ( dev->buf_use ) {
+ spin_unlock( &dev->count_lock );
+ return -EBUSY;
+ }
+ atomic_inc( &dev->buf_alloc );
+ spin_unlock( &dev->count_lock );
+
+ down( &dev->struct_sem );
+ entry = &dma->bufs[order];
+ if ( entry->buf_count ) {
+ up( &dev->struct_sem );
+ atomic_dec( &dev->buf_alloc );
+ return -ENOMEM; /* May only call once for each order */
+ }
+
+ entry->buflist = DRM(alloc)( count * sizeof(*entry->buflist),
+ DRM_MEM_BUFS );
+ if ( !entry->buflist ) {
+ up( &dev->struct_sem );
+ atomic_dec( &dev->buf_alloc );
+ return -ENOMEM;
+ }
+ memset( entry->buflist, 0, count * sizeof(*entry->buflist) );
+
+ entry->buf_size = size;
+ entry->page_order = page_order;
+
+ offset = 0;
+
+ while ( entry->buf_count < count ) {
+ buf = &entry->buflist[entry->buf_count];
+ buf->idx = dma->buf_count + entry->buf_count;
+ buf->total = alignment;
+ buf->order = order;
+ buf->used = 0;
+
+ buf->offset = (dma->byte_count + offset);
+ buf->bus_address = agp_offset + offset;
+ buf->address = (void *)(agp_offset + offset + dev->sg->handle);
+ buf->next = NULL;
+ buf->waiting = 0;
+ buf->pending = 0;
+ init_waitqueue_head( &buf->dma_wait );
+ buf->pid = 0;
+
+ buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T);
+ buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T),
+ DRM_MEM_BUFS );
+ memset( buf->dev_private, 0, buf->dev_priv_size );
+
+#if __HAVE_DMA_HISTOGRAM
+ buf->time_queued = 0;
+ buf->time_dispatched = 0;
+ buf->time_completed = 0;
+ buf->time_freed = 0;
+#endif
+ DRM_DEBUG( "buffer %d @ %p\n",
+ entry->buf_count, buf->address );
+
+ offset += alignment;
+ entry->buf_count++;
+ byte_count += PAGE_SIZE << page_order;
+ }
+
+ DRM_DEBUG( "byte_count: %d\n", byte_count );
+
+ dma->buflist = DRM(realloc)( dma->buflist,
+ dma->buf_count * sizeof(*dma->buflist),
+ (dma->buf_count + entry->buf_count)
+ * sizeof(*dma->buflist),
+ DRM_MEM_BUFS );
+ for ( i = 0 ; i < entry->buf_count ; i++ ) {
+ dma->buflist[i + dma->buf_count] = &entry->buflist[i];
+ }
+
+ dma->buf_count += entry->buf_count;
+ dma->byte_count += byte_count;
+
+ DRM_DEBUG( "dma->buf_count : %d\n", dma->buf_count );
+ DRM_DEBUG( "entry->buf_count : %d\n", entry->buf_count );
+
+#if __HAVE_DMA_FREELIST
+ DRM(freelist_create)( &entry->freelist, entry->buf_count );
+ for ( i = 0 ; i < entry->buf_count ; i++ ) {
+ DRM(freelist_put)( dev, &entry->freelist, &entry->buflist[i] );
+ }
+#endif
+ up( &dev->struct_sem );
+
+ request.count = entry->buf_count;
+ request.size = size;
+
+ if ( copy_to_user( (drm_buf_desc_t *)arg, &request, sizeof(request) ) )
+ return -EFAULT;
+
+ dma->flags = _DRM_DMA_USE_SG;
+
+ atomic_dec( &dev->buf_alloc );
+ return 0;
+}
+#endif /* __HAVE_SG */
+
int DRM(addbufs)( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg )
{
@@ -579,6 +751,11 @@ int DRM(addbufs)( struct inode *inode, struct file *filp,
return DRM(addbufs_agp)( inode, filp, cmd, arg );
else
#endif
+#if __HAVE_SG
+ if ( request.flags & _DRM_SG_BUFFER )
+ return DRM(addbufs_sg)( inode, filp, cmd, arg );
+ else
+#endif
#if __HAVE_PCI_DMA
return DRM(addbufs_pci)( inode, filp, cmd, arg );
#else
@@ -760,7 +937,8 @@ int DRM(mapbufs)( struct inode *inode, struct file *filp,
return -EFAULT;
if ( request.count >= dma->buf_count ) {
- if ( __HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP) ) {
+ if ( (__HAVE_AGP && (dma->flags & _DRM_DMA_USE_AGP)) ||
+ (__HAVE_SG && (dma->flags & _DRM_DMA_USE_SG)) ) {
drm_map_t *map = DRIVER_AGP_BUFFERS_MAP( dev );
if ( !map ) {
@@ -768,18 +946,34 @@ int DRM(mapbufs)( struct inode *inode, struct file *filp,
goto done;
}
+#if LINUX_VERSION_CODE <= 0x020402
down( &current->mm->mmap_sem );
+#else
+ down_write( &current->mm->mmap_sem );
+#endif
virtual = do_mmap( filp, 0, map->size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
(unsigned long)map->offset );
+#if LINUX_VERSION_CODE <= 0x020402
up( &current->mm->mmap_sem );
+#else
+ up_write( &current->mm->mmap_sem );
+#endif
} else {
+#if LINUX_VERSION_CODE <= 0x020402
down( &current->mm->mmap_sem );
+#else
+ down_write( &current->mm->mmap_sem );
+#endif
virtual = do_mmap( filp, 0, dma->byte_count,
PROT_READ | PROT_WRITE,
MAP_SHARED, 0 );
+#if LINUX_VERSION_CODE <= 0x020402
up( &current->mm->mmap_sem );
+#else
+ up_write( &current->mm->mmap_sem );
+#endif
}
if ( virtual > -1024UL ) {
/* Real error */
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_vm.h b/linux/drm_vm.h
index fb51926b..771c11bd 100644
--- a/linux/drm_vm.h
+++ b/linux/drm_vm.h
@@ -50,6 +50,12 @@ struct vm_operations_struct drm_vm_dma_ops = {
close: DRM(vm_close),
};
+struct vm_operations_struct drm_vm_sg_ops = {
+ nopage: DRM(vm_sg_nopage),
+ open: DRM(vm_open),
+ close: DRM(vm_close),
+};
+
#if LINUX_VERSION_CODE < 0x020317
unsigned long DRM(vm_nopage)(struct vm_area_struct *vma,
unsigned long address,
@@ -93,7 +99,7 @@ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma,
offset = address - vma->vm_start;
i = (unsigned long)map->handle + offset;
/* We have to walk page tables here because we need large SAREA's, and
- * they need to be virtually contigious in kernel space.
+ * they need to be virtually contiguous in kernel space.
*/
pgd = pgd_offset_k( i );
if( !pgd_present( *pgd ) ) return NOPAGE_OOM;
@@ -187,6 +193,7 @@ void DRM(vm_shm_close)(struct vm_area_struct *vma)
vfree(map->handle);
break;
case _DRM_AGP:
+ case _DRM_SCATTER_GATHER:
break;
}
DRM(free)(map, sizeof(*map), DRM_MEM_MAPS);
@@ -230,6 +237,48 @@ struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma,
#endif
}
+#if LINUX_VERSION_CODE < 0x020317
+unsigned long DRM(vm_sg_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#else
+ /* Return type changed in 2.3.23 */
+struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma,
+ unsigned long address,
+ int write_access)
+#endif
+{
+#if LINUX_VERSION_CODE >= 0x020300
+ drm_map_t *map = (drm_map_t *)vma->vm_private_data;
+#else
+ drm_map_t *map = (drm_map_t *)vma->vm_pte;
+#endif
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_sg_mem_t *entry = dev->sg;
+ unsigned long offset;
+ unsigned long map_offset;
+ unsigned long page_offset;
+ struct page *page;
+
+ if (!entry) return NOPAGE_SIGBUS; /* Error */
+ if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
+ if (!entry->pagelist) return NOPAGE_OOM ; /* Nothing allocated */
+
+
+ offset = address - vma->vm_start;
+ map_offset = map->offset - dev->sg->handle;
+ page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
+ page = entry->pagelist[page_offset];
+ atomic_inc(&page->count); /* Dec. by kernel */
+
+#if LINUX_VERSION_CODE < 0x020317
+ return (unsigned long)virt_to_phys(page->virtual);
+#else
+ return page;
+#endif
+}
+
void DRM(vm_open)(struct vm_area_struct *vma)
{
drm_file_t *priv = vma->vm_file->private_data;
@@ -322,6 +371,7 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
drm_device_t *dev = priv->dev;
drm_map_t *map = NULL;
drm_map_list_t *r_list;
+ unsigned long offset = 0;
struct list_head *list;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
@@ -374,19 +424,26 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
}
#elif defined(__ia64__)
if (map->type != _DRM_AGP)
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ vma->vm_page_prot =
+ pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__powerpc__)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
#endif
vma->vm_flags |= VM_IO; /* not in core dump */
}
+#ifdef __alpha__
+ offset = dev->hose->dense_mem_base -
+ dev->hose->mem_space->start;
+#endif
if (remap_page_range(vma->vm_start,
- VM_OFFSET(vma),
+ VM_OFFSET(vma) + offset,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%lx\n",
map->type,
- vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+ vma->vm_start, vma->vm_end, VM_OFFSET(vma) + offset);
vma->vm_ops = &drm_vm_ops;
break;
case _DRM_SHM:
@@ -400,6 +457,15 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
DRM_KERNEL advisory is supported. */
vma->vm_flags |= VM_LOCKED;
break;
+ case _DRM_SCATTER_GATHER:
+ vma->vm_ops = &drm_vm_sg_ops;
+#if LINUX_VERSION_CODE >= 0x020300
+ vma->vm_private_data = (void *)map;
+#else
+ vma->vm_pte = (unsigned long)map;
+#endif
+ vma->vm_flags |= VM_LOCKED;
+ break;
default:
return -EINVAL; /* This should never happen. */
}
diff --git a/linux/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/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:
*/