From 11f9e404fb66927146de30227fa05c5485aa1726 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 17:02:44 +0200 Subject: [PATCH 001/147] Avoid using vmalloc for small hash tables. --- linux-core/drm_hashtab.c | 17 +++++++++++++++-- linux-core/drm_hashtab.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_hashtab.c b/linux-core/drm_hashtab.c index 48061139..40599227 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, unsigned int order) 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 *ht, drm_hash_item_t *item) 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 40afec05..613091c9 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 42c2cfcf7d5730a2961d425228e042f533b312fa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 20:30:19 +0200 Subject: [PATCH 002/147] Generic DRM support base-class support for user-space objects, like fence objects and buffer objects: Refcounting, Inter-process sharing, Synchronization Destruction. --- 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(-) create mode 100644 linux-core/drm_object.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 211e5b05..651e30b0 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -12,7 +12,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ 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 6cbb810f..81ca6aec 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 handle, unsigned long offset, #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, struct poll_table_struct *wait); 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 *inode, struct file *filp, 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, unsigned long start, unsigned long size); 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 9712170b..ccfd1855 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -351,6 +351,7 @@ static void __exit drm_cleanup(drm_device_t * dev) 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 691edff9..10516bdd 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 *inode, struct file *filp, 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 *inode, struct file *filp, 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; jrefd_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, int on) } 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, struct file *filp) 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, struct file *filp) 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 a268d8ee..c12e4897 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 00000000..b928c01e --- /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 25bb5f33..9059f42c 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 * dev, struct pci_dev *pdev, 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 1c787f0d396c309131d5f34939598d657ee2459f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 20:38:57 +0200 Subject: [PATCH 003/147] Backwards compatibility code for ttms. --- linux-core/Makefile.kernel | 2 +- linux-core/drm_compat.c | 140 +++++++++++++++++++++++++++++++++++++ linux-core/drm_compat.h | 18 +++++ 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 linux-core/drm_compat.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 651e30b0..c7c47919 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -12,7 +12,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ 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 00000000..cdef4b97 --- /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 + * Linux kernel mm subsystem authors. + * (Most code taken from there). + */ + +#include "drmP.h" +#include +#include +#include + +#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 407853d7..80928319 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -227,4 +227,22 @@ static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from } #endif +#include +#include + +/* + * 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 166da9355d95affe427a6cff3525df60e80a99df Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:02:08 +0200 Subject: [PATCH 004/147] User / Kernel space fence objects (device-independent part). --- libdrm/xf86drm.c | 119 +++++++++ libdrm/xf86drm.h | 20 ++ linux-core/drmP.h | 76 +++++- linux-core/drm_drv.c | 3 + linux-core/drm_fence.c | 587 +++++++++++++++++++++++++++++++++++++++++ linux-core/drm_stub.c | 1 + shared-core/drm.h | 30 ++- 7 files changed, 834 insertions(+), 2 deletions(-) create mode 100644 linux-core/drm_fence.c diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index c9f1b2db..6302db3a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2236,3 +2236,122 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, } return 0; } + +int drmFenceCreate(int fd, int shareable, unsigned type, int emit, + drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.type = type; + 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->type = arg.type; + fence->signaled = 0; + return 0; +} + +int drmFenceDestroy(int fd, const drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.op = drm_fence_destroy; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + return 0; +} + +int drmFenceReference(int fd, unsigned handle, drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.handle = handle; + arg.op = drm_fence_reference; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->handle = arg.handle; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceUnreference(int fd, const drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.op = drm_fence_unreference; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + return 0; +} + +int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.type = flush_type; + arg.op = drm_fence_flush; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceSignaled(int fd, drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.op = drm_fence_signaled; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.type = emit_type; + arg.op = drm_fence_emit; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, + int lazy, int ignore_signals) +{ + drm_fence_arg_t arg; + int ret; + + arg.handle = fence->handle; + arg.type = flush_type; + arg.flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0; + arg.flags |= (ignore_signals) ? DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS : 0; + arg.op = drm_fence_wait; + do { + ret = ioctl(fd, DRM_IOCTL_FENCE, &arg); + } while (ret != 0 && errno == EAGAIN); + + if (ret) + return -errno; + + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + + diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 48a18f29..0e037daa 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -280,6 +280,11 @@ typedef struct _drmSetVersion { int drm_dd_minor; } drmSetVersion, *drmSetVersionPtr; +typedef struct _drmFence{ + unsigned handle; + unsigned type; + unsigned signaled; +} drmFence; #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) @@ -596,6 +601,21 @@ extern int drmScatterGatherFree(int fd, drm_handle_t handle); extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); +/* Fencing */ + +extern int drmFenceCreate(int fd, int shareable, unsigned type, int emit, + drmFence *fence); +extern int drmFenceDestroy(int fd, const drmFence *fence); +extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); +extern int drmFenceUnreference(int fd, const drmFence *fence); +extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); +extern int drmFenceSignaled(int fd, drmFence *fence); +extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, + int lazy, int ignore_signals); +extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); + + + /* Support routines */ extern int drmError(int err, const char *label); extern void *drmMalloc(int size); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 81ca6aec..4be49b56 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -155,6 +155,7 @@ #define DRM_MEM_MM 22 #define DRM_MEM_HASHTAB 23 #define DRM_MEM_OBJECTS 24 +#define DRM_MEM_FENCE 25 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) @@ -637,6 +638,8 @@ struct drm_driver { unsigned long (*get_reg_ofs) (struct drm_device * dev); void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); + struct drm_fence_driver *fence_driver; + int major; int minor; int patchlevel; @@ -667,6 +670,36 @@ typedef struct drm_head { } drm_head_t; +typedef struct drm_fence_driver{ + int no_types; + uint32_t wrap_diff; + uint32_t flush_diff; + uint32_t sequence_mask; + int lazy_capable; + int (*emit) (struct drm_device *dev, uint32_t *breadcrumb); + void (*poke_flush) (struct drm_device *dev); +} drm_fence_driver_t; + + +typedef struct drm_fence_manager{ + int initialized; + rwlock_t lock; + + /* + * The list below should be maintained in sequence order and + * access is protected by the above spinlock. + */ + + struct list_head ring; + struct list_head *fence_types[32]; + volatile uint32_t pending_flush; + wait_queue_head_t fence_queue; + int pending_exe_flush; + uint32_t last_exe_flush; + uint32_t exe_flush_sequence; +} drm_fence_manager_t; + + /** * DRM device structure. This structure represent a complete card that * may contain multiple heads. @@ -798,8 +831,20 @@ typedef struct drm_device { drm_local_map_t *agp_buffer_map; unsigned int agp_buffer_token; drm_head_t primary; /**< primary screen head */ + + drm_fence_manager_t fm; + } 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) { @@ -894,6 +939,24 @@ typedef struct drm_ref_object { drm_ref_t unref_action; } drm_ref_object_t; +typedef struct drm_fence_object{ + drm_user_object_t base; + atomic_t usage; + + /* + * The below three fields are protected by the fence manager spinlock. + */ + + struct list_head ring; + volatile uint32_t type; + volatile uint32_t signaled; + uint32_t sequence; + volatile uint32_t flush_mask; + volatile uint32_t submitted_flush; +} drm_fence_object_t; + + + /******************************************************************/ @@ -924,7 +987,6 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); 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" @@ -1205,6 +1267,18 @@ extern int drm_user_object_ref(drm_file_t *priv, uint32_t user_token, drm_object extern int drm_user_object_unref(drm_file_t *priv, uint32_t user_token, drm_object_type_t type); + +/* + * fence objects (drm_fence.c) + */ + +extern void drm_fence_handler(drm_device_t *dev, uint32_t breadcrumb, uint32_t type); +extern void drm_fence_manager_init(drm_device_t *dev); +extern void drm_fence_manager_takedown(drm_device_t *dev); +extern void drm_fence_flush_old(drm_device_t *dev, uint32_t sequence); +extern int drm_fence_ioctl(DRM_IOCTL_ARGS); + + /* 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 ccfd1855..e6ae690a 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -119,6 +119,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_FENCE)] = {drm_fence_ioctl, DRM_AUTH}, }; #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls ) @@ -347,6 +348,8 @@ static void __exit drm_cleanup(drm_device_t * dev) drm_lastclose(dev); + drm_fence_manager_takedown(dev); + if (dev->maplist) { drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c new file mode 100644 index 00000000..fc27c576 --- /dev/null +++ b/linux-core/drm_fence.c @@ -0,0 +1,587 @@ +/************************************************************************** + * + * 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 + */ + +#include "drmP.h" + +static void drm_fm_update_pointers(drm_fence_manager_t * fm, + struct list_head *list, int no_types, + uint32_t type) +{ + int i; + for (i = 0; i < no_types; ++i) { + if (type & (1 << i)) { + fm->fence_types[i] = list; + } + } +} + +/* + * Typically called by the IRQ handler. + */ + +void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) +{ + int i; + int wake = 0; + int largest = 0; + uint32_t diff; + uint32_t relevant; + int index = 0; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + struct list_head *list; + struct list_head *fence_list; + drm_fence_object_t *fence; + int found = 0; + + for (i = 0; i < driver->no_types; ++i) { + if (!(type & (1 << i))) + continue; + + list = fm->fence_types[i]; + fence_list = list->next; + + if (fence_list == &fm->ring) + continue; + + fence = list_entry(fence_list, drm_fence_object_t, ring); + + diff = (sequence - fence->sequence) & driver->sequence_mask; + + if (diff < driver->wrap_diff) { + if (diff >= largest) { + largest = diff; + index = i; + found = 1; + } + } + } + + if (!found) + return; + + /* + * Start with the fence object with the lowest sequence number, affected by + * the type mask of this call. Update signaled fields, + * Check if we need to wake sleeping processes + */ + + list = fm->fence_types[index]->next; + do { + if (list == &fm->ring) { + drm_fm_update_pointers(fm, list->prev, + driver->no_types, type); + break; + } + fence = list_entry(list, drm_fence_object_t, ring); + diff = (sequence - fence->sequence) & driver->sequence_mask; + if (diff >= driver->wrap_diff) { + drm_fm_update_pointers(fm, fence->ring.prev, + driver->no_types, type); + break; + } + relevant = type & fence->type; + if ((fence->signaled | relevant) != fence->signaled) { + fence->signaled |= relevant; + fence->submitted_flush |= relevant; + wake = 1; + } + + relevant = fence->flush_mask & + ~(fence->signaled | fence->submitted_flush); + if (relevant) { + fm->pending_flush |= relevant; + fence->submitted_flush = fence->flush_mask; + } + + list = list->next; + + /* + * Remove a completely signaled fence from the + * fence manager ring. + */ + + if (!(fence->type & ~fence->signaled)) { + fence_list = &fence->ring; + for (i = 0; i < driver->no_types; ++i) { + if (fm->fence_types[i] == fence_list) + fm->fence_types[i] = fence_list->prev; + } + list_del_init(fence_list); + } + + } while (1); + + /* + * Wake sleeping processes. + */ + + if (wake) { + DRM_WAKEUP(&fm->fence_queue); + } +} + +EXPORT_SYMBOL(drm_fence_handler); + +static void drm_fence_unring(drm_device_t * dev, struct list_head *ring) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + unsigned long flags; + int i; + + write_lock_irqsave(&fm->lock, flags); + for (i = 0; i < driver->no_types; ++i) { + if (fm->fence_types[i] == ring) + fm->fence_types[i] = ring->prev; + } + list_del_init(ring); + write_unlock_irqrestore(&fm->lock, flags); +} + +void drm_fence_usage_deref_locked(drm_device_t * dev, + drm_fence_object_t * fence) +{ + if (atomic_dec_and_test(&fence->usage)) { + drm_fence_unring(dev, &fence->ring); + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + } +} + +void drm_fence_usage_deref_unlocked(drm_device_t * dev, + drm_fence_object_t * fence) +{ + if (atomic_dec_and_test(&fence->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&fence->usage) == 0) { + drm_fence_unring(dev, &fence->ring); + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + } + mutex_unlock(&dev->struct_mutex); + } +} + +static void drm_fence_object_destroy(drm_file_t * priv, + drm_user_object_t * base) +{ + drm_device_t *dev = priv->head->dev; + drm_fence_object_t *fence = + drm_user_object_entry(base, drm_fence_object_t, base); + + drm_fence_usage_deref_locked(dev, fence); +} + +static int fence_signaled(drm_device_t * dev, drm_fence_object_t * fence, + uint32_t mask, int poke_flush) +{ + unsigned long flags; + int signaled; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + + if (poke_flush) + driver->poke_flush(dev); + read_lock_irqsave(&fm->lock, flags); + signaled = + (fence->type & mask & fence->signaled) == (fence->type & mask); + read_unlock_irqrestore(&fm->lock, flags); + + return signaled; +} + +static void drm_fence_flush_exe(drm_fence_manager_t * fm, + drm_fence_driver_t * driver, uint32_t sequence) +{ + uint32_t diff; + + if (!fm->pending_exe_flush) { + struct list_head *list; + + /* + * Last_exe_flush is invalid. Find oldest sequence. + */ + + list = fm->fence_types[_DRM_FENCE_TYPE_EXE]; + if (list->next == &fm->ring) { + return; + } else { + drm_fence_object_t *fence = + list_entry(list->next, drm_fence_object_t, ring); + fm->last_exe_flush = (fence->sequence - 1) & + driver->sequence_mask; + } + diff = (sequence - fm->last_exe_flush) & driver->sequence_mask; + if (diff >= driver->wrap_diff) + return; + fm->exe_flush_sequence = sequence; + fm->pending_exe_flush = 1; + } else { + diff = + (sequence - fm->exe_flush_sequence) & driver->sequence_mask; + if (diff < driver->wrap_diff) { + fm->exe_flush_sequence = sequence; + } + } +} + +/* + * Make sure old fence objects are signaled before their fence sequences are + * wrapped around and reused. + */ + +static int drm_fence_object_flush(drm_device_t * dev, + drm_fence_object_t * fence, uint32_t type) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + unsigned long flags; + + if (type & ~fence->type) { + DRM_ERROR("Flush trying to extend fence type\n"); + return -EINVAL; + } + + write_lock_irqsave(&fm->lock, flags); + fence->flush_mask |= type; + if (fence->submitted_flush == fence->signaled) { + if ((fence->type & DRM_FENCE_EXE) && + !(fence->submitted_flush & DRM_FENCE_EXE)) { + drm_fence_flush_exe(fm, driver, fence->sequence); + fence->submitted_flush |= DRM_FENCE_EXE; + } else { + fm->pending_flush |= (fence->flush_mask & + ~fence->submitted_flush); + fence->submitted_flush = fence->flush_mask; + } + } + write_unlock_irqrestore(&fm->lock, flags); + driver->poke_flush(dev); + return 0; +} + +void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + uint32_t old_sequence; + unsigned long flags; + drm_fence_object_t *fence; + uint32_t diff; + + mutex_lock(&dev->struct_mutex); + read_lock_irqsave(&fm->lock, flags); + if (fm->ring.next == &fm->ring) { + read_unlock_irqrestore(&fm->lock, flags); + mutex_unlock(&dev->struct_mutex); + return; + } + old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask; + fence = list_entry(fm->ring.next, drm_fence_object_t, ring); + atomic_inc(&fence->usage); + mutex_unlock(&dev->struct_mutex); + diff = (old_sequence - fence->sequence) & driver->sequence_mask; + read_unlock_irqrestore(&fm->lock, flags); + if (diff < driver->wrap_diff) { + drm_fence_object_flush(dev, fence, fence->type); + } + drm_fence_usage_deref_unlocked(dev, fence); +} + +EXPORT_SYMBOL(drm_fence_flush_old); + +static int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, + int lazy, int ignore_signals, uint32_t mask) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + int ret = 0; + unsigned long _end; + + if (mask & ~fence->type) { + DRM_ERROR("Wait trying to extend fence type\n"); + return -EINVAL; + } + + if (fence_signaled(dev, fence, mask, 0)) + return 0; + + _end = jiffies + 3 * DRM_HZ; + + drm_fence_object_flush(dev, fence, mask); + if (lazy && driver->lazy_capable) { + do { + DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, + fence_signaled(dev, fence, mask, 1)); + if (time_after_eq(jiffies, _end)) + break; + } while (ret == -EINTR && ignore_signals); + + if (time_after_eq(jiffies, _end) && (ret != 0)) + ret = -EBUSY; + return ret; + + } else { + int signaled; + do { + signaled = fence_signaled(dev, fence, mask, 1); + } while (!signaled && !time_after_eq(jiffies, _end)); + if (!signaled) + return -EBUSY; + } + return 0; +} + +int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, + uint32_t type) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + unsigned long flags; + uint32_t sequence; + int ret; + + drm_fence_unring(dev, &fence->ring); + ret = driver->emit(dev, &sequence); + if (ret) + return ret; + + write_lock_irqsave(&fm->lock, flags); + fence->type = type; + fence->flush_mask = 0x00; + fence->submitted_flush = 0x00; + fence->signaled = 0x00; + fence->sequence = sequence; + list_add_tail(&fence->ring, &fm->ring); + write_unlock_irqrestore(&fm->lock, flags); + return 0; +} + +int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, + drm_fence_object_t * fence) +{ + int ret = 0; + unsigned long flags; + drm_fence_manager_t *fm = &dev->fm; + + mutex_lock(&dev->struct_mutex); + atomic_set(&fence->usage, 1); + mutex_unlock(&dev->struct_mutex); + + write_lock_irqsave(&fm->lock, flags); + INIT_LIST_HEAD(&fence->ring); + fence->type = type; + fence->flush_mask = 0; + fence->submitted_flush = 0; + fence->signaled = 0; + fence->sequence = 0; + write_unlock_irqrestore(&fm->lock, flags); + if (emit) { + ret = drm_fence_object_emit(dev, fence, type); + } + return ret; +} + +EXPORT_SYMBOL(drm_fence_object_init); + +static int drm_fence_object_create(drm_file_t * priv, uint32_t type, + int emit, int shareable, + uint32_t * user_handle, + drm_fence_object_t ** c_fence) +{ + drm_device_t *dev = priv->head->dev; + int ret; + drm_fence_object_t *fence; + + fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + if (!fence) + return -ENOMEM; + ret = drm_fence_object_init(dev, type, emit, fence); + if (ret) { + drm_fence_usage_deref_unlocked(dev, fence); + return ret; + } + + mutex_lock(&dev->struct_mutex); + ret = drm_add_user_object(priv, &fence->base, shareable); + mutex_unlock(&dev->struct_mutex); + if (ret) { + drm_fence_usage_deref_unlocked(dev, fence); + *c_fence = NULL; + *user_handle = 0; + return ret; + } + fence->base.type = drm_fence_type; + fence->base.remove = &drm_fence_object_destroy; + *user_handle = fence->base.hash.key; + *c_fence = fence; + + return 0; +} + +void drm_fence_manager_init(drm_device_t * dev) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *fed = dev->driver->fence_driver; + int i; + + fm->lock = RW_LOCK_UNLOCKED; + INIT_LIST_HEAD(&fm->ring); + fm->pending_flush = 0; + DRM_INIT_WAITQUEUE(&fm->fence_queue); + fm->initialized = 0; + if (fed) { + fm->initialized = 1; + for (i = 0; i < fed->no_types; ++i) { + fm->fence_types[i] = &fm->ring; + } + } +} + +void drm_fence_manager_takedown(drm_device_t * dev) +{ +} + +drm_fence_object_t *drm_lookup_fence_object(drm_file_t * priv, uint32_t handle) +{ + drm_device_t *dev = priv->head->dev; + drm_user_object_t *uo; + drm_fence_object_t *fence; + + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, handle); + if (!uo || (uo->type != drm_fence_type)) { + mutex_unlock(&dev->struct_mutex); + return NULL; + } + fence = drm_user_object_entry(uo, drm_fence_object_t, base); + atomic_inc(&fence->usage); + mutex_unlock(&dev->struct_mutex); + return fence; +} + +int drm_fence_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + int ret; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_arg_t arg; + drm_fence_object_t *fence; + drm_user_object_t *uo; + unsigned long flags; + ret = 0; + + if (!fm->initialized) { + DRM_ERROR("The DRM driver does not support fencing.\n"); + return -EINVAL; + } + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + switch (arg.op) { + case drm_fence_create:{ + int emit = arg.flags & DRM_FENCE_FLAG_EMIT; + if (emit) + LOCK_TEST_WITH_RETURN(dev, filp); + ret = + drm_fence_object_create(priv, arg.type, + emit, + arg. + flags & + DRM_FENCE_FLAG_SHAREABLE, + &arg.handle, &fence); + if (ret) + return ret; + mutex_lock(&dev->struct_mutex); + atomic_inc(&fence->usage); + mutex_unlock(&dev->struct_mutex); + break; + } + case drm_fence_destroy: + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, arg.handle); + if (!uo || (uo->type != drm_fence_type) || uo->owner != priv) { + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + ret = drm_remove_user_object(priv, uo); + mutex_unlock(&dev->struct_mutex); + return ret; + case drm_fence_reference: + ret = + drm_user_object_ref(priv, arg.handle, drm_fence_type, &uo); + if (ret) + return ret; + fence = drm_lookup_fence_object(priv, arg.handle); + break; + case drm_fence_unreference: + ret = drm_user_object_unref(priv, arg.handle, drm_fence_type); + return ret; + case drm_fence_signaled: + fence = drm_lookup_fence_object(priv, arg.handle); + if (!fence) + return -EINVAL; + break; + case drm_fence_flush: + fence = drm_lookup_fence_object(priv, arg.handle); + if (!fence) + return -EINVAL; + ret = drm_fence_object_flush(dev, fence, arg.type); + break; + case drm_fence_wait: + fence = drm_lookup_fence_object(priv, arg.handle); + if (!fence) + return -EINVAL; + ret = + drm_fence_object_wait(dev, fence, + arg.flags & DRM_FENCE_FLAG_WAIT_LAZY, + arg. + flags & + DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS, + arg.type); + break; + case drm_fence_emit: + LOCK_TEST_WITH_RETURN(dev, filp); + fence = drm_lookup_fence_object(priv, arg.handle); + if (!fence) + return -EINVAL; + ret = drm_fence_object_emit(dev, fence, arg.type); + break; + default: + return -EINVAL; + } + read_lock_irqsave(&fm->lock, flags); + arg.type = fence->type; + arg.signaled = fence->signaled; + read_unlock_irqrestore(&fm->lock, flags); + drm_fence_usage_deref_unlocked(dev, fence); + + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); + return ret; +} diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 9059f42c..6182141a 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -133,6 +133,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, goto error_out_unreg; } + drm_fence_manager_init(dev); return 0; error_out_unreg: diff --git a/shared-core/drm.h b/shared-core/drm.h index 87f8da6b..65d04b72 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -259,7 +259,7 @@ typedef enum drm_map_type { _DRM_SHM = 2, /**< shared, cached */ _DRM_AGP = 3, /**< AGP/GART */ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ - _DRM_CONSISTENT = 5 /**< Consistent memory for PCI DMA */ + _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ } drm_map_type_t; /** @@ -629,6 +629,31 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; +#define DRM_FENCE_FLAG_EMIT 0x00000001 +#define DRM_FENCE_FLAG_SHAREABLE 0x00000002 +#define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 +#define DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS 0x00000008 + +#define DRM_FENCE_EXE 0x00000001 + +typedef struct drm_fence_arg { + unsigned handle; + unsigned type; + unsigned flags; + unsigned signaled; + enum { + drm_fence_create, + drm_fence_destroy, + drm_fence_reference, + drm_fence_unreference, + drm_fence_signaled, + drm_fence_flush, + drm_fence_wait, + drm_fence_emit + } op; +} drm_fence_arg_t; + + /** * \name Ioctls Definitions */ @@ -694,6 +719,9 @@ typedef struct drm_set_version { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) +#define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) + + /*@}*/ /** From 657bacc3953e8e51a0a15bd872e9818c9dbcbc10 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:04:36 +0200 Subject: [PATCH 005/147] Add missing fence type define. Add drm_fence.o to Makefile --- linux-core/Makefile.kernel | 3 ++- linux-core/drmP.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index c7c47919..3c31b013 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -12,7 +12,8 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ 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_compat.o + drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ + drm_fence.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 4be49b56..6db6ac9e 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -680,6 +680,7 @@ typedef struct drm_fence_driver{ void (*poke_flush) (struct drm_device *dev); } drm_fence_driver_t; +#define _DRM_FENCE_TYPE_EXE 0x00 typedef struct drm_fence_manager{ int initialized; From 6571f74a4906ae4f5f92916d64cc2cce3c8e0043 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:12:29 +0200 Subject: [PATCH 006/147] Remove some accidently included TTM code. --- linux-core/drmP.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6db6ac9e..b9549b63 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 e089de33e8efd87b30d59c571b9ab9aa302b23e1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:36:00 +0200 Subject: [PATCH 007/147] 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). --- 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(-) create mode 100644 linux-core/i915_fence.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 3c31b013..c5ce6638 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -19,7 +19,7 @@ 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 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 c6e25f9b..d1b8d2d2 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 00000000..46a2a728 --- /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 + */ + +#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 ba8c56ee..d6bb6c8e 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -434,15 +434,15 @@ static void i915_emit_breadcrumb(drm_device_t *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_t * dev) 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 a87075b1..475ff474 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(drm_device_t * dev); 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_IOCTL_ARGS); 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 * dev, int n, const char *caller); #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 * dev, int n, const char *caller); #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 14213b58..08d3140b 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -56,8 +56,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 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_IRQ_ARGS) 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_device_t * dev) { 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 8d5b7c77f9b31aa9bcf81536d39769f4f3feeb63 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:37:43 +0200 Subject: [PATCH 008/147] Allow longer sequence lifetimes. --- linux-core/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index d1b8d2d2..56ac5fc7 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 700bf80ca9fadf2c1404c220addebd92d9ad799d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 09:47:33 +0200 Subject: [PATCH 009/147] Bring in stripped TTM functionality. --- 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(-) create mode 100644 linux-core/drm_ttm.c create mode 100644 linux-core/drm_ttm.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index c5ce6638..bf5221d1 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,7 +13,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.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_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 b9549b63..33d8ecc2 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, struct poll_table_struct *wait); 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 2eeb401d..efb48dce 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, drm_local_map_t *map) 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 00000000..b3ea7c9b --- /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 + +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 00000000..07592a84 --- /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 cf3bc3cf..9f48f297 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -34,12 +34,42 @@ */ #include "drmP.h" + #if defined(__ia64__) #include #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_nopage(struct vm_area_struct *vma, } #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; ipage_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_area_struct *vma) 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(struct vm_area_struct *vma, 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(struct vm_area_struct *vma, 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_vm_sg_ops = { .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_struct *vma) } } +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_struct *vma) 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 vm_area_struct *vma) /* 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 vm_area_struct *vma) 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 65d04b72..b588b15c 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 b81ca5e031b2fbd9c5c401057c72f5857f7f5a3a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 10:09:57 +0200 Subject: [PATCH 010/147] AGP backends for TTM. --- linux-core/drmP.h | 12 +++ linux-core/drm_agpsupport.c | 165 ++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 33d8ecc2..8f8f324e 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_memory(struct agp_bridge_data *bridge, size 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 dce27cdf..92868005 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 * handle) 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 7058d06317e17253d874bf4df7b09d0d52a5fd74 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 10:24:48 +0200 Subject: [PATCH 011/147] Initial i915 buffer object driver --- 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(-) create mode 100644 linux-core/i915_buffer.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index bf5221d1..e571f29e 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -19,7 +19,8 @@ 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 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 92868005..e7226f1f 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_uncached(struct drm_device *dev) { 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_cached(struct drm_device *dev) { 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 00000000..bedbd41c --- /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 + */ + +#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 56ac5fc7..64ab3f50 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -48,6 +48,12 @@ static drm_fence_driver_t i915_fence_driver = { .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 475ff474..403124c9 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 *dev); 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 a6535c8db4614376ce8ecb7d889b92db066a96cc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 10:44:09 +0200 Subject: [PATCH 012/147] Add a fence object class field for future use (For example VSYNC fence objects) --- 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(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6302db3a..a2a2e28c 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2237,18 +2237,21 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, 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 handle, drmFence *fence) 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 *fence, unsigned flush_type) 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 *fence) 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, unsigned emit_type) 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, unsigned flush_type, 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 0e037daa..78730785 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 fd, drmVBlankPtr vbl); /* 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 8f8f324e..5a4a37fc 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 fc27c576..cfcda2b2 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 * dev, uint32_t type, int emit, 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 b588b15c..cd2b1907 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 ca4e34e532e818921f7b2d36fc6886874b7f7924 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 11:19:53 +0200 Subject: [PATCH 013/147] ttm code cleanup. Fix the sleep-in-page-table-spinlock bug discovered by Dave Airlie --- linux-core/drmP.h | 3 +- linux-core/drm_ttm.c | 98 +++++++++++++++++++------------------------- linux-core/drm_ttm.h | 42 ++++++++++++++----- 3 files changed, 75 insertions(+), 68 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5a4a37fc..e42b5e55 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 b3ea7c9b..493f1465 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 * ttm, struct mm_struct *mm) } 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, struct mm_struct *mm) 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 * ttm, unsigned long page_offset, 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 * ttm, unsigned long page_offset, (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_device * dev, unsigned long size) 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_device * dev, unsigned long size) } 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_device * dev, unsigned long size) 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_t * 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_t * 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 * ttm, unsigned long page_offset, 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 * ttm, unsigned long page_offset, && 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 * ttm, unsigned long page_offset, } 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_backend_list_t * entry) 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 * ttm, unsigned long page_offset, } } - 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_backend_list_t * entry) 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_backend_list_t * entry) } 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 * dev, unsigned long start, int len, 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 * dev, unsigned long start, int len, } 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, unsigned size, drm_map_list_t ** maplist) 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, unsigned size, drm_map_list_t ** maplist) 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, unsigned size, drm_map_list_t ** maplist) 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 07592a84..f695fcce 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 + */ + #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 * 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)); From e201511a0fbeb177a9ecd7f77d177fc88c1616fb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 11:57:08 +0200 Subject: [PATCH 014/147] More ttm cleanups. --- 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(-) diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 493f1465..df4c312c 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, struct mm_struct *mm) 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_device * dev, unsigned long size) 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_device * dev, unsigned long size) ttm->lhandle = (unsigned long)ttm; ttm->dev = dev; + return ttm; } @@ -395,9 +398,9 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, 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_list_t * entry) 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_backend_list_t * entry) 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_list_t * region, 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_list_t * region, 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 f695fcce..ea9a8372 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 9f48f297..85b39490 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_area_struct *vma) { *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_area_struct *vma) 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_area_struct *vma) 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 4c03030b12bae28dad50d69bd271de632c43ff13 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 18:05:35 +0200 Subject: [PATCH 015/147] Checkpoint commit Buffer object code. --- linux-core/Makefile.kernel | 2 +- linux-core/drmP.h | 49 +++++++ linux-core/drm_bo.c | 282 +++++++++++++++++++++++++++++++++++++ linux-core/drm_fence.c | 11 +- linux-core/drm_ttm.c | 12 +- linux-core/drm_vm.c | 2 - shared-core/drm.h | 17 +++ 7 files changed, 362 insertions(+), 13 deletions(-) create mode 100644 linux-core/drm_bo.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index e571f29e..fba57ddf 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,7 +13,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.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_compat.o \ - drm_fence.o drm_ttm.o + drm_fence.o drm_ttm.o drm_bo.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 e42b5e55..3dd7e775 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -714,6 +714,18 @@ typedef struct drm_fence_manager{ uint32_t exe_flush_sequence; } drm_fence_manager_t; +typedef struct drm_buffer_manager{ + int initialized; + struct mutex bm_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; +} drm_buffer_manager_t; + + /** * DRM device structure. This structure represent a complete card that @@ -848,6 +860,7 @@ typedef struct drm_device { drm_head_t primary; /**< primary screen head */ drm_fence_manager_t fm; + drm_buffer_manager_t bm; } drm_device_t; @@ -973,6 +986,29 @@ typedef struct drm_fence_object{ } drm_fence_object_t; +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_backend_list_t *ttm_region; + + atomic_t mapped; + + uint32_t flags; + uint32_t mask; + uint32_t mask_hint; + + drm_mm_node_t *vram; + drm_mm_node_t *tt; + struct list_head head; + struct list_head ddestroy; + + uint32_t fence_flags; + drm_fence_object_t *fence; + int unfenced; + wait_queue_head_t validate_queue; +} drm_buffer_object_t; @@ -1296,6 +1332,19 @@ extern void drm_fence_handler(drm_device_t *dev, uint32_t breadcrumb, uint32_t t extern void drm_fence_manager_init(drm_device_t *dev); extern void drm_fence_manager_takedown(drm_device_t *dev); extern void drm_fence_flush_old(drm_device_t *dev, uint32_t sequence); +extern int drm_fence_object_flush(drm_device_t * dev, + drm_fence_object_t * fence, uint32_t type); +extern int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type); +extern void drm_fence_usage_deref_locked(drm_device_t * dev, + drm_fence_object_t * fence); +extern void drm_fence_usage_deref_unlocked(drm_device_t * dev, + drm_fence_object_t * fence); +extern int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, + drm_fence_object_t * fence); +extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, + int lazy, int ignore_signals, uint32_t mask); + + extern int drm_fence_ioctl(DRM_IOCTL_ARGS); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c new file mode 100644 index 00000000..d87cd2a1 --- /dev/null +++ b/linux-core/drm_bo.c @@ -0,0 +1,282 @@ +/************************************************************************** + * + * 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 + */ + +#include "drmP.h" + +int drm_fence_buffer_objects(drm_file_t *priv) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry, *next; + uint32_t fence_flags = 0; + int count = 0; + drm_fence_object_t *fence; + int ret; + + mutex_lock(&bm->bm_mutex); + + list_for_each_entry(entry, &bm->unfenced, head) { + BUG_ON(!entry->unfenced); + fence_flags |= entry->fence_flags; + count++; + } + + if (!count) { + mutex_unlock(&bm->bm_mutex); + return 0; + } + + fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + + if (!fence) { + 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); + mutex_unlock(&bm->bm_mutex); + return ret; + } + + list_for_each_entry_safe(entry, next, &bm->unfenced, head) { + BUG_ON(entry->fence); + entry->unfenced = 0; + entry->fence = fence; + list_del_init(&entry->head); + + if (!(entry->flags & DRM_BO_FLAG_NO_EVICT)) { + if (entry->flags & DRM_BO_FLAG_MEM_TT) { + list_add_tail(&entry->head, &bm->tt_lru); + } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { + list_add_tail(&entry->head, &bm->vram_lru); + } + } + } + + mutex_lock(&dev->struct_mutex); + atomic_add(count - 1, &fence->usage); + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&bm->bm_mutex); + return 0; +} + +/* + * bm locked, + * dev locked. + */ + + +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, + 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; + buf->flags &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_UNCACHED); + buf->flags |= DRM_BO_FLAG_MEM_LOCAL; + + return 0; +} + + +void destroy_buffer_object(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); + return; + } else { + drm_fence_usage_deref_locked(dev, bo->fence); + bo->fence = NULL; + } + } + + /* + * Take away from lru lists. + */ + + list_del_init(&bo->head); + + if (bo->tt) { + int ret; + ret = drm_move_tt_to_local(bo, 0); + BUG_ON(ret); + } + if (bo->vram) { + drm_mm_put_block(&bm->vram_manager, bo->vram); + bo->vram = NULL; + } + + /* + * FIXME: Destroy ttm. + */ + + drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); +} + +static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, + int init, uint32_t *n_flags) +{ + uint32_t new_flags; + uint32_t new_props; + + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { + + /* + * We need to move memory. Default preferences are hard-coded + * here. + */ + + new_flags = new_mask & DRM_BO_MASK_MEM; + + if (!new_flags) { + 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)) { + new_flags &= ~DRM_BO_FLAG_MEM_LOCAL; + } else { + new_flags = DRM_BO_FLAG_MEM_LOCAL; + } + } + if (new_flags & DRM_BO_FLAG_MEM_TT) { + if ((hint & DRM_BO_HINT_PREFER_VRAM) && + new_flags & DRM_BO_FLAG_MEM_VRAM) { + new_flags = DRM_BO_FLAG_MEM_VRAM; + } else { + new_flags = DRM_BO_FLAG_MEM_TT; + } + } + } else { + new_flags = flags & DRM_BO_MASK_MEM; + } + + new_props = new_mask & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_READ); + + if (!new_props) { + DRM_ERROR("Invalid buffer object rwx properties\n"); + return -EINVAL; + } + + new_flags |= new_mask & ~DRM_BO_MASK_MEM; + *n_flags = new_flags; + return 0; +} + + + +#if 0 + +static int drm_bo_evict(drm_device_t *dev, drm_buffer_object_t *buf, int tt); +{ + int ret; + if (tt) { + ret = drm_move_tt_to_local(buf); + } else { + ret = drm_move_vram_to_local(buf); + } + return ret; +} + +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; + drm_buffer_object_t *bo; + drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; + + lru = (tt) ? &bm->tt_lru : &bm->vram_lru; + + do { + node = drm_mm_search_free(mm, size, 0, 1); + if (node) + break; + + 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); + } + + drm_bo_evict(dev, bo, tt); + } while (1); + + if (!node) { + DRM_ERROR("Out of aperture space\n"); + return -ENOMEM; + } + + node = drm_mm_get_block(node, size, 0); + BUG_ON(!node); + node->private = (void *)buf; + + if (tt) { + buf->tt = node; + } else { + buf->vram = node; + } + return 0; +} +#endif + + + + diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index cfcda2b2..897f84c5 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -252,12 +252,17 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, } } +int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type) +{ + return ((fence->signaled & type) == type); +} + /* * Make sure old fence objects are signaled before their fence sequences are * wrapped around and reused. */ -static int drm_fence_object_flush(drm_device_t * dev, +int drm_fence_object_flush(drm_device_t * dev, drm_fence_object_t * fence, uint32_t type) { drm_fence_manager_t *fm = &dev->fm; @@ -317,8 +322,8 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) EXPORT_SYMBOL(drm_fence_flush_old); -static int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, - int lazy, int ignore_signals, uint32_t mask) +int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, + int lazy, int ignore_signals, uint32_t mask) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index df4c312c..806c109b 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -398,10 +398,6 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, struct page **cur_page; pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; - drm_ttm_lock_mm(ttm, 0, 1); - unmap_vma_pages(ttm, page_offset, num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); - for (i = 0; i < num_pages; ++i) { cur = page_offset + i; cur_page = ttm->pages + cur; @@ -446,7 +442,6 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) 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, 0, 1); } be->unbind(entry->be); @@ -489,6 +484,10 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) be->clear(entry->be); 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, + entry->num_pages); + drm_ttm_unlock_mm(ttm, 0, 1); drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0, 1); if (!ret) @@ -792,8 +791,7 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) return -ENOMEM; } - list->user_token = - (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; + list->user_token = list->hash.key; list->map = map; *maplist = list; diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 85b39490..9c2fbe08 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -703,8 +703,6 @@ static void drm_vm_ttm_close(struct vm_area_struct *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; int ret; diff --git a/shared-core/drm.h b/shared-core/drm.h index cd2b1907..bda565b3 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -655,6 +655,23 @@ typedef struct drm_fence_arg { } op; } drm_fence_arg_t; +#define DRM_BO_FLAG_READ 0x00000001 +#define DRM_BO_FLAG_WRITE 0x00000002 +#define DRM_BO_FLAG_EXE 0x00000004 +#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_UNCACHED 0x00000080 + + +#define DRM_BO_FLAG_MEM_TT 0x01000000 +#define DRM_BO_FLAG_MEM_VRAM 0x02000000 +#define DRM_BO_FLAG_MEM_LOCAL 0x04000000 +#define DRM_BO_MASK_MEM 0xFFFFFFFF + +#define DRM_BO_HINT_PREFER_VRAM 0x00000001 +#define DRM_BO_HINT_AVOID_LOCAL 0x00000002 /** * \name Ioctls Definitions From 1d3cf107d20cb11ad07667622785ef8341ab9c2a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 18:14:22 +0200 Subject: [PATCH 016/147] Module protection map access is moving into mainline kernels. Update drm_compat accordingly. (Reported by Dave Airlie) --- 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(-) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index cdef4b97..86bae306 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 *vma, #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 80928319..779a7000 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_struct *vma, * 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 9c2fbe08..b5003c97 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -48,7 +48,7 @@ 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); + 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_ttm_nopage(struct vm_area_struct *vma, 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 35c8ce6c2945ff09dc52dbc2a7382798ba64c1da Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 19:03:42 +0200 Subject: [PATCH 017/147] ttm and buffer objects ioctl stubs. --- linux-core/drmP.h | 6 ++++ linux-core/drm_bo.c | 32 ++++++++++++++++++ linux-core/drm_ttm.c | 5 +++ linux-core/drm_ttm.h | 2 ++ shared-core/drm.h | 77 ++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 120 insertions(+), 2 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 3dd7e775..9e1e4ba8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1347,6 +1347,12 @@ extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, extern int drm_fence_ioctl(DRM_IOCTL_ARGS); +/* + * buffer objects (drm_bo.c) + */ + +extern int drm_bo_ioctl(DRM_IOCTL_ARGS); + /* 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 d87cd2a1..6a677578 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -277,6 +277,38 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif +static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, void __user *data) +{ + return 0; +} + +int drm_bo_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_bo_arg_t arg; + unsigned long data_ptr; + (void) dev; + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + data_ptr = arg.data_lo; + + if (sizeof(data_ptr) > 4) { + int shift = 32; + data_ptr |= arg.data_hi << shift; + } + + switch(arg.op) { + case drm_op_bo: + return drm_do_bo_ioctl(priv, arg.num_requests, + (void __user *) data_ptr); + case drm_op_ttm: + return drm_ttm_ioctl(priv, arg.num_requests, + (drm_ttm_arg_t __user *) data_ptr); + } + + return 0; +} + diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 806c109b..46878a7d 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -798,3 +798,8 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) return 0; } + +int drm_ttm_ioctl(drm_file_t *priv, int num_requests, drm_ttm_arg_t __user *data) +{ + return 0; +} diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index ea9a8372..81006c3c 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -148,6 +148,8 @@ 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 int drm_ttm_ioctl(drm_file_t *priv, int num_requests, + drm_ttm_arg_t __user *data); #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 bda565b3..fb18b5c5 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -671,7 +671,80 @@ typedef struct drm_fence_arg { #define DRM_BO_MASK_MEM 0xFFFFFFFF #define DRM_BO_HINT_PREFER_VRAM 0x00000001 -#define DRM_BO_HINT_AVOID_LOCAL 0x00000002 +#define DRM_BO_HINT_AVOID_LOCAL 0x00000002 +#define DRM_BO_HINT_DONT_BLOCK 0x00000004 + +/* + * Multiplexing ioctl argument. + */ + +typedef struct drm_bo_arg { + unsigned num_requests; + enum { + drm_op_bo, + drm_op_ttm + } op; + unsigned data_lo; + unsigned data_hi; +} drm_bo_arg_t; + +typedef struct drm_ttm_arg { + enum { + drm_ttm_create, + drm_ttm_destroy, + drm_ttm_reference, + drm_ttm_unreference + } op; + unsigned handle; + unsigned size_lo; + unsigned size_hi; +}drm_ttm_arg_t; + + +typedef struct drm_bo_arg_request { + unsigned handle; /* User space handle */ + unsigned mask; + unsigned hint; + unsigned size_lo; + unsigned size_hi; + + enum { + drm_bo_type_ttm, + drm_bo_type_dc, + drm_bo_type_user + }type; + unsigned arg_handle; + unsigned user_pointer_lo; + unsigned user_pointer_hi; + enum { + drm_bo_create, + drm_bo_validate, + drm_bo_map, + drm_bo_fence, + drm_bo_destroy, + drm_bo_reference, + drm_bo_unreference + } op; +} drm_bo_arg_request_t; + +typedef struct drm_bo_arg_reply { + int ret; + unsigned handle; + unsigned flags; + unsigned size_lo; + unsigned size_hi; + unsigned offset_lo; + unsigned offset_hi; + unsigned arg_handle; + unsigned map_flags; +}drm_bo_arg_reply_t; + + +typedef union { + drm_bo_arg_request_t bo_req; + drm_bo_arg_reply_t bo_rep; +}drm_bo_arg_data; + /** * \name Ioctls Definitions @@ -739,7 +812,7 @@ typedef struct drm_fence_arg { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) - +#define DRM_IOCTL_BUFFER_OBJECT DRM_IOWR(0x3c, drm_buffer_arg_t) /*@}*/ From c488e25ceb421c6f84f110d786d9814ac4dba1b2 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 20:03:39 +0200 Subject: [PATCH 018/147] More ioctl stubs. Buffer object locking order documentation. --- linux-core/drm_bo.c | 63 +++++++++++++++++++++++++++++++++++++++----- linux-core/drm_ttm.c | 2 +- linux-core/drm_ttm.h | 3 +-- shared-core/drm.h | 8 +++--- 4 files changed, 63 insertions(+), 13 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 6a677578..847b0406 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -31,6 +31,30 @@ #include "drmP.h" +/* + * Buffer object locking policy: + * Lock dev->struct_mutex; + * Increase usage + * Unlock dev->struct_mutex; + * Lock buffer->mutex; + * Do whatever you want; + * Unlock buffer->mutex; + * Decrease usage. Call destruction if zero. + * + * User object visibility ups usage just once, since it has its own + * refcounting. + * + * Destruction: + * lock dev->struct_mutex; + * Verify that usage is zero. Otherwise unlock and continue. + * Destroy object. + * unlock dev->struct_mutex; + * + * Mutex and spinlock locking orders: + * 1.) Buffer mutex + * 2.) Refer to ttm locking orders. + */ + int drm_fence_buffer_objects(drm_file_t *priv) { drm_device_t *dev = priv->head->dev; @@ -277,11 +301,35 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif -static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, void __user *data) +static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, + drm_bo_arg_data_t __user *data) { - return 0; + drm_bo_arg_data_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t rep; + int i, ret; + + for (i=0; i Date: Sun, 27 Aug 2006 19:03:20 +0200 Subject: [PATCH 019/147] ttm create / destroy / ref / unref ioctl. --- linux-core/drmP.h | 207 +++++++++++++++++++++++-------------------- linux-core/drm_bo.c | 8 +- linux-core/drm_ttm.c | 138 ++++++++++++++++++++++++----- linux-core/drm_ttm.h | 10 ++- shared-core/drm.h | 4 + 5 files changed, 243 insertions(+), 124 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 9e1e4ba8..43589342 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -587,6 +587,64 @@ typedef struct drm_mm { drm_mm_node_t root_node; } drm_mm_t; + +/* + * 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, + drm_ttm_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; + + #include "drm_ttm.h" /* @@ -873,101 +931,6 @@ typedef struct drm_agp_ttm_priv { } drm_agp_ttm_priv; #endif - -static __inline__ int drm_core_check_feature(struct drm_device *dev, - int feature) -{ - return ((dev->driver->driver_features & feature) ? 1 : 0); -} - -#if __OS_HAS_AGP -static inline int drm_core_has_AGP(struct drm_device *dev) -{ - return drm_core_check_feature(dev, DRIVER_USE_AGP); -} -#else -#define drm_core_has_AGP(dev) (0) -#endif - -#if __OS_HAS_MTRR -static inline int drm_core_has_MTRR(struct drm_device *dev) -{ - return drm_core_check_feature(dev, DRIVER_USE_MTRR); -} - -#define DRM_MTRR_WC MTRR_TYPE_WRCOMB - -static inline int drm_mtrr_add(unsigned long offset, unsigned long size, - unsigned int flags) -{ - return mtrr_add(offset, size, flags, 1); -} - -static inline int drm_mtrr_del(int handle, unsigned long offset, - unsigned long size, unsigned int flags) -{ - return mtrr_del(handle, offset, size); -} - -#else -#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; - typedef struct drm_fence_object{ drm_user_object_t base; atomic_t usage; @@ -1012,6 +975,46 @@ typedef struct drm_buffer_object{ +static __inline__ int drm_core_check_feature(struct drm_device *dev, + int feature) +{ + return ((dev->driver->driver_features & feature) ? 1 : 0); +} + +#if __OS_HAS_AGP +static inline int drm_core_has_AGP(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_AGP); +} +#else +#define drm_core_has_AGP(dev) (0) +#endif + +#if __OS_HAS_MTRR +static inline int drm_core_has_MTRR(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_MTRR); +} + +#define DRM_MTRR_WC MTRR_TYPE_WRCOMB + +static inline int drm_mtrr_add(unsigned long offset, unsigned long size, + unsigned int flags) +{ + return mtrr_add(offset, size, flags, 1); +} + +static inline int drm_mtrr_del(int handle, unsigned long offset, + unsigned long size, unsigned int flags) +{ + return mtrr_del(handle, offset, size); +} + +#else +#define drm_core_has_MTRR(dev) (0) +#endif + + /******************************************************************/ /** \name Internal function definitions */ /*@{*/ @@ -1353,6 +1356,20 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); +/* + * Convenience 2*32-bit to 64-bit function + */ + +static __inline__ unsigned long combine_64(uint32_t lo, uint32_t hi) +{ + unsigned long ret = lo; + + if (sizeof(ret) > 4) { + int shift = 32; + lo |= (hi << shift); + } + 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 847b0406..35d4aba7 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -338,13 +338,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) (void) dev; DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - data_ptr = arg.data_lo; - - if (sizeof(data_ptr) > 4) { - int shift = 32; - data_ptr |= arg.data_hi << shift; - } - + data_ptr = combine_64(arg.data_lo, arg.data_hi); switch(arg.op) { case drm_op_bo: arg.num_requests = drm_do_bo_ioctl(priv, arg.num_requests, diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 05bae7de..293b1f8c 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,6 +42,7 @@ 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 @@ -275,6 +276,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); + ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -746,25 +748,80 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, return 0; } + /* - * Create a ttm and add it to the drm book-keeping. + * dev->struct_mutex locked. */ -int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) +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; + + if (list->user_token) + drm_ht_remove_item(&dev->map_hash, &list->hash); + + map = list->map; + + if (map) { + 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); + } + } else { + drm_free(map, sizeof(*map), DRM_MEM_TTM); + } + } + + drm_free(object, sizeof(*object), DRM_MEM_TTM); +} + +/* + * dev->struct_mutex locked. + */ +static void drm_ttm_user_object_remove(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); +} + + + +/* + * 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) +{ + drm_ttm_object_t *object; drm_map_list_t *list; drm_map_t *map; drm_ttm_t *ttm; - map = drm_alloc(sizeof(*map), DRM_MEM_TTM); - if (!map) + object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); + 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); + return -ENOMEM; + } + map = list->map; ttm = drm_init_ttm(dev, size); - if (!ttm) { DRM_ERROR("Could not create ttm\n"); - drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_ttm_object_remove(dev, object); return -ENOMEM; } @@ -772,34 +829,73 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; map->size = size; - - list = drm_calloc(1, sizeof(*list), DRM_MEM_TTM); - if (!list) { - drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_TTM); - return -ENOMEM; - } - map->handle = (void *)list; - + map->handle = (void *)object; + 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_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_TTM); - drm_free(list, sizeof(*list), DRM_MEM_TTM); + drm_ttm_object_remove(dev, object); return -ENOMEM; } list->user_token = list->hash.key; - list->map = map; - - *maplist = list; + 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); return 0; } + int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) { + drm_ttm_arg_t arg; + drm_device_t *dev = priv->head->dev; + drm_ttm_object_t *entry; + drm_user_object_t *uo; + unsigned long size; + int ret; + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + + switch(arg.op) { + case drm_ttm_create: + mutex_lock(&dev->struct_mutex); + size = combine_64(arg.size_lo, arg.size_hi); + ret = drm_ttm_object_create(dev, size, arg.flags, &entry); + if (ret) { + mutex_unlock(&dev->struct_mutex); + return ret; + } + ret = drm_add_user_object(priv, &entry->base, + arg.flags & DRM_TTM_FLAG_SHAREABLE); + if (ret) { + drm_ttm_object_remove(dev, entry); + mutex_unlock(&dev->struct_mutex); + return ret; + } + arg.handle = entry->base.hash.key; + arg.user_token = entry->map_list.user_token; + mutex_unlock(&dev->struct_mutex); + break; + case drm_ttm_reference: + return drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); + case drm_ttm_unreference: + return drm_user_object_unref(priv, arg.handle, drm_ttm_type); + case drm_ttm_destroy: + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, arg.handle); + if (!uo || (uo->type != drm_ttm_type) || uo->owner != priv) { + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + ret = drm_remove_user_object(priv, uo); + mutex_unlock(&dev->struct_mutex); + return ret; + } + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); return 0; } diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 5a7569ff..bad21c97 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -101,7 +101,15 @@ typedef struct drm_ttm { int destroy; } drm_ttm_t; -int drm_add_ttm(struct drm_device * dev, unsigned size, drm_map_list_t ** maplist); +typedef struct drm_ttm_object { + drm_user_object_t base; + atomic_t usage; + uint32_t flags; + drm_map_list_t map_list; +} drm_ttm_object_t; + + + /* * Bind a part of the ttm starting at page_offset size n_pages into the GTT, at diff --git a/shared-core/drm.h b/shared-core/drm.h index feadfc67..450864bc 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -688,6 +688,8 @@ typedef struct drm_bo_arg { unsigned data_hi; } drm_bo_arg_t; +#define DRM_TTM_FLAG_SHAREABLE 0x00000001 + typedef struct drm_ttm_arg { enum { drm_ttm_create, @@ -696,8 +698,10 @@ typedef struct drm_ttm_arg { drm_ttm_unreference } op; unsigned handle; + unsigned user_token; unsigned size_lo; unsigned size_hi; + unsigned flags; }drm_ttm_arg_t; From 4fa58aa15242333a635cb590762c6e6312945745 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 19:07:38 +0200 Subject: [PATCH 020/147] Add TTM map handle on reference. --- linux-core/drm_ttm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 293b1f8c..6e132745 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -882,7 +882,15 @@ int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) mutex_unlock(&dev->struct_mutex); break; case drm_ttm_reference: - return drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); + ret = drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); + 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); + arg.user_token = entry->map_list.user_token; + mutex_unlock(&dev->struct_mutex); + break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); case drm_ttm_destroy: From ac26b51503dfedf422d6ae49518adcf41dff1af3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 19:45:38 +0200 Subject: [PATCH 021/147] Have TTM create and reference ioctl call return the actual TTM size. --- linux-core/drmP.h | 19 ++++++++++++++----- linux-core/drm_ttm.c | 14 ++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 43589342..d7494c23 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1363,14 +1363,23 @@ extern int drm_bo_ioctl(DRM_IOCTL_ARGS); static __inline__ unsigned long combine_64(uint32_t lo, uint32_t hi) { unsigned long ret = lo; - - if (sizeof(ret) > 4) { - int shift = 32; - lo |= (hi << shift); - } +#if (BITS_PER_LONG == 64) + ret |= (hi << 32); +#endif return ret; } +static __inline__ void split_32(unsigned long val, uint32_t *lo, uint32_t *hi) +{ + *lo = val & 0xFFFFFFFFUL; +#if (BITS_PER_LONG == 64) + *hi = val >> 32; +#else + *hi = 0; +#endif +} + + /* 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_ttm.c b/linux-core/drm_ttm.c index 6e132745..ecf3e0ac 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -828,7 +828,7 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, map->offset = ttm->lhandle; map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; - map->size = size; + map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, @@ -877,9 +877,7 @@ int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) mutex_unlock(&dev->struct_mutex); return ret; } - arg.handle = entry->base.hash.key; - arg.user_token = entry->map_list.user_token; - mutex_unlock(&dev->struct_mutex); + atomic_inc(&entry->usage); break; case drm_ttm_reference: ret = drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); @@ -888,8 +886,6 @@ int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, arg.handle); entry = drm_user_object_entry(uo, drm_ttm_object_t, base); - arg.user_token = entry->map_list.user_token; - mutex_unlock(&dev->struct_mutex); break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); @@ -904,6 +900,12 @@ int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) mutex_unlock(&dev->struct_mutex); return ret; } + arg.handle = entry->base.hash.key; + arg.user_token = entry->map_list.user_token; + split_32(entry->map_list.map->size, &arg.size_lo, &arg.size_hi); + atomic_dec(&entry->usage); + mutex_unlock(&dev->struct_mutex); + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); return 0; } From b4b7b997605f88f3ffdcb0cc7cd1271e0cb24073 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 21:16:13 +0200 Subject: [PATCH 022/147] Remove the ioctl multiplexing, and instead allow for generic drm ioctls 0x80 - 0xFF. --- libdrm/xf86drm.c | 96 ++++++++++++++++++++++++++++++++++++++++++++ libdrm/xf86drm.h | 7 ++++ linux-core/drm_bo.c | 43 -------------------- linux-core/drm_drv.c | 18 ++++++--- linux-core/drm_ttm.c | 4 +- linux-core/drm_ttm.h | 2 +- shared-core/drm.h | 3 +- 7 files changed, 120 insertions(+), 53 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a2a2e28c..e666df3c 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2362,4 +2362,100 @@ int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, return 0; } +static unsigned long combine64(unsigned lo, unsigned hi) +{ + unsigned long ret = lo; + if (sizeof(ret) == 8) { + int shift = 32; + ret |= (hi << shift); + } + return ret; +} +static void split32(unsigned long val, unsigned *lo, unsigned *hi) +{ + *lo = val & 0xFFFFFFFFUL; + if (sizeof(val) == 8) { + int shift = 32; + *hi = val >> shift; + } else { + *hi = 0; + } +} + +int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) +{ + drm_ttm_arg_t argTTM; + drm_bo_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); + + 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); + return 0; +} + +int drmTTMDestroy(int fd, const drmTTM *ttm) +{ + drm_ttm_arg_t argTTM; + drm_bo_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; + if (ioctl(fd, DRM_IOCTL_TTM, &arg)) + return -errno; + return 0; +} + + +int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) +{ + drm_ttm_arg_t argTTM; + drm_bo_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; + 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); + return 0; +} + +int drmTTMUnreference(int fd, const drmTTM *ttm) +{ + drm_ttm_arg_t argTTM; + drm_bo_arg_t arg; + + argTTM.op = drm_ttm_destroy; + argTTM.handle = ttm->handle; + if (ioctl(fd, DRM_IOCTL_TTM, &arg)) + return -errno; + return 0; +} + +drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm) +{ + (void) fd; + return ttm->user_token; +} diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 78730785..92cef4c0 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -287,6 +287,13 @@ typedef struct _drmFence{ unsigned signaled; } drmFence; +typedef struct _drmTTM{ + unsigned handle; + drm_handle_t user_token; + unsigned flags; + unsigned long size; +} drmTTM; + #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) #define DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 35d4aba7..5eb09839 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -301,34 +301,6 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif -static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, - drm_bo_arg_data_t __user *data) -{ - drm_bo_arg_data_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t rep; - int i, ret; - - for (i=0; ipid, cmd, nr, (long)old_encode_dev(priv->head->device), priv->authenticated); - if (nr < DRIVER_IOCTL_COUNT) - ioctl = &drm_ioctls[nr]; - else if ((nr >= DRM_COMMAND_BASE) - && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) - ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; - else + if (nr >= DRIVER_IOCTL_COUNT && + (nr < DRM_COMMAND_BASE || nr >= DRM_COMMAND_END)) goto err_i1; + if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) + && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) + ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; + else if (nr >= DRM_COMMAND_END || nr < DRM_COMMAND_BASE) + ioctl = &drm_ioctls[nr]; + else + goto err_i1; + + func = ioctl->func; if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl) /* Local override? */ diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index ecf3e0ac..950b0d4d 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -850,10 +850,10 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, } -int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) +int drm_ttm_ioctl(DRM_IOCTL_ARGS) { + DRM_DEVICE; drm_ttm_arg_t arg; - drm_device_t *dev = priv->head->dev; drm_ttm_object_t *entry; drm_user_object_t *uo; unsigned long size; diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index bad21c97..6ebb1aa2 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -156,7 +156,7 @@ 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 int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data); +extern int drm_ttm_ioctl(DRM_IOCTL_ARGS); #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 450864bc..726a5140 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -816,7 +816,7 @@ typedef union drm_bo_arg_data { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) -#define DRM_IOCTL_BUFFER_OBJECT DRM_IOWR(0x3c, drm_buffer_arg_t) +#define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) /*@}*/ @@ -828,5 +828,6 @@ typedef union drm_bo_arg_data { * drmCommandReadWrite(). */ #define DRM_COMMAND_BASE 0x40 +#define DRM_COMMAND_END 0x80 #endif From 928bdc6c1c9cd1e60f0b070533768aaca56c84d8 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 21:21:06 +0200 Subject: [PATCH 023/147] Initialize i915 saved flush flags. --- shared-core/i915_dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index d6bb6c8e..8ef9d8e1 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -195,7 +195,9 @@ static int i915_initialize(drm_device_t * dev, 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 886d3b3061cdf53f5a353cbaac843f63104d2658 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 22:01:33 +0200 Subject: [PATCH 024/147] Bugfixes. --- libdrm/xf86drm.c | 57 ++++++++++++++++---------------------------- libdrm/xf86drm.h | 7 ++++++ linux-core/drm_ttm.c | 1 + 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index e666df3c..88676083 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2385,37 +2385,28 @@ static void split32(unsigned long val, unsigned *lo, unsigned *hi) 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 *ttm) 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 92cef4c0..433191b4 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -623,6 +623,13 @@ extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, 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 950b0d4d..ad7b279e 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 *dev, unsigned long size, object->base.unref = NULL; atomic_set(&object->usage, 1); + *ttm_object = object; return 0; } From e181f594a4a75790ce1d2a8e907f9fcc5e88b419 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 09:49:09 +0200 Subject: [PATCH 025/147] Add a 64-bit drm unsigned type for 64-bit clean IOCTLS. Conversion functions in drmP.h and xf86drm.c. --- libdrm/xf86drm.c | 22 +++++++------- libdrm/xf86drm.h | 2 ++ linux-core/drmP.h | 19 +++++++----- linux-core/drm_ttm.c | 4 +-- shared-core/drm.h | 69 +++++++++++++++++++------------------------- 5 files changed, 56 insertions(+), 60 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 88676083..06c64303 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2362,25 +2362,27 @@ int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, return 0; } -static unsigned long combine64(unsigned lo, unsigned hi) +static unsigned long drmUL(drm_u64_t val) { - unsigned long ret = lo; + unsigned long ret = val.lo; if (sizeof(ret) == 8) { int shift = 32; - ret |= (hi << shift); + ret |= (val.hi << shift); } return ret; } -static void split32(unsigned long val, unsigned *lo, unsigned *hi) +static drm_u64_t drmU64(unsigned long val) { - *lo = val & 0xFFFFFFFFUL; + drm_u64_t ret; + ret.lo = val & 0xFFFFFFFFUL; if (sizeof(val) == 8) { int shift = 32; - *hi = val >> shift; + ret.hi = val >> shift; } else { - *hi = 0; + ret.hi = 0; } + return ret; } int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) @@ -2389,7 +2391,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) arg.op = drm_ttm_create; arg.flags = flags; - split32((unsigned long) size, &arg.size_lo, &arg.size_hi); + arg.size = drmU64(size); if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; @@ -2397,7 +2399,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) 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); + ttm->size = drmUL(arg.size); return 0; } @@ -2424,7 +2426,7 @@ int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) 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); + ttm->size = drmUL(arg.size); return 0; } diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 433191b4..58cbd16c 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -497,6 +497,8 @@ do { register unsigned int __old __asm("o0"); \ } \ } while(0) + + /* General user-level programmer's API: unprivileged */ extern int drmAvailable(void); extern int drmOpen(const char *name, const char *busid); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 2997293b..81f08dfc 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1359,26 +1359,29 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); /* - * Convenience 2*32-bit to 64-bit function + * Convenience drm_u64_t functions */ -static __inline__ unsigned long combine_64(uint32_t lo, uint32_t hi) +static __inline__ unsigned long drm_ul(drm_u64_t val) { - unsigned long ret = lo; + unsigned long ret = val.lo; #if (BITS_PER_LONG == 64) - ret |= (hi << 32); + ret |= (val.hi << 32); #endif return ret; } -static __inline__ void split_32(unsigned long val, uint32_t *lo, uint32_t *hi) +static __inline__ drm_u64_t drm_u64(unsigned long val) { - *lo = val & 0xFFFFFFFFUL; + drm_u64_t ret; + + ret.lo = val & 0xFFFFFFFFUL; #if (BITS_PER_LONG == 64) - *hi = val >> 32; + ret.hi = val >> 32; #else - *hi = 0; + ret.hi = 0; #endif + return ret; } diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index ad7b279e..e76b41fb 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -865,7 +865,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) switch(arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); - size = combine_64(arg.size_lo, arg.size_hi); + size = drm_ul(arg.size); ret = drm_ttm_object_create(dev, size, arg.flags, &entry); if (ret) { mutex_unlock(&dev->struct_mutex); @@ -903,7 +903,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) } arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; - split_32(entry->map_list.map->size, &arg.size_lo, &arg.size_hi); + arg.size = drm_u64(entry->map_list.map->size); atomic_dec(&entry->usage); mutex_unlock(&dev->struct_mutex); diff --git a/shared-core/drm.h b/shared-core/drm.h index 726a5140..7133eb8f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -630,6 +630,11 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; +typedef struct drm_u64{ + unsigned lo; + unsigned hi; +}drm_u64_t; + #define DRM_FENCE_FLAG_EMIT 0x00000001 #define DRM_FENCE_FLAG_SHAREABLE 0x00000002 #define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 @@ -655,6 +660,22 @@ typedef struct drm_fence_arg { } op; } drm_fence_arg_t; +#define DRM_TTM_FLAG_SHAREABLE 0x00000001 + +typedef struct drm_ttm_arg { + enum { + drm_ttm_create, + drm_ttm_destroy, + drm_ttm_reference, + drm_ttm_unreference + } op; + unsigned handle; + unsigned user_token; + drm_u64_t size; + unsigned flags; +}drm_ttm_arg_t; + + #define DRM_BO_FLAG_READ 0x00000001 #define DRM_BO_FLAG_WRITE 0x00000002 #define DRM_BO_FLAG_EXE 0x00000004 @@ -674,43 +695,12 @@ typedef struct drm_fence_arg { #define DRM_BO_HINT_AVOID_LOCAL 0x00000002 #define DRM_BO_HINT_DONT_BLOCK 0x00000004 -/* - * Multiplexing ioctl argument. - */ - -typedef struct drm_bo_arg { - unsigned num_requests; - enum { - drm_op_bo, - drm_op_ttm - } op; - unsigned data_lo; - unsigned data_hi; -} drm_bo_arg_t; - -#define DRM_TTM_FLAG_SHAREABLE 0x00000001 - -typedef struct drm_ttm_arg { - enum { - drm_ttm_create, - drm_ttm_destroy, - drm_ttm_reference, - drm_ttm_unreference - } op; - unsigned handle; - unsigned user_token; - unsigned size_lo; - unsigned size_hi; - unsigned flags; -}drm_ttm_arg_t; - typedef struct drm_bo_arg_request { unsigned handle; /* User space handle */ unsigned mask; unsigned hint; - unsigned size_lo; - unsigned size_hi; + drm_u64_t size; enum { drm_bo_type_ttm, @@ -718,8 +708,8 @@ typedef struct drm_bo_arg_request { drm_bo_type_user }type; unsigned arg_handle; - unsigned user_pointer_lo; - unsigned user_pointer_hi; + drm_u64_t user_pointer; + drm_u64_t next; enum { drm_bo_create, drm_bo_validate, @@ -733,21 +723,20 @@ typedef struct drm_bo_arg_request { typedef struct drm_bo_arg_reply { int ret; + int handled; unsigned handle; unsigned flags; - unsigned size_lo; - unsigned size_hi; - unsigned offset_lo; - unsigned offset_hi; + drm_u64_t size; + drm_u64_t offset; unsigned arg_handle; unsigned map_flags; }drm_bo_arg_reply_t; -typedef union drm_bo_arg_data { +typedef union drm_bo_arg{ drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; -} drm_bo_arg_data_t; +} drm_bo_arg_t; /** From 480ea65ee4b02fa21d1ddf3bea09ac23085618cc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 10:58:21 +0200 Subject: [PATCH 026/147] Checkpoint buffer object IOCTL stub. --- linux-core/drm_bo.c | 50 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 5eb09839..9661b70f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -306,9 +306,55 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_bo_arg_t arg; - unsigned long data_ptr; - (void) dev; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t rep; + unsigned long next; + drm_user_object_t *uo; + drm_buffer_object_t *entry; + + do { + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + rep.ret = 0; + rep.handled = 0; + switch (req->op) { + 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) { + mutex_unlock(&dev->struct_mutex); + rep.ret = -EINVAL; + break; + } + 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, + 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); + atomic_dec(&entry->usage); + mutex_unlock(&dev->struct_mutex); + break; + case drm_bo_unreference: + rep.ret = drm_user_object_unref(priv, req->handle, + drm_buffer_type); + break; + default: + rep.ret = -EINVAL; + } + next = drm_ul(req->next); + rep.handled = 1; + arg.rep = rep; + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); + data = next; + + } while (data); return 0; + } From 05536a64785223ee8c57556300a14ba9c89837ae Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 13:51:39 +0200 Subject: [PATCH 027/147] Buffer object idle and mapping synchronization. --- linux-core/drmP.h | 1 + linux-core/drm_bo.c | 147 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 81f08dfc..f83b4b4b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -967,6 +967,7 @@ typedef struct drm_buffer_object{ drm_fence_object_t *fence; int unfenced; wait_queue_head_t validate_queue; + struct mutex mutex; } drm_buffer_object_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 9661b70f..0aa0b138 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -302,6 +302,148 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) #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_user_object_t *uo; + drm_buffer_object_t *bo; + + uo = drm_lookup_user_object(priv, handle); + + if (!uo || (uo->type != drm_buffer_type)) + return NULL; + + if (check_owner && priv != uo->owner) { + if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) + return NULL; + } + + bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + 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) +{ + + drm_fence_object_t *fence = bo->fence; + int ret; + + if (fence) { + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + + /* + * Make sure another process doesn't destroy the fence + * object when we release the buffer object mutex. + * We don't need to take the dev->struct_mutex lock here, + * since the fence usage count is at least 1 already. + */ + + atomic_inc(&fence->usage); + mutex_unlock(&bo->mutex); + ret = drm_fence_object_wait(dev, fence, lazy, !lazy, bo->fence_flags); + mutex_lock(&bo->mutex); + if (ret) + return ret; + mutex_lock(&dev->struct_mutex); + drm_fence_usage_deref_locked(dev, fence); + if (bo->fence == fence) { + drm_fence_usage_deref_locked(dev, fence); + bo->fence = NULL; + } + mutex_unlock(&dev->struct_mutex); + } + return 0; +} + +/* + * Call bo->mutex locked. + * 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) +{ + drm_fence_object_t *fence = bo->fence; + + if (fence) { + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + drm_fence_object_flush(dev, fence, DRM_FENCE_EXE); + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + return 1; + } + return 0; +} + + +/* + * Wait for buffer idle and register that we've mapped the buffer. + */ + + +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); + + if (!bo) + return -EINVAL; + + mutex_lock(&bo->mutex); + + if (!wait) { + if ((atomic_read(&bo->mapped) == 0) && + drm_bo_busy(dev, bo)) { + mutex_unlock(&bo->mutex); + return -EBUSY; + } + } else { + ret = drm_bo_wait(dev, bo, 0); + if (ret) { + mutex_unlock(&bo->mutex); + return -EBUSY; + } + } + mutex_lock(&dev->struct_mutex); + ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); + mutex_unlock(&dev->struct_mutex); + if (!ret) { + atomic_inc(&bo->mapped); + } + mutex_unlock(&bo->mutex); + + return ret; +} + + + + int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -317,6 +459,11 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { + case drm_bo_map: + 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); From 0d67356de4e0c9e0d068ea9c16cf33df4fd13776 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 16:36:37 +0200 Subject: [PATCH 028/147] Proper TTM dereferencing Initial buffer object creation. --- 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(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f83b4b4b..07f3571b 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 0aa0b138..affee135 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_buffer_object_t *buf, int lazy) } -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 *dev, drm_buffer_object_t *bo) 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, drm_buffer_object_t *bo) /* * 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_file_t *priv, uint32_t handle, int wait) 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_file_t *priv, uint32_t handle, int wait) } 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 e76b41fb..cda3ec29 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, unsigned long start, int len, /* * 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_device_t *dev, drm_ttm_object_t *object) 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 *dev, unsigned long size, } 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 6ebb1aa2..a87cf53e 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 7133eb8f..14b1741f 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 205740647060bc3bdec2b4402a666eb1015932ff Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 17:51:53 +0200 Subject: [PATCH 029/147] Buffer object creation. --- linux-core/drm_bo.c | 46 ++++++++++++++++++++++++++++++++++++++++++--- shared-core/drm.h | 4 ++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index affee135..7f5088fb 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -507,11 +507,14 @@ static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) * 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 *priv, 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 *priv, 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 *priv, 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 14b1741f..d03eebcb 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 279e8d26c6cf7347aa9cb6d50d025a41dff9a5be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 10:45:34 +0200 Subject: [PATCH 030/147] =?UTF-8?q?64-bit=20IOCTL=20integer=20(Michel=20D?= =?UTF-8?q?=E4nzer=20&=20Brian=20Paul)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 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(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 06c64303..3731ee12 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2237,6 +2237,8 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, 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, unsigned flush_type, 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, unsigned long size, unsigned flags) 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 handle, drmTTM *ttm) 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, const drmTTM *ttm) (void) fd; return ttm->user_token; } +#endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 07f3571b..af082ad7 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_ARGS); 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 7f5088fb..23634955 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -531,6 +531,7 @@ 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, @@ -544,6 +545,7 @@ int drm_buffer_object_create(drm_file_t *priv, 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 *priv, 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 cda3ec29..8cd0af61 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 a87cf53e..ba4261bf 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_ttm_t * ttm, struct mm_struct *mm); 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 d03eebcb..f8479dd0 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 0dedfc2cd03f50b435476e56637b333d345fddbd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 14:52:02 +0200 Subject: [PATCH 031/147] Checkpoint ttm addition to buffer objects. --- 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(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index af082ad7..81b7a1b6 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 23634955..30656060 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_buffer_object_t *buf, int lazy) 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(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 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 *priv, 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 *priv, 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 8cd0af61..e111070e 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -784,6 +784,16 @@ void drm_ttm_object_deref_locked(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); + 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 ba4261bf..a1810509 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 f8479dd0..e50ebfe2 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 23f01c9fe8e6170459fe46ad5fc9757bbe967d96 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 18:40:08 +0200 Subject: [PATCH 032/147] Checkpoint commit. Buffer object flags and IOCTL argument list. --- 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(-) create mode 100644 libdrm/xf86mm.h diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3731ee12..6de6c06f 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, unsigned long size, unsigned flags) 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, const drmTTM *ttm) (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 00000000..5fb78723 --- /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 + + +/* + * 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 81b7a1b6..4d490abe 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 30656060..55901660 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_file_t *priv, drm_user_object_t *uo) } -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 flags, uint32_t new_mask, uint32_t hint, } 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(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 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 *priv, drm_buffer_object_t *bo, uint32_t ne 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 *priv, 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 e111070e..65d40344 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_backend_list_t * entry) 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_device_t *dev, drm_ttm_object_t *to) */ 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 64ab3f50..bc78dc2e 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -49,7 +49,8 @@ static drm_fence_driver_t i915_fence_driver = { }; 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 46a2a728..452d4ee8 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -86,6 +86,8 @@ static void i915_perform_flush(drm_device_t * dev) 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 e50ebfe2..5888c9be 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 8ef9d8e1..e661269b 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -195,9 +195,6 @@ static int i915_initialize(drm_device_t * dev, 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 08d3140b..4195555e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -275,6 +275,12 @@ void i915_driver_irq_postinstall(drm_device_t * 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 de144ba23c1245cf021a63cc739c7c9903568272 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 21:57:37 +0200 Subject: [PATCH 033/147] Part of buffer object libdrm interface. --- libdrm/xf86drm.c | 189 ++++++++++++++++++++++++++++++++++++++++------ libdrm/xf86drm.h | 2 + libdrm/xf86mm.h | 37 ++++++--- shared-core/drm.h | 4 + 4 files changed, 196 insertions(+), 36 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6de6c06f..3fccdf69 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2381,6 +2381,8 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) 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, const drmTTM *ttm) 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 *list) 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 *list, DrmBuf *item, drm_bo_arg_t *arg) 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, DrmBufList *list) * 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(DrmBufList *list) 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 58cbd16c..ca48bfbf 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 5fb78723..08149d08 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -29,7 +29,7 @@ #ifndef _XF86MM_H_ #define _XF86MM_H_ #include - +#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; + 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 _DrmBufNode { - DrmMMListHead head; - DrmBuf *buf; +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 5888c9be..c65ecc00 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 033bda07e9a4eab5058fb919b375deb57b08b5be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 09:57:35 +0200 Subject: [PATCH 034/147] Buffer object reply fill in. Lindent of drm_bo.c drm_ttm.c --- 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(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4d490abe..63bcde2e 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 55901660..24389447 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 *priv) 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 *priv) 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 *priv) * 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_buffer_object_t *buf, int lazy) 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_device_t *dev, drm_buffer_object_t *bo) 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_device_t *dev, drm_buffer_object_t *bo) } } -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_driver_t *driver, 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_driver_t *driver, } 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_driver_t *driver, 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_driver_t *driver, *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 *dev, drm_buffer_object_t *buf, int tt); } 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, int tt, drm_buffer_object_t *buf) 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, int tt, drm_buffer_object_t *buf) 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_object(drm_file_t *priv, uint32_t handle, 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, drm_buffer_object_t *bo, int lazy) 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, drm_buffer_object_t *bo, int lazy) bo->fence = NULL; } mutex_unlock(&dev->struct_mutex); - } + } return 0; } @@ -419,7 +418,7 @@ static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) * 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, drm_buffer_object_t *bo) } 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, drm_buffer_object_t *bo) * 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_file_t *priv, uint32_t handle, int wait) 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_file_t *priv, uint32_t handle, int wait) 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_file_t *priv, uint32_t handle) 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(drm_file_t *priv, drm_user_object_t *uo } } -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 *priv, drm_buffer_object_t *bo, uint32_t hi 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 *priv, drm_buffer_object_t *bo, uint32_t hi 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 *priv, drm_buffer_object_t *bo, uint32_t hi } 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 *priv, 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 *priv, 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_file_t *priv, drm_buffer_object_t *bo, 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 65d40344..33567d9b 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_t * 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_backend_list_t * entry) 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 * ttm, unsigned long page_offset, 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 * dev, unsigned long start, int len, 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_device_t *dev, drm_ttm_object_t *object) 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_device_t *dev, drm_ttm_object_t *object) 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_device_t *dev, drm_ttm_object_t *to) } } - /* * 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 *dev, unsigned long size, 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 *dev, unsigned long size, 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 *dev, unsigned long size, 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(drm_file_t *priv, uint32_t handle, 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(drm_file_t *priv, uint32_t handle, 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 a1810509..d647578c 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,18 +107,18 @@ 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, + +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 * aperture offset aper_offset. The region handle will be used to reference this @@ -166,7 +166,7 @@ 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 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 c65ecc00..f6abfeb9 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 e47a4fda2ef7aada45b7799ad20e8012102dc12e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 13:04:08 +0200 Subject: [PATCH 035/147] Memory manager init and takedown. --- 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(-) diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index b12e87fa..91a7e5dc 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 3fccdf69..c9005c41 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, unsigned long start, unsigned long size, 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 ca48bfbf..f257deda 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -670,4 +670,6 @@ extern int drmSLLookupNeighbors(void *l, unsigned long key, 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 08149d08..8711a144 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -29,7 +29,7 @@ #ifndef _XF86MM_H_ #define _XF86MM_H_ #include -#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 63bcde2e..59926968 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_ARGS); */ 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 24389447..5f557d55 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 * priv) 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 * priv) } 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 * priv) 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_device_t * dev, drm_buffer_object_t * bo) 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_object(drm_file_t * priv, 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(drm_file_t * priv, } } -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 * priv, drm_buffer_object_t * bo, 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 * priv, 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 f27a7aff..62df6803 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 f6abfeb9..f900dd51 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 14a835be616183e733a2d6a7dcc697b8a6f46caf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 15:08:40 +0200 Subject: [PATCH 036/147] Buffer object mapping and mapping synchronization for multiple clients. --- libdrm/xf86drm.c | 103 ++++++++++++++++++++++++++++++++++++---- libdrm/xf86mm.h | 8 ++-- linux-core/drm_bo.c | 3 ++ linux-core/drm_object.c | 4 +- linux-core/drm_vm.c | 1 + 5 files changed, 104 insertions(+), 15 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index c9005c41..f592ff2a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2606,10 +2606,10 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, 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->mapHandle = rep->arg_handle; + buf->mapFlags = rep->map_flags; + buf->mapVirtual = NULL; + buf->mapCount = 0; buf->virtual = NULL; buf->mask = rep->mask; buf->hint = rep->hint; @@ -2666,13 +2666,14 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) 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->mapHandle = rep->arg_handle; + buf->mapFlags = rep->map_flags; + buf->mapVirtual = NULL; + buf->mapCount = 0; buf->virtual = NULL; buf->mask = rep->mask; buf->hint = rep->hint; + buf->start = rep->buffer_start; return 0; } @@ -2699,6 +2700,92 @@ int drmBOUnReference(int fd, drmBO *buf) return 0; } +/* + * + */ + +int drmBOMap(int fd, drmBO *buf, unsigned map_flags, void **address) +{ + + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + int ret = 0; + + /* + * Make sure we have a virtual address of the buffer. + */ + + if (!buf->mapVirtual) { + if (buf->mapCount == 0) { + drmAddress virtual; + ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); + if (ret) + return ret; + ++buf->mapCount; + buf->mapVirtual = virtual; + buf->virtual = ((char *) virtual) + buf->start; + fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", + buf->mapVirtual, buf->virtual); + } + } + + req->handle = buf->handle; + req->mask = map_flags; + req->op = drm_bo_map; + req->next = 0; + + /* + * May hang if the buffer object is busy. + * This IOCTL synchronizes the buffer. + */ + + do { + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret != 0 && errno == EAGAIN); + + if (ret || !rep->handled || rep->ret) { + if (--buf->mapCount == 0) { + (void )drmUnmap(buf->mapVirtual, buf->start + buf->size); + } + } + if (ret) + return ret; + if (!rep->handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + + *address = buf->virtual; + + return 0; +} + +int drmBOUnmap(int fd, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + + if (buf->mapCount == 0) { + return -EINVAL; + } + + if (--buf->mapCount == 0) { + (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); + } + + req->handle = buf->handle; + req->op = drm_bo_unmap; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) { + return -errno; + } + + 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 8711a144..c811892f 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -85,17 +85,17 @@ typedef struct _drmMMListHead typedef struct _drmBO{ drm_bo_type_t type; unsigned handle; - drm_handle_t map_handle; + drm_handle_t mapHandle; unsigned flags; unsigned mask; unsigned hint; - unsigned map_flags; + unsigned mapFlags; unsigned long size; unsigned long offset; unsigned long start; void *virtual; - void *map_virtual; - int map_count; + void *mapVirtual; + int mapCount; drmTTM *ttm; } drmBO; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 5f557d55..aa59238f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -513,8 +513,11 @@ static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) goto out; } + DRM_ERROR("Removing ref object\n"); drm_remove_ref_object(priv, ro); + DRM_ERROR("Deregistering usage\n"); drm_bo_usage_deref_locked(dev, bo); + DRM_ERROR("Done\n"); out: mutex_unlock(&dev->struct_mutex); return ret; diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c index b928c01e..e1b79101 100644 --- a/linux-core/drm_object.c +++ b/linux-core/drm_object.c @@ -108,9 +108,6 @@ static int drm_object_ref_action(drm_file_t * priv, drm_user_object_t * ro, 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); @@ -164,6 +161,7 @@ int drm_add_ref_object(drm_file_t * priv, drm_user_object_t * referenced_object, atomic_set(&item->refcount, 1); item->hash.key = (unsigned long)referenced_object; ret = drm_ht_insert_item(ht, &item->hash); + item->unref_action = ref_action; if (ret) goto out; diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 7163341d..69391058 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -713,6 +713,7 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma) dev = ttm->dev; mutex_lock(&dev->struct_mutex); drm_ttm_delete_mm(ttm, vma->vm_mm); + list_del(&ttm_vma->head); drm_free(ttm_vma, sizeof(*ttm_vma), DRM_MEM_VMAS); if (atomic_dec_and_test(&ttm->vma_count)) { if (ttm->destroy) { From ff95ea5536d70f9bc8eac12f2c97dae71fb97066 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 15:11:50 +0200 Subject: [PATCH 037/147] Add missing map flags. --- libdrm/xf86drm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index f592ff2a..6ffc4b39 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2704,7 +2704,7 @@ int drmBOUnReference(int fd, drmBO *buf) * */ -int drmBOMap(int fd, drmBO *buf, unsigned map_flags, void **address) +int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, void **address) { drm_bo_arg_t arg; @@ -2731,7 +2731,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned map_flags, void **address) } req->handle = buf->handle; - req->mask = map_flags; + req->hint = mapFlags; req->op = drm_bo_map; req->next = 0; @@ -2756,6 +2756,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned map_flags, void **address) if (rep->ret) return rep->ret; + buf->mapFlags = mapFlags; *address = buf->virtual; return 0; From d39055174b5a487f0d848e1af4c3459fb4261bf1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 17:40:07 +0200 Subject: [PATCH 038/147] Remove the buffer object hint field and use it only as an argument. Validate stub. --- libdrm/xf86drm.c | 2 - libdrm/xf86mm.h | 1 - linux-core/drmP.h | 1 - linux-core/drm_bo.c | 107 +++++++++++++++++++++++++++++++++++++------ linux-core/drm_drv.c | 2 +- shared-core/drm.h | 33 ++++++++++--- 6 files changed, 120 insertions(+), 26 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6ffc4b39..1763b89a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2612,7 +2612,6 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, buf->mapCount = 0; buf->virtual = NULL; buf->mask = rep->mask; - buf->hint = rep->hint; buf->start = rep->buffer_start; return 0; @@ -2672,7 +2671,6 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) buf->mapCount = 0; buf->virtual = NULL; buf->mask = rep->mask; - buf->hint = rep->hint; buf->start = rep->buffer_start; return 0; } diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index c811892f..21fed6cf 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -88,7 +88,6 @@ typedef struct _drmBO{ drm_handle_t mapHandle; unsigned flags; unsigned mask; - unsigned hint; unsigned mapFlags; unsigned long size; unsigned long offset; diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 59926968..6cce6b8d 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -963,7 +963,6 @@ typedef struct drm_buffer_object{ uint32_t map_flags; uint32_t flags; uint32_t mask; - 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 aa59238f..057de9a0 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -55,6 +55,17 @@ * 2.) Refer to ttm locking orders. */ + +#define DRM_FLAG_MASKED(_old, _new, _mask) {\ +(_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) { drm_device_t *dev = priv->head->dev; @@ -243,7 +254,7 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, } } if (new_flags & DRM_BO_FLAG_MEM_TT) { - if ((hint & DRM_BO_HINT_PREFER_VRAM) && + if ((new_mask & DRM_BO_FLAG_PREFER_VRAM) && new_flags & DRM_BO_FLAG_MEM_VRAM) { new_flags = DRM_BO_FLAG_MEM_VRAM; } else { @@ -264,7 +275,7 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, new_flags |= new_mask & ~DRM_BO_MASK_MEM; - if (hint & DRM_BO_HINT_BIND_CACHED) { + 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) @@ -513,11 +524,8 @@ static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) goto out; } - DRM_ERROR("Removing ref object\n"); drm_remove_ref_object(priv, ro); - DRM_ERROR("Deregistering usage\n"); drm_bo_usage_deref_locked(dev, bo); - DRM_ERROR("Done\n"); out: mutex_unlock(&dev->struct_mutex); return ret; @@ -548,19 +556,91 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, } } -static int drm_buffer_object_validate(drm_device_t * dev, uint32_t new_flags, - drm_buffer_object_t * bo) +static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, + int no_wait) { - bo->flags = new_flags; return 0; } + +/* + * bo locked. + */ + + +static int drm_buffer_object_validate(drm_buffer_object_t * bo, + uint32_t new_flags, + int move_unfenced, + int no_wait) +{ + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + uint32_t flag_diff = (new_flags ^ bo->flags); + + int ret; + + if (new_flags & DRM_BO_FLAG_MEM_VRAM) { + DRM_ERROR("Vram support not implemented yet\n"); + return -EINVAL; + } + if ((new_flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM)) && + (new_flags & DRM_BO_FLAG_CACHED)) { + DRM_ERROR("Cached binding not implemented yet\n"); + return -EINVAL; + } + + /* + * Check whether we need to move buffer. + */ + + if (flag_diff & DRM_BO_MASK_MEM) { + mutex_lock(&bm->mutex); + ret = drm_bo_move_buffer(bo, new_flags, no_wait); + mutex_unlock(&bm->mutex); + if (ret) + return ret; + } + + if (flag_diff & DRM_BO_FLAG_NO_EVICT) { + mutex_lock(&bm->mutex); + list_del_init(&bo->head); + if (!(new_flags & DRM_BO_FLAG_NO_EVICT)) { + if (new_flags & DRM_BO_FLAG_MEM_TT) { + list_add_tail(&bo->head, &bm->tt_lru); + } else { + list_add_tail(&bo->head, &bm->vram_lru); + } + } + mutex_unlock(&bm->mutex); + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); + } + + if (move_unfenced) { + + /* + * Place on unfenced list. + */ + + mutex_lock(&bm->mutex); + list_del_init(&bo->head); + list_add_tail(&bo->head, &bm->unfenced); + mutex_unlock(&bm->mutex); + } + + /* + * FIXME: Remove below. + */ + + bo->flags = new_flags; + 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) + uint32_t mask, uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; @@ -605,7 +685,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, 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, + mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -661,14 +741,14 @@ int drm_buffer_object_create(drm_file_t * priv, 1, &new_flags); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); + ret = drm_bo_add_ttm(priv, bo, mask, ttm_handle); if (ret) goto out_err; bo->mask = mask; - bo->hint = hint; - ret = drm_buffer_object_validate(dev, new_flags, bo); + ret = drm_buffer_object_validate(bo, new_flags, 0, + hint & DRM_BO_HINT_DONT_BLOCK); if (ret) goto out_err; @@ -719,7 +799,6 @@ static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, rep->map_flags = bo->map_flags; rep->mask = bo->mask; - rep->hint = bo->hint; rep->buffer_start = bo->buffer_start; } diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 62df6803..1bf87703 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -123,7 +123,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [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}, + DRM_AUTH } }; #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index f900dd51..d992621b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -679,25 +679,45 @@ typedef struct drm_ttm_arg { }drm_ttm_arg_t; +/* Buffer permissions, referring to how the GPU uses the buffers. + these translate to fence types used for the buffers. + Typically a texture buffer is read, A destination buffer is write and + a command (batch-) buffer is exe. Can be or-ed together. */ + #define DRM_BO_FLAG_READ 0x00000001 #define DRM_BO_FLAG_WRITE 0x00000002 #define DRM_BO_FLAG_EXE 0x00000004 -#define DRM_BO_FLAG_NO_MOVE 0x00000008 + +/* Pinned buffer. */ #define DRM_BO_FLAG_NO_EVICT 0x00000010 +/* Always keep a system memory shadow to a vram buffer */ #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 +/* 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 +/* 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 +/* Bind this buffer cached if the hardware supports it. */ +#define DRM_BO_FLAG_BIND_CACHED 0x00000400 +/* Translation table aperture */ #define DRM_BO_FLAG_MEM_TT 0x01000000 +/* On-card VRAM */ #define DRM_BO_FLAG_MEM_VRAM 0x02000000 +/* System memory */ #define DRM_BO_FLAG_MEM_LOCAL 0x04000000 -#define DRM_BO_MASK_MEM 0xFFFFFFFF +/* Memory flag mask */ +#define DRM_BO_MASK_MEM 0xFF000000 -#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 +/* When creating a buffer, Avoid system storage even if allowed */ +#define DRM_BO_HINT_AVOID_LOCAL 0x00000001 +/* Don't block on validate and map */ +#define DRM_BO_HINT_DONT_BLOCK 0x00000002 typedef enum { drm_bo_type_ttm, @@ -738,7 +758,6 @@ typedef struct drm_bo_arg_reply { unsigned arg_handle; unsigned map_flags; unsigned mask; - unsigned hint; drm_u64_t buffer_start; }drm_bo_arg_reply_t; From 611662ab287c279a95ae33442325626e0191e2c5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 20:23:40 +0200 Subject: [PATCH 039/147] Buffer eviction. Reworked map refcounting so that any process waiting on buffer object unmap will allow in other processes to unmap the buffer object. --- linux-core/drm_bo.c | 151 ++++++++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 61 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 057de9a0..f3105283 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -127,32 +127,23 @@ int drm_fence_buffer_objects(drm_file_t * priv) } /* - * bm locked, - * dev locked. + * bo 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) { 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, - buf->fence_flags); - if (ret) - return ret; - drm_fence_usage_deref_unlocked(dev, buf->fence); - buf->fence = NULL; - } - + 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; - buf->flags &= ~(DRM_BO_FLAG_MEM_TT); - buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&bm->mutex); return 0; } @@ -183,7 +174,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) if (bo->tt) { int ret; - ret = drm_move_tt_to_local(bo, 0); + ret = drm_move_tt_to_local(bo); BUG_ON(ret); } if (bo->vram) { @@ -389,41 +380,31 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, * 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_buffer_object_t * bo, int lazy, int no_wait) { drm_fence_object_t *fence = bo->fence; int ret; if (fence) { + drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; - } + } + if (no_wait) + return -EBUSY; - /* - * Make sure another process doesn't destroy the fence - * object when we release the buffer object mutex. - * We don't need to take the dev->struct_mutex lock here, - * since the fence usage count is at least 1 already. - */ - - atomic_inc(&fence->usage); - mutex_unlock(&bo->mutex); ret = drm_fence_object_wait(dev, fence, lazy, !lazy, bo->fence_flags); - mutex_lock(&bo->mutex); if (ret) return ret; - mutex_lock(&dev->struct_mutex); - drm_fence_usage_deref_locked(dev, fence); - if (bo->fence == fence) { - drm_fence_usage_deref_locked(dev, fence); - bo->fence = NULL; - } - mutex_unlock(&dev->struct_mutex); + + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + } return 0; } @@ -433,11 +414,12 @@ static int drm_bo_wait(drm_device_t * dev, drm_buffer_object_t * bo, int lazy) * 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_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; if (fence) { + drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -476,29 +458,30 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) mutex_lock(&bo->mutex); - if (!wait) { - if ((atomic_read(&bo->mapped) == 0) && drm_bo_busy(dev, bo)) { - mutex_unlock(&bo->mutex); - ret = -EBUSY; - goto out; - } - } else { - ret = drm_bo_wait(dev, bo, 0); + /* + * If this returns true, we are currently unmapped. + * We need to do this test, because unmapping can + * be done without the bo->mutex held. + */ + + if (atomic_inc_and_test(&bo->mapped)) { + ret = drm_bo_wait(bo, 0, !wait); if (ret) { - mutex_unlock(&bo->mutex); - ret = -EBUSY; + atomic_dec(&bo->mapped); goto out; } } + mutex_lock(&dev->struct_mutex); ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); mutex_unlock(&dev->struct_mutex); - if (!ret) { - atomic_inc(&bo->mapped); - } - mutex_unlock(&bo->mutex); + if (ret) { + if (atomic_add_negative(-1, &bo->mapped)) + DRM_WAKEUP(&bo->validate_queue); + } out: + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); return ret; } @@ -539,26 +522,72 @@ 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_user_object_entry(uo, drm_buffer_object_t, base); + + /* + * We DON'T want to take the bo->lock here, because we want to + * hold it when we wait for unmapped buffer. + */ BUG_ON(action != _DRM_REF_TYPE1); - if (atomic_dec_and_test(&bo->mapped)) { - mutex_unlock(&dev->struct_mutex); - mutex_lock(&bo->mutex); - if (atomic_read(&bo->mapped) == 0) { + if (atomic_add_negative(-1, &bo->mapped)) DRM_WAKEUP(&bo->validate_queue); - } - mutex_unlock(&bo->mutex); - mutex_lock(&dev->struct_mutex); - } } +/* + * bo->mutex locked. + */ + + static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, int no_wait) { + int ret = 0; + + /* + * Flush outstanding fences. + */ + + drm_bo_busy(bo); + + /* + * Make sure we're not mapped. + */ + + if (atomic_read(&bo->mapped) >= 0) { + if (no_wait) + return -EBUSY; + else { + DRM_WAIT_ON(ret, bo->validate_queue, 3*DRM_HZ, + atomic_read(&bo->mapped) == -1); + if (ret == -EINTR) + return -EAGAIN; + if (ret) + return ret; + } + } + + /* + * Wait for outstanding fences. + */ + + ret = drm_bo_wait(bo, 0, no_wait); + + if (ret == -EINTR) + return -EAGAIN; + if (ret) + return ret; + + if (new_flags & DRM_BO_FLAG_MEM_TT) { + drm_move_local_to_tt(bo); + } else { + drm_move_tt_to_local(bo); + } + + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_MEM_TT); + return 0; } @@ -728,7 +757,7 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_lock(&bo->mutex); atomic_set(&bo->usage, 1); - atomic_set(&bo->mapped, 0); + atomic_set(&bo->mapped, -1); DRM_INIT_WAITQUEUE(&bo->validate_queue); INIT_LIST_HEAD(&bo->head); INIT_LIST_HEAD(&bo->ddestroy); From 914a77a15aae07cc305cc5da5ad6c7a639cbc121 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 21:30:47 +0200 Subject: [PATCH 040/147] Buffer object binding. Some code reordering. --- linux-core/drmP.h | 6 + linux-core/drm_bo.c | 268 ++++++++++++++++++++++++++++---------------- 2 files changed, 177 insertions(+), 97 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6cce6b8d..bbf9da0b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -951,6 +951,12 @@ typedef struct drm_fence_object{ typedef struct drm_buffer_object{ drm_device_t *dev; drm_user_object_t base; + + /* + * If there is a possibility that the usage variable is zero, + * then dev->struct_mutext should be locked before incrementing it. + */ + atomic_t usage; drm_ttm_object_t *ttm_object; drm_ttm_backend_list_t *ttm_region; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f3105283..18cfadc5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -126,6 +126,7 @@ int drm_fence_buffer_objects(drm_file_t * priv) return 0; } + /* * bo locked. */ @@ -148,6 +149,8 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) return 0; } + + static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { @@ -197,6 +200,13 @@ void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) } } +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)); +} + void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { @@ -207,13 +217,167 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } -static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo) + +/* + * Call bo->mutex locked. + * Wait until the buffer is idle. + */ + +static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) { - drm_bo_usage_deref_locked(priv->head->dev, - drm_user_object_entry(uo, drm_buffer_object_t, - base)); + + drm_fence_object_t *fence = bo->fence; + int ret; + + if (fence) { + drm_device_t *dev = bo->dev; + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + if (no_wait) + return -EBUSY; + + ret = + drm_fence_object_wait(dev, fence, lazy, !lazy, + bo->fence_flags); + if (ret) + return ret; + + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + + } + return 0; } +/* + * No locking required. + */ + +static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) +{ + int ret = 0; + + /* + * Someone might have taken out the buffer before we took the buffer mutex. + */ + + mutex_lock(&bo->mutex); + if (bo->unfenced) + goto out; + if (tt && !bo->tt) + goto out; + if (!tt && !bo->vram) + goto out; + + ret = drm_bo_wait(bo, 0, no_wait); + if (ret) + goto out; + + if (tt) { + ret = drm_move_tt_to_local(bo); + } +#if 0 + else { + ret = drm_move_vram_to_local(bo); + } +#endif +out: + mutex_unlock(&bo->mutex); + return ret; +} + +/* + * buf->mutex locked. + */ + +int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) +{ + drm_device_t *dev = buf->dev; + drm_mm_node_t *node; + drm_buffer_manager_t *bm = &dev->bm; + drm_buffer_object_t *bo; + drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; + struct list_head *lru; + unsigned long size = buf->num_pages; + int ret; + + mutex_lock(&bm->mutex); + do { + node = drm_mm_search_free(mm, size, 0, 1); + if (node) + break; + + lru = (tt) ? &bm->tt_lru : &bm->vram_lru; + if (lru->next == lru) + break; + + bo = list_entry(lru->next, drm_buffer_object_t, head); + + /* + * 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. + */ + + atomic_inc(&bo->usage); + mutex_unlock(&bm->mutex); + ret = drm_bo_evict(bo, tt, no_wait); + drm_bo_usage_deref_unlocked(dev, bo); + if (ret) + return ret; + mutex_lock(&bm->mutex); + } while (1); + + if (!node) { + DRM_ERROR("Out of aperture space\n"); + mutex_lock(&bm->mutex); + return -ENOMEM; + } + + node = drm_mm_get_block(node, size, 0); + mutex_unlock(&bm->mutex); + BUG_ON(!node); + node->private = (void *)buf; + + if (tt) { + buf->tt = node; + } else { + buf->vram = node; + } + return 0; +} + + +static int drm_move_local_to_tt(drm_buffer_object_t *bo, int no_wait) +{ + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + int ret; + + + BUG_ON(bo->tt); + ret = drm_bo_alloc_space(bo, 1, no_wait); + + if (ret) + return ret; + + 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); + } + + return ret; +} + + + 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) @@ -289,64 +453,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, return 0; } -#if 0 - -static int drm_bo_evict(drm_device_t * dev, drm_buffer_object_t * buf, int tt); -{ - int ret; - if (tt) { - ret = drm_move_tt_to_local(buf); - } else { - ret = drm_move_vram_to_local(buf); - } - return ret; -} - -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; - drm_buffer_object_t *bo; - drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; - - lru = (tt) ? &bm->tt_lru : &bm->vram_lru; - - do { - node = drm_mm_search_free(mm, size, 0, 1); - if (node) - break; - - 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); - } - - drm_bo_evict(dev, bo, tt); - } while (1); - - if (!node) { - DRM_ERROR("Out of aperture space\n"); - return -ENOMEM; - } - - node = drm_mm_get_block(node, size, 0); - BUG_ON(!node); - node->private = (void *)buf; - - if (tt) { - buf->tt = node; - } else { - buf->vram = node; - } - return 0; -} -#endif - /* * Call dev->struct_mutex locked. */ @@ -375,40 +481,6 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, return bo; } -/* - * Call bo->mutex locked. - * Wait until the buffer is idle. - */ - -static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) -{ - - drm_fence_object_t *fence = bo->fence; - int ret; - - if (fence) { - drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; - return 0; - } - if (no_wait) - return -EBUSY; - - ret = - drm_fence_object_wait(dev, fence, lazy, !lazy, - bo->fence_flags); - if (ret) - return ret; - - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; - - } - return 0; -} - /* * Call bo->mutex locked. * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. @@ -581,7 +653,9 @@ static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, return ret; if (new_flags & DRM_BO_FLAG_MEM_TT) { - drm_move_local_to_tt(bo); + ret = drm_move_local_to_tt(bo, no_wait); + if (ret) + return ret; } else { drm_move_tt_to_local(bo); } From ed9de124cc88cee398b7013de6b822bfaa3f397e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 21:31:38 +0200 Subject: [PATCH 041/147] Lindenting drm_bo.c and drm_ttm.c --- linux-core/drm_bo.c | 85 +++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 50 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 18cfadc5..faa2e007 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -55,12 +55,11 @@ * 2.) Refer to ttm locking orders. */ - #define DRM_FLAG_MASKED(_old, _new, _mask) {\ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } -static inline uint32_t drm_flag_masked(uint32_t old, uint32_t new, +static inline uint32_t drm_flag_masked(uint32_t old, uint32_t new, uint32_t mask) { return old ^ ((old ^ new) & mask); @@ -126,7 +125,6 @@ int drm_fence_buffer_objects(drm_file_t * priv) return 0; } - /* * bo locked. */ @@ -149,8 +147,6 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) return 0; } - - static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { @@ -217,7 +213,6 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } - /* * Call bo->mutex locked. * Wait until the buffer is idle. @@ -235,7 +230,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; - } + } if (no_wait) return -EBUSY; @@ -244,7 +239,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) bo->fence_flags); if (ret) return ret; - + drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -259,15 +254,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) { int ret = 0; - + /* * Someone might have taken out the buffer before we took the buffer mutex. */ - + mutex_lock(&bo->mutex); if (bo->unfenced) goto out; - if (tt && !bo->tt) + if (tt && !bo->tt) goto out; if (!tt && !bo->vram) goto out; @@ -284,7 +279,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) ret = drm_move_vram_to_local(bo); } #endif -out: + out: mutex_unlock(&bo->mutex); return ret; } @@ -315,7 +310,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) break; bo = list_entry(lru->next, drm_buffer_object_t, head); - + /* * 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. @@ -349,14 +344,12 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) return 0; } - -static int drm_move_local_to_tt(drm_buffer_object_t *bo, int no_wait) +static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; int ret; - BUG_ON(bo->tt); ret = drm_bo_alloc_space(bo, 1, no_wait); @@ -376,8 +369,6 @@ static int drm_move_local_to_tt(drm_buffer_object_t *bo, int no_wait) return ret; } - - 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) @@ -466,8 +457,7 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, uo = drm_lookup_user_object(priv, handle); if (!uo || (uo->type != drm_buffer_type)) { - DRM_ERROR("Could not find buffer object 0x%08x\n", - handle); + DRM_ERROR("Could not find buffer object 0x%08x\n", handle); return NULL; } @@ -595,7 +585,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, drm_ref_t action) { drm_buffer_object_t *bo = - drm_user_object_entry(uo, drm_buffer_object_t, base); + drm_user_object_entry(uo, drm_buffer_object_t, base); /* * We DON'T want to take the bo->lock here, because we want to @@ -605,15 +595,14 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, BUG_ON(action != _DRM_REF_TYPE1); if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->validate_queue); + DRM_WAKEUP(&bo->validate_queue); } /* * bo->mutex locked. */ - -static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, +static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, int no_wait) { int ret = 0; @@ -627,16 +616,16 @@ static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, /* * Make sure we're not mapped. */ - + if (atomic_read(&bo->mapped) >= 0) { - if (no_wait) + if (no_wait) return -EBUSY; else { - DRM_WAIT_ON(ret, bo->validate_queue, 3*DRM_HZ, + DRM_WAIT_ON(ret, bo->validate_queue, 3 * DRM_HZ, atomic_read(&bo->mapped) == -1); - if (ret == -EINTR) + if (ret == -EINTR) return -EAGAIN; - if (ret) + if (ret) return ret; } } @@ -659,22 +648,19 @@ static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, } else { drm_move_tt_to_local(bo); } - + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_MEM_TT); - + return 0; } - /* * bo locked. */ - static int drm_buffer_object_validate(drm_buffer_object_t * bo, uint32_t new_flags, - int move_unfenced, - int no_wait) + int move_unfenced, int no_wait) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -700,10 +686,10 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, mutex_lock(&bm->mutex); ret = drm_bo_move_buffer(bo, new_flags, no_wait); mutex_unlock(&bm->mutex); - if (ret) + if (ret) return ret; } - + if (flag_diff & DRM_BO_FLAG_NO_EVICT) { mutex_lock(&bm->mutex); list_del_init(&bo->head); @@ -723,7 +709,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, /* * Place on unfenced list. */ - + mutex_lock(&bm->mutex); list_del_init(&bo->head); list_add_tail(&bo->head, &bm->unfenced); @@ -737,7 +723,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, bo->flags = new_flags; return 0; } - + /* * Call bo->mutex locked. */ @@ -850,7 +836,7 @@ int drm_buffer_object_create(drm_file_t * priv, bo->mask = mask; - ret = drm_buffer_object_validate(bo, new_flags, 0, + ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); if (ret) goto out_err; @@ -1000,15 +986,14 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) } -static void drm_bo_clean_mm(drm_file_t *priv) +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; @@ -1021,7 +1006,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - switch(arg.req.op) { + switch (arg.req.op) { case mm_init: if (bm->initialized) { DRM_ERROR("Memory manager already initialized\n"); @@ -1033,8 +1018,8 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) bm->has_tt = 0; if (arg.req.vr_p_size) { - ret = drm_mm_init(&bm->vram_manager, - arg.req.vr_p_offset, + ret = drm_mm_init(&bm->vram_manager, + arg.req.vr_p_offset, arg.req.vr_p_size); bm->has_vram = 1; if (ret) @@ -1042,8 +1027,8 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) } if (arg.req.tt_p_size) { - ret = drm_mm_init(&bm->tt_manager, - arg.req.tt_p_offset, + ret = drm_mm_init(&bm->tt_manager, + arg.req.tt_p_offset, arg.req.tt_p_size); bm->has_tt = 1; if (ret) { @@ -1077,11 +1062,11 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) default: return -EINVAL; } - + mutex_unlock(&bm->mutex); if (ret) return ret; - + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); return 0; } From ec8c79b79de6544cc09b5a2c85213a5f30e0d906 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 14:10:13 +0200 Subject: [PATCH 042/147] More mapping synchronization. libdrm validate and fencing functions. --- 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(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 1763b89a..a99c979d 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 *list, drmBO *item, drm_bo_arg_t *arg) if (l == &list->free) { node = (drmBONode *) malloc(sizeof(*node)); if (!node) { - return -ENOMEM; + return NULL; } list->numCurrent++; } else { @@ -2518,11 +2520,43 @@ static int drmAddListItem(drmBOList *list, drmBO *item, drm_bo_arg_t *arg) 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; } +void *drmBOListIterator(drmBOList *list) +{ + void *ret = list->list.next; + + if (ret == &list->list) + return NULL; + return ret; +} + +void *drmBOListNext(drmBOList *list, void *iterator) +{ + void *ret; + + 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; +} + + int drmCreateBufList(int numTarget, drmBOList *list) { DRMINITLISTHEAD(&list->list); @@ -2533,32 +2567,6 @@ int drmCreateBufList(int numTarget, drmBOList *list) return drmAdjustListNodes(list); } -/* - * Prepare list for IOCTL submission. - */ - -static drm_bo_arg_t *drmPrepareList(drmBOList *list) -{ - drmMMListHead *cur, *next; - drmBONode *first, *curNode, *nextNode; - - cur = list->list.next; - if (cur == &list->list) - return NULL; - - 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 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) @@ -2567,6 +2575,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, 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, unsigned long start, unsigned long size, 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, unsigned long start, unsigned long size, 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 handle, drmBO *buf) 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 handle, drmBO *buf) 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, unsigned mapFlags, void **address) * 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, unsigned mapFlags, void **address) } } + 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, unsigned mapFlags, void **address) * 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 21fed6cf..aaee3c0b 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 bbf9da0b..fde89c30 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 faa2e007..232120a4 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -256,11 +256,11 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) 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_buffer_object_t * bo, int no_wait) 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_driver_t * driver, 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_driver_t * driver, } *n_flags = new_flags; + *n_mask = new_mask; return 0; } @@ -498,6 +521,12 @@ static int drm_bo_busy(drm_buffer_object_t * bo) 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_t * bo) * 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_file_t * priv, uint32_t handle, int wait) * 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(drm_buffer_object_t * bo, */ 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 * priv, drm_buffer_object_t * bo, 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 * priv, 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 drm_buffer_object_t * bo, 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 d992621b..9640855c 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 03c137c5f8d44c374406efe19c01105fcf34d583 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 15:36:40 +0200 Subject: [PATCH 043/147] 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. --- linux-core/drmP.h | 2 +- linux-core/drm_bo.c | 120 ++++++++++++++++++++++++++++++-------------- 2 files changed, 83 insertions(+), 39 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index fde89c30..01e3c66f 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 232120a4..e2513267 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 * priv) 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 * priv) } 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 * priv) } } - 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_buffer_object_t * buf) 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_device_t * dev, drm_buffer_object_t * bo) 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_t * buf, int tt, int no_wait) 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_t * buf, int tt, int no_wait) /* * 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_buffer_object_t * bo, int no_wait) 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(drm_buffer_object_t * bo, */ 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(drm_buffer_object_t * bo, 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(drm_buffer_object_t * bo, * 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 * priv, 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; From 44f6d08988a77a640bea40d09cb61eec7566a5ce Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 21:42:29 +0200 Subject: [PATCH 044/147] Validation and fencing. --- linux-core/drmP.h | 11 +- linux-core/drm_bo.c | 573 ++++++++++++++++++++++++++------------- linux-core/i915_buffer.c | 24 ++ linux-core/i915_drv.c | 4 +- linux-core/i915_fence.c | 1 + shared-core/drm.h | 14 +- shared-core/i915_dma.c | 23 ++ shared-core/i915_drv.h | 9 + 8 files changed, 463 insertions(+), 196 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 01e3c66f..5242b287 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -656,6 +656,8 @@ typedef struct drm_bo_driver{ int cached_vram; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev, int cached); + int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type); + int (*invalidate_caches)(struct drm_device *dev, uint32_t flags); } drm_bo_driver_t; @@ -783,7 +785,9 @@ typedef struct drm_buffer_manager{ struct list_head vram_lru; struct list_head unfenced; struct list_head ddestroy; + struct list_head other; struct timer_list timer; + uint32_t fence_flags; } drm_buffer_manager_t; @@ -975,12 +979,15 @@ typedef struct drm_buffer_object{ struct list_head ddestroy; uint32_t fence_flags; + uint32_t fence_class; drm_fence_object_t *fence; - int unfenced; - wait_queue_head_t validate_queue; + uint32_t priv_flags; + wait_queue_head_t event_queue; struct mutex mutex; } drm_buffer_object_t; +#define _DRM_BO_FLAG_UNFENCED 0x00000001 +#define _DRM_BO_FLAG_EVICTED 0x00000002 static __inline__ int drm_core_check_feature(struct drm_device *dev, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e2513267..8bca2e32 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -59,65 +59,6 @@ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } - -int drm_fence_buffer_objects(drm_file_t * priv) -{ - drm_device_t *dev = priv->head->dev; - drm_buffer_manager_t *bm = &dev->bm; - - drm_buffer_object_t *entry, *next; - uint32_t fence_flags = 0; - int count = 0; - drm_fence_object_t *fence; - int ret; - - mutex_lock(&dev->struct_mutex); - - list_for_each_entry(entry, &bm->unfenced, head) { - BUG_ON(!entry->unfenced); - fence_flags |= entry->fence_flags; - count++; - } - - if (!count) { - mutex_unlock(&dev->struct_mutex); - return 0; - } - - fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); - - if (!fence) { - 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(&dev->struct_mutex); - return ret; - } - - list_for_each_entry_safe(entry, next, &bm->unfenced, head) { - BUG_ON(entry->fence); - entry->unfenced = 0; - entry->fence = fence; - list_del_init(&entry->head); - - if (!(entry->flags & DRM_BO_FLAG_NO_EVICT)) { - if (entry->flags & DRM_BO_FLAG_MEM_TT) { - list_add_tail(&entry->head, &bm->tt_lru); - } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { - list_add_tail(&entry->head, &bm->vram_lru); - } - } - } - - atomic_add(count - 1, &fence->usage); - mutex_unlock(&dev->struct_mutex); - return 0; -} - /* * bo locked. */ @@ -135,11 +76,12 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) buf->tt = NULL; mutex_unlock(&dev->struct_mutex); + buf->flags &= ~DRM_BO_MASK_MEM; + buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + return 0; } - - /* * Lock dev->struct_mutex */ @@ -149,6 +91,7 @@ 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->priv_flags & _DRM_BO_FLAG_UNFENCED); if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); @@ -158,7 +101,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) bm->timer.expires = jiffies + 1; add_timer(&bm->timer); } - + return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -170,7 +113,8 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * Take away from lru lists. */ - list_del_init(&bo->head); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); if (bo->tt) { int ret; @@ -190,10 +134,10 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } -static void drm_bo_delayed_delete(drm_device_t *dev) +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; @@ -202,7 +146,7 @@ static void drm_bo_delayed_delete(drm_device_t *dev) list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { fence = entry->fence; - if (fence && drm_fence_object_signaled(fence, + if (fence && drm_fence_object_signaled(fence, entry->fence_flags)) { drm_fence_usage_deref_locked(dev, fence); entry->fence = NULL; @@ -217,13 +161,11 @@ static void drm_bo_delayed_delete(drm_device_t *dev) mutex_unlock(&dev->struct_mutex); } - -static void -drm_bo_delayed_timer(unsigned long data) +static void drm_bo_delayed_timer(unsigned long data) { - drm_device_t *dev = (drm_device_t *)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)) { @@ -233,7 +175,6 @@ drm_bo_delayed_timer(unsigned long data) 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)) { @@ -258,6 +199,103 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } +int drm_fence_buffer_objects(drm_file_t * priv, + struct list_head *list, + drm_fence_object_t *fence) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry; + uint32_t fence_flags = 0; + int count = 0; + int ret = 0; + struct list_head f_list, *l; + + mutex_lock(&dev->struct_mutex); + + list_for_each_entry(entry, list, head) { + BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); + fence_flags |= entry->fence_flags; + count++; + } + + if (!count) + goto out; + + if (fence) { + if ((fence_flags & fence->type) != fence_flags) { + DRM_ERROR("Given fence doesn't match buffers " + "on unfenced list.\n"); + ret = -EINVAL; + goto out; + } + } else { + fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + + if (!fence) { + ret = -ENOMEM; + goto out; + } + + ret = drm_fence_object_init(dev, fence_flags, 1, fence); + + if (ret) { + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + goto out; + } + } + + /* + * Transfer to a private list before we release the dev->struct_mutex; + * This is so we don't get any new unfenced objects while fencing + * these. + */ + + f_list = *list; + INIT_LIST_HEAD(list); + + count = 0; + l = f_list.next; + while(l != &f_list) { + entry = list_entry(l, drm_buffer_object_t, head); + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + mutex_lock(&dev->struct_mutex); + + if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { + count++; + if (entry->fence) + drm_fence_usage_deref_locked(dev, entry->fence); + entry->fence = fence; + DRM_FLAG_MASKED(entry->priv_flags, 0, + _DRM_BO_FLAG_UNFENCED); + DRM_WAKEUP(&entry->event_queue); + list_del_init(&entry->head); + if (entry->flags & DRM_BO_FLAG_NO_EVICT) + list_add_tail(&entry->head, &bm->other); + else if (entry->flags & DRM_BO_FLAG_MEM_TT) + list_add_tail(&entry->head, &bm->tt_lru); + else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) + list_add_tail(&entry->head, &bm->vram_lru); + else + list_add_tail(&entry->head, &bm->other); + } + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_locked(dev, entry); + l = f_list.next; + } + if (!count) + drm_fence_usage_deref_locked(dev, fence); + else if (count > 1) + atomic_add(count - 1, &fence->usage); + out: + mutex_unlock(&dev->struct_mutex); + return ret; +} + + /* * Call bo->mutex locked. * Wait until the buffer is idle. @@ -269,6 +307,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) drm_fence_object_t *fence = bo->fence; int ret; + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -299,13 +338,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) { int ret = 0; - + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; /* * Someone might have modified the buffer before we took the buffer mutex. */ mutex_lock(&bo->mutex); - if (bo->unfenced || (bo->flags & DRM_BO_FLAG_NO_EVICT)) + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) + || (bo->flags & DRM_BO_FLAG_NO_EVICT)) goto out; if (tt && !bo->tt) goto out; @@ -324,6 +365,12 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) ret = drm_move_vram_to_local(bo); } #endif + mutex_lock(&dev->struct_mutex); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, + _DRM_BO_FLAG_EVICTED); out: mutex_unlock(&bo->mutex); return ret; @@ -356,11 +403,6 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) bo = list_entry(lru->next, drm_buffer_object_t, head); - /* - * 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 dev->struct_mutex is held. - */ - atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); ret = drm_bo_evict(bo, tt, no_wait); @@ -407,13 +449,26 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) drm_mm_put_block(&bm->tt_manager, bo->tt); } mutex_unlock(&dev->struct_mutex); - return ret; + if (ret) + return ret; + + if (bo->ttm_region->be->needs_cache_adjust(bo->ttm_region->be)) + bo->flags &= ~DRM_BO_FLAG_CACHED; + bo->flags &= ~DRM_BO_MASK_MEM; + bo->flags |= DRM_BO_FLAG_MEM_TT; + + if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { + ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); + DRM_ERROR("Warning: Could not flush read caches\n"); + } + + return 0; } 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 *n_mask) + int init, uint32_t * n_flags, uint32_t * n_mask) { uint32_t new_flags = 0; uint32_t new_props; @@ -426,21 +481,23 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, 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_MEM_VRAM) + && !driver->cached_vram)) { new_mask &= ~DRM_BO_FLAG_BIND_CACHED; } else { - if (!driver->cached_tt) + if (!driver->cached_tt) new_flags &= DRM_BO_FLAG_MEM_TT; - if (!driver->cached_vram) + if (!driver->cached_vram) new_flags &= DRM_BO_FLAG_MEM_VRAM; } } - - if ((new_mask & DRM_BO_FLAG_READ_CACHED) && + + if ((new_mask & DRM_BO_FLAG_READ_CACHED) && !(new_mask & DRM_BO_FLAG_BIND_CACHED)) { - if ((new_mask & DRM_BO_FLAG_NO_EVICT) && + 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"); + 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); @@ -449,7 +506,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, /* * Determine new memory location: */ - if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { @@ -544,6 +600,7 @@ static int drm_bo_busy(drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -562,11 +619,93 @@ static int drm_bo_busy(drm_buffer_object_t * bo) return 0; } - -static int drm_bo_read_cached(drm_buffer_object_t *bo) { +static int drm_bo_read_cached(drm_buffer_object_t * bo) +{ + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, + _DRM_BO_FLAG_EVICTED); return 0; } +/* + * Wait until a buffer is unmapped. + */ + +static int drm_bo_wait_unmapped(drm_buffer_object_t *bo, int no_wait) +{ + int ret = 0; + + if ((atomic_read(&bo->mapped) >= 0) && no_wait) + return -EBUSY; + + DRM_WAIT_ON(ret, bo->event_queue, 3 * DRM_HZ, + atomic_read(&bo->mapped) == -1); + + if (ret == -EINTR) + ret = -EAGAIN; + + return ret; +} + +static int drm_bo_check_unfenced(drm_buffer_object_t *bo) +{ + int ret; + + mutex_lock(&bo->mutex); + ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + mutex_unlock(&bo->mutex); + return ret; +} + +/* + * Wait until a buffer, scheduled to be fenced moves off the unfenced list. + * Until then, we cannot really do anything with it except delete it. + * The unfenced list is a PITA, and the operations + * 1) validating + * 2) submitting commands + * 3) fencing + * Should really be an atomic operation. + * We now "solve" this problem by keeping + * the buffer "unfenced" after validating, but before fencing. + */ + +static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, + int eagain_if_wait) +{ + int ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + unsigned long _end = jiffies + 3*DRM_HZ; + + if (ret && no_wait) + return -EBUSY; + else if (!ret) + return 0; + + do { + mutex_unlock(&bo->mutex); + DRM_WAIT_ON(ret, bo->event_queue, 3 * DRM_HZ, + !drm_bo_check_unfenced(bo)); + mutex_lock(&bo->mutex); + if (ret == -EINTR) + return -EAGAIN; + if (ret) { + DRM_ERROR("Error waiting for buffer to become fenced\n"); + return ret; + } + ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + } while (ret && !time_after_eq(jiffies, _end)); + if (ret) { + DRM_ERROR("Timeout waiting for buffer to become fenced\n"); + return ret; + } + if (eagain_if_wait) + return -EAGAIN; + + return 0; +} + + + + /* * Wait for buffer idle and register that we've mapped the buffer. @@ -575,7 +714,7 @@ static int drm_bo_read_cached(drm_buffer_object_t *bo) { * unregistered. */ -static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, +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; @@ -590,6 +729,9 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, return -EINVAL; mutex_lock(&bo->mutex); + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + if (ret) + goto out; /* * If this returns true, we are currently unmapped. @@ -597,7 +739,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, * be done without the bo->mutex held. */ - while(1) { + while (1) { if (atomic_inc_and_test(&bo->mapped)) { ret = drm_bo_wait(bo, 0, no_wait); if (ret) { @@ -608,41 +750,33 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, 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))) { + } 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. + */ + + ret = drm_bo_wait_unmapped(bo, no_wait); + if (ret) + goto out; - /* - * 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; - } + continue; } + break; } - + mutex_lock(&dev->struct_mutex); ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); mutex_unlock(&dev->struct_mutex); if (ret) { if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->validate_queue); + DRM_WAKEUP(&bo->event_queue); } out: @@ -698,7 +832,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, BUG_ON(action != _DRM_REF_TYPE1); if (atomic_add_negative(-1, &bo->mapped)) - DRM_WAKEUP(&bo->validate_queue); + DRM_WAKEUP(&bo->event_queue); } /* @@ -720,18 +854,9 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Make sure we're not mapped. */ - if (atomic_read(&bo->mapped) >= 0) { - if (no_wait) - return -EBUSY; - else { - DRM_WAIT_ON(ret, bo->validate_queue, 3 * DRM_HZ, - atomic_read(&bo->mapped) == -1); - if (ret == -EINTR) - return -EAGAIN; - if (ret) - return ret; - } - } + ret = drm_bo_wait_unmapped(bo, no_wait); + if (ret) + return ret; /* * Wait for outstanding fences. @@ -752,8 +877,6 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, drm_move_tt_to_local(bo); } - DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_MEM_TT); - return 0; } @@ -768,6 +891,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; uint32_t flag_diff = (new_flags ^ bo->flags); + drm_bo_driver_t *driver = dev->driver->bo_driver; int ret; @@ -785,6 +909,12 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Check whether we need to move buffer. */ + ret = driver->fence_type(new_flags, &bo->fence_flags, &bo->fence_class); + if (ret) { + DRM_ERROR("Driver did not support given buffer permissions\n"); + return ret; + } + if (flag_diff & DRM_BO_MASK_MEM) { mutex_lock(&dev->struct_mutex); ret = drm_bo_move_buffer(bo, new_flags, no_wait); @@ -793,40 +923,72 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return ret; } - if (flag_diff & DRM_BO_FLAG_NO_EVICT) { - 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) { - list_add_tail(&bo->head, &bm->tt_lru); - } else { - list_add_tail(&bo->head, &bm->vram_lru); - } - } - mutex_unlock(&dev->struct_mutex); - DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); - } - if (move_unfenced) { /* * Place on unfenced list. */ + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, + _DRM_BO_FLAG_UNFENCED); mutex_lock(&dev->struct_mutex); - list_del_init(&bo->head); + list_del(&bo->head); list_add_tail(&bo->head, &bm->unfenced); mutex_unlock(&dev->struct_mutex); + } else { + mutex_lock(&dev->struct_mutex); + list_del(&bo->head); + if (new_flags & DRM_BO_FLAG_NO_EVICT) + list_add_tail(&bo->head, &bm->other); + else if (new_flags & DRM_BO_FLAG_MEM_TT) + list_add_tail(&bo->head, &bm->tt_lru); + else if (new_flags & DRM_BO_FLAG_MEM_VRAM) + list_add_tail(&bo->head, &bm->vram_lru); + else + list_add_tail(&bo->head, &bm->other); + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } - /* - * FIXME: Remove below. - */ - bo->flags = new_flags; return 0; } +static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, + uint32_t flags, uint32_t mask, uint32_t hint) +{ + drm_buffer_object_t *bo; + drm_device_t *dev = priv->head->dev; + int ret; + int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; + uint32_t new_flags; + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + return -EINVAL; + } + + mutex_lock(&bo->mutex); + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + + if (ret) + goto out; + + ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, + (flags & mask) | (bo->flags & ~mask), hint, + 0, &new_flags, &bo->mask); + + if (ret) + goto out; + + ret = drm_buffer_object_validate(bo, new_flags, !(hint & DRM_BO_HINT_DONT_FENCE), + no_wait); + +out: + mutex_unlock(&bo->mutex); + drm_bo_usage_deref_unlocked(dev, bo); + return ret; +} + /* * Call bo->mutex locked. */ @@ -886,6 +1048,10 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, return ret; } + + + + int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, @@ -896,6 +1062,7 @@ int drm_buffer_object_create(drm_file_t * priv, drm_buffer_object_t ** buf_obj) { drm_device_t *dev = priv->head->dev; + drm_buffer_manager_t *bm = &dev->bm; drm_buffer_object_t *bo; int ret = 0; uint32_t new_flags; @@ -922,13 +1089,15 @@ int drm_buffer_object_create(drm_file_t * priv, atomic_set(&bo->usage, 1); atomic_set(&bo->mapped, -1); - DRM_INIT_WAITQUEUE(&bo->validate_queue); + DRM_INIT_WAITQUEUE(&bo->event_queue); INIT_LIST_HEAD(&bo->head); + list_add_tail(&bo->head, &bm->other); INIT_LIST_HEAD(&bo->ddestroy); bo->dev = dev; bo->type = type; bo->num_pages = num_pages; bo->buffer_start = buffer_start; + bo->priv_flags = 0; ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, 1, &new_flags, &bo->mask); @@ -938,12 +1107,12 @@ int drm_buffer_object_create(drm_file_t * priv, if (ret) goto out_err; -#if 0 +#if 1 ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); #else bo->flags = new_flags; -#endif +#endif if (ret) goto out_err; @@ -996,6 +1165,12 @@ static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, rep->buffer_start = bo->buffer_start; } +static int drm_bo_lock_test(drm_device_t * dev, struct file *filp) +{ + LOCK_TEST_WITH_RETURN(dev, filp); + return 0; +} + int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -1005,43 +1180,43 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) unsigned long next; drm_user_object_t *uo; 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; + data = req->next; + continue; } rep.ret = 0; switch (req->op) { - case drm_bo_create:{ - rep.ret = - drm_buffer_object_create(priv, req->size, - req->type, - req->arg_handle, - req->mask, - req->hint, - req->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); + case drm_bo_create: + rep.ret = + drm_buffer_object_create(priv, req->size, + req->type, + req->arg_handle, + req->mask, + req->hint, + req->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); + + if (rep.ret) + break; + + mutex_lock(&entry->mutex); + drm_bo_fill_rep_arg(entry, &rep); + mutex_unlock(&entry->mutex); + break; case drm_bo_unmap: rep.ret = drm_buffer_object_unmap(priv, req->handle); break; @@ -1083,6 +1258,20 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_user_object_unref(priv, req->handle, drm_buffer_type); break; + case drm_bo_validate: + rep.ret = drm_bo_lock_test(dev, filp); + if (rep.ret) + break; + rep.ret = + drm_bo_handle_validate(priv, req->handle, req->mask, + req->arg_handle, req->hint); + break; + case drm_bo_fence: + rep.ret = drm_bo_lock_test(dev, filp); + if (rep.ret) + break; + /**/ + break; default: rep.ret = -EINVAL; } @@ -1104,12 +1293,12 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } - - -static void drm_bo_clean_mm(drm_file_t * priv) +int drm_bo_clean_mm(drm_file_t *priv) { + return 0; } + int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -1120,7 +1309,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) drm_bo_driver_t *driver = dev->driver->bo_driver; if (!driver) { - DRM_ERROR("Buffer objects is not supported by this driver\n"); + DRM_ERROR("Buffer objects are not sutt_lru); INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); + INIT_LIST_HEAD(&bm->other); init_timer(&bm->timer); bm->timer.function = &drm_bo_delayed_timer; - bm->timer.data = (unsigned long) dev; - + bm->timer.data = (unsigned long)dev; + bm->initialized = 1; break; case mm_takedown: @@ -1185,6 +1375,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) bm->initialized = 0; break; default: + DRM_ERROR("Function not implemented yet\n"); return -EINVAL; } diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index bedbd41c..ecc6cf8d 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -30,6 +30,8 @@ */ #include "drmP.h" +#include "i915_drm.h" +#include "i915_drv.h" drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, int cached) { @@ -38,3 +40,25 @@ drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, int cached) else return drm_agp_init_ttm_uncached(dev); } + +int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) +{ + *class = 0; + if (buffer_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) + *type = 1; + else + *type = 3; + return 0; +} + +int i915_invalidate_caches(drm_device_t *dev, uint32_t flags) +{ + uint32_t flush_cmd = MI_NO_WRITE_FLUSH; + + if (flags & DRM_BO_FLAG_READ) + flush_cmd |= MI_READ_FLUSH; + if (flags & DRM_BO_FLAG_EXE) + flush_cmd |= MI_EXE_FLUSH; + + return i915_emit_mi_flush(dev, flush_cmd); +} diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index bc78dc2e..fb4754d8 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -51,7 +51,9 @@ static drm_fence_driver_t i915_fence_driver = { static drm_bo_driver_t i915_bo_driver = { .cached_vram = 0, .cached_tt = 1, - .create_ttm_backend_entry = i915_create_ttm_backend_entry + .create_ttm_backend_entry = i915_create_ttm_backend_entry, + .fence_type = i915_fence_types, + .invalidate_caches = i915_invalidate_caches }; diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 452d4ee8..673ebd0e 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -121,3 +121,4 @@ void i915_fence_handler(drm_device_t * dev) i915_perform_flush(dev); write_unlock(&fm->lock); } + diff --git a/shared-core/drm.h b/shared-core/drm.h index 9640855c..f76fd86f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -723,7 +723,15 @@ typedef struct drm_ttm_arg { /* When creating a buffer, Avoid system storage even if allowed */ #define DRM_BO_HINT_AVOID_LOCAL 0x00000001 /* Don't block on validate and map */ -#define DRM_BO_HINT_DONT_BLOCK 0x00000002 +#define DRM_BO_HINT_DONT_BLOCK 0x00000002 +/* Don't place this buffer on the unfenced list.*/ +#define DRM_BO_HINT_DONT_FENCE 0x00000004 + + + + +/* Driver specific flags. Could be for example rendering engine */ +#define DRM_BO_MASK_DRIVER 0x00F00000 typedef enum { drm_bo_type_ttm, @@ -779,7 +787,9 @@ typedef union drm_mm_init_arg{ enum { mm_init, mm_takedown, - mm_query + mm_query, + mm_lock, + mm_unlock } op; drm_u64_t vr_p_offset; drm_u64_t vr_p_size; diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index e661269b..baeab383 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -444,6 +444,28 @@ static void i915_emit_breadcrumb(drm_device_t *dev) #endif } + +int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t flush_cmd = CMD_MI_FLUSH; + RING_LOCALS; + + flush_cmd |= flush; + + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(4); + OUT_RING(flush_cmd); + OUT_RING(0); + OUT_RING(0); + OUT_RING(0); + ADVANCE_LP_RING(); + + return 0; +} + + static int i915_dispatch_cmdbuffer(drm_device_t * dev, drm_i915_cmdbuffer_t * cmd) { @@ -680,6 +702,7 @@ static int i915_flip_bufs(DRM_IOCTL_ARGS) return i915_dispatch_flip(dev); } + static int i915_getparam(DRM_IOCTL_ARGS) { DRM_DEVICE; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 403124c9..8bf82ed8 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -124,6 +124,8 @@ extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp); extern int i915_driver_device_is_agp(drm_device_t * dev); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush); + /* i915_irq.c */ extern int i915_irq_emit(DRM_IOCTL_ARGS); @@ -158,6 +160,8 @@ extern void i915_sync_flush(drm_device_t *dev); /* i915_buffer.c */ extern drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, int cached); +extern int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type); +extern int i915_invalidate_caches(drm_device_t *dev, uint32_t buffer_flags); #endif #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) @@ -209,6 +213,11 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define INST_OP_FLUSH 0x02000000 #define INST_FLUSH_MAP_CACHE 0x00000001 +#define CMD_MI_FLUSH (0x04 << 23) +#define MI_NO_WRITE_FLUSH (1 << 2) +#define MI_READ_FLUSH (1 << 0) +#define MI_EXE_FLUSH (1 << 1) + #define BB1_START_ADDR_MASK (~0x7) #define BB1_PROTECTED (1<<0) #define BB1_UNPROTECTED (0<<0) From 4edb95d6e0a00a9a8885603cab2c99e3c6daa705 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 11:23:21 +0200 Subject: [PATCH 045/147] Various bugfixes. --- libdrm/xf86drm.c | 4 ++-- linux-core/drm_bo.c | 47 +++++++++++++++++++++++++++------------- linux-core/drm_ttm.c | 1 + linux-core/i915_buffer.c | 4 ++-- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a99c979d..41ad89cb 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3053,8 +3053,8 @@ int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, 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; + arg.req.tt_p_offset = ttPOffset; + arg.req.tt_p_size = ttPSize; if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) return -errno; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 8bca2e32..dcbf2d91 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -70,14 +70,15 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); + DRM_ERROR("Flipping out of AGP\n"); 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); buf->flags &= ~DRM_BO_MASK_MEM; buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + mutex_unlock(&dev->struct_mutex); return 0; } @@ -114,12 +115,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) */ list_del(&bo->head); - list_add_tail(&bo->head, &bm->other); if (bo->tt) { - int ret; - ret = drm_move_tt_to_local(bo); - BUG_ON(ret); + drm_unbind_ttm_region(bo->ttm_region); + drm_mm_put_block(&bm->tt_manager, bo->tt); + bo->tt = NULL; } if (bo->vram) { drm_mm_put_block(&bm->vram_manager, bo->vram); @@ -443,6 +443,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; + DRM_ERROR("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); if (ret) { @@ -458,10 +459,11 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) bo->flags |= DRM_BO_FLAG_MEM_TT; if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { + DRM_ERROR("Flush read caches\n"); ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); DRM_ERROR("Warning: Could not flush read caches\n"); } + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); return 0; } @@ -500,7 +502,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, ("Cannot read cached from a pinned VRAM / TT buffer\n"); return -EINVAL; } - new_mask &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM); } /* @@ -621,10 +622,19 @@ static int drm_bo_busy(drm_buffer_object_t * bo) static int drm_bo_read_cached(drm_buffer_object_t * bo) { + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - return 0; + + mutex_lock(&dev->struct_mutex); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); + return drm_move_tt_to_local(bo); } /* @@ -836,7 +846,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, } /* - * bo->mutex locked. + * bo->mutex locked. */ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, @@ -847,13 +857,14 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, /* * Flush outstanding fences. */ - + DRM_ERROR("Flushing fences\n"); drm_bo_busy(bo); /* * Make sure we're not mapped. */ + DRM_ERROR("Wait unmapped\n"); ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) return ret; @@ -862,6 +873,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ + DRM_ERROR("Wait fences\n"); ret = drm_bo_wait(bo, 0, no_wait); if (ret == -EINTR) @@ -909,16 +921,16 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Check whether we need to move buffer. */ - ret = driver->fence_type(new_flags, &bo->fence_flags, &bo->fence_class); + ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); + DRM_ERROR("Fence type = 0x%08x\n", bo->fence_flags); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } if (flag_diff & DRM_BO_MASK_MEM) { - mutex_lock(&dev->struct_mutex); + DRM_ERROR("Calling move buffer\n"); ret = drm_bo_move_buffer(bo, new_flags, no_wait); - mutex_unlock(&dev->struct_mutex); if (ret) return ret; } @@ -946,6 +958,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, list_add_tail(&bo->head, &bm->vram_lru); else list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -1098,9 +1111,10 @@ int drm_buffer_object_create(drm_file_t * priv, bo->num_pages = num_pages; bo->buffer_start = buffer_start; bo->priv_flags = 0; - + bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, 1, &new_flags, &bo->mask); + DRM_ERROR("New flags: 0x%08x\n", new_flags); if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, ttm_handle); @@ -1309,7 +1323,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) drm_bo_driver_t *driver = dev->driver->bo_driver; if (!driver) { - DRM_ERROR("Buffer objects are not sutt_manager, arg.req.tt_p_offset, arg.req.tt_p_size); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 33567d9b..97e3e96d 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -447,6 +447,7 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); } + DRM_ERROR("Unbinding\n"); be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index ecc6cf8d..598f8772 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -45,9 +45,9 @@ int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) { *class = 0; if (buffer_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) - *type = 1; - else *type = 3; + else + *type = 1; return 0; } From 11f51a9a877d1231551e8c6482a6f70daf380cdd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 15:41:55 +0200 Subject: [PATCH 046/147] Bugfixes, Memory allocation optimizations. Buffer manager takedown. --- linux-core/drmP.h | 13 +++- linux-core/drm_bo.c | 135 +++++++++++++++++++++++++++++++++-------- linux-core/drm_drv.c | 29 ++++++++- linux-core/drm_fence.c | 6 +- linux-core/drm_mm.c | 39 +++++++++--- linux-core/drm_stub.c | 30 +++++++++ 6 files changed, 216 insertions(+), 36 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5242b287..c6646212 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -84,6 +84,7 @@ #include #include #include "drm.h" +#include #define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE))) #define __OS_HAS_MTRR (defined(CONFIG_MTRR)) @@ -779,6 +780,8 @@ typedef struct drm_buffer_manager{ int initialized; int has_vram; int has_tt; + int use_vram; + int use_tt; drm_mm_t tt_manager; struct list_head tt_lru; drm_mm_t vram_manager; @@ -922,6 +925,12 @@ typedef struct drm_device { drm_fence_manager_t fm; drm_buffer_manager_t bm; + + /* + * Memory caches + */ + kmem_cache_t *mm_cache; + kmem_cache_t *fence_object_cache; } drm_device_t; @@ -1293,7 +1302,8 @@ extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, unsigned alignment, int best_match); extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern void drm_mm_takedown(drm_mm_t *mm); - +extern void drm_mm_set_cache(kmem_cache_t *cache); +extern int drm_mm_clean(drm_mm_t *mm); /* * User space object bookkeeping (drm_object.c) @@ -1377,6 +1387,7 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); +extern int drm_bo_clean_mm(drm_device_t *dev); /* Inline replacements for DRM_IOREMAP macros */ diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index dcbf2d91..1c71f345 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -231,7 +231,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { - fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + fence = kmem_cache_alloc(dev->fence_object_cache, GFP_KERNEL); if (!fence) { ret = -ENOMEM; @@ -241,7 +241,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { - drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + kmem_cache_free(dev->fence_object_cache, fence); goto out; } } @@ -468,18 +468,24 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) return 0; } -static int drm_bo_new_flags(drm_bo_driver_t * driver, +static int drm_bo_new_flags(drm_device_t *dev, uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t * n_flags, uint32_t * n_mask) { uint32_t new_flags = 0; uint32_t new_props; + drm_bo_driver_t *driver = dev->driver->bo_driver; + drm_buffer_manager_t *bm = &dev->bm; /* - * First adjust the mask. Vram is not supported yet. + * First adjust the mask. */ - new_mask &= ~DRM_BO_FLAG_MEM_VRAM; + if (!bm->use_vram) + new_mask &= ~DRM_BO_FLAG_MEM_VRAM; + if (!bm->use_tt) + new_mask &= ~DRM_BO_FLAG_MEM_TT; + if (new_mask & DRM_BO_FLAG_BIND_CACHED) { if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && @@ -986,7 +992,7 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, if (ret) goto out; - ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, + ret = drm_bo_new_flags(dev, bo->flags, (flags & mask) | (bo->flags & ~mask), hint, 0, &new_flags, &bo->mask); @@ -1112,7 +1118,7 @@ int drm_buffer_object_create(drm_file_t * priv, bo->buffer_start = buffer_start; bo->priv_flags = 0; bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; - ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, + ret = drm_bo_new_flags(dev, bo->flags, mask, hint, 1, &new_flags, &bo->mask); DRM_ERROR("New flags: 0x%08x\n", new_flags); if (ret) @@ -1194,7 +1200,12 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) unsigned long next; drm_user_object_t *uo; drm_buffer_object_t *entry; - + + if (!dev->bm.initialized) { + DRM_ERROR("Buffer object manager is not initialized.\n"); + return -EINVAL; + } + do { DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); @@ -1307,9 +1318,87 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } -int drm_bo_clean_mm(drm_file_t *priv) + +/* + * dev->struct_sem locked. + */ + + +static void drm_bo_force_clean(drm_device_t * dev) { - return 0; + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry, *next; + int nice_mode = 1; + int ret = 0; + + list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { + if (entry->fence) { + if (nice_mode) { + unsigned long _end = jiffies + 3*DRM_HZ; + do { + ret = drm_bo_wait(entry, 0, 0); + } while ((ret == -EINTR) && + !time_after_eq(jiffies, _end)); + } else { + drm_fence_usage_deref_locked(dev, entry->fence); + entry->fence = NULL; + } + if (entry->fence) { + DRM_ERROR("Detected GPU hang. " + "Removing waiting buffers.\n"); + nice_mode = 0; + drm_fence_usage_deref_locked(dev, entry->fence); + entry->fence = NULL; + } + + } + DRM_DEBUG("Destroying delayed buffer object\n"); + list_del(&entry->ddestroy); + drm_bo_destroy_locked(dev, entry); + } +} + + +int drm_bo_clean_mm(drm_device_t *dev) +{ + drm_buffer_manager_t *bm = &dev->bm; + int ret = 0; + + + mutex_lock(&dev->struct_mutex); + + if (!bm->initialized) + goto out; + + + drm_bo_force_clean(dev); + bm->use_vram = 0; + bm->use_tt = 0; + + if (bm->has_vram) { + if (drm_mm_clean(&bm->vram_manager)) { + drm_mm_takedown(&bm->vram_manager); + bm->has_vram = 0; + } else + ret = -EBUSY; + } + + if (bm->has_tt) { + if (drm_mm_clean(&bm->tt_manager)) { + drm_mm_takedown(&bm->tt_manager); + bm->has_tt = 0; + } else + ret = -EBUSY; + + if (!ret) + bm->initialized = 0; + } + + out: + mutex_unlock(&dev->struct_mutex); + + return ret; } @@ -1331,33 +1420,38 @@ 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_lock(&dev->struct_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; + /* + * VRAM not supported yet. + */ + + bm->use_vram = 0; if (ret) break; } if (arg.req.tt_p_size) { - DRM_ERROR("Initializing TT 0x%08x 0x%08x\n", + DRM_ERROR("Initializing TT 0x%08x 0x%08x\n", arg.req.tt_p_offset, 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; + bm->use_tt = 1; + if (ret) { if (bm->has_vram) drm_mm_takedown(&bm->vram_manager); @@ -1379,17 +1473,10 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) bm->initialized = 1; break; case mm_takedown: - if (!bm->initialized) { - DRM_ERROR("Memory manager was not initialized\n"); - return -EINVAL; + if (drm_bo_clean_mm(dev)) { + DRM_ERROR("Memory manager not clean. " + "Delaying takedown\n"); } - mutex_lock(&dev->struct_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: DRM_ERROR("Function not implemented yet\n"); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 1bf87703..8a1dcab9 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -128,6 +128,29 @@ static drm_ioctl_desc_t drm_ioctls[] = { #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) + +static void drm_free_mem_cache(kmem_cache_t *cache, + const char *name) +{ + if (!cache) + return; + if (kmem_cache_destroy(cache)) { + DRM_ERROR("Warning! DRM is leaking %s memory.\n", + name); + } +} + +static void drm_free_memory_caches(drm_device_t *dev) +{ + + drm_free_mem_cache(dev->fence_object_cache, "fence object"); + dev->fence_object_cache = NULL; + drm_mm_set_cache(NULL); + drm_free_mem_cache(dev->mm_cache, "memory manager block"); + dev->mm_cache = NULL; +} + + /** * Take down the DRM device. * @@ -249,6 +272,10 @@ int drm_lastclose(drm_device_t * dev) } mutex_unlock(&dev->struct_mutex); + if (drm_bo_clean_mm(dev)) { + DRM_ERROR("DRM memory manager still busy. " + "System is unstable. Please reboot.\n"); + } DRM_DEBUG("lastclose completed\n"); return 0; } @@ -351,7 +378,7 @@ static void drm_cleanup(drm_device_t * dev) } drm_lastclose(dev); - + drm_free_memory_caches(dev); drm_fence_manager_takedown(dev); if (dev->maplist) { diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 897f84c5..b4d13621 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -172,7 +172,7 @@ void drm_fence_usage_deref_locked(drm_device_t * dev, { if (atomic_dec_and_test(&fence->usage)) { drm_fence_unring(dev, &fence->ring); - drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + kmem_cache_free(dev->fence_object_cache, fence); } } @@ -183,7 +183,7 @@ void drm_fence_usage_deref_unlocked(drm_device_t * dev, mutex_lock(&dev->struct_mutex); if (atomic_read(&fence->usage) == 0) { drm_fence_unring(dev, &fence->ring); - drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + kmem_cache_free(dev->fence_object_cache, fence); } mutex_unlock(&dev->struct_mutex); } @@ -426,7 +426,7 @@ static int drm_fence_object_create(drm_file_t * priv, uint32_t type, int ret; drm_fence_object_t *fence; - fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + fence = kmem_cache_alloc(dev->fence_object_cache, GFP_KERNEL); if (!fence) return -ENOMEM; ret = drm_fence_object_init(dev, type, emit, fence); diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 617526bd..6e2da81a 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -42,6 +42,9 @@ */ #include "drmP.h" +#include + +static kmem_cache_t *mm_cache = NULL; drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment) @@ -57,7 +60,9 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, parent->free = 0; return parent; } else { - child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); + + child = (drm_mm_node_t *) kmem_cache_alloc(mm_cache, + GFP_KERNEL); if (!child) return NULL; @@ -105,8 +110,8 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - drm_free(next_node, sizeof(*next_node), - DRM_MEM_MM); + kmem_cache_free(mm_cache, next_node); + } else { next_node->size += cur->size; next_node->start = cur->start; @@ -119,7 +124,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) list_add(&cur->fl_entry, &list_root->fl_entry); } else { list_del(&cur->ml_entry); - drm_free(cur, sizeof(*cur), DRM_MEM_MM); + kmem_cache_free(mm_cache, cur); } } @@ -154,13 +159,34 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, return best; } +void drm_mm_set_cache(kmem_cache_t *cache) +{ + mm_cache = cache; +} + +int drm_mm_clean(drm_mm_t *mm) +{ + struct list_head *head = &mm->root_node.ml_entry; + + return (head->next->next == head); +} + int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) { drm_mm_node_t *child; + if (!mm_cache) { + DRM_ERROR("Memory manager memory cache " + "is not initialized.\n"); + return -EINVAL; + } + INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM); + + + child = (drm_mm_node_t *) kmem_cache_alloc(mm_cache, GFP_KERNEL); + if (!child) return -ENOMEM; @@ -194,8 +220,7 @@ void drm_mm_takedown(drm_mm_t * mm) list_del(&entry->fl_entry); list_del(&entry->ml_entry); - - drm_free(entry, sizeof(*entry), DRM_MEM_MM); + kmem_cache_free(mm_cache, entry); } EXPORT_SYMBOL(drm_mm_takedown); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 16e50a55..2d0f1d24 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -54,6 +54,30 @@ drm_head_t **drm_heads; struct drm_sysfs_class *drm_class; struct proc_dir_entry *drm_proc_root; + +static int drm_create_memory_caches(drm_device_t *dev) +{ + dev->mm_cache = kmem_cache_create("drm_mm_node_t", + sizeof(drm_mm_node_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL,NULL); + if (!dev->mm_cache) + return -ENOMEM; + + drm_mm_set_cache(dev->mm_cache); + dev->fence_object_cache = kmem_cache_create("drm_fence_object_t", + sizeof(drm_fence_object_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL,NULL); + if (!dev->fence_object_cache) + return -ENOMEM; + + return 0; +} + + static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver) @@ -127,6 +151,12 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, goto error_out_unreg; } + retcode = drm_create_memory_caches(dev); + if (retcode) { + DRM_ERROR("Failed creating memory caches\n"); + goto error_out_unreg; + } + drm_fence_manager_init(dev); return 0; From ef8e618cf30ab7dcbe8c7211e0c2508c5520a669 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 16:38:06 +0200 Subject: [PATCH 047/147] Export buffer info on map and validate ioctls. Add an info ioctl operation. --- libdrm/xf86drm.c | 84 ++++++++++++++++++++++++-------- libdrm/xf86mm.h | 2 + linux-core/drm_bo.c | 115 +++++++++++++++++++++++++++++++++----------- shared-core/drm.h | 12 ++++- 4 files changed, 164 insertions(+), 49 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 41ad89cb..aa1a5998 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2567,6 +2567,22 @@ int drmCreateBufList(int numTarget, drmBOList *list) return drmAdjustListNodes(list); } +static void drmBOCopyReply(const drm_bo_arg_reply_t *rep, + drmBO *buf) +{ + buf->handle = rep->handle; + buf->flags = rep->flags; + buf->size = rep->size; + buf->offset = rep->offset; + buf->mapHandle = rep->arg_handle; + buf->mask = rep->mask; + buf->start = rep->buffer_start; + buf->fenceFlags = rep->fence_flags; + buf->replyFlags = rep->rep_flags; +} + + + 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) @@ -2612,16 +2628,10 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, return rep->ret; } - buf->handle = rep->handle; - buf->flags = rep->flags; - buf->size = rep->size; - buf->offset = rep->offset; - buf->mapHandle = rep->arg_handle; + drmBOCopyReply(rep, buf); buf->mapVirtual = NULL; buf->mapCount = 0; buf->virtual = NULL; - buf->mask = rep->mask; - buf->start = rep->buffer_start; return 0; } @@ -2671,17 +2681,12 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) return rep->ret; } - buf->handle = rep->handle; + drmBOCopyReply(rep, buf); buf->type = drm_bo_type_dc; - buf->flags = rep->flags; - buf->size = rep->size; - buf->offset = rep->offset; - buf->mapHandle = rep->arg_handle; buf->mapVirtual = NULL; buf->mapCount = 0; buf->virtual = NULL; - buf->mask = rep->mask; - buf->start = rep->buffer_start; + return 0; } @@ -2777,6 +2782,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, buf->mapFlags = mapFlags; fprintf(stderr, "Address is 0x%08x\n", address); *address = buf->virtual; + drmBOCopyReply(rep, buf); return 0; } @@ -2838,9 +2844,7 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, if (rep->ret) return rep->ret; - buf->offset = rep->offset; - buf->flags = rep->flags; - buf->mask = rep->mask; + drmBOCopyReply(rep, buf); return 0; } @@ -2869,8 +2873,46 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) return rep->ret; return 0; } - +int drmBOInfo(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; + int ret = 0; + + arg.handled = 0; + req->handle = buf->handle; + req->op = drm_bo_info; + 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; + drmBOCopyReply(rep, buf); + return 0; +} + +int drmBufBusy(int fd, drmBO *buf, int *busy) +{ + if (!(buf->flags & DRM_BO_FLAG_SHAREABLE) && + !(buf->replyFlags & DRM_BO_REP_BUSY)) { + *busy = 0; + return 0; + } else { + int ret = drmBOInfo(fd, buf); + if (ret) + return ret; + *busy = (buf->replyFlags & DRM_BO_REP_BUSY); + return 0; + } +} + int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, unsigned mask, @@ -2978,9 +3020,7 @@ int drmBOValidateList(int fd, drmBOList *list) return rep->ret; buf = node->buf; - buf->offset = rep->offset; - buf->flags = rep->flags; - buf->mask = rep->mask; + drmBOCopyReply(rep, buf); } return 0; @@ -2997,6 +3037,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) drm_bo_arg_reply_t *rep; drm_u64_t *prevNext = NULL; drmBO *buf; + unsigned fence_flags; int ret; first = NULL; @@ -3040,6 +3081,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) return -EFAULT; if (rep->ret) return rep->ret; + drmBOCopyReply(rep, buf); } return 0; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index aaee3c0b..a8458b15 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -92,6 +92,8 @@ typedef struct _drmBO{ unsigned long size; unsigned long offset; unsigned long start; + unsigned replyFlags; + unsigned fenceFlags; void *virtual; void *mapVirtual; int mapCount; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1c71f345..317b5f7a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -598,6 +598,32 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, return bo; } +/* + * Call bo->mutex locked. + * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. + * Doesn't do any fence flushing as opposed to the drm_bo_busy function. + */ + + +static int drm_bo_quick_busy(drm_buffer_object_t *bo) +{ + drm_fence_object_t *fence = bo->fence; + + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + if (fence) { + drm_device_t *dev = bo->dev; + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + return 1; + } + return 0; +} + + /* * Call bo->mutex locked. * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. @@ -719,8 +745,36 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, return 0; } +/* + * Fill in the ioctl reply argument with buffer info. + * Bo locked. + */ +static void drm_bo_fill_rep_arg(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->mask = bo->mask; + rep->buffer_start = bo->buffer_start; + rep->fence_flags = bo->fence_flags; + rep->rep_flags = 0; + + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || + drm_bo_quick_busy(bo)) { + DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, DRM_BO_REP_BUSY); + } +} /* @@ -731,7 +785,8 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, */ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, - uint32_t map_flags, int no_wait) + uint32_t map_flags, int no_wait, + drm_bo_arg_reply_t *rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -794,7 +849,8 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, if (atomic_add_negative(-1, &bo->mapped)) DRM_WAKEUP(&bo->event_queue); - } + } else + drm_bo_fill_rep_arg(bo, rep); out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); @@ -973,7 +1029,8 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, } static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, - uint32_t flags, uint32_t mask, uint32_t hint) + uint32_t flags, uint32_t mask, uint32_t hint, + drm_bo_arg_reply_t *rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -1001,13 +1058,33 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, ret = drm_buffer_object_validate(bo, new_flags, !(hint & DRM_BO_HINT_DONT_FENCE), no_wait); + drm_bo_fill_rep_arg(bo, rep); -out: +out: + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); return ret; } +static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, + drm_bo_arg_reply_t *rep) +{ + drm_buffer_object_t *bo; + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + return -EINVAL; + } + mutex_lock(&bo->mutex); + if (!(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + (void) drm_bo_busy(bo); + drm_bo_fill_rep_arg(bo, rep); + mutex_unlock(&bo->mutex); + return 0; +} + + /* * Call bo->mutex locked. */ @@ -1167,24 +1244,6 @@ static int drm_bo_add_user_object(drm_file_t * priv, drm_buffer_object_t * bo, 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->mask = bo->mask; - rep->buffer_start = bo->buffer_start; -} - static int drm_bo_lock_test(drm_device_t * dev, struct file *filp) { LOCK_TEST_WITH_RETURN(dev, filp); @@ -1249,7 +1308,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, req->hint & - DRM_BO_HINT_DONT_BLOCK); + DRM_BO_HINT_DONT_BLOCK, + &rep); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -1289,7 +1349,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; rep.ret = drm_bo_handle_validate(priv, req->handle, req->mask, - req->arg_handle, req->hint); + req->arg_handle, req->hint, + &rep); break; case drm_bo_fence: rep.ret = drm_bo_lock_test(dev, filp); @@ -1297,6 +1358,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; /**/ break; + case drm_bo_info: + rep.ret = drm_bo_handle_info(priv, req->handle, &rep); + break; default: rep.ret = -EINVAL; } @@ -1443,9 +1507,6 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) } if (arg.req.tt_p_size) { - DRM_ERROR("Initializing TT 0x%08x 0x%08x\n", - arg.req.tt_p_offset, - arg.req.tt_p_size); ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, arg.req.tt_p_size); diff --git a/shared-core/drm.h b/shared-core/drm.h index f76fd86f..f781abc6 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -758,10 +758,18 @@ typedef struct drm_bo_arg_request { drm_bo_fence, drm_bo_destroy, drm_bo_reference, - drm_bo_unreference + drm_bo_unreference, + drm_bo_info } op; } drm_bo_arg_request_t; + +/* + * Reply flags + */ + +#define DRM_BO_REP_BUSY 0x00000001 + typedef struct drm_bo_arg_reply { int ret; unsigned handle; @@ -771,6 +779,8 @@ typedef struct drm_bo_arg_reply { unsigned arg_handle; unsigned mask; drm_u64_t buffer_start; + unsigned fence_flags; + unsigned rep_flags; }drm_bo_arg_reply_t; From 405b5d9ca8cc9f6c5c7bb764c684bf74ba7660c6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 18:11:05 +0200 Subject: [PATCH 048/147] Flag bit pattern bugfixes. Remove some error messages. --- libdrm/xf86drm.c | 74 +++++++++++++++++++++++++------------------- linux-core/drm_bo.c | 27 ++++++++-------- linux-core/drm_ttm.c | 2 ++ shared-core/drm.h | 14 ++++----- 4 files changed, 64 insertions(+), 53 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index aa1a5998..073fd0c4 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2598,6 +2598,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, req->type = type; buf->ttm = NULL; + buf->virtual = NULL; switch(type) { case drm_bo_type_ttm: @@ -2631,7 +2632,6 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, drmBOCopyReply(rep, buf); buf->mapVirtual = NULL; buf->mapCount = 0; - buf->virtual = NULL; return 0; } @@ -2642,6 +2642,12 @@ int drmBODestroy(int fd, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + if (buf->mapVirtual) { + (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); + buf->mapVirtual = NULL; + buf->virtual = NULL; + } + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_destroy; @@ -2729,26 +2735,32 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, drm_bo_arg_reply_t *rep = &arg.rep; int ret = 0; + /* + * At the moment, we don't allow recursive mapping of a buffer, since + * the first mapping may have to be unmapped before this one to succeed. + * This might result in a deadlock. We need a DRM mutex mechanism!! + */ + + if (buf->mapCount) { + drmMsg("Recursive mapping is currently not allowed.\n"); + return -EAGAIN; + } + /* * 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; - ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); - if (ret) - return ret; - ++buf->mapCount; - buf->mapVirtual = virtual; - buf->virtual = ((char *) virtual) + buf->start; - fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", - buf->mapVirtual, buf->virtual); - } + if (!buf->virtual) { + drmAddress virtual; + ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); + if (ret) + return ret; + buf->mapVirtual = virtual; + buf->virtual = ((char *) virtual) + buf->start; + fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", + buf->mapVirtual, buf->virtual); } - fprintf(stderr, "Address is 0x%08x\n", address); arg.handled = 0; req->handle = buf->handle; req->mask = mapFlags; @@ -2761,28 +2773,21 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, * 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); - 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 (!arg.handled) return -EFAULT; if (rep->ret) return rep->ret; - + + drmBOCopyReply(rep, buf); buf->mapFlags = mapFlags; - fprintf(stderr, "Address is 0x%08x\n", address); + ++buf->mapCount; *address = buf->virtual; - drmBOCopyReply(rep, buf); return 0; } @@ -2793,13 +2798,6 @@ int drmBOUnmap(int fd, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; - if (buf->mapCount == 0) { - return -EINVAL; - } - - if (--buf->mapCount == 0) { - (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); - } arg.handled = 0; req->handle = buf->handle; @@ -2814,6 +2812,8 @@ int drmBOUnmap(int fd, drmBO *buf) if (rep->ret) return rep->ret; + --buf->mapCount; + return 0; } @@ -2825,6 +2825,11 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, drm_bo_arg_reply_t *rep = &arg.rep; int ret = 0; + if (buf->mapCount) { + drmMsg("Cannot validate while buffer is mapped.\n"); + return -EAGAIN; + } + arg.handled = 0; req->handle = buf->handle; req->mask = flags; @@ -2988,6 +2993,11 @@ int drmBOValidateList(int fd, drmBOList *list) if (prevNext) *prevNext = (unsigned long) arg; + if (node->buf->mapCount) { + drmMsg("Cannot validate while buffer is mapped.\n"); + return -EAGAIN; + } + req->next = 0; prevNext = &req->next; arg->handled = 0; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 317b5f7a..70342ac9 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -70,7 +70,6 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); - DRM_ERROR("Flipping out of AGP\n"); mutex_lock(&dev->struct_mutex); drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); @@ -442,8 +441,9 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - +#ifdef BODEBUG DRM_ERROR("Flipping in to AGP 0x%08lx\n", bo->tt->start); +#endif mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); if (ret) { @@ -459,9 +459,9 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) bo->flags |= DRM_BO_FLAG_MEM_TT; if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { - DRM_ERROR("Flush read caches\n"); ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); - DRM_ERROR("Warning: Could not flush read caches\n"); + if (ret) + DRM_ERROR("Warning: Could not flush read caches\n"); } DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); @@ -919,14 +919,12 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, /* * Flush outstanding fences. */ - DRM_ERROR("Flushing fences\n"); drm_bo_busy(bo); /* * Make sure we're not mapped. */ - DRM_ERROR("Wait unmapped\n"); ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) return ret; @@ -935,7 +933,6 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ - DRM_ERROR("Wait fences\n"); ret = drm_bo_wait(bo, 0, no_wait); if (ret == -EINTR) @@ -979,19 +976,21 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return -EINVAL; } - /* - * Check whether we need to move buffer. - */ - +#ifdef BODEBUG + DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", + new_flags, bo->flags); +#endif ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); - DRM_ERROR("Fence type = 0x%08x\n", bo->fence_flags); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } + /* + * Check whether we need to move buffer. + */ + if (flag_diff & DRM_BO_MASK_MEM) { - DRM_ERROR("Calling move buffer\n"); ret = drm_bo_move_buffer(bo, new_flags, no_wait); if (ret) return ret; @@ -1050,7 +1049,7 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, goto out; ret = drm_bo_new_flags(dev, bo->flags, - (flags & mask) | (bo->flags & ~mask), hint, + (flags & mask) | (bo->mask & ~mask), hint, 0, &new_flags, &bo->mask); if (ret) diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 97e3e96d..26133f9c 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -447,7 +447,9 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); } +#ifdef BODEBUG DRM_ERROR("Unbinding\n"); +#endif be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, diff --git a/shared-core/drm.h b/shared-core/drm.h index f781abc6..a7d778ce 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -693,23 +693,23 @@ typedef struct drm_ttm_arg { */ /* Pinned buffer. */ -#define DRM_BO_FLAG_NO_EVICT 0x00000001 +#define DRM_BO_FLAG_NO_EVICT 0x00000010 /* Always keep a system memory shadow to a vram buffer */ -#define DRM_BO_FLAG_SHADOW_VRAM 0x00000002 +#define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 /* When mapped for reading, make sure the buffer is cached even if it means moving the buffer to system memory */ -#define DRM_BO_FLAG_SHAREABLE 0x00000004 +#define DRM_BO_FLAG_SHAREABLE 0x00000040 /* When there is a choice between VRAM and TT, prefer VRAM. The default behaviour is to prefer TT. */ -#define DRM_BO_FLAG_CACHED 0x00000008 +#define DRM_BO_FLAG_CACHED 0x00000080 /* The buffer is shareable with other processes */ -#define DRM_BO_FLAG_READ_CACHED 0x00001000 +#define DRM_BO_FLAG_READ_CACHED 0x00080000 /* The buffer is currently cached */ -#define DRM_BO_FLAG_PREFER_VRAM 0x00002000 +#define DRM_BO_FLAG_PREFER_VRAM 0x00040000 /* Bind this buffer cached if the hardware supports it. */ -#define DRM_BO_FLAG_BIND_CACHED 0x00004000 +#define DRM_BO_FLAG_BIND_CACHED 0x0002000 /* Translation table aperture */ #define DRM_BO_FLAG_MEM_TT 0x01000000 From a96b61fdc4fc3df50c91ca489f45f12cdad74f69 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 18:11:34 +0200 Subject: [PATCH 049/147] Lindent drm_bo.c --- linux-core/drm_bo.c | 118 ++++++++++++++++++-------------------------- 1 file changed, 49 insertions(+), 69 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 70342ac9..368ec0c5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -198,9 +198,8 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } -int drm_fence_buffer_objects(drm_file_t * priv, - struct list_head *list, - drm_fence_object_t *fence) +int drm_fence_buffer_objects(drm_file_t * priv, + struct list_head *list, drm_fence_object_t * fence) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -212,7 +211,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, struct list_head f_list, *l; mutex_lock(&dev->struct_mutex); - + list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_flags |= entry->fence_flags; @@ -256,7 +255,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, count = 0; l = f_list.next; - while(l != &f_list) { + while (l != &f_list) { entry = list_entry(l, drm_buffer_object_t, head); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); @@ -265,10 +264,10 @@ int drm_fence_buffer_objects(drm_file_t * priv, if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; - if (entry->fence) + if (entry->fence) drm_fence_usage_deref_locked(dev, entry->fence); entry->fence = fence; - DRM_FLAG_MASKED(entry->priv_flags, 0, + DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); list_del_init(&entry->head); @@ -294,7 +293,6 @@ int drm_fence_buffer_objects(drm_file_t * priv, return ret; } - /* * Call bo->mutex locked. * Wait until the buffer is idle. @@ -468,7 +466,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) return 0; } -static int drm_bo_new_flags(drm_device_t *dev, +static int drm_bo_new_flags(drm_device_t * dev, uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t * n_flags, uint32_t * n_mask) { @@ -486,7 +484,6 @@ static int drm_bo_new_flags(drm_device_t *dev, if (!bm->use_tt) new_mask &= ~DRM_BO_FLAG_MEM_TT; - 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) @@ -604,12 +601,10 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, * Doesn't do any fence flushing as opposed to the drm_bo_busy function. */ - -static int drm_bo_quick_busy(drm_buffer_object_t *bo) +static int drm_bo_quick_busy(drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; @@ -622,7 +617,6 @@ static int drm_bo_quick_busy(drm_buffer_object_t *bo) } return 0; } - /* * Call bo->mutex locked. @@ -656,7 +650,6 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, @@ -673,9 +666,9 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) * Wait until a buffer is unmapped. */ -static int drm_bo_wait_unmapped(drm_buffer_object_t *bo, int no_wait) +static int drm_bo_wait_unmapped(drm_buffer_object_t * bo, int no_wait) { - int ret = 0; + int ret = 0; if ((atomic_read(&bo->mapped) >= 0) && no_wait) return -EBUSY; @@ -685,11 +678,11 @@ static int drm_bo_wait_unmapped(drm_buffer_object_t *bo, int no_wait) if (ret == -EINTR) ret = -EAGAIN; - + return ret; } -static int drm_bo_check_unfenced(drm_buffer_object_t *bo) +static int drm_bo_check_unfenced(drm_buffer_object_t * bo) { int ret; @@ -711,17 +704,17 @@ static int drm_bo_check_unfenced(drm_buffer_object_t *bo) * the buffer "unfenced" after validating, but before fencing. */ -static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, +static int drm_bo_wait_unfenced(drm_buffer_object_t * bo, int no_wait, int eagain_if_wait) { int ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - unsigned long _end = jiffies + 3*DRM_HZ; + unsigned long _end = jiffies + 3 * DRM_HZ; if (ret && no_wait) return -EBUSY; else if (!ret) return 0; - + do { mutex_unlock(&bo->mutex); DRM_WAIT_ON(ret, bo->event_queue, 3 * DRM_HZ, @@ -730,7 +723,8 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, if (ret == -EINTR) return -EAGAIN; if (ret) { - DRM_ERROR("Error waiting for buffer to become fenced\n"); + DRM_ERROR + ("Error waiting for buffer to become fenced\n"); return ret; } ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); @@ -750,7 +744,6 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, * Bo locked. */ - static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, drm_bo_arg_reply_t * rep) { @@ -770,13 +763,12 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, rep->fence_flags = bo->fence_flags; rep->rep_flags = 0; - if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || - drm_bo_quick_busy(bo)) { - DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, DRM_BO_REP_BUSY); + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { + DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, + DRM_BO_REP_BUSY); } } - /* * 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, @@ -786,7 +778,7 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, uint32_t map_flags, int no_wait, - drm_bo_arg_reply_t *rep) + drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -827,12 +819,12 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, } 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. */ - + ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) goto out; @@ -849,7 +841,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, if (atomic_add_negative(-1, &bo->mapped)) DRM_WAKEUP(&bo->event_queue); - } else + } else drm_bo_fill_rep_arg(bo, rep); out: mutex_unlock(&bo->mutex); @@ -975,10 +967,8 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Cached binding not implemented yet\n"); return -EINVAL; } - #ifdef BODEBUG - DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", - new_flags, bo->flags); + DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); #endif ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); if (ret) { @@ -1029,7 +1019,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, uint32_t flags, uint32_t mask, uint32_t hint, - drm_bo_arg_reply_t *rep) + drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -1048,42 +1038,43 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, if (ret) goto out; - ret = drm_bo_new_flags(dev, bo->flags, + ret = drm_bo_new_flags(dev, bo->flags, (flags & mask) | (bo->mask & ~mask), hint, 0, &new_flags, &bo->mask); if (ret) goto out; - ret = drm_buffer_object_validate(bo, new_flags, !(hint & DRM_BO_HINT_DONT_FENCE), - no_wait); + ret = + drm_buffer_object_validate(bo, new_flags, + !(hint & DRM_BO_HINT_DONT_FENCE), + no_wait); drm_bo_fill_rep_arg(bo, rep); - -out: - + + out: + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); return ret; } static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, - drm_bo_arg_reply_t *rep) + drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; bo = drm_lookup_buffer_object(priv, handle, 1); if (!bo) { return -EINVAL; - } + } mutex_lock(&bo->mutex); - if (!(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) - (void) drm_bo_busy(bo); + if (!(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + (void)drm_bo_busy(bo); drm_bo_fill_rep_arg(bo, rep); mutex_unlock(&bo->mutex); return 0; } - /* * Call bo->mutex locked. */ @@ -1143,10 +1134,6 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, return ret; } - - - - int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, @@ -1355,8 +1342,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_bo_lock_test(dev, filp); if (rep.ret) break; - /**/ - break; + /**/ break; case drm_bo_info: rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break; @@ -1381,12 +1367,10 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } - /* * dev->struct_sem locked. */ - static void drm_bo_force_clean(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; @@ -1398,11 +1382,11 @@ static void drm_bo_force_clean(drm_device_t * dev) list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { if (entry->fence) { if (nice_mode) { - unsigned long _end = jiffies + 3*DRM_HZ; + unsigned long _end = jiffies + 3 * DRM_HZ; do { ret = drm_bo_wait(entry, 0, 0); - } while ((ret == -EINTR) && - !time_after_eq(jiffies, _end)); + } while ((ret == -EINTR) && + !time_after_eq(jiffies, _end)); } else { drm_fence_usage_deref_locked(dev, entry->fence); entry->fence = NULL; @@ -1422,23 +1406,20 @@ static void drm_bo_force_clean(drm_device_t * dev) } } - -int drm_bo_clean_mm(drm_device_t *dev) +int drm_bo_clean_mm(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; int ret = 0; - mutex_lock(&dev->struct_mutex); if (!bm->initialized) goto out; - drm_bo_force_clean(dev); bm->use_vram = 0; bm->use_tt = 0; - + if (bm->has_vram) { if (drm_mm_clean(&bm->vram_manager)) { drm_mm_takedown(&bm->vram_manager); @@ -1451,20 +1432,19 @@ int drm_bo_clean_mm(drm_device_t *dev) if (drm_mm_clean(&bm->tt_manager)) { drm_mm_takedown(&bm->tt_manager); bm->has_tt = 0; - } else + } else ret = -EBUSY; - + if (!ret) bm->initialized = 0; } - out: + out: mutex_unlock(&dev->struct_mutex); return ret; } - int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -1490,7 +1470,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) mutex_lock(&dev->struct_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, @@ -1499,7 +1479,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) /* * VRAM not supported yet. */ - + bm->use_vram = 0; if (ret) break; From a6b8e3eaf49044e135a0b9288192525f301458d5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 16:57:20 +0200 Subject: [PATCH 050/147] Make memory caches global so that they can be used with multiple heads. --- linux-core/drmP.h | 20 +++++++---- linux-core/drm_bo.c | 12 ++++--- linux-core/drm_drv.c | 82 ++++++++++++++++++++++++++++++------------ linux-core/drm_fence.c | 6 ++-- linux-core/drm_mm.c | 23 +++--------- linux-core/drm_stub.c | 34 +++--------------- 6 files changed, 92 insertions(+), 85 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index c6646212..23766373 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -745,6 +745,18 @@ typedef struct drm_head { struct class_device *dev_class; } drm_head_t; +typedef struct drm_cache { + + /* + * Memory caches + */ + + kmem_cache_t *mm; + kmem_cache_t *fence_object; + kmem_cache_t *ref_object; +} drm_cache_t; + + typedef struct drm_fence_driver{ int no_types; @@ -926,12 +938,6 @@ typedef struct drm_device { drm_fence_manager_t fm; drm_buffer_manager_t bm; - /* - * Memory caches - */ - kmem_cache_t *mm_cache; - kmem_cache_t *fence_object_cache; - } drm_device_t; #if __OS_HAS_AGP @@ -1254,6 +1260,7 @@ extern int drm_put_head(drm_head_t * head); extern unsigned int drm_debug; /* 1 to enable debug output */ extern unsigned int drm_cards_limit; extern drm_head_t **drm_heads; +extern drm_cache_t drm_cache; extern struct drm_sysfs_class *drm_class; extern struct proc_dir_entry *drm_proc_root; @@ -1302,7 +1309,6 @@ extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, unsigned alignment, int best_match); extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern void drm_mm_takedown(drm_mm_t *mm); -extern void drm_mm_set_cache(kmem_cache_t *cache); extern int drm_mm_clean(drm_mm_t *mm); /* diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 368ec0c5..7f50bacf 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -91,7 +91,8 @@ 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->priv_flags & _DRM_BO_FLAG_UNFENCED); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); @@ -229,7 +230,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { - fence = kmem_cache_alloc(dev->fence_object_cache, GFP_KERNEL); + fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) { ret = -ENOMEM; @@ -239,7 +240,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { - kmem_cache_free(dev->fence_object_cache, fence); + kmem_cache_free(drm_cache.fence_object, fence); goto out; } } @@ -1124,8 +1125,9 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, - bo->mask & DRM_BO_FLAG_BIND_CACHED, + bo->num_pages,1, + + /* bo->mask & DRM_BO_FLAG_BIND_CACHED,*/ &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 8a1dcab9..bca7b868 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -129,27 +129,6 @@ static drm_ioctl_desc_t drm_ioctls[] = { #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) -static void drm_free_mem_cache(kmem_cache_t *cache, - const char *name) -{ - if (!cache) - return; - if (kmem_cache_destroy(cache)) { - DRM_ERROR("Warning! DRM is leaking %s memory.\n", - name); - } -} - -static void drm_free_memory_caches(drm_device_t *dev) -{ - - drm_free_mem_cache(dev->fence_object_cache, "fence object"); - dev->fence_object_cache = NULL; - drm_mm_set_cache(NULL); - drm_free_mem_cache(dev->mm_cache, "memory manager block"); - dev->mm_cache = NULL; -} - /** * Take down the DRM device. @@ -378,7 +357,6 @@ static void drm_cleanup(drm_device_t * dev) } drm_lastclose(dev); - drm_free_memory_caches(dev); drm_fence_manager_takedown(dev); if (dev->maplist) { @@ -450,10 +428,67 @@ static struct file_operations drm_stub_fops = { .open = drm_stub_open }; +static int drm_create_memory_caches(void) +{ + drm_cache.mm = kmem_cache_create("drm_mm_node_t", + sizeof(drm_mm_node_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL,NULL); + if (!drm_cache.mm) + return -ENOMEM; + + drm_cache.fence_object= kmem_cache_create("drm_fence_object_t", + sizeof(drm_fence_object_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL,NULL); + if (!drm_cache.ref_object) + return -ENOMEM; + + drm_cache.ref_object= kmem_cache_create("drm_ref_object_t", + sizeof(drm_ref_object_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL,NULL); + if (!drm_cache.ref_object) + return -ENOMEM; + + return 0; +} + +static void drm_free_mem_cache(kmem_cache_t *cache, + const char *name) +{ + if (!cache) + return; + if (kmem_cache_destroy(cache)) { + DRM_ERROR("Warning! DRM is leaking %s memory.\n", + name); + } +} + +static void drm_free_memory_caches(void ) +{ + + drm_free_mem_cache(drm_cache.ref_object, "ref object"); + drm_cache.ref_object = NULL; + drm_free_mem_cache(drm_cache.fence_object, "fence object"); + drm_cache.fence_object = NULL; + drm_free_mem_cache(drm_cache.mm, "memory manager block"); + drm_cache.mm = NULL; +} + + static int __init drm_core_init(void) { - int ret = -ENOMEM; + int ret; + + ret = drm_create_memory_caches(); + if (ret) + goto err_p1; + ret = -ENOMEM; drm_cards_limit = (drm_cards_limit < DRM_MAX_MINOR + 1 ? drm_cards_limit : DRM_MAX_MINOR + 1); drm_heads = drm_calloc(drm_cards_limit, sizeof(*drm_heads), DRM_MEM_STUB); @@ -494,6 +529,7 @@ err_p1: static void __exit drm_core_exit(void) { + drm_free_memory_caches(); remove_proc_entry("dri", NULL); drm_sysfs_destroy(drm_class); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index b4d13621..622cad10 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -172,7 +172,7 @@ void drm_fence_usage_deref_locked(drm_device_t * dev, { if (atomic_dec_and_test(&fence->usage)) { drm_fence_unring(dev, &fence->ring); - kmem_cache_free(dev->fence_object_cache, fence); + kmem_cache_free(drm_cache.fence_object, fence); } } @@ -183,7 +183,7 @@ void drm_fence_usage_deref_unlocked(drm_device_t * dev, mutex_lock(&dev->struct_mutex); if (atomic_read(&fence->usage) == 0) { drm_fence_unring(dev, &fence->ring); - kmem_cache_free(dev->fence_object_cache, fence); + kmem_cache_free(drm_cache.fence_object, fence); } mutex_unlock(&dev->struct_mutex); } @@ -426,7 +426,7 @@ static int drm_fence_object_create(drm_file_t * priv, uint32_t type, int ret; drm_fence_object_t *fence; - fence = kmem_cache_alloc(dev->fence_object_cache, GFP_KERNEL); + fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) return -ENOMEM; ret = drm_fence_object_init(dev, type, emit, fence); diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 6e2da81a..debac9d9 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -44,8 +44,6 @@ #include "drmP.h" #include -static kmem_cache_t *mm_cache = NULL; - drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment) { @@ -61,7 +59,7 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, return parent; } else { - child = (drm_mm_node_t *) kmem_cache_alloc(mm_cache, + child = (drm_mm_node_t *) kmem_cache_alloc(drm_cache.mm, GFP_KERNEL); if (!child) return NULL; @@ -110,7 +108,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - kmem_cache_free(mm_cache, next_node); + kmem_cache_free(drm_cache.mm, next_node); } else { next_node->size += cur->size; @@ -124,7 +122,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) list_add(&cur->fl_entry, &list_root->fl_entry); } else { list_del(&cur->ml_entry); - kmem_cache_free(mm_cache, cur); + kmem_cache_free(drm_cache.mm, cur); } } @@ -159,11 +157,6 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, return best; } -void drm_mm_set_cache(kmem_cache_t *cache) -{ - mm_cache = cache; -} - int drm_mm_clean(drm_mm_t *mm) { struct list_head *head = &mm->root_node.ml_entry; @@ -175,17 +168,11 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) { drm_mm_node_t *child; - if (!mm_cache) { - DRM_ERROR("Memory manager memory cache " - "is not initialized.\n"); - return -EINVAL; - } - INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) kmem_cache_alloc(mm_cache, GFP_KERNEL); + child = (drm_mm_node_t *) kmem_cache_alloc(drm_cache.mm, GFP_KERNEL); if (!child) return -ENOMEM; @@ -220,7 +207,7 @@ void drm_mm_takedown(drm_mm_t * mm) list_del(&entry->fl_entry); list_del(&entry->ml_entry); - kmem_cache_free(mm_cache, entry); + kmem_cache_free(drm_cache.mm, entry); } EXPORT_SYMBOL(drm_mm_takedown); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 2d0f1d24..c4f33813 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -54,29 +54,11 @@ drm_head_t **drm_heads; struct drm_sysfs_class *drm_class; struct proc_dir_entry *drm_proc_root; - -static int drm_create_memory_caches(drm_device_t *dev) -{ - dev->mm_cache = kmem_cache_create("drm_mm_node_t", - sizeof(drm_mm_node_t), - 0, - SLAB_HWCACHE_ALIGN, - NULL,NULL); - if (!dev->mm_cache) - return -ENOMEM; - - drm_mm_set_cache(dev->mm_cache); - dev->fence_object_cache = kmem_cache_create("drm_fence_object_t", - sizeof(drm_fence_object_t), - 0, - SLAB_HWCACHE_ALIGN, - NULL,NULL); - if (!dev->fence_object_cache) - return -ENOMEM; - - return 0; -} - +drm_cache_t drm_cache = +{ .mm = NULL, + .fence_object = NULL, + .ref_object = NULL +}; static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, const struct pci_device_id *ent, @@ -151,12 +133,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, goto error_out_unreg; } - retcode = drm_create_memory_caches(dev); - if (retcode) { - DRM_ERROR("Failed creating memory caches\n"); - goto error_out_unreg; - } - drm_fence_manager_init(dev); return 0; From 550f51b4bf9920718aab2c611b15de3020537f92 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 21:50:12 +0200 Subject: [PATCH 051/147] Buffer object wait IOCTL operation. Remove option to wait for fence / buffers and block signals. --- linux-core/drm_bo.c | 48 ++++++++++++++++++++++++++++++++++++------ linux-core/drm_fence.c | 4 +--- shared-core/drm.h | 6 ++++-- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7f50bacf..1f0bbba5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -299,7 +299,8 @@ int drm_fence_buffer_objects(drm_file_t * priv, * Wait until the buffer is idle. */ -static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) +static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, + int no_wait) { drm_fence_object_t *fence = bo->fence; @@ -317,7 +318,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) return -EBUSY; ret = - drm_fence_object_wait(dev, fence, lazy, !lazy, + drm_fence_object_wait(dev, fence, lazy, ignore_signals, bo->fence_flags); if (ret) return ret; @@ -351,7 +352,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) if (!tt && !bo->vram) goto out; - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) goto out; @@ -805,7 +806,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) { atomic_dec(&bo->mapped); goto out; @@ -926,7 +927,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret == -EINTR) return -EAGAIN; @@ -1073,6 +1074,34 @@ static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, (void)drm_bo_busy(bo); drm_bo_fill_rep_arg(bo, rep); mutex_unlock(&bo->mutex); + drm_bo_usage_deref_unlocked(bo->dev, bo); + return 0; +} + +static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, + uint32_t hint, drm_bo_arg_reply_t * rep) +{ + drm_buffer_object_t *bo; + int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; + int ret; + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + return -EINVAL; + } + mutex_lock(&bo->mutex); + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + if (ret) + goto out; + ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, + 0, no_wait); + if (ret) + goto out; + + drm_bo_fill_rep_arg(bo, rep); +out: + mutex_unlock(&bo->mutex); + drm_bo_usage_deref_unlocked(bo->dev, bo); return 0; } @@ -1348,6 +1377,13 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_info: rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break; + case drm_bo_wait_idle: + rep.ret = drm_bo_handle_wait(priv, req->handle, + req->hint, &rep); + break; + case drm_bo_ref_fence: + rep.ret = -EINVAL; + DRM_ERROR("Function is not implemented yet.\n"); default: rep.ret = -EINVAL; } @@ -1386,7 +1422,7 @@ static void drm_bo_force_clean(drm_device_t * dev) if (nice_mode) { unsigned long _end = jiffies + 3 * DRM_HZ; do { - ret = drm_bo_wait(entry, 0, 0); + ret = drm_bo_wait(entry, 0, 1, 0); } while ((ret == -EINTR) && !time_after_eq(jiffies, _end)); } else { diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 622cad10..1deeaaa5 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -567,9 +567,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) ret = drm_fence_object_wait(dev, fence, arg.flags & DRM_FENCE_FLAG_WAIT_LAZY, - arg. - flags & - DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS, + 0, arg.type); break; case drm_fence_emit: diff --git a/shared-core/drm.h b/shared-core/drm.h index a7d778ce..1a43e0af 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -726,7 +726,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_HINT_DONT_BLOCK 0x00000002 /* Don't place this buffer on the unfenced list.*/ #define DRM_BO_HINT_DONT_FENCE 0x00000004 - +#define DRM_BO_HINT_WAIT_LAZY 0x00000008 @@ -759,7 +759,9 @@ typedef struct drm_bo_arg_request { drm_bo_destroy, drm_bo_reference, drm_bo_unreference, - drm_bo_info + drm_bo_info, + drm_bo_wait_idle, + drm_bo_ref_fence } op; } drm_bo_arg_request_t; From f88c32fd4cb93fe8b9dfa543a26d74733d0cd8ef Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 22:05:21 +0200 Subject: [PATCH 052/147] Libdrm function headers. Some renaming. --- libdrm/xf86drm.c | 10 +++++----- libdrm/xf86mm.h | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 073fd0c4..068d0fb9 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2457,7 +2457,7 @@ static int drmAdjustListNodes(drmBOList *list) return ret; } -static void drmFreeList(drmBOList *list) +void drmBOFreeList(drmBOList *list) { drmBONode *node; drmMMListHead *l; @@ -2483,7 +2483,7 @@ static void drmFreeList(drmBOList *list) } } -int drmResetList(drmBOList *list) { +int drmBOResetList(drmBOList *list) { drmMMListHead *l; int ret; @@ -2547,17 +2547,17 @@ void *drmBOListNext(drmBOList *list, void *iterator) return ret; } -void drmBOListBuf(void *iterator, drmBO **buf) +drmBO *drmBOListBuf(void *iterator) { drmBONode *node; drmMMListHead *l = (drmMMListHead *) iterator; node = DRMLISTENTRY(drmBONode, l, head); - *buf = node->buf; + return node->buf; } -int drmCreateBufList(int numTarget, drmBOList *list) +int drmBOCreateList(int numTarget, drmBOList *list) { DRMINITLISTHEAD(&list->list); DRMINITLISTHEAD(&list->free); diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index a8458b15..623f4d58 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -117,12 +117,63 @@ typedef struct _drmBOList { drmMMListHead free; } drmBOList; + +/* + * TTM functions. + */ + +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); + +/* + * Buffer object list functions. + */ + +extern void drmBOFreeList(drmBOList *list); +extern int drmBOResetList(drmBOList *list); +extern void *drmBOListIterator(drmBOList *list); +extern void *drmBOListNext(drmBOList *list, void *iterator); +extern drmBO *drmBOListBuf(void *iterator); +extern int drmBOCreateList(int numTarget, drmBOList *list); + +/* + * Buffer object functions. + */ + 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); +extern int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, + void **address); +extern int drmBOUnmap(int fd, drmBO *buf); +extern int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, + unsigned hint); +extern int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle); +extern int drmBOInfo(int fd, drmBO *buf); +extern int drmBufBusy(int fd, drmBO *buf, int *busy); + + +extern int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, + unsigned mask, + int *newItem); +extern int drmBOValidateList(int fd, drmBOList *list); +extern int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle); + + +/* + * Initialization functions. + */ + +extern int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, + unsigned long ttPOffset, unsigned long ttPSize); +extern int drmMMTakedown(int fd); #endif From 8c613a8363963330fbf701186f654007d6208bba Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 11:00:52 +0200 Subject: [PATCH 053/147] Fix memory cache initialization. --- linux-core/drm_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index bca7b868..89b20a9d 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -443,7 +443,7 @@ static int drm_create_memory_caches(void) 0, SLAB_HWCACHE_ALIGN, NULL,NULL); - if (!drm_cache.ref_object) + if (!drm_cache.fence_object) return -ENOMEM; drm_cache.ref_object= kmem_cache_create("drm_ref_object_t", @@ -524,6 +524,7 @@ err_p2: unregister_chrdev(DRM_MAJOR, "drm"); drm_free(drm_heads, sizeof(*drm_heads) * drm_cards_limit, DRM_MEM_STUB); err_p1: + drm_free_memory_caches(); return ret; } From 034fc31292edaa25779a938ab3e92ef34697eaf9 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 14:23:18 +0200 Subject: [PATCH 054/147] i915: Only turn on user IRQs when they are needed. --- linux-core/i915_fence.c | 8 ++------ shared-core/i915_drv.h | 6 ++++++ shared-core/i915_irq.c | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 673ebd0e..80ef3ab2 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -58,13 +58,9 @@ static void i915_perform_flush(drm_device_t * dev) diff = sequence - fm->exe_flush_sequence; if (diff < driver->wrap_diff) { fm->pending_exe_flush = 0; - /* - * Turn off user IRQs - */ + i915_user_irq_off(dev_priv); } else { - /* - * Turn on user IRQs - */ + i915_user_irq_on(dev_priv); } } } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 8bf82ed8..f8d08741 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -103,6 +103,10 @@ typedef struct drm_i915_private { struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; + spinlock_t user_irq_lock; + int user_irq_refcount; + uint32_t irq_enable_reg; + int irq_enabled; #ifdef I915_HAVE_FENCE uint32_t flush_sequence; @@ -139,6 +143,8 @@ 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); +extern void i915_user_irq_on(drm_i915_private_t *dev_priv); +extern void i915_user_irq_off(drm_i915_private_t *dev_priv); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4195555e..a3f6a03b 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -102,6 +102,29 @@ int i915_emit_irq(drm_device_t * dev) } +void i915_user_irq_on(drm_i915_private_t *dev_priv) +{ + + spin_lock(&dev_priv->user_irq_lock); + if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount > 0)){ + dev_priv->irq_enable_reg |= USER_INT_FLAG; + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } + spin_unlock(&dev_priv->user_irq_lock); + +} + +void i915_user_irq_off(drm_i915_private_t *dev_priv) +{ + spin_lock(&dev_priv->user_irq_lock); + if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + dev_priv->irq_enable_reg &= ~USER_INT_FLAG; + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } + spin_unlock(&dev_priv->user_irq_lock); +} + + static int i915_wait_irq(drm_device_t * dev, int irq_nr) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -114,9 +137,11 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr) return 0; dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - + + i915_user_irq_on(dev_priv); DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); + i915_user_irq_off(dev_priv); if (ret == DRM_ERR(EBUSY)) { DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", @@ -211,7 +236,11 @@ static int i915_enable_interrupt (drm_device_t *dev) __FUNCTION__, dev_priv->vblank_pipe); return DRM_ERR(EINVAL); } - I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); + dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; + dev_priv->user_irq_refcount = 0; + dev_priv->irq_enable_reg = flag; + I915_WRITE16(I915REG_INT_ENABLE_R, flag); + dev_priv->irq_enabled = 1; return 0; } @@ -290,6 +319,7 @@ void i915_driver_irq_uninstall(drm_device_t * dev) if (!dev_priv) return; + dev_priv->irq_enabled = 0; I915_WRITE16(I915REG_HWSTAM, 0xffff); I915_WRITE16(I915REG_INT_MASK_R, 0xffff); I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); From 604215396847a7964fd7d68aa89d4f778b3bf22b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 18:00:25 +0200 Subject: [PATCH 055/147] Fence all unfenced buffers function. --- libdrm/xf86drm.c | 15 +++++++ libdrm/xf86drm.h | 1 + linux-core/drmP.h | 14 +++++- linux-core/drm_bo.c | 33 +++++++-------- linux-core/drm_fence.c | 96 ++++++++++++++++++++++++++---------------- shared-core/drm.h | 3 +- 6 files changed, 105 insertions(+), 57 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 068d0fb9..6d087427 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2259,6 +2259,21 @@ int drmFenceCreate(int fd, int shareable, int class,unsigned type, fence->signaled = 0; return 0; } + +int drmFenceBuffers(int fd, int shareable, drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0; + arg.op = drm_fence_buffers; + 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; +} int drmFenceDestroy(int fd, const drmFence *fence) { diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index f257deda..be1eeeff 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -626,6 +626,7 @@ extern int drmFenceSignaled(int fd, drmFence *fence); extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, int lazy, int ignore_signals); extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); +extern int drmFenceBuffers(int fd, int shareable, drmFence *fence); /* TTMS */ extern int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 23766373..7de7422b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1379,10 +1379,16 @@ extern void drm_fence_usage_deref_locked(drm_device_t * dev, drm_fence_object_t * fence); extern void drm_fence_usage_deref_unlocked(drm_device_t * dev, drm_fence_object_t * fence); -extern int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, - drm_fence_object_t * fence); extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask); +extern int drm_fence_object_create(drm_device_t *dev, uint32_t type, + int emit, drm_fence_object_t **c_fence); +extern int drm_fence_add_user_object(drm_file_t *priv, + drm_fence_object_t *fence, + int shareable); + + + extern int drm_fence_ioctl(DRM_IOCTL_ARGS); @@ -1394,6 +1400,10 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_clean_mm(drm_device_t *dev); +extern int drm_fence_buffer_objects(drm_file_t * priv, + struct list_head *list, + drm_fence_object_t *fence, + drm_fence_object_t **used_fence); /* Inline replacements for DRM_IOREMAP macros */ diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1f0bbba5..68af5c31 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -199,8 +199,15 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } +/* + * Note. The caller has to register (if applicable) + * and deregister fence object usage. + */ + int drm_fence_buffer_objects(drm_file_t * priv, - struct list_head *list, drm_fence_object_t * fence) + struct list_head *list, + drm_fence_object_t *fence, + drm_fence_object_t **used_fence) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -230,19 +237,9 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { - fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); - - if (!fence) { - ret = -ENOMEM; - goto out; - } - - ret = drm_fence_object_init(dev, fence_flags, 1, fence); - - if (ret) { - kmem_cache_free(drm_cache.fence_object, fence); - goto out; - } + ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + if (ret) + goto out; } /* @@ -285,14 +282,14 @@ int drm_fence_buffer_objects(drm_file_t * priv, drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } - if (!count) - drm_fence_usage_deref_locked(dev, fence); - else if (count > 1) - atomic_add(count - 1, &fence->usage); + atomic_add(count, &fence->usage); out: mutex_unlock(&dev->struct_mutex); + *used_fence = fence; return ret; } +EXPORT_SYMBOL(drm_fence_buffer_objects); + /* * Call bo->mutex locked. diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 1deeaaa5..fd43d8bc 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -417,14 +417,28 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, EXPORT_SYMBOL(drm_fence_object_init); -static int drm_fence_object_create(drm_file_t * priv, uint32_t type, - int emit, int shareable, - uint32_t * user_handle, - drm_fence_object_t ** c_fence) +int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, + int shareable) { drm_device_t *dev = priv->head->dev; int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_add_user_object(priv, &fence->base, shareable); + mutex_unlock(&dev->struct_mutex); + if (ret) + return ret; + fence->base.type = drm_fence_type; + fence->base.remove = &drm_fence_object_destroy; + return 0; +} +EXPORT_SYMBOL(drm_fence_add_user_object); + +int drm_fence_object_create(drm_device_t *dev, uint32_t type, + int emit, drm_fence_object_t **c_fence) +{ drm_fence_object_t *fence; + int ret; fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) @@ -434,23 +448,11 @@ static int drm_fence_object_create(drm_file_t * priv, uint32_t type, drm_fence_usage_deref_unlocked(dev, fence); return ret; } - - mutex_lock(&dev->struct_mutex); - ret = drm_add_user_object(priv, &fence->base, shareable); - mutex_unlock(&dev->struct_mutex); - if (ret) { - drm_fence_usage_deref_unlocked(dev, fence); - *c_fence = NULL; - *user_handle = 0; - return ret; - } - fence->base.type = drm_fence_type; - fence->base.remove = &drm_fence_object_destroy; - *user_handle = fence->base.hash.key; - *c_fence = fence; - + *c_fence = fence; return 0; } +EXPORT_SYMBOL(drm_fence_object_create); + void drm_fence_manager_init(drm_device_t * dev) { @@ -511,24 +513,29 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); switch (arg.op) { - case drm_fence_create:{ - int emit = arg.flags & DRM_FENCE_FLAG_EMIT; - if (emit) - LOCK_TEST_WITH_RETURN(dev, filp); - ret = - drm_fence_object_create(priv, arg.type, - emit, - arg. - flags & - DRM_FENCE_FLAG_SHAREABLE, - &arg.handle, &fence); - if (ret) - return ret; - mutex_lock(&dev->struct_mutex); - atomic_inc(&fence->usage); - mutex_unlock(&dev->struct_mutex); - break; + case drm_fence_create: + if (arg.flags & DRM_FENCE_FLAG_EMIT) + LOCK_TEST_WITH_RETURN(dev, filp); + ret = drm_fence_object_create(dev, arg.type, + arg.flags & DRM_FENCE_FLAG_EMIT, + &fence); + if (ret) + return ret; + ret = drm_fence_add_user_object(priv, fence, + arg.flags & + DRM_FENCE_FLAG_SHAREABLE); + if (ret) { + drm_fence_usage_deref_unlocked(dev, fence); + return ret; } + + /* + * usage > 0. No need to lock dev->struct_mutex; + */ + + atomic_inc(&fence->usage); + arg.handle = fence->base.hash.key; + break; case drm_fence_destroy: mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, arg.handle); @@ -577,6 +584,23 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) return -EINVAL; ret = drm_fence_object_emit(dev, fence, arg.type); break; + case drm_fence_buffers: + if (!dev->bm.initialized) { + DRM_ERROR("Buffer object manager is not initialized\n"); + return -EINVAL; + } + LOCK_TEST_WITH_RETURN(dev, filp); + ret = drm_fence_buffer_objects(priv, NULL, NULL, &fence); + if (ret) + return ret; + ret = drm_fence_add_user_object(priv, fence, + arg.flags & + DRM_FENCE_FLAG_SHAREABLE); + if (ret) + return ret; + atomic_inc(&fence->usage); + arg.handle = fence->base.hash.key; + break; default: return -EINVAL; } diff --git a/shared-core/drm.h b/shared-core/drm.h index 1a43e0af..e39f888a 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -659,7 +659,8 @@ typedef struct drm_fence_arg { drm_fence_signaled, drm_fence_flush, drm_fence_wait, - drm_fence_emit + drm_fence_emit, + drm_fence_buffers } op; } drm_fence_arg_t; From e3f54ecdd9d266607afd7d8b62960b2154b63e9d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 19:36:45 +0200 Subject: [PATCH 056/147] Multithreaded application note. --- libdrm/xf86drm.c | 26 +++----------------------- libdrm/xf86mm.h | 13 +++++++++++++ 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6d087427..dd97e26e 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2750,17 +2750,6 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, drm_bo_arg_reply_t *rep = &arg.rep; int ret = 0; - /* - * At the moment, we don't allow recursive mapping of a buffer, since - * the first mapping may have to be unmapped before this one to succeed. - * This might result in a deadlock. We need a DRM mutex mechanism!! - */ - - if (buf->mapCount) { - drmMsg("Recursive mapping is currently not allowed.\n"); - return -EAGAIN; - } - /* * Make sure we have a virtual address of the buffer. */ @@ -2827,8 +2816,6 @@ int drmBOUnmap(int fd, drmBO *buf) if (rep->ret) return rep->ret; - --buf->mapCount; - return 0; } @@ -2840,11 +2827,6 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, drm_bo_arg_reply_t *rep = &arg.rep; int ret = 0; - if (buf->mapCount) { - drmMsg("Cannot validate while buffer is mapped.\n"); - return -EAGAIN; - } - arg.handled = 0; req->handle = buf->handle; req->mask = flags; @@ -2853,10 +2835,12 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, 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) @@ -3008,11 +2992,6 @@ int drmBOValidateList(int fd, drmBOList *list) if (prevNext) *prevNext = (unsigned long) arg; - if (node->buf->mapCount) { - drmMsg("Cannot validate while buffer is mapped.\n"); - return -EAGAIN; - } - req->next = 0; prevNext = &req->next; arg->handled = 0; @@ -3030,6 +3009,7 @@ int drmBOValidateList(int fd, drmBOList *list) ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); } while (ret && errno == -EAGAIN); + if (ret) return -errno; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 623f4d58..43ea71b8 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -31,6 +31,18 @@ #include #include "drm.h" +/* + * Note on multithreaded applications using this interface. + * Libdrm is not threadsafe, so common buffer, TTM, and fence objects need to + * be protected using an external mutex. + * + * Note: Don't protect the following functions, as it may lead to deadlocks: + * drmBOUnmap(), drmFenceBuffers(). + * The kernel is synchronizing and refcounting buffer maps. + * User space only needs to refcount object usage within the same application. + */ + + /* * List macros heavily inspired by the Linux kernel * list handling. No list looping yet. @@ -82,6 +94,7 @@ typedef struct _drmMMListHead ((__type *)(((char *) (__item)) - offsetof(__type, __field))) + typedef struct _drmBO{ drm_bo_type_t type; unsigned handle; From 99acb7936660843090ea8a9f22d2d50d9433e0de Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 8 Sep 2006 17:24:38 +0200 Subject: [PATCH 057/147] Various bugfixes. --- libdrm/xf86drm.c | 79 +++++++++++++-------- linux-core/drmP.h | 2 +- linux-core/drm_agpsupport.c | 1 + linux-core/drm_bo.c | 136 +++++++++++++++++++++--------------- linux-core/drm_compat.c | 7 +- linux-core/drm_fence.c | 15 ++++ linux-core/drm_ttm.c | 63 ++++++++++++++--- linux-core/drm_ttm.h | 3 + linux-core/i915_fence.c | 17 +++-- shared-core/drm.h | 4 +- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 2 +- 12 files changed, 227 insertions(+), 103 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index dd97e26e..298b812a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2512,6 +2512,7 @@ int drmBOResetList(drmBOList *list) { DRMLISTDEL(l); DRMLISTADD(l, &list->free); list->numOnList--; + l = list->list.next; } return drmAdjustListNodes(list); } @@ -2603,8 +2604,8 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, 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; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; arg.handled = 0; req->mask = mask; @@ -2628,6 +2629,9 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, req->buffer_start = (unsigned long) user_buffer; buf->virtual = user_buffer; break; + case drm_bo_type_fake: + req->buffer_start = start; + break; default: return -EINVAL; } @@ -2654,10 +2658,10 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, 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; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; - if (buf->mapVirtual) { + if (buf->mapVirtual && (buf->type != drm_bo_type_fake)) { (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); buf->mapVirtual = NULL; buf->virtual = NULL; @@ -2685,8 +2689,8 @@ 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; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; arg.handled = 0; req->handle = handle; @@ -2714,9 +2718,16 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) 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; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; + + if (buf->mapVirtual && (buf->type != drm_bo_type_fake)) { + (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); + buf->mapVirtual = NULL; + buf->virtual = NULL; + } + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unreference; @@ -2746,23 +2757,25 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; /* * Make sure we have a virtual address of the buffer. */ - if (!buf->virtual) { + if (!buf->virtual && buf->type != drm_bo_type_fake) { drmAddress virtual; ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); if (ret) return ret; buf->mapVirtual = virtual; buf->virtual = ((char *) virtual) + buf->start; +#ifdef BODEBUG fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", buf->mapVirtual, buf->virtual); +#endif } arg.handled = 0; @@ -2799,8 +2812,8 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, 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; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; arg.handled = 0; @@ -2823,8 +2836,8 @@ 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; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; arg.handled = 0; @@ -2856,8 +2869,8 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, 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; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; arg.handled = 0; @@ -2881,8 +2894,8 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) int drmBOInfo(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; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; arg.handled = 0; @@ -2963,6 +2976,7 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, cur->arg1 |= mask; cur->arg0 = (memFlags & flags) | ((cur->arg0 | flags) & cur->arg1); } + return 0; } @@ -2984,7 +2998,7 @@ int drmBOValidateList(int fd, drmBOList *list) node = DRMLISTENTRY(drmBONode, l, head); arg = &node->bo_arg; - req = &arg->req; + req = &arg->d.req; if (!first) first = arg; @@ -2999,14 +3013,20 @@ int drmBOValidateList(int fd, drmBOList *list) req->op = drm_bo_validate; req->mask = node->arg0; req->hint = 0; - req->arg_handle = node->arg1; + req->arg_handle = node->arg1 | DRM_BO_MASK_MEM; +#ifdef BODEBUG + fprintf(stderr, "Offset 0x%08x, Handle 0x%08x, " + "mask 0x%08x flags 0x%08x\n", + node->buf->offset, + req->handle, req->arg_handle, req->mask); +#endif } if (!first) return 0; do{ - ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, first); } while (ret && errno == -EAGAIN); @@ -3015,9 +3035,8 @@ int drmBOValidateList(int fd, drmBOList *list) for (l = list->list.next; l != &list->list; l = l->next) { node = DRMLISTENTRY(drmBONode, l, head); - arg = &node->bo_arg; - rep = &arg->rep; + rep = &arg->d.rep; if (!arg->handled) return -EFAULT; @@ -3026,6 +3045,10 @@ int drmBOValidateList(int fd, drmBOList *list) buf = node->buf; drmBOCopyReply(rep, buf); +#ifdef BODEBUG + fprintf(stderr,"Offset 0x%08x, Flags 0x%08x\n", + buf->offset, buf->flags); +#endif } return 0; @@ -3051,7 +3074,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) node = DRMLISTENTRY(drmBONode, l, head); arg = &node->bo_arg; - req = &arg->req; + req = &arg->d.req; if (!first) first = arg; @@ -3071,7 +3094,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) if (!first) return 0; - ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, first); if (ret) return -errno; @@ -3080,7 +3103,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) node = DRMLISTENTRY(drmBONode, l, head); arg = &node->bo_arg; - rep = &arg->rep; + rep = &arg->d.rep; if (!arg->handled) return -EFAULT; diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 7de7422b..da14bdfd 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -801,7 +801,7 @@ typedef struct drm_buffer_manager{ struct list_head unfenced; struct list_head ddestroy; struct list_head other; - struct timer_list timer; + struct work_struct wq; uint32_t fence_flags; } drm_buffer_manager_t; diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index e7226f1f..60ebc567 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -630,6 +630,7 @@ static void drm_agp_clear_ttm(drm_ttm_backend_t *backend) { } agp_free_memory(mem); } + agp_priv->mem = NULL; } diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 68af5c31..74722b1b 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -98,10 +98,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) 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); - } + schedule_delayed_work(&bm->wq, 2); return; } else { @@ -109,15 +106,14 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) bo->fence = NULL; } } - /* * Take away from lru lists. */ - list_del(&bo->head); + list_del_init(&bo->head); if (bo->tt) { - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm_region(bo->ttm_region); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -152,7 +148,9 @@ static void drm_bo_delayed_delete(drm_device_t * dev) entry->fence = NULL; } if (!entry->fence) { - DRM_DEBUG("Destroying delayed buffer object\n"); +#ifdef BODEBUG + DRM_ERROR("Destroying delayed buffer object\n"); +#endif list_del(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); } @@ -161,16 +159,18 @@ static void drm_bo_delayed_delete(drm_device_t * dev) mutex_unlock(&dev->struct_mutex); } -static void drm_bo_delayed_timer(unsigned long data) +static void drm_bo_delayed_workqueue(void *data) { drm_device_t *dev = (drm_device_t *) data; drm_buffer_manager_t *bm = &dev->bm; +#ifdef BODEBUG + DRM_ERROR("Delayed delete Worker\n"); +#endif 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_lock(&dev->struct_mutex); + if (!list_empty(&bm->ddestroy)) { + schedule_delayed_work(&bm->wq, 2); } mutex_unlock(&dev->struct_mutex); } @@ -220,14 +220,29 @@ int drm_fence_buffer_objects(drm_file_t * priv, mutex_lock(&dev->struct_mutex); + if (!list) + list = &bm->unfenced; + list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_flags |= entry->fence_flags; count++; } - if (!count) + if (!count) { + DRM_ERROR("No buffers to fence\n"); + ret = -EINVAL; goto out; + } + + /* + * Transfer to a local list before we release the dev->struct_mutex; + * This is so we don't get any new unfenced objects while fencing + * these. + */ + + list_add_tail(&f_list, list); + list_del_init(list); if (fence) { if ((fence_flags & fence->type) != fence_flags) { @@ -237,20 +252,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { + mutex_unlock(&dev->struct_mutex); ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + mutex_lock(&dev->struct_mutex); if (ret) goto out; } - /* - * Transfer to a private list before we release the dev->struct_mutex; - * This is so we don't get any new unfenced objects while fencing - * these. - */ - - f_list = *list; - INIT_LIST_HEAD(list); - count = 0; l = f_list.next; while (l != &f_list) { @@ -259,7 +267,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); mutex_lock(&dev->struct_mutex); - + list_del_init(l); if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; if (entry->fence) @@ -268,7 +276,6 @@ int drm_fence_buffer_objects(drm_file_t * priv, DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); - list_del_init(&entry->head); if (entry->flags & DRM_BO_FLAG_NO_EVICT) list_add_tail(&entry->head, &bm->other); else if (entry->flags & DRM_BO_FLAG_MEM_TT) @@ -277,12 +284,19 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_add_tail(&entry->head, &bm->vram_lru); else list_add_tail(&entry->head, &bm->other); + } else { +#ifdef BODEBUG + DRM_ERROR("Huh? Fenced object on unfenced list\n"); +#endif } mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } atomic_add(count, &fence->usage); +#ifdef BODEBUG + DRM_ERROR("Fenced %d buffers\n", count); +#endif out: mutex_unlock(&dev->struct_mutex); *used_fence = fence; @@ -303,7 +317,6 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, drm_fence_object_t *fence = bo->fence; int ret; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -424,6 +437,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) } else { buf->vram = node; } + buf->offset = node->start * PAGE_SIZE; return 0; } @@ -431,6 +445,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; + drm_ttm_backend_t *be; int ret; BUG_ON(bo->tt); @@ -450,7 +465,8 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - if (bo->ttm_region->be->needs_cache_adjust(bo->ttm_region->be)) + be = bo->ttm_region->be; + if (be->needs_cache_adjust(be)) bo->flags &= ~DRM_BO_FLAG_CACHED; bo->flags &= ~DRM_BO_MASK_MEM; bo->flags |= DRM_BO_FLAG_MEM_TT; @@ -458,7 +474,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); if (ret) - DRM_ERROR("Warning: Could not flush read caches\n"); + DRM_ERROR("Could not flush read caches\n"); } DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); @@ -776,12 +792,13 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, */ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, - uint32_t map_flags, int no_wait, + uint32_t map_flags, unsigned hint, drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; int ret = 0; + int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); @@ -791,9 +808,11 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, return -EINVAL; mutex_lock(&bo->mutex); - ret = drm_bo_wait_unfenced(bo, no_wait, 0); - if (ret) - goto out; + if (!(hint & DRM_BO_HINT_ALLOW_UNFENCED_MAP)) { + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + if (ret) + goto out; + } /* * If this returns true, we are currently unmapped. @@ -979,7 +998,11 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Check whether we need to move buffer. */ - if (flag_diff & DRM_BO_MASK_MEM) { + if ((bo->type != drm_bo_type_fake) && (flag_diff & DRM_BO_MASK_MEM)) { + if (bo->type == drm_bo_type_user) { + DRM_ERROR("User buffers are not implemented yet.\n"); + return -EINVAL; + } ret = drm_bo_move_buffer(bo, new_flags, no_wait); if (ret) return ret; @@ -1151,7 +1174,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages,1, + bo->num_pages, 0, /* bo->mask & DRM_BO_FLAG_BIND_CACHED,*/ &bo->ttm_region); @@ -1177,9 +1200,11 @@ int drm_buffer_object_create(drm_file_t * priv, int ret = 0; uint32_t new_flags; unsigned long num_pages; - + drm_bo_delayed_delete(dev); - if (buffer_start & ~PAGE_MASK) { + + if ((buffer_start & ~PAGE_MASK) && + (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } @@ -1206,24 +1231,24 @@ int drm_buffer_object_create(drm_file_t * priv, bo->dev = dev; bo->type = type; bo->num_pages = num_pages; - bo->buffer_start = buffer_start; + if (bo->type == drm_bo_type_fake) { + bo->offset = buffer_start; + bo->buffer_start = 0; + } else { + bo->buffer_start = buffer_start; + } bo->priv_flags = 0; bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; ret = drm_bo_new_flags(dev, bo->flags, mask, hint, 1, &new_flags, &bo->mask); - DRM_ERROR("New flags: 0x%08x\n", new_flags); if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, ttm_handle); if (ret) goto out_err; -#if 1 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; @@ -1268,7 +1293,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t rep; unsigned long next; drm_user_object_t *uo; @@ -1321,8 +1346,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, - req->hint & - DRM_BO_HINT_DONT_BLOCK, + req->hint, &rep); break; case drm_bo_destroy: @@ -1394,10 +1418,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return -EAGAIN; arg.handled = 1; - arg.rep = rep; + arg.d.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); data = next; - } while (data); return 0; } @@ -1409,17 +1432,22 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) static void drm_bo_force_clean(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; - - drm_buffer_object_t *entry, *next; + struct list_head *l; + drm_buffer_object_t *entry; int nice_mode = 1; int ret = 0; - list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { + l = bm->ddestroy.next; + while(l != &bm->ddestroy) { + entry = list_entry(l, drm_buffer_object_t, ddestroy); + list_del(l); if (entry->fence) { if (nice_mode) { unsigned long _end = jiffies + 3 * DRM_HZ; do { + mutex_unlock(&dev->struct_mutex); ret = drm_bo_wait(entry, 0, 1, 0); + mutex_lock(&dev->struct_mutex); } while ((ret == -EINTR) && !time_after_eq(jiffies, _end)); } else { @@ -1436,8 +1464,8 @@ static void drm_bo_force_clean(drm_device_t * dev) } DRM_DEBUG("Destroying delayed buffer object\n"); - list_del(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); + l = bm->ddestroy.next; } } @@ -1541,11 +1569,9 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_LIST_HEAD(&bm->ddestroy); INIT_LIST_HEAD(&bm->other); - init_timer(&bm->timer); - bm->timer.function = &drm_bo_delayed_timer; - bm->timer.data = (unsigned long)dev; - + INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; + break; case mm_takedown: if (drm_bo_clean_mm(dev)) { diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 86bae306..162e4656 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -59,9 +59,14 @@ static inline void change_pte_range(struct mm_struct *mm, pmd_t * pmd, do { if (pte_present(*pte)) { pte_t ptent; - ptent = *pte; ptep_get_and_clear(mm, addr, pte); + ptent = *pte; lazy_mmu_prot_update(ptent); + } else { + ptep_get_and_clear(mm, addr, pte); + } + if (!pte_none(*pte)) { + DRM_ERROR("Ugh. Pte was presen\n"); } } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap(pte - 1); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index fd43d8bc..eaaf7f40 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -111,6 +111,10 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) relevant = type & fence->type; if ((fence->signaled | relevant) != fence->signaled) { fence->signaled |= relevant; +#ifdef BODEBUG + DRM_ERROR("Fence 0x%08lx signaled 0x%08x\n", + fence->base.hash.key, fence->signaled); +#endif fence->submitted_flush |= relevant; wake = 1; } @@ -130,6 +134,10 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) */ if (!(fence->type & ~fence->signaled)) { +#ifdef BODEBUG + DRM_ERROR("Fence completely signaled 0x%08lx\n", + fence->base.hash.key); +#endif fence_list = &fence->ring; for (i = 0; i < driver->no_types; ++i) { if (fm->fence_types[i] == fence_list) @@ -172,6 +180,10 @@ void drm_fence_usage_deref_locked(drm_device_t * dev, { if (atomic_dec_and_test(&fence->usage)) { drm_fence_unring(dev, &fence->ring); +#ifdef BODEBUG + DRM_ERROR("Destroyed a fence object 0x%08lx\n", + fence->base.hash.key); +#endif kmem_cache_free(drm_cache.fence_object, fence); } } @@ -430,6 +442,9 @@ int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, return ret; fence->base.type = drm_fence_type; fence->base.remove = &drm_fence_object_destroy; +#ifdef BODEBUG + DRM_ERROR("Fence 0x%08lx created\n", fence->base.hash.key); +#endif return 0; } EXPORT_SYMBOL(drm_fence_add_user_object); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 26133f9c..a83d6401 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,6 +42,38 @@ typedef struct drm_val_action { int validated; } drm_val_action_t; +/* + * Use kmalloc if possible. Otherwise fall back to vmalloc. + */ + + +static void *ttm_alloc(unsigned long size, int type, int *do_vmalloc) +{ + void *ret = NULL; + + *do_vmalloc = 0; + if (size <= 4*PAGE_SIZE) { + ret = drm_alloc(size, type); + } + if (!ret) { + *do_vmalloc = 1; + ret = vmalloc(size); + } + return ret; +} + +static void ttm_free(void *pointer, unsigned long size, int type, + int do_vfree) +{ + if (!do_vfree) { + drm_free(pointer, size, type); + }else { + vfree(pointer); + } +} + + + /* * 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 @@ -161,6 +193,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, 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), @@ -205,7 +238,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) return -EBUSY; } - DRM_ERROR("Destroying a ttm\n"); + DRM_DEBUG("Destroying a ttm\n"); if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = @@ -231,12 +264,13 @@ int drm_destroy_ttm(drm_ttm_t * ttm) } } global_flush_tlb(); - vfree(ttm->pages); + ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), + DRM_MEM_TTM, ttm->pages_vmalloc); ttm->pages = NULL; } if (ttm->page_flags) { - vfree(ttm->page_flags); + ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM, ttm->pf_vmalloc); ttm->page_flags = NULL; } @@ -280,7 +314,8 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); + ttm->page_flags = ttm_alloc(ttm->num_pages * sizeof(*ttm->page_flags), + DRM_MEM_TTM, &ttm->pf_vmalloc); if (!ttm->page_flags) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page_flags table\n"); @@ -288,7 +323,8 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) } memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); - ttm->pages = vmalloc(ttm->num_pages * sizeof(*ttm->pages)); + ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), + DRM_MEM_TTM, &ttm->pages_vmalloc); if (!ttm->pages) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page table\n"); @@ -483,12 +519,13 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) uint32_t *cur_page_flags; int i; - DRM_ERROR("Destroying a TTM region\n"); + DRM_DEBUG("Destroying a TTM region\n"); list_del_init(&entry->head); drm_unbind_ttm_region(entry); if (be) { be->clear(entry->be); +#if 0 /* Hmm, Isn't this done in unbind? */ if (be->needs_cache_adjust(be)) { int ret = drm_ttm_lock_mmap_sem(ttm); drm_ttm_lock_mm(ttm, 0, 1); @@ -500,6 +537,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) if (!ret) drm_ttm_unlock_mm(ttm, 1, 0); } +#endif be->destroy(be); } cur_page_flags = ttm->page_flags + entry->page_offset; @@ -609,6 +647,12 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; + + drm_ttm_lock_mm(ttm, 0, 1); + unmap_vma_pages(ttm, region->page_offset, + region->num_pages); + drm_ttm_unlock_mm(ttm, 0, 1); + drm_set_caching(ttm, region->page_offset, region->num_pages, DRM_TTM_PAGE_UNCACHED, 1); } else { @@ -676,7 +720,9 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry) page_cache_release(*cur_page); cur_page++; } - vfree(entry->anon_pages); + ttm_free(entry->anon_pages, + sizeof(*entry->anon_pages)*entry->anon_locked, + DRM_MEM_TTM, entry->pages_vmalloc); } be->destroy(be); @@ -721,7 +767,8 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, return -EFAULT; } - tmp->anon_pages = vmalloc(sizeof(*(tmp->anon_pages)) * len); + tmp->anon_pages = ttm_alloc(sizeof(*(tmp->anon_pages)) * len, + DRM_MEM_TTM, &tmp->pages_vmalloc); if (!tmp->anon_pages) { drm_user_destroy_region(tmp); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index d647578c..5c65e747 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -70,6 +70,7 @@ typedef struct drm_ttm_backend_list { drm_file_t *anon_owner; struct page **anon_pages; int anon_locked; + int pages_vmalloc; enum { ttm_bound, ttm_evicted, @@ -99,6 +100,8 @@ typedef struct drm_ttm { atomic_t vma_count; int mmap_sem_locked; int destroy; + int pages_vmalloc; + int pf_vmalloc; } drm_ttm_t; typedef struct drm_ttm_object { diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 80ef3ab2..20e12d6a 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -55,13 +55,18 @@ static void i915_perform_flush(drm_device_t * dev) 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; + } + + diff = sequence - fm->exe_flush_sequence; + if (diff < driver->wrap_diff) { + fm->pending_exe_flush = 0; + if (dev_priv->fence_irq_on) { i915_user_irq_off(dev_priv); - } else { - i915_user_irq_on(dev_priv); + dev_priv->fence_irq_on = 0; } + } else if (!dev_priv->fence_irq_on) { + i915_user_irq_on(dev_priv); + dev_priv->fence_irq_on = 1; } } if (dev_priv->flush_pending) { @@ -82,8 +87,6 @@ static void i915_perform_flush(drm_device_t * dev) 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 e39f888a..bed55173 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -728,7 +728,7 @@ typedef struct drm_ttm_arg { /* Don't place this buffer on the unfenced list.*/ #define DRM_BO_HINT_DONT_FENCE 0x00000004 #define DRM_BO_HINT_WAIT_LAZY 0x00000008 - +#define DRM_BO_HINT_ALLOW_UNFENCED_MAP 0x00000010 /* Driver specific flags. Could be for example rendering engine */ @@ -792,7 +792,7 @@ typedef struct drm_bo_arg{ union { drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; - }; + } d; } drm_bo_arg_t; typedef union drm_mm_init_arg{ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index f8d08741..2aa3b947 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -105,6 +105,7 @@ typedef struct drm_i915_private { int vblank_pipe; spinlock_t user_irq_lock; int user_irq_refcount; + int fence_irq_on; uint32_t irq_enable_reg; int irq_enabled; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index a3f6a03b..4a1b2987 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -106,7 +106,7 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv) { spin_lock(&dev_priv->user_irq_lock); - if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount > 0)){ + if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= USER_INT_FLAG; I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } From 191e284709ee792a32124e96e43d5876406b93dc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 12:01:00 +0200 Subject: [PATCH 058/147] More bugfixes. Disable the i915 IRQ turnoff for now since it seems to be causing problems. --- libdrm/xf86drm.c | 70 ++++++++++++++++++++++++++++++------------ libdrm/xf86drm.h | 4 ++- libdrm/xf86mm.h | 3 +- linux-core/drmP.h | 3 ++ linux-core/drm_bo.c | 26 ++++++++++------ linux-core/drm_fence.c | 7 ++--- linux-core/drm_lock.c | 2 +- linux-core/drm_ttm.c | 16 ++++++++-- linux-core/drm_vm.c | 9 ++++-- shared-core/drm.h | 1 + shared-core/i915_drm.h | 8 +++++ shared-core/i915_irq.c | 8 +++-- 12 files changed, 115 insertions(+), 42 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 298b812a..2ea6656f 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2256,6 +2256,7 @@ int drmFenceCreate(int fd, int shareable, int class,unsigned type, fence->handle = arg.handle; fence->class = arg.class; fence->type = arg.type; + fence->flags = arg.flags; fence->signaled = 0; return 0; } @@ -2271,6 +2272,7 @@ int drmFenceBuffers(int fd, int shareable, drmFence *fence) fence->handle = arg.handle; fence->class = arg.class; fence->type = arg.type; + fence->flags = arg.flags; fence->signaled = 0; return 0; } @@ -2297,6 +2299,7 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence) fence->handle = arg.handle; fence->class = arg.class; fence->type = arg.type; + fence->flags = 0; fence->signaled = arg.signaled; return 0; } @@ -2327,20 +2330,41 @@ int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type) return 0; } -int drmFenceSignaled(int fd, drmFence *fence) +int drmFenceUpdate(int fd, drmFence *fence) { - drm_fence_arg_t arg; - - arg.handle = fence->handle; - 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; + drm_fence_arg_t arg; + + arg.handle = fence->handle; + 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; +} + +int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType, + int *signaled) +{ + int + ret; + + if ((fence->flags & DRM_FENCE_FLAG_SHAREABLE) || + ((fenceType & fence->signaled) != fenceType)) { + + ret = drmFenceFlush(fd, fence, fenceType); + if (ret) + return ret; + } + + *signaled = ((fenceType & fence->signaled) == fenceType); + return 0; } + + int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) { drm_fence_arg_t arg; @@ -2362,6 +2386,12 @@ int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, drm_fence_arg_t arg; int ret; + if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) { + if (flush_type & fence->signaled == flush_type) { + return 0; + } + } + arg.handle = fence->handle; arg.type = flush_type; arg.flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0; @@ -2942,8 +2972,6 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, *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) { @@ -2961,20 +2989,22 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, cur->arg0 = flags; cur->arg1 = mask; } else { - unsigned memFlags = cur->arg0 & DRM_BO_MASK_MEM; + unsigned memMask = (cur->arg1 | mask) & DRM_BO_MASK_MEM; + unsigned memFlags = cur->arg0 & flags & memMask; - if (!(memFlags & flags)) { + if (!memFlags) { drmMsg("Incompatible memory location requests " "on validate list.\n"); return -EINVAL; } - if ((cur->arg1 | mask) & (cur->arg0 ^ flags)) { + if ((cur->arg1 | mask) & ~DRM_BO_MASK_MEM & (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); + cur->arg0 = memFlags | ((cur->arg0 | flags) & + cur->arg1 & ~DRM_BO_MASK_MEM); } return 0; } @@ -3116,16 +3146,18 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) } int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, - unsigned long ttPOffset, unsigned long ttPSize) + unsigned long ttPOffset, unsigned long ttPSize, + unsigned long max_locked_size) { 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 = ttPOffset; arg.req.tt_p_size = ttPSize; - + arg.req.max_locked_pages = max_locked_size / getpagesize(); + if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) return -errno; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index be1eeeff..1b136d31 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -284,6 +284,7 @@ typedef struct _drmFence{ unsigned handle; int class; unsigned type; + unsigned flags; unsigned signaled; } drmFence; @@ -622,7 +623,8 @@ extern int drmFenceDestroy(int fd, const drmFence *fence); extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); extern int drmFenceUnreference(int fd, const drmFence *fence); extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); -extern int drmFenceSignaled(int fd, drmFence *fence); +extern int drmFenceSignaled(int fd, drmFence *fence, + unsigned fenceType, int *signaled); extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, int lazy, int ignore_signals); extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 43ea71b8..24e28245 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -185,7 +185,8 @@ extern int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle); */ extern int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, - unsigned long ttPOffset, unsigned long ttPSize); + unsigned long ttPOffset, unsigned long ttPSize, + unsigned long max_locked_size); extern int drmMMTakedown(int fd); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index da14bdfd..835b295a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -790,6 +790,7 @@ typedef struct drm_fence_manager{ typedef struct drm_buffer_manager{ int initialized; + drm_file_t *last_to_validate; int has_vram; int has_tt; int use_vram; @@ -803,6 +804,8 @@ typedef struct drm_buffer_manager{ struct list_head other; struct work_struct wq; uint32_t fence_flags; + unsigned long max_pages; + unsigned long cur_pages; } drm_buffer_manager_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 74722b1b..3a9c2313 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -95,11 +95,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) 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); - - schedule_delayed_work(&bm->wq, 2); - + schedule_delayed_work(&bm->wq, + ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -113,7 +113,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) list_del_init(&bo->head); if (bo->tt) { - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm_region(bo->ttm_region); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -170,7 +170,7 @@ static void drm_bo_delayed_workqueue(void *data) drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy)) { - schedule_delayed_work(&bm->wq, 2); + schedule_delayed_work(&bm->wq, ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); } mutex_unlock(&dev->struct_mutex); } @@ -822,6 +822,11 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { + if (no_wait && drm_bo_busy(bo)) { + atomic_dec(&bo->mapped); + ret = -EBUSY; + goto out; + } ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) { atomic_dec(&bo->mapped); @@ -1174,9 +1179,8 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, 0, - - /* bo->mask & DRM_BO_FLAG_BIND_CACHED,*/ + bo->num_pages, + bo->mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -1383,6 +1387,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; case drm_bo_validate: rep.ret = drm_bo_lock_test(dev, filp); + if (rep.ret) break; rep.ret = @@ -1571,13 +1576,16 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; - + bm->cur_pages = 0; + bm->max_pages = arg.req.max_locked_pages; break; case mm_takedown: if (drm_bo_clean_mm(dev)) { DRM_ERROR("Memory manager not clean. " "Delaying takedown\n"); } + DRM_DEBUG("We have %ld still locked pages\n", + bm->cur_pages); break; default: DRM_ERROR("Function not implemented yet\n"); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index eaaf7f40..df5db702 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -359,12 +359,11 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, fence_signaled(dev, fence, mask, 1)); if (time_after_eq(jiffies, _end)) break; - } while (ret == -EINTR && ignore_signals); - + } while (ret == -EINTR && ignore_signals); if (time_after_eq(jiffies, _end) && (ret != 0)) ret = -EBUSY; - return ret; - + if (ret) + return ((ret == -EINTR) ? -EAGAIN : ret); } else { int signaled; do { diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 91fad8bf..69ce2291 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -270,7 +270,7 @@ int drm_lock_free(drm_device_t * dev, prev = cmpxchg(lock, old, new); } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_ERROR("%d freed heavyweight lock held by %d\n", + DRM_DEBUG("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); return 1; } diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index a83d6401..8aba36ca 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -251,19 +251,24 @@ int drm_destroy_ttm(drm_ttm_t * ttm) } if (ttm->pages) { + drm_buffer_manager_t *bm = &ttm->dev->bm; + int do_tlbflush = 0; 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); + do_tlbflush = 1; } if (*cur_page) { ClearPageReserved(*cur_page); __free_page(*cur_page); + --bm->cur_pages; } } - global_flush_tlb(); + if (do_tlbflush) + global_flush_tlb(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), DRM_MEM_TTM, ttm->pages_vmalloc); ttm->pages = NULL; @@ -308,6 +313,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) if (!ttm) return NULL; + ttm->dev = dev; ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); @@ -354,7 +360,6 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) INIT_LIST_HEAD(&ttm->vma_list->head); ttm->lhandle = (unsigned long)ttm; - ttm->dev = dev; return ttm; } @@ -562,6 +567,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, drm_ttm_backend_list_t *entry; drm_ttm_backend_t *be; int ret, i; + drm_buffer_manager_t *bm = &ttm->dev->bm; if ((page_offset + n_pages) > ttm->num_pages || n_pages == 0) { DRM_ERROR("Region Doesn't fit ttm\n"); @@ -602,6 +608,11 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, for (i = 0; i < entry->num_pages; ++i) { cur_page = ttm->pages + (page_offset + i); if (!*cur_page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + drm_destroy_ttm_region(entry); + return -ENOMEM; + } *cur_page = alloc_page(GFP_KERNEL); if (!*cur_page) { DRM_ERROR("Page allocation failed\n"); @@ -609,6 +620,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, return -ENOMEM; } SetPageReserved(*cur_page); + ++bm->cur_pages; } } diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 69391058..e7b808cc 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -253,6 +253,7 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, drm_ttm_t *ttm; pgprot_t default_prot; uint32_t page_flags; + drm_buffer_manager_t *bm; if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ @@ -261,12 +262,18 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, map = (drm_map_t *) entry->map; ttm = (drm_ttm_t *) map->offset; + bm = &ttm->dev->bm; page_offset = (address - vma->vm_start) >> PAGE_SHIFT; page = ttm->pages[page_offset]; page_flags = ttm->page_flags[page_offset]; if (!page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + return NOPAGE_OOM; + } + ++bm->cur_pages; page = ttm->pages[page_offset] = alloc_page(GFP_KERNEL); SetPageReserved(page); @@ -274,8 +281,6 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, if (!page) return NOPAGE_OOM; - get_page(page); - default_prot = vm_get_page_prot(vma->vm_flags); BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED); diff --git a/shared-core/drm.h b/shared-core/drm.h index bed55173..d10b713b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -808,6 +808,7 @@ typedef union drm_mm_init_arg{ drm_u64_t vr_p_size; drm_u64_t tt_p_offset; drm_u64_t tt_p_size; + drm_u64_t max_locked_pages; } req; struct { drm_handle_t mm_sarea; diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index fcffb25c..1a79d403 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -106,6 +106,14 @@ typedef struct _drm_i915_sarea { unsigned int rotated2_tiled; } drm_i915_sarea_t; +/* Driver specific fence types and classes. + */ + +/* The only fence class we support */ +#define DRM_I915_FENCE_CLASS_ACCEL 0 +/* Fence type that guarantees read-write flush */ +#define DRM_I915_FENCE_TYPE_RW 2 + /* Flags for perf_boxes */ #define I915_BOX_RING_EMPTY 0x1 diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4a1b2987..8f3e79de 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -47,8 +47,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); +#if 0 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); - +#endif if (temp == 0) return IRQ_NONE; @@ -104,7 +105,7 @@ int i915_emit_irq(drm_device_t * dev) void i915_user_irq_on(drm_i915_private_t *dev_priv) { - + return; spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= USER_INT_FLAG; @@ -116,6 +117,7 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv) void i915_user_irq_off(drm_i915_private_t *dev_priv) { + return; spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { dev_priv->irq_enable_reg &= ~USER_INT_FLAG; @@ -239,7 +241,7 @@ static int i915_enable_interrupt (drm_device_t *dev) dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; dev_priv->user_irq_refcount = 0; dev_priv->irq_enable_reg = flag; - I915_WRITE16(I915REG_INT_ENABLE_R, flag); + I915_WRITE16(I915REG_INT_ENABLE_R, flag | USER_INT_FLAG); dev_priv->irq_enabled = 1; return 0; } From 861b26578cd5e497fb506ad5952fa62bd03ea201 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 16:28:34 +0200 Subject: [PATCH 059/147] Use lazy fence wait when possible even for RW fences. Saves some CPU. Lindent. --- libdrm/xf86drm.c | 12 +++++-- linux-core/drm_bo.c | 56 +++++++++++++++-------------- linux-core/drm_fence.c | 77 +++++++++++++++++++++++++++------------- linux-core/i915_buffer.c | 5 +++ 4 files changed, 97 insertions(+), 53 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 2ea6656f..3a23eae2 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2995,11 +2995,19 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, if (!memFlags) { drmMsg("Incompatible memory location requests " "on validate list.\n"); + drmMsg("Previous flag: 0x%08lx, mask: 0x%08lx\n", + cur->arg0, cur->arg1); + drmMsg("Current flag: 0x%08lx, mask: 0x%08lx\n", + flags, mask); return -EINVAL; } - if ((cur->arg1 | mask) & ~DRM_BO_MASK_MEM & (cur->arg0 ^ flags)) { + if (mask & cur->arg1 & ~DRM_BO_MASK_MEM & (cur->arg0 ^ flags)) { drmMsg("Incompatible buffer flag requests " - " on validate list.\n"); + "on validate list.\n"); + drmMsg("Previous flag: 0x%08lx, mask: 0x%08lx\n", + cur->arg0, cur->arg1); + drmMsg("Current flag: 0x%08lx, mask: 0x%08lx\n", + flags, mask); return -EINVAL; } cur->arg1 |= mask; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 3a9c2313..abad398f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -91,15 +91,16 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_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); - schedule_delayed_work(&bm->wq, - ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); + schedule_delayed_work(&bm->wq, + ((DRM_HZ / 100) < + 1) ? 1 : DRM_HZ / 100); return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -168,9 +169,10 @@ static void drm_bo_delayed_workqueue(void *data) DRM_ERROR("Delayed delete Worker\n"); #endif drm_bo_delayed_delete(dev); - mutex_lock(&dev->struct_mutex); + mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy)) { - schedule_delayed_work(&bm->wq, ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); + schedule_delayed_work(&bm->wq, + ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); } mutex_unlock(&dev->struct_mutex); } @@ -205,9 +207,9 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) */ int drm_fence_buffer_objects(drm_file_t * priv, - struct list_head *list, - drm_fence_object_t *fence, - drm_fence_object_t **used_fence) + struct list_head *list, + drm_fence_object_t * fence, + drm_fence_object_t ** used_fence) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -226,6 +228,12 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_flags |= entry->fence_flags; + if (entry->fence_class != 0) { + DRM_ERROR("Fence class %d is not implemented yet.\n", + entry->fence_class); + ret = -EINVAL; + goto out; + } count++; } @@ -238,7 +246,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, /* * Transfer to a local list before we release the dev->struct_mutex; * This is so we don't get any new unfenced objects while fencing - * these. + * the ones we already have.. */ list_add_tail(&f_list, list); @@ -256,7 +264,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, ret = drm_fence_object_create(dev, fence_flags, 1, &fence); mutex_lock(&dev->struct_mutex); if (ret) - goto out; + goto out; } count = 0; @@ -286,7 +294,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_add_tail(&entry->head, &bm->other); } else { #ifdef BODEBUG - DRM_ERROR("Huh? Fenced object on unfenced list\n"); + DRM_ERROR("Huh? Fenced object on unfenced list\n"); #endif } mutex_unlock(&entry->mutex); @@ -302,8 +310,8 @@ int drm_fence_buffer_objects(drm_file_t * priv, *used_fence = fence; return ret; } -EXPORT_SYMBOL(drm_fence_buffer_objects); +EXPORT_SYMBOL(drm_fence_buffer_objects); /* * Call bo->mutex locked. @@ -822,7 +830,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { - if (no_wait && drm_bo_busy(bo)) { + if (no_wait && drm_bo_busy(bo)) { atomic_dec(&bo->mapped); ret = -EBUSY; goto out; @@ -1109,7 +1117,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, drm_buffer_object_t *bo; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; int ret; - + bo = drm_lookup_buffer_object(priv, handle, 1); if (!bo) { return -EINVAL; @@ -1118,13 +1126,12 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, ret = drm_bo_wait_unfenced(bo, no_wait, 0); if (ret) goto out; - ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, - 0, no_wait); + ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, 0, no_wait); if (ret) goto out; drm_bo_fill_rep_arg(bo, rep); -out: + out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(bo->dev, bo); return 0; @@ -1204,11 +1211,10 @@ int drm_buffer_object_create(drm_file_t * priv, int ret = 0; uint32_t new_flags; unsigned long num_pages; - + drm_bo_delayed_delete(dev); - if ((buffer_start & ~PAGE_MASK) && - (type != drm_bo_type_fake)) { + if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } @@ -1350,8 +1356,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, - req->hint, - &rep); + req->hint, &rep); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -1404,7 +1409,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break; case drm_bo_wait_idle: - rep.ret = drm_bo_handle_wait(priv, req->handle, + rep.ret = drm_bo_handle_wait(priv, req->handle, req->hint, &rep); break; case drm_bo_ref_fence: @@ -1443,7 +1448,7 @@ static void drm_bo_force_clean(drm_device_t * dev) int ret = 0; l = bm->ddestroy.next; - while(l != &bm->ddestroy) { + while (l != &bm->ddestroy) { entry = list_entry(l, drm_buffer_object_t, ddestroy); list_del(l); if (entry->fence) { @@ -1584,8 +1589,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) DRM_ERROR("Memory manager not clean. " "Delaying takedown\n"); } - DRM_DEBUG("We have %ld still locked pages\n", - bm->cur_pages); + DRM_DEBUG("We have %ld still locked pages\n", bm->cur_pages); break; default: DRM_ERROR("Function not implemented yet\n"); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index df5db702..4ee5d2d0 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -112,7 +112,7 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) if ((fence->signaled | relevant) != fence->signaled) { fence->signaled |= relevant; #ifdef BODEBUG - DRM_ERROR("Fence 0x%08lx signaled 0x%08x\n", + DRM_ERROR("Fence 0x%08lx signaled 0x%08x\n", fence->base.hash.key, fence->signaled); #endif fence->submitted_flush |= relevant; @@ -135,7 +135,7 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) if (!(fence->type & ~fence->signaled)) { #ifdef BODEBUG - DRM_ERROR("Fence completely signaled 0x%08lx\n", + DRM_ERROR("Fence completely signaled 0x%08lx\n", fence->base.hash.key); #endif fence_list = &fence->ring; @@ -275,7 +275,7 @@ int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type) */ int drm_fence_object_flush(drm_device_t * dev, - drm_fence_object_t * fence, uint32_t type) + drm_fence_object_t * fence, uint32_t type) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; @@ -341,6 +341,7 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, drm_fence_driver_t *driver = dev->driver->fence_driver; int ret = 0; unsigned long _end; + int signaled; if (mask & ~fence->type) { DRM_ERROR("Wait trying to extend fence type\n"); @@ -353,25 +354,51 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, _end = jiffies + 3 * DRM_HZ; drm_fence_object_flush(dev, fence, mask); + if (lazy && driver->lazy_capable) { + do { DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, fence_signaled(dev, fence, mask, 1)); if (time_after_eq(jiffies, _end)) break; - } while (ret == -EINTR && ignore_signals); + } while (ret == -EINTR && ignore_signals); if (time_after_eq(jiffies, _end) && (ret != 0)) ret = -EBUSY; - if (ret) + if (ret) return ((ret == -EINTR) ? -EAGAIN : ret); - } else { - int signaled; + + } else if ((fence->class == 0) && (mask & DRM_FENCE_EXE) && + driver->lazy_capable) { + + /* + * We use IRQ wait for EXE fence if available to gain + * CPU in some cases. + */ + do { - signaled = fence_signaled(dev, fence, mask, 1); - } while (!signaled && !time_after_eq(jiffies, _end)); - if (!signaled) - return -EBUSY; + DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, + fence_signaled(dev, fence, DRM_FENCE_EXE, + 1)); + if (time_after_eq(jiffies, _end)) + break; + } while (ret == -EINTR && ignore_signals); + if (time_after_eq(jiffies, _end) && (ret != 0)) + ret = -EBUSY; + if (ret) + return ((ret == -EINTR) ? -EAGAIN : ret); } + + if (fence_signaled(dev, fence, mask, 0)) + return 0; + + do { + signaled = fence_signaled(dev, fence, mask, 1); + } while (!signaled && !time_after_eq(jiffies, _end)); + + if (!signaled) + return -EBUSY; + return 0; } @@ -413,7 +440,7 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, write_lock_irqsave(&fm->lock, flags); INIT_LIST_HEAD(&fence->ring); - fence->class = 0; + fence->class = 0; fence->type = type; fence->flush_mask = 0; fence->submitted_flush = 0; @@ -428,7 +455,7 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, EXPORT_SYMBOL(drm_fence_object_init); -int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, +int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence, int shareable) { drm_device_t *dev = priv->head->dev; @@ -446,10 +473,11 @@ int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, #endif return 0; } + EXPORT_SYMBOL(drm_fence_add_user_object); -int drm_fence_object_create(drm_device_t *dev, uint32_t type, - int emit, drm_fence_object_t **c_fence) +int drm_fence_object_create(drm_device_t * dev, uint32_t type, + int emit, drm_fence_object_t ** c_fence) { drm_fence_object_t *fence; int ret; @@ -462,11 +490,11 @@ int drm_fence_object_create(drm_device_t *dev, uint32_t type, drm_fence_usage_deref_unlocked(dev, fence); return ret; } - *c_fence = fence; + *c_fence = fence; return 0; } -EXPORT_SYMBOL(drm_fence_object_create); +EXPORT_SYMBOL(drm_fence_object_create); void drm_fence_manager_init(drm_device_t * dev) { @@ -535,8 +563,8 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) &fence); if (ret) return ret; - ret = drm_fence_add_user_object(priv, fence, - arg.flags & + ret = drm_fence_add_user_object(priv, fence, + arg.flags & DRM_FENCE_FLAG_SHAREABLE); if (ret) { drm_fence_usage_deref_unlocked(dev, fence); @@ -588,8 +616,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) ret = drm_fence_object_wait(dev, fence, arg.flags & DRM_FENCE_FLAG_WAIT_LAZY, - 0, - arg.type); + 0, arg.type); break; case drm_fence_emit: LOCK_TEST_WITH_RETURN(dev, filp); @@ -605,16 +632,16 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) } LOCK_TEST_WITH_RETURN(dev, filp); ret = drm_fence_buffer_objects(priv, NULL, NULL, &fence); - if (ret) + if (ret) return ret; - ret = drm_fence_add_user_object(priv, fence, - arg.flags & + ret = drm_fence_add_user_object(priv, fence, + arg.flags & DRM_FENCE_FLAG_SHAREABLE); if (ret) return ret; atomic_inc(&fence->usage); arg.handle = fence->base.hash.key; - break; + break; default: return -EINVAL; } diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 598f8772..9e8ae4a9 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -53,6 +53,10 @@ int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) int i915_invalidate_caches(drm_device_t *dev, uint32_t flags) { + /* + * FIXME: Only emit once per batchbuffer submission. + */ + uint32_t flush_cmd = MI_NO_WRITE_FLUSH; if (flags & DRM_BO_FLAG_READ) @@ -60,5 +64,6 @@ int i915_invalidate_caches(drm_device_t *dev, uint32_t flags) if (flags & DRM_BO_FLAG_EXE) flush_cmd |= MI_EXE_FLUSH; + return i915_emit_mi_flush(dev, flush_cmd); } From 9adc9584a7e0b61b16a943720bef31a71faeaef4 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 17:39:44 +0200 Subject: [PATCH 060/147] Fix some debug messages. --- linux-core/drm_bo.c | 28 +++++++--------------------- linux-core/drm_fence.c | 16 ++++------------ linux-core/drm_ttm.c | 3 --- 3 files changed, 11 insertions(+), 36 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index abad398f..f5a25c26 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -149,9 +149,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) entry->fence = NULL; } if (!entry->fence) { -#ifdef BODEBUG - DRM_ERROR("Destroying delayed buffer object\n"); -#endif + DRM_DEBUG("Destroying delayed buffer object\n"); list_del(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); } @@ -165,9 +163,8 @@ static void drm_bo_delayed_workqueue(void *data) drm_device_t *dev = (drm_device_t *) data; drm_buffer_manager_t *bm = &dev->bm; -#ifdef BODEBUG - DRM_ERROR("Delayed delete Worker\n"); -#endif + DRM_DEBUG("Delayed delete Worker\n"); + drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy)) { @@ -292,19 +289,12 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_add_tail(&entry->head, &bm->vram_lru); else list_add_tail(&entry->head, &bm->other); - } else { -#ifdef BODEBUG - DRM_ERROR("Huh? Fenced object on unfenced list\n"); -#endif - } - mutex_unlock(&entry->mutex); + } mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } atomic_add(count, &fence->usage); -#ifdef BODEBUG - DRM_ERROR("Fenced %d buffers\n", count); -#endif + DRM_DEBUG("Fenced %d buffers\n", count); out: mutex_unlock(&dev->struct_mutex); *used_fence = fence; @@ -461,9 +451,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; -#ifdef BODEBUG - DRM_ERROR("Flipping in to AGP 0x%08lx\n", bo->tt->start); -#endif + DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); if (ret) { @@ -998,9 +986,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Cached binding not implemented yet\n"); return -EINVAL; } -#ifdef BODEBUG - DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); -#endif + DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 4ee5d2d0..9ade8114 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -111,10 +111,8 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) relevant = type & fence->type; if ((fence->signaled | relevant) != fence->signaled) { fence->signaled |= relevant; -#ifdef BODEBUG - DRM_ERROR("Fence 0x%08lx signaled 0x%08x\n", + DRM_DEBUG("Fence 0x%08lx signaled 0x%08x\n", fence->base.hash.key, fence->signaled); -#endif fence->submitted_flush |= relevant; wake = 1; } @@ -134,10 +132,8 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) */ if (!(fence->type & ~fence->signaled)) { -#ifdef BODEBUG - DRM_ERROR("Fence completely signaled 0x%08lx\n", + DRM_DEBUG("Fence completely signaled 0x%08lx\n", fence->base.hash.key); -#endif fence_list = &fence->ring; for (i = 0; i < driver->no_types; ++i) { if (fm->fence_types[i] == fence_list) @@ -180,10 +176,8 @@ void drm_fence_usage_deref_locked(drm_device_t * dev, { if (atomic_dec_and_test(&fence->usage)) { drm_fence_unring(dev, &fence->ring); -#ifdef BODEBUG - DRM_ERROR("Destroyed a fence object 0x%08lx\n", + DRM_DEBUG("Destroyed a fence object 0x%08lx\n", fence->base.hash.key); -#endif kmem_cache_free(drm_cache.fence_object, fence); } } @@ -468,9 +462,7 @@ int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence, return ret; fence->base.type = drm_fence_type; fence->base.remove = &drm_fence_object_destroy; -#ifdef BODEBUG - DRM_ERROR("Fence 0x%08lx created\n", fence->base.hash.key); -#endif + DRM_DEBUG("Fence 0x%08lx created\n", fence->base.hash.key); return 0; } diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 8aba36ca..889e0001 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -488,9 +488,6 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); } -#ifdef BODEBUG - DRM_ERROR("Unbinding\n"); -#endif be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, From 682c6ed0293771b093452597540118f47fda1adf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 14 Sep 2006 12:17:38 +0200 Subject: [PATCH 061/147] Remove the use of reserved pages, and use locked pages instead. Update compatibility for latest linux versions. --- linux-core/drm_compat.c | 30 ++++++++++++++++++++++++------ linux-core/drm_ttm.c | 38 +++++++++++++++++++++----------------- linux-core/drm_vm.c | 5 +++-- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 162e4656..d387678e 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -54,19 +54,37 @@ static inline void change_pte_range(struct mm_struct *mm, pmd_t * pmd, unsigned long addr, unsigned long end) { pte_t *pte; + struct page *page; + unsigned long pfn; pte = pte_offset_map(pmd, addr); do { if (pte_present(*pte)) { pte_t ptent; - ptep_get_and_clear(mm, addr, pte); + pfn = pte_pfn(*pte); ptent = *pte; - lazy_mmu_prot_update(ptent); - } else { ptep_get_and_clear(mm, addr, pte); - } - if (!pte_none(*pte)) { - DRM_ERROR("Ugh. Pte was presen\n"); + if (pfn_valid(pfn)) { + page = pfn_to_page(pfn); + if (atomic_add_negative(-1, &page->_mapcount)) { + if (page_test_and_clear_dirty(page)) + set_page_dirty(page); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) + dec_zone_page_state(page, NR_FILE_MAPPED); +#else + dec_page_state(nr_mapped); +#endif + } + + put_page(page); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) + dec_mm_counter(mm, file_rss); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) + dec_mm_counter(mm, rss); +#else + --mm->rss; +#endif + } } } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap(pte - 1); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 889e0001..cd95e311 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -199,6 +199,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, (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 @@ -209,7 +210,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, #endif for (cur_page = first_page; cur_page != last_page; ++cur_page) { - if (page_mapcount(*cur_page) != 0) { + if (page_mapped(*cur_page)) { DRM_ERROR("Mapped page detected. Map count is %d\n", page_mapcount(*cur_page)); return -1; @@ -239,6 +240,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) } DRM_DEBUG("Destroying a ttm\n"); + if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = @@ -262,7 +264,22 @@ int drm_destroy_ttm(drm_ttm_t * ttm) do_tlbflush = 1; } if (*cur_page) { - ClearPageReserved(*cur_page); + ClearPageLocked(*cur_page); + + /* + * Debugging code. Remove if the error message never + * shows up. + */ + + if (page_count(*cur_page) != 1) { + DRM_ERROR("Erroneous page count. " + "Leaking pages.\n"); + } + + /* + * End debugging. + */ + __free_page(*cur_page); --bm->cur_pages; } @@ -526,20 +543,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) drm_unbind_ttm_region(entry); if (be) { - be->clear(entry->be); -#if 0 /* Hmm, Isn't this done in unbind? */ - 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, - entry->num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); - drm_set_caching(ttm, entry->page_offset, - entry->num_pages, 0, 1); - if (!ret) - drm_ttm_unlock_mm(ttm, 1, 0); - } -#endif + be->clear(be); be->destroy(be); } cur_page_flags = ttm->page_flags + entry->page_offset; @@ -616,7 +620,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, drm_destroy_ttm_region(entry); return -ENOMEM; } - SetPageReserved(*cur_page); + SetPageLocked(*cur_page); ++bm->cur_pages; } } diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index e7b808cc..aed0e04f 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -276,16 +276,17 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, ++bm->cur_pages; page = ttm->pages[page_offset] = alloc_page(GFP_KERNEL); - SetPageReserved(page); } if (!page) return NOPAGE_OOM; + SetPageLocked(page); + get_page(page); + default_prot = vm_get_page_prot(vma->vm_flags); BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED); vma->vm_page_prot = default_prot; - return page; } From 7223b4e264a64df2df70715d8777f2ccaa883d5e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 14 Sep 2006 16:42:00 +0200 Subject: [PATCH 062/147] Simplify ttm alloc and free. --- linux-core/drm_ttm.c | 36 +++++++++++++++++------------------- linux-core/drm_ttm.h | 3 --- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index cd95e311..f72e7d30 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -47,31 +47,29 @@ typedef struct drm_val_action { */ -static void *ttm_alloc(unsigned long size, int type, int *do_vmalloc) +static void *ttm_alloc(unsigned long size, int type) { void *ret = NULL; - *do_vmalloc = 0; if (size <= 4*PAGE_SIZE) { ret = drm_alloc(size, type); } if (!ret) { - *do_vmalloc = 1; ret = vmalloc(size); } return ret; } - -static void ttm_free(void *pointer, unsigned long size, int type, - int do_vfree) -{ - if (!do_vfree) { - drm_free(pointer, size, type); - }else { - vfree(pointer); - } -} +static void ttm_free(void *pointer, unsigned long size, int type) +{ + + if ((unsigned long) pointer >= VMALLOC_START && + (unsigned long) pointer <= VMALLOC_END) { + vfree(pointer); + } else { + drm_free(pointer, size, type); + } +} /* @@ -287,12 +285,12 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (do_tlbflush) global_flush_tlb(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), - DRM_MEM_TTM, ttm->pages_vmalloc); + DRM_MEM_TTM); ttm->pages = NULL; } if (ttm->page_flags) { - ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM, ttm->pf_vmalloc); + ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM); ttm->page_flags = NULL; } @@ -338,7 +336,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->page_flags = ttm_alloc(ttm->num_pages * sizeof(*ttm->page_flags), - DRM_MEM_TTM, &ttm->pf_vmalloc); + DRM_MEM_TTM); if (!ttm->page_flags) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page_flags table\n"); @@ -347,7 +345,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), - DRM_MEM_TTM, &ttm->pages_vmalloc); + DRM_MEM_TTM); if (!ttm->pages) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page table\n"); @@ -735,7 +733,7 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry) } ttm_free(entry->anon_pages, sizeof(*entry->anon_pages)*entry->anon_locked, - DRM_MEM_TTM, entry->pages_vmalloc); + DRM_MEM_TTM); } be->destroy(be); @@ -781,7 +779,7 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, } tmp->anon_pages = ttm_alloc(sizeof(*(tmp->anon_pages)) * len, - DRM_MEM_TTM, &tmp->pages_vmalloc); + DRM_MEM_TTM); if (!tmp->anon_pages) { drm_user_destroy_region(tmp); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 5c65e747..d647578c 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -70,7 +70,6 @@ typedef struct drm_ttm_backend_list { drm_file_t *anon_owner; struct page **anon_pages; int anon_locked; - int pages_vmalloc; enum { ttm_bound, ttm_evicted, @@ -100,8 +99,6 @@ typedef struct drm_ttm { atomic_t vma_count; int mmap_sem_locked; int destroy; - int pages_vmalloc; - int pf_vmalloc; } drm_ttm_t; typedef struct drm_ttm_object { From 49fbeb339c232804866cd548d6023fe559597353 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 15 Sep 2006 11:18:35 +0200 Subject: [PATCH 063/147] Some bugfixes. Change the fence object interface somewhat to allow some more flexibility. Make list IOCTLS really restartable. Try to avoid busy-waits in the kernel using immediate return to user-space with an -EAGAIN. --- libdrm/xf86drm.c | 92 +++++++++++++++++++++++------------------ libdrm/xf86drm.h | 42 ------------------- libdrm/xf86mm.h | 32 ++++++++++++++ linux-core/drmP.h | 1 + linux-core/drm_bo.c | 36 +++++++++------- linux-core/drm_fence.c | 20 ++++++--- linux-core/i915_drv.c | 1 + linux-core/i915_fence.c | 31 ++++++++++---- shared-core/drm.h | 7 +++- shared-core/i915_irq.c | 8 ++-- 10 files changed, 150 insertions(+), 120 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3a23eae2..2df74d14 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2240,16 +2240,20 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, #ifdef __linux__ -int drmFenceCreate(int fd, int shareable, int class,unsigned type, - int emit, +/* + * Valid flags are + * DRM_FENCE_FLAG_EMIT + * DRM_FENCE_FLAG_SHAREABLE + * DRM_FENCE_MASK_DRIVER + */ + +int drmFenceCreate(int fd, unsigned flags, int class,unsigned type, 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; @@ -2261,11 +2265,17 @@ int drmFenceCreate(int fd, int shareable, int class,unsigned type, return 0; } -int drmFenceBuffers(int fd, int shareable, drmFence *fence) +/* + * Valid flags are + * DRM_FENCE_FLAG_SHAREABLE + * DRM_FENCE_MASK_DRIVER + */ + +int drmFenceBuffers(int fd, unsigned flags, drmFence *fence) { drm_fence_arg_t arg; - arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0; + arg.flags = flags; arg.op = drm_fence_buffers; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; @@ -2299,7 +2309,7 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence) fence->handle = arg.handle; fence->class = arg.class; fence->type = arg.type; - fence->flags = 0; + fence->flags = arg.flags; fence->signaled = arg.signaled; return 0; } @@ -2363,12 +2373,18 @@ int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType, return 0; } +/* + * Valid flags are + * DRM_FENCE_FLAG_SHAREABLE + * DRM_FENCE_MASK_DRIVER + */ -int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) +int drmFenceEmit(int fd, unsigned flags, drmFence *fence, unsigned emit_type) { drm_fence_arg_t arg; + arg.flags = flags; arg.handle = fence->handle; arg.type = emit_type; arg.op = drm_fence_emit; @@ -2379,23 +2395,27 @@ int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) fence->signaled = arg.signaled; return 0; } + +/* + * Valid flags are + * DRM_FENCE_FLAG_WAIT_LAZY + * DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS + */ -int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, - int lazy, int ignore_signals) +int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) { drm_fence_arg_t arg; int ret; if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) { - if (flush_type & fence->signaled == flush_type) { + if ((flush_type & fence->signaled) == flush_type) { return 0; } } arg.handle = fence->handle; arg.type = flush_type; - arg.flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0; - arg.flags |= (ignore_signals) ? DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS : 0; + arg.flags = flags; arg.op = drm_fence_wait; do { ret = ioctl(fd, DRM_IOCTL_FENCE, &arg); @@ -2666,7 +2686,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, return -EINVAL; } req->op = drm_bo_create; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2700,7 +2720,7 @@ int drmBODestroy(int fd, drmBO *buf) arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_destroy; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2725,7 +2745,7 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) arg.handled = 0; req->handle = handle; req->op = drm_bo_reference; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2761,7 +2781,7 @@ int drmBOUnReference(int fd, drmBO *buf) arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unreference; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2813,7 +2833,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, req->mask = mapFlags; req->hint = mapHint; req->op = drm_bo_map; - req->next = 0; + arg.next = 0; /* * May hang if the buffer object is busy. @@ -2849,7 +2869,7 @@ int drmBOUnmap(int fd, drmBO *buf) arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unmap; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) { return -errno; @@ -2876,12 +2896,12 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, req->hint = hint; req->arg_handle = mask; /* Encode mask in the arg_handle field :/ */ req->op = drm_bo_validate; - req->next = 0; + arg.next = 0; do{ ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); - } while (ret && errno == -EAGAIN); + } while (ret && errno == EAGAIN); if (ret) @@ -2908,7 +2928,7 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) req->mask = flags; req->arg_handle = fenceHandle; req->op = drm_bo_validate; - req->next = 0; + arg.next = 0; ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -2931,7 +2951,7 @@ int drmBOInfo(int fd, drmBO *buf) arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_info; - req->next = 0; + arg.next = 0; ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -3044,20 +3064,14 @@ int drmBOValidateList(int fd, drmBOList *list) if (prevNext) *prevNext = (unsigned long) arg; - req->next = 0; - prevNext = &req->next; + arg->next = 0; + prevNext = &arg->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 | DRM_BO_MASK_MEM; -#ifdef BODEBUG - fprintf(stderr, "Offset 0x%08x, Handle 0x%08x, " - "mask 0x%08x flags 0x%08x\n", - node->buf->offset, - req->handle, req->arg_handle, req->mask); -#endif + req->arg_handle = node->arg1; } if (!first) @@ -3065,7 +3079,7 @@ int drmBOValidateList(int fd, drmBOList *list) do{ ret = ioctl(fd, DRM_IOCTL_BUFOBJ, first); - } while (ret && errno == -EAGAIN); + } while (ret && errno == EAGAIN); if (ret) @@ -3076,17 +3090,15 @@ int drmBOValidateList(int fd, drmBOList *list) arg = &node->bo_arg; rep = &arg->d.rep; - if (!arg->handled) + if (!arg->handled) { + drmMsg("Unhandled request\n"); return -EFAULT; + } if (rep->ret) return rep->ret; buf = node->buf; drmBOCopyReply(rep, buf); -#ifdef BODEBUG - fprintf(stderr,"Offset 0x%08x, Flags 0x%08x\n", - buf->offset, buf->flags); -#endif } return 0; @@ -3120,8 +3132,8 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) if (prevNext) *prevNext = (unsigned long) arg; - req->next = 0; - prevNext = &req->next; + arg->next = 0; + prevNext = &arg->next; arg->handled = 0; req->handle = node->buf->handle; req->op = drm_bo_fence; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 1b136d31..d97681c0 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -280,23 +280,6 @@ typedef struct _drmSetVersion { int drm_dd_minor; } drmSetVersion, *drmSetVersionPtr; -typedef struct _drmFence{ - unsigned handle; - int class; - unsigned type; - unsigned flags; - unsigned signaled; -} drmFence; - -typedef struct _drmTTM{ - unsigned handle; - drm_handle_t user_token; - unsigned flags; - unsigned long size; - void *virtual; - int mapCount; -} drmTTM; - #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) #define DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ @@ -614,31 +597,6 @@ extern int drmScatterGatherFree(int fd, drm_handle_t handle); extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); -/* Fencing */ - -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); -extern int drmFenceUnreference(int fd, const drmFence *fence); -extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); -extern int drmFenceSignaled(int fd, drmFence *fence, - unsigned fenceType, int *signaled); -extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, - int lazy, int ignore_signals); -extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); -extern int drmFenceBuffers(int fd, int shareable, drmFence *fence); - -/* 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 */ extern int drmError(int err, const char *label); extern void *drmMalloc(int size); diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 24e28245..4cb37e23 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -93,7 +93,22 @@ typedef struct _drmMMListHead #define DRMLISTENTRY(__type, __item, __field) \ ((__type *)(((char *) (__item)) - offsetof(__type, __field))) +typedef struct _drmFence{ + unsigned handle; + int class; + unsigned type; + unsigned flags; + unsigned signaled; +} drmFence; +typedef struct _drmTTM{ + unsigned handle; + drm_handle_t user_token; + unsigned flags; + unsigned long size; + void *virtual; + int mapCount; +} drmTTM; typedef struct _drmBO{ drm_bo_type_t type; @@ -130,6 +145,23 @@ typedef struct _drmBOList { drmMMListHead free; } drmBOList; +/* Fencing */ + +extern int drmFenceCreate(int fd, unsigned flags, int class, + unsigned type, + drmFence *fence); +extern int drmFenceDestroy(int fd, const drmFence *fence); +extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); +extern int drmFenceUnreference(int fd, const drmFence *fence); +extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); +extern int drmFenceSignaled(int fd, drmFence *fence, + unsigned fenceType, int *signaled); +extern int drmFenceWait(int fd, unsigned flags, drmFence *fence, + unsigned flush_type); +extern int drmFenceEmit(int fd, unsigned flags, drmFence *fence, + unsigned emit_type); +extern int drmFenceBuffers(int fd, unsigned flags, drmFence *fence); + /* * TTM functions. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 835b295a..d04a482b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -655,6 +655,7 @@ typedef struct drm_ref_object { typedef struct drm_bo_driver{ int cached_tt; int cached_vram; + drm_local_map_t *vram_map; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev, int cached); int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f5a25c26..858a4cde 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -322,15 +322,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, bo->fence = NULL; return 0; } - if (no_wait) + if (no_wait) { return -EBUSY; - + } ret = drm_fence_object_wait(dev, fence, lazy, ignore_signals, bo->fence_flags); - if (ret) - return ret; - + if (ret) + return ret; + drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -360,9 +360,14 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) if (!tt && !bo->vram) goto out; + ret = drm_bo_wait(bo, 0, 0, no_wait); - if (ret) + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed to expire fence before " + "buffer eviction.\n"); goto out; + } if (tt) { ret = drm_move_tt_to_local(bo); @@ -420,7 +425,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) } while (1); if (!node) { - DRM_ERROR("Out of aperture space\n"); + DRM_ERROR("Out of videoram / aperture space\n"); mutex_unlock(&dev->struct_mutex); return -ENOMEM; } @@ -646,7 +651,7 @@ static int drm_bo_busy(drm_buffer_object_t * bo) bo->fence = NULL; return 0; } - drm_fence_object_flush(dev, fence, DRM_FENCE_EXE); + drm_fence_object_flush(dev, fence, DRM_FENCE_TYPE_EXE); if (drm_fence_object_signaled(fence, bo->fence_flags)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -981,11 +986,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Vram support not implemented yet\n"); return -EINVAL; } - if ((new_flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM)) && - (new_flags & DRM_BO_FLAG_CACHED)) { - DRM_ERROR("Cached binding not implemented yet\n"); - return -EINVAL; - } + DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); if (ret) { @@ -1003,8 +1004,11 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return -EINVAL; } ret = drm_bo_move_buffer(bo, new_flags, no_wait); - if (ret) + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed moving buffer.\n"); return ret; + } } if (move_unfenced) { @@ -1304,7 +1308,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); if (arg.handled) { - data = req->next; + data = arg.next; continue; } @@ -1404,7 +1408,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) default: rep.ret = -EINVAL; } - next = req->next; + next = arg.next; /* * A signal interrupted us. Make sure the ioctl is restartable. diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 9ade8114..5078e952 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -283,10 +283,10 @@ int drm_fence_object_flush(drm_device_t * dev, write_lock_irqsave(&fm->lock, flags); fence->flush_mask |= type; if (fence->submitted_flush == fence->signaled) { - if ((fence->type & DRM_FENCE_EXE) && - !(fence->submitted_flush & DRM_FENCE_EXE)) { + if ((fence->type & DRM_FENCE_TYPE_EXE) && + !(fence->submitted_flush & DRM_FENCE_TYPE_EXE)) { drm_fence_flush_exe(fm, driver, fence->sequence); - fence->submitted_flush |= DRM_FENCE_EXE; + fence->submitted_flush |= DRM_FENCE_TYPE_EXE; } else { fm->pending_flush |= (fence->flush_mask & ~fence->submitted_flush); @@ -362,7 +362,7 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, if (ret) return ((ret == -EINTR) ? -EAGAIN : ret); - } else if ((fence->class == 0) && (mask & DRM_FENCE_EXE) && + } else if ((fence->class == 0) && (mask & DRM_FENCE_TYPE_EXE) && driver->lazy_capable) { /* @@ -372,7 +372,7 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, do { DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, - fence_signaled(dev, fence, DRM_FENCE_EXE, + fence_signaled(dev, fence, DRM_FENCE_TYPE_EXE, 1)); if (time_after_eq(jiffies, _end)) break; @@ -386,7 +386,15 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, if (fence_signaled(dev, fence, mask, 0)) return 0; - do { + /* + * Avoid kernel-space busy-waits. + */ +#if 1 + if (!ignore_signals) + return -EAGAIN; +#endif + do { + schedule(); signaled = fence_signaled(dev, fence, mask, 1); } while (!signaled && !time_after_eq(jiffies, _end)); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index fb4754d8..1718bb31 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -49,6 +49,7 @@ static drm_fence_driver_t i915_fence_driver = { }; static drm_bo_driver_t i915_bo_driver = { + .vram_map = NULL, .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 20e12d6a..5a8612cb 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -43,7 +43,6 @@ 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; @@ -52,9 +51,14 @@ static void i915_perform_flush(drm_device_t * dev) if (fm->pending_exe_flush) { sequence = READ_BREADCRUMB(dev_priv); + + /* + * First update fences with the current breadcrumb. + */ + diff = sequence - fm->last_exe_flush; if (diff < driver->wrap_diff && diff != 0) { - drm_fence_handler(dev, sequence, DRM_FENCE_EXE); + drm_fence_handler(dev, sequence, DRM_FENCE_TYPE_EXE); } diff = sequence - fm->exe_flush_sequence; @@ -69,20 +73,18 @@ static void i915_perform_flush(drm_device_t * dev) dev_priv->fence_irq_on = 1; } } + 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); + 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; @@ -91,6 +93,18 @@ static void i915_perform_flush(drm_device_t * dev) dev_priv->flush_pending = 1; fm->pending_flush = 0; } + + 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_flags = dev_priv->flush_flags; + flush_sequence = dev_priv->flush_sequence; + dev_priv->flush_pending = 0; + drm_fence_handler(dev, flush_sequence, flush_flags); + } + } + } void i915_poke_flush(drm_device_t * dev) @@ -117,7 +131,6 @@ void i915_fence_handler(drm_device_t * dev) write_lock(&fm->lock); i915_perform_flush(dev); - i915_perform_flush(dev); write_unlock(&fm->lock); } diff --git a/shared-core/drm.h b/shared-core/drm.h index d10b713b..b4dd61cb 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -643,7 +643,10 @@ typedef struct drm_set_version { #define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 #define DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS 0x00000008 -#define DRM_FENCE_EXE 0x00000001 +/* Reserved for driver use */ +#define DRM_FENCE_MASK_DRIVER 0xFF000000 + +#define DRM_FENCE_TYPE_EXE 0x00000001 typedef struct drm_fence_arg { unsigned handle; @@ -750,7 +753,6 @@ typedef struct drm_bo_arg_request { drm_bo_type_t type; unsigned arg_handle; drm_u64_t buffer_start; - drm_u64_t next; enum { drm_bo_create, drm_bo_validate, @@ -789,6 +791,7 @@ typedef struct drm_bo_arg_reply { typedef struct drm_bo_arg{ int handled; + drm_u64_t next; union { drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 8f3e79de..51112b62 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -45,7 +45,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) temp = I915_READ16(I915REG_INT_IDENTITY_R); - temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); + temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG); #if 0 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); @@ -105,7 +105,6 @@ int i915_emit_irq(drm_device_t * dev) void i915_user_irq_on(drm_i915_private_t *dev_priv) { - return; spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= USER_INT_FLAG; @@ -117,11 +116,10 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv) void i915_user_irq_off(drm_i915_private_t *dev_priv) { - return; spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { dev_priv->irq_enable_reg &= ~USER_INT_FLAG; - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } spin_unlock(&dev_priv->user_irq_lock); } @@ -241,7 +239,7 @@ static int i915_enable_interrupt (drm_device_t *dev) dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; dev_priv->user_irq_refcount = 0; dev_priv->irq_enable_reg = flag; - I915_WRITE16(I915REG_INT_ENABLE_R, flag | USER_INT_FLAG); + I915_WRITE16(I915REG_INT_ENABLE_R, flag); dev_priv->irq_enabled = 1; return 0; } From f613022ceef1814cb734bb3375f01962fd3bcf10 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 15 Sep 2006 16:47:09 +0200 Subject: [PATCH 064/147] Allow a "native type" to be associated with a fence sequence. In the intel case, we can associate a flush with a sequence. --- linux-core/drmP.h | 13 ++-- linux-core/drm_bo.c | 31 +++++----- linux-core/drm_fence.c | 128 ++++++++++------------------------------ linux-core/drm_lock.c | 4 +- linux-core/i915_fence.c | 8 ++- shared-core/i915_drm.h | 2 + shared-core/i915_drv.h | 6 +- 7 files changed, 73 insertions(+), 119 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index d04a482b..1d0b97ae 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -765,7 +765,9 @@ typedef struct drm_fence_driver{ uint32_t flush_diff; uint32_t sequence_mask; int lazy_capable; - int (*emit) (struct drm_device *dev, uint32_t *breadcrumb); + int (*emit) (struct drm_device *dev, uint32_t flags, + uint32_t *breadcrumb, + uint32_t *native_type); void (*poke_flush) (struct drm_device *dev); } drm_fence_driver_t; @@ -804,7 +806,7 @@ typedef struct drm_buffer_manager{ struct list_head ddestroy; struct list_head other; struct work_struct wq; - uint32_t fence_flags; + uint32_t fence_type; unsigned long max_pages; unsigned long cur_pages; } drm_buffer_manager_t; @@ -963,6 +965,7 @@ typedef struct drm_fence_object{ struct list_head ring; int class; + uint32_t native_type; volatile uint32_t type; volatile uint32_t signaled; uint32_t sequence; @@ -997,7 +1000,7 @@ typedef struct drm_buffer_object{ struct list_head head; struct list_head ddestroy; - uint32_t fence_flags; + uint32_t fence_type; uint32_t fence_class; drm_fence_object_t *fence; uint32_t priv_flags; @@ -1386,7 +1389,8 @@ extern void drm_fence_usage_deref_unlocked(drm_device_t * dev, extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask); extern int drm_fence_object_create(drm_device_t *dev, uint32_t type, - int emit, drm_fence_object_t **c_fence); + uint32_t fence_flags, + drm_fence_object_t **c_fence); extern int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, int shareable); @@ -1406,6 +1410,7 @@ extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_clean_mm(drm_device_t *dev); extern int drm_fence_buffer_objects(drm_file_t * priv, struct list_head *list, + uint32_t fence_flags, drm_fence_object_t *fence, drm_fence_object_t **used_fence); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 858a4cde..d176392a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -94,9 +94,9 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); if (bo->fence) { - if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { + if (!drm_fence_object_signaled(bo->fence, bo->fence_type)) { - drm_fence_object_flush(dev, bo->fence, bo->fence_flags); + drm_fence_object_flush(dev, bo->fence, bo->fence_type); list_add_tail(&bo->ddestroy, &bm->ddestroy); schedule_delayed_work(&bm->wq, ((DRM_HZ / 100) < @@ -144,7 +144,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) fence = entry->fence; if (fence && drm_fence_object_signaled(fence, - entry->fence_flags)) { + entry->fence_type)) { drm_fence_usage_deref_locked(dev, fence); entry->fence = NULL; } @@ -205,6 +205,7 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) int drm_fence_buffer_objects(drm_file_t * priv, struct list_head *list, + uint32_t fence_flags, drm_fence_object_t * fence, drm_fence_object_t ** used_fence) { @@ -212,7 +213,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, drm_buffer_manager_t *bm = &dev->bm; drm_buffer_object_t *entry; - uint32_t fence_flags = 0; + uint32_t fence_type = 0; int count = 0; int ret = 0; struct list_head f_list, *l; @@ -224,7 +225,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); - fence_flags |= entry->fence_flags; + fence_type |= entry->fence_type; if (entry->fence_class != 0) { DRM_ERROR("Fence class %d is not implemented yet.\n", entry->fence_class); @@ -250,7 +251,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_del_init(list); if (fence) { - if ((fence_flags & fence->type) != fence_flags) { + if ((fence_type & fence->type) != fence_type) { DRM_ERROR("Given fence doesn't match buffers " "on unfenced list.\n"); ret = -EINVAL; @@ -258,7 +259,9 @@ int drm_fence_buffer_objects(drm_file_t * priv, } } else { mutex_unlock(&dev->struct_mutex); - ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + ret = drm_fence_object_create(dev, fence_type, + fence_flags | DRM_FENCE_FLAG_EMIT, + &fence); mutex_lock(&dev->struct_mutex); if (ret) goto out; @@ -317,7 +320,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -327,7 +330,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, } ret = drm_fence_object_wait(dev, fence, lazy, ignore_signals, - bo->fence_flags); + bo->fence_type); if (ret) return ret; @@ -624,7 +627,7 @@ static int drm_bo_quick_busy(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -646,13 +649,13 @@ static int drm_bo_busy(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; } drm_fence_object_flush(dev, fence, DRM_FENCE_TYPE_EXE); - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -776,7 +779,7 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, rep->mask = bo->mask; rep->buffer_start = bo->buffer_start; - rep->fence_flags = bo->fence_flags; + rep->fence_flags = bo->fence_type; rep->rep_flags = 0; if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { @@ -988,7 +991,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, } DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); - ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); + ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_type); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 5078e952..5d051d4a 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -31,84 +31,35 @@ #include "drmP.h" -static void drm_fm_update_pointers(drm_fence_manager_t * fm, - struct list_head *list, int no_types, - uint32_t type) -{ - int i; - for (i = 0; i < no_types; ++i) { - if (type & (1 << i)) { - fm->fence_types[i] = list; - } - } -} - /* * Typically called by the IRQ handler. */ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) { - int i; int wake = 0; - int largest = 0; uint32_t diff; uint32_t relevant; - int index = 0; drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; - struct list_head *list; - struct list_head *fence_list; + struct list_head *list, *prev; drm_fence_object_t *fence; - int found = 0; - - for (i = 0; i < driver->no_types; ++i) { - if (!(type & (1 << i))) - continue; - - list = fm->fence_types[i]; - fence_list = list->next; - - if (fence_list == &fm->ring) - continue; - - fence = list_entry(fence_list, drm_fence_object_t, ring); + list_for_each_entry(fence, &fm->ring, ring) { diff = (sequence - fence->sequence) & driver->sequence_mask; - - if (diff < driver->wrap_diff) { - if (diff >= largest) { - largest = diff; - index = i; - found = 1; - } - } + if (diff > driver->wrap_diff) + break; } - if (!found) - return; + list = fence->ring.prev; + prev = list->prev; - /* - * Start with the fence object with the lowest sequence number, affected by - * the type mask of this call. Update signaled fields, - * Check if we need to wake sleeping processes - */ - - list = fm->fence_types[index]->next; - do { - if (list == &fm->ring) { - drm_fm_update_pointers(fm, list->prev, - driver->no_types, type); - break; - } + for (; list != &fm->ring; list = prev, prev = list->prev) { fence = list_entry(list, drm_fence_object_t, ring); - diff = (sequence - fence->sequence) & driver->sequence_mask; - if (diff >= driver->wrap_diff) { - drm_fm_update_pointers(fm, fence->ring.prev, - driver->no_types, type); - break; - } + + type |= fence->native_type; relevant = type & fence->type; + if ((fence->signaled | relevant) != fence->signaled) { fence->signaled |= relevant; DRM_DEBUG("Fence 0x%08lx signaled 0x%08x\n", @@ -119,35 +70,20 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) relevant = fence->flush_mask & ~(fence->signaled | fence->submitted_flush); + if (relevant) { fm->pending_flush |= relevant; fence->submitted_flush = fence->flush_mask; } - list = list->next; - - /* - * Remove a completely signaled fence from the - * fence manager ring. - */ - if (!(fence->type & ~fence->signaled)) { DRM_DEBUG("Fence completely signaled 0x%08lx\n", fence->base.hash.key); - fence_list = &fence->ring; - for (i = 0; i < driver->no_types; ++i) { - if (fm->fence_types[i] == fence_list) - fm->fence_types[i] = fence_list->prev; - } - list_del_init(fence_list); + list_del_init(&fence->ring); } - } while (1); - - /* - * Wake sleeping processes. - */ - + } + if (wake) { DRM_WAKEUP(&fm->fence_queue); } @@ -158,15 +94,9 @@ EXPORT_SYMBOL(drm_fence_handler); static void drm_fence_unring(drm_device_t * dev, struct list_head *ring) { drm_fence_manager_t *fm = &dev->fm; - drm_fence_driver_t *driver = dev->driver->fence_driver; unsigned long flags; - int i; write_lock_irqsave(&fm->lock, flags); - for (i = 0; i < driver->no_types; ++i) { - if (fm->fence_types[i] == ring) - fm->fence_types[i] = ring->prev; - } list_del_init(ring); write_unlock_irqrestore(&fm->lock, flags); } @@ -235,7 +165,8 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, * Last_exe_flush is invalid. Find oldest sequence. */ - list = fm->fence_types[_DRM_FENCE_TYPE_EXE]; +/* list = fm->fence_types[_DRM_FENCE_TYPE_EXE];*/ + list = &fm->ring; if (list->next == &fm->ring) { return; } else { @@ -405,16 +336,17 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, } int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, - uint32_t type) + uint32_t fence_flags, uint32_t type) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; unsigned long flags; uint32_t sequence; + uint32_t native_type; int ret; drm_fence_unring(dev, &fence->ring); - ret = driver->emit(dev, &sequence); + ret = driver->emit(dev, fence_flags, &sequence, &native_type); if (ret) return ret; @@ -424,13 +356,15 @@ int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, fence->submitted_flush = 0x00; fence->signaled = 0x00; fence->sequence = sequence; + fence->native_type = native_type; list_add_tail(&fence->ring, &fm->ring); write_unlock_irqrestore(&fm->lock, flags); return 0; } -int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, - drm_fence_object_t * fence) +static int drm_fence_object_init(drm_device_t * dev, uint32_t type, + uint32_t fence_flags, + drm_fence_object_t * fence) { int ret = 0; unsigned long flags; @@ -449,13 +383,12 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, fence->signaled = 0; fence->sequence = 0; write_unlock_irqrestore(&fm->lock, flags); - if (emit) { - ret = drm_fence_object_emit(dev, fence, type); + if (fence_flags & DRM_FENCE_FLAG_EMIT) { + ret = drm_fence_object_emit(dev, fence, fence_flags, type); } return ret; } -EXPORT_SYMBOL(drm_fence_object_init); int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence, int shareable) @@ -477,7 +410,7 @@ int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence, EXPORT_SYMBOL(drm_fence_add_user_object); int drm_fence_object_create(drm_device_t * dev, uint32_t type, - int emit, drm_fence_object_t ** c_fence) + unsigned flags, drm_fence_object_t ** c_fence) { drm_fence_object_t *fence; int ret; @@ -485,7 +418,7 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) return -ENOMEM; - ret = drm_fence_object_init(dev, type, emit, fence); + ret = drm_fence_object_init(dev, type, flags, fence); if (ret) { drm_fence_usage_deref_unlocked(dev, fence); return ret; @@ -559,7 +492,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) if (arg.flags & DRM_FENCE_FLAG_EMIT) LOCK_TEST_WITH_RETURN(dev, filp); ret = drm_fence_object_create(dev, arg.type, - arg.flags & DRM_FENCE_FLAG_EMIT, + arg.flags, &fence); if (ret) return ret; @@ -623,7 +556,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) fence = drm_lookup_fence_object(priv, arg.handle); if (!fence) return -EINVAL; - ret = drm_fence_object_emit(dev, fence, arg.type); + ret = drm_fence_object_emit(dev, fence, arg.flags, arg.type); break; case drm_fence_buffers: if (!dev->bm.initialized) { @@ -631,7 +564,8 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } LOCK_TEST_WITH_RETURN(dev, filp); - ret = drm_fence_buffer_objects(priv, NULL, NULL, &fence); + ret = drm_fence_buffer_objects(priv, NULL, arg.flags, + NULL, &fence); if (ret) return ret; ret = drm_fence_add_user_object(priv, fence, diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 69ce2291..8619defb 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -201,7 +201,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; else - new = context | _DRM_LOCK_HELD; + new = context | _DRM_LOCK_HELD | _DRM_LOCK_CONT; prev = cmpxchg(lock, old, new); } while (prev != old); if (_DRM_LOCKING_CONTEXT(old) == context) { @@ -213,7 +213,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) return 0; } } - if (new == (context | _DRM_LOCK_HELD)) { + if (new == (context | _DRM_LOCK_HELD | _DRM_LOCK_CONT)) { /* Have lock */ return 1; } diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 5a8612cb..8a3f81fe 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -86,6 +86,7 @@ static void i915_perform_flush(drm_device_t * dev) } if (fm->pending_flush && !dev_priv->flush_pending) { + DRM_ERROR("Sync flush"); 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); @@ -117,11 +118,16 @@ void i915_poke_flush(drm_device_t * dev) write_unlock_irqrestore(&fm->lock, flags); } -int i915_fence_emit_sequence(drm_device_t * dev, uint32_t * sequence) +int i915_fence_emit_sequence(drm_device_t * dev, uint32_t flags, + uint32_t * sequence, uint32_t *native_type) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; i915_emit_irq(dev); *sequence = (uint32_t) dev_priv->counter; + *native_type = DRM_FENCE_TYPE_EXE; + if (flags & DRM_I915_FENCE_FLAG_FLUSHED) + *native_type |= DRM_I915_FENCE_TYPE_RW; + return 0; } diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 1a79d403..e841105b 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -113,6 +113,8 @@ typedef struct _drm_i915_sarea { #define DRM_I915_FENCE_CLASS_ACCEL 0 /* Fence type that guarantees read-write flush */ #define DRM_I915_FENCE_TYPE_RW 2 +/* MI_FLUSH programmed just before the fence */ +#define DRM_I915_FENCE_FLAG_FLUSHED 0x01000000 /* Flags for perf_boxes */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 2aa3b947..65e80591 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -157,8 +157,12 @@ 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 int i915_fence_emit_sequence(drm_device_t *dev, uint32_t flags, + uint32_t *sequence, + uint32_t *native_type); extern void i915_poke_flush(drm_device_t *dev); extern void i915_sync_flush(drm_device_t *dev); #endif From c4fad4c96168a3dfabaa8a7e97758fefd014c8a7 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 18 Sep 2006 16:02:33 +0200 Subject: [PATCH 065/147] More verbose error reporting in some cases. Add a buffer object waitIdle user-space function. Fix some names and minor glitches. --- libdrm/xf86drm.c | 34 +++++++++++++++++++++++++++++++++- libdrm/xf86mm.h | 4 ++-- linux-core/drm_fence.c | 6 ++++-- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 2df74d14..606f098b 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2407,6 +2407,10 @@ int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) drm_fence_arg_t arg; int ret; + if (flush_type == 0) { + flush_type = fence->type; + } + if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) { if ((flush_type & fence->signaled) == flush_type) { return 0; @@ -2964,8 +2968,36 @@ int drmBOInfo(int fd, drmBO *buf) drmBOCopyReply(rep, buf); return 0; } + +int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; + int ret = 0; + + if ((buf->flags & DRM_BO_FLAG_SHAREABLE) || + (buf->replyFlags & DRM_BO_REP_BUSY)) { + arg.handled = 0; + req->handle = buf->handle; + req->op = drm_bo_wait_idle; + req->hint = hint; + arg.next = 0; + + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + + if (ret) + return ret; + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + drmBOCopyReply(rep, buf); + } + return 0; +} -int drmBufBusy(int fd, drmBO *buf, int *busy) +int drmBOBusy(int fd, drmBO *buf, int *busy) { if (!(buf->flags & DRM_BO_FLAG_SHAREABLE) && !(buf->replyFlags & DRM_BO_REP_BUSY)) { diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 4cb37e23..a62aef47 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -202,7 +202,7 @@ extern int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, unsigned hint); extern int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle); extern int drmBOInfo(int fd, drmBO *buf); -extern int drmBufBusy(int fd, drmBO *buf, int *busy); +extern int drmBOBusy(int fd, drmBO *buf, int *busy); extern int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, @@ -210,7 +210,7 @@ extern int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, int *newItem); extern int drmBOValidateList(int fd, drmBOList *list); extern int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle); - +extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint); /* * Initialization functions. diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 5d051d4a..41fe62a8 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -207,7 +207,8 @@ int drm_fence_object_flush(drm_device_t * dev, unsigned long flags; if (type & ~fence->type) { - DRM_ERROR("Flush trying to extend fence type\n"); + DRM_ERROR("Flush trying to extend fence type, " + "0x%x, 0x%x\n", type, fence->type); return -EINVAL; } @@ -269,7 +270,8 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, int signaled; if (mask & ~fence->type) { - DRM_ERROR("Wait trying to extend fence type\n"); + DRM_ERROR("Wait trying to extend fence type" + " 0x%08x 0x%08x\n", mask, fence->type); return -EINVAL; } From ca1b15d645c74e20f638f5a09981bcf02f58caee Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 18 Sep 2006 20:43:31 +0200 Subject: [PATCH 066/147] Alternative implementation of page table zeroing using zap page_range. (Disabled for now) Fix bo_wait_idle bug. Remove stray debug message. --- libdrm/xf86drm.c | 6 ++++-- linux-core/drm_bo.c | 4 +++- linux-core/drm_compat.c | 14 ++++++++++++++ linux-core/i915_fence.c | 1 - 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 606f098b..a7d4beb4 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2984,8 +2984,10 @@ int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint) req->hint = hint; arg.next = 0; - ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); - + do { + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret && errno == EAGAIN); + if (ret) return ret; if (!arg.handled) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d176392a..8e51985e 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1115,6 +1115,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, if (!bo) { return -EINVAL; } + mutex_lock(&bo->mutex); ret = drm_bo_wait_unfenced(bo, no_wait, 0); if (ret) @@ -1124,10 +1125,11 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, goto out; drm_bo_fill_rep_arg(bo, rep); + out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(bo->dev, bo); - return 0; + return ret; } /* diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index d387678e..e56f6608 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -124,6 +124,7 @@ static inline void change_pud_range(struct mm_struct *mm, pgd_t * pgd, * This function should be called with all relevant spinlocks held. */ +#if 1 void drm_clear_vma(struct vm_area_struct *vma, unsigned long addr, unsigned long end) { @@ -146,6 +147,19 @@ void drm_clear_vma(struct vm_area_struct *vma, flush_tlb_range(vma, addr, end); #endif } +#else + +void drm_clear_vma(struct vm_area_struct *vma, + unsigned long addr, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + + spin_unlock(&mm->page_table_lock); + (void) zap_page_range(vma, addr, end - addr, NULL); + spin_lock(&mm->page_table_lock); +} +#endif + pgprot_t vm_get_page_prot(unsigned long vm_flags) { diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 8a3f81fe..7491a672 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -86,7 +86,6 @@ static void i915_perform_flush(drm_device_t * dev) } if (fm->pending_flush && !dev_priv->flush_pending) { - DRM_ERROR("Sync flush"); 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); From aac918e7c72a46a1b0f2329380e2d6b4196d04e4 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 18 Sep 2006 21:50:00 +0200 Subject: [PATCH 067/147] Fence handler fix --- linux-core/drm_fence.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 41fe62a8..cb7aee09 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -31,6 +31,7 @@ #include "drmP.h" + /* * Typically called by the IRQ handler. */ @@ -44,14 +45,20 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) drm_fence_driver_t *driver = dev->driver->fence_driver; struct list_head *list, *prev; drm_fence_object_t *fence; + int found = 0; + + if (list_empty(&fm->ring)) + return; list_for_each_entry(fence, &fm->ring, ring) { diff = (sequence - fence->sequence) & driver->sequence_mask; - if (diff > driver->wrap_diff) + if (diff > driver->wrap_diff) { + found = 1; break; + } } - list = fence->ring.prev; + list = (found) ? fence->ring.prev : fm->ring.prev; prev = list->prev; for (; list != &fm->ring; list = prev, prev = list->prev) { From fa511a3ff5150d932fd963594d1ef67a94bb8b1f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 20 Sep 2006 16:31:15 +0200 Subject: [PATCH 068/147] Allow for 64-bit map handles of ttms and buffer objects. --- libdrm/xf86mm.h | 4 ++-- linux-core/drmP.h | 2 +- linux-core/drm_proc.c | 5 +++-- shared-core/drm.h | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index a62aef47..c0e4f1b6 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -103,7 +103,7 @@ typedef struct _drmFence{ typedef struct _drmTTM{ unsigned handle; - drm_handle_t user_token; + drm_u64_t user_token; unsigned flags; unsigned long size; void *virtual; @@ -113,7 +113,7 @@ typedef struct _drmTTM{ typedef struct _drmBO{ drm_bo_type_t type; unsigned handle; - drm_handle_t mapHandle; + drm_u64_t mapHandle; unsigned flags; unsigned mask; unsigned mapFlags; diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1d0b97ae..91be9d17 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -538,7 +538,7 @@ typedef struct drm_map_list { struct list_head head; /**< list head */ drm_hash_item_t hash; drm_map_t *map; /**< mapping */ - unsigned int user_token; + drm_u64_t user_token; } drm_map_list_t; typedef drm_map_t drm_local_map_t; diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 512a8f75..2efade26 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -238,10 +238,11 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, type = "??"; else type = types[map->type]; - DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08x ", + DRM_PROC_PRINT("%4d 0x%16lx 0x%16lx %4.4s 0x%02x 0x%16lx ", i, map->offset, - map->size, type, map->flags, r_list->user_token); + map->size, type, map->flags, + (unsigned long) r_list->user_token); if (map->mtrr < 0) { DRM_PROC_PRINT("none\n"); diff --git a/shared-core/drm.h b/shared-core/drm.h index b4dd61cb..8ac5a31e 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -677,7 +677,7 @@ typedef struct drm_ttm_arg { drm_ttm_unreference } op; unsigned handle; - unsigned user_token; + drm_u64_t user_token; drm_u64_t size; unsigned flags; }drm_ttm_arg_t; @@ -781,7 +781,7 @@ typedef struct drm_bo_arg_reply { unsigned flags; drm_u64_t size; drm_u64_t offset; - unsigned arg_handle; + drm_u64_t arg_handle; unsigned mask; drm_u64_t buffer_start; unsigned fence_flags; From a02155a0d92d3933d42a3655db261446bfe72b44 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 22 Sep 2006 09:25:36 +0200 Subject: [PATCH 069/147] Fix proc formatting broken by last commit. GPU lockup error reporting. --- linux-core/drm_fence.c | 7 +++++-- linux-core/drm_proc.c | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index cb7aee09..0640e755 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -299,9 +299,12 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, } while (ret == -EINTR && ignore_signals); if (time_after_eq(jiffies, _end) && (ret != 0)) ret = -EBUSY; - if (ret) + if (ret) { + if (ret == -EBUSY) { + DRM_ERROR("Fence timout. GPU lockup.\n"); + } return ((ret == -EINTR) ? -EAGAIN : ret); - + } } else if ((fence->class == 0) && (mask & DRM_FENCE_TYPE_EXE) && driver->lazy_capable) { diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 2efade26..6a0ee4fe 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -238,7 +238,7 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, type = "??"; else type = types[map->type]; - DRM_PROC_PRINT("%4d 0x%16lx 0x%16lx %4.4s 0x%02x 0x%16lx ", + DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", i, map->offset, map->size, type, map->flags, From 273eb7833d69db2d72430d5c96c21cebd05c206e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 25 Sep 2006 11:51:08 +0200 Subject: [PATCH 070/147] Add /proc filesystem buffer / fence object accounting. Check for NULL pointer in the i915 flush handler. Remove i915_sync_flush declaration. --- linux-core/drmP.h | 19 +++++++---- linux-core/drm_bo.c | 9 +++++- linux-core/drm_fence.c | 38 ++++++++++++++++------ linux-core/drm_proc.c | 71 +++++++++++++++++++++++++++++++++++++++++ linux-core/i915_fence.c | 3 ++ shared-core/i915_drv.h | 1 - 6 files changed, 122 insertions(+), 19 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 91be9d17..c8297228 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -789,6 +789,7 @@ typedef struct drm_fence_manager{ int pending_exe_flush; uint32_t last_exe_flush; uint32_t exe_flush_sequence; + atomic_t count; } drm_fence_manager_t; typedef struct drm_buffer_manager{ @@ -809,6 +810,7 @@ typedef struct drm_buffer_manager{ uint32_t fence_type; unsigned long max_pages; unsigned long cur_pages; + atomic_t count; } drm_buffer_manager_t; @@ -966,11 +968,11 @@ typedef struct drm_fence_object{ struct list_head ring; int class; uint32_t native_type; - volatile uint32_t type; - volatile uint32_t signaled; + uint32_t type; + uint32_t signaled; uint32_t sequence; - volatile uint32_t flush_mask; - volatile uint32_t submitted_flush; + uint32_t flush_mask; + uint32_t submitted_flush; } drm_fence_object_t; @@ -1380,13 +1382,16 @@ extern void drm_fence_manager_init(drm_device_t *dev); extern void drm_fence_manager_takedown(drm_device_t *dev); extern void drm_fence_flush_old(drm_device_t *dev, uint32_t sequence); extern int drm_fence_object_flush(drm_device_t * dev, - drm_fence_object_t * fence, uint32_t type); -extern int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type); + volatile drm_fence_object_t * fence, + uint32_t type); +extern int drm_fence_object_signaled(volatile drm_fence_object_t * fence, + uint32_t type); extern void drm_fence_usage_deref_locked(drm_device_t * dev, drm_fence_object_t * fence); extern void drm_fence_usage_deref_unlocked(drm_device_t * dev, drm_fence_object_t * fence); -extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, +extern int drm_fence_object_wait(drm_device_t * dev, + volatile drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask); extern int drm_fence_object_create(drm_device_t *dev, uint32_t type, uint32_t fence_flags, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 8e51985e..f479c81a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -128,6 +128,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) if (bo->ttm_object) { drm_ttm_object_deref_locked(dev, bo->ttm_object); } + atomic_dec(&bm->count); drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } @@ -140,6 +141,10 @@ static void drm_bo_delayed_delete(drm_device_t * dev) mutex_lock(&dev->struct_mutex); + /* + * FIXME: Lock buffer object mutex. + */ + list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { fence = entry->fence; @@ -1207,7 +1212,7 @@ int drm_buffer_object_create(drm_file_t * priv, uint32_t new_flags; unsigned long num_pages; - drm_bo_delayed_delete(dev); + // drm_bo_delayed_delete(dev); if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); @@ -1259,6 +1264,7 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_unlock(&bo->mutex); *buf_obj = bo; + atomic_inc(&bm->count); return 0; out_err: @@ -1576,6 +1582,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; + atomic_set(&bm->count, 0); bm->cur_pages = 0; bm->max_pages = arg.req.max_locked_pages; break; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 0640e755..ca6c8576 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -111,10 +111,13 @@ static void drm_fence_unring(drm_device_t * dev, struct list_head *ring) void drm_fence_usage_deref_locked(drm_device_t * dev, drm_fence_object_t * fence) { + drm_fence_manager_t *fm = &dev->fm; + if (atomic_dec_and_test(&fence->usage)) { drm_fence_unring(dev, &fence->ring); DRM_DEBUG("Destroyed a fence object 0x%08lx\n", fence->base.hash.key); + atomic_dec(&fm->count); kmem_cache_free(drm_cache.fence_object, fence); } } @@ -122,10 +125,13 @@ void drm_fence_usage_deref_locked(drm_device_t * dev, void drm_fence_usage_deref_unlocked(drm_device_t * dev, drm_fence_object_t * fence) { + drm_fence_manager_t *fm = &dev->fm; + if (atomic_dec_and_test(&fence->usage)) { mutex_lock(&dev->struct_mutex); if (atomic_read(&fence->usage) == 0) { drm_fence_unring(dev, &fence->ring); + atomic_dec(&fm->count); kmem_cache_free(drm_cache.fence_object, fence); } mutex_unlock(&dev->struct_mutex); @@ -142,7 +148,8 @@ static void drm_fence_object_destroy(drm_file_t * priv, drm_fence_usage_deref_locked(dev, fence); } -static int fence_signaled(drm_device_t * dev, drm_fence_object_t * fence, +static int fence_signaled(drm_device_t * dev, volatile + drm_fence_object_t * fence, uint32_t mask, int poke_flush) { unsigned long flags; @@ -166,7 +173,7 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, uint32_t diff; if (!fm->pending_exe_flush) { - struct list_head *list; + volatile struct list_head *list; /* * Last_exe_flush is invalid. Find oldest sequence. @@ -196,18 +203,15 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, } } -int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type) +int drm_fence_object_signaled(volatile drm_fence_object_t * fence, + uint32_t type) { return ((fence->signaled & type) == type); } -/* - * Make sure old fence objects are signaled before their fence sequences are - * wrapped around and reused. - */ - int drm_fence_object_flush(drm_device_t * dev, - drm_fence_object_t * fence, uint32_t type) + volatile drm_fence_object_t * fence, + uint32_t type) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; @@ -237,6 +241,12 @@ int drm_fence_object_flush(drm_device_t * dev, return 0; } +/* + * Make sure old fence objects are signaled before their fence sequences are + * wrapped around and reused. + */ + + void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) { drm_fence_manager_t *fm = &dev->fm; @@ -267,7 +277,8 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) EXPORT_SYMBOL(drm_fence_flush_old); -int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, +int drm_fence_object_wait(drm_device_t * dev, + volatile drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask) { drm_fence_manager_t *fm = &dev->fm; @@ -426,6 +437,8 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, { drm_fence_object_t *fence; int ret; + drm_fence_manager_t *fm = &dev->fm; + unsigned long fl; fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) @@ -436,6 +449,8 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, return ret; } *c_fence = fence; + atomic_inc(&fm->count); + return 0; } @@ -448,16 +463,19 @@ void drm_fence_manager_init(drm_device_t * dev) int i; fm->lock = RW_LOCK_UNLOCKED; + write_lock(&fm->lock); INIT_LIST_HEAD(&fm->ring); fm->pending_flush = 0; DRM_INIT_WAITQUEUE(&fm->fence_queue); fm->initialized = 0; if (fed) { fm->initialized = 1; + atomic_set(&fm->count,0); for (i = 0; i < fed->no_types; ++i) { fm->fence_types[i] = &fm->ring; } } + write_unlock(&fm->lock); } void drm_fence_manager_takedown(drm_device_t * dev) diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 6a0ee4fe..488d1e71 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -49,6 +49,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); static int drm_bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); +static int drm_objects_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data); #if DRM_DEBUG_CODE static int drm_vma_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); @@ -67,6 +69,7 @@ static struct drm_proc_list { {"clients", drm_clients_info}, {"queues", drm_queues_info}, {"bufs", drm_bufs_info}, + {"objects", drm_objects_info}, #if DRM_DEBUG_CODE {"vma", drm_vma_info}, #endif @@ -418,6 +421,74 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, return ret; } +/** + * Called when "/proc/dri/.../objects" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + */ +static int drm__objects_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *) data; + int len = 0; + drm_buffer_manager_t *bm = &dev->bm; + drm_fence_manager_t *fm = &dev->fm; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + + if (fm->initialized) { + DRM_PROC_PRINT("Number of active fence objects: %d.\n\n", + atomic_read(&fm->count)); + } else { + DRM_PROC_PRINT("Fence objects are not supported by this driver\n\n"); + } + + if (bm->initialized) { + DRM_PROC_PRINT("Number of active buffer objects: %d.\n\n", + atomic_read(&bm->count)); + DRM_PROC_PRINT("Number of locked GATT pages: %lu.\n", bm->cur_pages); + DRM_PROC_PRINT("Max allowed number of locked GATT pages %lu\n", + bm->max_pages); + } else { + DRM_PROC_PRINT("Buffer objects are not supported by this driver.\n\n"); + } + + + DRM_PROC_PRINT("\n"); + + if (len > request + offset) + return request; + *eof = 1; + return len - offset; +} + +/** + * Simply calls _objects_info() while holding the drm_device::struct_mutex lock. + */ +static int drm_objects_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *) data; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm__objects_info(buf, start, offset, request, eof, data); + mutex_unlock(&dev->struct_mutex); + return ret; +} + /** * Called when "/proc/dri/.../clients" is read. * diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 7491a672..49dc254f 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -49,6 +49,9 @@ static void i915_perform_flush(drm_device_t * dev) uint32_t diff; uint32_t sequence; + if (!dev_priv) + return; + if (fm->pending_exe_flush) { sequence = READ_BREADCRUMB(dev_priv); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 65e80591..402ad5b1 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -164,7 +164,6 @@ extern int i915_fence_emit_sequence(drm_device_t *dev, uint32_t flags, uint32_t *sequence, uint32_t *native_type); extern void i915_poke_flush(drm_device_t *dev); -extern void i915_sync_flush(drm_device_t *dev); #endif #ifdef I915_HAVE_BUFFER From 711f077b7423c1a436d703885c6d18a2ad2940aa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 26 Sep 2006 14:36:53 +0200 Subject: [PATCH 071/147] Allow for a driver to overload the ttm backend object methods. --- linux-core/drmP.h | 6 ++++-- linux-core/drm_agpsupport.c | 28 +++++++++++++++++----------- linux-core/drm_fence.c | 1 - linux-core/drm_ttm.h | 1 + linux-core/i915_buffer.c | 4 ++-- 5 files changed, 24 insertions(+), 16 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index c8297228..88f4c2cc 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1258,8 +1258,10 @@ extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size 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); +extern drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev, + drm_ttm_backend_t *backend); +extern drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev, + drm_ttm_backend_t *backend); /* 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 60ebc567..22987b07 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -625,9 +625,7 @@ static void drm_agp_clear_ttm(drm_ttm_backend_t *backend) { DRM_DEBUG("drm_agp_clear_ttm\n"); if (mem) { - if (mem->is_bound) { - drm_agp_unbind_memory(mem); - } + backend->unbind(backend); agp_free_memory(mem); } @@ -639,25 +637,28 @@ 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; + 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); + backend->clear(backend); } drm_free(agp_priv, sizeof(*agp_priv), DRM_MEM_MAPPINGS); } - drm_free(backend, sizeof(*backend), DRM_MEM_MAPPINGS); + if (backend->needs_free) + 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 *drm_agp_init_ttm_uncached(struct drm_device *dev, + drm_ttm_backend_t *backend) { drm_ttm_backend_t *agp_be; drm_agp_ttm_priv *agp_priv; - agp_be = drm_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); + agp_be = (backend != NULL) ? backend: + drm_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); if (!agp_be) return NULL; @@ -681,16 +682,20 @@ drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev) { agp_be->bind = drm_agp_bind_ttm; agp_be->unbind = drm_agp_unbind_ttm; agp_be->destroy = drm_agp_destroy_ttm; + agp_be->needs_free = (backend == NULL); return agp_be; } EXPORT_SYMBOL(drm_agp_init_ttm_uncached); -drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev) { +drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev, + drm_ttm_backend_t *backend) { drm_ttm_backend_t *agp_be; drm_agp_ttm_priv *agp_priv; - agp_be = drm_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); + + agp_be = (backend != NULL) ? backend: + drm_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); if (!agp_be) return NULL; @@ -714,6 +719,7 @@ drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev) { agp_be->bind = drm_agp_bind_ttm; agp_be->unbind = drm_agp_unbind_ttm; agp_be->destroy = drm_agp_destroy_ttm; + agp_be->needs_free = (backend == NULL); return agp_be; } EXPORT_SYMBOL(drm_agp_init_ttm_cached); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index ca6c8576..3e20f129 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -438,7 +438,6 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, drm_fence_object_t *fence; int ret; drm_fence_manager_t *fm = &dev->fm; - unsigned long fl; fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index d647578c..d65b17de 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -47,6 +47,7 @@ typedef struct drm_ttm_backend { unsigned long aperture_base; void *private; + int needs_free; int (*needs_cache_adjust) (struct drm_ttm_backend * backend); int (*populate) (struct drm_ttm_backend * backend, unsigned long num_pages, struct page ** pages); diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 9e8ae4a9..2d76f075 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -36,9 +36,9 @@ drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, int cached) { if (cached) - return drm_agp_init_ttm_cached(dev); + return drm_agp_init_ttm_cached(dev, NULL); else - return drm_agp_init_ttm_uncached(dev); + return drm_agp_init_ttm_uncached(dev, NULL); } int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) From 26528627a6cea7f92a949e89e5db6e17ef9560c2 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 26 Sep 2006 14:40:11 +0200 Subject: [PATCH 072/147] Remove the call to drm_lock_transfer, since it is not used anymore. Fix up drm_lock_free to retain the last locking context information. --- linux-core/drm_lock.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 8619defb..97417636 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -170,11 +170,8 @@ int drm_unlock(struct inode *inode, struct file *filp, if (dev->driver->kernel_context_switch_unlock) dev->driver->kernel_context_switch_unlock(dev); else { - drm_lock_transfer(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT); - if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { + lock.context)) { DRM_ERROR("\n"); } } @@ -263,12 +260,12 @@ int drm_lock_free(drm_device_t * dev, { unsigned int old, new, prev; - dev->lock.filp = NULL; do { old = *lock; - new = 0; + new = _DRM_LOCKING_CONTEXT(old); prev = cmpxchg(lock, old, new); } while (prev != old); + if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { DRM_DEBUG("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); From bd8ca12b7baff778d5bb7b4ad1d38d16b60a4d5a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 26 Sep 2006 16:00:22 +0200 Subject: [PATCH 073/147] Silence valgrind. --- libdrm/xf86drm.c | 58 ++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a7d4beb4..31d1c164 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2252,6 +2252,7 @@ int drmFenceCreate(int fd, unsigned flags, int class,unsigned type, { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.type = type; arg.class = class; arg.op = drm_fence_create; @@ -2275,6 +2276,7 @@ int drmFenceBuffers(int fd, unsigned flags, drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.flags = flags; arg.op = drm_fence_buffers; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2291,6 +2293,7 @@ int drmFenceDestroy(int fd, const drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.op = drm_fence_destroy; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2302,6 +2305,7 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = handle; arg.op = drm_fence_reference; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2318,6 +2322,7 @@ int drmFenceUnreference(int fd, const drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.op = drm_fence_unreference; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2329,6 +2334,7 @@ int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.type = flush_type; arg.op = drm_fence_flush; @@ -2344,6 +2350,7 @@ int drmFenceUpdate(int fd, drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.op = drm_fence_signaled; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2384,6 +2391,7 @@ int drmFenceEmit(int fd, unsigned flags, drmFence *fence, unsigned emit_type) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.flags = flags; arg.handle = fence->handle; arg.type = emit_type; @@ -2417,6 +2425,7 @@ int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) } } + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.type = flush_type; arg.flags = flags; @@ -2438,6 +2447,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) { drm_ttm_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.op = drm_ttm_create; arg.flags = flags; arg.size = size; @@ -2458,6 +2468,7 @@ int drmTTMDestroy(int fd, const drmTTM *ttm) { drm_ttm_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.op = drm_ttm_destroy; arg.handle = ttm->handle; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) @@ -2470,6 +2481,7 @@ int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) { drm_ttm_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = handle; arg.op = drm_ttm_reference; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) @@ -2485,6 +2497,7 @@ int drmTTMUnreference(int fd, const drmTTM *ttm) { drm_ttm_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.op = drm_ttm_destroy; arg.handle = ttm->handle; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) @@ -2660,8 +2673,9 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, drm_bo_arg_t arg; drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t *rep = &arg.d.rep; - - arg.handled = 0; + + memset(buf, 0, sizeof(*buf)); + memset(&arg, 0, sizeof(arg)); req->mask = mask; req->hint = hint; req->size = size; @@ -2690,7 +2704,6 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, return -EINVAL; } req->op = drm_bo_create; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2721,10 +2734,9 @@ int drmBODestroy(int fd, drmBO *buf) buf->virtual = NULL; } - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_destroy; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2746,10 +2758,9 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t *rep = &arg.d.rep; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = handle; req->op = drm_bo_reference; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2782,10 +2793,9 @@ int drmBOUnReference(int fd, drmBO *buf) buf->virtual = NULL; } - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_unreference; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2832,12 +2842,11 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, #endif } - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->mask = mapFlags; req->hint = mapHint; req->op = drm_bo_map; - arg.next = 0; /* * May hang if the buffer object is busy. @@ -2870,10 +2879,9 @@ int drmBOUnmap(int fd, drmBO *buf) drm_bo_arg_reply_t *rep = &arg.d.rep; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_unmap; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) { return -errno; @@ -2894,20 +2902,17 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); 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; - arg.next = 0; - do{ ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); } while (ret && errno == EAGAIN); - if (ret) return ret; if (!arg.handled) @@ -2927,12 +2932,11 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->mask = flags; req->arg_handle = fenceHandle; req->op = drm_bo_validate; - arg.next = 0; ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -2952,10 +2956,9 @@ int drmBOInfo(int fd, drmBO *buf) drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_info; - arg.next = 0; ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -2978,11 +2981,10 @@ int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint) if ((buf->flags & DRM_BO_FLAG_SHAREABLE) || (buf->replyFlags & DRM_BO_REP_BUSY)) { - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_wait_idle; req->hint = hint; - arg.next = 0; do { ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -3098,9 +3100,8 @@ int drmBOValidateList(int fd, drmBOList *list) if (prevNext) *prevNext = (unsigned long) arg; - arg->next = 0; + memset(arg, 0, sizeof(*arg)); prevNext = &arg->next; - arg->handled = 0; req->handle = node->buf->handle; req->op = drm_bo_validate; req->mask = node->arg0; @@ -3166,9 +3167,8 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) if (prevNext) *prevNext = (unsigned long) arg; - arg->next = 0; + memset(arg, 0, sizeof(*arg)); prevNext = &arg->next; - arg->handled = 0; req->handle = node->buf->handle; req->op = drm_bo_fence; req->mask = node->arg0; @@ -3205,6 +3205,7 @@ int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, { drm_mm_init_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.req.op = mm_init; arg.req.vr_p_offset = vramPOffset; arg.req.vr_p_size = vramPSize; @@ -3221,6 +3222,9 @@ int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, int drmMMTakedown(int fd) { drm_mm_init_arg_t arg; + + + memset(&arg, 0, sizeof(arg)); arg.req.op = mm_takedown; if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) From 235f6fc650e9974211843b9196a903963dae0211 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 09:27:31 +0200 Subject: [PATCH 074/147] Adapt to architecture-specific hooks for gatt pages. --- linux-core/drm_agpsupport.c | 2 +- linux-core/drm_bo.c | 2 +- linux-core/drm_compat.c | 20 ++++++++++++++++++++ linux-core/drm_compat.h | 23 +++++++++++++++++++++++ linux-core/drm_ttm.c | 32 +++++++++++++------------------- linux-core/drm_vm.c | 3 +-- 6 files changed, 59 insertions(+), 23 deletions(-) diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 22987b07..2dd80162 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -586,7 +586,7 @@ static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, 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); + mem->memory[mem->page_count++] = phys_to_gart(page_to_phys(*cur_page)); } agp_priv->mem = mem; return 0; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f479c81a..4f1c4173 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1562,7 +1562,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - arg.req.tt_p_size); + 3000 /*arg.req.tt_p_size*/); bm->has_tt = 1; bm->use_tt = 1; diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index e56f6608..8dbc636a 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -160,6 +160,26 @@ void drm_clear_vma(struct vm_area_struct *vma, } #endif +#if defined(CONFIG_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) +int drm_map_page_into_agp(struct page *page) +{ + int i; + i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE); + /* Caller's responsibility to call global_flush_tlb() for + * performance reasons */ + return i; +} + +int drm_unmap_page_from_agp(struct page *page) +{ + int i; + i = change_page_attr(page, 1, PAGE_KERNEL); + /* Caller's responsibility to call global_flush_tlb() for + * performance reasons */ + return i; +} +#endif + pgprot_t vm_get_page_prot(unsigned long vm_flags) { diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 779a7000..cf84a70b 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -31,6 +31,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #ifndef _DRM_COMPAT_H_ #define _DRM_COMPAT_H_ @@ -245,4 +246,26 @@ extern void drm_clear_vma(struct vm_area_struct *vma, extern pgprot_t vm_get_page_prot(unsigned long vm_flags); +/* + * These are similar to the current kernel gatt pages allocator, only that we + * want a struct page pointer instead of a virtual address. This allows for pages + * that are not in the kernel linear map. + */ + +#define drm_alloc_gatt_pages(order) virt_to_page(alloc_gatt_pages(order)) +#define drm_free_gatt_pages(pages, order) free_gatt_pages(page_address(pages), order) + +#if defined(CONFIG_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + +/* + * These are too slow in earlier kernels. + */ + +extern int drm_unmap_page_from_agp(struct page *page); +extern int drm_map_page_into_agp(struct page *page); + +#define map_page_into_agp drm_map_page_into_agp +#define unmap_page_from_agp drm_unmap_page_from_agp +#endif + #endif diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index f72e7d30..6790c886 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -170,7 +170,6 @@ static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, if (ret) break; } - global_flush_tlb(); return ret; } @@ -182,9 +181,7 @@ 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; + #if !defined(flush_tlb_mm) && defined(MODULE) int flush_tlb = 0; #endif @@ -207,13 +204,6 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, global_flush_tlb(); #endif - for (cur_page = first_page; cur_page != last_page; ++cur_page) { - if (page_mapped(*cur_page)) { - DRM_ERROR("Mapped page detected. Map count is %d\n", - page_mapcount(*cur_page)); - return -1; - } - } return 0; } @@ -258,7 +248,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) 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); + unmap_page_from_agp(*cur_page); do_tlbflush = 1; } if (*cur_page) { @@ -278,19 +268,20 @@ int drm_destroy_ttm(drm_ttm_t * ttm) * End debugging. */ - __free_page(*cur_page); + drm_free_gatt_pages(*cur_page, 0); --bm->cur_pages; } } if (do_tlbflush) - global_flush_tlb(); + flush_agp_mappings(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), DRM_MEM_TTM); ttm->pages = NULL; } if (ttm->page_flags) { - ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM); + ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), + DRM_MEM_TTM); ttm->page_flags = NULL; } @@ -455,7 +446,6 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, { int i, cur; struct page **cur_page; - pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -472,12 +462,16 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, 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 (noncached) { + map_page_into_agp(*cur_page); + } else { + unmap_page_from_agp(*cur_page); + } } } } if (do_tlbflush) - global_flush_tlb(); + flush_agp_mappings(); return 0; } @@ -612,7 +606,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, drm_destroy_ttm_region(entry); return -ENOMEM; } - *cur_page = alloc_page(GFP_KERNEL); + *cur_page = drm_alloc_gatt_pages(0); if (!*cur_page) { DRM_ERROR("Page allocation failed\n"); drm_destroy_ttm_region(entry); diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index aed0e04f..76d7fb4e 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -274,8 +274,7 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, return NOPAGE_OOM; } ++bm->cur_pages; - page = ttm->pages[page_offset] = - alloc_page(GFP_KERNEL); + page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); } if (!page) return NOPAGE_OOM; From c97149b45be9d0e9385d4c6721aa70dad68a1aa1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 09:31:39 +0200 Subject: [PATCH 075/147] Fix tt fixed size that slipped through in previous commit. --- linux-core/drm_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 4f1c4173..f479c81a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1562,7 +1562,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - 3000 /*arg.req.tt_p_size*/); + arg.req.tt_p_size); bm->has_tt = 1; bm->use_tt = 1; From f2c03ecae627df77db25391fe85fcd8a2a4bdc0c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 19:07:55 +0200 Subject: [PATCH 076/147] Fix racy buffer object destruction. --- linux-core/drm_bo.c | 70 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f479c81a..6a3a5020 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -93,6 +93,15 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + /* + * Somone might try to access us through the still active BM lists. + */ + + if (atomic_read(&bo->usage) != 0) + return; + if (!list_empty(&bo->ddestroy)) + return; + if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_type)) { @@ -114,6 +123,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) list_del_init(&bo->head); if (bo->tt) { + + /* + * This temporarily unlocks struct_mutex. + */ + drm_unbind_ttm_region(bo->ttm_region); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; @@ -136,33 +150,61 @@ static void drm_bo_delayed_delete(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; - drm_buffer_object_t *entry, *next; + drm_buffer_object_t *entry, *nentry; + struct list_head *list, *next; drm_fence_object_t *fence; mutex_lock(&dev->struct_mutex); + list = bm->ddestroy.next; + list_for_each_safe(list, next, &bm->ddestroy) { + entry = list_entry(list, drm_buffer_object_t, ddestroy); + nentry = NULL; - /* - * FIXME: Lock buffer object mutex. - */ + /* + * Another process may claim access to this entry through the + * lru lists. In that case, just skip it. + */ + + if (atomic_read(&entry->usage) != 0) + continue; + + /* + * Since we're the only users, No need to take the + * bo->mutex to watch the fence. + */ - list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { fence = entry->fence; - if (fence && drm_fence_object_signaled(fence, entry->fence_type)) { 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); - } - } + if (!entry->fence) { + + /* + * Protect the "next" entry against destruction in case + * drm_bo_destroy_locked temporarily releases the + * struct_mutex; + */ + + nentry = NULL; + if (next != &bm->ddestroy) { + nentry = list_entry(next, drm_buffer_object_t, + ddestroy); + atomic_inc(&nentry->usage); + } + DRM_DEBUG("Destroying delayed buffer object\n"); + list_del_init(&entry->ddestroy); + drm_bo_destroy_locked(dev, entry); + if (next != &bm->ddestroy) + atomic_dec(&nentry->usage); + } + } mutex_unlock(&dev->struct_mutex); } + static void drm_bo_delayed_workqueue(void *data) { drm_device_t *dev = (drm_device_t *) data; @@ -1212,7 +1254,7 @@ int drm_buffer_object_create(drm_file_t * priv, uint32_t new_flags; unsigned long num_pages; - // drm_bo_delayed_delete(dev); + drm_bo_delayed_delete(dev); if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); @@ -1241,6 +1283,8 @@ int drm_buffer_object_create(drm_file_t * priv, bo->dev = dev; bo->type = type; bo->num_pages = num_pages; + bo->vram = NULL; + bo->tt = NULL; if (bo->type == drm_bo_type_fake) { bo->offset = buffer_start; bo->buffer_start = 0; From 1c6f0ea43c47603c2265248ce8a91698c8982f3c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 19:11:27 +0200 Subject: [PATCH 077/147] Activate error message that was never hit since it was masked by drm_lock_transfer. Ifdef out drm_lock_transfer. I see no use for it currently. Should be removed. --- linux-core/drm_lock.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 97417636..86ee25cb 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -35,9 +35,12 @@ #include "drmP.h" +#if 0 static int drm_lock_transfer(drm_device_t * dev, __volatile__ unsigned int *lock, unsigned int context); +#endif + static int drm_notifier(void *priv); /** @@ -172,7 +175,7 @@ int drm_unlock(struct inode *inode, struct file *filp, else { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, lock.context)) { - DRM_ERROR("\n"); + /* FIXME: Should really bail out here. */ } } @@ -217,6 +220,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) return 0; } +#if 0 /** * This takes a lock forcibly and hands it to context. Should ONLY be used * inside *_unlock to give lock to kernel before calling *_dma_schedule. @@ -243,6 +247,7 @@ static int drm_lock_transfer(drm_device_t * dev, } while (prev != old); return 1; } +#endif /** * Free lock. @@ -267,7 +272,7 @@ int drm_lock_free(drm_device_t * dev, } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_DEBUG("%d freed heavyweight lock held by %d\n", + DRM_ERROR("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); return 1; } From c52fafa6288b4e6ecfce27151969749113a41f0b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 28 Sep 2006 11:33:03 +0200 Subject: [PATCH 078/147] Don't enable fence / buffer objects on non-linux systems. Bump driver minor and date. --- linux-core/i915_drv.c | 12 ++++++++---- shared-core/i915_drv.h | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 1718bb31..0a0e5f99 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -38,6 +38,7 @@ static struct pci_device_id pciidlist[] = { i915_PCI_IDS }; +#ifdef I915_HAVE_FENCE static drm_fence_driver_t i915_fence_driver = { .no_types = 2, .wrap_diff = (1 << 30), @@ -47,7 +48,8 @@ static drm_fence_driver_t i915_fence_driver = { .emit = i915_fence_emit_sequence, .poke_flush = i915_poke_flush, }; - +#endif +#ifdef I915_HAVE_BUFFER static drm_bo_driver_t i915_bo_driver = { .vram_map = NULL, .cached_vram = 0, @@ -56,7 +58,7 @@ static drm_bo_driver_t i915_bo_driver = { .fence_type = i915_fence_types, .invalidate_caches = i915_invalidate_caches }; - +#endif static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { @@ -97,10 +99,12 @@ static struct drm_driver driver = { .probe = probe, .remove = __devexit_p(drm_cleanup_pci), }, - +#ifdef I915_HAVE_FENCE .fence_driver = &i915_fence_driver, +#endif +#ifdef I915_HAVE_BUFFER .bo_driver = &i915_bo_driver, - +#endif .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 402ad5b1..745377c6 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -35,9 +35,9 @@ #define DRIVER_AUTHOR "Tungsten Graphics, Inc." -#define DRIVER_NAME "i915" +#define DRIVER_NAME "i915-mm" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20060119" +#define DRIVER_DATE "20060923" /* Interface history: * @@ -48,7 +48,7 @@ * 1.5: Add vblank pipe configuration */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 5 +#define DRIVER_MINOR 6 #define DRIVER_PATCHLEVEL 0 #if defined(__linux__) From b15bc8a0bad43c68dd1bbff27e7a7bd54e9e6938 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 28 Sep 2006 12:19:54 +0200 Subject: [PATCH 079/147] Libdrm version bump and naming. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 48813503..69b111fb 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libdrm], 2.0.2, [dri-devel@lists.sourceforge.net], libdrm) +AC_INIT([libdrm], 2.1.2-mm, [dri-devel@lists.sourceforge.net], libdrm) AC_CONFIG_SRCDIR([Makefile.am]) AM_INIT_AUTOMAKE([dist-bzip2]) From 3802f9adbf9a7e3d5c356f74b0c1ee966476fb97 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Sep 2006 11:15:59 +0200 Subject: [PATCH 080/147] Fix buffer manager takedown error. Prepare for the possibility to evict all buffers from vram / agp. This will be used by the X server when, for example, switching vts. --- linux-core/drmP.h | 7 +- linux-core/drm_bo.c | 192 ++++++++++++++++++++++++++++---------------- 2 files changed, 129 insertions(+), 70 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 88f4c2cc..aecad251 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -800,9 +800,11 @@ typedef struct drm_buffer_manager{ int use_vram; int use_tt; drm_mm_t tt_manager; - struct list_head tt_lru; drm_mm_t vram_manager; + struct list_head tt_lru; struct list_head vram_lru; + struct list_head tt_pinned; + struct list_head vram_pinned; struct list_head unfenced; struct list_head ddestroy; struct list_head other; @@ -999,7 +1001,8 @@ typedef struct drm_buffer_object{ drm_mm_node_t *vram; drm_mm_node_t *tt; - struct list_head head; + struct list_head tt_lru; + struct list_head vram_lru; struct list_head ddestroy; uint32_t fence_type; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 6a3a5020..d1989e49 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -120,7 +120,8 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * Take away from lru lists. */ - list_del_init(&bo->head); + list_del_init(&bo->tt_lru); + list_del_init(&bo->vram_lru); if (bo->tt) { @@ -155,6 +156,9 @@ static void drm_bo_delayed_delete(drm_device_t * dev) drm_fence_object_t *fence; mutex_lock(&dev->struct_mutex); + if (!bm->initialized) + goto out; + list = bm->ddestroy.next; list_for_each_safe(list, next, &bm->ddestroy) { entry = list_entry(list, drm_buffer_object_t, ddestroy); @@ -201,6 +205,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) atomic_dec(&nentry->usage); } } + out: mutex_unlock(&dev->struct_mutex); } @@ -264,13 +269,14 @@ int drm_fence_buffer_objects(drm_file_t * priv, int count = 0; int ret = 0; struct list_head f_list, *l; + struct list_head *q; mutex_lock(&dev->struct_mutex); if (!list) list = &bm->unfenced; - list_for_each_entry(entry, list, head) { + list_for_each_entry(entry, list, tt_lru) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_type |= entry->fence_type; if (entry->fence_class != 0) { @@ -317,12 +323,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, count = 0; l = f_list.next; while (l != &f_list) { - entry = list_entry(l, drm_buffer_object_t, head); + entry = list_entry(l, drm_buffer_object_t, tt_lru); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); mutex_lock(&dev->struct_mutex); list_del_init(l); + list_del_init(&entry->vram_lru); if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; if (entry->fence) @@ -331,15 +338,19 @@ int drm_fence_buffer_objects(drm_file_t * priv, DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); - if (entry->flags & DRM_BO_FLAG_NO_EVICT) - list_add_tail(&entry->head, &bm->other); - else if (entry->flags & DRM_BO_FLAG_MEM_TT) - list_add_tail(&entry->head, &bm->tt_lru); - else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) - list_add_tail(&entry->head, &bm->vram_lru); - else - list_add_tail(&entry->head, &bm->other); - } mutex_unlock(&entry->mutex); + if (entry->flags & DRM_BO_FLAG_MEM_TT) { + q = (entry->flags & DRM_BO_FLAG_NO_EVICT) ? + &bm->tt_pinned : &bm->tt_lru; + list_add_tail(&entry->tt_lru, q); + } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { + q = (entry->flags & DRM_BO_FLAG_NO_EVICT) ? + &bm->vram_pinned : &bm->vram_lru; + list_add_tail(&entry->vram_lru, q); + } else { + list_add_tail(&entry->tt_lru, &bm->other); + } + } + mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } @@ -389,7 +400,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, } /* - * No locking required. + * bo->mutex locked */ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) @@ -401,16 +412,13 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) * Someone might have modified the buffer before we took the buffer mutex. */ - mutex_lock(&bo->mutex); - if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) - || (bo->flags & DRM_BO_FLAG_NO_EVICT)) + if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) goto out; if (tt && !bo->tt) goto out; if (!tt && !bo->vram) goto out; - ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) { if (ret != -EAGAIN) @@ -428,13 +436,13 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) } #endif mutex_lock(&dev->struct_mutex); - list_del(&bo->head); - list_add_tail(&bo->head, &bm->other); + list_del_init((tt) ? &bo->tt_lru : &bo->vram_lru); + if (list_empty((tt) ? &bo->vram_lru : &bo->tt_lru)) + list_add_tail(&bo->tt_lru, &bm->other); mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); out: - mutex_unlock(&bo->mutex); return ret; } @@ -463,11 +471,17 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) if (lru->next == lru) break; - bo = list_entry(lru->next, drm_buffer_object_t, head); + 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); + } atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); + mutex_lock(&bo->mutex); ret = drm_bo_evict(bo, tt, no_wait); + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); if (ret) return ret; @@ -714,18 +728,16 @@ static int drm_bo_busy(drm_buffer_object_t * bo) static int drm_bo_read_cached(drm_buffer_object_t * bo) { - drm_device_t *dev = bo->dev; - drm_buffer_manager_t *bm = &dev->bm; + int ret = 0; BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, - _DRM_BO_FLAG_EVICTED); - - mutex_lock(&dev->struct_mutex); - list_del(&bo->head); - list_add_tail(&bo->head, &bm->other); - mutex_unlock(&dev->struct_mutex); - return drm_move_tt_to_local(bo); + if (bo->vram) + ret = drm_bo_evict(bo, 0, 1); + if (ret) + return ret; + if (bo->tt) + ret = drm_bo_evict(bo, 1, 1); + return ret; } /* @@ -1070,20 +1082,28 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, _DRM_BO_FLAG_UNFENCED); mutex_lock(&dev->struct_mutex); - list_del(&bo->head); - list_add_tail(&bo->head, &bm->unfenced); + list_del(&bo->tt_lru); + list_add_tail(&bo->tt_lru, &bm->unfenced); + list_del_init(&bo->vram_lru); mutex_unlock(&dev->struct_mutex); } else { + struct list_head *q; + mutex_lock(&dev->struct_mutex); - list_del(&bo->head); - if (new_flags & DRM_BO_FLAG_NO_EVICT) - list_add_tail(&bo->head, &bm->other); - else if (new_flags & DRM_BO_FLAG_MEM_TT) - list_add_tail(&bo->head, &bm->tt_lru); - else if (new_flags & DRM_BO_FLAG_MEM_VRAM) - list_add_tail(&bo->head, &bm->vram_lru); - else - list_add_tail(&bo->head, &bm->other); + list_del_init(&bo->tt_lru); + list_del_init(&bo->vram_lru); + + if (new_flags & DRM_BO_FLAG_MEM_TT) { + q = (new_flags & DRM_BO_FLAG_NO_EVICT) ? + &bm->tt_pinned : &bm->tt_lru; + list_add_tail(&bo->tt_lru, q); + } else if (new_flags & DRM_BO_FLAG_MEM_VRAM) { + q = (new_flags & DRM_BO_FLAG_NO_EVICT) ? + &bm->vram_pinned : &bm->vram_lru; + list_add_tail(&bo->vram_lru, q); + } else { + list_add_tail(&bo->tt_lru, &bm->other); + } mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -1277,9 +1297,10 @@ int drm_buffer_object_create(drm_file_t * priv, atomic_set(&bo->usage, 1); atomic_set(&bo->mapped, -1); DRM_INIT_WAITQUEUE(&bo->event_queue); - INIT_LIST_HEAD(&bo->head); - list_add_tail(&bo->head, &bm->other); + INIT_LIST_HEAD(&bo->tt_lru); + INIT_LIST_HEAD(&bo->vram_lru); INIT_LIST_HEAD(&bo->ddestroy); + list_add_tail(&bo->tt_lru, &bm->other); bo->dev = dev; bo->type = type; bo->num_pages = num_pages; @@ -1484,43 +1505,67 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) * dev->struct_sem locked. */ -static void drm_bo_force_clean(drm_device_t * dev) +static void drm_bo_force_list_clean(drm_device_t *dev, + struct list_head *head, int tt) { - drm_buffer_manager_t *bm = &dev->bm; struct list_head *l; drm_buffer_object_t *entry; int nice_mode = 1; - int ret = 0; + int ret; + + l = head->next; + while (l != head) { + if (tt) { + entry = list_entry(l, drm_buffer_object_t, + tt_lru); + } else { + entry = list_entry(l, drm_buffer_object_t, + vram_lru); + } + + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + + /* + * Expire the fence. + */ - l = bm->ddestroy.next; - while (l != &bm->ddestroy) { - entry = list_entry(l, drm_buffer_object_t, ddestroy); - list_del(l); if (entry->fence) { if (nice_mode) { - unsigned long _end = jiffies + 3 * DRM_HZ; + unsigned long _end = jiffies + 3*DRM_HZ; do { - mutex_unlock(&dev->struct_mutex); ret = drm_bo_wait(entry, 0, 1, 0); - mutex_lock(&dev->struct_mutex); - } while ((ret == -EINTR) && - !time_after_eq(jiffies, _end)); - } else { - drm_fence_usage_deref_locked(dev, entry->fence); - entry->fence = NULL; + } while (ret && !time_after_eq(jiffies, _end)); + + if (entry->fence) { + nice_mode = 0; + DRM_ERROR("Detected GPU hang. " + "Evicting waiting buffers\n"); + } } if (entry->fence) { - DRM_ERROR("Detected GPU hang. " - "Removing waiting buffers.\n"); - nice_mode = 0; - drm_fence_usage_deref_locked(dev, entry->fence); + drm_fence_usage_deref_unlocked(dev, entry->fence); entry->fence = NULL; } - } - DRM_DEBUG("Destroying delayed buffer object\n"); - drm_bo_destroy_locked(dev, entry); - l = bm->ddestroy.next; + ret = drm_bo_evict(entry, tt, 0); + if (ret) { + DRM_ERROR("Aargh. Eviction failed.\n"); + } + mutex_unlock(&entry->mutex); + mutex_lock(&dev->struct_mutex); + + if (!list_empty(l)) { + list_del_init(l); + if (list_empty(&entry->tt_lru) && + list_empty(&entry->vram_lru)) { + list_add_tail(l, &dev->bm.other); + } + } + + drm_bo_usage_deref_locked(dev, entry); + l = head->next; } } @@ -1534,10 +1579,18 @@ int drm_bo_clean_mm(drm_device_t * dev) if (!bm->initialized) goto out; - drm_bo_force_clean(dev); bm->use_vram = 0; bm->use_tt = 0; + /* + * FIXME: Need to handle unfenced list. + */ + + drm_bo_force_list_clean(dev, &bm->tt_lru, 1); + drm_bo_force_list_clean(dev, &bm->tt_pinned, 1); + drm_bo_force_list_clean(dev, &bm->vram_lru, 1); + drm_bo_force_list_clean(dev, &bm->vram_pinned, 1); + if (bm->has_vram) { if (drm_mm_clean(&bm->vram_manager)) { drm_mm_takedown(&bm->vram_manager); @@ -1620,6 +1673,8 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_LIST_HEAD(&bm->vram_lru); INIT_LIST_HEAD(&bm->tt_lru); + INIT_LIST_HEAD(&bm->vram_pinned); + INIT_LIST_HEAD(&bm->tt_pinned); INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); INIT_LIST_HEAD(&bm->other); @@ -1631,6 +1686,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) bm->max_pages = arg.req.max_locked_pages; break; case mm_takedown: + LOCK_TEST_WITH_RETURN(dev, filp); if (drm_bo_clean_mm(dev)) { DRM_ERROR("Memory manager not clean. " "Delaying takedown\n"); From ae96e264198323916ee58e293468c9b924feca75 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Sep 2006 11:46:45 +0200 Subject: [PATCH 081/147] Add a new buffer flag. Fix up some comments. --- shared-core/drm.h | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index 8ac5a31e..095823b7 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -696,21 +696,28 @@ typedef struct drm_ttm_arg { * Status flags. Can be read to determine the actual state of a buffer. */ -/* Pinned buffer. */ +/* + * Cannot evict this buffer. Not even with force. This type of buffer should + * only be available for root, and must be manually removed before buffer + * manager shutdown or swapout. + */ #define DRM_BO_FLAG_NO_EVICT 0x00000010 /* Always keep a system memory shadow to a vram buffer */ #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 -/* When mapped for reading, make sure the buffer is cached even - if it means moving the buffer to system memory */ +/* The buffer is shareable with other processes */ #define DRM_BO_FLAG_SHAREABLE 0x00000040 +/* The buffer is currently cached */ +#define DRM_BO_FLAG_CACHED 0x00000080 +/* Make sure that every time this buffer is validated, it ends up on the same + * location. The buffer will also not be evicted when claiming space for + * other buffers. Basically a pinned buffer but it may be thrown out as + * part of buffer manager shutdown or swapout. Not supported yet.*/ +#define DRM_BO_FLAG_NO_MOVE 0x00000100 + +/* Make sure the buffer is in cached memory when mapped for reading */ +#define DRM_BO_FLAG_READ_CACHED 0x00080000 /* When there is a choice between VRAM and TT, prefer VRAM. The default behaviour is to prefer TT. */ -#define DRM_BO_FLAG_CACHED 0x00000080 -/* The buffer is shareable with other processes */ - - -#define DRM_BO_FLAG_READ_CACHED 0x00080000 -/* The buffer is currently cached */ #define DRM_BO_FLAG_PREFER_VRAM 0x00040000 /* Bind this buffer cached if the hardware supports it. */ #define DRM_BO_FLAG_BIND_CACHED 0x0002000 From 2735f9e2908b786586d18f6384371b991bdce430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 11 Aug 2006 17:57:59 +0200 Subject: [PATCH 082/147] Add support for secondary vertical blank interrupt to DRM core. (cherry picked from ab351505f36a6c66405ea7604378268848340a42 commit) --- linux-core/drmP.h | 4 +++ linux-core/drm_core.h | 8 ++--- linux-core/drm_irq.c | 72 +++++++++++++++++++++++++++++-------------- shared-core/drm.h | 4 ++- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index aecad251..6a978f33 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -111,6 +111,7 @@ #define DRIVER_IRQ_VBL 0x100 #define DRIVER_DMA_QUEUE 0x200 #define DRIVER_FB_DMA 0x400 +#define DRIVER_IRQ_VBL2 0x800 /*@}*/ @@ -687,6 +688,7 @@ struct drm_driver { int new); void (*kernel_context_switch_unlock) (struct drm_device * dev); int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); + int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence); int (*dri_library_name) (struct drm_device * dev, char * buf); /** @@ -912,8 +914,10 @@ typedef struct drm_device { wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ atomic_t vbl_received; + atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ spinlock_t vbl_lock; drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ + drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */ unsigned int vbl_pending; /*@} */ diff --git a/linux-core/drm_core.h b/linux-core/drm_core.h index f5405fdf..705bbff7 100644 --- a/linux-core/drm_core.h +++ b/linux-core/drm_core.h @@ -25,11 +25,11 @@ #define CORE_NAME "drm" #define CORE_DESC "DRM shared core routines" -#define CORE_DATE "20051102" +#define CORE_DATE "20060810" #define DRM_IF_MAJOR 1 -#define DRM_IF_MINOR 2 +#define DRM_IF_MINOR 3 #define CORE_MAJOR 1 -#define CORE_MINOR 0 -#define CORE_PATCHLEVEL 1 +#define CORE_MINOR 1 +#define CORE_PATCHLEVEL 0 diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index c2a9e3d6..d4e5fbd5 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -120,6 +120,7 @@ static int drm_irq_install(drm_device_t * dev) spin_lock_init(&dev->vbl_lock); INIT_LIST_HEAD(&dev->vbl_sigs.head); + INIT_LIST_HEAD(&dev->vbl_sigs2.head); dev->vbl_pending = 0; } @@ -246,9 +247,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) struct timeval now; int ret = 0; unsigned int flags; - - if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL)) - return -EINVAL; + atomic_t *seq; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -256,9 +255,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) if (copy_from_user(&vblwait, argp, sizeof(vblwait))) return -EFAULT; - switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) { + if (vblwait.request.type & + ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { + DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", + vblwait.request.type, + (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); + return -EINVAL; + } + + flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; + + if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? + DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) + return -EINVAL; + + seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : + &dev->vbl_received; + + switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read(&dev->vbl_received); + vblwait.request.sequence += atomic_read(seq); vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; @@ -266,13 +282,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) return -EINVAL; } - flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; - if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; + drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) + ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = atomic_read(&dev->vbl_received); + vblwait.reply.sequence = atomic_read(seq); spin_lock_irqsave(&dev->vbl_lock, irqflags); @@ -280,7 +296,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) * for the same vblank sequence number; nothing to be done in * that case */ - list_for_each_entry(vbl_sig, &dev->vbl_sigs.head, head) { + list_for_each_entry(vbl_sig, &vbl_sigs->head, head) { if (vbl_sig->sequence == vblwait.request.sequence && vbl_sig->info.si_signo == vblwait.request.signal && vbl_sig->task == current) { @@ -313,11 +329,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) spin_lock_irqsave(&dev->vbl_lock, irqflags); - list_add_tail((struct list_head *)vbl_sig, &dev->vbl_sigs.head); + list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } else { - if (dev->driver->vblank_wait) + if (flags & _DRM_VBLANK_SECONDARY) { + if (dev->driver->vblank_wait2) + ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence); + } else if (dev->driver->vblank_wait) ret = dev->driver->vblank_wait(dev, &vblwait.request.sequence); @@ -345,25 +364,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) */ void drm_vbl_send_signals(drm_device_t * dev) { - struct list_head *list, *tmp; - drm_vbl_sig_t *vbl_sig; - unsigned int vbl_seq = atomic_read(&dev->vbl_received); unsigned long flags; + int i; spin_lock_irqsave(&dev->vbl_lock, flags); - list_for_each_safe(list, tmp, &dev->vbl_sigs.head) { - vbl_sig = list_entry(list, drm_vbl_sig_t, head); - if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { - vbl_sig->info.si_code = vbl_seq; - send_sig_info(vbl_sig->info.si_signo, &vbl_sig->info, - vbl_sig->task); + for (i = 0; i < 2; i++) { + struct list_head *list, *tmp; + drm_vbl_sig_t *vbl_sig; + drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; + unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : + &dev->vbl_received); - list_del(list); + list_for_each_safe(list, tmp, &vbl_sigs->head) { + vbl_sig = list_entry(list, drm_vbl_sig_t, head); + if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { + vbl_sig->info.si_code = vbl_seq; + send_sig_info(vbl_sig->info.si_signo, + &vbl_sig->info, vbl_sig->task); - drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER); + list_del(list); - dev->vbl_pending--; + drm_free(vbl_sig, sizeof(*vbl_sig), + DRM_MEM_DRIVER); + + dev->vbl_pending--; + } } } diff --git a/shared-core/drm.h b/shared-core/drm.h index 095823b7..c2bcf62c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -536,10 +536,12 @@ typedef struct drm_irq_busid { typedef enum { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; -#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL +#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) struct drm_wait_vblank_request { drm_vblank_seq_type_t type; From 596d7e998403f565a796c431dbbcaf9e0c49908b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 11 Aug 2006 18:06:46 +0200 Subject: [PATCH 083/147] Add support for secondary vertical blank interrupt to i915 driver. When the vertical blank interrupt is enabled for both pipes, pipe A is considered primary and pipe B secondary. When it's only enabled for one pipe, it's always considered primary for backwards compatibility. (cherry picked from 0c7d7f43610f705e8536a949cf2407efaa5ec217 commit) --- linux-core/i915_drv.c | 4 +++- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 26 +++++++++++++++++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 0a0e5f99..1263bcab 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -67,12 +67,14 @@ static struct drm_driver driver = { */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR | */ - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | + DRIVER_IRQ_VBL2, .load = i915_driver_load, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .device_is_agp = i915_driver_device_is_agp, .vblank_wait = i915_driver_vblank_wait, + .vblank_wait2 = i915_driver_vblank_wait2, .irq_preinstall = i915_driver_irq_preinstall, .irq_postinstall = i915_driver_irq_postinstall, .irq_uninstall = i915_driver_irq_uninstall, diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 745377c6..27324015 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -137,6 +137,7 @@ extern int i915_irq_emit(DRM_IOCTL_ARGS); extern int i915_irq_wait(DRM_IOCTL_ARGS); extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); +extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(drm_device_t * dev); extern void i915_driver_irq_postinstall(drm_device_t * dev); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 51112b62..c26c2769 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -65,7 +65,16 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - atomic_inc(&dev->vbl_received); + if ((dev_priv->vblank_pipe & + (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) + == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { + if (temp & VSYNC_PIPEA_FLAG) + atomic_inc(&dev->vbl_received); + if (temp & VSYNC_PIPEB_FLAG) + atomic_inc(&dev->vbl_received2); + } else + atomic_inc(&dev->vbl_received); + DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); } @@ -153,7 +162,8 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr) return ret; } -int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) +static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence, + atomic_t *counter) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned int cur_vblank; @@ -165,7 +175,7 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) } DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, - (((cur_vblank = atomic_read(&dev->vbl_received)) + (((cur_vblank = atomic_read(counter)) - *sequence) <= (1<<23))); *sequence = cur_vblank; @@ -173,6 +183,16 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) return ret; } +int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) +{ + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); +} + +int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence) +{ + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); +} + /* Needs the lock as it touches the ring. */ int i915_irq_emit(DRM_IOCTL_ARGS) From a7b8c8d523d7f726b8fb74cb37f807d2316cf5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 16 Aug 2006 15:47:22 +0200 Subject: [PATCH 084/147] Add support for interrupt triggered driver callback with lock held to DRM core. (cherry picked from d817cc1f30060fcc4a85a05b2de8a2a1687421b5 commit) --- linux-core/drmP.h | 3 ++ linux-core/drm_irq.c | 74 +++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_lock.c | 11 +++++++ 3 files changed, 88 insertions(+) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6a978f33..60354bce 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -919,6 +919,8 @@ typedef struct drm_device { drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */ unsigned int vbl_pending; + spinlock_t tasklet_lock; /**< For drm_locked_tasklet */ + void (*locked_tasklet_func)(struct drm_device *dev); /*@} */ cycles_t ctx_start; @@ -1230,6 +1232,7 @@ extern int drm_wait_vblank(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_vblank_wait(drm_device_t * dev, unsigned int *vbl_seq); extern void drm_vbl_send_signals(drm_device_t * dev); +extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*)); /* AGP/GART support (drm_agpsupport.h) */ extern drm_agp_head_t *drm_agp_init(drm_device_t *dev); diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index d4e5fbd5..b57fffb0 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -118,6 +118,7 @@ static int drm_irq_install(drm_device_t * dev) init_waitqueue_head(&dev->vbl_queue); spin_lock_init(&dev->vbl_lock); + spin_lock_init(&dev->tasklet_lock); INIT_LIST_HEAD(&dev->vbl_sigs.head); INIT_LIST_HEAD(&dev->vbl_sigs2.head); @@ -396,3 +397,76 @@ void drm_vbl_send_signals(drm_device_t * dev) spin_unlock_irqrestore(&dev->vbl_lock, flags); } EXPORT_SYMBOL(drm_vbl_send_signals); + +/** + * Tasklet wrapper function. + * + * \param data DRM device in disguise. + * + * Attempts to grab the HW lock and calls the driver callback on success. On + * failure, leave the lock marked as contended so the callback can be called + * from drm_unlock(). + */ +static void drm_locked_tasklet_func(unsigned long data) +{ + drm_device_t *dev = (drm_device_t*)data; + unsigned int irqflags; + + spin_lock_irqsave(&dev->tasklet_lock, irqflags); + + if (!dev->locked_tasklet_func || + !drm_lock_take(&dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); + return; + } + + dev->lock.lock_time = jiffies; + atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); + + dev->locked_tasklet_func(dev); + + drm_lock_free(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT); + + dev->locked_tasklet_func = NULL; + + spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); +} + +/** + * Schedule a tasklet to call back a driver hook with the HW lock held. + * + * \param dev DRM device. + * \param func Driver callback. + * + * This is intended for triggering actions that require the HW lock from an + * interrupt handler. The lock will be grabbed ASAP after the interrupt handler + * completes. Note that the callback may be called from interrupt or process + * context, it must not make any assumptions about this. Also, the HW lock will + * be held with the kernel context or any client context. + */ +void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*)) +{ + unsigned int irqflags; + static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0); + + if (test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state)) + return; + + spin_lock_irqsave(&dev->tasklet_lock, irqflags); + + if (dev->locked_tasklet_func) { + spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); + return; + } + + dev->locked_tasklet_func = func; + + spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); + + drm_tasklet.data = (unsigned long)dev; + + tasklet_hi_schedule(&drm_tasklet); +} +EXPORT_SYMBOL(drm_locked_tasklet); diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 86ee25cb..04c145a6 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -155,6 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; + unsigned int irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; @@ -165,6 +166,16 @@ int drm_unlock(struct inode *inode, struct file *filp, return -EINVAL; } + spin_lock_irqsave(&dev->tasklet_lock, irqflags); + + if (dev->locked_tasklet_func) { + dev->locked_tasklet_func(dev); + + dev->locked_tasklet_func = NULL; + } + + spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); + atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); /* kernel_context_switch isn't used by any of the x86 drm From 9810ec2737de6aa81e764225f580e4ea39de437a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Tue, 22 Aug 2006 16:40:07 +0200 Subject: [PATCH 085/147] Add support for tracking drawable information to core Actually make the existing ioctls for adding and removing drawables do something useful, and add another ioctl for the X server to update drawable information. The only kind of drawable information tracked so far is cliprects. (cherry picked from 29598e5253ff5c085ccf63580fd24b84db848424 commit) --- bsd-core/drm_drawable.c | 52 +------- libdrm/xf86drm.c | 16 +++ libdrm/xf86drm.h | 3 + linux-core/Makefile | 4 +- linux-core/drmP.h | 10 ++ linux-core/drm_drawable.c | 57 +-------- linux-core/drm_stub.c | 1 + shared-core/drm.h | 24 ++++ shared-core/drm_drawable.c | 256 +++++++++++++++++++++++++++++++++++++ 9 files changed, 314 insertions(+), 109 deletions(-) mode change 100644 => 120000 bsd-core/drm_drawable.c mode change 100644 => 120000 linux-core/drm_drawable.c create mode 100644 shared-core/drm_drawable.c diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c deleted file mode 100644 index 379e0aa7..00000000 --- a/bsd-core/drm_drawable.c +++ /dev/null @@ -1,51 +0,0 @@ -/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*- - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com - */ -/*- - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith - * Gareth Hughes - * - */ - -#include "drmP.h" - -int drm_adddraw(DRM_IOCTL_ARGS) -{ - drm_draw_t draw; - - draw.handle = 0; /* NOOP */ - DRM_DEBUG("%d\n", draw.handle); - - DRM_COPY_TO_USER_IOCTL( (drm_draw_t *)data, draw, sizeof(draw) ); - - return 0; -} - -int drm_rmdraw(DRM_IOCTL_ARGS) -{ - return 0; /* NOOP */ -} diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c new file mode 120000 index 00000000..d64bbe10 --- /dev/null +++ b/bsd-core/drm_drawable.c @@ -0,0 +1 @@ +../shared-core/drm_drawable.c \ No newline at end of file diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 31d1c164..ab884eb5 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -1398,6 +1398,22 @@ int drmDestroyDrawable(int fd, drm_drawable_t handle) return 0; } +int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, unsigned int num, + void *data) +{ + drm_update_draw_t update; + + update.handle = handle; + update.type = type; + update.num = num; + update.data = (unsigned long long)(unsigned long)data; + + if (ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) return -errno; + + return 0; +} + /** * Acquire the AGP device. * diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index d97681c0..d39974de 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -545,6 +545,9 @@ extern int drmSwitchToContext(int fd, drm_context_t context); extern int drmDestroyContext(int fd, drm_context_t handle); extern int drmCreateDrawable(int fd, drm_drawable_t * handle); extern int drmDestroyDrawable(int fd, drm_drawable_t handle); +extern int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, + unsigned int num, void *data); extern int drmCtlInstHandler(int fd, int irq); extern int drmCtlUninstHandler(int fd); diff --git a/linux-core/Makefile b/linux-core/Makefile index 32828d28..3aecec43 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -75,8 +75,8 @@ DRM_MODULES ?= $(MODULE_LIST) # These definitions are for handling dependencies in the out of kernel build. -DRMSHARED = drm.h drm_sarea.h -DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h $(DRMSHARED) +DRMSHARED = drm.h drm_sarea.h drm_drawable.c +DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h drm.h drm_sarea.h COREHEADERS = drm_core.h drm_sman.h drm_hashtab.h TDFXHEADERS = tdfx_drv.h $(DRMHEADERS) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 60354bce..8a099ba1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -954,6 +954,14 @@ typedef struct drm_device { drm_fence_manager_t fm; drm_buffer_manager_t bm; + /** \name Drawable information */ + /*@{ */ + spinlock_t drw_lock; + unsigned int drw_bitfield_length; + u32 *drw_bitfield; + unsigned int drw_info_length; + drm_drawable_info_t **drw_info; + /*@} */ } drm_device_t; #if __OS_HAS_AGP @@ -1161,6 +1169,8 @@ extern int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, + drm_drawable_t id); /* Authentication IOCTL support (drm_auth.h) */ extern int drm_getmagic(struct inode *inode, struct file *filp, diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c deleted file mode 100644 index 7857453c..00000000 --- a/linux-core/drm_drawable.c +++ /dev/null @@ -1,56 +0,0 @@ -/** - * \file drm_drawable.c - * IOCTLs for drawables - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS 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. - */ - -#include "drmP.h" - -/** No-op. */ -int drm_adddraw(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_draw_t draw; - - draw.handle = 0; /* NOOP */ - DRM_DEBUG("%d\n", draw.handle); - if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw))) - return -EFAULT; - return 0; -} - -/** No-op. */ -int drm_rmdraw(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return 0; /* NOOP */ -} diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c new file mode 120000 index 00000000..d64bbe10 --- /dev/null +++ b/linux-core/drm_drawable.c @@ -0,0 +1 @@ +../shared-core/drm_drawable.c \ No newline at end of file diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index c4f33813..5d28284c 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -67,6 +67,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, int retcode; spin_lock_init(&dev->count_lock); + spin_lock_init(&dev->drw_lock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); diff --git a/shared-core/drm.h b/shared-core/drm.h index c2bcf62c..0b241117 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -164,6 +164,14 @@ typedef struct drm_clip_rect { unsigned short y2; } drm_clip_rect_t; +/** + * Drawable information. + */ +typedef struct drm_drawable_info { + unsigned int num_rects; + drm_clip_rect_t *rects; +} drm_drawable_info_t; + /** * Texture region, */ @@ -514,6 +522,20 @@ typedef struct drm_draw { drm_drawable_t handle; } drm_draw_t; +/** + * DRM_IOCTL_UPDATE_DRAW ioctl argument type. + */ +typedef enum { + DRM_DRAWABLE_CLIPRECTS, +} drm_drawable_info_type_t; + +typedef struct drm_update_draw { + drm_drawable_t handle; + unsigned int type; + unsigned int num; + unsigned long long data; +} drm_update_draw_t; + /** * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type. */ @@ -901,6 +923,8 @@ typedef union drm_mm_init_arg{ #define DRM_IOCTL_MM_INIT DRM_IOWR(0x3e, drm_mm_init_arg_t) #endif +#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t) + /*@}*/ /** diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c new file mode 100644 index 00000000..ca6eb81c --- /dev/null +++ b/shared-core/drm_drawable.c @@ -0,0 +1,256 @@ +/** + * \file drm_drawable.c + * IOCTLs for drawables + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + * \author Michel Dänzer + */ + +/* + * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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. + */ + +#include "drmP.h" + +/** No-op. */ +int drm_adddraw(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + unsigned int irqflags; + int i, j = 0; + drm_draw_t draw; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + for (i = 0; i < dev->drw_bitfield_length; i++) { + u32 bitfield = dev->drw_bitfield[i]; + + if (bitfield == ~0) + continue; + + for (; j < sizeof(bitfield); j++) + if (!(bitfield & (1 << j))) + goto done; + } +done: + + if (i == dev->drw_bitfield_length) { + u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4, + (i + 1) * 4, DRM_MEM_BUFS); + + if (!new_bitfield) { + DRM_ERROR("Failed to allocate new drawable bitfield\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + if (32 * (i + 1) > dev->drw_info_length) { + void *new_info = drm_realloc(dev->drw_info, + dev->drw_info_length * + sizeof(drm_drawable_info_t*), + 32 * (i + 1) * + sizeof(drm_drawable_info_t*), + DRM_MEM_BUFS); + + if (!new_info) { + DRM_ERROR("Failed to allocate new drawable info" + " array\n"); + + drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + dev->drw_info = (drm_drawable_info_t**)new_info; + } + + new_bitfield[i] = 0; + + dev->drw_bitfield = new_bitfield; + dev->drw_bitfield_length++; + } + + dev->drw_bitfield[i] |= 1 << j; + + draw.handle = i * sizeof(u32) + j; + DRM_DEBUG("%d\n", draw.handle); + + dev->drw_info[draw.handle] = NULL; + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw)); + + return 0; +} + +/** No-op. */ +int drm_rmdraw(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_draw_t draw; + unsigned int idx, mod; + unsigned int irqflags; + + DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, + sizeof(draw)); + + idx = draw.handle / 32; + mod = draw.handle % 32; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_DEBUG("No such drawable %d\n", draw.handle); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return 0; + } + + dev->drw_bitfield[idx] &= ~(1 << mod); + + if (idx == (dev->drw_bitfield_length - 1)) { + while (idx >= 0 && !dev->drw_bitfield[idx]) + --idx; + + if (idx != draw.handle / 32) { + u32 *new_bitfield = drm_realloc(dev->drw_bitfield, + dev->drw_bitfield_length * 4, + (idx + 1) * 4, + DRM_MEM_BUFS); + + if (new_bitfield || idx == -1) { + dev->drw_bitfield = new_bitfield; + dev->drw_bitfield_length = idx + 1; + } + } + } + + if (32 * dev->drw_bitfield_length < dev->drw_info_length) { + void *new_info = drm_realloc(dev->drw_info, + dev->drw_info_length * + sizeof(drm_drawable_info_t*), + 32 * dev->drw_bitfield_length * + sizeof(drm_drawable_info_t*), + DRM_MEM_BUFS); + + if (new_info || !dev->drw_bitfield_length) { + dev->drw_info = (drm_drawable_info_t**)new_info; + dev->drw_info_length = 32 * dev->drw_bitfield_length; + } + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + return 0; +} + +int drm_update_drawable_info(DRM_IOCTL_ARGS) { + DRM_DEVICE; + drm_update_draw_t update; + unsigned int id, idx, mod; + unsigned int irqflags; + drm_drawable_info_t *info; + void *new_data; + + DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, + sizeof(update)); + + id = update.handle; + idx = id / 32; + mod = id % 32; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_ERROR("No such drawable %d\n", update.handle); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EINVAL); + } + + info = dev->drw_info[id]; + + if (!info) { + info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS); + + if (!info) { + DRM_ERROR("Failed to allocate drawable info memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + dev->drw_info[id] = info; + } + + switch (update.type) { + case DRM_DRAWABLE_CLIPRECTS: + new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + + if (!new_data) { + DRM_ERROR("Failed to allocate cliprect memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + if (DRM_COPY_FROM_USER(new_data, + (drm_clip_rect_t __user *) + (unsigned long)update.data, + update.num * sizeof(drm_clip_rect_t))) { + DRM_ERROR("Failed to copy cliprects from userspace\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EFAULT); + } + + drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + + info->rects = new_data; + info->num_rects = update.num; + break; + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + return 0; +} + +/** + * Caller must hold the drawable spinlock! + */ +drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { + unsigned int idx = id / 32, mod = id % 32; + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_DEBUG("No such drawable %d\n", id); + return NULL; + } + + return dev->drw_info[id]; +} From baa26c5faa3d5903569d1c94ad93b843d6979ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 23 Aug 2006 16:04:41 +0200 Subject: [PATCH 086/147] Only reallocate cliprect memory if the number of cliprects changes. Also improve diagnostic output. (cherry picked from af48be1096221d551319c67a9e782b50ef58fefd commit) --- shared-core/drm_drawable.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index ca6eb81c..511f3eae 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -166,6 +166,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_DEBUG("%d\n", draw.handle); return 0; } @@ -209,30 +210,42 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: - new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + if (update.num != info->num_rects) { + new_data = drm_alloc(update.num * + sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); - if (!new_data) { - DRM_ERROR("Failed to allocate cliprect memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(ENOMEM); + if (!new_data) { + DRM_ERROR("Can't allocate cliprect memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + info->rects = new_data; } - if (DRM_COPY_FROM_USER(new_data, + if (DRM_COPY_FROM_USER(info->rects, (drm_clip_rect_t __user *) (unsigned long)update.data, update.num * sizeof(drm_clip_rect_t))) { - DRM_ERROR("Failed to copy cliprects from userspace\n"); + DRM_ERROR("Can't copy cliprects from userspace\n"); spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EFAULT); } - drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + if (update.num != info->num_rects) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + info->num_rects = update.num; + } - info->rects = new_data; - info->num_rects = update.num; + DRM_DEBUG("Updated %d cliprects for drawable %d\n", + info->num_rects, id); break; + default: + DRM_ERROR("Invalid update type %d\n", update.type); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EINVAL); } spin_unlock_irqrestore(&dev->drw_lock, irqflags); From 67e88e5628d02cd94561e31fd68e02b6bde66e6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 23 Aug 2006 16:05:47 +0200 Subject: [PATCH 087/147] Hook up DRM_IOCTL_UPDATE_DRAW ioctl. (cherry picked from 98a89504589427a76c3f5cfa2266962a1a212672 commit) --- linux-core/drmP.h | 2 ++ linux-core/drm_drv.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 8a099ba1..8b3364e4 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1169,6 +1169,8 @@ extern int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int drm_update_drawable_info(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 89b20a9d..d4ef1306 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -123,7 +123,9 @@ static drm_ioctl_desc_t drm_ioctls[] = { [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_AUTH }, + + [DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, }; #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) From f93e4822694b066427f70c23216b78f92edb1bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 23 Aug 2006 19:00:26 +0200 Subject: [PATCH 088/147] Export drm_get_drawable_info symbol from core. (cherry picked from 43f8675534c7e95efbc92eaf2c8cc43aef95f125 commit) --- shared-core/drm_drawable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 511f3eae..0a357948 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -267,3 +267,4 @@ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) return dev->drw_info[id]; } +EXPORT_SYMBOL(drm_get_drawable_info); From ca3a1b5ec4a417785238fb7c0cb4c3570dbcb31a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 25 Aug 2006 18:55:06 +0200 Subject: [PATCH 089/147] Drop tasklet locked driver callback when uninstalling IRQ. (cherry picked from b9f3009160d8bd1a26a77d6f1616f1679c7b969d commit) --- linux-core/drm_irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index b57fffb0..fef0e8d4 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -176,6 +176,8 @@ int drm_irq_uninstall(drm_device_t * dev) free_irq(dev->irq, dev); + dev->locked_tasklet_func = NULL; + return 0; } EXPORT_SYMBOL(drm_irq_uninstall); From d7389a9758944ab0d241d3c1108adfeeec9eee76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 25 Aug 2006 18:55:55 +0200 Subject: [PATCH 090/147] Locking and memory management fixes. (cherry picked from 23d2833aaa37a33b9ddcf06cc796f59befc0d360 commit) --- shared-core/drm_drawable.c | 271 ++++++++++++++++++++++--------------- 1 file changed, 159 insertions(+), 112 deletions(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 0a357948..81eb9f08 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -36,70 +36,86 @@ #include "drmP.h" -/** No-op. */ +/** + * Allocate drawable ID and memory to store information about it. + */ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; unsigned int irqflags; - int i, j = 0; + int i, j; + u32 *bitfield = dev->drw_bitfield; + unsigned int bitfield_length = dev->drw_bitfield_length; + drm_drawable_info_t **info = dev->drw_info; + unsigned int info_length = dev->drw_info_length; drm_draw_t draw; - spin_lock_irqsave(&dev->drw_lock, irqflags); - - for (i = 0; i < dev->drw_bitfield_length; i++) { - u32 bitfield = dev->drw_bitfield[i]; - - if (bitfield == ~0) + for (i = 0, j = 0; i < bitfield_length; i++) { + if (bitfield[i] == ~0) continue; - for (; j < sizeof(bitfield); j++) - if (!(bitfield & (1 << j))) + for (; j < 8 * sizeof(*bitfield); j++) + if (!(bitfield[i] & (1 << j))) goto done; } done: - if (i == dev->drw_bitfield_length) { - u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4, - (i + 1) * 4, DRM_MEM_BUFS); + if (i == bitfield_length) { + bitfield_length++; - if (!new_bitfield) { + bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), + DRM_MEM_BUFS); + + if (!bitfield) { DRM_ERROR("Failed to allocate new drawable bitfield\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(ENOMEM); } - if (32 * (i + 1) > dev->drw_info_length) { - void *new_info = drm_realloc(dev->drw_info, - dev->drw_info_length * - sizeof(drm_drawable_info_t*), - 32 * (i + 1) * - sizeof(drm_drawable_info_t*), - DRM_MEM_BUFS); + if (8 * sizeof(*bitfield) * bitfield_length > info_length) { + info_length += 8 * sizeof(*bitfield); - if (!new_info) { + info = drm_alloc(info_length * sizeof(*info), + DRM_MEM_BUFS); + + if (!info) { DRM_ERROR("Failed to allocate new drawable info" " array\n"); - drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); + drm_free(bitfield, + bitfield_length * sizeof(*bitfield), + DRM_MEM_BUFS); return DRM_ERR(ENOMEM); } - - dev->drw_info = (drm_drawable_info_t**)new_info; } - new_bitfield[i] = 0; - - dev->drw_bitfield = new_bitfield; - dev->drw_bitfield_length++; + bitfield[i] = 0; } - dev->drw_bitfield[i] |= 1 << j; - - draw.handle = i * sizeof(u32) + j; + draw.handle = i * 8 * sizeof(*bitfield) + j; DRM_DEBUG("%d\n", draw.handle); - dev->drw_info[draw.handle] = NULL; + spin_lock_irqsave(&dev->drw_lock, irqflags); + + bitfield[i] |= 1 << j; + info[draw.handle] = NULL; + + if (bitfield != dev->drw_bitfield) { + memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * + sizeof(*bitfield)); + drm_free(dev->drw_bitfield, sizeof(*bitfield) * + dev->drw_bitfield_length, DRM_MEM_BUFS); + dev->drw_bitfield = bitfield; + dev->drw_bitfield_length = bitfield_length; + } + + if (info != dev->drw_info) { + memcpy(info, dev->drw_info, dev->drw_info_length * + sizeof(*info)); + drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length, + DRM_MEM_BUFS); + dev->drw_info = info; + dev->drw_info_length = info_length; + } spin_unlock_irqrestore(&dev->drw_lock, irqflags); @@ -108,64 +124,86 @@ done: return 0; } -/** No-op. */ +/** + * Free drawable ID and memory to store information about it. + */ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int idx, mod; + unsigned int idx, shift; unsigned int irqflags; + u32 *bitfield = dev->drw_bitfield; + unsigned int bitfield_length = dev->drw_bitfield_length; + drm_drawable_info_t **info = dev->drw_info; + unsigned int info_length = dev->drw_info_length; DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - idx = draw.handle / 32; - mod = draw.handle % 32; + idx = draw.handle / (8 * sizeof(*bitfield)); + shift = draw.handle % (8 * sizeof(*bitfield)); - spin_lock_irqsave(&dev->drw_lock, irqflags); - - if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + if (idx >= bitfield_length || + !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", draw.handle); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return 0; } - dev->drw_bitfield[idx] &= ~(1 << mod); + spin_lock_irqsave(&dev->drw_lock, irqflags); - if (idx == (dev->drw_bitfield_length - 1)) { - while (idx >= 0 && !dev->drw_bitfield[idx]) - --idx; - - if (idx != draw.handle / 32) { - u32 *new_bitfield = drm_realloc(dev->drw_bitfield, - dev->drw_bitfield_length * 4, - (idx + 1) * 4, - DRM_MEM_BUFS); - - if (new_bitfield || idx == -1) { - dev->drw_bitfield = new_bitfield; - dev->drw_bitfield_length = idx + 1; - } - } - } - - if (32 * dev->drw_bitfield_length < dev->drw_info_length) { - void *new_info = drm_realloc(dev->drw_info, - dev->drw_info_length * - sizeof(drm_drawable_info_t*), - 32 * dev->drw_bitfield_length * - sizeof(drm_drawable_info_t*), - DRM_MEM_BUFS); - - if (new_info || !dev->drw_bitfield_length) { - dev->drw_info = (drm_drawable_info_t**)new_info; - dev->drw_info_length = 32 * dev->drw_bitfield_length; - } - } + bitfield[idx] &= ~(1 << shift); spin_unlock_irqrestore(&dev->drw_lock, irqflags); + /* Can we shrink the arrays? */ + if (idx == bitfield_length - 1) { + while (idx >= 0 && !bitfield[idx]) + --idx; + + bitfield_length = idx + 1; + + if (idx != draw.handle / (8 * sizeof(*bitfield))) + bitfield = drm_alloc(bitfield_length * + sizeof(*bitfield), DRM_MEM_BUFS); + + if (!bitfield && bitfield_length) { + bitfield = dev->drw_bitfield; + bitfield_length = dev->drw_bitfield_length; + } + } + + if (bitfield != dev->drw_bitfield) { + info_length = 8 * sizeof(*bitfield) * bitfield_length; + + info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS); + + if (!info && info_length) { + info = dev->drw_info; + info_length = dev->drw_info_length; + } + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + memcpy(bitfield, dev->drw_bitfield, bitfield_length * + sizeof(*bitfield)); + drm_free(dev->drw_bitfield, sizeof(*bitfield) * + dev->drw_bitfield_length, DRM_MEM_BUFS); + dev->drw_bitfield = bitfield; + dev->drw_bitfield_length = bitfield_length; + + if (info != dev->drw_info) { + memcpy(info, dev->drw_info, info_length * + sizeof(*info)); + drm_free(dev->drw_info, sizeof(*info) * + dev->drw_info_length, DRM_MEM_BUFS); + dev->drw_info = info; + dev->drw_info_length = info_length; + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + } + DRM_DEBUG("%d\n", draw.handle); return 0; } @@ -173,24 +211,22 @@ int drm_rmdraw(DRM_IOCTL_ARGS) int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_update_draw_t update; - unsigned int id, idx, mod; - unsigned int irqflags; + unsigned int id, idx, shift; + u32 *bitfield = dev->drw_bitfield; + unsigned int irqflags, bitfield_length = dev->drw_bitfield_length; drm_drawable_info_t *info; - void *new_data; + drm_clip_rect_t *rects; + int err; DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, sizeof(update)); id = update.handle; - idx = id / 32; - mod = id % 32; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - spin_lock_irqsave(&dev->drw_lock, irqflags); - - if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_ERROR("No such drawable %d\n", update.handle); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EINVAL); } @@ -201,66 +237,77 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { if (!info) { DRM_ERROR("Failed to allocate drawable info memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(ENOMEM); } - - dev->drw_info[id] = info; } switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: if (update.num != info->num_rects) { - new_data = drm_alloc(update.num * - sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + rects = drm_alloc(update.num * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + } else + rects = info->rects; - if (!new_data) { - DRM_ERROR("Can't allocate cliprect memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(ENOMEM); - } - - info->rects = new_data; + if (update.num && !rects) { + DRM_ERROR("Failed to allocate cliprect memory\n"); + err = DRM_ERR(ENOMEM); + goto error; } - if (DRM_COPY_FROM_USER(info->rects, - (drm_clip_rect_t __user *) - (unsigned long)update.data, - update.num * sizeof(drm_clip_rect_t))) { - DRM_ERROR("Can't copy cliprects from userspace\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(EFAULT); + if (update.num && DRM_COPY_FROM_USER(rects, + (drm_clip_rect_t __user *) + (unsigned long)update.data, + update.num * + sizeof(*rects))) { + DRM_ERROR("Failed to copy cliprects from userspace\n"); + err = DRM_ERR(EFAULT); + goto error; } - if (update.num != info->num_rects) { + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (rects != info->rects) { drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), DRM_MEM_BUFS); - info->num_rects = update.num; } + info->rects = rects; + info->num_rects = update.num; + dev->drw_info[id] = info; + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_DEBUG("Updated %d cliprects for drawable %d\n", info->num_rects, id); break; default: DRM_ERROR("Invalid update type %d\n", update.type); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EINVAL); } - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return 0; + +error: + if (!dev->drw_info[id]) + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + else if (rects != dev->drw_info[id]->rects) + drm_free(rects, update.num * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + + return err; } /** * Caller must hold the drawable spinlock! */ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { - unsigned int idx = id / 32, mod = id % 32; + u32 *bitfield = dev->drw_bitfield; + unsigned int idx = id / (8 * sizeof(*bitfield)); + unsigned int shift = id % (8 * sizeof(*bitfield)); if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", id); return NULL; } From da75d59cd65764c6076ab9b96ad8195ed71ed80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 25 Aug 2006 19:01:05 +0200 Subject: [PATCH 091/147] i915: Add ioctl for scheduling buffer swaps at vertical blanks. This uses the core facility to schedule a driver callback that will be called ASAP after the given vertical blank interrupt with the HW lock held. (cherry picked from 257771fa290b62d4d2ad896843cf3a207978d0bb commit) --- shared-core/i915_dma.c | 2 + shared-core/i915_drm.h | 9 ++ shared-core/i915_drv.h | 16 ++++ shared-core/i915_irq.c | 183 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index baeab383..841761c8 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -163,6 +163,7 @@ static int i915_initialize(drm_device_t * dev, dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; dev_priv->front_offset = init->front_offset; dev_priv->current_page = 0; @@ -821,6 +822,7 @@ drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, + [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH}, }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index e841105b..e1db7a65 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -142,6 +142,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_DESTROY_HEAP 0x0c #define DRM_I915_SET_VBLANK_PIPE 0x0d #define DRM_I915_GET_VBLANK_PIPE 0x0e +#define DRM_I915_VBLANK_SWAP 0x0f #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -254,4 +255,12 @@ typedef struct drm_i915_vblank_pipe { int pipe; } drm_i915_vblank_pipe_t; +/* Schedule buffer swap at given vertical blank: + */ +typedef struct drm_i915_vblank_swap { + drm_drawable_t drawable; + unsigned int pipe; + unsigned int sequence; +} drm_i915_vblank_swap_t; + #endif /* _I915_DRM_H_ */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 27324015..c6bbcafb 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -76,6 +76,13 @@ struct mem_block { DRMFILE filp; /* 0: free, -1: heap, other: real files */ }; +typedef struct _drm_i915_vbl_swap { + struct list_head head; + drm_drawable_t drw_id; + unsigned int pipe; + unsigned int sequence; +} drm_i915_vbl_swap_t; + typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; @@ -88,6 +95,7 @@ typedef struct drm_i915_private { dma_addr_t dma_status_page; uint32_t counter; + unsigned int cpp; int back_offset; int front_offset; int current_page; @@ -116,6 +124,9 @@ typedef struct drm_i915_private { uint32_t saved_flush_status; #endif + spinlock_t swaps_lock; + drm_i915_vbl_swap_t vbl_swaps; + unsigned int swaps_pending; } drm_i915_private_t; extern drm_ioctl_desc_t i915_ioctls[]; @@ -147,6 +158,7 @@ extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); extern int i915_emit_irq(drm_device_t * dev); extern void i915_user_irq_on(drm_i915_private_t *dev_priv); extern void i915_user_irq_off(drm_i915_private_t *dev_priv); +extern int i915_vblank_swap(DRM_IOCTL_ARGS); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); @@ -304,6 +316,10 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) + #define MI_BATCH_BUFFER ((0x30<<23)|1) #define MI_BATCH_BUFFER_START (0x31<<23) #define MI_BATCH_BUFFER_END (0xA<<23) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index c26c2769..667a9ca8 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -37,6 +37,99 @@ #define MAX_NOPID ((u32)~0) +/** + * Emit blits for scheduled buffer swaps. + * + * This function will be called with the HW lock held. + */ +static void i915_vblank_tasklet(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned int irqflags; + struct list_head *list, *tmp; + + DRM_DEBUG("\n"); + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { + drm_i915_vbl_swap_t *vbl_swap = + list_entry(list, drm_i915_vbl_swap_t, head); + atomic_t *counter = vbl_swap->pipe ? &dev->vbl_received2 : + &dev->vbl_received; + + if ((atomic_read(counter) - vbl_swap->sequence) <= (1<<23)) { + drm_drawable_info_t *drw; + + spin_unlock(&dev_priv->swaps_lock); + + spin_lock(&dev->drw_lock); + + drw = drm_get_drawable_info(dev, vbl_swap->drw_id); + + if (drw) { + int i, num_rects = drw->num_rects; + drm_clip_rect_t *rect = drw->rects; + drm_i915_sarea_t *sarea_priv = + dev_priv->sarea_priv; + u32 cpp = dev_priv->cpp; + u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB) + : XY_SRC_COPY_BLT_CMD; + u32 pitchropcpp = (sarea_priv->pitch * cpp) | + (0xcc << 16) | (cpp << 23) | + (1 << 24); + RING_LOCALS; + + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(6); + + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(0); + OUT_RING(0); + OUT_RING(sarea_priv->width | + sarea_priv->height << 16); + OUT_RING(sarea_priv->width | + sarea_priv->height << 16); + OUT_RING(0); + + ADVANCE_LP_RING(); + + sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; + + for (i = 0; i < num_rects; i++, rect++) { + BEGIN_LP_RING(8); + + OUT_RING(cmd); + OUT_RING(pitchropcpp); + OUT_RING((rect->y1 << 16) | rect->x1); + OUT_RING((rect->y2 << 16) | rect->x2); + OUT_RING(sarea_priv->front_offset); + OUT_RING((rect->y1 << 16) | rect->x1); + OUT_RING(pitchropcpp & 0xffff); + OUT_RING(sarea_priv->back_offset); + + ADVANCE_LP_RING(); + } + } + + spin_unlock(&dev->drw_lock); + + spin_lock(&dev_priv->swaps_lock); + + list_del(list); + + drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); + + dev_priv->swaps_pending--; + } + } + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; @@ -77,6 +170,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); + + drm_locked_tasklet(dev, i915_vblank_tasklet); } return IRQ_HANDLED; @@ -307,6 +402,90 @@ int i915_vblank_pipe_get(DRM_IOCTL_ARGS) return 0; } +/** + * Schedule buffer swap at given vertical blank. + */ +int i915_vblank_swap(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_swap_t swap; + drm_i915_vbl_swap_t *vbl_swap; + unsigned int irqflags; + struct list_head *list; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __func__); + return DRM_ERR(EINVAL); + } + + if (dev_priv->sarea_priv->rotation) { + DRM_DEBUG("Rotation not supported\n"); + return DRM_ERR(EINVAL); + } + + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + + DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, + sizeof(swap)); + + if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { + DRM_ERROR("Invalid pipe %d\n", swap.pipe); + return DRM_ERR(EINVAL); + } + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (!drm_get_drawable_info(dev, swap.drawable)) { + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_ERROR("Invalid drawable ID %d\n", swap.drawable); + return DRM_ERR(EINVAL); + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_for_each(list, &dev_priv->vbl_swaps.head) { + vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); + + if (vbl_swap->drw_id == swap.drawable && + vbl_swap->pipe == swap.pipe && + vbl_swap->sequence == swap.sequence) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Already scheduled\n"); + return 0; + } + } + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); + + if (!vbl_swap) { + DRM_ERROR("Failed to allocate memory to queue swap\n"); + return DRM_ERR(ENOMEM); + } + + DRM_DEBUG("\n"); + + vbl_swap->drw_id = swap.drawable; + vbl_swap->pipe = swap.pipe; + vbl_swap->sequence = swap.sequence; + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head); + dev_priv->swaps_pending++; + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + return 0; +} + /* drm_dma.h hooks */ void i915_driver_irq_preinstall(drm_device_t * dev) @@ -322,6 +501,10 @@ void i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); + dev_priv->swaps_pending = 0; + i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); From 7d487602a31dd886037417db088b6e643ed86918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 28 Aug 2006 18:19:58 +0200 Subject: [PATCH 092/147] Add copyright notice. (cherry picked from d04751facea36cb888c7510b126658fdbc4277d5 commit) --- shared-core/drm_drawable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 81eb9f08..bbfaf139 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -12,6 +12,7 @@ * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a From 00531cecad3cf9a1ec230f7f33535d153b9d9bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 30 Aug 2006 19:24:04 +0200 Subject: [PATCH 093/147] Change first valid DRM drawable ID to be 1 instead of 0. This makes it easier for userspace to know when it needs to allocate an ID. Also free drawable information memory when it's no longer needed. (cherry picked from df7551ef7334d728ec0371423661bb403d3e270a commit) --- linux-core/drm_drv.c | 12 ++++++++++++ shared-core/drm_drawable.c | 35 +++++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index d4ef1306..37539f34 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -163,6 +163,18 @@ int drm_lastclose(drm_device_t * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); + /* Free drawable information memory */ + for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield); + i++) { + drm_drawable_info_t *info = drm_get_drawable_info(dev, i); + + if (info) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + } + } + mutex_lock(&dev->struct_mutex); del_timer(&dev->timer); diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index bbfaf139..5e2fc86c 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -92,13 +92,13 @@ done: bitfield[i] = 0; } - draw.handle = i * 8 * sizeof(*bitfield) + j; + draw.handle = i * 8 * sizeof(*bitfield) + j + 1; DRM_DEBUG("%d\n", draw.handle); spin_lock_irqsave(&dev->drw_lock, irqflags); bitfield[i] |= 1 << j; - info[draw.handle] = NULL; + info[draw.handle - 1] = NULL; if (bitfield != dev->drw_bitfield) { memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * @@ -132,7 +132,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int idx, shift; + unsigned int id, idx, shift; unsigned int irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; @@ -142,10 +142,11 @@ int drm_rmdraw(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - idx = draw.handle / (8 * sizeof(*bitfield)); - shift = draw.handle % (8 * sizeof(*bitfield)); + id = draw.handle - 1; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - if (idx >= bitfield_length || + if (idx < 0 || idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", draw.handle); return 0; @@ -157,6 +158,12 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + if (info[id]) { + drm_free(info[id]->rects, info[id]->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info[id], sizeof(**info), DRM_MEM_BUFS); + } + /* Can we shrink the arrays? */ if (idx == bitfield_length - 1) { while (idx >= 0 && !bitfield[idx]) @@ -164,7 +171,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) bitfield_length = idx + 1; - if (idx != draw.handle / (8 * sizeof(*bitfield))) + if (idx != id / (8 * sizeof(*bitfield))) bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), DRM_MEM_BUFS); @@ -222,11 +229,12 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, sizeof(update)); - id = update.handle; + id = update.handle - 1; idx = id / (8 * sizeof(*bitfield)); shift = id % (8 * sizeof(*bitfield)); - if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { + if (idx < 0 || idx >= bitfield_length || + !(bitfield[idx] & (1 << shift))) { DRM_ERROR("No such drawable %d\n", update.handle); return DRM_ERR(EINVAL); } @@ -304,10 +312,13 @@ error: */ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { u32 *bitfield = dev->drw_bitfield; - unsigned int idx = id / (8 * sizeof(*bitfield)); - unsigned int shift = id % (8 * sizeof(*bitfield)); + unsigned int idx, shift; - if (idx >= dev->drw_bitfield_length || + id--; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); + + if (idx < 0 || idx >= dev->drw_bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", id); return NULL; From 1f3493f65ba0959e401191c648f57501216eeb0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 30 Aug 2006 19:33:28 +0200 Subject: [PATCH 094/147] DRM_I915_VBLANK_SWAP ioctl: Take drm_vblank_seq_type_t instead of pipe number. Handle relative as well as absolute target sequence numbers. Return error if target sequence has already passed, so userspace can deal with this situation as it sees fit. On success, return the sequence number of the vertical blank when the buffer swap is expected to take place. Also add DRM_IOCTL_I915_VBLANK_SWAP definition for userspace code that may want to use ioctl() instead of drmCommandWriteRead(). (cherry picked from d5a0f107511e128658e2d5e15bd7e6215c507f29 commit) --- shared-core/i915_drm.h | 3 ++- shared-core/i915_irq.c | 43 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index e1db7a65..e2a70231 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -159,6 +159,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) /* Allow drivers to submit batchbuffers directly to hardware, relying @@ -259,7 +260,7 @@ typedef struct drm_i915_vblank_pipe { */ typedef struct drm_i915_vblank_swap { drm_drawable_t drawable; - unsigned int pipe; + drm_vblank_seq_type_t seqtype; unsigned int sequence; } drm_i915_vblank_swap_t; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 667a9ca8..3c562fdd 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -411,7 +411,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int irqflags; + unsigned int pipe, seqtype, irqflags, curseq; struct list_head *list; if (!dev_priv) { @@ -432,8 +432,23 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); - if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { - DRM_ERROR("Invalid pipe %d\n", swap.pipe); + if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | + _DRM_VBLANK_SECONDARY)) { + DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); + return DRM_ERR(EINVAL); + } + + pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; + + seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); + + if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { + DRM_DEBUG("Not scheduling swap for current sequence\n"); + return DRM_ERR(EINVAL); + } + + if (!(dev_priv->vblank_pipe & (1 << pipe))) { + DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); } @@ -447,13 +462,28 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + switch (seqtype) { + case _DRM_VBLANK_RELATIVE: + swap.sequence += curseq; + break; + case _DRM_VBLANK_ABSOLUTE: + if ((curseq - swap.sequence) > (1<<23)) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Missed target sequence\n"); + return DRM_ERR(EINVAL); + } + break; + } + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); if (vbl_swap->drw_id == swap.drawable && - vbl_swap->pipe == swap.pipe && + vbl_swap->pipe == pipe && vbl_swap->sequence == swap.sequence) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); @@ -473,7 +503,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_DEBUG("\n"); vbl_swap->drw_id = swap.drawable; - vbl_swap->pipe = swap.pipe; + vbl_swap->pipe = pipe; vbl_swap->sequence = swap.sequence; spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); @@ -483,6 +513,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap, + sizeof(swap)); + return 0; } From 4a3d270862f6dbc52ca3e16ba66fdb24667b2aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:30:55 +0200 Subject: [PATCH 095/147] Make handling of dev_priv->vblank_pipe more robust. Initialize it to default value if it hasn't been set by the X server yet. In i915_vblank_pipe_set(), only update dev_priv->vblank_pipe and call i915_enable_interrupt() if the argument passed from userspace is valid to avoid corrupting dev_priv->vblank_pipe on invalid arguments. (cherry picked from 87c57cba1a70221fc570b253bf3b24682ef6b894 commit) --- shared-core/i915_irq.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 3c562fdd..f82df5c9 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -336,7 +336,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } -static int i915_enable_interrupt (drm_device_t *dev) +static void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u16 flag; @@ -346,17 +346,11 @@ static int i915_enable_interrupt (drm_device_t *dev) flag |= VSYNC_PIPEA_FLAG; if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) flag |= VSYNC_PIPEB_FLAG; - if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { - DRM_ERROR("%s called with invalid pipe 0x%x\n", - __FUNCTION__, dev_priv->vblank_pipe); - return DRM_ERR(EINVAL); - } dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; dev_priv->user_irq_refcount = 0; dev_priv->irq_enable_reg = flag; I915_WRITE16(I915REG_INT_ENABLE_R, flag); dev_priv->irq_enabled = 1; - return 0; } /* Set the vblank monitor pipe @@ -375,8 +369,17 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data, sizeof(pipe)); + if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { + DRM_ERROR("%s called with invalid pipe 0x%x\n", + __FUNCTION__, pipe.pipe); + return DRM_ERR(EINVAL); + } + dev_priv->vblank_pipe = pipe.pipe; - return i915_enable_interrupt (dev); + + i915_enable_interrupt (dev); + + return 0; } int i915_vblank_pipe_get(DRM_IOCTL_ARGS) @@ -538,6 +541,8 @@ void i915_driver_irq_postinstall(drm_device_t * dev) INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; + if (!dev_priv->vblank_pipe) + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); From 316e73676861c0e019d52ec7bf7b7b1451eaed97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:32:08 +0200 Subject: [PATCH 096/147] Add definition of DRM_VBLANK_SECONDARY. (cherry picked from 84b38b63f05e04ade8b1ddfb770047fd86de0d64 commit) --- libdrm/xf86drm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index d39974de..07178ec3 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; From f9aa4f5973d6098b95e92f606dc1967c627897db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:33:04 +0200 Subject: [PATCH 097/147] Add SAREA fileds for determining which pipe to sync window buffer swaps to. (cherry picked from c2bdb76814755c9ac6e66a8815f23af0fe4f3a91 commit) --- shared-core/i915_drm.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index e2a70231..9eec109e 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -104,6 +104,15 @@ typedef struct _drm_i915_sarea { unsigned int depth_tiled; unsigned int rotated_tiled; unsigned int rotated2_tiled; + + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; } drm_i915_sarea_t; /* Driver specific fence types and classes. From c4c47a7eacf8e8cb96b2fb63164e28f0db7353ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 1 Sep 2006 11:24:38 +0200 Subject: [PATCH 098/147] Fix 'sequence has passed' condition in i915_vblank_swap(). (cherry picked from 7f09f957d9a61ac107f8fd29128d7899a3e8a228 commit) --- shared-core/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index f82df5c9..d88afdd0 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -474,7 +474,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) swap.sequence += curseq; break; case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) > (1<<23)) { + if ((curseq - swap.sequence) <= (1<<23)) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); From ed82172378666d35ca60e6094fdecb59511a135f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 1 Sep 2006 11:27:14 +0200 Subject: [PATCH 099/147] Core vsync: Add flag DRM_VBLANK_NEXTONMISS. When this flag is set and the target sequence is missed, wait for the next vertical blank instead of returning immediately. (cherry picked from 89e323e4900af84cc33219ad24eb0b435a039d23 commit) --- libdrm/xf86drm.h | 1 + linux-core/drm_irq.c | 16 ++++++++++------ shared-core/drm.h | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 07178ec3..ae89fd6f 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index fef0e8d4..bd8a9c82 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -249,8 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) drm_wait_vblank_t vblwait; struct timeval now; int ret = 0; - unsigned int flags; - atomic_t *seq; + unsigned int flags, seq; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -272,12 +271,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) return -EINVAL; - seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : - &dev->vbl_received; + seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 + : &dev->vbl_received); switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read(seq); + vblwait.request.sequence += seq; vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; @@ -285,13 +284,18 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) return -EINVAL; } + if ((flags & _DRM_VBLANK_NEXTONMISS) && + (seq - vblwait.request.sequence) <= (1<<23)) { + vblwait.request.sequence = seq + 1; + } + if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = atomic_read(seq); + vblwait.reply.sequence = seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); diff --git a/shared-core/drm.h b/shared-core/drm.h index 0b241117..17bf993b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -558,12 +558,14 @@ typedef struct drm_irq_busid { typedef enum { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) -#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \ + _DRM_VBLANK_NEXTONMISS) struct drm_wait_vblank_request { drm_vblank_seq_type_t type; From cef0f243251103be81c914d5b83ee3401c2a9c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 1 Sep 2006 11:35:31 +0200 Subject: [PATCH 100/147] Core vsync: Don't clobber target sequence number when scheduling signal. It looks like this would have caused signals to always get sent on the next vertical blank, regardless of the sequence number. (cherry picked from cf6b2c5299e9be3542d4deddfd05d5811f11d2ef commit) --- linux-core/drm_irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index bd8a9c82..d1a6a6b1 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -295,8 +295,6 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = seq; - spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Check if this task has already scheduled the same signal @@ -309,6 +307,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) && vbl_sig->task == current) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + vblwait.reply.sequence = seq; goto done; } } @@ -339,6 +338,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + + vblwait.reply.sequence = seq; } else { if (flags & _DRM_VBLANK_SECONDARY) { if (dev->driver->vblank_wait2) From c47ebd970783873164578126fa5481a166cd837e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 1 Sep 2006 11:48:07 +0200 Subject: [PATCH 101/147] Only return EBUSY after we've established we need to schedule a new swap. (cherry picked from 50a0284a61d4415c0ebdb02decee76ef3115007a commit) --- shared-core/i915_irq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index d88afdd0..158a91de 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -427,11 +427,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - if (dev_priv->swaps_pending >= 100) { - DRM_DEBUG("Too many swaps queued\n"); - return DRM_ERR(EBUSY); - } - DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); @@ -496,6 +491,11 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); if (!vbl_swap) { From 0a7d9edcfb427724f0cad5ff6d0a4493d266b4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 13 Sep 2006 08:59:35 +0200 Subject: [PATCH 102/147] i915_vblank_swap: Add support for DRM_VBLANK_NEXTONMISS. (cherry picked from 0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30 commit) --- shared-core/i915_irq.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 158a91de..b72ceb2b 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -431,7 +431,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) sizeof(swap)); if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | - _DRM_VBLANK_SECONDARY)) { + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); return DRM_ERR(EINVAL); } @@ -440,11 +440,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); - if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { - DRM_DEBUG("Not scheduling swap for current sequence\n"); - return DRM_ERR(EINVAL); - } - if (!(dev_priv->vblank_pipe & (1 << pipe))) { DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); @@ -462,21 +457,20 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); - spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); - - switch (seqtype) { - case _DRM_VBLANK_RELATIVE: + if (seqtype == _DRM_VBLANK_RELATIVE) swap.sequence += curseq; - break; - case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) <= (1<<23)) { - spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + if ((curseq - swap.sequence) <= (1<<23)) { + if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) { + swap.sequence = curseq + 1; + } else { DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); } - break; } + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); From c0bff9f9cd08066df7f3bccd77d4d4dd4edb4163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 18 Sep 2006 12:15:38 +0200 Subject: [PATCH 103/147] i915: Bump minor for swap scheduling ioctl and secondary vblank support. (cherry picked from 2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b commit) --- shared-core/i915_drv.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index c6bbcafb..cc575546 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -46,6 +46,8 @@ * 1.3: Add vblank support * 1.4: Fix cmdbuffer path, add heap destroy * 1.5: Add vblank pipe configuration + * 1.6: - New ioctl for scheduling buffer swaps on vertical blank + * - Support vertical blank on secondary display pipe */ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 6 From 390184df92915d232cab90469937de875ee65b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 27 Sep 2006 18:22:10 +0200 Subject: [PATCH 104/147] i915: Avoid mis-counting vblank interrupts when they're only enabled for pipe A. It looks like 'after a while', I915REG_INT_IDENTITY_R for some reason always has VSYNC_PIPEB_FLAG set in the interrupt handler, even though pipe B is disabled. So we only increase dev->vbl_received if the corresponding bit is also set in dev->vblank_pipe. (cherry picked from 881ba569929ceafd42e3c86228b0172099083d1d commit) --- shared-core/i915_irq.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index b72ceb2b..6afa9ca3 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -158,14 +158,19 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - if ((dev_priv->vblank_pipe & + int vblank_pipe = dev_priv->vblank_pipe; + + if ((vblank_pipe & (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { if (temp & VSYNC_PIPEA_FLAG) atomic_inc(&dev->vbl_received); if (temp & VSYNC_PIPEB_FLAG) atomic_inc(&dev->vbl_received2); - } else + } else if (((temp & VSYNC_PIPEA_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || + ((temp & VSYNC_PIPEB_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); From 3620a3ec85033d3d1d1a44ec32492fb2ef20fd8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 28 Sep 2006 19:05:58 +0200 Subject: [PATCH 105/147] i915: Bump minor again to differentiate from vsync changes. --- shared-core/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index cc575546..72cd41c3 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -50,7 +50,7 @@ * - Support vertical blank on secondary display pipe */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 6 +#define DRIVER_MINOR 7 #define DRIVER_PATCHLEVEL 0 #if defined(__linux__) From 48367fdfe677adada52ad61d850e2980e1070632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 28 Sep 2006 19:13:59 +0200 Subject: [PATCH 106/147] i915: Only initialize IRQ fields in postinstall, not the PIPE_SET ioctl. Some other minor changes in preparation for actually disabling user interrupts. --- shared-core/i915_irq.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 6afa9ca3..4f72d885 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -227,7 +227,7 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv) { spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - dev_priv->irq_enable_reg &= ~USER_INT_FLAG; + // dev_priv->irq_enable_reg &= ~USER_INT_FLAG; // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } spin_unlock(&dev_priv->user_irq_lock); @@ -344,17 +344,14 @@ int i915_irq_wait(DRM_IOCTL_ARGS) static void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u16 flag; - flag = 0; + dev_priv->irq_enable_reg = USER_INT_FLAG; //&= ~(VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) - flag |= VSYNC_PIPEA_FLAG; + dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) - flag |= VSYNC_PIPEB_FLAG; - dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; - dev_priv->user_irq_refcount = 0; - dev_priv->irq_enable_reg = flag; - I915_WRITE16(I915REG_INT_ENABLE_R, flag); + dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; + + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); dev_priv->irq_enabled = 1; } @@ -540,6 +537,9 @@ void i915_driver_irq_postinstall(drm_device_t * dev) INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; + dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; + dev_priv->user_irq_refcount = 0; + if (!dev_priv->vblank_pipe) dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; i915_enable_interrupt(dev); From 17a640419a447083470880f1266e14063cd5acd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 29 Sep 2006 10:27:29 +0200 Subject: [PATCH 107/147] i915: Only schedule vblank tasklet if there are scheduled swaps pending. This fixes issues on X server startup with versions of xf86-video-intel that enable the IRQ before they have a context ID. (cherry picked from 7af93dd9849442270ec89cb4bbeef5bfd4f9e424 commit) --- shared-core/i915_irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4f72d885..71b7230f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -176,7 +176,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); - drm_locked_tasklet(dev, i915_vblank_tasklet); + if (dev_priv->swaps_pending > 0) + drm_locked_tasklet(dev, i915_vblank_tasklet); } return IRQ_HANDLED; From 8e908eaf50d5331ee875fefbf793dbe07d99786a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Sep 2006 14:21:51 +0200 Subject: [PATCH 108/147] Bump driver date. --- shared-core/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 72cd41c3..a92205e4 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -37,7 +37,7 @@ #define DRIVER_NAME "i915-mm" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20060923" +#define DRIVER_DATE "20060929" /* Interface history: * From 58a23d193f7d25d23c76a58c192c814a415a843b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20K=C3=BChling?= Date: Mon, 2 Oct 2006 10:50:40 +0200 Subject: [PATCH 109/147] drm_rmdraw: Declare id and idx as signed so testing for < 0 works as intended. (cherry picked from d58389968124191a546a14b42ef84edc224be23d commit) --- shared-core/drm_drawable.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 5e2fc86c..d203b244 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -132,7 +132,8 @@ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int id, idx, shift; + int id, idx; + unsigned int shift; unsigned int irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; From c6be27401fbc12ec72bac13d07e3cc93bd63732a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:34:30 +0200 Subject: [PATCH 110/147] Trap and be verbose about a deadlock that occurs with AIGLX and drivers that use drm_reclaim_buffers_locked(). --- linux-core/drm_fops.c | 16 ++++++++++++++-- linux-core/drm_lock.c | 8 +++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index dcc05a0a..e4385cf6 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -421,14 +421,26 @@ int drm_release(struct inode *inode, struct file *filp) dev->open_count); if (dev->driver->reclaim_buffers_locked) { - retcode = drm_kernel_take_hw_lock(filp); + unsigned long _end = jiffies + DRM_HZ*3; + + do { + retcode = drm_kernel_take_hw_lock(filp); + } while(retcode && !time_after_eq(jiffies,_end)); + 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 { + DRM_ERROR("Reclaim buffers locked deadlock.\n"); + DRM_ERROR("This is probably a single thread having multiple\n"); + DRM_ERROR("DRM file descriptors open either dying or " + "closing file descriptors\n"); + DRM_ERROR("while having the lock. I will not reclaim buffers.\n"); + DRM_ERROR("Locking context is 0x%08x\n", + _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)); diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 04c145a6..0cf183a7 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -343,6 +343,7 @@ int drm_kernel_take_hw_lock(struct file *filp) DRM_DEVICE; int ret = 0; + unsigned long _end = jiffies + 3*DRM_HZ; if (!drm_i_have_hw_lock(filp)) { @@ -364,7 +365,12 @@ int drm_kernel_take_hw_lock(struct file *filp) break; /* Got lock */ } /* Contention */ - schedule(); + if (time_after_eq(jiffies,_end)) { + ret = -EBUSY; + break; + } + + schedule_timeout(1); if (signal_pending(current)) { ret = -ERESTARTSYS; break; From 418b81c65c55601d4e414b351db5b8d76db8a109 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:37:54 +0200 Subject: [PATCH 111/147] Add a comment to previos commit. --- linux-core/drm_fops.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index e4385cf6..5593e55c 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -433,6 +433,13 @@ int drm_release(struct inode *inode, struct file *filp) drm_lock_free(dev, &dev->lock.hw_lock->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); } else { + + /* + * FIXME: This is not a good solution. We should perhaps associate the + * DRM lock with a process context, and check whether the current process + * holds the lock. Then we can run reclaim buffers locked anyway. + */ + DRM_ERROR("Reclaim buffers locked deadlock.\n"); DRM_ERROR("This is probably a single thread having multiple\n"); DRM_ERROR("DRM file descriptors open either dying or " From d85b99435f0ea7a17b3b7be31b53c00632c07177 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:49:43 +0200 Subject: [PATCH 112/147] Allow for 44 bit user-tokens (or drm_file offsets) --- linux-core/drm_bufs.c | 9 +++++---- linux-core/drm_proc.c | 4 ++-- linux-core/drm_ttm.c | 6 +++--- linux-core/drm_vm.c | 14 +++++++------- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 03659143..dd897a19 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -80,14 +80,14 @@ static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, if (!use_hashed_handle) { int ret; - hash->key = user_token; + hash->key = user_token >> PAGE_SHIFT; ret = drm_ht_insert_item(&dev->map_hash, hash); if (ret != -EINVAL) return ret; } return drm_ht_just_insert_please(&dev->map_hash, hash, user_token, 32 - PAGE_SHIFT - 3, - PAGE_SHIFT, DRM_MAP_HASH_OFFSET); + 0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT); } /** @@ -301,7 +301,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, return ret; } - list->user_token = list->hash.key; + list->user_token = list->hash.key << PAGE_SHIFT; mutex_unlock(&dev->struct_mutex); *maplist = list; @@ -386,7 +386,8 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) if (r_list->map == map) { list_del(list); - drm_ht_remove_key(&dev->map_hash, r_list->user_token); + drm_ht_remove_key(&dev->map_hash, + r_list->user_token >> PAGE_SHIFT); drm_free(list, sizeof(*list), DRM_MEM_MAPS); break; } diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 488d1e71..b0b1748a 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -572,7 +572,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, for (pt = dev->vmalist; pt; pt = pt->next) { if (!(vma = pt->vma)) continue; - DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx", + DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000", pt->pid, vma->vm_start, vma->vm_end, @@ -582,7 +582,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request, vma->vm_flags & VM_MAYSHARE ? 's' : 'p', vma->vm_flags & VM_LOCKED ? 'l' : '-', vma->vm_flags & VM_IO ? 'i' : '-', - VM_OFFSET(vma)); + vma->vm_pgoff); #if defined(__i386__) pgprot = pgprot_val(vma->vm_page_prot); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 6790c886..5fbe283e 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -903,13 +903,13 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, 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)) { + 32 - PAGE_SHIFT - 3, 0, + DRM_MAP_HASH_OFFSET >> PAGE_SHIFT)) { drm_ttm_object_remove(dev, object); return -ENOMEM; } - list->user_token = list->hash.key; + list->user_token = list->hash.key << PAGE_SHIFT; atomic_set(&object->usage, 1); *ttm_object = object; diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 76d7fb4e..4755684e 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -100,7 +100,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, if (!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error; - if (drm_ht_find_item(&dev->map_hash, VM_OFFSET(vma), &hash)) + if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) goto vm_nopage_error; r_list = drm_hash_entry(hash, drm_map_list_t, hash); @@ -753,8 +753,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) lock_kernel(); dev = priv->head->dev; dma = dev->dma; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", - vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", + vma->vm_start, vma->vm_end, vma->vm_pgoff); /* Length must match exact page count */ if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { @@ -813,8 +813,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) unsigned long offset = 0; drm_hash_item_t *hash; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", - vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", + vma->vm_start, vma->vm_end, vma->vm_pgoff); if (!priv->authenticated) return -EACCES; @@ -823,7 +823,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) * the AGP mapped at physical address 0 * --BenH. */ - if (!VM_OFFSET(vma) + if (!vma->vm_pgoff #if __OS_HAS_AGP && (!dev->agp || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) @@ -831,7 +831,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) ) return drm_mmap_dma(filp, vma); - if (drm_ht_find_item(&dev->map_hash, VM_OFFSET(vma), &hash)) { + if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff , &hash)) { DRM_ERROR("Could not find map\n"); return -EINVAL; } From a31046b8734f12ed22127ef5f6ca4fc33df72ec1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 14:03:15 +0200 Subject: [PATCH 113/147] Add a buffer object manager for TTM maps. --- linux-core/drmP.h | 43 +++++++++++++++++++++++++------------------ linux-core/drm_drv.c | 1 + linux-core/drm_stub.c | 11 +++++++++-- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 8b3364e4..f17a3421 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -163,6 +163,10 @@ #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) #define DRM_MAP_HASH_OFFSET 0x10000000 +#define DRM_MAP_HASH_ORDER 12 +#define DRM_OBJECT_HASH_ORDER 12 +#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) +#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) /*@}*/ @@ -532,6 +536,25 @@ typedef struct drm_sigdata { drm_hw_lock_t *lock; } drm_sigdata_t; + +/* + * Generic memory manager structs + */ + +typedef struct drm_mm_node { + struct list_head fl_entry; + struct list_head ml_entry; + int free; + unsigned long start; + unsigned long size; + void *private; +} drm_mm_node_t; + +typedef struct drm_mm { + drm_mm_node_t root_node; +} drm_mm_t; + + /** * Mappings list */ @@ -540,6 +563,7 @@ typedef struct drm_map_list { drm_hash_item_t hash; drm_map_t *map; /**< mapping */ drm_u64_t user_token; + drm_mm_node_t *file_offset_node; } drm_map_list_t; typedef drm_map_t drm_local_map_t; @@ -572,24 +596,6 @@ typedef struct ati_pcigart_info { drm_local_map_t mapping; } drm_ati_pcigart_info; -/* - * Generic memory manager structs - */ - -typedef struct drm_mm_node { - struct list_head fl_entry; - struct list_head ml_entry; - int free; - unsigned long start; - unsigned long size; - void *private; -} drm_mm_node_t; - -typedef struct drm_mm { - drm_mm_node_t root_node; -} drm_mm_t; - - /* * User space objects and their references. */ @@ -866,6 +872,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_mm_t offset_manager; /**< User token manager */ drm_open_hash_t object_hash; /**< User token hash table for objects */ /** \name Context handle management */ diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 37539f34..ae0c37a5 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -377,6 +377,7 @@ static void drm_cleanup(drm_device_t * dev) drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; drm_ht_remove(&dev->map_hash); + drm_mm_takedown(&dev->offset_manager); drm_ht_remove(&dev->object_hash); } diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 5d28284c..1b406fef 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -83,14 +83,21 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, if (dev->maplist == NULL) return -ENOMEM; INIT_LIST_HEAD(&dev->maplist->head); - if (drm_ht_create(&dev->map_hash, 12)) { + if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) { drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); return -ENOMEM; } + if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START, + DRM_FILE_PAGE_OFFSET_SIZE)) { + drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); + drm_ht_remove(&dev->map_hash); + return -ENOMEM; + } - if (drm_ht_create(&dev->object_hash, 12)) { + if (drm_ht_create(&dev->object_hash, DRM_OBJECT_HASH_ORDER)) { drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); drm_ht_remove(&dev->map_hash); + drm_mm_takedown(&dev->offset_manager); return -ENOMEM; } From eacedf41a65f135722e7bee6f1a66a803619237f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 15:06:35 +0200 Subject: [PATCH 114/147] Make the user_token 44-bit for TTMs, and have them occupy a unique file space starting at 0x00100000000. This will hopefully allow us to use unmap_mapping_range(). Note that user-space will need 64-bit file offset support. --- configure.ac | 1 + libdrm/xf86drm.c | 13 ++++++++++--- linux-core/drm_ttm.c | 24 +++++++++++++++++++----- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 69b111fb..b5d79456 100644 --- a/configure.ac +++ b/configure.ac @@ -30,6 +30,7 @@ AC_PROG_LIBTOOL AC_PROG_CC AC_HEADER_STDC +AC_SYS_LARGEFILE pkgconfigdir=${libdir}/pkgconfig AC_SUBST(pkgconfigdir) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index ab884eb5..bce913d3 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -46,6 +46,9 @@ # include # endif #else +# ifdef HAVE_CONFIG_H +# include +# endif # include # include # include @@ -2804,7 +2807,7 @@ int drmBOUnReference(int fd, drmBO *buf) if (buf->mapVirtual && (buf->type != drm_bo_type_fake)) { - (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); + (void) munmap(buf->mapVirtual, buf->start + buf->size); buf->mapVirtual = NULL; buf->virtual = NULL; } @@ -2847,8 +2850,12 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, if (!buf->virtual && buf->type != drm_bo_type_fake) { drmAddress virtual; - ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); - if (ret) + virtual = mmap(0, buf->size + buf->start, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, buf->mapHandle); + if (virtual == MAP_FAILED) + ret = -errno; + if (ret) return ret; buf->mapVirtual = virtual; buf->virtual = ((char *) virtual) + buf->start; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 5fbe283e..311c57fa 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -817,6 +817,11 @@ static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) if (list->user_token) drm_ht_remove_item(&dev->map_hash, &list->hash); + if (list->file_offset_node) { + drm_mm_put_block(&dev->offset_manager, list->file_offset_node); + list->file_offset_node = NULL; + } + map = list->map; if (map) { @@ -901,15 +906,24 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, 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, - 32 - PAGE_SHIFT - 3, 0, - DRM_MAP_HASH_OFFSET >> PAGE_SHIFT)) { + list->file_offset_node = drm_mm_search_free(&dev->offset_manager, + ttm->num_pages, + 0,0); + if (!list->file_offset_node) { + drm_ttm_object_remove(dev, object); + return -ENOMEM; + } + list->file_offset_node = drm_mm_get_block(list->file_offset_node, + ttm->num_pages,0); + + list->hash.key = list->file_offset_node->start; + + if (drm_ht_insert_item(&dev->map_hash, &list->hash)) { drm_ttm_object_remove(dev, object); return -ENOMEM; } - list->user_token = list->hash.key << PAGE_SHIFT; + list->user_token = ((drm_u64_t) list->hash.key) << PAGE_SHIFT; atomic_set(&object->usage, 1); *ttm_object = object; From 16be6ba63a41f03e98a741464d3b51eefb277373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 2 Oct 2006 15:33:19 +0200 Subject: [PATCH 115/147] Fix type of second argument to spin_lock_irqsave(). (cherry picked from f6238cf6244b32bd84e3d2819963d7f5473867c8 commit) --- linux-core/drm_irq.c | 4 ++-- linux-core/drm_lock.c | 2 +- shared-core/drm_drawable.c | 8 ++++---- shared-core/i915_irq.c | 5 +++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index d1a6a6b1..21c3887d 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -417,7 +417,7 @@ EXPORT_SYMBOL(drm_vbl_send_signals); static void drm_locked_tasklet_func(unsigned long data) { drm_device_t *dev = (drm_device_t*)data; - unsigned int irqflags; + unsigned long irqflags; spin_lock_irqsave(&dev->tasklet_lock, irqflags); @@ -455,7 +455,7 @@ static void drm_locked_tasklet_func(unsigned long data) */ void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*)) { - unsigned int irqflags; + unsigned long irqflags; static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0); if (test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state)) diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 0cf183a7..d11c570e 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -155,7 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; - unsigned int irqflags; + unsigned long irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index d203b244..0817e321 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -43,7 +43,7 @@ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; - unsigned int irqflags; + unsigned long irqflags; int i, j; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; @@ -134,7 +134,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) drm_draw_t draw; int id, idx; unsigned int shift; - unsigned int irqflags; + unsigned long irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; drm_drawable_info_t **info = dev->drw_info; @@ -220,9 +220,9 @@ int drm_rmdraw(DRM_IOCTL_ARGS) int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_update_draw_t update; - unsigned int id, idx, shift; + unsigned int id, idx, shift, bitfield_length = dev->drw_bitfield_length; u32 *bitfield = dev->drw_bitfield; - unsigned int irqflags, bitfield_length = dev->drw_bitfield_length; + unsigned long irqflags; drm_drawable_info_t *info; drm_clip_rect_t *rects; int err; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 71b7230f..bc52a95c 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -45,7 +45,7 @@ static void i915_vblank_tasklet(drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned int irqflags; + unsigned long irqflags; struct list_head *list, *tmp; DRM_DEBUG("\n"); @@ -417,7 +417,8 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int pipe, seqtype, irqflags, curseq; + unsigned int pipe, seqtype, curseq; + unsigned long irqflags; struct list_head *list; if (!dev_priv) { From cee659afb56e7ac443402ac791144f391721061e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 3 Oct 2006 12:08:07 +0200 Subject: [PATCH 116/147] Get rid of all ugly PTE hacks. --- linux-core/drmP.h | 1 + linux-core/drm_compat.c | 133 ---------------------------------------- linux-core/drm_drv.c | 1 + linux-core/drm_fops.c | 7 +++ linux-core/drm_ttm.c | 77 ++++++----------------- linux-core/drm_ttm.h | 1 + 6 files changed, 29 insertions(+), 191 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f17a3421..089059c8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -874,6 +874,7 @@ typedef struct drm_device { drm_open_hash_t map_hash; /**< User token hash table for maps */ drm_mm_t offset_manager; /**< User token manager */ drm_open_hash_t object_hash; /**< User token hash table for objects */ + struct address_space *dev_mapping; /**< For unmap_mapping_range() */ /** \name Context handle management */ /*@{ */ diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 8dbc636a..81a2bd84 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -26,139 +26,6 @@ */ #include "drmP.h" -#include -#include -#include - -#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; - struct page *page; - unsigned long pfn; - - pte = pte_offset_map(pmd, addr); - do { - if (pte_present(*pte)) { - pte_t ptent; - pfn = pte_pfn(*pte); - ptent = *pte; - ptep_get_and_clear(mm, addr, pte); - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - if (atomic_add_negative(-1, &page->_mapcount)) { - if (page_test_and_clear_dirty(page)) - set_page_dirty(page); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18) - dec_zone_page_state(page, NR_FILE_MAPPED); -#else - dec_page_state(nr_mapped); -#endif - } - - put_page(page); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) - dec_mm_counter(mm, file_rss); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12) - dec_mm_counter(mm, rss); -#else - --mm->rss; -#endif - } - } - } 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. - */ - -#if 1 -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 -} -#else - -void drm_clear_vma(struct vm_area_struct *vma, - unsigned long addr, unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - - spin_unlock(&mm->page_table_lock); - (void) zap_page_range(vma, addr, end - addr, NULL); - spin_lock(&mm->page_table_lock); -} -#endif #if defined(CONFIG_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) int drm_map_page_into_agp(struct page *page) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index ae0c37a5..4cbe035f 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -263,6 +263,7 @@ int drm_lastclose(drm_device_t * dev) dev->lock.filp = NULL; wake_up_interruptible(&dev->lock.lock_queue); } + dev->dev_mapping = NULL; mutex_unlock(&dev->struct_mutex); if (drm_bo_clean_mm(dev)) { diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 5593e55c..b60ced34 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -158,6 +158,12 @@ int drm_open(struct inode *inode, struct file *filp) } spin_unlock(&dev->count_lock); } + mutex_lock(&dev->struct_mutex); + BUG_ON((dev->dev_mapping != NULL) && + (dev->dev_mapping != inode->i_mapping)); + if (dev->dev_mapping == NULL) + dev->dev_mapping = inode->i_mapping; + mutex_unlock(&dev->struct_mutex); return retcode; } @@ -465,6 +471,7 @@ int drm_release(struct inode *inode, struct file *filp) drm_fasync(-1, filp, 0); mutex_lock(&dev->ctxlist_mutex); + if (dev->ctxlist && (!list_empty(&dev->ctxlist->head))) { drm_ctx_list_t *pos, *n; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 311c57fa..ed50da90 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -123,31 +123,12 @@ void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) BUG_ON(1); } -static void drm_ttm_lock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +static void drm_ttm_unlock_mm(drm_ttm_t * ttm) { 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); - } + up_write(&entry->mm->mmap_sem); } } @@ -180,30 +161,13 @@ static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, unsigned long num_pages) { - struct list_head *list; - -#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); - - drm_clear_vma(entry->vma, - entry->vma->vm_start + - (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 + drm_device_t *dev = ttm->dev; + loff_t offset = ((loff_t) ttm->mapping_offset + page_offset) + << PAGE_SHIFT; + loff_t holelen = num_pages << PAGE_SHIFT; + + unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); return 0; } @@ -437,15 +401,16 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) } /* - * Change caching policy for range of pages in a ttm. + * Change caching policy for the linear kernel map + * 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) + unsigned long num_pages, int noncached) { int i, cur; struct page **cur_page; + int do_tlbflush = 0; for (i = 0; i < num_pages; ++i) { cur = page_offset + i; @@ -467,6 +432,7 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, } else { unmap_page_from_agp(*cur_page); } + do_tlbflush = 1; } } } @@ -492,16 +458,14 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; - drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); - 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, 1, 0); + entry->num_pages, 0); + drm_ttm_unlock_mm(ttm); } break; default: @@ -653,20 +617,17 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, if (ret) return ret; - drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, region->page_offset, region->num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); - drm_set_caching(ttm, region->page_offset, region->num_pages, - DRM_TTM_PAGE_UNCACHED, 1); + DRM_TTM_PAGE_UNCACHED); } 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, 1, 0); + drm_ttm_unlock_mm(ttm); drm_unbind_ttm_region(region); DRM_ERROR("Couldn't bind backend.\n"); return ret; @@ -682,7 +643,7 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, if (ttm && be->needs_cache_adjust(be)) { ioremap_vmas(ttm, region->page_offset, region->num_pages, aper_offset); - drm_ttm_unlock_mm(ttm, 1, 0); + drm_ttm_unlock_mm(ttm); } region->state = ttm_bound; @@ -924,7 +885,7 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, } list->user_token = ((drm_u64_t) list->hash.key) << PAGE_SHIFT; - + ttm->mapping_offset = list->hash.key; atomic_set(&object->usage, 1); *ttm_object = object; return 0; diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index d65b17de..53afe792 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -100,6 +100,7 @@ typedef struct drm_ttm { atomic_t vma_count; int mmap_sem_locked; int destroy; + uint32_t mapping_offset; } drm_ttm_t; typedef struct drm_ttm_object { From c58574c60505a699e19e1ed59e1b441be2594e53 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 10 Oct 2006 10:37:26 +0200 Subject: [PATCH 117/147] Use a nopage-based approach to fault in pfns. --- linux-core/drmP.h | 1 + linux-core/drm_compat.c | 79 ++++++++++++++++++ linux-core/drm_compat.h | 27 ++++++- linux-core/drm_drv.c | 3 + linux-core/drm_stub.c | 9 ++- linux-core/drm_ttm.c | 175 ++-------------------------------------- linux-core/drm_ttm.h | 2 - linux-core/drm_vm.c | 50 +++++++++--- 8 files changed, 156 insertions(+), 190 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 089059c8..bc57bd5c 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -875,6 +875,7 @@ typedef struct drm_device { drm_mm_t offset_manager; /**< User token manager */ drm_open_hash_t object_hash; /**< User token hash table for objects */ struct address_space *dev_mapping; /**< For unmap_mapping_range() */ + struct page *ttm_dummy_page; /** \name Context handle management */ /*@{ */ diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 81a2bd84..2b449e90 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -62,3 +62,82 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags) return protection_map[vm_flags & 0x0F]; #endif }; + +int drm_pte_is_clear(struct vm_area_struct *vma, + unsigned long addr) +{ + struct mm_struct *mm = vma->vm_mm; + int ret = 1; + pte_t *pte; + pmd_t *pmd; + pud_t *pud; + pgd_t *pgd; + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + spin_lock(&mm->page_table_lock); +#else + spinlock_t ptl; +#endif + + pgd = pgd_offset(mm, addr); + if (pgd_none(*pgd)) + goto unlock; + pud = pud_offset(pgd, addr); + if (pud_none(*pud)) + goto unlock; + pmd = pmd_offset(pud, addr); + if (pmd_none(*pmd)) + goto unlock; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + pte = pte_offset_map(pmd, addr); +#else + pte = pte_offset_map_lock(mm, pmd, addr, &ptl); +#endif + if (!pte) + goto unlock; + ret = pte_none(*pte); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + pte_unmap(pte); + unlock: + spin_unlock(&mm->page_table_lock); +#else + pte_unmap_unlock(pte, ptl); + unlock: +#endif + return ret; +} + + +static struct { + spinlock_t lock; + struct page *dummy_page; + atomic_t present; +} drm_np_retry = +{SPIN_LOCK_UNLOCKED, NOPAGE_OOM, ATOMIC_INIT(0)}; + +struct page * get_nopage_retry(void) +{ + if (atomic_read(&drm_np_retry.present) == 0) { + struct page *page = alloc_page(GFP_KERNEL); + if (!page) + return NOPAGE_OOM; + spin_lock(&drm_np_retry.lock); + drm_np_retry.dummy_page = page; + atomic_set(&drm_np_retry.present,1); + spin_unlock(&drm_np_retry.lock); + } + get_page(drm_np_retry.dummy_page); + return drm_np_retry.dummy_page; +} + +void free_nopage_retry(void) +{ + if (atomic_read(&drm_np_retry.present) == 1) { + spin_lock(&drm_np_retry.lock); + __free_page(drm_np_retry.dummy_page); + drm_np_retry.dummy_page = NULL; + atomic_set(&drm_np_retry.present, 0); + spin_unlock(&drm_np_retry.lock); + } +} diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index cf84a70b..784b9a7d 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -252,7 +252,9 @@ extern pgprot_t vm_get_page_prot(unsigned long vm_flags); * that are not in the kernel linear map. */ -#define drm_alloc_gatt_pages(order) virt_to_page(alloc_gatt_pages(order)) +#define drm_alloc_gatt_pages(order) ({ \ + void *_virt = alloc_gatt_pages(order); \ + ((_virt) ? virt_to_page(_virt) : NULL);}) #define drm_free_gatt_pages(pages, order) free_gatt_pages(page_address(pages), order) #if defined(CONFIG_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) @@ -268,4 +270,27 @@ extern int drm_map_page_into_agp(struct page *page); #define unmap_page_from_agp drm_unmap_page_from_agp #endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + +/* + * Hopefully, real NOPAGE_RETRY functionality will be in 2.6.19. + * For now, just return a dummy page that we've allocated out of + * static space. The page will be put by do_nopage() since we've already + * filled out the pte. + */ +extern struct page * get_nopage_retry(void); +extern void free_nopage_retry(void); + +#define NOPAGE_RETRY get_nopage_retry() + +#endif + +/* + * Is the PTE for this address really clear so that we can use + * io_remap_pfn_range? + */ + +int drm_pte_is_clear(struct vm_area_struct *vma, + unsigned long addr); + #endif diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 4cbe035f..11228363 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -434,6 +434,9 @@ void drm_exit(struct drm_driver *driver) } } else pci_unregister_driver(&driver->pci_driver); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + free_nopage_retry(); +#endif DRM_INFO("Module unloaded\n"); } EXPORT_SYMBOL(drm_exit); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 1b406fef..e3db07dc 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -79,10 +79,6 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, #endif dev->irq = pdev->irq; - dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS); - if (dev->maplist == NULL) - return -ENOMEM; - INIT_LIST_HEAD(&dev->maplist->head); if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) { drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); return -ENOMEM; @@ -101,6 +97,11 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, return -ENOMEM; } + dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS); + if (dev->maplist == NULL) + return -ENOMEM; + INIT_LIST_HEAD(&dev->maplist->head); + /* the DRM has 6 counters */ dev->counters = 6; dev->types[0] = _DRM_STAT_LOCK; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index ed50da90..51e28ac4 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -71,89 +71,6 @@ static void ttm_free(void *pointer, unsigned long size, int type) } } - -/* - * 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_TTM); - 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_TTM); - atomic_dec(&ttm->shared_count); - ttm->mm_list_seq++; - } - return; - } - } - BUG_ON(1); -} - -static void drm_ttm_unlock_mm(drm_ttm_t * ttm) -{ - p_mm_entry_t *entry; - - list_for_each_entry(entry, &ttm->p_mm_list, head) { - 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; - } - return ret; -} - /* * Unmap all vma pages from vmas mapping this ttm. */ @@ -216,17 +133,15 @@ int drm_destroy_ttm(drm_ttm_t * ttm) do_tlbflush = 1; } if (*cur_page) { - ClearPageLocked(*cur_page); - - /* - * Debugging code. Remove if the error message never - * shows up. - */ - + unlock_page(*cur_page); if (page_count(*cur_page) != 1) { DRM_ERROR("Erroneous page count. " "Leaking pages.\n"); } + if (page_mapped(*cur_page)) { + DRM_ERROR("Erroneous map count. " + "Leaking page mappings.\n"); + } /* * End debugging. @@ -334,72 +249,6 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) 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_TTM); - cur_count = shared_count + 10; - mm_list = - drm_alloc(sizeof(*mm_list) * cur_count, - DRM_MEM_TTM); - 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_TTM); - - return 0; -} - /* * Change caching policy for the linear kernel map * for range of pages in a ttm. @@ -449,15 +298,11 @@ 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; unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); } @@ -465,7 +310,6 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0); - drm_ttm_unlock_mm(ttm); } break; default: @@ -613,7 +457,6 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, ttm = region->owner; if (ttm && be->needs_cache_adjust(be)) { - ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; @@ -626,8 +469,6 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, } if ((ret = be->bind(be, aper_offset))) { - if (ttm && be->needs_cache_adjust(be)) - drm_ttm_unlock_mm(ttm); drm_unbind_ttm_region(region); DRM_ERROR("Couldn't bind backend.\n"); return ret; @@ -640,12 +481,6 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, 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); - } - region->state = ttm_bound; return 0; } diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 53afe792..fcac06b5 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -164,8 +164,6 @@ int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry, 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 int drm_ttm_ioctl(DRM_IOCTL_ARGS); static __inline__ drm_ttm_t *drm_ttm_from_object(drm_ttm_object_t * to) diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 4755684e..5fbbaadd 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -237,7 +237,7 @@ static int drm_ttm_remap_bound_pfn(struct vm_area_struct *vma, } if (ret) { - DRM_ERROR("Map returned %c\n", ret); + DRM_ERROR("Map returned %c\n", ret); } return ret; } @@ -254,6 +254,7 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, pgprot_t default_prot; uint32_t page_flags; drm_buffer_manager_t *bm; + drm_device_t *dev; if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ @@ -262,7 +263,11 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, map = (drm_map_t *) entry->map; ttm = (drm_ttm_t *) map->offset; - bm = &ttm->dev->bm; + + dev = ttm->dev; + mutex_lock(&dev->struct_mutex); + + bm = &dev->bm; page_offset = (address - vma->vm_start) >> PAGE_SHIFT; page = ttm->pages[page_offset]; @@ -270,22 +275,43 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, if (!page) { if (bm->cur_pages >= bm->max_pages) { - DRM_ERROR("Maximum locked page count exceeded\n"); - return NOPAGE_OOM; + DRM_ERROR("Maximum locked page count exceeded\n"); + page = NOPAGE_OOM; + goto out; } ++bm->cur_pages; page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); + if (page) { + SetPageLocked(page); + } else { + page = NOPAGE_OOM; + } } - if (!page) - return NOPAGE_OOM; - SetPageLocked(page); + if (page_flags & DRM_TTM_PAGE_UNCACHED) { + + /* + * This makes sure we don't race with another + * drm_ttm_remap_bound_pfn(); + */ + + if (!drm_pte_is_clear(vma, address)) { + page = NOPAGE_RETRY; + goto out1; + } + + drm_ttm_remap_bound_pfn(vma, address, PAGE_SIZE); + page = NOPAGE_RETRY; + goto out1; + } get_page(page); - - default_prot = vm_get_page_prot(vma->vm_flags); - - BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED); + + out1: + default_prot = vm_get_page_prot(vma->vm_flags); vma->vm_page_prot = default_prot; + + out: + mutex_unlock(&dev->struct_mutex); return page; } @@ -645,7 +671,6 @@ static int drm_vm_ttm_open(struct vm_area_struct *vma) { *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); @@ -717,7 +742,6 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma) ttm = (drm_ttm_t *) map->offset; dev = ttm->dev; mutex_lock(&dev->struct_mutex); - drm_ttm_delete_mm(ttm, vma->vm_mm); list_del(&ttm_vma->head); drm_free(ttm_vma, sizeof(*ttm_vma), DRM_MEM_VMAS); if (atomic_dec_and_test(&ttm->vma_count)) { From f2db76e2f206d2017f710eaddc4b33add4498898 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 11 Oct 2006 13:40:35 +0200 Subject: [PATCH 118/147] Big update: Adapt for new functions in the 2.6.19 kernel. Remove the ability to have multiple regions in one TTM. This simplifies a lot of code. Remove the ability to access TTMs from user space. We don't need it anymore without ttm regions. Don't change caching policy for evicted buffers. Instead change it only when the buffer is accessed by the CPU (on the first page fault). This tremendously speeds up eviction rates. Current code is safe for kernels <= 2.6.14. Should also be OK with 2.6.19 and above. --- libdrm/xf86drm.c | 82 +---- libdrm/xf86mm.h | 23 +- linux-core/drmP.h | 2 +- linux-core/drm_agpsupport.c | 2 + linux-core/drm_bo.c | 51 +-- linux-core/drm_compat.c | 50 ++- linux-core/drm_compat.h | 33 +- linux-core/drm_drv.c | 1 - linux-core/drm_ttm.c | 651 ++++++++---------------------------- linux-core/drm_ttm.h | 88 +---- linux-core/drm_vm.c | 255 +++++--------- shared-core/drm.h | 18 - 12 files changed, 338 insertions(+), 918 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index bce913d3..a083ca23 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2462,74 +2462,6 @@ int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) return 0; } -int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) -{ - drm_ttm_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.op = drm_ttm_create; - arg.flags = flags; - arg.size = size; - - if (ioctl(fd, DRM_IOCTL_TTM, &arg)) - return -errno; - - ttm->handle = arg.handle; - 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; -} - -int drmTTMDestroy(int fd, const drmTTM *ttm) -{ - drm_ttm_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.op = drm_ttm_destroy; - arg.handle = ttm->handle; - if (ioctl(fd, DRM_IOCTL_TTM, &arg)) - return -errno; - return 0; -} - - -int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) -{ - drm_ttm_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.handle = handle; - arg.op = drm_ttm_reference; - if (ioctl(fd, DRM_IOCTL_TTM, &arg)) - return -errno; - ttm->handle = arg.handle; - ttm->user_token = (drm_handle_t) arg.user_token; - ttm->flags = arg.flags; - ttm->size = arg.size; - return 0; -} - -int drmTTMUnreference(int fd, const drmTTM *ttm) -{ - drm_ttm_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.op = drm_ttm_destroy; - arg.handle = ttm->handle; - if (ioctl(fd, DRM_IOCTL_TTM, &arg)) - return -errno; - return 0; -} - -drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm) -{ - (void) fd; - return ttm->user_token; -} - static int drmAdjustListNodes(drmBOList *list) { drmBONode *node; @@ -2685,7 +2617,7 @@ static void drmBOCopyReply(const drm_bo_arg_reply_t *rep, -int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, +int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, void *user_buffer, drm_bo_type_t type, unsigned mask, unsigned hint, drmBO *buf) { @@ -2700,15 +2632,9 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, req->size = size; req->type = type; - buf->ttm = NULL; buf->virtual = 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: req->buffer_start = start; break; @@ -2727,10 +2653,10 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; if (!arg.handled) { - fprintf(stderr, "Not handled\n"); return -EFAULT; } if (rep->ret) { + fprintf(stderr, "Error %d\n", rep->ret); return rep->ret; } @@ -2853,8 +2779,10 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, virtual = mmap(0, buf->size + buf->start, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf->mapHandle); - if (virtual == MAP_FAILED) + if (virtual == MAP_FAILED) { ret = -errno; + fprintf(stderr, "Map error 0x%016llx\n", buf->mapHandle); + } if (ret) return ret; buf->mapVirtual = virtual; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index c0e4f1b6..78df37c3 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -101,15 +101,6 @@ typedef struct _drmFence{ unsigned signaled; } drmFence; -typedef struct _drmTTM{ - unsigned handle; - drm_u64_t user_token; - unsigned flags; - unsigned long size; - void *virtual; - int mapCount; -} drmTTM; - typedef struct _drmBO{ drm_bo_type_t type; unsigned handle; @@ -125,7 +116,6 @@ typedef struct _drmBO{ void *virtual; void *mapVirtual; int mapCount; - drmTTM *ttm; } drmBO; @@ -163,17 +153,6 @@ extern int drmFenceEmit(int fd, unsigned flags, drmFence *fence, extern int drmFenceBuffers(int fd, unsigned flags, drmFence *fence); -/* - * TTM functions. - */ - -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); - /* * Buffer object list functions. */ @@ -189,7 +168,7 @@ extern int drmBOCreateList(int numTarget, drmBOList *list); * Buffer object functions. */ -extern int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, +extern int drmBOCreate(int fd, void *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); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index bc57bd5c..1b6d94e4 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1012,7 +1012,7 @@ typedef struct drm_buffer_object{ atomic_t usage; drm_ttm_object_t *ttm_object; - drm_ttm_backend_list_t *ttm_region; + drm_ttm_t *ttm; unsigned long num_pages; unsigned long buffer_start; drm_bo_type_t type; diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 2dd80162..77994d5c 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -683,6 +683,7 @@ drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev, agp_be->unbind = drm_agp_unbind_ttm; agp_be->destroy = drm_agp_destroy_ttm; agp_be->needs_free = (backend == NULL); + agp_be->drm_map_type = _DRM_AGP; return agp_be; } EXPORT_SYMBOL(drm_agp_init_ttm_uncached); @@ -720,6 +721,7 @@ drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev, agp_be->unbind = drm_agp_unbind_ttm; agp_be->destroy = drm_agp_destroy_ttm; agp_be->needs_free = (backend == NULL); + agp_be->drm_map_type = _DRM_AGP; return agp_be; } EXPORT_SYMBOL(drm_agp_init_ttm_cached); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d1989e49..d8cab2ad 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -63,7 +63,7 @@ * bo locked. */ -static int drm_move_tt_to_local(drm_buffer_object_t * buf) +static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -71,7 +71,10 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); mutex_lock(&dev->struct_mutex); - drm_unbind_ttm_region(buf->ttm_region); + if (evict) + drm_evict_ttm(buf->ttm); + else + drm_unbind_ttm(buf->ttm); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -129,7 +132,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * This temporarily unlocks struct_mutex. */ - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm(bo->ttm); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -137,9 +140,6 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_mm_put_block(&bm->vram_manager, bo->vram); bo->vram = NULL; } - if (bo->ttm_region) { - drm_destroy_ttm_region(bo->ttm_region); - } if (bo->ttm_object) { drm_ttm_object_deref_locked(dev, bo->ttm_object); } @@ -428,7 +428,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) } if (tt) { - ret = drm_move_tt_to_local(bo); + ret = drm_move_tt_to_local(bo, 1); } #if 0 else { @@ -522,7 +522,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) return ret; DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); - ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); + ret = drm_bind_ttm(bo->ttm, bo->tt->start); if (ret) { drm_mm_put_block(&bm->tt_manager, bo->tt); } @@ -530,7 +530,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - be = bo->ttm_region->be; + be = bo->ttm->be; if (be->needs_cache_adjust(be)) bo->flags &= ~DRM_BO_FLAG_CACHED; bo->flags &= ~DRM_BO_MASK_MEM; @@ -1023,7 +1023,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, if (ret) return ret; } else { - drm_move_tt_to_local(bo); + drm_move_tt_to_local(bo, 0); } return 0; @@ -1203,34 +1203,24 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, - uint32_t ttm_handle) +static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo) { 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; + bo->ttm = 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, + bo->mask & DRM_BO_FLAG_BIND_CACHED, 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) { - DRM_ERROR("Could not find TTM object\n"); - ret = -EINVAL; - } - break; case drm_bo_type_user: case drm_bo_type_fake: break; @@ -1246,14 +1236,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, 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, - bo->mask & DRM_BO_FLAG_BIND_CACHED, - &bo->ttm_region); - if (ret) { - drm_ttm_object_deref_unlocked(dev, to); - } + bo->ttm = drm_ttm_from_object(to); } return ret; } @@ -1261,7 +1244,6 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, 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, @@ -1318,7 +1300,7 @@ int drm_buffer_object_create(drm_file_t * priv, 1, &new_flags, &bo->mask); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, ttm_handle); + ret = drm_bo_add_ttm(priv, bo); if (ret) goto out_err; @@ -1394,7 +1376,6 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_buffer_object_create(priv, req->size, req->type, - req->arg_handle, req->mask, req->hint, req->buffer_start, &entry); @@ -1659,7 +1640,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - arg.req.tt_p_size); + 3000 /* arg.req.tt_p_size */); bm->has_tt = 1; bm->use_tt = 1; diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 2b449e90..1aa835ca 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -63,8 +63,10 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags) #endif }; -int drm_pte_is_clear(struct vm_area_struct *vma, - unsigned long addr) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + +static int drm_pte_is_clear(struct vm_area_struct *vma, + unsigned long addr) { struct mm_struct *mm = vma->vm_mm; int ret = 1; @@ -77,7 +79,7 @@ int drm_pte_is_clear(struct vm_area_struct *vma, #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) spin_lock(&mm->page_table_lock); #else - spinlock_t ptl; + spinlock_t *ptl; #endif pgd = pgd_offset(mm, addr); @@ -92,7 +94,7 @@ int drm_pte_is_clear(struct vm_area_struct *vma, #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) pte = pte_offset_map(pmd, addr); #else - pte = pte_offset_map_lock(mm, pmd, addr, &ptl); + pte = pte_offset_map_lock(mm, pmd, addr, &ptl); #endif if (!pte) goto unlock; @@ -108,6 +110,17 @@ int drm_pte_is_clear(struct vm_area_struct *vma, return ret; } +int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, + unsigned long pfn, pgprot_t pgprot) +{ + int ret; + if (!drm_pte_is_clear(vma, addr)) + return -EBUSY; + + ret = io_remap_pfn_range(vma, addr, pfn, PAGE_SIZE, pgprot); + return ret; +} + static struct { spinlock_t lock; @@ -141,3 +154,32 @@ void free_nopage_retry(void) spin_unlock(&drm_np_retry.lock); } } +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + +struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + struct fault_data data; + + if (type) + *type = VM_FAULT_MINOR; + + data.address = address; + data.vma = vma; + drm_vm_ttm_fault(vma, &data); + switch (data.type) { + case VM_FAULT_OOM: + return NOPAGE_OOM; + case VM_FAULT_SIGBUS: + return NOPAGE_SIGBUS; + default: + break; + } + + return NOPAGE_REFAULT; +} + +#endif diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 784b9a7d..4e95679d 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -278,19 +278,30 @@ extern int drm_map_page_into_agp(struct page *page); * static space. The page will be put by do_nopage() since we've already * filled out the pte. */ -extern struct page * get_nopage_retry(void); + +struct fault_data { + struct vm_area_struct *vma; + unsigned long address; + pgoff_t pgoff; + unsigned int flags; + + int type; +}; + +extern struct page *get_nopage_retry(void); extern void free_nopage_retry(void); -#define NOPAGE_RETRY get_nopage_retry() +#define NOPAGE_REFAULT get_nopage_retry() + +extern int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, + unsigned long pfn, pgprot_t pgprot); + +extern struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type); + +extern struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, + struct fault_data *data); #endif - -/* - * Is the PTE for this address really clear so that we can use - * io_remap_pfn_range? - */ - -int drm_pte_is_clear(struct vm_area_struct *vma, - unsigned long addr); - #endif diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 11228363..c7f0f485 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -120,7 +120,6 @@ 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 }, diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 51e28ac4..297d4f71 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -27,20 +27,6 @@ **************************************************************************/ #include "drmP.h" -#include - -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; /* * Use kmalloc if possible. Otherwise fall back to vmalloc. @@ -75,19 +61,51 @@ static void ttm_free(void *pointer, unsigned long size, int type) * 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) +static int unmap_vma_pages(drm_ttm_t * ttm) { drm_device_t *dev = ttm->dev; - loff_t offset = ((loff_t) ttm->mapping_offset + page_offset) - << PAGE_SHIFT; - loff_t holelen = num_pages << PAGE_SHIFT; + loff_t offset = ((loff_t) ttm->mapping_offset) << PAGE_SHIFT; + loff_t holelen = ((loff_t) ttm->num_pages) << PAGE_SHIFT; - unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); return 0; } +/* + * Change caching policy for the linear kernel map + * for range of pages in a ttm. + */ + +static int drm_set_caching(drm_ttm_t * ttm, int noncached) +{ + int i; + struct page **cur_page; + int do_tlbflush = 0; + + if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached) + return 0; + + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages + i; + if (*cur_page) { + if (!PageHighMem(*cur_page)) { + if (noncached) { + map_page_into_agp(*cur_page); + } else { + unmap_page_from_agp(*cur_page); + } + do_tlbflush = 1; + } + } + } + if (do_tlbflush) + flush_agp_mappings(); + + DRM_MASK_VAL(ttm->page_flags, DRM_TTM_PAGE_UNCACHED, noncached); + + return 0; +} + /* * Free all resources associated with a ttm. */ @@ -96,8 +114,8 @@ int drm_destroy_ttm(drm_ttm_t * ttm) { int i; - struct list_head *list, *next; struct page **cur_page; + drm_ttm_backend_t *be; if (!ttm) return 0; @@ -110,30 +128,26 @@ int drm_destroy_ttm(drm_ttm_t * ttm) DRM_DEBUG("Destroying a ttm\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); - drm_destroy_ttm_region(entry); - } + be = ttm->be; - drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_TTM); - ttm->be_list = NULL; + if (be) { + be->destroy(be); + ttm->be = NULL; } if (ttm->pages) { drm_buffer_manager_t *bm = &ttm->dev->bm; - int do_tlbflush = 0; + if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) + drm_set_caching(ttm, 0); + 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)) { - unmap_page_from_agp(*cur_page); - do_tlbflush = 1; - } if (*cur_page) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) unlock_page(*cur_page); +#else + ClearPageReserved(*cur_page); +#endif if (page_count(*cur_page) != 1) { DRM_ERROR("Erroneous page count. " "Leaking pages.\n"); @@ -151,47 +165,66 @@ int drm_destroy_ttm(drm_ttm_t * ttm) --bm->cur_pages; } } - if (do_tlbflush) - flush_agp_mappings(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), DRM_MEM_TTM); ttm->pages = NULL; } - if (ttm->page_flags) { - ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), - DRM_MEM_TTM); - 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_TTM); - } - drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_TTM); - ttm->vma_list = NULL; - } - drm_free(ttm, sizeof(*ttm), DRM_MEM_TTM); return 0; } +static int drm_ttm_populate(drm_ttm_t *ttm) +{ + struct page *page; + unsigned long i; + drm_buffer_manager_t *bm; + drm_ttm_backend_t *be; + + + if (ttm->state != ttm_unpopulated) + return 0; + + bm = &ttm->dev->bm; + be = ttm->be; + for (i=0; inum_pages; ++i) { + page = ttm->pages[i]; + if (!page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + return -ENOMEM; + } + page = drm_alloc_gatt_pages(0); + if (!page) + return -ENOMEM; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) + SetPageLocked(page); +#else + SetPageReserved(page); +#endif + ttm->pages[i] = page; + ++bm->cur_pages; + } + } + be->populate(be, ttm->num_pages, ttm->pages); + ttm->state = ttm_unbound; + return 0; +} + + + /* * Initialize a 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, + int cached) { - + drm_bo_driver_t *bo_driver = dev->driver->bo_driver; drm_ttm_t *ttm; - if (!dev->driver->bo_driver) + if (!bo_driver) return NULL; ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_TTM); @@ -199,21 +232,12 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) return NULL; ttm->dev = dev; - ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - ttm->page_flags = ttm_alloc(ttm->num_pages * sizeof(*ttm->page_flags), - DRM_MEM_TTM); - 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->page_flags = 0; ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), DRM_MEM_TTM); if (!ttm->pages) { @@ -222,382 +246,86 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) return NULL; } memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); - - ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_TTM); - if (!ttm->be_list) { - DRM_ERROR("Alloc be regions failed\n"); + ttm->be = bo_driver->create_ttm_backend_entry(dev, cached); + if (!ttm->be) { drm_destroy_ttm(ttm); + DRM_ERROR("Failed creating ttm backend entry\n"); 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_TTM); - 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->state = ttm_unpopulated; return ttm; } -/* - * Change caching policy for the linear kernel map - * 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 i, cur; - struct page **cur_page; - int do_tlbflush = 0; - - 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"); - 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); - if (noncached) { - map_page_into_agp(*cur_page); - } else { - unmap_page_from_agp(*cur_page); - } - do_tlbflush = 1; - } - } - } - if (do_tlbflush) - flush_agp_mappings(); - return 0; -} - /* * Unbind a ttm region from the aperture. */ -int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) +int drm_evict_ttm(drm_ttm_t * ttm) { - drm_ttm_backend_t *be = entry->be; - drm_ttm_t *ttm = entry->owner; + drm_ttm_backend_t *be = ttm->be; - if (be) { - switch (entry->state) { - case ttm_bound: - if (ttm && be->needs_cache_adjust(be)) { - unmap_vma_pages(ttm, entry->page_offset, - entry->num_pages); - } - be->unbind(entry->be); - if (ttm && be->needs_cache_adjust(be)) { - drm_set_caching(ttm, entry->page_offset, - entry->num_pages, 0); - } - break; - default: - break; + switch (ttm->state) { + case ttm_bound: + if (be->needs_cache_adjust(be)) { + unmap_vma_pages(ttm); } + be->unbind(be); + break; + default: + break; } - entry->state = ttm_evicted; + ttm->state = ttm_evicted; return 0; } -void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry) +void drm_fixup_ttm_caching(drm_ttm_t * ttm) { - 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; - - DRM_DEBUG("Destroying a TTM region\n"); - list_del_init(&entry->head); - - drm_unbind_ttm_region(entry); - if (be) { - be->clear(be); - 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_TTM); -} - -/* - * 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; - drm_buffer_manager_t *bm = &ttm->dev->bm; - - 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); + if (ttm->state == ttm_evicted) { + drm_ttm_backend_t *be = ttm->be; + if (be->needs_cache_adjust(be)) { + drm_set_caching(ttm, 0); } + ttm->state = ttm_unbound; } +} + - entry = drm_calloc(1, sizeof(*entry), DRM_MEM_TTM); - if (!entry) - return -ENOMEM; +void drm_unbind_ttm(drm_ttm_t * ttm) +{ + if (ttm->state == ttm_bound) + drm_evict_ttm(ttm); - 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"); - 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) { - if (bm->cur_pages >= bm->max_pages) { - DRM_ERROR("Maximum locked page count exceeded\n"); - drm_destroy_ttm_region(entry); - return -ENOMEM; - } - *cur_page = drm_alloc_gatt_pages(0); - if (!*cur_page) { - DRM_ERROR("Page allocation failed\n"); - drm_destroy_ttm_region(entry); - return -ENOMEM; - } - SetPageLocked(*cur_page); - ++bm->cur_pages; - } - } - - 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; + drm_fixup_ttm_caching(ttm); } -/* - * Bind a ttm region. Set correct caching policy. - */ - -int drm_bind_ttm_region(drm_ttm_backend_list_t * region, - unsigned long aper_offset) +int drm_bind_ttm(drm_ttm_t * ttm, + 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) + if (!ttm) return -EINVAL; + if (ttm->state == ttm_bound) + return 0; - be = region->be; - ttm = region->owner; - - if (ttm && be->needs_cache_adjust(be)) { - if (ret) - return ret; - - unmap_vma_pages(ttm, region->page_offset, - region->num_pages); - drm_set_caching(ttm, region->page_offset, region->num_pages, - DRM_TTM_PAGE_UNCACHED); - } else { - DRM_DEBUG("Binding cached\n"); - } - + be = ttm->be; + + drm_ttm_populate(ttm); + if (ttm->state == ttm_unbound && be->needs_cache_adjust(be)) { + unmap_vma_pages(ttm); + drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); + } if ((ret = be->bind(be, aper_offset))) { - drm_unbind_ttm_region(region); + drm_unbind_ttm(ttm); 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++; - } - - 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_TTM); - 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++; - } - ttm_free(entry->anon_pages, - sizeof(*entry->anon_pages)*entry->anon_locked, - DRM_MEM_TTM); - } - - be->destroy(be); - drm_free(entry, sizeof(*entry), DRM_MEM_TTM); - 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_TTM); - - 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 = ttm_alloc(sizeof(*(tmp->anon_pages)) * len, - DRM_MEM_TTM); - - 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; - *entry = tmp; + ttm->aper_offset = aper_offset; + ttm->state = ttm_bound; return 0; } @@ -651,29 +379,18 @@ void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) } } -/* - * dev->struct_mutex locked. - */ -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, - 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) + uint32_t flags, int cached, + drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; drm_map_list_t *list; - drm_map_t *map; + drm_local_map_t *map; drm_ttm_t *ttm; object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); @@ -689,14 +406,14 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, } map = list->map; - ttm = drm_init_ttm(dev, size); + ttm = drm_init_ttm(dev, size, cached); if (!ttm) { DRM_ERROR("Could not create ttm\n"); drm_ttm_object_remove(dev, object); return -ENOMEM; } - map->offset = ttm->lhandle; + map->offset = (unsigned long) ttm; map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; map->size = ttm->num_pages * PAGE_SIZE; @@ -725,87 +442,3 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, *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) -{ - DRM_DEVICE; - drm_ttm_arg_t arg; - drm_ttm_object_t *entry; - drm_user_object_t *uo; - unsigned long size; - int ret; - - DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - - switch (arg.op) { - case drm_ttm_create: - mutex_lock(&dev->struct_mutex); - size = arg.size; - ret = drm_ttm_object_create(dev, size, arg.flags, &entry); - if (ret) { - mutex_unlock(&dev->struct_mutex); - return ret; - } - ret = drm_add_user_object(priv, &entry->base, - arg.flags & DRM_TTM_FLAG_SHAREABLE); - if (ret) { - drm_ttm_object_remove(dev, entry); - 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: - ret = drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); - if (ret) - return ret; - mutex_lock(&dev->struct_mutex); - 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); - case drm_ttm_destroy: - mutex_lock(&dev->struct_mutex); - uo = drm_lookup_user_object(priv, arg.handle); - if (!uo || (uo->type != drm_ttm_type) || uo->owner != priv) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - ret = drm_remove_user_object(priv, uo); - mutex_unlock(&dev->struct_mutex); - return ret; - } - arg.handle = entry->base.hash.key; - arg.user_token = entry->map_list.user_token; - arg.size = entry->map_list.map->size; - drm_ttm_object_deref_locked(dev, entry); - mutex_unlock(&dev->struct_mutex); - - DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); - return 0; -} diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index fcac06b5..19c1df51 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -48,6 +48,7 @@ typedef struct drm_ttm_backend { unsigned long aperture_base; void *private; int needs_free; + uint32_t drm_map_type; int (*needs_cache_adjust) (struct drm_ttm_backend * backend); int (*populate) (struct drm_ttm_backend * backend, unsigned long num_pages, struct page ** pages); @@ -57,61 +58,32 @@ typedef struct drm_ttm_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 { - uint32_t flags; - 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; +typedef struct drm_ttm { + struct page **pages; + uint32_t page_flags; + unsigned long num_pages; + unsigned long aper_offset; + atomic_t vma_count; + struct drm_device *dev; + int destroy; + uint32_t mapping_offset; + drm_ttm_backend_t *be; enum { ttm_bound, ttm_evicted, - ttm_unbound + ttm_unbound, + ttm_unpopulated, } 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; - int mmap_sem_locked; - int destroy; - uint32_t mapping_offset; } drm_ttm_t; typedef struct drm_ttm_object { - drm_user_object_t base; atomic_t usage; 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, + uint32_t flags, int cached, drm_ttm_object_t ** ttm_object); extern void drm_ttm_object_deref_locked(struct drm_device *dev, drm_ttm_object_t * to); @@ -120,41 +92,18 @@ extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, 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 - * 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, +extern int drm_bind_ttm(drm_ttm_t * ttm, 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); +extern void drm_unbind_ttm(drm_ttm_t * ttm); /* * Evict a ttm region. Keeps Aperture caching policy. */ -int drm_evict_ttm_region(drm_ttm_backend_list_t * entry); +extern int drm_evict_ttm(drm_ttm_t * ttm); +extern void drm_fixup_ttm_caching(drm_ttm_t *ttm); -/* - * 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, @@ -163,7 +112,6 @@ int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry, */ 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_ioctl(DRM_IOCTL_ARGS); static __inline__ drm_ttm_t *drm_ttm_from_object(drm_ttm_object_t * to) diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 5fbbaadd..45951156 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -159,120 +159,48 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, } #endif /* __OS_HAS_AGP */ - -static int drm_ttm_remap_bound_pfn(struct vm_area_struct *vma, - unsigned long address, - unsigned long size) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) +static +#endif +struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, + struct fault_data *data) { - 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; ipage_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 address = data->address; + drm_local_map_t *map = (drm_local_map_t *) vma->vm_private_data; unsigned long page_offset; struct page *page; drm_ttm_t *ttm; - pgprot_t default_prot; - uint32_t page_flags; drm_buffer_manager_t *bm; drm_device_t *dev; + unsigned long pfn; + int err; + pgprot_t pgprot; - if (address > vma->vm_end) - return NOPAGE_SIGBUS; /* Disallow mremap */ - if (!entry) - return NOPAGE_OOM; /* Nothing allocated */ + if (!map) { + data->type = VM_FAULT_OOM; + return NULL; + } + + if (address > vma->vm_end) { + data->type = VM_FAULT_SIGBUS; + return NULL; + } - map = (drm_map_t *) entry->map; ttm = (drm_ttm_t *) map->offset; dev = ttm->dev; + + /* + * Perhaps retry here? + */ + mutex_lock(&dev->struct_mutex); + drm_fixup_ttm_caching(ttm); bm = &dev->bm; page_offset = (address - vma->vm_start) >> PAGE_SHIFT; page = ttm->pages[page_offset]; - page_flags = ttm->page_flags[page_offset]; - if (!page) { if (bm->cur_pages >= bm->max_pages) { DRM_ERROR("Maximum locked page count exceeded\n"); @@ -281,40 +209,65 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, } ++bm->cur_pages; page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); - if (page) { - SetPageLocked(page); - } else { - page = NOPAGE_OOM; + if (!page) { + data->type = VM_FAULT_OOM; + goto out; } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) + SetPageLocked(page); +#else + SetPageReserved(page); +#endif } - if (page_flags & DRM_TTM_PAGE_UNCACHED) { + if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) { /* - * This makes sure we don't race with another - * drm_ttm_remap_bound_pfn(); + * FIXME: Check can't map aperture flag. */ - if (!drm_pte_is_clear(vma, address)) { - page = NOPAGE_RETRY; - goto out1; - } - - drm_ttm_remap_bound_pfn(vma, address, PAGE_SIZE); - page = NOPAGE_RETRY; - goto out1; + pfn = ttm->aper_offset + page_offset + + (ttm->be->aperture_base >> PAGE_SHIFT); + pgprot = drm_io_prot(ttm->be->drm_map_type, vma); + } else { + pfn = page_to_pfn(page); + pgprot = vma->vm_page_prot; } - get_page(page); - out1: - default_prot = vm_get_page_prot(vma->vm_flags); - vma->vm_page_prot = default_prot; + err = vm_insert_pfn(vma, address, pfn, pgprot); + if (!err && (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) && + ttm->num_pages > 1) { + + /* + * FIXME: Check can't map aperture flag. + */ + + /* + * Since we're not racing with anybody else, + * we might as well populate the whole object space. + * Note that we're touching vma->vm_flags with this + * operation, but we are not changing them, so we should be + * OK. + */ + + BUG_ON(ttm->state == ttm_unpopulated); + err = io_remap_pfn_range(vma, address + PAGE_SIZE, pfn+1, + (ttm->num_pages - 1) * PAGE_SIZE, + pgprot); + } + + + if (!err || err == -EBUSY) + data->type = VM_FAULT_MINOR; + else + data->type = VM_FAULT_OOM; out: mutex_unlock(&dev->struct_mutex); - return page; + return NULL; } + /** * \c nopage method for shared virtual memory. * @@ -547,14 +500,6 @@ static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, 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) */ @@ -582,13 +527,6 @@ static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, 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 */ @@ -619,11 +557,19 @@ static struct vm_operations_struct drm_vm_sg_ops = { .close = drm_vm_close, }; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) 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, }; +#else +static struct vm_operations_struct drm_vm_ttm_ops = { + .fault = drm_vm_ttm_fault, + .open = drm_vm_ttm_open_wrapper, + .close = drm_vm_ttm_close, +}; +#endif /** * \c open method for shared virtual memory. @@ -656,36 +602,17 @@ static void drm_vm_open(struct vm_area_struct *vma) 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_local_map_t *map = (drm_local_map_t *)vma->vm_private_data; 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; - 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; - } + ttm = (drm_ttm_t *) map->offset; + atomic_inc(&ttm->vma_count); mutex_unlock(&dev->struct_mutex); - return ret; + return 0; } static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma) @@ -729,21 +656,16 @@ static void drm_vm_close(struct vm_area_struct *vma) 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_local_map_t *map = (drm_local_map_t *) vma->vm_private_data; drm_ttm_t *ttm; drm_device_t *dev; int ret; drm_vm_close(vma); - if (ttm_vma) { - map = (drm_map_t *) ttm_vma->map; + if (map) { ttm = (drm_ttm_t *) map->offset; dev = ttm->dev; mutex_lock(&dev->struct_mutex); - list_del(&ttm_vma->head); - drm_free(ttm_vma, sizeof(*ttm_vma), DRM_MEM_VMAS); if (atomic_dec_and_test(&ttm->vma_count)) { if (ttm->destroy) { ret = drm_destroy_ttm(ttm); @@ -951,17 +873,10 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) #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_private_data = (void *) map; 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; diff --git a/shared-core/drm.h b/shared-core/drm.h index 17bf993b..32cad3bc 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -693,22 +693,6 @@ typedef struct drm_fence_arg { } op; } drm_fence_arg_t; -#define DRM_TTM_FLAG_SHAREABLE 0x00000001 - -typedef struct drm_ttm_arg { - enum { - drm_ttm_create, - drm_ttm_destroy, - drm_ttm_reference, - drm_ttm_unreference - } op; - unsigned handle; - drm_u64_t user_token; - drm_u64_t size; - unsigned flags; -}drm_ttm_arg_t; - - /* Buffer permissions, referring to how the GPU uses the buffers. these translate to fence types used for the buffers. Typically a texture buffer is read, A destination buffer is write and @@ -771,7 +755,6 @@ typedef struct drm_ttm_arg { #define DRM_BO_MASK_DRIVER 0x00F00000 typedef enum { - drm_bo_type_ttm, drm_bo_type_dc, drm_bo_type_user, drm_bo_type_fake @@ -920,7 +903,6 @@ typedef union drm_mm_init_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) #define DRM_IOCTL_MM_INIT DRM_IOWR(0x3e, drm_mm_init_arg_t) #endif From 30703893674b3da5b862dee2acd6efca13424398 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 11 Oct 2006 22:21:01 +0200 Subject: [PATCH 119/147] Compatibility code for 2.6.15-2.6.18. It is ugly but a little comfort is that it will go away in the mainstream kernel. Some bugfixes, mainly in error paths. --- libdrm/xf86drm.c | 9 +- linux-core/drm_bo.c | 54 +++++++-- linux-core/drm_compat.c | 236 ++++++++++++++++++++++++++++++++++++++++ linux-core/drm_compat.h | 68 ++++++++++++ linux-core/drm_ttm.c | 70 ++++++++++-- linux-core/drm_ttm.h | 7 +- linux-core/drm_vm.c | 37 +++---- 7 files changed, 435 insertions(+), 46 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a083ca23..c7683182 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2624,7 +2624,8 @@ int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, drm_bo_arg_t arg; drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t *rep = &arg.d.rep; - + int ret; + memset(buf, 0, sizeof(*buf)); memset(&arg, 0, sizeof(arg)); req->mask = mask; @@ -2650,7 +2651,11 @@ int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, } req->op = drm_bo_create; - if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + do { + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret != 0 && errno == EAGAIN); + + if (ret) return -errno; if (!arg.handled) { return -EFAULT; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d8cab2ad..0e2b3fa1 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -67,14 +67,23 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; + int ret; BUG_ON(!buf->tt); mutex_lock(&dev->struct_mutex); if (evict) - drm_evict_ttm(buf->ttm); + ret = drm_evict_ttm(buf->ttm); else - drm_unbind_ttm(buf->ttm); + ret = drm_unbind_ttm(buf->ttm); + + if (ret) { + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) + schedule(); + return ret; + } + drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -126,13 +135,31 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) list_del_init(&bo->tt_lru); list_del_init(&bo->vram_lru); - if (bo->tt) { + if (bo->ttm) { + unsigned long _end = jiffies + DRM_HZ; + int ret; /* * This temporarily unlocks struct_mutex. */ + + do { + ret = drm_unbind_ttm(bo->ttm); + if (ret == -EAGAIN) { + mutex_unlock(&dev->struct_mutex); + schedule(); + mutex_lock(&dev->struct_mutex); + } + } while (ret == -EAGAIN && !time_after_eq(jiffies, _end)); + + if (ret) { + DRM_ERROR("Couldn't unbind buffer. " + "Bad. Continuing anyway\n"); + } + } + + if (bo->tt) { - drm_unbind_ttm(bo->ttm); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -435,6 +462,9 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) ret = drm_move_vram_to_local(bo); } #endif + if (ret) + goto out; + mutex_lock(&dev->struct_mutex); list_del_init((tt) ? &bo->tt_lru : &bo->vram_lru); if (list_empty((tt) ? &bo->vram_lru : &bo->tt_lru)) @@ -442,7 +472,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - out: + out: return ret; } @@ -521,14 +551,18 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); + mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm(bo->ttm, bo->tt->start); if (ret) { drm_mm_put_block(&bm->tt_manager, bo->tt); + bo->tt = NULL; } mutex_unlock(&dev->struct_mutex); - if (ret) + + if (ret) { return ret; + } be = bo->ttm->be; if (be->needs_cache_adjust(be)) @@ -1296,6 +1330,7 @@ int drm_buffer_object_create(drm_file_t * priv, } bo->priv_flags = 0; bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + atomic_inc(&bm->count); ret = drm_bo_new_flags(dev, bo->flags, mask, hint, 1, &new_flags, &bo->mask); if (ret) @@ -1311,12 +1346,11 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_unlock(&bo->mutex); *buf_obj = bo; - atomic_inc(&bm->count); return 0; - - out_err: + + out_err: mutex_unlock(&bo->mutex); - drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + drm_bo_usage_deref_unlocked(dev, bo); return ret; } diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 1aa835ca..5287614d 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -183,3 +183,239 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, } #endif + +#ifdef DRM_ODD_MM_COMPAT + +typedef struct p_mm_entry { + struct list_head head; + struct mm_struct *mm; + atomic_t refcount; + int locked; +} p_mm_entry_t; + +typedef struct vma_entry { + struct list_head head; + struct vm_area_struct *vma; +} vma_entry_t; + + +struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + drm_local_map_t *map = (drm_local_map_t *) vma->vm_private_data; + unsigned long page_offset; + struct page *page; + drm_ttm_t *ttm; + drm_buffer_manager_t *bm; + drm_device_t *dev; + + /* + * FIXME: Check can't map aperture flag. + */ + + if (type) + *type = VM_FAULT_MINOR; + + if (!map) + return NOPAGE_OOM; + + if (address > vma->vm_end) + return NOPAGE_SIGBUS; + + ttm = (drm_ttm_t *) map->offset; + dev = ttm->dev; + mutex_lock(&dev->struct_mutex); + drm_fixup_ttm_caching(ttm); + BUG_ON(ttm->page_flags & DRM_TTM_PAGE_UNCACHED); + + bm = &dev->bm; + page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + page = ttm->pages[page_offset]; + + if (!page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + page = NOPAGE_OOM; + goto out; + } + page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); + if (!page) { + page = NOPAGE_OOM; + goto out; + } + ++bm->cur_pages; + SetPageLocked(page); + } + + get_page(page); + out: + mutex_unlock(&dev->struct_mutex); + return page; +} + + + + +int drm_ttm_map_bound(struct vm_area_struct *vma) +{ + drm_local_map_t *map = (drm_local_map_t *)vma->vm_private_data; + drm_ttm_t *ttm = (drm_ttm_t *) map->offset; + int ret = 0; + + if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) { + unsigned long pfn = ttm->aper_offset + + (ttm->be->aperture_base >> PAGE_SHIFT); + pgprot_t pgprot = drm_io_prot(ttm->be->drm_map_type, vma); + + ret = io_remap_pfn_range(vma, vma->vm_start, pfn, + vma->vm_end - vma->vm_start, + pgprot); + } + return ret; +} + + +int drm_ttm_add_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) +{ + p_mm_entry_t *entry, *n_entry; + vma_entry_t *v_entry; + drm_local_map_t *map = (drm_local_map_t *) + vma->vm_private_data; + struct mm_struct *mm = vma->vm_mm; + + v_entry = drm_alloc(sizeof(*v_entry), DRM_MEM_TTM); + if (!v_entry) { + DRM_ERROR("Allocation of vma pointer entry failed\n"); + return -ENOMEM; + } + v_entry->vma = vma; + map->handle = (void *) v_entry; + list_add_tail(&v_entry->head, &ttm->vma_list); + + 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_TTM); + if (!n_entry) { + DRM_ERROR("Allocation of process mm pointer entry failed\n"); + return -ENOMEM; + } + INIT_LIST_HEAD(&n_entry->head); + n_entry->mm = mm; + n_entry->locked = 0; + atomic_set(&n_entry->refcount, 0); + list_add_tail(&n_entry->head, &entry->head); + + return 0; +} + +void drm_ttm_delete_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) +{ + p_mm_entry_t *entry, *n; + vma_entry_t *v_entry, *v_n; + int found = 0; + struct mm_struct *mm = vma->vm_mm; + + list_for_each_entry_safe(v_entry, v_n, &ttm->vma_list, head) { + if (v_entry->vma == vma) { + found = 1; + list_del(&v_entry->head); + drm_free(v_entry, sizeof(*v_entry), DRM_MEM_TTM); + break; + } + } + BUG_ON(!found); + + 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); + BUG_ON(entry->locked); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); + } + return; + } + } + BUG_ON(1); +} + + + +int drm_ttm_lock_mm(drm_ttm_t * ttm) +{ + p_mm_entry_t *entry; + int lock_ok = 1; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + BUG_ON(entry->locked); + if (!down_write_trylock(&entry->mm->mmap_sem)) { + lock_ok = 0; + break; + } + entry->locked = 1; + } + + if (lock_ok) + return 0; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (!entry->locked) + break; + up_write(&entry->mm->mmap_sem); + entry->locked = 0; + } + + /* + * Possible deadlock. Try again. Our callers should handle this + * and restart. + */ + + return -EAGAIN; +} + +void drm_ttm_unlock_mm(drm_ttm_t * ttm) +{ + p_mm_entry_t *entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + BUG_ON(!entry->locked); + up_write(&entry->mm->mmap_sem); + entry->locked = 0; + } +} + +int drm_ttm_remap_bound(drm_ttm_t *ttm) +{ + vma_entry_t *v_entry; + int ret = 0; + + list_for_each_entry(v_entry, &ttm->vma_list, head) { + ret = drm_ttm_map_bound(v_entry->vma); + if (ret) + break; + } + + drm_ttm_unlock_mm(ttm); + return ret; +} + +void drm_ttm_finish_unmap(drm_ttm_t *ttm) +{ + vma_entry_t *v_entry; + + if (!(ttm->page_flags & DRM_TTM_PAGE_UNCACHED)) + return; + + list_for_each_entry(v_entry, &ttm->vma_list, head) { + v_entry->vma->vm_flags &= ~VM_PFNMAP; + } + drm_ttm_unlock_mm(ttm); +} + +#endif + diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 4e95679d..5617fb7f 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -231,6 +231,13 @@ static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from #include #include +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))) +#define DRM_ODD_MM_COMPAT +#endif + + + /* * Flush relevant caches and clear a VMA structure so that page references * will cause a page fault. Don't flush tlbs. @@ -303,5 +310,66 @@ extern struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, extern struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, struct fault_data *data); +#endif + +#ifdef DRM_ODD_MM_COMPAT + +struct drm_ttm; + + +/* + * Add a vma to the ttm vma list, and the + * process mm pointer to the ttm mm list. Needs the ttm mutex. + */ + +extern int drm_ttm_add_vma(struct drm_ttm * ttm, + struct vm_area_struct *vma); +/* + * Delete a vma and the corresponding mm pointer from the + * ttm lists. Needs the ttm mutex. + */ +extern void drm_ttm_delete_vma(struct drm_ttm * ttm, + struct vm_area_struct *vma); + +/* + * Attempts to lock all relevant mmap_sems for a ttm, while + * not releasing the ttm mutex. May return -EAGAIN to avoid + * deadlocks. In that case the caller shall release the ttm mutex, + * schedule() and try again. + */ + +extern int drm_ttm_lock_mm(struct drm_ttm * ttm); + +/* + * Unlock all relevant mmap_sems for a ttm. + */ +extern void drm_ttm_unlock_mm(struct drm_ttm * ttm); + +/* + * If the ttm was bound to the aperture, this function shall be called + * with all relevant mmap sems held. It deletes the flag VM_PFNMAP from all + * vmas mapping this ttm. This is needed just after unmapping the ptes of + * the vma, otherwise the do_nopage() function will bug :(. The function + * releases the mmap_sems for this ttm. + */ + +extern void drm_ttm_finish_unmap(struct drm_ttm *ttm); + +/* + * Remap all vmas of this ttm using io_remap_pfn_range. We cannot + * fault these pfns in, because the first one will set the vma VM_PFNMAP + * flag, which will make the next fault bug in do_nopage(). The function + * releases the mmap_sems for this ttm. + */ + +extern int drm_ttm_remap_bound(struct drm_ttm *ttm); + + +/* + * Remap a vma for a bound ttm. Call with the ttm mutex held and + * the relevant mmap_sem locked. + */ +extern int drm_ttm_map_bound(struct vm_area_struct *vma); + #endif #endif diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 297d4f71..b56270ea 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -66,8 +66,17 @@ static int unmap_vma_pages(drm_ttm_t * ttm) drm_device_t *dev = ttm->dev; loff_t offset = ((loff_t) ttm->mapping_offset) << PAGE_SHIFT; loff_t holelen = ((loff_t) ttm->num_pages) << PAGE_SHIFT; - + +#ifdef DRM_ODD_MM_COMPAT + int ret; + ret = drm_ttm_lock_mm(ttm); + if (ret) + return ret; +#endif unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); +#ifdef DRM_ODD_MM_COMPAT + drm_ttm_finish_unmap(ttm); +#endif return 0; } @@ -128,8 +137,11 @@ int drm_destroy_ttm(drm_ttm_t * ttm) DRM_DEBUG("Destroying a ttm\n"); +#ifdef DRM_TTM_ODD_COMPAT + BUG_ON(!list_empty(&ttm->vma_list)); + BUG_ON(!list_empty(&ttm->p_mm_list)); +#endif be = ttm->be; - if (be) { be->destroy(be); ttm->be = NULL; @@ -231,6 +243,11 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, if (!ttm) return NULL; +#ifdef DRM_ODD_MM_COMPAT + INIT_LIST_HEAD(&ttm->p_mm_list); + INIT_LIST_HEAD(&ttm->vma_list); +#endif + ttm->dev = dev; atomic_set(&ttm->vma_count, 0); @@ -263,11 +280,15 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, int drm_evict_ttm(drm_ttm_t * ttm) { drm_ttm_backend_t *be = ttm->be; + int ret; switch (ttm->state) { case ttm_bound: if (be->needs_cache_adjust(be)) { - unmap_vma_pages(ttm); + ret = unmap_vma_pages(ttm); + if (ret) { + return ret; + } } be->unbind(be); break; @@ -291,12 +312,18 @@ void drm_fixup_ttm_caching(drm_ttm_t * ttm) } -void drm_unbind_ttm(drm_ttm_t * ttm) +int drm_unbind_ttm(drm_ttm_t * ttm) { + int ret = 0; + if (ttm->state == ttm_bound) - drm_evict_ttm(ttm); + ret = drm_evict_ttm(ttm); + + if (ret) + return ret; drm_fixup_ttm_caching(ttm); + return 0; } int drm_bind_ttm(drm_ttm_t * ttm, @@ -313,20 +340,45 @@ int drm_bind_ttm(drm_ttm_t * ttm, be = ttm->be; - drm_ttm_populate(ttm); + ret = drm_ttm_populate(ttm); + if (ret) + return ret; if (ttm->state == ttm_unbound && be->needs_cache_adjust(be)) { - unmap_vma_pages(ttm); + ret = unmap_vma_pages(ttm); + if (ret) + return ret; + drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); - } + } +#ifdef DRM_ODD_MM_COMPAT + else if (ttm->state == ttm_evicted && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mm(ttm); + if (ret) + return ret; + } +#endif if ((ret = be->bind(be, aper_offset))) { - drm_unbind_ttm(ttm); + ttm->state = ttm_evicted; +#ifdef DRM_ODD_MM_COMPAT + if (be->needs_cache_adjust(be)) + drm_ttm_unlock_mm(ttm); +#endif DRM_ERROR("Couldn't bind backend.\n"); return ret; } + ttm->aper_offset = aper_offset; ttm->state = ttm_bound; +#ifdef DRM_ODD_MM_COMPAT + if (be->needs_cache_adjust(be)) { + ret = drm_ttm_remap_bound(ttm); + if (ret) + return ret; + } +#endif + return 0; } diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 19c1df51..5421c52a 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -74,6 +74,11 @@ typedef struct drm_ttm { ttm_unbound, ttm_unpopulated, } state; +#ifdef DRM_ODD_MM_COMPAT + struct list_head vma_list; + struct list_head p_mm_list; +#endif + } drm_ttm_t; typedef struct drm_ttm_object { @@ -95,7 +100,7 @@ extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, extern int drm_bind_ttm(drm_ttm_t * ttm, unsigned long aper_offset); -extern void drm_unbind_ttm(drm_ttm_t * ttm); +extern int drm_unbind_ttm(drm_ttm_t * ttm); /* * Evict a ttm region. Keeps Aperture caching policy. diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 45951156..091b43f7 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -204,15 +204,15 @@ struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, if (!page) { if (bm->cur_pages >= bm->max_pages) { DRM_ERROR("Maximum locked page count exceeded\n"); - page = NOPAGE_OOM; + data->type = VM_FAULT_OOM; goto out; } - ++bm->cur_pages; page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); if (!page) { data->type = VM_FAULT_OOM; goto out; } + ++bm->cur_pages; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) SetPageLocked(page); #else @@ -236,28 +236,6 @@ struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, err = vm_insert_pfn(vma, address, pfn, pgprot); - if (!err && (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) && - ttm->num_pages > 1) { - - /* - * FIXME: Check can't map aperture flag. - */ - - /* - * Since we're not racing with anybody else, - * we might as well populate the whole object space. - * Note that we're touching vma->vm_flags with this - * operation, but we are not changing them, so we should be - * OK. - */ - - BUG_ON(ttm->state == ttm_unpopulated); - err = io_remap_pfn_range(vma, address + PAGE_SIZE, pfn+1, - (ttm->num_pages - 1) * PAGE_SIZE, - pgprot); - } - - if (!err || err == -EBUSY) data->type = VM_FAULT_MINOR; else @@ -611,6 +589,9 @@ static int drm_vm_ttm_open(struct vm_area_struct *vma) { mutex_lock(&dev->struct_mutex); ttm = (drm_ttm_t *) map->offset; atomic_inc(&ttm->vma_count); +#ifdef DRM_ODD_MM_COMPAT + drm_ttm_add_vma(ttm, vma); +#endif mutex_unlock(&dev->struct_mutex); return 0; } @@ -666,6 +647,9 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma) ttm = (drm_ttm_t *) map->offset; dev = ttm->dev; mutex_lock(&dev->struct_mutex); +#ifdef DRM_ODD_MM_COMPAT + drm_ttm_delete_vma(ttm, vma); +#endif if (atomic_dec_and_test(&ttm->vma_count)) { if (ttm->destroy) { ret = drm_destroy_ttm(ttm); @@ -877,6 +861,11 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_private_data = (void *) map; vma->vm_file = filp; vma->vm_flags |= VM_RESERVED | VM_IO; +#ifdef DRM_ODD_MM_COMPAT + mutex_lock(&dev->struct_mutex); + drm_ttm_map_bound(vma); + mutex_unlock(&dev->struct_mutex); +#endif if (drm_vm_ttm_open(vma)) return -EAGAIN; return 0; From 10150df02b7062b9975661ccd82b475cd23c8839 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 12 Oct 2006 12:09:16 +0200 Subject: [PATCH 120/147] Simplify the AGP backend interface somewhat. Fix buffer bound caching policy changing, Allow on-the-fly changing of caching policy on bound buffers if the hardware supports it. Allow drivers to use driver-specific AGP memory types for TTM AGP pages. Will make AGP drivers much easier to migrate. --- linux-core/drmP.h | 16 ++++--- linux-core/drm_agpsupport.c | 85 ++++++++++++------------------------- linux-core/drm_bo.c | 35 +++++++++++---- linux-core/drm_ttm.c | 25 ++++++----- linux-core/drm_ttm.h | 15 ++++--- linux-core/i915_buffer.c | 17 ++++---- shared-core/i915_drv.h | 3 +- 7 files changed, 96 insertions(+), 100 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1b6d94e4..f706d4d8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -664,7 +664,7 @@ typedef struct drm_bo_driver{ int cached_vram; drm_local_map_t *vram_map; drm_ttm_backend_t *(*create_ttm_backend_entry) - (struct drm_device *dev, int cached); + (struct drm_device *dev); int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type); int (*invalidate_caches)(struct drm_device *dev, uint32_t flags); } drm_bo_driver_t; @@ -977,7 +977,9 @@ typedef struct drm_device { typedef struct drm_agp_ttm_priv { DRM_AGP_MEM *mem; struct agp_bridge_data *bridge; - unsigned mem_type; + unsigned alloc_type; + unsigned cached_type; + unsigned uncached_type; int populated; } drm_agp_ttm_priv; #endif @@ -1289,11 +1291,11 @@ extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size 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, - drm_ttm_backend_t *backend); -extern drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev, - drm_ttm_backend_t *backend); - +extern drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev, + drm_ttm_backend_t *backend, + unsigned alloc_type, + unsigned cached_type, + unsigned uncached_type); /* Stub support (drm_stub.h) */ extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 77994d5c..902b8947 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -552,20 +552,16 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) 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_unbind_cache_adjust(drm_ttm_backend_t *backend) { + return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 1 : 0); } -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) { @@ -576,9 +572,9 @@ static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, 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); + mem = drm_agp_allocate_memory(num_pages, agp_priv->alloc_type); #else - mem = drm_agp_allocate_memory(agp_priv->bridge, num_pages, agp_priv->mem_type); + mem = drm_agp_allocate_memory(agp_priv->bridge, num_pages, agp_priv->alloc_type); #endif if (!mem) return -1; @@ -592,14 +588,19 @@ static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, return 0; } -static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, unsigned long offset) { - +static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, + unsigned long offset, + int cached) +{ 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"); + DRM_MASK_VAL(backend->flags, DRM_BE_FLAG_BOUND_CACHED, + (cached) ? DRM_BE_FLAG_BOUND_CACHED : 0); mem->is_flushed = FALSE; + mem->type = (cached) ? agp_priv->cached_type : agp_priv->uncached_type; ret = drm_agp_bind_memory(mem, offset); if (ret) { DRM_ERROR("AGP Bind memory failed\n"); @@ -645,14 +646,17 @@ static void drm_agp_destroy_ttm(drm_ttm_backend_t *backend) { } drm_free(agp_priv, sizeof(*agp_priv), DRM_MEM_MAPPINGS); } - if (backend->needs_free) + if (backend->flags & DRM_BE_FLAG_NEEDS_FREE) 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 *backend) { +drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev, + drm_ttm_backend_t *backend, + unsigned alloc_type, + unsigned cached_type, + unsigned uncached_type) { drm_ttm_backend_t *agp_be; drm_agp_ttm_priv *agp_priv; @@ -671,59 +675,26 @@ drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev, } agp_priv->mem = NULL; - agp_priv->mem_type = AGP_MEM_USER; + agp_priv->alloc_type = alloc_type; + agp_priv->cached_type = cached_type; + agp_priv->uncached_type = uncached_type; 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->needs_ub_cache_adjust = drm_agp_needs_unbind_cache_adjust; 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; - agp_be->needs_free = (backend == NULL); + DRM_MASK_VAL(agp_be->flags, DRM_BE_FLAG_NEEDS_FREE, + (backend == NULL) ? DRM_BE_FLAG_NEEDS_FREE : 0); + DRM_MASK_VAL(agp_be->flags, DRM_BE_FLAG_CBA, + (dev->agp->cant_use_aperture) ? DRM_BE_FLAG_CBA : 0); agp_be->drm_map_type = _DRM_AGP; return agp_be; } -EXPORT_SYMBOL(drm_agp_init_ttm_uncached); - -drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev, - drm_ttm_backend_t *backend) { - - drm_ttm_backend_t *agp_be; - drm_agp_ttm_priv *agp_priv; - - - agp_be = (backend != NULL) ? backend: - 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; - agp_be->needs_free = (backend == NULL); - agp_be->drm_map_type = _DRM_AGP; - return agp_be; -} -EXPORT_SYMBOL(drm_agp_init_ttm_cached); +EXPORT_SYMBOL(drm_agp_init_ttm); #endif /* __OS_HAS_AGP */ diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 0e2b3fa1..a84734ab 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -553,7 +553,8 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); - ret = drm_bind_ttm(bo->ttm, bo->tt->start); + ret = drm_bind_ttm(bo->ttm, bo->flags & DRM_BO_FLAG_BIND_CACHED, + bo->tt->start); if (ret) { drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; @@ -565,7 +566,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) } be = bo->ttm->be; - if (be->needs_cache_adjust(be)) + if (be->needs_ub_cache_adjust(be)) bo->flags &= ~DRM_BO_FLAG_CACHED; bo->flags &= ~DRM_BO_MASK_MEM; bo->flags |= DRM_BO_FLAG_MEM_TT; @@ -1089,16 +1090,35 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } + + /* + * Move out if we need to change caching policy. + * FIXME: Failing is strictly not needed for NO_MOVE buffers. + * We just have to implement NO_MOVE buffers. + */ + + if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && + !(bo->flags & DRM_BO_FLAG_MEM_LOCAL)) { + if (bo->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) { + DRM_ERROR("Cannot change caching policy of " + "pinned buffer.\n"); + return -EINVAL; + } + ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait); + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed moving buffer.\n"); + return ret; + } + } + DRM_MASK_VAL(bo->flags, DRM_BO_FLAG_BIND_CACHED, new_flags); + flag_diff = (new_flags ^ bo->flags); /* * Check whether we need to move buffer. */ if ((bo->type != drm_bo_type_fake) && (flag_diff & DRM_BO_MASK_MEM)) { - if (bo->type == drm_bo_type_user) { - DRM_ERROR("User buffers are not implemented yet.\n"); - return -EINVAL; - } ret = drm_bo_move_buffer(bo, new_flags, no_wait); if (ret) { if (ret != -EAGAIN) @@ -1251,7 +1271,6 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo) case drm_bo_type_dc: mutex_lock(&dev->struct_mutex); ret = drm_ttm_object_create(dev, bo->num_pages * PAGE_SIZE, - bo->mask & DRM_BO_FLAG_BIND_CACHED, ttm_flags, &to); mutex_unlock(&dev->struct_mutex); break; @@ -1674,7 +1693,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - 3000 /* arg.req.tt_p_size */); + arg.req.tt_p_size); bm->has_tt = 1; bm->use_tt = 1; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index b56270ea..f1fe1c89 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -230,8 +230,7 @@ static int drm_ttm_populate(drm_ttm_t *ttm) * Initialize a ttm. */ -static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, - int cached) +static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) { drm_bo_driver_t *bo_driver = dev->driver->bo_driver; drm_ttm_t *ttm; @@ -263,7 +262,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, return NULL; } memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); - ttm->be = bo_driver->create_ttm_backend_entry(dev, cached); + ttm->be = bo_driver->create_ttm_backend_entry(dev); if (!ttm->be) { drm_destroy_ttm(ttm); DRM_ERROR("Failed creating ttm backend entry\n"); @@ -284,7 +283,7 @@ int drm_evict_ttm(drm_ttm_t * ttm) switch (ttm->state) { case ttm_bound: - if (be->needs_cache_adjust(be)) { + if (be->needs_ub_cache_adjust(be)) { ret = unmap_vma_pages(ttm); if (ret) { return ret; @@ -304,7 +303,7 @@ void drm_fixup_ttm_caching(drm_ttm_t * ttm) if (ttm->state == ttm_evicted) { drm_ttm_backend_t *be = ttm->be; - if (be->needs_cache_adjust(be)) { + if (be->needs_ub_cache_adjust(be)) { drm_set_caching(ttm, 0); } ttm->state = ttm_unbound; @@ -326,7 +325,7 @@ int drm_unbind_ttm(drm_ttm_t * ttm) return 0; } -int drm_bind_ttm(drm_ttm_t * ttm, +int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset) { @@ -343,7 +342,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, ret = drm_ttm_populate(ttm); if (ret) return ret; - if (ttm->state == ttm_unbound && be->needs_cache_adjust(be)) { + if (ttm->state == ttm_unbound && !cached) { ret = unmap_vma_pages(ttm); if (ret) return ret; @@ -351,16 +350,16 @@ int drm_bind_ttm(drm_ttm_t * ttm, drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); } #ifdef DRM_ODD_MM_COMPAT - else if (ttm->state == ttm_evicted && be->needs_cache_adjust(be)) { + else if (ttm->state == ttm_evicted && !cached) { ret = drm_ttm_lock_mm(ttm); if (ret) return ret; } #endif - if ((ret = be->bind(be, aper_offset))) { + if ((ret = be->bind(be, aper_offset, cached))) { ttm->state = ttm_evicted; #ifdef DRM_ODD_MM_COMPAT - if (be->needs_cache_adjust(be)) + if (be->needs_ub_cache_adjust(be)) drm_ttm_unlock_mm(ttm); #endif DRM_ERROR("Couldn't bind backend.\n"); @@ -372,7 +371,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, ttm->state = ttm_bound; #ifdef DRM_ODD_MM_COMPAT - if (be->needs_cache_adjust(be)) { + if (be->needs_ub_cache_adjust(be)) { ret = drm_ttm_remap_bound(ttm); if (ret) return ret; @@ -437,7 +436,7 @@ void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) */ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, - uint32_t flags, int cached, + uint32_t flags, drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; @@ -458,7 +457,7 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, } map = list->map; - ttm = drm_init_ttm(dev, size, cached); + ttm = drm_init_ttm(dev, size); if (!ttm) { DRM_ERROR("Could not create ttm\n"); drm_ttm_object_remove(dev, object); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 5421c52a..e5501d9c 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -44,16 +44,21 @@ * Most device drivers will let this point to the standard AGP implementation. */ +#define DRM_BE_FLAG_NEEDS_FREE 0x00000001 +#define DRM_BE_FLAG_BOUND_CACHED 0x00000002 +#define DRM_BE_FLAG_CBA 0x00000004 + typedef struct drm_ttm_backend { unsigned long aperture_base; void *private; - int needs_free; + uint32_t flags; uint32_t drm_map_type; - int (*needs_cache_adjust) (struct drm_ttm_backend * backend); + int (*needs_ub_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 (*bind) (struct drm_ttm_backend * backend, + unsigned long offset, int cached); int (*unbind) (struct drm_ttm_backend * backend); void (*destroy) (struct drm_ttm_backend * backend); } drm_ttm_backend_t; @@ -88,7 +93,7 @@ typedef struct drm_ttm_object { } drm_ttm_object_t; extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, - uint32_t flags, int cached, + 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); @@ -97,7 +102,7 @@ extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, uint32_t handle, int check_owner); -extern int drm_bind_ttm(drm_ttm_t * ttm, +extern int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset); extern int drm_unbind_ttm(drm_ttm_t * ttm); diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 2d76f075..8016bb1b 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -33,12 +33,13 @@ #include "i915_drm.h" #include "i915_drv.h" -drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, int cached) +#define INTEL_AGP_MEM_USER (1 << 16) +#define INTEL_AGP_MEM_UCACHED (2 << 16) + +drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev) { - if (cached) - return drm_agp_init_ttm_cached(dev, NULL); - else - return drm_agp_init_ttm_uncached(dev, NULL); + return drm_agp_init_ttm(dev, NULL, INTEL_AGP_MEM_USER, INTEL_AGP_MEM_UCACHED, + INTEL_AGP_MEM_USER); } int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) @@ -53,9 +54,9 @@ int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) int i915_invalidate_caches(drm_device_t *dev, uint32_t flags) { - /* - * FIXME: Only emit once per batchbuffer submission. - */ + /* + * FIXME: Only emit once per batchbuffer submission. + */ uint32_t flush_cmd = MI_NO_WRITE_FLUSH; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a92205e4..85804ce7 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -183,8 +183,7 @@ extern void i915_poke_flush(drm_device_t *dev); #ifdef I915_HAVE_BUFFER /* i915_buffer.c */ -extern drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, - int cached); +extern drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev); extern int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type); extern int i915_invalidate_caches(drm_device_t *dev, uint32_t buffer_flags); #endif From 540c64c378daafaad1c3f63faf5af81f39388665 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 12 Oct 2006 16:10:47 +0200 Subject: [PATCH 121/147] Bugfixes. --- linux-core/drm_agpsupport.c | 2 +- linux-core/drm_bo.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 902b8947..d9fd9c92 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -559,7 +559,7 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) */ static int drm_agp_needs_unbind_cache_adjust(drm_ttm_backend_t *backend) { - return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 1 : 0); + return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); } diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index a84734ab..c24f8d57 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1718,6 +1718,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) atomic_set(&bm->count, 0); bm->cur_pages = 0; bm->max_pages = arg.req.max_locked_pages; + mutex_unlock(&dev->struct_mutex); break; case mm_takedown: LOCK_TEST_WITH_RETURN(dev, filp); @@ -1732,7 +1733,6 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } - mutex_unlock(&dev->struct_mutex); if (ret) return ret; From 1bab514c0a1a535c19d53e3d39e3b351db3ab7a4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 14 Oct 2006 23:38:20 +1000 Subject: [PATCH 122/147] remove config.h from build no longer exists kbuild does it --- linux-core/drmP.h | 1 - linux-core/drm_drawable.c | 1 - linux-core/drm_memory.c | 1 - linux-core/drm_memory.h | 1 - linux-core/drm_memory_debug.c | 1 - linux-core/drm_memory_debug.h | 1 - linux-core/drm_scatter.c | 1 - linux-core/drm_sysfs.c | 1 - linux-core/ffb_drv.c | 1 - linux-core/i810_drv.c | 1 - linux-core/i830_drv.c | 2 -- linux-core/imagine_drv.c | 1 - linux-core/mach64_drv.c | 1 - linux-core/mga_drv.c | 1 - linux-core/nv_drv.c | 1 - linux-core/r128_drv.c | 1 - linux-core/radeon_drv.c | 1 - linux-core/savage_drv.c | 1 - linux-core/sis_drv.c | 1 - linux-core/tdfx_drv.c | 1 - shared-core/drm.h | 3 --- shared-core/via_drv.c | 1 - 22 files changed, 25 deletions(-) delete mode 120000 linux-core/drm_drawable.c diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 2bbec70c..1b314be1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -41,7 +41,6 @@ * can build the DRM (part of PI DRI). 4/21/2000 S + B */ #include #endif /* __alpha__ */ -#include #include #include #include diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c deleted file mode 120000 index d64bbe10..00000000 --- a/linux-core/drm_drawable.c +++ /dev/null @@ -1 +0,0 @@ -../shared-core/drm_drawable.c \ No newline at end of file diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c index 9125cd47..a249382d 100644 --- a/linux-core/drm_memory.c +++ b/linux-core/drm_memory.c @@ -33,7 +33,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include #include "drmP.h" diff --git a/linux-core/drm_memory.h b/linux-core/drm_memory.h index 4a4fd5c3..4a2c3583 100644 --- a/linux-core/drm_memory.h +++ b/linux-core/drm_memory.h @@ -33,7 +33,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include #include #include "drmP.h" diff --git a/linux-core/drm_memory_debug.c b/linux-core/drm_memory_debug.c index 2fe7aeaa..aa1b2922 100644 --- a/linux-core/drm_memory_debug.c +++ b/linux-core/drm_memory_debug.c @@ -31,7 +31,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" #ifdef DEBUG_MEMORY diff --git a/linux-core/drm_memory_debug.h b/linux-core/drm_memory_debug.h index 706b7525..1e0a63b7 100644 --- a/linux-core/drm_memory_debug.h +++ b/linux-core/drm_memory_debug.h @@ -31,7 +31,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" typedef struct drm_mem_stats { diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c index a7144f1a..e5c9f877 100644 --- a/linux-core/drm_scatter.c +++ b/linux-core/drm_scatter.c @@ -31,7 +31,6 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include "drmP.h" diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index df75d7b0..e5dd0532 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -11,7 +11,6 @@ * */ -#include #include #include #include diff --git a/linux-core/ffb_drv.c b/linux-core/ffb_drv.c index 7b028c86..9c88f061 100644 --- a/linux-core/ffb_drv.c +++ b/linux-core/ffb_drv.c @@ -4,7 +4,6 @@ * Copyright (C) 2000 David S. Miller (davem@redhat.com) */ -#include #include #include #include diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c index d4b73760..fc784a02 100644 --- a/linux-core/i810_drv.c +++ b/linux-core/i810_drv.c @@ -30,7 +30,6 @@ * Gareth Hughes */ -#include #include "drmP.h" #include "drm.h" #include "i810_drm.h" diff --git a/linux-core/i830_drv.c b/linux-core/i830_drv.c index 74b574aa..6416161e 100644 --- a/linux-core/i830_drv.c +++ b/linux-core/i830_drv.c @@ -32,8 +32,6 @@ * Keith Whitwell */ -#include - #include "drmP.h" #include "drm.h" #include "i830_drm.h" diff --git a/linux-core/imagine_drv.c b/linux-core/imagine_drv.c index bec2fae4..6d050999 100644 --- a/linux-core/imagine_drv.c +++ b/linux-core/imagine_drv.c @@ -22,7 +22,6 @@ /* derived from tdfx_drv.c */ -#include #include "drmP.h" #include "imagine_drv.h" diff --git a/linux-core/mach64_drv.c b/linux-core/mach64_drv.c index ba45132b..9709934d 100644 --- a/linux-core/mach64_drv.c +++ b/linux-core/mach64_drv.c @@ -27,7 +27,6 @@ * Leif Delgass */ -#include #include "drmP.h" #include "drm.h" #include "mach64_drm.h" diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 3a1e4b25..2bb1e8f3 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -29,7 +29,6 @@ * Gareth Hughes */ -#include #include "drmP.h" #include "drm.h" #include "mga_drm.h" diff --git a/linux-core/nv_drv.c b/linux-core/nv_drv.c index a6afb024..5049473a 100644 --- a/linux-core/nv_drv.c +++ b/linux-core/nv_drv.c @@ -32,7 +32,6 @@ * Lars Knoll */ -#include #include "drmP.h" #include "nv_drv.h" diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index edc04b03..ef4a5cbd 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -29,7 +29,6 @@ * Gareth Hughes */ -#include #include "drmP.h" #include "drm.h" #include "r128_drm.h" diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index b15e983e..43b9aca0 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -29,7 +29,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" #include "drm.h" #include "radeon_drm.h" diff --git a/linux-core/savage_drv.c b/linux-core/savage_drv.c index 9f12dfe2..bb3561e6 100644 --- a/linux-core/savage_drv.c +++ b/linux-core/savage_drv.c @@ -23,7 +23,6 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" #include "savage_drm.h" #include "savage_drv.h" diff --git a/linux-core/sis_drv.c b/linux-core/sis_drv.c index 36a525dc..9b0b9830 100644 --- a/linux-core/sis_drv.c +++ b/linux-core/sis_drv.c @@ -25,7 +25,6 @@ * */ -#include #include "drmP.h" #include "sis_drm.h" #include "sis_drv.h" diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c index ce1b7c5a..bc69c06a 100644 --- a/linux-core/tdfx_drv.c +++ b/linux-core/tdfx_drv.c @@ -30,7 +30,6 @@ * Gareth Hughes */ -#include #include "drmP.h" #include "tdfx_drv.h" diff --git a/shared-core/drm.h b/shared-core/drm.h index 8c0c5d22..7d7e2502 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -69,9 +69,6 @@ #endif #if defined(__linux__) -#if defined(__KERNEL__) -#include -#endif #include /* For _IO* macros */ #define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_IOC_VOID _IOC_NONE diff --git a/shared-core/via_drv.c b/shared-core/via_drv.c index bacfe37d..33b0a42d 100644 --- a/shared-core/via_drv.c +++ b/shared-core/via_drv.c @@ -22,7 +22,6 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" #include "via_drm.h" #include "via_drv.h" From 5b2a60f550090a41c13483ceaaa1a84d3a9257f8 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 16 Oct 2006 14:22:27 +0200 Subject: [PATCH 123/147] Change Intel AGP memory type numbers. --- linux-core/drm_drawable.c | 1 - linux-core/i915_buffer.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 120000 linux-core/drm_drawable.c diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c deleted file mode 120000 index d64bbe10..00000000 --- a/linux-core/drm_drawable.c +++ /dev/null @@ -1 +0,0 @@ -../shared-core/drm_drawable.c \ No newline at end of file diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 8016bb1b..8a3d7bf7 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -33,8 +33,8 @@ #include "i915_drm.h" #include "i915_drv.h" -#define INTEL_AGP_MEM_USER (1 << 16) -#define INTEL_AGP_MEM_UCACHED (2 << 16) +#define INTEL_AGP_MEM_USER 3 +#define INTEL_AGP_MEM_UCACHED 4 drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev) { From 561e23a7c2f06b382613d3e2ae8d23104d0949aa Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Mon, 16 Oct 2006 22:06:58 -0400 Subject: [PATCH 124/147] dev->agp_buffer_map is not initialized for AGP DMA on savages bug 8662 --- shared-core/savage_bci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/savage_bci.c b/shared-core/savage_bci.c index 20fea40f..01121b92 100644 --- a/shared-core/savage_bci.c +++ b/shared-core/savage_bci.c @@ -725,6 +725,7 @@ static int savage_do_init_bci(drm_device_t *dev, drm_savage_init_t *init) dev_priv->status = NULL; } if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) { + dev->agp_buffer_token = init->buffers_offset; dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { From 5881ce1b91034fbdf81dda37a23215cfc1310cdf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 11:05:37 +0200 Subject: [PATCH 125/147] Extend generality for more memory types. Fix up init and destruction code. --- libdrm/xf86drm.c | 31 ++- libdrm/xf86mm.h | 9 +- linux-core/drmP.h | 35 ++- linux-core/drm_bo.c | 582 ++++++++++++++++++++++++++--------------- linux-core/drm_drv.c | 9 +- linux-core/drm_stub.c | 1 + linux-core/i915_drv.c | 5 +- shared-core/drm.h | 34 ++- shared-core/i915_dma.c | 4 +- 9 files changed, 442 insertions(+), 268 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index c7683182..039c9b32 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3155,19 +3155,16 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) return 0; } -int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, - unsigned long ttPOffset, unsigned long ttPSize, - unsigned long max_locked_size) +int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, + unsigned memType) { drm_mm_init_arg_t arg; memset(&arg, 0, sizeof(arg)); arg.req.op = mm_init; - arg.req.vr_p_offset = vramPOffset; - arg.req.vr_p_size = vramPSize; - arg.req.tt_p_offset = ttPOffset; - arg.req.tt_p_size = ttPSize; - arg.req.max_locked_pages = max_locked_size / getpagesize(); + arg.req.p_offset = pOffset; + arg.req.p_size = pSize; + arg.req.mem_type = memType; if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) return -errno; @@ -3175,13 +3172,29 @@ int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, return 0; } -int drmMMTakedown(int fd) +int drmMMTakedown(int fd, unsigned memType) { drm_mm_init_arg_t arg; memset(&arg, 0, sizeof(arg)); arg.req.op = mm_takedown; + arg.req.mem_type = memType; + + if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) + return -errno; + + return 0; +} + +int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize) +{ + drm_mm_init_arg_t arg; + + + memset(&arg, 0, sizeof(arg)); + arg.req.op = mm_set_max_pages; + arg.req.p_size = maxLockedSize / getpagesize(); if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) return -errno; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 78df37c3..b2ba24d5 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -195,10 +195,11 @@ extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint); * Initialization functions. */ -extern int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, - unsigned long ttPOffset, unsigned long ttPSize, - unsigned long max_locked_size); -extern int drmMMTakedown(int fd); +extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, + unsigned memType); +extern int drmMMTakedown(int fd, unsigned memType); +extern int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize); + #endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f706d4d8..7e95569b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -167,6 +167,7 @@ #define DRM_OBJECT_HASH_ORDER 12 #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) +#define DRM_MM_INIT_MAX_PAGES 256 /*@}*/ @@ -660,9 +661,8 @@ typedef struct drm_ref_object { */ typedef struct drm_bo_driver{ - int cached_tt; - int cached_vram; - drm_local_map_t *vram_map; + int cached[DRM_BO_MEM_TYPES]; + drm_local_map_t *iomap[DRM_BO_MEM_TYPES]; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev); int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type); @@ -801,21 +801,17 @@ typedef struct drm_fence_manager{ } drm_fence_manager_t; typedef struct drm_buffer_manager{ + struct mutex init_mutex; + int nice_mode; int initialized; drm_file_t *last_to_validate; - int has_vram; - int has_tt; - int use_vram; - int use_tt; - drm_mm_t tt_manager; - drm_mm_t vram_manager; - struct list_head tt_lru; - struct list_head vram_lru; - struct list_head tt_pinned; - struct list_head vram_pinned; + int has_type[DRM_BO_MEM_TYPES]; + int use_type[DRM_BO_MEM_TYPES]; + drm_mm_t manager[DRM_BO_MEM_TYPES]; + struct list_head lru[DRM_BO_MEM_TYPES]; + struct list_head pinned[DRM_BO_MEM_TYPES]; struct list_head unfenced; struct list_head ddestroy; - struct list_head other; struct work_struct wq; uint32_t fence_type; unsigned long max_pages; @@ -1024,10 +1020,10 @@ typedef struct drm_buffer_object{ uint32_t flags; uint32_t mask; - drm_mm_node_t *vram; - drm_mm_node_t *tt; - struct list_head tt_lru; - struct list_head vram_lru; + drm_mm_node_t *node_ttm; /* MM node for on-card RAM */ + drm_mm_node_t *node_card; /* MM node for ttm*/ + struct list_head lru_ttm; /* LRU for the ttm pages*/ + struct list_head lru_card; /* For memory types with on-card RAM */ struct list_head ddestroy; uint32_t fence_type; @@ -1447,7 +1443,8 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); -extern int drm_bo_clean_mm(drm_device_t *dev); +extern int drm_bo_driver_finish(drm_device_t *dev); +extern int drm_bo_driver_init(drm_device_t *dev); extern int drm_fence_buffer_objects(drm_file_t * priv, struct list_head *list, uint32_t fence_flags, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index c24f8d57..20c58f21 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -59,6 +59,69 @@ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } +static inline uint32_t drm_bo_type_flags(unsigned type) +{ + return (1 << (24 + type)); +} + +static inline drm_buffer_object_t *drm_bo_entry(struct list_head *list, + unsigned type) +{ + switch(type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return list_entry(list, drm_buffer_object_t, lru_ttm); + case DRM_BO_MEM_VRAM: + case DRM_BO_MEM_VRAM_NM: + return list_entry(list, drm_buffer_object_t, lru_card); + default: + BUG_ON(1); + } + return NULL; +} + +static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t *bo, + unsigned type) +{ + switch(type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return bo->node_ttm; + case DRM_BO_MEM_VRAM: + case DRM_BO_MEM_VRAM_NM: + return bo->node_card; + default: + BUG_ON(1); + } + return NULL; +} + +/* + * bo locked. dev->struct_mutex locked. + */ + +static void drm_bo_add_to_lru(drm_buffer_object_t *buf, + drm_buffer_manager_t *bm) +{ + struct list_head *list; + unsigned mem_type; + + if (buf->flags & DRM_BO_FLAG_MEM_TT) { + mem_type = DRM_BO_MEM_TT; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_ttm, list); + } else { + mem_type = DRM_BO_MEM_LOCAL; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_ttm, list); + } + if (buf->flags & DRM_BO_FLAG_MEM_VRAM) { + mem_type = DRM_BO_MEM_VRAM; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_card, list); + } +} + /* * bo locked. */ @@ -69,27 +132,27 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) drm_buffer_manager_t *bm = &dev->bm; int ret; - BUG_ON(!buf->tt); + if (buf->node_ttm) { + mutex_lock(&dev->struct_mutex); + if (evict) + ret = drm_evict_ttm(buf->ttm); + else + ret = drm_unbind_ttm(buf->ttm); - mutex_lock(&dev->struct_mutex); - if (evict) - ret = drm_evict_ttm(buf->ttm); - else - ret = drm_unbind_ttm(buf->ttm); - - if (ret) { - mutex_unlock(&dev->struct_mutex); - if (ret == -EAGAIN) - schedule(); - return ret; - } + if (ret) { + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) + schedule(); + return ret; + } - drm_mm_put_block(&bm->tt_manager, buf->tt); - buf->tt = NULL; + drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], buf->node_ttm); + buf->node_ttm = NULL; + mutex_unlock(&dev->struct_mutex); + } - buf->flags &= ~DRM_BO_MASK_MEM; + buf->flags &= ~DRM_BO_FLAG_MEM_TT; buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; - mutex_unlock(&dev->struct_mutex); return 0; } @@ -103,6 +166,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); /* @@ -132,8 +196,8 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * Take away from lru lists. */ - list_del_init(&bo->tt_lru); - list_del_init(&bo->vram_lru); + list_del_init(&bo->lru_ttm); + list_del_init(&bo->lru_card); if (bo->ttm) { unsigned long _end = jiffies + DRM_HZ; @@ -158,14 +222,15 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) } } - if (bo->tt) { - - drm_mm_put_block(&bm->tt_manager, bo->tt); - bo->tt = NULL; + if (bo->node_ttm) { + drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], + bo->node_ttm); + bo->node_ttm = NULL; } - if (bo->vram) { - drm_mm_put_block(&bm->vram_manager, bo->vram); - bo->vram = NULL; + if (bo->node_card) { + drm_mm_put_block(&bm->manager[DRM_BO_MEM_VRAM], + bo->node_card); + bo->node_card = NULL; } if (bo->ttm_object) { drm_ttm_object_deref_locked(dev, bo->ttm_object); @@ -246,7 +311,7 @@ static void drm_bo_delayed_workqueue(void *data) drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); - if (!list_empty(&bm->ddestroy)) { + if (bm->initialized && !list_empty(&bm->ddestroy)) { schedule_delayed_work(&bm->wq, ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); } @@ -296,14 +361,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, int count = 0; int ret = 0; struct list_head f_list, *l; - struct list_head *q; mutex_lock(&dev->struct_mutex); if (!list) list = &bm->unfenced; - list_for_each_entry(entry, list, tt_lru) { + list_for_each_entry(entry, list, lru_ttm) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_type |= entry->fence_type; if (entry->fence_class != 0) { @@ -316,7 +380,6 @@ int drm_fence_buffer_objects(drm_file_t * priv, } if (!count) { - DRM_ERROR("No buffers to fence\n"); ret = -EINVAL; goto out; } @@ -350,13 +413,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, count = 0; l = f_list.next; while (l != &f_list) { - entry = list_entry(l, drm_buffer_object_t, tt_lru); + entry = list_entry(l, drm_buffer_object_t, lru_ttm); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); mutex_lock(&dev->struct_mutex); list_del_init(l); - list_del_init(&entry->vram_lru); + list_del_init(&entry->lru_card); if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; if (entry->fence) @@ -365,17 +428,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); - if (entry->flags & DRM_BO_FLAG_MEM_TT) { - q = (entry->flags & DRM_BO_FLAG_NO_EVICT) ? - &bm->tt_pinned : &bm->tt_lru; - list_add_tail(&entry->tt_lru, q); - } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { - q = (entry->flags & DRM_BO_FLAG_NO_EVICT) ? - &bm->vram_pinned : &bm->vram_lru; - list_add_tail(&entry->vram_lru, q); - } else { - list_add_tail(&entry->tt_lru, &bm->other); - } + drm_bo_add_to_lru(entry, bm); } mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); @@ -430,23 +483,24 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, * bo->mutex locked */ -static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) +static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, + int no_wait) { int ret = 0; drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; + /* * Someone might have modified the buffer before we took the buffer mutex. */ - if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) + if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) goto out; - if (tt && !bo->tt) - goto out; - if (!tt && !bo->vram) + if (!(bo->flags & drm_bo_type_flags(mem_type))) goto out; ret = drm_bo_wait(bo, 0, 0, no_wait); + if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed to expire fence before " @@ -454,22 +508,26 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) goto out; } - if (tt) { + if (mem_type == DRM_BO_MEM_TT) { ret = drm_move_tt_to_local(bo, 1); + if (ret) + goto out; + mutex_lock(&dev->struct_mutex); + list_del(&bo->lru_ttm); + list_add_tail(&bo->lru_ttm, &bm->lru[DRM_BO_MEM_LOCAL]); + mutex_unlock(&dev->struct_mutex); } #if 0 else { ret = drm_move_vram_to_local(bo); + mutex_lock(&dev->struct_mutex); + list_del_init(&bo->lru_card); + mutex_unlock(&dev->struct_mutex); } #endif if (ret) goto out; - mutex_lock(&dev->struct_mutex); - list_del_init((tt) ? &bo->tt_lru : &bo->vram_lru); - if (list_empty((tt) ? &bo->vram_lru : &bo->tt_lru)) - list_add_tail(&bo->tt_lru, &bm->other); - mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); out: @@ -480,13 +538,14 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) * buf->mutex locked. */ -int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) +int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, + int no_wait) { drm_device_t *dev = buf->dev; drm_mm_node_t *node; drm_buffer_manager_t *bm = &dev->bm; drm_buffer_object_t *bo; - drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; + drm_mm_t *mm = &bm->manager[mem_type]; struct list_head *lru; unsigned long size = buf->num_pages; int ret; @@ -497,20 +556,16 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) if (node) break; - lru = (tt) ? &bm->tt_lru : &bm->vram_lru; + lru = &bm->lru[mem_type]; 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 = drm_bo_entry(lru->next, mem_type); atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&bo->mutex); - ret = drm_bo_evict(bo, tt, no_wait); + ret = drm_bo_evict(bo, mem_type, no_wait); mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); if (ret) @@ -529,10 +584,10 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) BUG_ON(!node); node->private = (void *)buf; - if (tt) { - buf->tt = node; + if (mem_type == DRM_BO_MEM_TT) { + buf->node_ttm = node; } else { - buf->vram = node; + buf->node_card = node; } buf->offset = node->start * PAGE_SIZE; return 0; @@ -545,19 +600,19 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) drm_ttm_backend_t *be; int ret; - BUG_ON(bo->tt); + BUG_ON(bo->node_ttm); ret = drm_bo_alloc_space(bo, 1, no_wait); if (ret) return ret; - DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); + DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->node_ttm->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm(bo->ttm, bo->flags & DRM_BO_FLAG_BIND_CACHED, - bo->tt->start); + bo->node_ttm->start); if (ret) { - drm_mm_put_block(&bm->tt_manager, bo->tt); - bo->tt = NULL; + drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], bo->node_ttm); + bo->node_ttm = NULL; } mutex_unlock(&dev->struct_mutex); @@ -589,25 +644,27 @@ static int drm_bo_new_flags(drm_device_t * dev, uint32_t new_props; drm_bo_driver_t *driver = dev->driver->bo_driver; drm_buffer_manager_t *bm = &dev->bm; + unsigned i; /* - * First adjust the mask. + * First adjust the mask to take away nonexistant memory types. */ - if (!bm->use_vram) - new_mask &= ~DRM_BO_FLAG_MEM_VRAM; - if (!bm->use_tt) - new_mask &= ~DRM_BO_FLAG_MEM_TT; + for (i=0; iuse_type[i]) + new_mask &= ~drm_bo_type_flags(i); + } if (new_mask & DRM_BO_FLAG_BIND_CACHED) { - if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && + if (((new_mask & DRM_BO_FLAG_MEM_TT) && + !driver->cached[DRM_BO_MEM_TT]) && ((new_mask & DRM_BO_FLAG_MEM_VRAM) - && !driver->cached_vram)) { + && !driver->cached[DRM_BO_MEM_VRAM])) { new_mask &= ~DRM_BO_FLAG_BIND_CACHED; } else { - if (!driver->cached_tt) + if (!driver->cached[DRM_BO_MEM_TT]) new_flags &= DRM_BO_FLAG_MEM_TT; - if (!driver->cached_vram) + if (!driver->cached[DRM_BO_MEM_VRAM]) new_flags &= DRM_BO_FLAG_MEM_VRAM; } } @@ -766,12 +823,12 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) int ret = 0; BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - if (bo->vram) - ret = drm_bo_evict(bo, 0, 1); + if (bo->node_card) + ret = drm_bo_evict(bo, DRM_BO_MEM_VRAM, 1); if (ret) return ret; - if (bo->tt) - ret = drm_bo_evict(bo, 1, 1); + if (bo->node_ttm) + ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1); return ret; } @@ -1136,28 +1193,16 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_UNFENCED, _DRM_BO_FLAG_UNFENCED); mutex_lock(&dev->struct_mutex); - list_del(&bo->tt_lru); - list_add_tail(&bo->tt_lru, &bm->unfenced); - list_del_init(&bo->vram_lru); + list_del(&bo->lru_ttm); + list_add_tail(&bo->lru_ttm, &bm->unfenced); + list_del_init(&bo->lru_card); mutex_unlock(&dev->struct_mutex); } else { - struct list_head *q; mutex_lock(&dev->struct_mutex); - list_del_init(&bo->tt_lru); - list_del_init(&bo->vram_lru); - - if (new_flags & DRM_BO_FLAG_MEM_TT) { - q = (new_flags & DRM_BO_FLAG_NO_EVICT) ? - &bm->tt_pinned : &bm->tt_lru; - list_add_tail(&bo->tt_lru, q); - } else if (new_flags & DRM_BO_FLAG_MEM_VRAM) { - q = (new_flags & DRM_BO_FLAG_NO_EVICT) ? - &bm->vram_pinned : &bm->vram_lru; - list_add_tail(&bo->vram_lru, q); - } else { - list_add_tail(&bo->tt_lru, &bm->other); - } + list_del_init(&bo->lru_ttm); + list_del_init(&bo->lru_card); + drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -1332,15 +1377,14 @@ int drm_buffer_object_create(drm_file_t * priv, atomic_set(&bo->usage, 1); atomic_set(&bo->mapped, -1); DRM_INIT_WAITQUEUE(&bo->event_queue); - INIT_LIST_HEAD(&bo->tt_lru); - INIT_LIST_HEAD(&bo->vram_lru); + INIT_LIST_HEAD(&bo->lru_ttm); + INIT_LIST_HEAD(&bo->lru_card); INIT_LIST_HEAD(&bo->ddestroy); - list_add_tail(&bo->tt_lru, &bm->other); bo->dev = dev; bo->type = type; bo->num_pages = num_pages; - bo->vram = NULL; - bo->tt = NULL; + bo->node_card = NULL; + bo->node_ttm = NULL; if (bo->type == drm_bo_type_fake) { bo->offset = buffer_start; bo->buffer_start = 0; @@ -1540,22 +1584,17 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) */ static void drm_bo_force_list_clean(drm_device_t *dev, - struct list_head *head, int tt) + struct list_head *head, + unsigned mem_type) { + drm_buffer_manager_t *bm = &dev->bm; struct list_head *l; drm_buffer_object_t *entry; - int nice_mode = 1; int ret; l = head->next; while (l != head) { - if (tt) { - entry = list_entry(l, drm_buffer_object_t, - tt_lru); - } else { - entry = list_entry(l, drm_buffer_object_t, - vram_lru); - } + entry = drm_bo_entry(l, mem_type); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); @@ -1566,90 +1605,201 @@ static void drm_bo_force_list_clean(drm_device_t *dev, */ if (entry->fence) { - if (nice_mode) { + if (bm->nice_mode) { unsigned long _end = jiffies + 3*DRM_HZ; do { ret = drm_bo_wait(entry, 0, 1, 0); } while (ret && !time_after_eq(jiffies, _end)); if (entry->fence) { - nice_mode = 0; - DRM_ERROR("Detected GPU hang. " + bm->nice_mode = 0; + DRM_ERROR("Detected GPU hang or " + "fence manager was taken down. " "Evicting waiting buffers\n"); } } + if (entry->fence) { - drm_fence_usage_deref_unlocked(dev, entry->fence); + drm_fence_usage_deref_unlocked(dev, + entry->fence); entry->fence = NULL; } } - ret = drm_bo_evict(entry, tt, 0); + ret = drm_bo_evict(entry, mem_type, 0); if (ret) { DRM_ERROR("Aargh. Eviction failed.\n"); } mutex_unlock(&entry->mutex); mutex_lock(&dev->struct_mutex); - if (!list_empty(l)) { - list_del_init(l); - if (list_empty(&entry->tt_lru) && - list_empty(&entry->vram_lru)) { - list_add_tail(l, &dev->bm.other); - } - } - drm_bo_usage_deref_locked(dev, entry); l = head->next; } } -int drm_bo_clean_mm(drm_device_t * dev) +int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) { drm_buffer_manager_t *bm = &dev->bm; - int ret = 0; + int ret = -EINVAL; - mutex_lock(&dev->struct_mutex); - - if (!bm->initialized) - goto out; - - bm->use_vram = 0; - bm->use_tt = 0; - - /* - * FIXME: Need to handle unfenced list. - */ - - drm_bo_force_list_clean(dev, &bm->tt_lru, 1); - drm_bo_force_list_clean(dev, &bm->tt_pinned, 1); - drm_bo_force_list_clean(dev, &bm->vram_lru, 1); - drm_bo_force_list_clean(dev, &bm->vram_pinned, 1); - - if (bm->has_vram) { - if (drm_mm_clean(&bm->vram_manager)) { - drm_mm_takedown(&bm->vram_manager); - bm->has_vram = 0; - } else - ret = -EBUSY; + if (mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", mem_type); + return ret; } - if (bm->has_tt) { - if (drm_mm_clean(&bm->tt_manager)) { - drm_mm_takedown(&bm->tt_manager); - bm->has_tt = 0; - } else - ret = -EBUSY; - - if (!ret) - bm->initialized = 0; + if (!bm->has_type[mem_type]) { + DRM_ERROR("Trying to take down uninitialized " + "memory manager type\n"); + return ret; } + bm->use_type[mem_type] = 0; + bm->has_type[mem_type] = 0; - out: - mutex_unlock(&dev->struct_mutex); + ret = 0; + if (mem_type > 0) { + drm_bo_force_list_clean(dev, &bm->lru[mem_type], 1); + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], 1); + + if (drm_mm_clean(&bm->manager[mem_type])) { + drm_mm_takedown(&bm->manager[mem_type]); + } else { + ret = -EBUSY; + } + } return ret; } +static int drm_bo_init_mm(drm_device_t *dev, + unsigned type, + unsigned long p_offset, + unsigned long p_size) +{ + drm_buffer_manager_t *bm = &dev->bm; + int ret = -EINVAL; + + if (type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", type); + return ret; + } + if (bm->has_type[type]) { + DRM_ERROR("Memory manager already initialized for type %d\n", + type); + return ret; + } + + ret = 0; + if (type != DRM_BO_MEM_LOCAL) { + if (!p_size) { + DRM_ERROR("Zero size memory manager type %d\n", type); + return ret; + } + ret = drm_mm_init(&bm->manager[type],p_offset, p_size); + if (ret) + return ret; + } + bm->has_type[type] = 1; + bm->use_type[type] = 1; + + INIT_LIST_HEAD(&bm->lru[type]); + INIT_LIST_HEAD(&bm->pinned[type]); + + return 0; +} + + +/* + * call dev->struct_mutex locked; + */ + +static void drm_bo_release_unfenced(drm_buffer_manager_t *bm) +{ + struct list_head *list, *next; + + list_for_each_safe(list, next, &bm->unfenced) { + list_del(list); + list_add_tail(list, &bm->lru[0]); + } +} + +int drm_bo_driver_finish(drm_device_t *dev) +{ + drm_buffer_manager_t *bm = &dev->bm; + int ret = 0; + unsigned i = DRM_BO_MEM_TYPES; + + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + + if (!bm->initialized) + goto out; + drm_bo_release_unfenced(bm); + + while(i--) { + if (bm->has_type[i]) { + bm->use_type[i] = 0; + if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) { + ret = -EBUSY; + DRM_ERROR("DRM memory manager type %d " + "is not clean.\n", i); + } + bm->has_type[i] = 0; + } + } + mutex_unlock(&dev->struct_mutex); + drm_bo_delayed_delete(dev); + mutex_lock(&dev->struct_mutex); + bm->initialized = 0; + mutex_unlock(&dev->struct_mutex); + if (!cancel_delayed_work(&bm->wq)) { + flush_scheduled_work(); + } + mutex_lock(&dev->struct_mutex); + out: + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->bm.init_mutex); + return ret; +} + + +int drm_bo_driver_init(drm_device_t *dev) +{ + drm_bo_driver_t *driver = dev->driver->bo_driver; + drm_buffer_manager_t *bm = &dev->bm; + int ret = -EINVAL; + struct sysinfo si; + + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + if (!driver) + goto out_unlock; + + /* + * Initialize the system memory buffer type. + * Other types need to be driver / IOCTL initialized. + */ + + ret = drm_bo_init_mm(dev, 0, 0, 0); + if (ret) + goto out_unlock; + + INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); + bm->initialized = 1; + bm->nice_mode = 1; + atomic_set(&bm->count, 0); + bm->cur_pages = 0; + si_meminfo(&si); + bm->max_pages = si.totalram >> 1; + INIT_LIST_HEAD(&bm->unfenced); + INIT_LIST_HEAD(&bm->ddestroy); + out_unlock: + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->bm.init_mutex); + return ret; +} +EXPORT_SYMBOL(drm_bo_driver_init); + + int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -1668,71 +1818,69 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) switch (arg.req.op) { case mm_init: - if (bm->initialized) { - DRM_ERROR("Memory manager already initialized\n"); - return -EINVAL; - } + ret = -EINVAL; + mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_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; - /* - * VRAM not supported yet. - */ - - bm->use_vram = 0; - if (ret) - break; + if (!bm->initialized) { + DRM_ERROR("DRM memory manager was not initialized.\n"); + 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; - bm->use_tt = 1; - - if (ret) { - if (bm->has_vram) - drm_mm_takedown(&bm->vram_manager); - break; - } + if (arg.req.mem_type == 0) { + DRM_ERROR("System memory buffers already initialized.\n"); + break; } - arg.rep.mm_sarea = 0; - - INIT_LIST_HEAD(&bm->vram_lru); - INIT_LIST_HEAD(&bm->tt_lru); - INIT_LIST_HEAD(&bm->vram_pinned); - INIT_LIST_HEAD(&bm->tt_pinned); - INIT_LIST_HEAD(&bm->unfenced); - INIT_LIST_HEAD(&bm->ddestroy); - INIT_LIST_HEAD(&bm->other); - - INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); - bm->initialized = 1; - atomic_set(&bm->count, 0); - bm->cur_pages = 0; - bm->max_pages = arg.req.max_locked_pages; - mutex_unlock(&dev->struct_mutex); + ret = drm_bo_init_mm(dev, arg.req.mem_type, + arg.req.p_offset, + arg.req.p_size); break; case mm_takedown: LOCK_TEST_WITH_RETURN(dev, filp); - if (drm_bo_clean_mm(dev)) { - DRM_ERROR("Memory manager not clean. " - "Delaying takedown\n"); + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + ret = -EINVAL; + if (!bm->initialized) { + DRM_ERROR("DRM memory manager was not initialized\n"); + break; + } + if (arg.req.mem_type == 0) { + DRM_ERROR("No takedown for System memory buffers.\n"); + break; + } + ret = 0; + if (drm_bo_clean_mm(dev, arg.req.mem_type)) { + DRM_ERROR("Memory manager type %d not clean. " + "Delaying takedown\n", arg.req.mem_type); } - DRM_DEBUG("We have %ld still locked pages\n", bm->cur_pages); break; + case mm_set_max_pages: { + struct sysinfo si; + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + if (arg.req.p_size < bm->cur_pages) { + DRM_ERROR("Cannot currently decrease max number of " + "locked pages below the number currently " + "locked.\n"); + ret = -EINVAL; + break; + } + si_meminfo(&si); + if (arg.req.p_size > si.totalram) { + DRM_ERROR("Cannot set max number of locked pages " + "to %lu since the total number of RAM pages " + "is %lu.\n", (unsigned long) arg.req.p_size, + (unsigned long) si.totalram); + ret = -EINVAL; + break; + } + bm->max_pages = arg.req.p_size; + } default: DRM_ERROR("Function not implemented yet\n"); return -EINVAL; } + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->bm.init_mutex); if (ret) return ret; diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index c7f0f485..43b4f8d4 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -149,6 +149,11 @@ int drm_lastclose(drm_device_t * dev) DRM_DEBUG("\n"); + if (drm_bo_driver_finish(dev)) { + DRM_ERROR("DRM memory manager still busy. " + "System is unstable. Please reboot.\n"); + } + if (dev->driver->lastclose) dev->driver->lastclose(dev); DRM_DEBUG("driver lastclose completed\n"); @@ -265,10 +270,6 @@ int drm_lastclose(drm_device_t * dev) dev->dev_mapping = NULL; mutex_unlock(&dev->struct_mutex); - if (drm_bo_clean_mm(dev)) { - DRM_ERROR("DRM memory manager still busy. " - "System is unstable. Please reboot.\n"); - } DRM_DEBUG("lastclose completed\n"); return 0; } diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index e3db07dc..66310560 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -71,6 +71,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); + mutex_init(&dev->bm.init_mutex); dev->pdev = pdev; diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 1263bcab..2c5b43d0 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -51,9 +51,8 @@ static drm_fence_driver_t i915_fence_driver = { #endif #ifdef I915_HAVE_BUFFER static drm_bo_driver_t i915_bo_driver = { - .vram_map = NULL, - .cached_vram = 0, - .cached_tt = 1, + .iomap = {NULL, NULL}, + .cached = {1, 1}, .create_ttm_backend_entry = i915_create_ttm_backend_entry, .fence_type = i915_fence_types, .invalidate_caches = i915_invalidate_caches diff --git a/shared-core/drm.h b/shared-core/drm.h index 32cad3bc..915befba 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -680,6 +680,7 @@ typedef struct drm_fence_arg { unsigned type; unsigned flags; unsigned signaled; + unsigned expand_pad[4]; /*Future expansion */ enum { drm_fence_create, drm_fence_destroy, @@ -732,12 +733,14 @@ typedef struct drm_fence_arg { /* Bind this buffer cached if the hardware supports it. */ #define DRM_BO_FLAG_BIND_CACHED 0x0002000 -/* Translation table aperture */ -#define DRM_BO_FLAG_MEM_TT 0x01000000 -/* On-card VRAM */ -#define DRM_BO_FLAG_MEM_VRAM 0x02000000 -/* System memory */ -#define DRM_BO_FLAG_MEM_LOCAL 0x04000000 +/* System Memory */ +#define DRM_BO_FLAG_MEM_LOCAL 0x01000000 +/* Translation table memory */ +#define DRM_BO_FLAG_MEM_TT 0x02000000 +/* Vram memory */ +#define DRM_BO_FLAG_MEM_VRAM 0x04000000 +/* Unmappable Vram memory */ +#define DRM_BO_FLAG_MEM_VRAM_NM 0x08000000 /* Memory flag mask */ #define DRM_BO_MASK_MEM 0xFF000000 @@ -769,6 +772,7 @@ typedef struct drm_bo_arg_request { drm_bo_type_t type; unsigned arg_handle; drm_u64_t buffer_start; + unsigned expand_pad[4]; /*Future expansion */ enum { drm_bo_create, drm_bo_validate, @@ -802,6 +806,7 @@ typedef struct drm_bo_arg_reply { drm_u64_t buffer_start; unsigned fence_flags; unsigned rep_flags; + unsigned expand_pad[4]; /*Future expansion */ }drm_bo_arg_reply_t; @@ -814,23 +819,30 @@ typedef struct drm_bo_arg{ } d; } drm_bo_arg_t; +#define DRM_BO_MEM_LOCAL 0 +#define DRM_BO_MEM_TT 1 +#define DRM_BO_MEM_VRAM 2 +#define DRM_BO_MEM_VRAM_NM 3 +#define DRM_BO_MEM_TYPES 2 /* For now. */ + typedef union drm_mm_init_arg{ struct { enum { mm_init, + mm_set_max_pages, mm_takedown, mm_query, mm_lock, mm_unlock } 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; - drm_u64_t max_locked_pages; + drm_u64_t p_offset; + drm_u64_t p_size; + unsigned mem_type; + unsigned expand_pad[8]; /*Future expansion */ } req; struct { drm_handle_t mm_sarea; + unsigned expand_pad[8]; /*Future expansion */ } rep; } drm_mm_init_arg_t; #endif diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 841761c8..8c701b4d 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -197,7 +197,9 @@ static int i915_initialize(drm_device_t * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); dev->dev_private = (void *)dev_priv; - +#ifdef I915_HAVE_BUFFER + drm_bo_driver_init(dev); +#endif return 0; } From db5c671e86c3db8c99ce5a4954632248e6f849aa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 11:28:48 +0200 Subject: [PATCH 126/147] Remove the memory manager parameter from the put_block function, as this makes the client code a lot cleaner. Prepare buffer manager for lock and unlock calls. --- linux-core/drmP.h | 3 ++- linux-core/drm_bo.c | 45 +++++++++++++++++++++++-------------------- linux-core/drm_mm.c | 5 ++++- linux-core/drm_sman.c | 3 +-- linux-core/drm_ttm.c | 2 +- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 7e95569b..7ae001b3 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -548,6 +548,7 @@ typedef struct drm_mm_node { int free; unsigned long start; unsigned long size; + struct drm_mm *mm; void *private; } drm_mm_node_t; @@ -1344,7 +1345,7 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev); extern drm_mm_node_t * drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment); -extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur); +extern void drm_mm_put_block(drm_mm_node_t *cur); extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, unsigned alignment, int best_match); extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 20c58f21..67e90247 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -126,10 +126,10 @@ static void drm_bo_add_to_lru(drm_buffer_object_t *buf, * bo locked. */ -static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) +static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict, + int force_no_move) { drm_device_t *dev = buf->dev; - drm_buffer_manager_t *bm = &dev->bm; int ret; if (buf->node_ttm) { @@ -146,8 +146,11 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) return ret; } - drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], buf->node_ttm); - buf->node_ttm = NULL; + if (!(buf->flags & DRM_BO_FLAG_NO_MOVE) || + force_no_move) { + drm_mm_put_block(buf->node_ttm); + buf->node_ttm = NULL; + } mutex_unlock(&dev->struct_mutex); } @@ -223,13 +226,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) } if (bo->node_ttm) { - drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], - bo->node_ttm); + drm_mm_put_block(bo->node_ttm); bo->node_ttm = NULL; } if (bo->node_card) { - drm_mm_put_block(&bm->manager[DRM_BO_MEM_VRAM], - bo->node_card); + drm_mm_put_block(bo->node_card); bo->node_card = NULL; } if (bo->ttm_object) { @@ -484,7 +485,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, */ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, - int no_wait) + int no_wait, int force_no_move) { int ret = 0; drm_device_t *dev = bo->dev; @@ -509,7 +510,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, } if (mem_type == DRM_BO_MEM_TT) { - ret = drm_move_tt_to_local(bo, 1); + ret = drm_move_tt_to_local(bo, 1, force_no_move); if (ret) goto out; mutex_lock(&dev->struct_mutex); @@ -565,7 +566,8 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&bo->mutex); - ret = drm_bo_evict(bo, mem_type, no_wait); + BUG_ON(bo->flags & DRM_BO_FLAG_NO_MOVE); + ret = drm_bo_evict(bo, mem_type, no_wait, 0); mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); if (ret) @@ -596,22 +598,23 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) { drm_device_t *dev = bo->dev; - drm_buffer_manager_t *bm = &dev->bm; drm_ttm_backend_t *be; int ret; - BUG_ON(bo->node_ttm); - ret = drm_bo_alloc_space(bo, 1, no_wait); + if (!(bo->node_ttm && (bo->flags & DRM_BO_FLAG_NO_MOVE))) { + BUG_ON(bo->node_ttm); + ret = drm_bo_alloc_space(bo, DRM_BO_MEM_TT, no_wait); + if (ret) + return ret; + } - if (ret) - return ret; DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->node_ttm->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm(bo->ttm, bo->flags & DRM_BO_FLAG_BIND_CACHED, bo->node_ttm->start); if (ret) { - drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], bo->node_ttm); + drm_mm_put_block(bo->node_ttm); bo->node_ttm = NULL; } mutex_unlock(&dev->struct_mutex); @@ -824,11 +827,11 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (bo->node_card) - ret = drm_bo_evict(bo, DRM_BO_MEM_VRAM, 1); + ret = drm_bo_evict(bo, DRM_BO_MEM_VRAM, 1, 0); if (ret) return ret; if (bo->node_ttm) - ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1); + ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1, 0); return ret; } @@ -1115,7 +1118,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, if (ret) return ret; } else { - drm_move_tt_to_local(bo, 0); + drm_move_tt_to_local(bo, 0, 1); } return 0; @@ -1625,7 +1628,7 @@ static void drm_bo_force_list_clean(drm_device_t *dev, entry->fence = NULL; } } - ret = drm_bo_evict(entry, mem_type, 0); + ret = drm_bo_evict(entry, mem_type, 0, 1); if (ret) { DRM_ERROR("Aargh. Eviction failed.\n"); } diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index debac9d9..ef8bd7e9 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -70,6 +70,7 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, child->free = 0; child->size = size; child->start = parent->start; + child->mm = parent->mm; list_add_tail(&child->ml_entry, &parent->ml_entry); parent->size -= size; @@ -83,9 +84,10 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, * Otherwise add to the free stack. */ -void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur) +void drm_mm_put_block(drm_mm_node_t * cur) { + drm_mm_t *mm = cur->mm; drm_mm_node_t *list_root = &mm->root_node; struct list_head *cur_head = &cur->ml_entry; struct list_head *root_head = &list_root->ml_entry; @@ -183,6 +185,7 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) child->start = start; child->size = size; child->free = 1; + child->mm = mm; list_add(&child->fl_entry, &mm->root_node.fl_entry); list_add(&child->ml_entry, &mm->root_node.ml_entry); diff --git a/linux-core/drm_sman.c b/linux-core/drm_sman.c index 425c8233..19a13f3a 100644 --- a/linux-core/drm_sman.c +++ b/linux-core/drm_sman.c @@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size, static void drm_sman_mm_free(void *private, void *ref) { - drm_mm_t *mm = (drm_mm_t *) private; drm_mm_node_t *node = (drm_mm_node_t *) ref; - drm_mm_put_block(mm, node); + drm_mm_put_block(node); } static void drm_sman_mm_destroy(void *private) diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index f1fe1c89..0f9cb11f 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -393,7 +393,7 @@ static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) drm_ht_remove_item(&dev->map_hash, &list->hash); if (list->file_offset_node) { - drm_mm_put_block(&dev->offset_manager, list->file_offset_node); + drm_mm_put_block(list->file_offset_node); list->file_offset_node = NULL; } From 5443dbe35f182b9286a96d24d29037d5cb625e3d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 16:00:25 +0200 Subject: [PATCH 127/147] Implement mm_lock and mm_unlock functions. The mm_lock function is used when leaving vt. It evicts _all_ buffers. Buffers with the DRM_BO_NO_MOVE attribute set will be guaranteed to get the same offset when / if they are rebound. --- libdrm/xf86drm.c | 33 ++++++++ libdrm/xf86mm.h | 3 +- linux-core/drmP.h | 5 ++ linux-core/drm_bo.c | 188 ++++++++++++++++++++++++++++++++------------ 4 files changed, 178 insertions(+), 51 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 039c9b32..253ba690 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3202,4 +3202,37 @@ int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize) return 0; } +int drmMMLock(int fd, unsigned memType) +{ + drm_mm_init_arg_t arg; + int ret; + + memset(&arg, 0, sizeof(arg)); + arg.req.op = mm_lock; + arg.req.mem_type = memType; + + do{ + ret = ioctl(fd, DRM_IOCTL_MM_INIT, &arg); + } while (ret && errno == EAGAIN); + + return ret; +} + +int drmMMUnlock(int fd, unsigned memType) +{ + drm_mm_init_arg_t arg; + int ret; + + memset(&arg, 0, sizeof(arg)); + arg.req.op = mm_unlock; + arg.req.mem_type = memType; + + do{ + ret = ioctl(fd, DRM_IOCTL_MM_INIT, &arg); + } while (ret && errno == EAGAIN); + + return ret; +} + + #endif diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index b2ba24d5..c3112c90 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -199,7 +199,8 @@ extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, unsigned memType); extern int drmMMTakedown(int fd, unsigned memType); extern int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize); - +extern int drmMMLock(int fd, unsigned memType); +extern int drmMMUnlock(int fd, unsigned memType); #endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 7ae001b3..ff952250 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1351,6 +1351,11 @@ extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern void drm_mm_takedown(drm_mm_t *mm); extern int drm_mm_clean(drm_mm_t *mm); +static inline drm_mm_t *drm_get_mm(drm_mm_node_t *block) +{ + return block->mm; +} + /* * User space object bookkeeping (drm_object.c) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 67e90247..f671a046 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -514,8 +514,8 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, if (ret) goto out; mutex_lock(&dev->struct_mutex); - list_del(&bo->lru_ttm); - list_add_tail(&bo->lru_ttm, &bm->lru[DRM_BO_MEM_LOCAL]); + list_del_init(&bo->lru_ttm); + drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); } #if 0 @@ -658,6 +658,11 @@ static int drm_bo_new_flags(drm_device_t * dev, new_mask &= ~drm_bo_type_flags(i); } + if ((new_mask & DRM_BO_FLAG_NO_EVICT ) && !DRM_SUSER(DRM_CURPROC)) { + DRM_ERROR("DRM_BO_FLAG_NO_EVICT is only available to priviliged " + "processes\n"); + return -EPERM; + } if (new_mask & DRM_BO_FLAG_BIND_CACHED) { if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached[DRM_BO_MEM_TT]) && @@ -1085,7 +1090,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, */ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, - int no_wait) + int no_wait, int force_no_move) { int ret = 0; @@ -1118,7 +1123,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, if (ret) return ret; } else { - drm_move_tt_to_local(bo, 0, 1); + drm_move_tt_to_local(bo, 0, force_no_move); } return 0; @@ -1153,8 +1158,6 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, /* * Move out if we need to change caching policy. - * FIXME: Failing is strictly not needed for NO_MOVE buffers. - * We just have to implement NO_MOVE buffers. */ if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && @@ -1164,7 +1167,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, "pinned buffer.\n"); return -EINVAL; } - ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait); + ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait, 0); if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed moving buffer.\n"); @@ -1174,12 +1177,31 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_MASK_VAL(bo->flags, DRM_BO_FLAG_BIND_CACHED, new_flags); flag_diff = (new_flags ^ bo->flags); + /* + * Check whether we dropped no_move policy, and in that case, + * release reserved manager regions. + */ + + if ((flag_diff & DRM_BO_FLAG_NO_MOVE) && + !(new_flags & DRM_BO_FLAG_NO_MOVE)) { + mutex_lock(&dev->struct_mutex); + if (bo->node_ttm) { + drm_mm_put_block(bo->node_ttm); + bo->node_ttm = NULL; + } + if (bo->node_card) { + drm_mm_put_block(bo->node_card); + bo->node_card = NULL; + } + mutex_unlock(&dev->struct_mutex); + } + /* * Check whether we need to move buffer. */ if ((bo->type != drm_bo_type_fake) && (flag_diff & DRM_BO_MASK_MEM)) { - ret = drm_bo_move_buffer(bo, new_flags, no_wait); + ret = drm_bo_move_buffer(bo, new_flags, no_wait, 1); if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed moving buffer.\n"); @@ -1207,7 +1229,6 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, list_del_init(&bo->lru_card); drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); - DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } bo->flags = new_flags; @@ -1586,34 +1607,51 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) * dev->struct_sem locked. */ -static void drm_bo_force_list_clean(drm_device_t *dev, - struct list_head *head, - unsigned mem_type) +static int drm_bo_force_list_clean(drm_device_t *dev, + struct list_head *head, + unsigned mem_type, + int force_no_move, + int allow_errors) { drm_buffer_manager_t *bm = &dev->bm; - struct list_head *l; + struct list_head *list, *next, *prev; drm_buffer_object_t *entry; int ret; + int clean; - l = head->next; - while (l != head) { - entry = drm_bo_entry(l, mem_type); - + retry: + clean = 1; + list_for_each_safe(list, next, head) { + prev = list->prev; + entry = drm_bo_entry(list, mem_type); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); + mutex_lock(&dev->struct_mutex); - /* - * Expire the fence. - */ + if (prev != list->prev || next != list->next) { + mutex_unlock(&entry->mutex); + goto retry; + } + if (drm_bo_mm_node(entry, mem_type)) { + clean = 0; - if (entry->fence) { - if (bm->nice_mode) { + /* + * Expire the fence. + */ + + mutex_unlock(&dev->struct_mutex); + if (entry->fence && bm->nice_mode) { unsigned long _end = jiffies + 3*DRM_HZ; do { ret = drm_bo_wait(entry, 0, 1, 0); + if (ret && allow_errors) { + if (ret == -EINTR) + ret = -EAGAIN; + goto out_err; + } } while (ret && !time_after_eq(jiffies, _end)); - + if (entry->fence) { bm->nice_mode = 0; DRM_ERROR("Detected GPU hang or " @@ -1621,23 +1659,47 @@ static void drm_bo_force_list_clean(drm_device_t *dev, "Evicting waiting buffers\n"); } } - if (entry->fence) { - drm_fence_usage_deref_unlocked(dev, - entry->fence); + drm_fence_usage_deref_unlocked(dev, entry->fence); entry->fence = NULL; } - } - ret = drm_bo_evict(entry, mem_type, 0, 1); - if (ret) { - DRM_ERROR("Aargh. Eviction failed.\n"); + + DRM_MASK_VAL(entry->priv_flags, _DRM_BO_FLAG_UNFENCED, 0); + + if (force_no_move) { + DRM_MASK_VAL(entry->flags, DRM_BO_FLAG_NO_MOVE, 0); + } + if (entry->flags & DRM_BO_FLAG_NO_EVICT) { + DRM_ERROR("A DRM_BO_NO_EVICT buffer present at " + "cleanup. Removing flag and evicting.\n"); + entry->flags &= ~DRM_BO_FLAG_NO_EVICT; + entry->mask &= ~DRM_BO_FLAG_NO_EVICT; + } + + ret = drm_bo_evict(entry, mem_type, 1, force_no_move); + if (ret) { + if (allow_errors) { + goto out_err; + } else { + DRM_ERROR("Aargh. Eviction failed.\n"); + } + } + mutex_lock(&dev->struct_mutex); } mutex_unlock(&entry->mutex); - mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(dev, entry); - l = head->next; + if (prev != list->prev || next != list->next) { + goto retry; + } } + if (!clean) + goto retry; + return 0; + out_err: + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_unlocked(dev, entry); + mutex_lock(&dev->struct_mutex); + return ret; } int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) @@ -1660,8 +1722,21 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) ret = 0; if (mem_type > 0) { - drm_bo_force_list_clean(dev, &bm->lru[mem_type], 1); - drm_bo_force_list_clean(dev, &bm->pinned[mem_type], 1); + + /* + * Throw out unfenced buffers. + */ + + drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 1, 0); + + /* + * Throw out evicted no-move buffers. + */ + + drm_bo_force_list_clean(dev, &bm->pinned[DRM_BO_MEM_LOCAL], + mem_type, 1, 0); + drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 1, 0); + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 1, 0); if (drm_mm_clean(&bm->manager[mem_type])) { drm_mm_takedown(&bm->manager[mem_type]); @@ -1673,6 +1748,22 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) return ret; } +static int drm_bo_lock_mm(drm_device_t *dev, unsigned mem_type) +{ + int ret; + drm_buffer_manager_t *bm = &dev->bm; + + ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); + if (ret) + return ret; + ret = drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 0, 1); + if (ret) + return ret; + ret = drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 0, 1); + return ret; +} + + static int drm_bo_init_mm(drm_device_t *dev, unsigned type, unsigned long p_offset, @@ -1711,20 +1802,6 @@ static int drm_bo_init_mm(drm_device_t *dev, } -/* - * call dev->struct_mutex locked; - */ - -static void drm_bo_release_unfenced(drm_buffer_manager_t *bm) -{ - struct list_head *list, *next; - - list_for_each_safe(list, next, &bm->unfenced) { - list_del(list); - list_add_tail(list, &bm->lru[0]); - } -} - int drm_bo_driver_finish(drm_device_t *dev) { drm_buffer_manager_t *bm = &dev->bm; @@ -1736,7 +1813,6 @@ int drm_bo_driver_finish(drm_device_t *dev) if (!bm->initialized) goto out; - drm_bo_release_unfenced(bm); while(i--) { if (bm->has_type[i]) { @@ -1877,6 +1953,18 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) } bm->max_pages = arg.req.p_size; } + case mm_lock: + LOCK_TEST_WITH_RETURN(dev, filp); + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + ret = drm_bo_lock_mm(dev, arg.req.mem_type); + break; + case mm_unlock: + LOCK_TEST_WITH_RETURN(dev, filp); + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + ret = 0; + break; default: DRM_ERROR("Function not implemented yet\n"); return -EINVAL; From d515936ea7f98f6aaa9217699796beadef9d664b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:40:57 +0200 Subject: [PATCH 128/147] Add memory usage accounting to avoid DOS problems. --- linux-core/drmP.h | 60 ++++++++++++++++++++++++++++++++ linux-core/drm_agpsupport.c | 23 +++++++++---- linux-core/drm_bo.c | 10 ++++-- linux-core/drm_compat.c | 13 ++++--- linux-core/drm_drv.c | 4 ++- linux-core/drm_fence.c | 9 +++-- linux-core/drm_hashtab.c | 2 +- linux-core/drm_memory.c | 69 +++++++++++++++++++++++++++++++++++++ linux-core/drm_mm.c | 17 +++++---- linux-core/drm_object.c | 4 +-- linux-core/drm_proc.c | 14 ++++++-- linux-core/drm_ttm.c | 36 ++++++++++++------- linux-core/drm_vm.c | 6 ++-- 13 files changed, 223 insertions(+), 44 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index ff952250..e59322d0 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1129,6 +1129,14 @@ extern int drm_free_agp(DRM_AGP_MEM * handle, int pages); extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start); extern int drm_unbind_agp(DRM_AGP_MEM * handle); +extern void drm_free_memctl(size_t size); +extern int drm_alloc_memctl(size_t size); +extern void drm_query_memctl(drm_u64_t *cur_used, + drm_u64_t *low_threshold, + drm_u64_t *high_threshold); +extern void drm_init_memctl(size_t low_threshold, + size_t high_threshold); + /* Misc. IOCTL support (drm_ioctl.h) */ extern int drm_irq_by_busid(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); @@ -1527,6 +1535,58 @@ extern void *drm_alloc(size_t size, int area); extern void drm_free(void *pt, size_t size, int area); #endif +/* + * Accounting variants of standard calls. + */ + +static inline void *drm_ctl_alloc(size_t size, int area) +{ + void *ret; + if (drm_alloc_memctl(size)) + return NULL; + ret = drm_alloc(size, area); + if (!ret) + drm_free_memctl(size); + return ret; +} + +static inline void *drm_ctl_calloc(size_t nmemb, size_t size, int area) +{ + void *ret; + + if (drm_alloc_memctl(nmemb*size)) + return NULL; + ret = drm_calloc(nmemb, size, area); + if (!ret) + drm_free_memctl(nmemb*size); + return ret; +} + +static inline void drm_ctl_free(void *pt, size_t size, int area) +{ + drm_free(pt, size, area); + drm_free_memctl(size); +} + +static inline void *drm_ctl_cache_alloc(kmem_cache_t *cache, size_t size, + int flags) +{ + void *ret; + if (drm_alloc_memctl(size)) + return NULL; + ret = kmem_cache_alloc(cache, flags); + if (!ret) + drm_free_memctl(size); + return ret; +} + +static inline void drm_ctl_cache_free(kmem_cache_t *cache, size_t size, + void *obj) +{ + kmem_cache_free(cache, obj); + drm_free_memctl(size); +} + /*@}*/ #endif /* __KERNEL__ */ diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index d9fd9c92..ffbe04f8 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -570,14 +570,19 @@ static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, struct page **cur_page, **last_page = pages + num_pages; DRM_AGP_MEM *mem; + if (drm_alloc_memctl(num_pages * sizeof(void *))) + return -1; + 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->alloc_type); #else mem = drm_agp_allocate_memory(agp_priv->bridge, num_pages, agp_priv->alloc_type); #endif - if (!mem) + if (!mem) { + drm_free_memctl(num_pages *sizeof(void *)); return -1; + } DRM_DEBUG("Current page count is %ld\n", (long) mem->page_count); mem->page_count = 0; @@ -626,8 +631,10 @@ static void drm_agp_clear_ttm(drm_ttm_backend_t *backend) { DRM_DEBUG("drm_agp_clear_ttm\n"); if (mem) { + unsigned long num_pages = mem->page_count; backend->unbind(backend); agp_free_memory(mem); + drm_free_memctl(num_pages *sizeof(void *)); } agp_priv->mem = NULL; @@ -644,10 +651,12 @@ static void drm_agp_destroy_ttm(drm_ttm_backend_t *backend) { if (agp_priv->mem) { backend->clear(backend); } - drm_free(agp_priv, sizeof(*agp_priv), DRM_MEM_MAPPINGS); + drm_ctl_free(agp_priv, sizeof(*agp_priv), DRM_MEM_MAPPINGS); + backend->private = NULL; + } + if (backend->flags & DRM_BE_FLAG_NEEDS_FREE) { + drm_ctl_free(backend, sizeof(*backend), DRM_MEM_MAPPINGS); } - if (backend->flags & DRM_BE_FLAG_NEEDS_FREE) - drm_free(backend, sizeof(*backend), DRM_MEM_MAPPINGS); } } @@ -662,15 +671,15 @@ drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev, drm_agp_ttm_priv *agp_priv; agp_be = (backend != NULL) ? backend: - drm_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); + drm_ctl_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); if (!agp_be) return NULL; - agp_priv = drm_calloc(1, sizeof(agp_priv), DRM_MEM_MAPPINGS); + agp_priv = drm_ctl_calloc(1, sizeof(*agp_priv), DRM_MEM_MAPPINGS); if (!agp_priv) { - drm_free(agp_be, sizeof(*agp_be), DRM_MEM_MAPPINGS); + drm_ctl_free(agp_be, sizeof(*agp_be), DRM_MEM_MAPPINGS); return NULL; } diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f671a046..fb900982 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -237,7 +237,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_ttm_object_deref_locked(dev, bo->ttm_object); } atomic_dec(&bm->count); - drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } static void drm_bo_delayed_delete(drm_device_t * dev) @@ -1390,7 +1390,7 @@ int drm_buffer_object_create(drm_file_t * priv, return -EINVAL; } - bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); + bo = drm_ctl_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); if (!bo) return -ENOMEM; @@ -1752,6 +1752,12 @@ static int drm_bo_lock_mm(drm_device_t *dev, unsigned mem_type) { int ret; drm_buffer_manager_t *bm = &dev->bm; + + if (mem_type == 0 || mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory manager memory type %u,\n", + mem_type); + return -EINVAL; + } ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); if (ret) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 5287614d..4a035f49 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -239,8 +239,13 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, page = NOPAGE_OOM; goto out; } + if (drm_alloc_memctl(PAGE_SIZE)) { + page = NOPAGE_OOM; + goto out; + } page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); if (!page) { + drm_free_memctl(PAGE_SIZE); page = NOPAGE_OOM; goto out; } @@ -284,7 +289,7 @@ int drm_ttm_add_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) vma->vm_private_data; struct mm_struct *mm = vma->vm_mm; - v_entry = drm_alloc(sizeof(*v_entry), DRM_MEM_TTM); + v_entry = drm_ctl_alloc(sizeof(*v_entry), DRM_MEM_TTM); if (!v_entry) { DRM_ERROR("Allocation of vma pointer entry failed\n"); return -ENOMEM; @@ -300,7 +305,7 @@ int drm_ttm_add_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) } else if ((unsigned long)mm < (unsigned long)entry->mm) ; } - n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_TTM); + n_entry = drm_ctl_alloc(sizeof(*n_entry), DRM_MEM_TTM); if (!n_entry) { DRM_ERROR("Allocation of process mm pointer entry failed\n"); return -ENOMEM; @@ -325,7 +330,7 @@ void drm_ttm_delete_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) if (v_entry->vma == vma) { found = 1; list_del(&v_entry->head); - drm_free(v_entry, sizeof(*v_entry), DRM_MEM_TTM); + drm_ctl_free(v_entry, sizeof(*v_entry), DRM_MEM_TTM); break; } } @@ -336,7 +341,7 @@ void drm_ttm_delete_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) if (atomic_add_negative(-1, &entry->refcount)) { list_del(&entry->head); BUG_ON(entry->locked); - drm_free(entry, sizeof(*entry), DRM_MEM_TTM); + drm_ctl_free(entry, sizeof(*entry), DRM_MEM_TTM); } return; } diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 43b4f8d4..e1ee35c1 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -130,7 +130,6 @@ static drm_ioctl_desc_t drm_ioctls[] = { #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) - /** * Take down the DRM device. * @@ -502,7 +501,10 @@ static void drm_free_memory_caches(void ) static int __init drm_core_init(void) { int ret; + struct sysinfo si; + si_meminfo(&si); + drm_init_memctl(si.totalram/2, si.totalram*3/4); ret = drm_create_memory_caches(); if (ret) goto err_p1; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 3e20f129..c9a2a062 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -118,7 +118,8 @@ void drm_fence_usage_deref_locked(drm_device_t * dev, DRM_DEBUG("Destroyed a fence object 0x%08lx\n", fence->base.hash.key); atomic_dec(&fm->count); - kmem_cache_free(drm_cache.fence_object, fence); + drm_ctl_cache_free(drm_cache.fence_object, sizeof(*fence), + fence); } } @@ -132,7 +133,8 @@ void drm_fence_usage_deref_unlocked(drm_device_t * dev, if (atomic_read(&fence->usage) == 0) { drm_fence_unring(dev, &fence->ring); atomic_dec(&fm->count); - kmem_cache_free(drm_cache.fence_object, fence); + drm_ctl_cache_free(drm_cache.fence_object, + sizeof(*fence), fence); } mutex_unlock(&dev->struct_mutex); } @@ -439,7 +441,8 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, int ret; drm_fence_manager_t *fm = &dev->fm; - fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); + fence = drm_ctl_cache_alloc(drm_cache.fence_object, + sizeof(*fence), GFP_KERNEL); if (!fence) return -ENOMEM; ret = drm_fence_object_init(dev, type, flags, fence); diff --git a/linux-core/drm_hashtab.c b/linux-core/drm_hashtab.c index 63ee5f91..3a2aa80e 100644 --- a/linux-core/drm_hashtab.c +++ b/linux-core/drm_hashtab.c @@ -44,7 +44,7 @@ int drm_ht_create(drm_open_hash_t *ht, unsigned int order) ht->order = order; ht->fill = 0; ht->table = NULL; - ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > 4*PAGE_SIZE); + ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE); if (!ht->use_vmalloc) { ht->table = drm_calloc(ht->size, sizeof(*ht->table), DRM_MEM_HASHTAB); diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c index 9125cd47..ba65136a 100644 --- a/linux-core/drm_memory.c +++ b/linux-core/drm_memory.c @@ -37,6 +37,75 @@ #include #include "drmP.h" +static struct { + spinlock_t lock; + drm_u64_t cur_used; + drm_u64_t low_threshold; + drm_u64_t high_threshold; +} drm_memctl = { + .lock = SPIN_LOCK_UNLOCKED +}; + +static inline size_t drm_size_align(size_t size) { + + register size_t tmpSize = 4; + if (size > PAGE_SIZE) + return PAGE_ALIGN(size); + + while(tmpSize < size) + tmpSize <<= 1; + + return (size_t) tmpSize; +} + +int drm_alloc_memctl(size_t size) +{ + int ret; + unsigned long a_size = drm_size_align(size); + + spin_lock(&drm_memctl.lock); + ret = ((drm_memctl.cur_used + a_size) > drm_memctl.high_threshold) ? + -ENOMEM : 0; + if (!ret) + drm_memctl.cur_used += a_size; + spin_unlock(&drm_memctl.lock); + return ret; +} +EXPORT_SYMBOL(drm_alloc_memctl); + +void drm_free_memctl(size_t size) +{ + unsigned long a_size = drm_size_align(size); + + spin_lock(&drm_memctl.lock); + drm_memctl.cur_used -= a_size; + spin_unlock(&drm_memctl.lock); +} +EXPORT_SYMBOL(drm_free_memctl); + +void drm_query_memctl(drm_u64_t *cur_used, + drm_u64_t *low_threshold, + drm_u64_t *high_threshold) +{ + spin_lock(&drm_memctl.lock); + *cur_used = drm_memctl.cur_used; + *low_threshold = drm_memctl.low_threshold; + *high_threshold = drm_memctl.high_threshold; + spin_unlock(&drm_memctl.lock); +} +EXPORT_SYMBOL(drm_query_memctl); + +void drm_init_memctl(size_t p_low_threshold, + size_t p_high_threshold) +{ + spin_lock(&drm_memctl.lock); + drm_memctl.cur_used = 0; + drm_memctl.low_threshold = p_low_threshold << PAGE_SHIFT; + drm_memctl.high_threshold = p_high_threshold << PAGE_SHIFT; + spin_unlock(&drm_memctl.lock); +} + + #ifndef DEBUG_MEMORY /** No-op. */ diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index ef8bd7e9..6ab13af3 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -59,8 +59,9 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, return parent; } else { - child = (drm_mm_node_t *) kmem_cache_alloc(drm_cache.mm, - GFP_KERNEL); + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), + GFP_KERNEL); if (!child) return NULL; @@ -110,8 +111,9 @@ void drm_mm_put_block(drm_mm_node_t * cur) prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - kmem_cache_free(drm_cache.mm, next_node); - + drm_ctl_cache_free(drm_cache.mm, + sizeof(*next_node), + next_node); } else { next_node->size += cur->size; next_node->start = cur->start; @@ -124,7 +126,7 @@ void drm_mm_put_block(drm_mm_node_t * cur) list_add(&cur->fl_entry, &list_root->fl_entry); } else { list_del(&cur->ml_entry); - kmem_cache_free(drm_cache.mm, cur); + drm_ctl_cache_free(drm_cache.mm, sizeof(*cur), cur); } } @@ -174,7 +176,8 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) kmem_cache_alloc(drm_cache.mm, GFP_KERNEL); + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), GFP_KERNEL); if (!child) return -ENOMEM; @@ -210,7 +213,7 @@ void drm_mm_takedown(drm_mm_t * mm) list_del(&entry->fl_entry); list_del(&entry->ml_entry); - kmem_cache_free(drm_cache.mm, entry); + drm_ctl_cache_free(drm_cache.mm, sizeof(*entry), entry); } EXPORT_SYMBOL(drm_mm_takedown); diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c index e1b79101..0157329c 100644 --- a/linux-core/drm_object.c +++ b/linux-core/drm_object.c @@ -152,7 +152,7 @@ int drm_add_ref_object(drm_file_t * priv, drm_user_object_t * referenced_object, ref_action); } - item = drm_calloc(1, sizeof(*item), DRM_MEM_OBJECTS); + item = drm_ctl_calloc(1, sizeof(*item), DRM_MEM_OBJECTS); if (item == NULL) { DRM_ERROR("Could not allocate reference object\n"); return -ENOMEM; @@ -218,7 +218,7 @@ void drm_remove_ref_object(drm_file_t * priv, drm_ref_object_t * item) 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); + drm_ctl_free(item, sizeof(*item), DRM_MEM_OBJECTS); } switch (unref_action) { diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index b0b1748a..4bb71ca7 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -439,6 +439,10 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request, int len = 0; drm_buffer_manager_t *bm = &dev->bm; drm_fence_manager_t *fm = &dev->fm; + drm_u64_t used_mem; + drm_u64_t low_mem; + drm_u64_t high_mem; + if (offset > DRM_PROC_LIMIT) { *eof = 1; @@ -459,12 +463,18 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request, DRM_PROC_PRINT("Number of active buffer objects: %d.\n\n", atomic_read(&bm->count)); DRM_PROC_PRINT("Number of locked GATT pages: %lu.\n", bm->cur_pages); - DRM_PROC_PRINT("Max allowed number of locked GATT pages %lu\n", - bm->max_pages); } else { DRM_PROC_PRINT("Buffer objects are not supported by this driver.\n\n"); } + drm_query_memctl(&used_mem, &low_mem, &high_mem); + + DRM_PROC_PRINT("Used object memory is %lu pages.\n", + (unsigned long) (used_mem >> PAGE_SHIFT)); + DRM_PROC_PRINT("Soft object memory usage threshold is %lu pages.\n", + (unsigned long) (low_mem >> PAGE_SHIFT)); + DRM_PROC_PRINT("Hard object memory usage threshold is %lu pages.\n", + (unsigned long) (high_mem >> PAGE_SHIFT)); DRM_PROC_PRINT("\n"); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 0f9cb11f..3e66319a 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -37,12 +37,17 @@ static void *ttm_alloc(unsigned long size, int type) { void *ret = NULL; - if (size <= 4*PAGE_SIZE) { + if (drm_alloc_memctl(size)) + return NULL; + if (size <= PAGE_SIZE) { ret = drm_alloc(size, type); } if (!ret) { ret = vmalloc(size); } + if (!ret) { + drm_free_memctl(size); + } return ret; } @@ -55,6 +60,7 @@ static void ttm_free(void *pointer, unsigned long size, int type) } else { drm_free(pointer, size, type); } + drm_free_memctl(size); } /* @@ -174,6 +180,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) */ drm_free_gatt_pages(*cur_page, 0); + drm_free_memctl(PAGE_SIZE); --bm->cur_pages; } } @@ -182,8 +189,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) ttm->pages = NULL; } - drm_free(ttm, sizeof(*ttm), DRM_MEM_TTM); - + drm_ctl_free(ttm, sizeof(*ttm), DRM_MEM_TTM); return 0; } @@ -203,13 +209,14 @@ static int drm_ttm_populate(drm_ttm_t *ttm) for (i=0; inum_pages; ++i) { page = ttm->pages[i]; if (!page) { - if (bm->cur_pages >= bm->max_pages) { - DRM_ERROR("Maximum locked page count exceeded\n"); + if (drm_alloc_memctl(PAGE_SIZE)) { return -ENOMEM; } page = drm_alloc_gatt_pages(0); - if (!page) + if (!page) { + drm_free_memctl(PAGE_SIZE); return -ENOMEM; + } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) SetPageLocked(page); #else @@ -238,7 +245,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) if (!bo_driver) return NULL; - ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_TTM); + ttm = drm_ctl_calloc(1, sizeof(*ttm), DRM_MEM_TTM); if (!ttm) return NULL; @@ -254,6 +261,11 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; ttm->page_flags = 0; + + /* + * Account also for AGP module memory usage. + */ + ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), DRM_MEM_TTM); if (!ttm->pages) { @@ -403,14 +415,14 @@ static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) 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); + drm_ctl_free(map, sizeof(*map), DRM_MEM_TTM); } } else { - drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_ctl_free(map, sizeof(*map), DRM_MEM_TTM); } } - drm_free(object, sizeof(*object), DRM_MEM_TTM); + drm_ctl_free(object, sizeof(*object), DRM_MEM_TTM); } void drm_ttm_object_deref_locked(drm_device_t * dev, drm_ttm_object_t * to) @@ -444,13 +456,13 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, drm_local_map_t *map; drm_ttm_t *ttm; - object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); + object = drm_ctl_calloc(1, sizeof(*object), DRM_MEM_TTM); if (!object) return -ENOMEM; object->flags = flags; list = &object->map_list; - list->map = drm_calloc(1, sizeof(*map), DRM_MEM_TTM); + list->map = drm_ctl_calloc(1, sizeof(*map), DRM_MEM_TTM); if (!list->map) { drm_ttm_object_remove(dev, object); return -ENOMEM; diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 091b43f7..1654236d 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -202,13 +202,13 @@ struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, page = ttm->pages[page_offset]; if (!page) { - if (bm->cur_pages >= bm->max_pages) { - DRM_ERROR("Maximum locked page count exceeded\n"); + if (drm_alloc_memctl(PAGE_SIZE)) { data->type = VM_FAULT_OOM; goto out; } page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); if (!page) { + drm_free_memctl(PAGE_SIZE); data->type = VM_FAULT_OOM; goto out; } @@ -654,7 +654,7 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma) if (ttm->destroy) { ret = drm_destroy_ttm(ttm); BUG_ON(ret); - drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_ctl_free(map, sizeof(*map), DRM_MEM_TTM); } } mutex_unlock(&dev->struct_mutex); From f22f89e6b3c970a29197d3a53c170fb7d0340cbe Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:52:34 +0200 Subject: [PATCH 129/147] Add vma list memory usage to memory accounting. Use byte unit for /proc printout of memory usage for small sizes to be able to detect memory allocation bugs more easily. --- linux-core/drmP.h | 1 - linux-core/drm_drv.c | 12 +----------- linux-core/drm_proc.c | 9 +++++++-- linux-core/drm_stub.c | 3 +-- linux-core/drm_vm.c | 6 +++--- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index e59322d0..b10e9881 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -763,7 +763,6 @@ typedef struct drm_cache { kmem_cache_t *mm; kmem_cache_t *fence_object; - kmem_cache_t *ref_object; } drm_cache_t; diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index e1ee35c1..75c89c1c 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -228,7 +228,7 @@ int drm_lastclose(drm_device_t * dev) if (dev->vmalist) { for (vma = dev->vmalist; vma; vma = vma_next) { vma_next = vma->next; - drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS); } dev->vmalist = NULL; } @@ -464,14 +464,6 @@ static int drm_create_memory_caches(void) if (!drm_cache.fence_object) return -ENOMEM; - drm_cache.ref_object= kmem_cache_create("drm_ref_object_t", - sizeof(drm_ref_object_t), - 0, - SLAB_HWCACHE_ALIGN, - NULL,NULL); - if (!drm_cache.ref_object) - return -ENOMEM; - return 0; } @@ -489,8 +481,6 @@ static void drm_free_mem_cache(kmem_cache_t *cache, static void drm_free_memory_caches(void ) { - drm_free_mem_cache(drm_cache.ref_object, "ref object"); - drm_cache.ref_object = NULL; drm_free_mem_cache(drm_cache.fence_object, "fence object"); drm_cache.fence_object = NULL; drm_free_mem_cache(drm_cache.mm, "memory manager block"); diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 4bb71ca7..863cacfc 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -469,8 +469,13 @@ static int drm__objects_info(char *buf, char **start, off_t offset, int request, drm_query_memctl(&used_mem, &low_mem, &high_mem); - DRM_PROC_PRINT("Used object memory is %lu pages.\n", - (unsigned long) (used_mem >> PAGE_SHIFT)); + if (used_mem > 16*PAGE_SIZE) { + DRM_PROC_PRINT("Used object memory is %lu pages.\n", + (unsigned long) (used_mem >> PAGE_SHIFT)); + } else { + DRM_PROC_PRINT("Used object memory is %lu bytes.\n", + (unsigned long) used_mem); + } DRM_PROC_PRINT("Soft object memory usage threshold is %lu pages.\n", (unsigned long) (low_mem >> PAGE_SHIFT)); DRM_PROC_PRINT("Hard object memory usage threshold is %lu pages.\n", diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 66310560..8413fb4f 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -56,8 +56,7 @@ struct proc_dir_entry *drm_proc_root; drm_cache_t drm_cache = { .mm = NULL, - .fence_object = NULL, - .ref_object = NULL + .fence_object = NULL }; static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 1654236d..aa112751 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -315,7 +315,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) } else { dev->vmalist = pt->next; } - drm_free(pt, sizeof(*pt), DRM_MEM_VMAS); + drm_ctl_free(pt, sizeof(*pt), DRM_MEM_VMAS); } else { prev = pt; } @@ -567,7 +567,7 @@ static void drm_vm_open(struct vm_area_struct *vma) vma->vm_start, vma->vm_end - vma->vm_start); atomic_inc(&dev->vma_count); - vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); + vma_entry = drm_ctl_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); if (vma_entry) { mutex_lock(&dev->struct_mutex); vma_entry->vma = vma; @@ -627,7 +627,7 @@ static void drm_vm_close(struct vm_area_struct *vma) } else { dev->vmalist = pt->next; } - drm_free(pt, sizeof(*pt), DRM_MEM_VMAS); + drm_ctl_free(pt, sizeof(*pt), DRM_MEM_VMAS); break; } } From 89b944179856fadf8667587eff142129c2c6b826 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:57:06 +0200 Subject: [PATCH 130/147] Lindent. --- linux-core/drm_bo.c | 251 ++++++++++++++++++++------------------- linux-core/drm_fence.c | 40 +++---- linux-core/drm_hashtab.c | 38 +++--- linux-core/drm_mm.c | 19 ++- linux-core/drm_ttm.c | 53 ++++----- linux-core/drm_ttm.h | 22 ++-- linux-core/i915_buffer.c | 13 +- linux-core/i915_fence.c | 15 ++- 8 files changed, 219 insertions(+), 232 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index fb900982..e8e8a274 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -67,7 +67,7 @@ static inline uint32_t drm_bo_type_flags(unsigned type) static inline drm_buffer_object_t *drm_bo_entry(struct list_head *list, unsigned type) { - switch(type) { + switch (type) { case DRM_BO_MEM_LOCAL: case DRM_BO_MEM_TT: return list_entry(list, drm_buffer_object_t, lru_ttm); @@ -80,10 +80,10 @@ static inline drm_buffer_object_t *drm_bo_entry(struct list_head *list, return NULL; } -static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t *bo, +static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t * bo, unsigned type) { - switch(type) { + switch (type) { case DRM_BO_MEM_LOCAL: case DRM_BO_MEM_TT: return bo->node_ttm; @@ -95,29 +95,38 @@ static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t *bo, } return NULL; } - + /* * bo locked. dev->struct_mutex locked. */ -static void drm_bo_add_to_lru(drm_buffer_object_t *buf, - drm_buffer_manager_t *bm) +static void drm_bo_add_to_lru(drm_buffer_object_t * buf, + drm_buffer_manager_t * bm) { struct list_head *list; unsigned mem_type; if (buf->flags & DRM_BO_FLAG_MEM_TT) { mem_type = DRM_BO_MEM_TT; - list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list = + (buf-> + flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? + &bm->pinned[mem_type] : &bm->lru[mem_type]; list_add_tail(&buf->lru_ttm, list); } else { mem_type = DRM_BO_MEM_LOCAL; - list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list = + (buf-> + flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? + &bm->pinned[mem_type] : &bm->lru[mem_type]; list_add_tail(&buf->lru_ttm, list); } if (buf->flags & DRM_BO_FLAG_MEM_VRAM) { mem_type = DRM_BO_MEM_VRAM; - list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list = + (buf-> + flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? + &bm->pinned[mem_type] : &bm->lru[mem_type]; list_add_tail(&buf->lru_card, list); } } @@ -145,9 +154,8 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict, schedule(); return ret; } - - if (!(buf->flags & DRM_BO_FLAG_NO_MOVE) || - force_no_move) { + + if (!(buf->flags & DRM_BO_FLAG_NO_MOVE) || force_no_move) { drm_mm_put_block(buf->node_ttm); buf->node_ttm = NULL; } @@ -169,14 +177,13 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); /* * Somone might try to access us through the still active BM lists. */ - if (atomic_read(&bo->usage) != 0) + if (atomic_read(&bo->usage) != 0) return; if (!list_empty(&bo->ddestroy)) return; @@ -209,7 +216,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) /* * This temporarily unlocks struct_mutex. */ - + do { ret = drm_unbind_ttm(bo->ttm); if (ret == -EAGAIN) { @@ -224,7 +231,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) "Bad. Continuing anyway\n"); } } - + if (bo->node_ttm) { drm_mm_put_block(bo->node_ttm); bo->node_ttm = NULL; @@ -249,8 +256,8 @@ static void drm_bo_delayed_delete(drm_device_t * dev) drm_fence_object_t *fence; mutex_lock(&dev->struct_mutex); - if (!bm->initialized) - goto out; + if (!bm->initialized) + goto out; list = bm->ddestroy.next; list_for_each_safe(list, next, &bm->ddestroy) { @@ -264,7 +271,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) if (atomic_read(&entry->usage) != 0) continue; - + /* * Since we're the only users, No need to take the * bo->mutex to watch the fence. @@ -284,10 +291,10 @@ static void drm_bo_delayed_delete(drm_device_t * dev) * drm_bo_destroy_locked temporarily releases the * struct_mutex; */ - - nentry = NULL; + + nentry = NULL; if (next != &bm->ddestroy) { - nentry = list_entry(next, drm_buffer_object_t, + nentry = list_entry(next, drm_buffer_object_t, ddestroy); atomic_inc(&nentry->usage); } @@ -296,13 +303,12 @@ static void drm_bo_delayed_delete(drm_device_t * dev) drm_bo_destroy_locked(dev, entry); if (next != &bm->ddestroy) atomic_dec(&nentry->usage); - } + } } - out: + out: mutex_unlock(&dev->struct_mutex); } - static void drm_bo_delayed_workqueue(void *data) { drm_device_t *dev = (drm_device_t *) data; @@ -403,8 +409,8 @@ int drm_fence_buffer_objects(drm_file_t * priv, } } else { mutex_unlock(&dev->struct_mutex); - ret = drm_fence_object_create(dev, fence_type, - fence_flags | DRM_FENCE_FLAG_EMIT, + ret = drm_fence_object_create(dev, fence_type, + fence_flags | DRM_FENCE_FLAG_EMIT, &fence); mutex_lock(&dev->struct_mutex); if (ret) @@ -470,9 +476,9 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, ret = drm_fence_object_wait(dev, fence, lazy, ignore_signals, bo->fence_type); - if (ret) - return ret; - + if (ret) + return ret; + drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -484,7 +490,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, * bo->mutex locked */ -static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, +static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, int no_wait, int force_no_move) { int ret = 0; @@ -495,7 +501,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, * Someone might have modified the buffer before we took the buffer mutex. */ - if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) + if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) goto out; if (!(bo->flags & drm_bo_type_flags(mem_type))) goto out; @@ -531,7 +537,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - out: + out: return ret; } @@ -539,7 +545,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, * buf->mutex locked. */ -int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, +int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, int no_wait) { drm_device_t *dev = buf->dev; @@ -601,7 +607,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) drm_ttm_backend_t *be; int ret; - if (!(bo->node_ttm && (bo->flags & DRM_BO_FLAG_NO_MOVE))) { + if (!(bo->node_ttm && (bo->flags & DRM_BO_FLAG_NO_MOVE))) { BUG_ON(bo->node_ttm); ret = drm_bo_alloc_space(bo, DRM_BO_MEM_TT, no_wait); if (ret) @@ -653,18 +659,19 @@ static int drm_bo_new_flags(drm_device_t * dev, * First adjust the mask to take away nonexistant memory types. */ - for (i=0; iuse_type[i]) new_mask &= ~drm_bo_type_flags(i); } - if ((new_mask & DRM_BO_FLAG_NO_EVICT ) && !DRM_SUSER(DRM_CURPROC)) { - DRM_ERROR("DRM_BO_FLAG_NO_EVICT is only available to priviliged " - "processes\n"); + if ((new_mask & DRM_BO_FLAG_NO_EVICT) && !DRM_SUSER(DRM_CURPROC)) { + DRM_ERROR + ("DRM_BO_FLAG_NO_EVICT is only available to priviliged " + "processes\n"); return -EPERM; } if (new_mask & DRM_BO_FLAG_BIND_CACHED) { - if (((new_mask & DRM_BO_FLAG_MEM_TT) && + if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached[DRM_BO_MEM_TT]) && ((new_mask & DRM_BO_FLAG_MEM_VRAM) && !driver->cached[DRM_BO_MEM_VRAM])) { @@ -831,12 +838,12 @@ static int drm_bo_read_cached(drm_buffer_object_t * bo) int ret = 0; BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - if (bo->node_card) + if (bo->node_card) ret = drm_bo_evict(bo, DRM_BO_MEM_VRAM, 1, 0); if (ret) return ret; if (bo->node_ttm) - ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1, 0); + ret = drm_bo_evict(bo, DRM_BO_MEM_TT, 1, 0); return ret; } @@ -1155,18 +1162,18 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } - + /* * Move out if we need to change caching policy. */ - if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && + if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && !(bo->flags & DRM_BO_FLAG_MEM_LOCAL)) { if (bo->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) { DRM_ERROR("Cannot change caching policy of " "pinned buffer.\n"); return -EINVAL; - } + } ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait, 0); if (ret) { if (ret != -EAGAIN) @@ -1182,7 +1189,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * release reserved manager regions. */ - if ((flag_diff & DRM_BO_FLAG_NO_MOVE) && + if ((flag_diff & DRM_BO_FLAG_NO_MOVE) && !(new_flags & DRM_BO_FLAG_NO_MOVE)) { mutex_lock(&dev->struct_mutex); if (bo->node_ttm) { @@ -1434,10 +1441,10 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_unlock(&bo->mutex); *buf_obj = bo; return 0; - - out_err: + + out_err: mutex_unlock(&bo->mutex); - drm_bo_usage_deref_unlocked(dev, bo); + drm_bo_usage_deref_unlocked(dev, bo); return ret; } @@ -1607,11 +1614,10 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) * dev->struct_sem locked. */ -static int drm_bo_force_list_clean(drm_device_t *dev, - struct list_head *head, +static int drm_bo_force_list_clean(drm_device_t * dev, + struct list_head *head, unsigned mem_type, - int force_no_move, - int allow_errors) + int force_no_move, int allow_errors) { drm_buffer_manager_t *bm = &dev->bm; struct list_head *list, *next, *prev; @@ -1619,11 +1625,11 @@ static int drm_bo_force_list_clean(drm_device_t *dev, int ret; int clean; - retry: + retry: clean = 1; list_for_each_safe(list, next, head) { prev = list->prev; - entry = drm_bo_entry(list, mem_type); + entry = drm_bo_entry(list, mem_type); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); @@ -1639,10 +1645,10 @@ static int drm_bo_force_list_clean(drm_device_t *dev, /* * Expire the fence. */ - + mutex_unlock(&dev->struct_mutex); if (entry->fence && bm->nice_mode) { - unsigned long _end = jiffies + 3*DRM_HZ; + unsigned long _end = jiffies + 3 * DRM_HZ; do { ret = drm_bo_wait(entry, 0, 1, 0); if (ret && allow_errors) { @@ -1651,7 +1657,7 @@ static int drm_bo_force_list_clean(drm_device_t *dev, goto out_err; } } while (ret && !time_after_eq(jiffies, _end)); - + if (entry->fence) { bm->nice_mode = 0; DRM_ERROR("Detected GPU hang or " @@ -1660,14 +1666,17 @@ static int drm_bo_force_list_clean(drm_device_t *dev, } } if (entry->fence) { - drm_fence_usage_deref_unlocked(dev, entry->fence); + drm_fence_usage_deref_unlocked(dev, + entry->fence); entry->fence = NULL; } - DRM_MASK_VAL(entry->priv_flags, _DRM_BO_FLAG_UNFENCED, 0); + DRM_MASK_VAL(entry->priv_flags, _DRM_BO_FLAG_UNFENCED, + 0); if (force_no_move) { - DRM_MASK_VAL(entry->flags, DRM_BO_FLAG_NO_MOVE, 0); + DRM_MASK_VAL(entry->flags, DRM_BO_FLAG_NO_MOVE, + 0); } if (entry->flags & DRM_BO_FLAG_NO_EVICT) { DRM_ERROR("A DRM_BO_NO_EVICT buffer present at " @@ -1690,12 +1699,12 @@ static int drm_bo_force_list_clean(drm_device_t *dev, drm_bo_usage_deref_locked(dev, entry); if (prev != list->prev || next != list->next) { goto retry; - } + } } if (!clean) goto retry; return 0; - out_err: + out_err: mutex_unlock(&entry->mutex); drm_bo_usage_deref_unlocked(dev, entry); mutex_lock(&dev->struct_mutex); @@ -1715,7 +1724,7 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) if (!bm->has_type[mem_type]) { DRM_ERROR("Trying to take down uninitialized " "memory manager type\n"); - return ret; + return ret; } bm->use_type[mem_type] = 0; bm->has_type[mem_type] = 0; @@ -1733,10 +1742,12 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) * Throw out evicted no-move buffers. */ - drm_bo_force_list_clean(dev, &bm->pinned[DRM_BO_MEM_LOCAL], + drm_bo_force_list_clean(dev, &bm->pinned[DRM_BO_MEM_LOCAL], mem_type, 1, 0); - drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 1, 0); - drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 1, 0); + drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 1, + 0); + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 1, + 0); if (drm_mm_clean(&bm->manager[mem_type])) { drm_mm_takedown(&bm->manager[mem_type]); @@ -1748,32 +1759,30 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) return ret; } -static int drm_bo_lock_mm(drm_device_t *dev, unsigned mem_type) +static int drm_bo_lock_mm(drm_device_t * dev, unsigned mem_type) { int ret; drm_buffer_manager_t *bm = &dev->bm; if (mem_type == 0 || mem_type >= DRM_BO_MEM_TYPES) { - DRM_ERROR("Illegal memory manager memory type %u,\n", - mem_type); + DRM_ERROR("Illegal memory manager memory type %u,\n", mem_type); return -EINVAL; } - - ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); - if (ret) - return ret; - ret = drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 0, 1); + + ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); if (ret) return ret; - ret = drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 0, 1); + ret = drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 0, 1); + if (ret) + return ret; + ret = + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 0, 1); return ret; } - -static int drm_bo_init_mm(drm_device_t *dev, +static int drm_bo_init_mm(drm_device_t * dev, unsigned type, - unsigned long p_offset, - unsigned long p_size) + unsigned long p_offset, unsigned long p_size) { drm_buffer_manager_t *bm = &dev->bm; int ret = -EINVAL; @@ -1794,7 +1803,7 @@ static int drm_bo_init_mm(drm_device_t *dev, DRM_ERROR("Zero size memory manager type %d\n", type); return ret; } - ret = drm_mm_init(&bm->manager[type],p_offset, p_size); + ret = drm_mm_init(&bm->manager[type], p_offset, p_size); if (ret) return ret; } @@ -1807,8 +1816,7 @@ static int drm_bo_init_mm(drm_device_t *dev, return 0; } - -int drm_bo_driver_finish(drm_device_t *dev) +int drm_bo_driver_finish(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; int ret = 0; @@ -1817,10 +1825,10 @@ int drm_bo_driver_finish(drm_device_t *dev) mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); - if (!bm->initialized) + if (!bm->initialized) goto out; - while(i--) { + while (i--) { if (bm->has_type[i]) { bm->use_type[i] = 0; if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) { @@ -1840,25 +1848,24 @@ int drm_bo_driver_finish(drm_device_t *dev) flush_scheduled_work(); } mutex_lock(&dev->struct_mutex); - out: + out: mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->bm.init_mutex); return ret; } - -int drm_bo_driver_init(drm_device_t *dev) +int drm_bo_driver_init(drm_device_t * dev) { drm_bo_driver_t *driver = dev->driver->bo_driver; drm_buffer_manager_t *bm = &dev->bm; int ret = -EINVAL; struct sysinfo si; - + mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); if (!driver) goto out_unlock; - + /* * Initialize the system memory buffer type. * Other types need to be driver / IOCTL initialized. @@ -1876,14 +1883,14 @@ int drm_bo_driver_init(drm_device_t *dev) si_meminfo(&si); bm->max_pages = si.totalram >> 1; INIT_LIST_HEAD(&bm->unfenced); - INIT_LIST_HEAD(&bm->ddestroy); - out_unlock: + INIT_LIST_HEAD(&bm->ddestroy); + out_unlock: mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->bm.init_mutex); return ret; } -EXPORT_SYMBOL(drm_bo_driver_init); +EXPORT_SYMBOL(drm_bo_driver_init); int drm_mm_init_ioctl(DRM_IOCTL_ARGS) { @@ -1911,15 +1918,15 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) break; } if (arg.req.mem_type == 0) { - DRM_ERROR("System memory buffers already initialized.\n"); + DRM_ERROR + ("System memory buffers already initialized.\n"); break; } - ret = drm_bo_init_mm(dev, arg.req.mem_type, - arg.req.p_offset, - arg.req.p_size); + ret = drm_bo_init_mm(dev, arg.req.mem_type, + arg.req.p_offset, arg.req.p_size); break; case mm_takedown: - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); ret = -EINVAL; @@ -1937,36 +1944,38 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) "Delaying takedown\n", arg.req.mem_type); } break; - case mm_set_max_pages: { - struct sysinfo si; - mutex_lock(&dev->bm.init_mutex); - mutex_lock(&dev->struct_mutex); - if (arg.req.p_size < bm->cur_pages) { - DRM_ERROR("Cannot currently decrease max number of " - "locked pages below the number currently " - "locked.\n"); - ret = -EINVAL; - break; + case mm_set_max_pages:{ + struct sysinfo si; + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + if (arg.req.p_size < bm->cur_pages) { + DRM_ERROR + ("Cannot currently decrease max number of " + "locked pages below the number currently " + "locked.\n"); + ret = -EINVAL; + break; + } + si_meminfo(&si); + if (arg.req.p_size > si.totalram) { + DRM_ERROR + ("Cannot set max number of locked pages " + "to %lu since the total number of RAM pages " + "is %lu.\n", (unsigned long)arg.req.p_size, + (unsigned long)si.totalram); + ret = -EINVAL; + break; + } + bm->max_pages = arg.req.p_size; } - si_meminfo(&si); - if (arg.req.p_size > si.totalram) { - DRM_ERROR("Cannot set max number of locked pages " - "to %lu since the total number of RAM pages " - "is %lu.\n", (unsigned long) arg.req.p_size, - (unsigned long) si.totalram); - ret = -EINVAL; - break; - } - bm->max_pages = arg.req.p_size; - } case mm_lock: - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); ret = drm_bo_lock_mm(dev, arg.req.mem_type); break; case mm_unlock: - LOCK_TEST_WITH_RETURN(dev, filp); + LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); ret = 0; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index c9a2a062..aa382046 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -31,7 +31,6 @@ #include "drmP.h" - /* * Typically called by the IRQ handler. */ @@ -90,7 +89,7 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) } } - + if (wake) { DRM_WAKEUP(&fm->fence_queue); } @@ -132,8 +131,8 @@ void drm_fence_usage_deref_unlocked(drm_device_t * dev, mutex_lock(&dev->struct_mutex); if (atomic_read(&fence->usage) == 0) { drm_fence_unring(dev, &fence->ring); - atomic_dec(&fm->count); - drm_ctl_cache_free(drm_cache.fence_object, + atomic_dec(&fm->count); + drm_ctl_cache_free(drm_cache.fence_object, sizeof(*fence), fence); } mutex_unlock(&dev->struct_mutex); @@ -150,7 +149,7 @@ static void drm_fence_object_destroy(drm_file_t * priv, drm_fence_usage_deref_locked(dev, fence); } -static int fence_signaled(drm_device_t * dev, volatile +static int fence_signaled(drm_device_t * dev, volatile drm_fence_object_t * fence, uint32_t mask, int poke_flush) { @@ -205,15 +204,14 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, } } -int drm_fence_object_signaled(volatile drm_fence_object_t * fence, +int drm_fence_object_signaled(volatile drm_fence_object_t * fence, uint32_t type) { return ((fence->signaled & type) == type); } int drm_fence_object_flush(drm_device_t * dev, - volatile drm_fence_object_t * fence, - uint32_t type) + volatile drm_fence_object_t * fence, uint32_t type) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; @@ -221,7 +219,7 @@ int drm_fence_object_flush(drm_device_t * dev, if (type & ~fence->type) { DRM_ERROR("Flush trying to extend fence type, " - "0x%x, 0x%x\n", type, fence->type); + "0x%x, 0x%x\n", type, fence->type); return -EINVAL; } @@ -248,7 +246,6 @@ int drm_fence_object_flush(drm_device_t * dev, * wrapped around and reused. */ - void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) { drm_fence_manager_t *fm = &dev->fm; @@ -279,7 +276,7 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) EXPORT_SYMBOL(drm_fence_flush_old); -int drm_fence_object_wait(drm_device_t * dev, +int drm_fence_object_wait(drm_device_t * dev, volatile drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask) { @@ -328,8 +325,8 @@ int drm_fence_object_wait(drm_device_t * dev, do { DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, - fence_signaled(dev, fence, DRM_FENCE_TYPE_EXE, - 1)); + fence_signaled(dev, fence, + DRM_FENCE_TYPE_EXE, 1)); if (time_after_eq(jiffies, _end)) break; } while (ret == -EINTR && ignore_signals); @@ -347,9 +344,9 @@ int drm_fence_object_wait(drm_device_t * dev, */ #if 1 if (!ignore_signals) - return -EAGAIN; + return -EAGAIN; #endif - do { + do { schedule(); signaled = fence_signaled(dev, fence, mask, 1); } while (!signaled && !time_after_eq(jiffies, _end)); @@ -387,7 +384,7 @@ int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, return 0; } -static int drm_fence_object_init(drm_device_t * dev, uint32_t type, +static int drm_fence_object_init(drm_device_t * dev, uint32_t type, uint32_t fence_flags, drm_fence_object_t * fence) { @@ -414,7 +411,6 @@ static int drm_fence_object_init(drm_device_t * dev, uint32_t type, return ret; } - int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence, int shareable) { @@ -441,7 +437,7 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, int ret; drm_fence_manager_t *fm = &dev->fm; - fence = drm_ctl_cache_alloc(drm_cache.fence_object, + fence = drm_ctl_cache_alloc(drm_cache.fence_object, sizeof(*fence), GFP_KERNEL); if (!fence) return -ENOMEM; @@ -472,7 +468,7 @@ void drm_fence_manager_init(drm_device_t * dev) fm->initialized = 0; if (fed) { fm->initialized = 1; - atomic_set(&fm->count,0); + atomic_set(&fm->count, 0); for (i = 0; i < fed->no_types; ++i) { fm->fence_types[i] = &fm->ring; } @@ -523,9 +519,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) case drm_fence_create: if (arg.flags & DRM_FENCE_FLAG_EMIT) LOCK_TEST_WITH_RETURN(dev, filp); - ret = drm_fence_object_create(dev, arg.type, - arg.flags, - &fence); + ret = drm_fence_object_create(dev, arg.type, arg.flags, &fence); if (ret) return ret; ret = drm_fence_add_user_object(priv, fence, @@ -596,7 +590,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } LOCK_TEST_WITH_RETURN(dev, filp); - ret = drm_fence_buffer_objects(priv, NULL, arg.flags, + ret = drm_fence_buffer_objects(priv, NULL, arg.flags, NULL, &fence); if (ret) return ret; diff --git a/linux-core/drm_hashtab.c b/linux-core/drm_hashtab.c index 3a2aa80e..6f17e114 100644 --- a/linux-core/drm_hashtab.c +++ b/linux-core/drm_hashtab.c @@ -36,7 +36,7 @@ #include "drm_hashtab.h" #include -int drm_ht_create(drm_open_hash_t *ht, unsigned int order) +int drm_ht_create(drm_open_hash_t * ht, unsigned int order) { unsigned int i; @@ -46,24 +46,24 @@ int drm_ht_create(drm_open_hash_t *ht, unsigned int order) ht->table = NULL; ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE); if (!ht->use_vmalloc) { - ht->table = drm_calloc(ht->size, sizeof(*ht->table), + 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)); - } + ht->table = vmalloc(ht->size * sizeof(*ht->table)); + } if (!ht->table) { DRM_ERROR("Out of memory for hash table\n"); return -ENOMEM; } - for (i=0; i< ht->size; ++i) { + for (i = 0; i < ht->size; ++i) { INIT_HLIST_HEAD(&ht->table[i]); } return 0; } -void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key) +void drm_ht_verbose_list(drm_open_hash_t * ht, unsigned long key) { drm_hash_item_t *entry; struct hlist_head *h_list; @@ -80,7 +80,7 @@ void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key) } } -static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht, +static struct hlist_node *drm_ht_find_key(drm_open_hash_t * ht, unsigned long key) { drm_hash_item_t *entry; @@ -100,8 +100,7 @@ static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht, return NULL; } - -int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item) +int drm_ht_insert_item(drm_open_hash_t * ht, drm_hash_item_t * item) { drm_hash_item_t *entry; struct hlist_head *h_list; @@ -132,7 +131,7 @@ int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item) * Just insert an item and return any "bits" bit key that hasn't been * used before. */ -int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, +int drm_ht_just_insert_please(drm_open_hash_t * ht, drm_hash_item_t * item, unsigned long seed, int bits, int shift, unsigned long add) { @@ -147,7 +146,7 @@ int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, ret = drm_ht_insert_item(ht, item); if (ret) unshifted_key = (unshifted_key + 1) & mask; - } while(ret && (unshifted_key != first)); + } while (ret && (unshifted_key != first)); if (ret) { DRM_ERROR("Available key bit space exhausted\n"); @@ -156,8 +155,8 @@ int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item, return 0; } -int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, - drm_hash_item_t **item) +int drm_ht_find_item(drm_open_hash_t * ht, unsigned long key, + drm_hash_item_t ** item) { struct hlist_node *list; @@ -169,7 +168,7 @@ int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, return 0; } -int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key) +int drm_ht_remove_key(drm_open_hash_t * ht, unsigned long key) { struct hlist_node *list; @@ -182,22 +181,21 @@ int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key) return -EINVAL; } -int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item) +int drm_ht_remove_item(drm_open_hash_t * ht, drm_hash_item_t * item) { hlist_del_init(&item->head); ht->fill--; return 0; } -void drm_ht_remove(drm_open_hash_t *ht) +void drm_ht_remove(drm_open_hash_t * ht) { if (ht->table) { - if (ht->use_vmalloc) + if (ht->use_vmalloc) vfree(ht->table); else - drm_free(ht->table, ht->size*sizeof(*ht->table), + drm_free(ht->table, ht->size * sizeof(*ht->table), DRM_MEM_HASHTAB); ht->table = NULL; } } - diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 6ab13af3..4af33bde 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -59,9 +59,9 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, return parent; } else { - child = (drm_mm_node_t *) - drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), - GFP_KERNEL); + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), + GFP_KERNEL); if (!child) return NULL; @@ -111,8 +111,8 @@ void drm_mm_put_block(drm_mm_node_t * cur) prev_node->size += next_node->size; list_del(&next_node->ml_entry); list_del(&next_node->fl_entry); - drm_ctl_cache_free(drm_cache.mm, - sizeof(*next_node), + drm_ctl_cache_free(drm_cache.mm, + sizeof(*next_node), next_node); } else { next_node->size += cur->size; @@ -161,9 +161,9 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, return best; } -int drm_mm_clean(drm_mm_t *mm) +int drm_mm_clean(drm_mm_t * mm) { - struct list_head *head = &mm->root_node.ml_entry; + struct list_head *head = &mm->root_node.ml_entry; return (head->next->next == head); } @@ -175,9 +175,8 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->root_node.fl_entry); - - child = (drm_mm_node_t *) - drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), GFP_KERNEL); + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), GFP_KERNEL); if (!child) return -ENOMEM; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 3e66319a..599589fc 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -32,7 +32,6 @@ * Use kmalloc if possible. Otherwise fall back to vmalloc. */ - static void *ttm_alloc(unsigned long size, int type) { void *ret = NULL; @@ -53,15 +52,15 @@ static void *ttm_alloc(unsigned long size, int type) static void ttm_free(void *pointer, unsigned long size, int type) { - - if ((unsigned long) pointer >= VMALLOC_START && - (unsigned long) pointer <= VMALLOC_END) { + + if ((unsigned long)pointer >= VMALLOC_START && + (unsigned long)pointer <= VMALLOC_END) { vfree(pointer); } else { drm_free(pointer, size, type); } drm_free_memctl(size); -} +} /* * Unmap all vma pages from vmas mapping this ttm. @@ -155,7 +154,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (ttm->pages) { drm_buffer_manager_t *bm = &ttm->dev->bm; - if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) + if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) drm_set_caching(ttm, 0); for (i = 0; i < ttm->num_pages; ++i) { @@ -184,7 +183,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) --bm->cur_pages; } } - ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), + ttm_free(ttm->pages, ttm->num_pages * sizeof(*ttm->pages), DRM_MEM_TTM); ttm->pages = NULL; } @@ -193,20 +192,19 @@ int drm_destroy_ttm(drm_ttm_t * ttm) return 0; } -static int drm_ttm_populate(drm_ttm_t *ttm) +static int drm_ttm_populate(drm_ttm_t * ttm) { struct page *page; unsigned long i; drm_buffer_manager_t *bm; drm_ttm_backend_t *be; - - if (ttm->state != ttm_unpopulated) + if (ttm->state != ttm_unpopulated) return 0; - + bm = &ttm->dev->bm; be = ttm->be; - for (i=0; inum_pages; ++i) { + for (i = 0; i < ttm->num_pages; ++i) { page = ttm->pages[i]; if (!page) { if (drm_alloc_memctl(PAGE_SIZE)) { @@ -229,9 +227,7 @@ static int drm_ttm_populate(drm_ttm_t *ttm) be->populate(be, ttm->num_pages, ttm->pages); ttm->state = ttm_unbound; return 0; -} - - +} /* * Initialize a ttm. @@ -266,7 +262,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) * Account also for AGP module memory usage. */ - ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), + ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), DRM_MEM_TTM); if (!ttm->pages) { drm_destroy_ttm(ttm); @@ -321,13 +317,12 @@ void drm_fixup_ttm_caching(drm_ttm_t * ttm) ttm->state = ttm_unbound; } } - int drm_unbind_ttm(drm_ttm_t * ttm) { int ret = 0; - if (ttm->state == ttm_bound) + if (ttm->state == ttm_bound) ret = drm_evict_ttm(ttm); if (ret) @@ -337,8 +332,7 @@ int drm_unbind_ttm(drm_ttm_t * ttm) return 0; } -int drm_bind_ttm(drm_ttm_t * ttm, int cached, - unsigned long aper_offset) +int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset) { int ret = 0; @@ -350,7 +344,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, int cached, return 0; be = ttm->be; - + ret = drm_ttm_populate(ttm); if (ret) return ret; @@ -361,7 +355,7 @@ int drm_bind_ttm(drm_ttm_t * ttm, int cached, drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); } -#ifdef DRM_ODD_MM_COMPAT +#ifdef DRM_ODD_MM_COMPAT else if (ttm->state == ttm_evicted && !cached) { ret = drm_ttm_lock_mm(ttm); if (ret) @@ -378,18 +372,17 @@ int drm_bind_ttm(drm_ttm_t * ttm, int cached, return ret; } - ttm->aper_offset = aper_offset; ttm->state = ttm_bound; #ifdef DRM_ODD_MM_COMPAT if (be->needs_ub_cache_adjust(be)) { ret = drm_ttm_remap_bound(ttm); - if (ret) + if (ret) return ret; } #endif - + return 0; } @@ -448,8 +441,7 @@ void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) */ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, - uint32_t flags, - drm_ttm_object_t ** ttm_object) + uint32_t flags, drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; drm_map_list_t *list; @@ -476,21 +468,20 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, return -ENOMEM; } - map->offset = (unsigned long) ttm; + map->offset = (unsigned long)ttm; map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; list->file_offset_node = drm_mm_search_free(&dev->offset_manager, - ttm->num_pages, - 0,0); + ttm->num_pages, 0, 0); if (!list->file_offset_node) { drm_ttm_object_remove(dev, object); return -ENOMEM; } list->file_offset_node = drm_mm_get_block(list->file_offset_node, - ttm->num_pages,0); + ttm->num_pages, 0); list->hash.key = list->file_offset_node->start; diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index e5501d9c..11a13754 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -52,12 +52,12 @@ typedef struct drm_ttm_backend { unsigned long aperture_base; void *private; uint32_t flags; - uint32_t drm_map_type; + uint32_t drm_map_type; int (*needs_ub_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, + int (*bind) (struct drm_ttm_backend * backend, unsigned long offset, int cached); int (*unbind) (struct drm_ttm_backend * backend); void (*destroy) (struct drm_ttm_backend * backend); @@ -68,11 +68,11 @@ typedef struct drm_ttm { uint32_t page_flags; unsigned long num_pages; unsigned long aper_offset; - atomic_t vma_count; + atomic_t vma_count; struct drm_device *dev; int destroy; - uint32_t mapping_offset; - drm_ttm_backend_t *be; + uint32_t mapping_offset; + drm_ttm_backend_t *be; enum { ttm_bound, ttm_evicted, @@ -80,8 +80,8 @@ typedef struct drm_ttm { ttm_unpopulated, } state; #ifdef DRM_ODD_MM_COMPAT - struct list_head vma_list; - struct list_head p_mm_list; + struct list_head vma_list; + struct list_head p_mm_list; #endif } drm_ttm_t; @@ -93,7 +93,7 @@ typedef struct drm_ttm_object { } drm_ttm_object_t; extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, - uint32_t flags, + 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); @@ -102,8 +102,7 @@ extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, uint32_t handle, int check_owner); -extern int drm_bind_ttm(drm_ttm_t * ttm, int cached, - unsigned long aper_offset); +extern int drm_bind_ttm(drm_ttm_t * ttm, int cached, unsigned long aper_offset); extern int drm_unbind_ttm(drm_ttm_t * ttm); @@ -112,8 +111,7 @@ extern int drm_unbind_ttm(drm_ttm_t * ttm); */ extern int drm_evict_ttm(drm_ttm_t * ttm); -extern void drm_fixup_ttm_caching(drm_ttm_t *ttm); - +extern void drm_fixup_ttm_caching(drm_ttm_t * ttm); /* * Destroy a ttm. The user normally calls drmRmMap or a similar IOCTL to do this, diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 8a3d7bf7..729ba4b2 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -36,23 +36,23 @@ #define INTEL_AGP_MEM_USER 3 #define INTEL_AGP_MEM_UCACHED 4 -drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev) +drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t * dev) { - return drm_agp_init_ttm(dev, NULL, INTEL_AGP_MEM_USER, INTEL_AGP_MEM_UCACHED, - INTEL_AGP_MEM_USER); + return drm_agp_init_ttm(dev, NULL, INTEL_AGP_MEM_USER, + INTEL_AGP_MEM_UCACHED, INTEL_AGP_MEM_USER); } -int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) +int i915_fence_types(uint32_t buffer_flags, uint32_t * class, uint32_t * type) { *class = 0; - if (buffer_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) + if (buffer_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) *type = 3; else *type = 1; return 0; } -int i915_invalidate_caches(drm_device_t *dev, uint32_t flags) +int i915_invalidate_caches(drm_device_t * dev, uint32_t flags) { /* * FIXME: Only emit once per batchbuffer submission. @@ -65,6 +65,5 @@ int i915_invalidate_caches(drm_device_t *dev, uint32_t flags) if (flags & DRM_BO_FLAG_EXE) flush_cmd |= MI_EXE_FLUSH; - return i915_emit_mi_flush(dev, flush_cmd); } diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 49dc254f..fc8ab761 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -62,7 +62,7 @@ static void i915_perform_flush(drm_device_t * dev) diff = sequence - fm->last_exe_flush; if (diff < driver->wrap_diff && diff != 0) { drm_fence_handler(dev, sequence, DRM_FENCE_TYPE_EXE); - } + } diff = sequence - fm->exe_flush_sequence; if (diff < driver->wrap_diff) { @@ -85,7 +85,7 @@ static void i915_perform_flush(drm_device_t * dev) flush_sequence = dev_priv->flush_sequence; dev_priv->flush_pending = 0; drm_fence_handler(dev, flush_sequence, flush_flags); - } + } } if (fm->pending_flush && !dev_priv->flush_pending) { @@ -105,7 +105,7 @@ static void i915_perform_flush(drm_device_t * dev) flush_sequence = dev_priv->flush_sequence; dev_priv->flush_pending = 0; drm_fence_handler(dev, flush_sequence, flush_flags); - } + } } } @@ -121,15 +121,15 @@ void i915_poke_flush(drm_device_t * dev) } int i915_fence_emit_sequence(drm_device_t * dev, uint32_t flags, - uint32_t * sequence, uint32_t *native_type) + uint32_t * sequence, uint32_t * native_type) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; i915_emit_irq(dev); *sequence = (uint32_t) dev_priv->counter; - *native_type = DRM_FENCE_TYPE_EXE; - if (flags & DRM_I915_FENCE_FLAG_FLUSHED) + *native_type = DRM_FENCE_TYPE_EXE; + if (flags & DRM_I915_FENCE_FLAG_FLUSHED) *native_type |= DRM_I915_FENCE_TYPE_RW; - + return 0; } @@ -141,4 +141,3 @@ void i915_fence_handler(drm_device_t * dev) i915_perform_flush(dev); write_unlock(&fm->lock); } - From c34faf224b959bf61e4c3eb29c66a12edbd31841 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 20:03:26 +0200 Subject: [PATCH 131/147] Remove max number of locked pages check and call, since that is now handled by the memory accounting. --- libdrm/xf86drm.c | 15 --------------- libdrm/xf86mm.h | 1 - linux-core/drmP.h | 1 - linux-core/drm_bo.c | 27 --------------------------- linux-core/drm_compat.c | 5 ----- shared-core/drm.h | 1 - 6 files changed, 50 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 253ba690..5c799b6d 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3187,21 +3187,6 @@ int drmMMTakedown(int fd, unsigned memType) return 0; } -int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize) -{ - drm_mm_init_arg_t arg; - - - memset(&arg, 0, sizeof(arg)); - arg.req.op = mm_set_max_pages; - arg.req.p_size = maxLockedSize / getpagesize(); - - if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) - return -errno; - - return 0; -} - int drmMMLock(int fd, unsigned memType) { drm_mm_init_arg_t arg; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index c3112c90..da868fe5 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -198,7 +198,6 @@ extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint); extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, unsigned memType); extern int drmMMTakedown(int fd, unsigned memType); -extern int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize); extern int drmMMLock(int fd, unsigned memType); extern int drmMMUnlock(int fd, unsigned memType); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index b10e9881..fab3608f 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -814,7 +814,6 @@ typedef struct drm_buffer_manager{ struct list_head ddestroy; struct work_struct wq; uint32_t fence_type; - unsigned long max_pages; unsigned long cur_pages; atomic_t count; } drm_buffer_manager_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e8e8a274..b8ee6c15 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1859,7 +1859,6 @@ int drm_bo_driver_init(drm_device_t * dev) drm_bo_driver_t *driver = dev->driver->bo_driver; drm_buffer_manager_t *bm = &dev->bm; int ret = -EINVAL; - struct sysinfo si; mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); @@ -1880,8 +1879,6 @@ int drm_bo_driver_init(drm_device_t * dev) bm->nice_mode = 1; atomic_set(&bm->count, 0); bm->cur_pages = 0; - si_meminfo(&si); - bm->max_pages = si.totalram >> 1; INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); out_unlock: @@ -1944,30 +1941,6 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) "Delaying takedown\n", arg.req.mem_type); } break; - case mm_set_max_pages:{ - struct sysinfo si; - mutex_lock(&dev->bm.init_mutex); - mutex_lock(&dev->struct_mutex); - if (arg.req.p_size < bm->cur_pages) { - DRM_ERROR - ("Cannot currently decrease max number of " - "locked pages below the number currently " - "locked.\n"); - ret = -EINVAL; - break; - } - si_meminfo(&si); - if (arg.req.p_size > si.totalram) { - DRM_ERROR - ("Cannot set max number of locked pages " - "to %lu since the total number of RAM pages " - "is %lu.\n", (unsigned long)arg.req.p_size, - (unsigned long)si.totalram); - ret = -EINVAL; - break; - } - bm->max_pages = arg.req.p_size; - } case mm_lock: LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 4a035f49..90e53419 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -234,11 +234,6 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, page = ttm->pages[page_offset]; if (!page) { - if (bm->cur_pages >= bm->max_pages) { - DRM_ERROR("Maximum locked page count exceeded\n"); - page = NOPAGE_OOM; - goto out; - } if (drm_alloc_memctl(PAGE_SIZE)) { page = NOPAGE_OOM; goto out; diff --git a/shared-core/drm.h b/shared-core/drm.h index 915befba..4a6a370e 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -829,7 +829,6 @@ typedef union drm_mm_init_arg{ struct { enum { mm_init, - mm_set_max_pages, mm_takedown, mm_query, mm_lock, From 25fe4a80490bba709099f0401535d2f96ac7729c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 20:04:41 +0200 Subject: [PATCH 132/147] Remove some debugging messages. --- libdrm/xf86drm.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 5c799b6d..9047c8db 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2786,16 +2786,11 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, fd, buf->mapHandle); if (virtual == MAP_FAILED) { ret = -errno; - fprintf(stderr, "Map error 0x%016llx\n", buf->mapHandle); } if (ret) return ret; buf->mapVirtual = virtual; buf->virtual = ((char *) virtual) + buf->start; -#ifdef BODEBUG - fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", - buf->mapVirtual, buf->virtual); -#endif } memset(&arg, 0, sizeof(arg)); From e172945d668f1de1243ac2ae91ab77f3b2bda40a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 18 Oct 2006 16:54:17 +0200 Subject: [PATCH 133/147] Avoid driver-specific AGP user-populated types, since we don't know what AGP driver we're on. Avoid global cache flushes before inserting pages. In general, they are never mapped, and not accessed through the kernel map, so a cache flush should not be necessary. The exception is pages that are bound cached. We might need a cache flush for those. --- linux-core/drmP.h | 5 +---- linux-core/drm_agpsupport.c | 20 ++++++++++++-------- linux-core/i915_buffer.c | 5 +---- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index fab3608f..d78ea7c8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1295,10 +1295,7 @@ 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(struct drm_device *dev, - drm_ttm_backend_t *backend, - unsigned alloc_type, - unsigned cached_type, - unsigned uncached_type); + drm_ttm_backend_t *backend); /* Stub support (drm_stub.h) */ extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index ffbe04f8..a5f1f9ee 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -558,6 +558,12 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) * AGP ttm backend interface. */ +#ifndef AGP_USER_TYPES +#define AGP_USER_TYPES (1 << 16) +#define AGP_USER_MEMORY (AGP_USER_TYPES) +#define AGP_USER_CACHED_MEMORY (AGP_USER_TYPES + 1) +#endif + static int drm_agp_needs_unbind_cache_adjust(drm_ttm_backend_t *backend) { return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1); } @@ -604,7 +610,7 @@ static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, DRM_DEBUG("drm_agp_bind_ttm\n"); DRM_MASK_VAL(backend->flags, DRM_BE_FLAG_BOUND_CACHED, (cached) ? DRM_BE_FLAG_BOUND_CACHED : 0); - mem->is_flushed = FALSE; + mem->is_flushed = TRUE; mem->type = (cached) ? agp_priv->cached_type : agp_priv->uncached_type; ret = drm_agp_bind_memory(mem, offset); if (ret) { @@ -662,10 +668,8 @@ static void drm_agp_destroy_ttm(drm_ttm_backend_t *backend) { drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev, - drm_ttm_backend_t *backend, - unsigned alloc_type, - unsigned cached_type, - unsigned uncached_type) { + drm_ttm_backend_t *backend) +{ drm_ttm_backend_t *agp_be; drm_agp_ttm_priv *agp_priv; @@ -684,9 +688,9 @@ drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev, } agp_priv->mem = NULL; - agp_priv->alloc_type = alloc_type; - agp_priv->cached_type = cached_type; - agp_priv->uncached_type = uncached_type; + agp_priv->alloc_type = AGP_USER_MEMORY; + agp_priv->cached_type = AGP_USER_CACHED_MEMORY; + agp_priv->uncached_type = AGP_USER_MEMORY; agp_priv->bridge = dev->agp->bridge; agp_priv->populated = FALSE; agp_be->aperture_base = dev->agp->agp_info.aper_base; diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 729ba4b2..c3e54468 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -33,13 +33,10 @@ #include "i915_drm.h" #include "i915_drv.h" -#define INTEL_AGP_MEM_USER 3 -#define INTEL_AGP_MEM_UCACHED 4 drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t * dev) { - return drm_agp_init_ttm(dev, NULL, INTEL_AGP_MEM_USER, - INTEL_AGP_MEM_UCACHED, INTEL_AGP_MEM_USER); + return drm_agp_init_ttm(dev, NULL); } int i915_fence_types(uint32_t buffer_flags, uint32_t * class, uint32_t * type) From 11aaa358a0f56afb64df44c737ec331d90118537 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 18 Oct 2006 17:18:23 +0200 Subject: [PATCH 134/147] Remove stray softlink. --- linux-core/drm_drawable.c | 1 - 1 file changed, 1 deletion(-) delete mode 120000 linux-core/drm_drawable.c diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c deleted file mode 120000 index d64bbe10..00000000 --- a/linux-core/drm_drawable.c +++ /dev/null @@ -1 +0,0 @@ -../shared-core/drm_drawable.c \ No newline at end of file From e8ba62db722eb0b915377269d7e1c3a039928669 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 19 Oct 2006 16:58:00 +0200 Subject: [PATCH 135/147] Make sure delayed delete list is empty on lastclose. Fix some refcounting errors. Fix some error messages. --- linux-core/drm_bo.c | 180 +++++++++++++++++++++++----------------- linux-core/drm_fence.c | 4 +- linux-core/i915_fence.c | 3 + 3 files changed, 109 insertions(+), 78 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index b8ee6c15..954b7a03 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -247,7 +247,46 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_ctl_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } -static void drm_bo_delayed_delete(drm_device_t * dev) +/* + * Call bo->mutex locked. + * Wait until the buffer is idle. + */ + +static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, + int no_wait) +{ + + drm_fence_object_t *fence = bo->fence; + int ret; + + if (fence) { + drm_device_t *dev = bo->dev; + if (drm_fence_object_signaled(fence, bo->fence_type)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + if (no_wait) { + return -EBUSY; + } + ret = + drm_fence_object_wait(dev, fence, lazy, ignore_signals, + bo->fence_type); + if (ret) + return ret; + + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + + } + return 0; +} + +/* + * Call dev->struct_mutex locked. + */ + +static void drm_bo_delayed_delete(drm_device_t * dev, int remove_all) { drm_buffer_manager_t *bm = &dev->bm; @@ -255,28 +294,23 @@ static void drm_bo_delayed_delete(drm_device_t * dev) struct list_head *list, *next; drm_fence_object_t *fence; - mutex_lock(&dev->struct_mutex); - if (!bm->initialized) - goto out; - - list = bm->ddestroy.next; list_for_each_safe(list, next, &bm->ddestroy) { entry = list_entry(list, drm_buffer_object_t, ddestroy); - nentry = NULL; - - /* - * Another process may claim access to this entry through the - * lru lists. In that case, just skip it. - */ - - if (atomic_read(&entry->usage) != 0) + atomic_inc(&entry->usage); + if (atomic_read(&entry->usage) != 1) { + atomic_dec(&entry->usage); continue; + } - /* - * Since we're the only users, No need to take the - * bo->mutex to watch the fence. - */ + nentry = NULL; + if (next != &bm->ddestroy) { + nentry = list_entry(next, drm_buffer_object_t, + ddestroy); + atomic_inc(&nentry->usage); + } + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); fence = entry->fence; if (fence && drm_fence_object_signaled(fence, entry->fence_type)) { @@ -284,29 +318,38 @@ static void drm_bo_delayed_delete(drm_device_t * dev) entry->fence = NULL; } - if (!entry->fence) { + if (entry->fence && remove_all) { + if (bm->nice_mode) { + unsigned long _end = jiffies + 3 * DRM_HZ; + int ret; + do { + ret = drm_bo_wait(entry, 0, 1, 0); + } while (ret && !time_after_eq(jiffies, _end)); - /* - * Protect the "next" entry against destruction in case - * drm_bo_destroy_locked temporarily releases the - * struct_mutex; - */ - - nentry = NULL; - if (next != &bm->ddestroy) { - nentry = list_entry(next, drm_buffer_object_t, - ddestroy); - atomic_inc(&nentry->usage); + if (entry->fence) { + bm->nice_mode = 0; + DRM_ERROR("Detected GPU lockup or " + "fence driver was taken down. " + "Evicting waiting buffers.\n"); + } } - DRM_DEBUG("Destroying delayed buffer object\n"); + if (entry->fence) { + drm_fence_usage_deref_unlocked(dev, + entry->fence); + entry->fence = NULL; + } + } + mutex_lock(&dev->struct_mutex); + mutex_unlock(&entry->mutex); + if (atomic_dec_and_test(&entry->usage) && (!entry->fence)) { list_del_init(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); - if (next != &bm->ddestroy) - atomic_dec(&nentry->usage); + } + if (nentry) { + atomic_dec(&nentry->usage); } } - out: - mutex_unlock(&dev->struct_mutex); + } static void drm_bo_delayed_workqueue(void *data) @@ -316,8 +359,12 @@ static void drm_bo_delayed_workqueue(void *data) DRM_DEBUG("Delayed delete Worker\n"); - drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); + if (!bm->initialized) { + mutex_unlock(&dev->struct_mutex); + return; + } + drm_bo_delayed_delete(dev, 0); if (bm->initialized && !list_empty(&bm->ddestroy)) { schedule_delayed_work(&bm->wq, ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); @@ -451,41 +498,6 @@ int drm_fence_buffer_objects(drm_file_t * priv, EXPORT_SYMBOL(drm_fence_buffer_objects); -/* - * Call bo->mutex locked. - * Wait until the buffer is idle. - */ - -static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, - int no_wait) -{ - - drm_fence_object_t *fence = bo->fence; - int ret; - - if (fence) { - drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_type)) { - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; - return 0; - } - if (no_wait) { - return -EBUSY; - } - ret = - drm_fence_object_wait(dev, fence, lazy, ignore_signals, - bo->fence_type); - if (ret) - return ret; - - drm_fence_usage_deref_unlocked(dev, fence); - bo->fence = NULL; - - } - return 0; -} - /* * bo->mutex locked */ @@ -1385,8 +1397,6 @@ int drm_buffer_object_create(drm_file_t * priv, uint32_t new_flags; unsigned long num_pages; - drm_bo_delayed_delete(dev); - if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; @@ -1637,6 +1647,7 @@ static int drm_bo_force_list_clean(drm_device_t * dev, if (prev != list->prev || next != list->next) { mutex_unlock(&entry->mutex); + drm_bo_usage_deref_locked(dev, entry); goto retry; } if (drm_bo_mm_node(entry, mem_type)) { @@ -1816,6 +1827,11 @@ static int drm_bo_init_mm(drm_device_t * dev, return 0; } +/* + * This is called from lastclose, so we don't need to bother about + * any clients still running when we set the initialized flag to zero. + */ + int drm_bo_driver_finish(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; @@ -1827,6 +1843,7 @@ int drm_bo_driver_finish(drm_device_t * dev) if (!bm->initialized) goto out; + bm->initialized = 0; while (i--) { if (bm->has_type[i]) { @@ -1840,14 +1857,23 @@ int drm_bo_driver_finish(drm_device_t * dev) } } mutex_unlock(&dev->struct_mutex); - drm_bo_delayed_delete(dev); - mutex_lock(&dev->struct_mutex); - bm->initialized = 0; - mutex_unlock(&dev->struct_mutex); if (!cancel_delayed_work(&bm->wq)) { flush_scheduled_work(); } mutex_lock(&dev->struct_mutex); + drm_bo_delayed_delete(dev, 1); + if (list_empty(&bm->ddestroy)) { + DRM_DEBUG("Delayed destroy list was clean\n"); + } + if (list_empty(&bm->lru[0])) { + DRM_DEBUG("Swap list was clean\n"); + } + if (list_empty(&bm->pinned[0])) { + DRM_DEBUG("NO_MOVE list was clean\n"); + } + if (list_empty(&bm->unfenced)) { + DRM_DEBUG("Unfenced list was clean\n"); + } out: mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->bm.init_mutex); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index aa382046..f656340e 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -311,7 +311,9 @@ int drm_fence_object_wait(drm_device_t * dev, ret = -EBUSY; if (ret) { if (ret == -EBUSY) { - DRM_ERROR("Fence timout. GPU lockup.\n"); + DRM_ERROR("Fence timeout. " + "GPU lockup or fence driver was " + "taken down.\n"); } return ((ret == -EINTR) ? -EAGAIN : ret); } diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index fc8ab761..2182604c 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -124,6 +124,9 @@ int i915_fence_emit_sequence(drm_device_t * dev, uint32_t flags, uint32_t * sequence, uint32_t * native_type) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + if (!dev_priv) + return -EINVAL; + i915_emit_irq(dev); *sequence = (uint32_t) dev_priv->counter; *native_type = DRM_FENCE_TYPE_EXE; From 3624e43282b0c6aad32829f116fd8f7bce66fbb6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 20 Oct 2006 15:06:31 +0200 Subject: [PATCH 136/147] Bug #8707, 2.6.19-rc compatibility for memory manager code. --- linux-core/drm_compat.c | 53 +++++++++++++++++++++++++---------------- linux-core/drm_compat.h | 22 ++++++++++------- linux-core/drm_drv.c | 6 ++++- linux-core/drm_vm.c | 8 ++++--- 4 files changed, 56 insertions(+), 33 deletions(-) diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 90e53419..b466f8bd 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -28,6 +28,11 @@ #include "drmP.h" #if defined(CONFIG_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + +/* + * These have bad performance in the AGP module for the indicated kernel versions. + */ + int drm_map_page_into_agp(struct page *page) { int i; @@ -45,9 +50,15 @@ int drm_unmap_page_from_agp(struct page *page) * performance reasons */ return i; } -#endif +#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + +/* + * The protection map was exported in 2.6.19 + */ + pgprot_t vm_get_page_prot(unsigned long vm_flags) { #ifdef MODULE @@ -62,8 +73,17 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags) return protection_map[vm_flags & 0x0F]; #endif }; +#endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + +/* + * vm code for kernels below 2,6,15 in which version a major vm write + * occured. This implement a simple straightforward + * version similar to what's going to be + * in kernel 2.6.20+? + */ static int drm_pte_is_clear(struct vm_area_struct *vma, unsigned long addr) @@ -76,12 +96,7 @@ static int drm_pte_is_clear(struct vm_area_struct *vma, pgd_t *pgd; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) spin_lock(&mm->page_table_lock); -#else - spinlock_t *ptl; -#endif - pgd = pgd_offset(mm, addr); if (pgd_none(*pgd)) goto unlock; @@ -91,22 +106,13 @@ static int drm_pte_is_clear(struct vm_area_struct *vma, pmd = pmd_offset(pud, addr); if (pmd_none(*pmd)) goto unlock; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) pte = pte_offset_map(pmd, addr); -#else - pte = pte_offset_map_lock(mm, pmd, addr, &ptl); -#endif if (!pte) goto unlock; ret = pte_none(*pte); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) pte_unmap(pte); unlock: spin_unlock(&mm->page_table_lock); -#else - pte_unmap_unlock(pte, ptl); - unlock: -#endif return ret; } @@ -121,7 +127,6 @@ int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, return ret; } - static struct { spinlock_t lock; struct page *dummy_page; @@ -154,9 +159,6 @@ void free_nopage_retry(void) spin_unlock(&drm_np_retry.lock); } } -#endif - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, unsigned long address, @@ -186,6 +188,17 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, #ifdef DRM_ODD_MM_COMPAT +/* + * VM compatibility code for 2.6.15-2.6.19(?). This code implements a complicated + * workaround for a single BUG statement in do_no_page in these versions. The + * tricky thing is that we need to take the mmap_sem in exclusive mode for _all_ + * vmas mapping the ttm, before dev->struct_mutex is taken. The way we do this is to + * check first take the dev->struct_mutex, and then trylock all mmap_sems. If this + * fails for a single mmap_sem, we have to release all sems and the dev->struct_mutex, + * release the cpu and retry. We also need to keep track of all vmas mapping the ttm. + * phew. + */ + typedef struct p_mm_entry { struct list_head head; struct mm_struct *mm; diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 5617fb7f..a1a94399 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -231,7 +231,7 @@ static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from #include #include -#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) && \ +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) && \ (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))) #define DRM_ODD_MM_COMPAT #endif @@ -277,7 +277,18 @@ extern int drm_map_page_into_agp(struct page *page); #define unmap_page_from_agp drm_unmap_page_from_agp #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) +extern struct page *get_nopage_retry(void); +extern void free_nopage_retry(void); +struct fault_data; +extern struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, + struct fault_data *data); + +#define NOPAGE_REFAULT get_nopage_retry() +#endif + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) /* * Hopefully, real NOPAGE_RETRY functionality will be in 2.6.19. @@ -295,10 +306,6 @@ struct fault_data { int type; }; -extern struct page *get_nopage_retry(void); -extern void free_nopage_retry(void); - -#define NOPAGE_REFAULT get_nopage_retry() extern int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn, pgprot_t pgprot); @@ -307,9 +314,6 @@ extern struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, unsigned long address, int *type); -extern struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, - struct fault_data *data); - #endif #ifdef DRM_ODD_MM_COMPAT diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 75c89c1c..518e2aa3 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -433,7 +433,7 @@ void drm_exit(struct drm_driver *driver) } } else pci_unregister_driver(&driver->pci_driver); -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) free_nopage_retry(); #endif DRM_INFO("Module unloaded\n"); @@ -472,10 +472,14 @@ static void drm_free_mem_cache(kmem_cache_t *cache, { if (!cache) return; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) if (kmem_cache_destroy(cache)) { DRM_ERROR("Warning! DRM is leaking %s memory.\n", name); } +#else + kmem_cache_destroy(cache); +#endif } static void drm_free_memory_caches(void ) diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index ba4b1451..fd6e89d8 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -159,7 +159,9 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, } #endif /* __OS_HAS_AGP */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) || \ + LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) static #endif struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, @@ -244,7 +246,7 @@ struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, mutex_unlock(&dev->struct_mutex); return NULL; } - +#endif /** * \c nopage method for shared virtual memory. @@ -535,7 +537,7 @@ static struct vm_operations_struct drm_vm_sg_ops = { .close = drm_vm_close, }; -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) static struct vm_operations_struct drm_vm_ttm_ops = { .nopage = drm_vm_ttm_nopage, .open = drm_vm_ttm_open_wrapper, From 9321592149c031694c459bb05e7a31d1197fe5cb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 20 Oct 2006 15:07:21 +0200 Subject: [PATCH 137/147] We apparently need this global cache flush anyway. --- linux-core/drm_agpsupport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index a5f1f9ee..13a3ced3 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -610,7 +610,7 @@ static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, DRM_DEBUG("drm_agp_bind_ttm\n"); DRM_MASK_VAL(backend->flags, DRM_BE_FLAG_BOUND_CACHED, (cached) ? DRM_BE_FLAG_BOUND_CACHED : 0); - mem->is_flushed = TRUE; + mem->is_flushed = FALSE; mem->type = (cached) ? agp_priv->cached_type : agp_priv->uncached_type; ret = drm_agp_bind_memory(mem, offset); if (ret) { From a8909a0ebcc21ad6b92b93ffe87878ece4b56506 Mon Sep 17 00:00:00 2001 From: Tilman Sauerbeck Date: Fri, 20 Oct 2006 17:05:07 +0200 Subject: [PATCH 138/147] Bug #1746: Set dev_priv_size for the MGA driver. --- linux-core/mga_drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 2bb1e8f3..ef6f1e44 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -48,6 +48,7 @@ static struct drm_driver driver = { DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, + .dev_priv_size = sizeof (drm_mga_buf_priv_t), .load = mga_driver_load, .unload = mga_driver_unload, .lastclose = mga_driver_lastclose, From 9ed4656799043f24f4d64615ebb8128bedc99799 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sat, 21 Oct 2006 14:17:51 +0200 Subject: [PATCH 139/147] The CPU cache must be flushed _before_ we start modifying the kernel map ptes, otherwise data will be missing, which becomes apparent when the kernel evicts batch buffers which are likely to be written into in the evicted state, and then rebound to the AGP aperture. This means we cannot rely on the AGP module to flush the cache for us. --- linux-core/drm_agpsupport.c | 2 +- linux-core/drm_ttm.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 13a3ced3..a5f1f9ee 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -610,7 +610,7 @@ static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, DRM_DEBUG("drm_agp_bind_ttm\n"); DRM_MASK_VAL(backend->flags, DRM_BE_FLAG_BOUND_CACHED, (cached) ? DRM_BE_FLAG_BOUND_CACHED : 0); - mem->is_flushed = FALSE; + mem->is_flushed = TRUE; mem->type = (cached) ? agp_priv->cached_type : agp_priv->uncached_type; ret = drm_agp_bind_memory(mem, offset); if (ret) { diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 599589fc..7344acce 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -28,6 +28,18 @@ #include "drmP.h" +static void drm_ttm_ipi_handler(void *null) +{ + wbinvd(); +} + +static void drm_ttm_cache_flush(void) +{ + if (on_each_cpu(drm_ttm_ipi_handler, NULL, 1, 1) != 0) + DRM_ERROR("Timed out waiting for drm cache flush.\n"); +} + + /* * Use kmalloc if possible. Otherwise fall back to vmalloc. */ @@ -99,6 +111,9 @@ static int drm_set_caching(drm_ttm_t * ttm, int noncached) if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached) return 0; + if (noncached) + drm_ttm_cache_flush(); + for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages + i; if (*cur_page) { From b4fba1679b6156e3ca6f053b44cae0b003febe7f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:14:23 +0200 Subject: [PATCH 140/147] Add a one-page hole in the file offset space between buffers. --- linux-core/drm_ttm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 7344acce..13bec48b 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -489,14 +489,20 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; + /* + * Add a one-page "hole" to the block size to avoid the mm subsystem + * merging vmas. + * FIXME: Is this really needed? + */ + list->file_offset_node = drm_mm_search_free(&dev->offset_manager, - ttm->num_pages, 0, 0); + ttm->num_pages + 1, 0, 0); if (!list->file_offset_node) { drm_ttm_object_remove(dev, object); return -ENOMEM; } list->file_offset_node = drm_mm_get_block(list->file_offset_node, - ttm->num_pages, 0); + ttm->num_pages + 1, 0); list->hash.key = list->file_offset_node->start; From 47dbfc4e4a3e8ce2ec468bc3874f74f7e2b13476 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:17:43 +0200 Subject: [PATCH 141/147] Add improved alignment functionality to the core memory manager. This makes an allocated block actually align itself and returns any wasted space to the manager. Also add some functions to grow and shrink the managed area. This will be used in the future to manage the buffer object swap cache. --- linux-core/drm_mm.c | 171 ++++++++++++++++++++++++++++++++------------ 1 file changed, 126 insertions(+), 45 deletions(-) diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 4af33bde..5e0ba5e4 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -44,39 +44,132 @@ #include "drmP.h" #include +unsigned long tail_space(drm_mm_t *mm) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->root_node.ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) + return 0; + + return entry->size; +} + +int remove_space_from_tail(drm_mm_t *mm, unsigned long size) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->root_node.ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) + return -ENOMEM; + + if (entry->size <= size) + return -ENOMEM; + + entry->size -= size; + return 0; +} + + +static int drm_mm_create_tail_node(drm_mm_t *mm, + unsigned long start, + unsigned long size) +{ + drm_mm_node_t *child; + + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), + GFP_KERNEL); + if (!child) + return -ENOMEM; + + child->free = 1; + child->size = size; + child->start = start; + child->mm = mm; + + list_add_tail(&child->ml_entry, &mm->root_node.ml_entry); + list_add_tail(&child->fl_entry, &mm->root_node.fl_entry); + + return 0; +} + + +int add_space_to_tail(drm_mm_t *mm, unsigned long size) +{ + struct list_head *tail_node; + drm_mm_node_t *entry; + + tail_node = mm->root_node.ml_entry.prev; + entry = list_entry(tail_node, drm_mm_node_t, ml_entry); + if (!entry->free) { + return drm_mm_create_tail_node(mm, entry->start + entry->size, size); + } + entry->size += size; + return 0; +} + +static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent, + unsigned long size) +{ + drm_mm_node_t *child; + + child = (drm_mm_node_t *) + drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), + GFP_KERNEL); + if (!child) + return NULL; + + INIT_LIST_HEAD(&child->fl_entry); + + child->free = 0; + child->size = size; + child->start = parent->start; + child->mm = parent->mm; + + list_add_tail(&child->ml_entry, &parent->ml_entry); + INIT_LIST_HEAD(&child->fl_entry); + + parent->size -= size; + parent->start += size; + return child; +} + + + drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, unsigned long size, unsigned alignment) { + drm_mm_node_t *align_splitoff = NULL; drm_mm_node_t *child; - - if (alignment) - size += alignment - 1; - + unsigned tmp = size % alignment; + + if (tmp) { + align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); + if (!align_splitoff) + return NULL; + } + if (parent->size == size) { list_del_init(&parent->fl_entry); parent->free = 0; return parent; } else { - - child = (drm_mm_node_t *) - drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), - GFP_KERNEL); - if (!child) + child = drm_mm_split_at_start(parent, size); + if (!child) { + if (align_splitoff) + drm_mm_put_block(align_splitoff); return NULL; - - INIT_LIST_HEAD(&child->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); - - child->free = 0; - child->size = size; - child->start = parent->start; - child->mm = parent->mm; - - list_add_tail(&child->ml_entry, &parent->ml_entry); - parent->size -= size; - parent->start += size; + } } + if (align_splitoff) + drm_mm_put_block(align_splitoff); + return child; } @@ -139,16 +232,23 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm, drm_mm_node_t *entry; drm_mm_node_t *best; unsigned long best_size; + unsigned wasted; best = NULL; best_size = ~0UL; - if (alignment) - size += alignment - 1; - list_for_each(list, free_stack) { entry = list_entry(list, drm_mm_node_t, fl_entry); - if (entry->size >= size) { + wasted = 0; + + if (alignment) { + register unsigned tmp = size % alignment; + if (tmp) + wasted += alignment - tmp; + } + + + if (entry->size >= size + wasted) { if (!best_match) return entry; if (size < best_size) { @@ -170,29 +270,10 @@ int drm_mm_clean(drm_mm_t * mm) int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size) { - drm_mm_node_t *child; - INIT_LIST_HEAD(&mm->root_node.ml_entry); INIT_LIST_HEAD(&mm->root_node.fl_entry); - child = (drm_mm_node_t *) - drm_ctl_cache_alloc(drm_cache.mm, sizeof(*child), GFP_KERNEL); - - if (!child) - return -ENOMEM; - - INIT_LIST_HEAD(&child->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); - - child->start = start; - child->size = size; - child->free = 1; - child->mm = mm; - - list_add(&child->fl_entry, &mm->root_node.fl_entry); - list_add(&child->ml_entry, &mm->root_node.ml_entry); - - return 0; + return drm_mm_create_tail_node(mm, start, size); } EXPORT_SYMBOL(drm_mm_init); From e09544a2d3f44e96d01ed2bdcb4a4eb8eec26225 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:20:34 +0200 Subject: [PATCH 142/147] New mm function names. Update header. --- linux-core/drmP.h | 6 +++++- linux-core/drm_mm.c | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4ce5a3ec..1ed20b09 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1368,7 +1368,11 @@ extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern void drm_mm_takedown(drm_mm_t *mm); extern int drm_mm_clean(drm_mm_t *mm); -static inline drm_mm_t *drm_get_mm(drm_mm_node_t *block) +extern unsigned long drm_mm_tail_space(drm_mm_t *mm); +extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size); +extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size); + +static inline drm_mm_t *drm_get_mm(drm_mm_node_t *block) { return block->mm; } diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 5e0ba5e4..dcd55209 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -44,7 +44,7 @@ #include "drmP.h" #include -unsigned long tail_space(drm_mm_t *mm) +unsigned long drm_mm_tail_space(drm_mm_t *mm) { struct list_head *tail_node; drm_mm_node_t *entry; @@ -57,7 +57,7 @@ unsigned long tail_space(drm_mm_t *mm) return entry->size; } -int remove_space_from_tail(drm_mm_t *mm, unsigned long size) +int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size) { struct list_head *tail_node; drm_mm_node_t *entry; @@ -99,7 +99,7 @@ static int drm_mm_create_tail_node(drm_mm_t *mm, } -int add_space_to_tail(drm_mm_t *mm, unsigned long size) +int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size) { struct list_head *tail_node; drm_mm_node_t *entry; From f6d5fecdd20b9fd9e8744d8f43fa276b73a1da78 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 27 Oct 2006 11:28:37 +0200 Subject: [PATCH 143/147] Last minute changes to support multi-page size buffer offset alignments. This will come in very handy for tiled buffers on intel hardware. Also add some padding to interface structures to allow future binary backwards compatible changes. --- libdrm/xf86drm.c | 7 +++++-- libdrm/xf86mm.h | 10 +++++++--- linux-core/drmP.h | 2 +- linux-core/drm_bo.c | 8 ++++++-- linux-core/drm_mm.c | 5 ++++- shared-core/drm.h | 2 ++ 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 9047c8db..ebf3f834 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2613,12 +2613,14 @@ static void drmBOCopyReply(const drm_bo_arg_reply_t *rep, buf->start = rep->buffer_start; buf->fenceFlags = rep->fence_flags; buf->replyFlags = rep->rep_flags; + buf->pageAlignment = rep->page_alignment; } -int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, - void *user_buffer, drm_bo_type_t type, unsigned mask, +int drmBOCreate(int fd, unsigned long start, unsigned long size, + unsigned pageAlignment, void *user_buffer, drm_bo_type_t type, + unsigned mask, unsigned hint, drmBO *buf) { drm_bo_arg_t arg; @@ -2632,6 +2634,7 @@ int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, req->hint = hint; req->size = size; req->type = type; + req->page_alignment = pageAlignment; buf->virtual = NULL; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index da868fe5..bd0d2812 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -99,6 +99,7 @@ typedef struct _drmFence{ unsigned type; unsigned flags; unsigned signaled; + unsigned pad[4]; /* for future expansion */ } drmFence; typedef struct _drmBO{ @@ -113,9 +114,11 @@ typedef struct _drmBO{ unsigned long start; unsigned replyFlags; unsigned fenceFlags; + unsigned pageAlignment; void *virtual; void *mapVirtual; int mapCount; + unsigned pad[8]; /* for future expansion */ } drmBO; @@ -168,9 +171,10 @@ extern int drmBOCreateList(int numTarget, drmBOList *list); * Buffer object functions. */ -extern int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, - void *user_buffer, drm_bo_type_t type, unsigned mask, - unsigned hint, drmBO *buf); +extern int drmBOCreate(int fd, unsigned long start, unsigned long size, + unsigned pageAlignment,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); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1ed20b09..d02184c7 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1016,7 +1016,7 @@ typedef struct drm_buffer_object{ unsigned long buffer_start; drm_bo_type_t type; unsigned long offset; - + uint32_t page_alignment; atomic_t mapped; uint32_t flags; uint32_t mask; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 954b7a03..65e24fb6 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -571,7 +571,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, mutex_lock(&dev->struct_mutex); do { - node = drm_mm_search_free(mm, size, 0, 1); + node = drm_mm_search_free(mm, size, buf->page_alignment, 1); if (node) break; @@ -599,7 +599,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, return -ENOMEM; } - node = drm_mm_get_block(node, size, 0); + node = drm_mm_get_block(node, size, buf->page_alignment); mutex_unlock(&dev->struct_mutex); BUG_ON(!node); node->private = (void *)buf; @@ -959,6 +959,7 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, rep->buffer_start = bo->buffer_start; rep->fence_flags = bo->fence_type; rep->rep_flags = 0; + rep->page_alignment = bo->page_alignment; if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, @@ -1387,6 +1388,7 @@ int drm_buffer_object_create(drm_file_t * priv, drm_bo_type_t type, uint32_t mask, uint32_t hint, + uint32_t page_alignment, unsigned long buffer_start, drm_buffer_object_t ** buf_obj) { @@ -1426,6 +1428,7 @@ int drm_buffer_object_create(drm_file_t * priv, bo->num_pages = num_pages; bo->node_card = NULL; bo->node_ttm = NULL; + bo->page_alignment = page_alignment; if (bo->type == drm_bo_type_fake) { bo->offset = buffer_start; bo->buffer_start = 0; @@ -1516,6 +1519,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) req->type, req->mask, req->hint, + req->page_alignment, req->buffer_start, &entry); if (rep.ret) break; diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index dcd55209..a5566b2f 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -147,7 +147,10 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, drm_mm_node_t *align_splitoff = NULL; drm_mm_node_t *child; - unsigned tmp = size % alignment; + unsigned tmp = 0; + + if (alignment) + tmp = size % alignment; if (tmp) { align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); diff --git a/shared-core/drm.h b/shared-core/drm.h index 5784e59b..330aa3ff 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -770,6 +770,7 @@ typedef struct drm_bo_arg_request { drm_bo_type_t type; unsigned arg_handle; drm_u64_t buffer_start; + unsigned page_alignment; unsigned expand_pad[4]; /*Future expansion */ enum { drm_bo_create, @@ -804,6 +805,7 @@ typedef struct drm_bo_arg_reply { drm_u64_t buffer_start; unsigned fence_flags; unsigned rep_flags; + unsigned page_alignment; unsigned expand_pad[4]; /*Future expansion */ }drm_bo_arg_reply_t; From decacb2e6415029fe87a3680c8f967483ba05281 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 27 Oct 2006 13:08:31 +0200 Subject: [PATCH 144/147] Reserve the new IOCTLs also for *bsd. Bump libdrm version number to 2.2.0 --- configure.ac | 2 +- libdrm/xf86drm.c | 6 +----- shared-core/drm.h | 5 ----- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index b5d79456..224f43a5 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libdrm], 2.1.2-mm, [dri-devel@lists.sourceforge.net], libdrm) +AC_INIT([libdrm], 2.2.0, [dri-devel@lists.sourceforge.net], libdrm) AC_CONFIG_SRCDIR([Makefile.am]) AM_INIT_AUTOMAKE([dist-bzip2]) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index ebf3f834..df41d77a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -717,7 +717,7 @@ drmVersionPtr drmGetLibVersion(int fd) * revision 1.2.x = added drmSetInterfaceVersion * modified drmOpen to handle both busid and name */ - version->version_major = 1; + version->version_major = 2; version->version_minor = 2; version->version_patchlevel = 0; @@ -2257,7 +2257,6 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, return 0; } -#ifdef __linux__ /* * Valid flags are @@ -3216,6 +3215,3 @@ int drmMMUnlock(int fd, unsigned memType) return ret; } - - -#endif diff --git a/shared-core/drm.h b/shared-core/drm.h index 330aa3ff..16e86267 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -660,7 +660,6 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; -#ifdef __linux__ #define DRM_FENCE_FLAG_EMIT 0x00000001 #define DRM_FENCE_FLAG_SHAREABLE 0x00000002 @@ -844,8 +843,6 @@ typedef union drm_mm_init_arg{ unsigned expand_pad[8]; /*Future expansion */ } rep; } drm_mm_init_arg_t; -#endif - /** * \name Ioctls Definitions @@ -912,11 +909,9 @@ typedef union drm_mm_init_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_BUFOBJ DRM_IOWR(0x3d, drm_bo_arg_t) #define DRM_IOCTL_MM_INIT DRM_IOWR(0x3e, drm_mm_init_arg_t) -#endif #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t) From 56563c22d658b6dcb7926fd41513618cd46c31a6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 29 Oct 2006 15:39:11 +0100 Subject: [PATCH 145/147] Minor bugfix, indentation and removal of unnused variables. --- libdrm/xf86drm.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index df41d77a..5efb532b 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2369,14 +2369,14 @@ int drmFenceUpdate(int fd, drmFence *fence) drm_fence_arg_t arg; memset(&arg, 0, sizeof(arg)); - arg.handle = fence->handle; - 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; + arg.handle = fence->handle; + 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; } int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType, @@ -2493,7 +2493,6 @@ void drmBOFreeList(drmBOList *list) { drmBONode *node; drmMMListHead *l; - int ret = 0; l = list->list.next; while(l != &list->list) { @@ -2975,7 +2974,6 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, int *newItem) { drmBONode *node, *cur; - unsigned oldFlags, newFlags; drmMMListHead *l; *newItem = 0; @@ -3146,7 +3144,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) return -EFAULT; if (rep->ret) return rep->ret; - drmBOCopyReply(rep, buf); + drmBOCopyReply(rep, node->buf); } return 0; From 4b04c0cc45f7a89c757ce442e4f2742b9d3aa293 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 30 Oct 2006 11:18:44 +0100 Subject: [PATCH 146/147] Bugzilla Bug #8819 Build fixes for powerpc. Reported by Katerina Barone-Adesi --- linux-core/drm_ttm.c | 2 +- linux-core/drm_vm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 13bec48b..931972af 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -30,7 +30,7 @@ static void drm_ttm_ipi_handler(void *null) { - wbinvd(); + flush_agp_cache(); } static void drm_ttm_cache_flush(void) diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index fd6e89d8..6eb996ad 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -57,7 +57,7 @@ pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) } #elif defined(__powerpc__) pgprot_val(tmp) |= _PAGE_NO_CACHE; - if (map->type == _DRM_REGISTERS) + if (map_type == _DRM_REGISTERS) pgprot_val(tmp) |= _PAGE_GUARDED; #endif #if defined(__ia64__) From 7b6cd95bb6c41653aed78952da0a461bd4791413 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 31 Oct 2006 10:01:53 +0000 Subject: [PATCH 147/147] Fix bug #8839 - a comment --- bsd-core/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsd-core/i915_drv.c b/bsd-core/i915_drv.c index 269d7b36..d42b2076 100644 --- a/bsd-core/i915_drv.c +++ b/bsd-core/i915_drv.c @@ -1,4 +1,4 @@ -/* i915_drv.c -- ATI Radeon driver -*- linux-c -*- +/* i915_drv.c -- Intel i915 driver -*- linux-c -*- * Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com */ /*-