Merge part 2

This commit is contained in:
Jeff Hartmann 2001-02-28 18:47:39 +00:00
parent 7cbc7414db
commit 033735ef46
16 changed files with 1210 additions and 157 deletions

View file

@ -1,5 +1,5 @@
/* ati_pcigart.h -- ATI PCI GART support -*- linux-c -*-
* Created: Tue Jan 23 21:52:19 2000 by jhartmann@valinux.com
* Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com
*
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
@ -27,13 +27,100 @@
* Gareth Hughes <gareth@valinux.com>
*/
#ifndef _ATI_PCIGART_H_
#define _ATI_PCIGART_H_
#define __NO_VERSION__
#include "drmP.h"
#define ATI_PCIGART_TABLE_ORDER 3
#define ATI_PCIGART_TABLE_PAGES (1 << 3)
#define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture */
extern unsigned long ati_pcigart_init(drm_device_t *dev);
extern int ati_pcigart_cleanup(unsigned long address);
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;
int i;
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++ ) {
struct page *page = entry->pagelist[i];
pci_gart[i] = cpu_to_le32( virt_to_bus( page->virtual ) );
}
#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

@ -572,6 +572,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;
@ -652,6 +659,7 @@ typedef struct drm_device {
#if __REALLY_HAVE_AGP
drm_agp_head_t *agp;
#endif
drm_sg_mem_t *sg; /* Scatter gather memory */
unsigned long *ctx_bitmap;
void *dev_private;
drm_sigdata_t sigdata; /* For block_all_signals */
@ -706,6 +714,9 @@ extern unsigned long DRM(vm_shm_nopage_lock)(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,
@ -720,6 +731,10 @@ extern struct page *DRM(vm_shm_nopage_lock)(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);
@ -930,5 +945,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

@ -36,6 +36,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
@ -130,6 +134,13 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
map->offset = map->offset + dev->agp->base;
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;
@ -483,6 +494,160 @@ 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 )
{
@ -495,7 +660,11 @@ int DRM(addbufs)( struct inode *inode, struct file *filp,
#if __REALLY_HAVE_AGP
if ( request.flags & _DRM_AGP_BUFFER )
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 );
@ -678,7 +847,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,7 +81,9 @@
#ifndef __HAVE_COUNTERS
#define __HAVE_COUNTERS 0
#endif
#ifndef __HAVE_SG
#define __HAVE_SG 0
#endif
#ifndef DRIVER_PREINIT
#define DRIVER_PREINIT()
#endif
@ -174,6 +176,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
};
@ -402,6 +409,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 );
}

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

@ -56,6 +56,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,
@ -172,6 +178,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;
@ -354,6 +402,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

@ -1,123 +0,0 @@
/* ati_pcigart.c -- 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"
#include "ati_pcigart.h"
static unsigned long 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 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 ati_pcigart_init( drm_device_t *dev )
{
drm_sg_mem_t *entry = dev->sg;
unsigned long address;
unsigned long pages;
u32 *pci_gart;
int i;
if ( !entry ) {
DRM_ERROR( "no scatter/gather memory!\n" );
return 0;
}
address = 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++ ) {
struct page *page = entry->pagelist[i];
pci_gart[i] = cpu_to_le32( virt_to_bus( page->virtual ) );
}
#if __i386__
asm volatile ( "wbinvd" ::: "memory" );
#else
mb();
#endif
return address;
}
int ati_pcigart_cleanup( unsigned long address )
{
if ( address ) {
ati_free_pcigart_table( address );
}
return 0;
}

View file

@ -1,5 +1,5 @@
/* ati_pcigart.h -- ATI PCI GART support -*- linux-c -*-
* Created: Tue Jan 23 21:52:19 2000 by jhartmann@valinux.com
* Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com
*
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
@ -27,13 +27,100 @@
* Gareth Hughes <gareth@valinux.com>
*/
#ifndef _ATI_PCIGART_H_
#define _ATI_PCIGART_H_
#define __NO_VERSION__
#include "drmP.h"
#define ATI_PCIGART_TABLE_ORDER 3
#define ATI_PCIGART_TABLE_PAGES (1 << 3)
#define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture */
extern unsigned long ati_pcigart_init(drm_device_t *dev);
extern int ati_pcigart_cleanup(unsigned long address);
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;
int i;
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++ ) {
struct page *page = entry->pagelist[i];
pci_gart[i] = cpu_to_le32( virt_to_bus( page->virtual ) );
}
#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

@ -572,6 +572,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;
@ -652,6 +659,7 @@ typedef struct drm_device {
#if __REALLY_HAVE_AGP
drm_agp_head_t *agp;
#endif
drm_sg_mem_t *sg; /* Scatter gather memory */
unsigned long *ctx_bitmap;
void *dev_private;
drm_sigdata_t sigdata; /* For block_all_signals */
@ -706,6 +714,9 @@ extern unsigned long DRM(vm_shm_nopage_lock)(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,
@ -720,6 +731,10 @@ extern struct page *DRM(vm_shm_nopage_lock)(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);
@ -930,5 +945,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

@ -36,6 +36,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
@ -130,6 +134,13 @@ int DRM(addmap)( struct inode *inode, struct file *filp,
map->offset = map->offset + dev->agp->base;
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;
@ -483,6 +494,160 @@ 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 )
{
@ -495,7 +660,11 @@ int DRM(addbufs)( struct inode *inode, struct file *filp,
#if __REALLY_HAVE_AGP
if ( request.flags & _DRM_AGP_BUFFER )
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 );
@ -678,7 +847,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,7 +81,9 @@
#ifndef __HAVE_COUNTERS
#define __HAVE_COUNTERS 0
#endif
#ifndef __HAVE_SG
#define __HAVE_SG 0
#endif
#ifndef DRIVER_PREINIT
#define DRIVER_PREINIT()
#endif
@ -174,6 +176,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
};
@ -402,6 +409,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 );
}

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

@ -56,6 +56,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,
@ -172,6 +178,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;
@ -354,6 +402,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

@ -40,6 +40,7 @@
#define __MUST_HAVE_AGP 1
#define __HAVE_MTRR 1
#define __HAVE_CTX_BITMAP 1
#define __HAVE_SG 1
/* Driver customization:
*/

View file

@ -315,7 +315,13 @@ static void r128_cce_init_ring_buffer( drm_device_t *dev )
/* 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 +329,25 @@ 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,
@ -355,15 +378,12 @@ 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 ) {
DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER );
if ( dev_priv->is_pci && !dev->sg ) {
DRM_ERROR( "PCI GART memory not allocated!\n" );
drm_free( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER );
dev->dev_private = NULL;
return -EINVAL;
}
}
dev_priv->usec_timeout = init->usec_timeout;
if ( dev_priv->usec_timeout < 1 ||
@ -475,10 +495,25 @@ static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init )
dev_priv->sarea_priv =
(drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle +
init->sarea_priv_offset);
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;
}
DRM_IOREMAP( dev_priv->cce_ring );
DRM_IOREMAP( dev_priv->ring_rptr );
DRM_IOREMAP( dev_priv->buffers );
#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 +536,19 @@ 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_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 );

View file

@ -714,7 +714,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;
@ -1323,8 +1323,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;
}
@ -1386,8 +1386,9 @@ 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;
}