From: <th...@ke...> - 2006-08-21 15:03:43
|
linux-core/drm_hashtab.c | 17 +++++++++++++++-- linux-core/drm_hashtab.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) New commits: diff-tree 11f9e404fb66927146de30227fa05c5485aa1726 (from 0316f93d51abc52b816e936e0ece304ac47799c3) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Mon Aug 21 17:02:44 2006 +0200 Avoid using vmalloc for small hash tables. diff --git a/linux-core/drm_hashtab.c b/linux-core/drm_hashtab.c index 4806113..4059922 100644 --- a/linux-core/drm_hashtab.c +++ b/linux-core/drm_hashtab.c @@ -43,7 +43,16 @@ int drm_ht_create(drm_open_hash_t *ht, u ht->size = 1 << order; ht->order = order; ht->fill = 0; - ht->table = vmalloc(ht->size*sizeof(*ht->table)); + ht->table = NULL; + ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > 4*PAGE_SIZE); + if (!ht->use_vmalloc) { + ht->table = drm_calloc(ht->size, sizeof(*ht->table), + DRM_MEM_HASHTAB); + } + if (!ht->table) { + ht->use_vmalloc = 1; + ht->table = vmalloc(ht->size*sizeof(*ht->table)); + } if (!ht->table) { DRM_ERROR("Out of memory for hash table\n"); return -ENOMEM; @@ -183,7 +192,11 @@ int drm_ht_remove_item(drm_open_hash_t * void drm_ht_remove(drm_open_hash_t *ht) { if (ht->table) { - vfree(ht->table); + if (ht->use_vmalloc) + vfree(ht->table); + else + drm_free(ht->table, ht->size*sizeof(*ht->table), + DRM_MEM_HASHTAB); ht->table = NULL; } } diff --git a/linux-core/drm_hashtab.h b/linux-core/drm_hashtab.h index 40afec0..613091c 100644 --- a/linux-core/drm_hashtab.h +++ b/linux-core/drm_hashtab.h @@ -47,6 +47,7 @@ typedef struct drm_open_hash{ unsigned int order; unsigned int fill; struct hlist_head *table; + int use_vmalloc; } drm_open_hash_t; |
From: <th...@ke...> - 2006-08-21 18:32:51
|
linux-core/Makefile.kernel | 2 linux-core/drmP.h | 147 ++++++++++++++++++++++ linux-core/drm_drv.c | 1 linux-core/drm_fops.c | 123 ++++++++++++------- linux-core/drm_lock.c | 57 ++++++++ linux-core/drm_object.c | 289 +++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_stub.c | 6 7 files changed, 579 insertions(+), 46 deletions(-) New commits: diff-tree 42c2cfcf7d5730a2961d425228e042f533b312fa (from 11f9e404fb66927146de30227fa05c5485aa1726) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Mon Aug 21 20:30:19 2006 +0200 Generic DRM support base-class support for user-space objects, like fence objects and buffer objects: Refcounting, Inter-process sharing, Synchronization Destruction. diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 211e5b0..651e30b 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -12,7 +12,7 @@ drm-objs := drm_auth.o drm_bufs.o drm drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ - drm_hashtab.o drm_mm.o + drm_hashtab.o drm_mm.o drm_object.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6cbb810..81ca6ae 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -154,6 +154,8 @@ #define DRM_MEM_CTXLIST 21 #define DRM_MEM_MM 22 #define DRM_MEM_HASHTAB 23 +#define DRM_MEM_OBJECTS 24 + #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) #define DRM_MAP_HASH_OFFSET 0x10000000 @@ -387,6 +389,19 @@ typedef struct drm_buf_entry { drm_freelist_t freelist; } drm_buf_entry_t; +/* + * This should be small enough to allow the use of kmalloc for hash tables + * instead of vmalloc. + */ + +#define DRM_FILE_HASH_ORDER 8 +typedef enum{ + _DRM_REF_USE=0, + _DRM_REF_TYPE1, + _DRM_NO_REF_TYPES +} drm_ref_t; + + /** File private data */ typedef struct drm_file { int authenticated; @@ -401,6 +416,18 @@ typedef struct drm_file { struct drm_head *head; int remove_auth_on_close; unsigned long lock_count; + + /* + * The user object hash table is global and resides in the + * drm_device structure. We protect the lists and hash tables with the + * device struct_mutex. A bit coarse-grained but probably the best + * option. + */ + + struct list_head refd_objects; + struct list_head user_objects; + + drm_open_hash_t refd_object_hash[_DRM_NO_REF_TYPES]; void *driver_priv; } drm_file_t; @@ -564,6 +591,7 @@ typedef struct drm_mm { * a family of cards. There will one drm_device for each card present * in this family */ + struct drm_device; struct drm_driver { int (*load) (struct drm_device *, unsigned long flags); @@ -638,6 +666,7 @@ typedef struct drm_head { struct class_device *dev_class; } drm_head_t; + /** * DRM device structure. This structure represent a complete card that * may contain multiple heads. @@ -685,6 +714,7 @@ typedef struct drm_device { drm_map_list_t *maplist; /**< Linked list of regions */ int map_count; /**< Number of mappable regions */ drm_open_hash_t map_hash; /**< User token hash table for maps */ + drm_open_hash_t object_hash; /**< User token hash table for objects */ /** \name Context handle management */ /*@{ */ @@ -809,6 +839,63 @@ static inline int drm_mtrr_del(int handl #define drm_core_has_MTRR(dev) (0) #endif +/* + * User space objects and their references. + */ + +#define drm_user_object_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) + +typedef enum { + drm_fence_type, + drm_buffer_type + + /* + * Add other user space object types here. + */ + +} drm_object_type_t; + + + + +/* + * A user object is a structure that helps the drm give out user handles + * to kernel internal objects and to keep track of these objects so that + * they can be destroyed, for example when the user space process exits. + * Designed to be accessible using a user space 32-bit handle. + */ + +typedef struct drm_user_object{ + drm_hash_item_t hash; + struct list_head list; + drm_object_type_t type; + atomic_t refcount; + int shareable; + drm_file_t *owner; + void (*ref_struct_locked) (drm_file_t *priv, struct drm_user_object *obj, + drm_ref_t ref_action); + void (*unref)(drm_file_t *priv, struct drm_user_object *obj, + drm_ref_t unref_action); + void (*remove)(drm_file_t *priv, struct drm_user_object *obj); +} drm_user_object_t; + +/* + * A ref object is a structure which is used to + * keep track of references to user objects and to keep track of these + * references so that they can be destroyed for example when the user space + * process exits. Designed to be accessible using a pointer to the _user_ object. + */ + + +typedef struct drm_ref_object { + drm_hash_item_t hash; + struct list_head list; + atomic_t refcount; + drm_ref_t unref_action; +} drm_ref_object_t; + + + /******************************************************************/ /** \name Internal function definitions */ /*@{*/ @@ -837,6 +924,7 @@ unsigned int drm_poll(struct file *filp, extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); extern unsigned long drm_core_get_map_ofs(drm_map_t * map); extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev); +extern pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma); /* Memory management support (drm_memory.h) */ #include "drm_memory.h" @@ -915,6 +1003,13 @@ extern int drm_unlock(struct inode *inod extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context); extern int drm_lock_free(drm_device_t * dev, __volatile__ unsigned int *lock, unsigned int context); +/* + * These are exported to drivers so that they can implement fencing using + * DMA quiscent + idle. DMA quiescent usually requires the hardware lock. + */ + +extern int drm_i_have_hw_lock(struct file *filp); +extern int drm_kernel_take_hw_lock(struct file *filp); /* Buffer management support (drm_bufs.h) */ extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request); @@ -1058,6 +1153,58 @@ extern int drm_mm_init(drm_mm_t *mm, uns extern void drm_mm_takedown(drm_mm_t *mm); +/* + * User space object bookkeeping (drm_object.c) + */ + +/* + * Must be called with the struct_mutex held. + */ + +extern int drm_add_user_object(drm_file_t *priv, drm_user_object_t *item, + +/* + * Must be called with the struct_mutex held. + */ + int shareable); +extern drm_user_object_t *drm_lookup_user_object(drm_file_t *priv, uint32_t key); + +/* + * Must be called with the struct_mutex held. + * If "item" has been obtained by a call to drm_lookup_user_object. You may not + * release the struct_mutex before calling drm_remove_ref_object. + * This function may temporarily release the struct_mutex. + */ + +extern int drm_remove_user_object(drm_file_t *priv, drm_user_object_t *item); + +/* + * Must be called with the struct_mutex held. May temporarily release it. + */ + +extern int drm_add_ref_object(drm_file_t *priv, drm_user_object_t *referenced_object, + drm_ref_t ref_action); + +/* + * Must be called with the struct_mutex held. + */ + +drm_ref_object_t *drm_lookup_ref_object(drm_file_t *priv, + drm_user_object_t *referenced_object, + drm_ref_t ref_action); +/* + * Must be called with the struct_mutex held. + * If "item" has been obtained by a call to drm_lookup_ref_object. You may not + * release the struct_mutex before calling drm_remove_ref_object. + * This function may temporarily release the struct_mutex. + */ + +extern void drm_remove_ref_object(drm_file_t *priv, drm_ref_object_t *item); +extern int drm_user_object_ref(drm_file_t *priv, uint32_t user_token, drm_object_type_t type, + drm_user_object_t **object); +extern int drm_user_object_unref(drm_file_t *priv, uint32_t user_token, drm_object_type_t type); + + /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 9712170..ccfd185 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -351,6 +351,7 @@ static void __exit drm_cleanup(drm_devic drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; drm_ht_remove(&dev->map_hash); + drm_ht_remove(&dev->object_hash); } if (!drm_fb_loaded) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 691edff..10516bd 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -47,6 +47,7 @@ static int drm_setup(drm_device_t * dev) int i; int ret; + if (dev->driver->firstopen) { ret = dev->driver->firstopen(dev); if (ret != 0) @@ -56,6 +57,7 @@ static int drm_setup(drm_device_t * dev) dev->magicfree.next = NULL; /* prebuild the SAREA */ + i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map); if (i != 0) return i; @@ -233,6 +235,7 @@ static int drm_open_helper(struct inode int minor = iminor(inode); drm_file_t *priv; int ret; + int i,j; if (filp->f_flags & O_EXCL) return -EBUSY; /* No exclusive opens */ @@ -256,6 +259,22 @@ static int drm_open_helper(struct inode priv->authenticated = capable(CAP_SYS_ADMIN); priv->lock_count = 0; + INIT_LIST_HEAD(&priv->user_objects); + INIT_LIST_HEAD(&priv->refd_objects); + + for (i=0; i<_DRM_NO_REF_TYPES; ++i) { + ret = drm_ht_create(&priv->refd_object_hash[i], DRM_FILE_HASH_ORDER); + if (ret) + break; + } + + if (ret) { + for(j=0; j<i; ++j) { + drm_ht_remove(&priv->refd_object_hash[j]); + } + goto out_free; + } + if (dev->driver->open) { ret = dev->driver->open(dev, priv); if (ret < 0) @@ -320,6 +339,53 @@ int drm_fasync(int fd, struct file *filp } EXPORT_SYMBOL(drm_fasync); +static void drm_object_release(struct file *filp) { + + drm_file_t *priv = filp->private_data; + struct list_head *head; + drm_user_object_t *user_object; + drm_ref_object_t *ref_object; + int i; + + /* + * Free leftover ref objects created by me. Note that we cannot use + * list_for_each() here, as the struct_mutex may be temporarily released + * by the remove_() functions, and thus the lists may be altered. + * Also, a drm_remove_ref_object() will not remove it + * from the list unless its refcount is 1. + */ + + head = &priv->refd_objects; + while (head->next != head) { + ref_object = list_entry(head->next, drm_ref_object_t, list); + drm_remove_ref_object(priv, ref_object); + head = &priv->refd_objects; + } + + /* + * Free leftover user objects created by me. + */ + + head = &priv->user_objects; + while (head->next != head) { + user_object = list_entry(head->next, drm_user_object_t, list); + drm_remove_user_object(priv, user_object); + head = &priv->user_objects; + } + + + + + for(i=0; i<_DRM_NO_REF_TYPES; ++i) { + drm_ht_remove(&priv->refd_object_hash[i]); + } +} + + + + + + /** * Release file. * @@ -354,58 +420,24 @@ int drm_release(struct inode *inode, str current->pid, (long)old_encode_dev(priv->head->device), dev->open_count); - if (priv->lock_count && dev->lock.hw_lock && - _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.filp == filp) { + if (dev->driver->reclaim_buffers_locked) { + retcode = drm_kernel_take_hw_lock(filp); + if (!retcode) { + dev->driver->reclaim_buffers_locked(dev, filp); + + drm_lock_free(dev, &dev->lock.hw_lock->lock, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + } + + } else if (drm_i_have_hw_lock(filp)) { DRM_DEBUG("File %p released, freeing lock for context %d\n", filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - if (dev->driver->reclaim_buffers_locked) - dev->driver->reclaim_buffers_locked(dev, filp); - drm_lock_free(dev, &dev->lock.hw_lock->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - - /* FIXME: may require heavy-handed reset of - hardware at this point, possibly - processed via a callback to the X - server. */ - } else if (dev->driver->reclaim_buffers_locked && priv->lock_count - && dev->lock.hw_lock) { - /* The lock is required to reclaim buffers */ - DECLARE_WAITQUEUE(entry, current); - - add_wait_queue(&dev->lock.lock_queue, &entry); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - if (!dev->lock.hw_lock) { - /* Device has been unregistered */ - retcode = -EINTR; - break; - } - if (drm_lock_take(&dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - dev->lock.filp = filp; - dev->lock.lock_time = jiffies; - atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); - break; /* Got lock */ - } - /* Contention */ - schedule(); - if (signal_pending(current)) { - retcode = -ERESTARTSYS; - break; - } - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&dev->lock.lock_queue, &entry); - if (!retcode) { - dev->driver->reclaim_buffers_locked(dev, filp); - drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT); - } } + if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !dev->driver->reclaim_buffers_locked) { dev->driver->reclaim_buffers(dev, filp); @@ -435,6 +467,7 @@ int drm_release(struct inode *inode, str mutex_unlock(&dev->ctxlist_mutex); mutex_lock(&dev->struct_mutex); + drm_object_release(filp); if (priv->remove_auth_on_close == 1) { drm_file_t *temp = dev->file_first; while (temp) { diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index a268d8e..c12e489 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -308,3 +308,60 @@ static int drm_notifier(void *priv) } while (prev != old); return 0; } + +/* + * Can be used by drivers to take the hardware lock if necessary. + * (Waiting for idle before reclaiming buffers etc.) + */ + +int drm_i_have_hw_lock(struct file *filp) +{ + DRM_DEVICE; + + return (priv->lock_count && dev->lock.hw_lock && + _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && + dev->lock.filp == filp); +} + +EXPORT_SYMBOL(drm_i_have_hw_lock); + +int drm_kernel_take_hw_lock(struct file *filp) +{ + DRM_DEVICE; + + int ret = 0; + + if (!drm_i_have_hw_lock(filp)) { + + DECLARE_WAITQUEUE(entry, current); + + add_wait_queue(&dev->lock.lock_queue, &entry); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + if (!dev->lock.hw_lock) { + /* Device has been unregistered */ + ret = -EINTR; + break; + } + if (drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + dev->lock.filp = filp; + dev->lock.lock_time = jiffies; + atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); + break; /* Got lock */ + } + /* Contention */ + schedule(); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->lock.lock_queue, &entry); + } + return ret; +} + +EXPORT_SYMBOL(drm_kernel_take_hw_lock); + diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c new file mode 100644 index 0000000..b928c01 --- /dev/null +++ b/linux-core/drm_object.c @@ -0,0 +1,289 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +#include "drmP.h" + +int drm_add_user_object(drm_file_t * priv, drm_user_object_t * item, + int shareable) +{ + drm_device_t *dev = priv->head->dev; + int ret; + + atomic_set(&item->refcount, 1); + item->shareable = shareable; + item->owner = priv; + + ret = drm_ht_just_insert_please(&dev->object_hash, &item->hash, + (unsigned long)item, 32, 0, 0); + if (ret) + return ret; + + list_add_tail(&item->list, &priv->user_objects); + return 0; +} + +drm_user_object_t *drm_lookup_user_object(drm_file_t * priv, uint32_t key) +{ + drm_device_t *dev = priv->head->dev; + drm_hash_item_t *hash; + int ret; + drm_user_object_t *item; + + ret = drm_ht_find_item(&dev->object_hash, key, &hash); + if (ret) { + return NULL; + } + item = drm_hash_entry(hash, drm_user_object_t, hash); + + if (priv != item->owner) { + drm_open_hash_t *ht = &priv->refd_object_hash[_DRM_REF_USE]; + ret = drm_ht_find_item(ht, (unsigned long)item, &hash); + if (ret) { + DRM_ERROR("Object not registered for usage\n"); + return NULL; + } + } + return item; +} + +static void drm_deref_user_object(drm_file_t * priv, drm_user_object_t * item) +{ + drm_device_t *dev = priv->head->dev; + int ret; + + if (atomic_dec_and_test(&item->refcount)) { + ret = drm_ht_remove_item(&dev->object_hash, &item->hash); + BUG_ON(ret); + list_del_init(&item->list); + item->remove(priv, item); + } +} + +int drm_remove_user_object(drm_file_t * priv, drm_user_object_t * item) +{ + if (item->owner != priv) { + DRM_ERROR("Cannot destroy object not owned by you.\n"); + return -EINVAL; + } + item->owner = 0; + item->shareable = 0; + list_del_init(&item->list); + drm_deref_user_object(priv, item); + return 0; +} + +static int drm_object_ref_action(drm_file_t * priv, drm_user_object_t * ro, + drm_ref_t action) +{ + int ret = 0; + + switch (action) { + case _DRM_REF_USE: + atomic_inc(&ro->refcount); + break; + default: + if (!ro->ref_struct_locked) { + DRM_ERROR("Register object called without register" + " capabilities\n"); + ret = -EINVAL; + break; + } else { + ro->ref_struct_locked(priv, ro, action); + } + } + return ret; +} + +int drm_add_ref_object(drm_file_t * priv, drm_user_object_t * referenced_object, + drm_ref_t ref_action) +{ + int ret = 0; + drm_ref_object_t *item; + drm_open_hash_t *ht = &priv->refd_object_hash[ref_action]; + + if (!referenced_object->shareable && priv != referenced_object->owner) { + DRM_ERROR("Not allowed to reference this object\n"); + return -EINVAL; + } + + /* + * If this is not a usage reference, Check that usage has been registered + * first. Otherwise strange things may happen on destruction. + */ + + if ((ref_action != _DRM_REF_USE) && priv != referenced_object->owner) { + item = + drm_lookup_ref_object(priv, referenced_object, + _DRM_REF_USE); + if (!item) { + DRM_ERROR + ("Object not registered for usage by this client\n"); + return -EINVAL; + } + } + + if (NULL != + (item = + drm_lookup_ref_object(priv, referenced_object, ref_action))) { + atomic_inc(&item->refcount); + return drm_object_ref_action(priv, referenced_object, + ref_action); + } + + item = drm_calloc(1, sizeof(*item), DRM_MEM_OBJECTS); + if (item == NULL) { + DRM_ERROR("Could not allocate reference object\n"); + return -ENOMEM; + } + + atomic_set(&item->refcount, 1); + item->hash.key = (unsigned long)referenced_object; + ret = drm_ht_insert_item(ht, &item->hash); + + if (ret) + goto out; + + list_add(&item->list, &priv->refd_objects); + ret = drm_object_ref_action(priv, referenced_object, ref_action); + out: + return ret; +} + +drm_ref_object_t *drm_lookup_ref_object(drm_file_t * priv, + drm_user_object_t * referenced_object, + drm_ref_t ref_action) +{ + drm_hash_item_t *hash; + int ret; + + ret = drm_ht_find_item(&priv->refd_object_hash[ref_action], + (unsigned long)referenced_object, &hash); + if (ret) + return NULL; + + return drm_hash_entry(hash, drm_ref_object_t, hash); +} + +static void drm_remove_other_references(drm_file_t * priv, + drm_user_object_t * ro) +{ + int i; + drm_open_hash_t *ht; + drm_hash_item_t *hash; + drm_ref_object_t *item; + + for (i = _DRM_REF_USE + 1; i < _DRM_NO_REF_TYPES; ++i) { + ht = &priv->refd_object_hash[i]; + while (!drm_ht_find_item(ht, (unsigned long)ro, &hash)) { + item = drm_hash_entry(hash, drm_ref_object_t, hash); + drm_remove_ref_object(priv, item); + } + } +} + +void drm_remove_ref_object(drm_file_t * priv, drm_ref_object_t * item) +{ + int ret; + drm_user_object_t *user_object = (drm_user_object_t *) item->hash.key; + drm_open_hash_t *ht = &priv->refd_object_hash[item->unref_action]; + drm_ref_t unref_action; + + unref_action = item->unref_action; + if (atomic_dec_and_test(&item->refcount)) { + ret = drm_ht_remove_item(ht, &item->hash); + BUG_ON(ret); + list_del_init(&item->list); + if (unref_action == _DRM_REF_USE) + drm_remove_other_references(priv, user_object); + drm_free(item, sizeof(*item), DRM_MEM_OBJECTS); + } + + switch (unref_action) { + case _DRM_REF_USE: + drm_deref_user_object(priv, user_object); + break; + default: + BUG_ON(!user_object->unref); + user_object->unref(priv, user_object, unref_action); + break; + } + +} + +int drm_user_object_ref(drm_file_t * priv, uint32_t user_token, + drm_object_type_t type, drm_user_object_t ** object) +{ + drm_device_t *dev = priv->head->dev; + drm_user_object_t *uo; + int ret; + + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, user_token); + if (!uo || (uo->type != type)) { + ret = -EINVAL; + goto out_err; + } + ret = drm_add_ref_object(priv, uo, _DRM_REF_USE); + if (ret) + goto out_err; + mutex_unlock(&dev->struct_mutex); + *object = uo; + DRM_ERROR("Referenced an object\n"); + return 0; + out_err: + mutex_unlock(&dev->struct_mutex); + return ret; +} + +int drm_user_object_unref(drm_file_t * priv, uint32_t user_token, + drm_object_type_t type) +{ + drm_device_t *dev = priv->head->dev; + drm_user_object_t *uo; + drm_ref_object_t *ro; + int ret; + + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, user_token); + if (!uo || (uo->type != type)) { + ret = -EINVAL; + goto out_err; + } + ro = drm_lookup_ref_object(priv, uo, _DRM_REF_USE); + if (!ro) { + ret = -EINVAL; + goto out_err; + } + drm_remove_ref_object(priv, ro); + mutex_unlock(&dev->struct_mutex); + DRM_ERROR("Unreferenced an object\n"); + return 0; + out_err: + mutex_unlock(&dev->struct_mutex); + return ret; +} diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 25bb5f3..9059f42 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -87,6 +87,12 @@ static int drm_fill_in_dev(drm_device_t return -ENOMEM; } + if (drm_ht_create(&dev->object_hash, 12)) { + drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); + drm_ht_remove(&dev->map_hash); + return -ENOMEM; + } + /* the DRM has 6 counters */ dev->counters = 6; dev->types[0] = _DRM_STAT_LOCK; |
From: <th...@ke...> - 2006-08-21 18:39:15
|
linux-core/Makefile.kernel | 2 linux-core/drm_compat.c | 140 +++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_compat.h | 18 +++++ 3 files changed, 159 insertions(+), 1 deletion(-) New commits: diff-tree 1c787f0d396c309131d5f34939598d657ee2459f (from 42c2cfcf7d5730a2961d425228e042f533b312fa) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Mon Aug 21 20:38:57 2006 +0200 Backwards compatibility code for ttms. diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 651e30b..c7c4791 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -12,7 +12,7 @@ drm-objs := drm_auth.o drm_bufs.o drm drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ - drm_hashtab.o drm_mm.o drm_object.o + drm_hashtab.o drm_mm.o drm_object.o drm_compat.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c new file mode 100644 index 0000000..cdef4b9 --- /dev/null +++ b/linux-core/drm_compat.c @@ -0,0 +1,140 @@ +/************************************************************************** + * + * This kernel module is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + **************************************************************************/ +/* + * This code provides access to unexported mm kernel features. It is necessary + * to use the new DRM memory manager code with kernels that don't support it + * directly. + * + * Authors: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> + * Linux kernel mm subsystem authors. + * (Most code taken from there). + */ + +#include "drmP.h" +#include <asm/pgtable.h> +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> + +#ifdef MODULE +void pgd_clear_bad(pgd_t * pgd) +{ + pgd_ERROR(*pgd); + pgd_clear(pgd); +} + +void pud_clear_bad(pud_t * pud) +{ + pud_ERROR(*pud); + pud_clear(pud); +} + +void pmd_clear_bad(pmd_t * pmd) +{ + pmd_ERROR(*pmd); + pmd_clear(pmd); +} +#endif + +static inline void change_pte_range(struct mm_struct *mm, pmd_t * pmd, + unsigned long addr, unsigned long end) +{ + pte_t *pte; + + pte = pte_offset_map(pmd, addr); + do { + if (pte_present(*pte)) { + pte_t ptent; + ptent = *pte; + ptep_get_and_clear(mm, addr, pte); + lazy_mmu_prot_update(ptent); + } + } while (pte++, addr += PAGE_SIZE, addr != end); + pte_unmap(pte - 1); +} + +static inline void change_pmd_range(struct mm_struct *mm, pud_t * pud, + unsigned long addr, unsigned long end) +{ + pmd_t *pmd; + unsigned long next; + + pmd = pmd_offset(pud, addr); + do { + next = pmd_addr_end(addr, end); + if (pmd_none_or_clear_bad(pmd)) + continue; + change_pte_range(mm, pmd, addr, next); + } while (pmd++, addr = next, addr != end); +} + +static inline void change_pud_range(struct mm_struct *mm, pgd_t * pgd, + unsigned long addr, unsigned long end) +{ + pud_t *pud; + unsigned long next; + + pud = pud_offset(pgd, addr); + do { + next = pud_addr_end(addr, end); + if (pud_none_or_clear_bad(pud)) + continue; + change_pmd_range(mm, pud, addr, next); + } while (pud++, addr = next, addr != end); +} + +/* + * This function should be called with all relevant spinlocks held. + */ + +void drm_clear_vma(struct vm_area_struct *vma, + unsigned long addr, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + pgd_t *pgd; + unsigned long next; +#if defined(flush_tlb_mm) || !defined(MODULE) + unsigned long start = addr; +#endif + BUG_ON(addr >= end); + pgd = pgd_offset(mm, addr); + flush_cache_range(vma, addr, end); + do { + next = pgd_addr_end(addr, end); + if (pgd_none_or_clear_bad(pgd)) + continue; + change_pud_range(mm, pgd, addr, next); + } while (pgd++, addr = next, addr != end); +#if defined(flush_tlb_mm) || !defined(MODULE) + flush_tlb_range(vma, addr, end); +#endif +} + +pgprot_t drm_prot_map(uint32_t flags) +{ +#ifdef MODULE + static pgprot_t drm_protection_map[16] = { + __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, + __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 + }; + + return drm_protection_map[flags & 0x0F]; +#else + extern pgprot_t protection_map[]; + return protection_map[flags & 0x0F]; +#endif +}; diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 407853d..8092831 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -227,4 +227,22 @@ static inline int remap_pfn_range(struct } #endif +#include <linux/mm.h> +#include <asm/page.h> + +/* + * Flush relevant caches and clear a VMA structure so that page references + * will cause a page fault. Don't flush tlbs. + */ + +extern void drm_clear_vma(struct vm_area_struct *vma, + unsigned long addr, unsigned long end); + +/* + * Return the PTE protection map entries for the VMA flags given by + * flags. This is a functional interface to the kernel's protection map. + */ + +extern pgprot_t drm_prot_map(uint32_t flags); + #endif |
From: <th...@ke...> - 2006-08-21 19:12:50
|
linux-core/drmP.h | 9 --------- 1 files changed, 9 deletions(-) New commits: diff-tree 6571f74a4906ae4f5f92916d64cc2cce3c8e0043 (from 657bacc3953e8e51a0a15bd872e9818c9dbcbc10) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Mon Aug 21 21:12:29 2006 +0200 Remove some accidently included TTM code. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6db6ac9..b9549b6 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -837,15 +837,6 @@ typedef struct drm_device { } drm_device_t; -#if __OS_HAS_AGP -typedef struct drm_agp_ttm_priv { - DRM_AGP_MEM *mem; - struct agp_bridge_data *bridge; - unsigned mem_type; - int populated; -} drm_agp_ttm_priv; -#endif - static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) { |
From: <th...@ke...> - 2006-08-21 19:36:23
|
linux-core/Makefile.kernel | 2 linux-core/i915_drv.c | 11 ++++ linux-core/i915_fence.c | 121 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_dma.c | 10 ++- shared-core/i915_drv.h | 27 ++++++++-- shared-core/i915_irq.c | 10 ++- 6 files changed, 170 insertions(+), 11 deletions(-) New commits: diff-tree e089de33e8efd87b30d59c571b9ab9aa302b23e1 (from 6571f74a4906ae4f5f92916d64cc2cce3c8e0043) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Mon Aug 21 21:36:00 2006 +0200 i915 fence object driver implementing 2 fence object types: 0x00 EXE fence. Signals when command stream interpreter has reached the point where the fence was emitted. 0x01 FLUSH fence. Signals when command stream interpreter has reached the point where the fence was emitted, and all previous drawing operations have been completed and flushed. Implements busy wait (for fastest response time / high CPU) and lazy wait (User interrupt or timer driven). diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 3c31b01..c5ce663 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -19,7 +19,7 @@ r128-objs := r128_drv.o r128_cce.o r12 mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i830-objs := i830_drv.o i830_dma.o i830_irq.o -i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index c6e25f9..d1b8d2d 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -38,6 +38,16 @@ static struct pci_device_id pciidlist[] i915_PCI_IDS }; +static drm_fence_driver_t i915_fence_driver = { + .no_types = 2, + .wrap_diff = (1 << 30), + .flush_diff = 200, + .sequence_mask = 0xffffffffU, + .lazy_capable = 1, + .emit = i915_fence_emit_sequence, + .poke_flush = i915_poke_flush, +}; + static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { /* don't use mtrr's here, the Xserver or user space app should @@ -78,6 +88,7 @@ static struct drm_driver driver = { .remove = __devexit_p(drm_cleanup_pci), }, + .fence_driver = &i915_fence_driver, .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c new file mode 100644 index 0000000..46a2a72 --- /dev/null +++ b/linux-core/i915_fence.c @@ -0,0 +1,121 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* + * Implements an intel sync flush operation. + */ + +static void i915_perform_flush(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + int flush_completed = 0; + uint32_t flush_flags = 0; + uint32_t flush_sequence = 0; + uint32_t i_status; + uint32_t diff; + uint32_t sequence; + + if (fm->pending_exe_flush) { + sequence = READ_BREADCRUMB(dev_priv); + diff = sequence - fm->last_exe_flush; + if (diff < driver->wrap_diff && diff != 0) { + drm_fence_handler(dev, sequence, DRM_FENCE_EXE); + diff = sequence - fm->exe_flush_sequence; + if (diff < driver->wrap_diff) { + fm->pending_exe_flush = 0; + /* + * Turn off user IRQs + */ + } else { + /* + * Turn on user IRQs + */ + } + } + } + if (dev_priv->flush_pending) { + i_status = READ_HWSP(dev_priv, 0); + if ((i_status & (1 << 12)) != + (dev_priv->saved_flush_status & (1 << 12))) { + flush_completed = 1; + flush_flags = dev_priv->flush_flags; + flush_sequence = dev_priv->flush_sequence; + dev_priv->flush_pending = 0; + } else { + } + } + if (flush_completed) { + drm_fence_handler(dev, flush_sequence, flush_flags); + } + if (fm->pending_flush && !dev_priv->flush_pending) { + dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); + dev_priv->flush_flags = fm->pending_flush; + dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); + I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); + dev_priv->flush_pending = 1; + fm->pending_flush = 0; + } +} + +void i915_poke_flush(drm_device_t * dev) +{ + drm_fence_manager_t *fm = &dev->fm; + unsigned long flags; + + write_lock_irqsave(&fm->lock, flags); + i915_perform_flush(dev); + write_unlock_irqrestore(&fm->lock, flags); +} + +int i915_fence_emit_sequence(drm_device_t * dev, uint32_t * sequence) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + i915_emit_irq(dev); + *sequence = (uint32_t) dev_priv->counter; + return 0; +} + +void i915_fence_handler(drm_device_t * dev) +{ + drm_fence_manager_t *fm = &dev->fm; + + write_lock(&fm->lock); + i915_perform_flush(dev); + i915_perform_flush(dev); + write_unlock(&fm->lock); +} diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index ba8c56e..d6bb6c8 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -434,15 +434,15 @@ static void i915_emit_breadcrumb(drm_dev dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; - if (dev_priv->counter > 0x7FFFFFFFUL) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; - BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); OUT_RING(20); OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); +#ifdef I915_HAVE_FENCE + drm_fence_flush_old(dev, dev_priv->counter); +#endif } static int i915_dispatch_cmdbuffer(drm_device_t * dev, @@ -565,7 +565,9 @@ static int i915_dispatch_flip(drm_device OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); - +#ifdef I915_HAVE_FENCE + drm_fence_flush_old(dev, dev_priv->counter); +#endif dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; return 0; } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a87075b..475ff47 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -51,6 +51,10 @@ #define DRIVER_MINOR 5 #define DRIVER_PATCHLEVEL 0 +#if defined(__linux__) +#define I915_HAVE_FENCE +#endif + typedef struct _drm_i915_ring_buffer { int tail_mask; unsigned long Start; @@ -81,7 +85,7 @@ typedef struct drm_i915_private { drm_dma_handle_t *status_page_dmah; void *hw_status_page; dma_addr_t dma_status_page; - unsigned long counter; + uint32_t counter; int back_offset; int front_offset; @@ -98,6 +102,14 @@ typedef struct drm_i915_private { struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; + +#ifdef I915_HAVE_FENCE + uint32_t flush_sequence; + uint32_t flush_flags; + uint32_t flush_pending; + uint32_t saved_flush_status; +#endif + } drm_i915_private_t; extern drm_ioctl_desc_t i915_ioctls[]; @@ -123,6 +135,7 @@ extern void i915_driver_irq_postinstall( extern void i915_driver_irq_uninstall(drm_device_t * dev); extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS); extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); +extern int i915_emit_irq(drm_device_t * dev); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); @@ -132,6 +145,13 @@ extern int i915_mem_destroy_heap(DRM_IOC extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap); +#ifdef I915_HAVE_FENCE +/* i915_fence.c */ +extern void i915_fence_handler(drm_device_t *dev); +extern int i915_fence_emit_sequence(drm_device_t *dev, uint32_t *sequence); +extern void i915_poke_flush(drm_device_t *dev); +extern void i915_sync_flush(drm_device_t *dev); +#endif #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) @@ -191,6 +211,7 @@ extern int i915_wait_ring(drm_device_t * #define I915REG_INT_IDENTITY_R 0x020a4 #define I915REG_INT_MASK_R 0x020a8 #define I915REG_INT_ENABLE_R 0x020a0 +#define I915REG_INSTPM 0x020c0 #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 @@ -272,6 +293,6 @@ extern int i915_wait_ring(drm_device_t * #define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) -#define READ_BREADCRUMB(dev_priv) (((u32*)(dev_priv->hw_status_page))[5]) - +#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) +#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) #endif diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 14213b5..08d3140 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -56,8 +56,12 @@ irqreturn_t i915_driver_irq_handler(DRM_ dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - if (temp & USER_INT_FLAG) + if (temp & USER_INT_FLAG) { DRM_WAKEUP(&dev_priv->irq_queue); +#ifdef I915_HAVE_FENCE + i915_fence_handler(dev); +#endif + } if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { atomic_inc(&dev->vbl_received); @@ -68,7 +72,7 @@ irqreturn_t i915_driver_irq_handler(DRM_ return IRQ_HANDLED; } -static int i915_emit_irq(drm_device_t * dev) +int i915_emit_irq(drm_device_t * dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -260,7 +264,7 @@ void i915_driver_irq_preinstall(drm_devi { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - I915_WRITE16(I915REG_HWSTAM, 0xfffe); + I915_WRITE16(I915REG_HWSTAM, 0xeffe); I915_WRITE16(I915REG_INT_MASK_R, 0x0); I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); } |
From: <th...@ke...> - 2006-08-21 19:38:10
|
linux-core/i915_drv.c | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-) New commits: diff-tree 8d5b7c77f9b31aa9bcf81536d39769f4f3feeb63 (from e089de33e8efd87b30d59c571b9ab9aa302b23e1) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Mon Aug 21 21:37:43 2006 +0200 Allow longer sequence lifetimes. diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index d1b8d2d..56ac5fc 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -41,7 +41,7 @@ static struct pci_device_id pciidlist[] static drm_fence_driver_t i915_fence_driver = { .no_types = 2, .wrap_diff = (1 << 30), - .flush_diff = 200, + .flush_diff = (1 << 29), .sequence_mask = 0xffffffffU, .lazy_capable = 1, .emit = i915_fence_emit_sequence, |
From: <th...@ke...> - 2006-08-22 07:47:57
|
linux-core/Makefile.kernel | 2 linux-core/drmP.h | 14 linux-core/drm_bufs.c | 2 linux-core/drm_ttm.c | 813 +++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_ttm.h | 152 ++++++++ linux-core/drm_vm.c | 299 +++++++++++++++- shared-core/drm.h | 1 7 files changed, 1262 insertions(+), 21 deletions(-) New commits: diff-tree 700bf80ca9fadf2c1404c220addebd92d9ad799d (from 8d5b7c77f9b31aa9bcf81536d39769f4f3feeb63) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 22 09:47:33 2006 +0200 Bring in stripped TTM functionality. diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index c5ce663..bf5221d 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,7 +13,7 @@ drm-objs := drm_auth.o drm_bufs.o drm drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ - drm_fence.o + drm_fence.o drm_ttm.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drmP.h b/linux-core/drmP.h index b9549b6..33d8ecc 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -586,6 +586,18 @@ typedef struct drm_mm { drm_mm_node_t root_node; } drm_mm_t; +#include "drm_ttm.h" + +/* + * buffer object driver + */ + +typedef struct drm_bo_driver{ + int cached_pages; + drm_ttm_backend_t *(*create_ttm_backend_entry) + (struct drm_device *dev, int cached); +} drm_bo_driver_t; + /** * DRM driver structure. This structure represent the common code for @@ -639,6 +651,7 @@ struct drm_driver { void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); struct drm_fence_driver *fence_driver; + struct drm_bo_driver *bo_driver; int major; int minor; @@ -979,6 +992,7 @@ unsigned int drm_poll(struct file *filp, extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); extern unsigned long drm_core_get_map_ofs(drm_map_t * map); extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev); +extern pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma); /* Memory management support (drm_memory.h) */ #include "drm_memory.h" diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 2eeb401..efb48dc 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -420,6 +420,8 @@ int drm_rmmap_locked(drm_device_t *dev, dmah.size = map->size; __drm_pci_free(dev, &dmah); break; + case _DRM_TTM: + BUG_ON(1); } drm_free(map, sizeof(*map), DRM_MEM_MAPS); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c new file mode 100644 index 0000000..b3ea7c9 --- /dev/null +++ b/linux-core/drm_ttm.c @@ -0,0 +1,813 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO. + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +#include "drmP.h" +#include <asm/tlbflush.h> + +typedef struct p_mm_entry { + struct list_head head; + struct mm_struct *mm; + atomic_t refcount; +} p_mm_entry_t; + +typedef struct drm_val_action { + int needs_rx_flush; + int evicted_tt; + int evicted_vram; + int validated; +} drm_val_action_t; + +/* + * We may be manipulating other processes page tables, so for each TTM, keep track of + * which mm_structs are currently mapping the ttm so that we can take the appropriate + * locks when we modify their page tables. A typical application is when we evict another + * process' buffers. + */ + +int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm) +{ + p_mm_entry_t *entry, *n_entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (mm == entry->mm) { + atomic_inc(&entry->refcount); + return 0; + } else if ((unsigned long)mm < (unsigned long)entry->mm) ; + } + + n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_MM); + if (!entry) { + DRM_ERROR("Allocation of process mm pointer entry failed\n"); + return -ENOMEM; + } + INIT_LIST_HEAD(&n_entry->head); + n_entry->mm = mm; + atomic_set(&n_entry->refcount, 0); + atomic_inc(&ttm->shared_count); + ttm->mm_list_seq++; + + list_add_tail(&n_entry->head, &entry->head); + + return 0; +} + +void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) +{ + p_mm_entry_t *entry, *n; + list_for_each_entry_safe(entry, n, &ttm->p_mm_list, head) { + if (mm == entry->mm) { + if (atomic_add_negative(-1, &entry->refcount)) { + list_del(&entry->head); + drm_free(entry, sizeof(*entry), DRM_MEM_MM); + atomic_dec(&ttm->shared_count); + ttm->mm_list_seq++; + } + return; + } + } + BUG_ON(TRUE); +} + +static void drm_ttm_lock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +{ + p_mm_entry_t *entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (mm_sem) { + down_write(&entry->mm->mmap_sem); + } + if (page_table) { + spin_lock(&entry->mm->page_table_lock); + } + } +} + +static void drm_ttm_unlock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +{ + p_mm_entry_t *entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (page_table) { + spin_unlock(&entry->mm->page_table_lock); + } + if (mm_sem) { + up_write(&entry->mm->mmap_sem); + } + } +} + +static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages, unsigned long aper_offset) +{ + struct list_head *list; + int ret = 0; + + list_for_each(list, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + + ret = io_remap_pfn_range(entry->vma, + entry->vma->vm_start + + (page_offset << PAGE_SHIFT), + (ttm->aperture_base >> PAGE_SHIFT) + + aper_offset, num_pages << PAGE_SHIFT, + drm_io_prot(_DRM_AGP, entry->vma)); + if (ret) + break; + } + global_flush_tlb(); + return ret; +} + +/* + * Unmap all vma pages from vmas mapping this ttm. + */ + +static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages) +{ + struct list_head *list; + struct page **first_page = ttm->pages + page_offset; + struct page **last_page = ttm->pages + (page_offset + num_pages); + struct page **cur_page; + + list_for_each(list, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + drm_clear_vma(entry->vma, + entry->vma->vm_start + + (page_offset << PAGE_SHIFT), + entry->vma->vm_start + + ((page_offset + num_pages) << PAGE_SHIFT)); + } + + for (cur_page = first_page; cur_page != last_page; ++cur_page) { + if (page_mapcount(*cur_page) != 0) { + DRM_ERROR("Mapped page detected. Map count is %d\n", + page_mapcount(*cur_page)); + return -1; + } + } + return 0; +} + +/* + * Free all resources associated with a ttm. + */ + +int drm_destroy_ttm(drm_ttm_t * ttm) +{ + + int i; + struct list_head *list, *next; + struct page **cur_page; + + if (!ttm) + return 0; + + if (atomic_read(&ttm->vma_count) > 0) { + DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); + return -EBUSY; + } else { + DRM_DEBUG("Checking for busy regions.\n"); + } + + if (ttm->be_list) { + list_for_each_safe(list, next, &ttm->be_list->head) { + drm_ttm_backend_list_t *entry = + list_entry(list, drm_ttm_backend_list_t, head); +#ifdef REMOVED + drm_ht_remove_item(&ttm->dev->ttmreghash, + &entry->hash); +#endif + drm_destroy_ttm_region(entry); + } + + drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_MAPS); + ttm->be_list = NULL; + } + + if (atomic_read(&ttm->unfinished_regions) > 0) { + DRM_DEBUG("Regions are still busy. Skipping destruction.\n"); + ttm->destroy = TRUE; + return -EAGAIN; + } else { + DRM_DEBUG("About to really destroy ttm.\n"); + } + + if (ttm->pages) { + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages + i; + if (ttm->page_flags && + (ttm->page_flags[i] & DRM_TTM_PAGE_UNCACHED) && + *cur_page && !PageHighMem(*cur_page)) { + change_page_attr(*cur_page, 1, PAGE_KERNEL); + } + if (*cur_page) { + ClearPageReserved(*cur_page); + __free_page(*cur_page); + } + } + global_flush_tlb(); + vfree(ttm->pages); + ttm->pages = NULL; + } + if (ttm->page_flags) { + vfree(ttm->page_flags); + ttm->page_flags = NULL; + } + + if (ttm->vma_list) { + list_for_each_safe(list, next, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + list_del(list); + entry->vma->vm_private_data = NULL; + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + } + drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + ttm->vma_list = NULL; + } + drm_free(ttm, sizeof(*ttm), DRM_MEM_MAPS); + + return 0; +} + +/* + * Initialize a ttm. + * FIXME: Avoid using vmalloc for the page- and page_flags tables? + */ + +drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) +{ + + drm_ttm_t *ttm; + + if (!dev->driver->bo_driver) + return NULL; + + ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_MAPS); + if (!ttm) + return NULL; + + ttm->lhandle = 0; + atomic_set(&ttm->vma_count, 0); + atomic_set(&ttm->unfinished_regions, 0); + ttm->destroy = FALSE; + ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); + if (!ttm->page_flags) { + drm_destroy_ttm(ttm); + DRM_ERROR("Failed allocating page_flags table\n"); + return NULL; + } + memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); + + ttm->pages = vmalloc(ttm->num_pages * sizeof(*ttm->pages)); + if (!ttm->pages) { + drm_destroy_ttm(ttm); + DRM_ERROR("Failed allocating page table\n"); + return NULL; + } + memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); + + ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_MAPS); + if (!ttm->be_list) { + DRM_ERROR("Alloc be regions failed\n"); + drm_destroy_ttm(ttm); + return NULL; + } + + INIT_LIST_HEAD(&ttm->be_list->head); + INIT_LIST_HEAD(&ttm->p_mm_list); + atomic_set(&ttm->shared_count, 0); + ttm->mm_list_seq = 0; + + ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + if (!ttm->vma_list) { + DRM_ERROR("Alloc vma list failed\n"); + drm_destroy_ttm(ttm); + return NULL; + } + + INIT_LIST_HEAD(&ttm->vma_list->head); + + ttm->lhandle = (unsigned long)ttm; + ttm->dev = dev; + return ttm; +} + +/* + * Lock the mmap_sems for processes that are mapping this ttm. + * This looks a bit clumsy, since we need to maintain the correct + * locking order + * mm->mmap_sem + * dev->struct_sem; + * and while we release dev->struct_sem to lock the mmap_sems, + * the mmap_sem list may have been updated. We need to revalidate + * it after relocking dev->struc_sem. + */ + +static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) +{ + struct mm_struct **mm_list = NULL, **mm_list_p; + uint32_t list_seq; + uint32_t cur_count, shared_count; + p_mm_entry_t *entry; + unsigned i; + + cur_count = 0; + list_seq = ttm->mm_list_seq; + shared_count = atomic_read(&ttm->shared_count); + + do { + if (shared_count > cur_count) { + if (mm_list) + drm_free(mm_list, sizeof(*mm_list) * cur_count, + DRM_MEM_MM); + cur_count = shared_count + 10; + mm_list = + drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_MM); + if (!mm_list) + return -ENOMEM; + } + + mm_list_p = mm_list; + list_for_each_entry(entry, &ttm->p_mm_list, head) { + *mm_list_p++ = entry->mm; + } + + mutex_unlock(&ttm->dev->struct_mutex); + mm_list_p = mm_list; + for (i = 0; i < shared_count; ++i, ++mm_list_p) { + down_write(&((*mm_list_p)->mmap_sem)); + } + + mutex_lock(&ttm->dev->struct_mutex); + + if (list_seq != ttm->mm_list_seq) { + mm_list_p = mm_list; + for (i = 0; i < shared_count; ++i, ++mm_list_p) { + up_write(&((*mm_list_p)->mmap_sem)); + } + + } + shared_count = atomic_read(&ttm->shared_count); + + } while (list_seq != ttm->mm_list_seq); + + if (mm_list) + drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_MM); + + ttm->mmap_sem_locked = TRUE; + return 0; +} + +/* + * Change caching policy for range of pages in a ttm. + */ + +static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages, int noncached, + int do_tlbflush) +{ + int i, cur; + struct page **cur_page; + pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; + + drm_ttm_lock_mm(ttm, FALSE, TRUE); + unmap_vma_pages(ttm, page_offset, num_pages); + + for (i = 0; i < num_pages; ++i) { + cur = page_offset + i; + cur_page = ttm->pages + cur; + if (*cur_page) { + if (PageHighMem(*cur_page)) { + if (noncached + && page_address(*cur_page) != NULL) { + DRM_ERROR + ("Illegal mapped HighMem Page\n"); + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + return -EINVAL; + } + } else if ((ttm->page_flags[cur] & + DRM_TTM_PAGE_UNCACHED) != noncached) { + DRM_MASK_VAL(ttm->page_flags[cur], + DRM_TTM_PAGE_UNCACHED, noncached); + change_page_attr(*cur_page, 1, attr); + } + } + } + if (do_tlbflush) + global_flush_tlb(); + + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + return 0; +} + + +/* + * Unbind a ttm region from the aperture. + */ + +int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be = entry->be; + drm_ttm_t *ttm = entry->owner; + int ret; + + if (be) { + switch (entry->state) { + case ttm_bound: + if (ttm && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mmap_sem(ttm); + if (ret) + return ret; + drm_ttm_lock_mm(ttm, FALSE, TRUE); + unmap_vma_pages(ttm, entry->page_offset, + entry->num_pages); + global_flush_tlb(); + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + } + be->unbind(entry->be); + if (ttm && be->needs_cache_adjust(be)) { + drm_set_caching(ttm, entry->page_offset, + entry->num_pages, 0, 1); + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + break; + default: + break; + } + } + entry->state = ttm_evicted; + return 0; +} + +void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_evict_ttm_region(entry); + entry->state = ttm_unbound; +} + +/* + * Destroy and clean up all resources associated with a ttm region. + * FIXME: release pages to OS when doing this operation. + */ + +void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be = entry->be; + drm_ttm_t *ttm = entry->owner; + uint32_t *cur_page_flags; + int i; + + list_del_init(&entry->head); + + drm_unbind_ttm_region(entry); + if (be) { + be->clear(entry->be); + if (be->needs_cache_adjust(be)) { + int ret = drm_ttm_lock_mmap_sem(ttm); + drm_set_caching(ttm, entry->page_offset, + entry->num_pages, 0, 1); + if (!ret) + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + be->destroy(be); + } + cur_page_flags = ttm->page_flags + entry->page_offset; + for (i = 0; i < entry->num_pages; ++i) { + DRM_MASK_VAL(*cur_page_flags, DRM_TTM_PAGE_USED, 0); + cur_page_flags++; + } + + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); +} + +/* + * Create a ttm region from a range of ttm pages. + */ + +int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long n_pages, int cached, + drm_ttm_backend_list_t ** region) +{ + struct page **cur_page; + uint32_t *cur_page_flags; + drm_ttm_backend_list_t *entry; + drm_ttm_backend_t *be; + int ret, i; + + if ((page_offset + n_pages) > ttm->num_pages || n_pages == 0) { + DRM_ERROR("Region Doesn't fit ttm\n"); + return -EINVAL; + } + + cur_page_flags = ttm->page_flags + page_offset; + for (i = 0; i < n_pages; ++i, ++cur_page_flags) { + if (*cur_page_flags & DRM_TTM_PAGE_USED) { + DRM_ERROR("TTM region overlap\n"); + return -EINVAL; + } else { + DRM_MASK_VAL(*cur_page_flags, DRM_TTM_PAGE_USED, + DRM_TTM_PAGE_USED); + } + } + + entry = drm_calloc(1, sizeof(*entry), DRM_MEM_MAPS); + if (!entry) + return -ENOMEM; + + be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached); + if (!be) { + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + DRM_ERROR("Couldn't create backend.\n"); + return -EINVAL; + } + entry->state = ttm_unbound; + entry->page_offset = page_offset; + entry->num_pages = n_pages; + entry->be = be; + entry->owner = ttm; + + INIT_LIST_HEAD(&entry->head); + list_add_tail(&entry->head, &ttm->be_list->head); + + for (i = 0; i < entry->num_pages; ++i) { + cur_page = ttm->pages + (page_offset + i); + if (!*cur_page) { + *cur_page = alloc_page(GFP_KERNEL); + if (!*cur_page) { + DRM_ERROR("Page allocation failed\n"); + drm_destroy_ttm_region(entry); + return -ENOMEM; + } + SetPageReserved(*cur_page); + } + } + + if ((ret = be->populate(be, n_pages, ttm->pages + page_offset))) { + drm_destroy_ttm_region(entry); + DRM_ERROR("Couldn't populate backend.\n"); + return ret; + } + ttm->aperture_base = be->aperture_base; + + *region = entry; + return 0; +} + +/* + * Bind a ttm region. Set correct caching policy. + */ + +int drm_bind_ttm_region(drm_ttm_backend_list_t * region, + unsigned long aper_offset) +{ + + int i; + uint32_t *cur_page_flag; + int ret = 0; + drm_ttm_backend_t *be; + drm_ttm_t *ttm; + + if (!region || region->state == ttm_bound) + return -EINVAL; + + be = region->be; + ttm = region->owner; + + if (ttm && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mmap_sem(ttm); + if (ret) + return ret; + drm_set_caching(ttm, region->page_offset, region->num_pages, + DRM_TTM_PAGE_UNCACHED, TRUE); + } else { + DRM_DEBUG("Binding cached\n"); + } + + if ((ret = be->bind(be, aper_offset))) { + if (ttm && be->needs_cache_adjust(be)) + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_unbind_ttm_region(region); + DRM_ERROR("Couldn't bind backend.\n"); + return ret; + } + + cur_page_flag = ttm->page_flags + region->page_offset; + for (i = 0; i < region->num_pages; ++i) { + DRM_MASK_VAL(*cur_page_flag, DRM_TTM_MASK_PFN, + (i + aper_offset) << PAGE_SHIFT); + cur_page_flag++; + } + + if (ttm && be->needs_cache_adjust(be)) { + ioremap_vmas(ttm, region->page_offset, region->num_pages, + aper_offset); + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + + region->state = ttm_bound; + return 0; +} + +int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry, + unsigned long aper_offset) +{ + return drm_bind_ttm_region(entry, aper_offset); + +} + +/* + * Destroy an anonymous ttm region. + */ + +void drm_user_destroy_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be; + struct page **cur_page; + int i; + + if (!entry || entry->owner) + return; + + be = entry->be; + if (!be) { + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + return; + } + + be->unbind(be); + + if (entry->anon_pages) { + cur_page = entry->anon_pages; + for (i = 0; i < entry->anon_locked; ++i) { + if (!PageReserved(*cur_page)) + SetPageDirty(*cur_page); + page_cache_release(*cur_page); + cur_page++; + } + vfree(entry->anon_pages); + } + + be->destroy(be); + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + return; +} + +/* + * Create a ttm region from an arbitrary region of user pages. + * Since this region has no backing ttm, it's owner is set to + * null, and it is registered with the file of the caller. + * Gets destroyed when the file is closed. We call this an + * anonymous ttm region. + */ + +int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, + drm_ttm_backend_list_t ** entry) +{ + drm_ttm_backend_list_t *tmp; + drm_ttm_backend_t *be; + int ret; + + if (len <= 0) + return -EINVAL; + if (!dev->driver->bo_driver->create_ttm_backend_entry) + return -EFAULT; + + tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_MAPS); + + if (!tmp) + return -ENOMEM; + + be = dev->driver->bo_driver->create_ttm_backend_entry(dev, 1); + tmp->be = be; + + if (!be) { + drm_user_destroy_region(tmp); + return -ENOMEM; + } + if (be->needs_cache_adjust(be)) { + drm_user_destroy_region(tmp); + return -EFAULT; + } + + tmp->anon_pages = vmalloc(sizeof(*(tmp->anon_pages)) * len); + + if (!tmp->anon_pages) { + drm_user_destroy_region(tmp); + return -ENOMEM; + } + + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, start, len, 1, 0, + tmp->anon_pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (ret != len) { + drm_user_destroy_region(tmp); + DRM_ERROR("Could not lock %d pages. Return code was %d\n", + len, ret); + return -EPERM; + } + tmp->anon_locked = len; + + ret = be->populate(be, len, tmp->anon_pages); + + if (ret) { + drm_user_destroy_region(tmp); + return ret; + } + + tmp->state = ttm_unbound; +#ifdef REMOVED + tmp->mm = &dev->driver->bo_driver->ttm_mm; +#endif + *entry = tmp; + + return 0; +} + +/* + * Create a ttm and add it to the drm book-keeping. + */ + +int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) +{ + drm_map_list_t *list; + drm_map_t *map; + drm_ttm_t *ttm; + + map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + if (!map) + return -ENOMEM; + + ttm = drm_init_ttm(dev, size); + + if (!ttm) { + DRM_ERROR("Could not create ttm\n"); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -ENOMEM; + } + + map->offset = ttm->lhandle; + map->type = _DRM_TTM; + map->flags = _DRM_REMOVABLE; + map->size = size; + + list = drm_calloc(1, sizeof(*list), DRM_MEM_MAPS); + if (!list) { + drm_destroy_ttm(ttm); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -ENOMEM; + } + map->handle = (void *)list; + + +#ifdef REMOVED + if (drm_ht_just_insert_please(&dev->maphash, &list->hash, + (unsigned long) map->handle, + 32 - PAGE_SHIFT)) { + drm_destroy_ttm(ttm); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + drm_free(list, sizeof(*list), DRM_MEM_MAPS); + return -ENOMEM; + } +#endif + + list->user_token = + (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; + list->map = map; + + *maplist = list; + + return 0; +} diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h new file mode 100644 index 0000000..07592a8 --- /dev/null +++ b/linux-core/drm_ttm.h @@ -0,0 +1,152 @@ +#ifndef _DRM_TTM_H +#define _DRM_TTM_H +#define DRM_HAS_TTM + +/* + * The backend GART interface. (In our case AGP). Any similar type of device (PCIE?) + * needs only to implement these functions to be usable with the "TTM" interface. + * The AGP backend implementation lives in drm_agpsupport.c + * basically maps these calls to available functions in agpgart. Each drm device driver gets an + * additional function pointer that creates these types, + * so that the device can choose the correct aperture. + * (Multiple AGP apertures, etc.) + * Most device drivers will let this point to the standard AGP implementation. + */ + +typedef struct drm_ttm_backend { + unsigned long aperture_base; + void *private; + int (*needs_cache_adjust) (struct drm_ttm_backend * backend); + int (*populate) (struct drm_ttm_backend * backend, + unsigned long num_pages, struct page ** pages); + void (*clear) (struct drm_ttm_backend * backend); + int (*bind) (struct drm_ttm_backend * backend, unsigned long offset); + int (*unbind) (struct drm_ttm_backend * backend); + void (*destroy) (struct drm_ttm_backend * backend); +} drm_ttm_backend_t; + +#define DRM_FLUSH_READ (0x01) +#define DRM_FLUSH_WRITE (0x02) +#define DRM_FLUSH_EXE (0x04) + +typedef struct drm_ttm_backend_list { + drm_hash_item_t hash; + uint32_t flags; + atomic_t refcount; + struct list_head head; + drm_ttm_backend_t *be; + unsigned page_offset; + unsigned num_pages; + struct drm_ttm *owner; + drm_file_t *anon_owner; + struct page **anon_pages; + int anon_locked; + enum { + ttm_bound, + ttm_evicted, + ttm_unbound + } state; +} drm_ttm_backend_list_t; + +typedef struct drm_ttm_vma_list { + struct list_head head; + pgprot_t orig_protection; + struct vm_area_struct *vma; + drm_map_t *map; +} drm_ttm_vma_list_t; + +typedef struct drm_ttm { + struct list_head p_mm_list; + atomic_t shared_count; + uint32_t mm_list_seq; + unsigned long aperture_base; + struct page **pages; + uint32_t *page_flags; + unsigned long lhandle; + unsigned long num_pages; + drm_ttm_vma_list_t *vma_list; + struct drm_device *dev; + drm_ttm_backend_list_t *be_list; + atomic_t vma_count; + atomic_t unfinished_regions; + drm_file_t *owner; + int destroy; + int mmap_sem_locked; +} drm_ttm_t; + +/* + * Initialize a ttm. Currently the size is fixed. Currently drmAddMap calls this function + * and creates a DRM map of type _DRM_TTM, and returns a reference to that map to the + * caller. + */ + +drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size); + +/* + * Bind a part of the ttm starting at page_offset size n_pages into the GTT, at + * aperture offset aper_offset. The region handle will be used to reference this + * bound region in the future. Note that the region may be the whole ttm. + * Regions should not overlap. + * This function sets all affected pages as noncacheable and flushes cashes and TLB. + */ + +int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long n_pages, int cached, + drm_ttm_backend_list_t ** region); + +int drm_bind_ttm_region(drm_ttm_backend_list_t * region, + unsigned long aper_offset); + +/* + * Unbind a ttm region. Restores caching policy. Flushes caches and TLB. + */ + +void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry); +void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry); + +/* + * Evict a ttm region. Keeps Aperture caching policy. + */ + +int drm_evict_ttm_region(drm_ttm_backend_list_t * entry); + +/* + * Rebind an already evicted region into a possibly new location in the aperture. + */ + +int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry, + unsigned long aper_offset); + +/* + * Destroy a ttm. The user normally calls drmRmMap or a similar IOCTL to do this, + * which calls this function iff there are no vmas referencing it anymore. Otherwise it is called + * when the last vma exits. + */ + +extern int drm_destroy_ttm(drm_ttm_t * ttm); +extern void drm_user_destroy_region(drm_ttm_backend_list_t * entry); +extern int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm); +extern void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm); +extern void drm_ttm_fence_before_destroy(drm_ttm_t * ttm); +extern void drm_fence_unfenced_region(drm_ttm_backend_list_t * entry); + +extern int drm_ttm_ioctl(DRM_IOCTL_ARGS); +extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); +extern int drm_mm_fence_ioctl(DRM_IOCTL_ARGS); + +#define DRM_MASK_VAL(dest, mask, val) \ + (dest) = ((dest) & ~(mask)) | ((val) & (mask)); + +#define DRM_TTM_MASK_FLAGS ((1 << PAGE_SHIFT) - 1) +#define DRM_TTM_MASK_PFN (0xFFFFFFFFU - DRM_TTM_MASK_FLAGS) + +/* + * Page flags. + */ + +#define DRM_TTM_PAGE_UNCACHED 0x01 +#define DRM_TTM_PAGE_USED 0x02 +#define DRM_TTM_PAGE_BOUND 0x04 +#define DRM_TTM_PAGE_PRESENT 0x08 + +#endif diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index cf3bc3c..9f48f29 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -34,12 +34,42 @@ */ #include "drmP.h" + #if defined(__ia64__) #include <linux/efi.h> #endif static void drm_vm_open(struct vm_area_struct *vma); static void drm_vm_close(struct vm_area_struct *vma); +static void drm_vm_ttm_close(struct vm_area_struct *vma); +static int drm_vm_ttm_open(struct vm_area_struct *vma); +static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma); + + +pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) +{ + pgprot_t tmp = drm_prot_map(vma->vm_flags); + +#if defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { + pgprot_val(tmp) |= _PAGE_PCD; + pgprot_val(tmp) &= ~_PAGE_PWT; + } +#elif defined(__powerpc__) + pgprot_val(tmp) |= _PAGE_NO_CACHE; + if (map->type == _DRM_REGISTERS) + pgprot_val(tmp) |= _PAGE_GUARDED; +#endif +#if defined(__ia64__) + if (efi_range_is_wc(vma->vm_start, vma->vm_end - + vma->vm_start)) + tmp = pgprot_writecombine(tmp); + else + tmp = pgprot_noncached(tmp); +#endif + return tmp; +} + /** * \c nopage method for AGP virtual memory. @@ -129,6 +159,131 @@ static __inline__ struct page *drm_do_vm } #endif /* __OS_HAS_AGP */ + +static int drm_ttm_remap_bound_pfn(struct vm_area_struct *vma, + unsigned long address, + unsigned long size) +{ + unsigned long + page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + unsigned long + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + drm_ttm_vma_list_t *entry = (drm_ttm_vma_list_t *) + vma->vm_private_data; + drm_map_t *map = entry->map; + drm_ttm_t *ttm = (drm_ttm_t *) map->offset; + unsigned long i, cur_pfn; + unsigned long start = 0; + unsigned long end = 0; + unsigned long last_pfn = 0; + unsigned long start_pfn = 0; + int bound_sequence = FALSE; + int ret = 0; + uint32_t cur_flags; + + for (i=page_offset; i<page_offset + num_pages; ++i) { + cur_flags = ttm->page_flags[i]; + + if (!bound_sequence && (cur_flags & DRM_TTM_PAGE_UNCACHED)) { + + start = i; + end = i; + last_pfn = (cur_flags & DRM_TTM_MASK_PFN) >> PAGE_SHIFT; + start_pfn = last_pfn; + bound_sequence = TRUE; + + } else if (bound_sequence) { + + cur_pfn = (cur_flags & DRM_TTM_MASK_PFN) >> PAGE_SHIFT; + + if ( !(cur_flags & DRM_TTM_PAGE_UNCACHED) || + (cur_pfn != last_pfn + 1)) { + + ret = io_remap_pfn_range(vma, + vma->vm_start + (start << PAGE_SHIFT), + (ttm->aperture_base >> PAGE_SHIFT) + + start_pfn, + (end - start + 1) << PAGE_SHIFT, + drm_io_prot(_DRM_AGP, vma)); + + if (ret) + break; + + bound_sequence = (cur_flags & DRM_TTM_PAGE_UNCACHED); + if (!bound_sequence) + continue; + + start = i; + end = i; + last_pfn = cur_pfn; + start_pfn = last_pfn; + + } else { + + end++; + last_pfn = cur_pfn; + + } + } + } + + if (!ret && bound_sequence) { + ret = io_remap_pfn_range(vma, + vma->vm_start + (start << PAGE_SHIFT), + (ttm->aperture_base >> PAGE_SHIFT) + + start_pfn, + (end - start + 1) << PAGE_SHIFT, + drm_io_prot(_DRM_AGP, vma)); + } + + if (ret) { + DRM_ERROR("Map returned %c\n", ret); + } + return ret; +} + +static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address) +{ + drm_ttm_vma_list_t *entry = (drm_ttm_vma_list_t *) + vma->vm_private_data; + drm_map_t *map; + unsigned long page_offset; + struct page *page; + drm_ttm_t *ttm; + pgprot_t default_prot; + uint32_t page_flags; + + if (address > vma->vm_end) + return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!entry) + return NOPAGE_OOM; /* Nothing allocated */ + + map = (drm_map_t *) entry->map; + ttm = (drm_ttm_t *) map->offset; + page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + page = ttm->pages[page_offset]; + + page_flags = ttm->page_flags[page_offset]; + + if (!page) { + page = ttm->pages[page_offset] = + alloc_page(GFP_KERNEL); + SetPageReserved(page); + } + if (!page) + return NOPAGE_OOM; + + get_page(page); + + default_prot = drm_prot_map(vma->vm_flags); + + BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED); + vma->vm_page_prot = default_prot; + + return page; +} + /** * \c nopage method for shared virtual memory. * @@ -243,6 +398,9 @@ static void drm_vm_shm_close(struct vm_a dmah.size = map->size; __drm_pci_free(dev, &dmah); break; + case _DRM_TTM: + BUG_ON(1); + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); } @@ -358,6 +516,15 @@ static struct page *drm_vm_sg_nopage(str return drm_do_vm_sg_nopage(vma, address); } +static struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + if (type) + *type = VM_FAULT_MINOR; + return drm_do_vm_ttm_nopage(vma, address); +} + + #else /* LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0) */ static struct page *drm_vm_nopage(struct vm_area_struct *vma, @@ -384,6 +551,13 @@ static struct page *drm_vm_sg_nopage(str return drm_do_vm_sg_nopage(vma, address); } +static struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, int unused) +{ + return drm_do_vm_ttm_nopage(vma, address); +} + + #endif /** AGP virtual memory operations */ @@ -414,6 +588,12 @@ static struct vm_operations_struct drm_v .close = drm_vm_close, }; +static struct vm_operations_struct drm_vm_ttm_ops = { + .nopage = drm_vm_ttm_nopage, + .open = drm_vm_ttm_open_wrapper, + .close = drm_vm_ttm_close, +}; + /** * \c open method for shared virtual memory. * @@ -443,6 +623,46 @@ static void drm_vm_open(struct vm_area_s } } +static int drm_vm_ttm_open(struct vm_area_struct *vma) { + + drm_ttm_vma_list_t *entry, *tmp_vma = + (drm_ttm_vma_list_t *) vma->vm_private_data; + drm_map_t *map; + drm_ttm_t *ttm; + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->head->dev; + int ret = 0; + + drm_vm_open(vma); + mutex_lock(&dev->struct_mutex); + entry = drm_calloc(1, sizeof(*entry), DRM_MEM_VMAS); + if (entry) { + *entry = *tmp_vma; + map = (drm_map_t *) entry->map; + ttm = (drm_ttm_t *) map->offset; + /* ret = drm_ttm_add_mm_to_list(ttm, vma->vm_mm); */ + if (!ret) { + atomic_inc(&ttm->vma_count); + INIT_LIST_HEAD(&entry->head); + entry->vma = vma; + entry->orig_protection = vma->vm_page_prot; + list_add_tail(&entry->head, &ttm->vma_list->head); + vma->vm_private_data = (void *) entry; + DRM_DEBUG("Added VMA to ttm at 0x%016lx\n", + (unsigned long) ttm); + } + } else { + ret = -ENOMEM; + } + mutex_unlock(&dev->struct_mutex); + return ret; +} + +static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma) +{ + drm_vm_ttm_open(vma); +} + /** * \c close method for all virtual memory types. * @@ -476,6 +696,47 @@ static void drm_vm_close(struct vm_area_ mutex_unlock(&dev->struct_mutex); } + +static void drm_vm_ttm_close(struct vm_area_struct *vma) +{ + drm_ttm_vma_list_t *ttm_vma = + (drm_ttm_vma_list_t *) vma->vm_private_data; + drm_map_t *map; + drm_ttm_t *ttm; + int found_maps; + struct list_head *list; + drm_device_t *dev; + + drm_vm_close(vma); + if (ttm_vma) { + map = (drm_map_t *) ttm_vma->map; + ttm = (drm_ttm_t *) map->offset; + dev = ttm->dev; + mutex_lock(&dev->struct_mutex); + list_del(&ttm_vma->head); + /* drm_ttm_delete_mm(ttm, vma->vm_mm); */ + drm_free(ttm_vma, sizeof(*ttm_vma), DRM_MEM_VMAS); + atomic_dec(&ttm->vma_count); + found_maps = 0; + list = NULL; +#if 0 /* Reimplement with vma_count */ + list_for_each(list, &ttm->owner->ttms) { + r_list = list_entry(list, drm_map_list_t, head); + if (r_list->map == map) + found_maps++; + } + if (!found_maps) { + if (drm_destroy_ttm(ttm) != -EBUSY) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + } + } +#endif + mutex_unlock(&dev->struct_mutex); + } + return; +} + + /** * mmap DMA memory. * @@ -620,27 +881,9 @@ int drm_mmap(struct file *filp, struct v /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: -#if defined(__i386__) || defined(__x86_64__) - if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { - pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; - pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; - } -#elif defined(__powerpc__) - pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; - if (map->type == _DRM_REGISTERS) - pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED; -#endif - vma->vm_flags |= VM_IO; /* not in core dump */ -#if defined(__ia64__) - if (efi_range_is_wc(vma->vm_start, vma->vm_end - - vma->vm_start)) - vma->vm_page_prot = - pgprot_writecombine(vma->vm_page_prot); - else - vma->vm_page_prot = - pgprot_noncached(vma->vm_page_prot); -#endif offset = dev->driver->get_reg_ofs(dev); + vma->vm_flags |= VM_IO; /* not in core dump */ + vma->vm_page_prot = drm_io_prot(map->type, vma); #ifdef __sparc__ if (io_remap_pfn_range(vma, vma->vm_start, (map->offset + offset) >>PAGE_SHIFT, @@ -687,6 +930,22 @@ int drm_mmap(struct file *filp, struct v vma->vm_flags |= VM_RESERVED; #endif break; + case _DRM_TTM: { + drm_ttm_vma_list_t tmp_vma; + tmp_vma.orig_protection = vma->vm_page_prot; + tmp_vma.map = map; + vma->vm_ops = &drm_vm_ttm_ops; + vma->vm_private_data = (void *) &tmp_vma; + vma->vm_file = filp; + vma->vm_flags |= VM_RESERVED | VM_IO; + if (drm_ttm_remap_bound_pfn(vma, + vma->vm_start, + vma->vm_end - vma->vm_start)) + return -EAGAIN; + if (drm_vm_ttm_open(vma)) + return -EAGAIN; + return 0; + } default: return -EINVAL; /* This should never happen. */ } diff --git a/shared-core/drm.h b/shared-core/drm.h index 65d04b7..b588b15 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -260,6 +260,7 @@ typedef enum drm_map_type { _DRM_AGP = 3, /**< AGP/GART */ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ + _DRM_TTM = 6 } drm_map_type_t; /** |
From: <th...@ke...> - 2006-08-22 08:10:12
|
linux-core/drmP.h | 12 +++ linux-core/drm_agpsupport.c | 165 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) New commits: diff-tree b81ca5e031b2fbd9c5c401057c72f5857f7f5a3a (from 700bf80ca9fadf2c1404c220addebd92d9ad799d) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 22 10:09:57 2006 +0200 AGP backends for TTM. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 33d8ecc..8f8f324 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -850,6 +850,16 @@ typedef struct drm_device { } drm_device_t; +#if __OS_HAS_AGP +typedef struct drm_agp_ttm_priv { + DRM_AGP_MEM *mem; + struct agp_bridge_data *bridge; + unsigned mem_type; + int populated; +} drm_agp_ttm_priv; +#endif + + static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) { @@ -1162,6 +1172,8 @@ extern DRM_AGP_MEM *drm_agp_allocate_mem extern int drm_agp_free_memory(DRM_AGP_MEM * handle); extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start); extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); +extern drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev); +extern drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev); /* Stub support (drm_stub.h) */ extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index dce27cd..9286800 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -552,4 +552,169 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * return agp_unbind_memory(handle); } +/* + * AGP ttm backend interface. + */ + +static int drm_agp_needs_cache_adjust_true(drm_ttm_backend_t *backend) { + return TRUE; +} + +static int drm_agp_needs_cache_adjust_false(drm_ttm_backend_t *backend) { + return FALSE; +} + +#define AGP_MEM_USER (1 << 16) +#define AGP_MEM_UCACHED (2 << 16) + +static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, + struct page **pages) { + + drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; + struct page **cur_page, **last_page = pages + num_pages; + DRM_AGP_MEM *mem; + + DRM_DEBUG("drm_agp_populate_ttm\n"); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) + mem = drm_agp_allocate_memory(num_pages, agp_priv->mem_type); +#else + mem = drm_agp_allocate_memory(agp_priv->bridge, num_pages, agp_priv->mem_type); +#endif + if (!mem) + return -1; + + DRM_DEBUG("Current page count is %ld\n", (long) mem->page_count); + mem->page_count = 0; + for (cur_page = pages; cur_page < last_page; ++cur_page) { + mem->memory[mem->page_count++] = page_to_phys(*cur_page); + } + agp_priv->mem = mem; + return 0; +} + +static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, unsigned long offset) { + + drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; + DRM_AGP_MEM *mem = agp_priv->mem; + int ret; + + DRM_DEBUG("drm_agp_bind_ttm\n"); + mem->is_flushed = FALSE; + ret = drm_agp_bind_memory(mem, offset); + if (ret) { + DRM_ERROR("AGP Bind memory failed\n"); + } + return ret; +} + +static int drm_agp_unbind_ttm(drm_ttm_backend_t *backend) { + + drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; + + DRM_DEBUG("drm_agp_unbind_ttm\n"); + if (agp_priv->mem->is_bound) + return drm_agp_unbind_memory(agp_priv->mem); + else + return 0; +} + +static void drm_agp_clear_ttm(drm_ttm_backend_t *backend) { + + drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; + DRM_AGP_MEM *mem = agp_priv->mem; + + DRM_DEBUG("drm_agp_clear_ttm\n"); + if (mem) { + if (mem->is_bound) { + drm_agp_unbind_memory(mem); + } + agp_free_memory(mem); + } + agp_priv->mem = NULL; +} + +static void drm_agp_destroy_ttm(drm_ttm_backend_t *backend) { + + drm_agp_ttm_priv *agp_priv; + + if (backend) { + DRM_DEBUG("drm_agp_destroy_ttm\n"); + agp_priv = (drm_agp_ttm_priv *) backend->private; + if (agp_priv) { + if (agp_priv->mem) { + drm_agp_clear_ttm(backend); + } + drm_free(agp_priv, sizeof(*agp_priv), DRM_MEM_MAPPINGS); + } + drm_free(backend, sizeof(*backend), DRM_MEM_MAPPINGS); + } +} + + +drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev) { + + drm_ttm_backend_t *agp_be; + drm_agp_ttm_priv *agp_priv; + + agp_be = drm_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); + + if (!agp_be) + return NULL; + + agp_priv = drm_calloc(1, sizeof(agp_priv), DRM_MEM_MAPPINGS); + + if (!agp_priv) { + drm_free(agp_be, sizeof(*agp_be), DRM_MEM_MAPPINGS); + return NULL; + } + + agp_priv->mem = NULL; + agp_priv->mem_type = AGP_MEM_USER; + agp_priv->bridge = dev->agp->bridge; + agp_priv->populated = FALSE; + agp_be->aperture_base = dev->agp->agp_info.aper_base; + agp_be->private = (void *) agp_priv; + agp_be->needs_cache_adjust = drm_agp_needs_cache_adjust_true; + agp_be->populate = drm_agp_populate; + agp_be->clear = drm_agp_clear_ttm; + agp_be->bind = drm_agp_bind_ttm; + agp_be->unbind = drm_agp_unbind_ttm; + agp_be->destroy = drm_agp_destroy_ttm; + return agp_be; +} + + +drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev) { + + drm_ttm_backend_t *agp_be; + drm_agp_ttm_priv *agp_priv; + + agp_be = drm_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); + + if (!agp_be) + return NULL; + + agp_priv = drm_calloc(1, sizeof(agp_priv), DRM_MEM_MAPPINGS); + + if (!agp_priv) { + drm_free(agp_be, sizeof(*agp_be), DRM_MEM_MAPPINGS); + return NULL; + } + + agp_priv->mem = NULL; + agp_priv->mem_type = AGP_MEM_UCACHED; + agp_priv->bridge = dev->agp->bridge; + agp_priv->populated = FALSE; + agp_be->aperture_base = dev->agp->agp_info.aper_base; + agp_be->private = (void *) agp_priv; + agp_be->needs_cache_adjust = drm_agp_needs_cache_adjust_false; + agp_be->populate = drm_agp_populate; + agp_be->clear = drm_agp_clear_ttm; + agp_be->bind = drm_agp_bind_ttm; + agp_be->unbind = drm_agp_unbind_ttm; + agp_be->destroy = drm_agp_destroy_ttm; + return agp_be; +} + + #endif /* __OS_HAS_AGP */ |
From: <th...@ke...> - 2006-08-22 08:25:05
|
linux-core/Makefile.kernel | 3 ++- linux-core/drm_agpsupport.c | 4 ++-- linux-core/i915_buffer.c | 40 ++++++++++++++++++++++++++++++++++++++++ linux-core/i915_drv.c | 8 ++++++++ shared-core/i915_drv.h | 7 +++++++ 5 files changed, 59 insertions(+), 3 deletions(-) New commits: diff-tree 7058d06317e17253d874bf4df7b09d0d52a5fd74 (from b81ca5e031b2fbd9c5c401057c72f5857f7f5a3a) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 22 10:24:48 2006 +0200 Initial i915 buffer object driver diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index bf5221d..e571f29 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -19,7 +19,8 @@ r128-objs := r128_drv.o r128_cce.o r12 mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i830-objs := i830_drv.o i830_dma.o i830_irq.o -i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ + i915_buffer.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 9286800..e7226f1 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -682,7 +682,7 @@ drm_ttm_backend_t *drm_agp_init_ttm_unca agp_be->destroy = drm_agp_destroy_ttm; return agp_be; } - +EXPORT_SYMBOL(drm_agp_init_ttm_uncached); drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev) { @@ -715,6 +715,6 @@ drm_ttm_backend_t *drm_agp_init_ttm_cach agp_be->destroy = drm_agp_destroy_ttm; return agp_be; } - +EXPORT_SYMBOL(drm_agp_init_ttm_cached); #endif /* __OS_HAS_AGP */ diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c new file mode 100644 index 0000000..bedbd41 --- /dev/null +++ b/linux-core/i915_buffer.c @@ -0,0 +1,40 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + +#include "drmP.h" + +drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, int cached) +{ + if (cached) + return drm_agp_init_ttm_cached(dev); + else + return drm_agp_init_ttm_uncached(dev); +} diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 56ac5fc..64ab3f5 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -48,6 +48,12 @@ static drm_fence_driver_t i915_fence_dri .poke_flush = i915_poke_flush, }; +static drm_bo_driver_t i915_bo_driver = { + .cached_pages = 1, + .create_ttm_backend_entry = i915_create_ttm_backend_entry +}; + + static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { /* don't use mtrr's here, the Xserver or user space app should @@ -89,6 +95,8 @@ static struct drm_driver driver = { }, .fence_driver = &i915_fence_driver, + .bo_driver = &i915_bo_driver, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 475ff47..403124c 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -53,6 +53,7 @@ #if defined(__linux__) #define I915_HAVE_FENCE +#define I915_HAVE_BUFFER #endif typedef struct _drm_i915_ring_buffer { @@ -153,6 +154,12 @@ extern void i915_poke_flush(drm_device_t extern void i915_sync_flush(drm_device_t *dev); #endif +#ifdef I915_HAVE_BUFFER +/* i915_buffer.c */ +extern drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, + int cached); +#endif + #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) #define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg)) |
From: <th...@ke...> - 2006-08-22 08:45:06
|
libdrm/xf86drm.c | 10 +++++++++- libdrm/xf86drm.h | 4 +++- linux-core/drmP.h | 1 + linux-core/drm_fence.c | 2 ++ shared-core/drm.h | 1 + 5 files changed, 16 insertions(+), 2 deletions(-) New commits: diff-tree a6535c8db4614376ce8ecb7d889b92db066a96cc (from 7058d06317e17253d874bf4df7b09d0d52a5fd74) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 22 10:44:09 2006 +0200 Add a fence object class field for future use (For example VSYNC fence objects) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6302db3..a2a2e28 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2237,18 +2237,21 @@ int drmCommandWriteRead(int fd, unsigned return 0; } -int drmFenceCreate(int fd, int shareable, unsigned type, int emit, +int drmFenceCreate(int fd, int shareable, int class,unsigned type, + int emit, drmFence *fence) { drm_fence_arg_t arg; arg.type = type; + arg.class = class; arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0; arg.flags |= (emit) ? DRM_FENCE_FLAG_EMIT : 0; arg.op = drm_fence_create; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; fence->handle = arg.handle; + fence->class = arg.class; fence->type = arg.type; fence->signaled = 0; return 0; @@ -2274,6 +2277,7 @@ int drmFenceReference(int fd, unsigned h if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; fence->handle = arg.handle; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; @@ -2299,6 +2303,7 @@ int drmFenceFlush(int fd, drmFence *fenc arg.op = drm_fence_flush; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; @@ -2312,6 +2317,7 @@ int drmFenceSignaled(int fd, drmFence *f arg.op = drm_fence_signaled; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; @@ -2326,6 +2332,7 @@ int drmFenceEmit(int fd, drmFence *fence arg.op = drm_fence_emit; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; @@ -2349,6 +2356,7 @@ int drmFenceWait(int fd, drmFence *fence if (ret) return -errno; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 0e037da..7873078 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -282,6 +282,7 @@ typedef struct _drmSetVersion { typedef struct _drmFence{ unsigned handle; + int class; unsigned type; unsigned signaled; } drmFence; @@ -603,7 +604,8 @@ extern int drmWaitVBlank(int f /* Fencing */ -extern int drmFenceCreate(int fd, int shareable, unsigned type, int emit, +extern int drmFenceCreate(int fd, int shareable, int class, + unsigned type, int emit, drmFence *fence); extern int drmFenceDestroy(int fd, const drmFence *fence); extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 8f8f324..5a4a37f 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -963,6 +963,7 @@ typedef struct drm_fence_object{ */ struct list_head ring; + int class; volatile uint32_t type; volatile uint32_t signaled; uint32_t sequence; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index fc27c57..cfcda2b 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -397,6 +397,7 @@ int drm_fence_object_init(drm_device_t * write_lock_irqsave(&fm->lock, flags); INIT_LIST_HEAD(&fence->ring); + fence->class = 0; fence->type = type; fence->flush_mask = 0; fence->submitted_flush = 0; @@ -577,6 +578,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } read_lock_irqsave(&fm->lock, flags); + arg.class = fence->class; arg.type = fence->type; arg.signaled = fence->signaled; read_unlock_irqrestore(&fm->lock, flags); diff --git a/shared-core/drm.h b/shared-core/drm.h index b588b15..cd2b190 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -639,6 +639,7 @@ typedef struct drm_set_version { typedef struct drm_fence_arg { unsigned handle; + int class; unsigned type; unsigned flags; unsigned signaled; |
From: <th...@ke...> - 2006-08-22 09:21:09
|
linux-core/drmP.h | 3 + linux-core/drm_ttm.c | 98 +++++++++++++++++++++------------------------------ linux-core/drm_ttm.h | 42 ++++++++++++++++----- 3 files changed, 75 insertions(+), 68 deletions(-) New commits: diff-tree ca4e34e532e818921f7b2d36fc6886874b7f7924 (from a6535c8db4614376ce8ecb7d889b92db066a96cc) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 22 11:19:53 2006 +0200 ttm code cleanup. Fix the sleep-in-page-table-spinlock bug discovered by Dave Airlie diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5a4a37f..e42b5e5 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -156,7 +156,8 @@ #define DRM_MEM_HASHTAB 23 #define DRM_MEM_OBJECTS 24 #define DRM_MEM_FENCE 25 - +#define DRM_MEM_TTM 26 +#define DRM_MEM_BUFOBJ 27 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) #define DRM_MAP_HASH_OFFSET 0x10000000 diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index b3ea7c9..493f146 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -1,6 +1,6 @@ /************************************************************************** * - * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO. + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -60,7 +60,7 @@ int drm_ttm_add_mm_to_list(drm_ttm_t * t } else if ((unsigned long)mm < (unsigned long)entry->mm) ; } - n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_MM); + n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_TTM); if (!entry) { DRM_ERROR("Allocation of process mm pointer entry failed\n"); return -ENOMEM; @@ -83,7 +83,7 @@ void drm_ttm_delete_mm(drm_ttm_t * ttm, if (mm == entry->mm) { if (atomic_add_negative(-1, &entry->refcount)) { list_del(&entry->head); - drm_free(entry, sizeof(*entry), DRM_MEM_MM); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); atomic_dec(&ttm->shared_count); ttm->mm_list_seq++; } @@ -155,7 +155,9 @@ static int unmap_vma_pages(drm_ttm_t * t struct page **first_page = ttm->pages + page_offset; struct page **last_page = ttm->pages + (page_offset + num_pages); struct page **cur_page; - +#if !defined(flush_tlb_mm) && defined(MODULE) + int flush_tlb = 0; +#endif list_for_each(list, &ttm->vma_list->head) { drm_ttm_vma_list_t *entry = list_entry(list, drm_ttm_vma_list_t, head); @@ -164,7 +166,14 @@ static int unmap_vma_pages(drm_ttm_t * t (page_offset << PAGE_SHIFT), entry->vma->vm_start + ((page_offset + num_pages) << PAGE_SHIFT)); +#if !defined(flush_tlb_mm) && defined(MODULE) + flush_tlb = 1; +#endif } +#if !defined(flush_tlb_mm) && defined(MODULE) + if (flush_tlb) + global_flush_tlb(); +#endif for (cur_page = first_page; cur_page != last_page; ++cur_page) { if (page_mapcount(*cur_page) != 0) { @@ -193,33 +202,19 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (atomic_read(&ttm->vma_count) > 0) { DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; - } else { - DRM_DEBUG("Checking for busy regions.\n"); - } + } if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = list_entry(list, drm_ttm_backend_list_t, head); -#ifdef REMOVED - drm_ht_remove_item(&ttm->dev->ttmreghash, - &entry->hash); -#endif drm_destroy_ttm_region(entry); } - drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_MAPS); + drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_TTM); ttm->be_list = NULL; } - if (atomic_read(&ttm->unfinished_regions) > 0) { - DRM_DEBUG("Regions are still busy. Skipping destruction.\n"); - ttm->destroy = TRUE; - return -EAGAIN; - } else { - DRM_DEBUG("About to really destroy ttm.\n"); - } - if (ttm->pages) { for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages + i; @@ -237,6 +232,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) vfree(ttm->pages); ttm->pages = NULL; } + if (ttm->page_flags) { vfree(ttm->page_flags); ttm->page_flags = NULL; @@ -248,12 +244,13 @@ int drm_destroy_ttm(drm_ttm_t * ttm) list_entry(list, drm_ttm_vma_list_t, head); list_del(list); entry->vma->vm_private_data = NULL; - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); } - drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_TTM); ttm->vma_list = NULL; } - drm_free(ttm, sizeof(*ttm), DRM_MEM_MAPS); + + drm_free(ttm, sizeof(*ttm), DRM_MEM_TTM); return 0; } @@ -271,14 +268,12 @@ drm_ttm_t *drm_init_ttm(struct drm_devic if (!dev->driver->bo_driver) return NULL; - ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_MAPS); + ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_TTM); if (!ttm) return NULL; ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); - atomic_set(&ttm->unfinished_regions, 0); - ttm->destroy = FALSE; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); @@ -297,7 +292,7 @@ drm_ttm_t *drm_init_ttm(struct drm_devic } memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); - ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_MAPS); + ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_TTM); if (!ttm->be_list) { DRM_ERROR("Alloc be regions failed\n"); drm_destroy_ttm(ttm); @@ -309,7 +304,7 @@ drm_ttm_t *drm_init_ttm(struct drm_devic atomic_set(&ttm->shared_count, 0); ttm->mm_list_seq = 0; - ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_TTM); if (!ttm->vma_list) { DRM_ERROR("Alloc vma list failed\n"); drm_destroy_ttm(ttm); @@ -350,10 +345,10 @@ static int drm_ttm_lock_mmap_sem(drm_ttm if (shared_count > cur_count) { if (mm_list) drm_free(mm_list, sizeof(*mm_list) * cur_count, - DRM_MEM_MM); + DRM_MEM_TTM); cur_count = shared_count + 10; mm_list = - drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_MM); + drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_TTM); if (!mm_list) return -ENOMEM; } @@ -383,9 +378,8 @@ static int drm_ttm_lock_mmap_sem(drm_ttm } while (list_seq != ttm->mm_list_seq); if (mm_list) - drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_MM); + drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_TTM); - ttm->mmap_sem_locked = TRUE; return 0; } @@ -403,6 +397,7 @@ static int drm_set_caching(drm_ttm_t * t drm_ttm_lock_mm(ttm, FALSE, TRUE); unmap_vma_pages(ttm, page_offset, num_pages); + drm_ttm_unlock_mm(ttm, FALSE, TRUE); for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -413,7 +408,6 @@ static int drm_set_caching(drm_ttm_t * t && page_address(*cur_page) != NULL) { DRM_ERROR ("Illegal mapped HighMem Page\n"); - drm_ttm_unlock_mm(ttm, FALSE, TRUE); return -EINVAL; } } else if ((ttm->page_flags[cur] & @@ -426,12 +420,9 @@ static int drm_set_caching(drm_ttm_t * t } if (do_tlbflush) global_flush_tlb(); - - drm_ttm_unlock_mm(ttm, FALSE, TRUE); return 0; } - /* * Unbind a ttm region from the aperture. */ @@ -508,7 +499,7 @@ void drm_destroy_ttm_region(drm_ttm_back cur_page_flags++; } - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); } /* @@ -541,13 +532,13 @@ int drm_create_ttm_region(drm_ttm_t * tt } } - entry = drm_calloc(1, sizeof(*entry), DRM_MEM_MAPS); + entry = drm_calloc(1, sizeof(*entry), DRM_MEM_TTM); if (!entry) return -ENOMEM; be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached); if (!be) { - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); DRM_ERROR("Couldn't create backend.\n"); return -EINVAL; } @@ -661,7 +652,7 @@ void drm_user_destroy_region(drm_ttm_bac be = entry->be; if (!be) { - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); return; } @@ -679,7 +670,7 @@ void drm_user_destroy_region(drm_ttm_bac } be->destroy(be); - drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); return; } @@ -703,7 +694,7 @@ int drm_user_create_region(drm_device_t if (!dev->driver->bo_driver->create_ttm_backend_entry) return -EFAULT; - tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_MAPS); + tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_TTM); if (!tmp) return -ENOMEM; @@ -748,9 +739,6 @@ int drm_user_create_region(drm_device_t } tmp->state = ttm_unbound; -#ifdef REMOVED - tmp->mm = &dev->driver->bo_driver->ttm_mm; -#endif *entry = tmp; return 0; @@ -766,7 +754,7 @@ int drm_add_ttm(drm_device_t * dev, unsi drm_map_t *map; drm_ttm_t *ttm; - map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + map = drm_alloc(sizeof(*map), DRM_MEM_TTM); if (!map) return -ENOMEM; @@ -774,7 +762,7 @@ int drm_add_ttm(drm_device_t * dev, unsi if (!ttm) { DRM_ERROR("Could not create ttm\n"); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + drm_free(map, sizeof(*map), DRM_MEM_TTM); return -ENOMEM; } @@ -783,25 +771,23 @@ int drm_add_ttm(drm_device_t * dev, unsi map->flags = _DRM_REMOVABLE; map->size = size; - list = drm_calloc(1, sizeof(*list), DRM_MEM_MAPS); + list = drm_calloc(1, sizeof(*list), DRM_MEM_TTM); if (!list) { drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + drm_free(map, sizeof(*map), DRM_MEM_TTM); return -ENOMEM; } map->handle = (void *)list; - -#ifdef REMOVED - if (drm_ht_just_insert_please(&dev->maphash, &list->hash, + if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, (unsigned long) map->handle, - 32 - PAGE_SHIFT)) { + 32 - PAGE_SHIFT - 3, PAGE_SHIFT, + DRM_MAP_HASH_OFFSET)) { drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); - drm_free(list, sizeof(*list), DRM_MEM_MAPS); + drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_free(list, sizeof(*list), DRM_MEM_TTM); return -ENOMEM; } -#endif list->user_token = (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 07592a8..f695fcc 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -1,3 +1,34 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + #ifndef _DRM_TTM_H #define _DRM_TTM_H #define DRM_HAS_TTM @@ -30,9 +61,7 @@ typedef struct drm_ttm_backend { #define DRM_FLUSH_EXE (0x04) typedef struct drm_ttm_backend_list { - drm_hash_item_t hash; uint32_t flags; - atomic_t refcount; struct list_head head; drm_ttm_backend_t *be; unsigned page_offset; @@ -68,9 +97,6 @@ typedef struct drm_ttm { struct drm_device *dev; drm_ttm_backend_list_t *be_list; atomic_t vma_count; - atomic_t unfinished_regions; - drm_file_t *owner; - int destroy; int mmap_sem_locked; } drm_ttm_t; @@ -127,12 +153,6 @@ extern int drm_destroy_ttm(drm_ttm_t * t extern void drm_user_destroy_region(drm_ttm_backend_list_t * entry); extern int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm); extern void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm); -extern void drm_ttm_fence_before_destroy(drm_ttm_t * ttm); -extern void drm_fence_unfenced_region(drm_ttm_backend_list_t * entry); - -extern int drm_ttm_ioctl(DRM_IOCTL_ARGS); -extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); -extern int drm_mm_fence_ioctl(DRM_IOCTL_ARGS); #define DRM_MASK_VAL(dest, mask, val) \ (dest) = ((dest) & ~(mask)) | ((val) & (mask)); |
From: <th...@ke...> - 2006-08-22 09:57:29
|
linux-core/drm_ttm.c | 25 ++++++++++++++----------- linux-core/drm_ttm.h | 9 ++------- linux-core/drm_vm.c | 24 ++++++++---------------- 3 files changed, 24 insertions(+), 34 deletions(-) New commits: diff-tree e201511a0fbeb177a9ecd7f77d177fc88c1616fb (from ca4e34e532e818921f7b2d36fc6886874b7f7924) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 22 11:57:08 2006 +0200 More ttm cleanups. diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 493f146..df4c312 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -90,7 +90,7 @@ void drm_ttm_delete_mm(drm_ttm_t * ttm, return; } } - BUG_ON(TRUE); + BUG_ON(1); } static void drm_ttm_lock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) @@ -200,6 +200,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) return 0; if (atomic_read(&ttm->vma_count) > 0) { + ttm->destroy = 1; DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; } @@ -260,7 +261,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) * FIXME: Avoid using vmalloc for the page- and page_flags tables? */ -drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) +static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) { drm_ttm_t *ttm; @@ -274,6 +275,7 @@ drm_ttm_t *drm_init_ttm(struct drm_devic ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); + ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); @@ -315,6 +317,7 @@ drm_ttm_t *drm_init_ttm(struct drm_devic ttm->lhandle = (unsigned long)ttm; ttm->dev = dev; + return ttm; } @@ -395,9 +398,9 @@ static int drm_set_caching(drm_ttm_t * t struct page **cur_page; pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; - drm_ttm_lock_mm(ttm, FALSE, TRUE); + drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, page_offset, num_pages); - drm_ttm_unlock_mm(ttm, FALSE, TRUE); + drm_ttm_unlock_mm(ttm, 0, 1); for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -440,17 +443,17 @@ int drm_evict_ttm_region(drm_ttm_backend ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; - drm_ttm_lock_mm(ttm, FALSE, TRUE); + drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); global_flush_tlb(); - drm_ttm_unlock_mm(ttm, FALSE, TRUE); + drm_ttm_unlock_mm(ttm, 0, 1); } be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0, 1); - drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_ttm_unlock_mm(ttm, 1, 0); } break; default: @@ -489,7 +492,7 @@ void drm_destroy_ttm_region(drm_ttm_back drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0, 1); if (!ret) - drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_ttm_unlock_mm(ttm, 1, 0); } be->destroy(be); } @@ -600,14 +603,14 @@ int drm_bind_ttm_region(drm_ttm_backend_ if (ret) return ret; drm_set_caching(ttm, region->page_offset, region->num_pages, - DRM_TTM_PAGE_UNCACHED, TRUE); + DRM_TTM_PAGE_UNCACHED, 1); } else { DRM_DEBUG("Binding cached\n"); } if ((ret = be->bind(be, aper_offset))) { if (ttm && be->needs_cache_adjust(be)) - drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_ttm_unlock_mm(ttm, 1, 0); drm_unbind_ttm_region(region); DRM_ERROR("Couldn't bind backend.\n"); return ret; @@ -623,7 +626,7 @@ int drm_bind_ttm_region(drm_ttm_backend_ if (ttm && be->needs_cache_adjust(be)) { ioremap_vmas(ttm, region->page_offset, region->num_pages, aper_offset); - drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_ttm_unlock_mm(ttm, 1, 0); } region->state = ttm_bound; diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index f695fcc..ea9a837 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -98,15 +98,10 @@ typedef struct drm_ttm { drm_ttm_backend_list_t *be_list; atomic_t vma_count; int mmap_sem_locked; + int destroy; } drm_ttm_t; -/* - * Initialize a ttm. Currently the size is fixed. Currently drmAddMap calls this function - * and creates a DRM map of type _DRM_TTM, and returns a reference to that map to the - * caller. - */ - -drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size); +int drm_add_ttm(struct drm_device * dev, unsigned size, drm_map_list_t ** maplist); /* * Bind a part of the ttm starting at page_offset size n_pages into the GTT, at diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 9f48f29..85b3949 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -640,7 +640,7 @@ static int drm_vm_ttm_open(struct vm_are *entry = *tmp_vma; map = (drm_map_t *) entry->map; ttm = (drm_ttm_t *) map->offset; - /* ret = drm_ttm_add_mm_to_list(ttm, vma->vm_mm); */ + ret = drm_ttm_add_mm_to_list(ttm, vma->vm_mm); if (!ret) { atomic_inc(&ttm->vma_count); INIT_LIST_HEAD(&entry->head); @@ -706,6 +706,7 @@ static void drm_vm_ttm_close(struct vm_a int found_maps; struct list_head *list; drm_device_t *dev; + int ret; drm_vm_close(vma); if (ttm_vma) { @@ -713,24 +714,15 @@ static void drm_vm_ttm_close(struct vm_a ttm = (drm_ttm_t *) map->offset; dev = ttm->dev; mutex_lock(&dev->struct_mutex); - list_del(&ttm_vma->head); - /* drm_ttm_delete_mm(ttm, vma->vm_mm); */ + drm_ttm_delete_mm(ttm, vma->vm_mm); drm_free(ttm_vma, sizeof(*ttm_vma), DRM_MEM_VMAS); - atomic_dec(&ttm->vma_count); - found_maps = 0; - list = NULL; -#if 0 /* Reimplement with vma_count */ - list_for_each(list, &ttm->owner->ttms) { - r_list = list_entry(list, drm_map_list_t, head); - if (r_list->map == map) - found_maps++; - } - if (!found_maps) { - if (drm_destroy_ttm(ttm) != -EBUSY) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + if (atomic_dec_and_test(&ttm->vma_count)) { + if (ttm->destroy) { + ret = drm_destroy_ttm(ttm); + BUG_ON(ret); + drm_free(map, sizeof(*map), DRM_MEM_TTM); } } -#endif mutex_unlock(&dev->struct_mutex); } return; |
From: <th...@ke...> - 2006-08-25 16:14:40
|
linux-core/drm_compat.c | 6 +++--- linux-core/drm_compat.h | 2 +- linux-core/drm_vm.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) New commits: diff-tree 1d3cf107d20cb11ad07667622785ef8341ab9c2a (from 4c03030b12bae28dad50d69bd271de632c43ff13) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Fri Aug 25 18:14:22 2006 +0200 Module protection map access is moving into mainline kernels. Update drm_compat accordingly. (Reported by Dave Airlie) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index cdef4b9..86bae30 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -124,7 +124,7 @@ void drm_clear_vma(struct vm_area_struct #endif } -pgprot_t drm_prot_map(uint32_t flags) +pgprot_t vm_get_page_prot(unsigned long vm_flags) { #ifdef MODULE static pgprot_t drm_protection_map[16] = { @@ -132,9 +132,9 @@ pgprot_t drm_prot_map(uint32_t flags) __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; - return drm_protection_map[flags & 0x0F]; + return drm_protection_map[vm_flags & 0x0F]; #else extern pgprot_t protection_map[]; - return protection_map[flags & 0x0F]; + return protection_map[vm_flags & 0x0F]; #endif }; diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 8092831..779a700 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -243,6 +243,6 @@ extern void drm_clear_vma(struct vm_area * flags. This is a functional interface to the kernel's protection map. */ -extern pgprot_t drm_prot_map(uint32_t flags); +extern pgprot_t vm_get_page_prot(unsigned long vm_flags); #endif diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 9c2fbe0..b5003c9 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -48,7 +48,7 @@ static void drm_vm_ttm_open_wrapper(stru pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) { - pgprot_t tmp = drm_prot_map(vma->vm_flags); + pgprot_t tmp = vm_get_page_prot(vma->vm_flags); #if defined(__i386__) || defined(__x86_64__) if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { @@ -276,7 +276,7 @@ static __inline__ struct page *drm_do_vm get_page(page); - default_prot = drm_prot_map(vma->vm_flags); + default_prot = vm_get_page_prot(vma->vm_flags); BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED); vma->vm_page_prot = default_prot; |
From: <th...@ke...> - 2006-08-27 19:21:18
|
shared-core/i915_dma.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletion(-) New commits: diff-tree 928bdc6c1c9cd1e60f0b070533768aaca56c84d8 (from b4b7b997605f88f3ffdcb0cc7cd1271e0cb24073) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Sun Aug 27 21:21:06 2006 +0200 Initialize i915 saved flush flags. diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index d6bb6c8..8ef9d8e 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -195,7 +195,9 @@ static int i915_initialize(drm_device_t I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); - +#ifdef I915_HAVE_FENCE + dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); +#endif dev->dev_private = (void *)dev_priv; return 0; |
From: <th...@ke...> - 2006-08-27 20:01:47
|
libdrm/xf86drm.c | 57 ++++++++++++++++++--------------------------------- libdrm/xf86drm.h | 7 ++++++ linux-core/drm_ttm.c | 1 3 files changed, 29 insertions(+), 36 deletions(-) New commits: diff-tree 886d3b3061cdf53f5a353cbaac843f63104d2658 (from 928bdc6c1c9cd1e60f0b070533768aaca56c84d8) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Sun Aug 27 22:01:33 2006 +0200 Bugfixes. diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index e666df3..8867608 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2385,37 +2385,28 @@ static void split32(unsigned long val, u int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) { - drm_ttm_arg_t argTTM; - drm_bo_arg_t arg; + drm_ttm_arg_t arg; - arg.num_requests = 1; - arg.op = drm_op_ttm; - split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); - - argTTM.op = drm_ttm_create; - argTTM.flags = flags; - split32((unsigned long) &size, &argTTM.size_lo, &argTTM.size_hi); + arg.op = drm_ttm_create; + arg.flags = flags; + split32((unsigned long) size, &arg.size_lo, &arg.size_hi); if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; - ttm->handle = argTTM.handle; - ttm->user_token = (drm_handle_t) argTTM.user_token; - ttm->flags = argTTM.flags; - ttm->size = combine64(argTTM.size_lo, argTTM.size_hi); + ttm->handle = arg.handle; + ttm->user_token = (drm_handle_t) arg.user_token; + ttm->flags = arg.flags; + ttm->size = combine64(arg.size_lo, arg.size_hi); return 0; } int drmTTMDestroy(int fd, const drmTTM *ttm) { - drm_ttm_arg_t argTTM; - drm_bo_arg_t arg; + drm_ttm_arg_t arg; - arg.num_requests = 1; - arg.op = drm_op_ttm; - split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); - argTTM.op = drm_ttm_destroy; - argTTM.handle = ttm->handle; + arg.op = drm_ttm_destroy; + arg.handle = ttm->handle; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; return 0; @@ -2424,31 +2415,25 @@ int drmTTMDestroy(int fd, const drmTTM * int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) { - drm_ttm_arg_t argTTM; - drm_bo_arg_t arg; + drm_ttm_arg_t arg; - arg.num_requests = 1; - arg.op = drm_op_ttm; - split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); - - argTTM.handle = handle; - argTTM.op = drm_ttm_reference; + arg.handle = handle; + arg.op = drm_ttm_reference; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; - ttm->handle = argTTM.handle; - ttm->user_token = (drm_handle_t) argTTM.user_token; - ttm->flags = argTTM.flags; - ttm->size = combine64(argTTM.size_lo, argTTM.size_hi); + ttm->handle = arg.handle; + ttm->user_token = (drm_handle_t) arg.user_token; + ttm->flags = arg.flags; + ttm->size = combine64(arg.size_lo, arg.size_hi); return 0; } int drmTTMUnreference(int fd, const drmTTM *ttm) { - drm_ttm_arg_t argTTM; - drm_bo_arg_t arg; + drm_ttm_arg_t arg; - argTTM.op = drm_ttm_destroy; - argTTM.handle = ttm->handle; + arg.op = drm_ttm_destroy; + arg.handle = ttm->handle; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; return 0; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 92cef4c..433191b 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -623,6 +623,13 @@ extern int drmFenceWait(int fd int lazy, int ignore_signals); extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); +/* TTMS */ +extern int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, + unsigned flags); +extern int drmTTMDestroy(int fd, const drmTTM *ttm); +extern int drmTTMReference(int fd, unsigned handle, drmTTM *ttm); +extern int drmTTMUnreference(int fd, const drmTTM *ttm); +extern drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm); /* Support routines */ diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 950b0d4..ad7b279 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -846,6 +846,7 @@ int drm_ttm_object_create(drm_device_t * object->base.unref = NULL; atomic_set(&object->usage, 1); + *ttm_object = object; return 0; } |
From: <th...@ke...> - 2006-08-28 14:36:56
|
linux-core/drmP.h | 3 linux-core/drm_bo.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++- linux-core/drm_ttm.c | 56 +++++++++++++---- linux-core/drm_ttm.h | 7 ++ shared-core/drm.h | 14 ++-- 5 files changed, 215 insertions(+), 25 deletions(-) New commits: diff-tree 0d67356de4e0c9e0d068ea9c16cf33df4fd13776 (from 05536a64785223ee8c57556300a14ba9c89837ae) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Mon Aug 28 16:36:37 2006 +0200 Proper TTM dereferencing Initial buffer object creation. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f83b4b4..07f3571 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -949,8 +949,9 @@ typedef struct drm_buffer_object{ drm_device_t *dev; drm_user_object_t base; atomic_t usage; - drm_map_list_t *ttm_maplist; + drm_ttm_object_t *ttm_object; drm_ttm_backend_list_t *ttm_region; + void __user *user_pages; atomic_t mapped; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 0aa0b13..affee13 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -148,7 +148,7 @@ static int drm_move_tt_to_local(drm_buff } -void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo) +static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo) { drm_buffer_manager_t *bm = &dev->bm; @@ -189,6 +189,31 @@ void destroy_buffer_object(drm_device_t drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } + +void drm_bo_usage_deref_locked(drm_device_t *dev, drm_buffer_object_t *bo) +{ + if (atomic_dec_and_test(&bo->usage)) { + drm_bo_destroy_locked(dev, bo); + } +} + +void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) +{ + if (atomic_dec_and_test(&bo->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&bo->usage) == 0) + drm_bo_destroy_locked(dev, bo); + mutex_unlock(&dev->struct_mutex); + } +} + +static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) +{ + drm_bo_usage_deref_locked(priv->head->dev, + drm_user_object_entry(uo, drm_buffer_object_t, base)); +} + + static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t *n_flags) { @@ -399,6 +424,9 @@ static int drm_bo_busy(drm_device_t *dev /* * Wait for buffer idle and register that we've mapped the buffer. + * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, + * so that if the client dies, the mapping is automatically + * unregistered. */ @@ -421,13 +449,15 @@ static int drm_buffer_object_map(drm_fil if ((atomic_read(&bo->mapped) == 0) && drm_bo_busy(dev, bo)) { mutex_unlock(&bo->mutex); - return -EBUSY; + ret = -EBUSY; + goto out; } } else { ret = drm_bo_wait(dev, bo, 0); if (ret) { mutex_unlock(&bo->mutex); - return -EBUSY; + ret = -EBUSY; + goto out; } } mutex_lock(&dev->struct_mutex); @@ -438,11 +468,132 @@ static int drm_buffer_object_map(drm_fil } mutex_unlock(&bo->mutex); + out: + drm_bo_usage_deref_unlocked(dev,bo); + return ret; +} + + +static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo; + drm_ref_object_t *ro; + int ret = 0; + + mutex_lock(&dev->struct_mutex); + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + ret = -EINVAL; + goto out; + } + + ro = drm_lookup_ref_object(priv, &bo->base, _DRM_REF_TYPE1); + if (!ro) { + ret = -EINVAL; + goto out; + } + + drm_remove_ref_object(priv, ro); + drm_bo_usage_deref_locked(dev, bo); + out: + mutex_unlock(&dev->struct_mutex); return ret; } +/* + * Call struct-sem locked. + */ +static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + + if (atomic_dec_and_test(&bo->mapped)) { + mutex_unlock(&dev->struct_mutex); + mutex_lock(&bo->mutex); + if (atomic_read(&bo->mapped) == 0) { + DRM_WAKEUP(&bo->validate_queue); + } + mutex_unlock(&bo->mutex); + mutex_lock(&dev->struct_mutex); + } +} + +static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo) +{ + return 0; +} + +int drm_buffer_object_create(drm_file_t *priv, + int size, + drm_bo_type_t type, + uint32_t ttm_handle, + uint32_t mask, + uint32_t hint, + void __user *user_pages, + drm_buffer_object_t **buf_obj) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo; + int ret = 0; + uint32_t ttm_flags = 0; + + bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); + + if (!bo) + return -ENOMEM; + + mutex_init(&bo->mutex); + mutex_lock(&bo->mutex); + + atomic_set(&bo->usage, 1); + atomic_set(&bo->mapped, 0); + DRM_INIT_WAITQUEUE(&bo->validate_queue); + INIT_LIST_HEAD(&bo->head); + INIT_LIST_HEAD(&bo->ddestroy); + bo->dev = dev; + + switch(type) { + case drm_bo_type_dc: + ret = drm_ttm_object_create(dev, size, ttm_flags, &bo->ttm_object); + if (ret) + goto out_err; + break; + case drm_bo_type_ttm: + bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); + if (ret) + goto out_err; + break; + case drm_bo_type_user: + bo->user_pages = user_pages; + break; + default: + ret = -EINVAL; + goto out_err; + } + + bo->mask = mask; + bo->mask_hint = hint; + + ret = drm_buffer_object_validate(dev, bo); + if (ret) + goto out_err; + + mutex_unlock(&bo->mutex); + *buf_obj = bo; + return 0; + + out_err: + mutex_unlock(&bo->mutex); + drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + return ret; +} + + int drm_bo_ioctl(DRM_IOCTL_ARGS) { @@ -459,6 +610,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { + case drm_bo_unmap: + rep.ret = drm_buffer_object_unmap(priv, req->handle); + break; case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, !(req->hint & diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index e76b41f..cda3ec2 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -752,7 +752,6 @@ int drm_user_create_region(drm_device_t /* * dev->struct_mutex locked. */ - static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) { drm_map_list_t *list = &object->map_list; @@ -777,17 +776,24 @@ static void drm_ttm_object_remove(drm_de drm_free(object, sizeof(*object), DRM_MEM_TTM); } + +void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) +{ + if (atomic_dec_and_test(&to->usage)) { + drm_ttm_object_remove(dev, to); + } +} + + /* * dev->struct_mutex locked. */ -static void drm_ttm_user_object_remove(drm_file_t *priv, drm_user_object_t *base) +static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) { - drm_ttm_object_t *object; - drm_device_t *dev = priv->head->dev; - - object = drm_user_object_entry(base, drm_ttm_object_t, base); - if (atomic_dec_and_test(&object->usage)) - drm_ttm_object_remove(dev, object); + DRM_ERROR("User deref ttm\n"); + drm_ttm_object_deref_locked(priv->head->dev, + drm_user_object_entry(base, drm_ttm_object_t, + base)); } @@ -840,16 +846,33 @@ int drm_ttm_object_create(drm_device_t * } list->user_token = list->hash.key; - object->base.remove = drm_ttm_user_object_remove; - object->base.type = drm_ttm_type; - object->base.ref_struct_locked = NULL; - object->base.unref = NULL; atomic_set(&object->usage, 1); *ttm_object = object; return 0; } +drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, + int check_owner) +{ + drm_user_object_t *uo; + drm_ttm_object_t *to; + + uo = drm_lookup_user_object(priv, handle); + + if (!uo || (uo->type != drm_ttm_type)) + return NULL; + + if (check_owner && priv != uo->owner) { + if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) + return NULL; + } + + to = drm_user_object_entry(uo, drm_ttm_object_t, base); + atomic_inc(&to->usage); + return to; +} + int drm_ttm_ioctl(DRM_IOCTL_ARGS) { @@ -878,6 +901,10 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) mutex_unlock(&dev->struct_mutex); return ret; } + entry->base.remove = drm_ttm_user_deref_locked; + entry->base.type = drm_ttm_type; + entry->base.ref_struct_locked = NULL; + entry->base.unref = NULL; atomic_inc(&entry->usage); break; case drm_ttm_reference: @@ -885,8 +912,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) if (ret) return ret; mutex_lock(&dev->struct_mutex); - uo = drm_lookup_user_object(priv, arg.handle); - entry = drm_user_object_entry(uo, drm_ttm_object_t, base); + entry = drm_lookup_ttm_object(priv, arg.handle , 0); break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); @@ -904,7 +930,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; arg.size = drm_u64(entry->map_list.map->size); - atomic_dec(&entry->usage); + drm_ttm_object_deref_locked(dev, entry); mutex_unlock(&dev->struct_mutex); DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 6ebb1aa..a87cf53 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -108,6 +108,13 @@ typedef struct drm_ttm_object { drm_map_list_t map_list; } drm_ttm_object_t; +extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, + uint32_t flags, drm_ttm_object_t **ttm_object); +extern void drm_ttm_object_deref_locked(struct drm_device *dev, drm_ttm_object_t *to); +extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, + int check_owner); + + diff --git a/shared-core/drm.h b/shared-core/drm.h index 7133eb8..14b1741 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -695,18 +695,19 @@ typedef struct drm_ttm_arg { #define DRM_BO_HINT_AVOID_LOCAL 0x00000002 #define DRM_BO_HINT_DONT_BLOCK 0x00000004 +typedef enum { + drm_bo_type_ttm, + drm_bo_type_dc, + drm_bo_type_user +}drm_bo_type_t; + typedef struct drm_bo_arg_request { unsigned handle; /* User space handle */ unsigned mask; unsigned hint; drm_u64_t size; - - enum { - drm_bo_type_ttm, - drm_bo_type_dc, - drm_bo_type_user - }type; + drm_bo_type_t type; unsigned arg_handle; drm_u64_t user_pointer; drm_u64_t next; @@ -714,6 +715,7 @@ typedef struct drm_bo_arg_request { drm_bo_create, drm_bo_validate, drm_bo_map, + drm_bo_unmap, drm_bo_fence, drm_bo_destroy, drm_bo_reference, |
From: <th...@ke...> - 2006-08-28 15:52:12
|
linux-core/drm_bo.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- shared-core/drm.h | 4 ++-- 2 files changed, 45 insertions(+), 5 deletions(-) New commits: diff-tree 205740647060bc3bdec2b4402a666eb1015932ff (from 0d67356de4e0c9e0d068ea9c16cf33df4fd13776) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Mon Aug 28 17:51:53 2006 +0200 Buffer object creation. diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index affee13..7f5088f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -507,11 +507,14 @@ static int drm_buffer_object_unmap(drm_f * Call struct-sem locked. */ -static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo) +static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo, + drm_ref_t action) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + BUG_ON(action != _DRM_REF_TYPE1); + if (atomic_dec_and_test(&bo->mapped)) { mutex_unlock(&dev->struct_mutex); mutex_lock(&bo->mutex); @@ -534,7 +537,7 @@ int drm_buffer_object_create(drm_file_t uint32_t ttm_handle, uint32_t mask, uint32_t hint, - void __user *user_pages, + unsigned long buffer_start, drm_buffer_object_t **buf_obj) { drm_device_t *dev = priv->head->dev; @@ -569,7 +572,7 @@ int drm_buffer_object_create(drm_file_t goto out_err; break; case drm_bo_type_user: - bo->user_pages = user_pages; + bo->user_pages = (void __user *)buffer_start; break; default: ret = -EINVAL; @@ -592,6 +595,27 @@ int drm_buffer_object_create(drm_file_t drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); return ret; } + +static int drm_bo_add_user_object(drm_file_t *priv, drm_buffer_object_t *bo, + int shareable) +{ + drm_device_t *dev = priv->head->dev; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_add_user_object(priv, &bo->base, shareable); + if (ret) + goto out; + + bo->base.remove = drm_bo_base_deref_locked; + bo->base.type = drm_buffer_type; + bo->base.ref_struct_locked = NULL; + bo->base.unref = drm_buffer_user_object_unmap; + + out: + mutex_unlock(&dev->struct_mutex); + return ret; +} @@ -610,6 +634,22 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { + case drm_bo_create: { + unsigned long buffer_start = drm_ul(req->buffer_start); + rep.ret = drm_buffer_object_create(priv, drm_ul(req->size), + req->type, req->arg_handle, + req->mask, req->hint, + buffer_start, + &entry); + if (rep.ret) + break; + + rep.ret = drm_bo_add_user_object(priv, entry, req->mask & + DRM_BO_FLAG_SHAREABLE); + if (rep.ret) + drm_bo_usage_deref_unlocked(dev, entry); + break; + } case drm_bo_unmap: rep.ret = drm_buffer_object_unmap(priv, req->handle); break; diff --git a/shared-core/drm.h b/shared-core/drm.h index 14b1741..d03eebc 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -684,7 +684,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 #define DRM_BO_FLAG_READ_LOCAL 0x00000040 #define DRM_BO_FLAG_UNCACHED 0x00000080 - +#define DRM_BO_FLAG_SHAREABLE 0x00000100 #define DRM_BO_FLAG_MEM_TT 0x01000000 #define DRM_BO_FLAG_MEM_VRAM 0x02000000 @@ -709,7 +709,7 @@ typedef struct drm_bo_arg_request { drm_u64_t size; drm_bo_type_t type; unsigned arg_handle; - drm_u64_t user_pointer; + drm_u64_t buffer_start; drm_u64_t next; enum { drm_bo_create, |
From: <th...@ke...> - 2006-08-29 08:45:49
|
libdrm/xf86drm.c | 32 ++++++-------------------------- linux-core/drmP.h | 28 +--------------------------- linux-core/drm_bo.c | 32 +++++++++++++++++++++++++++++--- linux-core/drm_ttm.c | 4 ++-- linux-core/drm_ttm.h | 5 +++++ shared-core/drm.h | 15 ++++++++++----- 6 files changed, 53 insertions(+), 63 deletions(-) New commits: diff-tree 279e8d26c6cf7347aa9cb6d50d025a41dff9a5be (from 205740647060bc3bdec2b4402a666eb1015932ff) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 29 10:45:34 2006 +0200 64-bit IOCTL integer (Michel Dänzer & Brian Paul) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 06c6430..3731ee1 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2237,6 +2237,8 @@ int drmCommandWriteRead(int fd, unsigned return 0; } +#ifdef __linux__ + int drmFenceCreate(int fd, int shareable, int class,unsigned type, int emit, drmFence *fence) @@ -2362,36 +2364,13 @@ int drmFenceWait(int fd, drmFence *fence return 0; } -static unsigned long drmUL(drm_u64_t val) -{ - unsigned long ret = val.lo; - if (sizeof(ret) == 8) { - int shift = 32; - ret |= (val.hi << shift); - } - return ret; -} - -static drm_u64_t drmU64(unsigned long val) -{ - drm_u64_t ret; - ret.lo = val & 0xFFFFFFFFUL; - if (sizeof(val) == 8) { - int shift = 32; - ret.hi = val >> shift; - } else { - ret.hi = 0; - } - return ret; -} - int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) { drm_ttm_arg_t arg; arg.op = drm_ttm_create; arg.flags = flags; - arg.size = drmU64(size); + arg.size = size; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; @@ -2399,7 +2378,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, un ttm->handle = arg.handle; ttm->user_token = (drm_handle_t) arg.user_token; ttm->flags = arg.flags; - ttm->size = drmUL(arg.size); + ttm->size = arg.size; return 0; } @@ -2426,7 +2405,7 @@ int drmTTMReference(int fd, unsigned han ttm->handle = arg.handle; ttm->user_token = (drm_handle_t) arg.user_token; ttm->flags = arg.flags; - ttm->size = drmUL(arg.size); + ttm->size = arg.size; return 0; } @@ -2446,3 +2425,4 @@ drm_handle_t drmTTMMapHandle(int fd, con (void) fd; return ttm->user_token; } +#endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 07f3571..af082ad 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -952,9 +952,9 @@ typedef struct drm_buffer_object{ drm_ttm_object_t *ttm_object; drm_ttm_backend_list_t *ttm_region; void __user *user_pages; + unsigned long num_pages; atomic_t mapped; - uint32_t flags; uint32_t mask; uint32_t mask_hint; @@ -1360,32 +1360,6 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARG extern int drm_bo_ioctl(DRM_IOCTL_ARGS); -/* - * Convenience drm_u64_t functions - */ - -static __inline__ unsigned long drm_ul(drm_u64_t val) -{ - unsigned long ret = val.lo; -#if (BITS_PER_LONG == 64) - ret |= (val.hi << 32); -#endif - return ret; -} - -static __inline__ drm_u64_t drm_u64(unsigned long val) -{ - drm_u64_t ret; - - ret.lo = val & 0xFFFFFFFFUL; -#if (BITS_PER_LONG == 64) - ret.hi = val >> 32; -#else - ret.hi = 0; -#endif - return ret; -} - /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_map *map, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7f5088f..2363495 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -531,6 +531,7 @@ static int drm_buffer_object_validate(dr return 0; } + int drm_buffer_object_create(drm_file_t *priv, int size, drm_bo_type_t type, @@ -544,6 +545,7 @@ int drm_buffer_object_create(drm_file_t drm_buffer_object_t *bo; int ret = 0; uint32_t ttm_flags = 0; + drm_ttm_t *ttm; bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); @@ -567,11 +569,35 @@ int drm_buffer_object_create(drm_file_t goto out_err; break; case drm_bo_type_ttm: + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Illegal buffer object start\n"); + ret = -EINVAL; + } + bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (!bo->num_pages) { + DRM_ERROR("Illegal buffer object size\n"); + ret = -EINVAL; + goto out_err; + } bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); + if (!bo->ttm_object) { + DRM_ERROR("Could not find buffer object TTM\n"); + ret = -EINVAL; + goto out_err; + } + ttm = drm_ttm_from_object(bo->ttm_object); + ret = drm_create_ttm_region(ttm, buffer_start >> PAGE_SHIFT, + bo->num_pages, 0, &bo->ttm_region); if (ret) goto out_err; break; case drm_bo_type_user: + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Illegal buffer object start\n"); + ret = -EINVAL; + goto out_err; + } + bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; bo->user_pages = (void __user *)buffer_start; break; default: @@ -635,8 +661,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.handled = 0; switch (req->op) { case drm_bo_create: { - unsigned long buffer_start = drm_ul(req->buffer_start); - rep.ret = drm_buffer_object_create(priv, drm_ul(req->size), + unsigned long buffer_start = req->buffer_start; + rep.ret = drm_buffer_object_create(priv, req->size, req->type, req->arg_handle, req->mask, req->hint, buffer_start, @@ -687,7 +713,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) default: rep.ret = -EINVAL; } - next = drm_ul(req->next); + next = req->next; rep.handled = 1; arg.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index cda3ec2..8cd0af6 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -888,7 +888,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) switch(arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); - size = drm_ul(arg.size); + size = arg.size; ret = drm_ttm_object_create(dev, size, arg.flags, &entry); if (ret) { mutex_unlock(&dev->struct_mutex); @@ -929,7 +929,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) } arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; - arg.size = drm_u64(entry->map_list.map->size); + arg.size = entry->map_list.map->size; drm_ttm_object_deref_locked(dev, entry); mutex_unlock(&dev->struct_mutex); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index a87cf53..ba4261b 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -165,6 +165,11 @@ extern int drm_ttm_add_mm_to_list(drm_tt extern void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm); extern int drm_ttm_ioctl(DRM_IOCTL_ARGS); +static __inline__ drm_ttm_t *drm_ttm_from_object(drm_ttm_object_t *to) +{ + return (drm_ttm_t *) to->map_list.map->offset; +} + #define DRM_MASK_VAL(dest, mask, val) \ (dest) = ((dest) & ~(mask)) | ((val) & (mask)); diff --git a/shared-core/drm.h b/shared-core/drm.h index d03eebc..f8479dd 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -134,6 +134,12 @@ #define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) #if defined(__linux__) +#if defined(__KERNEL__) +typedef __u64 drm_u64_t; +#else +typedef unsigned long long drm_u64_t; +#endif + typedef unsigned int drm_handle_t; #else typedef unsigned long drm_handle_t; /**< To mapped regions */ @@ -630,10 +636,7 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; -typedef struct drm_u64{ - unsigned lo; - unsigned hi; -}drm_u64_t; +#ifdef __linux__ #define DRM_FENCE_FLAG_EMIT 0x00000001 #define DRM_FENCE_FLAG_SHAREABLE 0x00000002 @@ -739,7 +742,7 @@ typedef union drm_bo_arg{ drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; } drm_bo_arg_t; - +#endif /** * \name Ioctls Definitions @@ -806,8 +809,10 @@ typedef union drm_bo_arg{ #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) +#ifdef __linux__ #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) #define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) +#endif /*@}*/ |
From: <th...@ke...> - 2006-08-29 12:52:21
|
linux-core/drmP.h | 3 - linux-core/drm_bo.c | 124 +++++++++++++++++++++++++++++++-------------------- linux-core/drm_ttm.c | 10 ++++ linux-core/drm_ttm.h | 1 shared-core/drm.h | 2 5 files changed, 91 insertions(+), 49 deletions(-) New commits: diff-tree 0dedfc2cd03f50b435476e56637b333d345fddbd (from 279e8d26c6cf7347aa9cb6d50d025a41dff9a5be) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 29 14:52:02 2006 +0200 Checkpoint ttm addition to buffer objects. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index af082ad..81b7a1b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -951,8 +951,9 @@ typedef struct drm_buffer_object{ atomic_t usage; drm_ttm_object_t *ttm_object; drm_ttm_backend_list_t *ttm_region; - void __user *user_pages; unsigned long num_pages; + unsigned long buffer_start; + drm_bo_type_t type; atomic_t mapped; uint32_t flags; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 2363495..3065606 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -141,8 +141,8 @@ static int drm_move_tt_to_local(drm_buff drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; - buf->flags &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_UNCACHED); - buf->flags |= DRM_BO_FLAG_MEM_LOCAL; + buf->flags &= ~(DRM_BO_FLAG_MEM_TT); + buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; return 0; } @@ -531,9 +531,65 @@ static int drm_buffer_object_validate(dr return 0; } +/* + * Call bo->mutex locked. + */ + +static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t new_flags, + uint32_t ttm_handle) + +{ + drm_device_t *dev = bo->dev; + drm_ttm_object_t *to = NULL; + drm_ttm_t *ttm; + int ret=0; + uint32_t ttm_flags = 0; + + bo->ttm_object = NULL; + bo->ttm_region = NULL; + + switch(bo->type) { + case drm_bo_type_dc: + mutex_lock(&dev->struct_mutex); + ret = drm_ttm_object_create(dev, bo->num_pages*PAGE_SIZE, + ttm_flags, &to); + mutex_unlock(&dev->struct_mutex); + break; + case drm_bo_type_ttm: + mutex_lock(&dev->struct_mutex); + to = drm_lookup_ttm_object(priv, ttm_handle, 1); + mutex_unlock(&dev->struct_mutex); + if (!to) + ret = -EINVAL; + break; + case drm_bo_type_user: + + break; + default: + ret = -EINVAL; + } + + if (ret) { + return ret; + } + + if (to) { + bo->ttm_object = to; + ttm = drm_ttm_from_object(to); + ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, + bo->num_pages, + new_flags & DRM_BO_FLAG_CACHED, + &bo->ttm_region); + if (ret) { + drm_ttm_object_deref_unlocked(dev, to); + } + } + return ret; +} + int drm_buffer_object_create(drm_file_t *priv, - int size, + unsigned long size, drm_bo_type_t type, uint32_t ttm_handle, uint32_t mask, @@ -544,8 +600,18 @@ int drm_buffer_object_create(drm_file_t drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; int ret = 0; - uint32_t ttm_flags = 0; - drm_ttm_t *ttm; + uint32_t new_flags; + unsigned long num_pages; + + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Invalid buffer object start.\n"); + return -EINVAL; + } + num_pages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + if (num_pages == 0) { + DRM_ERROR("Illegal buffer object size.\n"); + return -EINVAL; + } bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); @@ -561,50 +627,14 @@ int drm_buffer_object_create(drm_file_t INIT_LIST_HEAD(&bo->head); INIT_LIST_HEAD(&bo->ddestroy); bo->dev = dev; + bo->type = type; + bo->num_pages = num_pages; + bo->buffer_start = buffer_start; - switch(type) { - case drm_bo_type_dc: - ret = drm_ttm_object_create(dev, size, ttm_flags, &bo->ttm_object); - if (ret) - goto out_err; - break; - case drm_bo_type_ttm: - if (buffer_start & ~PAGE_MASK) { - DRM_ERROR("Illegal buffer object start\n"); - ret = -EINVAL; - } - bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (!bo->num_pages) { - DRM_ERROR("Illegal buffer object size\n"); - ret = -EINVAL; - goto out_err; - } - bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); - if (!bo->ttm_object) { - DRM_ERROR("Could not find buffer object TTM\n"); - ret = -EINVAL; - goto out_err; - } - ttm = drm_ttm_from_object(bo->ttm_object); - ret = drm_create_ttm_region(ttm, buffer_start >> PAGE_SHIFT, - bo->num_pages, 0, &bo->ttm_region); - if (ret) - goto out_err; - break; - case drm_bo_type_user: - if (buffer_start & ~PAGE_MASK) { - DRM_ERROR("Illegal buffer object start\n"); - ret = -EINVAL; - goto out_err; - } - bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - bo->user_pages = (void __user *)buffer_start; - break; - default: - ret = -EINVAL; + ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); + if (ret) goto out_err; - } - + bo->mask = mask; bo->mask_hint = hint; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 8cd0af6..e111070 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -784,6 +784,16 @@ void drm_ttm_object_deref_locked(drm_dev } } +void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) +{ + if (atomic_dec_and_test(&to->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&to->usage) == 0) + drm_ttm_object_remove(dev, to); + mutex_unlock(&dev->struct_mutex); + } +} + /* * dev->struct_mutex locked. diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index ba4261b..a181050 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -111,6 +111,7 @@ typedef struct drm_ttm_object { extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, uint32_t flags, drm_ttm_object_t **ttm_object); extern void drm_ttm_object_deref_locked(struct drm_device *dev, drm_ttm_object_t *to); +extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, drm_ttm_object_t *to); extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, int check_owner); diff --git a/shared-core/drm.h b/shared-core/drm.h index f8479dd..e50ebfe 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -686,7 +686,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_NO_EVICT 0x00000010 #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 #define DRM_BO_FLAG_READ_LOCAL 0x00000040 -#define DRM_BO_FLAG_UNCACHED 0x00000080 +#define DRM_BO_FLAG_CACHED 0x00000080 #define DRM_BO_FLAG_SHAREABLE 0x00000100 #define DRM_BO_FLAG_MEM_TT 0x01000000 |
From: <th...@ke...> - 2006-08-29 16:41:18
|
libdrm/xf86drm.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++- libdrm/xf86mm.h | 105 +++++++++++++++++++++++++++++++++++++ linux-core/drmP.h | 3 - linux-core/drm_bo.c | 30 +++++++++- linux-core/drm_ttm.c | 5 + linux-core/i915_drv.c | 3 - linux-core/i915_fence.c | 2 shared-core/drm.h | 3 - shared-core/i915_dma.c | 3 - shared-core/i915_irq.c | 6 ++ 10 files changed, 283 insertions(+), 12 deletions(-) New commits: diff-tree 23f01c9fe8e6170459fe46ad5fc9757bbe967d96 (from 0dedfc2cd03f50b435476e56637b333d345fddbd) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 29 18:40:08 2006 +0200 Checkpoint commit. Buffer object flags and IOCTL argument list. diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3731ee1..6de6c06 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -65,6 +65,8 @@ # define _DRM_FREE free # include "drm.h" #endif +#include "xf86mm.h" + /* Not all systems have MAP_FAILED defined */ #ifndef MAP_FAILED @@ -2384,7 +2386,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, un int drmTTMDestroy(int fd, const drmTTM *ttm) { - drm_ttm_arg_t arg; + drm_ttm_arg_t arg; arg.op = drm_ttm_destroy; arg.handle = ttm->handle; @@ -2425,4 +2427,135 @@ drm_handle_t drmTTMMapHandle(int fd, con (void) fd; return ttm->user_token; } + +static int drmAdjustListNodes(DrmBufList *list) +{ + DrmBufNode *node; + DrmMMListHead *l; + int ret = 0; + + while(list->numCurrent < list->numTarget) { + node = (DrmBufNode *) malloc(sizeof(*node)); + if (!node) { + ret = -ENOMEM; + break; + } + list->numCurrent++; + DRMLISTADD(&node->head, &list->free); + } + + while(list->numCurrent > list->numTarget) { + l = list->free.next; + if (l == &list->free) + break; + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + list->numCurrent--; + } + return ret; +} + +static void drmFreeList(DrmBufList *list) +{ + DrmBufNode *node; + DrmMMListHead *l; + int ret = 0; + + l = list->list.next; + while(l != &list->list) { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + l = list->free.next; + list->numCurrent--; + list->numOnList--; + } + + l = list->free.next; + while(l != &list->free) { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + l = list->free.next; + list->numCurrent--; + } +} + +int drmResetList(DrmBufList *list) { + + DrmMMListHead *l; + int ret; + + ret = drmAdjustListNodes(list); + if (ret) + return ret; + + l = list->list.next; + while(l != &list->list) { + DRMLISTDEL(l); + DRMLISTADD(l, &list->free); + list->numOnList--; + } + return drmAdjustListNodes(list); +} + +static int drmAddListItem(DrmBufList *list, DrmBuf *item, drm_bo_arg_t *arg) +{ + DrmBufNode *node; + DrmMMListHead *l; + + l = list->free.next; + if (l == &list->free) { + node = (DrmBufNode *) malloc(sizeof(*node)); + if (!node) { + return -ENOMEM; + } + list->numCurrent++; + } else { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + } + node->buf = item; + DRMLISTADD(&node->head, &list->list); + list->numOnList++; + return 0; +} + +int drmCreateBufList(int numTarget, DrmBufList *list) +{ + DRMINITLISTHEAD(&list->list); + DRMINITLISTHEAD(&list->free); + list->numTarget = numTarget; + list->numCurrent = 0; + list->numOnList = 0; + return drmAdjustListNodes(list); +} + +/* + * Prepare list for IOCTL submission. + */ + +static drm_bo_arg_t *drmPrepareList(DrmBufList *list) +{ + DrmMMListHead *cur, *next; + DrmBufNode *first, *curNode, *nextNode; + + cur = list->list.next; + if (cur == &list->list) + return NULL; + + first = DRMLISTENTRY(DrmBufNode, cur, head); + curNode = DRMLISTENTRY(DrmBufNode, cur, head); + + for (next = cur->next; next != &list->list; + cur = next, next = cur->next) { + nextNode = DRMLISTENTRY(DrmBufNode, next, head); + curNode->bo_arg.req.next = ((unsigned long) &nextNode->bo_arg.req); + curNode = nextNode; + } + curNode->bo_arg.req.next = 0; + return &first->bo_arg; +} + #endif diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h new file mode 100644 index 0000000..5fb7872 --- /dev/null +++ b/libdrm/xf86mm.h @@ -0,0 +1,105 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +#ifndef _XF86MM_H_ +#define _XF86MM_H_ +#include <stddef.h> + + +/* + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + */ + +typedef struct _drmMMListHead +{ + struct _drmMMListHead *prev; + struct _drmMMListHead *next; +} DrmMMListHead; + +#define DRMINITLISTHEAD(__item) \ + do{ \ + (__item)->prev = (__item); \ + (__item)->next = (__item); \ + } while (0) + +#define DRMLISTADD(__item, __list) \ + do { \ + (__item)->prev = (__list); \ + (__item)->next = (__list)->next; \ + (__list)->next->prev = (__item); \ + (__list)->next = (__item); \ + } while (0) + +#define DRMLISTADDTAIL(__item, __list) \ + do { \ + (__item)->next = (__list); \ + (__item)->prev = (__list)->prev; \ + (__list)->prev->next = (__item); \ + (__list)->prev = (__item); \ + } while(0) + +#define DRMLISTDEL(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + } while(0) + +#define DRMLISTDELINIT(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + (__item)->next = (__item); \ + (__item)->prev = (__item); \ + } while(0) + +#define DRMLISTENTRY(__type, __item, __field) \ + ((__type *)(((char *) (__item)) - offsetof(__type, __field))) + + +typedef struct _DrmBuf{ + unsigned handle; +} DrmBuf; + + +typedef struct _DrmBufNode { + DrmMMListHead head; + DrmBuf *buf; + drm_bo_arg_t bo_arg; +} DrmBufNode; + +typedef struct _DrmMMBufList { + unsigned numTarget; + unsigned numCurrent; + unsigned numOnList; + DrmMMListHead list; + DrmMMListHead free; +} DrmBufList; + + +#endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 81b7a1b..4d490ab 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -652,7 +652,8 @@ typedef struct drm_ref_object { */ typedef struct drm_bo_driver{ - int cached_pages; + int cached_tt; + int cached_vram; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev, int cached); } drm_bo_driver_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 3065606..5590166 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -214,7 +214,8 @@ static void drm_bo_base_deref_locked(drm } -static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, +static int drm_bo_new_flags(drm_bo_driver_t *driver, + uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t *n_flags) { uint32_t new_flags; @@ -263,6 +264,24 @@ static int drm_bo_new_flags(uint32_t fla } new_flags |= new_mask & ~DRM_BO_MASK_MEM; + + if (hint & DRM_BO_HINT_BIND_CACHED) { + new_flags |= DRM_BO_FLAG_CACHED; + if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || + ((new_flags & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) + new_flags &= ~DRM_BO_FLAG_CACHED; + } + + if ((new_flags & DRM_BO_FLAG_NO_EVICT) && + ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { + if (flags & DRM_BO_FLAG_CACHED) { + DRM_ERROR("Cannot change caching policy of pinned buffer\n"); + return -EINVAL; + } else { + new_flags &= ~DRM_BO_FLAG_CACHED; + } + } + *n_flags = new_flags; return 0; } @@ -531,11 +550,12 @@ static int drm_buffer_object_validate(dr return 0; } + /* * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t new_flags, +static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hint, uint32_t ttm_handle) { @@ -578,7 +598,7 @@ static int drm_bo_add_ttm(drm_file_t *pr ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - new_flags & DRM_BO_FLAG_CACHED, + hint & DRM_BO_HINT_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -631,6 +651,10 @@ int drm_buffer_object_create(drm_file_t bo->num_pages = num_pages; bo->buffer_start = buffer_start; + ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, + 1, &new_flags); + if (ret) + goto out_err; ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); if (ret) goto out_err; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index e111070..65d4034 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -202,10 +202,11 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (atomic_read(&ttm->vma_count) > 0) { ttm->destroy = 1; - DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); + DRM_ERROR("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; } + DRM_ERROR("Destroying a ttm\n"); if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = @@ -479,6 +480,7 @@ void drm_destroy_ttm_region(drm_ttm_back uint32_t *cur_page_flags; int i; + DRM_ERROR("Destroying a TTM region\n"); list_del_init(&entry->head); drm_unbind_ttm_region(entry); @@ -800,7 +802,6 @@ void drm_ttm_object_deref_unlocked(drm_d */ static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) { - DRM_ERROR("User deref ttm\n"); drm_ttm_object_deref_locked(priv->head->dev, drm_user_object_entry(base, drm_ttm_object_t, base)); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 64ab3f5..bc78dc2 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -49,7 +49,8 @@ static drm_fence_driver_t i915_fence_dri }; static drm_bo_driver_t i915_bo_driver = { - .cached_pages = 1, + .cached_vram = 0, + .cached_tt = 1, .create_ttm_backend_entry = i915_create_ttm_backend_entry }; diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 46a2a72..452d4ee 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -86,6 +86,8 @@ static void i915_perform_flush(drm_devic dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fm->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); + DRM_ERROR("Saved flush status is 0x%08x\n", + dev_priv->saved_flush_status); I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); dev_priv->flush_pending = 1; fm->pending_flush = 0; diff --git a/shared-core/drm.h b/shared-core/drm.h index e50ebfe..5888c9b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -685,7 +685,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_NO_MOVE 0x00000008 #define DRM_BO_FLAG_NO_EVICT 0x00000010 #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 -#define DRM_BO_FLAG_READ_LOCAL 0x00000040 +#define DRM_BO_FLAG_READ_CACHED 0x00000040 #define DRM_BO_FLAG_CACHED 0x00000080 #define DRM_BO_FLAG_SHAREABLE 0x00000100 @@ -697,6 +697,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_HINT_PREFER_VRAM 0x00000001 #define DRM_BO_HINT_AVOID_LOCAL 0x00000002 #define DRM_BO_HINT_DONT_BLOCK 0x00000004 +#define DRM_BO_HINT_BIND_CACHED 0x00000008 typedef enum { drm_bo_type_ttm, diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 8ef9d8e..e661269 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -195,9 +195,6 @@ static int i915_initialize(drm_device_t I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); -#ifdef I915_HAVE_FENCE - dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); -#endif dev->dev_private = (void *)dev_priv; return 0; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 08d3140..4195555 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -275,6 +275,12 @@ void i915_driver_irq_postinstall(drm_dev i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + + /* + * Initialize the hardware status page IRQ location. + */ + + I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21)); } void i915_driver_irq_uninstall(drm_device_t * dev) |
From: <th...@ke...> - 2006-08-29 19:57:51
|
libdrm/xf86drm.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++------- libdrm/xf86drm.h | 2 libdrm/xf86mm.h | 41 +++++++---- shared-core/drm.h | 4 + 4 files changed, 198 insertions(+), 38 deletions(-) New commits: diff-tree de144ba23c1245cf021a63cc739c7c9903568272 (from 23f01c9fe8e6170459fe46ad5fc9757bbe967d96) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Tue Aug 29 21:57:37 2006 +0200 Part of buffer object libdrm interface. diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6de6c06..3fccdf6 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2381,6 +2381,8 @@ int drmTTMCreate(int fd, drmTTM *ttm, un ttm->user_token = (drm_handle_t) arg.user_token; ttm->flags = arg.flags; ttm->size = arg.size; + ttm->virtual = NULL; + ttm->mapCount = 0; return 0; } @@ -2428,14 +2430,14 @@ drm_handle_t drmTTMMapHandle(int fd, con return ttm->user_token; } -static int drmAdjustListNodes(DrmBufList *list) +static int drmAdjustListNodes(drmBOList *list) { - DrmBufNode *node; - DrmMMListHead *l; + drmBONode *node; + drmMMListHead *l; int ret = 0; while(list->numCurrent < list->numTarget) { - node = (DrmBufNode *) malloc(sizeof(*node)); + node = (drmBONode *) malloc(sizeof(*node)); if (!node) { ret = -ENOMEM; break; @@ -2449,23 +2451,23 @@ static int drmAdjustListNodes(DrmBufList if (l == &list->free) break; DRMLISTDEL(l); - node = DRMLISTENTRY(DrmBufNode, l, head); + node = DRMLISTENTRY(drmBONode, l, head); free(node); list->numCurrent--; } return ret; } -static void drmFreeList(DrmBufList *list) +static void drmFreeList(drmBOList *list) { - DrmBufNode *node; - DrmMMListHead *l; + drmBONode *node; + drmMMListHead *l; int ret = 0; l = list->list.next; while(l != &list->list) { DRMLISTDEL(l); - node = DRMLISTENTRY(DrmBufNode, l, head); + node = DRMLISTENTRY(drmBONode, l, head); free(node); l = list->free.next; list->numCurrent--; @@ -2475,16 +2477,16 @@ static void drmFreeList(DrmBufList *list l = list->free.next; while(l != &list->free) { DRMLISTDEL(l); - node = DRMLISTENTRY(DrmBufNode, l, head); + node = DRMLISTENTRY(drmBONode, l, head); free(node); l = list->free.next; list->numCurrent--; } } -int drmResetList(DrmBufList *list) { +int drmResetList(drmBOList *list) { - DrmMMListHead *l; + drmMMListHead *l; int ret; ret = drmAdjustListNodes(list); @@ -2500,21 +2502,21 @@ int drmResetList(DrmBufList *list) { return drmAdjustListNodes(list); } -static int drmAddListItem(DrmBufList *list, DrmBuf *item, drm_bo_arg_t *arg) +static int drmAddListItem(drmBOList *list, drmBO *item, drm_bo_arg_t *arg) { - DrmBufNode *node; - DrmMMListHead *l; + drmBONode *node; + drmMMListHead *l; l = list->free.next; if (l == &list->free) { - node = (DrmBufNode *) malloc(sizeof(*node)); + node = (drmBONode *) malloc(sizeof(*node)); if (!node) { return -ENOMEM; } list->numCurrent++; } else { DRMLISTDEL(l); - node = DRMLISTENTRY(DrmBufNode, l, head); + node = DRMLISTENTRY(drmBONode, l, head); } node->buf = item; DRMLISTADD(&node->head, &list->list); @@ -2522,7 +2524,7 @@ static int drmAddListItem(DrmBufList *li return 0; } -int drmCreateBufList(int numTarget, DrmBufList *list) +int drmCreateBufList(int numTarget, drmBOList *list) { DRMINITLISTHEAD(&list->list); DRMINITLISTHEAD(&list->free); @@ -2536,21 +2538,21 @@ int drmCreateBufList(int numTarget, DrmB * Prepare list for IOCTL submission. */ -static drm_bo_arg_t *drmPrepareList(DrmBufList *list) +static drm_bo_arg_t *drmPrepareList(drmBOList *list) { - DrmMMListHead *cur, *next; - DrmBufNode *first, *curNode, *nextNode; + drmMMListHead *cur, *next; + drmBONode *first, *curNode, *nextNode; cur = list->list.next; if (cur == &list->list) return NULL; - first = DRMLISTENTRY(DrmBufNode, cur, head); - curNode = DRMLISTENTRY(DrmBufNode, cur, head); + first = DRMLISTENTRY(drmBONode, cur, head); + curNode = DRMLISTENTRY(drmBONode, cur, head); for (next = cur->next; next != &list->list; cur = next, next = cur->next) { - nextNode = DRMLISTENTRY(DrmBufNode, next, head); + nextNode = DRMLISTENTRY(drmBONode, next, head); curNode->bo_arg.req.next = ((unsigned long) &nextNode->bo_arg.req); curNode = nextNode; } @@ -2558,4 +2560,143 @@ static drm_bo_arg_t *drmPrepareList(DrmB return &first->bo_arg; } +int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, + void *user_buffer, drm_bo_type_t type, unsigned mask, + unsigned hint, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + + req->mask = mask; + req->hint = hint; + req->size = size; + req->type = type; + + buf->ttm = NULL; + + switch(type) { + case drm_bo_type_ttm: + req->arg_handle = ttm->handle; + req->buffer_start = start; + buf->ttm = ttm; + break; + case drm_bo_type_dc: + break; + case drm_bo_type_user: + req->buffer_start = (unsigned long) user_buffer; + buf->virtual = user_buffer; + break; + default: + return -EINVAL; + } + req->op = drm_bo_create; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + return -errno; + if (!rep->handled) { + return -EFAULT; + } + if (rep->ret) { + return rep->ret; + } + + buf->handle = rep->handle; + buf->flags = rep->flags; + buf->size = rep->size; + buf->offset = rep->offset; + buf->map_handle = rep->arg_handle; + buf->map_flags = rep->map_flags; + buf->map_virtual = NULL; + buf->map_count = 0; + buf->virtual = NULL; + buf->mask = rep->mask; + buf->hint = rep->hint; + buf->start = rep->buffer_start; + + return 0; +} + +int drmBODestroy(int fd, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + + req->handle = buf->handle; + req->op = drm_bo_destroy; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + return -errno; + if (!rep->handled) { + return -EFAULT; + } + if (rep->ret) { + return rep->ret; + } + + buf->handle = 0; + return 0; +} + +int drmBOReference(int fd, unsigned handle, drmBO *buf) +{ + + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + + req->handle = handle; + req->op = drm_bo_reference; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + return -errno; + if (!rep->handled) { + return -EFAULT; + } + if (rep->ret) { + return rep->ret; + } + + buf->handle = rep->handle; + buf->type = drm_bo_type_dc; + buf->flags = rep->flags; + buf->size = rep->size; + buf->offset = rep->offset; + buf->map_handle = rep->arg_handle; + buf->map_flags = rep->map_flags; + buf->map_virtual = NULL; + buf->map_count = 0; + buf->virtual = NULL; + buf->mask = rep->mask; + buf->hint = rep->hint; + return 0; +} + +int drmBOUnReference(int fd, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + + req->handle = buf->handle; + req->op = drm_bo_unreference; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + return -errno; + if (!rep->handled) { + return -EFAULT; + } + if (rep->ret) { + return rep->ret; + } + + buf->handle = 0; + return 0; +} + #endif diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 58cbd16..ca48bfb 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -292,6 +292,8 @@ typedef struct _drmTTM{ drm_handle_t user_token; unsigned flags; unsigned long size; + void *virtual; + int mapCount; } drmTTM; #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 5fb7872..08149d0 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -29,7 +29,7 @@ #ifndef _XF86MM_H_ #define _XF86MM_H_ #include <stddef.h> - +#include "xf86drm.h" /* * List macros heavily inspired by the Linux kernel @@ -40,7 +40,7 @@ typedef struct _drmMMListHead { struct _drmMMListHead *prev; struct _drmMMListHead *next; -} DrmMMListHead; +} drmMMListHead; #define DRMINITLISTHEAD(__item) \ do{ \ @@ -82,24 +82,37 @@ typedef struct _drmMMListHead ((__type *)(((char *) (__item)) - offsetof(__type, __field))) -typedef struct _DrmBuf{ +typedef struct _drmBO{ + drm_bo_type_t type; unsigned handle; -} DrmBuf; - - -typedef struct _DrmBufNode { - DrmMMListHead head; - DrmBuf *buf; + drm_handle_t map_handle; + unsigned flags; + unsigned mask; + unsigned hint; + unsigned map_flags; + unsigned long size; + unsigned long offset; + unsigned long start; + void *virtual; + void *map_virtual; + int map_count; + drmTTM *ttm; +} drmBO; + + +typedef struct _drmBONode { + drmMMListHead head; + drmBO *buf; drm_bo_arg_t bo_arg; -} DrmBufNode; +} drmBONode; -typedef struct _DrmMMBufList { +typedef struct _drmBOList { unsigned numTarget; unsigned numCurrent; unsigned numOnList; - DrmMMListHead list; - DrmMMListHead free; -} DrmBufList; + drmMMListHead list; + drmMMListHead free; +} drmBOList; #endif diff --git a/shared-core/drm.h b/shared-core/drm.h index 5888c9b..c65ecc0 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -736,6 +736,9 @@ typedef struct drm_bo_arg_reply { drm_u64_t offset; unsigned arg_handle; unsigned map_flags; + unsigned mask; + unsigned hint; + drm_u64_t buffer_start; }drm_bo_arg_reply_t; @@ -813,6 +816,7 @@ typedef union drm_bo_arg{ #ifdef __linux__ #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) #define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) +#define DRM_IOCTL_BUFOBJ DRM_IOWR(0x3d, drm_bo_arg_t) #endif /*@}*/ |
From: <th...@ke...> - 2006-08-30 07:57:51
|
linux-core/drmP.h | 4 linux-core/drm_bo.c | 254 +++++++++++++++++++++++++++------------------------ linux-core/drm_ttm.c | 61 +++++------- linux-core/drm_ttm.h | 24 ++-- shared-core/drm.h | 8 + 5 files changed, 188 insertions(+), 163 deletions(-) New commits: diff-tree 033bda07e9a4eab5058fb919b375deb57b08b5be (from de144ba23c1245cf021a63cc739c7c9903568272) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Wed Aug 30 09:57:35 2006 +0200 Buffer object reply fill in. Lindent of drm_bo.c drm_ttm.c diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4d490ab..63bcde2 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -955,11 +955,13 @@ typedef struct drm_buffer_object{ unsigned long num_pages; unsigned long buffer_start; drm_bo_type_t type; + unsigned long offset; atomic_t mapped; + uint32_t map_flags; uint32_t flags; uint32_t mask; - uint32_t mask_hint; + uint32_t hint; drm_mm_node_t *vram; drm_mm_node_t *tt; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 5590166..2438944 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -55,7 +55,7 @@ * 2.) Refer to ttm locking orders. */ -int drm_fence_buffer_objects(drm_file_t *priv) +int drm_fence_buffer_objects(drm_file_t * priv) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -69,7 +69,7 @@ int drm_fence_buffer_objects(drm_file_t mutex_lock(&bm->bm_mutex); list_for_each_entry(entry, &bm->unfenced, head) { - BUG_ON(!entry->unfenced); + BUG_ON(!entry->unfenced); fence_flags |= entry->fence_flags; count++; } @@ -85,7 +85,7 @@ int drm_fence_buffer_objects(drm_file_t mutex_unlock(&bm->bm_mutex); return -ENOMEM; } - + ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); @@ -120,24 +120,23 @@ int drm_fence_buffer_objects(drm_file_t * dev locked. */ - -static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) +static int drm_move_tt_to_local(drm_buffer_object_t * buf, int lazy) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; int ret = 0; - + BUG_ON(!buf->tt); if (buf->fence) { - ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, + ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, buf->fence_flags); if (ret) return ret; drm_fence_usage_deref_unlocked(dev, buf->fence); buf->fence = NULL; } - + drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -147,10 +146,9 @@ static int drm_move_tt_to_local(drm_buff return 0; } - -static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo) +static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { - + drm_buffer_manager_t *bm = &dev->bm; BUG_ON(bo->unfenced); @@ -189,15 +187,14 @@ static void drm_bo_destroy_locked(drm_de drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } - -void drm_bo_usage_deref_locked(drm_device_t *dev, drm_buffer_object_t *bo) +void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { drm_bo_destroy_locked(dev, bo); } } -void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) +void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { mutex_lock(&dev->struct_mutex); @@ -207,20 +204,20 @@ void drm_bo_usage_deref_unlocked(drm_dev } } -static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) +static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo) { - drm_bo_usage_deref_locked(priv->head->dev, - drm_user_object_entry(uo, drm_buffer_object_t, base)); + drm_bo_usage_deref_locked(priv->head->dev, + drm_user_object_entry(uo, drm_buffer_object_t, + base)); } - -static int drm_bo_new_flags(drm_bo_driver_t *driver, +static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, - int init, uint32_t *n_flags) + int init, uint32_t * n_flags) { uint32_t new_flags; uint32_t new_props; - + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { /* @@ -234,10 +231,11 @@ static int drm_bo_new_flags(drm_bo_drive DRM_ERROR("Invalid buffer object memory flags\n"); return -EINVAL; } - + if (new_flags & DRM_BO_FLAG_MEM_LOCAL) { - if ((hint & DRM_BO_HINT_AVOID_LOCAL) && - new_flags & (DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_TT)) { + if ((hint & DRM_BO_HINT_AVOID_LOCAL) && + new_flags & (DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_MEM_TT)) { new_flags &= ~DRM_BO_FLAG_MEM_LOCAL; } else { new_flags = DRM_BO_FLAG_MEM_LOCAL; @@ -254,7 +252,7 @@ static int drm_bo_new_flags(drm_bo_drive } else { new_flags = flags & DRM_BO_MASK_MEM; } - + new_props = new_mask & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_READ); @@ -268,14 +266,16 @@ static int drm_bo_new_flags(drm_bo_drive if (hint & DRM_BO_HINT_BIND_CACHED) { new_flags |= DRM_BO_FLAG_CACHED; if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || - ((new_flags & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) + ((new_flags & DRM_BO_FLAG_MEM_VRAM) + && !driver->cached_vram)) new_flags &= ~DRM_BO_FLAG_CACHED; } - + if ((new_flags & DRM_BO_FLAG_NO_EVICT) && ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { if (flags & DRM_BO_FLAG_CACHED) { - DRM_ERROR("Cannot change caching policy of pinned buffer\n"); + DRM_ERROR + ("Cannot change caching policy of pinned buffer\n"); return -EINVAL; } else { new_flags &= ~DRM_BO_FLAG_CACHED; @@ -285,12 +285,10 @@ static int drm_bo_new_flags(drm_bo_drive *n_flags = new_flags; return 0; } - - #if 0 -static int drm_bo_evict(drm_device_t *dev, drm_buffer_object_t *buf, int tt); +static int drm_bo_evict(drm_device_t * dev, drm_buffer_object_t * buf, int tt); { int ret; if (tt) { @@ -300,8 +298,8 @@ static int drm_bo_evict(drm_device_t *de } return ret; } - -int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) + +int drm_bo_alloc_space(drm_device_t * dev, int tt, drm_buffer_object_t * buf) { drm_mm_node_t *node; drm_buffer_manager_t *bm = &dev->bm; @@ -315,13 +313,14 @@ int drm_bo_alloc_space(drm_device_t *dev if (node) break; - if (lru->next == lru) + if (lru->next == lru) break; if (tt) { bo = list_entry(lru->next, drm_buffer_object_t, tt_lru); } else { - bo = list_entry(lru->next, drm_buffer_object_t, vram_lru); + bo = list_entry(lru->next, drm_buffer_object_t, + vram_lru); } drm_bo_evict(dev, bo, tt); @@ -344,22 +343,20 @@ int drm_bo_alloc_space(drm_device_t *dev return 0; } #endif - /* * Call dev->struct_mutex locked. */ - -drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t *priv, uint32_t handle, - int check_owner) +drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, + uint32_t handle, int check_owner) { drm_user_object_t *uo; drm_buffer_object_t *bo; uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_buffer_type)) + if (!uo || (uo->type != drm_buffer_type)) return NULL; if (check_owner && priv != uo->owner) { @@ -371,15 +368,15 @@ drm_buffer_object_t *drm_lookup_buffer_o atomic_inc(&bo->usage); return bo; } - + /* * Call bo->mutex locked. * Wait until the buffer is idle. */ -static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) +static int drm_bo_wait(drm_device_t * dev, drm_buffer_object_t * bo, int lazy) { - + drm_fence_object_t *fence = bo->fence; int ret; @@ -399,7 +396,9 @@ static int drm_bo_wait(drm_device_t *dev atomic_inc(&fence->usage); mutex_unlock(&bo->mutex); - ret = drm_fence_object_wait(dev, fence, lazy, !lazy, bo->fence_flags); + ret = + drm_fence_object_wait(dev, fence, lazy, !lazy, + bo->fence_flags); mutex_lock(&bo->mutex); if (ret) return ret; @@ -410,7 +409,7 @@ static int drm_bo_wait(drm_device_t *dev bo->fence = NULL; } mutex_unlock(&dev->struct_mutex); - } + } return 0; } @@ -419,7 +418,7 @@ static int drm_bo_wait(drm_device_t *dev * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. */ -static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) +static int drm_bo_busy(drm_device_t * dev, drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; @@ -439,7 +438,6 @@ static int drm_bo_busy(drm_device_t *dev } return 0; } - /* * Wait for buffer idle and register that we've mapped the buffer. @@ -448,13 +446,12 @@ static int drm_bo_busy(drm_device_t *dev * unregistered. */ - -static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) +static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; int ret; - + mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); mutex_unlock(&dev->struct_mutex); @@ -465,8 +462,7 @@ static int drm_buffer_object_map(drm_fil mutex_lock(&bo->mutex); if (!wait) { - if ((atomic_read(&bo->mapped) == 0) && - drm_bo_busy(dev, bo)) { + if ((atomic_read(&bo->mapped) == 0) && drm_bo_busy(dev, bo)) { mutex_unlock(&bo->mutex); ret = -EBUSY; goto out; @@ -486,14 +482,13 @@ static int drm_buffer_object_map(drm_fil atomic_inc(&bo->mapped); } mutex_unlock(&bo->mutex); - - out: - drm_bo_usage_deref_unlocked(dev,bo); + + out: + drm_bo_usage_deref_unlocked(dev, bo); return ret; } - -static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) +static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; @@ -516,21 +511,22 @@ static int drm_buffer_object_unmap(drm_f drm_remove_ref_object(priv, ro); drm_bo_usage_deref_locked(dev, bo); - out: + out: mutex_unlock(&dev->struct_mutex); return ret; } - /* * Call struct-sem locked. */ -static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo, +static void drm_buffer_user_object_unmap(drm_file_t * priv, + drm_user_object_t * uo, drm_ref_t action) { drm_device_t *dev = priv->head->dev; - drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + drm_buffer_object_t *bo = + drm_user_object_entry(uo, drm_buffer_object_t, base); BUG_ON(action != _DRM_REF_TYPE1); @@ -545,33 +541,32 @@ static void drm_buffer_user_object_unmap } } -static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo) +static int drm_buffer_object_validate(drm_device_t * dev, + drm_buffer_object_t * bo) { return 0; } - /* * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hint, - uint32_t ttm_handle) - +static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, + uint32_t hint, uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; drm_ttm_t *ttm; - int ret=0; + int ret = 0; uint32_t ttm_flags = 0; bo->ttm_object = NULL; bo->ttm_region = NULL; - switch(bo->type) { + switch (bo->type) { case drm_bo_type_dc: mutex_lock(&dev->struct_mutex); - ret = drm_ttm_object_create(dev, bo->num_pages*PAGE_SIZE, + ret = drm_ttm_object_create(dev, bo->num_pages * PAGE_SIZE, ttm_flags, &to); mutex_unlock(&dev->struct_mutex); break; @@ -579,11 +574,11 @@ static int drm_bo_add_ttm(drm_file_t *pr mutex_lock(&dev->struct_mutex); to = drm_lookup_ttm_object(priv, ttm_handle, 1); mutex_unlock(&dev->struct_mutex); - if (!to) + if (!to) ret = -EINVAL; break; case drm_bo_type_user: - + case drm_bo_type_fake: break; default: ret = -EINVAL; @@ -597,8 +592,8 @@ static int drm_bo_add_ttm(drm_file_t *pr bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, - hint & DRM_BO_HINT_BIND_CACHED, + bo->num_pages, + hint & DRM_BO_HINT_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -606,28 +601,27 @@ static int drm_bo_add_ttm(drm_file_t *pr } return ret; } - -int drm_buffer_object_create(drm_file_t *priv, +int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, uint32_t ttm_handle, uint32_t mask, uint32_t hint, unsigned long buffer_start, - drm_buffer_object_t **buf_obj) + drm_buffer_object_t ** buf_obj) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; int ret = 0; uint32_t new_flags; unsigned long num_pages; - + if (buffer_start & ~PAGE_MASK) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } - num_pages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; if (num_pages == 0) { DRM_ERROR("Illegal buffer object size.\n"); return -EINVAL; @@ -653,14 +647,14 @@ int drm_buffer_object_create(drm_file_t ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, 1, &new_flags); - if (ret) + if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); - if (ret) + if (ret) goto out_err; bo->mask = mask; - bo->mask_hint = hint; + bo->hint = hint; ret = drm_buffer_object_validate(dev, bo); if (ret) @@ -669,14 +663,14 @@ int drm_buffer_object_create(drm_file_t mutex_unlock(&bo->mutex); *buf_obj = bo; return 0; - - out_err: + + out_err: mutex_unlock(&bo->mutex); drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); - return ret; + return ret; } -static int drm_bo_add_user_object(drm_file_t *priv, drm_buffer_object_t *bo, +static int drm_bo_add_user_object(drm_file_t * priv, drm_buffer_object_t * bo, int shareable) { drm_device_t *dev = priv->head->dev; @@ -691,13 +685,31 @@ static int drm_bo_add_user_object(drm_fi bo->base.type = drm_buffer_type; bo->base.ref_struct_locked = NULL; bo->base.unref = drm_buffer_user_object_unmap; - - out: + + out: mutex_unlock(&dev->struct_mutex); return ret; } - - + +static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, + drm_bo_arg_reply_t * rep) +{ + rep->handle = bo->base.hash.key; + rep->flags = bo->flags; + rep->size = bo->num_pages * PAGE_SIZE; + rep->offset = bo->offset; + + if (bo->ttm_object) { + rep->arg_handle = bo->ttm_object->map_list.user_token; + } else { + rep->arg_handle = 0; + } + + rep->map_flags = bo->map_flags; + rep->mask = bo->mask; + rep->hint = bo->hint; + rep->buffer_start = bo->buffer_start; +} int drm_bo_ioctl(DRM_IOCTL_ARGS) { @@ -714,34 +726,45 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { - case drm_bo_create: { - unsigned long buffer_start = req->buffer_start; - rep.ret = drm_buffer_object_create(priv, req->size, - req->type, req->arg_handle, - req->mask, req->hint, - buffer_start, - &entry); - if (rep.ret) + case drm_bo_create:{ + unsigned long buffer_start = req->buffer_start; + rep.ret = + drm_buffer_object_create(priv, req->size, + req->type, + req->arg_handle, + req->mask, + req->hint, + buffer_start, + &entry); + if (rep.ret) + break; + + rep.ret = + drm_bo_add_user_object(priv, entry, + req-> + mask & + DRM_BO_FLAG_SHAREABLE); + if (rep.ret) + drm_bo_usage_deref_unlocked(dev, entry); + + mutex_lock(&entry->mutex); + drm_bo_fill_rep_arg(entry, &rep); + mutex_unlock(&entry->mutex); break; - - rep.ret = drm_bo_add_user_object(priv, entry, req->mask & - DRM_BO_FLAG_SHAREABLE); - if (rep.ret) - drm_bo_usage_deref_unlocked(dev, entry); - break; - } + } case drm_bo_unmap: rep.ret = drm_buffer_object_unmap(priv, req->handle); break; case drm_bo_map: - rep.ret = drm_buffer_object_map(priv, req->handle, - !(req->hint & + rep.ret = drm_buffer_object_map(priv, req->handle, + !(req->hint & DRM_BO_HINT_DONT_BLOCK)); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, req->handle); - if (!uo || (uo->type != drm_buffer_type) || uo->owner != priv) { + if (!uo || (uo->type != drm_buffer_type) + || uo->owner != priv) { mutex_unlock(&dev->struct_mutex); rep.ret = -EINVAL; break; @@ -749,19 +772,24 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_remove_user_object(priv, uo); mutex_unlock(&dev->struct_mutex); break; - case drm_bo_reference: - rep.ret = drm_user_object_ref(priv, req->handle, + case drm_bo_reference: + rep.ret = drm_user_object_ref(priv, req->handle, drm_buffer_type, &uo); if (rep.ret) break; mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, req->handle); - entry = drm_user_object_entry(uo, drm_buffer_object_t, base); + entry = + drm_user_object_entry(uo, drm_buffer_object_t, + base); atomic_dec(&entry->usage); mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + drm_bo_fill_rep_arg(entry, &rep); + mutex_unlock(&entry->mutex); break; case drm_bo_unreference: - rep.ret = drm_user_object_unref(priv, req->handle, + rep.ret = drm_user_object_unref(priv, req->handle, drm_buffer_type); break; default: @@ -777,7 +805,3 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } - - - - diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 65d4034..33567d9 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,7 +42,6 @@ typedef struct drm_val_action { int validated; } drm_val_action_t; - /* * We may be manipulating other processes page tables, so for each TTM, keep track of * which mm_structs are currently mapping the ttm so that we can take the appropriate @@ -204,7 +203,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) ttm->destroy = 1; DRM_ERROR("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; - } + } DRM_ERROR("Destroying a ttm\n"); if (ttm->be_list) { @@ -263,7 +262,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) * FIXME: Avoid using vmalloc for the page- and page_flags tables? */ -static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) +static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) { drm_ttm_t *ttm; @@ -354,7 +353,8 @@ static int drm_ttm_lock_mmap_sem(drm_ttm DRM_MEM_TTM); cur_count = shared_count + 10; mm_list = - drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_TTM); + drm_alloc(sizeof(*mm_list) * cur_count, + DRM_MEM_TTM); if (!mm_list) return -ENOMEM; } @@ -489,7 +489,7 @@ void drm_destroy_ttm_region(drm_ttm_back if (be->needs_cache_adjust(be)) { int ret = drm_ttm_lock_mmap_sem(ttm); drm_ttm_lock_mm(ttm, 0, 1); - unmap_vma_pages(ttm, entry->page_offset, + unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); drm_set_caching(ttm, entry->page_offset, @@ -542,7 +542,8 @@ int drm_create_ttm_region(drm_ttm_t * tt if (!entry) return -ENOMEM; - be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached); + be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, + cached); if (!be) { drm_free(entry, sizeof(*entry), DRM_MEM_TTM); DRM_ERROR("Couldn't create backend.\n"); @@ -750,11 +751,10 @@ int drm_user_create_region(drm_device_t return 0; } - /* * dev->struct_mutex locked. */ -static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) +static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) { drm_map_list_t *list = &object->map_list; drm_local_map_t *map; @@ -765,7 +765,7 @@ static void drm_ttm_object_remove(drm_de map = list->map; if (map) { - drm_ttm_t *ttm = (drm_ttm_t *)map->offset; + drm_ttm_t *ttm = (drm_ttm_t *) map->offset; if (ttm) { if (drm_destroy_ttm(ttm) != -EBUSY) { drm_free(map, sizeof(*map), DRM_MEM_TTM); @@ -778,15 +778,14 @@ static void drm_ttm_object_remove(drm_de drm_free(object, sizeof(*object), DRM_MEM_TTM); } - -void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) +void drm_ttm_object_deref_locked(drm_device_t * dev, drm_ttm_object_t * to) { if (atomic_dec_and_test(&to->usage)) { drm_ttm_object_remove(dev, to); } } -void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) +void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) { if (atomic_dec_and_test(&to->usage)) { mutex_lock(&dev->struct_mutex); @@ -796,26 +795,25 @@ void drm_ttm_object_deref_unlocked(drm_d } } - /* * dev->struct_mutex locked. */ -static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) +static void drm_ttm_user_deref_locked(drm_file_t * priv, + drm_user_object_t * base) { drm_ttm_object_deref_locked(priv->head->dev, - drm_user_object_entry(base, drm_ttm_object_t, + drm_user_object_entry(base, + drm_ttm_object_t, base)); } - - /* * Create a ttm and add it to the drm book-keeping. * dev->struct_mutex locked. */ -int drm_ttm_object_create(drm_device_t *dev, unsigned long size, - uint32_t flags, drm_ttm_object_t **ttm_object) +int drm_ttm_object_create(drm_device_t * dev, unsigned long size, + uint32_t flags, drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; drm_map_list_t *list; @@ -823,11 +821,11 @@ int drm_ttm_object_create(drm_device_t * drm_ttm_t *ttm; object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); - if (!object) + if (!object) return -ENOMEM; object->flags = flags; list = &object->map_list; - + list->map = drm_calloc(1, sizeof(*map), DRM_MEM_TTM); if (!list->map) { drm_ttm_object_remove(dev, object); @@ -847,9 +845,9 @@ int drm_ttm_object_create(drm_device_t * map->flags = _DRM_REMOVABLE; map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; - - if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, - (unsigned long) map->handle, + + if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, + (unsigned long)map->handle, 32 - PAGE_SHIFT - 3, PAGE_SHIFT, DRM_MAP_HASH_OFFSET)) { drm_ttm_object_remove(dev, object); @@ -863,7 +861,7 @@ int drm_ttm_object_create(drm_device_t * return 0; } -drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, +drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, uint32_t handle, int check_owner) { drm_user_object_t *uo; @@ -871,7 +869,7 @@ drm_ttm_object_t *drm_lookup_ttm_object( uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_ttm_type)) + if (!uo || (uo->type != drm_ttm_type)) return NULL; if (check_owner && priv != uo->owner) { @@ -884,10 +882,9 @@ drm_ttm_object_t *drm_lookup_ttm_object( return to; } - int drm_ttm_ioctl(DRM_IOCTL_ARGS) { - DRM_DEVICE; + DRM_DEVICE; drm_ttm_arg_t arg; drm_ttm_object_t *entry; drm_user_object_t *uo; @@ -895,8 +892,8 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) int ret; DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - - switch(arg.op) { + + switch (arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); size = arg.size; @@ -905,7 +902,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) mutex_unlock(&dev->struct_mutex); return ret; } - ret = drm_add_user_object(priv, &entry->base, + ret = drm_add_user_object(priv, &entry->base, arg.flags & DRM_TTM_FLAG_SHAREABLE); if (ret) { drm_ttm_object_remove(dev, entry); @@ -923,7 +920,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) if (ret) return ret; mutex_lock(&dev->struct_mutex); - entry = drm_lookup_ttm_object(priv, arg.handle , 0); + entry = drm_lookup_ttm_object(priv, arg.handle, 0); break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index a181050..d647578 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -98,7 +98,7 @@ typedef struct drm_ttm { drm_ttm_backend_list_t *be_list; atomic_t vma_count; int mmap_sem_locked; - int destroy; + int destroy; } drm_ttm_t; typedef struct drm_ttm_object { @@ -107,17 +107,17 @@ typedef struct drm_ttm_object { uint32_t flags; drm_map_list_t map_list; } drm_ttm_object_t; - -extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, - uint32_t flags, drm_ttm_object_t **ttm_object); -extern void drm_ttm_object_deref_locked(struct drm_device *dev, drm_ttm_object_t *to); -extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, drm_ttm_object_t *to); -extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, - int check_owner); - - - +extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, + uint32_t flags, + drm_ttm_object_t ** ttm_object); +extern void drm_ttm_object_deref_locked(struct drm_device *dev, + drm_ttm_object_t * to); +extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, + drm_ttm_object_t * to); +extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, + uint32_t handle, + int check_owner); /* * Bind a part of the ttm starting at page_offset size n_pages into the GTT, at @@ -166,7 +166,7 @@ extern int drm_ttm_add_mm_to_list(drm_tt extern void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm); extern int drm_ttm_ioctl(DRM_IOCTL_ARGS); -static __inline__ drm_ttm_t *drm_ttm_from_object(drm_ttm_object_t *to) +static __inline__ drm_ttm_t *drm_ttm_from_object(drm_ttm_object_t * to) { return (drm_ttm_t *) to->map_list.map->offset; } diff --git a/shared-core/drm.h b/shared-core/drm.h index c65ecc0..f6abfeb 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -702,7 +702,8 @@ typedef struct drm_ttm_arg { typedef enum { drm_bo_type_ttm, drm_bo_type_dc, - drm_bo_type_user + drm_bo_type_user, + drm_bo_type_fake }drm_bo_type_t; @@ -823,12 +824,13 @@ typedef union drm_bo_arg{ /** * Device specific ioctls should only be in their respective headers - * The device specific ioctl range is from 0x40 to 0x79. + * The device specific ioctl range is from 0x40 to 0x99. + * Generic IOCTLS restart at 0xA0. * * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and * drmCommandReadWrite(). */ #define DRM_COMMAND_BASE 0x40 -#define DRM_COMMAND_END 0x80 +#define DRM_COMMAND_END 0xA0 #endif |
From: <th...@ke...> - 2006-08-30 11:04:23
|
libdrm/Makefile.am | 2 libdrm/xf86drm.c | 30 ++++++++++++ libdrm/xf86drm.h | 2 libdrm/xf86mm.h | 9 +++ linux-core/drmP.h | 5 +- linux-core/drm_bo.c | 123 +++++++++++++++++++++++++++++++++++++++++++++------ linux-core/drm_drv.c | 3 + shared-core/drm.h | 19 +++++++ 8 files changed, 175 insertions(+), 18 deletions(-) New commits: diff-tree e47a4fda2ef7aada45b7799ad20e8012102dc12e (from 033bda07e9a4eab5058fb919b375deb57b08b5be) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Wed Aug 30 13:04:08 2006 +0200 Memory manager init and takedown. diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index b12e87f..91a7e5d 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -26,6 +26,6 @@ AM_CFLAGS = -I$(top_srcdir)/shared-core libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c libdrmincludedir = ${includedir} -libdrminclude_HEADERS = xf86drm.h +libdrminclude_HEADERS = xf86drm.h xf86mm.h EXTRA_DIST = ChangeLog TODO diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3fccdf6..c9005c4 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -65,7 +65,6 @@ # define _DRM_FREE free # include "drm.h" #endif -#include "xf86mm.h" /* Not all systems have MAP_FAILED defined */ @@ -2582,6 +2581,7 @@ int drmBOCreate(int fd, drmTTM *ttm, uns buf->ttm = ttm; break; case drm_bo_type_dc: + req->buffer_start = start; break; case drm_bo_type_user: req->buffer_start = (unsigned long) user_buffer; @@ -2699,4 +2699,32 @@ int drmBOUnReference(int fd, drmBO *buf) return 0; } +int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, + unsigned long ttPOffset, unsigned long ttPSize) +{ + drm_mm_init_arg_t arg; + + arg.req.op = mm_init; + arg.req.vr_p_offset = vramPOffset; + arg.req.vr_p_size = vramPSize; + arg.req.tt_p_offset = vramPOffset; + arg.req.tt_p_size = vramPSize; + + if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) + return -errno; + + return 0; +} + +int drmMMTakedown(int fd) +{ + drm_mm_init_arg_t arg; + arg.req.op = mm_takedown; + + if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) + return -errno; + + return 0; +} + #endif diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index ca48bfb..f257ded 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -670,4 +670,6 @@ extern int drmSLLookupNeighbors(void *l unsigned long *prev_key, void **prev_value, unsigned long *next_key, void **next_value); +#include "xf86mm.h" + #endif diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 08149d0..8711a14 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -29,7 +29,7 @@ #ifndef _XF86MM_H_ #define _XF86MM_H_ #include <stddef.h> -#include "xf86drm.h" +#include "drm.h" /* * List macros heavily inspired by the Linux kernel @@ -114,5 +114,12 @@ typedef struct _drmBOList { drmMMListHead free; } drmBOList; +extern int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, + void *user_buffer, drm_bo_type_t type, unsigned mask, + unsigned hint, drmBO *buf); +extern int drmBODestroy(int fd, drmBO *buf); +extern int drmBOReference(int fd, unsigned handle, drmBO *buf); +extern int drmBOUnReference(int fd, drmBO *buf); + #endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 63bcde2..5992696 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -775,7 +775,9 @@ typedef struct drm_fence_manager{ typedef struct drm_buffer_manager{ int initialized; - struct mutex bm_mutex; + int has_vram; + int has_tt; + struct mutex mutex; drm_mm_t tt_manager; struct list_head tt_lru; drm_mm_t vram_manager; @@ -1363,6 +1365,7 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARG */ extern int drm_bo_ioctl(DRM_IOCTL_ARGS); +extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); /* Inline replacements for DRM_IOREMAP macros */ diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 2438944..5f557d5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -66,7 +66,7 @@ int drm_fence_buffer_objects(drm_file_t drm_fence_object_t *fence; int ret; - mutex_lock(&bm->bm_mutex); + mutex_lock(&bm->mutex); list_for_each_entry(entry, &bm->unfenced, head) { BUG_ON(!entry->unfenced); @@ -75,21 +75,21 @@ int drm_fence_buffer_objects(drm_file_t } if (!count) { - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return 0; } fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); if (!fence) { - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return -ENOMEM; } ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return ret; } @@ -111,7 +111,7 @@ int drm_fence_buffer_objects(drm_file_t mutex_lock(&dev->struct_mutex); atomic_add(count - 1, &fence->usage); mutex_unlock(&dev->struct_mutex); - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return 0; } @@ -179,11 +179,12 @@ static void drm_bo_destroy_locked(drm_de drm_mm_put_block(&bm->vram_manager, bo->vram); bo->vram = NULL; } - - /* - * FIXME: Destroy ttm. - */ - + if (bo->ttm_region) { + drm_destroy_ttm_region(bo->ttm_region); + } + if (bo->ttm_object) { + drm_ttm_object_deref_locked(dev, bo->ttm_object); + } drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } @@ -356,8 +357,11 @@ drm_buffer_object_t *drm_lookup_buffer_o uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_buffer_type)) + if (!uo || (uo->type != drm_buffer_type)) { + DRM_ERROR("Could not find buffer object 0x%08x\n", + handle); return NULL; + } if (check_owner && priv != uo->owner) { if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) @@ -541,9 +545,10 @@ static void drm_buffer_user_object_unmap } } -static int drm_buffer_object_validate(drm_device_t * dev, +static int drm_buffer_object_validate(drm_device_t * dev, uint32_t new_flags, drm_buffer_object_t * bo) { + bo->flags = new_flags; return 0; } @@ -574,14 +579,18 @@ static int drm_bo_add_ttm(drm_file_t * p mutex_lock(&dev->struct_mutex); to = drm_lookup_ttm_object(priv, ttm_handle, 1); mutex_unlock(&dev->struct_mutex); - if (!to) + if (!to) { + DRM_ERROR("Could not find TTM object\n"); ret = -EINVAL; + } break; case drm_bo_type_user: case drm_bo_type_fake: break; default: + DRM_ERROR("Illegal buffer object type\n"); ret = -EINVAL; + break; } if (ret) { @@ -656,7 +665,7 @@ int drm_buffer_object_create(drm_file_t bo->mask = mask; bo->hint = hint; - ret = drm_buffer_object_validate(dev, bo); + ret = drm_buffer_object_validate(dev, new_flags, bo); if (ret) goto out_err; @@ -805,3 +814,89 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } + +static void drm_bo_clean_mm(drm_file_t *priv) +{ +} + + +int drm_mm_init_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + + int ret = 0; + drm_mm_init_arg_t arg; + drm_buffer_manager_t *bm = &dev->bm; + drm_bo_driver_t *driver = dev->driver->bo_driver; + + if (!driver) { + DRM_ERROR("Buffer objects is not supported by this driver\n"); + return -EINVAL; + } + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + + switch(arg.req.op) { + case mm_init: + if (bm->initialized) { + DRM_ERROR("Memory manager already initialized\n"); + return -EINVAL; + } + mutex_init(&bm->mutex); + mutex_lock(&bm->mutex); + bm->has_vram = 0; + bm->has_tt = 0; + + if (arg.req.vr_p_size) { + ret = drm_mm_init(&bm->vram_manager, + arg.req.vr_p_offset, + arg.req.vr_p_size); + bm->has_vram = 1; + if (ret) + break; + } + + if (arg.req.tt_p_size) { + ret = drm_mm_init(&bm->tt_manager, + arg.req.tt_p_offset, + arg.req.tt_p_size); + bm->has_tt = 1; + if (ret) { + if (bm->has_vram) + drm_mm_takedown(&bm->vram_manager); + break; + } + } + arg.rep.mm_sarea = 0; + + INIT_LIST_HEAD(&bm->vram_lru); + INIT_LIST_HEAD(&bm->tt_lru); + INIT_LIST_HEAD(&bm->unfenced); + INIT_LIST_HEAD(&bm->ddestroy); + + bm->initialized = 1; + break; + case mm_takedown: + if (!bm->initialized) { + DRM_ERROR("Memory manager was not initialized\n"); + return -EINVAL; + } + mutex_lock(&bm->mutex); + drm_bo_clean_mm(priv); + if (bm->has_vram) + drm_mm_takedown(&bm->vram_manager); + if (bm->has_tt) + drm_mm_takedown(&bm->tt_manager); + bm->initialized = 0; + break; + default: + return -EINVAL; + } + + mutex_unlock(&bm->mutex); + if (ret) + return ret; + + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); + return 0; +} diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index f27a7af..62df680 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -121,6 +121,9 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, [DRM_IOCTL_NR(DRM_IOCTL_FENCE)] = {drm_fence_ioctl, DRM_AUTH}, [DRM_IOCTL_NR(DRM_IOCTL_TTM)] = {drm_ttm_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_BUFOBJ)] = {drm_bo_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_MM_INIT)] = {drm_mm_init_ioctl, + DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}, }; #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index f6abfeb..f900dd5 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -747,8 +747,26 @@ typedef union drm_bo_arg{ drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; } drm_bo_arg_t; + +typedef union drm_mm_init_arg{ + struct { + enum { + mm_init, + mm_takedown, + mm_query + } op; + drm_u64_t vr_p_offset; + drm_u64_t vr_p_size; + drm_u64_t tt_p_offset; + drm_u64_t tt_p_size; + } req; + struct { + drm_handle_t mm_sarea; + } rep; +} drm_mm_init_arg_t; #endif + /** * \name Ioctls Definitions */ @@ -818,6 +836,7 @@ typedef union drm_bo_arg{ #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) #define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) #define DRM_IOCTL_BUFOBJ DRM_IOWR(0x3d, drm_bo_arg_t) +#define DRM_IOCTL_MM_INIT DRM_IOWR(0x3e, drm_mm_init_arg_t) #endif /*@}*/ |
From: <th...@ke...> - 2006-08-31 12:10:34
|
libdrm/xf86drm.c | 340 +++++++++++++++++++++++++++++++++++++++++++++------- libdrm/xf86mm.h | 2 linux-core/drmP.h | 1 linux-core/drm_bo.c | 163 ++++++++++++++++++------ shared-core/drm.h | 35 +++-- 5 files changed, 445 insertions(+), 96 deletions(-) New commits: diff-tree ec8c79b79de6544cc09b5a2c85213a5f30e0d906 (from ed9de124cc88cee398b7013de6b822bfaa3f397e) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Thu Aug 31 14:10:13 2006 +0200 More mapping synchronization. libdrm validate and fencing functions. diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 1763b89..a99c979 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2501,7 +2501,9 @@ int drmResetList(drmBOList *list) { return drmAdjustListNodes(list); } -static int drmAddListItem(drmBOList *list, drmBO *item, drm_bo_arg_t *arg) +static drmBONode *drmAddListItem(drmBOList *list, drmBO *item, + unsigned long arg0, + unsigned long arg1) { drmBONode *node; drmMMListHead *l; @@ -2510,7 +2512,7 @@ static int drmAddListItem(drmBOList *lis if (l == &list->free) { node = (drmBONode *) malloc(sizeof(*node)); if (!node) { - return -ENOMEM; + return NULL; } list->numCurrent++; } else { @@ -2518,45 +2520,51 @@ static int drmAddListItem(drmBOList *lis node = DRMLISTENTRY(drmBONode, l, head); } node->buf = item; + node->arg0 = arg0; + node->arg1 = arg1; DRMLISTADD(&node->head, &list->list); list->numOnList++; - return 0; + return node; } -int drmCreateBufList(int numTarget, drmBOList *list) +void *drmBOListIterator(drmBOList *list) { - DRMINITLISTHEAD(&list->list); - DRMINITLISTHEAD(&list->free); - list->numTarget = numTarget; - list->numCurrent = 0; - list->numOnList = 0; - return drmAdjustListNodes(list); -} + void *ret = list->list.next; -/* - * Prepare list for IOCTL submission. - */ + if (ret == &list->list) + return NULL; + return ret; +} -static drm_bo_arg_t *drmPrepareList(drmBOList *list) +void *drmBOListNext(drmBOList *list, void *iterator) { - drmMMListHead *cur, *next; - drmBONode *first, *curNode, *nextNode; + void *ret; - cur = list->list.next; - if (cur == &list->list) + drmMMListHead *l = (drmMMListHead *) iterator; + ret = l->next; + if (ret == &list->list) return NULL; + return ret; +} + +void drmBOListBuf(void *iterator, drmBO **buf) +{ + drmBONode *node; + drmMMListHead *l = (drmMMListHead *) iterator; + node = DRMLISTENTRY(drmBONode, l, head); + + *buf = node->buf; +} - first = DRMLISTENTRY(drmBONode, cur, head); - curNode = DRMLISTENTRY(drmBONode, cur, head); - for (next = cur->next; next != &list->list; - cur = next, next = cur->next) { - nextNode = DRMLISTENTRY(drmBONode, next, head); - curNode->bo_arg.req.next = ((unsigned long) &nextNode->bo_arg.req); - curNode = nextNode; - } - curNode->bo_arg.req.next = 0; - return &first->bo_arg; +int drmCreateBufList(int numTarget, drmBOList *list) +{ + DRMINITLISTHEAD(&list->list); + DRMINITLISTHEAD(&list->free); + list->numTarget = numTarget; + list->numCurrent = 0; + list->numOnList = 0; + return drmAdjustListNodes(list); } int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, @@ -2567,6 +2575,7 @@ int drmBOCreate(int fd, drmTTM *ttm, uns drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + arg.handled = 0; req->mask = mask; req->hint = hint; req->size = size; @@ -2595,7 +2604,8 @@ int drmBOCreate(int fd, drmTTM *ttm, uns if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; - if (!rep->handled) { + if (!arg.handled) { + fprintf(stderr, "Not handled\n"); return -EFAULT; } if (rep->ret) { @@ -2607,7 +2617,6 @@ int drmBOCreate(int fd, drmTTM *ttm, uns buf->size = rep->size; buf->offset = rep->offset; buf->mapHandle = rep->arg_handle; - buf->mapFlags = rep->map_flags; buf->mapVirtual = NULL; buf->mapCount = 0; buf->virtual = NULL; @@ -2623,13 +2632,14 @@ int drmBODestroy(int fd, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_destroy; req->next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; - if (!rep->handled) { + if (!arg.handled) { return -EFAULT; } if (rep->ret) { @@ -2647,13 +2657,14 @@ int drmBOReference(int fd, unsigned hand drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + arg.handled = 0; req->handle = handle; req->op = drm_bo_reference; req->next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; - if (!rep->handled) { + if (!arg.handled) { return -EFAULT; } if (rep->ret) { @@ -2666,7 +2677,6 @@ int drmBOReference(int fd, unsigned hand buf->size = rep->size; buf->offset = rep->offset; buf->mapHandle = rep->arg_handle; - buf->mapFlags = rep->map_flags; buf->mapVirtual = NULL; buf->mapCount = 0; buf->virtual = NULL; @@ -2681,13 +2691,14 @@ int drmBOUnReference(int fd, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unreference; req->next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; - if (!rep->handled) { + if (!arg.handled) { return -EFAULT; } if (rep->ret) { @@ -2699,10 +2710,13 @@ int drmBOUnReference(int fd, drmBO *buf) } /* - * + * Flags can be DRM_BO_FLAG_READ, DRM_BO_FLAG_WRITE or'ed together + * Hint currently be DRM_BO_HINT_DONT_BLOCK, which makes the + * call return an -EBUSY if it can' immediately honor the mapping request. */ -int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, void **address) +int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, + void **address) { drm_bo_arg_t arg; @@ -2714,6 +2728,7 @@ int drmBOMap(int fd, drmBO *buf, unsigne * Make sure we have a virtual address of the buffer. */ + fprintf(stderr, "Address is 0x%08x\n", address); if (!buf->mapVirtual) { if (buf->mapCount == 0) { drmAddress virtual; @@ -2728,8 +2743,11 @@ int drmBOMap(int fd, drmBO *buf, unsigne } } + fprintf(stderr, "Address is 0x%08x\n", address); + arg.handled = 0; req->handle = buf->handle; - req->hint = mapFlags; + req->mask = mapFlags; + req->hint = mapHint; req->op = drm_bo_map; req->next = 0; @@ -2738,23 +2756,26 @@ int drmBOMap(int fd, drmBO *buf, unsigne * This IOCTL synchronizes the buffer. */ + fprintf(stderr, "Address is 0x%08x\n", address); do { ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); } while (ret != 0 && errno == EAGAIN); - if (ret || !rep->handled || rep->ret) { + fprintf(stderr, "Address is 0x%08x\n", address); + if (ret || !arg.handled || rep->ret) { if (--buf->mapCount == 0) { (void )drmUnmap(buf->mapVirtual, buf->start + buf->size); } } if (ret) return ret; - if (!rep->handled) + if (!arg.handled) return -EFAULT; if (rep->ret) return rep->ret; buf->mapFlags = mapFlags; + fprintf(stderr, "Address is 0x%08x\n", address); *address = buf->virtual; return 0; @@ -2764,6 +2785,7 @@ int drmBOUnmap(int fd, drmBO *buf) { drm_bo_arg_t arg; drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; if (buf->mapCount == 0) { return -EINVAL; @@ -2773,6 +2795,7 @@ int drmBOUnmap(int fd, drmBO *buf) (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); } + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unmap; req->next = 0; @@ -2780,10 +2803,247 @@ int drmBOUnmap(int fd, drmBO *buf) if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) { return -errno; } + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; return 0; } +int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, + unsigned hint) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + int ret = 0; + + arg.handled = 0; + req->handle = buf->handle; + req->mask = flags; + req->hint = hint; + req->arg_handle = mask; /* Encode mask in the arg_handle field :/ */ + req->op = drm_bo_validate; + req->next = 0; + + do{ + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret && errno == -EAGAIN); + + if (ret) + return ret; + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + + buf->offset = rep->offset; + buf->flags = rep->flags; + buf->mask = rep->mask; + return 0; +} + + +int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + int ret = 0; + + arg.handled = 0; + req->handle = buf->handle; + req->mask = flags; + req->arg_handle = fenceHandle; + req->op = drm_bo_validate; + req->next = 0; + + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + + if (ret) + return ret; + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + return 0; +} + + + +int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, + unsigned mask, + int *newItem) +{ + drmBONode *node, *cur; + unsigned oldFlags, newFlags; + drmMMListHead *l; + + *newItem = 0; + cur = NULL; + + mask &= ~DRM_BO_MASK_MEM; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + if (node->buf == buf) { + cur = node; + break; + } + } + if (!cur) { + cur = drmAddListItem(list, buf, flags, mask); + if (!cur) { + drmMsg("Out of memory creating validate list node.\n"); + return -ENOMEM; + } + *newItem = 1; + cur->arg0 = flags; + cur->arg1 = mask; + } else { + unsigned memFlags = cur->arg0 & DRM_BO_MASK_MEM; + + if (!(memFlags & flags)) { + drmMsg("Incompatible memory location requests " + "on validate list.\n"); + return -EINVAL; + } + if ((cur->arg1 | mask) & (cur->arg0 ^ flags)) { + drmMsg("Incompatible buffer flag requests " + " on validate list.\n"); + return -EINVAL; + } + cur->arg1 |= mask; + cur->arg0 = (memFlags & flags) | ((cur->arg0 | flags) & cur->arg1); + } +} + + +int drmBOValidateList(int fd, drmBOList *list) +{ + + drmBONode *node; + drmMMListHead *l; + drm_bo_arg_t *arg, *first; + drm_bo_arg_request_t *req; + drm_bo_arg_reply_t *rep; + drm_u64_t *prevNext = NULL; + drmBO *buf; + int ret; + + first = NULL; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + + arg = &node->bo_arg; + req = &arg->req; + + if (!first) + first = arg; + + if (prevNext) + *prevNext = (unsigned long) arg; + + req->next = 0; + prevNext = &req->next; + arg->handled = 0; + req->handle = node->buf->handle; + req->op = drm_bo_validate; + req->mask = node->arg0; + req->hint = 0; + req->arg_handle = node->arg1; + } + + if (!first) + return 0; + + do{ + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret && errno == -EAGAIN); + + if (ret) + return -errno; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + + arg = &node->bo_arg; + rep = &arg->rep; + + if (!arg->handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + + buf = node->buf; + buf->offset = rep->offset; + buf->flags = rep->flags; + buf->mask = rep->mask; + } + + return 0; +} + + +int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) +{ + + drmBONode *node; + drmMMListHead *l; + drm_bo_arg_t *arg, *first; + drm_bo_arg_request_t *req; + drm_bo_arg_reply_t *rep; + drm_u64_t *prevNext = NULL; + drmBO *buf; + int ret; + + first = NULL; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + + arg = &node->bo_arg; + req = &arg->req; + + if (!first) + first = arg; + + if (prevNext) + *prevNext = (unsigned long) arg; + + req->next = 0; + prevNext = &req->next; + arg->handled = 0; + req->handle = node->buf->handle; + req->op = drm_bo_fence; + req->mask = node->arg0; + req->arg_handle = fenceHandle; + } + + if (!first) + return 0; + + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + + if (ret) + return -errno; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + + arg = &node->bo_arg; + rep = &arg->rep; + + if (!arg->handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + } + + return 0; +} int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, unsigned long ttPOffset, unsigned long ttPSize) diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 21fed6c..aaee3c0 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -103,6 +103,8 @@ typedef struct _drmBONode { drmMMListHead head; drmBO *buf; drm_bo_arg_t bo_arg; + unsigned long arg0; + unsigned long arg1; } drmBONode; typedef struct _drmBOList { diff --git a/linux-core/drmP.h b/linux-core/drmP.h index bbf9da0..fde89c3 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -966,7 +966,6 @@ typedef struct drm_buffer_object{ unsigned long offset; atomic_t mapped; - uint32_t map_flags; uint32_t flags; uint32_t mask; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index faa2e00..232120a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -256,11 +256,11 @@ static int drm_bo_evict(drm_buffer_objec int ret = 0; /* - * Someone might have taken out the buffer before we took the buffer mutex. + * Someone might have modified the buffer before we took the buffer mutex. */ mutex_lock(&bo->mutex); - if (bo->unfenced) + if (bo->unfenced || (bo->flags & DRM_BO_FLAG_NO_EVICT)) goto out; if (tt && !bo->tt) goto out; @@ -371,17 +371,46 @@ static int drm_move_local_to_tt(drm_buff static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, - int init, uint32_t * n_flags) + int init, uint32_t * n_flags, + uint32_t *n_mask) { - uint32_t new_flags; + uint32_t new_flags = 0; uint32_t new_props; - if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { + /* + * First adjust the mask. Vram is not supported yet. + */ - /* - * We need to move memory. Default preferences are hard-coded - * here. - */ + new_mask &= ~DRM_BO_FLAG_MEM_VRAM; + + if (new_mask & DRM_BO_FLAG_BIND_CACHED) { + if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && + ((new_mask & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) { + new_mask &= ~DRM_BO_FLAG_BIND_CACHED; + } else { + if (!driver->cached_tt) + new_flags &= DRM_BO_FLAG_MEM_TT; + if (!driver->cached_vram) + new_flags &= DRM_BO_FLAG_MEM_VRAM; + } + } + + if ((new_mask & DRM_BO_FLAG_READ_CACHED) && + !(new_mask & DRM_BO_FLAG_BIND_CACHED)) { + if ((new_mask & DRM_BO_FLAG_NO_EVICT) && + !(new_mask & DRM_BO_FLAG_MEM_LOCAL)) { + DRM_ERROR("Cannot read cached from a pinned VRAM / TT buffer\n"); + return -EINVAL; + } + new_mask &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM); + } + + /* + * Determine new memory location: + */ + + + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { new_flags = new_mask & DRM_BO_MASK_MEM; @@ -421,17 +450,10 @@ static int drm_bo_new_flags(drm_bo_drive new_flags |= new_mask & ~DRM_BO_MASK_MEM; - if (new_mask & DRM_BO_FLAG_BIND_CACHED) { - new_flags |= DRM_BO_FLAG_CACHED; - if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || - ((new_flags & DRM_BO_FLAG_MEM_VRAM) - && !driver->cached_vram)) - new_flags &= ~DRM_BO_FLAG_CACHED; - } - - if ((new_flags & DRM_BO_FLAG_NO_EVICT) && - ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { - if (flags & DRM_BO_FLAG_CACHED) { + if (((flags ^ new_flags) & DRM_BO_FLAG_BIND_CACHED) && + (new_flags & DRM_BO_FLAG_NO_EVICT) && + (flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM))) { + if (!(flags & DRM_BO_FLAG_CACHED)) { DRM_ERROR ("Cannot change caching policy of pinned buffer\n"); return -EINVAL; @@ -441,6 +463,7 @@ static int drm_bo_new_flags(drm_bo_drive } *n_flags = new_flags; + *n_mask = new_mask; return 0; } @@ -498,6 +521,12 @@ static int drm_bo_busy(drm_buffer_object return 0; } + +static int drm_bo_read_cached(drm_buffer_object_t *bo) { + return 0; +} + + /* * Wait for buffer idle and register that we've mapped the buffer. * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, @@ -505,11 +534,12 @@ static int drm_bo_busy(drm_buffer_object * unregistered. */ -static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) +static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, + uint32_t map_flags, int no_wait) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; - int ret; + int ret = 0; mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); @@ -526,14 +556,46 @@ static int drm_buffer_object_map(drm_fil * be done without the bo->mutex held. */ - if (atomic_inc_and_test(&bo->mapped)) { - ret = drm_bo_wait(bo, 0, !wait); - if (ret) { - atomic_dec(&bo->mapped); - goto out; + while(1) { + if (atomic_inc_and_test(&bo->mapped)) { + ret = drm_bo_wait(bo, 0, no_wait); + if (ret) { + atomic_dec(&bo->mapped); + goto out; + } + + if ((map_flags & DRM_BO_FLAG_READ) && + (bo->flags & DRM_BO_FLAG_READ_CACHED) && + (!(bo->flags & DRM_BO_FLAG_CACHED))) { + + drm_bo_read_cached(bo); + } + break; + } else { + if ((map_flags & DRM_BO_FLAG_READ) && + (bo->flags & DRM_BO_FLAG_READ_CACHED) && + (!(bo->flags & DRM_BO_FLAG_CACHED))) { + + /* + * We are already mapped with different flags. + * need to wait for unmap. + */ + + if (no_wait) { + ret = -EBUSY; + goto out; + } + DRM_WAIT_ON(ret, bo->validate_queue, 3 * DRM_HZ, + atomic_read(&bo->mapped) == -1); + if (ret == -EINTR) + ret = -EAGAIN; + if (ret) + goto out; + continue; + } } } - + mutex_lock(&dev->struct_mutex); ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); mutex_unlock(&dev->struct_mutex); @@ -729,7 +791,7 @@ static int drm_buffer_object_validate(dr */ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, - uint32_t mask, uint32_t ttm_handle) + uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; @@ -774,7 +836,7 @@ static int drm_bo_add_ttm(drm_file_t * p ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - mask & DRM_BO_FLAG_BIND_CACHED, + bo->mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -827,17 +889,19 @@ int drm_buffer_object_create(drm_file_t bo->buffer_start = buffer_start; ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, - 1, &new_flags); + 1, &new_flags, &bo->mask); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, mask, ttm_handle); + ret = drm_bo_add_ttm(priv, bo, ttm_handle); if (ret) goto out_err; - bo->mask = mask; - +#if 0 ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); +#else + bo->flags = new_flags; +#endif if (ret) goto out_err; @@ -886,7 +950,6 @@ static void drm_bo_fill_rep_arg(const dr rep->arg_handle = 0; } - rep->map_flags = bo->map_flags; rep->mask = bo->mask; rep->buffer_start = bo->buffer_start; } @@ -902,9 +965,15 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) drm_buffer_object_t *entry; do { - DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, + sizeof(arg)); + + if (arg.handled) { + data = req->next; + continue; + } + rep.ret = 0; - rep.handled = 0; switch (req->op) { case drm_bo_create:{ unsigned long buffer_start = req->buffer_start; @@ -937,8 +1006,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, - !(req->hint & - DRM_BO_HINT_DONT_BLOCK)); + req->mask, + req->hint & + DRM_BO_HINT_DONT_BLOCK); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -976,16 +1046,25 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = -EINVAL; } next = req->next; - rep.handled = 1; + + /* + * A signal interrupted us. Make sure the ioctl is restartable. + */ + + if (rep.ret == -EAGAIN) + return -EAGAIN; + + arg.handled = 1; arg.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); data = next; } while (data); return 0; - } + + static void drm_bo_clean_mm(drm_file_t * priv) { } @@ -1008,10 +1087,12 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) switch (arg.req.op) { case mm_init: +#if 0 if (bm->initialized) { DRM_ERROR("Memory manager already initialized\n"); return -EINVAL; } +#endif mutex_init(&bm->mutex); mutex_lock(&bm->mutex); bm->has_vram = 0; diff --git a/shared-core/drm.h b/shared-core/drm.h index d992621..9640855 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -688,22 +688,28 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_WRITE 0x00000002 #define DRM_BO_FLAG_EXE 0x00000004 +/* + * Status flags. Can be read to determine the actual state of a buffer. + */ + /* Pinned buffer. */ -#define DRM_BO_FLAG_NO_EVICT 0x00000010 +#define DRM_BO_FLAG_NO_EVICT 0x00000001 /* Always keep a system memory shadow to a vram buffer */ -#define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 +#define DRM_BO_FLAG_SHADOW_VRAM 0x00000002 /* When mapped for reading, make sure the buffer is cached even if it means moving the buffer to system memory */ -#define DRM_BO_FLAG_READ_CACHED 0x00000040 -/* The buffer is currently cached */ -#define DRM_BO_FLAG_CACHED 0x00000080 -/* The buffer is shareable with other processes */ -#define DRM_BO_FLAG_SHAREABLE 0x00000100 +#define DRM_BO_FLAG_SHAREABLE 0x00000004 /* When there is a choice between VRAM and TT, prefer VRAM. The default behaviour is to prefer TT. */ -#define DRM_BO_FLAG_PREFER_VRAM 0x00000200 +#define DRM_BO_FLAG_CACHED 0x00000008 +/* The buffer is shareable with other processes */ + + +#define DRM_BO_FLAG_READ_CACHED 0x00001000 +/* The buffer is currently cached */ +#define DRM_BO_FLAG_PREFER_VRAM 0x00002000 /* Bind this buffer cached if the hardware supports it. */ -#define DRM_BO_FLAG_BIND_CACHED 0x00000400 +#define DRM_BO_FLAG_BIND_CACHED 0x00004000 /* Translation table aperture */ #define DRM_BO_FLAG_MEM_TT 0x01000000 @@ -750,21 +756,22 @@ typedef struct drm_bo_arg_request { typedef struct drm_bo_arg_reply { int ret; - int handled; unsigned handle; unsigned flags; drm_u64_t size; drm_u64_t offset; unsigned arg_handle; - unsigned map_flags; unsigned mask; drm_u64_t buffer_start; }drm_bo_arg_reply_t; -typedef union drm_bo_arg{ - drm_bo_arg_request_t req; - drm_bo_arg_reply_t rep; +typedef struct drm_bo_arg{ + int handled; + union { + drm_bo_arg_request_t req; + drm_bo_arg_reply_t rep; + }; } drm_bo_arg_t; typedef union drm_mm_init_arg{ |
From: <th...@ke...> - 2006-08-31 13:36:55
|
linux-core/drmP.h | 2 linux-core/drm_bo.c | 120 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 83 insertions(+), 39 deletions(-) New commits: diff-tree 03c137c5f8d44c374406efe19c01105fcf34d583 (from ec8c79b79de6544cc09b5a2c85213a5f30e0d906) Author: Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> Date: Thu Aug 31 15:36:40 2006 +0200 Remove the buffer manager mutex. Use dev->struct_mutex instead. Add a function to free buffers on hold for destruction if their fence object has expired. Add a timer to periodically call that function when there are buffers pending deletion. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index fde89c3..01e3c66 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -777,13 +777,13 @@ typedef struct drm_buffer_manager{ int initialized; int has_vram; int has_tt; - struct mutex mutex; drm_mm_t tt_manager; struct list_head tt_lru; drm_mm_t vram_manager; struct list_head vram_lru; struct list_head unfenced; struct list_head ddestroy; + struct timer_list timer; } drm_buffer_manager_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 232120a..e251326 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -59,11 +59,6 @@ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } -static inline uint32_t drm_flag_masked(uint32_t old, uint32_t new, - uint32_t mask) -{ - return old ^ ((old ^ new) & mask); -} int drm_fence_buffer_objects(drm_file_t * priv) { @@ -76,7 +71,7 @@ int drm_fence_buffer_objects(drm_file_t drm_fence_object_t *fence; int ret; - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); list_for_each_entry(entry, &bm->unfenced, head) { BUG_ON(!entry->unfenced); @@ -85,21 +80,21 @@ int drm_fence_buffer_objects(drm_file_t } if (!count) { - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); return 0; } fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); if (!fence) { - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); return -ENOMEM; } ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -118,10 +113,8 @@ int drm_fence_buffer_objects(drm_file_t } } - mutex_lock(&dev->struct_mutex); atomic_add(count - 1, &fence->usage); mutex_unlock(&dev->struct_mutex); - mutex_unlock(&bm->mutex); return 0; } @@ -136,28 +129,36 @@ static int drm_move_tt_to_local(drm_buff BUG_ON(!buf->tt); - mutex_lock(&bm->mutex); mutex_lock(&dev->struct_mutex); drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; mutex_unlock(&dev->struct_mutex); - mutex_unlock(&bm->mutex); return 0; } + + +/* + * Lock dev->struct_mutex + */ + static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { drm_buffer_manager_t *bm = &dev->bm; - BUG_ON(bo->unfenced); - if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); list_add_tail(&bo->ddestroy, &bm->ddestroy); + + if (!timer_pending(&bm->timer)) { + bm->timer.expires = jiffies + 1; + add_timer(&bm->timer); + } + return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -189,6 +190,50 @@ static void drm_bo_destroy_locked(drm_de drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } +static void drm_bo_delayed_delete(drm_device_t *dev) +{ + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry, *next; + drm_fence_object_t *fence; + + mutex_lock(&dev->struct_mutex); + + list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { + fence = entry->fence; + + if (fence && drm_fence_object_signaled(fence, + entry->fence_flags)) { + drm_fence_usage_deref_locked(dev, fence); + entry->fence = NULL; + } + if (!entry->fence) { + DRM_DEBUG("Destroying delayed buffer object\n"); + list_del(&entry->ddestroy); + drm_bo_destroy_locked(dev, entry); + } + } + + mutex_unlock(&dev->struct_mutex); +} + + +static void +drm_bo_delayed_timer(unsigned long data) +{ + drm_device_t *dev = (drm_device_t *)data; + drm_buffer_manager_t *bm = &dev->bm; + + drm_bo_delayed_delete(dev); + mutex_lock(&dev->struct_mutex); + if (!list_empty(&bm->ddestroy) && !timer_pending(&bm->timer)) { + bm->timer.expires = jiffies + 1; + add_timer(&bm->timer); + } + mutex_unlock(&dev->struct_mutex); +} + + void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { @@ -299,7 +344,7 @@ int drm_bo_alloc_space(drm_buffer_object unsigned long size = buf->num_pages; int ret; - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); do { node = drm_mm_search_free(mm, size, 0, 1); if (node) @@ -313,26 +358,26 @@ int drm_bo_alloc_space(drm_buffer_object /* * No need to take dev->struct_mutex here, because bo->usage is at least 1 already, - * since it's on the lru list, and the bm->mutex is held. + * since it's on the lru list, and the dev->struct_mutex is held. */ atomic_inc(&bo->usage); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); ret = drm_bo_evict(bo, tt, no_wait); drm_bo_usage_deref_unlocked(dev, bo); if (ret) return ret; - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); } while (1); if (!node) { DRM_ERROR("Out of aperture space\n"); - mutex_lock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); return -ENOMEM; } node = drm_mm_get_block(node, size, 0); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); BUG_ON(!node); node->private = (void *)buf; @@ -358,14 +403,10 @@ static int drm_move_local_to_tt(drm_buff mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); - mutex_unlock(&dev->struct_mutex); - if (ret) { - mutex_lock(&bm->mutex); drm_mm_put_block(&bm->tt_manager, bo->tt); - mutex_unlock(&bm->mutex); } - + mutex_unlock(&dev->struct_mutex); return ret; } @@ -745,15 +786,15 @@ static int drm_buffer_object_validate(dr */ if (flag_diff & DRM_BO_MASK_MEM) { - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); ret = drm_bo_move_buffer(bo, new_flags, no_wait); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); if (ret) return ret; } if (flag_diff & DRM_BO_FLAG_NO_EVICT) { - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); list_del_init(&bo->head); if (!(new_flags & DRM_BO_FLAG_NO_EVICT)) { if (new_flags & DRM_BO_FLAG_MEM_TT) { @@ -762,7 +803,7 @@ static int drm_buffer_object_validate(dr list_add_tail(&bo->head, &bm->vram_lru); } } - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -772,10 +813,10 @@ static int drm_buffer_object_validate(dr * Place on unfenced list. */ - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); list_del_init(&bo->head); list_add_tail(&bo->head, &bm->unfenced); - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); } /* @@ -860,6 +901,7 @@ int drm_buffer_object_create(drm_file_t uint32_t new_flags; unsigned long num_pages; + drm_bo_delayed_delete(dev); if (buffer_start & ~PAGE_MASK) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; @@ -976,14 +1018,13 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; switch (req->op) { case drm_bo_create:{ - unsigned long buffer_start = req->buffer_start; rep.ret = drm_buffer_object_create(priv, req->size, req->type, req->arg_handle, req->mask, req->hint, - buffer_start, + req->buffer_start, &entry); if (rep.ret) break; @@ -1093,8 +1134,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } #endif - mutex_init(&bm->mutex); - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); bm->has_vram = 0; bm->has_tt = 0; @@ -1125,6 +1165,10 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); + init_timer(&bm->timer); + bm->timer.function = &drm_bo_delayed_timer; + bm->timer.data = (unsigned long) dev; + bm->initialized = 1; break; case mm_takedown: @@ -1132,7 +1176,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) DRM_ERROR("Memory manager was not initialized\n"); return -EINVAL; } - mutex_lock(&bm->mutex); + mutex_lock(&dev->struct_mutex); drm_bo_clean_mm(priv); if (bm->has_vram) drm_mm_takedown(&bm->vram_manager); @@ -1144,7 +1188,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } - mutex_unlock(&bm->mutex); + mutex_unlock(&dev->struct_mutex); if (ret) return ret; |