Skip to content

Commit

Permalink
drm: updated DRM map patch for 32/64 bit systems
Browse files Browse the repository at this point in the history
I basically combined Paul's patches with additions that I had made
for PCI scatter gather.
I also tried more carefully to avoid problems with the same token
assigned multiple times while trying to use the base address in the
token if possible to gain as much backward compatibility as possible
for broken DRI clients.

From: Paul Mackerras <paulus@samba.org> and Egbert Eich <eich@suse.de>
Signed-off-by: Dave Airlie <airlied@linux.ie>
  • Loading branch information
Dave Airlie authored and Dave Airlie committed Aug 5, 2005
1 parent c73681e commit d1f2b55
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 54 deletions.
14 changes: 6 additions & 8 deletions drivers/char/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ typedef struct drm_dma_handle {
typedef struct drm_map_list {
struct list_head head; /**< list head */
drm_map_t *map; /**< mapping */
unsigned int user_token;
} drm_map_list_t;

typedef drm_map_t drm_local_map_t;
Expand Down Expand Up @@ -759,6 +760,7 @@ typedef struct drm_device {

struct drm_driver *driver;
drm_local_map_t *agp_buffer_map;
unsigned int agp_buffer_token;
drm_head_t primary; /**< primary screen head */
} drm_device_t;

Expand Down Expand Up @@ -1048,16 +1050,12 @@ static __inline__ void drm_core_ioremapfree(struct drm_map *map, struct drm_devi
drm_ioremapfree( map->handle, map->size, dev );
}

static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned long offset)
static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev, unsigned int token)
{
struct list_head *_list;
list_for_each( _list, &dev->maplist->head ) {
drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head );
if ( _entry->map &&
_entry->map->offset == offset ) {
drm_map_list_t *_entry;
list_for_each_entry(_entry, &dev->maplist->head, head)
if (_entry->user_token == token)
return _entry->map;
}
}
return NULL;
}

Expand Down
81 changes: 59 additions & 22 deletions drivers/char/drm/drm_bufs.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,41 @@ static drm_local_map_t *drm_find_matching_map(drm_device_t *dev,
return NULL;
}

#ifdef CONFIG_COMPAT
/*
* Used to allocate 32-bit handles for _DRM_SHM regions
* The 0x10000000 value is chosen to be out of the way of
* FB/register and GART physical addresses.
* Used to allocate 32-bit handles for mappings.
*/
static unsigned int map32_handle = 0x10000000;
#define START_RANGE 0x10000000
#define END_RANGE 0x40000000

#ifdef _LP64
static __inline__ unsigned int HandleID(unsigned long lhandle, drm_device_t *dev)
{
static unsigned int map32_handle = START_RANGE;
unsigned int hash;

if (lhandle & 0xffffffff00000000) {
hash = map32_handle;
map32_handle += PAGE_SIZE;
if (map32_handle > END_RANGE)
map32_handle = START_RANGE;
} else
hash = lhandle;

while (1) {
drm_map_list_t *_entry;
list_for_each_entry(_entry, &dev->maplist->head,head) {
if (_entry->user_token == hash)
break;
}
if (&_entry->head == &dev->maplist->head)
return hash;

hash += PAGE_SIZE;
map32_handle += PAGE_SIZE;
}
}
#else
# define HandleID(x,dev) (unsigned int)(x)
#endif

/**
Expand Down Expand Up @@ -198,7 +226,7 @@ int drm_addmap(drm_device_t * dev, unsigned int offset,
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
map->offset += dev->sg->handle;
map->offset += (unsigned long)dev->sg->virtual;
break;
case _DRM_CONSISTENT:
/* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G,
Expand Down Expand Up @@ -229,12 +257,11 @@ int drm_addmap(drm_device_t * dev, unsigned int offset,

down(&dev->struct_sem);
list_add(&list->head, &dev->maplist->head);
#ifdef CONFIG_COMPAT
/* Assign a 32-bit handle for _DRM_SHM mappings */
/* Assign a 32-bit handle */
/* We do it here so that dev->struct_sem protects the increment */
if (map->type == _DRM_SHM)
map->offset = map32_handle += PAGE_SIZE;
#endif
list->user_token = HandleID(map->type==_DRM_SHM
? (unsigned long)map->handle
: map->offset, dev);
up(&dev->struct_sem);

*map_ptr = map;
Expand All @@ -251,6 +278,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
drm_map_t *map_ptr;
drm_map_t __user *argp = (void __user *)arg;
int err;
unsigned long handle = 0;

