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(-) 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 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 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). --- libdrm/xf86drm.c | 119 ++++++++++ libdrm/xf86drm.h | 20 ++ linux-core/drmP.h | 76 ++++++- linux-core/drm_drv.c | 3 + linux-core/drm_fence.c | 587 +++++++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_stub.c | 1 + shared-core/drm.h | 30 ++- 7 files changed, 834 insertions(+), 2 deletions(-) create mode 100644 linux-core/drm_fence.c diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index c9f1b2db..6302db3a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2236,3 +2236,122 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, } return 0; } + +int drmFenceCreate(int fd, int shareable, unsigned type, int emit, + drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.type = type; + arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0; + arg.flags |= (emit) ? DRM_FENCE_FLAG_EMIT : 0; + arg.op = drm_fence_create; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->handle = arg.handle; + fence->type = arg.type; + fence->signaled = 0; + return 0; +} + +int drmFenceDestroy(int fd, const drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.op = drm_fence_destroy; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + return 0; +} + +int drmFenceReference(int fd, unsigned handle, drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.handle = handle; + arg.op = drm_fence_reference; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->handle = arg.handle; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceUnreference(int fd, const drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.op = drm_fence_unreference; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + return 0; +} + +int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.type = flush_type; + arg.op = drm_fence_flush; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceSignaled(int fd, drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.op = drm_fence_signaled; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) +{ + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.type = emit_type; + arg.op = drm_fence_emit; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, + int lazy, int ignore_signals) +{ + drm_fence_arg_t arg; + int ret; + + arg.handle = fence->handle; + arg.type = flush_type; + arg.flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0; + arg.flags |= (ignore_signals) ? DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS : 0; + arg.op = drm_fence_wait; + do { + ret = ioctl(fd, DRM_IOCTL_FENCE, &arg); + } while (ret != 0 && errno == EAGAIN); + + if (ret) + return -errno; + + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + + diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 48a18f29..0e037daa 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -280,6 +280,11 @@ typedef struct _drmSetVersion { int drm_dd_minor; } drmSetVersion, *drmSetVersionPtr; +typedef struct _drmFence{ + unsigned handle; + unsigned type; + unsigned signaled; +} drmFence; #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) @@ -596,6 +601,21 @@ extern int drmScatterGatherFree(int fd, drm_handle_t handle); extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); +/* Fencing */ + +extern int drmFenceCreate(int fd, int shareable, unsigned type, int emit, + drmFence *fence); +extern int drmFenceDestroy(int fd, const drmFence *fence); +extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); +extern int drmFenceUnreference(int fd, const drmFence *fence); +extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); +extern int drmFenceSignaled(int fd, drmFence *fence); +extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, + int lazy, int ignore_signals); +extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); + + + /* Support routines */ extern int drmError(int err, const char *label); extern void *drmMalloc(int size); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 81ca6aec..4be49b56 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -155,6 +155,7 @@ #define DRM_MEM_MM 22 #define DRM_MEM_HASHTAB 23 #define DRM_MEM_OBJECTS 24 +#define DRM_MEM_FENCE 25 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) @@ -637,6 +638,8 @@ struct drm_driver { unsigned long (*get_reg_ofs) (struct drm_device * dev); void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); + struct drm_fence_driver *fence_driver; + int major; int minor; int patchlevel; @@ -667,6 +670,36 @@ typedef struct drm_head { } drm_head_t; +typedef struct drm_fence_driver{ + int no_types; + uint32_t wrap_diff; + uint32_t flush_diff; + uint32_t sequence_mask; + int lazy_capable; + int (*emit) (struct drm_device *dev, uint32_t *breadcrumb); + void (*poke_flush) (struct drm_device *dev); +} drm_fence_driver_t; + + +typedef struct drm_fence_manager{ + int initialized; + rwlock_t lock; + + /* + * The list below should be maintained in sequence order and + * access is protected by the above spinlock. + */ + + struct list_head ring; + struct list_head *fence_types[32]; + volatile uint32_t pending_flush; + wait_queue_head_t fence_queue; + int pending_exe_flush; + uint32_t last_exe_flush; + uint32_t exe_flush_sequence; +} drm_fence_manager_t; + + /** * DRM device structure. This structure represent a complete card that * may contain multiple heads. @@ -798,8 +831,20 @@ typedef struct drm_device { drm_local_map_t *agp_buffer_map; unsigned int agp_buffer_token; drm_head_t primary; /**< primary screen head */ + + drm_fence_manager_t fm; + } drm_device_t; +#if __OS_HAS_AGP +typedef struct drm_agp_ttm_priv { + DRM_AGP_MEM *mem; + struct agp_bridge_data *bridge; + unsigned mem_type; + int populated; +} drm_agp_ttm_priv; +#endif + static __inline__ int drm_core_check_feature(struct drm_device *dev, int feature) { @@ -894,6 +939,24 @@ typedef struct drm_ref_object { drm_ref_t unref_action; } drm_ref_object_t; +typedef struct drm_fence_object{ + drm_user_object_t base; + atomic_t usage; + + /* + * The below three fields are protected by the fence manager spinlock. + */ + + struct list_head ring; + volatile uint32_t type; + volatile uint32_t signaled; + uint32_t sequence; + volatile uint32_t flush_mask; + volatile uint32_t submitted_flush; +} drm_fence_object_t; + + + /******************************************************************/ @@ -924,7 +987,6 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); extern unsigned long drm_core_get_map_ofs(drm_map_t * map); extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev); -extern pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma); /* Memory management support (drm_memory.h) */ #include "drm_memory.h" @@ -1205,6 +1267,18 @@ extern int drm_user_object_ref(drm_file_t *priv, uint32_t user_token, drm_object extern int drm_user_object_unref(drm_file_t *priv, uint32_t user_token, drm_object_type_t type); + +/* + * fence objects (drm_fence.c) + */ + +extern void drm_fence_handler(drm_device_t *dev, uint32_t breadcrumb, uint32_t type); +extern void drm_fence_manager_init(drm_device_t *dev); +extern void drm_fence_manager_takedown(drm_device_t *dev); +extern void drm_fence_flush_old(drm_device_t *dev, uint32_t sequence); +extern int drm_fence_ioctl(DRM_IOCTL_ARGS); + + /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_map *map, struct drm_device *dev) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index ccfd1855..e6ae690a 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -119,6 +119,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE)] = {drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, + [DRM_IOCTL_NR(DRM_IOCTL_FENCE)] = {drm_fence_ioctl, DRM_AUTH}, }; #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls ) @@ -347,6 +348,8 @@ static void __exit drm_cleanup(drm_device_t * dev) drm_lastclose(dev); + drm_fence_manager_takedown(dev); + if (dev->maplist) { drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c new file mode 100644 index 00000000..fc27c576 --- /dev/null +++ b/linux-core/drm_fence.c @@ -0,0 +1,587 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" + +static void drm_fm_update_pointers(drm_fence_manager_t * fm, + struct list_head *list, int no_types, + uint32_t type) +{ + int i; + for (i = 0; i < no_types; ++i) { + if (type & (1 << i)) { + fm->fence_types[i] = list; + } + } +} + +/* + * Typically called by the IRQ handler. + */ + +void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) +{ + int i; + int wake = 0; + int largest = 0; + uint32_t diff; + uint32_t relevant; + int index = 0; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + struct list_head *list; + struct list_head *fence_list; + drm_fence_object_t *fence; + int found = 0; + + for (i = 0; i < driver->no_types; ++i) { + if (!(type & (1 << i))) + continue; + + list = fm->fence_types[i]; + fence_list = list->next; + + if (fence_list == &fm->ring) + continue; + + fence = list_entry(fence_list, drm_fence_object_t, ring); + + diff = (sequence - fence->sequence) & driver->sequence_mask; + + if (diff < driver->wrap_diff) { + if (diff >= largest) { + largest = diff; + index = i; + found = 1; + } + } + } + + if (!found) + return; + + /* + * Start with the fence object with the lowest sequence number, affected by + * the type mask of this call. Update signaled fields, + * Check if we need to wake sleeping processes + */ + + list = fm->fence_types[index]->next; + do { + if (list == &fm->ring) { + drm_fm_update_pointers(fm, list->prev, + driver->no_types, type); + break; + } + fence = list_entry(list, drm_fence_object_t, ring); + diff = (sequence - fence->sequence) & driver->sequence_mask; + if (diff >= driver->wrap_diff) { + drm_fm_update_pointers(fm, fence->ring.prev, + driver->no_types, type); + break; + } + relevant = type & fence->type; + if ((fence->signaled | relevant) != fence->signaled) { + fence->signaled |= relevant; + fence->submitted_flush |= relevant; + wake = 1; + } + + relevant = fence->flush_mask & + ~(fence->signaled | fence->submitted_flush); + if (relevant) { + fm->pending_flush |= relevant; + fence->submitted_flush = fence->flush_mask; + } + + list = list->next; + + /* + * Remove a completely signaled fence from the + * fence manager ring. + */ + + if (!(fence->type & ~fence->signaled)) { + fence_list = &fence->ring; + for (i = 0; i < driver->no_types; ++i) { + if (fm->fence_types[i] == fence_list) + fm->fence_types[i] = fence_list->prev; + } + list_del_init(fence_list); + } + + } while (1); + + /* + * Wake sleeping processes. + */ + + if (wake) { + DRM_WAKEUP(&fm->fence_queue); + } +} + +EXPORT_SYMBOL(drm_fence_handler); + +static void drm_fence_unring(drm_device_t * dev, struct list_head *ring) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + unsigned long flags; + int i; + + write_lock_irqsave(&fm->lock, flags); + for (i = 0; i < driver->no_types; ++i) { + if (fm->fence_types[i] == ring) + fm->fence_types[i] = ring->prev; + } + list_del_init(ring); + write_unlock_irqrestore(&fm->lock, flags); +} + +void drm_fence_usage_deref_locked(drm_device_t * dev, + drm_fence_object_t * fence) +{ + if (atomic_dec_and_test(&fence->usage)) { + drm_fence_unring(dev, &fence->ring); + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + } +} + +void drm_fence_usage_deref_unlocked(drm_device_t * dev, + drm_fence_object_t * fence) +{ + if (atomic_dec_and_test(&fence->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&fence->usage) == 0) { + drm_fence_unring(dev, &fence->ring); + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + } + mutex_unlock(&dev->struct_mutex); + } +} + +static void drm_fence_object_destroy(drm_file_t * priv, + drm_user_object_t * base) +{ + drm_device_t *dev = priv->head->dev; + drm_fence_object_t *fence = + drm_user_object_entry(base, drm_fence_object_t, base); + + drm_fence_usage_deref_locked(dev, fence); +} + +static int fence_signaled(drm_device_t * dev, drm_fence_object_t * fence, + uint32_t mask, int poke_flush) +{ + unsigned long flags; + int signaled; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + + if (poke_flush) + driver->poke_flush(dev); + read_lock_irqsave(&fm->lock, flags); + signaled = + (fence->type & mask & fence->signaled) == (fence->type & mask); + read_unlock_irqrestore(&fm->lock, flags); + + return signaled; +} + +static void drm_fence_flush_exe(drm_fence_manager_t * fm, + drm_fence_driver_t * driver, uint32_t sequence) +{ + uint32_t diff; + + if (!fm->pending_exe_flush) { + struct list_head *list; + + /* + * Last_exe_flush is invalid. Find oldest sequence. + */ + + list = fm->fence_types[_DRM_FENCE_TYPE_EXE]; + if (list->next == &fm->ring) { + return; + } else { + drm_fence_object_t *fence = + list_entry(list->next, drm_fence_object_t, ring); + fm->last_exe_flush = (fence->sequence - 1) & + driver->sequence_mask; + } + diff = (sequence - fm->last_exe_flush) & driver->sequence_mask; + if (diff >= driver->wrap_diff) + return; + fm->exe_flush_sequence = sequence; + fm->pending_exe_flush = 1; + } else { + diff = + (sequence - fm->exe_flush_sequence) & driver->sequence_mask; + if (diff < driver->wrap_diff) { + fm->exe_flush_sequence = sequence; + } + } +} + +/* + * Make sure old fence objects are signaled before their fence sequences are + * wrapped around and reused. + */ + +static int drm_fence_object_flush(drm_device_t * dev, + drm_fence_object_t * fence, uint32_t type) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + unsigned long flags; + + if (type & ~fence->type) { + DRM_ERROR("Flush trying to extend fence type\n"); + return -EINVAL; + } + + write_lock_irqsave(&fm->lock, flags); + fence->flush_mask |= type; + if (fence->submitted_flush == fence->signaled) { + if ((fence->type & DRM_FENCE_EXE) && + !(fence->submitted_flush & DRM_FENCE_EXE)) { + drm_fence_flush_exe(fm, driver, fence->sequence); + fence->submitted_flush |= DRM_FENCE_EXE; + } else { + fm->pending_flush |= (fence->flush_mask & + ~fence->submitted_flush); + fence->submitted_flush = fence->flush_mask; + } + } + write_unlock_irqrestore(&fm->lock, flags); + driver->poke_flush(dev); + return 0; +} + +void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + uint32_t old_sequence; + unsigned long flags; + drm_fence_object_t *fence; + uint32_t diff; + + mutex_lock(&dev->struct_mutex); + read_lock_irqsave(&fm->lock, flags); + if (fm->ring.next == &fm->ring) { + read_unlock_irqrestore(&fm->lock, flags); + mutex_unlock(&dev->struct_mutex); + return; + } + old_sequence = (sequence - driver->flush_diff) & driver->sequence_mask; + fence = list_entry(fm->ring.next, drm_fence_object_t, ring); + atomic_inc(&fence->usage); + mutex_unlock(&dev->struct_mutex); + diff = (old_sequence - fence->sequence) & driver->sequence_mask; + read_unlock_irqrestore(&fm->lock, flags); + if (diff < driver->wrap_diff) { + drm_fence_object_flush(dev, fence, fence->type); + } + drm_fence_usage_deref_unlocked(dev, fence); +} + +EXPORT_SYMBOL(drm_fence_flush_old); + +static int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, + int lazy, int ignore_signals, uint32_t mask) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + int ret = 0; + unsigned long _end; + + if (mask & ~fence->type) { + DRM_ERROR("Wait trying to extend fence type\n"); + return -EINVAL; + } + + if (fence_signaled(dev, fence, mask, 0)) + return 0; + + _end = jiffies + 3 * DRM_HZ; + + drm_fence_object_flush(dev, fence, mask); + if (lazy && driver->lazy_capable) { + do { + DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, + fence_signaled(dev, fence, mask, 1)); + if (time_after_eq(jiffies, _end)) + break; + } while (ret == -EINTR && ignore_signals); + + if (time_after_eq(jiffies, _end) && (ret != 0)) + ret = -EBUSY; + return ret; + + } else { + int signaled; + do { + signaled = fence_signaled(dev, fence, mask, 1); + } while (!signaled && !time_after_eq(jiffies, _end)); + if (!signaled) + return -EBUSY; + } + return 0; +} + +int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, + uint32_t type) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + unsigned long flags; + uint32_t sequence; + int ret; + + drm_fence_unring(dev, &fence->ring); + ret = driver->emit(dev, &sequence); + if (ret) + return ret; + + write_lock_irqsave(&fm->lock, flags); + fence->type = type; + fence->flush_mask = 0x00; + fence->submitted_flush = 0x00; + fence->signaled = 0x00; + fence->sequence = sequence; + list_add_tail(&fence->ring, &fm->ring); + write_unlock_irqrestore(&fm->lock, flags); + return 0; +} + +int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, + drm_fence_object_t * fence) +{ + int ret = 0; + unsigned long flags; + drm_fence_manager_t *fm = &dev->fm; + + mutex_lock(&dev->struct_mutex); + atomic_set(&fence->usage, 1); + mutex_unlock(&dev->struct_mutex); + + write_lock_irqsave(&fm->lock, flags); + INIT_LIST_HEAD(&fence->ring); + fence->type = type; + fence->flush_mask = 0; + fence->submitted_flush = 0; + fence->signaled = 0; + fence->sequence = 0; + write_unlock_irqrestore(&fm->lock, flags); + if (emit) { + ret = drm_fence_object_emit(dev, fence, type); + } + return ret; +} + +EXPORT_SYMBOL(drm_fence_object_init); + +static int drm_fence_object_create(drm_file_t * priv, uint32_t type, + int emit, int shareable, + uint32_t * user_handle, + drm_fence_object_t ** c_fence) +{ + drm_device_t *dev = priv->head->dev; + int ret; + drm_fence_object_t *fence; + + fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + if (!fence) + return -ENOMEM; + ret = drm_fence_object_init(dev, type, emit, fence); + if (ret) { + drm_fence_usage_deref_unlocked(dev, fence); + return ret; + } + + mutex_lock(&dev->struct_mutex); + ret = drm_add_user_object(priv, &fence->base, shareable); + mutex_unlock(&dev->struct_mutex); + if (ret) { + drm_fence_usage_deref_unlocked(dev, fence); + *c_fence = NULL; + *user_handle = 0; + return ret; + } + fence->base.type = drm_fence_type; + fence->base.remove = &drm_fence_object_destroy; + *user_handle = fence->base.hash.key; + *c_fence = fence; + + return 0; +} + +void drm_fence_manager_init(drm_device_t * dev) +{ + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *fed = dev->driver->fence_driver; + int i; + + fm->lock = RW_LOCK_UNLOCKED; + INIT_LIST_HEAD(&fm->ring); + fm->pending_flush = 0; + DRM_INIT_WAITQUEUE(&fm->fence_queue); + fm->initialized = 0; + if (fed) { + fm->initialized = 1; + for (i = 0; i < fed->no_types; ++i) { + fm->fence_types[i] = &fm->ring; + } + } +} + +void drm_fence_manager_takedown(drm_device_t * dev) +{ +} + +drm_fence_object_t *drm_lookup_fence_object(drm_file_t * priv, uint32_t handle) +{ + drm_device_t *dev = priv->head->dev; + drm_user_object_t *uo; + drm_fence_object_t *fence; + + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, handle); + if (!uo || (uo->type != drm_fence_type)) { + mutex_unlock(&dev->struct_mutex); + return NULL; + } + fence = drm_user_object_entry(uo, drm_fence_object_t, base); + atomic_inc(&fence->usage); + mutex_unlock(&dev->struct_mutex); + return fence; +} + +int drm_fence_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + int ret; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_arg_t arg; + drm_fence_object_t *fence; + drm_user_object_t *uo; + unsigned long flags; + ret = 0; + + if (!fm->initialized) { + DRM_ERROR("The DRM driver does not support fencing.\n"); + return -EINVAL; + } + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + switch (arg.op) { + case drm_fence_create:{ + int emit = arg.flags & DRM_FENCE_FLAG_EMIT; + if (emit) + LOCK_TEST_WITH_RETURN(dev, filp); + ret = + drm_fence_object_create(priv, arg.type, + emit, + arg. + flags & + DRM_FENCE_FLAG_SHAREABLE, + &arg.handle, &fence); + if (ret) + return ret; + mutex_lock(&dev->struct_mutex); + atomic_inc(&fence->usage); + mutex_unlock(&dev->struct_mutex); + break; + } + case drm_fence_destroy: + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, arg.handle); + if (!uo || (uo->type != drm_fence_type) || uo->owner != priv) { + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + ret = drm_remove_user_object(priv, uo); + mutex_unlock(&dev->struct_mutex); + return ret; + case drm_fence_reference: + ret = + drm_user_object_ref(priv, arg.handle, drm_fence_type, &uo); + if (ret) + return ret; + fence = drm_lookup_fence_object(priv, arg.handle); + break; + case drm_fence_unreference: + ret = drm_user_object_unref(priv, arg.handle, drm_fence_type); + return ret; + case drm_fence_signaled: + fence = drm_lookup_fence_object(priv, arg.handle); + if (!fence) + return -EINVAL; + break; + case drm_fence_flush: + fence = drm_lookup_fence_object(priv, arg.handle); + if (!fence) + return -EINVAL; + ret = drm_fence_object_flush(dev, fence, arg.type); + break; + case drm_fence_wait: + fence = drm_lookup_fence_object(priv, arg.handle); + if (!fence) + return -EINVAL; + ret = + drm_fence_object_wait(dev, fence, + arg.flags & DRM_FENCE_FLAG_WAIT_LAZY, + arg. + flags & + DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS, + arg.type); + break; + case drm_fence_emit: + LOCK_TEST_WITH_RETURN(dev, filp); + fence = drm_lookup_fence_object(priv, arg.handle); + if (!fence) + return -EINVAL; + ret = drm_fence_object_emit(dev, fence, arg.type); + break; + default: + return -EINVAL; + } + read_lock_irqsave(&fm->lock, flags); + arg.type = fence->type; + arg.signaled = fence->signaled; + read_unlock_irqrestore(&fm->lock, flags); + drm_fence_usage_deref_unlocked(dev, fence); + + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); + return ret; +} diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 9059f42c..6182141a 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -133,6 +133,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, goto error_out_unreg; } + drm_fence_manager_init(dev); return 0; error_out_unreg: diff --git a/shared-core/drm.h b/shared-core/drm.h index 87f8da6b..65d04b72 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -259,7 +259,7 @@ typedef enum drm_map_type { _DRM_SHM = 2, /**< shared, cached */ _DRM_AGP = 3, /**< AGP/GART */ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ - _DRM_CONSISTENT = 5 /**< Consistent memory for PCI DMA */ + _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ } drm_map_type_t; /** @@ -629,6 +629,31 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; +#define DRM_FENCE_FLAG_EMIT 0x00000001 +#define DRM_FENCE_FLAG_SHAREABLE 0x00000002 +#define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 +#define DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS 0x00000008 + +#define DRM_FENCE_EXE 0x00000001 + +typedef struct drm_fence_arg { + unsigned handle; + unsigned type; + unsigned flags; + unsigned signaled; + enum { + drm_fence_create, + drm_fence_destroy, + drm_fence_reference, + drm_fence_unreference, + drm_fence_signaled, + drm_fence_flush, + drm_fence_wait, + drm_fence_emit + } op; +} drm_fence_arg_t; + + /** * \name Ioctls Definitions */ @@ -694,6 +719,9 @@ typedef struct drm_set_version { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) +#define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) + + /*@}*/ /** -- 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(-) 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(-) 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 +++++++++++++++++++++++++++++++++++++++++++++ shared-core/i915_dma.c | 10 ++-- shared-core/i915_drv.h | 27 ++++++++-- shared-core/i915_irq.c | 10 ++-- 6 files changed, 170 insertions(+), 11 deletions(-) create mode 100644 linux-core/i915_fence.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 3c31b013..c5ce6638 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -19,7 +19,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i830-objs := i830_drv.o i830_dma.o i830_irq.o -i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index c6e25f9b..d1b8d2d2 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -38,6 +38,16 @@ static struct pci_device_id pciidlist[] = { i915_PCI_IDS }; +static drm_fence_driver_t i915_fence_driver = { + .no_types = 2, + .wrap_diff = (1 << 30), + .flush_diff = 200, + .sequence_mask = 0xffffffffU, + .lazy_capable = 1, + .emit = i915_fence_emit_sequence, + .poke_flush = i915_poke_flush, +}; + static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { /* don't use mtrr's here, the Xserver or user space app should @@ -78,6 +88,7 @@ static struct drm_driver driver = { .remove = __devexit_p(drm_cleanup_pci), }, + .fence_driver = &i915_fence_driver, .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c new file mode 100644 index 00000000..46a2a728 --- /dev/null +++ b/linux-core/i915_fence.c @@ -0,0 +1,121 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" +#include "drm.h" +#include "i915_drm.h" +#include "i915_drv.h" + +/* + * Implements an intel sync flush operation. + */ + +static void i915_perform_flush(drm_device_t * dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + drm_fence_manager_t *fm = &dev->fm; + drm_fence_driver_t *driver = dev->driver->fence_driver; + int flush_completed = 0; + uint32_t flush_flags = 0; + uint32_t flush_sequence = 0; + uint32_t i_status; + uint32_t diff; + uint32_t sequence; + + if (fm->pending_exe_flush) { + sequence = READ_BREADCRUMB(dev_priv); + diff = sequence - fm->last_exe_flush; + if (diff < driver->wrap_diff && diff != 0) { + drm_fence_handler(dev, sequence, DRM_FENCE_EXE); + diff = sequence - fm->exe_flush_sequence; + if (diff < driver->wrap_diff) { + fm->pending_exe_flush = 0; + /* + * Turn off user IRQs + */ + } else { + /* + * Turn on user IRQs + */ + } + } + } + if (dev_priv->flush_pending) { + i_status = READ_HWSP(dev_priv, 0); + if ((i_status & (1 << 12)) != + (dev_priv->saved_flush_status & (1 << 12))) { + flush_completed = 1; + flush_flags = dev_priv->flush_flags; + flush_sequence = dev_priv->flush_sequence; + dev_priv->flush_pending = 0; + } else { + } + } + if (flush_completed) { + drm_fence_handler(dev, flush_sequence, flush_flags); + } + if (fm->pending_flush && !dev_priv->flush_pending) { + dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); + dev_priv->flush_flags = fm->pending_flush; + dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); + I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); + dev_priv->flush_pending = 1; + fm->pending_flush = 0; + } +} + +void i915_poke_flush(drm_device_t * dev) +{ + drm_fence_manager_t *fm = &dev->fm; + unsigned long flags; + + write_lock_irqsave(&fm->lock, flags); + i915_perform_flush(dev); + write_unlock_irqrestore(&fm->lock, flags); +} + +int i915_fence_emit_sequence(drm_device_t * dev, uint32_t * sequence) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + i915_emit_irq(dev); + *sequence = (uint32_t) dev_priv->counter; + return 0; +} + +void i915_fence_handler(drm_device_t * dev) +{ + drm_fence_manager_t *fm = &dev->fm; + + write_lock(&fm->lock); + i915_perform_flush(dev); + i915_perform_flush(dev); + write_unlock(&fm->lock); +} diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index ba8c56ee..d6bb6c8e 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -434,15 +434,15 @@ static void i915_emit_breadcrumb(drm_device_t *dev) dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter; - if (dev_priv->counter > 0x7FFFFFFFUL) - dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1; - BEGIN_LP_RING(4); OUT_RING(CMD_STORE_DWORD_IDX); OUT_RING(20); OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); +#ifdef I915_HAVE_FENCE + drm_fence_flush_old(dev, dev_priv->counter); +#endif } static int i915_dispatch_cmdbuffer(drm_device_t * dev, @@ -565,7 +565,9 @@ static int i915_dispatch_flip(drm_device_t * dev) OUT_RING(dev_priv->counter); OUT_RING(0); ADVANCE_LP_RING(); - +#ifdef I915_HAVE_FENCE + drm_fence_flush_old(dev, dev_priv->counter); +#endif dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; return 0; } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a87075b1..475ff474 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -51,6 +51,10 @@ #define DRIVER_MINOR 5 #define DRIVER_PATCHLEVEL 0 +#if defined(__linux__) +#define I915_HAVE_FENCE +#endif + typedef struct _drm_i915_ring_buffer { int tail_mask; unsigned long Start; @@ -81,7 +85,7 @@ typedef struct drm_i915_private { drm_dma_handle_t *status_page_dmah; void *hw_status_page; dma_addr_t dma_status_page; - unsigned long counter; + uint32_t counter; int back_offset; int front_offset; @@ -98,6 +102,14 @@ typedef struct drm_i915_private { struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; + +#ifdef I915_HAVE_FENCE + uint32_t flush_sequence; + uint32_t flush_flags; + uint32_t flush_pending; + uint32_t saved_flush_status; +#endif + } drm_i915_private_t; extern drm_ioctl_desc_t i915_ioctls[]; @@ -123,6 +135,7 @@ extern void i915_driver_irq_postinstall(drm_device_t * dev); extern void i915_driver_irq_uninstall(drm_device_t * dev); extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS); extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); +extern int i915_emit_irq(drm_device_t * dev); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); @@ -132,6 +145,13 @@ extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS); extern void i915_mem_takedown(struct mem_block **heap); extern void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap); +#ifdef I915_HAVE_FENCE +/* i915_fence.c */ +extern void i915_fence_handler(drm_device_t *dev); +extern int i915_fence_emit_sequence(drm_device_t *dev, uint32_t *sequence); +extern void i915_poke_flush(drm_device_t *dev); +extern void i915_sync_flush(drm_device_t *dev); +#endif #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) @@ -191,6 +211,7 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define I915REG_INT_IDENTITY_R 0x020a4 #define I915REG_INT_MASK_R 0x020a8 #define I915REG_INT_ENABLE_R 0x020a0 +#define I915REG_INSTPM 0x020c0 #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 @@ -272,6 +293,6 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) -#define READ_BREADCRUMB(dev_priv) (((u32*)(dev_priv->hw_status_page))[5]) - +#define READ_BREADCRUMB(dev_priv) (((volatile u32*)(dev_priv->hw_status_page))[5]) +#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg]) #endif diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 14213b58..08d3140b 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -56,8 +56,12 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); - if (temp & USER_INT_FLAG) + if (temp & USER_INT_FLAG) { DRM_WAKEUP(&dev_priv->irq_queue); +#ifdef I915_HAVE_FENCE + i915_fence_handler(dev); +#endif + } if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { atomic_inc(&dev->vbl_received); @@ -68,7 +72,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_HANDLED; } -static int i915_emit_irq(drm_device_t * dev) +int i915_emit_irq(drm_device_t * dev) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -260,7 +264,7 @@ void i915_driver_irq_preinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - I915_WRITE16(I915REG_HWSTAM, 0xfffe); + I915_WRITE16(I915REG_HWSTAM, 0xeffe); I915_WRITE16(I915REG_INT_MASK_R, 0x0); I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); } -- 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(-) 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 +++++++++++++++-- shared-core/drm.h | 1 + 7 files changed, 1262 insertions(+), 21 deletions(-) create mode 100644 linux-core/drm_ttm.c create mode 100644 linux-core/drm_ttm.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index c5ce6638..bf5221d1 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,7 +13,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ - drm_fence.o + drm_fence.o drm_ttm.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drmP.h b/linux-core/drmP.h index b9549b63..33d8ecc2 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -586,6 +586,18 @@ typedef struct drm_mm { drm_mm_node_t root_node; } drm_mm_t; +#include "drm_ttm.h" + +/* + * buffer object driver + */ + +typedef struct drm_bo_driver{ + int cached_pages; + drm_ttm_backend_t *(*create_ttm_backend_entry) + (struct drm_device *dev, int cached); +} drm_bo_driver_t; + /** * DRM driver structure. This structure represent the common code for @@ -639,6 +651,7 @@ struct drm_driver { void (*set_version) (struct drm_device * dev, drm_set_version_t * sv); struct drm_fence_driver *fence_driver; + struct drm_bo_driver *bo_driver; int major; int minor; @@ -979,6 +992,7 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); extern int drm_mmap(struct file *filp, struct vm_area_struct *vma); extern unsigned long drm_core_get_map_ofs(drm_map_t * map); extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev); +extern pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma); /* Memory management support (drm_memory.h) */ #include "drm_memory.h" diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 2eeb401d..efb48dce 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -420,6 +420,8 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map) dmah.size = map->size; __drm_pci_free(dev, &dmah); break; + case _DRM_TTM: + BUG_ON(1); } drm_free(map, sizeof(*map), DRM_MEM_MAPS); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c new file mode 100644 index 00000000..b3ea7c9b --- /dev/null +++ b/linux-core/drm_ttm.c @@ -0,0 +1,813 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Steamboat Springs, CO. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +#include "drmP.h" +#include + +typedef struct p_mm_entry { + struct list_head head; + struct mm_struct *mm; + atomic_t refcount; +} p_mm_entry_t; + +typedef struct drm_val_action { + int needs_rx_flush; + int evicted_tt; + int evicted_vram; + int validated; +} drm_val_action_t; + +/* + * We may be manipulating other processes page tables, so for each TTM, keep track of + * which mm_structs are currently mapping the ttm so that we can take the appropriate + * locks when we modify their page tables. A typical application is when we evict another + * process' buffers. + */ + +int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm) +{ + p_mm_entry_t *entry, *n_entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (mm == entry->mm) { + atomic_inc(&entry->refcount); + return 0; + } else if ((unsigned long)mm < (unsigned long)entry->mm) ; + } + + n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_MM); + if (!entry) { + DRM_ERROR("Allocation of process mm pointer entry failed\n"); + return -ENOMEM; + } + INIT_LIST_HEAD(&n_entry->head); + n_entry->mm = mm; + atomic_set(&n_entry->refcount, 0); + atomic_inc(&ttm->shared_count); + ttm->mm_list_seq++; + + list_add_tail(&n_entry->head, &entry->head); + + return 0; +} + +void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm) +{ + p_mm_entry_t *entry, *n; + list_for_each_entry_safe(entry, n, &ttm->p_mm_list, head) { + if (mm == entry->mm) { + if (atomic_add_negative(-1, &entry->refcount)) { + list_del(&entry->head); + drm_free(entry, sizeof(*entry), DRM_MEM_MM); + atomic_dec(&ttm->shared_count); + ttm->mm_list_seq++; + } + return; + } + } + BUG_ON(TRUE); +} + +static void drm_ttm_lock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +{ + p_mm_entry_t *entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (mm_sem) { + down_write(&entry->mm->mmap_sem); + } + if (page_table) { + spin_lock(&entry->mm->page_table_lock); + } + } +} + +static void drm_ttm_unlock_mm(drm_ttm_t * ttm, int mm_sem, int page_table) +{ + p_mm_entry_t *entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (page_table) { + spin_unlock(&entry->mm->page_table_lock); + } + if (mm_sem) { + up_write(&entry->mm->mmap_sem); + } + } +} + +static int ioremap_vmas(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages, unsigned long aper_offset) +{ + struct list_head *list; + int ret = 0; + + list_for_each(list, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + + ret = io_remap_pfn_range(entry->vma, + entry->vma->vm_start + + (page_offset << PAGE_SHIFT), + (ttm->aperture_base >> PAGE_SHIFT) + + aper_offset, num_pages << PAGE_SHIFT, + drm_io_prot(_DRM_AGP, entry->vma)); + if (ret) + break; + } + global_flush_tlb(); + return ret; +} + +/* + * Unmap all vma pages from vmas mapping this ttm. + */ + +static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages) +{ + struct list_head *list; + struct page **first_page = ttm->pages + page_offset; + struct page **last_page = ttm->pages + (page_offset + num_pages); + struct page **cur_page; + + list_for_each(list, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + drm_clear_vma(entry->vma, + entry->vma->vm_start + + (page_offset << PAGE_SHIFT), + entry->vma->vm_start + + ((page_offset + num_pages) << PAGE_SHIFT)); + } + + for (cur_page = first_page; cur_page != last_page; ++cur_page) { + if (page_mapcount(*cur_page) != 0) { + DRM_ERROR("Mapped page detected. Map count is %d\n", + page_mapcount(*cur_page)); + return -1; + } + } + return 0; +} + +/* + * Free all resources associated with a ttm. + */ + +int drm_destroy_ttm(drm_ttm_t * ttm) +{ + + int i; + struct list_head *list, *next; + struct page **cur_page; + + if (!ttm) + return 0; + + if (atomic_read(&ttm->vma_count) > 0) { + DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); + return -EBUSY; + } else { + DRM_DEBUG("Checking for busy regions.\n"); + } + + if (ttm->be_list) { + list_for_each_safe(list, next, &ttm->be_list->head) { + drm_ttm_backend_list_t *entry = + list_entry(list, drm_ttm_backend_list_t, head); +#ifdef REMOVED + drm_ht_remove_item(&ttm->dev->ttmreghash, + &entry->hash); +#endif + drm_destroy_ttm_region(entry); + } + + drm_free(ttm->be_list, sizeof(*ttm->be_list), DRM_MEM_MAPS); + ttm->be_list = NULL; + } + + if (atomic_read(&ttm->unfinished_regions) > 0) { + DRM_DEBUG("Regions are still busy. Skipping destruction.\n"); + ttm->destroy = TRUE; + return -EAGAIN; + } else { + DRM_DEBUG("About to really destroy ttm.\n"); + } + + if (ttm->pages) { + for (i = 0; i < ttm->num_pages; ++i) { + cur_page = ttm->pages + i; + if (ttm->page_flags && + (ttm->page_flags[i] & DRM_TTM_PAGE_UNCACHED) && + *cur_page && !PageHighMem(*cur_page)) { + change_page_attr(*cur_page, 1, PAGE_KERNEL); + } + if (*cur_page) { + ClearPageReserved(*cur_page); + __free_page(*cur_page); + } + } + global_flush_tlb(); + vfree(ttm->pages); + ttm->pages = NULL; + } + if (ttm->page_flags) { + vfree(ttm->page_flags); + ttm->page_flags = NULL; + } + + if (ttm->vma_list) { + list_for_each_safe(list, next, &ttm->vma_list->head) { + drm_ttm_vma_list_t *entry = + list_entry(list, drm_ttm_vma_list_t, head); + list_del(list); + entry->vma->vm_private_data = NULL; + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + } + drm_free(ttm->vma_list, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + ttm->vma_list = NULL; + } + drm_free(ttm, sizeof(*ttm), DRM_MEM_MAPS); + + return 0; +} + +/* + * Initialize a ttm. + * FIXME: Avoid using vmalloc for the page- and page_flags tables? + */ + +drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) +{ + + drm_ttm_t *ttm; + + if (!dev->driver->bo_driver) + return NULL; + + ttm = drm_calloc(1, sizeof(*ttm), DRM_MEM_MAPS); + if (!ttm) + return NULL; + + ttm->lhandle = 0; + atomic_set(&ttm->vma_count, 0); + atomic_set(&ttm->unfinished_regions, 0); + ttm->destroy = FALSE; + ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + + ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); + if (!ttm->page_flags) { + drm_destroy_ttm(ttm); + DRM_ERROR("Failed allocating page_flags table\n"); + return NULL; + } + memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); + + ttm->pages = vmalloc(ttm->num_pages * sizeof(*ttm->pages)); + if (!ttm->pages) { + drm_destroy_ttm(ttm); + DRM_ERROR("Failed allocating page table\n"); + return NULL; + } + memset(ttm->pages, 0, ttm->num_pages * sizeof(*ttm->pages)); + + ttm->be_list = drm_calloc(1, sizeof(*ttm->be_list), DRM_MEM_MAPS); + if (!ttm->be_list) { + DRM_ERROR("Alloc be regions failed\n"); + drm_destroy_ttm(ttm); + return NULL; + } + + INIT_LIST_HEAD(&ttm->be_list->head); + INIT_LIST_HEAD(&ttm->p_mm_list); + atomic_set(&ttm->shared_count, 0); + ttm->mm_list_seq = 0; + + ttm->vma_list = drm_calloc(1, sizeof(*ttm->vma_list), DRM_MEM_MAPS); + if (!ttm->vma_list) { + DRM_ERROR("Alloc vma list failed\n"); + drm_destroy_ttm(ttm); + return NULL; + } + + INIT_LIST_HEAD(&ttm->vma_list->head); + + ttm->lhandle = (unsigned long)ttm; + ttm->dev = dev; + return ttm; +} + +/* + * Lock the mmap_sems for processes that are mapping this ttm. + * This looks a bit clumsy, since we need to maintain the correct + * locking order + * mm->mmap_sem + * dev->struct_sem; + * and while we release dev->struct_sem to lock the mmap_sems, + * the mmap_sem list may have been updated. We need to revalidate + * it after relocking dev->struc_sem. + */ + +static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) +{ + struct mm_struct **mm_list = NULL, **mm_list_p; + uint32_t list_seq; + uint32_t cur_count, shared_count; + p_mm_entry_t *entry; + unsigned i; + + cur_count = 0; + list_seq = ttm->mm_list_seq; + shared_count = atomic_read(&ttm->shared_count); + + do { + if (shared_count > cur_count) { + if (mm_list) + drm_free(mm_list, sizeof(*mm_list) * cur_count, + DRM_MEM_MM); + cur_count = shared_count + 10; + mm_list = + drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_MM); + if (!mm_list) + return -ENOMEM; + } + + mm_list_p = mm_list; + list_for_each_entry(entry, &ttm->p_mm_list, head) { + *mm_list_p++ = entry->mm; + } + + mutex_unlock(&ttm->dev->struct_mutex); + mm_list_p = mm_list; + for (i = 0; i < shared_count; ++i, ++mm_list_p) { + down_write(&((*mm_list_p)->mmap_sem)); + } + + mutex_lock(&ttm->dev->struct_mutex); + + if (list_seq != ttm->mm_list_seq) { + mm_list_p = mm_list; + for (i = 0; i < shared_count; ++i, ++mm_list_p) { + up_write(&((*mm_list_p)->mmap_sem)); + } + + } + shared_count = atomic_read(&ttm->shared_count); + + } while (list_seq != ttm->mm_list_seq); + + if (mm_list) + drm_free(mm_list, sizeof(*mm_list) * cur_count, DRM_MEM_MM); + + ttm->mmap_sem_locked = TRUE; + return 0; +} + +/* + * Change caching policy for range of pages in a ttm. + */ + +static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long num_pages, int noncached, + int do_tlbflush) +{ + int i, cur; + struct page **cur_page; + pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; + + drm_ttm_lock_mm(ttm, FALSE, TRUE); + unmap_vma_pages(ttm, page_offset, num_pages); + + for (i = 0; i < num_pages; ++i) { + cur = page_offset + i; + cur_page = ttm->pages + cur; + if (*cur_page) { + if (PageHighMem(*cur_page)) { + if (noncached + && page_address(*cur_page) != NULL) { + DRM_ERROR + ("Illegal mapped HighMem Page\n"); + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + return -EINVAL; + } + } else if ((ttm->page_flags[cur] & + DRM_TTM_PAGE_UNCACHED) != noncached) { + DRM_MASK_VAL(ttm->page_flags[cur], + DRM_TTM_PAGE_UNCACHED, noncached); + change_page_attr(*cur_page, 1, attr); + } + } + } + if (do_tlbflush) + global_flush_tlb(); + + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + return 0; +} + + +/* + * Unbind a ttm region from the aperture. + */ + +int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be = entry->be; + drm_ttm_t *ttm = entry->owner; + int ret; + + if (be) { + switch (entry->state) { + case ttm_bound: + if (ttm && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mmap_sem(ttm); + if (ret) + return ret; + drm_ttm_lock_mm(ttm, FALSE, TRUE); + unmap_vma_pages(ttm, entry->page_offset, + entry->num_pages); + global_flush_tlb(); + drm_ttm_unlock_mm(ttm, FALSE, TRUE); + } + be->unbind(entry->be); + if (ttm && be->needs_cache_adjust(be)) { + drm_set_caching(ttm, entry->page_offset, + entry->num_pages, 0, 1); + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + break; + default: + break; + } + } + entry->state = ttm_evicted; + return 0; +} + +void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_evict_ttm_region(entry); + entry->state = ttm_unbound; +} + +/* + * Destroy and clean up all resources associated with a ttm region. + * FIXME: release pages to OS when doing this operation. + */ + +void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be = entry->be; + drm_ttm_t *ttm = entry->owner; + uint32_t *cur_page_flags; + int i; + + list_del_init(&entry->head); + + drm_unbind_ttm_region(entry); + if (be) { + be->clear(entry->be); + if (be->needs_cache_adjust(be)) { + int ret = drm_ttm_lock_mmap_sem(ttm); + drm_set_caching(ttm, entry->page_offset, + entry->num_pages, 0, 1); + if (!ret) + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + be->destroy(be); + } + cur_page_flags = ttm->page_flags + entry->page_offset; + for (i = 0; i < entry->num_pages; ++i) { + DRM_MASK_VAL(*cur_page_flags, DRM_TTM_PAGE_USED, 0); + cur_page_flags++; + } + + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); +} + +/* + * Create a ttm region from a range of ttm pages. + */ + +int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long n_pages, int cached, + drm_ttm_backend_list_t ** region) +{ + struct page **cur_page; + uint32_t *cur_page_flags; + drm_ttm_backend_list_t *entry; + drm_ttm_backend_t *be; + int ret, i; + + if ((page_offset + n_pages) > ttm->num_pages || n_pages == 0) { + DRM_ERROR("Region Doesn't fit ttm\n"); + return -EINVAL; + } + + cur_page_flags = ttm->page_flags + page_offset; + for (i = 0; i < n_pages; ++i, ++cur_page_flags) { + if (*cur_page_flags & DRM_TTM_PAGE_USED) { + DRM_ERROR("TTM region overlap\n"); + return -EINVAL; + } else { + DRM_MASK_VAL(*cur_page_flags, DRM_TTM_PAGE_USED, + DRM_TTM_PAGE_USED); + } + } + + entry = drm_calloc(1, sizeof(*entry), DRM_MEM_MAPS); + if (!entry) + return -ENOMEM; + + be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached); + if (!be) { + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + DRM_ERROR("Couldn't create backend.\n"); + return -EINVAL; + } + entry->state = ttm_unbound; + entry->page_offset = page_offset; + entry->num_pages = n_pages; + entry->be = be; + entry->owner = ttm; + + INIT_LIST_HEAD(&entry->head); + list_add_tail(&entry->head, &ttm->be_list->head); + + for (i = 0; i < entry->num_pages; ++i) { + cur_page = ttm->pages + (page_offset + i); + if (!*cur_page) { + *cur_page = alloc_page(GFP_KERNEL); + if (!*cur_page) { + DRM_ERROR("Page allocation failed\n"); + drm_destroy_ttm_region(entry); + return -ENOMEM; + } + SetPageReserved(*cur_page); + } + } + + if ((ret = be->populate(be, n_pages, ttm->pages + page_offset))) { + drm_destroy_ttm_region(entry); + DRM_ERROR("Couldn't populate backend.\n"); + return ret; + } + ttm->aperture_base = be->aperture_base; + + *region = entry; + return 0; +} + +/* + * Bind a ttm region. Set correct caching policy. + */ + +int drm_bind_ttm_region(drm_ttm_backend_list_t * region, + unsigned long aper_offset) +{ + + int i; + uint32_t *cur_page_flag; + int ret = 0; + drm_ttm_backend_t *be; + drm_ttm_t *ttm; + + if (!region || region->state == ttm_bound) + return -EINVAL; + + be = region->be; + ttm = region->owner; + + if (ttm && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mmap_sem(ttm); + if (ret) + return ret; + drm_set_caching(ttm, region->page_offset, region->num_pages, + DRM_TTM_PAGE_UNCACHED, TRUE); + } else { + DRM_DEBUG("Binding cached\n"); + } + + if ((ret = be->bind(be, aper_offset))) { + if (ttm && be->needs_cache_adjust(be)) + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + drm_unbind_ttm_region(region); + DRM_ERROR("Couldn't bind backend.\n"); + return ret; + } + + cur_page_flag = ttm->page_flags + region->page_offset; + for (i = 0; i < region->num_pages; ++i) { + DRM_MASK_VAL(*cur_page_flag, DRM_TTM_MASK_PFN, + (i + aper_offset) << PAGE_SHIFT); + cur_page_flag++; + } + + if (ttm && be->needs_cache_adjust(be)) { + ioremap_vmas(ttm, region->page_offset, region->num_pages, + aper_offset); + drm_ttm_unlock_mm(ttm, TRUE, FALSE); + } + + region->state = ttm_bound; + return 0; +} + +int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry, + unsigned long aper_offset) +{ + return drm_bind_ttm_region(entry, aper_offset); + +} + +/* + * Destroy an anonymous ttm region. + */ + +void drm_user_destroy_region(drm_ttm_backend_list_t * entry) +{ + drm_ttm_backend_t *be; + struct page **cur_page; + int i; + + if (!entry || entry->owner) + return; + + be = entry->be; + if (!be) { + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + return; + } + + be->unbind(be); + + if (entry->anon_pages) { + cur_page = entry->anon_pages; + for (i = 0; i < entry->anon_locked; ++i) { + if (!PageReserved(*cur_page)) + SetPageDirty(*cur_page); + page_cache_release(*cur_page); + cur_page++; + } + vfree(entry->anon_pages); + } + + be->destroy(be); + drm_free(entry, sizeof(*entry), DRM_MEM_MAPS); + return; +} + +/* + * Create a ttm region from an arbitrary region of user pages. + * Since this region has no backing ttm, it's owner is set to + * null, and it is registered with the file of the caller. + * Gets destroyed when the file is closed. We call this an + * anonymous ttm region. + */ + +int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, + drm_ttm_backend_list_t ** entry) +{ + drm_ttm_backend_list_t *tmp; + drm_ttm_backend_t *be; + int ret; + + if (len <= 0) + return -EINVAL; + if (!dev->driver->bo_driver->create_ttm_backend_entry) + return -EFAULT; + + tmp = drm_calloc(1, sizeof(*tmp), DRM_MEM_MAPS); + + if (!tmp) + return -ENOMEM; + + be = dev->driver->bo_driver->create_ttm_backend_entry(dev, 1); + tmp->be = be; + + if (!be) { + drm_user_destroy_region(tmp); + return -ENOMEM; + } + if (be->needs_cache_adjust(be)) { + drm_user_destroy_region(tmp); + return -EFAULT; + } + + tmp->anon_pages = vmalloc(sizeof(*(tmp->anon_pages)) * len); + + if (!tmp->anon_pages) { + drm_user_destroy_region(tmp); + return -ENOMEM; + } + + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, start, len, 1, 0, + tmp->anon_pages, NULL); + up_read(¤t->mm->mmap_sem); + + if (ret != len) { + drm_user_destroy_region(tmp); + DRM_ERROR("Could not lock %d pages. Return code was %d\n", + len, ret); + return -EPERM; + } + tmp->anon_locked = len; + + ret = be->populate(be, len, tmp->anon_pages); + + if (ret) { + drm_user_destroy_region(tmp); + return ret; + } + + tmp->state = ttm_unbound; +#ifdef REMOVED + tmp->mm = &dev->driver->bo_driver->ttm_mm; +#endif + *entry = tmp; + + return 0; +} + +/* + * Create a ttm and add it to the drm book-keeping. + */ + +int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) +{ + drm_map_list_t *list; + drm_map_t *map; + drm_ttm_t *ttm; + + map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + if (!map) + return -ENOMEM; + + ttm = drm_init_ttm(dev, size); + + if (!ttm) { + DRM_ERROR("Could not create ttm\n"); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -ENOMEM; + } + + map->offset = ttm->lhandle; + map->type = _DRM_TTM; + map->flags = _DRM_REMOVABLE; + map->size = size; + + list = drm_calloc(1, sizeof(*list), DRM_MEM_MAPS); + if (!list) { + drm_destroy_ttm(ttm); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + return -ENOMEM; + } + map->handle = (void *)list; + + +#ifdef REMOVED + if (drm_ht_just_insert_please(&dev->maphash, &list->hash, + (unsigned long) map->handle, + 32 - PAGE_SHIFT)) { + drm_destroy_ttm(ttm); + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + drm_free(list, sizeof(*list), DRM_MEM_MAPS); + return -ENOMEM; + } +#endif + + list->user_token = + (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; + list->map = map; + + *maplist = list; + + return 0; +} diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h new file mode 100644 index 00000000..07592a84 --- /dev/null +++ b/linux-core/drm_ttm.h @@ -0,0 +1,152 @@ +#ifndef _DRM_TTM_H +#define _DRM_TTM_H +#define DRM_HAS_TTM + +/* + * The backend GART interface. (In our case AGP). Any similar type of device (PCIE?) + * needs only to implement these functions to be usable with the "TTM" interface. + * The AGP backend implementation lives in drm_agpsupport.c + * basically maps these calls to available functions in agpgart. Each drm device driver gets an + * additional function pointer that creates these types, + * so that the device can choose the correct aperture. + * (Multiple AGP apertures, etc.) + * Most device drivers will let this point to the standard AGP implementation. + */ + +typedef struct drm_ttm_backend { + unsigned long aperture_base; + void *private; + int (*needs_cache_adjust) (struct drm_ttm_backend * backend); + int (*populate) (struct drm_ttm_backend * backend, + unsigned long num_pages, struct page ** pages); + void (*clear) (struct drm_ttm_backend * backend); + int (*bind) (struct drm_ttm_backend * backend, unsigned long offset); + int (*unbind) (struct drm_ttm_backend * backend); + void (*destroy) (struct drm_ttm_backend * backend); +} drm_ttm_backend_t; + +#define DRM_FLUSH_READ (0x01) +#define DRM_FLUSH_WRITE (0x02) +#define DRM_FLUSH_EXE (0x04) + +typedef struct drm_ttm_backend_list { + drm_hash_item_t hash; + uint32_t flags; + atomic_t refcount; + struct list_head head; + drm_ttm_backend_t *be; + unsigned page_offset; + unsigned num_pages; + struct drm_ttm *owner; + drm_file_t *anon_owner; + struct page **anon_pages; + int anon_locked; + enum { + ttm_bound, + ttm_evicted, + ttm_unbound + } state; +} drm_ttm_backend_list_t; + +typedef struct drm_ttm_vma_list { + struct list_head head; + pgprot_t orig_protection; + struct vm_area_struct *vma; + drm_map_t *map; +} drm_ttm_vma_list_t; + +typedef struct drm_ttm { + struct list_head p_mm_list; + atomic_t shared_count; + uint32_t mm_list_seq; + unsigned long aperture_base; + struct page **pages; + uint32_t *page_flags; + unsigned long lhandle; + unsigned long num_pages; + drm_ttm_vma_list_t *vma_list; + struct drm_device *dev; + drm_ttm_backend_list_t *be_list; + atomic_t vma_count; + atomic_t unfinished_regions; + drm_file_t *owner; + int destroy; + int mmap_sem_locked; +} drm_ttm_t; + +/* + * Initialize a ttm. Currently the size is fixed. Currently drmAddMap calls this function + * and creates a DRM map of type _DRM_TTM, and returns a reference to that map to the + * caller. + */ + +drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size); + +/* + * Bind a part of the ttm starting at page_offset size n_pages into the GTT, at + * aperture offset aper_offset. The region handle will be used to reference this + * bound region in the future. Note that the region may be the whole ttm. + * Regions should not overlap. + * This function sets all affected pages as noncacheable and flushes cashes and TLB. + */ + +int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, + unsigned long n_pages, int cached, + drm_ttm_backend_list_t ** region); + +int drm_bind_ttm_region(drm_ttm_backend_list_t * region, + unsigned long aper_offset); + +/* + * Unbind a ttm region. Restores caching policy. Flushes caches and TLB. + */ + +void drm_unbind_ttm_region(drm_ttm_backend_list_t * entry); +void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry); + +/* + * Evict a ttm region. Keeps Aperture caching policy. + */ + +int drm_evict_ttm_region(drm_ttm_backend_list_t * entry); + +/* + * Rebind an already evicted region into a possibly new location in the aperture. + */ + +int drm_rebind_ttm_region(drm_ttm_backend_list_t * entry, + unsigned long aper_offset); + +/* + * Destroy a ttm. The user normally calls drmRmMap or a similar IOCTL to do this, + * which calls this function iff there are no vmas referencing it anymore. Otherwise it is called + * when the last vma exits. + */ + +extern int drm_destroy_ttm(drm_ttm_t * ttm); +extern void drm_user_destroy_region(drm_ttm_backend_list_t * entry); +extern int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm); +extern void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm); +extern void drm_ttm_fence_before_destroy(drm_ttm_t * ttm); +extern void drm_fence_unfenced_region(drm_ttm_backend_list_t * entry); + +extern int drm_ttm_ioctl(DRM_IOCTL_ARGS); +extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); +extern int drm_mm_fence_ioctl(DRM_IOCTL_ARGS); + +#define DRM_MASK_VAL(dest, mask, val) \ + (dest) = ((dest) & ~(mask)) | ((val) & (mask)); + +#define DRM_TTM_MASK_FLAGS ((1 << PAGE_SHIFT) - 1) +#define DRM_TTM_MASK_PFN (0xFFFFFFFFU - DRM_TTM_MASK_FLAGS) + +/* + * Page flags. + */ + +#define DRM_TTM_PAGE_UNCACHED 0x01 +#define DRM_TTM_PAGE_USED 0x02 +#define DRM_TTM_PAGE_BOUND 0x04 +#define DRM_TTM_PAGE_PRESENT 0x08 + +#endif diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index cf3bc3cf..9f48f297 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -34,12 +34,42 @@ */ #include "drmP.h" + #if defined(__ia64__) #include #endif static void drm_vm_open(struct vm_area_struct *vma); static void drm_vm_close(struct vm_area_struct *vma); +static void drm_vm_ttm_close(struct vm_area_struct *vma); +static int drm_vm_ttm_open(struct vm_area_struct *vma); +static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma); + + +pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) +{ + pgprot_t tmp = drm_prot_map(vma->vm_flags); + +#if defined(__i386__) || defined(__x86_64__) + if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) { + pgprot_val(tmp) |= _PAGE_PCD; + pgprot_val(tmp) &= ~_PAGE_PWT; + } +#elif defined(__powerpc__) + pgprot_val(tmp) |= _PAGE_NO_CACHE; + if (map->type == _DRM_REGISTERS) + pgprot_val(tmp) |= _PAGE_GUARDED; +#endif +#if defined(__ia64__) + if (efi_range_is_wc(vma->vm_start, vma->vm_end - + vma->vm_start)) + tmp = pgprot_writecombine(tmp); + else + tmp = pgprot_noncached(tmp); +#endif + return tmp; +} + /** * \c nopage method for AGP virtual memory. @@ -129,6 +159,131 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, } #endif /* __OS_HAS_AGP */ + +static int drm_ttm_remap_bound_pfn(struct vm_area_struct *vma, + unsigned long address, + unsigned long size) +{ + unsigned long + page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + unsigned long + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + drm_ttm_vma_list_t *entry = (drm_ttm_vma_list_t *) + vma->vm_private_data; + drm_map_t *map = entry->map; + drm_ttm_t *ttm = (drm_ttm_t *) map->offset; + unsigned long i, cur_pfn; + unsigned long start = 0; + unsigned long end = 0; + unsigned long last_pfn = 0; + unsigned long start_pfn = 0; + int bound_sequence = FALSE; + int ret = 0; + uint32_t cur_flags; + + for (i=page_offset; ipage_flags[i]; + + if (!bound_sequence && (cur_flags & DRM_TTM_PAGE_UNCACHED)) { + + start = i; + end = i; + last_pfn = (cur_flags & DRM_TTM_MASK_PFN) >> PAGE_SHIFT; + start_pfn = last_pfn; + bound_sequence = TRUE; + + } else if (bound_sequence) { + + cur_pfn = (cur_flags & DRM_TTM_MASK_PFN) >> PAGE_SHIFT; + + if ( !(cur_flags & DRM_TTM_PAGE_UNCACHED) || + (cur_pfn != last_pfn + 1)) { + + ret = io_remap_pfn_range(vma, + vma->vm_start + (start << PAGE_SHIFT), + (ttm->aperture_base >> PAGE_SHIFT) + + start_pfn, + (end - start + 1) << PAGE_SHIFT, + drm_io_prot(_DRM_AGP, vma)); + + if (ret) + break; + + bound_sequence = (cur_flags & DRM_TTM_PAGE_UNCACHED); + if (!bound_sequence) + continue; + + start = i; + end = i; + last_pfn = cur_pfn; + start_pfn = last_pfn; + + } else { + + end++; + last_pfn = cur_pfn; + + } + } + } + + if (!ret && bound_sequence) { + ret = io_remap_pfn_range(vma, + vma->vm_start + (start << PAGE_SHIFT), + (ttm->aperture_base >> PAGE_SHIFT) + + start_pfn, + (end - start + 1) << PAGE_SHIFT, + drm_io_prot(_DRM_AGP, vma)); + } + + if (ret) { + DRM_ERROR("Map returned %c\n", ret); + } + return ret; +} + +static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address) +{ + drm_ttm_vma_list_t *entry = (drm_ttm_vma_list_t *) + vma->vm_private_data; + drm_map_t *map; + unsigned long page_offset; + struct page *page; + drm_ttm_t *ttm; + pgprot_t default_prot; + uint32_t page_flags; + + if (address > vma->vm_end) + return NOPAGE_SIGBUS; /* Disallow mremap */ + if (!entry) + return NOPAGE_OOM; /* Nothing allocated */ + + map = (drm_map_t *) entry->map; + ttm = (drm_ttm_t *) map->offset; + page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + page = ttm->pages[page_offset]; + + page_flags = ttm->page_flags[page_offset]; + + if (!page) { + page = ttm->pages[page_offset] = + alloc_page(GFP_KERNEL); + SetPageReserved(page); + } + if (!page) + return NOPAGE_OOM; + + get_page(page); + + default_prot = drm_prot_map(vma->vm_flags); + + BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED); + vma->vm_page_prot = default_prot; + + return page; +} + /** * \c nopage method for shared virtual memory. * @@ -243,6 +398,9 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) dmah.size = map->size; __drm_pci_free(dev, &dmah); break; + case _DRM_TTM: + BUG_ON(1); + break; } drm_free(map, sizeof(*map), DRM_MEM_MAPS); } @@ -358,6 +516,15 @@ static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, return drm_do_vm_sg_nopage(vma, address); } +static struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + if (type) + *type = VM_FAULT_MINOR; + return drm_do_vm_ttm_nopage(vma, address); +} + + #else /* LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0) */ static struct page *drm_vm_nopage(struct vm_area_struct *vma, @@ -384,6 +551,13 @@ static struct page *drm_vm_sg_nopage(struct vm_area_struct *vma, return drm_do_vm_sg_nopage(vma, address); } +static struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, int unused) +{ + return drm_do_vm_ttm_nopage(vma, address); +} + + #endif /** AGP virtual memory operations */ @@ -414,6 +588,12 @@ static struct vm_operations_struct drm_vm_sg_ops = { .close = drm_vm_close, }; +static struct vm_operations_struct drm_vm_ttm_ops = { + .nopage = drm_vm_ttm_nopage, + .open = drm_vm_ttm_open_wrapper, + .close = drm_vm_ttm_close, +}; + /** * \c open method for shared virtual memory. * @@ -443,6 +623,46 @@ static void drm_vm_open(struct vm_area_struct *vma) } } +static int drm_vm_ttm_open(struct vm_area_struct *vma) { + + drm_ttm_vma_list_t *entry, *tmp_vma = + (drm_ttm_vma_list_t *) vma->vm_private_data; + drm_map_t *map; + drm_ttm_t *ttm; + drm_file_t *priv = vma->vm_file->private_data; + drm_device_t *dev = priv->head->dev; + int ret = 0; + + drm_vm_open(vma); + mutex_lock(&dev->struct_mutex); + entry = drm_calloc(1, sizeof(*entry), DRM_MEM_VMAS); + if (entry) { + *entry = *tmp_vma; + map = (drm_map_t *) entry->map; + ttm = (drm_ttm_t *) map->offset; + /* ret = drm_ttm_add_mm_to_list(ttm, vma->vm_mm); */ + if (!ret) { + atomic_inc(&ttm->vma_count); + INIT_LIST_HEAD(&entry->head); + entry->vma = vma; + entry->orig_protection = vma->vm_page_prot; + list_add_tail(&entry->head, &ttm->vma_list->head); + vma->vm_private_data = (void *) entry; + DRM_DEBUG("Added VMA to ttm at 0x%016lx\n", + (unsigned long) ttm); + } + } else { + ret = -ENOMEM; + } + mutex_unlock(&dev->struct_mutex); + return ret; +} + +static void drm_vm_ttm_open_wrapper(struct vm_area_struct *vma) +{ + drm_vm_ttm_open(vma); +} + /** * \c close method for all virtual memory types. * @@ -476,6 +696,47 @@ static void drm_vm_close(struct vm_area_struct *vma) mutex_unlock(&dev->struct_mutex); } + +static void drm_vm_ttm_close(struct vm_area_struct *vma) +{ + drm_ttm_vma_list_t *ttm_vma = + (drm_ttm_vma_list_t *) vma->vm_private_data; + drm_map_t *map; + drm_ttm_t *ttm; + int found_maps; + struct list_head *list; + drm_device_t *dev; + + drm_vm_close(vma); + if (ttm_vma) { + map = (drm_map_t *) ttm_vma->map; + ttm = (drm_ttm_t *) map->offset; + dev = ttm->dev; + mutex_lock(&dev->struct_mutex); + list_del(&ttm_vma->head); + /* drm_ttm_delete_mm(ttm, vma->vm_mm); */ + drm_free(ttm_vma, sizeof(*ttm_vma), DRM_MEM_VMAS); + atomic_dec(&ttm->vma_count); + found_maps = 0; + list = NULL; +#if 0 /* Reimplement with vma_count */ + list_for_each(list, &ttm->owner->ttms) { + r_list = list_entry(list, drm_map_list_t, head); + if (r_list->map == map) + found_maps++; + } + if (!found_maps) { + if (drm_destroy_ttm(ttm) != -EBUSY) { + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + } + } +#endif + mutex_unlock(&dev->struct_mutex); + } + return; +} + + /** * mmap DMA memory. * @@ -620,27 +881,9 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: -#if defined(__i386__) || defined(__x86_64__) - if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { - pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; - pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; - } -#elif defined(__powerpc__) - pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; - if (map->type == _DRM_REGISTERS) - pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED; -#endif - vma->vm_flags |= VM_IO; /* not in core dump */ -#if defined(__ia64__) - if (efi_range_is_wc(vma->vm_start, vma->vm_end - - vma->vm_start)) - vma->vm_page_prot = - pgprot_writecombine(vma->vm_page_prot); - else - vma->vm_page_prot = - pgprot_noncached(vma->vm_page_prot); -#endif offset = dev->driver->get_reg_ofs(dev); + vma->vm_flags |= VM_IO; /* not in core dump */ + vma->vm_page_prot = drm_io_prot(map->type, vma); #ifdef __sparc__ if (io_remap_pfn_range(vma, vma->vm_start, (map->offset + offset) >>PAGE_SHIFT, @@ -687,6 +930,22 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; #endif break; + case _DRM_TTM: { + drm_ttm_vma_list_t tmp_vma; + tmp_vma.orig_protection = vma->vm_page_prot; + tmp_vma.map = map; + vma->vm_ops = &drm_vm_ttm_ops; + vma->vm_private_data = (void *) &tmp_vma; + vma->vm_file = filp; + vma->vm_flags |= VM_RESERVED | VM_IO; + if (drm_ttm_remap_bound_pfn(vma, + vma->vm_start, + vma->vm_end - vma->vm_start)) + return -EAGAIN; + if (drm_vm_ttm_open(vma)) + return -EAGAIN; + return 0; + } default: return -EINVAL; /* This should never happen. */ } diff --git a/shared-core/drm.h b/shared-core/drm.h index 65d04b72..b588b15c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -260,6 +260,7 @@ typedef enum drm_map_type { _DRM_AGP = 3, /**< AGP/GART */ _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ _DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */ + _DRM_TTM = 6 } drm_map_type_t; /** -- 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(+) 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 ++++++++ shared-core/i915_drv.h | 7 +++++++ 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 linux-core/i915_buffer.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index bf5221d1..e571f29e 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -19,7 +19,8 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i830-objs := i830_drv.o i830_dma.o i830_irq.o -i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o +i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \ + i915_buffer.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o sis-objs := sis_drv.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 92868005..e7226f1f 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -682,7 +682,7 @@ drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev) { agp_be->destroy = drm_agp_destroy_ttm; return agp_be; } - +EXPORT_SYMBOL(drm_agp_init_ttm_uncached); drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev) { @@ -715,6 +715,6 @@ drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev) { agp_be->destroy = drm_agp_destroy_ttm; return agp_be; } - +EXPORT_SYMBOL(drm_agp_init_ttm_cached); #endif /* __OS_HAS_AGP */ diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c new file mode 100644 index 00000000..bedbd41c --- /dev/null +++ b/linux-core/i915_buffer.c @@ -0,0 +1,40 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" + +drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, int cached) +{ + if (cached) + return drm_agp_init_ttm_cached(dev); + else + return drm_agp_init_ttm_uncached(dev); +} diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 56ac5fc7..64ab3f50 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -48,6 +48,12 @@ static drm_fence_driver_t i915_fence_driver = { .poke_flush = i915_poke_flush, }; +static drm_bo_driver_t i915_bo_driver = { + .cached_pages = 1, + .create_ttm_backend_entry = i915_create_ttm_backend_entry +}; + + static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { /* don't use mtrr's here, the Xserver or user space app should @@ -89,6 +95,8 @@ static struct drm_driver driver = { }, .fence_driver = &i915_fence_driver, + .bo_driver = &i915_bo_driver, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 475ff474..403124c9 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -53,6 +53,7 @@ #if defined(__linux__) #define I915_HAVE_FENCE +#define I915_HAVE_BUFFER #endif typedef struct _drm_i915_ring_buffer { @@ -153,6 +154,12 @@ extern void i915_poke_flush(drm_device_t *dev); extern void i915_sync_flush(drm_device_t *dev); #endif +#ifdef I915_HAVE_BUFFER +/* i915_buffer.c */ +extern drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, + int cached); +#endif + #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) #define I915_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, (reg), (val)) #define I915_READ16(reg) DRM_READ16(dev_priv->mmio_map, (reg)) -- 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) --- libdrm/xf86drm.c | 10 +++++++++- libdrm/xf86drm.h | 4 +++- linux-core/drmP.h | 1 + linux-core/drm_fence.c | 2 ++ shared-core/drm.h | 1 + 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6302db3a..a2a2e28c 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2237,18 +2237,21 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, return 0; } -int drmFenceCreate(int fd, int shareable, unsigned type, int emit, +int drmFenceCreate(int fd, int shareable, int class,unsigned type, + int emit, drmFence *fence) { drm_fence_arg_t arg; arg.type = type; + arg.class = class; arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0; arg.flags |= (emit) ? DRM_FENCE_FLAG_EMIT : 0; arg.op = drm_fence_create; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; fence->handle = arg.handle; + fence->class = arg.class; fence->type = arg.type; fence->signaled = 0; return 0; @@ -2274,6 +2277,7 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence) if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; fence->handle = arg.handle; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; @@ -2299,6 +2303,7 @@ int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type) arg.op = drm_fence_flush; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; @@ -2312,6 +2317,7 @@ int drmFenceSignaled(int fd, drmFence *fence) arg.op = drm_fence_signaled; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; @@ -2326,6 +2332,7 @@ int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) arg.op = drm_fence_emit; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; @@ -2349,6 +2356,7 @@ int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, if (ret) return -errno; + fence->class = arg.class; fence->type = arg.type; fence->signaled = arg.signaled; return 0; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 0e037daa..78730785 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -282,6 +282,7 @@ typedef struct _drmSetVersion { typedef struct _drmFence{ unsigned handle; + int class; unsigned type; unsigned signaled; } drmFence; @@ -603,7 +604,8 @@ extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); /* Fencing */ -extern int drmFenceCreate(int fd, int shareable, unsigned type, int emit, +extern int drmFenceCreate(int fd, int shareable, int class, + unsigned type, int emit, drmFence *fence); extern int drmFenceDestroy(int fd, const drmFence *fence); extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 8f8f324e..5a4a37fc 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -963,6 +963,7 @@ typedef struct drm_fence_object{ */ struct list_head ring; + int class; volatile uint32_t type; volatile uint32_t signaled; uint32_t sequence; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index fc27c576..cfcda2b2 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -397,6 +397,7 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, write_lock_irqsave(&fm->lock, flags); INIT_LIST_HEAD(&fence->ring); + fence->class = 0; fence->type = type; fence->flush_mask = 0; fence->submitted_flush = 0; @@ -577,6 +578,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } read_lock_irqsave(&fm->lock, flags); + arg.class = fence->class; arg.type = fence->type; arg.signaled = fence->signaled; read_unlock_irqrestore(&fm->lock, flags); diff --git a/shared-core/drm.h b/shared-core/drm.h index b588b15c..cd2b1907 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -639,6 +639,7 @@ typedef struct drm_set_version { typedef struct drm_fence_arg { unsigned handle; + int class; unsigned type; unsigned flags; unsigned signaled; -- 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(-) 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(-) 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 8dfe917cb26bbeddda0e1b52060d8dce188468f3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 23 Aug 2006 11:21:33 +0200 Subject: Fix hashtab implementation leaking illegal error codes to user space. (Reported by Dave Airlie) --- linux-core/drm_hashtab.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_hashtab.c b/linux-core/drm_hashtab.c index 48061139..a0b2d680 100644 --- a/linux-core/drm_hashtab.c +++ b/linux-core/drm_hashtab.c @@ -106,7 +106,7 @@ int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item) hlist_for_each(list, h_list) { entry = hlist_entry(list, drm_hash_item_t, head); if (entry->key == key) - return -1; + return -EINVAL; if (entry->key > key) break; parent = list; @@ -154,7 +154,7 @@ int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, list = drm_ht_find_key(ht, key); if (!list) - return -1; + return -EINVAL; *item = hlist_entry(list, drm_hash_item_t, head); return 0; @@ -170,7 +170,7 @@ int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key) ht->fill--; return 0; } - return -1; + return -EINVAL; } int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item) -- cgit v1.2.3 From 459b234d79daaa8a003da9ea48775a5587d5ba2a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 23 Aug 2006 11:31:10 +0200 Subject: Allow multiple addMaps with the same 32-bit map offset. (Reported by Dave Airlie) --- linux-core/drm_bufs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 2eeb401d..13b0b174 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -78,14 +78,16 @@ int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, #error Unsupported long size. Neither 64 nor 32 bits. #endif - if (use_hashed_handle) { - return drm_ht_just_insert_please(&dev->map_hash, hash, - user_token, 32 - PAGE_SHIFT - 3, - PAGE_SHIFT, DRM_MAP_HASH_OFFSET); - } else { + if (!use_hashed_handle) { + int ret; hash->key = user_token; - return drm_ht_insert_item(&dev->map_hash, hash); + ret = drm_ht_insert_item(&dev->map_hash, hash); + if (!ret) + return 0; } + return drm_ht_just_insert_please(&dev->map_hash, hash, + user_token, 32 - PAGE_SHIFT - 3, + PAGE_SHIFT, DRM_MAP_HASH_OFFSET); } /** -- cgit v1.2.3 From ea5709997329a6c425261dcc454cf7dd97a81167 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 23 Aug 2006 13:49:13 +0200 Subject: Fix previous commit: Only fall back to hashed handles when there is a duplicate handle error. Not for other errors. --- linux-core/drm_bufs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 13b0b174..1d9c0386 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -82,8 +82,8 @@ int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, int ret; hash->key = user_token; ret = drm_ht_insert_item(&dev->map_hash, hash); - if (!ret) - return 0; + if (ret != -EINVAL) + return ret; } return drm_ht_just_insert_please(&dev->map_hash, hash, user_token, 32 - PAGE_SHIFT - 3, -- 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 - shared-core/drm.h | 17 +++ 7 files changed, 362 insertions(+), 13 deletions(-) create mode 100644 linux-core/drm_bo.c diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index e571f29e..fba57ddf 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -13,7 +13,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \ drm_memory_debug.o ati_pcigart.o drm_sman.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ - drm_fence.o drm_ttm.o + drm_fence.o drm_ttm.o drm_bo.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drmP.h b/linux-core/drmP.h index e42b5e55..3dd7e775 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -714,6 +714,18 @@ typedef struct drm_fence_manager{ uint32_t exe_flush_sequence; } drm_fence_manager_t; +typedef struct drm_buffer_manager{ + int initialized; + struct mutex bm_mutex; + drm_mm_t tt_manager; + struct list_head tt_lru; + drm_mm_t vram_manager; + struct list_head vram_lru; + struct list_head unfenced; + struct list_head ddestroy; +} drm_buffer_manager_t; + + /** * DRM device structure. This structure represent a complete card that @@ -848,6 +860,7 @@ typedef struct drm_device { drm_head_t primary; /**< primary screen head */ drm_fence_manager_t fm; + drm_buffer_manager_t bm; } drm_device_t; @@ -973,6 +986,29 @@ typedef struct drm_fence_object{ } drm_fence_object_t; +typedef struct drm_buffer_object{ + drm_device_t *dev; + drm_user_object_t base; + atomic_t usage; + drm_map_list_t *ttm_maplist; + drm_ttm_backend_list_t *ttm_region; + + atomic_t mapped; + + uint32_t flags; + uint32_t mask; + uint32_t mask_hint; + + drm_mm_node_t *vram; + drm_mm_node_t *tt; + struct list_head head; + struct list_head ddestroy; + + uint32_t fence_flags; + drm_fence_object_t *fence; + int unfenced; + wait_queue_head_t validate_queue; +} drm_buffer_object_t; @@ -1296,6 +1332,19 @@ extern void drm_fence_handler(drm_device_t *dev, uint32_t breadcrumb, uint32_t t extern void drm_fence_manager_init(drm_device_t *dev); extern void drm_fence_manager_takedown(drm_device_t *dev); extern void drm_fence_flush_old(drm_device_t *dev, uint32_t sequence); +extern int drm_fence_object_flush(drm_device_t * dev, + drm_fence_object_t * fence, uint32_t type); +extern int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type); +extern void drm_fence_usage_deref_locked(drm_device_t * dev, + drm_fence_object_t * fence); +extern void drm_fence_usage_deref_unlocked(drm_device_t * dev, + drm_fence_object_t * fence); +extern int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, + drm_fence_object_t * fence); +extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, + int lazy, int ignore_signals, uint32_t mask); + + extern int drm_fence_ioctl(DRM_IOCTL_ARGS); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c new file mode 100644 index 00000000..d87cd2a1 --- /dev/null +++ b/linux-core/drm_bo.c @@ -0,0 +1,282 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + */ + +#include "drmP.h" + +int drm_fence_buffer_objects(drm_file_t *priv) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry, *next; + uint32_t fence_flags = 0; + int count = 0; + drm_fence_object_t *fence; + int ret; + + mutex_lock(&bm->bm_mutex); + + list_for_each_entry(entry, &bm->unfenced, head) { + BUG_ON(!entry->unfenced); + fence_flags |= entry->fence_flags; + count++; + } + + if (!count) { + mutex_unlock(&bm->bm_mutex); + return 0; + } + + fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + + if (!fence) { + mutex_unlock(&bm->bm_mutex); + return -ENOMEM; + } + + ret = drm_fence_object_init(dev, fence_flags, 1, fence); + if (ret) { + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + mutex_unlock(&bm->bm_mutex); + return ret; + } + + list_for_each_entry_safe(entry, next, &bm->unfenced, head) { + BUG_ON(entry->fence); + entry->unfenced = 0; + entry->fence = fence; + list_del_init(&entry->head); + + if (!(entry->flags & DRM_BO_FLAG_NO_EVICT)) { + if (entry->flags & DRM_BO_FLAG_MEM_TT) { + list_add_tail(&entry->head, &bm->tt_lru); + } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { + list_add_tail(&entry->head, &bm->vram_lru); + } + } + } + + mutex_lock(&dev->struct_mutex); + atomic_add(count - 1, &fence->usage); + mutex_unlock(&dev->struct_mutex); + mutex_unlock(&bm->bm_mutex); + return 0; +} + +/* + * bm locked, + * dev locked. + */ + + +static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) +{ + drm_device_t *dev = buf->dev; + drm_buffer_manager_t *bm = &dev->bm; + int ret = 0; + + BUG_ON(!buf->tt); + + if (buf->fence) { + ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, + buf->fence_flags); + if (ret) + return ret; + drm_fence_usage_deref_unlocked(dev, buf->fence); + buf->fence = NULL; + } + + drm_unbind_ttm_region(buf->ttm_region); + drm_mm_put_block(&bm->tt_manager, buf->tt); + buf->tt = NULL; + buf->flags &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_UNCACHED); + buf->flags |= DRM_BO_FLAG_MEM_LOCAL; + + return 0; +} + + +void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo) +{ + + drm_buffer_manager_t *bm = &dev->bm; + + BUG_ON(bo->unfenced); + + if (bo->fence) { + if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { + drm_fence_object_flush(dev, bo->fence, bo->fence_flags); + list_add_tail(&bo->ddestroy, &bm->ddestroy); + return; + } else { + drm_fence_usage_deref_locked(dev, bo->fence); + bo->fence = NULL; + } + } + + /* + * Take away from lru lists. + */ + + list_del_init(&bo->head); + + if (bo->tt) { + int ret; + ret = drm_move_tt_to_local(bo, 0); + BUG_ON(ret); + } + if (bo->vram) { + drm_mm_put_block(&bm->vram_manager, bo->vram); + bo->vram = NULL; + } + + /* + * FIXME: Destroy ttm. + */ + + drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); +} + +static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, + int init, uint32_t *n_flags) +{ + uint32_t new_flags; + uint32_t new_props; + + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { + + /* + * We need to move memory. Default preferences are hard-coded + * here. + */ + + new_flags = new_mask & DRM_BO_MASK_MEM; + + if (!new_flags) { + DRM_ERROR("Invalid buffer object memory flags\n"); + return -EINVAL; + } + + if (new_flags & DRM_BO_FLAG_MEM_LOCAL) { + if ((hint & DRM_BO_HINT_AVOID_LOCAL) && + new_flags & (DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_TT)) { + new_flags &= ~DRM_BO_FLAG_MEM_LOCAL; + } else { + new_flags = DRM_BO_FLAG_MEM_LOCAL; + } + } + if (new_flags & DRM_BO_FLAG_MEM_TT) { + if ((hint & DRM_BO_HINT_PREFER_VRAM) && + new_flags & DRM_BO_FLAG_MEM_VRAM) { + new_flags = DRM_BO_FLAG_MEM_VRAM; + } else { + new_flags = DRM_BO_FLAG_MEM_TT; + } + } + } else { + new_flags = flags & DRM_BO_MASK_MEM; + } + + new_props = new_mask & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_READ); + + if (!new_props) { + DRM_ERROR("Invalid buffer object rwx properties\n"); + return -EINVAL; + } + + new_flags |= new_mask & ~DRM_BO_MASK_MEM; + *n_flags = new_flags; + return 0; +} + + + +#if 0 + +static int drm_bo_evict(drm_device_t *dev, drm_buffer_object_t *buf, int tt); +{ + int ret; + if (tt) { + ret = drm_move_tt_to_local(buf); + } else { + ret = drm_move_vram_to_local(buf); + } + return ret; +} + +int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) +{ + drm_mm_node_t *node; + drm_buffer_manager_t *bm = &dev->bm; + drm_buffer_object_t *bo; + drm_mm_t *mm = (tt) ? &bm->tt_manager : &bm->vram_manager; + + lru = (tt) ? &bm->tt_lru : &bm->vram_lru; + + do { + node = drm_mm_search_free(mm, size, 0, 1); + if (node) + break; + + if (lru->next == lru) + break; + + if (tt) { + bo = list_entry(lru->next, drm_buffer_object_t, tt_lru); + } else { + bo = list_entry(lru->next, drm_buffer_object_t, vram_lru); + } + + drm_bo_evict(dev, bo, tt); + } while (1); + + if (!node) { + DRM_ERROR("Out of aperture space\n"); + return -ENOMEM; + } + + node = drm_mm_get_block(node, size, 0); + BUG_ON(!node); + node->private = (void *)buf; + + if (tt) { + buf->tt = node; + } else { + buf->vram = node; + } + return 0; +} +#endif + + + + diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index cfcda2b2..897f84c5 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -252,12 +252,17 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, } } +int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type) +{ + return ((fence->signaled & type) == type); +} + /* * Make sure old fence objects are signaled before their fence sequences are * wrapped around and reused. */ -static int drm_fence_object_flush(drm_device_t * dev, +int drm_fence_object_flush(drm_device_t * dev, drm_fence_object_t * fence, uint32_t type) { drm_fence_manager_t *fm = &dev->fm; @@ -317,8 +322,8 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) EXPORT_SYMBOL(drm_fence_flush_old); -static int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, - int lazy, int ignore_signals, uint32_t mask) +int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, + int lazy, int ignore_signals, uint32_t mask) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index df4c312c..806c109b 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -398,10 +398,6 @@ static int drm_set_caching(drm_ttm_t * ttm, unsigned long page_offset, struct page **cur_page; pgprot_t attr = (noncached) ? PAGE_KERNEL_NOCACHE : PAGE_KERNEL; - drm_ttm_lock_mm(ttm, 0, 1); - unmap_vma_pages(ttm, page_offset, num_pages); - drm_ttm_unlock_mm(ttm, 0, 1); - for (i = 0; i < num_pages; ++i) { cur = page_offset + i; cur_page = ttm->pages + cur; @@ -446,7 +442,6 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) drm_ttm_lock_mm(ttm, 0, 1); unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); - global_flush_tlb(); drm_ttm_unlock_mm(ttm, 0, 1); } be->unbind(entry->be); @@ -489,6 +484,10 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) be->clear(entry->be); if (be->needs_cache_adjust(be)) { int ret = drm_ttm_lock_mmap_sem(ttm); + drm_ttm_lock_mm(ttm, 0, 1); + unmap_vma_pages(ttm, entry->page_offset, + entry->num_pages); + drm_ttm_unlock_mm(ttm, 0, 1); drm_set_caching(ttm, entry->page_offset, entry->num_pages, 0, 1); if (!ret) @@ -792,8 +791,7 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) return -ENOMEM; } - list->user_token = - (list->hash.key << PAGE_SHIFT) + DRM_MAP_HASH_OFFSET; + list->user_token = list->hash.key; list->map = map; *maplist = list; diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 85b39490..9c2fbe08 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -703,8 +703,6 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma) (drm_ttm_vma_list_t *) vma->vm_private_data; drm_map_t *map; drm_ttm_t *ttm; - int found_maps; - struct list_head *list; drm_device_t *dev; int ret; diff --git a/shared-core/drm.h b/shared-core/drm.h index cd2b1907..bda565b3 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -655,6 +655,23 @@ typedef struct drm_fence_arg { } op; } drm_fence_arg_t; +#define DRM_BO_FLAG_READ 0x00000001 +#define DRM_BO_FLAG_WRITE 0x00000002 +#define DRM_BO_FLAG_EXE 0x00000004 +#define DRM_BO_FLAG_NO_MOVE 0x00000008 +#define DRM_BO_FLAG_NO_EVICT 0x00000010 +#define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 +#define DRM_BO_FLAG_READ_LOCAL 0x00000040 +#define DRM_BO_FLAG_UNCACHED 0x00000080 + + +#define DRM_BO_FLAG_MEM_TT 0x01000000 +#define DRM_BO_FLAG_MEM_VRAM 0x02000000 +#define DRM_BO_FLAG_MEM_LOCAL 0x04000000 +#define DRM_BO_MASK_MEM 0xFFFFFFFF + +#define DRM_BO_HINT_PREFER_VRAM 0x00000001 +#define DRM_BO_HINT_AVOID_LOCAL 0x00000002 /** * \name Ioctls Definitions -- 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(-) 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 ++ shared-core/drm.h | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 120 insertions(+), 2 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 3dd7e775..9e1e4ba8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1347,6 +1347,12 @@ extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, extern int drm_fence_ioctl(DRM_IOCTL_ARGS); +/* + * buffer objects (drm_bo.c) + */ + +extern int drm_bo_ioctl(DRM_IOCTL_ARGS); + /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_map *map, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d87cd2a1..6a677578 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -277,6 +277,38 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif +static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, void __user *data) +{ + return 0; +} + +int drm_bo_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_bo_arg_t arg; + unsigned long data_ptr; + (void) dev; + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + data_ptr = arg.data_lo; + + if (sizeof(data_ptr) > 4) { + int shift = 32; + data_ptr |= arg.data_hi << shift; + } + + switch(arg.op) { + case drm_op_bo: + return drm_do_bo_ioctl(priv, arg.num_requests, + (void __user *) data_ptr); + case drm_op_ttm: + return drm_ttm_ioctl(priv, arg.num_requests, + (drm_ttm_arg_t __user *) data_ptr); + } + + return 0; +} + diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 806c109b..46878a7d 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -798,3 +798,8 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) return 0; } + +int drm_ttm_ioctl(drm_file_t *priv, int num_requests, drm_ttm_arg_t __user *data) +{ + return 0; +} diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index ea9a8372..81006c3c 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -148,6 +148,8 @@ extern int drm_destroy_ttm(drm_ttm_t * ttm); extern void drm_user_destroy_region(drm_ttm_backend_list_t * entry); extern int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm); extern void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm); +extern int drm_ttm_ioctl(drm_file_t *priv, int num_requests, + drm_ttm_arg_t __user *data); #define DRM_MASK_VAL(dest, mask, val) \ (dest) = ((dest) & ~(mask)) | ((val) & (mask)); diff --git a/shared-core/drm.h b/shared-core/drm.h index bda565b3..fb18b5c5 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -671,7 +671,80 @@ typedef struct drm_fence_arg { #define DRM_BO_MASK_MEM 0xFFFFFFFF #define DRM_BO_HINT_PREFER_VRAM 0x00000001 -#define DRM_BO_HINT_AVOID_LOCAL 0x00000002 +#define DRM_BO_HINT_AVOID_LOCAL 0x00000002 +#define DRM_BO_HINT_DONT_BLOCK 0x00000004 + +/* + * Multiplexing ioctl argument. + */ + +typedef struct drm_bo_arg { + unsigned num_requests; + enum { + drm_op_bo, + drm_op_ttm + } op; + unsigned data_lo; + unsigned data_hi; +} drm_bo_arg_t; + +typedef struct drm_ttm_arg { + enum { + drm_ttm_create, + drm_ttm_destroy, + drm_ttm_reference, + drm_ttm_unreference + } op; + unsigned handle; + unsigned size_lo; + unsigned size_hi; +}drm_ttm_arg_t; + + +typedef struct drm_bo_arg_request { + unsigned handle; /* User space handle */ + unsigned mask; + unsigned hint; + unsigned size_lo; + unsigned size_hi; + + enum { + drm_bo_type_ttm, + drm_bo_type_dc, + drm_bo_type_user + }type; + unsigned arg_handle; + unsigned user_pointer_lo; + unsigned user_pointer_hi; + enum { + drm_bo_create, + drm_bo_validate, + drm_bo_map, + drm_bo_fence, + drm_bo_destroy, + drm_bo_reference, + drm_bo_unreference + } op; +} drm_bo_arg_request_t; + +typedef struct drm_bo_arg_reply { + int ret; + unsigned handle; + unsigned flags; + unsigned size_lo; + unsigned size_hi; + unsigned offset_lo; + unsigned offset_hi; + unsigned arg_handle; + unsigned map_flags; +}drm_bo_arg_reply_t; + + +typedef union { + drm_bo_arg_request_t bo_req; + drm_bo_arg_reply_t bo_rep; +}drm_bo_arg_data; + /** * \name Ioctls Definitions @@ -739,7 +812,7 @@ typedef struct drm_fence_arg { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) - +#define DRM_IOCTL_BUFFER_OBJECT DRM_IOWR(0x3c, drm_buffer_arg_t) /*@}*/ -- 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 +-- shared-core/drm.h | 8 +++---- 4 files changed, 63 insertions(+), 13 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 6a677578..847b0406 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -31,6 +31,30 @@ #include "drmP.h" +/* + * Buffer object locking policy: + * Lock dev->struct_mutex; + * Increase usage + * Unlock dev->struct_mutex; + * Lock buffer->mutex; + * Do whatever you want; + * Unlock buffer->mutex; + * Decrease usage. Call destruction if zero. + * + * User object visibility ups usage just once, since it has its own + * refcounting. + * + * Destruction: + * lock dev->struct_mutex; + * Verify that usage is zero. Otherwise unlock and continue. + * Destroy object. + * unlock dev->struct_mutex; + * + * Mutex and spinlock locking orders: + * 1.) Buffer mutex + * 2.) Refer to ttm locking orders. + */ + int drm_fence_buffer_objects(drm_file_t *priv) { drm_device_t *dev = priv->head->dev; @@ -277,11 +301,35 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif -static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, void __user *data) +static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, + drm_bo_arg_data_t __user *data) { - return 0; + drm_bo_arg_data_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t rep; + int i, ret; + + for (i=0; i Date: Sat, 26 Aug 2006 12:21:11 +0200 Subject: Bug #7595: Avoid u32 overflows in radeon_check_and_fixup_offset(). The overflows could cause valid offsets to get rejected under some circumstances, e.g. when the framebuffer resides at the very end of the card's address space. --- shared-core/radeon_state.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 58251dd7..38b87148 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -42,7 +42,11 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * drm_file_t * filp_priv, u32 * offset) { - u32 off = *offset; + u64 off = *offset; + u32 fb_start = dev_priv->fb_location; + u32 fb_end = fb_start + dev_priv->fb_size - 1; + u32 gart_start = dev_priv->gart_vm_start; + u32 gart_end = gart_start + dev_priv->gart_size - 1; struct drm_radeon_driver_file_fields *radeon_priv; /* Hrm ... the story of the offset ... So this function converts @@ -62,10 +66,8 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * /* First, the best case, the offset already lands in either the * framebuffer or the GART mapped space */ - if ((off >= dev_priv->fb_location && - off < (dev_priv->fb_location + dev_priv->fb_size)) || - (off >= dev_priv->gart_vm_start && - off < (dev_priv->gart_vm_start + dev_priv->gart_size))) + if ((off >= fb_start && off <= fb_end) || + (off >= gart_start && off <= gart_end)) return 0; /* Ok, that didn't happen... now check if we have a zero based @@ -78,16 +80,13 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t * } /* Finally, assume we aimed at a GART offset if beyond the fb */ - if (off > (dev_priv->fb_location + dev_priv->fb_size)) - off = off - (dev_priv->fb_location + dev_priv->fb_size) + - dev_priv->gart_vm_start; + if (off > fb_end) + off = off - fb_end - 1 + gart_start; /* Now recheck and fail if out of bounds */ - if ((off >= dev_priv->fb_location && - off < (dev_priv->fb_location + dev_priv->fb_size)) || - (off >= dev_priv->gart_vm_start && - off < (dev_priv->gart_vm_start + dev_priv->gart_size))) { - DRM_DEBUG("offset fixed up to 0x%x\n", off); + if ((off >= fb_start && off <= fb_end) || + (off >= gart_start && off <= gart_end)) { + DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off); *offset = off; return 0; } -- cgit v1.2.3 From 65e7274008446d2059b7fd7cd6d7b1d6b04da0ce Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom 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 ++- shared-core/drm.h | 4 + 5 files changed, 243 insertions(+), 124 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 9e1e4ba8..43589342 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -587,6 +587,64 @@ typedef struct drm_mm { drm_mm_node_t root_node; } drm_mm_t; + +/* + * User space objects and their references. + */ + +#define drm_user_object_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) + +typedef enum { + drm_fence_type, + drm_buffer_type, + drm_ttm_type + + /* + * Add other user space object types here. + */ + +} drm_object_type_t; + + + + +/* + * A user object is a structure that helps the drm give out user handles + * to kernel internal objects and to keep track of these objects so that + * they can be destroyed, for example when the user space process exits. + * Designed to be accessible using a user space 32-bit handle. + */ + +typedef struct drm_user_object{ + drm_hash_item_t hash; + struct list_head list; + drm_object_type_t type; + atomic_t refcount; + int shareable; + drm_file_t *owner; + void (*ref_struct_locked) (drm_file_t *priv, struct drm_user_object *obj, + drm_ref_t ref_action); + void (*unref)(drm_file_t *priv, struct drm_user_object *obj, + drm_ref_t unref_action); + void (*remove)(drm_file_t *priv, struct drm_user_object *obj); +} drm_user_object_t; + +/* + * A ref object is a structure which is used to + * keep track of references to user objects and to keep track of these + * references so that they can be destroyed for example when the user space + * process exits. Designed to be accessible using a pointer to the _user_ object. + */ + + +typedef struct drm_ref_object { + drm_hash_item_t hash; + struct list_head list; + atomic_t refcount; + drm_ref_t unref_action; +} drm_ref_object_t; + + #include "drm_ttm.h" /* @@ -873,101 +931,6 @@ typedef struct drm_agp_ttm_priv { } drm_agp_ttm_priv; #endif - -static __inline__ int drm_core_check_feature(struct drm_device *dev, - int feature) -{ - return ((dev->driver->driver_features & feature) ? 1 : 0); -} - -#if __OS_HAS_AGP -static inline int drm_core_has_AGP(struct drm_device *dev) -{ - return drm_core_check_feature(dev, DRIVER_USE_AGP); -} -#else -#define drm_core_has_AGP(dev) (0) -#endif - -#if __OS_HAS_MTRR -static inline int drm_core_has_MTRR(struct drm_device *dev) -{ - return drm_core_check_feature(dev, DRIVER_USE_MTRR); -} - -#define DRM_MTRR_WC MTRR_TYPE_WRCOMB - -static inline int drm_mtrr_add(unsigned long offset, unsigned long size, - unsigned int flags) -{ - return mtrr_add(offset, size, flags, 1); -} - -static inline int drm_mtrr_del(int handle, unsigned long offset, - unsigned long size, unsigned int flags) -{ - return mtrr_del(handle, offset, size); -} - -#else -#define drm_core_has_MTRR(dev) (0) -#endif - -/* - * User space objects and their references. - */ - -#define drm_user_object_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) - -typedef enum { - drm_fence_type, - drm_buffer_type - - /* - * Add other user space object types here. - */ - -} drm_object_type_t; - - - - -/* - * A user object is a structure that helps the drm give out user handles - * to kernel internal objects and to keep track of these objects so that - * they can be destroyed, for example when the user space process exits. - * Designed to be accessible using a user space 32-bit handle. - */ - -typedef struct drm_user_object{ - drm_hash_item_t hash; - struct list_head list; - drm_object_type_t type; - atomic_t refcount; - int shareable; - drm_file_t *owner; - void (*ref_struct_locked) (drm_file_t *priv, struct drm_user_object *obj, - drm_ref_t ref_action); - void (*unref)(drm_file_t *priv, struct drm_user_object *obj, - drm_ref_t unref_action); - void (*remove)(drm_file_t *priv, struct drm_user_object *obj); -} drm_user_object_t; - -/* - * A ref object is a structure which is used to - * keep track of references to user objects and to keep track of these - * references so that they can be destroyed for example when the user space - * process exits. Designed to be accessible using a pointer to the _user_ object. - */ - - -typedef struct drm_ref_object { - drm_hash_item_t hash; - struct list_head list; - atomic_t refcount; - drm_ref_t unref_action; -} drm_ref_object_t; - typedef struct drm_fence_object{ drm_user_object_t base; atomic_t usage; @@ -1012,6 +975,46 @@ typedef struct drm_buffer_object{ +static __inline__ int drm_core_check_feature(struct drm_device *dev, + int feature) +{ + return ((dev->driver->driver_features & feature) ? 1 : 0); +} + +#if __OS_HAS_AGP +static inline int drm_core_has_AGP(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_AGP); +} +#else +#define drm_core_has_AGP(dev) (0) +#endif + +#if __OS_HAS_MTRR +static inline int drm_core_has_MTRR(struct drm_device *dev) +{ + return drm_core_check_feature(dev, DRIVER_USE_MTRR); +} + +#define DRM_MTRR_WC MTRR_TYPE_WRCOMB + +static inline int drm_mtrr_add(unsigned long offset, unsigned long size, + unsigned int flags) +{ + return mtrr_add(offset, size, flags, 1); +} + +static inline int drm_mtrr_del(int handle, unsigned long offset, + unsigned long size, unsigned int flags) +{ + return mtrr_del(handle, offset, size); +} + +#else +#define drm_core_has_MTRR(dev) (0) +#endif + + /******************************************************************/ /** \name Internal function definitions */ /*@{*/ @@ -1353,6 +1356,20 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); +/* + * Convenience 2*32-bit to 64-bit function + */ + +static __inline__ unsigned long combine_64(uint32_t lo, uint32_t hi) +{ + unsigned long ret = lo; + + if (sizeof(ret) > 4) { + int shift = 32; + lo |= (hi << shift); + } + return ret; +} /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_map *map, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 847b0406..35d4aba7 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -338,13 +338,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) (void) dev; DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - data_ptr = arg.data_lo; - - if (sizeof(data_ptr) > 4) { - int shift = 32; - data_ptr |= arg.data_hi << shift; - } - + data_ptr = combine_64(arg.data_lo, arg.data_hi); switch(arg.op) { case drm_op_bo: arg.num_requests = drm_do_bo_ioctl(priv, arg.num_requests, diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 05bae7de..293b1f8c 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,6 +42,7 @@ typedef struct drm_val_action { int validated; } drm_val_action_t; + /* * We may be manipulating other processes page tables, so for each TTM, keep track of * which mm_structs are currently mapping the ttm so that we can take the appropriate @@ -275,6 +276,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); + ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -746,25 +748,80 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, return 0; } + /* - * Create a ttm and add it to the drm book-keeping. + * dev->struct_mutex locked. */ -int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) +static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) { + drm_map_list_t *list = &object->map_list; + drm_local_map_t *map; + + if (list->user_token) + drm_ht_remove_item(&dev->map_hash, &list->hash); + + map = list->map; + + if (map) { + drm_ttm_t *ttm = (drm_ttm_t *)map->offset; + if (ttm) { + if (drm_destroy_ttm(ttm) != -EBUSY) { + drm_free(map, sizeof(*map), DRM_MEM_TTM); + } + } else { + drm_free(map, sizeof(*map), DRM_MEM_TTM); + } + } + + drm_free(object, sizeof(*object), DRM_MEM_TTM); +} + +/* + * dev->struct_mutex locked. + */ +static void drm_ttm_user_object_remove(drm_file_t *priv, drm_user_object_t *base) +{ + drm_ttm_object_t *object; + drm_device_t *dev = priv->head->dev; + + object = drm_user_object_entry(base, drm_ttm_object_t, base); + if (atomic_dec_and_test(&object->usage)) + drm_ttm_object_remove(dev, object); +} + + + +/* + * Create a ttm and add it to the drm book-keeping. + * dev->struct_mutex locked. + */ + +int drm_ttm_object_create(drm_device_t *dev, unsigned long size, + uint32_t flags, drm_ttm_object_t **ttm_object) +{ + drm_ttm_object_t *object; drm_map_list_t *list; drm_map_t *map; drm_ttm_t *ttm; - map = drm_alloc(sizeof(*map), DRM_MEM_TTM); - if (!map) + object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); + if (!object) + return -ENOMEM; + object->flags = flags; + list = &object->map_list; + + list->map = drm_calloc(1, sizeof(*map), DRM_MEM_TTM); + if (!list->map) { + drm_ttm_object_remove(dev, object); return -ENOMEM; + } + map = list->map; ttm = drm_init_ttm(dev, size); - if (!ttm) { DRM_ERROR("Could not create ttm\n"); - drm_free(map, sizeof(*map), DRM_MEM_TTM); + drm_ttm_object_remove(dev, object); return -ENOMEM; } @@ -772,34 +829,73 @@ int drm_add_ttm(drm_device_t * dev, unsigned size, drm_map_list_t ** maplist) map->type = _DRM_TTM; map->flags = _DRM_REMOVABLE; map->size = size; - - list = drm_calloc(1, sizeof(*list), DRM_MEM_TTM); - if (!list) { - drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_TTM); - return -ENOMEM; - } - map->handle = (void *)list; - + map->handle = (void *)object; + if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, (unsigned long) map->handle, 32 - PAGE_SHIFT - 3, PAGE_SHIFT, DRM_MAP_HASH_OFFSET)) { - drm_destroy_ttm(ttm); - drm_free(map, sizeof(*map), DRM_MEM_TTM); - drm_free(list, sizeof(*list), DRM_MEM_TTM); + drm_ttm_object_remove(dev, object); return -ENOMEM; } list->user_token = list->hash.key; - list->map = map; - - *maplist = list; + object->base.remove = drm_ttm_user_object_remove; + object->base.type = drm_ttm_type; + object->base.ref_struct_locked = NULL; + object->base.unref = NULL; + atomic_set(&object->usage, 1); return 0; } + int drm_ttm_ioctl(drm_file_t *priv, drm_ttm_arg_t __user *data) { + drm_ttm_arg_t arg; + drm_device_t *dev = priv->head->dev; + drm_ttm_object_t *entry; + drm_user_object_t *uo; + unsigned long size; + int ret; + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + + switch(arg.op) { + case drm_ttm_create: + mutex_lock(&dev->struct_mutex); + size = combine_64(arg.size_lo, arg.size_hi); + ret = drm_ttm_object_create(dev, size, arg.flags, &entry); + if (ret) { + mutex_unlock(&dev->struct_mutex); + return ret; + } + ret = drm_add_user_object(priv, &entry->base, + arg.flags & DRM_TTM_FLAG_SHAREABLE); + if (ret) { + drm_ttm_object_remove(dev, entry); + mutex_unlock(&dev->struct_mutex); + return ret; + } + arg.handle = entry->base.hash.key; + arg.user_token = entry->map_list.user_token; + mutex_unlock(&dev->struct_mutex); + break; + case drm_ttm_reference: + return drm_user_object_ref(priv, arg.handle, drm_ttm_type, &uo); + case drm_ttm_unreference: + return drm_user_object_unref(priv, arg.handle, drm_ttm_type); + case drm_ttm_destroy: + mutex_lock(&dev->struct_mutex); + uo = drm_lookup_user_object(priv, arg.handle); + if (!uo || (uo->type != drm_ttm_type) || uo->owner != priv) { + mutex_unlock(&dev->struct_mutex); + return -EINVAL; + } + ret = drm_remove_user_object(priv, uo); + mutex_unlock(&dev->struct_mutex); + return ret; + } + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); return 0; } diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 5a7569ff..bad21c97 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -101,7 +101,15 @@ typedef struct drm_ttm { int destroy; } drm_ttm_t; -int drm_add_ttm(struct drm_device * dev, unsigned size, drm_map_list_t ** maplist); +typedef struct drm_ttm_object { + drm_user_object_t base; + atomic_t usage; + uint32_t flags; + drm_map_list_t map_list; +} drm_ttm_object_t; + + + /* * Bind a part of the ttm starting at page_offset size n_pages into the GTT, at diff --git a/shared-core/drm.h b/shared-core/drm.h index feadfc67..450864bc 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -688,6 +688,8 @@ typedef struct drm_bo_arg { unsigned data_hi; } drm_bo_arg_t; +#define DRM_TTM_FLAG_SHAREABLE 0x00000001 + typedef struct drm_ttm_arg { enum { drm_ttm_create, @@ -696,8 +698,10 @@ typedef struct drm_ttm_arg { drm_ttm_unreference } op; unsigned handle; + unsigned user_token; unsigned size_lo; unsigned size_hi; + unsigned flags; }drm_ttm_arg_t; -- 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(-) 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(-) 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. --- libdrm/xf86drm.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++ libdrm/xf86drm.h | 7 ++++ linux-core/drm_bo.c | 43 ----------------------- linux-core/drm_drv.c | 16 ++++++--- linux-core/drm_ttm.c | 4 +-- linux-core/drm_ttm.h | 2 +- shared-core/drm.h | 3 +- 7 files changed, 119 insertions(+), 52 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a2a2e28c..e666df3c 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2362,4 +2362,100 @@ int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, return 0; } +static unsigned long combine64(unsigned lo, unsigned hi) +{ + unsigned long ret = lo; + if (sizeof(ret) == 8) { + int shift = 32; + ret |= (hi << shift); + } + return ret; +} + +static void split32(unsigned long val, unsigned *lo, unsigned *hi) +{ + *lo = val & 0xFFFFFFFFUL; + if (sizeof(val) == 8) { + int shift = 32; + *hi = val >> shift; + } else { + *hi = 0; + } +} + +int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) +{ + drm_ttm_arg_t argTTM; + drm_bo_arg_t arg; + + arg.num_requests = 1; + arg.op = drm_op_ttm; + split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); + + argTTM.op = drm_ttm_create; + argTTM.flags = flags; + split32((unsigned long) &size, &argTTM.size_lo, &argTTM.size_hi); + + if (ioctl(fd, DRM_IOCTL_TTM, &arg)) + return -errno; + + ttm->handle = argTTM.handle; + ttm->user_token = (drm_handle_t) argTTM.user_token; + ttm->flags = argTTM.flags; + ttm->size = combine64(argTTM.size_lo, argTTM.size_hi); + return 0; +} + +int drmTTMDestroy(int fd, const drmTTM *ttm) +{ + drm_ttm_arg_t argTTM; + drm_bo_arg_t arg; + arg.num_requests = 1; + arg.op = drm_op_ttm; + split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); + argTTM.op = drm_ttm_destroy; + argTTM.handle = ttm->handle; + if (ioctl(fd, DRM_IOCTL_TTM, &arg)) + return -errno; + return 0; +} + + +int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) +{ + drm_ttm_arg_t argTTM; + drm_bo_arg_t arg; + + arg.num_requests = 1; + arg.op = drm_op_ttm; + split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); + + argTTM.handle = handle; + argTTM.op = drm_ttm_reference; + if (ioctl(fd, DRM_IOCTL_TTM, &arg)) + return -errno; + ttm->handle = argTTM.handle; + ttm->user_token = (drm_handle_t) argTTM.user_token; + ttm->flags = argTTM.flags; + ttm->size = combine64(argTTM.size_lo, argTTM.size_hi); + return 0; +} + +int drmTTMUnreference(int fd, const drmTTM *ttm) +{ + drm_ttm_arg_t argTTM; + drm_bo_arg_t arg; + + argTTM.op = drm_ttm_destroy; + argTTM.handle = ttm->handle; + if (ioctl(fd, DRM_IOCTL_TTM, &arg)) + return -errno; + return 0; +} + +drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm) +{ + (void) fd; + return ttm->user_token; +} diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 78730785..92cef4c0 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -287,6 +287,13 @@ typedef struct _drmFence{ unsigned signaled; } drmFence; +typedef struct _drmTTM{ + unsigned handle; + drm_handle_t user_token; + unsigned flags; + unsigned long size; +} drmTTM; + #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) #define DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 35d4aba7..5eb09839 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -301,34 +301,6 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) } #endif -static int drm_do_bo_ioctl(drm_file_t *priv, int num_requests, - drm_bo_arg_data_t __user *data) -{ - drm_bo_arg_data_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t rep; - int i, ret; - - for (i=0; ipid, cmd, nr, (long)old_encode_dev(priv->head->device), priv->authenticated); - if (nr < DRIVER_IOCTL_COUNT) + 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)); diff --git a/shared-core/drm.h b/shared-core/drm.h index 450864bc..726a5140 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -816,7 +816,7 @@ typedef union drm_bo_arg_data { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) -#define DRM_IOCTL_BUFFER_OBJECT DRM_IOWR(0x3c, drm_buffer_arg_t) +#define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) /*@}*/ @@ -828,5 +828,6 @@ typedef union drm_bo_arg_data { * drmCommandReadWrite(). */ #define DRM_COMMAND_BASE 0x40 +#define DRM_COMMAND_END 0x80 #endif -- cgit v1.2.3 From 928bdc6c1c9cd1e60f0b070533768aaca56c84d8 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 27 Aug 2006 21:21:06 +0200 Subject: Initialize i915 saved flush flags. --- shared-core/i915_dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index d6bb6c8e..8ef9d8e1 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -195,7 +195,9 @@ static int i915_initialize(drm_device_t * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); - +#ifdef I915_HAVE_FENCE + dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); +#endif dev->dev_private = (void *)dev_priv; return 0; -- 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. --- libdrm/xf86drm.c | 57 +++++++++++++++++++--------------------------------- libdrm/xf86drm.h | 7 +++++++ linux-core/drm_ttm.c | 1 + 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index e666df3c..88676083 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2385,37 +2385,28 @@ static void split32(unsigned long val, unsigned *lo, unsigned *hi) int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) { - drm_ttm_arg_t argTTM; - drm_bo_arg_t arg; + drm_ttm_arg_t arg; - arg.num_requests = 1; - arg.op = drm_op_ttm; - split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); - - argTTM.op = drm_ttm_create; - argTTM.flags = flags; - split32((unsigned long) &size, &argTTM.size_lo, &argTTM.size_hi); + arg.op = drm_ttm_create; + arg.flags = flags; + split32((unsigned long) size, &arg.size_lo, &arg.size_hi); if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; - ttm->handle = argTTM.handle; - ttm->user_token = (drm_handle_t) argTTM.user_token; - ttm->flags = argTTM.flags; - ttm->size = combine64(argTTM.size_lo, argTTM.size_hi); + ttm->handle = arg.handle; + ttm->user_token = (drm_handle_t) arg.user_token; + ttm->flags = arg.flags; + ttm->size = combine64(arg.size_lo, arg.size_hi); return 0; } int drmTTMDestroy(int fd, const drmTTM *ttm) { - drm_ttm_arg_t argTTM; - drm_bo_arg_t arg; + drm_ttm_arg_t arg; - arg.num_requests = 1; - arg.op = drm_op_ttm; - split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); - argTTM.op = drm_ttm_destroy; - argTTM.handle = ttm->handle; + arg.op = drm_ttm_destroy; + arg.handle = ttm->handle; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; return 0; @@ -2424,31 +2415,25 @@ int drmTTMDestroy(int fd, const drmTTM *ttm) int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) { - drm_ttm_arg_t argTTM; - drm_bo_arg_t arg; - - arg.num_requests = 1; - arg.op = drm_op_ttm; - split32((unsigned long) &argTTM, &arg.data_lo, &arg.data_hi); + drm_ttm_arg_t arg; - argTTM.handle = handle; - argTTM.op = drm_ttm_reference; + arg.handle = handle; + arg.op = drm_ttm_reference; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; - ttm->handle = argTTM.handle; - ttm->user_token = (drm_handle_t) argTTM.user_token; - ttm->flags = argTTM.flags; - ttm->size = combine64(argTTM.size_lo, argTTM.size_hi); + ttm->handle = arg.handle; + ttm->user_token = (drm_handle_t) arg.user_token; + ttm->flags = arg.flags; + ttm->size = combine64(arg.size_lo, arg.size_hi); return 0; } int drmTTMUnreference(int fd, const drmTTM *ttm) { - drm_ttm_arg_t argTTM; - drm_bo_arg_t arg; + drm_ttm_arg_t arg; - argTTM.op = drm_ttm_destroy; - argTTM.handle = ttm->handle; + arg.op = drm_ttm_destroy; + arg.handle = ttm->handle; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; return 0; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 92cef4c0..433191b4 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -623,6 +623,13 @@ extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, int lazy, int ignore_signals); extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); +/* TTMS */ +extern int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, + unsigned flags); +extern int drmTTMDestroy(int fd, const drmTTM *ttm); +extern int drmTTMReference(int fd, unsigned handle, drmTTM *ttm); +extern int drmTTMUnreference(int fd, const drmTTM *ttm); +extern drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm); /* Support routines */ diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 950b0d4d..ad7b279e 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -846,6 +846,7 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, object->base.unref = NULL; atomic_set(&object->usage, 1); + *ttm_object = object; return 0; } -- cgit v1.2.3 From 27c72b67eceec7517c34d2ca456c7474a353d6e6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 19 Aug 2006 16:31:34 +1000 Subject: drm: i810_dma.c: fix pointer arithmetic for 64-bit target First warning result from open-coded PTR_ERR, the rest is caused by code like this: *(u32 *) ((u32) buf_priv->kernel_virtual + used) I've also fixed a missing PTR_ERR in i830_dma.c From: Denis Vlasenko Signed-off-by: Dave Airlie --- linux-core/i810_dma.c | 8 ++++---- linux-core/i830_dma.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 800c5f61..27d8efb9 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -166,10 +166,10 @@ static int i810_map_buffer(drm_buf_t * buf, struct file *filp) MAP_SHARED, buf->bus_address); dev_priv->mmap_buffer = NULL; filp->f_op = old_fops; - if ((unsigned long)buf_priv->virtual > -1024UL) { + if (IS_ERR(buf_priv->virtual)) { /* Real error */ DRM_ERROR("mmap error\n"); - retcode = (signed int)buf_priv->virtual; + retcode = PTR_ERR(buf_priv->virtual); buf_priv->virtual = NULL; } up_write(¤t->mm->mmap_sem); @@ -833,7 +833,7 @@ static void i810_dma_dispatch_vertex(drm_device_t * dev, ((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2))); if (used & 4) { - *(u32 *) ((u32) buf_priv->kernel_virtual + used) = 0; + *(u32 *) ((char *) buf_priv->kernel_virtual + used) = 0; used += 4; } @@ -1191,7 +1191,7 @@ static void i810_dma_dispatch_mc(drm_device_t * dev, drm_buf_t * buf, int used, if (buf_priv->currently_mapped == I810_BUF_MAPPED) { if (used & 4) { - *(u32 *) ((u32) buf_priv->virtual + used) = 0; + *(u32 *) ((char *) buf_priv->virtual + used) = 0; used += 4; } diff --git a/linux-core/i830_dma.c b/linux-core/i830_dma.c index a122898b..9694f64a 100644 --- a/linux-core/i830_dma.c +++ b/linux-core/i830_dma.c @@ -155,7 +155,7 @@ static int i830_map_buffer(drm_buf_t * buf, struct file *filp) if (IS_ERR((void *)virtual)) { /* ugh */ /* Real error */ DRM_ERROR("mmap error\n"); - retcode = virtual; + retcode = PTR_ERR((void *)virtual); buf_priv->virtual = NULL; } else { buf_priv->virtual = (void __user *)virtual; -- cgit v1.2.3 From 3a91e1a5fbfbca4654cca0ef41dc016fd8be80dd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 19 Aug 2006 16:36:26 +1000 Subject: fixup some of the comments in drm_context.c --- linux-core/drm_context.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_context.c b/linux-core/drm_context.c index 95581b53..49042272 100644 --- a/linux-core/drm_context.c +++ b/linux-core/drm_context.c @@ -53,7 +53,7 @@ * \param ctx_handle context handle. * * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry - * in drm_device::context_sareas, while holding the drm_device::struct_sem + * in drm_device::context_sareas, while holding the drm_device::struct_mutex * lock. */ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle) @@ -83,7 +83,7 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle) * * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates * drm_device::context_sareas to accommodate the new entry while holding the - * drm_device::struct_sem lock. + * drm_device::struct_mutex lock. */ static int drm_ctxbitmap_next(drm_device_t * dev) { @@ -145,7 +145,7 @@ static int drm_ctxbitmap_next(drm_device_t * dev) * \param dev DRM device. * * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding - * the drm_device::struct_sem lock. + * the drm_device::struct_mutex lock. */ int drm_ctxbitmap_init(drm_device_t * dev) { @@ -178,7 +178,7 @@ int drm_ctxbitmap_init(drm_device_t * dev) * \param dev DRM device. * * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding - * the drm_device::struct_sem lock. + * the drm_device::struct_mutex lock. */ void drm_ctxbitmap_cleanup(drm_device_t * dev) { -- cgit v1.2.3 From b4feb2c04efdcf31d094b03ea32327a06d9dcdd2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 19 Aug 2006 16:43:16 +1000 Subject: remove some DRM_ARRAY_SIZE from linux core code --- linux-core/drm_drv.c | 2 +- linux-core/drm_fops.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 9712170b..da22700e 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -121,7 +121,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, }; -#define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls ) +#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) /** * Take down the DRM device. diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 691edff9..74fcf4bd 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -71,7 +71,7 @@ static int drm_setup(drm_device_t * dev) return i; } - for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++) + for (i = 0; i < ARRAY_SIZE(dev->counts); i++) atomic_set(&dev->counts[i], 0); drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); -- cgit v1.2.3 From 205c573e449b38d759273f6a51eb8c1131585ece Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 19 Aug 2006 16:55:00 +1000 Subject: remove local copies of pci domain/bus/slot/num --- linux-core/drmP.h | 10 ++++++---- linux-core/drm_ioctl.c | 12 ++++++++---- linux-core/drm_irq.c | 6 +++--- linux-core/drm_stub.c | 6 ------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6cbb810f..642ab4b0 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -747,10 +747,6 @@ typedef struct drm_device { drm_agp_head_t *agp; /**< AGP data */ struct pci_dev *pdev; /**< PCI device structure */ - int pci_domain; /**< PCI bus domain number */ - int pci_bus; /**< PCI bus number */ - int pci_slot; /**< PCI slot number */ - int pci_func; /**< PCI function number */ #ifdef __alpha__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) struct pci_controler *hose; @@ -776,6 +772,12 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev, return ((dev->driver->driver_features & feature) ? 1 : 0); } +#ifdef __alpha__ +#define drm_get_pci_domain(dev) dev->hose->bus->number +#else +#define drm_get_pci_domain(dev) pci_domain_nr(dev->pdev->bus) +#endif + #if __OS_HAS_AGP static inline int drm_core_has_AGP(struct drm_device *dev) { diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c index 54024e1b..2ea6af08 100644 --- a/linux-core/drm_ioctl.c +++ b/linux-core/drm_ioctl.c @@ -125,9 +125,10 @@ int drm_setunique(struct inode *inode, struct file *filp, domain = bus >> 8; bus &= 0xff; - if ((domain != dev->pci_domain) || - (bus != dev->pci_bus) || - (slot != dev->pci_slot) || (func != dev->pci_func)) + if ((domain != drm_get_pci_domain(dev)) || + (bus != dev->pdev->bus->number) || + (slot != PCI_SLOT(dev->pdev->devfn)) || + (func != PCI_FUNC(dev->pdev->devfn))) return -EINVAL; return 0; @@ -145,7 +146,10 @@ static int drm_set_busid(drm_device_t * dev) return ENOMEM; len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", - dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); + drm_get_pci_domain(dev), + dev->pdev->bus->number, + PCI_SLOT(dev->pdev->devfn), + PCI_FUNC(dev->pdev->devfn)); if (len > dev->unique_len) DRM_ERROR("buffer overflow"); diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index d76fd51d..21a649bc 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -64,9 +64,9 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp, if (copy_from_user(&p, argp, sizeof(p))) return -EFAULT; - if ((p.busnum >> 8) != dev->pci_domain || - (p.busnum & 0xff) != dev->pci_bus || - p.devnum != dev->pci_slot || p.funcnum != dev->pci_func) + if ((p.busnum >> 8) != drm_get_pci_domain(dev) || + (p.busnum & 0xff) != dev->pdev->bus->number || + p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn)) return -EINVAL; p.irq = dev->irq; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index 25bb5f33..e4d61dcf 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -69,13 +69,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, #ifdef __alpha__ dev->hose = pdev->sysdata; - dev->pci_domain = dev->hose->bus->number; -#else - dev->pci_domain = 0; #endif - dev->pci_bus = pdev->bus->number; - dev->pci_slot = PCI_SLOT(pdev->devfn); - dev->pci_func = PCI_FUNC(pdev->devfn); dev->irq = pdev->irq; dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS); -- cgit v1.2.3 From 3586ecd060d9468eba73c203c5e9de965fe904fb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 19 Aug 2006 16:55:30 +1000 Subject: fix const pointer warnings with file_operations --- linux-core/drm_fops.c | 2 +- linux-core/i810_dma.c | 2 +- linux-core/i830_dma.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 74fcf4bd..377007c6 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -175,7 +175,7 @@ int drm_stub_open(struct inode *inode, struct file *filp) drm_device_t *dev = NULL; int minor = iminor(inode); int err = -ENODEV; - struct file_operations *old_fops; + const struct file_operations *old_fops; DRM_DEBUG("\n"); diff --git a/linux-core/i810_dma.c b/linux-core/i810_dma.c index 27d8efb9..bdbb31fa 100644 --- a/linux-core/i810_dma.c +++ b/linux-core/i810_dma.c @@ -151,7 +151,7 @@ static int i810_map_buffer(drm_buf_t * buf, struct file *filp) drm_device_t *dev = priv->head->dev; drm_i810_buf_priv_t *buf_priv = buf->dev_private; drm_i810_private_t *dev_priv = dev->dev_private; - struct file_operations *old_fops; + const struct file_operations *old_fops; int retcode = 0; if (buf_priv->currently_mapped == I810_BUF_MAPPED) diff --git a/linux-core/i830_dma.c b/linux-core/i830_dma.c index 9694f64a..4526ccf1 100644 --- a/linux-core/i830_dma.c +++ b/linux-core/i830_dma.c @@ -137,7 +137,7 @@ static int i830_map_buffer(drm_buf_t * buf, struct file *filp) drm_device_t *dev = priv->head->dev; drm_i830_buf_priv_t *buf_priv = buf->dev_private; drm_i830_private_t *dev_priv = dev->dev_private; - struct file_operations *old_fops; + const struct file_operations *old_fops; unsigned long virtual; int retcode = 0; -- cgit v1.2.3 From 60ddaaf2e07b57997bcbaef0576005b52130bd24 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 19 Aug 2006 16:56:03 +1000 Subject: add static function, and remove bad attributions --- linux-core/drm_bufs.c | 4 ++-- linux-core/drm_drv.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index 1d9c0386..c2c84597 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -65,8 +65,8 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev, return NULL; } -int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, - unsigned long user_token, int hashed_handle) +static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash, + unsigned long user_token, int hashed_handle) { int use_hashed_handle; diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index da22700e..5ddcd4c1 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -50,7 +50,7 @@ #include "drmP.h" #include "drm_core.h" -static void __exit drm_cleanup(drm_device_t * dev); +static void drm_cleanup(drm_device_t * dev); int drm_fb_loaded = 0; static int drm_version(struct inode *inode, struct file *filp, @@ -336,7 +336,7 @@ EXPORT_SYMBOL(drm_init); * * \sa drm_init */ -static void __exit drm_cleanup(drm_device_t * dev) +static void drm_cleanup(drm_device_t * dev) { DRM_DEBUG("\n"); @@ -379,7 +379,7 @@ static void __exit drm_cleanup(drm_device_t * dev) DRM_ERROR("Cannot unload module\n"); } -void __exit drm_exit(struct drm_driver *driver) +void drm_exit(struct drm_driver *driver) { int i; drm_device_t *dev = NULL; -- cgit v1.2.3 From 9b984b34e99f694e10251e15bc2ec1bc844dcca4 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 19 Aug 2006 17:59:18 +1000 Subject: drm: lots of small cleanups and whitespace issues fixed up remove a mach64 warning, align a lot of things from linux kernel --- linux-core/drmP.h | 12 ++++++------ linux-core/drm_bufs.c | 12 ++++++------ linux-core/drm_fops.c | 4 ++-- linux-core/drm_ioctl.c | 10 ++++++---- linux-core/drm_irq.c | 10 ++++++---- linux-core/drm_lock.c | 2 +- linux-core/drm_pci.c | 18 ++---------------- linux-core/drm_proc.c | 8 ++++---- linux-core/drm_sman.c | 2 +- linux-core/drm_stub.c | 8 ++++---- linux-core/drm_vm.c | 18 +++++++++--------- linux-core/i810_drv.h | 20 ++++++++++---------- linux-core/sis_drv.c | 14 +++++++------- linux-core/via_dmablit.c | 25 ++++++++++++------------- linux-core/via_dmablit.h | 10 ++++++---- shared-core/mach64_drm.h | 2 +- shared-core/radeon_drv.h | 2 +- shared-core/radeon_state.c | 8 ++++---- shared-core/sis_drv.h | 22 +++++++++++----------- shared-core/via_dma.c | 18 +++++++++--------- shared-core/via_drm.h | 42 +++++++++++++++++++++--------------------- shared-core/via_drv.h | 16 +++++++--------- shared-core/via_irq.c | 25 +++++++++++++------------ shared-core/via_verifier.h | 8 ++++---- 24 files changed, 153 insertions(+), 163 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 642ab4b0..6046dde6 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -298,8 +298,8 @@ typedef struct drm_devstate { } drm_devstate_t; typedef struct drm_magic_entry { - drm_hash_item_t hash_item; - struct list_head head; + drm_hash_item_t hash_item; + struct list_head head; struct drm_file *priv; } drm_magic_entry_t; @@ -506,7 +506,7 @@ typedef struct drm_sigdata { */ typedef struct drm_map_list { struct list_head head; /**< list head */ - drm_hash_item_t hash; + drm_hash_item_t hash; drm_map_t *map; /**< mapping */ unsigned int user_token; } drm_map_list_t; @@ -676,15 +676,15 @@ typedef struct drm_device { /*@{ */ drm_file_t *file_first; /**< file list head */ drm_file_t *file_last; /**< file list tail */ - drm_open_hash_t magiclist; - struct list_head magicfree; + drm_open_hash_t magiclist; + struct list_head magicfree; /*@} */ /** \name Memory management */ /*@{ */ 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 map_hash; /**< User token hash table for maps */ /** \name Context handle management */ /*@{ */ diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index c2c84597..abd7c829 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -292,13 +292,13 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset, user_token = (map->type == _DRM_SHM) ? (unsigned long) map->handle : map->offset; - ret = drm_map_handle(dev, &list->hash, user_token, 0); + ret = drm_map_handle(dev, &list->hash, user_token, 0); if (ret) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); - drm_free(list, sizeof(*list), DRM_MEM_MAPS); - mutex_unlock(&dev->struct_mutex); - return ret; + drm_free(map, sizeof(*map), DRM_MEM_MAPS); + drm_free(list, sizeof(*list), DRM_MEM_MAPS); + mutex_unlock(&dev->struct_mutex); + return ret; } list->user_token = list->hash.key; @@ -386,7 +386,7 @@ 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); drm_free(list, sizeof(*list), DRM_MEM_MAPS); break; } diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c index 377007c6..48c77545 100644 --- a/linux-core/drm_fops.c +++ b/linux-core/drm_fops.c @@ -74,8 +74,8 @@ static int drm_setup(drm_device_t * dev) for (i = 0; i < ARRAY_SIZE(dev->counts); i++) atomic_set(&dev->counts[i], 0); - drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); - INIT_LIST_HEAD(&dev->magicfree); + drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER); + INIT_LIST_HEAD(&dev->magicfree); dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST); if (dev->ctxlist == NULL) diff --git a/linux-core/drm_ioctl.c b/linux-core/drm_ioctl.c index 2ea6af08..776f462e 100644 --- a/linux-core/drm_ioctl.c +++ b/linux-core/drm_ioctl.c @@ -242,7 +242,7 @@ int drm_getclient(struct inode *inode, struct file *filp, { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; - drm_client_t __user *argp = (void __user *)arg; + drm_client_t __user *argp = (drm_client_t __user *)arg; drm_client_t client; drm_file_t *pt; int idx; @@ -329,21 +329,23 @@ int drm_setversion(DRM_IOCTL_ARGS) int if_version; drm_set_version_t __user *argp = (void __user *)data; - DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv)); + if (copy_from_user(&sv, argp, sizeof(sv))) + return -EFAULT; retv.drm_di_major = DRM_IF_MAJOR; retv.drm_di_minor = DRM_IF_MINOR; retv.drm_dd_major = dev->driver->major; retv.drm_dd_minor = dev->driver->minor; - DRM_COPY_TO_USER_IOCTL(argp, retv, sizeof(sv)); + if (copy_to_user(argp, &retv, sizeof(sv))) + return -EFAULT; if (sv.drm_di_major != -1) { if (sv.drm_di_major != DRM_IF_MAJOR || sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) return EINVAL; if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor); - dev->if_version = DRM_MAX(if_version, dev->if_version); + dev->if_version = max(if_version, dev->if_version); if (sv.drm_di_minor >= 1) { /* * Version 1.1 includes tying of DRM to specific device diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 21a649bc..c2a9e3d6 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -222,12 +222,12 @@ int drm_control(struct inode *inode, struct file *filp, * Wait for VBLANK. * * \param inode device inode. - * \param filp file pointer.rm. + * \param filp file pointer. * \param cmd command. * \param data user argument, pointing to a drm_wait_vblank structure. * \return zero on success or a negative number on failure. * - * Verifies the IRQ is installed + * Verifies the IRQ is installed. * * If a signal is requested checks if this task has already scheduled the same signal * for the same vblank sequence number - nothing to be done in @@ -253,7 +253,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; - DRM_COPY_FROM_USER_IOCTL(vblwait, argp, sizeof(vblwait)); + if (copy_from_user(&vblwait, argp, sizeof(vblwait))) + return -EFAULT; switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) { case _DRM_VBLANK_RELATIVE: @@ -327,7 +328,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) } done: - DRM_COPY_TO_USER_IOCTL(argp, vblwait, sizeof(vblwait)); + if (copy_to_user(argp, &vblwait, sizeof(vblwait))) + return -EFAULT; return ret; } diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index a268d8ee..7aa00bc2 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -104,7 +104,7 @@ int drm_lock(struct inode *inode, struct file *filp, __set_current_state(TASK_RUNNING); remove_wait_queue(&dev->lock.lock_queue, &entry); - DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); + DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); if (ret) return ret; sigemptyset(&dev->sigmask); diff --git a/linux-core/drm_pci.c b/linux-core/drm_pci.c index b69dda22..40a65f3e 100644 --- a/linux-core/drm_pci.c +++ b/linux-core/drm_pci.c @@ -37,6 +37,7 @@ */ #include +#include #include "drmP.h" /**********************************************************************/ @@ -83,11 +84,7 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, return NULL; dmah->size = size; -#if 0 - dmah->vaddr = pci_alloc_consistent(dev->pdev, size, &dmah->busaddr); -#else dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP); -#endif #ifdef DRM_DEBUG_MEMORY if (dmah->vaddr == NULL) { @@ -112,14 +109,12 @@ drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align, memset(dmah->vaddr, 0, size); -#if 1 /* XXX - Is virt_to_page() legal for consistent mem? */ /* Reserve */ for (addr = (unsigned long)dmah->vaddr, sz = size; sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { SetPageReserved(virt_to_page(addr)); } -#endif return dmah; } @@ -132,10 +127,8 @@ EXPORT_SYMBOL(drm_pci_alloc); */ void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t *dmah) { -#if 1 unsigned long addr; size_t sz; -#endif #ifdef DRM_DEBUG_MEMORY int area = DRM_MEM_DMA; int alloc_count; @@ -147,21 +140,14 @@ void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t *dmah) DRM_MEM_ERROR(area, "Attempt to free address 0\n"); #endif } else { -#if 1 /* XXX - Is virt_to_page() legal for consistent mem? */ /* Unreserve */ for (addr = (unsigned long)dmah->vaddr, sz = dmah->size; sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); } -#endif -#if 0 - pci_free_consistent(dev->pdev, dmah->size, dmah->vaddr, - dmah->busaddr); -#else dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr, dmah->busaddr); -#endif } #ifdef DRM_DEBUG_MEMORY @@ -181,7 +167,7 @@ void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t *dmah) } /** - * \brief Free a PCI consistent memory block. + * \brief Free a PCI consistent memory block */ void drm_pci_free(drm_device_t * dev, drm_dma_handle_t *dmah) { diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 014486c1..512a8f75 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -258,7 +258,7 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, } /** - * Simply calls _vm_info() while holding the drm_device::struct_sem lock. + * Simply calls _vm_info() while holding the drm_device::struct_mutex lock. */ static int drm_vm_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) @@ -331,7 +331,7 @@ static int drm__queues_info(char *buf, char **start, off_t offset, } /** - * Simply calls _queues_info() while holding the drm_device::struct_sem lock. + * Simply calls _queues_info() while holding the drm_device::struct_mutex lock. */ static int drm_queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) @@ -403,7 +403,7 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request, } /** - * Simply calls _bufs_info() while holding the drm_device::struct_sem lock. + * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock. */ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) @@ -459,7 +459,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset, } /** - * Simply calls _clients_info() while holding the drm_device::struct_sem lock. + * Simply calls _clients_info() while holding the drm_device::struct_mutex lock. */ static int drm_clients_info(char *buf, char **start, off_t offset, int request, int *eof, void *data) diff --git a/linux-core/drm_sman.c b/linux-core/drm_sman.c index b92f0ee7..425c8233 100644 --- a/linux-core/drm_sman.c +++ b/linux-core/drm_sman.c @@ -114,7 +114,7 @@ static void drm_sman_mm_destroy(void *private) drm_free(mm, sizeof(*mm), DRM_MEM_MM); } -unsigned long drm_sman_mm_offset(void *private, void *ref) +static unsigned long drm_sman_mm_offset(void *private, void *ref) { drm_mm_node_t *node = (drm_mm_node_t *) ref; return node->start; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index e4d61dcf..bdc36552 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -76,10 +76,10 @@ 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)) { - drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); - return -ENOMEM; - } + if (drm_ht_create(&dev->map_hash, 12)) { + drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); + return -ENOMEM; + } /* the DRM has 6 counters */ dev->counters = 6; diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index cf3bc3cf..9672269a 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, drm_device_t *dev = priv->head->dev; drm_map_t *map = NULL; drm_map_list_t *r_list; - drm_hash_item_t *hash; + drm_hash_item_t *hash; /* * Find the right map @@ -70,10 +70,10 @@ 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)) - goto vm_nopage_error; + if (drm_ht_find_item(&dev->map_hash, VM_OFFSET(vma), &hash)) + goto vm_nopage_error; - r_list = drm_hash_entry(hash, drm_map_list_t, hash); + r_list = drm_hash_entry(hash, drm_map_list_t, hash); map = r_list->map; if (map && map->type == _DRM_AGP) { @@ -554,7 +554,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) drm_device_t *dev = priv->head->dev; drm_map_t *map = NULL; unsigned long offset = 0; - drm_hash_item_t *hash; + 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)); @@ -574,11 +574,11 @@ 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)) { - DRM_ERROR("Could not find map\n"); + if (drm_ht_find_item(&dev->map_hash, VM_OFFSET(vma), &hash)) { + DRM_ERROR("Could not find map\n"); return -EINVAL; - } - + } + map = drm_hash_entry(hash,drm_map_list_t, hash)->map; if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) diff --git a/linux-core/i810_drv.h b/linux-core/i810_drv.h index e8cf3ff6..bb7358d2 100644 --- a/linux-core/i810_drv.h +++ b/linux-core/i810_drv.h @@ -141,8 +141,8 @@ extern int i810_max_ioctl; volatile char *virt; #define BEGIN_LP_RING(n) do { \ - if (I810_VERBOSE) \ - DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__); \ + if (I810_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__);\ if (dev_priv->ring.space < n*4) \ i810_wait_ring(dev, n*4); \ dev_priv->ring.space -= n*4; \ @@ -151,17 +151,17 @@ extern int i810_max_ioctl; virt = dev_priv->ring.virtual_start; \ } while (0) -#define ADVANCE_LP_RING() do { \ +#define ADVANCE_LP_RING() do { \ if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ - dev_priv->ring.tail = outring; \ - I810_WRITE(LP_RING + RING_TAIL, outring); \ + dev_priv->ring.tail = outring; \ + I810_WRITE(LP_RING + RING_TAIL, outring); \ } while(0) -#define OUT_RING(n) do { \ +#define OUT_RING(n) do { \ if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ - *(volatile unsigned int *)(virt + outring) = n; \ - outring += 4; \ - outring &= ringmask; \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ } while (0) #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) @@ -193,7 +193,7 @@ extern int i810_max_ioctl; #define HEAD_WRAP_ONE 0x00200000 #define HEAD_ADDR 0x001FFFFC #define RING_START 0x08 -#define START_ADDR 0x00FFFFF8 +#define START_ADDR 0x00FFFFF8 #define RING_LEN 0x0C #define RING_NR_PAGES 0x000FF000 #define RING_REPORT_MASK 0x00000006 diff --git a/linux-core/sis_drv.c b/linux-core/sis_drv.c index 3fdbd88e..36a525dc 100644 --- a/linux-core/sis_drv.c +++ b/linux-core/sis_drv.c @@ -40,15 +40,15 @@ static struct pci_device_id pciidlist[] = { static int sis_driver_load(drm_device_t *dev, unsigned long chipset) { drm_sis_private_t *dev_priv; - int ret; + int ret; dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER); if (dev_priv == NULL) return DRM_ERR(ENOMEM); dev->dev_private = (void *)dev_priv; - dev_priv->chipset = chipset; - ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); + dev_priv->chipset = chipset; + ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); if (ret) { drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER); } @@ -60,7 +60,7 @@ static int sis_driver_unload(drm_device_t *dev) { drm_sis_private_t *dev_priv = dev->dev_private; - drm_sman_takedown(&dev_priv->sman); + drm_sman_takedown(&dev_priv->sman); drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); return 0; @@ -70,10 +70,10 @@ static int sis_driver_unload(drm_device_t *dev) static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR, - .load = sis_driver_load, - .unload = sis_driver_unload, + .load = sis_driver_load, + .unload = sis_driver_unload, .context_dtor = NULL, - .dma_quiescent = sis_idle, + .dma_quiescent = sis_idle, .reclaim_buffers = NULL, .reclaim_buffers_locked = sis_reclaim_buffers_locked, .lastclose = sis_lastclose, diff --git a/linux-core/via_dmablit.c b/linux-core/via_dmablit.c index 4a3a7524..fdc2bd67 100644 --- a/linux-core/via_dmablit.c +++ b/linux-core/via_dmablit.c @@ -121,19 +121,18 @@ via_map_blit_for_device(struct pci_dev *pdev, while (line_len > 0) { - remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len); + remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len); line_len -= remaining_len; if (mode == 1) { - desc_ptr->mem_addr = - dma_map_page(&pdev->dev, - vsg->pages[VIA_PFN(cur_mem) - - VIA_PFN(first_addr)], - VIA_PGOFF(cur_mem), remaining_len, - vsg->direction); - desc_ptr->dev_addr = cur_fb; + desc_ptr->mem_addr = dma_map_page(&pdev->dev, + vsg->pages[VIA_PFN(cur_mem) - + VIA_PFN(first_addr)], + VIA_PGOFF(cur_mem), remaining_len, + vsg->direction); + desc_ptr->dev_addr = cur_fb; - desc_ptr->size = remaining_len; + desc_ptr->size = remaining_len; desc_ptr->next = (uint32_t) next; next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr), DMA_TO_DEVICE); @@ -167,7 +166,7 @@ via_map_blit_for_device(struct pci_dev *pdev, */ -void +static void via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) { struct page *page; @@ -648,13 +647,13 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t * if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) || ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) { DRM_ERROR("Invalid DRM bitblt alignment.\n"); - return DRM_ERR(EINVAL); + return DRM_ERR(EINVAL); } #else if ((((unsigned long)xfer->mem_addr & 15) || ((unsigned long)xfer->fb_addr & 3)) || ((xfer->num_lines > 1) && ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) { DRM_ERROR("Invalid DRM bitblt alignment.\n"); - return DRM_ERR(EINVAL); + return DRM_ERR(EINVAL); } #endif @@ -732,7 +731,7 @@ via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer) drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; drm_via_sg_info_t *vsg; drm_via_blitq_t *blitq; - int ret; + int ret; int engine; unsigned long irqsave; diff --git a/linux-core/via_dmablit.h b/linux-core/via_dmablit.h index 64863917..f6ae03ec 100644 --- a/linux-core/via_dmablit.h +++ b/linux-core/via_dmablit.h @@ -30,6 +30,8 @@ #ifndef _VIA_DMABLIT_H #define _VIA_DMABLIT_H +#include + #define VIA_NUM_BLIT_ENGINES 2 #define VIA_NUM_BLIT_SLOTS 8 @@ -43,12 +45,12 @@ typedef struct _drm_via_sg_info { int num_desc; enum dma_data_direction direction; unsigned char *bounce_buffer; - dma_addr_t chain_start; + dma_addr_t chain_start; uint32_t free_on_sequence; - unsigned int descriptors_per_page; + unsigned int descriptors_per_page; int aborted; enum { - dr_via_device_mapped, + dr_via_device_mapped, dr_via_desc_pages_alloc, dr_via_pages_locked, dr_via_pages_alloc, @@ -66,7 +68,7 @@ typedef struct _drm_via_blitq { unsigned num_free; unsigned num_outstanding; unsigned long end; - int aborting; + int aborting; int is_active; drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS]; spinlock_t blit_lock; diff --git a/shared-core/mach64_drm.h b/shared-core/mach64_drm.h index d92ece2c..1fd8c002 100644 --- a/shared-core/mach64_drm.h +++ b/shared-core/mach64_drm.h @@ -68,7 +68,7 @@ /* Max number of swaps allowed on the ring * before the client must wait */ -#define MACH64_MAX_QUEUED_FRAMES 3 +#define MACH64_MAX_QUEUED_FRAMES 3U /* Byte offsets for host blit buffer data */ diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index ff75480a..5fa8254a 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -1095,7 +1095,7 @@ do { \ n, __FUNCTION__ ); \ } \ if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ - COMMIT_RING(); \ + COMMIT_RING(); \ radeon_wait_ring( dev_priv, (n) * sizeof(u32) ); \ } \ _nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \ diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 38b87148..8c1a4065 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -2652,10 +2652,10 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv, int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8); RING_LOCALS; - if (!sz) - return 0; - if (sz * 4 > cmdbuf->bufsz) - return DRM_ERR(EINVAL); + if (!sz) + return 0; + if (sz * 4 > cmdbuf->bufsz) + return DRM_ERR(EINVAL); BEGIN_RING(5 + sz); OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); diff --git a/shared-core/sis_drv.h b/shared-core/sis_drv.h index b739a483..d1cdc19c 100644 --- a/shared-core/sis_drv.h +++ b/shared-core/sis_drv.h @@ -40,8 +40,8 @@ #define DRIVER_PATCHLEVEL 1 enum sis_family { - SIS_OTHER = 0, - SIS_CHIP_315 = 1, + SIS_OTHER = 0, + SIS_CHIP_315 = 1, }; #if defined(__linux__) @@ -52,18 +52,18 @@ enum sis_family { #include "drm_sman.h" #define SIS_BASE (dev_priv->mmio) -#define SIS_READ(reg) DRM_READ32(SIS_BASE, reg); +#define SIS_READ(reg) DRM_READ32(SIS_BASE, reg); #define SIS_WRITE(reg, val) DRM_WRITE32(SIS_BASE, reg, val); typedef struct drm_sis_private { - drm_local_map_t *mmio; - unsigned idle_fault; - drm_sman_t sman; - unsigned long chipset; - int vram_initialized; - int agp_initialized; - unsigned long vram_offset; - unsigned long agp_offset; + drm_local_map_t *mmio; + unsigned idle_fault; + drm_sman_t sman; + unsigned long chipset; + int vram_initialized; + int agp_initialized; + unsigned long vram_offset; + unsigned long agp_offset; } drm_sis_private_t; extern int sis_idle(drm_device_t *dev); diff --git a/shared-core/via_dma.c b/shared-core/via_dma.c index 11fa7388..c6e7aa77 100644 --- a/shared-core/via_dma.c +++ b/shared-core/via_dma.c @@ -44,14 +44,14 @@ #define CMDBUF_ALIGNMENT_MASK (0x0ff) /* defines for VIA 3D registers */ -#define VIA_REG_STATUS 0x400 -#define VIA_REG_TRANSET 0x43C +#define VIA_REG_STATUS 0x400 +#define VIA_REG_TRANSET 0x43C #define VIA_REG_TRANSPACE 0x440 /* VIA_REG_STATUS(0x400): Engine Status */ #define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */ -#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */ -#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */ +#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */ +#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */ #define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */ #define SetReg2DAGP(nReg, nData) { \ @@ -120,7 +120,7 @@ via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size) next_addr = cur_addr + size + 512*1024; count = 1000000; do { - hw_addr = *hw_addr_ptr - agp_base; + hw_addr = *hw_addr_ptr - agp_base; if (count-- == 0) { DRM_ERROR ("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n", @@ -247,10 +247,10 @@ static int via_dma_init(DRM_IOCTL_ARGS) else retcode = via_dma_cleanup(dev); break; - case VIA_DMA_INITIALIZED: + case VIA_DMA_INITIALIZED: retcode = (dev_priv->ring.virtual_start != NULL) ? 0: DRM_ERR( EFAULT ); - break; + break; default: retcode = DRM_ERR(EINVAL); break; @@ -406,7 +406,7 @@ static int via_pci_cmdbuffer(DRM_IOCTL_ARGS) static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv, uint32_t * vb, int qw_count) { - for (; qw_count > 0; --qw_count) { + for (; qw_count > 0; --qw_count) { VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY); } return vb; @@ -471,7 +471,7 @@ static int via_hook_segment(drm_via_private_t *dev_priv, } if (paused && !no_pci_fire) { - uint32_t rgtr,ptr; + uint32_t rgtr,ptr; uint32_t ptr_low; count = 1000000; diff --git a/shared-core/via_drm.h b/shared-core/via_drm.h index 049c63e1..ee92ff69 100644 --- a/shared-core/via_drm.h +++ b/shared-core/via_drm.h @@ -47,12 +47,12 @@ #define VIA_DRM_DRIVER_MAJOR 2 #define VIA_DRM_DRIVER_MINOR 10 #define VIA_DRM_DRIVER_PATCHLEVEL 2 -#define VIA_DRM_DRIVER_VERSION (((VIA_DRM_DRIVER_MAJOR) << 16) | (VIA_DRM_DRIVER_MINOR)) +#define VIA_DRM_DRIVER_VERSION (((VIA_DRM_DRIVER_MAJOR) << 16) | (VIA_DRM_DRIVER_MINOR)) #define VIA_NR_SAREA_CLIPRECTS 8 -#define VIA_NR_XVMC_PORTS 10 -#define VIA_NR_XVMC_LOCKS 5 -#define VIA_MAX_CACHELINE_SIZE 64 +#define VIA_NR_XVMC_PORTS 10 +#define VIA_NR_XVMC_LOCKS 5 +#define VIA_MAX_CACHELINE_SIZE 64 #define XVMCLOCKPTR(saPriv,lockNo) \ ((volatile drm_hw_lock_t *)(((((unsigned long) (saPriv)->XvMCLockArea) + \ (VIA_MAX_CACHELINE_SIZE - 1)) & \ @@ -67,29 +67,29 @@ #define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ #define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ -#define VIA_UPLOAD_CTX 0x4 +#define VIA_UPLOAD_CTX 0x4 #define VIA_UPLOAD_BUFFERS 0x8 #define VIA_UPLOAD_TEX0 0x10 #define VIA_UPLOAD_TEX1 0x20 #define VIA_UPLOAD_CLIPRECTS 0x40 -#define VIA_UPLOAD_ALL 0xff +#define VIA_UPLOAD_ALL 0xff /* VIA specific ioctls */ #define DRM_VIA_ALLOCMEM 0x00 -#define DRM_VIA_FREEMEM 0x01 +#define DRM_VIA_FREEMEM 0x01 #define DRM_VIA_AGP_INIT 0x02 -#define DRM_VIA_FB_INIT 0x03 +#define DRM_VIA_FB_INIT 0x03 #define DRM_VIA_MAP_INIT 0x04 #define DRM_VIA_DEC_FUTEX 0x05 #define NOT_USED #define DRM_VIA_DMA_INIT 0x07 #define DRM_VIA_CMDBUFFER 0x08 -#define DRM_VIA_FLUSH 0x09 -#define DRM_VIA_PCICMD 0x0a +#define DRM_VIA_FLUSH 0x09 +#define DRM_VIA_PCICMD 0x0a #define DRM_VIA_CMDBUF_SIZE 0x0b #define NOT_USED -#define DRM_VIA_WAIT_IRQ 0x0d -#define DRM_VIA_DMA_BLIT 0x0e +#define DRM_VIA_WAIT_IRQ 0x0d +#define DRM_VIA_DMA_BLIT 0x0e #define DRM_VIA_BLIT_SYNC 0x0f #define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t) @@ -172,7 +172,7 @@ typedef struct _drm_via_dma_init { enum { VIA_INIT_DMA = 0x01, VIA_CLEANUP_DMA = 0x02, - VIA_DMA_INITIALIZED = 0x03 + VIA_DMA_INITIALIZED = 0x03 } func; unsigned long offset; @@ -217,7 +217,7 @@ typedef struct _drm_via_sarea { /* Used by the 3d driver only at this point, for pageflipping: */ - unsigned int pfCurrentOffset; + unsigned int pfCurrentOffset; } drm_via_sarea_t; typedef struct _drm_via_cmdbuf_size { @@ -273,17 +273,17 @@ typedef struct drm_via_blitsync { */ typedef struct drm_via_dmablit { - uint32_t num_lines; - uint32_t line_length; + uint32_t num_lines; + uint32_t line_length; - uint32_t fb_addr; - uint32_t fb_stride; + uint32_t fb_addr; + uint32_t fb_stride; - unsigned char *mem_addr; - uint32_t mem_stride; + unsigned char *mem_addr; + uint32_t mem_stride; uint32_t flags; - int to_fb; + int to_fb; drm_via_blitsync_t sync; } drm_via_dmablit_t; diff --git a/shared-core/via_drv.h b/shared-core/via_drv.h index 86cd049d..18d2a331 100644 --- a/shared-core/via_drv.h +++ b/shared-core/via_drv.h @@ -76,9 +76,9 @@ typedef struct drm_via_private { volatile uint32_t *last_pause_ptr; volatile uint32_t *hw_addr_ptr; drm_via_ring_buffer_t ring; - struct timeval last_vblank; - int last_vblank_valid; - unsigned usec_per_vblank; + struct timeval last_vblank; + int last_vblank_valid; + unsigned usec_per_vblank; drm_via_state_t hc_state; char pci_buf[VIA_PCI_BUF_SIZE]; const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE]; @@ -90,14 +90,14 @@ typedef struct drm_via_private { uint32_t irq_enable_mask; uint32_t irq_pending_mask; int *irq_map; - /* Memory manager stuff */ + /* Memory manager stuff */ #ifdef VIA_HAVE_CORE_MM - unsigned idle_fault; + unsigned int idle_fault; drm_sman_t sman; int vram_initialized; int agp_initialized; - unsigned long vram_offset; - unsigned long agp_offset; + unsigned long vram_offset; + unsigned long agp_offset; #endif #ifdef VIA_HAVE_DMABLIT drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES]; @@ -148,8 +148,6 @@ extern int via_driver_dma_quiescent(drm_device_t * dev); extern void via_init_futex(drm_via_private_t *dev_priv); extern void via_cleanup_futex(drm_via_private_t *dev_priv); extern void via_release_futex(drm_via_private_t *dev_priv, int context); -extern int via_driver_irq_wait(drm_device_t * dev, unsigned int irq, - int force_sequence, unsigned int *sequence); #ifdef VIA_HAVE_CORE_MM extern void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp); diff --git a/shared-core/via_irq.c b/shared-core/via_irq.c index aaba0cb6..db60b28e 100644 --- a/shared-core/via_irq.c +++ b/shared-core/via_irq.c @@ -43,7 +43,7 @@ #define VIA_REG_INTERRUPT 0x200 /* VIA_REG_INTERRUPT */ -#define VIA_IRQ_GLOBAL (1 << 31) +#define VIA_IRQ_GLOBAL (1 << 31) #define VIA_IRQ_VBLANK_ENABLE (1 << 19) #define VIA_IRQ_VBLANK_PENDING (1 << 3) #define VIA_IRQ_HQV0_ENABLE (1 << 11) @@ -93,8 +93,8 @@ static int via_irqmap_unichrome[] = {-1, -1, -1, 0, -1, 1}; static unsigned time_diff(struct timeval *now,struct timeval *then) { return (now->tv_usec >= then->tv_usec) ? - now->tv_usec - then->tv_usec : - 1000000 - (then->tv_usec - now->tv_usec); + now->tv_usec - then->tv_usec : + 1000000 - (then->tv_usec - now->tv_usec); } irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) @@ -110,21 +110,21 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) status = VIA_READ(VIA_REG_INTERRUPT); if (status & VIA_IRQ_VBLANK_PENDING) { atomic_inc(&dev->vbl_received); - if (!(atomic_read(&dev->vbl_received) & 0x0F)) { + if (!(atomic_read(&dev->vbl_received) & 0x0F)) { #ifdef __linux__ do_gettimeofday(&cur_vblank); #else microtime(&cur_vblank); #endif - if (dev_priv->last_vblank_valid) { + if (dev_priv->last_vblank_valid) { dev_priv->usec_per_vblank = time_diff(&cur_vblank, &dev_priv->last_vblank) >> 4; } dev_priv->last_vblank = cur_vblank; dev_priv->last_vblank_valid = 1; - } - if (!(atomic_read(&dev->vbl_received) & 0xFF)) { + } + if (!(atomic_read(&dev->vbl_received) & 0xFF)) { DRM_DEBUG("US per vblank is: %u\n", dev_priv->usec_per_vblank); } @@ -198,13 +198,13 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence) return ret; } -int +static int via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, unsigned int *sequence) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; unsigned int cur_irq_sequence; - drm_via_irq_t *cur_irq = dev_priv->via_irqs; + drm_via_irq_t *cur_irq; int ret = 0; maskarray_t *masks; int real_irq; @@ -231,7 +231,7 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence, } masks = dev_priv->irq_masks; - cur_irq += real_irq; + cur_irq = dev_priv->via_irqs + real_irq; if (masks[real_irq][2] && !force_sequence) { DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ, @@ -257,11 +257,12 @@ void via_driver_irq_preinstall(drm_device_t * dev) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; u32 status; - drm_via_irq_t *cur_irq = dev_priv->via_irqs; + drm_via_irq_t *cur_irq; int i; DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv); if (dev_priv) { + cur_irq = dev_priv->via_irqs; dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE; dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING; @@ -285,7 +286,7 @@ void via_driver_irq_preinstall(drm_device_t * dev) DRM_DEBUG("Initializing IRQ %d\n", i); } - dev_priv->last_vblank_valid = 0; + dev_priv->last_vblank_valid = 0; /* Clear VSync interrupt regs */ status = VIA_READ(VIA_REG_INTERRUPT); diff --git a/shared-core/via_verifier.h b/shared-core/via_verifier.h index c0ffc97f..96708a39 100644 --- a/shared-core/via_verifier.h +++ b/shared-core/via_verifier.h @@ -26,20 +26,20 @@ #ifndef _VIA_VERIFIER_H_ #define _VIA_VERIFIER_H_ -typedef enum{ +typedef enum { no_sequence = 0, z_address, dest_address, tex_address -}drm_via_sequence_t; +} drm_via_sequence_t; -typedef struct{ +typedef struct { unsigned texture; uint32_t z_addr; uint32_t d_addr; - uint32_t t_addr[2][10]; + uint32_t t_addr[2][10]; uint32_t pitch[2][10]; uint32_t height[2][10]; uint32_t tex_level_lo[2]; -- 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. --- libdrm/xf86drm.c | 22 +++++++++-------- libdrm/xf86drm.h | 2 ++ linux-core/drmP.h | 19 +++++++++------ linux-core/drm_ttm.c | 4 +-- shared-core/drm.h | 69 ++++++++++++++++++++++------------------------------ 5 files changed, 56 insertions(+), 60 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 88676083..06c64303 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2362,25 +2362,27 @@ int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, return 0; } -static unsigned long combine64(unsigned lo, unsigned hi) +static unsigned long drmUL(drm_u64_t val) { - unsigned long ret = lo; + unsigned long ret = val.lo; if (sizeof(ret) == 8) { int shift = 32; - ret |= (hi << shift); + ret |= (val.hi << shift); } return ret; } -static void split32(unsigned long val, unsigned *lo, unsigned *hi) +static drm_u64_t drmU64(unsigned long val) { - *lo = val & 0xFFFFFFFFUL; + drm_u64_t ret; + ret.lo = val & 0xFFFFFFFFUL; if (sizeof(val) == 8) { int shift = 32; - *hi = val >> shift; + ret.hi = val >> shift; } else { - *hi = 0; + ret.hi = 0; } + return ret; } int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) @@ -2389,7 +2391,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) arg.op = drm_ttm_create; arg.flags = flags; - split32((unsigned long) size, &arg.size_lo, &arg.size_hi); + arg.size = drmU64(size); if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; @@ -2397,7 +2399,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) ttm->handle = arg.handle; ttm->user_token = (drm_handle_t) arg.user_token; ttm->flags = arg.flags; - ttm->size = combine64(arg.size_lo, arg.size_hi); + ttm->size = drmUL(arg.size); return 0; } @@ -2424,7 +2426,7 @@ int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) ttm->handle = arg.handle; ttm->user_token = (drm_handle_t) arg.user_token; ttm->flags = arg.flags; - ttm->size = combine64(arg.size_lo, arg.size_hi); + ttm->size = drmUL(arg.size); return 0; } diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 433191b4..58cbd16c 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -497,6 +497,8 @@ do { register unsigned int __old __asm("o0"); \ } \ } while(0) + + /* General user-level programmer's API: unprivileged */ extern int drmAvailable(void); extern int drmOpen(const char *name, const char *busid); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 2997293b..81f08dfc 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1359,26 +1359,29 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); /* - * Convenience 2*32-bit to 64-bit function + * Convenience drm_u64_t functions */ -static __inline__ unsigned long combine_64(uint32_t lo, uint32_t hi) +static __inline__ unsigned long drm_ul(drm_u64_t val) { - unsigned long ret = lo; + unsigned long ret = val.lo; #if (BITS_PER_LONG == 64) - ret |= (hi << 32); + ret |= (val.hi << 32); #endif return ret; } -static __inline__ void split_32(unsigned long val, uint32_t *lo, uint32_t *hi) +static __inline__ drm_u64_t drm_u64(unsigned long val) { - *lo = val & 0xFFFFFFFFUL; + drm_u64_t ret; + + ret.lo = val & 0xFFFFFFFFUL; #if (BITS_PER_LONG == 64) - *hi = val >> 32; + ret.hi = val >> 32; #else - *hi = 0; + ret.hi = 0; #endif + return ret; } diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index ad7b279e..e76b41fb 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -865,7 +865,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) switch(arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); - size = combine_64(arg.size_lo, arg.size_hi); + size = drm_ul(arg.size); ret = drm_ttm_object_create(dev, size, arg.flags, &entry); if (ret) { mutex_unlock(&dev->struct_mutex); @@ -903,7 +903,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) } arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; - split_32(entry->map_list.map->size, &arg.size_lo, &arg.size_hi); + arg.size = drm_u64(entry->map_list.map->size); atomic_dec(&entry->usage); mutex_unlock(&dev->struct_mutex); diff --git a/shared-core/drm.h b/shared-core/drm.h index 726a5140..7133eb8f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -630,6 +630,11 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; +typedef struct drm_u64{ + unsigned lo; + unsigned hi; +}drm_u64_t; + #define DRM_FENCE_FLAG_EMIT 0x00000001 #define DRM_FENCE_FLAG_SHAREABLE 0x00000002 #define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 @@ -655,6 +660,22 @@ typedef struct drm_fence_arg { } op; } drm_fence_arg_t; +#define DRM_TTM_FLAG_SHAREABLE 0x00000001 + +typedef struct drm_ttm_arg { + enum { + drm_ttm_create, + drm_ttm_destroy, + drm_ttm_reference, + drm_ttm_unreference + } op; + unsigned handle; + unsigned user_token; + drm_u64_t size; + unsigned flags; +}drm_ttm_arg_t; + + #define DRM_BO_FLAG_READ 0x00000001 #define DRM_BO_FLAG_WRITE 0x00000002 #define DRM_BO_FLAG_EXE 0x00000004 @@ -674,43 +695,12 @@ typedef struct drm_fence_arg { #define DRM_BO_HINT_AVOID_LOCAL 0x00000002 #define DRM_BO_HINT_DONT_BLOCK 0x00000004 -/* - * Multiplexing ioctl argument. - */ - -typedef struct drm_bo_arg { - unsigned num_requests; - enum { - drm_op_bo, - drm_op_ttm - } op; - unsigned data_lo; - unsigned data_hi; -} drm_bo_arg_t; - -#define DRM_TTM_FLAG_SHAREABLE 0x00000001 - -typedef struct drm_ttm_arg { - enum { - drm_ttm_create, - drm_ttm_destroy, - drm_ttm_reference, - drm_ttm_unreference - } op; - unsigned handle; - unsigned user_token; - unsigned size_lo; - unsigned size_hi; - unsigned flags; -}drm_ttm_arg_t; - typedef struct drm_bo_arg_request { unsigned handle; /* User space handle */ unsigned mask; unsigned hint; - unsigned size_lo; - unsigned size_hi; + drm_u64_t size; enum { drm_bo_type_ttm, @@ -718,8 +708,8 @@ typedef struct drm_bo_arg_request { drm_bo_type_user }type; unsigned arg_handle; - unsigned user_pointer_lo; - unsigned user_pointer_hi; + drm_u64_t user_pointer; + drm_u64_t next; enum { drm_bo_create, drm_bo_validate, @@ -733,21 +723,20 @@ typedef struct drm_bo_arg_request { typedef struct drm_bo_arg_reply { int ret; + int handled; unsigned handle; unsigned flags; - unsigned size_lo; - unsigned size_hi; - unsigned offset_lo; - unsigned offset_hi; + drm_u64_t size; + drm_u64_t offset; unsigned arg_handle; unsigned map_flags; }drm_bo_arg_reply_t; -typedef union drm_bo_arg_data { +typedef union drm_bo_arg{ drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; -} drm_bo_arg_data_t; +} drm_bo_arg_t; /** -- 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(-) 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(+) 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 +++ shared-core/drm.h | 14 +++-- 5 files changed, 215 insertions(+), 25 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f83b4b4b..07f3571b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -949,8 +949,9 @@ typedef struct drm_buffer_object{ drm_device_t *dev; drm_user_object_t base; atomic_t usage; - drm_map_list_t *ttm_maplist; + drm_ttm_object_t *ttm_object; drm_ttm_backend_list_t *ttm_region; + void __user *user_pages; atomic_t mapped; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 0aa0b138..affee135 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -148,7 +148,7 @@ static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) } -void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo) +static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo) { drm_buffer_manager_t *bm = &dev->bm; @@ -189,6 +189,31 @@ void destroy_buffer_object(drm_device_t *dev, drm_buffer_object_t *bo) drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } + +void drm_bo_usage_deref_locked(drm_device_t *dev, drm_buffer_object_t *bo) +{ + if (atomic_dec_and_test(&bo->usage)) { + drm_bo_destroy_locked(dev, bo); + } +} + +void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) +{ + if (atomic_dec_and_test(&bo->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&bo->usage) == 0) + drm_bo_destroy_locked(dev, bo); + mutex_unlock(&dev->struct_mutex); + } +} + +static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) +{ + drm_bo_usage_deref_locked(priv->head->dev, + drm_user_object_entry(uo, drm_buffer_object_t, base)); +} + + static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t *n_flags) { @@ -399,6 +424,9 @@ static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) /* * Wait for buffer idle and register that we've mapped the buffer. + * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, + * so that if the client dies, the mapping is automatically + * unregistered. */ @@ -421,13 +449,15 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) if ((atomic_read(&bo->mapped) == 0) && drm_bo_busy(dev, bo)) { mutex_unlock(&bo->mutex); - return -EBUSY; + ret = -EBUSY; + goto out; } } else { ret = drm_bo_wait(dev, bo, 0); if (ret) { mutex_unlock(&bo->mutex); - return -EBUSY; + ret = -EBUSY; + goto out; } } mutex_lock(&dev->struct_mutex); @@ -438,11 +468,132 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) } mutex_unlock(&bo->mutex); + out: + drm_bo_usage_deref_unlocked(dev,bo); + return ret; +} + + +static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo; + drm_ref_object_t *ro; + int ret = 0; + + mutex_lock(&dev->struct_mutex); + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + ret = -EINVAL; + goto out; + } + + ro = drm_lookup_ref_object(priv, &bo->base, _DRM_REF_TYPE1); + if (!ro) { + ret = -EINVAL; + goto out; + } + + drm_remove_ref_object(priv, ro); + drm_bo_usage_deref_locked(dev, bo); + out: + mutex_unlock(&dev->struct_mutex); return ret; } +/* + * Call struct-sem locked. + */ +static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + + if (atomic_dec_and_test(&bo->mapped)) { + mutex_unlock(&dev->struct_mutex); + mutex_lock(&bo->mutex); + if (atomic_read(&bo->mapped) == 0) { + DRM_WAKEUP(&bo->validate_queue); + } + mutex_unlock(&bo->mutex); + mutex_lock(&dev->struct_mutex); + } +} + +static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo) +{ + return 0; +} + +int drm_buffer_object_create(drm_file_t *priv, + int size, + drm_bo_type_t type, + uint32_t ttm_handle, + uint32_t mask, + uint32_t hint, + void __user *user_pages, + drm_buffer_object_t **buf_obj) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_object_t *bo; + int ret = 0; + uint32_t ttm_flags = 0; + + bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); + + if (!bo) + return -ENOMEM; + + mutex_init(&bo->mutex); + mutex_lock(&bo->mutex); + + atomic_set(&bo->usage, 1); + atomic_set(&bo->mapped, 0); + DRM_INIT_WAITQUEUE(&bo->validate_queue); + INIT_LIST_HEAD(&bo->head); + INIT_LIST_HEAD(&bo->ddestroy); + bo->dev = dev; + + switch(type) { + case drm_bo_type_dc: + ret = drm_ttm_object_create(dev, size, ttm_flags, &bo->ttm_object); + if (ret) + goto out_err; + break; + case drm_bo_type_ttm: + bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); + if (ret) + goto out_err; + break; + case drm_bo_type_user: + bo->user_pages = user_pages; + break; + default: + ret = -EINVAL; + goto out_err; + } + + bo->mask = mask; + bo->mask_hint = hint; + + ret = drm_buffer_object_validate(dev, bo); + if (ret) + goto out_err; + + mutex_unlock(&bo->mutex); + *buf_obj = bo; + return 0; + + out_err: + mutex_unlock(&bo->mutex); + drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + return ret; +} + + int drm_bo_ioctl(DRM_IOCTL_ARGS) { @@ -459,6 +610,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { + case drm_bo_unmap: + rep.ret = drm_buffer_object_unmap(priv, req->handle); + break; case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, !(req->hint & diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index e76b41fb..cda3ec29 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -752,7 +752,6 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, /* * dev->struct_mutex locked. */ - static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) { drm_map_list_t *list = &object->map_list; @@ -777,17 +776,24 @@ static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) drm_free(object, sizeof(*object), DRM_MEM_TTM); } + +void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) +{ + if (atomic_dec_and_test(&to->usage)) { + drm_ttm_object_remove(dev, to); + } +} + + /* * dev->struct_mutex locked. */ -static void drm_ttm_user_object_remove(drm_file_t *priv, drm_user_object_t *base) +static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) { - drm_ttm_object_t *object; - drm_device_t *dev = priv->head->dev; - - object = drm_user_object_entry(base, drm_ttm_object_t, base); - if (atomic_dec_and_test(&object->usage)) - drm_ttm_object_remove(dev, object); + DRM_ERROR("User deref ttm\n"); + drm_ttm_object_deref_locked(priv->head->dev, + drm_user_object_entry(base, drm_ttm_object_t, + base)); } @@ -840,16 +846,33 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, } list->user_token = list->hash.key; - object->base.remove = drm_ttm_user_object_remove; - object->base.type = drm_ttm_type; - object->base.ref_struct_locked = NULL; - object->base.unref = NULL; atomic_set(&object->usage, 1); *ttm_object = object; return 0; } +drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, + int check_owner) +{ + drm_user_object_t *uo; + drm_ttm_object_t *to; + + uo = drm_lookup_user_object(priv, handle); + + if (!uo || (uo->type != drm_ttm_type)) + return NULL; + + if (check_owner && priv != uo->owner) { + if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) + return NULL; + } + + to = drm_user_object_entry(uo, drm_ttm_object_t, base); + atomic_inc(&to->usage); + return to; +} + int drm_ttm_ioctl(DRM_IOCTL_ARGS) { @@ -878,6 +901,10 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) mutex_unlock(&dev->struct_mutex); return ret; } + entry->base.remove = drm_ttm_user_deref_locked; + entry->base.type = drm_ttm_type; + entry->base.ref_struct_locked = NULL; + entry->base.unref = NULL; atomic_inc(&entry->usage); break; case drm_ttm_reference: @@ -885,8 +912,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) if (ret) return ret; mutex_lock(&dev->struct_mutex); - uo = drm_lookup_user_object(priv, arg.handle); - entry = drm_user_object_entry(uo, drm_ttm_object_t, base); + entry = drm_lookup_ttm_object(priv, arg.handle , 0); break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); @@ -904,7 +930,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; arg.size = drm_u64(entry->map_list.map->size); - atomic_dec(&entry->usage); + drm_ttm_object_deref_locked(dev, entry); mutex_unlock(&dev->struct_mutex); DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 6ebb1aa2..a87cf53e 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -108,6 +108,13 @@ typedef struct drm_ttm_object { drm_map_list_t map_list; } drm_ttm_object_t; +extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, + uint32_t flags, drm_ttm_object_t **ttm_object); +extern void drm_ttm_object_deref_locked(struct drm_device *dev, drm_ttm_object_t *to); +extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, + int check_owner); + + diff --git a/shared-core/drm.h b/shared-core/drm.h index 7133eb8f..14b1741f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -695,18 +695,19 @@ typedef struct drm_ttm_arg { #define DRM_BO_HINT_AVOID_LOCAL 0x00000002 #define DRM_BO_HINT_DONT_BLOCK 0x00000004 +typedef enum { + drm_bo_type_ttm, + drm_bo_type_dc, + drm_bo_type_user +}drm_bo_type_t; + typedef struct drm_bo_arg_request { unsigned handle; /* User space handle */ unsigned mask; unsigned hint; drm_u64_t size; - - enum { - drm_bo_type_ttm, - drm_bo_type_dc, - drm_bo_type_user - }type; + drm_bo_type_t type; unsigned arg_handle; drm_u64_t user_pointer; drm_u64_t next; @@ -714,6 +715,7 @@ typedef struct drm_bo_arg_request { drm_bo_create, drm_bo_validate, drm_bo_map, + drm_bo_unmap, drm_bo_fence, drm_bo_destroy, drm_bo_reference, -- 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 +++++++++++++++++++++++++++++++++++++++++++--- shared-core/drm.h | 4 ++-- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index affee135..7f5088fb 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -507,11 +507,14 @@ static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) * Call struct-sem locked. */ -static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo) +static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo, + drm_ref_t action) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + BUG_ON(action != _DRM_REF_TYPE1); + if (atomic_dec_and_test(&bo->mapped)) { mutex_unlock(&dev->struct_mutex); mutex_lock(&bo->mutex); @@ -534,7 +537,7 @@ int drm_buffer_object_create(drm_file_t *priv, uint32_t ttm_handle, uint32_t mask, uint32_t hint, - void __user *user_pages, + unsigned long buffer_start, drm_buffer_object_t **buf_obj) { drm_device_t *dev = priv->head->dev; @@ -569,7 +572,7 @@ int drm_buffer_object_create(drm_file_t *priv, goto out_err; break; case drm_bo_type_user: - bo->user_pages = user_pages; + bo->user_pages = (void __user *)buffer_start; break; default: ret = -EINVAL; @@ -592,6 +595,27 @@ int drm_buffer_object_create(drm_file_t *priv, drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); return ret; } + +static int drm_bo_add_user_object(drm_file_t *priv, drm_buffer_object_t *bo, + int shareable) +{ + drm_device_t *dev = priv->head->dev; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_add_user_object(priv, &bo->base, shareable); + if (ret) + goto out; + + bo->base.remove = drm_bo_base_deref_locked; + bo->base.type = drm_buffer_type; + bo->base.ref_struct_locked = NULL; + bo->base.unref = drm_buffer_user_object_unmap; + + out: + mutex_unlock(&dev->struct_mutex); + return ret; +} @@ -610,6 +634,22 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { + case drm_bo_create: { + unsigned long buffer_start = drm_ul(req->buffer_start); + rep.ret = drm_buffer_object_create(priv, drm_ul(req->size), + req->type, req->arg_handle, + req->mask, req->hint, + buffer_start, + &entry); + if (rep.ret) + break; + + rep.ret = drm_bo_add_user_object(priv, entry, req->mask & + DRM_BO_FLAG_SHAREABLE); + if (rep.ret) + drm_bo_usage_deref_unlocked(dev, entry); + break; + } case drm_bo_unmap: rep.ret = drm_buffer_object_unmap(priv, req->handle); break; diff --git a/shared-core/drm.h b/shared-core/drm.h index 14b1741f..d03eebcb 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -684,7 +684,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 #define DRM_BO_FLAG_READ_LOCAL 0x00000040 #define DRM_BO_FLAG_UNCACHED 0x00000080 - +#define DRM_BO_FLAG_SHAREABLE 0x00000100 #define DRM_BO_FLAG_MEM_TT 0x01000000 #define DRM_BO_FLAG_MEM_VRAM 0x02000000 @@ -709,7 +709,7 @@ typedef struct drm_bo_arg_request { drm_u64_t size; drm_bo_type_t type; unsigned arg_handle; - drm_u64_t user_pointer; + drm_u64_t buffer_start; drm_u64_t next; enum { drm_bo_create, -- 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 --- libdrm/xf86drm.c | 32 ++++++-------------------------- linux-core/drmP.h | 28 +--------------------------- linux-core/drm_bo.c | 32 +++++++++++++++++++++++++++++--- linux-core/drm_ttm.c | 4 ++-- linux-core/drm_ttm.h | 5 +++++ shared-core/drm.h | 15 ++++++++++----- 6 files changed, 53 insertions(+), 63 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 06c64303..3731ee12 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2237,6 +2237,8 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, return 0; } +#ifdef __linux__ + int drmFenceCreate(int fd, int shareable, int class,unsigned type, int emit, drmFence *fence) @@ -2362,36 +2364,13 @@ int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, return 0; } -static unsigned long drmUL(drm_u64_t val) -{ - unsigned long ret = val.lo; - if (sizeof(ret) == 8) { - int shift = 32; - ret |= (val.hi << shift); - } - return ret; -} - -static drm_u64_t drmU64(unsigned long val) -{ - drm_u64_t ret; - ret.lo = val & 0xFFFFFFFFUL; - if (sizeof(val) == 8) { - int shift = 32; - ret.hi = val >> shift; - } else { - ret.hi = 0; - } - return ret; -} - int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) { drm_ttm_arg_t arg; arg.op = drm_ttm_create; arg.flags = flags; - arg.size = drmU64(size); + arg.size = size; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) return -errno; @@ -2399,7 +2378,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) ttm->handle = arg.handle; ttm->user_token = (drm_handle_t) arg.user_token; ttm->flags = arg.flags; - ttm->size = drmUL(arg.size); + ttm->size = arg.size; return 0; } @@ -2426,7 +2405,7 @@ int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) ttm->handle = arg.handle; ttm->user_token = (drm_handle_t) arg.user_token; ttm->flags = arg.flags; - ttm->size = drmUL(arg.size); + ttm->size = arg.size; return 0; } @@ -2446,3 +2425,4 @@ drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm) (void) fd; return ttm->user_token; } +#endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 07f3571b..af082ad7 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -952,9 +952,9 @@ typedef struct drm_buffer_object{ drm_ttm_object_t *ttm_object; drm_ttm_backend_list_t *ttm_region; void __user *user_pages; + unsigned long num_pages; atomic_t mapped; - uint32_t flags; uint32_t mask; uint32_t mask_hint; @@ -1360,32 +1360,6 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); -/* - * Convenience drm_u64_t functions - */ - -static __inline__ unsigned long drm_ul(drm_u64_t val) -{ - unsigned long ret = val.lo; -#if (BITS_PER_LONG == 64) - ret |= (val.hi << 32); -#endif - return ret; -} - -static __inline__ drm_u64_t drm_u64(unsigned long val) -{ - drm_u64_t ret; - - ret.lo = val & 0xFFFFFFFFUL; -#if (BITS_PER_LONG == 64) - ret.hi = val >> 32; -#else - ret.hi = 0; -#endif - return ret; -} - /* Inline replacements for DRM_IOREMAP macros */ static __inline__ void drm_core_ioremap(struct drm_map *map, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7f5088fb..23634955 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -531,6 +531,7 @@ static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo return 0; } + int drm_buffer_object_create(drm_file_t *priv, int size, drm_bo_type_t type, @@ -544,6 +545,7 @@ int drm_buffer_object_create(drm_file_t *priv, drm_buffer_object_t *bo; int ret = 0; uint32_t ttm_flags = 0; + drm_ttm_t *ttm; bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); @@ -567,11 +569,35 @@ int drm_buffer_object_create(drm_file_t *priv, goto out_err; break; case drm_bo_type_ttm: + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Illegal buffer object start\n"); + ret = -EINVAL; + } + bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (!bo->num_pages) { + DRM_ERROR("Illegal buffer object size\n"); + ret = -EINVAL; + goto out_err; + } bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); + if (!bo->ttm_object) { + DRM_ERROR("Could not find buffer object TTM\n"); + ret = -EINVAL; + goto out_err; + } + ttm = drm_ttm_from_object(bo->ttm_object); + ret = drm_create_ttm_region(ttm, buffer_start >> PAGE_SHIFT, + bo->num_pages, 0, &bo->ttm_region); if (ret) goto out_err; break; case drm_bo_type_user: + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Illegal buffer object start\n"); + ret = -EINVAL; + goto out_err; + } + bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; bo->user_pages = (void __user *)buffer_start; break; default: @@ -635,8 +661,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.handled = 0; switch (req->op) { case drm_bo_create: { - unsigned long buffer_start = drm_ul(req->buffer_start); - rep.ret = drm_buffer_object_create(priv, drm_ul(req->size), + unsigned long buffer_start = req->buffer_start; + rep.ret = drm_buffer_object_create(priv, req->size, req->type, req->arg_handle, req->mask, req->hint, buffer_start, @@ -687,7 +713,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) default: rep.ret = -EINVAL; } - next = drm_ul(req->next); + next = req->next; rep.handled = 1; arg.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index cda3ec29..8cd0af61 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -888,7 +888,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) switch(arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); - size = drm_ul(arg.size); + size = arg.size; ret = drm_ttm_object_create(dev, size, arg.flags, &entry); if (ret) { mutex_unlock(&dev->struct_mutex); @@ -929,7 +929,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) } arg.handle = entry->base.hash.key; arg.user_token = entry->map_list.user_token; - arg.size = drm_u64(entry->map_list.map->size); + arg.size = entry->map_list.map->size; drm_ttm_object_deref_locked(dev, entry); mutex_unlock(&dev->struct_mutex); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index a87cf53e..ba4261bf 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -165,6 +165,11 @@ extern int drm_ttm_add_mm_to_list(drm_ttm_t * ttm, struct mm_struct *mm); extern void drm_ttm_delete_mm(drm_ttm_t * ttm, struct mm_struct *mm); extern int drm_ttm_ioctl(DRM_IOCTL_ARGS); +static __inline__ drm_ttm_t *drm_ttm_from_object(drm_ttm_object_t *to) +{ + return (drm_ttm_t *) to->map_list.map->offset; +} + #define DRM_MASK_VAL(dest, mask, val) \ (dest) = ((dest) & ~(mask)) | ((val) & (mask)); diff --git a/shared-core/drm.h b/shared-core/drm.h index d03eebcb..f8479dd0 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -134,6 +134,12 @@ #define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) #if defined(__linux__) +#if defined(__KERNEL__) +typedef __u64 drm_u64_t; +#else +typedef unsigned long long drm_u64_t; +#endif + typedef unsigned int drm_handle_t; #else typedef unsigned long drm_handle_t; /**< To mapped regions */ @@ -630,10 +636,7 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; -typedef struct drm_u64{ - unsigned lo; - unsigned hi; -}drm_u64_t; +#ifdef __linux__ #define DRM_FENCE_FLAG_EMIT 0x00000001 #define DRM_FENCE_FLAG_SHAREABLE 0x00000002 @@ -739,7 +742,7 @@ typedef union drm_bo_arg{ drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; } drm_bo_arg_t; - +#endif /** * \name Ioctls Definitions @@ -806,8 +809,10 @@ typedef union drm_bo_arg{ #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) +#ifdef __linux__ #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) #define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) +#endif /*@}*/ -- 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 + shared-core/drm.h | 2 +- 5 files changed, 91 insertions(+), 49 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index af082ad7..81b7a1b6 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -951,8 +951,9 @@ typedef struct drm_buffer_object{ atomic_t usage; drm_ttm_object_t *ttm_object; drm_ttm_backend_list_t *ttm_region; - void __user *user_pages; unsigned long num_pages; + unsigned long buffer_start; + drm_bo_type_t type; atomic_t mapped; uint32_t flags; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 23634955..30656060 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -141,8 +141,8 @@ static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; - buf->flags &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_UNCACHED); - buf->flags |= DRM_BO_FLAG_MEM_LOCAL; + buf->flags &= ~(DRM_BO_FLAG_MEM_TT); + buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; return 0; } @@ -531,9 +531,65 @@ static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo return 0; } +/* + * Call bo->mutex locked. + */ + +static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t new_flags, + uint32_t ttm_handle) + +{ + drm_device_t *dev = bo->dev; + drm_ttm_object_t *to = NULL; + drm_ttm_t *ttm; + int ret=0; + uint32_t ttm_flags = 0; + + bo->ttm_object = NULL; + bo->ttm_region = NULL; + + switch(bo->type) { + case drm_bo_type_dc: + mutex_lock(&dev->struct_mutex); + ret = drm_ttm_object_create(dev, bo->num_pages*PAGE_SIZE, + ttm_flags, &to); + mutex_unlock(&dev->struct_mutex); + break; + case drm_bo_type_ttm: + mutex_lock(&dev->struct_mutex); + to = drm_lookup_ttm_object(priv, ttm_handle, 1); + mutex_unlock(&dev->struct_mutex); + if (!to) + ret = -EINVAL; + break; + case drm_bo_type_user: + + break; + default: + ret = -EINVAL; + } + + if (ret) { + return ret; + } + + if (to) { + bo->ttm_object = to; + ttm = drm_ttm_from_object(to); + ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, + bo->num_pages, + new_flags & DRM_BO_FLAG_CACHED, + &bo->ttm_region); + if (ret) { + drm_ttm_object_deref_unlocked(dev, to); + } + } + return ret; +} + int drm_buffer_object_create(drm_file_t *priv, - int size, + unsigned long size, drm_bo_type_t type, uint32_t ttm_handle, uint32_t mask, @@ -544,8 +600,18 @@ int drm_buffer_object_create(drm_file_t *priv, drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; int ret = 0; - uint32_t ttm_flags = 0; - drm_ttm_t *ttm; + uint32_t new_flags; + unsigned long num_pages; + + if (buffer_start & ~PAGE_MASK) { + DRM_ERROR("Invalid buffer object start.\n"); + return -EINVAL; + } + num_pages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + if (num_pages == 0) { + DRM_ERROR("Illegal buffer object size.\n"); + return -EINVAL; + } bo = drm_calloc(1, sizeof(*bo), DRM_MEM_BUFOBJ); @@ -561,50 +627,14 @@ int drm_buffer_object_create(drm_file_t *priv, INIT_LIST_HEAD(&bo->head); INIT_LIST_HEAD(&bo->ddestroy); bo->dev = dev; + bo->type = type; + bo->num_pages = num_pages; + bo->buffer_start = buffer_start; - switch(type) { - case drm_bo_type_dc: - ret = drm_ttm_object_create(dev, size, ttm_flags, &bo->ttm_object); - if (ret) - goto out_err; - break; - case drm_bo_type_ttm: - if (buffer_start & ~PAGE_MASK) { - DRM_ERROR("Illegal buffer object start\n"); - ret = -EINVAL; - } - bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (!bo->num_pages) { - DRM_ERROR("Illegal buffer object size\n"); - ret = -EINVAL; - goto out_err; - } - bo->ttm_object = drm_lookup_ttm_object(priv, ttm_handle, 1); - if (!bo->ttm_object) { - DRM_ERROR("Could not find buffer object TTM\n"); - ret = -EINVAL; - goto out_err; - } - ttm = drm_ttm_from_object(bo->ttm_object); - ret = drm_create_ttm_region(ttm, buffer_start >> PAGE_SHIFT, - bo->num_pages, 0, &bo->ttm_region); - if (ret) - goto out_err; - break; - case drm_bo_type_user: - if (buffer_start & ~PAGE_MASK) { - DRM_ERROR("Illegal buffer object start\n"); - ret = -EINVAL; - goto out_err; - } - bo->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - bo->user_pages = (void __user *)buffer_start; - break; - default: - ret = -EINVAL; + ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); + if (ret) goto out_err; - } - + bo->mask = mask; bo->mask_hint = hint; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 8cd0af61..e111070e 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -784,6 +784,16 @@ void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) } } +void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) +{ + if (atomic_dec_and_test(&to->usage)) { + mutex_lock(&dev->struct_mutex); + if (atomic_read(&to->usage) == 0) + drm_ttm_object_remove(dev, to); + mutex_unlock(&dev->struct_mutex); + } +} + /* * dev->struct_mutex locked. diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index ba4261bf..a1810509 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -111,6 +111,7 @@ typedef struct drm_ttm_object { extern int drm_ttm_object_create(struct drm_device *dev, unsigned long size, uint32_t flags, drm_ttm_object_t **ttm_object); extern void drm_ttm_object_deref_locked(struct drm_device *dev, drm_ttm_object_t *to); +extern void drm_ttm_object_deref_unlocked(struct drm_device *dev, drm_ttm_object_t *to); extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, int check_owner); diff --git a/shared-core/drm.h b/shared-core/drm.h index f8479dd0..e50ebfe2 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -686,7 +686,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_NO_EVICT 0x00000010 #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 #define DRM_BO_FLAG_READ_LOCAL 0x00000040 -#define DRM_BO_FLAG_UNCACHED 0x00000080 +#define DRM_BO_FLAG_CACHED 0x00000080 #define DRM_BO_FLAG_SHAREABLE 0x00000100 #define DRM_BO_FLAG_MEM_TT 0x01000000 -- 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. --- libdrm/xf86drm.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++- libdrm/xf86mm.h | 105 +++++++++++++++++++++++++++++++++++++ linux-core/drmP.h | 3 +- linux-core/drm_bo.c | 30 +++++++++-- linux-core/drm_ttm.c | 5 +- linux-core/i915_drv.c | 3 +- linux-core/i915_fence.c | 2 + shared-core/drm.h | 3 +- shared-core/i915_dma.c | 3 -- shared-core/i915_irq.c | 6 +++ 10 files changed, 283 insertions(+), 12 deletions(-) create mode 100644 libdrm/xf86mm.h diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3731ee12..6de6c06f 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -65,6 +65,8 @@ # define _DRM_FREE free # include "drm.h" #endif +#include "xf86mm.h" + /* Not all systems have MAP_FAILED defined */ #ifndef MAP_FAILED @@ -2384,7 +2386,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) int drmTTMDestroy(int fd, const drmTTM *ttm) { - drm_ttm_arg_t arg; + drm_ttm_arg_t arg; arg.op = drm_ttm_destroy; arg.handle = ttm->handle; @@ -2425,4 +2427,135 @@ drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm) (void) fd; return ttm->user_token; } + +static int drmAdjustListNodes(DrmBufList *list) +{ + DrmBufNode *node; + DrmMMListHead *l; + int ret = 0; + + while(list->numCurrent < list->numTarget) { + node = (DrmBufNode *) malloc(sizeof(*node)); + if (!node) { + ret = -ENOMEM; + break; + } + list->numCurrent++; + DRMLISTADD(&node->head, &list->free); + } + + while(list->numCurrent > list->numTarget) { + l = list->free.next; + if (l == &list->free) + break; + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + list->numCurrent--; + } + return ret; +} + +static void drmFreeList(DrmBufList *list) +{ + DrmBufNode *node; + DrmMMListHead *l; + int ret = 0; + + l = list->list.next; + while(l != &list->list) { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + l = list->free.next; + list->numCurrent--; + list->numOnList--; + } + + l = list->free.next; + while(l != &list->free) { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + free(node); + l = list->free.next; + list->numCurrent--; + } +} + +int drmResetList(DrmBufList *list) { + + DrmMMListHead *l; + int ret; + + ret = drmAdjustListNodes(list); + if (ret) + return ret; + + l = list->list.next; + while(l != &list->list) { + DRMLISTDEL(l); + DRMLISTADD(l, &list->free); + list->numOnList--; + } + return drmAdjustListNodes(list); +} + +static int drmAddListItem(DrmBufList *list, DrmBuf *item, drm_bo_arg_t *arg) +{ + DrmBufNode *node; + DrmMMListHead *l; + + l = list->free.next; + if (l == &list->free) { + node = (DrmBufNode *) malloc(sizeof(*node)); + if (!node) { + return -ENOMEM; + } + list->numCurrent++; + } else { + DRMLISTDEL(l); + node = DRMLISTENTRY(DrmBufNode, l, head); + } + node->buf = item; + DRMLISTADD(&node->head, &list->list); + list->numOnList++; + return 0; +} + +int drmCreateBufList(int numTarget, DrmBufList *list) +{ + DRMINITLISTHEAD(&list->list); + DRMINITLISTHEAD(&list->free); + list->numTarget = numTarget; + list->numCurrent = 0; + list->numOnList = 0; + return drmAdjustListNodes(list); +} + +/* + * Prepare list for IOCTL submission. + */ + +static drm_bo_arg_t *drmPrepareList(DrmBufList *list) +{ + DrmMMListHead *cur, *next; + DrmBufNode *first, *curNode, *nextNode; + + cur = list->list.next; + if (cur == &list->list) + return NULL; + + first = DRMLISTENTRY(DrmBufNode, cur, head); + curNode = DRMLISTENTRY(DrmBufNode, cur, head); + + for (next = cur->next; next != &list->list; + cur = next, next = cur->next) { + nextNode = DRMLISTENTRY(DrmBufNode, next, head); + curNode->bo_arg.req.next = ((unsigned long) &nextNode->bo_arg.req); + curNode = nextNode; + } + curNode->bo_arg.req.next = 0; + return &first->bo_arg; +} + #endif diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h new file mode 100644 index 00000000..5fb78723 --- /dev/null +++ b/libdrm/xf86mm.h @@ -0,0 +1,105 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ + +#ifndef _XF86MM_H_ +#define _XF86MM_H_ +#include + + +/* + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + */ + +typedef struct _drmMMListHead +{ + struct _drmMMListHead *prev; + struct _drmMMListHead *next; +} DrmMMListHead; + +#define DRMINITLISTHEAD(__item) \ + do{ \ + (__item)->prev = (__item); \ + (__item)->next = (__item); \ + } while (0) + +#define DRMLISTADD(__item, __list) \ + do { \ + (__item)->prev = (__list); \ + (__item)->next = (__list)->next; \ + (__list)->next->prev = (__item); \ + (__list)->next = (__item); \ + } while (0) + +#define DRMLISTADDTAIL(__item, __list) \ + do { \ + (__item)->next = (__list); \ + (__item)->prev = (__list)->prev; \ + (__list)->prev->next = (__item); \ + (__list)->prev = (__item); \ + } while(0) + +#define DRMLISTDEL(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + } while(0) + +#define DRMLISTDELINIT(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + (__item)->next = (__item); \ + (__item)->prev = (__item); \ + } while(0) + +#define DRMLISTENTRY(__type, __item, __field) \ + ((__type *)(((char *) (__item)) - offsetof(__type, __field))) + + +typedef struct _DrmBuf{ + unsigned handle; +} DrmBuf; + + +typedef struct _DrmBufNode { + DrmMMListHead head; + DrmBuf *buf; + drm_bo_arg_t bo_arg; +} DrmBufNode; + +typedef struct _DrmMMBufList { + unsigned numTarget; + unsigned numCurrent; + unsigned numOnList; + DrmMMListHead list; + DrmMMListHead free; +} DrmBufList; + + +#endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 81b7a1b6..4d490abe 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -652,7 +652,8 @@ typedef struct drm_ref_object { */ typedef struct drm_bo_driver{ - int cached_pages; + int cached_tt; + int cached_vram; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev, int cached); } drm_bo_driver_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 30656060..55901660 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -214,7 +214,8 @@ static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) } -static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, +static int drm_bo_new_flags(drm_bo_driver_t *driver, + uint32_t flags, uint32_t new_mask, uint32_t hint, int init, uint32_t *n_flags) { uint32_t new_flags; @@ -263,6 +264,24 @@ static int drm_bo_new_flags(uint32_t flags, uint32_t new_mask, uint32_t hint, } new_flags |= new_mask & ~DRM_BO_MASK_MEM; + + if (hint & DRM_BO_HINT_BIND_CACHED) { + new_flags |= DRM_BO_FLAG_CACHED; + if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || + ((new_flags & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) + new_flags &= ~DRM_BO_FLAG_CACHED; + } + + if ((new_flags & DRM_BO_FLAG_NO_EVICT) && + ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { + if (flags & DRM_BO_FLAG_CACHED) { + DRM_ERROR("Cannot change caching policy of pinned buffer\n"); + return -EINVAL; + } else { + new_flags &= ~DRM_BO_FLAG_CACHED; + } + } + *n_flags = new_flags; return 0; } @@ -531,11 +550,12 @@ static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo return 0; } + /* * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t new_flags, +static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hint, uint32_t ttm_handle) { @@ -578,7 +598,7 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t ne ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - new_flags & DRM_BO_FLAG_CACHED, + hint & DRM_BO_HINT_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -631,6 +651,10 @@ int drm_buffer_object_create(drm_file_t *priv, bo->num_pages = num_pages; bo->buffer_start = buffer_start; + ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, + 1, &new_flags); + if (ret) + goto out_err; ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); if (ret) goto out_err; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index e111070e..65d40344 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -202,10 +202,11 @@ int drm_destroy_ttm(drm_ttm_t * ttm) if (atomic_read(&ttm->vma_count) > 0) { ttm->destroy = 1; - DRM_DEBUG("VMAs are still alive. Skipping destruction.\n"); + DRM_ERROR("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; } + DRM_ERROR("Destroying a ttm\n"); if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = @@ -479,6 +480,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) uint32_t *cur_page_flags; int i; + DRM_ERROR("Destroying a TTM region\n"); list_del_init(&entry->head); drm_unbind_ttm_region(entry); @@ -800,7 +802,6 @@ void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) */ static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) { - DRM_ERROR("User deref ttm\n"); drm_ttm_object_deref_locked(priv->head->dev, drm_user_object_entry(base, drm_ttm_object_t, base)); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 64ab3f50..bc78dc2e 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -49,7 +49,8 @@ static drm_fence_driver_t i915_fence_driver = { }; static drm_bo_driver_t i915_bo_driver = { - .cached_pages = 1, + .cached_vram = 0, + .cached_tt = 1, .create_ttm_backend_entry = i915_create_ttm_backend_entry }; diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 46a2a728..452d4ee8 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -86,6 +86,8 @@ static void i915_perform_flush(drm_device_t * dev) dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fm->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); + DRM_ERROR("Saved flush status is 0x%08x\n", + dev_priv->saved_flush_status); I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); dev_priv->flush_pending = 1; fm->pending_flush = 0; diff --git a/shared-core/drm.h b/shared-core/drm.h index e50ebfe2..5888c9be 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -685,7 +685,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_NO_MOVE 0x00000008 #define DRM_BO_FLAG_NO_EVICT 0x00000010 #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 -#define DRM_BO_FLAG_READ_LOCAL 0x00000040 +#define DRM_BO_FLAG_READ_CACHED 0x00000040 #define DRM_BO_FLAG_CACHED 0x00000080 #define DRM_BO_FLAG_SHAREABLE 0x00000100 @@ -697,6 +697,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_HINT_PREFER_VRAM 0x00000001 #define DRM_BO_HINT_AVOID_LOCAL 0x00000002 #define DRM_BO_HINT_DONT_BLOCK 0x00000004 +#define DRM_BO_HINT_BIND_CACHED 0x00000008 typedef enum { drm_bo_type_ttm, diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 8ef9d8e1..e661269b 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -195,9 +195,6 @@ static int i915_initialize(drm_device_t * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); -#ifdef I915_HAVE_FENCE - dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); -#endif dev->dev_private = (void *)dev_priv; return 0; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 08d3140b..4195555e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -275,6 +275,12 @@ void i915_driver_irq_postinstall(drm_device_t * dev) i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); + + /* + * Initialize the hardware status page IRQ location. + */ + + I915_WRITE(I915REG_INSTPM, ( 1 << 5) | ( 1 << 21)); } void i915_driver_irq_uninstall(drm_device_t * dev) -- cgit v1.2.3 From de144ba23c1245cf021a63cc739c7c9903568272 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 29 Aug 2006 21:57:37 +0200 Subject: Part of buffer object libdrm interface. --- libdrm/xf86drm.c | 189 +++++++++++++++++++++++++++++++++++++++++++++++------- libdrm/xf86drm.h | 2 + libdrm/xf86mm.h | 41 ++++++++---- shared-core/drm.h | 4 ++ 4 files changed, 198 insertions(+), 38 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6de6c06f..3fccdf69 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2381,6 +2381,8 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) ttm->user_token = (drm_handle_t) arg.user_token; ttm->flags = arg.flags; ttm->size = arg.size; + ttm->virtual = NULL; + ttm->mapCount = 0; return 0; } @@ -2428,14 +2430,14 @@ drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm) return ttm->user_token; } -static int drmAdjustListNodes(DrmBufList *list) +static int drmAdjustListNodes(drmBOList *list) { - DrmBufNode *node; - DrmMMListHead *l; + drmBONode *node; + drmMMListHead *l; int ret = 0; while(list->numCurrent < list->numTarget) { - node = (DrmBufNode *) malloc(sizeof(*node)); + node = (drmBONode *) malloc(sizeof(*node)); if (!node) { ret = -ENOMEM; break; @@ -2449,23 +2451,23 @@ static int drmAdjustListNodes(DrmBufList *list) if (l == &list->free) break; DRMLISTDEL(l); - node = DRMLISTENTRY(DrmBufNode, l, head); + node = DRMLISTENTRY(drmBONode, l, head); free(node); list->numCurrent--; } return ret; } -static void drmFreeList(DrmBufList *list) +static void drmFreeList(drmBOList *list) { - DrmBufNode *node; - DrmMMListHead *l; + drmBONode *node; + drmMMListHead *l; int ret = 0; l = list->list.next; while(l != &list->list) { DRMLISTDEL(l); - node = DRMLISTENTRY(DrmBufNode, l, head); + node = DRMLISTENTRY(drmBONode, l, head); free(node); l = list->free.next; list->numCurrent--; @@ -2475,16 +2477,16 @@ static void drmFreeList(DrmBufList *list) l = list->free.next; while(l != &list->free) { DRMLISTDEL(l); - node = DRMLISTENTRY(DrmBufNode, l, head); + node = DRMLISTENTRY(drmBONode, l, head); free(node); l = list->free.next; list->numCurrent--; } } -int drmResetList(DrmBufList *list) { +int drmResetList(drmBOList *list) { - DrmMMListHead *l; + drmMMListHead *l; int ret; ret = drmAdjustListNodes(list); @@ -2500,21 +2502,21 @@ int drmResetList(DrmBufList *list) { return drmAdjustListNodes(list); } -static int drmAddListItem(DrmBufList *list, DrmBuf *item, drm_bo_arg_t *arg) +static int drmAddListItem(drmBOList *list, drmBO *item, drm_bo_arg_t *arg) { - DrmBufNode *node; - DrmMMListHead *l; + drmBONode *node; + drmMMListHead *l; l = list->free.next; if (l == &list->free) { - node = (DrmBufNode *) malloc(sizeof(*node)); + node = (drmBONode *) malloc(sizeof(*node)); if (!node) { return -ENOMEM; } list->numCurrent++; } else { DRMLISTDEL(l); - node = DRMLISTENTRY(DrmBufNode, l, head); + node = DRMLISTENTRY(drmBONode, l, head); } node->buf = item; DRMLISTADD(&node->head, &list->list); @@ -2522,7 +2524,7 @@ static int drmAddListItem(DrmBufList *list, DrmBuf *item, drm_bo_arg_t *arg) return 0; } -int drmCreateBufList(int numTarget, DrmBufList *list) +int drmCreateBufList(int numTarget, drmBOList *list) { DRMINITLISTHEAD(&list->list); DRMINITLISTHEAD(&list->free); @@ -2536,21 +2538,21 @@ int drmCreateBufList(int numTarget, DrmBufList *list) * Prepare list for IOCTL submission. */ -static drm_bo_arg_t *drmPrepareList(DrmBufList *list) +static drm_bo_arg_t *drmPrepareList(drmBOList *list) { - DrmMMListHead *cur, *next; - DrmBufNode *first, *curNode, *nextNode; + drmMMListHead *cur, *next; + drmBONode *first, *curNode, *nextNode; cur = list->list.next; if (cur == &list->list) return NULL; - first = DRMLISTENTRY(DrmBufNode, cur, head); - curNode = DRMLISTENTRY(DrmBufNode, cur, head); + first = DRMLISTENTRY(drmBONode, cur, head); + curNode = DRMLISTENTRY(drmBONode, cur, head); for (next = cur->next; next != &list->list; cur = next, next = cur->next) { - nextNode = DRMLISTENTRY(DrmBufNode, next, head); + nextNode = DRMLISTENTRY(drmBONode, next, head); curNode->bo_arg.req.next = ((unsigned long) &nextNode->bo_arg.req); curNode = nextNode; } @@ -2558,4 +2560,143 @@ static drm_bo_arg_t *drmPrepareList(DrmBufList *list) return &first->bo_arg; } +int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, + void *user_buffer, drm_bo_type_t type, unsigned mask, + unsigned hint, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + + req->mask = mask; + req->hint = hint; + req->size = size; + req->type = type; + + buf->ttm = NULL; + + switch(type) { + case drm_bo_type_ttm: + req->arg_handle = ttm->handle; + req->buffer_start = start; + buf->ttm = ttm; + break; + case drm_bo_type_dc: + break; + case drm_bo_type_user: + req->buffer_start = (unsigned long) user_buffer; + buf->virtual = user_buffer; + break; + default: + return -EINVAL; + } + req->op = drm_bo_create; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + return -errno; + if (!rep->handled) { + return -EFAULT; + } + if (rep->ret) { + return rep->ret; + } + + buf->handle = rep->handle; + buf->flags = rep->flags; + buf->size = rep->size; + buf->offset = rep->offset; + buf->map_handle = rep->arg_handle; + buf->map_flags = rep->map_flags; + buf->map_virtual = NULL; + buf->map_count = 0; + buf->virtual = NULL; + buf->mask = rep->mask; + buf->hint = rep->hint; + buf->start = rep->buffer_start; + + return 0; +} + +int drmBODestroy(int fd, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + + req->handle = buf->handle; + req->op = drm_bo_destroy; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + return -errno; + if (!rep->handled) { + return -EFAULT; + } + if (rep->ret) { + return rep->ret; + } + + buf->handle = 0; + return 0; +} + +int drmBOReference(int fd, unsigned handle, drmBO *buf) +{ + + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + + req->handle = handle; + req->op = drm_bo_reference; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + return -errno; + if (!rep->handled) { + return -EFAULT; + } + if (rep->ret) { + return rep->ret; + } + + buf->handle = rep->handle; + buf->type = drm_bo_type_dc; + buf->flags = rep->flags; + buf->size = rep->size; + buf->offset = rep->offset; + buf->map_handle = rep->arg_handle; + buf->map_flags = rep->map_flags; + buf->map_virtual = NULL; + buf->map_count = 0; + buf->virtual = NULL; + buf->mask = rep->mask; + buf->hint = rep->hint; + return 0; +} + +int drmBOUnReference(int fd, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + + req->handle = buf->handle; + req->op = drm_bo_unreference; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + return -errno; + if (!rep->handled) { + return -EFAULT; + } + if (rep->ret) { + return rep->ret; + } + + buf->handle = 0; + return 0; +} + #endif diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 58cbd16c..ca48bfbf 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -292,6 +292,8 @@ typedef struct _drmTTM{ drm_handle_t user_token; unsigned flags; unsigned long size; + void *virtual; + int mapCount; } drmTTM; #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 5fb78723..08149d08 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -29,7 +29,7 @@ #ifndef _XF86MM_H_ #define _XF86MM_H_ #include - +#include "xf86drm.h" /* * List macros heavily inspired by the Linux kernel @@ -40,7 +40,7 @@ typedef struct _drmMMListHead { struct _drmMMListHead *prev; struct _drmMMListHead *next; -} DrmMMListHead; +} drmMMListHead; #define DRMINITLISTHEAD(__item) \ do{ \ @@ -82,24 +82,37 @@ typedef struct _drmMMListHead ((__type *)(((char *) (__item)) - offsetof(__type, __field))) -typedef struct _DrmBuf{ +typedef struct _drmBO{ + drm_bo_type_t type; unsigned handle; -} DrmBuf; - - -typedef struct _DrmBufNode { - DrmMMListHead head; - DrmBuf *buf; + drm_handle_t map_handle; + unsigned flags; + unsigned mask; + unsigned hint; + unsigned map_flags; + unsigned long size; + unsigned long offset; + unsigned long start; + void *virtual; + void *map_virtual; + int map_count; + drmTTM *ttm; +} drmBO; + + +typedef struct _drmBONode { + drmMMListHead head; + drmBO *buf; drm_bo_arg_t bo_arg; -} DrmBufNode; +} drmBONode; -typedef struct _DrmMMBufList { +typedef struct _drmBOList { unsigned numTarget; unsigned numCurrent; unsigned numOnList; - DrmMMListHead list; - DrmMMListHead free; -} DrmBufList; + drmMMListHead list; + drmMMListHead free; +} drmBOList; #endif diff --git a/shared-core/drm.h b/shared-core/drm.h index 5888c9be..c65ecc00 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -736,6 +736,9 @@ typedef struct drm_bo_arg_reply { drm_u64_t offset; unsigned arg_handle; unsigned map_flags; + unsigned mask; + unsigned hint; + drm_u64_t buffer_start; }drm_bo_arg_reply_t; @@ -813,6 +816,7 @@ typedef union drm_bo_arg{ #ifdef __linux__ #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) #define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) +#define DRM_IOCTL_BUFOBJ DRM_IOWR(0x3d, drm_bo_arg_t) #endif /*@}*/ -- 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 ++--- shared-core/drm.h | 8 +- 5 files changed, 188 insertions(+), 163 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4d490abe..63bcde2e 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -955,11 +955,13 @@ typedef struct drm_buffer_object{ unsigned long num_pages; unsigned long buffer_start; drm_bo_type_t type; + unsigned long offset; atomic_t mapped; + uint32_t map_flags; uint32_t flags; uint32_t mask; - uint32_t mask_hint; + uint32_t hint; drm_mm_node_t *vram; drm_mm_node_t *tt; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 55901660..24389447 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -55,7 +55,7 @@ * 2.) Refer to ttm locking orders. */ -int drm_fence_buffer_objects(drm_file_t *priv) +int drm_fence_buffer_objects(drm_file_t * priv) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -69,7 +69,7 @@ int drm_fence_buffer_objects(drm_file_t *priv) mutex_lock(&bm->bm_mutex); list_for_each_entry(entry, &bm->unfenced, head) { - BUG_ON(!entry->unfenced); + BUG_ON(!entry->unfenced); fence_flags |= entry->fence_flags; count++; } @@ -85,7 +85,7 @@ int drm_fence_buffer_objects(drm_file_t *priv) mutex_unlock(&bm->bm_mutex); return -ENOMEM; } - + ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); @@ -120,24 +120,23 @@ int drm_fence_buffer_objects(drm_file_t *priv) * dev locked. */ - -static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) +static int drm_move_tt_to_local(drm_buffer_object_t * buf, int lazy) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; int ret = 0; - + BUG_ON(!buf->tt); if (buf->fence) { - ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, + ret = drm_fence_object_wait(dev, buf->fence, lazy, !lazy, buf->fence_flags); if (ret) return ret; drm_fence_usage_deref_unlocked(dev, buf->fence); buf->fence = NULL; } - + drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -147,10 +146,9 @@ static int drm_move_tt_to_local(drm_buffer_object_t *buf, int lazy) return 0; } - -static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo) +static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) { - + drm_buffer_manager_t *bm = &dev->bm; BUG_ON(bo->unfenced); @@ -189,15 +187,14 @@ static void drm_bo_destroy_locked(drm_device_t *dev, drm_buffer_object_t *bo) drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } - -void drm_bo_usage_deref_locked(drm_device_t *dev, drm_buffer_object_t *bo) +void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { drm_bo_destroy_locked(dev, bo); } } -void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) +void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { mutex_lock(&dev->struct_mutex); @@ -207,20 +204,20 @@ void drm_bo_usage_deref_unlocked(drm_device_t *dev, drm_buffer_object_t *bo) } } -static void drm_bo_base_deref_locked(drm_file_t *priv, drm_user_object_t *uo) +static void drm_bo_base_deref_locked(drm_file_t * priv, drm_user_object_t * uo) { - drm_bo_usage_deref_locked(priv->head->dev, - drm_user_object_entry(uo, drm_buffer_object_t, base)); + drm_bo_usage_deref_locked(priv->head->dev, + drm_user_object_entry(uo, drm_buffer_object_t, + base)); } - -static int drm_bo_new_flags(drm_bo_driver_t *driver, +static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, - int init, uint32_t *n_flags) + int init, uint32_t * n_flags) { uint32_t new_flags; uint32_t new_props; - + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { /* @@ -234,10 +231,11 @@ static int drm_bo_new_flags(drm_bo_driver_t *driver, DRM_ERROR("Invalid buffer object memory flags\n"); return -EINVAL; } - + if (new_flags & DRM_BO_FLAG_MEM_LOCAL) { - if ((hint & DRM_BO_HINT_AVOID_LOCAL) && - new_flags & (DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_TT)) { + if ((hint & DRM_BO_HINT_AVOID_LOCAL) && + new_flags & (DRM_BO_FLAG_MEM_VRAM | + DRM_BO_FLAG_MEM_TT)) { new_flags &= ~DRM_BO_FLAG_MEM_LOCAL; } else { new_flags = DRM_BO_FLAG_MEM_LOCAL; @@ -254,7 +252,7 @@ static int drm_bo_new_flags(drm_bo_driver_t *driver, } else { new_flags = flags & DRM_BO_MASK_MEM; } - + new_props = new_mask & (DRM_BO_FLAG_EXE | DRM_BO_FLAG_WRITE | DRM_BO_FLAG_READ); @@ -268,14 +266,16 @@ static int drm_bo_new_flags(drm_bo_driver_t *driver, if (hint & DRM_BO_HINT_BIND_CACHED) { new_flags |= DRM_BO_FLAG_CACHED; if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || - ((new_flags & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) + ((new_flags & DRM_BO_FLAG_MEM_VRAM) + && !driver->cached_vram)) new_flags &= ~DRM_BO_FLAG_CACHED; } - + if ((new_flags & DRM_BO_FLAG_NO_EVICT) && ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { if (flags & DRM_BO_FLAG_CACHED) { - DRM_ERROR("Cannot change caching policy of pinned buffer\n"); + DRM_ERROR + ("Cannot change caching policy of pinned buffer\n"); return -EINVAL; } else { new_flags &= ~DRM_BO_FLAG_CACHED; @@ -285,12 +285,10 @@ static int drm_bo_new_flags(drm_bo_driver_t *driver, *n_flags = new_flags; return 0; } - - #if 0 -static int drm_bo_evict(drm_device_t *dev, drm_buffer_object_t *buf, int tt); +static int drm_bo_evict(drm_device_t * dev, drm_buffer_object_t * buf, int tt); { int ret; if (tt) { @@ -300,8 +298,8 @@ static int drm_bo_evict(drm_device_t *dev, drm_buffer_object_t *buf, int tt); } return ret; } - -int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) + +int drm_bo_alloc_space(drm_device_t * dev, int tt, drm_buffer_object_t * buf) { drm_mm_node_t *node; drm_buffer_manager_t *bm = &dev->bm; @@ -315,13 +313,14 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) if (node) break; - if (lru->next == lru) + if (lru->next == lru) break; if (tt) { bo = list_entry(lru->next, drm_buffer_object_t, tt_lru); } else { - bo = list_entry(lru->next, drm_buffer_object_t, vram_lru); + bo = list_entry(lru->next, drm_buffer_object_t, + vram_lru); } drm_bo_evict(dev, bo, tt); @@ -344,22 +343,20 @@ int drm_bo_alloc_space(drm_device_t *dev, int tt, drm_buffer_object_t *buf) return 0; } #endif - /* * Call dev->struct_mutex locked. */ - -drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t *priv, uint32_t handle, - int check_owner) +drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, + uint32_t handle, int check_owner) { drm_user_object_t *uo; drm_buffer_object_t *bo; uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_buffer_type)) + if (!uo || (uo->type != drm_buffer_type)) return NULL; if (check_owner && priv != uo->owner) { @@ -371,15 +368,15 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t *priv, uint32_t handle, atomic_inc(&bo->usage); return bo; } - + /* * Call bo->mutex locked. * Wait until the buffer is idle. */ -static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) +static int drm_bo_wait(drm_device_t * dev, drm_buffer_object_t * bo, int lazy) { - + drm_fence_object_t *fence = bo->fence; int ret; @@ -399,7 +396,9 @@ static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) atomic_inc(&fence->usage); mutex_unlock(&bo->mutex); - ret = drm_fence_object_wait(dev, fence, lazy, !lazy, bo->fence_flags); + ret = + drm_fence_object_wait(dev, fence, lazy, !lazy, + bo->fence_flags); mutex_lock(&bo->mutex); if (ret) return ret; @@ -410,7 +409,7 @@ static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) bo->fence = NULL; } mutex_unlock(&dev->struct_mutex); - } + } return 0; } @@ -419,7 +418,7 @@ static int drm_bo_wait(drm_device_t *dev, drm_buffer_object_t *bo, int lazy) * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. */ -static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) +static int drm_bo_busy(drm_device_t * dev, drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; @@ -439,7 +438,6 @@ static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) } return 0; } - /* * Wait for buffer idle and register that we've mapped the buffer. @@ -448,13 +446,12 @@ static int drm_bo_busy(drm_device_t *dev, drm_buffer_object_t *bo) * unregistered. */ - -static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) +static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; int ret; - + mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); mutex_unlock(&dev->struct_mutex); @@ -465,8 +462,7 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) mutex_lock(&bo->mutex); if (!wait) { - if ((atomic_read(&bo->mapped) == 0) && - drm_bo_busy(dev, bo)) { + if ((atomic_read(&bo->mapped) == 0) && drm_bo_busy(dev, bo)) { mutex_unlock(&bo->mutex); ret = -EBUSY; goto out; @@ -486,14 +482,13 @@ static int drm_buffer_object_map(drm_file_t *priv, uint32_t handle, int wait) atomic_inc(&bo->mapped); } mutex_unlock(&bo->mutex); - - out: - drm_bo_usage_deref_unlocked(dev,bo); + + out: + drm_bo_usage_deref_unlocked(dev, bo); return ret; } - -static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) +static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; @@ -516,21 +511,22 @@ static int drm_buffer_object_unmap(drm_file_t *priv, uint32_t handle) drm_remove_ref_object(priv, ro); drm_bo_usage_deref_locked(dev, bo); - out: + out: mutex_unlock(&dev->struct_mutex); return ret; } - /* * Call struct-sem locked. */ -static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo, +static void drm_buffer_user_object_unmap(drm_file_t * priv, + drm_user_object_t * uo, drm_ref_t action) { drm_device_t *dev = priv->head->dev; - drm_buffer_object_t *bo = drm_user_object_entry(uo, drm_buffer_object_t, base); + drm_buffer_object_t *bo = + drm_user_object_entry(uo, drm_buffer_object_t, base); BUG_ON(action != _DRM_REF_TYPE1); @@ -545,33 +541,32 @@ static void drm_buffer_user_object_unmap(drm_file_t *priv, drm_user_object_t *uo } } -static int drm_buffer_object_validate(drm_device_t *dev, drm_buffer_object_t *bo) +static int drm_buffer_object_validate(drm_device_t * dev, + drm_buffer_object_t * bo) { return 0; } - /* * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hint, - uint32_t ttm_handle) - +static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, + uint32_t hint, uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; drm_ttm_t *ttm; - int ret=0; + int ret = 0; uint32_t ttm_flags = 0; bo->ttm_object = NULL; bo->ttm_region = NULL; - switch(bo->type) { + switch (bo->type) { case drm_bo_type_dc: mutex_lock(&dev->struct_mutex); - ret = drm_ttm_object_create(dev, bo->num_pages*PAGE_SIZE, + ret = drm_ttm_object_create(dev, bo->num_pages * PAGE_SIZE, ttm_flags, &to); mutex_unlock(&dev->struct_mutex); break; @@ -579,11 +574,11 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hi mutex_lock(&dev->struct_mutex); to = drm_lookup_ttm_object(priv, ttm_handle, 1); mutex_unlock(&dev->struct_mutex); - if (!to) + if (!to) ret = -EINVAL; break; case drm_bo_type_user: - + case drm_bo_type_fake: break; default: ret = -EINVAL; @@ -597,8 +592,8 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hi bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, - hint & DRM_BO_HINT_BIND_CACHED, + bo->num_pages, + hint & DRM_BO_HINT_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -606,28 +601,27 @@ static int drm_bo_add_ttm(drm_file_t *priv, drm_buffer_object_t *bo, uint32_t hi } return ret; } - -int drm_buffer_object_create(drm_file_t *priv, +int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, uint32_t ttm_handle, uint32_t mask, uint32_t hint, unsigned long buffer_start, - drm_buffer_object_t **buf_obj) + drm_buffer_object_t ** buf_obj) { drm_device_t *dev = priv->head->dev; drm_buffer_object_t *bo; int ret = 0; uint32_t new_flags; unsigned long num_pages; - + if (buffer_start & ~PAGE_MASK) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } - num_pages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; if (num_pages == 0) { DRM_ERROR("Illegal buffer object size.\n"); return -EINVAL; @@ -653,14 +647,14 @@ int drm_buffer_object_create(drm_file_t *priv, ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, 1, &new_flags); - if (ret) + if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); - if (ret) + if (ret) goto out_err; bo->mask = mask; - bo->mask_hint = hint; + bo->hint = hint; ret = drm_buffer_object_validate(dev, bo); if (ret) @@ -669,14 +663,14 @@ int drm_buffer_object_create(drm_file_t *priv, mutex_unlock(&bo->mutex); *buf_obj = bo; return 0; - - out_err: + + out_err: mutex_unlock(&bo->mutex); drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); - return ret; + return ret; } -static int drm_bo_add_user_object(drm_file_t *priv, drm_buffer_object_t *bo, +static int drm_bo_add_user_object(drm_file_t * priv, drm_buffer_object_t * bo, int shareable) { drm_device_t *dev = priv->head->dev; @@ -691,13 +685,31 @@ static int drm_bo_add_user_object(drm_file_t *priv, drm_buffer_object_t *bo, bo->base.type = drm_buffer_type; bo->base.ref_struct_locked = NULL; bo->base.unref = drm_buffer_user_object_unmap; - - out: + + out: mutex_unlock(&dev->struct_mutex); return ret; } - - + +static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, + drm_bo_arg_reply_t * rep) +{ + rep->handle = bo->base.hash.key; + rep->flags = bo->flags; + rep->size = bo->num_pages * PAGE_SIZE; + rep->offset = bo->offset; + + if (bo->ttm_object) { + rep->arg_handle = bo->ttm_object->map_list.user_token; + } else { + rep->arg_handle = 0; + } + + rep->map_flags = bo->map_flags; + rep->mask = bo->mask; + rep->hint = bo->hint; + rep->buffer_start = bo->buffer_start; +} int drm_bo_ioctl(DRM_IOCTL_ARGS) { @@ -714,34 +726,45 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = 0; rep.handled = 0; switch (req->op) { - case drm_bo_create: { - unsigned long buffer_start = req->buffer_start; - rep.ret = drm_buffer_object_create(priv, req->size, - req->type, req->arg_handle, - req->mask, req->hint, - buffer_start, - &entry); - if (rep.ret) + case drm_bo_create:{ + unsigned long buffer_start = req->buffer_start; + rep.ret = + drm_buffer_object_create(priv, req->size, + req->type, + req->arg_handle, + req->mask, + req->hint, + buffer_start, + &entry); + if (rep.ret) + break; + + rep.ret = + drm_bo_add_user_object(priv, entry, + req-> + mask & + DRM_BO_FLAG_SHAREABLE); + if (rep.ret) + drm_bo_usage_deref_unlocked(dev, entry); + + mutex_lock(&entry->mutex); + drm_bo_fill_rep_arg(entry, &rep); + mutex_unlock(&entry->mutex); break; - - rep.ret = drm_bo_add_user_object(priv, entry, req->mask & - DRM_BO_FLAG_SHAREABLE); - if (rep.ret) - drm_bo_usage_deref_unlocked(dev, entry); - break; - } + } case drm_bo_unmap: rep.ret = drm_buffer_object_unmap(priv, req->handle); break; case drm_bo_map: - rep.ret = drm_buffer_object_map(priv, req->handle, - !(req->hint & + rep.ret = drm_buffer_object_map(priv, req->handle, + !(req->hint & DRM_BO_HINT_DONT_BLOCK)); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, req->handle); - if (!uo || (uo->type != drm_buffer_type) || uo->owner != priv) { + if (!uo || (uo->type != drm_buffer_type) + || uo->owner != priv) { mutex_unlock(&dev->struct_mutex); rep.ret = -EINVAL; break; @@ -749,19 +772,24 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_remove_user_object(priv, uo); mutex_unlock(&dev->struct_mutex); break; - case drm_bo_reference: - rep.ret = drm_user_object_ref(priv, req->handle, + case drm_bo_reference: + rep.ret = drm_user_object_ref(priv, req->handle, drm_buffer_type, &uo); if (rep.ret) break; mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, req->handle); - entry = drm_user_object_entry(uo, drm_buffer_object_t, base); + entry = + drm_user_object_entry(uo, drm_buffer_object_t, + base); atomic_dec(&entry->usage); mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + drm_bo_fill_rep_arg(entry, &rep); + mutex_unlock(&entry->mutex); break; case drm_bo_unreference: - rep.ret = drm_user_object_unref(priv, req->handle, + rep.ret = drm_user_object_unref(priv, req->handle, drm_buffer_type); break; default: @@ -777,7 +805,3 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } - - - - diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 65d40344..33567d9b 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,7 +42,6 @@ typedef struct drm_val_action { int validated; } drm_val_action_t; - /* * We may be manipulating other processes page tables, so for each TTM, keep track of * which mm_structs are currently mapping the ttm so that we can take the appropriate @@ -204,7 +203,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) ttm->destroy = 1; DRM_ERROR("VMAs are still alive. Skipping destruction.\n"); return -EBUSY; - } + } DRM_ERROR("Destroying a ttm\n"); if (ttm->be_list) { @@ -263,7 +262,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) * FIXME: Avoid using vmalloc for the page- and page_flags tables? */ -static drm_ttm_t *drm_init_ttm(struct drm_device * dev, unsigned long size) +static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) { drm_ttm_t *ttm; @@ -354,7 +353,8 @@ static int drm_ttm_lock_mmap_sem(drm_ttm_t * ttm) DRM_MEM_TTM); cur_count = shared_count + 10; mm_list = - drm_alloc(sizeof(*mm_list) * cur_count, DRM_MEM_TTM); + drm_alloc(sizeof(*mm_list) * cur_count, + DRM_MEM_TTM); if (!mm_list) return -ENOMEM; } @@ -489,7 +489,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) if (be->needs_cache_adjust(be)) { int ret = drm_ttm_lock_mmap_sem(ttm); drm_ttm_lock_mm(ttm, 0, 1); - unmap_vma_pages(ttm, entry->page_offset, + unmap_vma_pages(ttm, entry->page_offset, entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); drm_set_caching(ttm, entry->page_offset, @@ -542,7 +542,8 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, if (!entry) return -ENOMEM; - be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, cached); + be = ttm->dev->driver->bo_driver->create_ttm_backend_entry(ttm->dev, + cached); if (!be) { drm_free(entry, sizeof(*entry), DRM_MEM_TTM); DRM_ERROR("Couldn't create backend.\n"); @@ -750,11 +751,10 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, return 0; } - /* * dev->struct_mutex locked. */ -static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) +static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) { drm_map_list_t *list = &object->map_list; drm_local_map_t *map; @@ -765,7 +765,7 @@ static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) map = list->map; if (map) { - drm_ttm_t *ttm = (drm_ttm_t *)map->offset; + drm_ttm_t *ttm = (drm_ttm_t *) map->offset; if (ttm) { if (drm_destroy_ttm(ttm) != -EBUSY) { drm_free(map, sizeof(*map), DRM_MEM_TTM); @@ -778,15 +778,14 @@ static void drm_ttm_object_remove(drm_device_t *dev, drm_ttm_object_t *object) drm_free(object, sizeof(*object), DRM_MEM_TTM); } - -void drm_ttm_object_deref_locked(drm_device_t *dev, drm_ttm_object_t *to) +void drm_ttm_object_deref_locked(drm_device_t * dev, drm_ttm_object_t * to) { if (atomic_dec_and_test(&to->usage)) { drm_ttm_object_remove(dev, to); } } -void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) +void drm_ttm_object_deref_unlocked(drm_device_t * dev, drm_ttm_object_t * to) { if (atomic_dec_and_test(&to->usage)) { mutex_lock(&dev->struct_mutex); @@ -796,26 +795,25 @@ void drm_ttm_object_deref_unlocked(drm_device_t *dev, drm_ttm_object_t *to) } } - /* * dev->struct_mutex locked. */ -static void drm_ttm_user_deref_locked(drm_file_t *priv, drm_user_object_t *base) +static void drm_ttm_user_deref_locked(drm_file_t * priv, + drm_user_object_t * base) { drm_ttm_object_deref_locked(priv->head->dev, - drm_user_object_entry(base, drm_ttm_object_t, + drm_user_object_entry(base, + drm_ttm_object_t, base)); } - - /* * Create a ttm and add it to the drm book-keeping. * dev->struct_mutex locked. */ -int drm_ttm_object_create(drm_device_t *dev, unsigned long size, - uint32_t flags, drm_ttm_object_t **ttm_object) +int drm_ttm_object_create(drm_device_t * dev, unsigned long size, + uint32_t flags, drm_ttm_object_t ** ttm_object) { drm_ttm_object_t *object; drm_map_list_t *list; @@ -823,11 +821,11 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, drm_ttm_t *ttm; object = drm_calloc(1, sizeof(*object), DRM_MEM_TTM); - if (!object) + if (!object) return -ENOMEM; object->flags = flags; list = &object->map_list; - + list->map = drm_calloc(1, sizeof(*map), DRM_MEM_TTM); if (!list->map) { drm_ttm_object_remove(dev, object); @@ -847,9 +845,9 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, map->flags = _DRM_REMOVABLE; map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; - - if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, - (unsigned long) map->handle, + + if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, + (unsigned long)map->handle, 32 - PAGE_SHIFT - 3, PAGE_SHIFT, DRM_MAP_HASH_OFFSET)) { drm_ttm_object_remove(dev, object); @@ -863,7 +861,7 @@ int drm_ttm_object_create(drm_device_t *dev, unsigned long size, return 0; } -drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, +drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, uint32_t handle, int check_owner) { drm_user_object_t *uo; @@ -871,7 +869,7 @@ drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_ttm_type)) + if (!uo || (uo->type != drm_ttm_type)) return NULL; if (check_owner && priv != uo->owner) { @@ -884,10 +882,9 @@ drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t *priv, uint32_t handle, return to; } - int drm_ttm_ioctl(DRM_IOCTL_ARGS) { - DRM_DEVICE; + DRM_DEVICE; drm_ttm_arg_t arg; drm_ttm_object_t *entry; drm_user_object_t *uo; @@ -895,8 +892,8 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) int ret; DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); - - switch(arg.op) { + + switch (arg.op) { case drm_ttm_create: mutex_lock(&dev->struct_mutex); size = arg.size; @@ -905,7 +902,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) mutex_unlock(&dev->struct_mutex); return ret; } - ret = drm_add_user_object(priv, &entry->base, + ret = drm_add_user_object(priv, &entry->base, arg.flags & DRM_TTM_FLAG_SHAREABLE); if (ret) { drm_ttm_object_remove(dev, entry); @@ -923,7 +920,7 @@ int drm_ttm_ioctl(DRM_IOCTL_ARGS) if (ret) return ret; mutex_lock(&dev->struct_mutex); - entry = drm_lookup_ttm_object(priv, arg.handle , 0); + entry = drm_lookup_ttm_object(priv, arg.handle, 0); break; case drm_ttm_unreference: return drm_user_object_unref(priv, arg.handle, drm_ttm_type); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index a1810509..d647578c 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -98,7 +98,7 @@ typedef struct drm_ttm { drm_ttm_backend_list_t *be_list; atomic_t vma_count; int mmap_sem_locked; - int destroy; + int destroy; } drm_ttm_t; typedef struct drm_ttm_object { @@ -107,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; } diff --git a/shared-core/drm.h b/shared-core/drm.h index c65ecc00..f6abfeb9 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -702,7 +702,8 @@ typedef struct drm_ttm_arg { typedef enum { drm_bo_type_ttm, drm_bo_type_dc, - drm_bo_type_user + drm_bo_type_user, + drm_bo_type_fake }drm_bo_type_t; @@ -823,12 +824,13 @@ typedef union drm_bo_arg{ /** * Device specific ioctls should only be in their respective headers - * The device specific ioctl range is from 0x40 to 0x79. + * The device specific ioctl range is from 0x40 to 0x99. + * Generic IOCTLS restart at 0xA0. * * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and * drmCommandReadWrite(). */ #define DRM_COMMAND_BASE 0x40 -#define DRM_COMMAND_END 0x80 +#define DRM_COMMAND_END 0xA0 #endif -- 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. --- libdrm/Makefile.am | 2 +- libdrm/xf86drm.c | 30 ++++++++++++- libdrm/xf86drm.h | 2 + libdrm/xf86mm.h | 9 +++- linux-core/drmP.h | 5 ++- linux-core/drm_bo.c | 123 +++++++++++++++++++++++++++++++++++++++++++++------ linux-core/drm_drv.c | 3 ++ shared-core/drm.h | 19 ++++++++ 8 files changed, 175 insertions(+), 18 deletions(-) diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index b12e87fa..91a7e5dc 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -26,6 +26,6 @@ AM_CFLAGS = -I$(top_srcdir)/shared-core libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c libdrmincludedir = ${includedir} -libdrminclude_HEADERS = xf86drm.h +libdrminclude_HEADERS = xf86drm.h xf86mm.h EXTRA_DIST = ChangeLog TODO diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3fccdf69..c9005c41 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -65,7 +65,6 @@ # define _DRM_FREE free # include "drm.h" #endif -#include "xf86mm.h" /* Not all systems have MAP_FAILED defined */ @@ -2582,6 +2581,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, buf->ttm = ttm; break; case drm_bo_type_dc: + req->buffer_start = start; break; case drm_bo_type_user: req->buffer_start = (unsigned long) user_buffer; @@ -2699,4 +2699,32 @@ int drmBOUnReference(int fd, drmBO *buf) return 0; } +int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, + unsigned long ttPOffset, unsigned long ttPSize) +{ + drm_mm_init_arg_t arg; + + arg.req.op = mm_init; + arg.req.vr_p_offset = vramPOffset; + arg.req.vr_p_size = vramPSize; + arg.req.tt_p_offset = vramPOffset; + arg.req.tt_p_size = vramPSize; + + if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) + return -errno; + + return 0; +} + +int drmMMTakedown(int fd) +{ + drm_mm_init_arg_t arg; + arg.req.op = mm_takedown; + + if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) + return -errno; + + return 0; +} + #endif diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index ca48bfbf..f257deda 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -670,4 +670,6 @@ extern int drmSLLookupNeighbors(void *l, unsigned long key, unsigned long *prev_key, void **prev_value, unsigned long *next_key, void **next_value); +#include "xf86mm.h" + #endif diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 08149d08..8711a144 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -29,7 +29,7 @@ #ifndef _XF86MM_H_ #define _XF86MM_H_ #include -#include "xf86drm.h" +#include "drm.h" /* * List macros heavily inspired by the Linux kernel @@ -114,5 +114,12 @@ typedef struct _drmBOList { drmMMListHead free; } drmBOList; +extern int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, + void *user_buffer, drm_bo_type_t type, unsigned mask, + unsigned hint, drmBO *buf); +extern int drmBODestroy(int fd, drmBO *buf); +extern int drmBOReference(int fd, unsigned handle, drmBO *buf); +extern int drmBOUnReference(int fd, drmBO *buf); + #endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 63bcde2e..59926968 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -775,7 +775,9 @@ typedef struct drm_fence_manager{ typedef struct drm_buffer_manager{ int initialized; - struct mutex bm_mutex; + int has_vram; + int has_tt; + struct mutex mutex; drm_mm_t tt_manager; struct list_head tt_lru; drm_mm_t vram_manager; @@ -1363,6 +1365,7 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); */ extern int drm_bo_ioctl(DRM_IOCTL_ARGS); +extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); /* Inline replacements for DRM_IOREMAP macros */ diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 24389447..5f557d55 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -66,7 +66,7 @@ int drm_fence_buffer_objects(drm_file_t * priv) drm_fence_object_t *fence; int ret; - mutex_lock(&bm->bm_mutex); + mutex_lock(&bm->mutex); list_for_each_entry(entry, &bm->unfenced, head) { BUG_ON(!entry->unfenced); @@ -75,21 +75,21 @@ int drm_fence_buffer_objects(drm_file_t * priv) } if (!count) { - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return 0; } fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); if (!fence) { - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return -ENOMEM; } ret = drm_fence_object_init(dev, fence_flags, 1, fence); if (ret) { drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return ret; } @@ -111,7 +111,7 @@ int drm_fence_buffer_objects(drm_file_t * priv) mutex_lock(&dev->struct_mutex); atomic_add(count - 1, &fence->usage); mutex_unlock(&dev->struct_mutex); - mutex_unlock(&bm->bm_mutex); + mutex_unlock(&bm->mutex); return 0; } @@ -179,11 +179,12 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_mm_put_block(&bm->vram_manager, bo->vram); bo->vram = NULL; } - - /* - * FIXME: Destroy ttm. - */ - + if (bo->ttm_region) { + drm_destroy_ttm_region(bo->ttm_region); + } + if (bo->ttm_object) { + drm_ttm_object_deref_locked(dev, bo->ttm_object); + } drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } @@ -356,8 +357,11 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, uo = drm_lookup_user_object(priv, handle); - if (!uo || (uo->type != drm_buffer_type)) + if (!uo || (uo->type != drm_buffer_type)) { + DRM_ERROR("Could not find buffer object 0x%08x\n", + handle); return NULL; + } if (check_owner && priv != uo->owner) { if (!drm_lookup_ref_object(priv, uo, _DRM_REF_USE)) @@ -541,9 +545,10 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, } } -static int drm_buffer_object_validate(drm_device_t * dev, +static int drm_buffer_object_validate(drm_device_t * dev, uint32_t new_flags, drm_buffer_object_t * bo) { + bo->flags = new_flags; return 0; } @@ -574,14 +579,18 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, mutex_lock(&dev->struct_mutex); to = drm_lookup_ttm_object(priv, ttm_handle, 1); mutex_unlock(&dev->struct_mutex); - if (!to) + if (!to) { + DRM_ERROR("Could not find TTM object\n"); ret = -EINVAL; + } break; case drm_bo_type_user: case drm_bo_type_fake: break; default: + DRM_ERROR("Illegal buffer object type\n"); ret = -EINVAL; + break; } if (ret) { @@ -656,7 +665,7 @@ int drm_buffer_object_create(drm_file_t * priv, bo->mask = mask; bo->hint = hint; - ret = drm_buffer_object_validate(dev, bo); + ret = drm_buffer_object_validate(dev, new_flags, bo); if (ret) goto out_err; @@ -805,3 +814,89 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return 0; } + +static void drm_bo_clean_mm(drm_file_t *priv) +{ +} + + +int drm_mm_init_ioctl(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + + int ret = 0; + drm_mm_init_arg_t arg; + drm_buffer_manager_t *bm = &dev->bm; + drm_bo_driver_t *driver = dev->driver->bo_driver; + + if (!driver) { + DRM_ERROR("Buffer objects is not supported by this driver\n"); + return -EINVAL; + } + + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + + switch(arg.req.op) { + case mm_init: + if (bm->initialized) { + DRM_ERROR("Memory manager already initialized\n"); + return -EINVAL; + } + mutex_init(&bm->mutex); + mutex_lock(&bm->mutex); + bm->has_vram = 0; + bm->has_tt = 0; + + if (arg.req.vr_p_size) { + ret = drm_mm_init(&bm->vram_manager, + arg.req.vr_p_offset, + arg.req.vr_p_size); + bm->has_vram = 1; + if (ret) + break; + } + + if (arg.req.tt_p_size) { + ret = drm_mm_init(&bm->tt_manager, + arg.req.tt_p_offset, + arg.req.tt_p_size); + bm->has_tt = 1; + if (ret) { + if (bm->has_vram) + drm_mm_takedown(&bm->vram_manager); + break; + } + } + arg.rep.mm_sarea = 0; + + INIT_LIST_HEAD(&bm->vram_lru); + INIT_LIST_HEAD(&bm->tt_lru); + INIT_LIST_HEAD(&bm->unfenced); + INIT_LIST_HEAD(&bm->ddestroy); + + bm->initialized = 1; + break; + case mm_takedown: + if (!bm->initialized) { + DRM_ERROR("Memory manager was not initialized\n"); + return -EINVAL; + } + mutex_lock(&bm->mutex); + drm_bo_clean_mm(priv); + if (bm->has_vram) + drm_mm_takedown(&bm->vram_manager); + if (bm->has_tt) + drm_mm_takedown(&bm->tt_manager); + bm->initialized = 0; + break; + default: + return -EINVAL; + } + + mutex_unlock(&bm->mutex); + if (ret) + return ret; + + DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); + return 0; +} diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index f27a7aff..62df6803 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -121,6 +121,9 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0}, [DRM_IOCTL_NR(DRM_IOCTL_FENCE)] = {drm_fence_ioctl, DRM_AUTH}, [DRM_IOCTL_NR(DRM_IOCTL_TTM)] = {drm_ttm_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_BUFOBJ)] = {drm_bo_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_IOCTL_MM_INIT)] = {drm_mm_init_ioctl, + DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}, }; #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index f6abfeb9..f900dd51 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -747,8 +747,26 @@ typedef union drm_bo_arg{ drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; } drm_bo_arg_t; + +typedef union drm_mm_init_arg{ + struct { + enum { + mm_init, + mm_takedown, + mm_query + } op; + drm_u64_t vr_p_offset; + drm_u64_t vr_p_size; + drm_u64_t tt_p_offset; + drm_u64_t tt_p_size; + } req; + struct { + drm_handle_t mm_sarea; + } rep; +} drm_mm_init_arg_t; #endif + /** * \name Ioctls Definitions */ @@ -818,6 +836,7 @@ typedef union drm_bo_arg{ #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) #define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) #define DRM_IOCTL_BUFOBJ DRM_IOWR(0x3d, drm_bo_arg_t) +#define DRM_IOCTL_MM_INIT DRM_IOWR(0x3e, drm_mm_init_arg_t) #endif /*@}*/ -- 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. --- libdrm/xf86drm.c | 103 ++++++++++++++++++++++++++++++++++++++++++++---- libdrm/xf86mm.h | 8 ++-- linux-core/drm_bo.c | 3 ++ linux-core/drm_object.c | 4 +- linux-core/drm_vm.c | 1 + 5 files changed, 104 insertions(+), 15 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index c9005c41..f592ff2a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2606,10 +2606,10 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, buf->flags = rep->flags; buf->size = rep->size; buf->offset = rep->offset; - buf->map_handle = rep->arg_handle; - buf->map_flags = rep->map_flags; - buf->map_virtual = NULL; - buf->map_count = 0; + buf->mapHandle = rep->arg_handle; + buf->mapFlags = rep->map_flags; + buf->mapVirtual = NULL; + buf->mapCount = 0; buf->virtual = NULL; buf->mask = rep->mask; buf->hint = rep->hint; @@ -2666,13 +2666,14 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) buf->flags = rep->flags; buf->size = rep->size; buf->offset = rep->offset; - buf->map_handle = rep->arg_handle; - buf->map_flags = rep->map_flags; - buf->map_virtual = NULL; - buf->map_count = 0; + buf->mapHandle = rep->arg_handle; + buf->mapFlags = rep->map_flags; + buf->mapVirtual = NULL; + buf->mapCount = 0; buf->virtual = NULL; buf->mask = rep->mask; buf->hint = rep->hint; + buf->start = rep->buffer_start; return 0; } @@ -2699,6 +2700,92 @@ int drmBOUnReference(int fd, drmBO *buf) return 0; } +/* + * + */ + +int drmBOMap(int fd, drmBO *buf, unsigned map_flags, void **address) +{ + + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + int ret = 0; + + /* + * Make sure we have a virtual address of the buffer. + */ + + if (!buf->mapVirtual) { + if (buf->mapCount == 0) { + drmAddress virtual; + ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); + if (ret) + return ret; + ++buf->mapCount; + buf->mapVirtual = virtual; + buf->virtual = ((char *) virtual) + buf->start; + fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", + buf->mapVirtual, buf->virtual); + } + } + + req->handle = buf->handle; + req->mask = map_flags; + req->op = drm_bo_map; + req->next = 0; + + /* + * May hang if the buffer object is busy. + * This IOCTL synchronizes the buffer. + */ + + do { + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret != 0 && errno == EAGAIN); + + if (ret || !rep->handled || rep->ret) { + if (--buf->mapCount == 0) { + (void )drmUnmap(buf->mapVirtual, buf->start + buf->size); + } + } + if (ret) + return ret; + if (!rep->handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + + *address = buf->virtual; + + return 0; +} + +int drmBOUnmap(int fd, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + + if (buf->mapCount == 0) { + return -EINVAL; + } + + if (--buf->mapCount == 0) { + (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); + } + + req->handle = buf->handle; + req->op = drm_bo_unmap; + req->next = 0; + + if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) { + return -errno; + } + + return 0; +} + + int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, unsigned long ttPOffset, unsigned long ttPSize) { diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 8711a144..c811892f 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -85,17 +85,17 @@ typedef struct _drmMMListHead typedef struct _drmBO{ drm_bo_type_t type; unsigned handle; - drm_handle_t map_handle; + drm_handle_t mapHandle; unsigned flags; unsigned mask; unsigned hint; - unsigned map_flags; + unsigned mapFlags; unsigned long size; unsigned long offset; unsigned long start; void *virtual; - void *map_virtual; - int map_count; + void *mapVirtual; + int mapCount; drmTTM *ttm; } drmBO; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 5f557d55..aa59238f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -513,8 +513,11 @@ static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) goto out; } + DRM_ERROR("Removing ref object\n"); drm_remove_ref_object(priv, ro); + DRM_ERROR("Deregistering usage\n"); drm_bo_usage_deref_locked(dev, bo); + DRM_ERROR("Done\n"); out: mutex_unlock(&dev->struct_mutex); return ret; diff --git a/linux-core/drm_object.c b/linux-core/drm_object.c index b928c01e..e1b79101 100644 --- a/linux-core/drm_object.c +++ b/linux-core/drm_object.c @@ -108,9 +108,6 @@ static int drm_object_ref_action(drm_file_t * priv, drm_user_object_t * ro, break; default: if (!ro->ref_struct_locked) { - DRM_ERROR("Register object called without register" - " capabilities\n"); - ret = -EINVAL; break; } else { ro->ref_struct_locked(priv, ro, action); @@ -164,6 +161,7 @@ int drm_add_ref_object(drm_file_t * priv, drm_user_object_t * referenced_object, atomic_set(&item->refcount, 1); item->hash.key = (unsigned long)referenced_object; ret = drm_ht_insert_item(ht, &item->hash); + item->unref_action = ref_action; if (ret) goto out; diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 7163341d..69391058 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -713,6 +713,7 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma) dev = ttm->dev; mutex_lock(&dev->struct_mutex); drm_ttm_delete_mm(ttm, vma->vm_mm); + list_del(&ttm_vma->head); drm_free(ttm_vma, sizeof(*ttm_vma), DRM_MEM_VMAS); if (atomic_dec_and_test(&ttm->vma_count)) { if (ttm->destroy) { -- cgit v1.2.3 From ff95ea5536d70f9bc8eac12f2c97dae71fb97066 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 30 Aug 2006 15:11:50 +0200 Subject: Add missing map flags. --- libdrm/xf86drm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index f592ff2a..6ffc4b39 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2704,7 +2704,7 @@ int drmBOUnReference(int fd, drmBO *buf) * */ -int drmBOMap(int fd, drmBO *buf, unsigned map_flags, void **address) +int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, void **address) { drm_bo_arg_t arg; @@ -2731,7 +2731,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned map_flags, void **address) } req->handle = buf->handle; - req->mask = map_flags; + req->hint = mapFlags; req->op = drm_bo_map; req->next = 0; @@ -2756,6 +2756,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned map_flags, void **address) if (rep->ret) return rep->ret; + buf->mapFlags = mapFlags; *address = buf->virtual; return 0; -- 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. --- libdrm/xf86drm.c | 2 - libdrm/xf86mm.h | 1 - linux-core/drmP.h | 1 - linux-core/drm_bo.c | 107 ++++++++++++++++++++++++++++++++++++++++++++------- linux-core/drm_drv.c | 2 +- shared-core/drm.h | 33 ++++++++++++---- 6 files changed, 120 insertions(+), 26 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6ffc4b39..1763b89a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2612,7 +2612,6 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, buf->mapCount = 0; buf->virtual = NULL; buf->mask = rep->mask; - buf->hint = rep->hint; buf->start = rep->buffer_start; return 0; @@ -2672,7 +2671,6 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) buf->mapCount = 0; buf->virtual = NULL; buf->mask = rep->mask; - buf->hint = rep->hint; buf->start = rep->buffer_start; return 0; } diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index c811892f..21fed6cf 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -88,7 +88,6 @@ typedef struct _drmBO{ drm_handle_t mapHandle; unsigned flags; unsigned mask; - unsigned hint; unsigned mapFlags; unsigned long size; unsigned long offset; diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 59926968..6cce6b8d 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -963,7 +963,6 @@ typedef struct drm_buffer_object{ uint32_t map_flags; uint32_t flags; uint32_t mask; - uint32_t hint; drm_mm_node_t *vram; drm_mm_node_t *tt; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index aa59238f..057de9a0 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -55,6 +55,17 @@ * 2.) Refer to ttm locking orders. */ + +#define DRM_FLAG_MASKED(_old, _new, _mask) {\ +(_old) ^= (((_old) ^ (_new)) & (_mask)); \ +} + +static inline uint32_t drm_flag_masked(uint32_t old, uint32_t new, + uint32_t mask) +{ + return old ^ ((old ^ new) & mask); +} + int drm_fence_buffer_objects(drm_file_t * priv) { drm_device_t *dev = priv->head->dev; @@ -243,7 +254,7 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, } } if (new_flags & DRM_BO_FLAG_MEM_TT) { - if ((hint & DRM_BO_HINT_PREFER_VRAM) && + if ((new_mask & DRM_BO_FLAG_PREFER_VRAM) && new_flags & DRM_BO_FLAG_MEM_VRAM) { new_flags = DRM_BO_FLAG_MEM_VRAM; } else { @@ -264,7 +275,7 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, new_flags |= new_mask & ~DRM_BO_MASK_MEM; - if (hint & DRM_BO_HINT_BIND_CACHED) { + if (new_mask & DRM_BO_FLAG_BIND_CACHED) { new_flags |= DRM_BO_FLAG_CACHED; if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || ((new_flags & DRM_BO_FLAG_MEM_VRAM) @@ -513,11 +524,8 @@ static int drm_buffer_object_unmap(drm_file_t * priv, uint32_t handle) goto out; } - DRM_ERROR("Removing ref object\n"); drm_remove_ref_object(priv, ro); - DRM_ERROR("Deregistering usage\n"); drm_bo_usage_deref_locked(dev, bo); - DRM_ERROR("Done\n"); out: mutex_unlock(&dev->struct_mutex); return ret; @@ -548,19 +556,91 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, } } -static int drm_buffer_object_validate(drm_device_t * dev, uint32_t new_flags, - drm_buffer_object_t * bo) +static int drm_bo_move_buffer(drm_buffer_object_t *bo, uint32_t new_flags, + int no_wait) { - bo->flags = new_flags; return 0; } + +/* + * bo locked. + */ + + +static int drm_buffer_object_validate(drm_buffer_object_t * bo, + uint32_t new_flags, + int move_unfenced, + int no_wait) +{ + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + uint32_t flag_diff = (new_flags ^ bo->flags); + + int ret; + + if (new_flags & DRM_BO_FLAG_MEM_VRAM) { + DRM_ERROR("Vram support not implemented yet\n"); + return -EINVAL; + } + if ((new_flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM)) && + (new_flags & DRM_BO_FLAG_CACHED)) { + DRM_ERROR("Cached binding not implemented yet\n"); + return -EINVAL; + } + + /* + * Check whether we need to move buffer. + */ + + if (flag_diff & DRM_BO_MASK_MEM) { + mutex_lock(&bm->mutex); + ret = drm_bo_move_buffer(bo, new_flags, no_wait); + mutex_unlock(&bm->mutex); + if (ret) + return ret; + } + + if (flag_diff & DRM_BO_FLAG_NO_EVICT) { + mutex_lock(&bm->mutex); + list_del_init(&bo->head); + if (!(new_flags & DRM_BO_FLAG_NO_EVICT)) { + if (new_flags & DRM_BO_FLAG_MEM_TT) { + list_add_tail(&bo->head, &bm->tt_lru); + } else { + list_add_tail(&bo->head, &bm->vram_lru); + } + } + mutex_unlock(&bm->mutex); + DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); + } + + if (move_unfenced) { + + /* + * Place on unfenced list. + */ + + mutex_lock(&bm->mutex); + list_del_init(&bo->head); + list_add_tail(&bo->head, &bm->unfenced); + mutex_unlock(&bm->mutex); + } + + /* + * FIXME: Remove below. + */ + + bo->flags = new_flags; + return 0; +} + /* * Call bo->mutex locked. */ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, - uint32_t hint, uint32_t ttm_handle) + uint32_t mask, uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; @@ -605,7 +685,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - hint & DRM_BO_HINT_BIND_CACHED, + mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -661,14 +741,14 @@ int drm_buffer_object_create(drm_file_t * priv, 1, &new_flags); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, new_flags, ttm_handle); + ret = drm_bo_add_ttm(priv, bo, mask, ttm_handle); if (ret) goto out_err; bo->mask = mask; - bo->hint = hint; - ret = drm_buffer_object_validate(dev, new_flags, bo); + ret = drm_buffer_object_validate(bo, new_flags, 0, + hint & DRM_BO_HINT_DONT_BLOCK); if (ret) goto out_err; @@ -719,7 +799,6 @@ static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, rep->map_flags = bo->map_flags; rep->mask = bo->mask; - rep->hint = bo->hint; rep->buffer_start = bo->buffer_start; } diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 62df6803..1bf87703 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -123,7 +123,7 @@ static drm_ioctl_desc_t drm_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_TTM)] = {drm_ttm_ioctl, DRM_AUTH}, [DRM_IOCTL_NR(DRM_IOCTL_BUFOBJ)] = {drm_bo_ioctl, DRM_AUTH}, [DRM_IOCTL_NR(DRM_IOCTL_MM_INIT)] = {drm_mm_init_ioctl, - DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}, + DRM_AUTH } }; #define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls ) diff --git a/shared-core/drm.h b/shared-core/drm.h index f900dd51..d992621b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -679,25 +679,45 @@ typedef struct drm_ttm_arg { }drm_ttm_arg_t; +/* Buffer permissions, referring to how the GPU uses the buffers. + these translate to fence types used for the buffers. + Typically a texture buffer is read, A destination buffer is write and + a command (batch-) buffer is exe. Can be or-ed together. */ + #define DRM_BO_FLAG_READ 0x00000001 #define DRM_BO_FLAG_WRITE 0x00000002 #define DRM_BO_FLAG_EXE 0x00000004 -#define DRM_BO_FLAG_NO_MOVE 0x00000008 + +/* Pinned buffer. */ #define DRM_BO_FLAG_NO_EVICT 0x00000010 +/* Always keep a system memory shadow to a vram buffer */ #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 +/* When mapped for reading, make sure the buffer is cached even + if it means moving the buffer to system memory */ #define DRM_BO_FLAG_READ_CACHED 0x00000040 +/* The buffer is currently cached */ #define DRM_BO_FLAG_CACHED 0x00000080 +/* The buffer is shareable with other processes */ #define DRM_BO_FLAG_SHAREABLE 0x00000100 +/* When there is a choice between VRAM and TT, prefer VRAM. + The default behaviour is to prefer TT. */ +#define DRM_BO_FLAG_PREFER_VRAM 0x00000200 +/* Bind this buffer cached if the hardware supports it. */ +#define DRM_BO_FLAG_BIND_CACHED 0x00000400 +/* Translation table aperture */ #define DRM_BO_FLAG_MEM_TT 0x01000000 +/* On-card VRAM */ #define DRM_BO_FLAG_MEM_VRAM 0x02000000 +/* System memory */ #define DRM_BO_FLAG_MEM_LOCAL 0x04000000 -#define DRM_BO_MASK_MEM 0xFFFFFFFF +/* Memory flag mask */ +#define DRM_BO_MASK_MEM 0xFF000000 -#define DRM_BO_HINT_PREFER_VRAM 0x00000001 -#define DRM_BO_HINT_AVOID_LOCAL 0x00000002 -#define DRM_BO_HINT_DONT_BLOCK 0x00000004 -#define DRM_BO_HINT_BIND_CACHED 0x00000008 +/* When creating a buffer, Avoid system storage even if allowed */ +#define DRM_BO_HINT_AVOID_LOCAL 0x00000001 +/* Don't block on validate and map */ +#define DRM_BO_HINT_DONT_BLOCK 0x00000002 typedef enum { drm_bo_type_ttm, @@ -738,7 +758,6 @@ typedef struct drm_bo_arg_reply { unsigned arg_handle; unsigned map_flags; unsigned mask; - unsigned hint; drm_u64_t buffer_start; }drm_bo_arg_reply_t; -- 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(-) 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(-) 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(-) 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. --- libdrm/xf86drm.c | 340 +++++++++++++++++++++++++++++++++++++++++++++------- libdrm/xf86mm.h | 2 + linux-core/drmP.h | 1 - linux-core/drm_bo.c | 163 ++++++++++++++++++------- shared-core/drm.h | 35 +++--- 5 files changed, 445 insertions(+), 96 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 1763b89a..a99c979d 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2501,7 +2501,9 @@ int drmResetList(drmBOList *list) { return drmAdjustListNodes(list); } -static int drmAddListItem(drmBOList *list, drmBO *item, drm_bo_arg_t *arg) +static drmBONode *drmAddListItem(drmBOList *list, drmBO *item, + unsigned long arg0, + unsigned long arg1) { drmBONode *node; drmMMListHead *l; @@ -2510,7 +2512,7 @@ static int drmAddListItem(drmBOList *list, drmBO *item, drm_bo_arg_t *arg) if (l == &list->free) { node = (drmBONode *) malloc(sizeof(*node)); if (!node) { - return -ENOMEM; + return NULL; } list->numCurrent++; } else { @@ -2518,45 +2520,51 @@ static int drmAddListItem(drmBOList *list, drmBO *item, drm_bo_arg_t *arg) node = DRMLISTENTRY(drmBONode, l, head); } node->buf = item; + node->arg0 = arg0; + node->arg1 = arg1; DRMLISTADD(&node->head, &list->list); list->numOnList++; - return 0; + return node; } -int drmCreateBufList(int numTarget, drmBOList *list) +void *drmBOListIterator(drmBOList *list) { - DRMINITLISTHEAD(&list->list); - DRMINITLISTHEAD(&list->free); - list->numTarget = numTarget; - list->numCurrent = 0; - list->numOnList = 0; - return drmAdjustListNodes(list); -} + void *ret = list->list.next; -/* - * Prepare list for IOCTL submission. - */ + if (ret == &list->list) + return NULL; + return ret; +} -static drm_bo_arg_t *drmPrepareList(drmBOList *list) +void *drmBOListNext(drmBOList *list, void *iterator) { - drmMMListHead *cur, *next; - drmBONode *first, *curNode, *nextNode; + void *ret; - cur = list->list.next; - if (cur == &list->list) + drmMMListHead *l = (drmMMListHead *) iterator; + ret = l->next; + if (ret == &list->list) return NULL; + return ret; +} - first = DRMLISTENTRY(drmBONode, cur, head); - curNode = DRMLISTENTRY(drmBONode, cur, head); +void drmBOListBuf(void *iterator, drmBO **buf) +{ + drmBONode *node; + drmMMListHead *l = (drmMMListHead *) iterator; + node = DRMLISTENTRY(drmBONode, l, head); + + *buf = node->buf; +} - for (next = cur->next; next != &list->list; - cur = next, next = cur->next) { - nextNode = DRMLISTENTRY(drmBONode, next, head); - curNode->bo_arg.req.next = ((unsigned long) &nextNode->bo_arg.req); - curNode = nextNode; - } - curNode->bo_arg.req.next = 0; - return &first->bo_arg; + +int drmCreateBufList(int numTarget, drmBOList *list) +{ + DRMINITLISTHEAD(&list->list); + DRMINITLISTHEAD(&list->free); + list->numTarget = numTarget; + list->numCurrent = 0; + list->numOnList = 0; + return drmAdjustListNodes(list); } int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, @@ -2567,6 +2575,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + arg.handled = 0; req->mask = mask; req->hint = hint; req->size = size; @@ -2595,7 +2604,8 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; - if (!rep->handled) { + if (!arg.handled) { + fprintf(stderr, "Not handled\n"); return -EFAULT; } if (rep->ret) { @@ -2607,7 +2617,6 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, buf->size = rep->size; buf->offset = rep->offset; buf->mapHandle = rep->arg_handle; - buf->mapFlags = rep->map_flags; buf->mapVirtual = NULL; buf->mapCount = 0; buf->virtual = NULL; @@ -2623,13 +2632,14 @@ int drmBODestroy(int fd, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_destroy; req->next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; - if (!rep->handled) { + if (!arg.handled) { return -EFAULT; } if (rep->ret) { @@ -2647,13 +2657,14 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + arg.handled = 0; req->handle = handle; req->op = drm_bo_reference; req->next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; - if (!rep->handled) { + if (!arg.handled) { return -EFAULT; } if (rep->ret) { @@ -2666,7 +2677,6 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) buf->size = rep->size; buf->offset = rep->offset; buf->mapHandle = rep->arg_handle; - buf->mapFlags = rep->map_flags; buf->mapVirtual = NULL; buf->mapCount = 0; buf->virtual = NULL; @@ -2681,13 +2691,14 @@ int drmBOUnReference(int fd, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unreference; req->next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; - if (!rep->handled) { + if (!arg.handled) { return -EFAULT; } if (rep->ret) { @@ -2699,10 +2710,13 @@ int drmBOUnReference(int fd, drmBO *buf) } /* - * + * Flags can be DRM_BO_FLAG_READ, DRM_BO_FLAG_WRITE or'ed together + * Hint currently be DRM_BO_HINT_DONT_BLOCK, which makes the + * call return an -EBUSY if it can' immediately honor the mapping request. */ -int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, void **address) +int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, + void **address) { drm_bo_arg_t arg; @@ -2714,6 +2728,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, void **address) * Make sure we have a virtual address of the buffer. */ + fprintf(stderr, "Address is 0x%08x\n", address); if (!buf->mapVirtual) { if (buf->mapCount == 0) { drmAddress virtual; @@ -2728,8 +2743,11 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, void **address) } } + fprintf(stderr, "Address is 0x%08x\n", address); + arg.handled = 0; req->handle = buf->handle; - req->hint = mapFlags; + req->mask = mapFlags; + req->hint = mapHint; req->op = drm_bo_map; req->next = 0; @@ -2738,23 +2756,26 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, void **address) * This IOCTL synchronizes the buffer. */ + fprintf(stderr, "Address is 0x%08x\n", address); do { ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); } while (ret != 0 && errno == EAGAIN); - if (ret || !rep->handled || rep->ret) { + fprintf(stderr, "Address is 0x%08x\n", address); + if (ret || !arg.handled || rep->ret) { if (--buf->mapCount == 0) { (void )drmUnmap(buf->mapVirtual, buf->start + buf->size); } } if (ret) return ret; - if (!rep->handled) + if (!arg.handled) return -EFAULT; if (rep->ret) return rep->ret; buf->mapFlags = mapFlags; + fprintf(stderr, "Address is 0x%08x\n", address); *address = buf->virtual; return 0; @@ -2764,6 +2785,7 @@ int drmBOUnmap(int fd, drmBO *buf) { drm_bo_arg_t arg; drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; if (buf->mapCount == 0) { return -EINVAL; @@ -2773,6 +2795,7 @@ int drmBOUnmap(int fd, drmBO *buf) (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); } + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unmap; req->next = 0; @@ -2780,10 +2803,247 @@ int drmBOUnmap(int fd, drmBO *buf) if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) { return -errno; } + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + + return 0; +} + +int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, + unsigned hint) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + int ret = 0; + + arg.handled = 0; + req->handle = buf->handle; + req->mask = flags; + req->hint = hint; + req->arg_handle = mask; /* Encode mask in the arg_handle field :/ */ + req->op = drm_bo_validate; + req->next = 0; + + do{ + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret && errno == -EAGAIN); + + if (ret) + return ret; + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + + buf->offset = rep->offset; + buf->flags = rep->flags; + buf->mask = rep->mask; + return 0; +} + + +int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + int ret = 0; + + arg.handled = 0; + req->handle = buf->handle; + req->mask = flags; + req->arg_handle = fenceHandle; + req->op = drm_bo_validate; + req->next = 0; + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + + if (ret) + return ret; + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; return 0; } + + +int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, + unsigned mask, + int *newItem) +{ + drmBONode *node, *cur; + unsigned oldFlags, newFlags; + drmMMListHead *l; + + *newItem = 0; + cur = NULL; + + mask &= ~DRM_BO_MASK_MEM; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + if (node->buf == buf) { + cur = node; + break; + } + } + if (!cur) { + cur = drmAddListItem(list, buf, flags, mask); + if (!cur) { + drmMsg("Out of memory creating validate list node.\n"); + return -ENOMEM; + } + *newItem = 1; + cur->arg0 = flags; + cur->arg1 = mask; + } else { + unsigned memFlags = cur->arg0 & DRM_BO_MASK_MEM; + + if (!(memFlags & flags)) { + drmMsg("Incompatible memory location requests " + "on validate list.\n"); + return -EINVAL; + } + if ((cur->arg1 | mask) & (cur->arg0 ^ flags)) { + drmMsg("Incompatible buffer flag requests " + " on validate list.\n"); + return -EINVAL; + } + cur->arg1 |= mask; + cur->arg0 = (memFlags & flags) | ((cur->arg0 | flags) & cur->arg1); + } +} + + +int drmBOValidateList(int fd, drmBOList *list) +{ + + drmBONode *node; + drmMMListHead *l; + drm_bo_arg_t *arg, *first; + drm_bo_arg_request_t *req; + drm_bo_arg_reply_t *rep; + drm_u64_t *prevNext = NULL; + drmBO *buf; + int ret; + + first = NULL; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + + arg = &node->bo_arg; + req = &arg->req; + + if (!first) + first = arg; + + if (prevNext) + *prevNext = (unsigned long) arg; + + req->next = 0; + prevNext = &req->next; + arg->handled = 0; + req->handle = node->buf->handle; + req->op = drm_bo_validate; + req->mask = node->arg0; + req->hint = 0; + req->arg_handle = node->arg1; + } + + if (!first) + return 0; + + do{ + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret && errno == -EAGAIN); + + if (ret) + return -errno; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + + arg = &node->bo_arg; + rep = &arg->rep; + + if (!arg->handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + + buf = node->buf; + buf->offset = rep->offset; + buf->flags = rep->flags; + buf->mask = rep->mask; + } + + return 0; +} + + +int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) +{ + + drmBONode *node; + drmMMListHead *l; + drm_bo_arg_t *arg, *first; + drm_bo_arg_request_t *req; + drm_bo_arg_reply_t *rep; + drm_u64_t *prevNext = NULL; + drmBO *buf; + int ret; + + first = NULL; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + + arg = &node->bo_arg; + req = &arg->req; + + if (!first) + first = arg; + + if (prevNext) + *prevNext = (unsigned long) arg; + + req->next = 0; + prevNext = &req->next; + arg->handled = 0; + req->handle = node->buf->handle; + req->op = drm_bo_fence; + req->mask = node->arg0; + req->arg_handle = fenceHandle; + } + + if (!first) + return 0; + + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + + if (ret) + return -errno; + + for (l = list->list.next; l != &list->list; l = l->next) { + node = DRMLISTENTRY(drmBONode, l, head); + + arg = &node->bo_arg; + rep = &arg->rep; + + if (!arg->handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + } + + return 0; +} int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, unsigned long ttPOffset, unsigned long ttPSize) diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 21fed6cf..aaee3c0b 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -103,6 +103,8 @@ typedef struct _drmBONode { drmMMListHead head; drmBO *buf; drm_bo_arg_t bo_arg; + unsigned long arg0; + unsigned long arg1; } drmBONode; typedef struct _drmBOList { diff --git a/linux-core/drmP.h b/linux-core/drmP.h index bbf9da0b..fde89c30 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -966,7 +966,6 @@ typedef struct drm_buffer_object{ unsigned long offset; atomic_t mapped; - uint32_t map_flags; uint32_t flags; uint32_t mask; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index faa2e007..232120a4 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -256,11 +256,11 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) int ret = 0; /* - * Someone might have taken out the buffer before we took the buffer mutex. + * Someone might have modified the buffer before we took the buffer mutex. */ mutex_lock(&bo->mutex); - if (bo->unfenced) + if (bo->unfenced || (bo->flags & DRM_BO_FLAG_NO_EVICT)) goto out; if (tt && !bo->tt) goto out; @@ -371,17 +371,46 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, - int init, uint32_t * n_flags) + int init, uint32_t * n_flags, + uint32_t *n_mask) { - uint32_t new_flags; + uint32_t new_flags = 0; uint32_t new_props; - if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { + /* + * First adjust the mask. Vram is not supported yet. + */ - /* - * We need to move memory. Default preferences are hard-coded - * here. - */ + new_mask &= ~DRM_BO_FLAG_MEM_VRAM; + + if (new_mask & DRM_BO_FLAG_BIND_CACHED) { + if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && + ((new_mask & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) { + new_mask &= ~DRM_BO_FLAG_BIND_CACHED; + } else { + if (!driver->cached_tt) + new_flags &= DRM_BO_FLAG_MEM_TT; + if (!driver->cached_vram) + new_flags &= DRM_BO_FLAG_MEM_VRAM; + } + } + + if ((new_mask & DRM_BO_FLAG_READ_CACHED) && + !(new_mask & DRM_BO_FLAG_BIND_CACHED)) { + if ((new_mask & DRM_BO_FLAG_NO_EVICT) && + !(new_mask & DRM_BO_FLAG_MEM_LOCAL)) { + DRM_ERROR("Cannot read cached from a pinned VRAM / TT buffer\n"); + return -EINVAL; + } + new_mask &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM); + } + + /* + * Determine new memory location: + */ + + + if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { new_flags = new_mask & DRM_BO_MASK_MEM; @@ -421,17 +450,10 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, new_flags |= new_mask & ~DRM_BO_MASK_MEM; - if (new_mask & DRM_BO_FLAG_BIND_CACHED) { - new_flags |= DRM_BO_FLAG_CACHED; - if (((new_flags & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) || - ((new_flags & DRM_BO_FLAG_MEM_VRAM) - && !driver->cached_vram)) - new_flags &= ~DRM_BO_FLAG_CACHED; - } - - if ((new_flags & DRM_BO_FLAG_NO_EVICT) && - ((flags ^ new_flags) & DRM_BO_FLAG_CACHED)) { - if (flags & DRM_BO_FLAG_CACHED) { + if (((flags ^ new_flags) & DRM_BO_FLAG_BIND_CACHED) && + (new_flags & DRM_BO_FLAG_NO_EVICT) && + (flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM))) { + if (!(flags & DRM_BO_FLAG_CACHED)) { DRM_ERROR ("Cannot change caching policy of pinned buffer\n"); return -EINVAL; @@ -441,6 +463,7 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, } *n_flags = new_flags; + *n_mask = new_mask; return 0; } @@ -498,6 +521,12 @@ static int drm_bo_busy(drm_buffer_object_t * bo) return 0; } + +static int drm_bo_read_cached(drm_buffer_object_t *bo) { + return 0; +} + + /* * Wait for buffer idle and register that we've mapped the buffer. * Mapping is registered as a drm_ref_object with type _DRM_REF_TYPE1, @@ -505,11 +534,12 @@ static int drm_bo_busy(drm_buffer_object_t * bo) * unregistered. */ -static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) +static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, + uint32_t map_flags, int no_wait) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; - int ret; + int ret = 0; mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); @@ -526,14 +556,46 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, int wait) * be done without the bo->mutex held. */ - if (atomic_inc_and_test(&bo->mapped)) { - ret = drm_bo_wait(bo, 0, !wait); - if (ret) { - atomic_dec(&bo->mapped); - goto out; + while(1) { + if (atomic_inc_and_test(&bo->mapped)) { + ret = drm_bo_wait(bo, 0, no_wait); + if (ret) { + atomic_dec(&bo->mapped); + goto out; + } + + if ((map_flags & DRM_BO_FLAG_READ) && + (bo->flags & DRM_BO_FLAG_READ_CACHED) && + (!(bo->flags & DRM_BO_FLAG_CACHED))) { + + drm_bo_read_cached(bo); + } + break; + } else { + if ((map_flags & DRM_BO_FLAG_READ) && + (bo->flags & DRM_BO_FLAG_READ_CACHED) && + (!(bo->flags & DRM_BO_FLAG_CACHED))) { + + /* + * We are already mapped with different flags. + * need to wait for unmap. + */ + + if (no_wait) { + ret = -EBUSY; + goto out; + } + DRM_WAIT_ON(ret, bo->validate_queue, 3 * DRM_HZ, + atomic_read(&bo->mapped) == -1); + if (ret == -EINTR) + ret = -EAGAIN; + if (ret) + goto out; + continue; + } } } - + mutex_lock(&dev->struct_mutex); ret = drm_add_ref_object(priv, &bo->base, _DRM_REF_TYPE1); mutex_unlock(&dev->struct_mutex); @@ -729,7 +791,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, */ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, - uint32_t mask, uint32_t ttm_handle) + uint32_t ttm_handle) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; @@ -774,7 +836,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, bo->num_pages, - mask & DRM_BO_FLAG_BIND_CACHED, + bo->mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -827,17 +889,19 @@ int drm_buffer_object_create(drm_file_t * priv, bo->buffer_start = buffer_start; ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, - 1, &new_flags); + 1, &new_flags, &bo->mask); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, mask, ttm_handle); + ret = drm_bo_add_ttm(priv, bo, ttm_handle); if (ret) goto out_err; - bo->mask = mask; - +#if 0 ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); +#else + bo->flags = new_flags; +#endif if (ret) goto out_err; @@ -886,7 +950,6 @@ static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, rep->arg_handle = 0; } - rep->map_flags = bo->map_flags; rep->mask = bo->mask; rep->buffer_start = bo->buffer_start; } @@ -902,9 +965,15 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) drm_buffer_object_t *entry; do { - DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); + DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, + sizeof(arg)); + + if (arg.handled) { + data = req->next; + continue; + } + rep.ret = 0; - rep.handled = 0; switch (req->op) { case drm_bo_create:{ unsigned long buffer_start = req->buffer_start; @@ -937,8 +1006,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, - !(req->hint & - DRM_BO_HINT_DONT_BLOCK)); + req->mask, + req->hint & + DRM_BO_HINT_DONT_BLOCK); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -976,16 +1046,25 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = -EINVAL; } next = req->next; - rep.handled = 1; + + /* + * A signal interrupted us. Make sure the ioctl is restartable. + */ + + if (rep.ret == -EAGAIN) + return -EAGAIN; + + arg.handled = 1; arg.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); data = next; } while (data); return 0; - } + + static void drm_bo_clean_mm(drm_file_t * priv) { } @@ -1008,10 +1087,12 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) switch (arg.req.op) { case mm_init: +#if 0 if (bm->initialized) { DRM_ERROR("Memory manager already initialized\n"); return -EINVAL; } +#endif mutex_init(&bm->mutex); mutex_lock(&bm->mutex); bm->has_vram = 0; diff --git a/shared-core/drm.h b/shared-core/drm.h index d992621b..9640855c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -688,22 +688,28 @@ typedef struct drm_ttm_arg { #define DRM_BO_FLAG_WRITE 0x00000002 #define DRM_BO_FLAG_EXE 0x00000004 +/* + * Status flags. Can be read to determine the actual state of a buffer. + */ + /* Pinned buffer. */ -#define DRM_BO_FLAG_NO_EVICT 0x00000010 +#define DRM_BO_FLAG_NO_EVICT 0x00000001 /* Always keep a system memory shadow to a vram buffer */ -#define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 +#define DRM_BO_FLAG_SHADOW_VRAM 0x00000002 /* When mapped for reading, make sure the buffer is cached even if it means moving the buffer to system memory */ -#define DRM_BO_FLAG_READ_CACHED 0x00000040 -/* The buffer is currently cached */ -#define DRM_BO_FLAG_CACHED 0x00000080 -/* The buffer is shareable with other processes */ -#define DRM_BO_FLAG_SHAREABLE 0x00000100 +#define DRM_BO_FLAG_SHAREABLE 0x00000004 /* When there is a choice between VRAM and TT, prefer VRAM. The default behaviour is to prefer TT. */ -#define DRM_BO_FLAG_PREFER_VRAM 0x00000200 +#define DRM_BO_FLAG_CACHED 0x00000008 +/* The buffer is shareable with other processes */ + + +#define DRM_BO_FLAG_READ_CACHED 0x00001000 +/* The buffer is currently cached */ +#define DRM_BO_FLAG_PREFER_VRAM 0x00002000 /* Bind this buffer cached if the hardware supports it. */ -#define DRM_BO_FLAG_BIND_CACHED 0x00000400 +#define DRM_BO_FLAG_BIND_CACHED 0x00004000 /* Translation table aperture */ #define DRM_BO_FLAG_MEM_TT 0x01000000 @@ -750,21 +756,22 @@ typedef struct drm_bo_arg_request { typedef struct drm_bo_arg_reply { int ret; - int handled; unsigned handle; unsigned flags; drm_u64_t size; drm_u64_t offset; unsigned arg_handle; - unsigned map_flags; unsigned mask; drm_u64_t buffer_start; }drm_bo_arg_reply_t; -typedef union drm_bo_arg{ - drm_bo_arg_request_t req; - drm_bo_arg_reply_t rep; +typedef struct drm_bo_arg{ + int handled; + union { + drm_bo_arg_request_t req; + drm_bo_arg_reply_t rep; + }; } drm_bo_arg_t; typedef union drm_mm_init_arg{ -- 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(-) 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 + shared-core/drm.h | 14 +- shared-core/i915_dma.c | 23 ++ shared-core/i915_drv.h | 9 + 8 files changed, 462 insertions(+), 195 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 01e3c66f..5242b287 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -656,6 +656,8 @@ typedef struct drm_bo_driver{ int cached_vram; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev, int cached); + int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type); + int (*invalidate_caches)(struct drm_device *dev, uint32_t flags); } drm_bo_driver_t; @@ -783,7 +785,9 @@ typedef struct drm_buffer_manager{ struct list_head vram_lru; struct list_head unfenced; struct list_head ddestroy; + struct list_head other; struct timer_list timer; + uint32_t fence_flags; } drm_buffer_manager_t; @@ -975,12 +979,15 @@ typedef struct drm_buffer_object{ struct list_head ddestroy; uint32_t fence_flags; + uint32_t fence_class; drm_fence_object_t *fence; - int unfenced; - wait_queue_head_t validate_queue; + uint32_t priv_flags; + wait_queue_head_t event_queue; struct mutex mutex; } drm_buffer_object_t; +#define _DRM_BO_FLAG_UNFENCED 0x00000001 +#define _DRM_BO_FLAG_EVICTED 0x00000002 static __inline__ int drm_core_check_feature(struct drm_device *dev, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e2513267..8bca2e32 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -59,65 +59,6 @@ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } - -int drm_fence_buffer_objects(drm_file_t * priv) -{ - drm_device_t *dev = priv->head->dev; - drm_buffer_manager_t *bm = &dev->bm; - - drm_buffer_object_t *entry, *next; - uint32_t fence_flags = 0; - int count = 0; - drm_fence_object_t *fence; - int ret; - - mutex_lock(&dev->struct_mutex); - - list_for_each_entry(entry, &bm->unfenced, head) { - BUG_ON(!entry->unfenced); - fence_flags |= entry->fence_flags; - count++; - } - - if (!count) { - mutex_unlock(&dev->struct_mutex); - return 0; - } - - fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); - - if (!fence) { - mutex_unlock(&dev->struct_mutex); - return -ENOMEM; - } - - ret = drm_fence_object_init(dev, fence_flags, 1, fence); - if (ret) { - drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); - mutex_unlock(&dev->struct_mutex); - return ret; - } - - list_for_each_entry_safe(entry, next, &bm->unfenced, head) { - BUG_ON(entry->fence); - entry->unfenced = 0; - entry->fence = fence; - list_del_init(&entry->head); - - if (!(entry->flags & DRM_BO_FLAG_NO_EVICT)) { - if (entry->flags & DRM_BO_FLAG_MEM_TT) { - list_add_tail(&entry->head, &bm->tt_lru); - } else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) { - list_add_tail(&entry->head, &bm->vram_lru); - } - } - } - - atomic_add(count - 1, &fence->usage); - mutex_unlock(&dev->struct_mutex); - return 0; -} - /* * bo locked. */ @@ -135,11 +76,12 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) buf->tt = NULL; mutex_unlock(&dev->struct_mutex); + buf->flags &= ~DRM_BO_MASK_MEM; + buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + return 0; } - - /* * Lock dev->struct_mutex */ @@ -149,6 +91,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); @@ -158,7 +101,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) bm->timer.expires = jiffies + 1; add_timer(&bm->timer); } - + return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -170,7 +113,8 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * Take away from lru lists. */ - list_del_init(&bo->head); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); if (bo->tt) { int ret; @@ -190,10 +134,10 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } -static void drm_bo_delayed_delete(drm_device_t *dev) +static void drm_bo_delayed_delete(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; - + drm_buffer_object_t *entry, *next; drm_fence_object_t *fence; @@ -202,7 +146,7 @@ static void drm_bo_delayed_delete(drm_device_t *dev) list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { fence = entry->fence; - if (fence && drm_fence_object_signaled(fence, + if (fence && drm_fence_object_signaled(fence, entry->fence_flags)) { drm_fence_usage_deref_locked(dev, fence); entry->fence = NULL; @@ -217,13 +161,11 @@ static void drm_bo_delayed_delete(drm_device_t *dev) mutex_unlock(&dev->struct_mutex); } - -static void -drm_bo_delayed_timer(unsigned long data) +static void drm_bo_delayed_timer(unsigned long data) { - drm_device_t *dev = (drm_device_t *)data; + drm_device_t *dev = (drm_device_t *) data; drm_buffer_manager_t *bm = &dev->bm; - + drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy) && !timer_pending(&bm->timer)) { @@ -233,7 +175,6 @@ drm_bo_delayed_timer(unsigned long data) mutex_unlock(&dev->struct_mutex); } - void drm_bo_usage_deref_locked(drm_device_t * dev, drm_buffer_object_t * bo) { if (atomic_dec_and_test(&bo->usage)) { @@ -258,6 +199,103 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } +int drm_fence_buffer_objects(drm_file_t * priv, + struct list_head *list, + drm_fence_object_t *fence) +{ + drm_device_t *dev = priv->head->dev; + drm_buffer_manager_t *bm = &dev->bm; + + drm_buffer_object_t *entry; + uint32_t fence_flags = 0; + int count = 0; + int ret = 0; + struct list_head f_list, *l; + + mutex_lock(&dev->struct_mutex); + + list_for_each_entry(entry, list, head) { + BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); + fence_flags |= entry->fence_flags; + count++; + } + + if (!count) + goto out; + + if (fence) { + if ((fence_flags & fence->type) != fence_flags) { + DRM_ERROR("Given fence doesn't match buffers " + "on unfenced list.\n"); + ret = -EINVAL; + goto out; + } + } else { + fence = drm_calloc(1, sizeof(*fence), DRM_MEM_FENCE); + + if (!fence) { + ret = -ENOMEM; + goto out; + } + + ret = drm_fence_object_init(dev, fence_flags, 1, fence); + + if (ret) { + drm_free(fence, sizeof(*fence), DRM_MEM_FENCE); + goto out; + } + } + + /* + * Transfer to a private list before we release the dev->struct_mutex; + * This is so we don't get any new unfenced objects while fencing + * these. + */ + + f_list = *list; + INIT_LIST_HEAD(list); + + count = 0; + l = f_list.next; + while(l != &f_list) { + entry = list_entry(l, drm_buffer_object_t, head); + atomic_inc(&entry->usage); + mutex_unlock(&dev->struct_mutex); + mutex_lock(&entry->mutex); + mutex_lock(&dev->struct_mutex); + + if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { + count++; + if (entry->fence) + drm_fence_usage_deref_locked(dev, entry->fence); + entry->fence = fence; + DRM_FLAG_MASKED(entry->priv_flags, 0, + _DRM_BO_FLAG_UNFENCED); + DRM_WAKEUP(&entry->event_queue); + list_del_init(&entry->head); + if (entry->flags & DRM_BO_FLAG_NO_EVICT) + list_add_tail(&entry->head, &bm->other); + else if (entry->flags & DRM_BO_FLAG_MEM_TT) + list_add_tail(&entry->head, &bm->tt_lru); + else if (entry->flags & DRM_BO_FLAG_MEM_VRAM) + list_add_tail(&entry->head, &bm->vram_lru); + else + list_add_tail(&entry->head, &bm->other); + } + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_locked(dev, entry); + l = f_list.next; + } + if (!count) + drm_fence_usage_deref_locked(dev, fence); + else if (count > 1) + atomic_add(count - 1, &fence->usage); + out: + mutex_unlock(&dev->struct_mutex); + return ret; +} + + /* * Call bo->mutex locked. * Wait until the buffer is idle. @@ -269,6 +307,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) drm_fence_object_t *fence = bo->fence; int ret; + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -299,13 +338,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) { int ret = 0; - + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; /* * Someone might have modified the buffer before we took the buffer mutex. */ mutex_lock(&bo->mutex); - if (bo->unfenced || (bo->flags & DRM_BO_FLAG_NO_EVICT)) + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) + || (bo->flags & DRM_BO_FLAG_NO_EVICT)) goto out; if (tt && !bo->tt) goto out; @@ -324,6 +365,12 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) ret = drm_move_vram_to_local(bo); } #endif + mutex_lock(&dev->struct_mutex); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, + _DRM_BO_FLAG_EVICTED); out: mutex_unlock(&bo->mutex); return ret; @@ -356,11 +403,6 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) bo = list_entry(lru->next, drm_buffer_object_t, head); - /* - * No need to take dev->struct_mutex here, because bo->usage is at least 1 already, - * since it's on the lru list, and the dev->struct_mutex is held. - */ - atomic_inc(&bo->usage); mutex_unlock(&dev->struct_mutex); ret = drm_bo_evict(bo, tt, no_wait); @@ -407,13 +449,26 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) drm_mm_put_block(&bm->tt_manager, bo->tt); } mutex_unlock(&dev->struct_mutex); - return ret; + if (ret) + return ret; + + if (bo->ttm_region->be->needs_cache_adjust(bo->ttm_region->be)) + bo->flags &= ~DRM_BO_FLAG_CACHED; + bo->flags &= ~DRM_BO_MASK_MEM; + bo->flags |= DRM_BO_FLAG_MEM_TT; + + if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { + ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); + DRM_ERROR("Warning: Could not flush read caches\n"); + } + + return 0; } static int drm_bo_new_flags(drm_bo_driver_t * driver, uint32_t flags, uint32_t new_mask, uint32_t hint, - int init, uint32_t * n_flags, - uint32_t *n_mask) + int init, uint32_t * n_flags, uint32_t * n_mask) { uint32_t new_flags = 0; uint32_t new_props; @@ -426,21 +481,23 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, if (new_mask & DRM_BO_FLAG_BIND_CACHED) { if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached_tt) && - ((new_mask & DRM_BO_FLAG_MEM_VRAM) && !driver->cached_vram)) { + ((new_mask & DRM_BO_FLAG_MEM_VRAM) + && !driver->cached_vram)) { new_mask &= ~DRM_BO_FLAG_BIND_CACHED; } else { - if (!driver->cached_tt) + if (!driver->cached_tt) new_flags &= DRM_BO_FLAG_MEM_TT; - if (!driver->cached_vram) + if (!driver->cached_vram) new_flags &= DRM_BO_FLAG_MEM_VRAM; } } - - if ((new_mask & DRM_BO_FLAG_READ_CACHED) && + + if ((new_mask & DRM_BO_FLAG_READ_CACHED) && !(new_mask & DRM_BO_FLAG_BIND_CACHED)) { - if ((new_mask & DRM_BO_FLAG_NO_EVICT) && + if ((new_mask & DRM_BO_FLAG_NO_EVICT) && !(new_mask & DRM_BO_FLAG_MEM_LOCAL)) { - DRM_ERROR("Cannot read cached from a pinned VRAM / TT buffer\n"); + DRM_ERROR + ("Cannot read cached from a pinned VRAM / TT buffer\n"); return -EINVAL; } new_mask &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM); @@ -449,7 +506,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, /* * Determine new memory location: */ - if (!(flags & new_mask & DRM_BO_MASK_MEM) || init) { @@ -544,6 +600,7 @@ static int drm_bo_busy(drm_buffer_object_t * bo) { drm_fence_object_t *fence = bo->fence; + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -562,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); } + diff --git a/shared-core/drm.h b/shared-core/drm.h index 9640855c..f76fd86f 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -723,7 +723,15 @@ typedef struct drm_ttm_arg { /* When creating a buffer, Avoid system storage even if allowed */ #define DRM_BO_HINT_AVOID_LOCAL 0x00000001 /* Don't block on validate and map */ -#define DRM_BO_HINT_DONT_BLOCK 0x00000002 +#define DRM_BO_HINT_DONT_BLOCK 0x00000002 +/* Don't place this buffer on the unfenced list.*/ +#define DRM_BO_HINT_DONT_FENCE 0x00000004 + + + + +/* Driver specific flags. Could be for example rendering engine */ +#define DRM_BO_MASK_DRIVER 0x00F00000 typedef enum { drm_bo_type_ttm, @@ -779,7 +787,9 @@ typedef union drm_mm_init_arg{ enum { mm_init, mm_takedown, - mm_query + mm_query, + mm_lock, + mm_unlock } op; drm_u64_t vr_p_offset; drm_u64_t vr_p_size; diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index e661269b..baeab383 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -444,6 +444,28 @@ static void i915_emit_breadcrumb(drm_device_t *dev) #endif } + +int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + uint32_t flush_cmd = CMD_MI_FLUSH; + RING_LOCALS; + + flush_cmd |= flush; + + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(4); + OUT_RING(flush_cmd); + OUT_RING(0); + OUT_RING(0); + OUT_RING(0); + ADVANCE_LP_RING(); + + return 0; +} + + static int i915_dispatch_cmdbuffer(drm_device_t * dev, drm_i915_cmdbuffer_t * cmd) { @@ -680,6 +702,7 @@ static int i915_flip_bufs(DRM_IOCTL_ARGS) return i915_dispatch_flip(dev); } + static int i915_getparam(DRM_IOCTL_ARGS) { DRM_DEVICE; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 403124c9..8bf82ed8 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -124,6 +124,8 @@ extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp); extern int i915_driver_device_is_agp(drm_device_t * dev); extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +extern int i915_emit_mi_flush(drm_device_t *dev, uint32_t flush); + /* i915_irq.c */ extern int i915_irq_emit(DRM_IOCTL_ARGS); @@ -158,6 +160,8 @@ extern void i915_sync_flush(drm_device_t *dev); /* i915_buffer.c */ extern drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, int cached); +extern int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type); +extern int i915_invalidate_caches(drm_device_t *dev, uint32_t buffer_flags); #endif #define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg)) @@ -209,6 +213,11 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define INST_OP_FLUSH 0x02000000 #define INST_FLUSH_MAP_CACHE 0x00000001 +#define CMD_MI_FLUSH (0x04 << 23) +#define MI_NO_WRITE_FLUSH (1 << 2) +#define MI_READ_FLUSH (1 << 0) +#define MI_EXE_FLUSH (1 << 1) + #define BB1_START_ADDR_MASK (~0x7) #define BB1_PROTECTED (1<<0) #define BB1_UNPROTECTED (0<<0) -- 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. --- libdrm/xf86drm.c | 4 ++-- linux-core/drm_bo.c | 47 ++++++++++++++++++++++++++++++++--------------- linux-core/drm_ttm.c | 1 + linux-core/i915_buffer.c | 4 ++-- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a99c979d..41ad89cb 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3053,8 +3053,8 @@ int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, arg.req.op = mm_init; arg.req.vr_p_offset = vramPOffset; arg.req.vr_p_size = vramPSize; - arg.req.tt_p_offset = vramPOffset; - arg.req.tt_p_size = vramPSize; + arg.req.tt_p_offset = ttPOffset; + arg.req.tt_p_size = ttPSize; if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) return -errno; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 8bca2e32..dcbf2d91 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -70,14 +70,15 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); + DRM_ERROR("Flipping out of AGP\n"); mutex_lock(&dev->struct_mutex); drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; - mutex_unlock(&dev->struct_mutex); buf->flags &= ~DRM_BO_MASK_MEM; buf->flags |= DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + mutex_unlock(&dev->struct_mutex); return 0; } @@ -114,12 +115,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) */ list_del(&bo->head); - list_add_tail(&bo->head, &bm->other); if (bo->tt) { - int ret; - ret = drm_move_tt_to_local(bo); - BUG_ON(ret); + drm_unbind_ttm_region(bo->ttm_region); + drm_mm_put_block(&bm->tt_manager, bo->tt); + bo->tt = NULL; } if (bo->vram) { drm_mm_put_block(&bm->vram_manager, bo->vram); @@ -443,6 +443,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; + DRM_ERROR("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); if (ret) { @@ -458,10 +459,11 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) bo->flags |= DRM_BO_FLAG_MEM_TT; if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { + DRM_ERROR("Flush read caches\n"); ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); DRM_ERROR("Warning: Could not flush read caches\n"); } + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); return 0; } @@ -500,7 +502,6 @@ static int drm_bo_new_flags(drm_bo_driver_t * driver, ("Cannot read cached from a pinned VRAM / TT buffer\n"); return -EINVAL; } - new_mask &= ~(DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM); } /* @@ -621,10 +622,19 @@ static int drm_bo_busy(drm_buffer_object_t * bo) static int drm_bo_read_cached(drm_buffer_object_t * bo) { + drm_device_t *dev = bo->dev; + drm_buffer_manager_t *bm = &dev->bm; + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - return 0; + + mutex_lock(&dev->struct_mutex); + list_del(&bo->head); + list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); + return drm_move_tt_to_local(bo); } /* @@ -836,7 +846,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, } /* - * bo->mutex locked. + * bo->mutex locked. */ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, @@ -847,13 +857,14 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, /* * Flush outstanding fences. */ - + DRM_ERROR("Flushing fences\n"); drm_bo_busy(bo); /* * Make sure we're not mapped. */ + DRM_ERROR("Wait unmapped\n"); ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) return ret; @@ -862,6 +873,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ + DRM_ERROR("Wait fences\n"); ret = drm_bo_wait(bo, 0, no_wait); if (ret == -EINTR) @@ -909,16 +921,16 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Check whether we need to move buffer. */ - ret = driver->fence_type(new_flags, &bo->fence_flags, &bo->fence_class); + ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); + DRM_ERROR("Fence type = 0x%08x\n", bo->fence_flags); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } if (flag_diff & DRM_BO_MASK_MEM) { - mutex_lock(&dev->struct_mutex); + DRM_ERROR("Calling move buffer\n"); ret = drm_bo_move_buffer(bo, new_flags, no_wait); - mutex_unlock(&dev->struct_mutex); if (ret) return ret; } @@ -946,6 +958,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, list_add_tail(&bo->head, &bm->vram_lru); else list_add_tail(&bo->head, &bm->other); + mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } @@ -1098,9 +1111,10 @@ int drm_buffer_object_create(drm_file_t * priv, bo->num_pages = num_pages; bo->buffer_start = buffer_start; bo->priv_flags = 0; - + bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; ret = drm_bo_new_flags(dev->driver->bo_driver, bo->flags, mask, hint, 1, &new_flags, &bo->mask); + DRM_ERROR("New flags: 0x%08x\n", new_flags); if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, ttm_handle); @@ -1309,7 +1323,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) drm_bo_driver_t *driver = dev->driver->bo_driver; if (!driver) { - DRM_ERROR("Buffer objects are not sutt_manager, arg.req.tt_p_offset, arg.req.tt_p_size); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 33567d9b..97e3e96d 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -447,6 +447,7 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); } + DRM_ERROR("Unbinding\n"); be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index ecc6cf8d..598f8772 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -45,9 +45,9 @@ int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) { *class = 0; if (buffer_flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE)) - *type = 1; - else *type = 3; + else + *type = 1; return 0; } -- 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(-) 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. --- libdrm/xf86drm.c | 84 ++++++++++++++++++++++++++++---------- libdrm/xf86mm.h | 2 + linux-core/drm_bo.c | 115 ++++++++++++++++++++++++++++++++++++++++------------ shared-core/drm.h | 12 +++++- 4 files changed, 164 insertions(+), 49 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 41ad89cb..aa1a5998 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2567,6 +2567,22 @@ int drmCreateBufList(int numTarget, drmBOList *list) return drmAdjustListNodes(list); } +static void drmBOCopyReply(const drm_bo_arg_reply_t *rep, + drmBO *buf) +{ + buf->handle = rep->handle; + buf->flags = rep->flags; + buf->size = rep->size; + buf->offset = rep->offset; + buf->mapHandle = rep->arg_handle; + buf->mask = rep->mask; + buf->start = rep->buffer_start; + buf->fenceFlags = rep->fence_flags; + buf->replyFlags = rep->rep_flags; +} + + + int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, void *user_buffer, drm_bo_type_t type, unsigned mask, unsigned hint, drmBO *buf) @@ -2612,16 +2628,10 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, return rep->ret; } - buf->handle = rep->handle; - buf->flags = rep->flags; - buf->size = rep->size; - buf->offset = rep->offset; - buf->mapHandle = rep->arg_handle; + drmBOCopyReply(rep, buf); buf->mapVirtual = NULL; buf->mapCount = 0; buf->virtual = NULL; - buf->mask = rep->mask; - buf->start = rep->buffer_start; return 0; } @@ -2671,17 +2681,12 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) return rep->ret; } - buf->handle = rep->handle; + drmBOCopyReply(rep, buf); buf->type = drm_bo_type_dc; - buf->flags = rep->flags; - buf->size = rep->size; - buf->offset = rep->offset; - buf->mapHandle = rep->arg_handle; buf->mapVirtual = NULL; buf->mapCount = 0; buf->virtual = NULL; - buf->mask = rep->mask; - buf->start = rep->buffer_start; + return 0; } @@ -2777,6 +2782,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, buf->mapFlags = mapFlags; fprintf(stderr, "Address is 0x%08x\n", address); *address = buf->virtual; + drmBOCopyReply(rep, buf); return 0; } @@ -2838,9 +2844,7 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, if (rep->ret) return rep->ret; - buf->offset = rep->offset; - buf->flags = rep->flags; - buf->mask = rep->mask; + drmBOCopyReply(rep, buf); return 0; } @@ -2869,8 +2873,46 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) return rep->ret; return 0; } - +int drmBOInfo(int fd, drmBO *buf) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_reply_t *rep = &arg.rep; + int ret = 0; + + arg.handled = 0; + req->handle = buf->handle; + req->op = drm_bo_info; + req->next = 0; + + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + + if (ret) + return ret; + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + drmBOCopyReply(rep, buf); + return 0; +} + +int drmBufBusy(int fd, drmBO *buf, int *busy) +{ + if (!(buf->flags & DRM_BO_FLAG_SHAREABLE) && + !(buf->replyFlags & DRM_BO_REP_BUSY)) { + *busy = 0; + return 0; + } else { + int ret = drmBOInfo(fd, buf); + if (ret) + return ret; + *busy = (buf->replyFlags & DRM_BO_REP_BUSY); + return 0; + } +} + int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, unsigned mask, @@ -2978,9 +3020,7 @@ int drmBOValidateList(int fd, drmBOList *list) return rep->ret; buf = node->buf; - buf->offset = rep->offset; - buf->flags = rep->flags; - buf->mask = rep->mask; + drmBOCopyReply(rep, buf); } return 0; @@ -2997,6 +3037,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) drm_bo_arg_reply_t *rep; drm_u64_t *prevNext = NULL; drmBO *buf; + unsigned fence_flags; int ret; first = NULL; @@ -3040,6 +3081,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) return -EFAULT; if (rep->ret) return rep->ret; + drmBOCopyReply(rep, buf); } return 0; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index aaee3c0b..a8458b15 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -92,6 +92,8 @@ typedef struct _drmBO{ unsigned long size; unsigned long offset; unsigned long start; + unsigned replyFlags; + unsigned fenceFlags; void *virtual; void *mapVirtual; int mapCount; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1c71f345..317b5f7a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -598,6 +598,32 @@ drm_buffer_object_t *drm_lookup_buffer_object(drm_file_t * priv, return bo; } +/* + * Call bo->mutex locked. + * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. + * Doesn't do any fence flushing as opposed to the drm_bo_busy function. + */ + + +static int drm_bo_quick_busy(drm_buffer_object_t *bo) +{ + drm_fence_object_t *fence = bo->fence; + + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + if (fence) { + drm_device_t *dev = bo->dev; + if (drm_fence_object_signaled(fence, bo->fence_flags)) { + drm_fence_usage_deref_unlocked(dev, fence); + bo->fence = NULL; + return 0; + } + return 1; + } + return 0; +} + + /* * Call bo->mutex locked. * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. @@ -719,8 +745,36 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, return 0; } +/* + * Fill in the ioctl reply argument with buffer info. + * Bo locked. + */ +static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, + drm_bo_arg_reply_t * rep) +{ + rep->handle = bo->base.hash.key; + rep->flags = bo->flags; + rep->size = bo->num_pages * PAGE_SIZE; + rep->offset = bo->offset; + + if (bo->ttm_object) { + rep->arg_handle = bo->ttm_object->map_list.user_token; + } else { + rep->arg_handle = 0; + } + + rep->mask = bo->mask; + rep->buffer_start = bo->buffer_start; + rep->fence_flags = bo->fence_flags; + rep->rep_flags = 0; + + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || + drm_bo_quick_busy(bo)) { + DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, DRM_BO_REP_BUSY); + } +} /* @@ -731,7 +785,8 @@ static int drm_bo_wait_unfenced(drm_buffer_object_t *bo, int no_wait, */ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, - uint32_t map_flags, int no_wait) + uint32_t map_flags, int no_wait, + drm_bo_arg_reply_t *rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -794,7 +849,8 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, if (atomic_add_negative(-1, &bo->mapped)) DRM_WAKEUP(&bo->event_queue); - } + } else + drm_bo_fill_rep_arg(bo, rep); out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); @@ -973,7 +1029,8 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, } static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, - uint32_t flags, uint32_t mask, uint32_t hint) + uint32_t flags, uint32_t mask, uint32_t hint, + drm_bo_arg_reply_t *rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; @@ -1001,13 +1058,33 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, ret = drm_buffer_object_validate(bo, new_flags, !(hint & DRM_BO_HINT_DONT_FENCE), no_wait); + drm_bo_fill_rep_arg(bo, rep); -out: +out: + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(dev, bo); return ret; } +static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, + drm_bo_arg_reply_t *rep) +{ + drm_buffer_object_t *bo; + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + return -EINVAL; + } + mutex_lock(&bo->mutex); + if (!(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + (void) drm_bo_busy(bo); + drm_bo_fill_rep_arg(bo, rep); + mutex_unlock(&bo->mutex); + return 0; +} + + /* * Call bo->mutex locked. */ @@ -1167,24 +1244,6 @@ static int drm_bo_add_user_object(drm_file_t * priv, drm_buffer_object_t * bo, return ret; } -static void drm_bo_fill_rep_arg(const drm_buffer_object_t * bo, - drm_bo_arg_reply_t * rep) -{ - rep->handle = bo->base.hash.key; - rep->flags = bo->flags; - rep->size = bo->num_pages * PAGE_SIZE; - rep->offset = bo->offset; - - if (bo->ttm_object) { - rep->arg_handle = bo->ttm_object->map_list.user_token; - } else { - rep->arg_handle = 0; - } - - rep->mask = bo->mask; - rep->buffer_start = bo->buffer_start; -} - static int drm_bo_lock_test(drm_device_t * dev, struct file *filp) { LOCK_TEST_WITH_RETURN(dev, filp); @@ -1249,7 +1308,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, req->hint & - DRM_BO_HINT_DONT_BLOCK); + DRM_BO_HINT_DONT_BLOCK, + &rep); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -1289,7 +1349,8 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; rep.ret = drm_bo_handle_validate(priv, req->handle, req->mask, - req->arg_handle, req->hint); + req->arg_handle, req->hint, + &rep); break; case drm_bo_fence: rep.ret = drm_bo_lock_test(dev, filp); @@ -1297,6 +1358,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; /**/ break; + case drm_bo_info: + rep.ret = drm_bo_handle_info(priv, req->handle, &rep); + break; default: rep.ret = -EINVAL; } @@ -1443,9 +1507,6 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) } if (arg.req.tt_p_size) { - DRM_ERROR("Initializing TT 0x%08x 0x%08x\n", - arg.req.tt_p_offset, - arg.req.tt_p_size); ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, arg.req.tt_p_size); diff --git a/shared-core/drm.h b/shared-core/drm.h index f76fd86f..f781abc6 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -758,10 +758,18 @@ typedef struct drm_bo_arg_request { drm_bo_fence, drm_bo_destroy, drm_bo_reference, - drm_bo_unreference + drm_bo_unreference, + drm_bo_info } op; } drm_bo_arg_request_t; + +/* + * Reply flags + */ + +#define DRM_BO_REP_BUSY 0x00000001 + typedef struct drm_bo_arg_reply { int ret; unsigned handle; @@ -771,6 +779,8 @@ typedef struct drm_bo_arg_reply { unsigned arg_handle; unsigned mask; drm_u64_t buffer_start; + unsigned fence_flags; + unsigned rep_flags; }drm_bo_arg_reply_t; -- 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. --- libdrm/xf86drm.c | 74 +++++++++++++++++++++++++++++----------------------- linux-core/drm_bo.c | 27 +++++++++---------- linux-core/drm_ttm.c | 2 ++ shared-core/drm.h | 14 +++++----- 4 files changed, 64 insertions(+), 53 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index aa1a5998..073fd0c4 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2598,6 +2598,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, req->type = type; buf->ttm = NULL; + buf->virtual = NULL; switch(type) { case drm_bo_type_ttm: @@ -2631,7 +2632,6 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, drmBOCopyReply(rep, buf); buf->mapVirtual = NULL; buf->mapCount = 0; - buf->virtual = NULL; return 0; } @@ -2642,6 +2642,12 @@ int drmBODestroy(int fd, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; + if (buf->mapVirtual) { + (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); + buf->mapVirtual = NULL; + buf->virtual = NULL; + } + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_destroy; @@ -2729,26 +2735,32 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, drm_bo_arg_reply_t *rep = &arg.rep; int ret = 0; + /* + * At the moment, we don't allow recursive mapping of a buffer, since + * the first mapping may have to be unmapped before this one to succeed. + * This might result in a deadlock. We need a DRM mutex mechanism!! + */ + + if (buf->mapCount) { + drmMsg("Recursive mapping is currently not allowed.\n"); + return -EAGAIN; + } + /* * Make sure we have a virtual address of the buffer. */ - fprintf(stderr, "Address is 0x%08x\n", address); - if (!buf->mapVirtual) { - if (buf->mapCount == 0) { - drmAddress virtual; - ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); - if (ret) - return ret; - ++buf->mapCount; - buf->mapVirtual = virtual; - buf->virtual = ((char *) virtual) + buf->start; - fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", - buf->mapVirtual, buf->virtual); - } + if (!buf->virtual) { + drmAddress virtual; + ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); + if (ret) + return ret; + buf->mapVirtual = virtual; + buf->virtual = ((char *) virtual) + buf->start; + fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", + buf->mapVirtual, buf->virtual); } - fprintf(stderr, "Address is 0x%08x\n", address); arg.handled = 0; req->handle = buf->handle; req->mask = mapFlags; @@ -2761,28 +2773,21 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, * This IOCTL synchronizes the buffer. */ - fprintf(stderr, "Address is 0x%08x\n", address); do { ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); } while (ret != 0 && errno == EAGAIN); - fprintf(stderr, "Address is 0x%08x\n", address); - if (ret || !arg.handled || rep->ret) { - if (--buf->mapCount == 0) { - (void )drmUnmap(buf->mapVirtual, buf->start + buf->size); - } - } if (ret) return ret; if (!arg.handled) return -EFAULT; if (rep->ret) return rep->ret; - + + drmBOCopyReply(rep, buf); buf->mapFlags = mapFlags; - fprintf(stderr, "Address is 0x%08x\n", address); + ++buf->mapCount; *address = buf->virtual; - drmBOCopyReply(rep, buf); return 0; } @@ -2793,13 +2798,6 @@ int drmBOUnmap(int fd, drmBO *buf) drm_bo_arg_request_t *req = &arg.req; drm_bo_arg_reply_t *rep = &arg.rep; - if (buf->mapCount == 0) { - return -EINVAL; - } - - if (--buf->mapCount == 0) { - (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); - } arg.handled = 0; req->handle = buf->handle; @@ -2814,6 +2812,8 @@ int drmBOUnmap(int fd, drmBO *buf) if (rep->ret) return rep->ret; + --buf->mapCount; + return 0; } @@ -2825,6 +2825,11 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, drm_bo_arg_reply_t *rep = &arg.rep; int ret = 0; + if (buf->mapCount) { + drmMsg("Cannot validate while buffer is mapped.\n"); + return -EAGAIN; + } + arg.handled = 0; req->handle = buf->handle; req->mask = flags; @@ -2988,6 +2993,11 @@ int drmBOValidateList(int fd, drmBOList *list) if (prevNext) *prevNext = (unsigned long) arg; + if (node->buf->mapCount) { + drmMsg("Cannot validate while buffer is mapped.\n"); + return -EAGAIN; + } + req->next = 0; prevNext = &req->next; arg->handled = 0; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 317b5f7a..70342ac9 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -70,7 +70,6 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); - DRM_ERROR("Flipping out of AGP\n"); mutex_lock(&dev->struct_mutex); drm_unbind_ttm_region(buf->ttm_region); drm_mm_put_block(&bm->tt_manager, buf->tt); @@ -442,8 +441,9 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - +#ifdef BODEBUG DRM_ERROR("Flipping in to AGP 0x%08lx\n", bo->tt->start); +#endif mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); if (ret) { @@ -459,9 +459,9 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) bo->flags |= DRM_BO_FLAG_MEM_TT; if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { - DRM_ERROR("Flush read caches\n"); ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); - DRM_ERROR("Warning: Could not flush read caches\n"); + if (ret) + DRM_ERROR("Warning: Could not flush read caches\n"); } DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); @@ -919,14 +919,12 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, /* * Flush outstanding fences. */ - DRM_ERROR("Flushing fences\n"); drm_bo_busy(bo); /* * Make sure we're not mapped. */ - DRM_ERROR("Wait unmapped\n"); ret = drm_bo_wait_unmapped(bo, no_wait); if (ret) return ret; @@ -935,7 +933,6 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ - DRM_ERROR("Wait fences\n"); ret = drm_bo_wait(bo, 0, no_wait); if (ret == -EINTR) @@ -979,19 +976,21 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return -EINVAL; } - /* - * Check whether we need to move buffer. - */ - +#ifdef BODEBUG + DRM_ERROR("New flags 0x%08x, Old flags 0x%08x\n", + new_flags, bo->flags); +#endif ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); - DRM_ERROR("Fence type = 0x%08x\n", bo->fence_flags); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; } + /* + * Check whether we need to move buffer. + */ + if (flag_diff & DRM_BO_MASK_MEM) { - DRM_ERROR("Calling move buffer\n"); ret = drm_bo_move_buffer(bo, new_flags, no_wait); if (ret) return ret; @@ -1050,7 +1049,7 @@ static int drm_bo_handle_validate(drm_file_t * priv, uint32_t handle, goto out; ret = drm_bo_new_flags(dev, bo->flags, - (flags & mask) | (bo->flags & ~mask), hint, + (flags & mask) | (bo->mask & ~mask), hint, 0, &new_flags, &bo->mask); if (ret) diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 97e3e96d..26133f9c 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -447,7 +447,9 @@ int drm_evict_ttm_region(drm_ttm_backend_list_t * entry) entry->num_pages); drm_ttm_unlock_mm(ttm, 0, 1); } +#ifdef BODEBUG DRM_ERROR("Unbinding\n"); +#endif be->unbind(entry->be); if (ttm && be->needs_cache_adjust(be)) { drm_set_caching(ttm, entry->page_offset, diff --git a/shared-core/drm.h b/shared-core/drm.h index f781abc6..a7d778ce 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -693,23 +693,23 @@ typedef struct drm_ttm_arg { */ /* Pinned buffer. */ -#define DRM_BO_FLAG_NO_EVICT 0x00000001 +#define DRM_BO_FLAG_NO_EVICT 0x00000010 /* Always keep a system memory shadow to a vram buffer */ -#define DRM_BO_FLAG_SHADOW_VRAM 0x00000002 +#define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 /* When mapped for reading, make sure the buffer is cached even if it means moving the buffer to system memory */ -#define DRM_BO_FLAG_SHAREABLE 0x00000004 +#define DRM_BO_FLAG_SHAREABLE 0x00000040 /* When there is a choice between VRAM and TT, prefer VRAM. The default behaviour is to prefer TT. */ -#define DRM_BO_FLAG_CACHED 0x00000008 +#define DRM_BO_FLAG_CACHED 0x00000080 /* The buffer is shareable with other processes */ -#define DRM_BO_FLAG_READ_CACHED 0x00001000 +#define DRM_BO_FLAG_READ_CACHED 0x00080000 /* The buffer is currently cached */ -#define DRM_BO_FLAG_PREFER_VRAM 0x00002000 +#define DRM_BO_FLAG_PREFER_VRAM 0x00040000 /* Bind this buffer cached if the hardware supports it. */ -#define DRM_BO_FLAG_BIND_CACHED 0x00004000 +#define DRM_BO_FLAG_BIND_CACHED 0x0002000 /* Translation table aperture */ #define DRM_BO_FLAG_MEM_TT 0x01000000 -- 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(-) 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(-) 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 +--- shared-core/drm.h | 6 ++++-- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 7f50bacf..1f0bbba5 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -299,7 +299,8 @@ int drm_fence_buffer_objects(drm_file_t * priv, * Wait until the buffer is idle. */ -static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) +static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, + int no_wait) { drm_fence_object_t *fence = bo->fence; @@ -317,7 +318,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int no_wait) return -EBUSY; ret = - drm_fence_object_wait(dev, fence, lazy, !lazy, + drm_fence_object_wait(dev, fence, lazy, ignore_signals, bo->fence_flags); if (ret) return ret; @@ -351,7 +352,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) if (!tt && !bo->vram) goto out; - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) goto out; @@ -805,7 +806,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) { atomic_dec(&bo->mapped); goto out; @@ -926,7 +927,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, * Wait for outstanding fences. */ - ret = drm_bo_wait(bo, 0, no_wait); + ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret == -EINTR) return -EAGAIN; @@ -1073,6 +1074,34 @@ static int drm_bo_handle_info(drm_file_t * priv, uint32_t handle, (void)drm_bo_busy(bo); drm_bo_fill_rep_arg(bo, rep); mutex_unlock(&bo->mutex); + drm_bo_usage_deref_unlocked(bo->dev, bo); + return 0; +} + +static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, + uint32_t hint, drm_bo_arg_reply_t * rep) +{ + drm_buffer_object_t *bo; + int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; + int ret; + + bo = drm_lookup_buffer_object(priv, handle, 1); + if (!bo) { + return -EINVAL; + } + mutex_lock(&bo->mutex); + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + if (ret) + goto out; + ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, + 0, no_wait); + if (ret) + goto out; + + drm_bo_fill_rep_arg(bo, rep); +out: + mutex_unlock(&bo->mutex); + drm_bo_usage_deref_unlocked(bo->dev, bo); return 0; } @@ -1348,6 +1377,13 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_info: rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break; + case drm_bo_wait_idle: + rep.ret = drm_bo_handle_wait(priv, req->handle, + req->hint, &rep); + break; + case drm_bo_ref_fence: + rep.ret = -EINVAL; + DRM_ERROR("Function is not implemented yet.\n"); default: rep.ret = -EINVAL; } @@ -1386,7 +1422,7 @@ static void drm_bo_force_clean(drm_device_t * dev) if (nice_mode) { unsigned long _end = jiffies + 3 * DRM_HZ; do { - ret = drm_bo_wait(entry, 0, 0); + ret = drm_bo_wait(entry, 0, 1, 0); } while ((ret == -EINTR) && !time_after_eq(jiffies, _end)); } else { diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 622cad10..1deeaaa5 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -567,9 +567,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) ret = drm_fence_object_wait(dev, fence, arg.flags & DRM_FENCE_FLAG_WAIT_LAZY, - arg. - flags & - DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS, + 0, arg.type); break; case drm_fence_emit: diff --git a/shared-core/drm.h b/shared-core/drm.h index a7d778ce..1a43e0af 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -726,7 +726,7 @@ typedef struct drm_ttm_arg { #define DRM_BO_HINT_DONT_BLOCK 0x00000002 /* Don't place this buffer on the unfenced list.*/ #define DRM_BO_HINT_DONT_FENCE 0x00000004 - +#define DRM_BO_HINT_WAIT_LAZY 0x00000008 @@ -759,7 +759,9 @@ typedef struct drm_bo_arg_request { drm_bo_destroy, drm_bo_reference, drm_bo_unreference, - drm_bo_info + drm_bo_info, + drm_bo_wait_idle, + drm_bo_ref_fence } op; } drm_bo_arg_request_t; -- cgit v1.2.3 From f88c32fd4cb93fe8b9dfa543a26d74733d0cd8ef Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Mon, 4 Sep 2006 22:05:21 +0200 Subject: Libdrm function headers. Some renaming. --- libdrm/xf86drm.c | 10 +++++----- libdrm/xf86mm.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 073fd0c4..068d0fb9 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2457,7 +2457,7 @@ static int drmAdjustListNodes(drmBOList *list) return ret; } -static void drmFreeList(drmBOList *list) +void drmBOFreeList(drmBOList *list) { drmBONode *node; drmMMListHead *l; @@ -2483,7 +2483,7 @@ static void drmFreeList(drmBOList *list) } } -int drmResetList(drmBOList *list) { +int drmBOResetList(drmBOList *list) { drmMMListHead *l; int ret; @@ -2547,17 +2547,17 @@ void *drmBOListNext(drmBOList *list, void *iterator) return ret; } -void drmBOListBuf(void *iterator, drmBO **buf) +drmBO *drmBOListBuf(void *iterator) { drmBONode *node; drmMMListHead *l = (drmMMListHead *) iterator; node = DRMLISTENTRY(drmBONode, l, head); - *buf = node->buf; + return node->buf; } -int drmCreateBufList(int numTarget, drmBOList *list) +int drmBOCreateList(int numTarget, drmBOList *list) { DRMINITLISTHEAD(&list->list); DRMINITLISTHEAD(&list->free); diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index a8458b15..623f4d58 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -117,12 +117,63 @@ typedef struct _drmBOList { drmMMListHead free; } drmBOList; + +/* + * TTM functions. + */ + +extern int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, + unsigned flags); +extern int drmTTMDestroy(int fd, const drmTTM *ttm); +extern int drmTTMReference(int fd, unsigned handle, drmTTM *ttm); +extern int drmTTMUnreference(int fd, const drmTTM *ttm); +extern drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm); + +/* + * Buffer object list functions. + */ + +extern void drmBOFreeList(drmBOList *list); +extern int drmBOResetList(drmBOList *list); +extern void *drmBOListIterator(drmBOList *list); +extern void *drmBOListNext(drmBOList *list, void *iterator); +extern drmBO *drmBOListBuf(void *iterator); +extern int drmBOCreateList(int numTarget, drmBOList *list); + +/* + * Buffer object functions. + */ + extern int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, void *user_buffer, drm_bo_type_t type, unsigned mask, unsigned hint, drmBO *buf); extern int drmBODestroy(int fd, drmBO *buf); extern int drmBOReference(int fd, unsigned handle, drmBO *buf); extern int drmBOUnReference(int fd, drmBO *buf); +extern int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, + void **address); +extern int drmBOUnmap(int fd, drmBO *buf); +extern int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, + unsigned hint); +extern int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle); +extern int drmBOInfo(int fd, drmBO *buf); +extern int drmBufBusy(int fd, drmBO *buf, int *busy); + + +extern int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, + unsigned mask, + int *newItem); +extern int drmBOValidateList(int fd, drmBOList *list); +extern int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle); + + +/* + * Initialization functions. + */ + +extern int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, + unsigned long ttPOffset, unsigned long ttPSize); +extern int drmMMTakedown(int fd); #endif -- 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(-) 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 ++------ shared-core/i915_drv.h | 6 ++++++ shared-core/i915_irq.c | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 673ebd0e..80ef3ab2 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -58,13 +58,9 @@ static void i915_perform_flush(drm_device_t * dev) diff = sequence - fm->exe_flush_sequence; if (diff < driver->wrap_diff) { fm->pending_exe_flush = 0; - /* - * Turn off user IRQs - */ + i915_user_irq_off(dev_priv); } else { - /* - * Turn on user IRQs - */ + i915_user_irq_on(dev_priv); } } } diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 8bf82ed8..f8d08741 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -103,6 +103,10 @@ typedef struct drm_i915_private { struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; + spinlock_t user_irq_lock; + int user_irq_refcount; + uint32_t irq_enable_reg; + int irq_enabled; #ifdef I915_HAVE_FENCE uint32_t flush_sequence; @@ -139,6 +143,8 @@ extern void i915_driver_irq_uninstall(drm_device_t * dev); extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS); extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); extern int i915_emit_irq(drm_device_t * dev); +extern void i915_user_irq_on(drm_i915_private_t *dev_priv); +extern void i915_user_irq_off(drm_i915_private_t *dev_priv); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4195555e..a3f6a03b 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -102,6 +102,29 @@ int i915_emit_irq(drm_device_t * dev) } +void i915_user_irq_on(drm_i915_private_t *dev_priv) +{ + + spin_lock(&dev_priv->user_irq_lock); + if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount > 0)){ + dev_priv->irq_enable_reg |= USER_INT_FLAG; + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } + spin_unlock(&dev_priv->user_irq_lock); + +} + +void i915_user_irq_off(drm_i915_private_t *dev_priv) +{ + spin_lock(&dev_priv->user_irq_lock); + if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { + dev_priv->irq_enable_reg &= ~USER_INT_FLAG; + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } + spin_unlock(&dev_priv->user_irq_lock); +} + + static int i915_wait_irq(drm_device_t * dev, int irq_nr) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; @@ -114,9 +137,11 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr) return 0; dev_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT; - + + i915_user_irq_on(dev_priv); DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ, READ_BREADCRUMB(dev_priv) >= irq_nr); + i915_user_irq_off(dev_priv); if (ret == DRM_ERR(EBUSY)) { DRM_ERROR("%s: EBUSY -- rec: %d emitted: %d\n", @@ -211,7 +236,11 @@ static int i915_enable_interrupt (drm_device_t *dev) __FUNCTION__, dev_priv->vblank_pipe); return DRM_ERR(EINVAL); } - I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); + dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; + dev_priv->user_irq_refcount = 0; + dev_priv->irq_enable_reg = flag; + I915_WRITE16(I915REG_INT_ENABLE_R, flag); + dev_priv->irq_enabled = 1; return 0; } @@ -290,6 +319,7 @@ void i915_driver_irq_uninstall(drm_device_t * dev) if (!dev_priv) return; + dev_priv->irq_enabled = 0; I915_WRITE16(I915REG_HWSTAM, 0xffff); I915_WRITE16(I915REG_INT_MASK_R, 0xffff); I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); -- 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. --- libdrm/xf86drm.c | 15 ++++++++ libdrm/xf86drm.h | 1 + linux-core/drmP.h | 14 ++++++-- linux-core/drm_bo.c | 33 ++++++++--------- linux-core/drm_fence.c | 96 +++++++++++++++++++++++++++++++------------------- shared-core/drm.h | 3 +- 6 files changed, 105 insertions(+), 57 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 068d0fb9..6d087427 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2259,6 +2259,21 @@ int drmFenceCreate(int fd, int shareable, int class,unsigned type, fence->signaled = 0; return 0; } + +int drmFenceBuffers(int fd, int shareable, drmFence *fence) +{ + drm_fence_arg_t arg; + + arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0; + arg.op = drm_fence_buffers; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->handle = arg.handle; + fence->class = arg.class; + fence->type = arg.type; + fence->signaled = 0; + return 0; +} int drmFenceDestroy(int fd, const drmFence *fence) { diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index f257deda..be1eeeff 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -626,6 +626,7 @@ extern int drmFenceSignaled(int fd, drmFence *fence); extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, int lazy, int ignore_signals); extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); +extern int drmFenceBuffers(int fd, int shareable, drmFence *fence); /* TTMS */ extern int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 23766373..7de7422b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1379,10 +1379,16 @@ extern void drm_fence_usage_deref_locked(drm_device_t * dev, drm_fence_object_t * fence); extern void drm_fence_usage_deref_unlocked(drm_device_t * dev, drm_fence_object_t * fence); -extern int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, - drm_fence_object_t * fence); extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask); +extern int drm_fence_object_create(drm_device_t *dev, uint32_t type, + int emit, drm_fence_object_t **c_fence); +extern int drm_fence_add_user_object(drm_file_t *priv, + drm_fence_object_t *fence, + int shareable); + + + extern int drm_fence_ioctl(DRM_IOCTL_ARGS); @@ -1394,6 +1400,10 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_clean_mm(drm_device_t *dev); +extern int drm_fence_buffer_objects(drm_file_t * priv, + struct list_head *list, + drm_fence_object_t *fence, + drm_fence_object_t **used_fence); /* Inline replacements for DRM_IOREMAP macros */ diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 1f0bbba5..68af5c31 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -199,8 +199,15 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) } } +/* + * Note. The caller has to register (if applicable) + * and deregister fence object usage. + */ + int drm_fence_buffer_objects(drm_file_t * priv, - struct list_head *list, drm_fence_object_t * fence) + struct list_head *list, + drm_fence_object_t *fence, + drm_fence_object_t **used_fence) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -230,19 +237,9 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { - fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); - - if (!fence) { - ret = -ENOMEM; - goto out; - } - - ret = drm_fence_object_init(dev, fence_flags, 1, fence); - - if (ret) { - kmem_cache_free(drm_cache.fence_object, fence); - goto out; - } + ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + if (ret) + goto out; } /* @@ -285,14 +282,14 @@ int drm_fence_buffer_objects(drm_file_t * priv, drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } - if (!count) - drm_fence_usage_deref_locked(dev, fence); - else if (count > 1) - atomic_add(count - 1, &fence->usage); + atomic_add(count, &fence->usage); out: mutex_unlock(&dev->struct_mutex); + *used_fence = fence; return ret; } +EXPORT_SYMBOL(drm_fence_buffer_objects); + /* * Call bo->mutex locked. diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 1deeaaa5..fd43d8bc 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -417,14 +417,28 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, EXPORT_SYMBOL(drm_fence_object_init); -static int drm_fence_object_create(drm_file_t * priv, uint32_t type, - int emit, int shareable, - uint32_t * user_handle, - drm_fence_object_t ** c_fence) +int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, + int shareable) { drm_device_t *dev = priv->head->dev; int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm_add_user_object(priv, &fence->base, shareable); + mutex_unlock(&dev->struct_mutex); + if (ret) + return ret; + fence->base.type = drm_fence_type; + fence->base.remove = &drm_fence_object_destroy; + return 0; +} +EXPORT_SYMBOL(drm_fence_add_user_object); + +int drm_fence_object_create(drm_device_t *dev, uint32_t type, + int emit, drm_fence_object_t **c_fence) +{ drm_fence_object_t *fence; + int ret; fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) @@ -434,23 +448,11 @@ static int drm_fence_object_create(drm_file_t * priv, uint32_t type, drm_fence_usage_deref_unlocked(dev, fence); return ret; } - - mutex_lock(&dev->struct_mutex); - ret = drm_add_user_object(priv, &fence->base, shareable); - mutex_unlock(&dev->struct_mutex); - if (ret) { - drm_fence_usage_deref_unlocked(dev, fence); - *c_fence = NULL; - *user_handle = 0; - return ret; - } - fence->base.type = drm_fence_type; - fence->base.remove = &drm_fence_object_destroy; - *user_handle = fence->base.hash.key; - *c_fence = fence; - + *c_fence = fence; return 0; } +EXPORT_SYMBOL(drm_fence_object_create); + void drm_fence_manager_init(drm_device_t * dev) { @@ -511,24 +513,29 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); switch (arg.op) { - case drm_fence_create:{ - int emit = arg.flags & DRM_FENCE_FLAG_EMIT; - if (emit) - LOCK_TEST_WITH_RETURN(dev, filp); - ret = - drm_fence_object_create(priv, arg.type, - emit, - arg. - flags & - DRM_FENCE_FLAG_SHAREABLE, - &arg.handle, &fence); - if (ret) - return ret; - mutex_lock(&dev->struct_mutex); - atomic_inc(&fence->usage); - mutex_unlock(&dev->struct_mutex); - break; + case drm_fence_create: + if (arg.flags & DRM_FENCE_FLAG_EMIT) + LOCK_TEST_WITH_RETURN(dev, filp); + ret = drm_fence_object_create(dev, arg.type, + arg.flags & DRM_FENCE_FLAG_EMIT, + &fence); + if (ret) + return ret; + ret = drm_fence_add_user_object(priv, fence, + arg.flags & + DRM_FENCE_FLAG_SHAREABLE); + if (ret) { + drm_fence_usage_deref_unlocked(dev, fence); + return ret; } + + /* + * usage > 0. No need to lock dev->struct_mutex; + */ + + atomic_inc(&fence->usage); + arg.handle = fence->base.hash.key; + break; case drm_fence_destroy: mutex_lock(&dev->struct_mutex); uo = drm_lookup_user_object(priv, arg.handle); @@ -577,6 +584,23 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) return -EINVAL; ret = drm_fence_object_emit(dev, fence, arg.type); break; + case drm_fence_buffers: + if (!dev->bm.initialized) { + DRM_ERROR("Buffer object manager is not initialized\n"); + return -EINVAL; + } + LOCK_TEST_WITH_RETURN(dev, filp); + ret = drm_fence_buffer_objects(priv, NULL, NULL, &fence); + if (ret) + return ret; + ret = drm_fence_add_user_object(priv, fence, + arg.flags & + DRM_FENCE_FLAG_SHAREABLE); + if (ret) + return ret; + atomic_inc(&fence->usage); + arg.handle = fence->base.hash.key; + break; default: return -EINVAL; } diff --git a/shared-core/drm.h b/shared-core/drm.h index 1a43e0af..e39f888a 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -659,7 +659,8 @@ typedef struct drm_fence_arg { drm_fence_signaled, drm_fence_flush, drm_fence_wait, - drm_fence_emit + drm_fence_emit, + drm_fence_buffers } op; } drm_fence_arg_t; -- cgit v1.2.3 From e3f54ecdd9d266607afd7d8b62960b2154b63e9d Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 5 Sep 2006 19:36:45 +0200 Subject: Multithreaded application note. --- libdrm/xf86drm.c | 26 +++----------------------- libdrm/xf86mm.h | 13 +++++++++++++ 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 6d087427..dd97e26e 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2750,17 +2750,6 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, drm_bo_arg_reply_t *rep = &arg.rep; int ret = 0; - /* - * At the moment, we don't allow recursive mapping of a buffer, since - * the first mapping may have to be unmapped before this one to succeed. - * This might result in a deadlock. We need a DRM mutex mechanism!! - */ - - if (buf->mapCount) { - drmMsg("Recursive mapping is currently not allowed.\n"); - return -EAGAIN; - } - /* * Make sure we have a virtual address of the buffer. */ @@ -2827,8 +2816,6 @@ int drmBOUnmap(int fd, drmBO *buf) if (rep->ret) return rep->ret; - --buf->mapCount; - return 0; } @@ -2840,11 +2827,6 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, drm_bo_arg_reply_t *rep = &arg.rep; int ret = 0; - if (buf->mapCount) { - drmMsg("Cannot validate while buffer is mapped.\n"); - return -EAGAIN; - } - arg.handled = 0; req->handle = buf->handle; req->mask = flags; @@ -2853,10 +2835,12 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, req->op = drm_bo_validate; req->next = 0; + do{ ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); } while (ret && errno == -EAGAIN); + if (ret) return ret; if (!arg.handled) @@ -3008,11 +2992,6 @@ int drmBOValidateList(int fd, drmBOList *list) if (prevNext) *prevNext = (unsigned long) arg; - if (node->buf->mapCount) { - drmMsg("Cannot validate while buffer is mapped.\n"); - return -EAGAIN; - } - req->next = 0; prevNext = &req->next; arg->handled = 0; @@ -3030,6 +3009,7 @@ int drmBOValidateList(int fd, drmBOList *list) ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); } while (ret && errno == -EAGAIN); + if (ret) return -errno; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 623f4d58..43ea71b8 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -31,6 +31,18 @@ #include #include "drm.h" +/* + * Note on multithreaded applications using this interface. + * Libdrm is not threadsafe, so common buffer, TTM, and fence objects need to + * be protected using an external mutex. + * + * Note: Don't protect the following functions, as it may lead to deadlocks: + * drmBOUnmap(), drmFenceBuffers(). + * The kernel is synchronizing and refcounting buffer maps. + * User space only needs to refcount object usage within the same application. + */ + + /* * List macros heavily inspired by the Linux kernel * list handling. No list looping yet. @@ -82,6 +94,7 @@ typedef struct _drmMMListHead ((__type *)(((char *) (__item)) - offsetof(__type, __field))) + typedef struct _drmBO{ drm_bo_type_t type; unsigned handle; -- cgit v1.2.3 From d5726761858b1ff0fd6e6ee92ec1648fbb958a53 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 6 Sep 2006 23:08:29 -0700 Subject: Add a typedef for u64. --- bsd-core/drmP.h | 1 + 1 file changed, 1 insertion(+) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 074e1d2c..e6c1d060 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -270,6 +270,7 @@ extern struct cfdriver drm_cd; #endif typedef unsigned long dma_addr_t; +typedef u_int64_t u64; typedef u_int32_t u32; typedef u_int16_t u16; typedef u_int8_t u8; -- cgit v1.2.3 From 55057660f035a03078910d678e5fd9b0cb0b795a Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 6 Sep 2006 23:25:14 -0700 Subject: Put the PCI device/vendor id in the drm_device_t. This helps us unbreak FreeBSD DRM from the 965 changes. --- bsd-core/drmP.h | 3 +++ bsd-core/drm_drv.c | 3 +++ linux-core/drmP.h | 2 ++ linux-core/drm_stub.c | 2 ++ shared-core/i915_dma.c | 8 ++++---- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index e6c1d060..6fa39734 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -714,6 +714,9 @@ struct drm_device { struct drm_driver_info driver; drm_pci_id_list_t *id_entry; /* PCI ID, name, and chipset private */ + u_int16_t pci_device; /* PCI device id */ + u_int16_t pci_vendor; /* PCI vendor id */ + char *unique; /* Unique identifier: e.g., busid */ int unique_len; /* Length of unique field */ #ifdef __FreeBSD__ diff --git a/bsd-core/drm_drv.c b/bsd-core/drm_drv.c index 3f53a72f..9fb10c53 100644 --- a/bsd-core/drm_drv.c +++ b/bsd-core/drm_drv.c @@ -516,6 +516,9 @@ static int drm_load(drm_device_t *dev) dev->pci_slot = pci_get_slot(dev->device); dev->pci_func = pci_get_function(dev->device); + dev->pci_vendor = pci_get_vendor(dev->device); + dev->pci_device = pci_get_device(dev->device); + TAILQ_INIT(&dev->maplist); drm_mem_init(); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 6046dde6..70bf3495 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -747,6 +747,8 @@ typedef struct drm_device { drm_agp_head_t *agp; /**< AGP data */ struct pci_dev *pdev; /**< PCI device structure */ + int pci_vendor; /**< PCI vendor id */ + int pci_device; /**< PCI device id */ #ifdef __alpha__ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) struct pci_controler *hose; diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index bdc36552..4708222f 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -66,6 +66,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, mutex_init(&dev->ctxlist_mutex); dev->pdev = pdev; + dev->pci_device = pdev->device; + dev->pci_vendor = pdev->vendor; #ifdef __alpha__ dev->hose = pdev->sysdata; diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index ba8c56ee..3863490c 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -31,10 +31,10 @@ #include "i915_drm.h" #include "i915_drv.h" -#define IS_I965G(dev) (dev->pdev->device == 0x2972 || \ - dev->pdev->device == 0x2982 || \ - dev->pdev->device == 0x2992 || \ - dev->pdev->device == 0x29A2) +#define IS_I965G(dev) (dev->pci_device == 0x2972 || \ + dev->pci_device == 0x2982 || \ + dev->pci_device == 0x2992 || \ + dev->pci_device == 0x29A2) /* Really want an OS-independent resettable timer. Would like to have -- cgit v1.2.3 From dddacd7a3a4bd0c453b346cee70d1d36a401e539 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 6 Sep 2006 23:26:50 -0700 Subject: Use the DRM_INIT_WAITQUEUE argument (needed on Linux) to avoid a warning. --- bsd-core/drmP.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsd-core/drmP.h b/bsd-core/drmP.h index 6fa39734..9ebb12ae 100644 --- a/bsd-core/drmP.h +++ b/bsd-core/drmP.h @@ -170,7 +170,7 @@ MALLOC_DECLARE(M_DRM); #define wait_queue_head_t atomic_t #define DRM_WAKEUP(w) wakeup((void *)w) #define DRM_WAKEUP_INT(w) wakeup(w) -#define DRM_INIT_WAITQUEUE(queue) do {} while (0) +#define DRM_INIT_WAITQUEUE(queue) do {(void)(queue);} while (0) #if defined(__FreeBSD__) && __FreeBSD_version < 502109 #define bus_alloc_resource_any(dev, type, rid, flags) \ -- 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. --- libdrm/xf86drm.c | 79 ++++++++++++++++--------- linux-core/drmP.h | 2 +- linux-core/drm_agpsupport.c | 1 + linux-core/drm_bo.c | 136 ++++++++++++++++++++++++++------------------ linux-core/drm_compat.c | 7 ++- linux-core/drm_fence.c | 15 +++++ linux-core/drm_ttm.c | 63 +++++++++++++++++--- linux-core/drm_ttm.h | 3 + linux-core/i915_fence.c | 17 +++--- shared-core/drm.h | 4 +- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 2 +- 12 files changed, 227 insertions(+), 103 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index dd97e26e..298b812a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2512,6 +2512,7 @@ int drmBOResetList(drmBOList *list) { DRMLISTDEL(l); DRMLISTADD(l, &list->free); list->numOnList--; + l = list->list.next; } return drmAdjustListNodes(list); } @@ -2603,8 +2604,8 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, unsigned hint, drmBO *buf) { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; arg.handled = 0; req->mask = mask; @@ -2628,6 +2629,9 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, req->buffer_start = (unsigned long) user_buffer; buf->virtual = user_buffer; break; + case drm_bo_type_fake: + req->buffer_start = start; + break; default: return -EINVAL; } @@ -2654,10 +2658,10 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, int drmBODestroy(int fd, drmBO *buf) { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; - if (buf->mapVirtual) { + if (buf->mapVirtual && (buf->type != drm_bo_type_fake)) { (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); buf->mapVirtual = NULL; buf->virtual = NULL; @@ -2685,8 +2689,8 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; arg.handled = 0; req->handle = handle; @@ -2714,9 +2718,16 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) int drmBOUnReference(int fd, drmBO *buf) { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; + + if (buf->mapVirtual && (buf->type != drm_bo_type_fake)) { + (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); + buf->mapVirtual = NULL; + buf->virtual = NULL; + } + arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unreference; @@ -2746,23 +2757,25 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; /* * Make sure we have a virtual address of the buffer. */ - if (!buf->virtual) { + if (!buf->virtual && buf->type != drm_bo_type_fake) { drmAddress virtual; ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); if (ret) return ret; buf->mapVirtual = virtual; buf->virtual = ((char *) virtual) + buf->start; +#ifdef BODEBUG fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", buf->mapVirtual, buf->virtual); +#endif } arg.handled = 0; @@ -2799,8 +2812,8 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, int drmBOUnmap(int fd, drmBO *buf) { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; arg.handled = 0; @@ -2823,8 +2836,8 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, unsigned hint) { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; arg.handled = 0; @@ -2856,8 +2869,8 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; arg.handled = 0; @@ -2881,8 +2894,8 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) int drmBOInfo(int fd, drmBO *buf) { drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; - drm_bo_arg_reply_t *rep = &arg.rep; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; arg.handled = 0; @@ -2963,6 +2976,7 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, cur->arg1 |= mask; cur->arg0 = (memFlags & flags) | ((cur->arg0 | flags) & cur->arg1); } + return 0; } @@ -2984,7 +2998,7 @@ int drmBOValidateList(int fd, drmBOList *list) node = DRMLISTENTRY(drmBONode, l, head); arg = &node->bo_arg; - req = &arg->req; + req = &arg->d.req; if (!first) first = arg; @@ -2999,14 +3013,20 @@ int drmBOValidateList(int fd, drmBOList *list) req->op = drm_bo_validate; req->mask = node->arg0; req->hint = 0; - req->arg_handle = node->arg1; + req->arg_handle = node->arg1 | DRM_BO_MASK_MEM; +#ifdef BODEBUG + fprintf(stderr, "Offset 0x%08x, Handle 0x%08x, " + "mask 0x%08x flags 0x%08x\n", + node->buf->offset, + req->handle, req->arg_handle, req->mask); +#endif } if (!first) return 0; do{ - ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, first); } while (ret && errno == -EAGAIN); @@ -3015,9 +3035,8 @@ int drmBOValidateList(int fd, drmBOList *list) for (l = list->list.next; l != &list->list; l = l->next) { node = DRMLISTENTRY(drmBONode, l, head); - arg = &node->bo_arg; - rep = &arg->rep; + rep = &arg->d.rep; if (!arg->handled) return -EFAULT; @@ -3026,6 +3045,10 @@ int drmBOValidateList(int fd, drmBOList *list) buf = node->buf; drmBOCopyReply(rep, buf); +#ifdef BODEBUG + fprintf(stderr,"Offset 0x%08x, Flags 0x%08x\n", + buf->offset, buf->flags); +#endif } return 0; @@ -3051,7 +3074,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) node = DRMLISTENTRY(drmBONode, l, head); arg = &node->bo_arg; - req = &arg->req; + req = &arg->d.req; if (!first) first = arg; @@ -3071,7 +3094,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) if (!first) return 0; - ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, first); if (ret) return -errno; @@ -3080,7 +3103,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) node = DRMLISTENTRY(drmBONode, l, head); arg = &node->bo_arg; - rep = &arg->rep; + rep = &arg->d.rep; if (!arg->handled) return -EFAULT; diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 7de7422b..da14bdfd 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -801,7 +801,7 @@ typedef struct drm_buffer_manager{ struct list_head unfenced; struct list_head ddestroy; struct list_head other; - struct timer_list timer; + struct work_struct wq; uint32_t fence_flags; } drm_buffer_manager_t; diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index e7226f1f..60ebc567 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -630,6 +630,7 @@ static void drm_agp_clear_ttm(drm_ttm_backend_t *backend) { } agp_free_memory(mem); } + agp_priv->mem = NULL; } diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 68af5c31..74722b1b 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -98,10 +98,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_fence_object_flush(dev, bo->fence, bo->fence_flags); list_add_tail(&bo->ddestroy, &bm->ddestroy); - if (!timer_pending(&bm->timer)) { - bm->timer.expires = jiffies + 1; - add_timer(&bm->timer); - } + schedule_delayed_work(&bm->wq, 2); return; } else { @@ -109,15 +106,14 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) bo->fence = NULL; } } - /* * Take away from lru lists. */ - list_del(&bo->head); + list_del_init(&bo->head); if (bo->tt) { - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm_region(bo->ttm_region); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -152,7 +148,9 @@ static void drm_bo_delayed_delete(drm_device_t * dev) entry->fence = NULL; } if (!entry->fence) { - DRM_DEBUG("Destroying delayed buffer object\n"); +#ifdef BODEBUG + DRM_ERROR("Destroying delayed buffer object\n"); +#endif list_del(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); } @@ -161,16 +159,18 @@ static void drm_bo_delayed_delete(drm_device_t * dev) mutex_unlock(&dev->struct_mutex); } -static void drm_bo_delayed_timer(unsigned long data) +static void drm_bo_delayed_workqueue(void *data) { drm_device_t *dev = (drm_device_t *) data; drm_buffer_manager_t *bm = &dev->bm; +#ifdef BODEBUG + DRM_ERROR("Delayed delete Worker\n"); +#endif drm_bo_delayed_delete(dev); - mutex_lock(&dev->struct_mutex); - if (!list_empty(&bm->ddestroy) && !timer_pending(&bm->timer)) { - bm->timer.expires = jiffies + 1; - add_timer(&bm->timer); + mutex_lock(&dev->struct_mutex); + if (!list_empty(&bm->ddestroy)) { + schedule_delayed_work(&bm->wq, 2); } mutex_unlock(&dev->struct_mutex); } @@ -220,14 +220,29 @@ int drm_fence_buffer_objects(drm_file_t * priv, mutex_lock(&dev->struct_mutex); + if (!list) + list = &bm->unfenced; + list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_flags |= entry->fence_flags; count++; } - if (!count) + if (!count) { + DRM_ERROR("No buffers to fence\n"); + ret = -EINVAL; goto out; + } + + /* + * Transfer to a local list before we release the dev->struct_mutex; + * This is so we don't get any new unfenced objects while fencing + * these. + */ + + list_add_tail(&f_list, list); + list_del_init(list); if (fence) { if ((fence_flags & fence->type) != fence_flags) { @@ -237,20 +252,13 @@ int drm_fence_buffer_objects(drm_file_t * priv, goto out; } } else { + mutex_unlock(&dev->struct_mutex); ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + mutex_lock(&dev->struct_mutex); if (ret) goto out; } - /* - * Transfer to a private list before we release the dev->struct_mutex; - * This is so we don't get any new unfenced objects while fencing - * these. - */ - - f_list = *list; - INIT_LIST_HEAD(list); - count = 0; l = f_list.next; while (l != &f_list) { @@ -259,7 +267,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); mutex_lock(&dev->struct_mutex); - + list_del_init(l); if (entry->priv_flags & _DRM_BO_FLAG_UNFENCED) { count++; if (entry->fence) @@ -268,7 +276,6 @@ int drm_fence_buffer_objects(drm_file_t * priv, DRM_FLAG_MASKED(entry->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); DRM_WAKEUP(&entry->event_queue); - list_del_init(&entry->head); if (entry->flags & DRM_BO_FLAG_NO_EVICT) list_add_tail(&entry->head, &bm->other); else if (entry->flags & DRM_BO_FLAG_MEM_TT) @@ -277,12 +284,19 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_add_tail(&entry->head, &bm->vram_lru); else list_add_tail(&entry->head, &bm->other); + } else { +#ifdef BODEBUG + DRM_ERROR("Huh? Fenced object on unfenced list\n"); +#endif } mutex_unlock(&entry->mutex); drm_bo_usage_deref_locked(dev, entry); l = f_list.next; } atomic_add(count, &fence->usage); +#ifdef BODEBUG + DRM_ERROR("Fenced %d buffers\n", count); +#endif out: mutex_unlock(&dev->struct_mutex); *used_fence = fence; @@ -303,7 +317,6 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, drm_fence_object_t *fence = bo->fence; int ret; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; if (drm_fence_object_signaled(fence, bo->fence_flags)) { @@ -424,6 +437,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) } else { buf->vram = node; } + buf->offset = node->start * PAGE_SIZE; return 0; } @@ -431,6 +445,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) { drm_device_t *dev = bo->dev; drm_buffer_manager_t *bm = &dev->bm; + drm_ttm_backend_t *be; int ret; BUG_ON(bo->tt); @@ -450,7 +465,8 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - if (bo->ttm_region->be->needs_cache_adjust(bo->ttm_region->be)) + be = bo->ttm_region->be; + if (be->needs_cache_adjust(be)) bo->flags &= ~DRM_BO_FLAG_CACHED; bo->flags &= ~DRM_BO_MASK_MEM; bo->flags |= DRM_BO_FLAG_MEM_TT; @@ -458,7 +474,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (bo->priv_flags & _DRM_BO_FLAG_EVICTED) { ret = dev->driver->bo_driver->invalidate_caches(dev, bo->flags); if (ret) - DRM_ERROR("Warning: Could not flush read caches\n"); + DRM_ERROR("Could not flush read caches\n"); } DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_EVICTED); @@ -776,12 +792,13 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, */ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, - uint32_t map_flags, int no_wait, + uint32_t map_flags, unsigned hint, drm_bo_arg_reply_t * rep) { drm_buffer_object_t *bo; drm_device_t *dev = priv->head->dev; int ret = 0; + int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; mutex_lock(&dev->struct_mutex); bo = drm_lookup_buffer_object(priv, handle, 1); @@ -791,9 +808,11 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, return -EINVAL; mutex_lock(&bo->mutex); - ret = drm_bo_wait_unfenced(bo, no_wait, 0); - if (ret) - goto out; + if (!(hint & DRM_BO_HINT_ALLOW_UNFENCED_MAP)) { + ret = drm_bo_wait_unfenced(bo, no_wait, 0); + if (ret) + goto out; + } /* * If this returns true, we are currently unmapped. @@ -979,7 +998,11 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, * Check whether we need to move buffer. */ - if (flag_diff & DRM_BO_MASK_MEM) { + if ((bo->type != drm_bo_type_fake) && (flag_diff & DRM_BO_MASK_MEM)) { + if (bo->type == drm_bo_type_user) { + DRM_ERROR("User buffers are not implemented yet.\n"); + return -EINVAL; + } ret = drm_bo_move_buffer(bo, new_flags, no_wait); if (ret) return ret; @@ -1151,7 +1174,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages,1, + bo->num_pages, 0, /* bo->mask & DRM_BO_FLAG_BIND_CACHED,*/ &bo->ttm_region); @@ -1177,9 +1200,11 @@ int drm_buffer_object_create(drm_file_t * priv, int ret = 0; uint32_t new_flags; unsigned long num_pages; - + drm_bo_delayed_delete(dev); - if (buffer_start & ~PAGE_MASK) { + + if ((buffer_start & ~PAGE_MASK) && + (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } @@ -1206,24 +1231,24 @@ int drm_buffer_object_create(drm_file_t * priv, bo->dev = dev; bo->type = type; bo->num_pages = num_pages; - bo->buffer_start = buffer_start; + if (bo->type == drm_bo_type_fake) { + bo->offset = buffer_start; + bo->buffer_start = 0; + } else { + bo->buffer_start = buffer_start; + } bo->priv_flags = 0; bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; ret = drm_bo_new_flags(dev, bo->flags, mask, hint, 1, &new_flags, &bo->mask); - DRM_ERROR("New flags: 0x%08x\n", new_flags); if (ret) goto out_err; ret = drm_bo_add_ttm(priv, bo, ttm_handle); if (ret) goto out_err; -#if 1 ret = drm_buffer_object_validate(bo, new_flags, 0, hint & DRM_BO_HINT_DONT_BLOCK); -#else - bo->flags = new_flags; -#endif if (ret) goto out_err; @@ -1268,7 +1293,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_bo_arg_t arg; - drm_bo_arg_request_t *req = &arg.req; + drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t rep; unsigned long next; drm_user_object_t *uo; @@ -1321,8 +1346,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, - req->hint & - DRM_BO_HINT_DONT_BLOCK, + req->hint, &rep); break; case drm_bo_destroy: @@ -1394,10 +1418,9 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) return -EAGAIN; arg.handled = 1; - arg.rep = rep; + arg.d.rep = rep; DRM_COPY_TO_USER_IOCTL((void __user *)data, arg, sizeof(arg)); data = next; - } while (data); return 0; } @@ -1409,17 +1432,22 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) static void drm_bo_force_clean(drm_device_t * dev) { drm_buffer_manager_t *bm = &dev->bm; - - drm_buffer_object_t *entry, *next; + struct list_head *l; + drm_buffer_object_t *entry; int nice_mode = 1; int ret = 0; - list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { + l = bm->ddestroy.next; + while(l != &bm->ddestroy) { + entry = list_entry(l, drm_buffer_object_t, ddestroy); + list_del(l); if (entry->fence) { if (nice_mode) { unsigned long _end = jiffies + 3 * DRM_HZ; do { + mutex_unlock(&dev->struct_mutex); ret = drm_bo_wait(entry, 0, 1, 0); + mutex_lock(&dev->struct_mutex); } while ((ret == -EINTR) && !time_after_eq(jiffies, _end)); } else { @@ -1436,8 +1464,8 @@ static void drm_bo_force_clean(drm_device_t * dev) } DRM_DEBUG("Destroying delayed buffer object\n"); - list_del(&entry->ddestroy); drm_bo_destroy_locked(dev, entry); + l = bm->ddestroy.next; } } @@ -1541,11 +1569,9 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_LIST_HEAD(&bm->ddestroy); INIT_LIST_HEAD(&bm->other); - init_timer(&bm->timer); - bm->timer.function = &drm_bo_delayed_timer; - bm->timer.data = (unsigned long)dev; - + INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; + break; case mm_takedown: if (drm_bo_clean_mm(dev)) { diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 86bae306..162e4656 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -59,9 +59,14 @@ static inline void change_pte_range(struct mm_struct *mm, pmd_t * pmd, do { if (pte_present(*pte)) { pte_t ptent; - ptent = *pte; ptep_get_and_clear(mm, addr, pte); + ptent = *pte; lazy_mmu_prot_update(ptent); + } else { + ptep_get_and_clear(mm, addr, pte); + } + if (!pte_none(*pte)) { + DRM_ERROR("Ugh. Pte was presen\n"); } } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap(pte - 1); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index fd43d8bc..eaaf7f40 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -111,6 +111,10 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) relevant = type & fence->type; if ((fence->signaled | relevant) != fence->signaled) { fence->signaled |= relevant; +#ifdef BODEBUG + DRM_ERROR("Fence 0x%08lx signaled 0x%08x\n", + fence->base.hash.key, fence->signaled); +#endif fence->submitted_flush |= relevant; wake = 1; } @@ -130,6 +134,10 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) */ if (!(fence->type & ~fence->signaled)) { +#ifdef BODEBUG + DRM_ERROR("Fence completely signaled 0x%08lx\n", + fence->base.hash.key); +#endif fence_list = &fence->ring; for (i = 0; i < driver->no_types; ++i) { if (fm->fence_types[i] == fence_list) @@ -172,6 +180,10 @@ void drm_fence_usage_deref_locked(drm_device_t * dev, { if (atomic_dec_and_test(&fence->usage)) { drm_fence_unring(dev, &fence->ring); +#ifdef BODEBUG + DRM_ERROR("Destroyed a fence object 0x%08lx\n", + fence->base.hash.key); +#endif kmem_cache_free(drm_cache.fence_object, fence); } } @@ -430,6 +442,9 @@ int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, return ret; fence->base.type = drm_fence_type; fence->base.remove = &drm_fence_object_destroy; +#ifdef BODEBUG + DRM_ERROR("Fence 0x%08lx created\n", fence->base.hash.key); +#endif return 0; } EXPORT_SYMBOL(drm_fence_add_user_object); diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 26133f9c..a83d6401 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -42,6 +42,38 @@ typedef struct drm_val_action { int validated; } drm_val_action_t; +/* + * Use kmalloc if possible. Otherwise fall back to vmalloc. + */ + + +static void *ttm_alloc(unsigned long size, int type, int *do_vmalloc) +{ + void *ret = NULL; + + *do_vmalloc = 0; + if (size <= 4*PAGE_SIZE) { + ret = drm_alloc(size, type); + } + if (!ret) { + *do_vmalloc = 1; + ret = vmalloc(size); + } + return ret; +} + +static void ttm_free(void *pointer, unsigned long size, int type, + int do_vfree) +{ + if (!do_vfree) { + drm_free(pointer, size, type); + }else { + vfree(pointer); + } +} + + + /* * We may be manipulating other processes page tables, so for each TTM, keep track of * which mm_structs are currently mapping the ttm so that we can take the appropriate @@ -161,6 +193,7 @@ static int unmap_vma_pages(drm_ttm_t * ttm, unsigned long page_offset, list_for_each(list, &ttm->vma_list->head) { drm_ttm_vma_list_t *entry = list_entry(list, drm_ttm_vma_list_t, head); + drm_clear_vma(entry->vma, entry->vma->vm_start + (page_offset << PAGE_SHIFT), @@ -205,7 +238,7 @@ int drm_destroy_ttm(drm_ttm_t * ttm) return -EBUSY; } - DRM_ERROR("Destroying a ttm\n"); + DRM_DEBUG("Destroying a ttm\n"); if (ttm->be_list) { list_for_each_safe(list, next, &ttm->be_list->head) { drm_ttm_backend_list_t *entry = @@ -231,12 +264,13 @@ int drm_destroy_ttm(drm_ttm_t * ttm) } } global_flush_tlb(); - vfree(ttm->pages); + ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), + DRM_MEM_TTM, ttm->pages_vmalloc); ttm->pages = NULL; } if (ttm->page_flags) { - vfree(ttm->page_flags); + ttm_free(ttm->page_flags, ttm->num_pages*sizeof(*ttm->page_flags), DRM_MEM_TTM, ttm->pf_vmalloc); ttm->page_flags = NULL; } @@ -280,7 +314,8 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) ttm->destroy = 0; ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - ttm->page_flags = vmalloc(ttm->num_pages * sizeof(*ttm->page_flags)); + ttm->page_flags = ttm_alloc(ttm->num_pages * sizeof(*ttm->page_flags), + DRM_MEM_TTM, &ttm->pf_vmalloc); if (!ttm->page_flags) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page_flags table\n"); @@ -288,7 +323,8 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) } memset(ttm->page_flags, 0, ttm->num_pages * sizeof(*ttm->page_flags)); - ttm->pages = vmalloc(ttm->num_pages * sizeof(*ttm->pages)); + ttm->pages = ttm_alloc(ttm->num_pages * sizeof(*ttm->pages), + DRM_MEM_TTM, &ttm->pages_vmalloc); if (!ttm->pages) { drm_destroy_ttm(ttm); DRM_ERROR("Failed allocating page table\n"); @@ -483,12 +519,13 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) uint32_t *cur_page_flags; int i; - DRM_ERROR("Destroying a TTM region\n"); + DRM_DEBUG("Destroying a TTM region\n"); list_del_init(&entry->head); drm_unbind_ttm_region(entry); if (be) { be->clear(entry->be); +#if 0 /* Hmm, Isn't this done in unbind? */ if (be->needs_cache_adjust(be)) { int ret = drm_ttm_lock_mmap_sem(ttm); drm_ttm_lock_mm(ttm, 0, 1); @@ -500,6 +537,7 @@ void drm_destroy_ttm_region(drm_ttm_backend_list_t * entry) if (!ret) drm_ttm_unlock_mm(ttm, 1, 0); } +#endif be->destroy(be); } cur_page_flags = ttm->page_flags + entry->page_offset; @@ -609,6 +647,12 @@ int drm_bind_ttm_region(drm_ttm_backend_list_t * region, ret = drm_ttm_lock_mmap_sem(ttm); if (ret) return ret; + + drm_ttm_lock_mm(ttm, 0, 1); + unmap_vma_pages(ttm, region->page_offset, + region->num_pages); + drm_ttm_unlock_mm(ttm, 0, 1); + drm_set_caching(ttm, region->page_offset, region->num_pages, DRM_TTM_PAGE_UNCACHED, 1); } else { @@ -676,7 +720,9 @@ void drm_user_destroy_region(drm_ttm_backend_list_t * entry) page_cache_release(*cur_page); cur_page++; } - vfree(entry->anon_pages); + ttm_free(entry->anon_pages, + sizeof(*entry->anon_pages)*entry->anon_locked, + DRM_MEM_TTM, entry->pages_vmalloc); } be->destroy(be); @@ -721,7 +767,8 @@ int drm_user_create_region(drm_device_t * dev, unsigned long start, int len, return -EFAULT; } - tmp->anon_pages = vmalloc(sizeof(*(tmp->anon_pages)) * len); + tmp->anon_pages = ttm_alloc(sizeof(*(tmp->anon_pages)) * len, + DRM_MEM_TTM, &tmp->pages_vmalloc); if (!tmp->anon_pages) { drm_user_destroy_region(tmp); diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index d647578c..5c65e747 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -70,6 +70,7 @@ typedef struct drm_ttm_backend_list { drm_file_t *anon_owner; struct page **anon_pages; int anon_locked; + int pages_vmalloc; enum { ttm_bound, ttm_evicted, @@ -99,6 +100,8 @@ typedef struct drm_ttm { atomic_t vma_count; int mmap_sem_locked; int destroy; + int pages_vmalloc; + int pf_vmalloc; } drm_ttm_t; typedef struct drm_ttm_object { diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 80ef3ab2..20e12d6a 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -55,13 +55,18 @@ static void i915_perform_flush(drm_device_t * dev) diff = sequence - fm->last_exe_flush; if (diff < driver->wrap_diff && diff != 0) { drm_fence_handler(dev, sequence, DRM_FENCE_EXE); - diff = sequence - fm->exe_flush_sequence; - if (diff < driver->wrap_diff) { - fm->pending_exe_flush = 0; + } + + diff = sequence - fm->exe_flush_sequence; + if (diff < driver->wrap_diff) { + fm->pending_exe_flush = 0; + if (dev_priv->fence_irq_on) { i915_user_irq_off(dev_priv); - } else { - i915_user_irq_on(dev_priv); + dev_priv->fence_irq_on = 0; } + } else if (!dev_priv->fence_irq_on) { + i915_user_irq_on(dev_priv); + dev_priv->fence_irq_on = 1; } } if (dev_priv->flush_pending) { @@ -82,8 +87,6 @@ static void i915_perform_flush(drm_device_t * dev) dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fm->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); - DRM_ERROR("Saved flush status is 0x%08x\n", - dev_priv->saved_flush_status); I915_WRITE(I915REG_INSTPM, (1 << 5) | (1 << 21)); dev_priv->flush_pending = 1; fm->pending_flush = 0; diff --git a/shared-core/drm.h b/shared-core/drm.h index e39f888a..bed55173 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -728,7 +728,7 @@ typedef struct drm_ttm_arg { /* Don't place this buffer on the unfenced list.*/ #define DRM_BO_HINT_DONT_FENCE 0x00000004 #define DRM_BO_HINT_WAIT_LAZY 0x00000008 - +#define DRM_BO_HINT_ALLOW_UNFENCED_MAP 0x00000010 /* Driver specific flags. Could be for example rendering engine */ @@ -792,7 +792,7 @@ typedef struct drm_bo_arg{ union { drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; - }; + } d; } drm_bo_arg_t; typedef union drm_mm_init_arg{ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index f8d08741..2aa3b947 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -105,6 +105,7 @@ typedef struct drm_i915_private { int vblank_pipe; spinlock_t user_irq_lock; int user_irq_refcount; + int fence_irq_on; uint32_t irq_enable_reg; int irq_enabled; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index a3f6a03b..4a1b2987 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -106,7 +106,7 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv) { spin_lock(&dev_priv->user_irq_lock); - if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount > 0)){ + if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= USER_INT_FLAG; I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } -- cgit v1.2.3 From 3cc64a943a7240c73c92ab103ba0502b9ec07fee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 12 Sep 2006 06:13:14 +1000 Subject: drm: use radeon specific names for radeon flags --- linux-core/radeon_drv.c | 2 +- shared-core/drm_pciids.txt | 176 ++++++++++++++++++++++----------------------- shared-core/radeon_cp.c | 46 ++++++------ shared-core/radeon_drv.h | 20 +++--- shared-core/radeon_state.c | 10 +-- 5 files changed, 127 insertions(+), 127 deletions(-) diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index fca2d4e7..b15e983e 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -45,7 +45,7 @@ module_param_named(no_wb, radeon_no_wb, int, 0444); static int dri_library_name(struct drm_device * dev, char * buf) { drm_radeon_private_t *dev_priv = dev->dev_private; - int family = dev_priv->flags & CHIP_FAMILY_MASK; + int family = dev_priv->flags & RADEON_FAMILY_MASK; return snprintf(buf, PAGE_SIZE, "%s\n", (family < CHIP_R200) ? "radeon" : diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 9ef2c001..9e0c0992 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -1,11 +1,11 @@ [radeon] -0x1002 0x3150 CHIP_RV380|CHIP_IS_MOBILITY "ATI Radeon Mobility X600 M24" -0x1002 0x3152 CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon Mobility X300 M24" -0x1002 0x3154 CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI FireGL M24 GL" -0x1002 0x3E50 CHIP_RV380|CHIP_NEW_MEMMAP "ATI Radeon RV380 X600" -0x1002 0x3E54 CHIP_RV380|CHIP_NEW_MEMMAP "ATI FireGL V3200 RV380" -0x1002 0x4136 CHIP_RS100|CHIP_IS_IGP "ATI Radeon RS100 IGP 320" -0x1002 0x4137 CHIP_RS200|CHIP_IS_IGP "ATI Radeon RS200 IGP 340" +0x1002 0x3150 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 M24" +0x1002 0x3152 CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X300 M24" +0x1002 0x3154 CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI FireGL M24 GL" +0x1002 0x3E50 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV380 X600" +0x1002 0x3E54 CHIP_RV380|RADEON_NEW_MEMMAP "ATI FireGL V3200 RV380" +0x1002 0x4136 CHIP_RS100|RADEON_IS_IGP "ATI Radeon RS100 IGP 320" +0x1002 0x4137 CHIP_RS200|RADEON_IS_IGP "ATI Radeon RS200 IGP 340" 0x1002 0x4144 CHIP_R300 "ATI Radeon AD 9500" 0x1002 0x4145 CHIP_R300 "ATI Radeon AE 9700 Pro" 0x1002 0x4146 CHIP_R300 "ATI Radeon AF R300 9600TX" @@ -21,35 +21,35 @@ 0x1002 0x4154 CHIP_RV350 "ATI FireGL AT T2" 0x1002 0x4155 CHIP_RV350 "ATI Radeon 9650" 0x1002 0x4156 CHIP_RV350 "ATI FireGL AV RV360 T2" -0x1002 0x4237 CHIP_RS200|CHIP_IS_IGP "ATI Radeon RS250 IGP" +0x1002 0x4237 CHIP_RS200|RADEON_IS_IGP "ATI Radeon RS250 IGP" 0x1002 0x4242 CHIP_R200 "ATI Radeon BB R200 AIW 8500DV" 0x1002 0x4243 CHIP_R200 "ATI Radeon BC R200" -0x1002 0x4336 CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY "ATI Radeon RS100 Mobility U1" -0x1002 0x4337 CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY "ATI Radeon RS200 Mobility IGP 340M" -0x1002 0x4437 CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY "ATI Radeon RS250 Mobility IGP" +0x1002 0x4336 CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon RS100 Mobility U1" +0x1002 0x4337 CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon RS200 Mobility IGP 340M" +0x1002 0x4437 CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon RS250 Mobility IGP" 0x1002 0x4966 CHIP_RV250 "ATI Radeon If RV250 9000" 0x1002 0x4967 CHIP_RV250 "ATI Radeon Ig RV250 9000" -0x1002 0x4A48 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JH R420 X800" -0x1002 0x4A49 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JI R420 X800 Pro" -0x1002 0x4A4A CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JJ R420 X800 SE" -0x1002 0x4A4B CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JK R420 X800 XT" -0x1002 0x4A4C CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JL R420 X800" -0x1002 0x4A4D CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL JM X3-256" -0x1002 0x4A4E CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon JN R420 Mobility M18" -0x1002 0x4A4F CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JO R420 X800 SE" -0x1002 0x4A50 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JP R420 X800 XT PE" -0x1002 0x4A54 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon JT R420 AIW X800 VE" -0x1002 0x4B49 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R481 X850 XT" -0x1002 0x4B4A CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R481 X850 SE" -0x1002 0x4B4B CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R481 X850 Pro" -0x1002 0x4B4C CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R481 X850 XT PE" -0x1002 0x4C57 CHIP_RV200|CHIP_IS_MOBILITY "ATI Radeon LW RV200 Mobility 7500 M7" -0x1002 0x4C58 CHIP_RV200|CHIP_IS_MOBILITY "ATI Radeon LX RV200 Mobility FireGL 7800 M7" -0x1002 0x4C59 CHIP_RV100|CHIP_IS_MOBILITY "ATI Radeon LY RV100 Mobility M6" -0x1002 0x4C5A CHIP_RV100|CHIP_IS_MOBILITY "ATI Radeon LZ RV100 Mobility M6" -0x1002 0x4C64 CHIP_RV250|CHIP_IS_MOBILITY "ATI Radeon Ld RV250 Mobility 9000 M9" +0x1002 0x4A48 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JH R420 X800" +0x1002 0x4A49 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JI R420 X800 Pro" +0x1002 0x4A4A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JJ R420 X800 SE" +0x1002 0x4A4B CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JK R420 X800 XT" +0x1002 0x4A4C CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JL R420 X800" +0x1002 0x4A4D CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL JM X3-256" +0x1002 0x4A4E CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon JN R420 Mobility M18" +0x1002 0x4A4F CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JO R420 X800 SE" +0x1002 0x4A50 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JP R420 X800 XT PE" +0x1002 0x4A54 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon JT R420 AIW X800 VE" +0x1002 0x4B49 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R481 X850 XT" +0x1002 0x4B4A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R481 X850 SE" +0x1002 0x4B4B CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R481 X850 Pro" +0x1002 0x4B4C CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R481 X850 XT PE" +0x1002 0x4C57 CHIP_RV200|RADEON_IS_MOBILITY "ATI Radeon LW RV200 Mobility 7500 M7" +0x1002 0x4C58 CHIP_RV200|RADEON_IS_MOBILITY "ATI Radeon LX RV200 Mobility FireGL 7800 M7" +0x1002 0x4C59 CHIP_RV100|RADEON_IS_MOBILITY "ATI Radeon LY RV100 Mobility M6" +0x1002 0x4C5A CHIP_RV100|RADEON_IS_MOBILITY "ATI Radeon LZ RV100 Mobility M6" +0x1002 0x4C64 CHIP_RV250|RADEON_IS_MOBILITY "ATI Radeon Ld RV250 Mobility 9000 M9" 0x1002 0x4C66 CHIP_RV250 "ATI Radeon Lf RV250 Mobility 9000 M9 / FireMV 2400 PCI" -0x1002 0x4C67 CHIP_RV250|CHIP_IS_MOBILITY "ATI Radeon Lg RV250 Mobility 9000 M9" +0x1002 0x4C67 CHIP_RV250|RADEON_IS_MOBILITY "ATI Radeon Lg RV250 Mobility 9000 M9" 0x1002 0x4E44 CHIP_R300 "ATI Radeon ND R300 9700 Pro" 0x1002 0x4E45 CHIP_R300 "ATI Radeon NE R300 9500 Pro / 9700" 0x1002 0x4E46 CHIP_R300 "ATI Radeon NF R300 9600TX" @@ -58,16 +58,16 @@ 0x1002 0x4E49 CHIP_R350 "ATI Radeon NI R350 9800" 0x1002 0x4E4A CHIP_R350 "ATI Radeon NJ R360 9800 XT" 0x1002 0x4E4B CHIP_R350 "ATI FireGL NK X2" -0x1002 0x4E50 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NP" -0x1002 0x4E51 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NQ" -0x1002 0x4E52 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M11 NR" -0x1002 0x4E53 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NS" -0x1002 0x4E54 CHIP_RV350|CHIP_IS_MOBILITY "ATI FireGL T2/T2e" -0x1002 0x4E56 CHIP_RV350|CHIP_IS_MOBILITY "ATI Radeon Mobility 9550" -0x1002 0x5144 CHIP_R100|CHIP_SINGLE_CRTC "ATI Radeon QD R100" -0x1002 0x5145 CHIP_R100|CHIP_SINGLE_CRTC "ATI Radeon QE R100" -0x1002 0x5146 CHIP_R100|CHIP_SINGLE_CRTC "ATI Radeon QF R100" -0x1002 0x5147 CHIP_R100|CHIP_SINGLE_CRTC "ATI Radeon QG R100" +0x1002 0x4E50 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NP" +0x1002 0x4E51 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NQ" +0x1002 0x4E52 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M11 NR" +0x1002 0x4E53 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon RV350 Mobility 9600 M10 NS" +0x1002 0x4E54 CHIP_RV350|RADEON_IS_MOBILITY "ATI FireGL T2/T2e" +0x1002 0x4E56 CHIP_RV350|RADEON_IS_MOBILITY "ATI Radeon Mobility 9550" +0x1002 0x5144 CHIP_R100|RADEON_SINGLE_CRTC "ATI Radeon QD R100" +0x1002 0x5145 CHIP_R100|RADEON_SINGLE_CRTC "ATI Radeon QE R100" +0x1002 0x5146 CHIP_R100|RADEON_SINGLE_CRTC "ATI Radeon QF R100" +0x1002 0x5147 CHIP_R100|RADEON_SINGLE_CRTC "ATI Radeon QG R100" 0x1002 0x5148 CHIP_R200 "ATI Radeon QH R200 8500" 0x1002 0x514C CHIP_R200 "ATI Radeon QL R200 8500 LE" 0x1002 0x514D CHIP_R200 "ATI Radeon QM R200 9100" @@ -76,59 +76,59 @@ 0x1002 0x5159 CHIP_RV100 "ATI Radeon QY RV100 7000/VE" 0x1002 0x515A CHIP_RV100 "ATI Radeon QZ RV100 7000/VE" 0x1002 0x515E CHIP_RV100 "ATI ES1000 RN50" -0x1002 0x5460 CHIP_RV380|CHIP_IS_MOBILITY "ATI Radeon Mobility X300 M22" -0x1002 0x5462 CHIP_RV380|CHIP_IS_MOBILITY "ATI Radeon Mobility X600 SE M24C" -0x1002 0x5464 CHIP_RV380|CHIP_IS_MOBILITY "ATI FireGL M22 GL 5464" -0x1002 0x5548 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800" -0x1002 0x5549 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800 Pro" -0x1002 0x554A CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800 XT PE" -0x1002 0x554B CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800 SE" -0x1002 0x554C CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R430 X800 XTP" -0x1002 0x554D CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R430 X800 XL" -0x1002 0x554E CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R430 X800 SE" -0x1002 0x554F CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R430 X800" -0x1002 0x5550 CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL V7100 R423" -0x1002 0x5551 CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL V5100 R423 UQ" -0x1002 0x5552 CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL unknown R423 UR" -0x1002 0x5554 CHIP_R420|CHIP_NEW_MEMMAP "ATI FireGL unknown R423 UT" -0x1002 0x564A CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility FireGL V5000 M26" -0x1002 0x564B CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility FireGL V5000 M26" -0x1002 0x564F CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon Mobility X700 XL M26" -0x1002 0x5652 CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon Mobility X700 M26" -0x1002 0x5653 CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon Mobility X700 M26" -0x1002 0x5834 CHIP_RS300|CHIP_IS_IGP "ATI Radeon RS300 9100 IGP" -0x1002 0x5835 CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY "ATI Radeon RS300 Mobility IGP" +0x1002 0x5460 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X300 M22" +0x1002 0x5462 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 SE M24C" +0x1002 0x5464 CHIP_RV380|RADEON_IS_MOBILITY "ATI FireGL M22 GL 5464" +0x1002 0x5548 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800" +0x1002 0x5549 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 Pro" +0x1002 0x554A CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT PE" +0x1002 0x554B CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 SE" +0x1002 0x554C CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 XTP" +0x1002 0x554D CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 XL" +0x1002 0x554E CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800 SE" +0x1002 0x554F CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R430 X800" +0x1002 0x5550 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL V7100 R423" +0x1002 0x5551 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL V5100 R423 UQ" +0x1002 0x5552 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL unknown R423 UR" +0x1002 0x5554 CHIP_R420|RADEON_NEW_MEMMAP "ATI FireGL unknown R423 UT" +0x1002 0x564A CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility FireGL V5000 M26" +0x1002 0x564B CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility FireGL V5000 M26" +0x1002 0x564F CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 XL M26" +0x1002 0x5652 CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 M26" +0x1002 0x5653 CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X700 M26" +0x1002 0x5834 CHIP_RS300|RADEON_IS_IGP "ATI Radeon RS300 9100 IGP" +0x1002 0x5835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY "ATI Radeon RS300 Mobility IGP" 0x1002 0x5960 CHIP_RV280 "ATI Radeon RV280 9250" 0x1002 0x5961 CHIP_RV280 "ATI Radeon RV280 9200" 0x1002 0x5962 CHIP_RV280 "ATI Radeon RV280 9200" 0x1002 0x5964 CHIP_RV280 "ATI Radeon RV280 9200 SE" 0x1002 0x5965 CHIP_RV280 "ATI FireMV 2200 PCI" 0x1002 0x5969 CHIP_RV100 "ATI ES1000 RN50" -0x1002 0x5b60 CHIP_RV380|CHIP_NEW_MEMMAP "ATI Radeon RV370 X300 SE" -0x1002 0x5b62 CHIP_RV380|CHIP_NEW_MEMMAP "ATI Radeon RV370 X600 Pro" -0x1002 0x5b63 CHIP_RV380|CHIP_NEW_MEMMAP "ATI Radeon RV370 X550" -0x1002 0x5b64 CHIP_RV380|CHIP_NEW_MEMMAP "ATI FireGL V3100 (RV370) 5B64" -0x1002 0x5b65 CHIP_RV380|CHIP_NEW_MEMMAP "ATI FireMV 2200 PCIE (RV370) 5B65" -0x1002 0x5c61 CHIP_RV280|CHIP_IS_MOBILITY "ATI Radeon RV280 Mobility" -0x1002 0x5c63 CHIP_RV280|CHIP_IS_MOBILITY "ATI Radeon RV280 Mobility" -0x1002 0x5d48 CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility Radeon X800 XT M28" -0x1002 0x5d49 CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility FireGL V5100 M28" -0x1002 0x5d4a CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Mobility Radeon X800 M28" -0x1002 0x5d4c CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850" -0x1002 0x5d4d CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850 XT PE" -0x1002 0x5d4e CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850 SE" -0x1002 0x5d4f CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850 Pro" -0x1002 0x5d50 CHIP_R420|CHIP_NEW_MEMMAP "ATI unknown Radeon / FireGL R480" -0x1002 0x5d52 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R480 X850 XT" -0x1002 0x5d57 CHIP_R420|CHIP_NEW_MEMMAP "ATI Radeon R423 X800 XT" -0x1002 0x5e48 CHIP_RV410|CHIP_NEW_MEMMAP "ATI FireGL V5000 RV410" -0x1002 0x5e4a CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700 XT" -0x1002 0x5e4b CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700 Pro" -0x1002 0x5e4c CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700 SE" -0x1002 0x5e4d CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700" -0x1002 0x5e4f CHIP_RV410|CHIP_NEW_MEMMAP "ATI Radeon RV410 X700 SE" -0x1002 0x7834 CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP "ATI Radeon RS350 9000/9100 IGP" -0x1002 0x7835 CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP "ATI Radeon RS350 Mobility IGP" +0x1002 0x5b60 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X300 SE" +0x1002 0x5b62 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X600 Pro" +0x1002 0x5b63 CHIP_RV380|RADEON_NEW_MEMMAP "ATI Radeon RV370 X550" +0x1002 0x5b64 CHIP_RV380|RADEON_NEW_MEMMAP "ATI FireGL V3100 (RV370) 5B64" +0x1002 0x5b65 CHIP_RV380|RADEON_NEW_MEMMAP "ATI FireMV 2200 PCIE (RV370) 5B65" +0x1002 0x5c61 CHIP_RV280|RADEON_IS_MOBILITY "ATI Radeon RV280 Mobility" +0x1002 0x5c63 CHIP_RV280|RADEON_IS_MOBILITY "ATI Radeon RV280 Mobility" +0x1002 0x5d48 CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility Radeon X800 XT M28" +0x1002 0x5d49 CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility FireGL V5100 M28" +0x1002 0x5d4a CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Mobility Radeon X800 M28" +0x1002 0x5d4c CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850" +0x1002 0x5d4d CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 XT PE" +0x1002 0x5d4e CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 SE" +0x1002 0x5d4f CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 Pro" +0x1002 0x5d50 CHIP_R420|RADEON_NEW_MEMMAP "ATI unknown Radeon / FireGL R480" +0x1002 0x5d52 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R480 X850 XT" +0x1002 0x5d57 CHIP_R420|RADEON_NEW_MEMMAP "ATI Radeon R423 X800 XT" +0x1002 0x5e48 CHIP_RV410|RADEON_NEW_MEMMAP "ATI FireGL V5000 RV410" +0x1002 0x5e4a CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 XT" +0x1002 0x5e4b CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 Pro" +0x1002 0x5e4c CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 SE" +0x1002 0x5e4d CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700" +0x1002 0x5e4f CHIP_RV410|RADEON_NEW_MEMMAP "ATI Radeon RV410 X700 SE" +0x1002 0x7834 CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP "ATI Radeon RS350 9000/9100 IGP" +0x1002 0x7835 CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon RS350 Mobility IGP" [r128] 0x1002 0x4c45 0 "ATI Rage 128 Mobility LE (PCI)" diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c index 4e7b2823..4135f4d5 100644 --- a/shared-core/radeon_cp.c +++ b/shared-core/radeon_cp.c @@ -1130,7 +1130,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, | (dev_priv->fb_location >> 16)); #if __OS_HAS_AGP - if (dev_priv->flags & CHIP_IS_AGP) { + if (dev_priv->flags & RADEON_IS_AGP) { RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base); RADEON_WRITE(RADEON_MC_AGP_LOCATION, (((dev_priv->gart_vm_start - 1 + @@ -1158,7 +1158,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev, dev_priv->ring.tail = cur_read_ptr; #if __OS_HAS_AGP - if (dev_priv->flags & CHIP_IS_AGP) { + if (dev_priv->flags & RADEON_IS_AGP) { RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR, dev_priv->ring_rptr->offset - dev->agp->base + dev_priv->gart_vm_start); @@ -1301,7 +1301,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on) { u32 tmp; - if (dev_priv->flags & CHIP_IS_PCIE) { + if (dev_priv->flags & RADEON_IS_PCIE) { radeon_set_pciegart(dev_priv, on); return; } @@ -1339,26 +1339,26 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) DRM_DEBUG("\n"); /* if we require new memory map but we don't have it fail */ - if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap) + if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) { DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n"); radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); } - if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP)) + if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) { DRM_DEBUG("Forcing AGP card to PCI mode\n"); - dev_priv->flags &= ~CHIP_IS_AGP; + dev_priv->flags &= ~RADEON_IS_AGP; } - else if (!(dev_priv->flags & (CHIP_IS_AGP | CHIP_IS_PCI | CHIP_IS_PCIE)) + else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE)) && !init->is_pci) { DRM_DEBUG("Restoring AGP flag\n"); - dev_priv->flags |= CHIP_IS_AGP; + dev_priv->flags |= RADEON_IS_AGP; } - if ((!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg) { + if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) { DRM_ERROR("PCI GART memory not allocated!\n"); radeon_do_cleanup_cp(dev); return DRM_ERR(EINVAL); @@ -1501,7 +1501,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) init->sarea_priv_offset); #if __OS_HAS_AGP - if (dev_priv->flags & CHIP_IS_AGP) { + if (dev_priv->flags & RADEON_IS_AGP) { drm_core_ioremap(dev_priv->cp_ring, dev); drm_core_ioremap(dev_priv->ring_rptr, dev); drm_core_ioremap(dev->agp_buffer_map, dev); @@ -1560,7 +1560,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) * align it down. */ #if __OS_HAS_AGP - if (dev_priv->flags & CHIP_IS_AGP) { + if (dev_priv->flags & RADEON_IS_AGP) { base = dev->agp->base; /* Check if valid */ if ((base + dev_priv->gart_size) > dev_priv->fb_location && @@ -1590,7 +1590,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) } #if __OS_HAS_AGP - if (dev_priv->flags & CHIP_IS_AGP) + if (dev_priv->flags & RADEON_IS_AGP) dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset - dev->agp->base + dev_priv->gart_vm_start); @@ -1616,7 +1616,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; #if __OS_HAS_AGP - if (dev_priv->flags & CHIP_IS_AGP) { + if (dev_priv->flags & RADEON_IS_AGP) { /* Turn off PCI GART */ radeon_set_pcigart(dev_priv, 0); } else @@ -1636,7 +1636,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) dev_priv->gart_info.mapping.handle; dev_priv->gart_info.is_pcie = - !!(dev_priv->flags & CHIP_IS_PCIE); + !!(dev_priv->flags & RADEON_IS_PCIE); dev_priv->gart_info.gart_table_location = DRM_ATI_GART_FB; @@ -1648,7 +1648,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init) DRM_ATI_GART_MAIN; dev_priv->gart_info.addr = NULL; dev_priv->gart_info.bus_addr = 0; - if (dev_priv->flags & CHIP_IS_PCIE) { + if (dev_priv->flags & RADEON_IS_PCIE) { DRM_ERROR ("Cannot use PCI Express without GART in FB memory\n"); radeon_do_cleanup_cp(dev); @@ -1690,7 +1690,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev) drm_irq_uninstall(dev); #if __OS_HAS_AGP - if (dev_priv->flags & CHIP_IS_AGP) { + if (dev_priv->flags & RADEON_IS_AGP) { if (dev_priv->cp_ring != NULL) { drm_core_ioremapfree(dev_priv->cp_ring, dev); dev_priv->cp_ring = NULL; @@ -1745,7 +1745,7 @@ static int radeon_do_resume_cp(drm_device_t * dev) DRM_DEBUG("Starting radeon_do_resume_cp()\n"); #if __OS_HAS_AGP - if (dev_priv->flags & CHIP_IS_AGP) { + if (dev_priv->flags & RADEON_IS_AGP) { /* Turn off PCI GART */ radeon_set_pcigart(dev_priv, 0); } else @@ -2194,7 +2194,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)dev_priv; dev_priv->flags = flags; - switch (flags & CHIP_FAMILY_MASK) { + switch (flags & RADEON_FAMILY_MASK) { case CHIP_R100: case CHIP_RV200: case CHIP_R200: @@ -2202,7 +2202,7 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) case CHIP_R350: case CHIP_R420: case CHIP_RV410: - dev_priv->flags |= CHIP_HAS_HIERZ; + dev_priv->flags |= RADEON_HAS_HIERZ; break; default: /* all other chips have no hierarchical z buffer */ @@ -2210,14 +2210,14 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) } if (drm_device_is_agp(dev)) - dev_priv->flags |= CHIP_IS_AGP; + dev_priv->flags |= RADEON_IS_AGP; else if (drm_device_is_pcie(dev)) - dev_priv->flags |= CHIP_IS_PCIE; + dev_priv->flags |= RADEON_IS_PCIE; else - dev_priv->flags |= CHIP_IS_PCI; + dev_priv->flags |= RADEON_IS_PCI; DRM_DEBUG("%s card detected\n", - ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : (((dev_priv->flags & CHIP_IS_PCIE) ? "PCIE" : "PCI")))); + ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI")))); return ret; } diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 5fa8254a..5fc93310 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -134,16 +134,16 @@ enum radeon_cp_microcode_version { * Chip flags */ enum radeon_chip_flags { - CHIP_FAMILY_MASK = 0x0000ffffUL, - CHIP_FLAGS_MASK = 0xffff0000UL, - CHIP_IS_MOBILITY = 0x00010000UL, - CHIP_IS_IGP = 0x00020000UL, - CHIP_SINGLE_CRTC = 0x00040000UL, - CHIP_IS_AGP = 0x00080000UL, - CHIP_HAS_HIERZ = 0x00100000UL, - CHIP_IS_PCIE = 0x00200000UL, - CHIP_NEW_MEMMAP = 0x00400000UL, - CHIP_IS_PCI = 0x00800000UL, + RADEON_FAMILY_MASK = 0x0000ffffUL, + RADEON_FLAGS_MASK = 0xffff0000UL, + RADEON_IS_MOBILITY = 0x00010000UL, + RADEON_IS_IGP = 0x00020000UL, + RADEON_SINGLE_CRTC = 0x00040000UL, + RADEON_IS_AGP = 0x00080000UL, + RADEON_HAS_HIERZ = 0x00100000UL, + RADEON_IS_PCIE = 0x00200000UL, + RADEON_NEW_MEMMAP = 0x00400000UL, + RADEON_IS_PCI = 0x00800000UL, }; #define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \ diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 8c1a4065..0a196c06 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -861,7 +861,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, */ dev_priv->sarea_priv->ctx_owner = 0; - if ((dev_priv->flags & CHIP_HAS_HIERZ) + if ((dev_priv->flags & RADEON_HAS_HIERZ) && (flags & RADEON_USE_HIERZ)) { /* FIXME : reverse engineer that for Rx00 cards */ /* FIXME : the mask supposedly contains low-res z values. So can't set @@ -906,7 +906,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, for (i = 0; i < nbox; i++) { int tileoffset, nrtilesx, nrtilesy, j; /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */ - if ((dev_priv->flags & CHIP_HAS_HIERZ) + if ((dev_priv->flags & RADEON_HAS_HIERZ) && !(dev_priv->microcode_version == UCODE_R200)) { /* FIXME : figure this out for r200 (when hierz is enabled). Or maybe r200 actually doesn't need to put the low-res z value into @@ -990,7 +990,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev, } /* TODO don't always clear all hi-level z tiles */ - if ((dev_priv->flags & CHIP_HAS_HIERZ) + if ((dev_priv->flags & RADEON_HAS_HIERZ) && (dev_priv->microcode_version == UCODE_R200) && (flags & RADEON_USE_HIERZ)) /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */ @@ -3031,9 +3031,9 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS) break; case RADEON_PARAM_CARD_TYPE: - if (dev_priv->flags & CHIP_IS_PCIE) + if (dev_priv->flags & RADEON_IS_PCIE) value = RADEON_CARD_PCIE; - else if (dev_priv->flags & CHIP_IS_AGP) + else if (dev_priv->flags & RADEON_IS_AGP) value = RADEON_CARD_AGP; else value = RADEON_CARD_PCI; -- 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. --- libdrm/xf86drm.c | 70 ++++++++++++++++++++++++++++++++++++-------------- libdrm/xf86drm.h | 4 ++- libdrm/xf86mm.h | 3 ++- linux-core/drmP.h | 3 +++ linux-core/drm_bo.c | 26 ++++++++++++------- linux-core/drm_fence.c | 7 +++-- linux-core/drm_lock.c | 2 +- linux-core/drm_ttm.c | 16 ++++++++++-- linux-core/drm_vm.c | 9 +++++-- shared-core/drm.h | 1 + shared-core/i915_drm.h | 8 ++++++ shared-core/i915_irq.c | 8 +++--- 12 files changed, 115 insertions(+), 42 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 298b812a..2ea6656f 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2256,6 +2256,7 @@ int drmFenceCreate(int fd, int shareable, int class,unsigned type, fence->handle = arg.handle; fence->class = arg.class; fence->type = arg.type; + fence->flags = arg.flags; fence->signaled = 0; return 0; } @@ -2271,6 +2272,7 @@ int drmFenceBuffers(int fd, int shareable, drmFence *fence) fence->handle = arg.handle; fence->class = arg.class; fence->type = arg.type; + fence->flags = arg.flags; fence->signaled = 0; return 0; } @@ -2297,6 +2299,7 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence) fence->handle = arg.handle; fence->class = arg.class; fence->type = arg.type; + fence->flags = 0; fence->signaled = arg.signaled; return 0; } @@ -2327,20 +2330,41 @@ int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type) return 0; } -int drmFenceSignaled(int fd, drmFence *fence) +int drmFenceUpdate(int fd, drmFence *fence) { - drm_fence_arg_t arg; - - arg.handle = fence->handle; - arg.op = drm_fence_signaled; - if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) - return -errno; - fence->class = arg.class; - fence->type = arg.type; - fence->signaled = arg.signaled; + drm_fence_arg_t arg; + + arg.handle = fence->handle; + arg.op = drm_fence_signaled; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->class = arg.class; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; +} + +int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType, + int *signaled) +{ + int + ret; + + if ((fence->flags & DRM_FENCE_FLAG_SHAREABLE) || + ((fenceType & fence->signaled) != fenceType)) { + + ret = drmFenceFlush(fd, fence, fenceType); + if (ret) + return ret; + } + + *signaled = ((fenceType & fence->signaled) == fenceType); + return 0; } + + int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) { drm_fence_arg_t arg; @@ -2362,6 +2386,12 @@ int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, drm_fence_arg_t arg; int ret; + if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) { + if (flush_type & fence->signaled == flush_type) { + return 0; + } + } + arg.handle = fence->handle; arg.type = flush_type; arg.flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0; @@ -2942,8 +2972,6 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, *newItem = 0; cur = NULL; - mask &= ~DRM_BO_MASK_MEM; - for (l = list->list.next; l != &list->list; l = l->next) { node = DRMLISTENTRY(drmBONode, l, head); if (node->buf == buf) { @@ -2961,20 +2989,22 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, cur->arg0 = flags; cur->arg1 = mask; } else { - unsigned memFlags = cur->arg0 & DRM_BO_MASK_MEM; + unsigned memMask = (cur->arg1 | mask) & DRM_BO_MASK_MEM; + unsigned memFlags = cur->arg0 & flags & memMask; - if (!(memFlags & flags)) { + if (!memFlags) { drmMsg("Incompatible memory location requests " "on validate list.\n"); return -EINVAL; } - if ((cur->arg1 | mask) & (cur->arg0 ^ flags)) { + if ((cur->arg1 | mask) & ~DRM_BO_MASK_MEM & (cur->arg0 ^ flags)) { drmMsg("Incompatible buffer flag requests " " on validate list.\n"); return -EINVAL; } cur->arg1 |= mask; - cur->arg0 = (memFlags & flags) | ((cur->arg0 | flags) & cur->arg1); + cur->arg0 = memFlags | ((cur->arg0 | flags) & + cur->arg1 & ~DRM_BO_MASK_MEM); } return 0; } @@ -3116,16 +3146,18 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) } int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, - unsigned long ttPOffset, unsigned long ttPSize) + unsigned long ttPOffset, unsigned long ttPSize, + unsigned long max_locked_size) { drm_mm_init_arg_t arg; - + arg.req.op = mm_init; arg.req.vr_p_offset = vramPOffset; arg.req.vr_p_size = vramPSize; arg.req.tt_p_offset = ttPOffset; arg.req.tt_p_size = ttPSize; - + arg.req.max_locked_pages = max_locked_size / getpagesize(); + if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) return -errno; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index be1eeeff..1b136d31 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -284,6 +284,7 @@ typedef struct _drmFence{ unsigned handle; int class; unsigned type; + unsigned flags; unsigned signaled; } drmFence; @@ -622,7 +623,8 @@ extern int drmFenceDestroy(int fd, const drmFence *fence); extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); extern int drmFenceUnreference(int fd, const drmFence *fence); extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); -extern int drmFenceSignaled(int fd, drmFence *fence); +extern int drmFenceSignaled(int fd, drmFence *fence, + unsigned fenceType, int *signaled); extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, int lazy, int ignore_signals); extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 43ea71b8..24e28245 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -185,7 +185,8 @@ extern int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle); */ extern int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, - unsigned long ttPOffset, unsigned long ttPSize); + unsigned long ttPOffset, unsigned long ttPSize, + unsigned long max_locked_size); extern int drmMMTakedown(int fd); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index da14bdfd..835b295a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -790,6 +790,7 @@ typedef struct drm_fence_manager{ typedef struct drm_buffer_manager{ int initialized; + drm_file_t *last_to_validate; int has_vram; int has_tt; int use_vram; @@ -803,6 +804,8 @@ typedef struct drm_buffer_manager{ struct list_head other; struct work_struct wq; uint32_t fence_flags; + unsigned long max_pages; + unsigned long cur_pages; } drm_buffer_manager_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 74722b1b..3a9c2313 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -95,11 +95,11 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { + drm_fence_object_flush(dev, bo->fence, bo->fence_flags); list_add_tail(&bo->ddestroy, &bm->ddestroy); - - schedule_delayed_work(&bm->wq, 2); - + schedule_delayed_work(&bm->wq, + ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -113,7 +113,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) list_del_init(&bo->head); if (bo->tt) { - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm_region(bo->ttm_region); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -170,7 +170,7 @@ static void drm_bo_delayed_workqueue(void *data) drm_bo_delayed_delete(dev); mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy)) { - schedule_delayed_work(&bm->wq, 2); + schedule_delayed_work(&bm->wq, ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); } mutex_unlock(&dev->struct_mutex); } @@ -822,6 +822,11 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { + if (no_wait && drm_bo_busy(bo)) { + atomic_dec(&bo->mapped); + ret = -EBUSY; + goto out; + } ret = drm_bo_wait(bo, 0, 0, no_wait); if (ret) { atomic_dec(&bo->mapped); @@ -1174,9 +1179,8 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, bo->ttm_object = to; ttm = drm_ttm_from_object(to); ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, 0, - - /* bo->mask & DRM_BO_FLAG_BIND_CACHED,*/ + bo->num_pages, + bo->mask & DRM_BO_FLAG_BIND_CACHED, &bo->ttm_region); if (ret) { drm_ttm_object_deref_unlocked(dev, to); @@ -1383,6 +1387,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) break; case drm_bo_validate: rep.ret = drm_bo_lock_test(dev, filp); + if (rep.ret) break; rep.ret = @@ -1571,13 +1576,16 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; - + bm->cur_pages = 0; + bm->max_pages = arg.req.max_locked_pages; break; case mm_takedown: if (drm_bo_clean_mm(dev)) { DRM_ERROR("Memory manager not clean. " "Delaying takedown\n"); } + DRM_DEBUG("We have %ld still locked pages\n", + bm->cur_pages); break; default: DRM_ERROR("Function not implemented yet\n"); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index eaaf7f40..df5db702 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -359,12 +359,11 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, fence_signaled(dev, fence, mask, 1)); if (time_after_eq(jiffies, _end)) break; - } while (ret == -EINTR && ignore_signals); - + } while (ret == -EINTR && ignore_signals); if (time_after_eq(jiffies, _end) && (ret != 0)) ret = -EBUSY; - return ret; - + if (ret) + return ((ret == -EINTR) ? -EAGAIN : ret); } else { int signaled; do { diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 91fad8bf..69ce2291 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -270,7 +270,7 @@ int drm_lock_free(drm_device_t * dev, prev = cmpxchg(lock, old, new); } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_ERROR("%d freed heavyweight lock held by %d\n", + DRM_DEBUG("%d freed heavyweight lock held by %d\n", context, _DRM_LOCKING_CONTEXT(old)); return 1; } diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index a83d6401..8aba36ca 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -251,19 +251,24 @@ int drm_destroy_ttm(drm_ttm_t * ttm) } if (ttm->pages) { + drm_buffer_manager_t *bm = &ttm->dev->bm; + int do_tlbflush = 0; for (i = 0; i < ttm->num_pages; ++i) { cur_page = ttm->pages + i; if (ttm->page_flags && (ttm->page_flags[i] & DRM_TTM_PAGE_UNCACHED) && *cur_page && !PageHighMem(*cur_page)) { change_page_attr(*cur_page, 1, PAGE_KERNEL); + do_tlbflush = 1; } if (*cur_page) { ClearPageReserved(*cur_page); __free_page(*cur_page); + --bm->cur_pages; } } - global_flush_tlb(); + if (do_tlbflush) + global_flush_tlb(); ttm_free(ttm->pages, ttm->num_pages*sizeof(*ttm->pages), DRM_MEM_TTM, ttm->pages_vmalloc); ttm->pages = NULL; @@ -308,6 +313,7 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) if (!ttm) return NULL; + ttm->dev = dev; ttm->lhandle = 0; atomic_set(&ttm->vma_count, 0); @@ -354,7 +360,6 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size) INIT_LIST_HEAD(&ttm->vma_list->head); ttm->lhandle = (unsigned long)ttm; - ttm->dev = dev; return ttm; } @@ -562,6 +567,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, drm_ttm_backend_list_t *entry; drm_ttm_backend_t *be; int ret, i; + drm_buffer_manager_t *bm = &ttm->dev->bm; if ((page_offset + n_pages) > ttm->num_pages || n_pages == 0) { DRM_ERROR("Region Doesn't fit ttm\n"); @@ -602,6 +608,11 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, for (i = 0; i < entry->num_pages; ++i) { cur_page = ttm->pages + (page_offset + i); if (!*cur_page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + drm_destroy_ttm_region(entry); + return -ENOMEM; + } *cur_page = alloc_page(GFP_KERNEL); if (!*cur_page) { DRM_ERROR("Page allocation failed\n"); @@ -609,6 +620,7 @@ int drm_create_ttm_region(drm_ttm_t * ttm, unsigned long page_offset, return -ENOMEM; } SetPageReserved(*cur_page); + ++bm->cur_pages; } } diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 69391058..e7b808cc 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -253,6 +253,7 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, drm_ttm_t *ttm; pgprot_t default_prot; uint32_t page_flags; + drm_buffer_manager_t *bm; if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */ @@ -261,12 +262,18 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, map = (drm_map_t *) entry->map; ttm = (drm_ttm_t *) map->offset; + bm = &ttm->dev->bm; page_offset = (address - vma->vm_start) >> PAGE_SHIFT; page = ttm->pages[page_offset]; page_flags = ttm->page_flags[page_offset]; if (!page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + return NOPAGE_OOM; + } + ++bm->cur_pages; page = ttm->pages[page_offset] = alloc_page(GFP_KERNEL); SetPageReserved(page); @@ -274,8 +281,6 @@ static __inline__ struct page *drm_do_vm_ttm_nopage(struct vm_area_struct *vma, if (!page) return NOPAGE_OOM; - get_page(page); - default_prot = vm_get_page_prot(vma->vm_flags); BUG_ON(page_flags & DRM_TTM_PAGE_UNCACHED); diff --git a/shared-core/drm.h b/shared-core/drm.h index bed55173..d10b713b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -808,6 +808,7 @@ typedef union drm_mm_init_arg{ drm_u64_t vr_p_size; drm_u64_t tt_p_offset; drm_u64_t tt_p_size; + drm_u64_t max_locked_pages; } req; struct { drm_handle_t mm_sarea; diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index fcffb25c..1a79d403 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -106,6 +106,14 @@ typedef struct _drm_i915_sarea { unsigned int rotated2_tiled; } drm_i915_sarea_t; +/* Driver specific fence types and classes. + */ + +/* The only fence class we support */ +#define DRM_I915_FENCE_CLASS_ACCEL 0 +/* Fence type that guarantees read-write flush */ +#define DRM_I915_FENCE_TYPE_RW 2 + /* Flags for perf_boxes */ #define I915_BOX_RING_EMPTY 0x1 diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4a1b2987..8f3e79de 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -47,8 +47,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); +#if 0 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); - +#endif if (temp == 0) return IRQ_NONE; @@ -104,7 +105,7 @@ int i915_emit_irq(drm_device_t * dev) void i915_user_irq_on(drm_i915_private_t *dev_priv) { - + return; spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= USER_INT_FLAG; @@ -116,6 +117,7 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv) void i915_user_irq_off(drm_i915_private_t *dev_priv) { + return; spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { dev_priv->irq_enable_reg &= ~USER_INT_FLAG; @@ -239,7 +241,7 @@ static int i915_enable_interrupt (drm_device_t *dev) dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; dev_priv->user_irq_refcount = 0; dev_priv->irq_enable_reg = flag; - I915_WRITE16(I915REG_INT_ENABLE_R, flag); + I915_WRITE16(I915REG_INT_ENABLE_R, flag | USER_INT_FLAG); dev_priv->irq_enabled = 1; return 0; } -- 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. --- libdrm/xf86drm.c | 12 ++++++-- linux-core/drm_bo.c | 56 +++++++++++++++++++---------------- linux-core/drm_fence.c | 77 ++++++++++++++++++++++++++++++++---------------- linux-core/i915_buffer.c | 5 ++++ 4 files changed, 97 insertions(+), 53 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 2ea6656f..3a23eae2 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2995,11 +2995,19 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, if (!memFlags) { drmMsg("Incompatible memory location requests " "on validate list.\n"); + drmMsg("Previous flag: 0x%08lx, mask: 0x%08lx\n", + cur->arg0, cur->arg1); + drmMsg("Current flag: 0x%08lx, mask: 0x%08lx\n", + flags, mask); return -EINVAL; } - if ((cur->arg1 | mask) & ~DRM_BO_MASK_MEM & (cur->arg0 ^ flags)) { + if (mask & cur->arg1 & ~DRM_BO_MASK_MEM & (cur->arg0 ^ flags)) { drmMsg("Incompatible buffer flag requests " - " on validate list.\n"); + "on validate list.\n"); + drmMsg("Previous flag: 0x%08lx, mask: 0x%08lx\n", + cur->arg0, cur->arg1); + drmMsg("Current flag: 0x%08lx, mask: 0x%08lx\n", + flags, mask); return -EINVAL; } cur->arg1 |= mask; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 3a9c2313..abad398f 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -91,15 +91,16 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_buffer_manager_t *bm = &dev->bm; - DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); + DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); if (bo->fence) { if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { drm_fence_object_flush(dev, bo->fence, bo->fence_flags); list_add_tail(&bo->ddestroy, &bm->ddestroy); - schedule_delayed_work(&bm->wq, - ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); + schedule_delayed_work(&bm->wq, + ((DRM_HZ / 100) < + 1) ? 1 : DRM_HZ / 100); return; } else { drm_fence_usage_deref_locked(dev, bo->fence); @@ -168,9 +169,10 @@ static void drm_bo_delayed_workqueue(void *data) DRM_ERROR("Delayed delete Worker\n"); #endif drm_bo_delayed_delete(dev); - mutex_lock(&dev->struct_mutex); + mutex_lock(&dev->struct_mutex); if (!list_empty(&bm->ddestroy)) { - schedule_delayed_work(&bm->wq, ((DRM_HZ/100) < 1) ? 1 : DRM_HZ/100); + schedule_delayed_work(&bm->wq, + ((DRM_HZ / 100) < 1) ? 1 : DRM_HZ / 100); } mutex_unlock(&dev->struct_mutex); } @@ -205,9 +207,9 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) */ int drm_fence_buffer_objects(drm_file_t * priv, - struct list_head *list, - drm_fence_object_t *fence, - drm_fence_object_t **used_fence) + struct list_head *list, + drm_fence_object_t * fence, + drm_fence_object_t ** used_fence) { drm_device_t *dev = priv->head->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -226,6 +228,12 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); fence_flags |= entry->fence_flags; + if (entry->fence_class != 0) { + DRM_ERROR("Fence class %d is not implemented yet.\n", + entry->fence_class); + ret = -EINVAL; + goto out; + } count++; } @@ -238,7 +246,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, /* * Transfer to a local list before we release the dev->struct_mutex; * This is so we don't get any new unfenced objects while fencing - * these. + * the ones we already have.. */ list_add_tail(&f_list, list); @@ -256,7 +264,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, ret = drm_fence_object_create(dev, fence_flags, 1, &fence); mutex_lock(&dev->struct_mutex); if (ret) - goto out; + goto out; } count = 0; @@ -286,7 +294,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_add_tail(&entry->head, &bm->other); } else { #ifdef BODEBUG - DRM_ERROR("Huh? Fenced object on unfenced list\n"); + DRM_ERROR("Huh? Fenced object on unfenced list\n"); #endif } mutex_unlock(&entry->mutex); @@ -302,8 +310,8 @@ int drm_fence_buffer_objects(drm_file_t * priv, *used_fence = fence; return ret; } -EXPORT_SYMBOL(drm_fence_buffer_objects); +EXPORT_SYMBOL(drm_fence_buffer_objects); /* * Call bo->mutex locked. @@ -822,7 +830,7 @@ static int drm_buffer_object_map(drm_file_t * priv, uint32_t handle, while (1) { if (atomic_inc_and_test(&bo->mapped)) { - if (no_wait && drm_bo_busy(bo)) { + if (no_wait && drm_bo_busy(bo)) { atomic_dec(&bo->mapped); ret = -EBUSY; goto out; @@ -1109,7 +1117,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, drm_buffer_object_t *bo; int no_wait = hint & DRM_BO_HINT_DONT_BLOCK; int ret; - + bo = drm_lookup_buffer_object(priv, handle, 1); if (!bo) { return -EINVAL; @@ -1118,13 +1126,12 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, ret = drm_bo_wait_unfenced(bo, no_wait, 0); if (ret) goto out; - ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, - 0, no_wait); + ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, 0, no_wait); if (ret) goto out; drm_bo_fill_rep_arg(bo, rep); -out: + out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(bo->dev, bo); return 0; @@ -1204,11 +1211,10 @@ int drm_buffer_object_create(drm_file_t * priv, int ret = 0; uint32_t new_flags; unsigned long num_pages; - + drm_bo_delayed_delete(dev); - if ((buffer_start & ~PAGE_MASK) && - (type != drm_bo_type_fake)) { + if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); return -EINVAL; } @@ -1350,8 +1356,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) case drm_bo_map: rep.ret = drm_buffer_object_map(priv, req->handle, req->mask, - req->hint, - &rep); + req->hint, &rep); break; case drm_bo_destroy: mutex_lock(&dev->struct_mutex); @@ -1404,7 +1409,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_bo_handle_info(priv, req->handle, &rep); break; case drm_bo_wait_idle: - rep.ret = drm_bo_handle_wait(priv, req->handle, + rep.ret = drm_bo_handle_wait(priv, req->handle, req->hint, &rep); break; case drm_bo_ref_fence: @@ -1443,7 +1448,7 @@ static void drm_bo_force_clean(drm_device_t * dev) int ret = 0; l = bm->ddestroy.next; - while(l != &bm->ddestroy) { + while (l != &bm->ddestroy) { entry = list_entry(l, drm_buffer_object_t, ddestroy); list_del(l); if (entry->fence) { @@ -1584,8 +1589,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) DRM_ERROR("Memory manager not clean. " "Delaying takedown\n"); } - DRM_DEBUG("We have %ld still locked pages\n", - bm->cur_pages); + DRM_DEBUG("We have %ld still locked pages\n", bm->cur_pages); break; default: DRM_ERROR("Function not implemented yet\n"); diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index df5db702..4ee5d2d0 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -112,7 +112,7 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) if ((fence->signaled | relevant) != fence->signaled) { fence->signaled |= relevant; #ifdef BODEBUG - DRM_ERROR("Fence 0x%08lx signaled 0x%08x\n", + DRM_ERROR("Fence 0x%08lx signaled 0x%08x\n", fence->base.hash.key, fence->signaled); #endif fence->submitted_flush |= relevant; @@ -135,7 +135,7 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) if (!(fence->type & ~fence->signaled)) { #ifdef BODEBUG - DRM_ERROR("Fence completely signaled 0x%08lx\n", + DRM_ERROR("Fence completely signaled 0x%08lx\n", fence->base.hash.key); #endif fence_list = &fence->ring; @@ -275,7 +275,7 @@ int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type) */ int drm_fence_object_flush(drm_device_t * dev, - drm_fence_object_t * fence, uint32_t type) + drm_fence_object_t * fence, uint32_t type) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; @@ -341,6 +341,7 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, drm_fence_driver_t *driver = dev->driver->fence_driver; int ret = 0; unsigned long _end; + int signaled; if (mask & ~fence->type) { DRM_ERROR("Wait trying to extend fence type\n"); @@ -353,25 +354,51 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, _end = jiffies + 3 * DRM_HZ; drm_fence_object_flush(dev, fence, mask); + if (lazy && driver->lazy_capable) { + do { DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, fence_signaled(dev, fence, mask, 1)); if (time_after_eq(jiffies, _end)) break; - } while (ret == -EINTR && ignore_signals); + } while (ret == -EINTR && ignore_signals); if (time_after_eq(jiffies, _end) && (ret != 0)) ret = -EBUSY; - if (ret) + if (ret) return ((ret == -EINTR) ? -EAGAIN : ret); - } else { - int signaled; + + } else if ((fence->class == 0) && (mask & DRM_FENCE_EXE) && + driver->lazy_capable) { + + /* + * We use IRQ wait for EXE fence if available to gain + * CPU in some cases. + */ + do { - signaled = fence_signaled(dev, fence, mask, 1); - } while (!signaled && !time_after_eq(jiffies, _end)); - if (!signaled) - return -EBUSY; + DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, + fence_signaled(dev, fence, DRM_FENCE_EXE, + 1)); + if (time_after_eq(jiffies, _end)) + break; + } while (ret == -EINTR && ignore_signals); + if (time_after_eq(jiffies, _end) && (ret != 0)) + ret = -EBUSY; + if (ret) + return ((ret == -EINTR) ? -EAGAIN : ret); } + + if (fence_signaled(dev, fence, mask, 0)) + return 0; + + do { + signaled = fence_signaled(dev, fence, mask, 1); + } while (!signaled && !time_after_eq(jiffies, _end)); + + if (!signaled) + return -EBUSY; + return 0; } @@ -413,7 +440,7 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, write_lock_irqsave(&fm->lock, flags); INIT_LIST_HEAD(&fence->ring); - fence->class = 0; + fence->class = 0; fence->type = type; fence->flush_mask = 0; fence->submitted_flush = 0; @@ -428,7 +455,7 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, EXPORT_SYMBOL(drm_fence_object_init); -int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, +int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence, int shareable) { drm_device_t *dev = priv->head->dev; @@ -446,10 +473,11 @@ int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, #endif return 0; } + EXPORT_SYMBOL(drm_fence_add_user_object); -int drm_fence_object_create(drm_device_t *dev, uint32_t type, - int emit, drm_fence_object_t **c_fence) +int drm_fence_object_create(drm_device_t * dev, uint32_t type, + int emit, drm_fence_object_t ** c_fence) { drm_fence_object_t *fence; int ret; @@ -462,11 +490,11 @@ int drm_fence_object_create(drm_device_t *dev, uint32_t type, drm_fence_usage_deref_unlocked(dev, fence); return ret; } - *c_fence = fence; + *c_fence = fence; return 0; } -EXPORT_SYMBOL(drm_fence_object_create); +EXPORT_SYMBOL(drm_fence_object_create); void drm_fence_manager_init(drm_device_t * dev) { @@ -535,8 +563,8 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) &fence); if (ret) return ret; - ret = drm_fence_add_user_object(priv, fence, - arg.flags & + ret = drm_fence_add_user_object(priv, fence, + arg.flags & DRM_FENCE_FLAG_SHAREABLE); if (ret) { drm_fence_usage_deref_unlocked(dev, fence); @@ -588,8 +616,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) ret = drm_fence_object_wait(dev, fence, arg.flags & DRM_FENCE_FLAG_WAIT_LAZY, - 0, - arg.type); + 0, arg.type); break; case drm_fence_emit: LOCK_TEST_WITH_RETURN(dev, filp); @@ -605,16 +632,16 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) } LOCK_TEST_WITH_RETURN(dev, filp); ret = drm_fence_buffer_objects(priv, NULL, NULL, &fence); - if (ret) + if (ret) return ret; - ret = drm_fence_add_user_object(priv, fence, - arg.flags & + ret = drm_fence_add_user_object(priv, fence, + arg.flags & DRM_FENCE_FLAG_SHAREABLE); if (ret) return ret; atomic_inc(&fence->usage); arg.handle = fence->base.hash.key; - break; + break; default: return -EINVAL; } diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c index 598f8772..9e8ae4a9 100644 --- a/linux-core/i915_buffer.c +++ b/linux-core/i915_buffer.c @@ -53,6 +53,10 @@ int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type) int i915_invalidate_caches(drm_device_t *dev, uint32_t flags) { + /* + * FIXME: Only emit once per batchbuffer submission. + */ + uint32_t flush_cmd = MI_NO_WRITE_FLUSH; if (flags & DRM_BO_FLAG_READ) @@ -60,5 +64,6 @@ int i915_invalidate_caches(drm_device_t *dev, uint32_t flags) if (flags & DRM_BO_FLAG_EXE) flush_cmd |= MI_EXE_FLUSH; + return i915_emit_mi_flush(dev, flush_cmd); } -- 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(-) 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(-) 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(-) 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. --- libdrm/xf86drm.c | 92 ++++++++++++++++++++++++++++--------------------- libdrm/xf86drm.h | 42 ---------------------- libdrm/xf86mm.h | 34 +++++++++++++++++- linux-core/drmP.h | 1 + linux-core/drm_bo.c | 36 ++++++++++--------- linux-core/drm_fence.c | 20 +++++++---- linux-core/i915_drv.c | 1 + linux-core/i915_fence.c | 31 ++++++++++++----- shared-core/drm.h | 7 ++-- shared-core/i915_irq.c | 8 ++--- 10 files changed, 151 insertions(+), 121 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 3a23eae2..2df74d14 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2240,16 +2240,20 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, #ifdef __linux__ -int drmFenceCreate(int fd, int shareable, int class,unsigned type, - int emit, +/* + * Valid flags are + * DRM_FENCE_FLAG_EMIT + * DRM_FENCE_FLAG_SHAREABLE + * DRM_FENCE_MASK_DRIVER + */ + +int drmFenceCreate(int fd, unsigned flags, int class,unsigned type, drmFence *fence) { drm_fence_arg_t arg; arg.type = type; arg.class = class; - arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0; - arg.flags |= (emit) ? DRM_FENCE_FLAG_EMIT : 0; arg.op = drm_fence_create; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; @@ -2261,11 +2265,17 @@ int drmFenceCreate(int fd, int shareable, int class,unsigned type, return 0; } -int drmFenceBuffers(int fd, int shareable, drmFence *fence) +/* + * Valid flags are + * DRM_FENCE_FLAG_SHAREABLE + * DRM_FENCE_MASK_DRIVER + */ + +int drmFenceBuffers(int fd, unsigned flags, drmFence *fence) { drm_fence_arg_t arg; - arg.flags = (shareable) ? DRM_FENCE_FLAG_SHAREABLE : 0; + arg.flags = flags; arg.op = drm_fence_buffers; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) return -errno; @@ -2299,7 +2309,7 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence) fence->handle = arg.handle; fence->class = arg.class; fence->type = arg.type; - fence->flags = 0; + fence->flags = arg.flags; fence->signaled = arg.signaled; return 0; } @@ -2363,12 +2373,18 @@ int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType, return 0; } +/* + * Valid flags are + * DRM_FENCE_FLAG_SHAREABLE + * DRM_FENCE_MASK_DRIVER + */ -int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) +int drmFenceEmit(int fd, unsigned flags, drmFence *fence, unsigned emit_type) { drm_fence_arg_t arg; + arg.flags = flags; arg.handle = fence->handle; arg.type = emit_type; arg.op = drm_fence_emit; @@ -2379,23 +2395,27 @@ int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type) fence->signaled = arg.signaled; return 0; } + +/* + * Valid flags are + * DRM_FENCE_FLAG_WAIT_LAZY + * DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS + */ -int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, - int lazy, int ignore_signals) +int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) { drm_fence_arg_t arg; int ret; if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) { - if (flush_type & fence->signaled == flush_type) { + if ((flush_type & fence->signaled) == flush_type) { return 0; } } arg.handle = fence->handle; arg.type = flush_type; - arg.flags = (lazy) ? DRM_FENCE_FLAG_WAIT_LAZY : 0; - arg.flags |= (ignore_signals) ? DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS : 0; + arg.flags = flags; arg.op = drm_fence_wait; do { ret = ioctl(fd, DRM_IOCTL_FENCE, &arg); @@ -2666,7 +2686,7 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, return -EINVAL; } req->op = drm_bo_create; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2700,7 +2720,7 @@ int drmBODestroy(int fd, drmBO *buf) arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_destroy; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2725,7 +2745,7 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) arg.handled = 0; req->handle = handle; req->op = drm_bo_reference; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2761,7 +2781,7 @@ int drmBOUnReference(int fd, drmBO *buf) arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unreference; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2813,7 +2833,7 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, req->mask = mapFlags; req->hint = mapHint; req->op = drm_bo_map; - req->next = 0; + arg.next = 0; /* * May hang if the buffer object is busy. @@ -2849,7 +2869,7 @@ int drmBOUnmap(int fd, drmBO *buf) arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_unmap; - req->next = 0; + arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) { return -errno; @@ -2876,12 +2896,12 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, req->hint = hint; req->arg_handle = mask; /* Encode mask in the arg_handle field :/ */ req->op = drm_bo_validate; - req->next = 0; + arg.next = 0; do{ ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); - } while (ret && errno == -EAGAIN); + } while (ret && errno == EAGAIN); if (ret) @@ -2908,7 +2928,7 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) req->mask = flags; req->arg_handle = fenceHandle; req->op = drm_bo_validate; - req->next = 0; + arg.next = 0; ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -2931,7 +2951,7 @@ int drmBOInfo(int fd, drmBO *buf) arg.handled = 0; req->handle = buf->handle; req->op = drm_bo_info; - req->next = 0; + arg.next = 0; ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -3044,20 +3064,14 @@ int drmBOValidateList(int fd, drmBOList *list) if (prevNext) *prevNext = (unsigned long) arg; - req->next = 0; - prevNext = &req->next; + arg->next = 0; + prevNext = &arg->next; arg->handled = 0; req->handle = node->buf->handle; req->op = drm_bo_validate; req->mask = node->arg0; req->hint = 0; - req->arg_handle = node->arg1 | DRM_BO_MASK_MEM; -#ifdef BODEBUG - fprintf(stderr, "Offset 0x%08x, Handle 0x%08x, " - "mask 0x%08x flags 0x%08x\n", - node->buf->offset, - req->handle, req->arg_handle, req->mask); -#endif + req->arg_handle = node->arg1; } if (!first) @@ -3065,7 +3079,7 @@ int drmBOValidateList(int fd, drmBOList *list) do{ ret = ioctl(fd, DRM_IOCTL_BUFOBJ, first); - } while (ret && errno == -EAGAIN); + } while (ret && errno == EAGAIN); if (ret) @@ -3076,17 +3090,15 @@ int drmBOValidateList(int fd, drmBOList *list) arg = &node->bo_arg; rep = &arg->d.rep; - if (!arg->handled) + if (!arg->handled) { + drmMsg("Unhandled request\n"); return -EFAULT; + } if (rep->ret) return rep->ret; buf = node->buf; drmBOCopyReply(rep, buf); -#ifdef BODEBUG - fprintf(stderr,"Offset 0x%08x, Flags 0x%08x\n", - buf->offset, buf->flags); -#endif } return 0; @@ -3120,8 +3132,8 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) if (prevNext) *prevNext = (unsigned long) arg; - req->next = 0; - prevNext = &req->next; + arg->next = 0; + prevNext = &arg->next; arg->handled = 0; req->handle = node->buf->handle; req->op = drm_bo_fence; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 1b136d31..d97681c0 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -280,23 +280,6 @@ typedef struct _drmSetVersion { int drm_dd_minor; } drmSetVersion, *drmSetVersionPtr; -typedef struct _drmFence{ - unsigned handle; - int class; - unsigned type; - unsigned flags; - unsigned signaled; -} drmFence; - -typedef struct _drmTTM{ - unsigned handle; - drm_handle_t user_token; - unsigned flags; - unsigned long size; - void *virtual; - int mapCount; -} drmTTM; - #define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) #define DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ @@ -614,31 +597,6 @@ extern int drmScatterGatherFree(int fd, drm_handle_t handle); extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); -/* Fencing */ - -extern int drmFenceCreate(int fd, int shareable, int class, - unsigned type, int emit, - drmFence *fence); -extern int drmFenceDestroy(int fd, const drmFence *fence); -extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); -extern int drmFenceUnreference(int fd, const drmFence *fence); -extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); -extern int drmFenceSignaled(int fd, drmFence *fence, - unsigned fenceType, int *signaled); -extern int drmFenceWait(int fd, drmFence *fence, unsigned flush_type, - int lazy, int ignore_signals); -extern int drmFenceEmit(int fd, drmFence *fence, unsigned emit_type); -extern int drmFenceBuffers(int fd, int shareable, drmFence *fence); - -/* TTMS */ -extern int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, - unsigned flags); -extern int drmTTMDestroy(int fd, const drmTTM *ttm); -extern int drmTTMReference(int fd, unsigned handle, drmTTM *ttm); -extern int drmTTMUnreference(int fd, const drmTTM *ttm); -extern drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm); - - /* Support routines */ extern int drmError(int err, const char *label); extern void *drmMalloc(int size); diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 24e28245..4cb37e23 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -93,7 +93,22 @@ typedef struct _drmMMListHead #define DRMLISTENTRY(__type, __item, __field) \ ((__type *)(((char *) (__item)) - offsetof(__type, __field))) - +typedef struct _drmFence{ + unsigned handle; + int class; + unsigned type; + unsigned flags; + unsigned signaled; +} drmFence; + +typedef struct _drmTTM{ + unsigned handle; + drm_handle_t user_token; + unsigned flags; + unsigned long size; + void *virtual; + int mapCount; +} drmTTM; typedef struct _drmBO{ drm_bo_type_t type; @@ -130,6 +145,23 @@ typedef struct _drmBOList { drmMMListHead free; } drmBOList; +/* Fencing */ + +extern int drmFenceCreate(int fd, unsigned flags, int class, + unsigned type, + drmFence *fence); +extern int drmFenceDestroy(int fd, const drmFence *fence); +extern int drmFenceReference(int fd, unsigned handle, drmFence *fence); +extern int drmFenceUnreference(int fd, const drmFence *fence); +extern int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type); +extern int drmFenceSignaled(int fd, drmFence *fence, + unsigned fenceType, int *signaled); +extern int drmFenceWait(int fd, unsigned flags, drmFence *fence, + unsigned flush_type); +extern int drmFenceEmit(int fd, unsigned flags, drmFence *fence, + unsigned emit_type); +extern int drmFenceBuffers(int fd, unsigned flags, drmFence *fence); + /* * TTM functions. diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 835b295a..d04a482b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -655,6 +655,7 @@ typedef struct drm_ref_object { typedef struct drm_bo_driver{ int cached_tt; int cached_vram; + drm_local_map_t *vram_map; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev, int cached); int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index f5a25c26..858a4cde 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -322,15 +322,15 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, bo->fence = NULL; return 0; } - if (no_wait) + if (no_wait) { return -EBUSY; - + } ret = drm_fence_object_wait(dev, fence, lazy, ignore_signals, bo->fence_flags); - if (ret) - return ret; - + if (ret) + return ret; + drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -360,9 +360,14 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) if (!tt && !bo->vram) goto out; + ret = drm_bo_wait(bo, 0, 0, no_wait); - if (ret) + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed to expire fence before " + "buffer eviction.\n"); goto out; + } if (tt) { ret = drm_move_tt_to_local(bo); @@ -420,7 +425,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, int tt, int no_wait) } while (1); if (!node) { - DRM_ERROR("Out of aperture space\n"); + DRM_ERROR("Out of videoram / aperture space\n"); mutex_unlock(&dev->struct_mutex); return -ENOMEM; } @@ -646,7 +651,7 @@ static int drm_bo_busy(drm_buffer_object_t * bo) bo->fence = NULL; return 0; } - drm_fence_object_flush(dev, fence, DRM_FENCE_EXE); + drm_fence_object_flush(dev, fence, DRM_FENCE_TYPE_EXE); if (drm_fence_object_signaled(fence, bo->fence_flags)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; @@ -981,11 +986,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_ERROR("Vram support not implemented yet\n"); return -EINVAL; } - if ((new_flags & (DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_MEM_VRAM)) && - (new_flags & DRM_BO_FLAG_CACHED)) { - DRM_ERROR("Cached binding not implemented yet\n"); - return -EINVAL; - } + DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); if (ret) { @@ -1003,8 +1004,11 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, return -EINVAL; } ret = drm_bo_move_buffer(bo, new_flags, no_wait); - if (ret) + if (ret) { + if (ret != -EAGAIN) + DRM_ERROR("Failed moving buffer.\n"); return ret; + } } if (move_unfenced) { @@ -1304,7 +1308,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(arg, (void __user *)data, sizeof(arg)); if (arg.handled) { - data = req->next; + data = arg.next; continue; } @@ -1404,7 +1408,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) default: rep.ret = -EINVAL; } - next = req->next; + next = arg.next; /* * A signal interrupted us. Make sure the ioctl is restartable. diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 9ade8114..5078e952 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -283,10 +283,10 @@ int drm_fence_object_flush(drm_device_t * dev, write_lock_irqsave(&fm->lock, flags); fence->flush_mask |= type; if (fence->submitted_flush == fence->signaled) { - if ((fence->type & DRM_FENCE_EXE) && - !(fence->submitted_flush & DRM_FENCE_EXE)) { + if ((fence->type & DRM_FENCE_TYPE_EXE) && + !(fence->submitted_flush & DRM_FENCE_TYPE_EXE)) { drm_fence_flush_exe(fm, driver, fence->sequence); - fence->submitted_flush |= DRM_FENCE_EXE; + fence->submitted_flush |= DRM_FENCE_TYPE_EXE; } else { fm->pending_flush |= (fence->flush_mask & ~fence->submitted_flush); @@ -362,7 +362,7 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, if (ret) return ((ret == -EINTR) ? -EAGAIN : ret); - } else if ((fence->class == 0) && (mask & DRM_FENCE_EXE) && + } else if ((fence->class == 0) && (mask & DRM_FENCE_TYPE_EXE) && driver->lazy_capable) { /* @@ -372,7 +372,7 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, do { DRM_WAIT_ON(ret, fm->fence_queue, 3 * DRM_HZ, - fence_signaled(dev, fence, DRM_FENCE_EXE, + fence_signaled(dev, fence, DRM_FENCE_TYPE_EXE, 1)); if (time_after_eq(jiffies, _end)) break; @@ -386,7 +386,15 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, if (fence_signaled(dev, fence, mask, 0)) return 0; - do { + /* + * Avoid kernel-space busy-waits. + */ +#if 1 + if (!ignore_signals) + return -EAGAIN; +#endif + do { + schedule(); signaled = fence_signaled(dev, fence, mask, 1); } while (!signaled && !time_after_eq(jiffies, _end)); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index fb4754d8..1718bb31 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -49,6 +49,7 @@ static drm_fence_driver_t i915_fence_driver = { }; static drm_bo_driver_t i915_bo_driver = { + .vram_map = NULL, .cached_vram = 0, .cached_tt = 1, .create_ttm_backend_entry = i915_create_ttm_backend_entry, diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 20e12d6a..5a8612cb 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -43,7 +43,6 @@ static void i915_perform_flush(drm_device_t * dev) drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; - int flush_completed = 0; uint32_t flush_flags = 0; uint32_t flush_sequence = 0; uint32_t i_status; @@ -52,9 +51,14 @@ static void i915_perform_flush(drm_device_t * dev) if (fm->pending_exe_flush) { sequence = READ_BREADCRUMB(dev_priv); + + /* + * First update fences with the current breadcrumb. + */ + diff = sequence - fm->last_exe_flush; if (diff < driver->wrap_diff && diff != 0) { - drm_fence_handler(dev, sequence, DRM_FENCE_EXE); + drm_fence_handler(dev, sequence, DRM_FENCE_TYPE_EXE); } diff = sequence - fm->exe_flush_sequence; @@ -69,20 +73,18 @@ static void i915_perform_flush(drm_device_t * dev) dev_priv->fence_irq_on = 1; } } + if (dev_priv->flush_pending) { i_status = READ_HWSP(dev_priv, 0); if ((i_status & (1 << 12)) != (dev_priv->saved_flush_status & (1 << 12))) { - flush_completed = 1; flush_flags = dev_priv->flush_flags; flush_sequence = dev_priv->flush_sequence; dev_priv->flush_pending = 0; - } else { - } - } - if (flush_completed) { - drm_fence_handler(dev, flush_sequence, flush_flags); + drm_fence_handler(dev, flush_sequence, flush_flags); + } } + if (fm->pending_flush && !dev_priv->flush_pending) { dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fm->pending_flush; @@ -91,6 +93,18 @@ static void i915_perform_flush(drm_device_t * dev) dev_priv->flush_pending = 1; fm->pending_flush = 0; } + + if (dev_priv->flush_pending) { + i_status = READ_HWSP(dev_priv, 0); + if ((i_status & (1 << 12)) != + (dev_priv->saved_flush_status & (1 << 12))) { + flush_flags = dev_priv->flush_flags; + flush_sequence = dev_priv->flush_sequence; + dev_priv->flush_pending = 0; + drm_fence_handler(dev, flush_sequence, flush_flags); + } + } + } void i915_poke_flush(drm_device_t * dev) @@ -117,7 +131,6 @@ void i915_fence_handler(drm_device_t * dev) write_lock(&fm->lock); i915_perform_flush(dev); - i915_perform_flush(dev); write_unlock(&fm->lock); } diff --git a/shared-core/drm.h b/shared-core/drm.h index d10b713b..b4dd61cb 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -643,7 +643,10 @@ typedef struct drm_set_version { #define DRM_FENCE_FLAG_WAIT_LAZY 0x00000004 #define DRM_FENCE_FLAG_WAIT_IGNORE_SIGNALS 0x00000008 -#define DRM_FENCE_EXE 0x00000001 +/* Reserved for driver use */ +#define DRM_FENCE_MASK_DRIVER 0xFF000000 + +#define DRM_FENCE_TYPE_EXE 0x00000001 typedef struct drm_fence_arg { unsigned handle; @@ -750,7 +753,6 @@ typedef struct drm_bo_arg_request { drm_bo_type_t type; unsigned arg_handle; drm_u64_t buffer_start; - drm_u64_t next; enum { drm_bo_create, drm_bo_validate, @@ -789,6 +791,7 @@ typedef struct drm_bo_arg_reply { typedef struct drm_bo_arg{ int handled; + drm_u64_t next; union { drm_bo_arg_request_t req; drm_bo_arg_reply_t rep; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 8f3e79de..51112b62 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -45,7 +45,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) temp = I915_READ16(I915REG_INT_IDENTITY_R); - temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); + temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG); #if 0 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); @@ -105,7 +105,6 @@ int i915_emit_irq(drm_device_t * dev) void i915_user_irq_on(drm_i915_private_t *dev_priv) { - return; spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){ dev_priv->irq_enable_reg |= USER_INT_FLAG; @@ -117,11 +116,10 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv) void i915_user_irq_off(drm_i915_private_t *dev_priv) { - return; spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { dev_priv->irq_enable_reg &= ~USER_INT_FLAG; - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } spin_unlock(&dev_priv->user_irq_lock); } @@ -241,7 +239,7 @@ static int i915_enable_interrupt (drm_device_t *dev) dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; dev_priv->user_irq_refcount = 0; dev_priv->irq_enable_reg = flag; - I915_WRITE16(I915REG_INT_ENABLE_R, flag | USER_INT_FLAG); + I915_WRITE16(I915REG_INT_ENABLE_R, flag); dev_priv->irq_enabled = 1; return 0; } -- 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 ++- shared-core/i915_drm.h | 2 + shared-core/i915_drv.h | 6 ++- 7 files changed, 73 insertions(+), 119 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index d04a482b..1d0b97ae 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -765,7 +765,9 @@ typedef struct drm_fence_driver{ uint32_t flush_diff; uint32_t sequence_mask; int lazy_capable; - int (*emit) (struct drm_device *dev, uint32_t *breadcrumb); + int (*emit) (struct drm_device *dev, uint32_t flags, + uint32_t *breadcrumb, + uint32_t *native_type); void (*poke_flush) (struct drm_device *dev); } drm_fence_driver_t; @@ -804,7 +806,7 @@ typedef struct drm_buffer_manager{ struct list_head ddestroy; struct list_head other; struct work_struct wq; - uint32_t fence_flags; + uint32_t fence_type; unsigned long max_pages; unsigned long cur_pages; } drm_buffer_manager_t; @@ -963,6 +965,7 @@ typedef struct drm_fence_object{ struct list_head ring; int class; + uint32_t native_type; volatile uint32_t type; volatile uint32_t signaled; uint32_t sequence; @@ -997,7 +1000,7 @@ typedef struct drm_buffer_object{ struct list_head head; struct list_head ddestroy; - uint32_t fence_flags; + uint32_t fence_type; uint32_t fence_class; drm_fence_object_t *fence; uint32_t priv_flags; @@ -1386,7 +1389,8 @@ extern void drm_fence_usage_deref_unlocked(drm_device_t * dev, extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask); extern int drm_fence_object_create(drm_device_t *dev, uint32_t type, - int emit, drm_fence_object_t **c_fence); + uint32_t fence_flags, + drm_fence_object_t **c_fence); extern int drm_fence_add_user_object(drm_file_t *priv, drm_fence_object_t *fence, int shareable); @@ -1406,6 +1410,7 @@ extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_clean_mm(drm_device_t *dev); extern int drm_fence_buffer_objects(drm_file_t * priv, struct list_head *list, + uint32_t fence_flags, drm_fence_object_t *fence, drm_fence_object_t **used_fence); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 858a4cde..d176392a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -94,9 +94,9 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) DRM_FLAG_MASKED(bo->priv_flags, 0, _DRM_BO_FLAG_UNFENCED); if (bo->fence) { - if (!drm_fence_object_signaled(bo->fence, bo->fence_flags)) { + if (!drm_fence_object_signaled(bo->fence, bo->fence_type)) { - drm_fence_object_flush(dev, bo->fence, bo->fence_flags); + drm_fence_object_flush(dev, bo->fence, bo->fence_type); list_add_tail(&bo->ddestroy, &bm->ddestroy); schedule_delayed_work(&bm->wq, ((DRM_HZ / 100) < @@ -144,7 +144,7 @@ static void drm_bo_delayed_delete(drm_device_t * dev) fence = entry->fence; if (fence && drm_fence_object_signaled(fence, - entry->fence_flags)) { + entry->fence_type)) { drm_fence_usage_deref_locked(dev, fence); entry->fence = NULL; } @@ -205,6 +205,7 @@ void drm_bo_usage_deref_unlocked(drm_device_t * dev, drm_buffer_object_t * bo) int drm_fence_buffer_objects(drm_file_t * priv, struct list_head *list, + uint32_t fence_flags, drm_fence_object_t * fence, drm_fence_object_t ** used_fence) { @@ -212,7 +213,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, drm_buffer_manager_t *bm = &dev->bm; drm_buffer_object_t *entry; - uint32_t fence_flags = 0; + uint32_t fence_type = 0; int count = 0; int ret = 0; struct list_head f_list, *l; @@ -224,7 +225,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_for_each_entry(entry, list, head) { BUG_ON(!(entry->priv_flags & _DRM_BO_FLAG_UNFENCED)); - fence_flags |= entry->fence_flags; + fence_type |= entry->fence_type; if (entry->fence_class != 0) { DRM_ERROR("Fence class %d is not implemented yet.\n", entry->fence_class); @@ -250,7 +251,7 @@ int drm_fence_buffer_objects(drm_file_t * priv, list_del_init(list); if (fence) { - if ((fence_flags & fence->type) != fence_flags) { + if ((fence_type & fence->type) != fence_type) { DRM_ERROR("Given fence doesn't match buffers " "on unfenced list.\n"); ret = -EINVAL; @@ -258,7 +259,9 @@ int drm_fence_buffer_objects(drm_file_t * priv, } } else { mutex_unlock(&dev->struct_mutex); - ret = drm_fence_object_create(dev, fence_flags, 1, &fence); + ret = drm_fence_object_create(dev, fence_type, + fence_flags | DRM_FENCE_FLAG_EMIT, + &fence); mutex_lock(&dev->struct_mutex); if (ret) goto out; @@ -317,7 +320,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -327,7 +330,7 @@ static int drm_bo_wait(drm_buffer_object_t * bo, int lazy, int ignore_signals, } ret = drm_fence_object_wait(dev, fence, lazy, ignore_signals, - bo->fence_flags); + bo->fence_type); if (ret) return ret; @@ -624,7 +627,7 @@ static int drm_bo_quick_busy(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -646,13 +649,13 @@ static int drm_bo_busy(drm_buffer_object_t * bo) BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { drm_device_t *dev = bo->dev; - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; } drm_fence_object_flush(dev, fence, DRM_FENCE_TYPE_EXE); - if (drm_fence_object_signaled(fence, bo->fence_flags)) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(dev, fence); bo->fence = NULL; return 0; @@ -776,7 +779,7 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, rep->mask = bo->mask; rep->buffer_start = bo->buffer_start; - rep->fence_flags = bo->fence_flags; + rep->fence_flags = bo->fence_type; rep->rep_flags = 0; if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { @@ -988,7 +991,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, } DRM_DEBUG("New flags 0x%08x, Old flags 0x%08x\n", new_flags, bo->flags); - ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_flags); + ret = driver->fence_type(new_flags, &bo->fence_class, &bo->fence_type); if (ret) { DRM_ERROR("Driver did not support given buffer permissions\n"); return ret; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 5078e952..5d051d4a 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -31,84 +31,35 @@ #include "drmP.h" -static void drm_fm_update_pointers(drm_fence_manager_t * fm, - struct list_head *list, int no_types, - uint32_t type) -{ - int i; - for (i = 0; i < no_types; ++i) { - if (type & (1 << i)) { - fm->fence_types[i] = list; - } - } -} - /* * Typically called by the IRQ handler. */ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) { - int i; int wake = 0; - int largest = 0; uint32_t diff; uint32_t relevant; - int index = 0; drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; - struct list_head *list; - struct list_head *fence_list; + struct list_head *list, *prev; drm_fence_object_t *fence; - int found = 0; - - for (i = 0; i < driver->no_types; ++i) { - if (!(type & (1 << i))) - continue; - - list = fm->fence_types[i]; - fence_list = list->next; - - if (fence_list == &fm->ring) - continue; - - fence = list_entry(fence_list, drm_fence_object_t, ring); + list_for_each_entry(fence, &fm->ring, ring) { diff = (sequence - fence->sequence) & driver->sequence_mask; - - if (diff < driver->wrap_diff) { - if (diff >= largest) { - largest = diff; - index = i; - found = 1; - } - } + if (diff > driver->wrap_diff) + break; } - if (!found) - return; + list = fence->ring.prev; + prev = list->prev; - /* - * Start with the fence object with the lowest sequence number, affected by - * the type mask of this call. Update signaled fields, - * Check if we need to wake sleeping processes - */ - - list = fm->fence_types[index]->next; - do { - if (list == &fm->ring) { - drm_fm_update_pointers(fm, list->prev, - driver->no_types, type); - break; - } + for (; list != &fm->ring; list = prev, prev = list->prev) { fence = list_entry(list, drm_fence_object_t, ring); - diff = (sequence - fence->sequence) & driver->sequence_mask; - if (diff >= driver->wrap_diff) { - drm_fm_update_pointers(fm, fence->ring.prev, - driver->no_types, type); - break; - } + + type |= fence->native_type; relevant = type & fence->type; + if ((fence->signaled | relevant) != fence->signaled) { fence->signaled |= relevant; DRM_DEBUG("Fence 0x%08lx signaled 0x%08x\n", @@ -119,35 +70,20 @@ void drm_fence_handler(drm_device_t * dev, uint32_t sequence, uint32_t type) relevant = fence->flush_mask & ~(fence->signaled | fence->submitted_flush); + if (relevant) { fm->pending_flush |= relevant; fence->submitted_flush = fence->flush_mask; } - list = list->next; - - /* - * Remove a completely signaled fence from the - * fence manager ring. - */ - if (!(fence->type & ~fence->signaled)) { DRM_DEBUG("Fence completely signaled 0x%08lx\n", fence->base.hash.key); - fence_list = &fence->ring; - for (i = 0; i < driver->no_types; ++i) { - if (fm->fence_types[i] == fence_list) - fm->fence_types[i] = fence_list->prev; - } - list_del_init(fence_list); + list_del_init(&fence->ring); } - } while (1); - - /* - * Wake sleeping processes. - */ - + } + if (wake) { DRM_WAKEUP(&fm->fence_queue); } @@ -158,15 +94,9 @@ EXPORT_SYMBOL(drm_fence_handler); static void drm_fence_unring(drm_device_t * dev, struct list_head *ring) { drm_fence_manager_t *fm = &dev->fm; - drm_fence_driver_t *driver = dev->driver->fence_driver; unsigned long flags; - int i; write_lock_irqsave(&fm->lock, flags); - for (i = 0; i < driver->no_types; ++i) { - if (fm->fence_types[i] == ring) - fm->fence_types[i] = ring->prev; - } list_del_init(ring); write_unlock_irqrestore(&fm->lock, flags); } @@ -235,7 +165,8 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, * Last_exe_flush is invalid. Find oldest sequence. */ - list = fm->fence_types[_DRM_FENCE_TYPE_EXE]; +/* list = fm->fence_types[_DRM_FENCE_TYPE_EXE];*/ + list = &fm->ring; if (list->next == &fm->ring) { return; } else { @@ -405,16 +336,17 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, } int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, - uint32_t type) + uint32_t fence_flags, uint32_t type) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; unsigned long flags; uint32_t sequence; + uint32_t native_type; int ret; drm_fence_unring(dev, &fence->ring); - ret = driver->emit(dev, &sequence); + ret = driver->emit(dev, fence_flags, &sequence, &native_type); if (ret) return ret; @@ -424,13 +356,15 @@ int drm_fence_object_emit(drm_device_t * dev, drm_fence_object_t * fence, fence->submitted_flush = 0x00; fence->signaled = 0x00; fence->sequence = sequence; + fence->native_type = native_type; list_add_tail(&fence->ring, &fm->ring); write_unlock_irqrestore(&fm->lock, flags); return 0; } -int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, - drm_fence_object_t * fence) +static int drm_fence_object_init(drm_device_t * dev, uint32_t type, + uint32_t fence_flags, + drm_fence_object_t * fence) { int ret = 0; unsigned long flags; @@ -449,13 +383,12 @@ int drm_fence_object_init(drm_device_t * dev, uint32_t type, int emit, fence->signaled = 0; fence->sequence = 0; write_unlock_irqrestore(&fm->lock, flags); - if (emit) { - ret = drm_fence_object_emit(dev, fence, type); + if (fence_flags & DRM_FENCE_FLAG_EMIT) { + ret = drm_fence_object_emit(dev, fence, fence_flags, type); } return ret; } -EXPORT_SYMBOL(drm_fence_object_init); int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence, int shareable) @@ -477,7 +410,7 @@ int drm_fence_add_user_object(drm_file_t * priv, drm_fence_object_t * fence, EXPORT_SYMBOL(drm_fence_add_user_object); int drm_fence_object_create(drm_device_t * dev, uint32_t type, - int emit, drm_fence_object_t ** c_fence) + unsigned flags, drm_fence_object_t ** c_fence) { drm_fence_object_t *fence; int ret; @@ -485,7 +418,7 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) return -ENOMEM; - ret = drm_fence_object_init(dev, type, emit, fence); + ret = drm_fence_object_init(dev, type, flags, fence); if (ret) { drm_fence_usage_deref_unlocked(dev, fence); return ret; @@ -559,7 +492,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) if (arg.flags & DRM_FENCE_FLAG_EMIT) LOCK_TEST_WITH_RETURN(dev, filp); ret = drm_fence_object_create(dev, arg.type, - arg.flags & DRM_FENCE_FLAG_EMIT, + arg.flags, &fence); if (ret) return ret; @@ -623,7 +556,7 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) fence = drm_lookup_fence_object(priv, arg.handle); if (!fence) return -EINVAL; - ret = drm_fence_object_emit(dev, fence, arg.type); + ret = drm_fence_object_emit(dev, fence, arg.flags, arg.type); break; case drm_fence_buffers: if (!dev->bm.initialized) { @@ -631,7 +564,8 @@ int drm_fence_ioctl(DRM_IOCTL_ARGS) return -EINVAL; } LOCK_TEST_WITH_RETURN(dev, filp); - ret = drm_fence_buffer_objects(priv, NULL, NULL, &fence); + ret = drm_fence_buffer_objects(priv, NULL, arg.flags, + NULL, &fence); if (ret) return ret; ret = drm_fence_add_user_object(priv, fence, diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 69ce2291..8619defb 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -201,7 +201,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; else - new = context | _DRM_LOCK_HELD; + new = context | _DRM_LOCK_HELD | _DRM_LOCK_CONT; prev = cmpxchg(lock, old, new); } while (prev != old); if (_DRM_LOCKING_CONTEXT(old) == context) { @@ -213,7 +213,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context) return 0; } } - if (new == (context | _DRM_LOCK_HELD)) { + if (new == (context | _DRM_LOCK_HELD | _DRM_LOCK_CONT)) { /* Have lock */ return 1; } diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 5a8612cb..8a3f81fe 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -86,6 +86,7 @@ static void i915_perform_flush(drm_device_t * dev) } if (fm->pending_flush && !dev_priv->flush_pending) { + DRM_ERROR("Sync flush"); dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fm->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); @@ -117,11 +118,16 @@ void i915_poke_flush(drm_device_t * dev) write_unlock_irqrestore(&fm->lock, flags); } -int i915_fence_emit_sequence(drm_device_t * dev, uint32_t * sequence) +int i915_fence_emit_sequence(drm_device_t * dev, uint32_t flags, + uint32_t * sequence, uint32_t *native_type) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; i915_emit_irq(dev); *sequence = (uint32_t) dev_priv->counter; + *native_type = DRM_FENCE_TYPE_EXE; + if (flags & DRM_I915_FENCE_FLAG_FLUSHED) + *native_type |= DRM_I915_FENCE_TYPE_RW; + return 0; } diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 1a79d403..e841105b 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -113,6 +113,8 @@ typedef struct _drm_i915_sarea { #define DRM_I915_FENCE_CLASS_ACCEL 0 /* Fence type that guarantees read-write flush */ #define DRM_I915_FENCE_TYPE_RW 2 +/* MI_FLUSH programmed just before the fence */ +#define DRM_I915_FENCE_FLAG_FLUSHED 0x01000000 /* Flags for perf_boxes */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 2aa3b947..65e80591 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -157,8 +157,12 @@ extern void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap); #ifdef I915_HAVE_FENCE /* i915_fence.c */ + + extern void i915_fence_handler(drm_device_t *dev); -extern int i915_fence_emit_sequence(drm_device_t *dev, uint32_t *sequence); +extern int i915_fence_emit_sequence(drm_device_t *dev, uint32_t flags, + uint32_t *sequence, + uint32_t *native_type); extern void i915_poke_flush(drm_device_t *dev); extern void i915_sync_flush(drm_device_t *dev); #endif -- cgit v1.2.3 From 6ba9127753eff7615ba553fbc567aec98ecf8104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 15 Sep 2006 16:37:47 +0200 Subject: Use register writes instead of BITBLT_MULTI packets for buffer swap blits. This takes up two more ring buffer entries per rectangle blitted but makes sure the blit is performed top to bottom, reducing the likelyhood of tearing. --- shared-core/radeon_drv.h | 3 +++ shared-core/radeon_state.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h index 5fc93310..6ea2a175 100644 --- a/shared-core/radeon_drv.h +++ b/shared-core/radeon_drv.h @@ -423,6 +423,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t *dev, DRMFILE filp, #define RADEON_RB3D_COLOROFFSET 0x1c40 #define RADEON_RB3D_COLORPITCH 0x1c48 +#define RADEON_SRC_X_Y 0x1590 + #define RADEON_DP_GUI_MASTER_CNTL 0x146c # define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) # define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) @@ -440,6 +442,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t *dev, DRMFILE filp, # define RADEON_ROP3_S 0x00cc0000 # define RADEON_ROP3_P 0x00f00000 #define RADEON_DP_WRITE_MASK 0x16cc +#define RADEON_SRC_PITCH_OFFSET 0x1428 #define RADEON_DST_PITCH_OFFSET 0x142c #define RADEON_DST_PITCH_OFFSET_C 0x1c80 # define RADEON_DST_TILE_LINEAR (0 << 30) diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 0a196c06..5b1ca539 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -1262,9 +1262,9 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h); - BEGIN_RING(7); + BEGIN_RING(9); - OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5)); + OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0)); OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_DST_PITCH_OFFSET_CNTL | RADEON_GMC_BRUSH_NONE | @@ -1276,6 +1276,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) /* Make this work even if front & back are flipped: */ + OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1)); if (dev_priv->current_page == 0) { OUT_RING(dev_priv->back_pitch_offset); OUT_RING(dev_priv->front_pitch_offset); @@ -1284,6 +1285,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev) OUT_RING(dev_priv->back_pitch_offset); } + OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2)); OUT_RING((x << 16) | y); OUT_RING((x << 16) | y); OUT_RING((w << 16) | h); -- cgit v1.2.3 From ef98a8e20dad8ae7e38f397d63c13bd24105ce53 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 18 Sep 2006 21:22:12 +1000 Subject: drm: put domain number back to 0, domain support is seriously fubar.. --- linux-core/drmP.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 70bf3495..a955c3de 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -777,7 +777,7 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev, #ifdef __alpha__ #define drm_get_pci_domain(dev) dev->hose->bus->number #else -#define drm_get_pci_domain(dev) pci_domain_nr(dev->pdev->bus) +#define drm_get_pci_domain(dev) 0 #endif #if __OS_HAS_AGP -- 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. --- libdrm/xf86drm.c | 34 +++++++++++++++++++++++++++++++++- libdrm/xf86mm.h | 4 ++-- linux-core/drm_fence.c | 6 ++++-- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 2df74d14..606f098b 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2407,6 +2407,10 @@ int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) drm_fence_arg_t arg; int ret; + if (flush_type == 0) { + flush_type = fence->type; + } + if (!(fence->flags & DRM_FENCE_FLAG_SHAREABLE)) { if ((flush_type & fence->signaled) == flush_type) { return 0; @@ -2964,8 +2968,36 @@ int drmBOInfo(int fd, drmBO *buf) drmBOCopyReply(rep, buf); return 0; } + +int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint) +{ + drm_bo_arg_t arg; + drm_bo_arg_request_t *req = &arg.d.req; + drm_bo_arg_reply_t *rep = &arg.d.rep; + int ret = 0; + + if ((buf->flags & DRM_BO_FLAG_SHAREABLE) || + (buf->replyFlags & DRM_BO_REP_BUSY)) { + arg.handled = 0; + req->handle = buf->handle; + req->op = drm_bo_wait_idle; + req->hint = hint; + arg.next = 0; + + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + + if (ret) + return ret; + if (!arg.handled) + return -EFAULT; + if (rep->ret) + return rep->ret; + drmBOCopyReply(rep, buf); + } + return 0; +} -int drmBufBusy(int fd, drmBO *buf, int *busy) +int drmBOBusy(int fd, drmBO *buf, int *busy) { if (!(buf->flags & DRM_BO_FLAG_SHAREABLE) && !(buf->replyFlags & DRM_BO_REP_BUSY)) { diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 4cb37e23..a62aef47 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -202,7 +202,7 @@ extern int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, unsigned hint); extern int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle); extern int drmBOInfo(int fd, drmBO *buf); -extern int drmBufBusy(int fd, drmBO *buf, int *busy); +extern int drmBOBusy(int fd, drmBO *buf, int *busy); extern int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, @@ -210,7 +210,7 @@ extern int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, int *newItem); extern int drmBOValidateList(int fd, drmBOList *list); extern int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle); - +extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint); /* * Initialization functions. diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 5d051d4a..41fe62a8 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -207,7 +207,8 @@ int drm_fence_object_flush(drm_device_t * dev, unsigned long flags; if (type & ~fence->type) { - DRM_ERROR("Flush trying to extend fence type\n"); + DRM_ERROR("Flush trying to extend fence type, " + "0x%x, 0x%x\n", type, fence->type); return -EINVAL; } @@ -269,7 +270,8 @@ int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, int signaled; if (mask & ~fence->type) { - DRM_ERROR("Wait trying to extend fence type\n"); + DRM_ERROR("Wait trying to extend fence type" + " 0x%08x 0x%08x\n", mask, fence->type); return -EINVAL; } -- 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. --- libdrm/xf86drm.c | 6 ++++-- linux-core/drm_bo.c | 4 +++- linux-core/drm_compat.c | 14 ++++++++++++++ linux-core/i915_fence.c | 1 - 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 606f098b..a7d4beb4 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2984,8 +2984,10 @@ int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint) req->hint = hint; arg.next = 0; - ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); - + do { + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret && errno == EAGAIN); + if (ret) return ret; if (!arg.handled) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d176392a..8e51985e 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1115,6 +1115,7 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, if (!bo) { return -EINVAL; } + mutex_lock(&bo->mutex); ret = drm_bo_wait_unfenced(bo, no_wait, 0); if (ret) @@ -1124,10 +1125,11 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, goto out; drm_bo_fill_rep_arg(bo, rep); + out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(bo->dev, bo); - return 0; + return ret; } /* diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index d387678e..e56f6608 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -124,6 +124,7 @@ static inline void change_pud_range(struct mm_struct *mm, pgd_t * pgd, * This function should be called with all relevant spinlocks held. */ +#if 1 void drm_clear_vma(struct vm_area_struct *vma, unsigned long addr, unsigned long end) { @@ -146,6 +147,19 @@ void drm_clear_vma(struct vm_area_struct *vma, flush_tlb_range(vma, addr, end); #endif } +#else + +void drm_clear_vma(struct vm_area_struct *vma, + unsigned long addr, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + + spin_unlock(&mm->page_table_lock); + (void) zap_page_range(vma, addr, end - addr, NULL); + spin_lock(&mm->page_table_lock); +} +#endif + pgprot_t vm_get_page_prot(unsigned long vm_flags) { diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 8a3f81fe..7491a672 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -86,7 +86,6 @@ static void i915_perform_flush(drm_device_t * dev) } if (fm->pending_flush && !dev_priv->flush_pending) { - DRM_ERROR("Sync flush"); dev_priv->flush_sequence = (uint32_t) READ_BREADCRUMB(dev_priv); dev_priv->flush_flags = fm->pending_flush; dev_priv->saved_flush_status = READ_HWSP(dev_priv, 0); -- 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(-) 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. --- libdrm/xf86mm.h | 4 ++-- linux-core/drmP.h | 2 +- linux-core/drm_proc.c | 5 +++-- shared-core/drm.h | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index a62aef47..c0e4f1b6 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -103,7 +103,7 @@ typedef struct _drmFence{ typedef struct _drmTTM{ unsigned handle; - drm_handle_t user_token; + drm_u64_t user_token; unsigned flags; unsigned long size; void *virtual; @@ -113,7 +113,7 @@ typedef struct _drmTTM{ typedef struct _drmBO{ drm_bo_type_t type; unsigned handle; - drm_handle_t mapHandle; + drm_u64_t mapHandle; unsigned flags; unsigned mask; unsigned mapFlags; diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1d0b97ae..91be9d17 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -538,7 +538,7 @@ typedef struct drm_map_list { struct list_head head; /**< list head */ drm_hash_item_t hash; drm_map_t *map; /**< mapping */ - unsigned int user_token; + drm_u64_t user_token; } drm_map_list_t; typedef drm_map_t drm_local_map_t; diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 512a8f75..2efade26 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -238,10 +238,11 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request, type = "??"; else type = types[map->type]; - DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08x ", + DRM_PROC_PRINT("%4d 0x%16lx 0x%16lx %4.4s 0x%02x 0x%16lx ", i, map->offset, - map->size, type, map->flags, r_list->user_token); + map->size, type, map->flags, + (unsigned long) r_list->user_token); if (map->mtrr < 0) { DRM_PROC_PRINT("none\n"); diff --git a/shared-core/drm.h b/shared-core/drm.h index b4dd61cb..8ac5a31e 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -677,7 +677,7 @@ typedef struct drm_ttm_arg { drm_ttm_unreference } op; unsigned handle; - unsigned user_token; + drm_u64_t user_token; drm_u64_t size; unsigned flags; }drm_ttm_arg_t; @@ -781,7 +781,7 @@ typedef struct drm_bo_arg_reply { unsigned flags; drm_u64_t size; drm_u64_t offset; - unsigned arg_handle; + drm_u64_t arg_handle; unsigned mask; drm_u64_t buffer_start; unsigned fence_flags; -- cgit v1.2.3 From 1f71b8d7a456fe3ec4bfc2fed70b7420cdd0d55a Mon Sep 17 00:00:00 2001 From: Roland Scheidegger Date: Wed, 20 Sep 2006 19:44:57 +0200 Subject: do a TCL state flush before accessing VAP_CNTL to prevent lockups on r200 when enabling/disabling vertex programs --- shared-core/radeon_state.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index 5b1ca539..b4478019 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -174,6 +174,14 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * } break; + case R200_EMIT_VAP_CTL: { + RING_LOCALS; + BEGIN_RING(2); + OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0); + ADVANCE_RING(); + } + break; + case RADEON_EMIT_RB3D_COLORPITCH: case RADEON_EMIT_RE_LINE_PATTERN: case RADEON_EMIT_SE_LINE_WIDTH: @@ -201,7 +209,6 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t * case R200_EMIT_TCL_LIGHT_MODEL_CTL_0: case R200_EMIT_TFACTOR_0: case R200_EMIT_VTX_FMT_0: - case R200_EMIT_VAP_CTL: case R200_EMIT_MATRIX_SELECT_0: case R200_EMIT_TEX_PROC_CTL_2: case R200_EMIT_TCL_UCP_VERT_BLEND_CTL: -- cgit v1.2.3 From 255f3e6f76dfd267a14765dd1293229184298d89 Mon Sep 17 00:00:00 2001 From: Anish Mistry Date: Fri, 22 Sep 2006 03:43:34 +1000 Subject: bug 7092 : add pci ids for mach64 in Dell poweredge 4200 --- shared-core/drm_pciids.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt index 9e0c0992..c597708d 100644 --- a/shared-core/drm_pciids.txt +++ b/shared-core/drm_pciids.txt @@ -186,6 +186,7 @@ 0x1002 0x4c51 0 "3D Rage LT Pro" 0x1002 0x4c42 0 "3D Rage LT Pro AGP-133" 0x1002 0x4c44 0 "3D Rage LT Pro AGP-66" +0x1002 0x4759 0 "Rage 3D IICATI 3D RAGE IIC AGP(A12/A13) 0x1002 0x474c 0 "Rage XC" 0x1002 0x474f 0 "Rage XL" 0x1002 0x4752 0 "Rage XL" -- cgit v1.2.3 From 62f6ea225615392098dedee47d4ccdd69e126a43 Mon Sep 17 00:00:00 2001 From: Felix Kuhling Date: Fri, 22 Sep 2006 03:46:54 +1000 Subject: bug 5942: add stubs for drm_mtrr_add/del for non-MTRR configured linux --- linux-core/drmP.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index a955c3de..fd48059a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -810,6 +810,18 @@ static inline int drm_mtrr_del(int handle, unsigned long offset, } #else +static inline int drm_mtrr_add(unsigned long offset, unsigned long size, + unsigned int flags) +{ + return -ENODEV; +} + +static inline int drm_mtrr_del(int handle, unsigned long offset, + unsigned long size, unsigned int flags) +{ + return -ENODEV; +} + #define drm_core_has_MTRR(dev) (0) #endif -- 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(-) 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 +++ shared-core/i915_drv.h | 1 - 6 files changed, 122 insertions(+), 19 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 91be9d17..c8297228 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -789,6 +789,7 @@ typedef struct drm_fence_manager{ int pending_exe_flush; uint32_t last_exe_flush; uint32_t exe_flush_sequence; + atomic_t count; } drm_fence_manager_t; typedef struct drm_buffer_manager{ @@ -809,6 +810,7 @@ typedef struct drm_buffer_manager{ uint32_t fence_type; unsigned long max_pages; unsigned long cur_pages; + atomic_t count; } drm_buffer_manager_t; @@ -966,11 +968,11 @@ typedef struct drm_fence_object{ struct list_head ring; int class; uint32_t native_type; - volatile uint32_t type; - volatile uint32_t signaled; + uint32_t type; + uint32_t signaled; uint32_t sequence; - volatile uint32_t flush_mask; - volatile uint32_t submitted_flush; + uint32_t flush_mask; + uint32_t submitted_flush; } drm_fence_object_t; @@ -1380,13 +1382,16 @@ extern void drm_fence_manager_init(drm_device_t *dev); extern void drm_fence_manager_takedown(drm_device_t *dev); extern void drm_fence_flush_old(drm_device_t *dev, uint32_t sequence); extern int drm_fence_object_flush(drm_device_t * dev, - drm_fence_object_t * fence, uint32_t type); -extern int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type); + volatile drm_fence_object_t * fence, + uint32_t type); +extern int drm_fence_object_signaled(volatile drm_fence_object_t * fence, + uint32_t type); extern void drm_fence_usage_deref_locked(drm_device_t * dev, drm_fence_object_t * fence); extern void drm_fence_usage_deref_unlocked(drm_device_t * dev, drm_fence_object_t * fence); -extern int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, +extern int drm_fence_object_wait(drm_device_t * dev, + volatile drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask); extern int drm_fence_object_create(drm_device_t *dev, uint32_t type, uint32_t fence_flags, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 8e51985e..f479c81a 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -128,6 +128,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) if (bo->ttm_object) { drm_ttm_object_deref_locked(dev, bo->ttm_object); } + atomic_dec(&bm->count); drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); } @@ -140,6 +141,10 @@ static void drm_bo_delayed_delete(drm_device_t * dev) mutex_lock(&dev->struct_mutex); + /* + * FIXME: Lock buffer object mutex. + */ + list_for_each_entry_safe(entry, next, &bm->ddestroy, ddestroy) { fence = entry->fence; @@ -1207,7 +1212,7 @@ int drm_buffer_object_create(drm_file_t * priv, uint32_t new_flags; unsigned long num_pages; - drm_bo_delayed_delete(dev); + // drm_bo_delayed_delete(dev); if ((buffer_start & ~PAGE_MASK) && (type != drm_bo_type_fake)) { DRM_ERROR("Invalid buffer object start.\n"); @@ -1259,6 +1264,7 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_unlock(&bo->mutex); *buf_obj = bo; + atomic_inc(&bm->count); return 0; out_err: @@ -1576,6 +1582,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) INIT_WORK(&bm->wq, &drm_bo_delayed_workqueue, dev); bm->initialized = 1; + atomic_set(&bm->count, 0); bm->cur_pages = 0; bm->max_pages = arg.req.max_locked_pages; break; diff --git a/linux-core/drm_fence.c b/linux-core/drm_fence.c index 0640e755..ca6c8576 100644 --- a/linux-core/drm_fence.c +++ b/linux-core/drm_fence.c @@ -111,10 +111,13 @@ static void drm_fence_unring(drm_device_t * dev, struct list_head *ring) void drm_fence_usage_deref_locked(drm_device_t * dev, drm_fence_object_t * fence) { + drm_fence_manager_t *fm = &dev->fm; + if (atomic_dec_and_test(&fence->usage)) { drm_fence_unring(dev, &fence->ring); DRM_DEBUG("Destroyed a fence object 0x%08lx\n", fence->base.hash.key); + atomic_dec(&fm->count); kmem_cache_free(drm_cache.fence_object, fence); } } @@ -122,10 +125,13 @@ void drm_fence_usage_deref_locked(drm_device_t * dev, void drm_fence_usage_deref_unlocked(drm_device_t * dev, drm_fence_object_t * fence) { + drm_fence_manager_t *fm = &dev->fm; + if (atomic_dec_and_test(&fence->usage)) { mutex_lock(&dev->struct_mutex); if (atomic_read(&fence->usage) == 0) { drm_fence_unring(dev, &fence->ring); + atomic_dec(&fm->count); kmem_cache_free(drm_cache.fence_object, fence); } mutex_unlock(&dev->struct_mutex); @@ -142,7 +148,8 @@ static void drm_fence_object_destroy(drm_file_t * priv, drm_fence_usage_deref_locked(dev, fence); } -static int fence_signaled(drm_device_t * dev, drm_fence_object_t * fence, +static int fence_signaled(drm_device_t * dev, volatile + drm_fence_object_t * fence, uint32_t mask, int poke_flush) { unsigned long flags; @@ -166,7 +173,7 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, uint32_t diff; if (!fm->pending_exe_flush) { - struct list_head *list; + volatile struct list_head *list; /* * Last_exe_flush is invalid. Find oldest sequence. @@ -196,18 +203,15 @@ static void drm_fence_flush_exe(drm_fence_manager_t * fm, } } -int drm_fence_object_signaled(drm_fence_object_t * fence, uint32_t type) +int drm_fence_object_signaled(volatile drm_fence_object_t * fence, + uint32_t type) { return ((fence->signaled & type) == type); } -/* - * Make sure old fence objects are signaled before their fence sequences are - * wrapped around and reused. - */ - int drm_fence_object_flush(drm_device_t * dev, - drm_fence_object_t * fence, uint32_t type) + volatile drm_fence_object_t * fence, + uint32_t type) { drm_fence_manager_t *fm = &dev->fm; drm_fence_driver_t *driver = dev->driver->fence_driver; @@ -237,6 +241,12 @@ int drm_fence_object_flush(drm_device_t * dev, return 0; } +/* + * Make sure old fence objects are signaled before their fence sequences are + * wrapped around and reused. + */ + + void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) { drm_fence_manager_t *fm = &dev->fm; @@ -267,7 +277,8 @@ void drm_fence_flush_old(drm_device_t * dev, uint32_t sequence) EXPORT_SYMBOL(drm_fence_flush_old); -int drm_fence_object_wait(drm_device_t * dev, drm_fence_object_t * fence, +int drm_fence_object_wait(drm_device_t * dev, + volatile drm_fence_object_t * fence, int lazy, int ignore_signals, uint32_t mask) { drm_fence_manager_t *fm = &dev->fm; @@ -426,6 +437,8 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, { drm_fence_object_t *fence; int ret; + drm_fence_manager_t *fm = &dev->fm; + unsigned long fl; fence = kmem_cache_alloc(drm_cache.fence_object, GFP_KERNEL); if (!fence) @@ -436,6 +449,8 @@ int drm_fence_object_create(drm_device_t * dev, uint32_t type, return ret; } *c_fence = fence; + atomic_inc(&fm->count); + return 0; } @@ -448,16 +463,19 @@ void drm_fence_manager_init(drm_device_t * dev) int i; fm->lock = RW_LOCK_UNLOCKED; + write_lock(&fm->lock); INIT_LIST_HEAD(&fm->ring); fm->pending_flush = 0; DRM_INIT_WAITQUEUE(&fm->fence_queue); fm->initialized = 0; if (fed) { fm->initialized = 1; + atomic_set(&fm->count,0); for (i = 0; i < fed->no_types; ++i) { fm->fence_types[i] = &fm->ring; } } + write_unlock(&fm->lock); } void drm_fence_manager_takedown(drm_device_t * dev) diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c index 6a0ee4fe..488d1e71 100644 --- a/linux-core/drm_proc.c +++ b/linux-core/drm_proc.c @@ -49,6 +49,8 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); static int drm_bufs_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); +static int drm_objects_info(char *buf, char **start, off_t offset, + int request, int *eof, void *data); #if DRM_DEBUG_CODE static int drm_vma_info(char *buf, char **start, off_t offset, int request, int *eof, void *data); @@ -67,6 +69,7 @@ static struct drm_proc_list { {"clients", drm_clients_info}, {"queues", drm_queues_info}, {"bufs", drm_bufs_info}, + {"objects", drm_objects_info}, #if DRM_DEBUG_CODE {"vma", drm_vma_info}, #endif @@ -418,6 +421,74 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request, return ret; } +/** + * Called when "/proc/dri/.../objects" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + */ +static int drm__objects_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *) data; + int len = 0; + drm_buffer_manager_t *bm = &dev->bm; + drm_fence_manager_t *fm = &dev->fm; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *start = &buf[offset]; + *eof = 0; + + if (fm->initialized) { + DRM_PROC_PRINT("Number of active fence objects: %d.\n\n", + atomic_read(&fm->count)); + } else { + DRM_PROC_PRINT("Fence objects are not supported by this driver\n\n"); + } + + if (bm->initialized) { + DRM_PROC_PRINT("Number of active buffer objects: %d.\n\n", + atomic_read(&bm->count)); + DRM_PROC_PRINT("Number of locked GATT pages: %lu.\n", bm->cur_pages); + DRM_PROC_PRINT("Max allowed number of locked GATT pages %lu\n", + bm->max_pages); + } else { + DRM_PROC_PRINT("Buffer objects are not supported by this driver.\n\n"); + } + + + DRM_PROC_PRINT("\n"); + + if (len > request + offset) + return request; + *eof = 1; + return len - offset; +} + +/** + * Simply calls _objects_info() while holding the drm_device::struct_mutex lock. + */ +static int drm_objects_info(char *buf, char **start, off_t offset, int request, + int *eof, void *data) +{ + drm_device_t *dev = (drm_device_t *) data; + int ret; + + mutex_lock(&dev->struct_mutex); + ret = drm__objects_info(buf, start, offset, request, eof, data); + mutex_unlock(&dev->struct_mutex); + return ret; +} + /** * Called when "/proc/dri/.../clients" is read. * diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c index 7491a672..49dc254f 100644 --- a/linux-core/i915_fence.c +++ b/linux-core/i915_fence.c @@ -49,6 +49,9 @@ static void i915_perform_flush(drm_device_t * dev) uint32_t diff; uint32_t sequence; + if (!dev_priv) + return; + if (fm->pending_exe_flush) { sequence = READ_BREADCRUMB(dev_priv); diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 65e80591..402ad5b1 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -164,7 +164,6 @@ extern int i915_fence_emit_sequence(drm_device_t *dev, uint32_t flags, uint32_t *sequence, uint32_t *native_type); extern void i915_poke_flush(drm_device_t *dev); -extern void i915_sync_flush(drm_device_t *dev); #endif #ifdef I915_HAVE_BUFFER -- 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(-) 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(-) 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 bd8ca12b7baff778d5bb7b4ad1d38d16b60a4d5a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 26 Sep 2006 16:00:22 +0200 Subject: Silence valgrind. --- libdrm/xf86drm.c | 58 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a7d4beb4..31d1c164 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2252,6 +2252,7 @@ int drmFenceCreate(int fd, unsigned flags, int class,unsigned type, { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.type = type; arg.class = class; arg.op = drm_fence_create; @@ -2275,6 +2276,7 @@ int drmFenceBuffers(int fd, unsigned flags, drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.flags = flags; arg.op = drm_fence_buffers; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2291,6 +2293,7 @@ int drmFenceDestroy(int fd, const drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.op = drm_fence_destroy; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2302,6 +2305,7 @@ int drmFenceReference(int fd, unsigned handle, drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = handle; arg.op = drm_fence_reference; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2318,6 +2322,7 @@ int drmFenceUnreference(int fd, const drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.op = drm_fence_unreference; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2329,6 +2334,7 @@ int drmFenceFlush(int fd, drmFence *fence, unsigned flush_type) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.type = flush_type; arg.op = drm_fence_flush; @@ -2344,6 +2350,7 @@ int drmFenceUpdate(int fd, drmFence *fence) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.op = drm_fence_signaled; if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) @@ -2384,6 +2391,7 @@ int drmFenceEmit(int fd, unsigned flags, drmFence *fence, unsigned emit_type) { drm_fence_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.flags = flags; arg.handle = fence->handle; arg.type = emit_type; @@ -2417,6 +2425,7 @@ int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) } } + memset(&arg, 0, sizeof(arg)); arg.handle = fence->handle; arg.type = flush_type; arg.flags = flags; @@ -2438,6 +2447,7 @@ int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) { drm_ttm_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.op = drm_ttm_create; arg.flags = flags; arg.size = size; @@ -2458,6 +2468,7 @@ int drmTTMDestroy(int fd, const drmTTM *ttm) { drm_ttm_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.op = drm_ttm_destroy; arg.handle = ttm->handle; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) @@ -2470,6 +2481,7 @@ int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) { drm_ttm_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.handle = handle; arg.op = drm_ttm_reference; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) @@ -2485,6 +2497,7 @@ int drmTTMUnreference(int fd, const drmTTM *ttm) { drm_ttm_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.op = drm_ttm_destroy; arg.handle = ttm->handle; if (ioctl(fd, DRM_IOCTL_TTM, &arg)) @@ -2660,8 +2673,9 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, drm_bo_arg_t arg; drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t *rep = &arg.d.rep; - - arg.handled = 0; + + memset(buf, 0, sizeof(*buf)); + memset(&arg, 0, sizeof(arg)); req->mask = mask; req->hint = hint; req->size = size; @@ -2690,7 +2704,6 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, return -EINVAL; } req->op = drm_bo_create; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2721,10 +2734,9 @@ int drmBODestroy(int fd, drmBO *buf) buf->virtual = NULL; } - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_destroy; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2746,10 +2758,9 @@ int drmBOReference(int fd, unsigned handle, drmBO *buf) drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t *rep = &arg.d.rep; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = handle; req->op = drm_bo_reference; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2782,10 +2793,9 @@ int drmBOUnReference(int fd, drmBO *buf) buf->virtual = NULL; } - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_unreference; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; @@ -2832,12 +2842,11 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, #endif } - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->mask = mapFlags; req->hint = mapHint; req->op = drm_bo_map; - arg.next = 0; /* * May hang if the buffer object is busy. @@ -2870,10 +2879,9 @@ int drmBOUnmap(int fd, drmBO *buf) drm_bo_arg_reply_t *rep = &arg.d.rep; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_unmap; - arg.next = 0; if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) { return -errno; @@ -2894,20 +2902,17 @@ int drmBOValidate(int fd, drmBO *buf, unsigned flags, unsigned mask, drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->mask = flags; req->hint = hint; req->arg_handle = mask; /* Encode mask in the arg_handle field :/ */ req->op = drm_bo_validate; - arg.next = 0; - do{ ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); } while (ret && errno == EAGAIN); - if (ret) return ret; if (!arg.handled) @@ -2927,12 +2932,11 @@ int drmBOFence(int fd, drmBO *buf, unsigned flags, unsigned fenceHandle) drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->mask = flags; req->arg_handle = fenceHandle; req->op = drm_bo_validate; - arg.next = 0; ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -2952,10 +2956,9 @@ int drmBOInfo(int fd, drmBO *buf) drm_bo_arg_reply_t *rep = &arg.d.rep; int ret = 0; - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_info; - arg.next = 0; ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -2978,11 +2981,10 @@ int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint) if ((buf->flags & DRM_BO_FLAG_SHAREABLE) || (buf->replyFlags & DRM_BO_REP_BUSY)) { - arg.handled = 0; + memset(&arg, 0, sizeof(arg)); req->handle = buf->handle; req->op = drm_bo_wait_idle; req->hint = hint; - arg.next = 0; do { ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); @@ -3098,9 +3100,8 @@ int drmBOValidateList(int fd, drmBOList *list) if (prevNext) *prevNext = (unsigned long) arg; - arg->next = 0; + memset(arg, 0, sizeof(*arg)); prevNext = &arg->next; - arg->handled = 0; req->handle = node->buf->handle; req->op = drm_bo_validate; req->mask = node->arg0; @@ -3166,9 +3167,8 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) if (prevNext) *prevNext = (unsigned long) arg; - arg->next = 0; + memset(arg, 0, sizeof(*arg)); prevNext = &arg->next; - arg->handled = 0; req->handle = node->buf->handle; req->op = drm_bo_fence; req->mask = node->arg0; @@ -3205,6 +3205,7 @@ int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, { drm_mm_init_arg_t arg; + memset(&arg, 0, sizeof(arg)); arg.req.op = mm_init; arg.req.vr_p_offset = vramPOffset; arg.req.vr_p_size = vramPSize; @@ -3221,6 +3222,9 @@ int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, int drmMMTakedown(int fd) { drm_mm_init_arg_t arg; + + + memset(&arg, 0, sizeof(arg)); arg.req.op = mm_takedown; if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) -- 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(-) 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(-) 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(-) 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(-) 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 ++++++++---- shared-core/i915_drv.h | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 1718bb31..0a0e5f99 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -38,6 +38,7 @@ static struct pci_device_id pciidlist[] = { i915_PCI_IDS }; +#ifdef I915_HAVE_FENCE static drm_fence_driver_t i915_fence_driver = { .no_types = 2, .wrap_diff = (1 << 30), @@ -47,7 +48,8 @@ static drm_fence_driver_t i915_fence_driver = { .emit = i915_fence_emit_sequence, .poke_flush = i915_poke_flush, }; - +#endif +#ifdef I915_HAVE_BUFFER static drm_bo_driver_t i915_bo_driver = { .vram_map = NULL, .cached_vram = 0, @@ -56,7 +58,7 @@ static drm_bo_driver_t i915_bo_driver = { .fence_type = i915_fence_types, .invalidate_caches = i915_invalidate_caches }; - +#endif static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static struct drm_driver driver = { @@ -97,10 +99,12 @@ static struct drm_driver driver = { .probe = probe, .remove = __devexit_p(drm_cleanup_pci), }, - +#ifdef I915_HAVE_FENCE .fence_driver = &i915_fence_driver, +#endif +#ifdef I915_HAVE_BUFFER .bo_driver = &i915_bo_driver, - +#endif .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 402ad5b1..745377c6 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -35,9 +35,9 @@ #define DRIVER_AUTHOR "Tungsten Graphics, Inc." -#define DRIVER_NAME "i915" +#define DRIVER_NAME "i915-mm" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20060119" +#define DRIVER_DATE "20060923" /* Interface history: * @@ -48,7 +48,7 @@ * 1.5: Add vblank pipe configuration */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 5 +#define DRIVER_MINOR 6 #define DRIVER_PATCHLEVEL 0 #if defined(__linux__) -- cgit v1.2.3 From b15bc8a0bad43c68dd1bbff27e7a7bd54e9e6938 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 28 Sep 2006 12:19:54 +0200 Subject: Libdrm version bump and naming. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 48813503..69b111fb 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libdrm], 2.0.2, [dri-devel@lists.sourceforge.net], libdrm) +AC_INIT([libdrm], 2.1.2-mm, [dri-devel@lists.sourceforge.net], libdrm) AC_CONFIG_SRCDIR([Makefile.am]) AM_INIT_AUTOMAKE([dist-bzip2]) -- cgit v1.2.3 From ab351505f36a6c66405ea7604378268848340a42 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. --- linux-core/drmP.h | 4 +++ linux-core/drm_core.h | 8 +++--- linux-core/drm_irq.c | 72 +++++++++++++++++++++++++++++++++++---------------- shared-core/drm.h | 4 ++- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index fd48059a..200b6493 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -110,6 +110,7 @@ #define DRIVER_IRQ_VBL 0x100 #define DRIVER_DMA_QUEUE 0x200 #define DRIVER_FB_DMA 0x400 +#define DRIVER_IRQ_VBL2 0x800 /*@}*/ @@ -582,6 +583,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); /** @@ -732,8 +734,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--; + } } } diff --git a/shared-core/drm.h b/shared-core/drm.h index 87f8da6b..eaeb21e4 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -529,10 +529,12 @@ typedef struct drm_irq_busid { typedef enum { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; -#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL +#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) struct drm_wait_vblank_request { drm_vblank_seq_type_t type; -- cgit v1.2.3 From 0c7d7f43610f705e8536a949cf2407efaa5ec217 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. --- linux-core/i915_drv.c | 4 +++- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 26 +++++++++++++++++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index c6e25f9b..209500be 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -45,12 +45,14 @@ static struct drm_driver driver = { */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR | */ - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | + DRIVER_IRQ_VBL2, .load = i915_driver_load, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .device_is_agp = i915_driver_device_is_agp, .vblank_wait = i915_driver_vblank_wait, + .vblank_wait2 = i915_driver_vblank_wait2, .irq_preinstall = i915_driver_irq_preinstall, .irq_postinstall = i915_driver_irq_postinstall, .irq_uninstall = i915_driver_irq_uninstall, diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a87075b1..69cf8118 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -117,6 +117,7 @@ extern int i915_irq_emit(DRM_IOCTL_ARGS); extern int i915_irq_wait(DRM_IOCTL_ARGS); extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); +extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(drm_device_t * dev); extern void i915_driver_irq_postinstall(drm_device_t * dev); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 14213b58..2eac29fc 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -60,7 +60,16 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev_priv->irq_queue); if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - atomic_inc(&dev->vbl_received); + if ((dev_priv->vblank_pipe & + (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) + == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { + if (temp & VSYNC_PIPEA_FLAG) + atomic_inc(&dev->vbl_received); + if (temp & VSYNC_PIPEB_FLAG) + atomic_inc(&dev->vbl_received2); + } else + atomic_inc(&dev->vbl_received); + DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); } @@ -124,7 +133,8 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr) return ret; } -int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) +static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence, + atomic_t *counter) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned int cur_vblank; @@ -136,7 +146,7 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) } DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, - (((cur_vblank = atomic_read(&dev->vbl_received)) + (((cur_vblank = atomic_read(counter)) - *sequence) <= (1<<23))); *sequence = cur_vblank; @@ -144,6 +154,16 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) return ret; } +int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) +{ + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); +} + +int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence) +{ + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); +} + /* Needs the lock as it touches the ring. */ int i915_irq_emit(DRM_IOCTL_ARGS) -- cgit v1.2.3 From d817cc1f30060fcc4a85a05b2de8a2a1687421b5 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. --- linux-core/drmP.h | 3 +++ linux-core/drm_irq.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_lock.c | 11 ++++++++ 3 files changed, 88 insertions(+) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 200b6493..e61be1a1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -739,6 +739,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; @@ -984,6 +986,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 7aa00bc2..fa677bae 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -152,6 +152,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; @@ -162,6 +163,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 29598e5253ff5c085ccf63580fd24b84db848424 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. --- bsd-core/drm_drawable.c | 52 +-------- libdrm/xf86drm.c | 16 +++ libdrm/xf86drm.h | 3 + linux-core/Makefile | 4 +- linux-core/drmP.h | 11 ++ linux-core/drm_drawable.c | 57 +--------- linux-core/drm_stub.c | 1 + shared-core/drm.h | 24 +++++ shared-core/drm_drawable.c | 256 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 315 insertions(+), 109 deletions(-) mode change 100644 => 120000 bsd-core/drm_drawable.c mode change 100644 => 120000 linux-core/drm_drawable.c create mode 100644 shared-core/drm_drawable.c diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c deleted file mode 100644 index 379e0aa7..00000000 --- a/bsd-core/drm_drawable.c +++ /dev/null @@ -1,51 +0,0 @@ -/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*- - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com - */ -/*- - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith - * Gareth Hughes - * - */ - -#include "drmP.h" - -int drm_adddraw(DRM_IOCTL_ARGS) -{ - drm_draw_t draw; - - draw.handle = 0; /* NOOP */ - DRM_DEBUG("%d\n", draw.handle); - - DRM_COPY_TO_USER_IOCTL( (drm_draw_t *)data, draw, sizeof(draw) ); - - return 0; -} - -int drm_rmdraw(DRM_IOCTL_ARGS) -{ - return 0; /* NOOP */ -} diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c new file mode 120000 index 00000000..d64bbe10 --- /dev/null +++ b/bsd-core/drm_drawable.c @@ -0,0 +1 @@ +../shared-core/drm_drawable.c \ No newline at end of file diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index c9f1b2db..d4f80b4e 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -1397,6 +1397,22 @@ int drmDestroyDrawable(int fd, drm_drawable_t handle) return 0; } +int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, unsigned int num, + void *data) +{ + drm_update_draw_t update; + + update.handle = handle; + update.type = type; + update.num = num; + update.data = (unsigned long long)(unsigned long)data; + + if (ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) return -errno; + + return 0; +} + /** * Acquire the AGP device. * diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 48a18f29..9e71eb65 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -544,6 +544,9 @@ extern int drmSwitchToContext(int fd, drm_context_t context); extern int drmDestroyContext(int fd, drm_context_t handle); extern int drmCreateDrawable(int fd, drm_drawable_t * handle); extern int drmDestroyDrawable(int fd, drm_drawable_t handle); +extern int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, + unsigned int num, void *data); extern int drmCtlInstHandler(int fd, int irq); extern int drmCtlUninstHandler(int fd); diff --git a/linux-core/Makefile b/linux-core/Makefile index 32828d28..3aecec43 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -75,8 +75,8 @@ DRM_MODULES ?= $(MODULE_LIST) # These definitions are for handling dependencies in the out of kernel build. -DRMSHARED = drm.h drm_sarea.h -DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h $(DRMSHARED) +DRMSHARED = drm.h drm_sarea.h drm_drawable.c +DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h drm.h drm_sarea.h COREHEADERS = drm_core.h drm_sman.h drm_hashtab.h TDFXHEADERS = tdfx_drv.h $(DRMHEADERS) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index e61be1a1..8ccbed4f 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -772,6 +772,15 @@ typedef struct drm_device { drm_local_map_t *agp_buffer_map; unsigned int agp_buffer_token; drm_head_t primary; /**< primary screen head */ + + /** \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; static __inline__ int drm_core_check_feature(struct drm_device *dev, @@ -922,6 +931,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 4708222f..ad78dcf7 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -61,6 +61,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, int retcode; spin_lock_init(&dev->count_lock); + spin_lock_init(&dev->drw_lock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); diff --git a/shared-core/drm.h b/shared-core/drm.h index eaeb21e4..614422bd 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -158,6 +158,14 @@ typedef struct drm_clip_rect { unsigned short y2; } drm_clip_rect_t; +/** + * Drawable information. + */ +typedef struct drm_drawable_info { + unsigned int num_rects; + drm_clip_rect_t *rects; +} drm_drawable_info_t; + /** * Texture region, */ @@ -507,6 +515,20 @@ typedef struct drm_draw { drm_drawable_t handle; } drm_draw_t; +/** + * DRM_IOCTL_UPDATE_DRAW ioctl argument type. + */ +typedef enum { + DRM_DRAWABLE_CLIPRECTS, +} drm_drawable_info_type_t; + +typedef struct drm_update_draw { + drm_drawable_t handle; + unsigned int type; + unsigned int num; + unsigned long long data; +} drm_update_draw_t; + /** * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type. */ @@ -696,6 +718,8 @@ typedef struct drm_set_version { #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) +#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t) + /*@}*/ /** diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c new file mode 100644 index 00000000..ca6eb81c --- /dev/null +++ b/shared-core/drm_drawable.c @@ -0,0 +1,256 @@ +/** + * \file drm_drawable.c + * IOCTLs for drawables + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + * \author Michel Dänzer + */ + +/* + * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "drmP.h" + +/** No-op. */ +int drm_adddraw(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + unsigned int irqflags; + int i, j = 0; + drm_draw_t draw; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + for (i = 0; i < dev->drw_bitfield_length; i++) { + u32 bitfield = dev->drw_bitfield[i]; + + if (bitfield == ~0) + continue; + + for (; j < sizeof(bitfield); j++) + if (!(bitfield & (1 << j))) + goto done; + } +done: + + if (i == dev->drw_bitfield_length) { + u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4, + (i + 1) * 4, DRM_MEM_BUFS); + + if (!new_bitfield) { + DRM_ERROR("Failed to allocate new drawable bitfield\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + if (32 * (i + 1) > dev->drw_info_length) { + void *new_info = drm_realloc(dev->drw_info, + dev->drw_info_length * + sizeof(drm_drawable_info_t*), + 32 * (i + 1) * + sizeof(drm_drawable_info_t*), + DRM_MEM_BUFS); + + if (!new_info) { + DRM_ERROR("Failed to allocate new drawable info" + " array\n"); + + drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + dev->drw_info = (drm_drawable_info_t**)new_info; + } + + new_bitfield[i] = 0; + + dev->drw_bitfield = new_bitfield; + dev->drw_bitfield_length++; + } + + dev->drw_bitfield[i] |= 1 << j; + + draw.handle = i * sizeof(u32) + j; + DRM_DEBUG("%d\n", draw.handle); + + dev->drw_info[draw.handle] = NULL; + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw)); + + return 0; +} + +/** No-op. */ +int drm_rmdraw(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_draw_t draw; + unsigned int idx, mod; + unsigned int irqflags; + + DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, + sizeof(draw)); + + idx = draw.handle / 32; + mod = draw.handle % 32; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_DEBUG("No such drawable %d\n", draw.handle); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return 0; + } + + dev->drw_bitfield[idx] &= ~(1 << mod); + + if (idx == (dev->drw_bitfield_length - 1)) { + while (idx >= 0 && !dev->drw_bitfield[idx]) + --idx; + + if (idx != draw.handle / 32) { + u32 *new_bitfield = drm_realloc(dev->drw_bitfield, + dev->drw_bitfield_length * 4, + (idx + 1) * 4, + DRM_MEM_BUFS); + + if (new_bitfield || idx == -1) { + dev->drw_bitfield = new_bitfield; + dev->drw_bitfield_length = idx + 1; + } + } + } + + if (32 * dev->drw_bitfield_length < dev->drw_info_length) { + void *new_info = drm_realloc(dev->drw_info, + dev->drw_info_length * + sizeof(drm_drawable_info_t*), + 32 * dev->drw_bitfield_length * + sizeof(drm_drawable_info_t*), + DRM_MEM_BUFS); + + if (new_info || !dev->drw_bitfield_length) { + dev->drw_info = (drm_drawable_info_t**)new_info; + dev->drw_info_length = 32 * dev->drw_bitfield_length; + } + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + return 0; +} + +int drm_update_drawable_info(DRM_IOCTL_ARGS) { + DRM_DEVICE; + drm_update_draw_t update; + unsigned int id, idx, mod; + unsigned int irqflags; + drm_drawable_info_t *info; + void *new_data; + + DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, + sizeof(update)); + + id = update.handle; + idx = id / 32; + mod = id % 32; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_ERROR("No such drawable %d\n", update.handle); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EINVAL); + } + + info = dev->drw_info[id]; + + if (!info) { + info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS); + + if (!info) { + DRM_ERROR("Failed to allocate drawable info memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + dev->drw_info[id] = info; + } + + switch (update.type) { + case DRM_DRAWABLE_CLIPRECTS: + new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + + if (!new_data) { + DRM_ERROR("Failed to allocate cliprect memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + if (DRM_COPY_FROM_USER(new_data, + (drm_clip_rect_t __user *) + (unsigned long)update.data, + update.num * sizeof(drm_clip_rect_t))) { + DRM_ERROR("Failed to copy cliprects from userspace\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EFAULT); + } + + drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + + info->rects = new_data; + info->num_rects = update.num; + break; + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + return 0; +} + +/** + * Caller must hold the drawable spinlock! + */ +drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { + unsigned int idx = id / 32, mod = id % 32; + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_DEBUG("No such drawable %d\n", id); + return NULL; + } + + return dev->drw_info[id]; +} -- cgit v1.2.3 From af48be1096221d551319c67a9e782b50ef58fefd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 23 Aug 2006 16:04:41 +0200 Subject: Only reallocate cliprect memory if the number of cliprects changes. Also improve diagnostic output. --- shared-core/drm_drawable.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index ca6eb81c..511f3eae 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -166,6 +166,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_DEBUG("%d\n", draw.handle); return 0; } @@ -209,30 +210,42 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: - new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + if (update.num != info->num_rects) { + new_data = drm_alloc(update.num * + sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); - if (!new_data) { - DRM_ERROR("Failed to allocate cliprect memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(ENOMEM); + if (!new_data) { + DRM_ERROR("Can't allocate cliprect memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + info->rects = new_data; } - if (DRM_COPY_FROM_USER(new_data, + if (DRM_COPY_FROM_USER(info->rects, (drm_clip_rect_t __user *) (unsigned long)update.data, update.num * sizeof(drm_clip_rect_t))) { - DRM_ERROR("Failed to copy cliprects from userspace\n"); + DRM_ERROR("Can't copy cliprects from userspace\n"); spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EFAULT); } - drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + if (update.num != info->num_rects) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + info->num_rects = update.num; + } - info->rects = new_data; - info->num_rects = update.num; + DRM_DEBUG("Updated %d cliprects for drawable %d\n", + info->num_rects, id); break; + default: + DRM_ERROR("Invalid update type %d\n", update.type); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EINVAL); } spin_unlock_irqrestore(&dev->drw_lock, irqflags); -- cgit v1.2.3 From 98a89504589427a76c3f5cfa2266962a1a212672 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. --- linux-core/drmP.h | 2 ++ linux-core/drm_drv.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 8ccbed4f..5c9644e0 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -931,6 +931,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 5ddcd4c1..2c878b61 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -119,6 +119,8 @@ 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_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 43f8675534c7e95efbc92eaf2c8cc43aef95f125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 23 Aug 2006 19:00:26 +0200 Subject: Export drm_get_drawable_info symbol from core. --- shared-core/drm_drawable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 511f3eae..0a357948 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -267,3 +267,4 @@ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) return dev->drw_info[id]; } +EXPORT_SYMBOL(drm_get_drawable_info); -- cgit v1.2.3 From b9f3009160d8bd1a26a77d6f1616f1679c7b969d 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. --- linux-core/drm_irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index b57fffb0..fef0e8d4 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -176,6 +176,8 @@ int drm_irq_uninstall(drm_device_t * dev) free_irq(dev->irq, dev); + dev->locked_tasklet_func = NULL; + return 0; } EXPORT_SYMBOL(drm_irq_uninstall); -- cgit v1.2.3 From 23d2833aaa37a33b9ddcf06cc796f59befc0d360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 25 Aug 2006 18:55:55 +0200 Subject: Locking and memory management fixes. --- shared-core/drm_drawable.c | 261 ++++++++++++++++++++++++++------------------- 1 file changed, 154 insertions(+), 107 deletions(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 0a357948..81eb9f08 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -36,70 +36,86 @@ #include "drmP.h" -/** No-op. */ +/** + * Allocate drawable ID and memory to store information about it. + */ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; unsigned int irqflags; - int i, j = 0; + int i, j; + u32 *bitfield = dev->drw_bitfield; + unsigned int bitfield_length = dev->drw_bitfield_length; + drm_drawable_info_t **info = dev->drw_info; + unsigned int info_length = dev->drw_info_length; drm_draw_t draw; - spin_lock_irqsave(&dev->drw_lock, irqflags); - - for (i = 0; i < dev->drw_bitfield_length; i++) { - u32 bitfield = dev->drw_bitfield[i]; - - if (bitfield == ~0) + for (i = 0, j = 0; i < bitfield_length; i++) { + if (bitfield[i] == ~0) continue; - for (; j < sizeof(bitfield); j++) - if (!(bitfield & (1 << j))) + for (; j < 8 * sizeof(*bitfield); j++) + if (!(bitfield[i] & (1 << j))) goto done; } done: - if (i == dev->drw_bitfield_length) { - u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4, - (i + 1) * 4, DRM_MEM_BUFS); + if (i == bitfield_length) { + bitfield_length++; + + bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), + DRM_MEM_BUFS); - if (!new_bitfield) { + if (!bitfield) { DRM_ERROR("Failed to allocate new drawable bitfield\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(ENOMEM); } - if (32 * (i + 1) > dev->drw_info_length) { - void *new_info = drm_realloc(dev->drw_info, - dev->drw_info_length * - sizeof(drm_drawable_info_t*), - 32 * (i + 1) * - sizeof(drm_drawable_info_t*), - DRM_MEM_BUFS); + if (8 * sizeof(*bitfield) * bitfield_length > info_length) { + info_length += 8 * sizeof(*bitfield); - if (!new_info) { + info = drm_alloc(info_length * sizeof(*info), + DRM_MEM_BUFS); + + if (!info) { DRM_ERROR("Failed to allocate new drawable info" " array\n"); - drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); + drm_free(bitfield, + bitfield_length * sizeof(*bitfield), + DRM_MEM_BUFS); return DRM_ERR(ENOMEM); } - - dev->drw_info = (drm_drawable_info_t**)new_info; } - new_bitfield[i] = 0; - - dev->drw_bitfield = new_bitfield; - dev->drw_bitfield_length++; + bitfield[i] = 0; } - dev->drw_bitfield[i] |= 1 << j; - - draw.handle = i * sizeof(u32) + j; + draw.handle = i * 8 * sizeof(*bitfield) + j; DRM_DEBUG("%d\n", draw.handle); - dev->drw_info[draw.handle] = NULL; + spin_lock_irqsave(&dev->drw_lock, irqflags); + + bitfield[i] |= 1 << j; + info[draw.handle] = NULL; + + if (bitfield != dev->drw_bitfield) { + memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * + sizeof(*bitfield)); + drm_free(dev->drw_bitfield, sizeof(*bitfield) * + dev->drw_bitfield_length, DRM_MEM_BUFS); + dev->drw_bitfield = bitfield; + dev->drw_bitfield_length = bitfield_length; + } + + if (info != dev->drw_info) { + memcpy(info, dev->drw_info, dev->drw_info_length * + sizeof(*info)); + drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length, + DRM_MEM_BUFS); + dev->drw_info = info; + dev->drw_info_length = info_length; + } spin_unlock_irqrestore(&dev->drw_lock, irqflags); @@ -108,63 +124,85 @@ done: return 0; } -/** No-op. */ +/** + * Free drawable ID and memory to store information about it. + */ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int idx, mod; + unsigned int idx, shift; unsigned int irqflags; + u32 *bitfield = dev->drw_bitfield; + unsigned int bitfield_length = dev->drw_bitfield_length; + drm_drawable_info_t **info = dev->drw_info; + unsigned int info_length = dev->drw_info_length; DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - idx = draw.handle / 32; - mod = draw.handle % 32; + idx = draw.handle / (8 * sizeof(*bitfield)); + shift = draw.handle % (8 * sizeof(*bitfield)); - spin_lock_irqsave(&dev->drw_lock, irqflags); - - if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + if (idx >= bitfield_length || + !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", draw.handle); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return 0; } - dev->drw_bitfield[idx] &= ~(1 << mod); + spin_lock_irqsave(&dev->drw_lock, irqflags); + + bitfield[idx] &= ~(1 << shift); + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); - if (idx == (dev->drw_bitfield_length - 1)) { - while (idx >= 0 && !dev->drw_bitfield[idx]) + /* Can we shrink the arrays? */ + if (idx == bitfield_length - 1) { + while (idx >= 0 && !bitfield[idx]) --idx; - if (idx != draw.handle / 32) { - u32 *new_bitfield = drm_realloc(dev->drw_bitfield, - dev->drw_bitfield_length * 4, - (idx + 1) * 4, - DRM_MEM_BUFS); + bitfield_length = idx + 1; - if (new_bitfield || idx == -1) { - dev->drw_bitfield = new_bitfield; - dev->drw_bitfield_length = idx + 1; - } + if (idx != draw.handle / (8 * sizeof(*bitfield))) + bitfield = drm_alloc(bitfield_length * + sizeof(*bitfield), DRM_MEM_BUFS); + + if (!bitfield && bitfield_length) { + bitfield = dev->drw_bitfield; + bitfield_length = dev->drw_bitfield_length; } } - if (32 * dev->drw_bitfield_length < dev->drw_info_length) { - void *new_info = drm_realloc(dev->drw_info, - dev->drw_info_length * - sizeof(drm_drawable_info_t*), - 32 * dev->drw_bitfield_length * - sizeof(drm_drawable_info_t*), - DRM_MEM_BUFS); - - if (new_info || !dev->drw_bitfield_length) { - dev->drw_info = (drm_drawable_info_t**)new_info; - dev->drw_info_length = 32 * dev->drw_bitfield_length; + if (bitfield != dev->drw_bitfield) { + info_length = 8 * sizeof(*bitfield) * bitfield_length; + + info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS); + + if (!info && info_length) { + info = dev->drw_info; + info_length = dev->drw_info_length; } - } - spin_unlock_irqrestore(&dev->drw_lock, irqflags); + spin_lock_irqsave(&dev->drw_lock, irqflags); + + memcpy(bitfield, dev->drw_bitfield, bitfield_length * + sizeof(*bitfield)); + drm_free(dev->drw_bitfield, sizeof(*bitfield) * + dev->drw_bitfield_length, DRM_MEM_BUFS); + dev->drw_bitfield = bitfield; + dev->drw_bitfield_length = bitfield_length; + + if (info != dev->drw_info) { + memcpy(info, dev->drw_info, info_length * + sizeof(*info)); + drm_free(dev->drw_info, sizeof(*info) * + dev->drw_info_length, DRM_MEM_BUFS); + dev->drw_info = info; + dev->drw_info_length = info_length; + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + } DRM_DEBUG("%d\n", draw.handle); return 0; @@ -173,24 +211,22 @@ int drm_rmdraw(DRM_IOCTL_ARGS) int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_update_draw_t update; - unsigned int id, idx, mod; - unsigned int irqflags; + unsigned int id, idx, shift; + u32 *bitfield = dev->drw_bitfield; + unsigned int irqflags, bitfield_length = dev->drw_bitfield_length; drm_drawable_info_t *info; - void *new_data; + drm_clip_rect_t *rects; + int err; DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, sizeof(update)); id = update.handle; - idx = id / 32; - mod = id % 32; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - spin_lock_irqsave(&dev->drw_lock, irqflags); - - if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_ERROR("No such drawable %d\n", update.handle); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EINVAL); } @@ -201,66 +237,77 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { if (!info) { DRM_ERROR("Failed to allocate drawable info memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(ENOMEM); } - - dev->drw_info[id] = info; } switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: if (update.num != info->num_rects) { - new_data = drm_alloc(update.num * - sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); - - if (!new_data) { - DRM_ERROR("Can't allocate cliprect memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(ENOMEM); - } - - info->rects = new_data; + rects = drm_alloc(update.num * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + } else + rects = info->rects; + + if (update.num && !rects) { + DRM_ERROR("Failed to allocate cliprect memory\n"); + err = DRM_ERR(ENOMEM); + goto error; } - if (DRM_COPY_FROM_USER(info->rects, - (drm_clip_rect_t __user *) - (unsigned long)update.data, - update.num * sizeof(drm_clip_rect_t))) { - DRM_ERROR("Can't copy cliprects from userspace\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(EFAULT); + if (update.num && DRM_COPY_FROM_USER(rects, + (drm_clip_rect_t __user *) + (unsigned long)update.data, + update.num * + sizeof(*rects))) { + DRM_ERROR("Failed to copy cliprects from userspace\n"); + err = DRM_ERR(EFAULT); + goto error; } - if (update.num != info->num_rects) { + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (rects != info->rects) { drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), DRM_MEM_BUFS); - info->num_rects = update.num; } + info->rects = rects; + info->num_rects = update.num; + dev->drw_info[id] = info; + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_DEBUG("Updated %d cliprects for drawable %d\n", info->num_rects, id); break; default: DRM_ERROR("Invalid update type %d\n", update.type); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EINVAL); } - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return 0; + +error: + if (!dev->drw_info[id]) + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + else if (rects != dev->drw_info[id]->rects) + drm_free(rects, update.num * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + + return err; } /** * Caller must hold the drawable spinlock! */ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { - unsigned int idx = id / 32, mod = id % 32; + u32 *bitfield = dev->drw_bitfield; + unsigned int idx = id / (8 * sizeof(*bitfield)); + unsigned int shift = id % (8 * sizeof(*bitfield)); if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", id); return NULL; } -- cgit v1.2.3 From 257771fa290b62d4d2ad896843cf3a207978d0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 25 Aug 2006 19:01:05 +0200 Subject: i915: Add ioctl for scheduling buffer swaps at vertical blanks. This uses the core facility to schedule a driver callback that will be called ASAP after the given vertical blank interrupt with the HW lock held. --- shared-core/i915_dma.c | 2 + shared-core/i915_drm.h | 9 +++ shared-core/i915_drv.h | 17 +++++ shared-core/i915_irq.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 211 insertions(+) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 3863490c..be235c17 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -163,6 +163,7 @@ static int i915_initialize(drm_device_t * dev, dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; dev_priv->front_offset = init->front_offset; dev_priv->current_page = 0; @@ -797,6 +798,7 @@ drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, + [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH}, }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index fcffb25c..7e4ba13d 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -132,6 +132,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_DESTROY_HEAP 0x0c #define DRM_I915_SET_VBLANK_PIPE 0x0d #define DRM_I915_GET_VBLANK_PIPE 0x0e +#define DRM_I915_VBLANK_SWAP 0x0f #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -244,4 +245,12 @@ typedef struct drm_i915_vblank_pipe { int pipe; } drm_i915_vblank_pipe_t; +/* Schedule buffer swap at given vertical blank: + */ +typedef struct drm_i915_vblank_swap { + drm_drawable_t drawable; + unsigned int pipe; + unsigned int sequence; +} drm_i915_vblank_swap_t; + #endif /* _I915_DRM_H_ */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 69cf8118..dc9bbc5c 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -71,6 +71,13 @@ struct mem_block { DRMFILE filp; /* 0: free, -1: heap, other: real files */ }; +typedef struct _drm_i915_vbl_swap { + struct list_head head; + drm_drawable_t drw_id; + unsigned int pipe; + unsigned int sequence; +} drm_i915_vbl_swap_t; + typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; @@ -83,6 +90,7 @@ typedef struct drm_i915_private { dma_addr_t dma_status_page; unsigned long counter; + unsigned int cpp; int back_offset; int front_offset; int current_page; @@ -98,6 +106,10 @@ typedef struct drm_i915_private { struct mem_block *agp_heap; unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds; int vblank_pipe; + + spinlock_t swaps_lock; + drm_i915_vbl_swap_t vbl_swaps; + unsigned int swaps_pending; } drm_i915_private_t; extern drm_ioctl_desc_t i915_ioctls[]; @@ -124,6 +136,7 @@ extern void i915_driver_irq_postinstall(drm_device_t * dev); extern void i915_driver_irq_uninstall(drm_device_t * dev); extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS); extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); +extern int i915_vblank_swap(DRM_IOCTL_ARGS); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); @@ -257,6 +270,10 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) + #define MI_BATCH_BUFFER ((0x30<<23)|1) #define MI_BATCH_BUFFER_START (0x31<<23) #define MI_BATCH_BUFFER_END (0xA<<23) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 2eac29fc..39d8c386 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -37,6 +37,99 @@ #define MAX_NOPID ((u32)~0) +/** + * Emit blits for scheduled buffer swaps. + * + * This function will be called with the HW lock held. + */ +static void i915_vblank_tasklet(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned int irqflags; + struct list_head *list, *tmp; + + DRM_DEBUG("\n"); + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { + drm_i915_vbl_swap_t *vbl_swap = + list_entry(list, drm_i915_vbl_swap_t, head); + atomic_t *counter = vbl_swap->pipe ? &dev->vbl_received2 : + &dev->vbl_received; + + if ((atomic_read(counter) - vbl_swap->sequence) <= (1<<23)) { + drm_drawable_info_t *drw; + + spin_unlock(&dev_priv->swaps_lock); + + spin_lock(&dev->drw_lock); + + drw = drm_get_drawable_info(dev, vbl_swap->drw_id); + + if (drw) { + int i, num_rects = drw->num_rects; + drm_clip_rect_t *rect = drw->rects; + drm_i915_sarea_t *sarea_priv = + dev_priv->sarea_priv; + u32 cpp = dev_priv->cpp; + u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB) + : XY_SRC_COPY_BLT_CMD; + u32 pitchropcpp = (sarea_priv->pitch * cpp) | + (0xcc << 16) | (cpp << 23) | + (1 << 24); + RING_LOCALS; + + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(6); + + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(0); + OUT_RING(0); + OUT_RING(sarea_priv->width | + sarea_priv->height << 16); + OUT_RING(sarea_priv->width | + sarea_priv->height << 16); + OUT_RING(0); + + ADVANCE_LP_RING(); + + sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; + + for (i = 0; i < num_rects; i++, rect++) { + BEGIN_LP_RING(8); + + OUT_RING(cmd); + OUT_RING(pitchropcpp); + OUT_RING((rect->y1 << 16) | rect->x1); + OUT_RING((rect->y2 << 16) | rect->x2); + OUT_RING(sarea_priv->front_offset); + OUT_RING((rect->y1 << 16) | rect->x1); + OUT_RING(pitchropcpp & 0xffff); + OUT_RING(sarea_priv->back_offset); + + ADVANCE_LP_RING(); + } + } + + spin_unlock(&dev->drw_lock); + + spin_lock(&dev_priv->swaps_lock); + + list_del(list); + + drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); + + dev_priv->swaps_pending--; + } + } + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; @@ -72,6 +165,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); + + drm_locked_tasklet(dev, i915_vblank_tasklet); } return IRQ_HANDLED; @@ -274,6 +369,90 @@ int i915_vblank_pipe_get(DRM_IOCTL_ARGS) return 0; } +/** + * Schedule buffer swap at given vertical blank. + */ +int i915_vblank_swap(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_swap_t swap; + drm_i915_vbl_swap_t *vbl_swap; + unsigned int irqflags; + struct list_head *list; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __func__); + return DRM_ERR(EINVAL); + } + + if (dev_priv->sarea_priv->rotation) { + DRM_DEBUG("Rotation not supported\n"); + return DRM_ERR(EINVAL); + } + + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + + DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, + sizeof(swap)); + + if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { + DRM_ERROR("Invalid pipe %d\n", swap.pipe); + return DRM_ERR(EINVAL); + } + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (!drm_get_drawable_info(dev, swap.drawable)) { + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_ERROR("Invalid drawable ID %d\n", swap.drawable); + return DRM_ERR(EINVAL); + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_for_each(list, &dev_priv->vbl_swaps.head) { + vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); + + if (vbl_swap->drw_id == swap.drawable && + vbl_swap->pipe == swap.pipe && + vbl_swap->sequence == swap.sequence) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Already scheduled\n"); + return 0; + } + } + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); + + if (!vbl_swap) { + DRM_ERROR("Failed to allocate memory to queue swap\n"); + return DRM_ERR(ENOMEM); + } + + DRM_DEBUG("\n"); + + vbl_swap->drw_id = swap.drawable; + vbl_swap->pipe = swap.pipe; + vbl_swap->sequence = swap.sequence; + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head); + dev_priv->swaps_pending++; + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + return 0; +} + /* drm_dma.h hooks */ void i915_driver_irq_preinstall(drm_device_t * dev) @@ -289,6 +468,10 @@ void i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); + dev_priv->swaps_pending = 0; + i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); } -- cgit v1.2.3 From d04751facea36cb888c7510b126658fdbc4277d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 28 Aug 2006 18:19:58 +0200 Subject: Add copyright notice. --- shared-core/drm_drawable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 81eb9f08..bbfaf139 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -12,6 +12,7 @@ * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a -- cgit v1.2.3 From df7551ef7334d728ec0371423661bb403d3e270a 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. --- linux-core/drm_drv.c | 12 ++++++++++++ shared-core/drm_drawable.c | 35 +++++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 2c878b61..228c8b89 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -156,6 +156,18 @@ int drm_lastclose(drm_device_t * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); + /* Free drawable information memory */ + for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield); + i++) { + drm_drawable_info_t *info = drm_get_drawable_info(dev, i); + + if (info) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + } + } + mutex_lock(&dev->struct_mutex); del_timer(&dev->timer); diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index bbfaf139..5e2fc86c 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -92,13 +92,13 @@ done: bitfield[i] = 0; } - draw.handle = i * 8 * sizeof(*bitfield) + j; + draw.handle = i * 8 * sizeof(*bitfield) + j + 1; DRM_DEBUG("%d\n", draw.handle); spin_lock_irqsave(&dev->drw_lock, irqflags); bitfield[i] |= 1 << j; - info[draw.handle] = NULL; + info[draw.handle - 1] = NULL; if (bitfield != dev->drw_bitfield) { memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * @@ -132,7 +132,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int idx, shift; + unsigned int id, idx, shift; unsigned int irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; @@ -142,10 +142,11 @@ int drm_rmdraw(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - idx = draw.handle / (8 * sizeof(*bitfield)); - shift = draw.handle % (8 * sizeof(*bitfield)); + id = draw.handle - 1; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - if (idx >= bitfield_length || + if (idx < 0 || idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", draw.handle); return 0; @@ -157,6 +158,12 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + if (info[id]) { + drm_free(info[id]->rects, info[id]->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info[id], sizeof(**info), DRM_MEM_BUFS); + } + /* Can we shrink the arrays? */ if (idx == bitfield_length - 1) { while (idx >= 0 && !bitfield[idx]) @@ -164,7 +171,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) bitfield_length = idx + 1; - if (idx != draw.handle / (8 * sizeof(*bitfield))) + if (idx != id / (8 * sizeof(*bitfield))) bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), DRM_MEM_BUFS); @@ -222,11 +229,12 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, sizeof(update)); - id = update.handle; + id = update.handle - 1; idx = id / (8 * sizeof(*bitfield)); shift = id % (8 * sizeof(*bitfield)); - if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { + if (idx < 0 || idx >= bitfield_length || + !(bitfield[idx] & (1 << shift))) { DRM_ERROR("No such drawable %d\n", update.handle); return DRM_ERR(EINVAL); } @@ -304,10 +312,13 @@ error: */ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { u32 *bitfield = dev->drw_bitfield; - unsigned int idx = id / (8 * sizeof(*bitfield)); - unsigned int shift = id % (8 * sizeof(*bitfield)); + unsigned int idx, shift; + + id--; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - if (idx >= dev->drw_bitfield_length || + if (idx < 0 || idx >= dev->drw_bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", id); return NULL; -- cgit v1.2.3 From d5a0f107511e128658e2d5e15bd7e6215c507f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 30 Aug 2006 19:33:28 +0200 Subject: DRM_I915_VBLANK_SWAP ioctl: Take drm_vblank_seq_type_t instead of pipe number. Handle relative as well as absolute target sequence numbers. Return error if target sequence has already passed, so userspace can deal with this situation as it sees fit. On success, return the sequence number of the vertical blank when the buffer swap is expected to take place. Also add DRM_IOCTL_I915_VBLANK_SWAP definition for userspace code that may want to use ioctl() instead of drmCommandWriteRead(). --- shared-core/i915_drm.h | 3 ++- shared-core/i915_irq.c | 43 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 7e4ba13d..3a39d531 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -149,6 +149,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) /* Allow drivers to submit batchbuffers directly to hardware, relying @@ -249,7 +250,7 @@ typedef struct drm_i915_vblank_pipe { */ typedef struct drm_i915_vblank_swap { drm_drawable_t drawable; - unsigned int pipe; + drm_vblank_seq_type_t seqtype; unsigned int sequence; } drm_i915_vblank_swap_t; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 39d8c386..6f00febc 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -378,7 +378,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int irqflags; + unsigned int pipe, seqtype, irqflags, curseq; struct list_head *list; if (!dev_priv) { @@ -399,8 +399,23 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); - if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { - DRM_ERROR("Invalid pipe %d\n", swap.pipe); + if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | + _DRM_VBLANK_SECONDARY)) { + DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); + return DRM_ERR(EINVAL); + } + + pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; + + seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); + + if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { + DRM_DEBUG("Not scheduling swap for current sequence\n"); + return DRM_ERR(EINVAL); + } + + if (!(dev_priv->vblank_pipe & (1 << pipe))) { + DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); } @@ -414,13 +429,28 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + switch (seqtype) { + case _DRM_VBLANK_RELATIVE: + swap.sequence += curseq; + break; + case _DRM_VBLANK_ABSOLUTE: + if ((curseq - swap.sequence) > (1<<23)) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Missed target sequence\n"); + return DRM_ERR(EINVAL); + } + break; + } + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); if (vbl_swap->drw_id == swap.drawable && - vbl_swap->pipe == swap.pipe && + vbl_swap->pipe == pipe && vbl_swap->sequence == swap.sequence) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); @@ -440,7 +470,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_DEBUG("\n"); vbl_swap->drw_id = swap.drawable; - vbl_swap->pipe = swap.pipe; + vbl_swap->pipe = pipe; vbl_swap->sequence = swap.sequence; spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); @@ -450,6 +480,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap, + sizeof(swap)); + return 0; } -- cgit v1.2.3 From 87c57cba1a70221fc570b253bf3b24682ef6b894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:30:55 +0200 Subject: Make handling of dev_priv->vblank_pipe more robust. Initialize it to default value if it hasn't been set by the X server yet. In i915_vblank_pipe_set(), only update dev_priv->vblank_pipe and call i915_enable_interrupt() if the argument passed from userspace is valid to avoid corrupting dev_priv->vblank_pipe on invalid arguments. --- shared-core/i915_irq.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 6f00febc..68e7c668 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -307,7 +307,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } -static int i915_enable_interrupt (drm_device_t *dev) +static void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u16 flag; @@ -317,13 +317,8 @@ static int i915_enable_interrupt (drm_device_t *dev) flag |= VSYNC_PIPEA_FLAG; if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) flag |= VSYNC_PIPEB_FLAG; - if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { - DRM_ERROR("%s called with invalid pipe 0x%x\n", - __FUNCTION__, dev_priv->vblank_pipe); - return DRM_ERR(EINVAL); - } + I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag); - return 0; } /* Set the vblank monitor pipe @@ -342,8 +337,17 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data, sizeof(pipe)); + if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { + DRM_ERROR("%s called with invalid pipe 0x%x\n", + __FUNCTION__, pipe.pipe); + return DRM_ERR(EINVAL); + } + dev_priv->vblank_pipe = pipe.pipe; - return i915_enable_interrupt (dev); + + i915_enable_interrupt (dev); + + return 0; } int i915_vblank_pipe_get(DRM_IOCTL_ARGS) @@ -505,6 +509,8 @@ void i915_driver_irq_postinstall(drm_device_t * dev) INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; + if (!dev_priv->vblank_pipe) + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); } -- cgit v1.2.3 From 84b38b63f05e04ade8b1ddfb770047fd86de0d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:32:08 +0200 Subject: Add definition of DRM_VBLANK_SECONDARY. --- libdrm/xf86drm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 9e71eb65..cda570de 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; -- cgit v1.2.3 From c2bdb76814755c9ac6e66a8815f23af0fe4f3a91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:33:04 +0200 Subject: Add SAREA fileds for determining which pipe to sync window buffer swaps to. --- shared-core/i915_drm.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index 3a39d531..358b11e2 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -104,6 +104,15 @@ typedef struct _drm_i915_sarea { unsigned int depth_tiled; unsigned int rotated_tiled; unsigned int rotated2_tiled; + + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; } drm_i915_sarea_t; /* Flags for perf_boxes -- cgit v1.2.3 From 7f09f957d9a61ac107f8fd29128d7899a3e8a228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 1 Sep 2006 11:24:38 +0200 Subject: Fix 'sequence has passed' condition in i915_vblank_swap(). --- shared-core/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 68e7c668..9cd8ece4 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -442,7 +442,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) swap.sequence += curseq; break; case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) > (1<<23)) { + if ((curseq - swap.sequence) <= (1<<23)) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); -- cgit v1.2.3 From 89e323e4900af84cc33219ad24eb0b435a039d23 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. --- libdrm/xf86drm.h | 1 + linux-core/drm_irq.c | 16 ++++++++++------ shared-core/drm.h | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index cda570de..2ad70807 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index fef0e8d4..bd8a9c82 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -249,8 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) drm_wait_vblank_t vblwait; struct timeval now; int ret = 0; - unsigned int flags; - atomic_t *seq; + unsigned int flags, seq; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -272,12 +271,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) return -EINVAL; - seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : - &dev->vbl_received; + seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 + : &dev->vbl_received); switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read(seq); + vblwait.request.sequence += seq; vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; @@ -285,13 +284,18 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) return -EINVAL; } + if ((flags & _DRM_VBLANK_NEXTONMISS) && + (seq - vblwait.request.sequence) <= (1<<23)) { + vblwait.request.sequence = seq + 1; + } + if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = atomic_read(seq); + vblwait.reply.sequence = seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); diff --git a/shared-core/drm.h b/shared-core/drm.h index 614422bd..7f90a96d 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -551,12 +551,14 @@ typedef struct drm_irq_busid { typedef enum { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) -#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \ + _DRM_VBLANK_NEXTONMISS) struct drm_wait_vblank_request { drm_vblank_seq_type_t type; -- cgit v1.2.3 From cf6b2c5299e9be3542d4deddfd05d5811f11d2ef 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. --- linux-core/drm_irq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index bd8a9c82..d1a6a6b1 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -295,8 +295,6 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = seq; - spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Check if this task has already scheduled the same signal @@ -309,6 +307,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) && vbl_sig->task == current) { spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + vblwait.reply.sequence = seq; goto done; } } @@ -339,6 +338,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + + vblwait.reply.sequence = seq; } else { if (flags & _DRM_VBLANK_SECONDARY) { if (dev->driver->vblank_wait2) -- cgit v1.2.3 From 50a0284a61d4415c0ebdb02decee76ef3115007a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 1 Sep 2006 11:48:07 +0200 Subject: Only return EBUSY after we've established we need to schedule a new swap. --- shared-core/i915_irq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9cd8ece4..d32f592f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -395,11 +395,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - if (dev_priv->swaps_pending >= 100) { - DRM_DEBUG("Too many swaps queued\n"); - return DRM_ERR(EBUSY); - } - DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); @@ -464,6 +459,11 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); if (!vbl_swap) { -- cgit v1.2.3 From 0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 13 Sep 2006 08:59:35 +0200 Subject: i915_vblank_swap: Add support for DRM_VBLANK_NEXTONMISS. --- shared-core/i915_irq.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index d32f592f..9db38706 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -399,7 +399,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) sizeof(swap)); if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | - _DRM_VBLANK_SECONDARY)) { + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); return DRM_ERR(EINVAL); } @@ -408,11 +408,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); - if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { - DRM_DEBUG("Not scheduling swap for current sequence\n"); - return DRM_ERR(EINVAL); - } - if (!(dev_priv->vblank_pipe & (1 << pipe))) { DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); @@ -430,21 +425,20 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); - spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); - - switch (seqtype) { - case _DRM_VBLANK_RELATIVE: + if (seqtype == _DRM_VBLANK_RELATIVE) swap.sequence += curseq; - break; - case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) <= (1<<23)) { - spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + if ((curseq - swap.sequence) <= (1<<23)) { + if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) { + swap.sequence = curseq + 1; + } else { DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); } - break; } + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); -- cgit v1.2.3 From 2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 18 Sep 2006 12:15:38 +0200 Subject: i915: Bump minor for swap scheduling ioctl and secondary vblank support. --- shared-core/i915_drv.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index dc9bbc5c..de7f8224 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -46,9 +46,11 @@ * 1.3: Add vblank support * 1.4: Fix cmdbuffer path, add heap destroy * 1.5: Add vblank pipe configuration + * 1.6: - New ioctl for scheduling buffer swaps on vertical blank + * - Support vertical blank on secondary display pipe */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 5 +#define DRIVER_MINOR 6 #define DRIVER_PATCHLEVEL 0 typedef struct _drm_i915_ring_buffer { -- cgit v1.2.3 From 881ba569929ceafd42e3c86228b0172099083d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 27 Sep 2006 18:22:10 +0200 Subject: i915: Avoid mis-counting vblank interrupts when they're only enabled for pipe A. It looks like 'after a while', I915REG_INT_IDENTITY_R for some reason always has VSYNC_PIPEB_FLAG set in the interrupt handler, even though pipe B is disabled. So we only increase dev->vbl_received if the corresponding bit is also set in dev->vblank_pipe. --- shared-core/i915_irq.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 9db38706..fbc66749 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -153,14 +153,19 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev_priv->irq_queue); if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - if ((dev_priv->vblank_pipe & + int vblank_pipe = dev_priv->vblank_pipe; + + if ((vblank_pipe & (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { if (temp & VSYNC_PIPEA_FLAG) atomic_inc(&dev->vbl_received); if (temp & VSYNC_PIPEB_FLAG) atomic_inc(&dev->vbl_received2); - } else + } else if (((temp & VSYNC_PIPEA_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || + ((temp & VSYNC_PIPEB_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); -- cgit v1.2.3 From 7af93dd9849442270ec89cb4bbeef5bfd4f9e424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 29 Sep 2006 10:27:29 +0200 Subject: i915: Only schedule vblank tasklet if there are scheduled swaps pending. This fixes issues on X server startup with versions of xf86-video-intel that enable the IRQ before they have a context ID. --- shared-core/i915_irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index fbc66749..76c3a810 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -171,7 +171,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); - drm_locked_tasklet(dev, i915_vblank_tasklet); + if (dev_priv->swaps_pending > 0) + drm_locked_tasklet(dev, i915_vblank_tasklet); } return IRQ_HANDLED; -- 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(-) 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 ae96e264198323916ee58e293468c9b924feca75 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Sep 2006 11:46:45 +0200 Subject: Add a new buffer flag. Fix up some comments. --- shared-core/drm.h | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/shared-core/drm.h b/shared-core/drm.h index 8ac5a31e..095823b7 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -696,21 +696,28 @@ typedef struct drm_ttm_arg { * Status flags. Can be read to determine the actual state of a buffer. */ -/* Pinned buffer. */ +/* + * Cannot evict this buffer. Not even with force. This type of buffer should + * only be available for root, and must be manually removed before buffer + * manager shutdown or swapout. + */ #define DRM_BO_FLAG_NO_EVICT 0x00000010 /* Always keep a system memory shadow to a vram buffer */ #define DRM_BO_FLAG_SHADOW_VRAM 0x00000020 -/* When mapped for reading, make sure the buffer is cached even - if it means moving the buffer to system memory */ +/* The buffer is shareable with other processes */ #define DRM_BO_FLAG_SHAREABLE 0x00000040 -/* When there is a choice between VRAM and TT, prefer VRAM. - The default behaviour is to prefer TT. */ +/* The buffer is currently cached */ #define DRM_BO_FLAG_CACHED 0x00000080 -/* The buffer is shareable with other processes */ - +/* Make sure that every time this buffer is validated, it ends up on the same + * location. The buffer will also not be evicted when claiming space for + * other buffers. Basically a pinned buffer but it may be thrown out as + * part of buffer manager shutdown or swapout. Not supported yet.*/ +#define DRM_BO_FLAG_NO_MOVE 0x00000100 +/* Make sure the buffer is in cached memory when mapped for reading */ #define DRM_BO_FLAG_READ_CACHED 0x00080000 -/* The buffer is currently cached */ +/* When there is a choice between VRAM and TT, prefer VRAM. + The default behaviour is to prefer TT. */ #define DRM_BO_FLAG_PREFER_VRAM 0x00040000 /* Bind this buffer cached if the hardware supports it. */ #define DRM_BO_FLAG_BIND_CACHED 0x0002000 -- 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 +++++++++++++++++++++++++++++++++++---------------- shared-core/drm.h | 4 ++- 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index aecad251..6a978f33 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -111,6 +111,7 @@ #define DRIVER_IRQ_VBL 0x100 #define DRIVER_DMA_QUEUE 0x200 #define DRIVER_FB_DMA 0x400 +#define DRIVER_IRQ_VBL2 0x800 /*@}*/ @@ -687,6 +688,7 @@ struct drm_driver { int new); void (*kernel_context_switch_unlock) (struct drm_device * dev); int (*vblank_wait) (struct drm_device * dev, unsigned int *sequence); + int (*vblank_wait2) (struct drm_device * dev, unsigned int *sequence); int (*dri_library_name) (struct drm_device * dev, char * buf); /** @@ -912,8 +914,10 @@ typedef struct drm_device { wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ atomic_t vbl_received; + atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */ spinlock_t vbl_lock; drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ + drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */ unsigned int vbl_pending; /*@} */ diff --git a/linux-core/drm_core.h b/linux-core/drm_core.h index f5405fdf..705bbff7 100644 --- a/linux-core/drm_core.h +++ b/linux-core/drm_core.h @@ -25,11 +25,11 @@ #define CORE_NAME "drm" #define CORE_DESC "DRM shared core routines" -#define CORE_DATE "20051102" +#define CORE_DATE "20060810" #define DRM_IF_MAJOR 1 -#define DRM_IF_MINOR 2 +#define DRM_IF_MINOR 3 #define CORE_MAJOR 1 -#define CORE_MINOR 0 -#define CORE_PATCHLEVEL 1 +#define CORE_MINOR 1 +#define CORE_PATCHLEVEL 0 diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index c2a9e3d6..d4e5fbd5 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -120,6 +120,7 @@ static int drm_irq_install(drm_device_t * dev) spin_lock_init(&dev->vbl_lock); INIT_LIST_HEAD(&dev->vbl_sigs.head); + INIT_LIST_HEAD(&dev->vbl_sigs2.head); dev->vbl_pending = 0; } @@ -246,9 +247,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) struct timeval now; int ret = 0; unsigned int flags; - - if (!drm_core_check_feature(dev, DRIVER_IRQ_VBL)) - return -EINVAL; + atomic_t *seq; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -256,9 +255,26 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) if (copy_from_user(&vblwait, argp, sizeof(vblwait))) return -EFAULT; - switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) { + if (vblwait.request.type & + ~(_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)) { + DRM_ERROR("Unsupported type value 0x%x, supported mask 0x%x\n", + vblwait.request.type, + (_DRM_VBLANK_TYPES_MASK | _DRM_VBLANK_FLAGS_MASK)); + return -EINVAL; + } + + flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; + + if (!drm_core_check_feature(dev, (flags & _DRM_VBLANK_SECONDARY) ? + DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) + return -EINVAL; + + seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : + &dev->vbl_received; + + switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read(&dev->vbl_received); + vblwait.request.sequence += atomic_read(seq); vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; @@ -266,13 +282,13 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) return -EINVAL; } - flags = vblwait.request.type & _DRM_VBLANK_FLAGS_MASK; - if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; + drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) + ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = atomic_read(&dev->vbl_received); + vblwait.reply.sequence = atomic_read(seq); spin_lock_irqsave(&dev->vbl_lock, irqflags); @@ -280,7 +296,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) * for the same vblank sequence number; nothing to be done in * that case */ - list_for_each_entry(vbl_sig, &dev->vbl_sigs.head, head) { + list_for_each_entry(vbl_sig, &vbl_sigs->head, head) { if (vbl_sig->sequence == vblwait.request.sequence && vbl_sig->info.si_signo == vblwait.request.signal && vbl_sig->task == current) { @@ -313,11 +329,14 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) spin_lock_irqsave(&dev->vbl_lock, irqflags); - list_add_tail((struct list_head *)vbl_sig, &dev->vbl_sigs.head); + list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head); spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } else { - if (dev->driver->vblank_wait) + if (flags & _DRM_VBLANK_SECONDARY) { + if (dev->driver->vblank_wait2) + ret = dev->driver->vblank_wait2(dev, &vblwait.request.sequence); + } else if (dev->driver->vblank_wait) ret = dev->driver->vblank_wait(dev, &vblwait.request.sequence); @@ -345,25 +364,32 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) */ void drm_vbl_send_signals(drm_device_t * dev) { - struct list_head *list, *tmp; - drm_vbl_sig_t *vbl_sig; - unsigned int vbl_seq = atomic_read(&dev->vbl_received); unsigned long flags; + int i; spin_lock_irqsave(&dev->vbl_lock, flags); - list_for_each_safe(list, tmp, &dev->vbl_sigs.head) { - vbl_sig = list_entry(list, drm_vbl_sig_t, head); - if ((vbl_seq - vbl_sig->sequence) <= (1 << 23)) { - vbl_sig->info.si_code = vbl_seq; - send_sig_info(vbl_sig->info.si_signo, &vbl_sig->info, - vbl_sig->task); + for (i = 0; i < 2; i++) { + struct list_head *list, *tmp; + drm_vbl_sig_t *vbl_sig; + drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs; + unsigned int vbl_seq = atomic_read(i ? &dev->vbl_received2 : + &dev->vbl_received); + + list_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--; + } } } diff --git a/shared-core/drm.h b/shared-core/drm.h index 095823b7..c2bcf62c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -536,10 +536,12 @@ typedef struct drm_irq_busid { typedef enum { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; -#define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL +#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) struct drm_wait_vblank_request { drm_vblank_seq_type_t type; -- 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 +++- shared-core/i915_drv.h | 1 + shared-core/i915_irq.c | 26 +++++++++++++++++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index 0a0e5f99..1263bcab 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -67,12 +67,14 @@ static struct drm_driver driver = { */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR | */ - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL, + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL | + DRIVER_IRQ_VBL2, .load = i915_driver_load, .lastclose = i915_driver_lastclose, .preclose = i915_driver_preclose, .device_is_agp = i915_driver_device_is_agp, .vblank_wait = i915_driver_vblank_wait, + .vblank_wait2 = i915_driver_vblank_wait2, .irq_preinstall = i915_driver_irq_preinstall, .irq_postinstall = i915_driver_irq_postinstall, .irq_uninstall = i915_driver_irq_uninstall, diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 745377c6..27324015 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -137,6 +137,7 @@ extern int i915_irq_emit(DRM_IOCTL_ARGS); extern int i915_irq_wait(DRM_IOCTL_ARGS); extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence); +extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence); extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS); extern void i915_driver_irq_preinstall(drm_device_t * dev); extern void i915_driver_irq_postinstall(drm_device_t * dev); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 51112b62..c26c2769 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -65,7 +65,16 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - atomic_inc(&dev->vbl_received); + if ((dev_priv->vblank_pipe & + (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) + == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { + if (temp & VSYNC_PIPEA_FLAG) + atomic_inc(&dev->vbl_received); + if (temp & VSYNC_PIPEB_FLAG) + atomic_inc(&dev->vbl_received2); + } else + atomic_inc(&dev->vbl_received); + DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); } @@ -153,7 +162,8 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr) return ret; } -int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) +static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence, + atomic_t *counter) { drm_i915_private_t *dev_priv = dev->dev_private; unsigned int cur_vblank; @@ -165,7 +175,7 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) } DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ, - (((cur_vblank = atomic_read(&dev->vbl_received)) + (((cur_vblank = atomic_read(counter)) - *sequence) <= (1<<23))); *sequence = cur_vblank; @@ -173,6 +183,16 @@ int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) return ret; } +int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) +{ + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received); +} + +int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence) +{ + return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2); +} + /* Needs the lock as it touches the ring. */ int i915_irq_emit(DRM_IOCTL_ARGS) -- 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(+) 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) --- bsd-core/drm_drawable.c | 52 +-------- libdrm/xf86drm.c | 16 +++ libdrm/xf86drm.h | 3 + linux-core/Makefile | 4 +- linux-core/drmP.h | 10 ++ linux-core/drm_drawable.c | 57 +--------- linux-core/drm_stub.c | 1 + shared-core/drm.h | 24 +++++ shared-core/drm_drawable.c | 256 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 314 insertions(+), 109 deletions(-) mode change 100644 => 120000 bsd-core/drm_drawable.c mode change 100644 => 120000 linux-core/drm_drawable.c create mode 100644 shared-core/drm_drawable.c diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c deleted file mode 100644 index 379e0aa7..00000000 --- a/bsd-core/drm_drawable.c +++ /dev/null @@ -1,51 +0,0 @@ -/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*- - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com - */ -/*- - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: - * Rickard E. (Rik) Faith - * Gareth Hughes - * - */ - -#include "drmP.h" - -int drm_adddraw(DRM_IOCTL_ARGS) -{ - drm_draw_t draw; - - draw.handle = 0; /* NOOP */ - DRM_DEBUG("%d\n", draw.handle); - - DRM_COPY_TO_USER_IOCTL( (drm_draw_t *)data, draw, sizeof(draw) ); - - return 0; -} - -int drm_rmdraw(DRM_IOCTL_ARGS) -{ - return 0; /* NOOP */ -} diff --git a/bsd-core/drm_drawable.c b/bsd-core/drm_drawable.c new file mode 120000 index 00000000..d64bbe10 --- /dev/null +++ b/bsd-core/drm_drawable.c @@ -0,0 +1 @@ +../shared-core/drm_drawable.c \ No newline at end of file diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 31d1c164..ab884eb5 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -1398,6 +1398,22 @@ int drmDestroyDrawable(int fd, drm_drawable_t handle) return 0; } +int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, unsigned int num, + void *data) +{ + drm_update_draw_t update; + + update.handle = handle; + update.type = type; + update.num = num; + update.data = (unsigned long long)(unsigned long)data; + + if (ioctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) return -errno; + + return 0; +} + /** * Acquire the AGP device. * diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index d97681c0..d39974de 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -545,6 +545,9 @@ extern int drmSwitchToContext(int fd, drm_context_t context); extern int drmDestroyContext(int fd, drm_context_t handle); extern int drmCreateDrawable(int fd, drm_drawable_t * handle); extern int drmDestroyDrawable(int fd, drm_drawable_t handle); +extern int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, + unsigned int num, void *data); extern int drmCtlInstHandler(int fd, int irq); extern int drmCtlUninstHandler(int fd); diff --git a/linux-core/Makefile b/linux-core/Makefile index 32828d28..3aecec43 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -75,8 +75,8 @@ DRM_MODULES ?= $(MODULE_LIST) # These definitions are for handling dependencies in the out of kernel build. -DRMSHARED = drm.h drm_sarea.h -DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h $(DRMSHARED) +DRMSHARED = drm.h drm_sarea.h drm_drawable.c +DRMHEADERS = drmP.h drm_compat.h drm_os_linux.h drm.h drm_sarea.h COREHEADERS = drm_core.h drm_sman.h drm_hashtab.h TDFXHEADERS = tdfx_drv.h $(DRMHEADERS) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 60354bce..8a099ba1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -954,6 +954,14 @@ typedef struct drm_device { drm_fence_manager_t fm; drm_buffer_manager_t bm; + /** \name Drawable information */ + /*@{ */ + spinlock_t drw_lock; + unsigned int drw_bitfield_length; + u32 *drw_bitfield; + unsigned int drw_info_length; + drm_drawable_info_t **drw_info; + /*@} */ } drm_device_t; #if __OS_HAS_AGP @@ -1161,6 +1169,8 @@ extern int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_rmdraw(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, + drm_drawable_t id); /* Authentication IOCTL support (drm_auth.h) */ extern int drm_getmagic(struct inode *inode, struct file *filp, diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c deleted file mode 100644 index 7857453c..00000000 --- a/linux-core/drm_drawable.c +++ /dev/null @@ -1,56 +0,0 @@ -/** - * \file drm_drawable.c - * IOCTLs for drawables - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "drmP.h" - -/** No-op. */ -int drm_adddraw(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_draw_t draw; - - draw.handle = 0; /* NOOP */ - DRM_DEBUG("%d\n", draw.handle); - if (copy_to_user((drm_draw_t __user *) arg, &draw, sizeof(draw))) - return -EFAULT; - return 0; -} - -/** No-op. */ -int drm_rmdraw(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - return 0; /* NOOP */ -} diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c new file mode 120000 index 00000000..d64bbe10 --- /dev/null +++ b/linux-core/drm_drawable.c @@ -0,0 +1 @@ +../shared-core/drm_drawable.c \ No newline at end of file diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index c4f33813..5d28284c 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -67,6 +67,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, int retcode; spin_lock_init(&dev->count_lock); + spin_lock_init(&dev->drw_lock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); diff --git a/shared-core/drm.h b/shared-core/drm.h index c2bcf62c..0b241117 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -164,6 +164,14 @@ typedef struct drm_clip_rect { unsigned short y2; } drm_clip_rect_t; +/** + * Drawable information. + */ +typedef struct drm_drawable_info { + unsigned int num_rects; + drm_clip_rect_t *rects; +} drm_drawable_info_t; + /** * Texture region, */ @@ -514,6 +522,20 @@ typedef struct drm_draw { drm_drawable_t handle; } drm_draw_t; +/** + * DRM_IOCTL_UPDATE_DRAW ioctl argument type. + */ +typedef enum { + DRM_DRAWABLE_CLIPRECTS, +} drm_drawable_info_type_t; + +typedef struct drm_update_draw { + drm_drawable_t handle; + unsigned int type; + unsigned int num; + unsigned long long data; +} drm_update_draw_t; + /** * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type. */ @@ -901,6 +923,8 @@ typedef union drm_mm_init_arg{ #define DRM_IOCTL_MM_INIT DRM_IOWR(0x3e, drm_mm_init_arg_t) #endif +#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t) + /*@}*/ /** diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c new file mode 100644 index 00000000..ca6eb81c --- /dev/null +++ b/shared-core/drm_drawable.c @@ -0,0 +1,256 @@ +/** + * \file drm_drawable.c + * IOCTLs for drawables + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + * \author Michel Dänzer + */ + +/* + * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "drmP.h" + +/** No-op. */ +int drm_adddraw(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + unsigned int irqflags; + int i, j = 0; + drm_draw_t draw; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + for (i = 0; i < dev->drw_bitfield_length; i++) { + u32 bitfield = dev->drw_bitfield[i]; + + if (bitfield == ~0) + continue; + + for (; j < sizeof(bitfield); j++) + if (!(bitfield & (1 << j))) + goto done; + } +done: + + if (i == dev->drw_bitfield_length) { + u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4, + (i + 1) * 4, DRM_MEM_BUFS); + + if (!new_bitfield) { + DRM_ERROR("Failed to allocate new drawable bitfield\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + if (32 * (i + 1) > dev->drw_info_length) { + void *new_info = drm_realloc(dev->drw_info, + dev->drw_info_length * + sizeof(drm_drawable_info_t*), + 32 * (i + 1) * + sizeof(drm_drawable_info_t*), + DRM_MEM_BUFS); + + if (!new_info) { + DRM_ERROR("Failed to allocate new drawable info" + " array\n"); + + drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + dev->drw_info = (drm_drawable_info_t**)new_info; + } + + new_bitfield[i] = 0; + + dev->drw_bitfield = new_bitfield; + dev->drw_bitfield_length++; + } + + dev->drw_bitfield[i] |= 1 << j; + + draw.handle = i * sizeof(u32) + j; + DRM_DEBUG("%d\n", draw.handle); + + dev->drw_info[draw.handle] = NULL; + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw)); + + return 0; +} + +/** No-op. */ +int drm_rmdraw(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_draw_t draw; + unsigned int idx, mod; + unsigned int irqflags; + + DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, + sizeof(draw)); + + idx = draw.handle / 32; + mod = draw.handle % 32; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_DEBUG("No such drawable %d\n", draw.handle); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return 0; + } + + dev->drw_bitfield[idx] &= ~(1 << mod); + + if (idx == (dev->drw_bitfield_length - 1)) { + while (idx >= 0 && !dev->drw_bitfield[idx]) + --idx; + + if (idx != draw.handle / 32) { + u32 *new_bitfield = drm_realloc(dev->drw_bitfield, + dev->drw_bitfield_length * 4, + (idx + 1) * 4, + DRM_MEM_BUFS); + + if (new_bitfield || idx == -1) { + dev->drw_bitfield = new_bitfield; + dev->drw_bitfield_length = idx + 1; + } + } + } + + if (32 * dev->drw_bitfield_length < dev->drw_info_length) { + void *new_info = drm_realloc(dev->drw_info, + dev->drw_info_length * + sizeof(drm_drawable_info_t*), + 32 * dev->drw_bitfield_length * + sizeof(drm_drawable_info_t*), + DRM_MEM_BUFS); + + if (new_info || !dev->drw_bitfield_length) { + dev->drw_info = (drm_drawable_info_t**)new_info; + dev->drw_info_length = 32 * dev->drw_bitfield_length; + } + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + return 0; +} + +int drm_update_drawable_info(DRM_IOCTL_ARGS) { + DRM_DEVICE; + drm_update_draw_t update; + unsigned int id, idx, mod; + unsigned int irqflags; + drm_drawable_info_t *info; + void *new_data; + + DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, + sizeof(update)); + + id = update.handle; + idx = id / 32; + mod = id % 32; + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_ERROR("No such drawable %d\n", update.handle); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EINVAL); + } + + info = dev->drw_info[id]; + + if (!info) { + info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS); + + if (!info) { + DRM_ERROR("Failed to allocate drawable info memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + dev->drw_info[id] = info; + } + + switch (update.type) { + case DRM_DRAWABLE_CLIPRECTS: + new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + + if (!new_data) { + DRM_ERROR("Failed to allocate cliprect memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + if (DRM_COPY_FROM_USER(new_data, + (drm_clip_rect_t __user *) + (unsigned long)update.data, + update.num * sizeof(drm_clip_rect_t))) { + DRM_ERROR("Failed to copy cliprects from userspace\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EFAULT); + } + + drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + + info->rects = new_data; + info->num_rects = update.num; + break; + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + return 0; +} + +/** + * Caller must hold the drawable spinlock! + */ +drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { + unsigned int idx = id / 32, mod = id % 32; + + if (idx >= dev->drw_bitfield_length || + !(dev->drw_bitfield[idx] & (1 << mod))) { + DRM_DEBUG("No such drawable %d\n", id); + return NULL; + } + + return dev->drw_info[id]; +} -- cgit v1.2.3 From baa26c5faa3d5903569d1c94ad93b843d6979ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 23 Aug 2006 16:04:41 +0200 Subject: Only reallocate cliprect memory if the number of cliprects changes. Also improve diagnostic output. (cherry picked from af48be1096221d551319c67a9e782b50ef58fefd commit) --- shared-core/drm_drawable.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index ca6eb81c..511f3eae 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -166,6 +166,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_DEBUG("%d\n", draw.handle); return 0; } @@ -209,30 +210,42 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: - new_data = drm_alloc(update.num * sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + if (update.num != info->num_rects) { + new_data = drm_alloc(update.num * + sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); - if (!new_data) { - DRM_ERROR("Failed to allocate cliprect memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(ENOMEM); + if (!new_data) { + DRM_ERROR("Can't allocate cliprect memory\n"); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(ENOMEM); + } + + info->rects = new_data; } - if (DRM_COPY_FROM_USER(new_data, + if (DRM_COPY_FROM_USER(info->rects, (drm_clip_rect_t __user *) (unsigned long)update.data, update.num * sizeof(drm_clip_rect_t))) { - DRM_ERROR("Failed to copy cliprects from userspace\n"); + DRM_ERROR("Can't copy cliprects from userspace\n"); spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EFAULT); } - drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); + if (update.num != info->num_rects) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + info->num_rects = update.num; + } - info->rects = new_data; - info->num_rects = update.num; + DRM_DEBUG("Updated %d cliprects for drawable %d\n", + info->num_rects, id); break; + default: + DRM_ERROR("Invalid update type %d\n", update.type); + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + return DRM_ERR(EINVAL); } spin_unlock_irqrestore(&dev->drw_lock, irqflags); -- 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(-) 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 f93e4822694b066427f70c23216b78f92edb1bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 23 Aug 2006 19:00:26 +0200 Subject: Export drm_get_drawable_info symbol from core. (cherry picked from 43f8675534c7e95efbc92eaf2c8cc43aef95f125 commit) --- shared-core/drm_drawable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 511f3eae..0a357948 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -267,3 +267,4 @@ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) return dev->drw_info[id]; } +EXPORT_SYMBOL(drm_get_drawable_info); -- 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(+) 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 d7389a9758944ab0d241d3c1108adfeeec9eee76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 25 Aug 2006 18:55:55 +0200 Subject: Locking and memory management fixes. (cherry picked from 23d2833aaa37a33b9ddcf06cc796f59befc0d360 commit) --- shared-core/drm_drawable.c | 261 ++++++++++++++++++++++++++------------------- 1 file changed, 154 insertions(+), 107 deletions(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 0a357948..81eb9f08 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -36,70 +36,86 @@ #include "drmP.h" -/** No-op. */ +/** + * Allocate drawable ID and memory to store information about it. + */ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; unsigned int irqflags; - int i, j = 0; + int i, j; + u32 *bitfield = dev->drw_bitfield; + unsigned int bitfield_length = dev->drw_bitfield_length; + drm_drawable_info_t **info = dev->drw_info; + unsigned int info_length = dev->drw_info_length; drm_draw_t draw; - spin_lock_irqsave(&dev->drw_lock, irqflags); - - for (i = 0; i < dev->drw_bitfield_length; i++) { - u32 bitfield = dev->drw_bitfield[i]; - - if (bitfield == ~0) + for (i = 0, j = 0; i < bitfield_length; i++) { + if (bitfield[i] == ~0) continue; - for (; j < sizeof(bitfield); j++) - if (!(bitfield & (1 << j))) + for (; j < 8 * sizeof(*bitfield); j++) + if (!(bitfield[i] & (1 << j))) goto done; } done: - if (i == dev->drw_bitfield_length) { - u32 *new_bitfield = drm_realloc(dev->drw_bitfield, i * 4, - (i + 1) * 4, DRM_MEM_BUFS); + if (i == bitfield_length) { + bitfield_length++; + + bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), + DRM_MEM_BUFS); - if (!new_bitfield) { + if (!bitfield) { DRM_ERROR("Failed to allocate new drawable bitfield\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(ENOMEM); } - if (32 * (i + 1) > dev->drw_info_length) { - void *new_info = drm_realloc(dev->drw_info, - dev->drw_info_length * - sizeof(drm_drawable_info_t*), - 32 * (i + 1) * - sizeof(drm_drawable_info_t*), - DRM_MEM_BUFS); + if (8 * sizeof(*bitfield) * bitfield_length > info_length) { + info_length += 8 * sizeof(*bitfield); - if (!new_info) { + info = drm_alloc(info_length * sizeof(*info), + DRM_MEM_BUFS); + + if (!info) { DRM_ERROR("Failed to allocate new drawable info" " array\n"); - drm_free(new_bitfield, (i + 1) * 4, DRM_MEM_BUFS); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); + drm_free(bitfield, + bitfield_length * sizeof(*bitfield), + DRM_MEM_BUFS); return DRM_ERR(ENOMEM); } - - dev->drw_info = (drm_drawable_info_t**)new_info; } - new_bitfield[i] = 0; - - dev->drw_bitfield = new_bitfield; - dev->drw_bitfield_length++; + bitfield[i] = 0; } - dev->drw_bitfield[i] |= 1 << j; - - draw.handle = i * sizeof(u32) + j; + draw.handle = i * 8 * sizeof(*bitfield) + j; DRM_DEBUG("%d\n", draw.handle); - dev->drw_info[draw.handle] = NULL; + spin_lock_irqsave(&dev->drw_lock, irqflags); + + bitfield[i] |= 1 << j; + info[draw.handle] = NULL; + + if (bitfield != dev->drw_bitfield) { + memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * + sizeof(*bitfield)); + drm_free(dev->drw_bitfield, sizeof(*bitfield) * + dev->drw_bitfield_length, DRM_MEM_BUFS); + dev->drw_bitfield = bitfield; + dev->drw_bitfield_length = bitfield_length; + } + + if (info != dev->drw_info) { + memcpy(info, dev->drw_info, dev->drw_info_length * + sizeof(*info)); + drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length, + DRM_MEM_BUFS); + dev->drw_info = info; + dev->drw_info_length = info_length; + } spin_unlock_irqrestore(&dev->drw_lock, irqflags); @@ -108,63 +124,85 @@ done: return 0; } -/** No-op. */ +/** + * Free drawable ID and memory to store information about it. + */ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int idx, mod; + unsigned int idx, shift; unsigned int irqflags; + u32 *bitfield = dev->drw_bitfield; + unsigned int bitfield_length = dev->drw_bitfield_length; + drm_drawable_info_t **info = dev->drw_info; + unsigned int info_length = dev->drw_info_length; DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - idx = draw.handle / 32; - mod = draw.handle % 32; + idx = draw.handle / (8 * sizeof(*bitfield)); + shift = draw.handle % (8 * sizeof(*bitfield)); - spin_lock_irqsave(&dev->drw_lock, irqflags); - - if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + if (idx >= bitfield_length || + !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", draw.handle); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return 0; } - dev->drw_bitfield[idx] &= ~(1 << mod); + spin_lock_irqsave(&dev->drw_lock, irqflags); + + bitfield[idx] &= ~(1 << shift); + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); - if (idx == (dev->drw_bitfield_length - 1)) { - while (idx >= 0 && !dev->drw_bitfield[idx]) + /* Can we shrink the arrays? */ + if (idx == bitfield_length - 1) { + while (idx >= 0 && !bitfield[idx]) --idx; - if (idx != draw.handle / 32) { - u32 *new_bitfield = drm_realloc(dev->drw_bitfield, - dev->drw_bitfield_length * 4, - (idx + 1) * 4, - DRM_MEM_BUFS); + bitfield_length = idx + 1; - if (new_bitfield || idx == -1) { - dev->drw_bitfield = new_bitfield; - dev->drw_bitfield_length = idx + 1; - } + if (idx != draw.handle / (8 * sizeof(*bitfield))) + bitfield = drm_alloc(bitfield_length * + sizeof(*bitfield), DRM_MEM_BUFS); + + if (!bitfield && bitfield_length) { + bitfield = dev->drw_bitfield; + bitfield_length = dev->drw_bitfield_length; } } - if (32 * dev->drw_bitfield_length < dev->drw_info_length) { - void *new_info = drm_realloc(dev->drw_info, - dev->drw_info_length * - sizeof(drm_drawable_info_t*), - 32 * dev->drw_bitfield_length * - sizeof(drm_drawable_info_t*), - DRM_MEM_BUFS); - - if (new_info || !dev->drw_bitfield_length) { - dev->drw_info = (drm_drawable_info_t**)new_info; - dev->drw_info_length = 32 * dev->drw_bitfield_length; + if (bitfield != dev->drw_bitfield) { + info_length = 8 * sizeof(*bitfield) * bitfield_length; + + info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS); + + if (!info && info_length) { + info = dev->drw_info; + info_length = dev->drw_info_length; } - } - spin_unlock_irqrestore(&dev->drw_lock, irqflags); + spin_lock_irqsave(&dev->drw_lock, irqflags); + + memcpy(bitfield, dev->drw_bitfield, bitfield_length * + sizeof(*bitfield)); + drm_free(dev->drw_bitfield, sizeof(*bitfield) * + dev->drw_bitfield_length, DRM_MEM_BUFS); + dev->drw_bitfield = bitfield; + dev->drw_bitfield_length = bitfield_length; + + if (info != dev->drw_info) { + memcpy(info, dev->drw_info, info_length * + sizeof(*info)); + drm_free(dev->drw_info, sizeof(*info) * + dev->drw_info_length, DRM_MEM_BUFS); + dev->drw_info = info; + dev->drw_info_length = info_length; + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + } DRM_DEBUG("%d\n", draw.handle); return 0; @@ -173,24 +211,22 @@ int drm_rmdraw(DRM_IOCTL_ARGS) int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_update_draw_t update; - unsigned int id, idx, mod; - unsigned int irqflags; + unsigned int id, idx, shift; + u32 *bitfield = dev->drw_bitfield; + unsigned int irqflags, bitfield_length = dev->drw_bitfield_length; drm_drawable_info_t *info; - void *new_data; + drm_clip_rect_t *rects; + int err; DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, sizeof(update)); id = update.handle; - idx = id / 32; - mod = id % 32; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - spin_lock_irqsave(&dev->drw_lock, irqflags); - - if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_ERROR("No such drawable %d\n", update.handle); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EINVAL); } @@ -201,66 +237,77 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { if (!info) { DRM_ERROR("Failed to allocate drawable info memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(ENOMEM); } - - dev->drw_info[id] = info; } switch (update.type) { case DRM_DRAWABLE_CLIPRECTS: if (update.num != info->num_rects) { - new_data = drm_alloc(update.num * - sizeof(drm_clip_rect_t), - DRM_MEM_BUFS); - - if (!new_data) { - DRM_ERROR("Can't allocate cliprect memory\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(ENOMEM); - } - - info->rects = new_data; + rects = drm_alloc(update.num * sizeof(drm_clip_rect_t), + DRM_MEM_BUFS); + } else + rects = info->rects; + + if (update.num && !rects) { + DRM_ERROR("Failed to allocate cliprect memory\n"); + err = DRM_ERR(ENOMEM); + goto error; } - if (DRM_COPY_FROM_USER(info->rects, - (drm_clip_rect_t __user *) - (unsigned long)update.data, - update.num * sizeof(drm_clip_rect_t))) { - DRM_ERROR("Can't copy cliprects from userspace\n"); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return DRM_ERR(EFAULT); + if (update.num && DRM_COPY_FROM_USER(rects, + (drm_clip_rect_t __user *) + (unsigned long)update.data, + update.num * + sizeof(*rects))) { + DRM_ERROR("Failed to copy cliprects from userspace\n"); + err = DRM_ERR(EFAULT); + goto error; } - if (update.num != info->num_rects) { + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (rects != info->rects) { drm_free(info->rects, info->num_rects * sizeof(drm_clip_rect_t), DRM_MEM_BUFS); - info->num_rects = update.num; } + info->rects = rects; + info->num_rects = update.num; + dev->drw_info[id] = info; + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_DEBUG("Updated %d cliprects for drawable %d\n", info->num_rects, id); break; default: DRM_ERROR("Invalid update type %d\n", update.type); - spin_unlock_irqrestore(&dev->drw_lock, irqflags); return DRM_ERR(EINVAL); } - spin_unlock_irqrestore(&dev->drw_lock, irqflags); - return 0; + +error: + if (!dev->drw_info[id]) + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + else if (rects != dev->drw_info[id]->rects) + drm_free(rects, update.num * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + + return err; } /** * Caller must hold the drawable spinlock! */ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { - unsigned int idx = id / 32, mod = id % 32; + u32 *bitfield = dev->drw_bitfield; + unsigned int idx = id / (8 * sizeof(*bitfield)); + unsigned int shift = id % (8 * sizeof(*bitfield)); if (idx >= dev->drw_bitfield_length || - !(dev->drw_bitfield[idx] & (1 << mod))) { + !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", id); return NULL; } -- cgit v1.2.3 From da75d59cd65764c6076ab9b96ad8195ed71ed80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 25 Aug 2006 19:01:05 +0200 Subject: i915: Add ioctl for scheduling buffer swaps at vertical blanks. This uses the core facility to schedule a driver callback that will be called ASAP after the given vertical blank interrupt with the HW lock held. (cherry picked from 257771fa290b62d4d2ad896843cf3a207978d0bb commit) --- shared-core/i915_dma.c | 2 + shared-core/i915_drm.h | 9 +++ shared-core/i915_drv.h | 16 +++++ shared-core/i915_irq.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index baeab383..841761c8 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -163,6 +163,7 @@ static int i915_initialize(drm_device_t * dev, dev_priv->ring.virtual_start = dev_priv->ring.map.handle; + dev_priv->cpp = init->cpp; dev_priv->back_offset = init->back_offset; dev_priv->front_offset = init->front_offset; dev_priv->current_page = 0; @@ -821,6 +822,7 @@ drm_ioctl_desc_t i915_ioctls[] = { [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }, [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH }, + [DRM_IOCTL_NR(DRM_I915_VBLANK_SWAP)] = {i915_vblank_swap, DRM_AUTH}, }; int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls); diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index e841105b..e1db7a65 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -142,6 +142,7 @@ typedef struct _drm_i915_sarea { #define DRM_I915_DESTROY_HEAP 0x0c #define DRM_I915_SET_VBLANK_PIPE 0x0d #define DRM_I915_GET_VBLANK_PIPE 0x0e +#define DRM_I915_VBLANK_SWAP 0x0f #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -254,4 +255,12 @@ typedef struct drm_i915_vblank_pipe { int pipe; } drm_i915_vblank_pipe_t; +/* Schedule buffer swap at given vertical blank: + */ +typedef struct drm_i915_vblank_swap { + drm_drawable_t drawable; + unsigned int pipe; + unsigned int sequence; +} drm_i915_vblank_swap_t; + #endif /* _I915_DRM_H_ */ diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 27324015..c6bbcafb 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -76,6 +76,13 @@ struct mem_block { DRMFILE filp; /* 0: free, -1: heap, other: real files */ }; +typedef struct _drm_i915_vbl_swap { + struct list_head head; + drm_drawable_t drw_id; + unsigned int pipe; + unsigned int sequence; +} drm_i915_vbl_swap_t; + typedef struct drm_i915_private { drm_local_map_t *sarea; drm_local_map_t *mmio_map; @@ -88,6 +95,7 @@ typedef struct drm_i915_private { dma_addr_t dma_status_page; uint32_t counter; + unsigned int cpp; int back_offset; int front_offset; int current_page; @@ -116,6 +124,9 @@ typedef struct drm_i915_private { uint32_t saved_flush_status; #endif + spinlock_t swaps_lock; + drm_i915_vbl_swap_t vbl_swaps; + unsigned int swaps_pending; } drm_i915_private_t; extern drm_ioctl_desc_t i915_ioctls[]; @@ -147,6 +158,7 @@ extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS); extern int i915_emit_irq(drm_device_t * dev); extern void i915_user_irq_on(drm_i915_private_t *dev_priv); extern void i915_user_irq_off(drm_i915_private_t *dev_priv); +extern int i915_vblank_swap(DRM_IOCTL_ARGS); /* i915_mem.c */ extern int i915_mem_alloc(DRM_IOCTL_ARGS); @@ -304,6 +316,10 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller); #define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2) +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) + #define MI_BATCH_BUFFER ((0x30<<23)|1) #define MI_BATCH_BUFFER_START (0x31<<23) #define MI_BATCH_BUFFER_END (0xA<<23) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index c26c2769..667a9ca8 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -37,6 +37,99 @@ #define MAX_NOPID ((u32)~0) +/** + * Emit blits for scheduled buffer swaps. + * + * This function will be called with the HW lock held. + */ +static void i915_vblank_tasklet(drm_device_t *dev) +{ + drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + unsigned int irqflags; + struct list_head *list, *tmp; + + DRM_DEBUG("\n"); + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) { + drm_i915_vbl_swap_t *vbl_swap = + list_entry(list, drm_i915_vbl_swap_t, head); + atomic_t *counter = vbl_swap->pipe ? &dev->vbl_received2 : + &dev->vbl_received; + + if ((atomic_read(counter) - vbl_swap->sequence) <= (1<<23)) { + drm_drawable_info_t *drw; + + spin_unlock(&dev_priv->swaps_lock); + + spin_lock(&dev->drw_lock); + + drw = drm_get_drawable_info(dev, vbl_swap->drw_id); + + if (drw) { + int i, num_rects = drw->num_rects; + drm_clip_rect_t *rect = drw->rects; + drm_i915_sarea_t *sarea_priv = + dev_priv->sarea_priv; + u32 cpp = dev_priv->cpp; + u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD | + XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB) + : XY_SRC_COPY_BLT_CMD; + u32 pitchropcpp = (sarea_priv->pitch * cpp) | + (0xcc << 16) | (cpp << 23) | + (1 << 24); + RING_LOCALS; + + i915_kernel_lost_context(dev); + + BEGIN_LP_RING(6); + + OUT_RING(GFX_OP_DRAWRECT_INFO); + OUT_RING(0); + OUT_RING(0); + OUT_RING(sarea_priv->width | + sarea_priv->height << 16); + OUT_RING(sarea_priv->width | + sarea_priv->height << 16); + OUT_RING(0); + + ADVANCE_LP_RING(); + + sarea_priv->ctxOwner = DRM_KERNEL_CONTEXT; + + for (i = 0; i < num_rects; i++, rect++) { + BEGIN_LP_RING(8); + + OUT_RING(cmd); + OUT_RING(pitchropcpp); + OUT_RING((rect->y1 << 16) | rect->x1); + OUT_RING((rect->y2 << 16) | rect->x2); + OUT_RING(sarea_priv->front_offset); + OUT_RING((rect->y1 << 16) | rect->x1); + OUT_RING(pitchropcpp & 0xffff); + OUT_RING(sarea_priv->back_offset); + + ADVANCE_LP_RING(); + } + } + + spin_unlock(&dev->drw_lock); + + spin_lock(&dev_priv->swaps_lock); + + list_del(list); + + drm_free(vbl_swap, sizeof(*vbl_swap), DRM_MEM_DRIVER); + + dev_priv->swaps_pending--; + } + } + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { drm_device_t *dev = (drm_device_t *) arg; @@ -77,6 +170,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); + + drm_locked_tasklet(dev, i915_vblank_tasklet); } return IRQ_HANDLED; @@ -307,6 +402,90 @@ int i915_vblank_pipe_get(DRM_IOCTL_ARGS) return 0; } +/** + * Schedule buffer swap at given vertical blank. + */ +int i915_vblank_swap(DRM_IOCTL_ARGS) +{ + DRM_DEVICE; + drm_i915_private_t *dev_priv = dev->dev_private; + drm_i915_vblank_swap_t swap; + drm_i915_vbl_swap_t *vbl_swap; + unsigned int irqflags; + struct list_head *list; + + if (!dev_priv) { + DRM_ERROR("%s called with no initialization\n", __func__); + return DRM_ERR(EINVAL); + } + + if (dev_priv->sarea_priv->rotation) { + DRM_DEBUG("Rotation not supported\n"); + return DRM_ERR(EINVAL); + } + + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + + DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, + sizeof(swap)); + + if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { + DRM_ERROR("Invalid pipe %d\n", swap.pipe); + return DRM_ERR(EINVAL); + } + + spin_lock_irqsave(&dev->drw_lock, irqflags); + + if (!drm_get_drawable_info(dev, swap.drawable)) { + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + DRM_ERROR("Invalid drawable ID %d\n", swap.drawable); + return DRM_ERR(EINVAL); + } + + spin_unlock_irqrestore(&dev->drw_lock, irqflags); + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_for_each(list, &dev_priv->vbl_swaps.head) { + vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); + + if (vbl_swap->drw_id == swap.drawable && + vbl_swap->pipe == swap.pipe && + vbl_swap->sequence == swap.sequence) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Already scheduled\n"); + return 0; + } + } + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); + + if (!vbl_swap) { + DRM_ERROR("Failed to allocate memory to queue swap\n"); + return DRM_ERR(ENOMEM); + } + + DRM_DEBUG("\n"); + + vbl_swap->drw_id = swap.drawable; + vbl_swap->pipe = swap.pipe; + vbl_swap->sequence = swap.sequence; + + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + + list_add_tail((struct list_head *)vbl_swap, &dev_priv->vbl_swaps.head); + dev_priv->swaps_pending++; + + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + return 0; +} + /* drm_dma.h hooks */ void i915_driver_irq_preinstall(drm_device_t * dev) @@ -322,6 +501,10 @@ void i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; + dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED; + INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); + dev_priv->swaps_pending = 0; + i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); -- cgit v1.2.3 From 7d487602a31dd886037417db088b6e643ed86918 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 28 Aug 2006 18:19:58 +0200 Subject: Add copyright notice. (cherry picked from d04751facea36cb888c7510b126658fdbc4277d5 commit) --- shared-core/drm_drawable.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 81eb9f08..bbfaf139 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -12,6 +12,7 @@ * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, North Dakota. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a -- 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 ++++++++++++ shared-core/drm_drawable.c | 35 +++++++++++++++++++++++------------ 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index d4ef1306..37539f34 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -163,6 +163,18 @@ int drm_lastclose(drm_device_t * dev) if (dev->irq_enabled) drm_irq_uninstall(dev); + /* Free drawable information memory */ + for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield); + i++) { + drm_drawable_info_t *info = drm_get_drawable_info(dev, i); + + if (info) { + drm_free(info->rects, info->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info, sizeof(*info), DRM_MEM_BUFS); + } + } + mutex_lock(&dev->struct_mutex); del_timer(&dev->timer); diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index bbfaf139..5e2fc86c 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -92,13 +92,13 @@ done: bitfield[i] = 0; } - draw.handle = i * 8 * sizeof(*bitfield) + j; + draw.handle = i * 8 * sizeof(*bitfield) + j + 1; DRM_DEBUG("%d\n", draw.handle); spin_lock_irqsave(&dev->drw_lock, irqflags); bitfield[i] |= 1 << j; - info[draw.handle] = NULL; + info[draw.handle - 1] = NULL; if (bitfield != dev->drw_bitfield) { memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length * @@ -132,7 +132,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int idx, shift; + unsigned int id, idx, shift; unsigned int irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; @@ -142,10 +142,11 @@ int drm_rmdraw(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data, sizeof(draw)); - idx = draw.handle / (8 * sizeof(*bitfield)); - shift = draw.handle % (8 * sizeof(*bitfield)); + id = draw.handle - 1; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - if (idx >= bitfield_length || + if (idx < 0 || idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", draw.handle); return 0; @@ -157,6 +158,12 @@ int drm_rmdraw(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + if (info[id]) { + drm_free(info[id]->rects, info[id]->num_rects * + sizeof(drm_clip_rect_t), DRM_MEM_BUFS); + drm_free(info[id], sizeof(**info), DRM_MEM_BUFS); + } + /* Can we shrink the arrays? */ if (idx == bitfield_length - 1) { while (idx >= 0 && !bitfield[idx]) @@ -164,7 +171,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) bitfield_length = idx + 1; - if (idx != draw.handle / (8 * sizeof(*bitfield))) + if (idx != id / (8 * sizeof(*bitfield))) bitfield = drm_alloc(bitfield_length * sizeof(*bitfield), DRM_MEM_BUFS); @@ -222,11 +229,12 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data, sizeof(update)); - id = update.handle; + id = update.handle - 1; idx = id / (8 * sizeof(*bitfield)); shift = id % (8 * sizeof(*bitfield)); - if (idx >= bitfield_length || !(bitfield[idx] & (1 << shift))) { + if (idx < 0 || idx >= bitfield_length || + !(bitfield[idx] & (1 << shift))) { DRM_ERROR("No such drawable %d\n", update.handle); return DRM_ERR(EINVAL); } @@ -304,10 +312,13 @@ error: */ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) { u32 *bitfield = dev->drw_bitfield; - unsigned int idx = id / (8 * sizeof(*bitfield)); - unsigned int shift = id % (8 * sizeof(*bitfield)); + unsigned int idx, shift; + + id--; + idx = id / (8 * sizeof(*bitfield)); + shift = id % (8 * sizeof(*bitfield)); - if (idx >= dev->drw_bitfield_length || + if (idx < 0 || idx >= dev->drw_bitfield_length || !(bitfield[idx] & (1 << shift))) { DRM_DEBUG("No such drawable %d\n", id); return NULL; -- cgit v1.2.3 From 1f3493f65ba0959e401191c648f57501216eeb0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 30 Aug 2006 19:33:28 +0200 Subject: DRM_I915_VBLANK_SWAP ioctl: Take drm_vblank_seq_type_t instead of pipe number. Handle relative as well as absolute target sequence numbers. Return error if target sequence has already passed, so userspace can deal with this situation as it sees fit. On success, return the sequence number of the vertical blank when the buffer swap is expected to take place. Also add DRM_IOCTL_I915_VBLANK_SWAP definition for userspace code that may want to use ioctl() instead of drmCommandWriteRead(). (cherry picked from d5a0f107511e128658e2d5e15bd7e6215c507f29 commit) --- shared-core/i915_drm.h | 3 ++- shared-core/i915_irq.c | 43 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index e1db7a65..e2a70231 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -159,6 +159,7 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) #define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) #define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) /* Allow drivers to submit batchbuffers directly to hardware, relying @@ -259,7 +260,7 @@ typedef struct drm_i915_vblank_pipe { */ typedef struct drm_i915_vblank_swap { drm_drawable_t drawable; - unsigned int pipe; + drm_vblank_seq_type_t seqtype; unsigned int sequence; } drm_i915_vblank_swap_t; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 667a9ca8..3c562fdd 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -411,7 +411,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int irqflags; + unsigned int pipe, seqtype, irqflags, curseq; struct list_head *list; if (!dev_priv) { @@ -432,8 +432,23 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); - if (swap.pipe > 1 || !(dev_priv->vblank_pipe & (1 << swap.pipe))) { - DRM_ERROR("Invalid pipe %d\n", swap.pipe); + if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | + _DRM_VBLANK_SECONDARY)) { + DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); + return DRM_ERR(EINVAL); + } + + pipe = (swap.seqtype & _DRM_VBLANK_SECONDARY) ? 1 : 0; + + seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); + + if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { + DRM_DEBUG("Not scheduling swap for current sequence\n"); + return DRM_ERR(EINVAL); + } + + if (!(dev_priv->vblank_pipe & (1 << pipe))) { + DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); } @@ -447,13 +462,28 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev->drw_lock, irqflags); + curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + switch (seqtype) { + case _DRM_VBLANK_RELATIVE: + swap.sequence += curseq; + break; + case _DRM_VBLANK_ABSOLUTE: + if ((curseq - swap.sequence) > (1<<23)) { + spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_DEBUG("Missed target sequence\n"); + return DRM_ERR(EINVAL); + } + break; + } + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); if (vbl_swap->drw_id == swap.drawable && - vbl_swap->pipe == swap.pipe && + vbl_swap->pipe == pipe && vbl_swap->sequence == swap.sequence) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Already scheduled\n"); @@ -473,7 +503,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) DRM_DEBUG("\n"); vbl_swap->drw_id = swap.drawable; - vbl_swap->pipe = swap.pipe; + vbl_swap->pipe = pipe; vbl_swap->sequence = swap.sequence; spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); @@ -483,6 +513,9 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_swap_t __user *) data, swap, + sizeof(swap)); + return 0; } -- cgit v1.2.3 From 4a3d270862f6dbc52ca3e16ba66fdb24667b2aa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:30:55 +0200 Subject: Make handling of dev_priv->vblank_pipe more robust. Initialize it to default value if it hasn't been set by the X server yet. In i915_vblank_pipe_set(), only update dev_priv->vblank_pipe and call i915_enable_interrupt() if the argument passed from userspace is valid to avoid corrupting dev_priv->vblank_pipe on invalid arguments. (cherry picked from 87c57cba1a70221fc570b253bf3b24682ef6b894 commit) --- shared-core/i915_irq.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 3c562fdd..f82df5c9 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -336,7 +336,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS) return i915_wait_irq(dev, irqwait.irq_seq); } -static int i915_enable_interrupt (drm_device_t *dev) +static void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; u16 flag; @@ -346,17 +346,11 @@ static int i915_enable_interrupt (drm_device_t *dev) flag |= VSYNC_PIPEA_FLAG; if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) flag |= VSYNC_PIPEB_FLAG; - if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { - DRM_ERROR("%s called with invalid pipe 0x%x\n", - __FUNCTION__, dev_priv->vblank_pipe); - return DRM_ERR(EINVAL); - } dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; dev_priv->user_irq_refcount = 0; dev_priv->irq_enable_reg = flag; I915_WRITE16(I915REG_INT_ENABLE_R, flag); dev_priv->irq_enabled = 1; - return 0; } /* Set the vblank monitor pipe @@ -375,8 +369,17 @@ int i915_vblank_pipe_set(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data, sizeof(pipe)); + if (pipe.pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) { + DRM_ERROR("%s called with invalid pipe 0x%x\n", + __FUNCTION__, pipe.pipe); + return DRM_ERR(EINVAL); + } + dev_priv->vblank_pipe = pipe.pipe; - return i915_enable_interrupt (dev); + + i915_enable_interrupt (dev); + + return 0; } int i915_vblank_pipe_get(DRM_IOCTL_ARGS) @@ -538,6 +541,8 @@ void i915_driver_irq_postinstall(drm_device_t * dev) INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; + if (!dev_priv->vblank_pipe) + dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; i915_enable_interrupt(dev); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); -- cgit v1.2.3 From 316e73676861c0e019d52ec7bf7b7b1451eaed97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:32:08 +0200 Subject: Add definition of DRM_VBLANK_SECONDARY. (cherry picked from 84b38b63f05e04ade8b1ddfb770047fd86de0d64 commit) --- libdrm/xf86drm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index d39974de..07178ec3 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; -- cgit v1.2.3 From f9aa4f5973d6098b95e92f606dc1967c627897db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 31 Aug 2006 18:33:04 +0200 Subject: Add SAREA fileds for determining which pipe to sync window buffer swaps to. (cherry picked from c2bdb76814755c9ac6e66a8815f23af0fe4f3a91 commit) --- shared-core/i915_drm.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h index e2a70231..9eec109e 100644 --- a/shared-core/i915_drm.h +++ b/shared-core/i915_drm.h @@ -104,6 +104,15 @@ typedef struct _drm_i915_sarea { unsigned int depth_tiled; unsigned int rotated_tiled; unsigned int rotated2_tiled; + + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; } drm_i915_sarea_t; /* Driver specific fence types and classes. -- cgit v1.2.3 From c4c47a7eacf8e8cb96b2fb63164e28f0db7353ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 1 Sep 2006 11:24:38 +0200 Subject: Fix 'sequence has passed' condition in i915_vblank_swap(). (cherry picked from 7f09f957d9a61ac107f8fd29128d7899a3e8a228 commit) --- shared-core/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index f82df5c9..d88afdd0 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -474,7 +474,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) swap.sequence += curseq; break; case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) > (1<<23)) { + if ((curseq - swap.sequence) <= (1<<23)) { spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); -- 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) --- libdrm/xf86drm.h | 1 + linux-core/drm_irq.c | 16 ++++++++++------ shared-core/drm.h | 4 +++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 07178ec3..ae89fd6f 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -252,6 +252,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ } drmVBlankSeqType; diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index fef0e8d4..bd8a9c82 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -249,8 +249,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) drm_wait_vblank_t vblwait; struct timeval now; int ret = 0; - unsigned int flags; - atomic_t *seq; + unsigned int flags, seq; if ((!dev->irq) || (!dev->irq_enabled)) return -EINVAL; @@ -272,12 +271,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL)) return -EINVAL; - seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 : - &dev->vbl_received; + seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 + : &dev->vbl_received); switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) { case _DRM_VBLANK_RELATIVE: - vblwait.request.sequence += atomic_read(seq); + vblwait.request.sequence += seq; vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; @@ -285,13 +284,18 @@ int drm_wait_vblank(DRM_IOCTL_ARGS) return -EINVAL; } + if ((flags & _DRM_VBLANK_NEXTONMISS) && + (seq - vblwait.request.sequence) <= (1<<23)) { + vblwait.request.sequence = seq + 1; + } + if (flags & _DRM_VBLANK_SIGNAL) { unsigned long irqflags; drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_sigs2 : &dev->vbl_sigs; drm_vbl_sig_t *vbl_sig; - vblwait.reply.sequence = atomic_read(seq); + vblwait.reply.sequence = seq; spin_lock_irqsave(&dev->vbl_lock, irqflags); diff --git a/shared-core/drm.h b/shared-core/drm.h index 0b241117..17bf993b 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -558,12 +558,14 @@ typedef struct drm_irq_busid { typedef enum { _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; #define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) -#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \ + _DRM_VBLANK_NEXTONMISS) struct drm_wait_vblank_request { drm_vblank_seq_type_t type; -- 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(-) 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 c47ebd970783873164578126fa5481a166cd837e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 1 Sep 2006 11:48:07 +0200 Subject: Only return EBUSY after we've established we need to schedule a new swap. (cherry picked from 50a0284a61d4415c0ebdb02decee76ef3115007a commit) --- shared-core/i915_irq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index d88afdd0..158a91de 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -427,11 +427,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) return DRM_ERR(EINVAL); } - if (dev_priv->swaps_pending >= 100) { - DRM_DEBUG("Too many swaps queued\n"); - return DRM_ERR(EBUSY); - } - DRM_COPY_FROM_USER_IOCTL(swap, (drm_i915_vblank_swap_t __user *) data, sizeof(swap)); @@ -496,6 +491,11 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + if (dev_priv->swaps_pending >= 100) { + DRM_DEBUG("Too many swaps queued\n"); + return DRM_ERR(EBUSY); + } + vbl_swap = drm_calloc(1, sizeof(vbl_swap), DRM_MEM_DRIVER); if (!vbl_swap) { -- cgit v1.2.3 From 0a7d9edcfb427724f0cad5ff6d0a4493d266b4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 13 Sep 2006 08:59:35 +0200 Subject: i915_vblank_swap: Add support for DRM_VBLANK_NEXTONMISS. (cherry picked from 0356fe260dcf80f6d2d20e3384f2a1f4ee7f5b30 commit) --- shared-core/i915_irq.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 158a91de..b72ceb2b 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -431,7 +431,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) sizeof(swap)); if (swap.seqtype & ~(_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE | - _DRM_VBLANK_SECONDARY)) { + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS)) { DRM_ERROR("Invalid sequence type 0x%x\n", swap.seqtype); return DRM_ERR(EINVAL); } @@ -440,11 +440,6 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) seqtype = swap.seqtype & (_DRM_VBLANK_RELATIVE | _DRM_VBLANK_ABSOLUTE); - if (seqtype == _DRM_VBLANK_RELATIVE && swap.sequence == 0) { - DRM_DEBUG("Not scheduling swap for current sequence\n"); - return DRM_ERR(EINVAL); - } - if (!(dev_priv->vblank_pipe & (1 << pipe))) { DRM_ERROR("Invalid pipe %d\n", pipe); return DRM_ERR(EINVAL); @@ -462,21 +457,20 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) curseq = atomic_read(pipe ? &dev->vbl_received2 : &dev->vbl_received); - spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); - - switch (seqtype) { - case _DRM_VBLANK_RELATIVE: + if (seqtype == _DRM_VBLANK_RELATIVE) swap.sequence += curseq; - break; - case _DRM_VBLANK_ABSOLUTE: - if ((curseq - swap.sequence) <= (1<<23)) { - spin_unlock_irqrestore(&dev_priv->swaps_lock, irqflags); + + if ((curseq - swap.sequence) <= (1<<23)) { + if (swap.seqtype & _DRM_VBLANK_NEXTONMISS) { + swap.sequence = curseq + 1; + } else { DRM_DEBUG("Missed target sequence\n"); return DRM_ERR(EINVAL); } - break; } + spin_lock_irqsave(&dev_priv->swaps_lock, irqflags); + list_for_each(list, &dev_priv->vbl_swaps.head) { vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head); -- cgit v1.2.3 From c0bff9f9cd08066df7f3bccd77d4d4dd4edb4163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 18 Sep 2006 12:15:38 +0200 Subject: i915: Bump minor for swap scheduling ioctl and secondary vblank support. (cherry picked from 2627131e5d0c8cd5e3f0db06451c2e7ae7569b1b commit) --- shared-core/i915_drv.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index c6bbcafb..cc575546 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -46,6 +46,8 @@ * 1.3: Add vblank support * 1.4: Fix cmdbuffer path, add heap destroy * 1.5: Add vblank pipe configuration + * 1.6: - New ioctl for scheduling buffer swaps on vertical blank + * - Support vertical blank on secondary display pipe */ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 6 -- cgit v1.2.3 From 390184df92915d232cab90469937de875ee65b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 27 Sep 2006 18:22:10 +0200 Subject: i915: Avoid mis-counting vblank interrupts when they're only enabled for pipe A. It looks like 'after a while', I915REG_INT_IDENTITY_R for some reason always has VSYNC_PIPEB_FLAG set in the interrupt handler, even though pipe B is disabled. So we only increase dev->vbl_received if the corresponding bit is also set in dev->vblank_pipe. (cherry picked from 881ba569929ceafd42e3c86228b0172099083d1d commit) --- shared-core/i915_irq.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index b72ceb2b..6afa9ca3 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -158,14 +158,19 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) } if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) { - if ((dev_priv->vblank_pipe & + int vblank_pipe = dev_priv->vblank_pipe; + + if ((vblank_pipe & (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) == (DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B)) { if (temp & VSYNC_PIPEA_FLAG) atomic_inc(&dev->vbl_received); if (temp & VSYNC_PIPEB_FLAG) atomic_inc(&dev->vbl_received2); - } else + } else if (((temp & VSYNC_PIPEA_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_A)) || + ((temp & VSYNC_PIPEB_FLAG) && + (vblank_pipe & DRM_I915_VBLANK_PIPE_B))) atomic_inc(&dev->vbl_received); DRM_WAKEUP(&dev->vbl_queue); -- cgit v1.2.3 From 3620a3ec85033d3d1d1a44ec32492fb2ef20fd8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 28 Sep 2006 19:05:58 +0200 Subject: i915: Bump minor again to differentiate from vsync changes. --- shared-core/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index cc575546..72cd41c3 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -50,7 +50,7 @@ * - Support vertical blank on secondary display pipe */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 6 +#define DRIVER_MINOR 7 #define DRIVER_PATCHLEVEL 0 #if defined(__linux__) -- cgit v1.2.3 From 48367fdfe677adada52ad61d850e2980e1070632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 28 Sep 2006 19:13:59 +0200 Subject: i915: Only initialize IRQ fields in postinstall, not the PIPE_SET ioctl. Some other minor changes in preparation for actually disabling user interrupts. --- shared-core/i915_irq.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 6afa9ca3..4f72d885 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -227,7 +227,7 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv) { spin_lock(&dev_priv->user_irq_lock); if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) { - dev_priv->irq_enable_reg &= ~USER_INT_FLAG; + // dev_priv->irq_enable_reg &= ~USER_INT_FLAG; // I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); } spin_unlock(&dev_priv->user_irq_lock); @@ -344,17 +344,14 @@ int i915_irq_wait(DRM_IOCTL_ARGS) static void i915_enable_interrupt (drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - u16 flag; - flag = 0; + dev_priv->irq_enable_reg = USER_INT_FLAG; //&= ~(VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG); if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A) - flag |= VSYNC_PIPEA_FLAG; + dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG; if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) - flag |= VSYNC_PIPEB_FLAG; - dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; - dev_priv->user_irq_refcount = 0; - dev_priv->irq_enable_reg = flag; - I915_WRITE16(I915REG_INT_ENABLE_R, flag); + dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; + + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); dev_priv->irq_enabled = 1; } @@ -540,6 +537,9 @@ void i915_driver_irq_postinstall(drm_device_t * dev) INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; + dev_priv->user_irq_lock = SPIN_LOCK_UNLOCKED; + dev_priv->user_irq_refcount = 0; + if (!dev_priv->vblank_pipe) dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A; i915_enable_interrupt(dev); -- cgit v1.2.3 From 17a640419a447083470880f1266e14063cd5acd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 29 Sep 2006 10:27:29 +0200 Subject: i915: Only schedule vblank tasklet if there are scheduled swaps pending. This fixes issues on X server startup with versions of xf86-video-intel that enable the IRQ before they have a context ID. (cherry picked from 7af93dd9849442270ec89cb4bbeef5bfd4f9e424 commit) --- shared-core/i915_irq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4f72d885..71b7230f 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -176,7 +176,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) DRM_WAKEUP(&dev->vbl_queue); drm_vbl_send_signals(dev); - drm_locked_tasklet(dev, i915_vblank_tasklet); + if (dev_priv->swaps_pending > 0) + drm_locked_tasklet(dev, i915_vblank_tasklet); } return IRQ_HANDLED; -- cgit v1.2.3 From 8e908eaf50d5331ee875fefbf793dbe07d99786a Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 29 Sep 2006 14:21:51 +0200 Subject: Bump driver date. --- shared-core/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 72cd41c3..a92205e4 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -37,7 +37,7 @@ #define DRIVER_NAME "i915-mm" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20060923" +#define DRIVER_DATE "20060929" /* Interface history: * -- cgit v1.2.3 From d58389968124191a546a14b42ef84edc224be23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20K=C3=BChling?= Date: Mon, 2 Oct 2006 10:50:40 +0200 Subject: drm_rmdraw: Declare id and idx as signed so testing for < 0 works as intended. --- shared-core/drm_drawable.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 5e2fc86c..d203b244 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -132,7 +132,8 @@ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int id, idx, shift; + int id, idx; + unsigned int shift; unsigned int irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; -- cgit v1.2.3 From 3a16e615cabfed18b1891a732e7243ef41dc0ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Mon, 2 Oct 2006 11:04:42 +0200 Subject: Make locked tasklet handling more robust. Initialize the spinlock unconditionally when struct drm_device is filled in, and return early in drm_locked_tasklet() if the driver doesn't support IRQs. --- linux-core/drm_irq.c | 4 ++-- linux-core/drm_stub.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index d1a6a6b1..41038fd7 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -118,7 +118,6 @@ 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); @@ -458,7 +457,8 @@ 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)) + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) || + test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state)) return; spin_lock_irqsave(&dev->tasklet_lock, irqflags); diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c index ad78dcf7..839cf441 100644 --- a/linux-core/drm_stub.c +++ b/linux-core/drm_stub.c @@ -62,6 +62,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev, spin_lock_init(&dev->count_lock); spin_lock_init(&dev->drw_lock); + spin_lock_init(&dev->tasklet_lock); init_timer(&dev->timer); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); -- cgit v1.2.3 From 58a23d193f7d25d23c76a58c192c814a415a843b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20K=C3=BChling?= Date: Mon, 2 Oct 2006 10:50:40 +0200 Subject: drm_rmdraw: Declare id and idx as signed so testing for < 0 works as intended. (cherry picked from d58389968124191a546a14b42ef84edc224be23d commit) --- shared-core/drm_drawable.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index 5e2fc86c..d203b244 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -132,7 +132,8 @@ int drm_rmdraw(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_draw_t draw; - unsigned int id, idx, shift; + int id, idx; + unsigned int shift; unsigned int irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; -- 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(-) 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(+) 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(-) 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(-) 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. --- configure.ac | 1 + libdrm/xf86drm.c | 13 ++++++++++--- linux-core/drm_ttm.c | 24 +++++++++++++++++++----- 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 69b111fb..b5d79456 100644 --- a/configure.ac +++ b/configure.ac @@ -30,6 +30,7 @@ AC_PROG_LIBTOOL AC_PROG_CC AC_HEADER_STDC +AC_SYS_LARGEFILE pkgconfigdir=${libdir}/pkgconfig AC_SUBST(pkgconfigdir) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index ab884eb5..bce913d3 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -46,6 +46,9 @@ # include # endif #else +# ifdef HAVE_CONFIG_H +# include +# endif # include # include # include @@ -2804,7 +2807,7 @@ int drmBOUnReference(int fd, drmBO *buf) if (buf->mapVirtual && (buf->type != drm_bo_type_fake)) { - (void) drmUnmap(buf->mapVirtual, buf->start + buf->size); + (void) munmap(buf->mapVirtual, buf->start + buf->size); buf->mapVirtual = NULL; buf->virtual = NULL; } @@ -2847,8 +2850,12 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, if (!buf->virtual && buf->type != drm_bo_type_fake) { drmAddress virtual; - ret = drmMap(fd, buf->mapHandle, buf->size + buf->start, &virtual); - if (ret) + virtual = mmap(0, buf->size + buf->start, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, buf->mapHandle); + if (virtual == MAP_FAILED) + ret = -errno; + if (ret) return ret; buf->mapVirtual = virtual; buf->virtual = ((char *) virtual) + buf->start; diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 5fbe283e..311c57fa 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -817,6 +817,11 @@ static void drm_ttm_object_remove(drm_device_t * dev, drm_ttm_object_t * object) if (list->user_token) drm_ht_remove_item(&dev->map_hash, &list->hash); + if (list->file_offset_node) { + drm_mm_put_block(&dev->offset_manager, list->file_offset_node); + list->file_offset_node = NULL; + } + map = list->map; if (map) { @@ -901,15 +906,24 @@ int drm_ttm_object_create(drm_device_t * dev, unsigned long size, map->size = ttm->num_pages * PAGE_SIZE; map->handle = (void *)object; - if (drm_ht_just_insert_please(&dev->map_hash, &list->hash, - (unsigned long)map->handle, - 32 - PAGE_SHIFT - 3, 0, - DRM_MAP_HASH_OFFSET >> PAGE_SHIFT)) { + list->file_offset_node = drm_mm_search_free(&dev->offset_manager, + ttm->num_pages, + 0,0); + if (!list->file_offset_node) { + drm_ttm_object_remove(dev, object); + return -ENOMEM; + } + list->file_offset_node = drm_mm_get_block(list->file_offset_node, + ttm->num_pages,0); + + list->hash.key = list->file_offset_node->start; + + if (drm_ht_insert_item(&dev->map_hash, &list->hash)) { drm_ttm_object_remove(dev, object); return -ENOMEM; } - list->user_token = list->hash.key << PAGE_SHIFT; + list->user_token = ((drm_u64_t) list->hash.key) << PAGE_SHIFT; atomic_set(&object->usage, 1); *ttm_object = object; -- cgit v1.2.3 From f6238cf6244b32bd84e3d2819963d7f5473867c8 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(). --- linux-core/drm_irq.c | 4 ++-- linux-core/drm_lock.c | 2 +- shared-core/drm_drawable.c | 8 ++++---- shared-core/i915_irq.c | 5 +++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 41038fd7..4d8e4a25 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -416,7 +416,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); @@ -454,7 +454,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 (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ) || diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index fa677bae..d1b85a15 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -152,7 +152,7 @@ int drm_unlock(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; - unsigned int irqflags; + unsigned long irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index d203b244..0817e321 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -43,7 +43,7 @@ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; - unsigned int irqflags; + unsigned long irqflags; int i, j; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; @@ -134,7 +134,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) drm_draw_t draw; int id, idx; unsigned int shift; - unsigned int irqflags; + unsigned long irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; drm_drawable_info_t **info = dev->drw_info; @@ -220,9 +220,9 @@ int drm_rmdraw(DRM_IOCTL_ARGS) int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_update_draw_t update; - unsigned int id, idx, shift; + unsigned int id, idx, shift, bitfield_length = dev->drw_bitfield_length; u32 *bitfield = dev->drw_bitfield; - unsigned int irqflags, bitfield_length = dev->drw_bitfield_length; + unsigned long irqflags; drm_drawable_info_t *info; drm_clip_rect_t *rects; int err; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 76c3a810..feb7acc7 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -45,7 +45,7 @@ static void i915_vblank_tasklet(drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned int irqflags; + unsigned long irqflags; struct list_head *list, *tmp; DRM_DEBUG("\n"); @@ -388,7 +388,8 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int pipe, seqtype, irqflags, curseq; + unsigned int pipe, seqtype, curseq; + unsigned long irqflags; struct list_head *list; if (!dev_priv) { -- 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 +- shared-core/drm_drawable.c | 8 ++++---- shared-core/i915_irq.c | 5 +++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index d1a6a6b1..21c3887d 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -417,7 +417,7 @@ EXPORT_SYMBOL(drm_vbl_send_signals); static void drm_locked_tasklet_func(unsigned long data) { drm_device_t *dev = (drm_device_t*)data; - unsigned int irqflags; + unsigned long irqflags; spin_lock_irqsave(&dev->tasklet_lock, irqflags); @@ -455,7 +455,7 @@ static void drm_locked_tasklet_func(unsigned long data) */ void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*)) { - unsigned int irqflags; + unsigned long irqflags; static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0); if (test_bit(TASKLET_STATE_SCHED, &drm_tasklet.state)) diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 0cf183a7..d11c570e 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -155,7 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp, drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->head->dev; drm_lock_t lock; - unsigned int irqflags; + unsigned long irqflags; if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock))) return -EFAULT; diff --git a/shared-core/drm_drawable.c b/shared-core/drm_drawable.c index d203b244..0817e321 100644 --- a/shared-core/drm_drawable.c +++ b/shared-core/drm_drawable.c @@ -43,7 +43,7 @@ int drm_adddraw(DRM_IOCTL_ARGS) { DRM_DEVICE; - unsigned int irqflags; + unsigned long irqflags; int i, j; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; @@ -134,7 +134,7 @@ int drm_rmdraw(DRM_IOCTL_ARGS) drm_draw_t draw; int id, idx; unsigned int shift; - unsigned int irqflags; + unsigned long irqflags; u32 *bitfield = dev->drw_bitfield; unsigned int bitfield_length = dev->drw_bitfield_length; drm_drawable_info_t **info = dev->drw_info; @@ -220,9 +220,9 @@ int drm_rmdraw(DRM_IOCTL_ARGS) int drm_update_drawable_info(DRM_IOCTL_ARGS) { DRM_DEVICE; drm_update_draw_t update; - unsigned int id, idx, shift; + unsigned int id, idx, shift, bitfield_length = dev->drw_bitfield_length; u32 *bitfield = dev->drw_bitfield; - unsigned int irqflags, bitfield_length = dev->drw_bitfield_length; + unsigned long irqflags; drm_drawable_info_t *info; drm_clip_rect_t *rects; int err; diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 71b7230f..bc52a95c 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -45,7 +45,7 @@ static void i915_vblank_tasklet(drm_device_t *dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - unsigned int irqflags; + unsigned long irqflags; struct list_head *list, *tmp; DRM_DEBUG("\n"); @@ -417,7 +417,8 @@ int i915_vblank_swap(DRM_IOCTL_ARGS) drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_vblank_swap_t swap; drm_i915_vbl_swap_t *vbl_swap; - unsigned int pipe, seqtype, irqflags, curseq; + unsigned int pipe, seqtype, curseq; + unsigned long irqflags; struct list_head *list; if (!dev_priv) { -- cgit v1.2.3 From d1b31a228b72b8dd8e588f0a0cc8eeabc3845f70 Mon Sep 17 00:00:00 2001 From: George Sapountzis Date: Sun, 16 Jul 2006 01:02:06 +0300 Subject: Bug 6209: [mach64] AGP DMA buffers not mapped correctly. Map the DMA buffers from the same linear address as the vertex bufs. If dev->agp_buffer_token is not set, mach64 drm maps the DMA buffers from linear address 0x0. --- shared-core/mach64_dma.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 4c8edeab..36fddf0e 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -834,6 +834,7 @@ static int mach64_do_dma_init(drm_device_t * dev, drm_mach64_init_t * init) mach64_do_cleanup_dma(dev); return DRM_ERR(ENOMEM); } + dev->agp_buffer_token = init->buffers_offset; dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { -- cgit v1.2.3 From eea150e776657faca7d5b76aca75a33dc74fbc9d Mon Sep 17 00:00:00 2001 From: George Sapountzis Date: Sun, 16 Jul 2006 02:15:02 +0300 Subject: Bug 6242: [mach64] Use private DMA buffers, part #1. Factor out from mach64_freelist_get() the code to reclaim a completed buffer, this is to improve readability for me. --- shared-core/mach64_dma.c | 155 ++++++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 75 deletions(-) diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 36fddf0e..3f4394c0 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -1329,17 +1329,88 @@ int mach64_do_release_used_buffers(drm_mach64_private_t * dev_priv) return 0; } +static int mach64_do_reclaim_completed(drm_mach64_private_t * dev_priv) +{ + drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; + struct list_head *ptr; + struct list_head *tmp; + drm_mach64_freelist_t *entry; + u32 head, tail, ofs; + + mach64_ring_tick(dev_priv, ring); + head = ring->head; + tail = ring->tail; + + if (head == tail) { +#if MACH64_EXTRA_CHECKING + if (MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE) { + DRM_ERROR("Empty ring with non-idle engine!\n"); + mach64_dump_ring_info(dev_priv); + return -1; + } +#endif + /* last pass is complete, so release everything */ + mach64_do_release_used_buffers(dev_priv); + DRM_DEBUG("%s: idle engine, freed all buffers.\n", + __FUNCTION__); + if (list_empty(&dev_priv->free_list)) { + DRM_ERROR("Freelist empty with idle engine\n"); + return -1; + } + return 0; + } + /* Look for a completed buffer and bail out of the loop + * as soon as we find one -- don't waste time trying + * to free extra bufs here, leave that to do_release_used_buffers + */ + list_for_each_safe(ptr, tmp, &dev_priv->pending) { + entry = list_entry(ptr, drm_mach64_freelist_t, list); + ofs = entry->ring_ofs; + if (entry->discard && + ((head < tail && (ofs < head || ofs >= tail)) || + (head > tail && (ofs < head && ofs >= tail)))) { +#if MACH64_EXTRA_CHECKING + int i; + + for (i = head; i != tail; i = (i + 4) & ring->tail_mask) + { + u32 o1 = le32_to_cpu(((u32 *) ring-> + start)[i + 1]); + u32 o2 = GETBUFADDR(entry->buf); + + if (o1 == o2) { + DRM_ERROR + ("Attempting to free used buffer: " + "i=%d buf=0x%08x\n", + i, o1); + mach64_dump_ring_info(dev_priv); + return -1; + } + } +#endif + /* found a processed buffer */ + entry->buf->pending = 0; + list_del(ptr); + list_add_tail(ptr, &dev_priv->free_list); + DRM_DEBUG + ("%s: freed processed buffer (head=%d tail=%d " + "buf ring ofs=%d).\n", + __FUNCTION__, head, tail, ofs); + return 0; + } + } + + return 1; +} + drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv) { drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; drm_mach64_freelist_t *entry; struct list_head *ptr; - struct list_head *tmp; int t; if (list_empty(&dev_priv->free_list)) { - u32 head, tail, ofs; - if (list_empty(&dev_priv->pending)) { DRM_ERROR ("Couldn't get buffer - pending and free lists empty\n"); @@ -1351,81 +1422,15 @@ drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv) return NULL; } - tail = ring->tail; for (t = 0; t < dev_priv->usec_timeout; t++) { - mach64_ring_tick(dev_priv, ring); - head = ring->head; + int ret; - if (head == tail) { -#if MACH64_EXTRA_CHECKING - if (MACH64_READ(MACH64_GUI_STAT) & - MACH64_GUI_ACTIVE) { - DRM_ERROR - ("Empty ring with non-idle engine!\n"); - mach64_dump_ring_info(dev_priv); - return NULL; - } -#endif - /* last pass is complete, so release everything */ - mach64_do_release_used_buffers(dev_priv); - DRM_DEBUG - ("%s: idle engine, freed all buffers.\n", - __FUNCTION__); - if (list_empty(&dev_priv->free_list)) { - DRM_ERROR - ("Freelist empty with idle engine\n"); - return NULL; - } + ret = mach64_do_reclaim_completed(dev_priv); + if (ret == 0) goto _freelist_entry_found; - } - /* Look for a completed buffer and bail out of the loop - * as soon as we find one -- don't waste time trying - * to free extra bufs here, leave that to do_release_used_buffers - */ - list_for_each_safe(ptr, tmp, &dev_priv->pending) { - entry = - list_entry(ptr, drm_mach64_freelist_t, - list); - ofs = entry->ring_ofs; - if (entry->discard && - ((head < tail - && (ofs < head || ofs >= tail)) - || (head > tail - && (ofs < head && ofs >= tail)))) { -#if MACH64_EXTRA_CHECKING - int i; - - for (i = head; i != tail; - i = (i + 4) & ring->tail_mask) { - u32 o1 = - le32_to_cpu(((u32 *) ring-> - start)[i + 1]); - u32 o2 = GETBUFADDR(entry->buf); - - if (o1 == o2) { - DRM_ERROR - ("Attempting to free used buffer: " - "i=%d buf=0x%08x\n", - i, o1); - mach64_dump_ring_info - (dev_priv); - return NULL; - } - } -#endif - /* found a processed buffer */ - entry->buf->pending = 0; - list_del(ptr); - entry->buf->used = 0; - list_add_tail(ptr, - &dev_priv->placeholders); - DRM_DEBUG - ("%s: freed processed buffer (head=%d tail=%d " - "buf ring ofs=%d).\n", - __FUNCTION__, head, tail, ofs); - return entry->buf; - } - } + if (ret < 0) + return NULL; + DRM_UDELAY(1); } mach64_dump_ring_info(dev_priv); -- cgit v1.2.3 From 25760c30d4aedb370423d0bb03c014cab47b5d4f Mon Sep 17 00:00:00 2001 From: George Sapountzis Date: Mon, 28 Aug 2006 05:44:37 +0300 Subject: Bug 6242: [mach64] Use private DMA buffers, part #2. Factor out from mach64_dma_dispatch_vertex() the code to reclaim an unsed buffer, in preperation for using it in mach64_dma_dispatch_blit() also. --- shared-core/mach64_dma.c | 27 ++++++++++ shared-core/mach64_drv.h | 2 + shared-core/mach64_state.c | 124 +++++++++++++++++++-------------------------- 3 files changed, 81 insertions(+), 72 deletions(-) diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 3f4394c0..7cba8ade 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -1449,6 +1449,33 @@ drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv) return entry->buf; } +int mach64_freelist_put(drm_mach64_private_t * dev_priv, drm_buf_t * copy_buf) +{ + struct list_head *ptr; + drm_mach64_freelist_t *entry; + +#if MACH64_EXTRA_CHECKING + list_for_each(ptr, &dev_priv->pending) { + entry = list_entry(ptr, drm_mach64_freelist_t, list); + if (copy_buf == entry->buf) { + DRM_ERROR("%s: Trying to release a pending buf\n", + __FUNCTION__); + return DRM_ERR(EFAULT); + } + } +#endif + ptr = dev_priv->placeholders.next; + entry = list_entry(ptr, drm_mach64_freelist_t, list); + copy_buf->pending = 0; + copy_buf->used = 0; + entry->buf = copy_buf; + entry->discard = 1; + list_del(ptr); + list_add_tail(ptr, &dev_priv->free_list); + + return 0; +} + /*@}*/ diff --git a/shared-core/mach64_drv.h b/shared-core/mach64_drv.h index 2a5f2ff9..e8dc71ef 100644 --- a/shared-core/mach64_drv.h +++ b/shared-core/mach64_drv.h @@ -123,6 +123,8 @@ extern void mach64_driver_lastclose(drm_device_t * dev); extern int mach64_init_freelist(drm_device_t * dev); extern void mach64_destroy_freelist(drm_device_t * dev); extern drm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv); +extern int mach64_freelist_put(drm_mach64_private_t * dev_priv, + drm_buf_t * copy_buf); extern int mach64_do_wait_for_fifo(drm_mach64_private_t * dev_priv, int entries); diff --git a/shared-core/mach64_state.c b/shared-core/mach64_state.c index ce44f0d5..31e3b563 100644 --- a/shared-core/mach64_state.c +++ b/shared-core/mach64_state.c @@ -546,12 +546,15 @@ static __inline__ int copy_and_verify_from_user(u32 *to, } static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev, - int prim, void *buf, unsigned long used, - int discard) + drm_mach64_vertex_t * vertex) { drm_mach64_private_t *dev_priv = dev->dev_private; drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_buf_t *copy_buf; + void *buf = vertex->buf; + unsigned long used = vertex->used; + int ret = 0; + int i = 0; int done = 0; int verify_ret = 0; DMALOCALS; @@ -559,87 +562,65 @@ static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev, DRM_DEBUG("%s: buf=%p used=%lu nbox=%d\n", __FUNCTION__, buf, used, sarea_priv->nbox); - if (used) { - int ret = 0; - int i = 0; + if (!used) + goto _vertex_done; - copy_buf = mach64_freelist_get(dev_priv); - if (copy_buf == NULL) { - DRM_ERROR("%s: couldn't get buffer in DMAGETPTR\n", - __FUNCTION__); - return DRM_ERR(EAGAIN); - } + copy_buf = mach64_freelist_get(dev_priv); + if (copy_buf == NULL) { + DRM_ERROR("%s: couldn't get buffer\n", __FUNCTION__); + return DRM_ERR(EAGAIN); + } + + verify_ret = copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, used); - if ((verify_ret = - copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, - used)) == 0) { + if (verify_ret != 0) { + mach64_freelist_put(dev_priv, copy_buf); + goto _vertex_done; + } - copy_buf->used = used; + copy_buf->used = used; - DMASETPTR(copy_buf); + DMASETPTR(copy_buf); - if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) { - ret = mach64_emit_state(filp, dev_priv); - if (ret < 0) - return ret; - } + if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) { + ret = mach64_emit_state(filp, dev_priv); + if (ret < 0) + return ret; + } - do { - /* Emit the next cliprect */ - if (i < sarea_priv->nbox) { - ret = - mach64_emit_cliprect(filp, dev_priv, - &sarea_priv-> - boxes[i]); - if (ret < 0) { - /* failed to get buffer */ - return ret; - } else if (ret != 0) { - /* null intersection with scissor */ - continue; - } - } - if ((i >= sarea_priv->nbox - 1)) - done = 1; - - /* Add the buffer to the DMA queue */ - DMAADVANCE(dev_priv, done); - - } while (++i < sarea_priv->nbox); + do { + /* Emit the next cliprect */ + if (i < sarea_priv->nbox) { + ret = mach64_emit_cliprect(filp, dev_priv, + &sarea_priv->boxes[i]); + if (ret < 0) { + /* failed to get buffer */ + return ret; + } else if (ret != 0) { + /* null intersection with scissor */ + continue; + } } + if ((i >= sarea_priv->nbox - 1)) + done = 1; + + /* Add the buffer to the DMA queue */ + DMAADVANCE(dev_priv, done); + + } while (++i < sarea_priv->nbox); - if (copy_buf->pending && !done) { + if (!done) { + if (copy_buf->pending) { DMADISCARDBUF(); - } else if (!done) { - /* This buffer wasn't used (no cliprects or verify failed), so place it back - * on the free list + } else { + /* This buffer wasn't used (no cliprects), so place it + * back on the free list */ - struct list_head *ptr; - drm_mach64_freelist_t *entry; -#if MACH64_EXTRA_CHECKING - list_for_each(ptr, &dev_priv->pending) { - entry = - list_entry(ptr, drm_mach64_freelist_t, - list); - if (copy_buf == entry->buf) { - DRM_ERROR - ("%s: Trying to release a pending buf\n", - __FUNCTION__); - return DRM_ERR(EFAULT); - } - } -#endif - ptr = dev_priv->placeholders.next; - entry = list_entry(ptr, drm_mach64_freelist_t, list); - copy_buf->pending = 0; - copy_buf->used = 0; - entry->buf = copy_buf; - entry->discard = 1; - list_del(ptr); - list_add_tail(ptr, &dev_priv->free_list); + mach64_freelist_put(dev_priv, copy_buf); } } +_vertex_done: sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS; sarea_priv->nbox = 0; @@ -842,8 +823,7 @@ int mach64_dma_vertex(DRM_IOCTL_ARGS) if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS) sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS; - return mach64_dma_dispatch_vertex(filp, dev, vertex.prim, vertex.buf, - vertex.used, vertex.discard); + return mach64_dma_dispatch_vertex(filp, dev, &vertex); } int mach64_dma_blit(DRM_IOCTL_ARGS) -- cgit v1.2.3 From f3deef730d52c94ce21ada7e4ceb63aa28a8601b Mon Sep 17 00:00:00 2001 From: George Sapountzis Date: Mon, 2 Oct 2006 05:46:42 +0300 Subject: Bug 6242: [mach64] Use private DMA buffers, part #3. Add DRM_PCI_BUFFER_RO flag for mapping PCI DMA buffer read-only. An additional flag is needed, since PCI DMA buffers do not have an associated map. --- libdrm/xf86drm.h | 3 ++- linux-core/drmP.h | 3 ++- linux-core/drm_bufs.c | 10 +++++++--- linux-core/drm_vm.c | 16 ++++++++++++++++ shared-core/drm.h | 3 ++- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 2ad70807..d58baa76 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -149,7 +149,8 @@ typedef enum { DRM_PAGE_ALIGN = 0x01, DRM_AGP_BUFFER = 0x02, DRM_SG_BUFFER = 0x04, - DRM_FB_BUFFER = 0x08 + DRM_FB_BUFFER = 0x08, + DRM_PCI_BUFFER_RO = 0x10 } drmBufDescFlags; typedef enum { diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 5c9644e0..2bbec70c 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -449,7 +449,8 @@ typedef struct drm_device_dma { enum { _DRM_DMA_USE_AGP = 0x01, _DRM_DMA_USE_SG = 0x02, - _DRM_DMA_USE_FB = 0x04 + _DRM_DMA_USE_FB = 0x04, + _DRM_DMA_USE_PCI_RO = 0x08 } flags; } drm_device_dma_t; diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c index abd7c829..a2a3dbf7 100644 --- a/linux-core/drm_bufs.c +++ b/linux-core/drm_bufs.c @@ -942,6 +942,9 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request) request->count = entry->buf_count; request->size = size; + if (request->flags & _DRM_PCI_BUFFER_RO) + dma->flags = _DRM_DMA_USE_PCI_RO; + atomic_dec(&dev->buf_alloc); return 0; @@ -1528,9 +1531,10 @@ int drm_freebufs(struct inode *inode, struct file *filp, * \param arg pointer to a drm_buf_map structure. * \return zero on success or a negative number on failure. * - * Maps the AGP or SG buffer region with do_mmap(), and copies information - * about each buffer into user space. The PCI buffers are already mapped on the - * addbufs_pci() call. + * Maps the AGP, SG or PCI buffer region with do_mmap(), and copies information + * about each buffer into user space. For PCI buffers, it calls do_mmap() with + * offset equal to 0, which drm_mmap() interpretes as PCI buffers and calls + * drm_mmap_dma(). */ int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 9672269a..adff7d1a 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -506,6 +506,22 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) } unlock_kernel(); + if (!capable(CAP_SYS_ADMIN) && + (dma->flags & _DRM_DMA_USE_PCI_RO)) { + vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); +#if defined(__i386__) || defined(__x86_64__) + pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; +#else + /* Ye gads this is ugly. With more thought + we could move this up higher and use + `protection_map' instead. */ + vma->vm_page_prot = + __pgprot(pte_val + (pte_wrprotect + (__pte(pgprot_val(vma->vm_page_prot))))); +#endif + } + vma->vm_ops = &drm_vm_dma_ops; #if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ diff --git a/shared-core/drm.h b/shared-core/drm.h index 7f90a96d..8c0c5d22 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -416,7 +416,8 @@ typedef struct drm_buf_desc { _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */ _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */ _DRM_SG_BUFFER = 0x04, /**< Scatter/gather memory buffer */ - _DRM_FB_BUFFER = 0x08 /**< Buffer is in frame buffer */ + _DRM_FB_BUFFER = 0x08, /**< Buffer is in frame buffer */ + _DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */ } flags; unsigned long agp_start; /**< * Start address of where the AGP buffers are -- cgit v1.2.3 From c9e3aa961eb90265ec024ff57013786e4d47d0e7 Mon Sep 17 00:00:00 2001 From: George Sapountzis Date: Mon, 2 Oct 2006 06:13:38 +0300 Subject: Bug 6242: [mach64] Use private DMA buffers, part #4. mach64_state.c: convert the DRM_MACH64_BLIT ioctl to submit a pointer to user-space memory rather than a DMA buffer index, similar to DRM_MACH64_VERTEX. This change allows the DDX to map the DMA buffers read-only and eliminate a security problem where a client can alter the contents of the DMA buffer after submission to the DRM. This change also affects the DRI/DRM interface. Performace-wise, it basically affects PCI mode where I get a ~12% speedup for some Mesa demos I tested. This is mainly due to eliminating an ioctl for allocating the DMA buffer. mach64_dma.c: move the responsibility for allocating memory for the DMA ring in PCI mode to the DDX. This change affects the DDX/DRM interface and unifies a couple of PCI/AGP code paths for ring memory in the DRM. Bump the mach64 DRM version major and date. --- shared-core/mach64_dma.c | 51 +++++++++------------------- shared-core/mach64_drm.h | 2 +- shared-core/mach64_drv.h | 5 ++- shared-core/mach64_state.c | 83 ++++++++++++++++++++++++---------------------- 4 files changed, 62 insertions(+), 79 deletions(-) diff --git a/shared-core/mach64_dma.c b/shared-core/mach64_dma.c index 7cba8ade..3a5fdee8 100644 --- a/shared-core/mach64_dma.c +++ b/shared-core/mach64_dma.c @@ -815,17 +815,18 @@ static int mach64_do_dma_init(drm_device_t * dev, drm_mach64_init_t * init) return DRM_ERR(EINVAL); } + dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset); + if (!dev_priv->ring_map) { + DRM_ERROR("can not find ring map!\n"); + dev->dev_private = (void *)dev_priv; + mach64_do_cleanup_dma(dev); + return DRM_ERR(EINVAL); + } + dev_priv->sarea_priv = (drm_mach64_sarea_t *) ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); if (!dev_priv->is_pci) { - dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset); - if (!dev_priv->ring_map) { - DRM_ERROR("can not find ring map!\n"); - dev->dev_private = (void *)dev_priv; - mach64_do_cleanup_dma(dev); - return DRM_ERR(EINVAL); - } drm_core_ioremap(dev_priv->ring_map, dev); if (!dev_priv->ring_map->handle) { DRM_ERROR("can not ioremap virtual address for" @@ -891,27 +892,9 @@ static int mach64_do_dma_init(drm_device_t * dev, drm_mach64_init_t * init) } } - /* allocate descriptor memory from pci pool */ - DRM_DEBUG("Allocating dma descriptor ring\n"); dev_priv->ring.size = 0x4000; /* 16KB */ - - if (dev_priv->is_pci) { - dev_priv->ring.dmah = drm_pci_alloc(dev, dev_priv->ring.size, - dev_priv->ring.size, - 0xfffffffful); - - if (!dev_priv->ring.dmah) { - DRM_ERROR("Allocating dma descriptor ring failed\n"); - return DRM_ERR(ENOMEM); - } else { - dev_priv->ring.start = dev_priv->ring.dmah->vaddr; - dev_priv->ring.start_addr = - (u32) dev_priv->ring.dmah->busaddr; - } - } else { - dev_priv->ring.start = dev_priv->ring_map->handle; - dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset; - } + dev_priv->ring.start = dev_priv->ring_map->handle; + dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset; memset(dev_priv->ring.start, 0, dev_priv->ring.size); DRM_INFO("descriptor ring: cpu addr %p, bus addr: 0x%08x\n", @@ -1149,18 +1132,14 @@ int mach64_do_cleanup_dma(drm_device_t * dev) if (dev->dev_private) { drm_mach64_private_t *dev_priv = dev->dev_private; - if (dev_priv->is_pci) { - if (dev_priv->ring.dmah) { - drm_pci_free(dev, dev_priv->ring.dmah); - } - } else { + if (!dev_priv->is_pci) { if (dev_priv->ring_map) drm_core_ioremapfree(dev_priv->ring_map, dev); - } - if (dev->agp_buffer_map) { - drm_core_ioremapfree(dev->agp_buffer_map, dev); - dev->agp_buffer_map = NULL; + if (dev->agp_buffer_map) { + drm_core_ioremapfree(dev->agp_buffer_map, dev); + dev->agp_buffer_map = NULL; + } } mach64_destroy_freelist(dev); diff --git a/shared-core/mach64_drm.h b/shared-core/mach64_drm.h index 1fd8c002..083f959d 100644 --- a/shared-core/mach64_drm.h +++ b/shared-core/mach64_drm.h @@ -237,7 +237,7 @@ typedef struct drm_mach64_vertex { } drm_mach64_vertex_t; typedef struct drm_mach64_blit { - int idx; + void *buf; int pitch; int offset; int format; diff --git a/shared-core/mach64_drv.h b/shared-core/mach64_drv.h index e8dc71ef..bb8b309e 100644 --- a/shared-core/mach64_drv.h +++ b/shared-core/mach64_drv.h @@ -42,9 +42,9 @@ #define DRIVER_NAME "mach64" #define DRIVER_DESC "DRM module for the ATI Rage Pro" -#define DRIVER_DATE "20020904" +#define DRIVER_DATE "20060718" -#define DRIVER_MAJOR 1 +#define DRIVER_MAJOR 2 #define DRIVER_MINOR 0 #define DRIVER_PATCHLEVEL 0 @@ -61,7 +61,6 @@ typedef struct drm_mach64_freelist { } drm_mach64_freelist_t; typedef struct drm_mach64_descriptor_ring { - drm_dma_handle_t *dmah; /* Handle to pci dma memory */ void *start; /* write pointer (cpu address) to start of descriptor ring */ u32 start_addr; /* bus address of beginning of descriptor ring */ int size; /* size of ring in bytes */ diff --git a/shared-core/mach64_state.c b/shared-core/mach64_state.c index 31e3b563..38cefca9 100644 --- a/shared-core/mach64_state.c +++ b/shared-core/mach64_state.c @@ -480,16 +480,16 @@ static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv) /* Copy and verify a client submited buffer. * FIXME: Make an assembly optimized version */ -static __inline__ int copy_and_verify_from_user(u32 *to, - const u32 __user *ufrom, - unsigned long bytes) +static __inline__ int copy_from_user_vertex(u32 *to, + const u32 __user *ufrom, + unsigned long bytes) { unsigned long n = bytes; /* dwords remaining in buffer */ u32 *from, *orig_from; from = drm_alloc(bytes, DRM_MEM_DRIVER); if (from == NULL) - return ENOMEM; + return DRM_ERR(ENOMEM); if (DRM_COPY_FROM_USER(from, ufrom, bytes)) { drm_free(from, bytes, DRM_MEM_DRIVER); @@ -571,7 +571,7 @@ static int mach64_dma_dispatch_vertex(DRMFILE filp, drm_device_t * dev, return DRM_ERR(EAGAIN); } - verify_ret = copy_and_verify_from_user(GETBUFPTR(copy_buf), buf, used); + verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used); if (verify_ret != 0) { mach64_freelist_put(dev_priv, copy_buf); @@ -627,13 +627,27 @@ _vertex_done: return verify_ret; } +static __inline__ int copy_from_user_blit(u32 *to, + const u32 __user *ufrom, + unsigned long bytes) +{ + to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET); + + if (DRM_COPY_FROM_USER(to, ufrom, bytes)) { + return DRM_ERR(EFAULT); + } + + return 0; +} + static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev, drm_mach64_blit_t * blit) { drm_mach64_private_t *dev_priv = dev->dev_private; - drm_device_dma_t *dma = dev->dma; int dword_shift, dwords; - drm_buf_t *buf; + unsigned long used; + drm_buf_t *copy_buf; + int verify_ret = 0; DMALOCALS; /* The compiler won't optimize away a division by a variable, @@ -660,34 +674,34 @@ static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev, return DRM_ERR(EINVAL); } - /* Dispatch the blit buffer. - */ - buf = dma->buflist[blit->idx]; - - if (buf->filp != filp) { - DRM_ERROR("process %d (filp %p) using buffer with filp %p\n", - DRM_CURRENTPID, filp, buf->filp); - return DRM_ERR(EINVAL); - } - - if (buf->pending) { - DRM_ERROR("sending pending buffer %d\n", blit->idx); - return DRM_ERR(EINVAL); - } - /* Set buf->used to the bytes of blit data based on the blit dimensions * and verify the size. When the setup is emitted to the buffer with * the DMA* macros below, buf->used is incremented to include the bytes * used for setup as well as the blit data. */ dwords = (blit->width * blit->height) >> dword_shift; - buf->used = dwords << 2; - if (buf->used <= 0 || - buf->used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) { - DRM_ERROR("Invalid blit size: %d bytes\n", buf->used); + used = dwords << 2; + if (used <= 0 || + used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) { + DRM_ERROR("Invalid blit size: %lu bytes\n", used); return DRM_ERR(EINVAL); } + copy_buf = mach64_freelist_get(dev_priv); + if (copy_buf == NULL) { + DRM_ERROR("%s: couldn't get buffer\n", __FUNCTION__); + return DRM_ERR(EAGAIN); + } + + verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used); + + if (verify_ret != 0) { + mach64_freelist_put(dev_priv, copy_buf); + goto _blit_done; + } + + copy_buf->used = used; + /* FIXME: Use a last buffer flag and reduce the state emitted for subsequent, * continuation buffers? */ @@ -696,7 +710,7 @@ static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev, * a register command every 16 dwords. State setup is added at the start of the * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET */ - DMASETPTR(buf); + DMASETPTR(copy_buf); DMAOUTREG(MACH64_Z_CNTL, 0); DMAOUTREG(MACH64_SCALE_3D_CNTL, 0); @@ -726,12 +740,13 @@ static int mach64_dma_dispatch_blit(DRMFILE filp, drm_device_t * dev, DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x); DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width); - DRM_DEBUG("%s: %d bytes\n", __FUNCTION__, buf->used); + DRM_DEBUG("%s: %lu bytes\n", __FUNCTION__, used); /* Add the buffer to the queue */ DMAADVANCEHOSTDATA(dev_priv); - return 0; +_blit_done: + return verify_ret; } /* ================================================================ @@ -829,7 +844,6 @@ int mach64_dma_vertex(DRM_IOCTL_ARGS) int mach64_dma_blit(DRM_IOCTL_ARGS) { DRM_DEVICE; - drm_device_dma_t *dma = dev->dma; drm_mach64_private_t *dev_priv = dev->dev_private; drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mach64_blit_t blit; @@ -840,15 +854,6 @@ int mach64_dma_blit(DRM_IOCTL_ARGS) DRM_COPY_FROM_USER_IOCTL(blit, (drm_mach64_blit_t *) data, sizeof(blit)); - DRM_DEBUG("%s: pid=%d index=%d\n", - __FUNCTION__, DRM_CURRENTPID, blit.idx); - - if (blit.idx < 0 || blit.idx >= dma->buf_count) { - DRM_ERROR("buffer index %d (of %d max)\n", - blit.idx, dma->buf_count - 1); - return DRM_ERR(EINVAL); - } - ret = mach64_dma_dispatch_blit(filp, dev, &blit); /* Make sure we restore the 3D state next time. -- 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(-) 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 a9f57a2b9c5897cbf568bf75342204b780566de0 Mon Sep 17 00:00:00 2001 From: Roland Scheidegger Date: Tue, 10 Oct 2006 02:24:19 +0200 Subject: only allow specific type-3 packets to pass the verifier instead of all for r100/r200 as others might be unsafe (r300 already does this), and add checking for these we need but aren't safe. Check the RADEON_CP_INDX_BUFFER packet on both r200 and r300 as it isn't safe neither. --- shared-core/r300_cmdbuf.c | 33 +++++++++++++- shared-core/radeon_state.c | 109 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 138 insertions(+), 4 deletions(-) diff --git a/shared-core/r300_cmdbuf.c b/shared-core/r300_cmdbuf.c index dc866823..c65ffd59 100644 --- a/shared-core/r300_cmdbuf.c +++ b/shared-core/r300_cmdbuf.c @@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv, return 0; } +static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv, + drm_radeon_kcmd_buffer_t *cmdbuf) +{ + u32 *cmd = (u32 *) cmdbuf->buf; + int count, ret; + RING_LOCALS; + + count=(cmd[0]>>16) & 0x3fff; + + if ((cmd[1] & 0x8000ffff) != 0x80000810) { + DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); + return DRM_ERR(EINVAL); + } + ret = r300_check_offset(dev_priv, cmd[2]); + if (ret) { + DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); + return DRM_ERR(EINVAL); + } + + BEGIN_RING(count+2); + OUT_RING(cmd[0]); + OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1); + ADVANCE_RING(); + + cmdbuf->buf += (count+2)*4; + cmdbuf->bufsz -= (count+2)*4; + + return 0; +} + static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, drm_radeon_kcmd_buffer_t *cmdbuf) { @@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, case RADEON_CNTL_BITBLT_MULTI: return r300_emit_bitblt_multi(dev_priv, cmdbuf); + case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ + return r300_emit_indx_buffer(dev_priv, cmdbuf); case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ - case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */ case RADEON_WAIT_FOR_IDLE: case RADEON_CP_NOP: /* these packets are safe */ diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c index b4478019..bf5e3d29 100644 --- a/shared-core/radeon_state.c +++ b/shared-core/radeon_state.c @@ -275,6 +275,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * unsigned int *cmdsz) { u32 *cmd = (u32 *) cmdbuf->buf; + u32 offset, narrays; + int count, i, k; *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); @@ -288,10 +290,106 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * return DRM_ERR(EINVAL); } - /* Check client state and fix it up if necessary */ - if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */ - u32 offset; + switch(cmd[0] & 0xff00) { + /* XXX Are there old drivers needing other packets? */ + case RADEON_3D_DRAW_IMMD: + case RADEON_3D_DRAW_VBUF: + case RADEON_3D_DRAW_INDX: + case RADEON_WAIT_FOR_IDLE: + case RADEON_CP_NOP: + case RADEON_3D_CLEAR_ZMASK: +/* case RADEON_CP_NEXT_CHAR: + case RADEON_CP_PLY_NEXTSCAN: + case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */ + /* these packets are safe */ + break; + + case RADEON_CP_3D_DRAW_IMMD_2: + case RADEON_CP_3D_DRAW_VBUF_2: + case RADEON_CP_3D_DRAW_INDX_2: + case RADEON_3D_CLEAR_HIZ: + /* safe but r200 only */ + if (dev_priv->microcode_version != UCODE_R200) { + DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_3D_LOAD_VBPNTR: + count = (cmd[0] >> 16) & 0x3fff; + + if (count > 18) { /* 12 arrays max */ + DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n", + count); + return DRM_ERR(EINVAL); + } + + /* carefully check packet contents */ + narrays = cmd[1] & ~0xc000; + k = 0; + i = 2; + while ((k < narrays) && (i < (count + 2))) { + i++; /* skip attribute field */ + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { + DRM_ERROR + ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", + k, i); + return DRM_ERR(EINVAL); + } + k++; + i++; + if (k == narrays) + break; + /* have one more to process, they come in pairs */ + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) { + DRM_ERROR + ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n", + k, i); + return DRM_ERR(EINVAL); + } + k++; + i++; + } + /* do the counts match what we expect ? */ + if ((k != narrays) || (i != (count + 2))) { + DRM_ERROR + ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n", + k, i, narrays, count + 1); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_3D_RNDR_GEN_INDX_PRIM: + if (dev_priv->microcode_version != UCODE_R100) { + DRM_ERROR("Invalid 3d packet for r200-class chip\n"); + return DRM_ERR(EINVAL); + } + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) { + DRM_ERROR("Invalid rndr_gen_indx offset\n"); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_CP_INDX_BUFFER: + if (dev_priv->microcode_version != UCODE_R200) { + DRM_ERROR("Invalid 3d packet for r100-class chip\n"); + return DRM_ERR(EINVAL); + } + if ((cmd[1] & 0x8000ffff) != 0x80000810) { + DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]); + return DRM_ERR(EINVAL); + } + if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) { + DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]); + return DRM_ERR(EINVAL); + } + break; + + case RADEON_CNTL_HOSTDATA_BLT: + case RADEON_CNTL_PAINT_MULTI: + case RADEON_CNTL_BITBLT_MULTI: + /* MSB of opcode: next DWORD GUI_CNTL */ if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { offset = cmd[2] << 10; @@ -313,6 +411,11 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t * } cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; } + break; + + default: + DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00); + return DRM_ERR(EINVAL); } return 0; -- 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(-) 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. --- libdrm/xf86drm.c | 82 +----- libdrm/xf86mm.h | 23 +- linux-core/drmP.h | 2 +- linux-core/drm_agpsupport.c | 2 + linux-core/drm_bo.c | 51 ++-- linux-core/drm_compat.c | 50 +++- linux-core/drm_compat.h | 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 ++++++----------- shared-core/drm.h | 18 -- 12 files changed, 333 insertions(+), 913 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index bce913d3..a083ca23 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2462,74 +2462,6 @@ int drmFenceWait(int fd, unsigned flags, drmFence *fence, unsigned flush_type) return 0; } -int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, unsigned flags) -{ - drm_ttm_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.op = drm_ttm_create; - arg.flags = flags; - arg.size = size; - - if (ioctl(fd, DRM_IOCTL_TTM, &arg)) - return -errno; - - ttm->handle = arg.handle; - ttm->user_token = (drm_handle_t) arg.user_token; - ttm->flags = arg.flags; - ttm->size = arg.size; - ttm->virtual = NULL; - ttm->mapCount = 0; - return 0; -} - -int drmTTMDestroy(int fd, const drmTTM *ttm) -{ - drm_ttm_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.op = drm_ttm_destroy; - arg.handle = ttm->handle; - if (ioctl(fd, DRM_IOCTL_TTM, &arg)) - return -errno; - return 0; -} - - -int drmTTMReference(int fd, unsigned handle, drmTTM *ttm) -{ - drm_ttm_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.handle = handle; - arg.op = drm_ttm_reference; - if (ioctl(fd, DRM_IOCTL_TTM, &arg)) - return -errno; - ttm->handle = arg.handle; - ttm->user_token = (drm_handle_t) arg.user_token; - ttm->flags = arg.flags; - ttm->size = arg.size; - return 0; -} - -int drmTTMUnreference(int fd, const drmTTM *ttm) -{ - drm_ttm_arg_t arg; - - memset(&arg, 0, sizeof(arg)); - arg.op = drm_ttm_destroy; - arg.handle = ttm->handle; - if (ioctl(fd, DRM_IOCTL_TTM, &arg)) - return -errno; - return 0; -} - -drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm) -{ - (void) fd; - return ttm->user_token; -} - static int drmAdjustListNodes(drmBOList *list) { drmBONode *node; @@ -2685,7 +2617,7 @@ static void drmBOCopyReply(const drm_bo_arg_reply_t *rep, -int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, +int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, void *user_buffer, drm_bo_type_t type, unsigned mask, unsigned hint, drmBO *buf) { @@ -2700,15 +2632,9 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, req->size = size; req->type = type; - buf->ttm = NULL; buf->virtual = NULL; switch(type) { - case drm_bo_type_ttm: - req->arg_handle = ttm->handle; - req->buffer_start = start; - buf->ttm = ttm; - break; case drm_bo_type_dc: req->buffer_start = start; break; @@ -2727,10 +2653,10 @@ int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) return -errno; if (!arg.handled) { - fprintf(stderr, "Not handled\n"); return -EFAULT; } if (rep->ret) { + fprintf(stderr, "Error %d\n", rep->ret); return rep->ret; } @@ -2853,8 +2779,10 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, virtual = mmap(0, buf->size + buf->start, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf->mapHandle); - if (virtual == MAP_FAILED) + if (virtual == MAP_FAILED) { ret = -errno; + fprintf(stderr, "Map error 0x%016llx\n", buf->mapHandle); + } if (ret) return ret; buf->mapVirtual = virtual; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index c0e4f1b6..78df37c3 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -101,15 +101,6 @@ typedef struct _drmFence{ unsigned signaled; } drmFence; -typedef struct _drmTTM{ - unsigned handle; - drm_u64_t user_token; - unsigned flags; - unsigned long size; - void *virtual; - int mapCount; -} drmTTM; - typedef struct _drmBO{ drm_bo_type_t type; unsigned handle; @@ -125,7 +116,6 @@ typedef struct _drmBO{ void *virtual; void *mapVirtual; int mapCount; - drmTTM *ttm; } drmBO; @@ -163,17 +153,6 @@ extern int drmFenceEmit(int fd, unsigned flags, drmFence *fence, extern int drmFenceBuffers(int fd, unsigned flags, drmFence *fence); -/* - * TTM functions. - */ - -extern int drmTTMCreate(int fd, drmTTM *ttm, unsigned long size, - unsigned flags); -extern int drmTTMDestroy(int fd, const drmTTM *ttm); -extern int drmTTMReference(int fd, unsigned handle, drmTTM *ttm); -extern int drmTTMUnreference(int fd, const drmTTM *ttm); -extern drm_handle_t drmTTMMapHandle(int fd, const drmTTM *ttm); - /* * Buffer object list functions. */ @@ -189,7 +168,7 @@ extern int drmBOCreateList(int numTarget, drmBOList *list); * Buffer object functions. */ -extern int drmBOCreate(int fd, drmTTM *ttm, unsigned long start, unsigned long size, +extern int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, void *user_buffer, drm_bo_type_t type, unsigned mask, unsigned hint, drmBO *buf); extern int drmBODestroy(int fd, drmBO *buf); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index bc57bd5c..1b6d94e4 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1012,7 +1012,7 @@ typedef struct drm_buffer_object{ atomic_t usage; drm_ttm_object_t *ttm_object; - drm_ttm_backend_list_t *ttm_region; + drm_ttm_t *ttm; unsigned long num_pages; unsigned long buffer_start; drm_bo_type_t type; diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 2dd80162..77994d5c 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -683,6 +683,7 @@ drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev, agp_be->unbind = drm_agp_unbind_ttm; agp_be->destroy = drm_agp_destroy_ttm; agp_be->needs_free = (backend == NULL); + agp_be->drm_map_type = _DRM_AGP; return agp_be; } EXPORT_SYMBOL(drm_agp_init_ttm_uncached); @@ -720,6 +721,7 @@ drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev, agp_be->unbind = drm_agp_unbind_ttm; agp_be->destroy = drm_agp_destroy_ttm; agp_be->needs_free = (backend == NULL); + agp_be->drm_map_type = _DRM_AGP; return agp_be; } EXPORT_SYMBOL(drm_agp_init_ttm_cached); diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d1989e49..d8cab2ad 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -63,7 +63,7 @@ * bo locked. */ -static int drm_move_tt_to_local(drm_buffer_object_t * buf) +static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; @@ -71,7 +71,10 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf) BUG_ON(!buf->tt); mutex_lock(&dev->struct_mutex); - drm_unbind_ttm_region(buf->ttm_region); + if (evict) + drm_evict_ttm(buf->ttm); + else + drm_unbind_ttm(buf->ttm); drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -129,7 +132,7 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) * This temporarily unlocks struct_mutex. */ - drm_unbind_ttm_region(bo->ttm_region); + drm_unbind_ttm(bo->ttm); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -137,9 +140,6 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) drm_mm_put_block(&bm->vram_manager, bo->vram); bo->vram = NULL; } - if (bo->ttm_region) { - drm_destroy_ttm_region(bo->ttm_region); - } if (bo->ttm_object) { drm_ttm_object_deref_locked(dev, bo->ttm_object); } @@ -428,7 +428,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) } if (tt) { - ret = drm_move_tt_to_local(bo); + ret = drm_move_tt_to_local(bo, 1); } #if 0 else { @@ -522,7 +522,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) return ret; DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); mutex_lock(&dev->struct_mutex); - ret = drm_bind_ttm_region(bo->ttm_region, bo->tt->start); + ret = drm_bind_ttm(bo->ttm, bo->tt->start); if (ret) { drm_mm_put_block(&bm->tt_manager, bo->tt); } @@ -530,7 +530,7 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; - be = bo->ttm_region->be; + be = bo->ttm->be; if (be->needs_cache_adjust(be)) bo->flags &= ~DRM_BO_FLAG_CACHED; bo->flags &= ~DRM_BO_MASK_MEM; @@ -1023,7 +1023,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, if (ret) return ret; } else { - drm_move_tt_to_local(bo); + drm_move_tt_to_local(bo, 0); } return 0; @@ -1203,34 +1203,24 @@ static int drm_bo_handle_wait(drm_file_t * priv, uint32_t handle, * Call bo->mutex locked. */ -static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, - uint32_t ttm_handle) +static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo) { drm_device_t *dev = bo->dev; drm_ttm_object_t *to = NULL; - drm_ttm_t *ttm; int ret = 0; uint32_t ttm_flags = 0; bo->ttm_object = NULL; - bo->ttm_region = NULL; + bo->ttm = NULL; switch (bo->type) { case drm_bo_type_dc: mutex_lock(&dev->struct_mutex); ret = drm_ttm_object_create(dev, bo->num_pages * PAGE_SIZE, + bo->mask & DRM_BO_FLAG_BIND_CACHED, ttm_flags, &to); mutex_unlock(&dev->struct_mutex); break; - case drm_bo_type_ttm: - mutex_lock(&dev->struct_mutex); - to = drm_lookup_ttm_object(priv, ttm_handle, 1); - mutex_unlock(&dev->struct_mutex); - if (!to) { - DRM_ERROR("Could not find TTM object\n"); - ret = -EINVAL; - } - break; case drm_bo_type_user: case drm_bo_type_fake: break; @@ -1246,14 +1236,7 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, if (to) { bo->ttm_object = to; - ttm = drm_ttm_from_object(to); - ret = drm_create_ttm_region(ttm, bo->buffer_start >> PAGE_SHIFT, - bo->num_pages, - bo->mask & DRM_BO_FLAG_BIND_CACHED, - &bo->ttm_region); - if (ret) { - drm_ttm_object_deref_unlocked(dev, to); - } + bo->ttm = drm_ttm_from_object(to); } return ret; } @@ -1261,7 +1244,6 @@ static int drm_bo_add_ttm(drm_file_t * priv, drm_buffer_object_t * bo, int drm_buffer_object_create(drm_file_t * priv, unsigned long size, drm_bo_type_t type, - uint32_t ttm_handle, uint32_t mask, uint32_t hint, unsigned long buffer_start, @@ -1318,7 +1300,7 @@ int drm_buffer_object_create(drm_file_t * priv, 1, &new_flags, &bo->mask); if (ret) goto out_err; - ret = drm_bo_add_ttm(priv, bo, ttm_handle); + ret = drm_bo_add_ttm(priv, bo); if (ret) goto out_err; @@ -1394,7 +1376,6 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) rep.ret = drm_buffer_object_create(priv, req->size, req->type, - req->arg_handle, req->mask, req->hint, req->buffer_start, &entry); @@ -1659,7 +1640,7 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) if (arg.req.tt_p_size) { ret = drm_mm_init(&bm->tt_manager, arg.req.tt_p_offset, - arg.req.tt_p_size); + 3000 /* arg.req.tt_p_size */); bm->has_tt = 1; bm->use_tt = 1; diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 2b449e90..1aa835ca 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -63,8 +63,10 @@ pgprot_t vm_get_page_prot(unsigned long vm_flags) #endif }; -int drm_pte_is_clear(struct vm_area_struct *vma, - unsigned long addr) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) + +static int drm_pte_is_clear(struct vm_area_struct *vma, + unsigned long addr) { struct mm_struct *mm = vma->vm_mm; int ret = 1; @@ -77,7 +79,7 @@ int drm_pte_is_clear(struct vm_area_struct *vma, #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) spin_lock(&mm->page_table_lock); #else - spinlock_t ptl; + spinlock_t *ptl; #endif pgd = pgd_offset(mm, addr); @@ -92,7 +94,7 @@ int drm_pte_is_clear(struct vm_area_struct *vma, #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) pte = pte_offset_map(pmd, addr); #else - pte = pte_offset_map_lock(mm, pmd, addr, &ptl); + pte = pte_offset_map_lock(mm, pmd, addr, &ptl); #endif if (!pte) goto unlock; @@ -108,6 +110,17 @@ int drm_pte_is_clear(struct vm_area_struct *vma, return ret; } +int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, + unsigned long pfn, pgprot_t pgprot) +{ + int ret; + if (!drm_pte_is_clear(vma, addr)) + return -EBUSY; + + ret = io_remap_pfn_range(vma, addr, pfn, PAGE_SIZE, pgprot); + return ret; +} + static struct { spinlock_t lock; @@ -141,3 +154,32 @@ void free_nopage_retry(void) spin_unlock(&drm_np_retry.lock); } } +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)) + +struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + struct fault_data data; + + if (type) + *type = VM_FAULT_MINOR; + + data.address = address; + data.vma = vma; + drm_vm_ttm_fault(vma, &data); + switch (data.type) { + case VM_FAULT_OOM: + return NOPAGE_OOM; + case VM_FAULT_SIGBUS: + return NOPAGE_SIGBUS; + default: + break; + } + + return NOPAGE_REFAULT; +} + +#endif diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 784b9a7d..4e95679d 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -278,19 +278,30 @@ extern int drm_map_page_into_agp(struct page *page); * static space. The page will be put by do_nopage() since we've already * filled out the pte. */ -extern struct page * get_nopage_retry(void); + +struct fault_data { + struct vm_area_struct *vma; + unsigned long address; + pgoff_t pgoff; + unsigned int flags; + + int type; +}; + +extern struct page *get_nopage_retry(void); extern void free_nopage_retry(void); -#define NOPAGE_RETRY get_nopage_retry() +#define NOPAGE_REFAULT get_nopage_retry() -#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; diff --git a/shared-core/drm.h b/shared-core/drm.h index 17bf993b..32cad3bc 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -693,22 +693,6 @@ typedef struct drm_fence_arg { } op; } drm_fence_arg_t; -#define DRM_TTM_FLAG_SHAREABLE 0x00000001 - -typedef struct drm_ttm_arg { - enum { - drm_ttm_create, - drm_ttm_destroy, - drm_ttm_reference, - drm_ttm_unreference - } op; - unsigned handle; - drm_u64_t user_token; - drm_u64_t size; - unsigned flags; -}drm_ttm_arg_t; - - /* Buffer permissions, referring to how the GPU uses the buffers. these translate to fence types used for the buffers. Typically a texture buffer is read, A destination buffer is write and @@ -771,7 +755,6 @@ typedef struct drm_ttm_arg { #define DRM_BO_MASK_DRIVER 0x00F00000 typedef enum { - drm_bo_type_ttm, drm_bo_type_dc, drm_bo_type_user, drm_bo_type_fake @@ -920,7 +903,6 @@ typedef union drm_mm_init_arg{ #ifdef __linux__ #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) -#define DRM_IOCTL_TTM DRM_IOWR(0x3c, drm_ttm_arg_t) #define DRM_IOCTL_BUFOBJ DRM_IOWR(0x3d, drm_bo_arg_t) #define DRM_IOCTL_MM_INIT DRM_IOWR(0x3e, drm_mm_init_arg_t) #endif -- 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. --- libdrm/xf86drm.c | 9 +- linux-core/drm_bo.c | 54 +++++++++-- linux-core/drm_compat.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++++ linux-core/drm_compat.h | 68 ++++++++++++++ linux-core/drm_ttm.c | 70 ++++++++++++-- linux-core/drm_ttm.h | 7 +- linux-core/drm_vm.c | 37 +++----- 7 files changed, 435 insertions(+), 46 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index a083ca23..c7683182 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2624,7 +2624,8 @@ int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, drm_bo_arg_t arg; drm_bo_arg_request_t *req = &arg.d.req; drm_bo_arg_reply_t *rep = &arg.d.rep; - + int ret; + memset(buf, 0, sizeof(*buf)); memset(&arg, 0, sizeof(arg)); req->mask = mask; @@ -2650,7 +2651,11 @@ int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, } req->op = drm_bo_create; - if (ioctl(fd, DRM_IOCTL_BUFOBJ, &arg)) + do { + ret = ioctl(fd, DRM_IOCTL_BUFOBJ, &arg); + } while (ret != 0 && errno == EAGAIN); + + if (ret) return -errno; if (!arg.handled) { return -EFAULT; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index d8cab2ad..0e2b3fa1 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -67,14 +67,23 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) { drm_device_t *dev = buf->dev; drm_buffer_manager_t *bm = &dev->bm; + int ret; BUG_ON(!buf->tt); mutex_lock(&dev->struct_mutex); if (evict) - drm_evict_ttm(buf->ttm); + ret = drm_evict_ttm(buf->ttm); else - drm_unbind_ttm(buf->ttm); + ret = drm_unbind_ttm(buf->ttm); + + if (ret) { + mutex_unlock(&dev->struct_mutex); + if (ret == -EAGAIN) + schedule(); + return ret; + } + drm_mm_put_block(&bm->tt_manager, buf->tt); buf->tt = NULL; @@ -126,13 +135,31 @@ static void drm_bo_destroy_locked(drm_device_t * dev, drm_buffer_object_t * bo) list_del_init(&bo->tt_lru); list_del_init(&bo->vram_lru); - if (bo->tt) { + if (bo->ttm) { + unsigned long _end = jiffies + DRM_HZ; + int ret; /* * This temporarily unlocks struct_mutex. */ + + do { + ret = drm_unbind_ttm(bo->ttm); + if (ret == -EAGAIN) { + mutex_unlock(&dev->struct_mutex); + schedule(); + mutex_lock(&dev->struct_mutex); + } + } while (ret == -EAGAIN && !time_after_eq(jiffies, _end)); + + if (ret) { + DRM_ERROR("Couldn't unbind buffer. " + "Bad. Continuing anyway\n"); + } + } + + if (bo->tt) { - drm_unbind_ttm(bo->ttm); drm_mm_put_block(&bm->tt_manager, bo->tt); bo->tt = NULL; } @@ -435,6 +462,9 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) ret = drm_move_vram_to_local(bo); } #endif + if (ret) + goto out; + mutex_lock(&dev->struct_mutex); list_del_init((tt) ? &bo->tt_lru : &bo->vram_lru); if (list_empty((tt) ? &bo->vram_lru : &bo->tt_lru)) @@ -442,7 +472,7 @@ static int drm_bo_evict(drm_buffer_object_t * bo, int tt, int no_wait) mutex_unlock(&dev->struct_mutex); DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, _DRM_BO_FLAG_EVICTED); - out: + out: return ret; } @@ -521,14 +551,18 @@ static int drm_move_local_to_tt(drm_buffer_object_t * bo, int no_wait) if (ret) return ret; DRM_DEBUG("Flipping in to AGP 0x%08lx\n", bo->tt->start); + mutex_lock(&dev->struct_mutex); ret = drm_bind_ttm(bo->ttm, bo->tt->start); if (ret) { drm_mm_put_block(&bm->tt_manager, bo->tt); + bo->tt = NULL; } mutex_unlock(&dev->struct_mutex); - if (ret) + + if (ret) { return ret; + } be = bo->ttm->be; if (be->needs_cache_adjust(be)) @@ -1296,6 +1330,7 @@ int drm_buffer_object_create(drm_file_t * priv, } bo->priv_flags = 0; bo->flags = DRM_BO_FLAG_MEM_LOCAL | DRM_BO_FLAG_CACHED; + atomic_inc(&bm->count); ret = drm_bo_new_flags(dev, bo->flags, mask, hint, 1, &new_flags, &bo->mask); if (ret) @@ -1311,12 +1346,11 @@ int drm_buffer_object_create(drm_file_t * priv, mutex_unlock(&bo->mutex); *buf_obj = bo; - atomic_inc(&bm->count); return 0; - - out_err: + + out_err: mutex_unlock(&bo->mutex); - drm_free(bo, sizeof(*bo), DRM_MEM_BUFOBJ); + drm_bo_usage_deref_unlocked(dev, bo); return ret; } diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 1aa835ca..5287614d 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -183,3 +183,239 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, } #endif + +#ifdef DRM_ODD_MM_COMPAT + +typedef struct p_mm_entry { + struct list_head head; + struct mm_struct *mm; + atomic_t refcount; + int locked; +} p_mm_entry_t; + +typedef struct vma_entry { + struct list_head head; + struct vm_area_struct *vma; +} vma_entry_t; + + +struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + drm_local_map_t *map = (drm_local_map_t *) vma->vm_private_data; + unsigned long page_offset; + struct page *page; + drm_ttm_t *ttm; + drm_buffer_manager_t *bm; + drm_device_t *dev; + + /* + * FIXME: Check can't map aperture flag. + */ + + if (type) + *type = VM_FAULT_MINOR; + + if (!map) + return NOPAGE_OOM; + + if (address > vma->vm_end) + return NOPAGE_SIGBUS; + + ttm = (drm_ttm_t *) map->offset; + dev = ttm->dev; + mutex_lock(&dev->struct_mutex); + drm_fixup_ttm_caching(ttm); + BUG_ON(ttm->page_flags & DRM_TTM_PAGE_UNCACHED); + + bm = &dev->bm; + page_offset = (address - vma->vm_start) >> PAGE_SHIFT; + page = ttm->pages[page_offset]; + + if (!page) { + if (bm->cur_pages >= bm->max_pages) { + DRM_ERROR("Maximum locked page count exceeded\n"); + page = NOPAGE_OOM; + goto out; + } + page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); + if (!page) { + page = NOPAGE_OOM; + goto out; + } + ++bm->cur_pages; + SetPageLocked(page); + } + + get_page(page); + out: + mutex_unlock(&dev->struct_mutex); + return page; +} + + + + +int drm_ttm_map_bound(struct vm_area_struct *vma) +{ + drm_local_map_t *map = (drm_local_map_t *)vma->vm_private_data; + drm_ttm_t *ttm = (drm_ttm_t *) map->offset; + int ret = 0; + + if (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) { + unsigned long pfn = ttm->aper_offset + + (ttm->be->aperture_base >> PAGE_SHIFT); + pgprot_t pgprot = drm_io_prot(ttm->be->drm_map_type, vma); + + ret = io_remap_pfn_range(vma, vma->vm_start, pfn, + vma->vm_end - vma->vm_start, + pgprot); + } + return ret; +} + + +int drm_ttm_add_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) +{ + p_mm_entry_t *entry, *n_entry; + vma_entry_t *v_entry; + drm_local_map_t *map = (drm_local_map_t *) + vma->vm_private_data; + struct mm_struct *mm = vma->vm_mm; + + v_entry = drm_alloc(sizeof(*v_entry), DRM_MEM_TTM); + if (!v_entry) { + DRM_ERROR("Allocation of vma pointer entry failed\n"); + return -ENOMEM; + } + v_entry->vma = vma; + map->handle = (void *) v_entry; + list_add_tail(&v_entry->head, &ttm->vma_list); + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (mm == entry->mm) { + atomic_inc(&entry->refcount); + return 0; + } else if ((unsigned long)mm < (unsigned long)entry->mm) ; + } + + n_entry = drm_alloc(sizeof(*n_entry), DRM_MEM_TTM); + if (!n_entry) { + DRM_ERROR("Allocation of process mm pointer entry failed\n"); + return -ENOMEM; + } + INIT_LIST_HEAD(&n_entry->head); + n_entry->mm = mm; + n_entry->locked = 0; + atomic_set(&n_entry->refcount, 0); + list_add_tail(&n_entry->head, &entry->head); + + return 0; +} + +void drm_ttm_delete_vma(drm_ttm_t * ttm, struct vm_area_struct *vma) +{ + p_mm_entry_t *entry, *n; + vma_entry_t *v_entry, *v_n; + int found = 0; + struct mm_struct *mm = vma->vm_mm; + + list_for_each_entry_safe(v_entry, v_n, &ttm->vma_list, head) { + if (v_entry->vma == vma) { + found = 1; + list_del(&v_entry->head); + drm_free(v_entry, sizeof(*v_entry), DRM_MEM_TTM); + break; + } + } + BUG_ON(!found); + + list_for_each_entry_safe(entry, n, &ttm->p_mm_list, head) { + if (mm == entry->mm) { + if (atomic_add_negative(-1, &entry->refcount)) { + list_del(&entry->head); + BUG_ON(entry->locked); + drm_free(entry, sizeof(*entry), DRM_MEM_TTM); + } + return; + } + } + BUG_ON(1); +} + + + +int drm_ttm_lock_mm(drm_ttm_t * ttm) +{ + p_mm_entry_t *entry; + int lock_ok = 1; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + BUG_ON(entry->locked); + if (!down_write_trylock(&entry->mm->mmap_sem)) { + lock_ok = 0; + break; + } + entry->locked = 1; + } + + if (lock_ok) + return 0; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + if (!entry->locked) + break; + up_write(&entry->mm->mmap_sem); + entry->locked = 0; + } + + /* + * Possible deadlock. Try again. Our callers should handle this + * and restart. + */ + + return -EAGAIN; +} + +void drm_ttm_unlock_mm(drm_ttm_t * ttm) +{ + p_mm_entry_t *entry; + + list_for_each_entry(entry, &ttm->p_mm_list, head) { + BUG_ON(!entry->locked); + up_write(&entry->mm->mmap_sem); + entry->locked = 0; + } +} + +int drm_ttm_remap_bound(drm_ttm_t *ttm) +{ + vma_entry_t *v_entry; + int ret = 0; + + list_for_each_entry(v_entry, &ttm->vma_list, head) { + ret = drm_ttm_map_bound(v_entry->vma); + if (ret) + break; + } + + drm_ttm_unlock_mm(ttm); + return ret; +} + +void drm_ttm_finish_unmap(drm_ttm_t *ttm) +{ + vma_entry_t *v_entry; + + if (!(ttm->page_flags & DRM_TTM_PAGE_UNCACHED)) + return; + + list_for_each_entry(v_entry, &ttm->vma_list, head) { + v_entry->vma->vm_flags &= ~VM_PFNMAP; + } + drm_ttm_unlock_mm(ttm); +} + +#endif + diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 4e95679d..5617fb7f 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -231,6 +231,13 @@ static inline int remap_pfn_range(struct vm_area_struct *vma, unsigned long from #include #include +#if ((LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15))) +#define DRM_ODD_MM_COMPAT +#endif + + + /* * Flush relevant caches and clear a VMA structure so that page references * will cause a page fault. Don't flush tlbs. @@ -303,5 +310,66 @@ extern struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, extern struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, struct fault_data *data); +#endif + +#ifdef DRM_ODD_MM_COMPAT + +struct drm_ttm; + + +/* + * Add a vma to the ttm vma list, and the + * process mm pointer to the ttm mm list. Needs the ttm mutex. + */ + +extern int drm_ttm_add_vma(struct drm_ttm * ttm, + struct vm_area_struct *vma); +/* + * Delete a vma and the corresponding mm pointer from the + * ttm lists. Needs the ttm mutex. + */ +extern void drm_ttm_delete_vma(struct drm_ttm * ttm, + struct vm_area_struct *vma); + +/* + * Attempts to lock all relevant mmap_sems for a ttm, while + * not releasing the ttm mutex. May return -EAGAIN to avoid + * deadlocks. In that case the caller shall release the ttm mutex, + * schedule() and try again. + */ + +extern int drm_ttm_lock_mm(struct drm_ttm * ttm); + +/* + * Unlock all relevant mmap_sems for a ttm. + */ +extern void drm_ttm_unlock_mm(struct drm_ttm * ttm); + +/* + * If the ttm was bound to the aperture, this function shall be called + * with all relevant mmap sems held. It deletes the flag VM_PFNMAP from all + * vmas mapping this ttm. This is needed just after unmapping the ptes of + * the vma, otherwise the do_nopage() function will bug :(. The function + * releases the mmap_sems for this ttm. + */ + +extern void drm_ttm_finish_unmap(struct drm_ttm *ttm); + +/* + * Remap all vmas of this ttm using io_remap_pfn_range. We cannot + * fault these pfns in, because the first one will set the vma VM_PFNMAP + * flag, which will make the next fault bug in do_nopage(). The function + * releases the mmap_sems for this ttm. + */ + +extern int drm_ttm_remap_bound(struct drm_ttm *ttm); + + +/* + * Remap a vma for a bound ttm. Call with the ttm mutex held and + * the relevant mmap_sem locked. + */ +extern int drm_ttm_map_bound(struct vm_area_struct *vma); + #endif #endif diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c index 297d4f71..b56270ea 100644 --- a/linux-core/drm_ttm.c +++ b/linux-core/drm_ttm.c @@ -66,8 +66,17 @@ static int unmap_vma_pages(drm_ttm_t * ttm) drm_device_t *dev = ttm->dev; loff_t offset = ((loff_t) ttm->mapping_offset) << PAGE_SHIFT; loff_t holelen = ((loff_t) ttm->num_pages) << PAGE_SHIFT; - + +#ifdef DRM_ODD_MM_COMPAT + int ret; + ret = drm_ttm_lock_mm(ttm); + if (ret) + return ret; +#endif unmap_mapping_range(dev->dev_mapping, offset, holelen, 1); +#ifdef DRM_ODD_MM_COMPAT + drm_ttm_finish_unmap(ttm); +#endif return 0; } @@ -128,8 +137,11 @@ int drm_destroy_ttm(drm_ttm_t * ttm) DRM_DEBUG("Destroying a ttm\n"); +#ifdef DRM_TTM_ODD_COMPAT + BUG_ON(!list_empty(&ttm->vma_list)); + BUG_ON(!list_empty(&ttm->p_mm_list)); +#endif be = ttm->be; - if (be) { be->destroy(be); ttm->be = NULL; @@ -231,6 +243,11 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, if (!ttm) return NULL; +#ifdef DRM_ODD_MM_COMPAT + INIT_LIST_HEAD(&ttm->p_mm_list); + INIT_LIST_HEAD(&ttm->vma_list); +#endif + ttm->dev = dev; atomic_set(&ttm->vma_count, 0); @@ -263,11 +280,15 @@ static drm_ttm_t *drm_init_ttm(struct drm_device *dev, unsigned long size, int drm_evict_ttm(drm_ttm_t * ttm) { drm_ttm_backend_t *be = ttm->be; + int ret; switch (ttm->state) { case ttm_bound: if (be->needs_cache_adjust(be)) { - unmap_vma_pages(ttm); + ret = unmap_vma_pages(ttm); + if (ret) { + return ret; + } } be->unbind(be); break; @@ -291,12 +312,18 @@ void drm_fixup_ttm_caching(drm_ttm_t * ttm) } -void drm_unbind_ttm(drm_ttm_t * ttm) +int drm_unbind_ttm(drm_ttm_t * ttm) { + int ret = 0; + if (ttm->state == ttm_bound) - drm_evict_ttm(ttm); + ret = drm_evict_ttm(ttm); + + if (ret) + return ret; drm_fixup_ttm_caching(ttm); + return 0; } int drm_bind_ttm(drm_ttm_t * ttm, @@ -313,20 +340,45 @@ int drm_bind_ttm(drm_ttm_t * ttm, be = ttm->be; - drm_ttm_populate(ttm); + ret = drm_ttm_populate(ttm); + if (ret) + return ret; if (ttm->state == ttm_unbound && be->needs_cache_adjust(be)) { - unmap_vma_pages(ttm); + ret = unmap_vma_pages(ttm); + if (ret) + return ret; + drm_set_caching(ttm, DRM_TTM_PAGE_UNCACHED); - } + } +#ifdef DRM_ODD_MM_COMPAT + else if (ttm->state == ttm_evicted && be->needs_cache_adjust(be)) { + ret = drm_ttm_lock_mm(ttm); + if (ret) + return ret; + } +#endif if ((ret = be->bind(be, aper_offset))) { - drm_unbind_ttm(ttm); + ttm->state = ttm_evicted; +#ifdef DRM_ODD_MM_COMPAT + if (be->needs_cache_adjust(be)) + drm_ttm_unlock_mm(ttm); +#endif DRM_ERROR("Couldn't bind backend.\n"); return ret; } + ttm->aper_offset = aper_offset; ttm->state = ttm_bound; +#ifdef DRM_ODD_MM_COMPAT + if (be->needs_cache_adjust(be)) { + ret = drm_ttm_remap_bound(ttm); + if (ret) + return ret; + } +#endif + return 0; } diff --git a/linux-core/drm_ttm.h b/linux-core/drm_ttm.h index 19c1df51..5421c52a 100644 --- a/linux-core/drm_ttm.h +++ b/linux-core/drm_ttm.h @@ -74,6 +74,11 @@ typedef struct drm_ttm { ttm_unbound, ttm_unpopulated, } state; +#ifdef DRM_ODD_MM_COMPAT + struct list_head vma_list; + struct list_head p_mm_list; +#endif + } drm_ttm_t; typedef struct drm_ttm_object { @@ -95,7 +100,7 @@ extern drm_ttm_object_t *drm_lookup_ttm_object(drm_file_t * priv, extern int drm_bind_ttm(drm_ttm_t * ttm, unsigned long aper_offset); -extern void drm_unbind_ttm(drm_ttm_t * ttm); +extern int drm_unbind_ttm(drm_ttm_t * ttm); /* * Evict a ttm region. Keeps Aperture caching policy. diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index 45951156..091b43f7 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -204,15 +204,15 @@ struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, if (!page) { if (bm->cur_pages >= bm->max_pages) { DRM_ERROR("Maximum locked page count exceeded\n"); - page = NOPAGE_OOM; + data->type = VM_FAULT_OOM; goto out; } - ++bm->cur_pages; page = ttm->pages[page_offset] = drm_alloc_gatt_pages(0); if (!page) { data->type = VM_FAULT_OOM; goto out; } + ++bm->cur_pages; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)) SetPageLocked(page); #else @@ -236,28 +236,6 @@ struct page *drm_vm_ttm_fault(struct vm_area_struct *vma, err = vm_insert_pfn(vma, address, pfn, pgprot); - if (!err && (ttm->page_flags & DRM_TTM_PAGE_UNCACHED) && - ttm->num_pages > 1) { - - /* - * FIXME: Check can't map aperture flag. - */ - - /* - * Since we're not racing with anybody else, - * we might as well populate the whole object space. - * Note that we're touching vma->vm_flags with this - * operation, but we are not changing them, so we should be - * OK. - */ - - BUG_ON(ttm->state == ttm_unpopulated); - err = io_remap_pfn_range(vma, address + PAGE_SIZE, pfn+1, - (ttm->num_pages - 1) * PAGE_SIZE, - pgprot); - } - - if (!err || err == -EBUSY) data->type = VM_FAULT_MINOR; else @@ -611,6 +589,9 @@ static int drm_vm_ttm_open(struct vm_area_struct *vma) { mutex_lock(&dev->struct_mutex); ttm = (drm_ttm_t *) map->offset; atomic_inc(&ttm->vma_count); +#ifdef DRM_ODD_MM_COMPAT + drm_ttm_add_vma(ttm, vma); +#endif mutex_unlock(&dev->struct_mutex); return 0; } @@ -666,6 +647,9 @@ static void drm_vm_ttm_close(struct vm_area_struct *vma) ttm = (drm_ttm_t *) map->offset; dev = ttm->dev; mutex_lock(&dev->struct_mutex); +#ifdef DRM_ODD_MM_COMPAT + drm_ttm_delete_vma(ttm, vma); +#endif if (atomic_dec_and_test(&ttm->vma_count)) { if (ttm->destroy) { ret = drm_destroy_ttm(ttm); @@ -877,6 +861,11 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_private_data = (void *) map; vma->vm_file = filp; vma->vm_flags |= VM_RESERVED | VM_IO; +#ifdef DRM_ODD_MM_COMPAT + mutex_lock(&dev->struct_mutex); + drm_ttm_map_bound(vma); + mutex_unlock(&dev->struct_mutex); +#endif if (drm_vm_ttm_open(vma)) return -EAGAIN; return 0; -- 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 ++++----- shared-core/i915_drv.h | 3 +- 7 files changed, 96 insertions(+), 100 deletions(-) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1b6d94e4..f706d4d8 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -664,7 +664,7 @@ typedef struct drm_bo_driver{ int cached_vram; drm_local_map_t *vram_map; drm_ttm_backend_t *(*create_ttm_backend_entry) - (struct drm_device *dev, int cached); + (struct drm_device *dev); int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type); int (*invalidate_caches)(struct drm_device *dev, uint32_t flags); } drm_bo_driver_t; @@ -977,7 +977,9 @@ typedef struct drm_device { typedef struct drm_agp_ttm_priv { DRM_AGP_MEM *mem; struct agp_bridge_data *bridge; - unsigned mem_type; + unsigned alloc_type; + unsigned cached_type; + unsigned uncached_type; int populated; } drm_agp_ttm_priv; #endif @@ -1289,11 +1291,11 @@ extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge, size extern int drm_agp_free_memory(DRM_AGP_MEM * handle); extern int drm_agp_bind_memory(DRM_AGP_MEM * handle, off_t start); extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle); -extern drm_ttm_backend_t *drm_agp_init_ttm_cached(struct drm_device *dev, - drm_ttm_backend_t *backend); -extern drm_ttm_backend_t *drm_agp_init_ttm_uncached(struct drm_device *dev, - drm_ttm_backend_t *backend); - +extern drm_ttm_backend_t *drm_agp_init_ttm(struct drm_device *dev, + drm_ttm_backend_t *backend, + unsigned alloc_type, + unsigned cached_type, + unsigned uncached_type); /* Stub support (drm_stub.h) */ extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, struct drm_driver *driver); diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c index 77994d5c..902b8947 100644 --- a/linux-core/drm_agpsupport.c +++ b/linux-core/drm_agpsupport.c @@ -552,20 +552,16 @@ int drm_agp_unbind_memory(DRM_AGP_MEM * handle) return agp_unbind_memory(handle); } + + /* * AGP ttm backend interface. */ -static int drm_agp_needs_cache_adjust_true(drm_ttm_backend_t *backend) { - return TRUE; +static int drm_agp_needs_unbind_cache_adjust(drm_ttm_backend_t *backend) { + return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 1 : 0); } -static int drm_agp_needs_cache_adjust_false(drm_ttm_backend_t *backend) { - return FALSE; -} - -#define AGP_MEM_USER (1 << 16) -#define AGP_MEM_UCACHED (2 << 16) static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, struct page **pages) { @@ -576,9 +572,9 @@ static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, DRM_DEBUG("drm_agp_populate_ttm\n"); #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,11) - mem = drm_agp_allocate_memory(num_pages, agp_priv->mem_type); + mem = drm_agp_allocate_memory(num_pages, agp_priv->alloc_type); #else - mem = drm_agp_allocate_memory(agp_priv->bridge, num_pages, agp_priv->mem_type); + mem = drm_agp_allocate_memory(agp_priv->bridge, num_pages, agp_priv->alloc_type); #endif if (!mem) return -1; @@ -592,14 +588,19 @@ static int drm_agp_populate(drm_ttm_backend_t *backend, unsigned long num_pages, return 0; } -static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, unsigned long offset) { - +static int drm_agp_bind_ttm(drm_ttm_backend_t *backend, + unsigned long offset, + int cached) +{ drm_agp_ttm_priv *agp_priv = (drm_agp_ttm_priv *) backend->private; DRM_AGP_MEM *mem = agp_priv->mem; int ret; DRM_DEBUG("drm_agp_bind_ttm\n"); + DRM_MASK_VAL(backend->flags, DRM_BE_FLAG_BOUND_CACHED, + (cached) ? DRM_BE_FLAG_BOUND_CACHED : 0); mem->is_flushed = FALSE; + mem->type = (cached) ? agp_priv->cached_type : agp_priv->uncached_type; ret = drm_agp_bind_memory(mem, offset); if (ret) { DRM_ERROR("AGP Bind memory failed\n"); @@ -645,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; diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index a92205e4..85804ce7 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -183,8 +183,7 @@ extern void i915_poke_flush(drm_device_t *dev); #ifdef I915_HAVE_BUFFER /* i915_buffer.c */ -extern drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev, - int cached); +extern drm_ttm_backend_t *i915_create_ttm_backend_entry(drm_device_t *dev); extern int i915_fence_types(uint32_t buffer_flags, uint32_t *class, uint32_t *type); extern int i915_invalidate_caches(drm_device_t *dev, uint32_t buffer_flags); #endif -- 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(-) 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 - shared-core/drm.h | 3 --- shared-core/via_drv.c | 1 - 22 files changed, 25 deletions(-) delete mode 120000 linux-core/drm_drawable.c diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 2bbec70c..1b314be1 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -41,7 +41,6 @@ * can build the DRM (part of PI DRI). 4/21/2000 S + B */ #include #endif /* __alpha__ */ -#include #include #include #include diff --git a/linux-core/drm_drawable.c b/linux-core/drm_drawable.c deleted file mode 120000 index d64bbe10..00000000 --- a/linux-core/drm_drawable.c +++ /dev/null @@ -1 +0,0 @@ -../shared-core/drm_drawable.c \ No newline at end of file diff --git a/linux-core/drm_memory.c b/linux-core/drm_memory.c index 9125cd47..a249382d 100644 --- a/linux-core/drm_memory.c +++ b/linux-core/drm_memory.c @@ -33,7 +33,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include #include "drmP.h" diff --git a/linux-core/drm_memory.h b/linux-core/drm_memory.h index 4a4fd5c3..4a2c3583 100644 --- a/linux-core/drm_memory.h +++ b/linux-core/drm_memory.h @@ -33,7 +33,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include #include #include "drmP.h" diff --git a/linux-core/drm_memory_debug.c b/linux-core/drm_memory_debug.c index 2fe7aeaa..aa1b2922 100644 --- a/linux-core/drm_memory_debug.c +++ b/linux-core/drm_memory_debug.c @@ -31,7 +31,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" #ifdef DEBUG_MEMORY diff --git a/linux-core/drm_memory_debug.h b/linux-core/drm_memory_debug.h index 706b7525..1e0a63b7 100644 --- a/linux-core/drm_memory_debug.h +++ b/linux-core/drm_memory_debug.h @@ -31,7 +31,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" typedef struct drm_mem_stats { diff --git a/linux-core/drm_scatter.c b/linux-core/drm_scatter.c index a7144f1a..e5c9f877 100644 --- a/linux-core/drm_scatter.c +++ b/linux-core/drm_scatter.c @@ -31,7 +31,6 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include "drmP.h" diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index df75d7b0..e5dd0532 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -11,7 +11,6 @@ * */ -#include #include #include #include diff --git a/linux-core/ffb_drv.c b/linux-core/ffb_drv.c index 7b028c86..9c88f061 100644 --- a/linux-core/ffb_drv.c +++ b/linux-core/ffb_drv.c @@ -4,7 +4,6 @@ * Copyright (C) 2000 David S. Miller (davem@redhat.com) */ -#include #include #include #include diff --git a/linux-core/i810_drv.c b/linux-core/i810_drv.c index d4b73760..fc784a02 100644 --- a/linux-core/i810_drv.c +++ b/linux-core/i810_drv.c @@ -30,7 +30,6 @@ * Gareth Hughes */ -#include #include "drmP.h" #include "drm.h" #include "i810_drm.h" diff --git a/linux-core/i830_drv.c b/linux-core/i830_drv.c index 74b574aa..6416161e 100644 --- a/linux-core/i830_drv.c +++ b/linux-core/i830_drv.c @@ -32,8 +32,6 @@ * Keith Whitwell */ -#include - #include "drmP.h" #include "drm.h" #include "i830_drm.h" diff --git a/linux-core/imagine_drv.c b/linux-core/imagine_drv.c index bec2fae4..6d050999 100644 --- a/linux-core/imagine_drv.c +++ b/linux-core/imagine_drv.c @@ -22,7 +22,6 @@ /* derived from tdfx_drv.c */ -#include #include "drmP.h" #include "imagine_drv.h" diff --git a/linux-core/mach64_drv.c b/linux-core/mach64_drv.c index ba45132b..9709934d 100644 --- a/linux-core/mach64_drv.c +++ b/linux-core/mach64_drv.c @@ -27,7 +27,6 @@ * Leif Delgass */ -#include #include "drmP.h" #include "drm.h" #include "mach64_drm.h" diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 3a1e4b25..2bb1e8f3 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -29,7 +29,6 @@ * Gareth Hughes */ -#include #include "drmP.h" #include "drm.h" #include "mga_drm.h" diff --git a/linux-core/nv_drv.c b/linux-core/nv_drv.c index a6afb024..5049473a 100644 --- a/linux-core/nv_drv.c +++ b/linux-core/nv_drv.c @@ -32,7 +32,6 @@ * Lars Knoll */ -#include #include "drmP.h" #include "nv_drv.h" diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index edc04b03..ef4a5cbd 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -29,7 +29,6 @@ * Gareth Hughes */ -#include #include "drmP.h" #include "drm.h" #include "r128_drm.h" diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c index b15e983e..43b9aca0 100644 --- a/linux-core/radeon_drv.c +++ b/linux-core/radeon_drv.c @@ -29,7 +29,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" #include "drm.h" #include "radeon_drm.h" diff --git a/linux-core/savage_drv.c b/linux-core/savage_drv.c index 9f12dfe2..bb3561e6 100644 --- a/linux-core/savage_drv.c +++ b/linux-core/savage_drv.c @@ -23,7 +23,6 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" #include "savage_drm.h" #include "savage_drv.h" diff --git a/linux-core/sis_drv.c b/linux-core/sis_drv.c index 36a525dc..9b0b9830 100644 --- a/linux-core/sis_drv.c +++ b/linux-core/sis_drv.c @@ -25,7 +25,6 @@ * */ -#include #include "drmP.h" #include "sis_drm.h" #include "sis_drv.h" diff --git a/linux-core/tdfx_drv.c b/linux-core/tdfx_drv.c index ce1b7c5a..bc69c06a 100644 --- a/linux-core/tdfx_drv.c +++ b/linux-core/tdfx_drv.c @@ -30,7 +30,6 @@ * Gareth Hughes */ -#include #include "drmP.h" #include "tdfx_drv.h" diff --git a/shared-core/drm.h b/shared-core/drm.h index 8c0c5d22..7d7e2502 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -69,9 +69,6 @@ #endif #if defined(__linux__) -#if defined(__KERNEL__) -#include -#endif #include /* For _IO* macros */ #define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_IOC_VOID _IOC_NONE diff --git a/shared-core/via_drv.c b/shared-core/via_drv.c index bacfe37d..33b0a42d 100644 --- a/shared-core/via_drv.c +++ b/shared-core/via_drv.c @@ -22,7 +22,6 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include "drmP.h" #include "via_drm.h" #include "via_drv.h" -- 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 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 561e23a7c2f06b382613d3e2ae8d23104d0949aa Mon Sep 17 00:00:00 2001 From: Michael Karcher Date: Mon, 16 Oct 2006 22:06:58 -0400 Subject: dev->agp_buffer_map is not initialized for AGP DMA on savages bug 8662 --- shared-core/savage_bci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-core/savage_bci.c b/shared-core/savage_bci.c index 20fea40f..01121b92 100644 --- a/shared-core/savage_bci.c +++ b/shared-core/savage_bci.c @@ -725,6 +725,7 @@ static int savage_do_init_bci(drm_device_t *dev, drm_savage_init_t *init) dev_priv->status = NULL; } if (dev_priv->dma_type == SAVAGE_DMA_AGP && init->buffers_offset) { + dev->agp_buffer_token = init->buffers_offset; dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); if (!dev->agp_buffer_map) { -- 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. --- libdrm/xf86drm.c | 31 ++- libdrm/xf86mm.h | 9 +- 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 +- shared-core/drm.h | 34 ++- shared-core/i915_dma.c | 4 +- 9 files changed, 434 insertions(+), 260 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index c7683182..039c9b32 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3155,19 +3155,16 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) return 0; } -int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, - unsigned long ttPOffset, unsigned long ttPSize, - unsigned long max_locked_size) +int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, + unsigned memType) { drm_mm_init_arg_t arg; memset(&arg, 0, sizeof(arg)); arg.req.op = mm_init; - arg.req.vr_p_offset = vramPOffset; - arg.req.vr_p_size = vramPSize; - arg.req.tt_p_offset = ttPOffset; - arg.req.tt_p_size = ttPSize; - arg.req.max_locked_pages = max_locked_size / getpagesize(); + arg.req.p_offset = pOffset; + arg.req.p_size = pSize; + arg.req.mem_type = memType; if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) return -errno; @@ -3175,13 +3172,29 @@ int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, return 0; } -int drmMMTakedown(int fd) +int drmMMTakedown(int fd, unsigned memType) { drm_mm_init_arg_t arg; memset(&arg, 0, sizeof(arg)); arg.req.op = mm_takedown; + arg.req.mem_type = memType; + + if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) + return -errno; + + return 0; +} + +int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize) +{ + drm_mm_init_arg_t arg; + + + memset(&arg, 0, sizeof(arg)); + arg.req.op = mm_set_max_pages; + arg.req.p_size = maxLockedSize / getpagesize(); if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) return -errno; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index 78df37c3..b2ba24d5 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -195,10 +195,11 @@ extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint); * Initialization functions. */ -extern int drmMMInit(int fd, unsigned long vramPOffset, unsigned long vramPSize, - unsigned long ttPOffset, unsigned long ttPSize, - unsigned long max_locked_size); -extern int drmMMTakedown(int fd); +extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, + unsigned memType); +extern int drmMMTakedown(int fd, unsigned memType); +extern int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize); + #endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index f706d4d8..7e95569b 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -167,6 +167,7 @@ #define DRM_OBJECT_HASH_ORDER 12 #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) +#define DRM_MM_INIT_MAX_PAGES 256 /*@}*/ @@ -660,9 +661,8 @@ typedef struct drm_ref_object { */ typedef struct drm_bo_driver{ - int cached_tt; - int cached_vram; - drm_local_map_t *vram_map; + int cached[DRM_BO_MEM_TYPES]; + drm_local_map_t *iomap[DRM_BO_MEM_TYPES]; drm_ttm_backend_t *(*create_ttm_backend_entry) (struct drm_device *dev); int (*fence_type)(uint32_t flags, uint32_t *class, uint32_t *type); @@ -801,21 +801,17 @@ typedef struct drm_fence_manager{ } drm_fence_manager_t; typedef struct drm_buffer_manager{ + struct mutex init_mutex; + int nice_mode; int initialized; drm_file_t *last_to_validate; - int has_vram; - int has_tt; - int use_vram; - int use_tt; - drm_mm_t tt_manager; - drm_mm_t vram_manager; - struct list_head tt_lru; - struct list_head vram_lru; - struct list_head tt_pinned; - struct list_head vram_pinned; + int has_type[DRM_BO_MEM_TYPES]; + int use_type[DRM_BO_MEM_TYPES]; + drm_mm_t manager[DRM_BO_MEM_TYPES]; + struct list_head lru[DRM_BO_MEM_TYPES]; + struct list_head pinned[DRM_BO_MEM_TYPES]; struct list_head unfenced; struct list_head ddestroy; - struct list_head other; struct work_struct wq; uint32_t fence_type; unsigned long max_pages; @@ -1024,10 +1020,10 @@ typedef struct drm_buffer_object{ uint32_t flags; uint32_t mask; - drm_mm_node_t *vram; - drm_mm_node_t *tt; - struct list_head tt_lru; - struct list_head vram_lru; + drm_mm_node_t *node_ttm; /* MM node for on-card RAM */ + drm_mm_node_t *node_card; /* MM node for ttm*/ + struct list_head lru_ttm; /* LRU for the ttm pages*/ + struct list_head lru_card; /* For memory types with on-card RAM */ struct list_head ddestroy; uint32_t fence_type; @@ -1447,7 +1443,8 @@ extern int drm_fence_ioctl(DRM_IOCTL_ARGS); extern int drm_bo_ioctl(DRM_IOCTL_ARGS); extern int drm_mm_init_ioctl(DRM_IOCTL_ARGS); -extern int drm_bo_clean_mm(drm_device_t *dev); +extern int drm_bo_driver_finish(drm_device_t *dev); +extern int drm_bo_driver_init(drm_device_t *dev); extern int drm_fence_buffer_objects(drm_file_t * priv, struct list_head *list, uint32_t fence_flags, diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index c24f8d57..20c58f21 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -59,6 +59,69 @@ (_old) ^= (((_old) ^ (_new)) & (_mask)); \ } +static inline uint32_t drm_bo_type_flags(unsigned type) +{ + return (1 << (24 + type)); +} + +static inline drm_buffer_object_t *drm_bo_entry(struct list_head *list, + unsigned type) +{ + switch(type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return list_entry(list, drm_buffer_object_t, lru_ttm); + case DRM_BO_MEM_VRAM: + case DRM_BO_MEM_VRAM_NM: + return list_entry(list, drm_buffer_object_t, lru_card); + default: + BUG_ON(1); + } + return NULL; +} + +static inline drm_mm_node_t *drm_bo_mm_node(drm_buffer_object_t *bo, + unsigned type) +{ + switch(type) { + case DRM_BO_MEM_LOCAL: + case DRM_BO_MEM_TT: + return bo->node_ttm; + case DRM_BO_MEM_VRAM: + case DRM_BO_MEM_VRAM_NM: + return bo->node_card; + default: + BUG_ON(1); + } + return NULL; +} + +/* + * bo locked. dev->struct_mutex locked. + */ + +static void drm_bo_add_to_lru(drm_buffer_object_t *buf, + drm_buffer_manager_t *bm) +{ + struct list_head *list; + unsigned mem_type; + + if (buf->flags & DRM_BO_FLAG_MEM_TT) { + mem_type = DRM_BO_MEM_TT; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_ttm, list); + } else { + mem_type = DRM_BO_MEM_LOCAL; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_ttm, list); + } + if (buf->flags & DRM_BO_FLAG_MEM_VRAM) { + mem_type = DRM_BO_MEM_VRAM; + list = (buf->flags & (DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE)) ? &bm->pinned[mem_type] : &bm->lru[mem_type]; + list_add_tail(&buf->lru_card, list); + } +} + /* * bo locked. */ @@ -69,27 +132,27 @@ static int drm_move_tt_to_local(drm_buffer_object_t * buf, int evict) drm_buffer_manager_t *bm = &dev->bm; int ret; - BUG_ON(!buf->tt); - - 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 diff --git a/shared-core/drm.h b/shared-core/drm.h index 32cad3bc..915befba 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -680,6 +680,7 @@ typedef struct drm_fence_arg { unsigned type; unsigned flags; unsigned signaled; + unsigned expand_pad[4]; /*Future expansion */ enum { drm_fence_create, drm_fence_destroy, @@ -732,12 +733,14 @@ typedef struct drm_fence_arg { /* Bind this buffer cached if the hardware supports it. */ #define DRM_BO_FLAG_BIND_CACHED 0x0002000 -/* Translation table aperture */ -#define DRM_BO_FLAG_MEM_TT 0x01000000 -/* On-card VRAM */ -#define DRM_BO_FLAG_MEM_VRAM 0x02000000 -/* System memory */ -#define DRM_BO_FLAG_MEM_LOCAL 0x04000000 +/* System Memory */ +#define DRM_BO_FLAG_MEM_LOCAL 0x01000000 +/* Translation table memory */ +#define DRM_BO_FLAG_MEM_TT 0x02000000 +/* Vram memory */ +#define DRM_BO_FLAG_MEM_VRAM 0x04000000 +/* Unmappable Vram memory */ +#define DRM_BO_FLAG_MEM_VRAM_NM 0x08000000 /* Memory flag mask */ #define DRM_BO_MASK_MEM 0xFF000000 @@ -769,6 +772,7 @@ typedef struct drm_bo_arg_request { drm_bo_type_t type; unsigned arg_handle; drm_u64_t buffer_start; + unsigned expand_pad[4]; /*Future expansion */ enum { drm_bo_create, drm_bo_validate, @@ -802,6 +806,7 @@ typedef struct drm_bo_arg_reply { drm_u64_t buffer_start; unsigned fence_flags; unsigned rep_flags; + unsigned expand_pad[4]; /*Future expansion */ }drm_bo_arg_reply_t; @@ -814,23 +819,30 @@ typedef struct drm_bo_arg{ } d; } drm_bo_arg_t; +#define DRM_BO_MEM_LOCAL 0 +#define DRM_BO_MEM_TT 1 +#define DRM_BO_MEM_VRAM 2 +#define DRM_BO_MEM_VRAM_NM 3 +#define DRM_BO_MEM_TYPES 2 /* For now. */ + typedef union drm_mm_init_arg{ struct { enum { mm_init, + mm_set_max_pages, mm_takedown, mm_query, mm_lock, mm_unlock } op; - drm_u64_t vr_p_offset; - drm_u64_t vr_p_size; - drm_u64_t tt_p_offset; - drm_u64_t tt_p_size; - drm_u64_t max_locked_pages; + drm_u64_t p_offset; + drm_u64_t p_size; + unsigned mem_type; + unsigned expand_pad[8]; /*Future expansion */ } req; struct { drm_handle_t mm_sarea; + unsigned expand_pad[8]; /*Future expansion */ } rep; } drm_mm_init_arg_t; #endif diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index 841761c8..8c701b4d 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -197,7 +197,9 @@ static int i915_initialize(drm_device_t * dev, I915_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); dev->dev_private = (void *)dev_priv; - +#ifdef I915_HAVE_BUFFER + drm_bo_driver_init(dev); +#endif return 0; } -- 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(-) 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. --- libdrm/xf86drm.c | 33 +++++++++ libdrm/xf86mm.h | 3 +- linux-core/drmP.h | 5 ++ linux-core/drm_bo.c | 188 ++++++++++++++++++++++++++++++++++++++-------------- 4 files changed, 178 insertions(+), 51 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 039c9b32..253ba690 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3202,4 +3202,37 @@ int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize) return 0; } +int drmMMLock(int fd, unsigned memType) +{ + drm_mm_init_arg_t arg; + int ret; + + memset(&arg, 0, sizeof(arg)); + arg.req.op = mm_lock; + arg.req.mem_type = memType; + + do{ + ret = ioctl(fd, DRM_IOCTL_MM_INIT, &arg); + } while (ret && errno == EAGAIN); + + return ret; +} + +int drmMMUnlock(int fd, unsigned memType) +{ + drm_mm_init_arg_t arg; + int ret; + + memset(&arg, 0, sizeof(arg)); + arg.req.op = mm_unlock; + arg.req.mem_type = memType; + + do{ + ret = ioctl(fd, DRM_IOCTL_MM_INIT, &arg); + } while (ret && errno == EAGAIN); + + return ret; +} + + #endif diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index b2ba24d5..c3112c90 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -199,7 +199,8 @@ extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, unsigned memType); extern int drmMMTakedown(int fd, unsigned memType); extern int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize); - +extern int drmMMLock(int fd, unsigned memType); +extern int drmMMUnlock(int fd, unsigned memType); #endif diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 7ae001b3..ff952250 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1351,6 +1351,11 @@ extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size, extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size); extern void drm_mm_takedown(drm_mm_t *mm); extern int drm_mm_clean(drm_mm_t *mm); +static inline drm_mm_t *drm_get_mm(drm_mm_node_t *block) +{ + return block->mm; +} + /* * User space object bookkeeping (drm_object.c) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 67e90247..f671a046 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -514,8 +514,8 @@ static int drm_bo_evict(drm_buffer_object_t * bo, unsigned mem_type, if (ret) goto out; mutex_lock(&dev->struct_mutex); - list_del(&bo->lru_ttm); - list_add_tail(&bo->lru_ttm, &bm->lru[DRM_BO_MEM_LOCAL]); + list_del_init(&bo->lru_ttm); + drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); } #if 0 @@ -658,6 +658,11 @@ static int drm_bo_new_flags(drm_device_t * dev, new_mask &= ~drm_bo_type_flags(i); } + if ((new_mask & DRM_BO_FLAG_NO_EVICT ) && !DRM_SUSER(DRM_CURPROC)) { + DRM_ERROR("DRM_BO_FLAG_NO_EVICT is only available to priviliged " + "processes\n"); + return -EPERM; + } if (new_mask & DRM_BO_FLAG_BIND_CACHED) { if (((new_mask & DRM_BO_FLAG_MEM_TT) && !driver->cached[DRM_BO_MEM_TT]) && @@ -1085,7 +1090,7 @@ static void drm_buffer_user_object_unmap(drm_file_t * priv, */ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, - int no_wait) + int no_wait, int force_no_move) { int ret = 0; @@ -1118,7 +1123,7 @@ static int drm_bo_move_buffer(drm_buffer_object_t * bo, uint32_t new_flags, if (ret) return ret; } else { - drm_move_tt_to_local(bo, 0, 1); + drm_move_tt_to_local(bo, 0, force_no_move); } return 0; @@ -1153,8 +1158,6 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, /* * Move out if we need to change caching policy. - * FIXME: Failing is strictly not needed for NO_MOVE buffers. - * We just have to implement NO_MOVE buffers. */ if ((flag_diff & DRM_BO_FLAG_BIND_CACHED) && @@ -1164,7 +1167,7 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, "pinned buffer.\n"); return -EINVAL; } - ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait); + ret = drm_bo_move_buffer(bo, DRM_BO_FLAG_MEM_LOCAL, no_wait, 0); if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed moving buffer.\n"); @@ -1174,12 +1177,31 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, DRM_MASK_VAL(bo->flags, DRM_BO_FLAG_BIND_CACHED, new_flags); flag_diff = (new_flags ^ bo->flags); + /* + * Check whether we dropped no_move policy, and in that case, + * release reserved manager regions. + */ + + if ((flag_diff & DRM_BO_FLAG_NO_MOVE) && + !(new_flags & DRM_BO_FLAG_NO_MOVE)) { + mutex_lock(&dev->struct_mutex); + if (bo->node_ttm) { + drm_mm_put_block(bo->node_ttm); + bo->node_ttm = NULL; + } + if (bo->node_card) { + drm_mm_put_block(bo->node_card); + bo->node_card = NULL; + } + mutex_unlock(&dev->struct_mutex); + } + /* * Check whether we need to move buffer. */ if ((bo->type != drm_bo_type_fake) && (flag_diff & DRM_BO_MASK_MEM)) { - ret = drm_bo_move_buffer(bo, new_flags, no_wait); + ret = drm_bo_move_buffer(bo, new_flags, no_wait, 1); if (ret) { if (ret != -EAGAIN) DRM_ERROR("Failed moving buffer.\n"); @@ -1207,7 +1229,6 @@ static int drm_buffer_object_validate(drm_buffer_object_t * bo, list_del_init(&bo->lru_card); drm_bo_add_to_lru(bo, bm); mutex_unlock(&dev->struct_mutex); - DRM_FLAG_MASKED(bo->flags, new_flags, DRM_BO_FLAG_NO_EVICT); } bo->flags = new_flags; @@ -1586,34 +1607,51 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) * dev->struct_sem locked. */ -static void drm_bo_force_list_clean(drm_device_t *dev, - struct list_head *head, - unsigned mem_type) +static int drm_bo_force_list_clean(drm_device_t *dev, + struct list_head *head, + unsigned mem_type, + int force_no_move, + int allow_errors) { drm_buffer_manager_t *bm = &dev->bm; - struct list_head *l; + struct list_head *list, *next, *prev; drm_buffer_object_t *entry; int ret; + int clean; - l = head->next; - while (l != head) { - entry = drm_bo_entry(l, mem_type); - + retry: + clean = 1; + list_for_each_safe(list, next, head) { + prev = list->prev; + entry = drm_bo_entry(list, mem_type); atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); + mutex_lock(&dev->struct_mutex); - /* - * Expire the fence. - */ + if (prev != list->prev || next != list->next) { + mutex_unlock(&entry->mutex); + goto retry; + } + if (drm_bo_mm_node(entry, mem_type)) { + clean = 0; - if (entry->fence) { - if (bm->nice_mode) { + /* + * Expire the fence. + */ + + mutex_unlock(&dev->struct_mutex); + if (entry->fence && bm->nice_mode) { unsigned long _end = jiffies + 3*DRM_HZ; do { ret = drm_bo_wait(entry, 0, 1, 0); + if (ret && allow_errors) { + if (ret == -EINTR) + ret = -EAGAIN; + goto out_err; + } } while (ret && !time_after_eq(jiffies, _end)); - + if (entry->fence) { bm->nice_mode = 0; DRM_ERROR("Detected GPU hang or " @@ -1621,23 +1659,47 @@ static void drm_bo_force_list_clean(drm_device_t *dev, "Evicting waiting buffers\n"); } } - if (entry->fence) { - drm_fence_usage_deref_unlocked(dev, - entry->fence); + drm_fence_usage_deref_unlocked(dev, entry->fence); entry->fence = NULL; } - } - ret = drm_bo_evict(entry, mem_type, 0, 1); - if (ret) { - DRM_ERROR("Aargh. Eviction failed.\n"); + + DRM_MASK_VAL(entry->priv_flags, _DRM_BO_FLAG_UNFENCED, 0); + + if (force_no_move) { + DRM_MASK_VAL(entry->flags, DRM_BO_FLAG_NO_MOVE, 0); + } + if (entry->flags & DRM_BO_FLAG_NO_EVICT) { + DRM_ERROR("A DRM_BO_NO_EVICT buffer present at " + "cleanup. Removing flag and evicting.\n"); + entry->flags &= ~DRM_BO_FLAG_NO_EVICT; + entry->mask &= ~DRM_BO_FLAG_NO_EVICT; + } + + ret = drm_bo_evict(entry, mem_type, 1, force_no_move); + if (ret) { + if (allow_errors) { + goto out_err; + } else { + DRM_ERROR("Aargh. Eviction failed.\n"); + } + } + mutex_lock(&dev->struct_mutex); } mutex_unlock(&entry->mutex); - mutex_lock(&dev->struct_mutex); - drm_bo_usage_deref_locked(dev, entry); - l = head->next; + if (prev != list->prev || next != list->next) { + goto retry; + } } + if (!clean) + goto retry; + return 0; + out_err: + mutex_unlock(&entry->mutex); + drm_bo_usage_deref_unlocked(dev, entry); + mutex_lock(&dev->struct_mutex); + return ret; } int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) @@ -1660,8 +1722,21 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) ret = 0; if (mem_type > 0) { - drm_bo_force_list_clean(dev, &bm->lru[mem_type], 1); - drm_bo_force_list_clean(dev, &bm->pinned[mem_type], 1); + + /* + * Throw out unfenced buffers. + */ + + drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 1, 0); + + /* + * Throw out evicted no-move buffers. + */ + + drm_bo_force_list_clean(dev, &bm->pinned[DRM_BO_MEM_LOCAL], + mem_type, 1, 0); + drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 1, 0); + drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 1, 0); if (drm_mm_clean(&bm->manager[mem_type])) { drm_mm_takedown(&bm->manager[mem_type]); @@ -1673,6 +1748,22 @@ int drm_bo_clean_mm(drm_device_t * dev, unsigned mem_type) return ret; } +static int drm_bo_lock_mm(drm_device_t *dev, unsigned mem_type) +{ + int ret; + drm_buffer_manager_t *bm = &dev->bm; + + ret = drm_bo_force_list_clean(dev, &bm->unfenced, mem_type, 0, 1); + if (ret) + return ret; + ret = drm_bo_force_list_clean(dev, &bm->lru[mem_type], mem_type, 0, 1); + if (ret) + return ret; + ret = drm_bo_force_list_clean(dev, &bm->pinned[mem_type], mem_type, 0, 1); + return ret; +} + + static int drm_bo_init_mm(drm_device_t *dev, unsigned type, unsigned long p_offset, @@ -1711,20 +1802,6 @@ static int drm_bo_init_mm(drm_device_t *dev, } -/* - * call dev->struct_mutex locked; - */ - -static void drm_bo_release_unfenced(drm_buffer_manager_t *bm) -{ - struct list_head *list, *next; - - list_for_each_safe(list, next, &bm->unfenced) { - list_del(list); - list_add_tail(list, &bm->lru[0]); - } -} - int drm_bo_driver_finish(drm_device_t *dev) { drm_buffer_manager_t *bm = &dev->bm; @@ -1736,7 +1813,6 @@ int drm_bo_driver_finish(drm_device_t *dev) if (!bm->initialized) goto out; - drm_bo_release_unfenced(bm); while(i--) { if (bm->has_type[i]) { @@ -1877,6 +1953,18 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) } bm->max_pages = arg.req.p_size; } + case mm_lock: + LOCK_TEST_WITH_RETURN(dev, filp); + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + ret = drm_bo_lock_mm(dev, arg.req.mem_type); + break; + case mm_unlock: + LOCK_TEST_WITH_RETURN(dev, filp); + mutex_lock(&dev->bm.init_mutex); + mutex_lock(&dev->struct_mutex); + ret = 0; + break; default: DRM_ERROR("Function not implemented yet\n"); return -EINVAL; -- 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(-) 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(-) 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(-) 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. --- libdrm/xf86drm.c | 15 --------------- libdrm/xf86mm.h | 1 - linux-core/drmP.h | 1 - linux-core/drm_bo.c | 27 --------------------------- linux-core/drm_compat.c | 5 ----- shared-core/drm.h | 1 - 6 files changed, 50 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 253ba690..5c799b6d 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3187,21 +3187,6 @@ int drmMMTakedown(int fd, unsigned memType) return 0; } -int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize) -{ - drm_mm_init_arg_t arg; - - - memset(&arg, 0, sizeof(arg)); - arg.req.op = mm_set_max_pages; - arg.req.p_size = maxLockedSize / getpagesize(); - - if (ioctl(fd, DRM_IOCTL_MM_INIT, &arg)) - return -errno; - - return 0; -} - int drmMMLock(int fd, unsigned memType) { drm_mm_init_arg_t arg; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index c3112c90..da868fe5 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -198,7 +198,6 @@ extern int drmBOWaitIdle(int fd, drmBO *buf, unsigned hint); extern int drmMMInit(int fd, unsigned long pOffset, unsigned long pSize, unsigned memType); extern int drmMMTakedown(int fd, unsigned memType); -extern int drmMMMaxLockedSize(int fd, unsigned long maxLockedSize); extern int drmMMLock(int fd, unsigned memType); extern int drmMMUnlock(int fd, unsigned memType); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index b10e9881..fab3608f 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -814,7 +814,6 @@ typedef struct drm_buffer_manager{ struct list_head ddestroy; struct work_struct wq; uint32_t fence_type; - unsigned long max_pages; unsigned long cur_pages; atomic_t count; } drm_buffer_manager_t; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index e8e8a274..b8ee6c15 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -1859,7 +1859,6 @@ int drm_bo_driver_init(drm_device_t * dev) drm_bo_driver_t *driver = dev->driver->bo_driver; drm_buffer_manager_t *bm = &dev->bm; int ret = -EINVAL; - struct sysinfo si; mutex_lock(&dev->bm.init_mutex); mutex_lock(&dev->struct_mutex); @@ -1880,8 +1879,6 @@ int drm_bo_driver_init(drm_device_t * dev) bm->nice_mode = 1; atomic_set(&bm->count, 0); bm->cur_pages = 0; - si_meminfo(&si); - bm->max_pages = si.totalram >> 1; INIT_LIST_HEAD(&bm->unfenced); INIT_LIST_HEAD(&bm->ddestroy); out_unlock: @@ -1944,30 +1941,6 @@ int drm_mm_init_ioctl(DRM_IOCTL_ARGS) "Delaying takedown\n", arg.req.mem_type); } break; - case mm_set_max_pages:{ - struct sysinfo si; - mutex_lock(&dev->bm.init_mutex); - mutex_lock(&dev->struct_mutex); - if (arg.req.p_size < bm->cur_pages) { - DRM_ERROR - ("Cannot currently decrease max number of " - "locked pages below the number currently " - "locked.\n"); - ret = -EINVAL; - break; - } - si_meminfo(&si); - if (arg.req.p_size > si.totalram) { - DRM_ERROR - ("Cannot set max number of locked pages " - "to %lu since the total number of RAM pages " - "is %lu.\n", (unsigned long)arg.req.p_size, - (unsigned long)si.totalram); - ret = -EINVAL; - break; - } - bm->max_pages = arg.req.p_size; - } case mm_lock: LOCK_TEST_WITH_RETURN(dev, filp); mutex_lock(&dev->bm.init_mutex); diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index 4a035f49..90e53419 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -234,11 +234,6 @@ struct page *drm_vm_ttm_nopage(struct vm_area_struct *vma, page = ttm->pages[page_offset]; if (!page) { - if (bm->cur_pages >= bm->max_pages) { - DRM_ERROR("Maximum locked page count exceeded\n"); - page = NOPAGE_OOM; - goto out; - } if (drm_alloc_memctl(PAGE_SIZE)) { page = NOPAGE_OOM; goto out; diff --git a/shared-core/drm.h b/shared-core/drm.h index 915befba..4a6a370e 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -829,7 +829,6 @@ typedef union drm_mm_init_arg{ struct { enum { mm_init, - mm_set_max_pages, mm_takedown, mm_query, mm_lock, -- cgit v1.2.3 From 25fe4a80490bba709099f0401535d2f96ac7729c Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 17 Oct 2006 20:04:41 +0200 Subject: Remove some debugging messages. --- libdrm/xf86drm.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 5c799b6d..9047c8db 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2786,16 +2786,11 @@ int drmBOMap(int fd, drmBO *buf, unsigned mapFlags, unsigned mapHint, fd, buf->mapHandle); if (virtual == MAP_FAILED) { ret = -errno; - fprintf(stderr, "Map error 0x%016llx\n", buf->mapHandle); } if (ret) return ret; buf->mapVirtual = virtual; buf->virtual = ((char *) virtual) + buf->start; -#ifdef BODEBUG - fprintf(stderr,"Mapvirtual, virtual: 0x%08x 0x%08x\n", - buf->mapVirtual, buf->virtual); -#endif } memset(&arg, 0, sizeof(arg)); -- 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(-) 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 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(-) 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(-) 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(-) 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(+) 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(-) 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(-) 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(-) 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(-) 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. --- libdrm/xf86drm.c | 7 +++++-- libdrm/xf86mm.h | 10 +++++++--- linux-core/drmP.h | 2 +- linux-core/drm_bo.c | 8 ++++++-- linux-core/drm_mm.c | 5 ++++- shared-core/drm.h | 2 ++ 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 9047c8db..ebf3f834 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2613,12 +2613,14 @@ static void drmBOCopyReply(const drm_bo_arg_reply_t *rep, buf->start = rep->buffer_start; buf->fenceFlags = rep->fence_flags; buf->replyFlags = rep->rep_flags; + buf->pageAlignment = rep->page_alignment; } -int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, - void *user_buffer, drm_bo_type_t type, unsigned mask, +int drmBOCreate(int fd, unsigned long start, unsigned long size, + unsigned pageAlignment, void *user_buffer, drm_bo_type_t type, + unsigned mask, unsigned hint, drmBO *buf) { drm_bo_arg_t arg; @@ -2632,6 +2634,7 @@ int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, req->hint = hint; req->size = size; req->type = type; + req->page_alignment = pageAlignment; buf->virtual = NULL; diff --git a/libdrm/xf86mm.h b/libdrm/xf86mm.h index da868fe5..bd0d2812 100644 --- a/libdrm/xf86mm.h +++ b/libdrm/xf86mm.h @@ -99,6 +99,7 @@ typedef struct _drmFence{ unsigned type; unsigned flags; unsigned signaled; + unsigned pad[4]; /* for future expansion */ } drmFence; typedef struct _drmBO{ @@ -113,9 +114,11 @@ typedef struct _drmBO{ unsigned long start; unsigned replyFlags; unsigned fenceFlags; + unsigned pageAlignment; void *virtual; void *mapVirtual; int mapCount; + unsigned pad[8]; /* for future expansion */ } drmBO; @@ -168,9 +171,10 @@ extern int drmBOCreateList(int numTarget, drmBOList *list); * Buffer object functions. */ -extern int drmBOCreate(int fd, void *ttm, unsigned long start, unsigned long size, - void *user_buffer, drm_bo_type_t type, unsigned mask, - unsigned hint, drmBO *buf); +extern int drmBOCreate(int fd, unsigned long start, unsigned long size, + unsigned pageAlignment,void *user_buffer, + drm_bo_type_t type, unsigned mask, + unsigned hint, drmBO *buf); extern int drmBODestroy(int fd, drmBO *buf); extern int drmBOReference(int fd, unsigned handle, drmBO *buf); extern int drmBOUnReference(int fd, drmBO *buf); diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 1ed20b09..d02184c7 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -1016,7 +1016,7 @@ typedef struct drm_buffer_object{ unsigned long buffer_start; drm_bo_type_t type; unsigned long offset; - + uint32_t page_alignment; atomic_t mapped; uint32_t flags; uint32_t mask; diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 954b7a03..65e24fb6 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -571,7 +571,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, mutex_lock(&dev->struct_mutex); do { - node = drm_mm_search_free(mm, size, 0, 1); + node = drm_mm_search_free(mm, size, buf->page_alignment, 1); if (node) break; @@ -599,7 +599,7 @@ int drm_bo_alloc_space(drm_buffer_object_t * buf, unsigned mem_type, return -ENOMEM; } - node = drm_mm_get_block(node, size, 0); + node = drm_mm_get_block(node, size, buf->page_alignment); mutex_unlock(&dev->struct_mutex); BUG_ON(!node); node->private = (void *)buf; @@ -959,6 +959,7 @@ static void drm_bo_fill_rep_arg(drm_buffer_object_t * bo, rep->buffer_start = bo->buffer_start; rep->fence_flags = bo->fence_type; rep->rep_flags = 0; + rep->page_alignment = bo->page_alignment; if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, @@ -1387,6 +1388,7 @@ int drm_buffer_object_create(drm_file_t * priv, drm_bo_type_t type, uint32_t mask, uint32_t hint, + uint32_t page_alignment, unsigned long buffer_start, drm_buffer_object_t ** buf_obj) { @@ -1426,6 +1428,7 @@ int drm_buffer_object_create(drm_file_t * priv, bo->num_pages = num_pages; bo->node_card = NULL; bo->node_ttm = NULL; + bo->page_alignment = page_alignment; if (bo->type == drm_bo_type_fake) { bo->offset = buffer_start; bo->buffer_start = 0; @@ -1516,6 +1519,7 @@ int drm_bo_ioctl(DRM_IOCTL_ARGS) req->type, req->mask, req->hint, + req->page_alignment, req->buffer_start, &entry); if (rep.ret) break; diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index dcd55209..a5566b2f 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -147,7 +147,10 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent, drm_mm_node_t *align_splitoff = NULL; drm_mm_node_t *child; - unsigned tmp = size % alignment; + unsigned tmp = 0; + + if (alignment) + tmp = size % alignment; if (tmp) { align_splitoff = drm_mm_split_at_start(parent, alignment - tmp); diff --git a/shared-core/drm.h b/shared-core/drm.h index 5784e59b..330aa3ff 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -770,6 +770,7 @@ typedef struct drm_bo_arg_request { drm_bo_type_t type; unsigned arg_handle; drm_u64_t buffer_start; + unsigned page_alignment; unsigned expand_pad[4]; /*Future expansion */ enum { drm_bo_create, @@ -804,6 +805,7 @@ typedef struct drm_bo_arg_reply { drm_u64_t buffer_start; unsigned fence_flags; unsigned rep_flags; + unsigned page_alignment; unsigned expand_pad[4]; /*Future expansion */ }drm_bo_arg_reply_t; -- cgit v1.2.3 From decacb2e6415029fe87a3680c8f967483ba05281 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Fri, 27 Oct 2006 13:08:31 +0200 Subject: Reserve the new IOCTLs also for *bsd. Bump libdrm version number to 2.2.0 --- configure.ac | 2 +- libdrm/xf86drm.c | 6 +----- shared-core/drm.h | 5 ----- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index b5d79456..224f43a5 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libdrm], 2.1.2-mm, [dri-devel@lists.sourceforge.net], libdrm) +AC_INIT([libdrm], 2.2.0, [dri-devel@lists.sourceforge.net], libdrm) AC_CONFIG_SRCDIR([Makefile.am]) AM_INIT_AUTOMAKE([dist-bzip2]) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index ebf3f834..df41d77a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -717,7 +717,7 @@ drmVersionPtr drmGetLibVersion(int fd) * revision 1.2.x = added drmSetInterfaceVersion * modified drmOpen to handle both busid and name */ - version->version_major = 1; + version->version_major = 2; version->version_minor = 2; version->version_patchlevel = 0; @@ -2257,7 +2257,6 @@ int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, void *data, return 0; } -#ifdef __linux__ /* * Valid flags are @@ -3216,6 +3215,3 @@ int drmMMUnlock(int fd, unsigned memType) return ret; } - - -#endif diff --git a/shared-core/drm.h b/shared-core/drm.h index 330aa3ff..16e86267 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -660,7 +660,6 @@ typedef struct drm_set_version { int drm_dd_minor; } drm_set_version_t; -#ifdef __linux__ #define DRM_FENCE_FLAG_EMIT 0x00000001 #define DRM_FENCE_FLAG_SHAREABLE 0x00000002 @@ -844,8 +843,6 @@ typedef union drm_mm_init_arg{ unsigned expand_pad[8]; /*Future expansion */ } rep; } drm_mm_init_arg_t; -#endif - /** * \name Ioctls Definitions @@ -912,11 +909,9 @@ typedef union drm_mm_init_arg{ #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) -#ifdef __linux__ #define DRM_IOCTL_FENCE DRM_IOWR(0x3b, drm_fence_arg_t) #define DRM_IOCTL_BUFOBJ DRM_IOWR(0x3d, drm_bo_arg_t) #define DRM_IOCTL_MM_INIT DRM_IOWR(0x3e, drm_mm_init_arg_t) -#endif #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t) -- cgit v1.2.3 From 56563c22d658b6dcb7926fd41513618cd46c31a6 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sun, 29 Oct 2006 15:39:11 +0100 Subject: Minor bugfix, indentation and removal of unnused variables. --- libdrm/xf86drm.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index df41d77a..5efb532b 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -2369,14 +2369,14 @@ int drmFenceUpdate(int fd, drmFence *fence) drm_fence_arg_t arg; memset(&arg, 0, sizeof(arg)); - arg.handle = fence->handle; - arg.op = drm_fence_signaled; - if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) - return -errno; - fence->class = arg.class; - fence->type = arg.type; - fence->signaled = arg.signaled; - return 0; + arg.handle = fence->handle; + arg.op = drm_fence_signaled; + if (ioctl(fd, DRM_IOCTL_FENCE, &arg)) + return -errno; + fence->class = arg.class; + fence->type = arg.type; + fence->signaled = arg.signaled; + return 0; } int drmFenceSignaled(int fd, drmFence *fence, unsigned fenceType, @@ -2493,7 +2493,6 @@ void drmBOFreeList(drmBOList *list) { drmBONode *node; drmMMListHead *l; - int ret = 0; l = list->list.next; while(l != &list->list) { @@ -2975,7 +2974,6 @@ int drmAddValidateItem(drmBOList *list, drmBO *buf, unsigned flags, int *newItem) { drmBONode *node, *cur; - unsigned oldFlags, newFlags; drmMMListHead *l; *newItem = 0; @@ -3146,7 +3144,7 @@ int drmBOFenceList(int fd, drmBOList *list, unsigned fenceHandle) return -EFAULT; if (rep->ret) return rep->ret; - drmBOCopyReply(rep, buf); + drmBOCopyReply(rep, node->buf); } return 0; -- 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(-) 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 From 7b6cd95bb6c41653aed78952da0a461bd4791413 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Tue, 31 Oct 2006 10:01:53 +0000 Subject: Fix bug #8839 - a comment --- bsd-core/i915_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bsd-core/i915_drv.c b/bsd-core/i915_drv.c index 269d7b36..d42b2076 100644 --- a/bsd-core/i915_drv.c +++ b/bsd-core/i915_drv.c @@ -1,4 +1,4 @@ -/* i915_drv.c -- ATI Radeon driver -*- linux-c -*- +/* i915_drv.c -- Intel i915 driver -*- linux-c -*- * Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com */ /*- -- cgit v1.2.3 From 584acab6d6103552711bd6b5596ee4ccad305bc2 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 7 Nov 2006 09:36:40 -0800 Subject: Add drm_u64_t typedef on non-linux to fix libdrm build. --- shared-core/drm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared-core/drm.h b/shared-core/drm.h index 16e86267..9efb1dc4 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -139,6 +139,8 @@ typedef unsigned long long drm_u64_t; typedef unsigned int drm_handle_t; #else +#include +typedef u_int64_t drm_u64_t; typedef unsigned long drm_handle_t; /**< To mapped regions */ #endif typedef unsigned int drm_context_t; /**< GLXContext handle */ -- cgit v1.2.3 From 79038751ffe47ed1ce82766e027d98fd2f0e2c6a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 8 Nov 2006 15:08:09 +1100 Subject: libdrm: add support for server side functionality in libdrm This adds APIs to allow the X server to use libdrm from the system rather than its own in-built copy. --- configure.ac | 2 +- libdrm/Makefile.am | 2 +- libdrm/xf86drm.c | 168 +++++++++++++++++++++++++++-------------------------- libdrm/xf86drm.h | 18 ++++++ 4 files changed, 105 insertions(+), 85 deletions(-) diff --git a/configure.ac b/configure.ac index 224f43a5..c0b11b20 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libdrm], 2.2.0, [dri-devel@lists.sourceforge.net], libdrm) +AC_INIT([libdrm], 2.3.0, [dri-devel@lists.sourceforge.net], libdrm) AC_CONFIG_SRCDIR([Makefile.am]) AM_INIT_AUTOMAKE([dist-bzip2]) diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am index 91a7e5dc..e7e07e47 100644 --- a/libdrm/Makefile.am +++ b/libdrm/Makefile.am @@ -20,7 +20,7 @@ libdrm_la_LTLIBRARIES = libdrm.la libdrm_ladir = $(libdir) -libdrm_la_LDFLAGS = -version-number 2:0:0 -no-undefined +libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined AM_CFLAGS = -I$(top_srcdir)/shared-core libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 5efb532b..05b40f7a 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -35,40 +35,25 @@ #include #endif -#ifdef XFree86Server -# include "xf86.h" -# include "xf86_OSproc.h" -# include "drm.h" -# include "xf86_ansic.h" -# define _DRM_MALLOC xalloc -# define _DRM_FREE xfree -# ifndef XFree86LOADER -# include -# endif -#else -# ifdef HAVE_CONFIG_H -# include -# endif -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# define stat_t struct stat -# include -# include -# include -# include -# define _DRM_MALLOC malloc -# define _DRM_FREE free -# include "drm.h" +#ifdef HAVE_CONFIG_H +# include #endif - +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define stat_t struct stat +#include +#include +#include +#include +#include "drm.h" /* Not all systems have MAP_FAILED defined */ #ifndef MAP_FAILED @@ -107,6 +92,13 @@ #define DRM_MSG_VERBOSITY 3 +static drmServerInfoPtr drm_server_info; + +void drmSetServerInfo(drmServerInfoPtr info) +{ + drm_server_info = info; +} + /** * Output a message to stderr. * @@ -115,44 +107,54 @@ * \internal * This function is a wrapper around vfprintf(). */ + +static int drmDebugPrint(const char *format, va_list ap) +{ + return vfprintf(stderr, format, ap); +} + +static int (*drm_debug_print)(const char *format, va_list ap) = drmDebugPrint; + static void drmMsg(const char *format, ...) { va_list ap; - -#ifndef XFree86Server const char *env; - if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) -#endif + if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || drm_server_info) { va_start(ap, format); -#ifdef XFree86Server - xf86VDrvMsgVerb(-1, X_NONE, DRM_MSG_VERBOSITY, format, ap); -#else - vfprintf(stderr, format, ap); -#endif + if (drm_server_info) { + drm_server_info->debug_print(format,ap); + } else { + drm_debug_print(format, ap); + } va_end(ap); } } +void +drmSetDebugMsgFunction(int (*debug_msg_ptr)(const char *format, va_list ap)) +{ + drm_debug_print = debug_msg_ptr; +} + static void *drmHashTable = NULL; /* Context switch callbacks */ -typedef struct drmHashEntry { - int fd; - void (*f)(int, void *, void *); - void *tagTable; -} drmHashEntry; +void *drmGetHashTable(void) +{ + return drmHashTable; +} void *drmMalloc(int size) { void *pt; - if ((pt = _DRM_MALLOC(size))) memset(pt, 0, size); + if ((pt = malloc(size))) memset(pt, 0, size); return pt; } void drmFree(void *pt) { - if (pt) _DRM_FREE(pt); + if (pt) free(pt); } /* drmStrdup can't use strdup(3), since it doesn't call _DRM_MALLOC... */ @@ -163,7 +165,7 @@ static char *drmStrdup(const char *s) if (!s) return NULL; - retval = _DRM_MALLOC(strlen(s)+1); + retval = malloc(strlen(s)+1); if (!retval) return NULL; @@ -182,7 +184,7 @@ static unsigned long drmGetKeyFromFd(int fd) return st.st_rdev; } -static drmHashEntry *drmGetEntry(int fd) +drmHashEntry *drmGetEntry(int fd) { unsigned long key = drmGetKeyFromFd(fd); void *value; @@ -269,21 +271,20 @@ static int drmOpenDevice(long dev, int minor) stat_t st; char buf[64]; int fd; - mode_t devmode = DRM_DEV_MODE; + mode_t devmode = DRM_DEV_MODE, serv_mode; int isroot = !geteuid(); -#if defined(XFree86Server) uid_t user = DRM_DEV_UID; - gid_t group = DRM_DEV_GID; -#endif - + gid_t group = DRM_DEV_GID, serv_group; + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor); drmMsg("drmOpenDevice: node name is %s\n", buf); -#if defined(XFree86Server) - devmode = xf86ConfigDRI.mode ? xf86ConfigDRI.mode : DRM_DEV_MODE; - devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); - group = (xf86ConfigDRI.group >= 0) ? xf86ConfigDRI.group : DRM_DEV_GID; -#endif + if (drm_server_info) { + drm_server_info->get_perms(&serv_group, &serv_mode); + devmode = serv_mode ? serv_mode : DRM_DEV_MODE; + devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); + group = (serv_group >= 0) ? serv_group : DRM_DEV_GID; + } if (stat(DRM_DIR_NAME, &st)) { if (!isroot) return DRM_ERR_NOT_ROOT; @@ -298,10 +299,11 @@ static int drmOpenDevice(long dev, int minor) remove(buf); mknod(buf, S_IFCHR | devmode, dev); } -#if defined(XFree86Server) - chown(buf, user, group); - chmod(buf, devmode); -#endif + + if (drm_server_info) { + chown(buf, user, group); + chmod(buf, devmode); + } fd = open(buf, O_RDWR, 0); drmMsg("drmOpenDevice: open result is %d, (%s)\n", @@ -315,10 +317,10 @@ static int drmOpenDevice(long dev, int minor) if (!isroot) return DRM_ERR_NOT_ROOT; remove(buf); mknod(buf, S_IFCHR | devmode, dev); -#if defined(XFree86Server) - chown(buf, user, group); - chmod(buf, devmode); -#endif + if (drm_server_info) { + chown(buf, user, group); + chmod(buf, devmode); + } } fd = open(buf, O_RDWR, 0); drmMsg("drmOpenDevice: open result is %d, (%s)\n", @@ -456,16 +458,16 @@ static int drmOpenByName(const char *name) char * id; if (!drmAvailable()) { -#if !defined(XFree86Server) + if (!drm_server_info) return -1; -#else + else { /* try to load the kernel module now */ - if (!xf86LoadKernelModule(name)) { - ErrorF("[drm] failed to load kernel module \"%s\"\n", - name); - return -1; + if (!drm_server_info->load_module(name)) { + drmMsg("[drm] failed to load kernel module \"%s\"\n", + name); + return -1; } -#endif + } } /* @@ -547,16 +549,14 @@ static int drmOpenByName(const char *name) */ int drmOpen(const char *name, const char *busid) { -#ifdef XFree86Server - if (!drmAvailable() && name != NULL) { + if (!drmAvailable() && name != NULL && drm_server_info) { /* try to load the kernel */ - if (!xf86LoadKernelModule(name)) { - ErrorF("[drm] failed to load kernel module \"%s\"\n", + if (!drm_server_info->load_module(name)) { + drmMsg("[drm] failed to load kernel module \"%s\"\n", name); return -1; } } -#endif if (busid) { int fd; @@ -710,15 +710,17 @@ drmVersionPtr drmGetLibVersion(int fd) drm_version_t *version = drmMalloc(sizeof(*version)); /* Version history: + * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it * revision 1.0.x = original DRM interface with no drmGetLibVersion * entry point and many drm extensions * revision 1.1.x = added drmCommand entry points for device extensions * added drmGetLibVersion to identify libdrm.a version * revision 1.2.x = added drmSetInterfaceVersion * modified drmOpen to handle both busid and name + * revision 1.3.x = added server + memory manager */ - version->version_major = 2; - version->version_minor = 2; + version->version_major = 1; + version->version_minor = 3; version->version_patchlevel = 0; return (drmVersionPtr)version; diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 86ee7d30..4d9580c4 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -36,6 +36,8 @@ #ifndef _XF86DRM_H_ #define _XF86DRM_H_ +#include +#include #include /* Defaults, if nothing set in xf86config */ @@ -61,6 +63,21 @@ typedef unsigned int drmSize, *drmSizePtr; /**< For mapped regions */ typedef void *drmAddress, **drmAddressPtr; /**< For mapped regions */ +typedef struct _drmServerInfo { + int (*debug_print)(const char *format, va_list ap); + int (*load_module)(const char *name); + void (*get_perms)(gid_t *, mode_t *); +} drmServerInfo, *drmServerInfoPtr; + +typedef struct drmHashEntry { + int fd; + void (*f)(int, void *, void *); + void *tagTable; +} drmHashEntry; + +extern void *drmGetHashTable(void); +extern drmHashEntry *drmGetEntry(int fd); + /** * Driver version information. * @@ -604,6 +621,7 @@ extern int drmScatterGatherFree(int fd, drm_handle_t handle); extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); /* Support routines */ +extern void drmSetServerInfo(drmServerInfoPtr info); extern int drmError(int err, const char *label); extern void *drmMalloc(int size); extern void drmFree(void *pt); -- cgit v1.2.3 From d51e1bb56ca2f7858cdeac6f61a7b747c1e15b1e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 9 Nov 2006 08:55:58 +1100 Subject: libdrm: add drmOpenOnce + drmCloseOnce to libdrm --- libdrm/xf86drm.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ libdrm/xf86drm.h | 3 +++ 2 files changed, 64 insertions(+) diff --git a/libdrm/xf86drm.c b/libdrm/xf86drm.c index 05b40f7a..56450e80 100644 --- a/libdrm/xf86drm.c +++ b/libdrm/xf86drm.c @@ -3215,3 +3215,64 @@ int drmMMUnlock(int fd, unsigned memType) return ret; } + +#define DRM_MAX_FDS 16 +static struct { + char *BusID; + int fd; + int refcount; +} connection[DRM_MAX_FDS]; + +static int nr_fds = 0; + +int drmOpenOnce(void *unused, + const char *BusID, + int *newlyopened) +{ + int i; + int fd; + + for (i = 0; i < nr_fds; i++) + if (strcmp(BusID, connection[i].BusID) == 0) { + connection[i].refcount++; + *newlyopened = 0; + return connection[i].fd; + } + + fd = drmOpen(unused, BusID); + if (fd <= 0 || nr_fds == DRM_MAX_FDS) + return fd; + + connection[nr_fds].BusID = strdup(BusID); + connection[nr_fds].fd = fd; + connection[nr_fds].refcount = 1; + *newlyopened = 1; + + if (0) + fprintf(stderr, "saved connection %d for %s %d\n", + nr_fds, connection[nr_fds].BusID, + strcmp(BusID, connection[nr_fds].BusID)); + + nr_fds++; + + return fd; +} + +void drmCloseOnce(int fd) +{ + int i; + + for (i = 0; i < nr_fds; i++) { + if (fd == connection[i].fd) { + if (--connection[i].refcount == 0) { + drmClose(connection[i].fd); + free(connection[i].BusID); + + if (i < --nr_fds) + connection[i] = connection[nr_fds]; + + return; + } + } + } +} diff --git a/libdrm/xf86drm.h b/libdrm/xf86drm.h index 4d9580c4..34c9ec0e 100644 --- a/libdrm/xf86drm.h +++ b/libdrm/xf86drm.h @@ -655,6 +655,9 @@ extern int drmSLLookupNeighbors(void *l, unsigned long key, unsigned long *prev_key, void **prev_value, unsigned long *next_key, void **next_value); +extern int drmOpenOnce(void *unused, const char *BusID, int *newlyopened); +extern void drmCloseOnce(int fd); + #include "xf86mm.h" #endif -- cgit v1.2.3