From 11f9e404fb66927146de30227fa05c5485aa1726 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 17:02:44 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 42c2cfcf7d5730a2961d425228e042f533b312fa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 20:30:19 +0200 Subject: 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 (limited to 'linux-core') 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; -- cgit v1.2.3 From 1c787f0d396c309131d5f34939598d657ee2459f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 20:38:57 +0200 Subject: 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 (limited to 'linux-core') 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 -- cgit v1.2.3 From 166da9355d95affe427a6cff3525df60e80a99df Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:02:08 +0200 Subject: User / Kernel space fence objects (device-independent part). --- linux-core/drmP.h | 76 ++++++- linux-core/drm_drv.c | 3 + linux-core/drm_fence.c | 587 +++++++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_stub.c | 1 + 4 files changed, 666 insertions(+), 1 deletion(-) create mode 100644 linux-core/drm_fence.c (limited to 'linux-core') 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: -- cgit v1.2.3 From 657bacc3953e8e51a0a15bd872e9818c9dbcbc10 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:04:36 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 6571f74a4906ae4f5f92916d64cc2cce3c8e0043 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:12:29 +0200 Subject: Remove some accidently included TTM code. --- linux-core/drmP.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'linux-core') 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) { -- cgit v1.2.3 From e089de33e8efd87b30d59c571b9ab9aa302b23e1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:36:00 +0200 Subject: 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 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 linux-core/i915_fence.c (limited to 'linux-core') 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); +} -- cgit v1.2.3 From 8d5b7c77f9b31aa9bcf81536d39769f4f3feeb63 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 21 Aug 2006 21:37:43 +0200 Subject: Allow longer sequence lifetimes. --- linux-core/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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, -- cgit v1.2.3 From 700bf80ca9fadf2c1404c220addebd92d9ad799d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 09:47:33 +0200 Subject: 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 +++++++++++++++-- 6 files changed, 1261 insertions(+), 21 deletions(-) create mode 100644 linux-core/drm_ttm.c create mode 100644 linux-core/drm_ttm.h (limited to 'linux-core') 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. */ } -- cgit v1.2.3 From b81ca5e031b2fbd9c5c401057c72f5857f7f5a3a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 10:09:57 +0200 Subject: AGP backends for TTM. --- linux-core/drmP.h | 12 ++++ linux-core/drm_agpsupport.c | 165 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) (limited to 'linux-core') 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 */ -- cgit v1.2.3 From 7058d06317e17253d874bf4df7b09d0d52a5fd74 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 10:24:48 +0200 Subject: 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 ++++++++ 4 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 linux-core/i915_buffer.c (limited to 'linux-core') 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, -- cgit v1.2.3 From a6535c8db4614376ce8ecb7d889b92db066a96cc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 10:44:09 +0200 Subject: Add a fence object class field for future use (For example VSYNC fence objects) --- linux-core/drmP.h | 1 + linux-core/drm_fence.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'linux-core') 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); -- cgit v1.2.3 From ca4e34e532e818921f7b2d36fc6886874b7f7924 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 11:19:53 +0200 Subject: 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(-) (limited to 'linux-core') 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)); -- cgit v1.2.3 From e201511a0fbeb177a9ecd7f77d177fc88c1616fb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 22 Aug 2006 11:57:08 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 4c03030b12bae28dad50d69bd271de632c43ff13 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 18:05:35 +0200 Subject: 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 - 6 files changed, 345 insertions(+), 13 deletions(-) create mode 100644 linux-core/drm_bo.c (limited to 'linux-core') 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; -- cgit v1.2.3 From 1d3cf107d20cb11ad07667622785ef8341ab9c2a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 18:14:22 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 35c8ce6c2945ff09dc52dbc2a7382798ba64c1da Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 19:03:42 +0200 Subject: 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 ++ 4 files changed, 45 insertions(+) (limited to 'linux-core') 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)); -- cgit v1.2.3 From c488e25ceb421c6f84f110d786d9814ac4dba1b2 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 25 Aug 2006 20:03:39 +0200 Subject: 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 +-- 3 files changed, 59 insertions(+), 9 deletions(-) (limited to 'linux-core') 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: 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 ++- 4 files changed, 239 insertions(+), 124 deletions(-) (limited to 'linux-core') 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 -- cgit v1.2.3 From 4fa58aa15242333a635cb590762c6e6312945745 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 19:07:38 +0200 Subject: Add TTM map handle on reference. --- linux-core/drm_ttm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'linux-core') 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: -- cgit v1.2.3 From ac26b51503dfedf422d6ae49518adcf41dff1af3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 19:45:38 +0200 Subject: 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(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From b4b7b997605f88f3ffdcb0cc7cd1271e0cb24073 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 21:16:13 +0200 Subject: Remove the ioctl multiplexing, and instead allow for generic drm ioctls 0x80 - 0xFF. --- linux-core/drm_bo.c | 43 ------------------------------------------- linux-core/drm_drv.c | 16 +++++++++++----- linux-core/drm_ttm.c | 4 ++-- linux-core/drm_ttm.h | 2 +- 4 files changed, 14 insertions(+), 51 deletions(-) (limited to 'linux-core') 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) + 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 if ((nr >= DRM_COMMAND_BASE) - && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) - ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; - else + else goto err_i1; + + func = ioctl->func; if ((nr == DRM_IOCTL_NR(DRM_IOCTL_DMA)) && dev->driver->dma_ioctl) /* Local override? */ func = dev->driver->dma_ioctl; 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)); -- cgit v1.2.3 From 886d3b3061cdf53f5a353cbaac843f63104d2658 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 22:01:33 +0200 Subject: Bugfixes. --- linux-core/drm_ttm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core') 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; } -- cgit v1.2.3 From e181f594a4a75790ce1d2a8e907f9fcc5e88b419 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 09:49:09 +0200 Subject: Add a 64-bit drm unsigned type for 64-bit clean IOCTLS. Conversion functions in drmP.h and xf86drm.c. --- linux-core/drmP.h | 19 +++++++++++-------- linux-core/drm_ttm.c | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From 480ea65ee4b02fa21d1ddf3bea09ac23085618cc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 10:58:21 +0200 Subject: Checkpoint buffer object IOCTL stub. --- linux-core/drm_bo.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) (limited to 'linux-core') 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; + } -- cgit v1.2.3 From 05536a64785223ee8c57556300a14ba9c89837ae Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 13:51:39 +0200 Subject: Buffer object idle and mapping synchronization. --- linux-core/drmP.h | 1 + linux-core/drm_bo.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) (limited to 'linux-core') 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); -- cgit v1.2.3 From 0d67356de4e0c9e0d068ea9c16cf33df4fd13776 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 16:36:37 +0200 Subject: 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 +++ 4 files changed, 207 insertions(+), 19 deletions(-) (limited to 'linux-core') 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); + + -- cgit v1.2.3 From 205740647060bc3bdec2b4402a666eb1015932ff Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 28 Aug 2006 17:51:53 +0200 Subject: Buffer object creation. --- linux-core/drm_bo.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 279e8d26c6cf7347aa9cb6d50d025a41dff9a5be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 10:45:34 +0200 Subject: =?UTF-8?q?64-bit=20IOCTL=20integer=20(Michel=20D=E4nzer=20&=20Bri?= =?UTF-8?q?an=20Paul)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- linux-core/drmP.h | 28 +--------------------------- linux-core/drm_bo.c | 32 +++++++++++++++++++++++++++++--- linux-core/drm_ttm.c | 4 ++-- linux-core/drm_ttm.h | 5 +++++ 4 files changed, 37 insertions(+), 32 deletions(-) (limited to 'linux-core') 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)); -- cgit v1.2.3 From 0dedfc2cd03f50b435476e56637b333d345fddbd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 14:52:02 +0200 Subject: 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 + 4 files changed, 90 insertions(+), 48 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From 23f01c9fe8e6170459fe46ad5fc9757bbe967d96 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 18:40:08 +0200 Subject: Checkpoint commit. Buffer object flags and IOCTL argument list. --- 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 ++ 5 files changed, 36 insertions(+), 7 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 033bda07e9a4eab5058fb919b375deb57b08b5be Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 09:57:35 +0200 Subject: 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 ++--- 4 files changed, 183 insertions(+), 160 deletions(-) (limited to 'linux-core') 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,17 +107,17 @@ typedef struct drm_ttm_object { uint32_t flags; drm_map_list_t map_list; } drm_ttm_object_t; - -extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, - uint32_t flags, drm_ttm_object_t **ttm_object); -extern void drm_ttm_object_deref_locked(struct drm_device *dev, drm_ttm_object_t *to); -extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, drm_ttm_object_t *to); -extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, - int check_owner); - - - +extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, + uint32_t flags, + drm_ttm_object_t ** ttm_object); +extern void drm_ttm_object_deref_locked(struct drm_device *dev, + drm_ttm_object_t * to); +extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, + drm_ttm_object_t * to); +extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, + uint32_t handle, + int check_owner); /* * Bind a part of the ttm starting at page_offset size n_pages into the GTT, at @@ -166,7 +166,7 @@ extern int drm_ttm_add_mm_to_list(drm_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; } -- cgit v1.2.3 From e47a4fda2ef7aada45b7799ad20e8012102dc12e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 13:04:08 +0200 Subject: Memory manager init and takedown. --- linux-core/drmP.h | 5 ++- linux-core/drm_bo.c | 123 +++++++++++++++++++++++++++++++++++++++++++++------ linux-core/drm_drv.c | 3 ++ 3 files changed, 116 insertions(+), 15 deletions(-) (limited to 'linux-core') 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 ) -- cgit v1.2.3 From 14a835be616183e733a2d6a7dcc697b8a6f46caf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 15:08:40 +0200 Subject: Buffer object mapping and mapping synchronization for multiple clients. --- linux-core/drm_bo.c | 3 +++ linux-core/drm_object.c | 4 +--- linux-core/drm_vm.c | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'linux-core') 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) { -- cgit v1.2.3 From d39055174b5a487f0d848e1af4c3459fb4261bf1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 17:40:07 +0200 Subject: Remove the buffer object hint field and use it only as an argument. Validate stub. --- linux-core/drmP.h | 1 - linux-core/drm_bo.c | 107 ++++++++++++++++++++++++++++++++++++++++++++------- linux-core/drm_drv.c | 2 +- 3 files changed, 94 insertions(+), 16 deletions(-) (limited to 'linux-core') 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 ) -- cgit v1.2.3 From 611662ab287c279a95ae33442325626e0191e2c5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 20:23:40 +0200 Subject: 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(-) (limited to 'linux-core') 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; - } - - /* - * 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. - */ + } + if (no_wait) + return -EBUSY; - 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); -- cgit v1.2.3 From 914a77a15aae07cc305cc5da5ad6c7a639cbc121 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 21:30:47 +0200 Subject: Buffer object binding. Some code reordering. --- linux-core/drmP.h | 6 ++ linux-core/drm_bo.c | 268 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 177 insertions(+), 97 deletions(-) (limited to 'linux-core') 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); } -- cgit v1.2.3 From ed9de124cc88cee398b7013de6b822bfaa3f397e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 21:31:38 +0200 Subject: Lindenting drm_bo.c and drm_ttm.c --- linux-core/drm_bo.c | 85 ++++++++++++++++++++++------------------------------- 1 file changed, 35 insertions(+), 50 deletions(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From ec8c79b79de6544cc09b5a2c85213a5f30e0d906 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 14:10:13 +0200 Subject: More mapping synchronization. libdrm validate and fencing functions. --- linux-core/drmP.h | 1 - linux-core/drm_bo.c | 163 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 122 insertions(+), 42 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 03c137c5f8d44c374406efe19c01105fcf34d583 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 15:36:40 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 44f6d08988a77a640bea40d09cb61eec7566a5ce Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 31 Aug 2006 21:42:29 +0200 Subject: Validation and fencing. --- linux-core/drmP.h | 11 +- linux-core/drm_bo.c | 571 +++++++++++++++++++++++++++++++---------------- linux-core/i915_buffer.c | 24 ++ linux-core/i915_drv.c | 4 +- linux-core/i915_fence.c | 1 + 5 files changed, 418 insertions(+), 193 deletions(-) (limited to 'linux-core') 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,12 +619,94 @@ static int drm_bo_busy(drm_buffer_object_t * bo) return 0; } +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; -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, @@ -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); } + -- cgit v1.2.3 From 4edb95d6e0a00a9a8885603cab2c99e3c6daa705 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 11:23:21 +0200 Subject: Various bugfixes. --- linux-core/drm_bo.c | 47 ++++++++++++++++++++++++++++++++--------------- linux-core/drm_ttm.c | 1 + linux-core/i915_buffer.c | 4 ++-- 3 files changed, 35 insertions(+), 17 deletions(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From 11f51a9a877d1231551e8c6482a6f70daf380cdd Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 15:41:55 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From ef8e618cf30ab7dcbe8c7211e0c2508c5520a669 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 16:38:06 +0200 Subject: Export buffer info on map and validate ioctls. Add an info ioctl operation. --- linux-core/drm_bo.c | 115 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 27 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From 405b5d9ca8cc9f6c5c7bb764c684bf74ba7660c6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 18:11:05 +0200 Subject: Flag bit pattern bugfixes. Remove some error messages. --- linux-core/drm_bo.c | 27 +++++++++++++-------------- linux-core/drm_ttm.c | 2 ++ 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'linux-core') 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, -- cgit v1.2.3 From a96b61fdc4fc3df50c91ca489f45f12cdad74f69 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 1 Sep 2006 18:11:34 +0200 Subject: Lindent drm_bo.c --- linux-core/drm_bo.c | 118 ++++++++++++++++++++++------------------------------ 1 file changed, 49 insertions(+), 69 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From a6b8e3eaf49044e135a0b9288192525f301458d5 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 16:57:20 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 550f51b4bf9920718aab2c611b15de3020537f92 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 21:50:12 +0200 Subject: 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 +--- 2 files changed, 43 insertions(+), 9 deletions(-) (limited to 'linux-core') 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: -- cgit v1.2.3 From 8c613a8363963330fbf701186f654007d6208bba Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 11:00:52 +0200 Subject: Fix memory cache initialization. --- linux-core/drm_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From 034fc31292edaa25779a938ab3e92ef34697eaf9 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 14:23:18 +0200 Subject: i915: Only turn on user IRQs when they are needed. --- linux-core/i915_fence.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'linux-core') 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); } } } -- cgit v1.2.3 From 604215396847a7964fd7d68aa89d4f778b3bf22b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 18:00:25 +0200 Subject: Fence all unfenced buffers function. --- linux-core/drmP.h | 14 ++++++-- linux-core/drm_bo.c | 33 ++++++++--------- linux-core/drm_fence.c | 96 +++++++++++++++++++++++++++++++------------------- 3 files changed, 87 insertions(+), 56 deletions(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From 99acb7936660843090ea8a9f22d2d50d9433e0de Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 8 Sep 2006 17:24:38 +0200 Subject: Various bugfixes. --- 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 +++--- 8 files changed, 172 insertions(+), 72 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 191e284709ee792a32124e96e43d5876406b93dc Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 12:01:00 +0200 Subject: More bugfixes. Disable the i915 IRQ turnoff for now since it seems to be causing problems. --- 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 +++++++-- 6 files changed, 45 insertions(+), 18 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From 861b26578cd5e497fb506ad5952fa62bd03ea201 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 16:28:34 +0200 Subject: Use lazy fence wait when possible even for RW fences. Saves some CPU. Lindent. --- linux-core/drm_bo.c | 56 +++++++++++++++++++---------------- linux-core/drm_fence.c | 77 ++++++++++++++++++++++++++++++++---------------- linux-core/i915_buffer.c | 5 ++++ 3 files changed, 87 insertions(+), 51 deletions(-) (limited to 'linux-core') 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); } -- cgit v1.2.3 From 9adc9584a7e0b61b16a943720bef31a71faeaef4 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 12 Sep 2006 17:39:44 +0200 Subject: 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(-) (limited to 'linux-core') 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, -- cgit v1.2.3 From 682c6ed0293771b093452597540118f47fda1adf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 14 Sep 2006 12:17:38 +0200 Subject: 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(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From 7223b4e264a64df2df70715d8777f2ccaa883d5e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 14 Sep 2006 16:42:00 +0200 Subject: Simplify ttm alloc and free. --- linux-core/drm_ttm.c | 32 +++++++++++++++----------------- linux-core/drm_ttm.h | 3 --- 2 files changed, 15 insertions(+), 20 deletions(-) (limited to 'linux-core') 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) + +static void ttm_free(void *pointer, unsigned long size, int type) { - if (!do_vfree) { - drm_free(pointer, size, type); - }else { + + 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 { -- cgit v1.2.3 From 49fbeb339c232804866cd548d6023fe559597353 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 15 Sep 2006 11:18:35 +0200 Subject: 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. --- 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 ++++++++++++++++++++++--------- 5 files changed, 58 insertions(+), 31 deletions(-) (limited to 'linux-core') 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); } -- cgit v1.2.3 From f613022ceef1814cb734bb3375f01962fd3bcf10 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 15 Sep 2006 16:47:09 +0200 Subject: 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 ++- 5 files changed, 66 insertions(+), 118 deletions(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From c4fad4c96168a3dfabaa8a7e97758fefd014c8a7 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 18 Sep 2006 16:02:33 +0200 Subject: More verbose error reporting in some cases. Add a buffer object waitIdle user-space function. Fix some names and minor glitches. --- linux-core/drm_fence.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From ca1b15d645c74e20f638f5a09981bcf02f58caee Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 18 Sep 2006 20:43:31 +0200 Subject: Alternative implementation of page table zeroing using zap page_range. (Disabled for now) Fix bo_wait_idle bug. Remove stray debug message. --- linux-core/drm_bo.c | 4 +++- linux-core/drm_compat.c | 14 ++++++++++++++ linux-core/i915_fence.c | 1 - 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From aac918e7c72a46a1b0f2329380e2d6b4196d04e4 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 18 Sep 2006 21:50:00 +0200 Subject: Fence handler fix --- linux-core/drm_fence.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'linux-core') 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) { -- cgit v1.2.3 From fa511a3ff5150d932fd963594d1ef67a94bb8b1f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 20 Sep 2006 16:31:15 +0200 Subject: Allow for 64-bit map handles of ttms and buffer objects. --- linux-core/drmP.h | 2 +- linux-core/drm_proc.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'linux-core') 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"); -- cgit v1.2.3 From a02155a0d92d3933d42a3655db261446bfe72b44 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 22 Sep 2006 09:25:36 +0200 Subject: 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(-) (limited to 'linux-core') 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, -- cgit v1.2.3 From 273eb7833d69db2d72430d5c96c21cebd05c206e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 25 Sep 2006 11:51:08 +0200 Subject: 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 +++ 5 files changed, 122 insertions(+), 18 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From 711f077b7423c1a436d703885c6d18a2ad2940aa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 26 Sep 2006 14:36:53 +0200 Subject: 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(-) (limited to 'linux-core') 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) -- cgit v1.2.3 From 26528627a6cea7f92a949e89e5db6e17ef9560c2 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 26 Sep 2006 14:40:11 +0200 Subject: 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(-) (limited to 'linux-core') 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)); -- cgit v1.2.3 From 235f6fc650e9974211843b9196a903963dae0211 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 09:27:31 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From c97149b45be9d0e9385d4c6721aa70dad68a1aa1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 09:31:39 +0200 Subject: Fix tt fixed size that slipped through in previous commit. --- linux-core/drm_bo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From f2c03ecae627df77db25391fe85fcd8a2a4bdc0c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 19:07:55 +0200 Subject: Fix racy buffer object destruction. --- linux-core/drm_bo.c | 64 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 10 deletions(-) (limited to 'linux-core') 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. + */ - list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { - fence = entry->fence; + if (atomic_read(&entry->usage) != 0) + continue; + + /* + * Since we're the only users, No need to take the + * bo->mutex to watch the fence. + */ + 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) { + + /* + * 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(&entry->ddestroy); + 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; -- cgit v1.2.3 From 1c6f0ea43c47603c2265248ce8a91698c8982f3c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 27 Sep 2006 19:11:27 +0200 Subject: 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(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From c52fafa6288b4e6ecfce27151969749113a41f0b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 28 Sep 2006 11:33:03 +0200 Subject: Don't enable fence / buffer objects on non-linux systems. Bump driver minor and date. --- linux-core/i915_drv.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'linux-core') 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, -- cgit v1.2.3 From 3802f9adbf9a7e3d5c356f74b0c1ee966476fb97 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Sep 2006 11:15:59 +0200 Subject: 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 | 190 ++++++++++++++++++++++++++++++++++------------------ 2 files changed, 128 insertions(+), 69 deletions(-) (limited to 'linux-core') 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; } + } + 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_DEBUG("Destroying delayed buffer object\n"); - drm_bo_destroy_locked(dev, entry); - l = bm->ddestroy.next; + + 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"); -- cgit v1.2.3 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: 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 +++++++++++++++++++++++++++++++++++---------------- 3 files changed, 57 insertions(+), 27 deletions(-) (limited to 'linux-core') 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_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); - list_del(list); + list_del(list); - drm_free(vbl_sig, sizeof(*vbl_sig), DRM_MEM_DRIVER); + drm_free(vbl_sig, sizeof(*vbl_sig), + DRM_MEM_DRIVER); - dev->vbl_pending--; + dev->vbl_pending--; + } } } -- cgit v1.2.3 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: 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 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux-core') 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, -- cgit v1.2.3 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: 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(+) (limited to 'linux-core') 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 -- cgit v1.2.3 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: 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) --- linux-core/Makefile | 4 ++-- linux-core/drmP.h | 10 +++++++++ linux-core/drm_drawable.c | 57 +---------------------------------------------- linux-core/drm_stub.c | 1 + 4 files changed, 14 insertions(+), 58 deletions(-) mode change 100644 => 120000 linux-core/drm_drawable.c (limited to 'linux-core') 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); -- cgit v1.2.3 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: 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(-) (limited to 'linux-core') 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 ) -- cgit v1.2.3 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: Drop tasklet locked driver callback when uninstalling IRQ. (cherry picked from b9f3009160d8bd1a26a77d6f1616f1679c7b969d commit) --- linux-core/drm_irq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux-core') 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); -- cgit v1.2.3 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: 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 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'linux-core') 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); -- cgit v1.2.3 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: 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) --- linux-core/drm_irq.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 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: 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(-) (limited to 'linux-core') 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) -- cgit v1.2.3 From c6be27401fbc12ec72bac13d07e3cc93bd63732a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:34:30 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 418b81c65c55601d4e414b351db5b8d76db8a109 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:37:54 +0200 Subject: Add a comment to previos commit. --- linux-core/drm_fops.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'linux-core') 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 " -- cgit v1.2.3 From d85b99435f0ea7a17b3b7be31b53c00632c07177 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 13:49:43 +0200 Subject: 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(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From a31046b8734f12ed22127ef5f6ca4fc33df72ec1 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 14:03:15 +0200 Subject: 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(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From eacedf41a65f135722e7bee6f1a66a803619237f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 2 Oct 2006 15:06:35 +0200 Subject: 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. --- linux-core/drm_ttm.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 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: 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 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From cee659afb56e7ac443402ac791144f391721061e Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 3 Oct 2006 12:08:07 +0200 Subject: 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(-) (limited to 'linux-core') 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 { -- cgit v1.2.3 From c58574c60505a699e19e1ed59e1b441be2594e53 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 10 Oct 2006 10:37:26 +0200 Subject: 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 | 48 +++++++++---- 8 files changed, 155 insertions(+), 189 deletions(-) (limited to 'linux-core') 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); - get_page(page); + if (page_flags & DRM_TTM_PAGE_UNCACHED) { - default_prot = vm_get_page_prot(vma->vm_flags); + /* + * This makes sure we don't race with another + * drm_ttm_remap_bound_pfn(); + */ - BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED); + 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); + + 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)) { -- cgit v1.2.3 From f2db76e2f206d2017f710eaddc4b33add4498898 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 11 Oct 2006 13:40:35 +0200 Subject: 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. --- 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 | 29 +- linux-core/drm_drv.c | 1 - linux-core/drm_ttm.c | 649 ++++++++++---------------------------------- linux-core/drm_ttm.h | 84 ++---- linux-core/drm_vm.c | 255 ++++++----------- 9 files changed, 327 insertions(+), 796 deletions(-) (limited to 'linux-core') 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() -#endif +extern int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, + unsigned long pfn, pgprot_t pgprot); -/* - * Is the PTE for this address really clear so that we can use - * io_remap_pfn_range? - */ +extern struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type); -int drm_pte_is_clear(struct vm_area_struct *vma, - unsigned long addr); +extern struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, + struct fault_data *data); #endif +#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"); - 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_TTM); - if (!ttm->vma_list) { - DRM_ERROR("Alloc vma list 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->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. + * Unbind a ttm region from the aperture. */ -static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, - unsigned long num_pages, int noncached) +int drm_evict_ttm(drm_ttm_t * ttm) { - int i, cur; - struct page **cur_page; - int do_tlbflush = 0; + drm_ttm_backend_t *be = ttm->be; - 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; - } + switch (ttm->state) { + case ttm_bound: + if (be->needs_cache_adjust(be)) { + unmap_vma_pages(ttm); } + be->unbind(be); + break; + default: + break; } - if (do_tlbflush) - flush_agp_mappings(); + ttm->state = ttm_evicted; return 0; } -/* - * Unbind a ttm region from the aperture. - */ - -int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) +void drm_fixup_ttm_caching(drm_ttm_t * ttm) { - drm_ttm_backend_t *be = entry->be; - drm_ttm_t *ttm = entry->owner; - 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; + 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->state = ttm_evicted; - return 0; } + -void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry) +void drm_unbind_ttm(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); + if (ttm->state == ttm_bound) + drm_evict_ttm(ttm); - 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); + drm_fixup_ttm_caching(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) +int drm_bind_ttm(drm_ttm_t * ttm, + unsigned long aper_offset) { - 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); - } - } - - 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_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; -} - -/* - * 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) + 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; - 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; + uint32_t page_flags; unsigned long num_pages; - drm_ttm_vma_list_t *vma_list; + unsigned long aper_offset; + atomic_t vma_count; 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_backend_t *be; + enum { + ttm_bound, + ttm_evicted, + ttm_unbound, + ttm_unpopulated, + } state; } 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); - -/* - * Rebind an already evicted region into a possibly new location in the aperture. - */ +extern int drm_evict_ttm(drm_ttm_t * ttm); +extern void drm_fixup_ttm_caching(drm_ttm_t *ttm); -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) -{ - 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) +#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) { - 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; -- cgit v1.2.3 From 30703893674b3da5b862dee2acd6efca13424398 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 11 Oct 2006 22:21:01 +0200 Subject: 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. --- 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 +++----- 6 files changed, 428 insertions(+), 44 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 10150df02b7062b9975661ccd82b475cd23c8839 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 12 Oct 2006 12:09:16 +0200 Subject: 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 ++++----- 6 files changed, 95 insertions(+), 98 deletions(-) (limited to 'linux-core') 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,56 +646,21 @@ 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 *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_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; - agp_be->needs_free = (backend == NULL); - 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 *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; - agp_be = (backend != NULL) ? backend: drm_calloc(1, sizeof(*agp_be), DRM_MEM_MAPPINGS); @@ -709,21 +675,26 @@ drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev, } agp_priv->mem = NULL; - agp_priv->mem_type = AGP_MEM_UCACHED; + 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_false; + 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_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; -- cgit v1.2.3 From 540c64c378daafaad1c3f63faf5af81f39388665 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 12 Oct 2006 16:10:47 +0200 Subject: Bugfixes. --- linux-core/drm_agpsupport.c | 2 +- linux-core/drm_bo.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 1bab514c0a1a535c19d53e3d39e3b351db3ab7a4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 14 Oct 2006 23:38:20 +1000 Subject: 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 - 20 files changed, 21 deletions(-) delete mode 120000 linux-core/drm_drawable.c (limited to 'linux-core') 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" -- cgit v1.2.3 From 5b2a60f550090a41c13483ceaaa1a84d3a9257f8 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 16 Oct 2006 14:22:27 +0200 Subject: 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 (limited to 'linux-core') 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) { -- cgit v1.2.3 From 5881ce1b91034fbdf81dda37a23215cfc1310cdf Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 11:05:37 +0200 Subject: Extend generality for more memory types. Fix up init and destruction code. --- linux-core/drmP.h | 35 ++-- linux-core/drm_bo.c | 566 +++++++++++++++++++++++++++++++------------------- linux-core/drm_drv.c | 9 +- linux-core/drm_stub.c | 1 + linux-core/i915_drv.c | 5 +- 5 files changed, 381 insertions(+), 235 deletions(-) (limited to 'linux-core') 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); - - mutex_lock(&dev->struct_mutex); - if (evict) - ret = drm_evict_ttm(buf->ttm); - else - ret = drm_unbind_ttm(buf->ttm); + if (buf->node_ttm) { + mutex_lock(&dev->struct_mutex); + if (evict) + ret = drm_evict_ttm(buf->ttm); + else + ret = drm_unbind_ttm(buf->ttm); - if (ret) { + if (ret) { + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) + schedule(); + return ret; + } + + drm_mm_put_block(&bm->manager[DRM_BO_MEM_TT], buf->node_ttm); + buf->node_ttm = NULL; mutex_unlock(&dev->struct_mutex); - if (ret == -EAGAIN) - schedule(); - return ret; } - - drm_mm_put_block(&bm->tt_manager, buf->tt); - buf->tt = NULL; - 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,89 +1605,200 @@ 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 (mem_type >= DRM_BO_MEM_TYPES) { + DRM_ERROR("Illegal memory type %d\n", mem_type); + return ret; + } - if (!bm->initialized) - goto out; + 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; - bm->use_vram = 0; - bm->use_tt = 0; + 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); - /* - * FIXME: Need to handle unfenced list. - */ + if (drm_mm_clean(&bm->manager[mem_type])) { + drm_mm_takedown(&bm->manager[mem_type]); + } else { + ret = -EBUSY; + } + } - 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); + return ret; +} - if (bm->has_vram) { - if (drm_mm_clean(&bm->vram_manager)) { - drm_mm_takedown(&bm->vram_manager); - bm->has_vram = 0; - } else - ret = -EBUSY; +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; } - if (bm->has_tt) { - if (drm_mm_clean(&bm->tt_manager)) { - drm_mm_takedown(&bm->tt_manager); - bm->has_tt = 0; - } else - ret = -EBUSY; + 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; +} + - if (!ret) - bm->initialized = 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]); } +} - out: +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) { @@ -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 -- cgit v1.2.3 From db5c671e86c3db8c99ce5a4954632248e6f849aa Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 11:28:48 +0200 Subject: 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(-) (limited to 'linux-core') 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; } -- cgit v1.2.3 From 5443dbe35f182b9286a96d24d29037d5cb625e3d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 16:00:25 +0200 Subject: 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. --- linux-core/drmP.h | 5 ++ linux-core/drm_bo.c | 188 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 143 insertions(+), 50 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From d515936ea7f98f6aaa9217699796beadef9d664b Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:40:57 +0200 Subject: 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(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From f22f89e6b3c970a29197d3a53c170fb7d0340cbe Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:52:34 +0200 Subject: 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(-) (limited to 'linux-core') 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; } } -- cgit v1.2.3 From 89b944179856fadf8667587eff142129c2c6b826 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 19:57:06 +0200 Subject: Lindent. --- linux-core/drm_bo.c | 249 ++++++++++++++++++++++++----------------------- 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, 218 insertions(+), 231 deletions(-) (limited to 'linux-core') 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) + + 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->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); + 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; - } - 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; + 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; } - 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); } - -- cgit v1.2.3 From c34faf224b959bf61e4c3eb29c66a12edbd31841 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 20:03:26 +0200 Subject: Remove max number of locked pages check and call, since that is now handled by the memory accounting. --- linux-core/drmP.h | 1 - linux-core/drm_bo.c | 27 --------------------------- linux-core/drm_compat.c | 5 ----- 3 files changed, 33 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From e172945d668f1de1243ac2ae91ab77f3b2bda40a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 18 Oct 2006 16:54:17 +0200 Subject: 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(-) (limited to 'linux-core') 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) -- cgit v1.2.3 From 11aaa358a0f56afb64df44c737ec331d90118537 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 18 Oct 2006 17:18:23 +0200 Subject: Remove stray softlink. --- linux-core/drm_drawable.c | 1 - 1 file changed, 1 deletion(-) delete mode 120000 linux-core/drm_drawable.c (limited to 'linux-core') 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 -- cgit v1.2.3 From e8ba62db722eb0b915377269d7e1c3a039928669 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 19 Oct 2006 16:58:00 +0200 Subject: 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(-) (limited to 'linux-core') 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) { - - /* - * Protect the "next" entry against destruction in case - * drm_bo_destroy_locked temporarily releases the - * struct_mutex; - */ + 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)); - 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"); + } + } + if (entry->fence) { + drm_fence_usage_deref_unlocked(dev, + entry->fence); + entry->fence = NULL; } - DRM_DEBUG("Destroying delayed buffer object\n"); + } + 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; -- cgit v1.2.3 From 3624e43282b0c6aad32829f116fd8f7bce66fbb6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 20 Oct 2006 15:06:31 +0200 Subject: 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(-) (limited to 'linux-core') 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,8 +50,14 @@ 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) { @@ -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, -- cgit v1.2.3 From 9321592149c031694c459bb05e7a31d1197fe5cb Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 20 Oct 2006 15:07:21 +0200 Subject: We apparently need this global cache flush anyway. --- linux-core/drm_agpsupport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core') 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) { -- cgit v1.2.3 From a8909a0ebcc21ad6b92b93ffe87878ece4b56506 Mon Sep 17 00:00:00 2001 From: Tilman Sauerbeck Date: Fri, 20 Oct 2006 17:05:07 +0200 Subject: Bug #1746: Set dev_priv_size for the MGA driver. --- linux-core/mga_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core') 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, -- cgit v1.2.3 From 9ed4656799043f24f4d64615ebb8128bedc99799 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sat, 21 Oct 2006 14:17:51 +0200 Subject: 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(-) (limited to 'linux-core') 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) { -- cgit v1.2.3 From b4fba1679b6156e3ca6f053b44cae0b003febe7f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:14:23 +0200 Subject: 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(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From 47dbfc4e4a3e8ce2ec468bc3874f74f7e2b13476 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:17:43 +0200 Subject: 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(-) (limited to 'linux-core') 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 -drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, - unsigned long size, unsigned alignment) +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; - if (alignment) - size += alignment - 1; + 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; + 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); -- cgit v1.2.3 From e09544a2d3f44e96d01ed2bdcb4a4eb8eec26225 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 26 Oct 2006 21:20:34 +0200 Subject: New mm function names. Update header. --- linux-core/drmP.h | 6 +++++- linux-core/drm_mm.c | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'linux-core') 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; -- cgit v1.2.3 From f6d5fecdd20b9fd9e8744d8f43fa276b73a1da78 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 27 Oct 2006 11:28:37 +0200 Subject: 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. --- linux-core/drmP.h | 2 +- linux-core/drm_bo.c | 8 ++++++-- linux-core/drm_mm.c | 5 ++++- 3 files changed, 11 insertions(+), 4 deletions(-) (limited to 'linux-core') 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); -- cgit v1.2.3 From 4b04c0cc45f7a89c757ce442e4f2742b9d3aa293 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 30 Oct 2006 11:18:44 +0100 Subject: 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(-) (limited to 'linux-core') 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__) -- cgit v1.2.3