if (!(filp->f_mode & 3))
return -EACCES; /* Require read/write */
Expand All @@ -259,22 +287,29 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
return -EFAULT;
}

err = drm_addmap( dev, map.offset, map.size, map.type, map.flags,
&map_ptr );
err = drm_addmap(dev, map.offset, map.size, map.type, map.flags,
&map_ptr);

if (err) {
return err;
}

if (copy_to_user(argp, map_ptr, sizeof(*map_ptr)))
return -EFAULT;
if (map_ptr->type != _DRM_SHM) {
if (copy_to_user(&argp->handle, &map_ptr->offset,
sizeof(map_ptr->offset)))
{
drm_map_list_t *_entry;
list_for_each_entry(_entry, &dev->maplist->head, head) {
if (_entry->map == map_ptr)
handle = _entry->user_token;
}
if (!handle)
return -EFAULT;
}

if (copy_to_user(argp, map_ptr, sizeof(*map_ptr)))
return -EFAULT;
if (put_user(handle, &argp->handle))
return -EFAULT;
return 0;
}
}


/**
Expand Down Expand Up @@ -388,7 +423,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);

if (r_list->map &&
r_list->map->handle == request.handle &&
r_list->user_token == (unsigned long) request.handle &&
r_list->map->flags & _DRM_REMOVABLE) {
map = r_list->map;
break;
Expand Down Expand Up @@ -939,7 +974,8 @@ static int drm_addbufs_sg(drm_device_t *dev, drm_buf_desc_t *request)

buf->offset = (dma->byte_count + offset);
buf->bus_address = agp_offset + offset;
buf->address = (void *)(agp_offset + offset + dev->sg->handle);
buf->address = (void *)(agp_offset + offset
+ (unsigned long)dev->sg->virtual);
buf->next = NULL;
buf->waiting = 0;
buf->pending = 0;
Expand Down Expand Up @@ -1456,6 +1492,7 @@ int drm_mapbufs( struct inode *inode, struct file *filp,
|| (drm_core_check_feature(dev, DRIVER_FB_DMA)
&& (dma->flags & _DRM_DMA_USE_FB))) {
drm_map_t *map = dev->agp_buffer_map;
unsigned long token = dev->agp_buffer_token;

if ( !map ) {
retcode = -EINVAL;
Expand All @@ -1470,7 +1507,7 @@ int drm_mapbufs( struct inode *inode, struct file *filp,
virtual = do_mmap( filp, 0, map->size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
(unsigned long)map->offset );
token );
#if LINUX_VERSION_CODE <= 0x020402
up( &current->mm->mmap_sem );
#else
Expand Down
15 changes: 13 additions & 2 deletions drivers/char/drm/drm_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
drm_ctx_priv_map_t __user *argp = (void __user *)arg;
drm_ctx_priv_map_t request;
drm_map_t *map;
drm_map_list_t *_entry;

if (copy_from_user(&request, argp, sizeof(request)))
return -EFAULT;
Expand All @@ -225,7 +226,17 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
map = dev->context_sareas[request.ctx_id];
up(&dev->struct_sem);

request.handle = (void *) map->offset;
request.handle = 0;
list_for_each_entry(_entry, &dev->maplist->head,head) {
if (_entry->map == map) {
request.handle = (void *)(unsigned long)_entry->user_token;
break;
}
}
if (request.handle == 0)
return -EINVAL;


if (copy_to_user(argp, &request, sizeof(request)))
return -EFAULT;
return 0;
Expand Down Expand Up @@ -262,7 +273,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
list_for_each(list, &dev->maplist->head) {
r_list = list_entry(list, drm_map_list_t, head);
if (r_list->map
&& r_list->map->offset == (unsigned long) request.handle)
&& r_list->user_token == (unsigned long) request.handle)
goto found;
}
bad:
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/drm/drm_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ int drm_getmap( struct inode *inode, struct file *filp,
map.size = r_list->map->size;
map.type = r_list->map->type;
map.flags = r_list->map->flags;
map.handle = r_list->map->handle;
map.handle = (void *)(unsigned long) r_list->user_token;
map.mtrr = r_list->map->mtrr;
up(&dev->struct_sem);

Expand Down
4 changes: 2 additions & 2 deletions drivers/char/drm/drm_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,13 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
type = "??";
else
type = types[map->type];
DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ",
DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08x ",
i,
map->offset,
map->size,
type,
map->flags,
(unsigned long)map->handle);
r_list->user_token);
if (map->mtrr < 0) {
DRM_PROC_PRINT("none\n");
} else {
Expand Down
11 changes: 9 additions & 2 deletions drivers/char/drm/drm_scatter.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ void drm_sg_cleanup( drm_sg_mem_t *entry )
DRM_MEM_SGLISTS );
}

#ifdef _LP64
# define ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1)))
#else
# define ScatterHandle(x) (unsigned int)(x)
#endif

int drm_sg_alloc( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg )
{
Expand Down Expand Up @@ -133,12 +139,13 @@ int drm_sg_alloc( struct inode *inode, struct file *filp,
*/
memset( entry->virtual, 0, pages << PAGE_SHIFT );

entry->handle = (unsigned long)entry->virtual;
entry->handle = ScatterHandle((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++ ) {
for (i = (unsigned long)entry->virtual, j = 0; j < pages;
i += PAGE_SIZE, j++) {
entry->pagelist[j] = vmalloc_to_page((void *)i);
if (!entry->pagelist[j])
goto failed;
Expand Down
20 changes: 10 additions & 10 deletions drivers/char/drm/drm_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,13 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
r_list = list_entry(list, drm_map_list_t, head);
map = r_list->map;
if (!map) continue;
if (map->offset == VM_OFFSET(vma)) break;
if (r_list->user_token == VM_OFFSET(vma))
break;
}

if (map && map->type == _DRM_AGP) {
unsigned long offset = address - vma->vm_start;
unsigned long baddr = VM_OFFSET(vma) + offset;
unsigned long baddr = map->offset + offset;
struct drm_agp_mem *agpmem;
struct page *page;

Expand Down Expand Up @@ -304,7 +305,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,


offset = address - vma->vm_start;
map_offset = map->offset - dev->sg->handle;
map_offset = map->offset - (unsigned long)dev->sg->virtual;
page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
page = entry->pagelist[page_offset];
get_page(page);
Expand Down Expand Up @@ -568,13 +569,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
for performance, even if the list was a
bit longer. */
list_for_each(list, &dev->maplist->head) {
unsigned long off;

r_list = list_entry(list, drm_map_list_t, head);
map = r_list->map;
if (!map) continue;
off = dev->driver->get_map_ofs(map);
if (off == VM_OFFSET(vma)) break;
if (r_list->user_token == VM_OFFSET(vma))
break;
}

if (!map || ((map->flags&_DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
Expand Down Expand Up @@ -613,7 +613,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
/* fall through to _DRM_FRAME_BUFFER... */
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
if (VM_OFFSET(vma) >= __pa(high_memory)) {
if (map->offset >= __pa(high_memory)) {
#if defined(__i386__) || defined(__x86_64__)
if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
Expand All @@ -636,20 +636,20 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
offset = dev->driver->get_reg_ofs(dev);
#ifdef __sparc__
if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
(VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
#else
if (io_remap_pfn_range(vma, vma->vm_start,
(VM_OFFSET(vma) + offset) >> PAGE_SHIFT,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
#endif
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) + offset);
vma->vm_start, vma->vm_end, map->offset + offset);
vma->vm_ops = &drm_vm_ops;
break;
case _DRM_SHM:
Expand Down
5 changes: 1 addition & 4 deletions drivers/char/drm/ffb_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,11 @@ static drm_map_t *ffb_find_map(struct file *filp, unsigned long off)
return NULL;

list_for_each(list, &dev->maplist->head) {
unsigned long uoff;

r_list = (drm_map_list_t *)list;
map = r_list->map;
if (!map)
continue;
uoff = (map->offset & 0xffffffff);
if (uoff == off)
if (r_list->user_token == off)
return map;
}

Expand Down
1 change: 1 addition & 0 deletions drivers/char/drm/i810_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ static int i810_dma_initialize(drm_device_t *dev,
DRM_ERROR("can not find mmio map!\n");
return -EINVAL;
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
if (!dev->agp_buffer_map) {
dev->dev_private = (void *)dev_priv;
Expand Down
1 change: 1 addition & 0 deletions drivers/char/drm/i830_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ static int i830_dma_initialize(drm_device_t *dev,
DRM_ERROR("can not find mmio map!\n");
return -EINVAL;
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
if(!dev->agp_buffer_map) {
dev->dev_private = (void *)dev_priv;
Expand Down
1 change: 1 addition & 0 deletions drivers/char/drm/mga_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,7 @@ static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
DRM_ERROR("failed to find primary dma region!\n");
return DRM_ERR(EINVAL);
}
dev->agp_buffer_token = init->buffers_offset;
dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
if (!dev->agp_buffer_map) {
DRM_ERROR("failed to find dma buffer region!\n");
Expand Down
Loading

0 comments on commit d1f2b55

Please sign in to comment.