From 2140e102f942edf7982cee2a3f00caf234551687 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 1 May 2008 11:39:06 -0700 Subject: checkpoint: rename to GEM and a few more i915 bits. --- linux-core/drm_gem.c | 371 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 linux-core/drm_gem.c (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c new file mode 100644 index 00000000..bd51362e --- /dev/null +++ b/linux-core/drm_gem.c @@ -0,0 +1,371 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 + * THE AUTHORS OR COPYRIGHT HOLDERS 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: + * Eric Anholt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "drmP.h" + +/** @file drm_gem.c + * + * This file provides some of the base ioctls and library routines for + * the graphics memory manager implemented by each device driver. + * + * Because various devices have different requirements in terms of + * synchronization and migration strategies, implementing that is left up to + * the driver, and all that the general API provides should be generic -- + * allocating objects, reading/writing data with the cpu, freeing objects. + * Even there, platform-dependent optimizations for reading/writing data with + * the CPU mean we'll likely hook those out to driver-specific calls. However, + * the DRI2 implementation wants to have at least allocate/mmap be generic. + * + * The goal was to have swap-backed object allocation managed through + * struct file. However, file descriptors as handles to a struct file have + * two major failings: + * - Process limits prevent more than 1024 or so being used at a time by + * default. + * - Inability to allocate high fds will aggravate the X Server's select() + * handling, and likely that of many GL client applications as well. + * + * This led to a plan of using our own integer IDs (called handles, following + * DRM terminology) to mimic fds, and implement the fd syscalls we need as + * ioctls. The objects themselves will still include the struct file so + * that we can transition to fds if the required kernel infrastructure shows + * up at a later data, and as our interface with shmfs for memory allocation. + */ + +static struct drm_gem_object * +drm_gem_object_alloc(struct drm_device *dev, size_t size) +{ + struct drm_gem_object *obj; + + BUG_ON((size & (PAGE_SIZE - 1)) != 0); + + obj = kcalloc(1, sizeof(*obj), GFP_KERNEL); + + obj->filp = shmem_file_setup("drm mm object", size, 0); + if (IS_ERR(obj->filp)) { + kfree(obj); + return NULL; + } + + obj->refcount = 1; + + if (dev->driver->gem_init_object != NULL && + dev->driver->gem_init_object(dev, obj) != 0) { + fput(obj->filp); + kfree(obj); + return NULL; + } + return obj; +} + +/** + * Removes the mapping from handle to filp for this object. + */ +static int +drm_gem_handle_delete(struct drm_device *dev, struct drm_file *filp, + int handle) +{ + struct drm_gem_object *obj; + + /* This is gross. The idr system doesn't let us try a delete and + * return an error code. It just spews if you fail at deleting. + * So, we have to grab a lock around finding the object and then + * doing the delete on it and dropping the refcount, or the user + * could race us to double-decrement the refcount and cause a + * use-after-free later. Given the frequency of our handle lookups, + * we may want to use ida for number allocation and a hash table + * for the pointers, anyway. + */ + spin_lock(&filp->table_lock); + + /* Check if we currently have a reference on the object */ + obj = idr_find(&filp->object_idr, handle); + if (obj == NULL) { + spin_unlock(&filp->table_lock); + return -EINVAL; + } + + /* Release reference and decrement refcount. */ + idr_remove(&filp->object_idr, handle); + drm_gem_object_unreference(dev, obj); + + spin_unlock(&filp->table_lock); + + return 0; +} + +/** Returns a reference to the object named by the handle. */ +static struct drm_gem_object * +drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, + int handle) +{ + struct drm_gem_object *obj; + + spin_lock(&filp->table_lock); + + /* Check if we currently have a reference on the object */ + obj = idr_find(&filp->object_idr, handle); + if (obj == NULL) { + spin_unlock(&filp->table_lock); + return NULL; + } + + drm_gem_object_reference(dev, obj); + + spin_unlock(&filp->table_lock); + + return obj; +} + + +/** + * Allocates a new mm object and returns a handle to it. + */ +int +drm_gem_alloc_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_alloc_args *args = data; + struct drm_gem_object *obj; + int handle, ret; + + /* Round requested size up to page size */ + args->size = (args->size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + + /* Allocate the new object */ + obj = drm_gem_object_alloc(dev, args->size); + if (obj == NULL) + return -ENOMEM; + + /* Get the user-visible handle using idr. + * + * I'm not really sure why the idr api needs us to do this in two + * repeating steps. It handles internal locking of its data + * structure, yet insists that we keep its memory allocation step + * separate from its slot-finding step for locking purposes. + */ + do { + if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) { + kfree(obj); + return -EFAULT; + } + + ret = idr_get_new(&file_priv->object_idr, obj, &handle); + } while (ret == -EAGAIN); + + if (ret != 0) { + drm_gem_object_unreference(dev, obj); + return -EFAULT; + } + + args->handle = handle; + + return 0; +} + +/** + * Releases the handle to an mm object. + */ +int +drm_gem_unreference_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_unreference_args *args = data; + int ret; + + ret = drm_gem_handle_delete(dev, file_priv, args->handle); + + return ret; +} + +/** + * Reads data from the object referenced by handle. + * + * On error, the contents of *data are undefined. + */ +int +drm_gem_pread_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_pread_args *args = data; + struct drm_gem_object *obj; + ssize_t read; + loff_t offset; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + offset = args->offset; + + read = obj->filp->f_op->read(obj->filp, (char __user *)args->data, + args->size, &offset); + if (read != args->size) { + drm_gem_object_unreference(dev, obj); + if (read < 0) + return read; + else + return -EINVAL; + } + + drm_gem_object_unreference(dev, obj); + + return 0; +} + +/** + * Maps the contents of an object, returning the address it is mapped + * into. + * + * While the mapping holds a reference on the contents of the object, it doesn't + * imply a ref on the object itself. + */ +int +drm_gem_mmap_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_mmap_args *args = data; + struct drm_gem_object *obj; + loff_t offset; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + offset = args->offset; + + down_write(¤t->mm->mmap_sem); + args->addr = (void *)do_mmap(obj->filp, 0, args->size, + PROT_READ | PROT_WRITE, MAP_SHARED, + args->offset); + up_write(¤t->mm->mmap_sem); + + drm_gem_object_unreference(dev, obj); + + return 0; +} + +/** + * Writes data to the object referenced by handle. + * + * On error, the contents of the buffer that were to be modified are undefined. + */ +int +drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_pwrite_args *args = data; + struct drm_gem_object *obj; + ssize_t written; + loff_t offset; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + offset = args->offset; + + written = obj->filp->f_op->write(obj->filp, (char __user *)args->data, + args->size, &offset); + if (written != args->size) { + drm_gem_object_unreference(dev, obj); + if (written < 0) + return written; + else + return -EINVAL; + } + + drm_gem_object_unreference(dev, obj); + + return 0; +} + +/** + * Called at device open time, sets up the structure for handling refcounting + * of mm objects. + */ +void +drm_gem_open(struct drm_device *dev, struct drm_file *file_private) +{ + idr_init(&file_private->object_idr); +} + +/** Called at device close to release the file's references on objects. */ +static int +drm_gem_object_release(int id, void *ptr, void *data) +{ + struct drm_device *dev = data; + struct drm_gem_object *obj = ptr; + + drm_gem_object_unreference(dev, obj); + + return 0; +} + +/** + * Called at close time when the filp is going away. + * + * Releases any remaining references on objects by this filp. + */ +void +drm_gem_release(struct drm_device *dev, struct drm_file *file_private) +{ + idr_for_each(&file_private->object_idr, &drm_gem_object_release, dev); + + idr_destroy(&file_private->object_idr); +} + +void +drm_gem_object_reference(struct drm_device *dev, struct drm_gem_object *obj) +{ + spin_lock(&obj->lock); + obj->refcount++; + spin_unlock(&obj->lock); +} + +void +drm_gem_object_unreference(struct drm_device *dev, struct drm_gem_object *obj) +{ + spin_lock(&obj->lock); + obj->refcount--; + spin_unlock(&obj->lock); + if (obj->refcount == 0) { + if (dev->driver->gem_free_object != NULL) + dev->driver->gem_free_object(dev, obj); + + fput(obj->filp); + kfree(obj); + } +} -- cgit v1.2.3 From 5af87acbc2025b9f72d51b30f176e9c3909695ac Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 1 May 2008 14:20:44 -0700 Subject: checkpoint: gtt binding written. --- linux-core/drm_gem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index bd51362e..def526f0 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -127,7 +127,7 @@ drm_gem_handle_delete(struct drm_device *dev, struct drm_file *filp, } /** Returns a reference to the object named by the handle. */ -static struct drm_gem_object * +struct drm_gem_object * drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, int handle) { @@ -358,6 +358,9 @@ drm_gem_object_reference(struct drm_device *dev, struct drm_gem_object *obj) void drm_gem_object_unreference(struct drm_device *dev, struct drm_gem_object *obj) { + if (obj == NULL) + return; + spin_lock(&obj->lock); obj->refcount--; spin_unlock(&obj->lock); -- cgit v1.2.3 From ccd1bae0f676490a88240c62f02e072d2cf3b030 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 1 May 2008 15:22:21 -0700 Subject: checkpoint: relocations support. --- linux-core/drm_gem.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index def526f0..09c0fe85 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -148,7 +148,7 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, return obj; } - +EXPORT_SYMBOL(drm_gem_object_lookup); /** * Allocates a new mm object and returns a handle to it. @@ -354,6 +354,7 @@ drm_gem_object_reference(struct drm_device *dev, struct drm_gem_object *obj) obj->refcount++; spin_unlock(&obj->lock); } +EXPORT_SYMBOL(drm_gem_object_reference); void drm_gem_object_unreference(struct drm_device *dev, struct drm_gem_object *obj) @@ -372,3 +373,4 @@ drm_gem_object_unreference(struct drm_device *dev, struct drm_gem_object *obj) kfree(obj); } } +EXPORT_SYMBOL(drm_gem_object_unreference); -- cgit v1.2.3 From d2529d13961f0df00754393e1ad9b72da5e998a4 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 1 May 2008 16:27:03 -0700 Subject: Remove _args from gem ioctl argument structure tags. --- linux-core/drm_gem.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 09c0fe85..7326d6bb 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -157,7 +157,7 @@ int drm_gem_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_gem_alloc_args *args = data; + struct drm_gem_alloc *args = data; struct drm_gem_object *obj; int handle, ret; @@ -202,7 +202,7 @@ int drm_gem_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_gem_unreference_args *args = data; + struct drm_gem_unreference *args = data; int ret; ret = drm_gem_handle_delete(dev, file_priv, args->handle); @@ -219,7 +219,7 @@ int drm_gem_pread_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_gem_pread_args *args = data; + struct drm_gem_pread *args = data; struct drm_gem_object *obj; ssize_t read; loff_t offset; @@ -256,7 +256,7 @@ int drm_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_gem_mmap_args *args = data; + struct drm_gem_mmap *args = data; struct drm_gem_object *obj; loff_t offset; @@ -286,7 +286,7 @@ int drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_gem_pwrite_args *args = data; + struct drm_gem_pwrite *args = data; struct drm_gem_object *obj; ssize_t written; loff_t offset; -- cgit v1.2.3 From 7d5f783eca3302ec7efa164e2980c75e5e591585 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 1 May 2008 16:38:37 -0700 Subject: Make GEM object handles be nonzero. --- linux-core/drm_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 7326d6bb..f6038d5c 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -182,7 +182,8 @@ drm_gem_alloc_ioctl(struct drm_device *dev, void *data, return -EFAULT; } - ret = idr_get_new(&file_priv->object_idr, obj, &handle); + ret = idr_get_new_above(&file_priv->object_idr, obj, 1, + &handle); } while (ret == -EAGAIN); if (ret != 0) { -- cgit v1.2.3 From 3f641b56c79d48f7e11aa3eb1dc678e09c8e01f7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 1 May 2008 16:48:25 -0700 Subject: Fix missing member settings in obj/obj_priv, and some error paths. --- linux-core/drm_gem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index f6038d5c..ee3dbe47 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -80,6 +80,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) } obj->refcount = 1; + obj->size = size; if (dev->driver->gem_init_object != NULL && dev->driver->gem_init_object(dev, obj) != 0) { -- cgit v1.2.3 From abc896638fdcd8ccb457ad7b43dbe7ad229ba501 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 1 May 2008 20:12:39 -0700 Subject: Use krefs for refcounting. krefs are way easier than a custom-coded spinlock+int combo. --- linux-core/drm_gem.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index ee3dbe47..d39585e9 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -73,13 +73,14 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) obj = kcalloc(1, sizeof(*obj), GFP_KERNEL); + obj->dev = dev; obj->filp = shmem_file_setup("drm mm object", size, 0); if (IS_ERR(obj->filp)) { kfree(obj); return NULL; } - obj->refcount = 1; + kref_init (&obj->refcount); obj->size = size; if (dev->driver->gem_init_object != NULL && @@ -352,27 +353,29 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private) void drm_gem_object_reference(struct drm_device *dev, struct drm_gem_object *obj) { - spin_lock(&obj->lock); - obj->refcount++; - spin_unlock(&obj->lock); + kref_get(&obj->refcount); } EXPORT_SYMBOL(drm_gem_object_reference); +static void +drm_gem_object_free (struct kref *kref) +{ + struct drm_gem_object *obj = (struct drm_gem_object *) kref; + struct drm_device *dev = obj->dev; + + if (dev->driver->gem_free_object != NULL) + dev->driver->gem_free_object(dev, obj); + + fput(obj->filp); + kfree(obj); +} + void drm_gem_object_unreference(struct drm_device *dev, struct drm_gem_object *obj) { if (obj == NULL) return; - spin_lock(&obj->lock); - obj->refcount--; - spin_unlock(&obj->lock); - if (obj->refcount == 0) { - if (dev->driver->gem_free_object != NULL) - dev->driver->gem_free_object(dev, obj); - - fput(obj->filp); - kfree(obj); - } + kref_put (&obj->refcount, drm_gem_object_free); } EXPORT_SYMBOL(drm_gem_object_unreference); -- cgit v1.2.3 From 30efad5113944681c1abd6452e10355c105e9c39 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 1 May 2008 20:31:16 -0700 Subject: Fix gem ioctls to be 32/64-bit clean. mixed 32/64 bit systems need 'special' help for ioctl where the user-space and kernel-space datatypes differ. Fixing the datatypes to be the same size, and align the same way for both 32 and 64-bit ppc and x86 environments will elimiante the need to have magic 32/64-bit ioctl translation code. --- linux-core/drm_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index d39585e9..41976bc7 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -233,7 +233,7 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, offset = args->offset; - read = obj->filp->f_op->read(obj->filp, (char __user *)args->data, + read = obj->filp->f_op->read(obj->filp, (char __user *)(uintptr_t)args->data_ptr, args->size, &offset); if (read != args->size) { drm_gem_object_unreference(dev, obj); @@ -270,7 +270,7 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, offset = args->offset; down_write(¤t->mm->mmap_sem); - args->addr = (void *)do_mmap(obj->filp, 0, args->size, + args->addr_ptr = (uint64_t) do_mmap(obj->filp, 0, args->size, PROT_READ | PROT_WRITE, MAP_SHARED, args->offset); up_write(¤t->mm->mmap_sem); @@ -300,7 +300,7 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, offset = args->offset; - written = obj->filp->f_op->write(obj->filp, (char __user *)args->data, + written = obj->filp->f_op->write(obj->filp, (char __user *)args->data_ptr, args->size, &offset); if (written != args->size) { drm_gem_object_unreference(dev, obj); -- cgit v1.2.3 From 49e8e3372afcf5fab9ffef5691d87ad8bc19599a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 2 May 2008 10:36:00 -0700 Subject: Remove drm_driver argument to functions taking drm_gem_object. Now that drm_gem_object has a drm_driver * in it, functions don't need both parameters. --- linux-core/drm_gem.c | 45 ++++++++++++++------------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 41976bc7..80e8657b 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -84,7 +84,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) obj->size = size; if (dev->driver->gem_init_object != NULL && - dev->driver->gem_init_object(dev, obj) != 0) { + dev->driver->gem_init_object(obj) != 0) { fput(obj->filp); kfree(obj); return NULL; @@ -121,7 +121,7 @@ drm_gem_handle_delete(struct drm_device *dev, struct drm_file *filp, /* Release reference and decrement refcount. */ idr_remove(&filp->object_idr, handle); - drm_gem_object_unreference(dev, obj); + drm_gem_object_unreference(obj); spin_unlock(&filp->table_lock); @@ -144,7 +144,7 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, return NULL; } - drm_gem_object_reference(dev, obj); + drm_gem_object_reference(obj); spin_unlock(&filp->table_lock); @@ -189,7 +189,7 @@ drm_gem_alloc_ioctl(struct drm_device *dev, void *data, } while (ret == -EAGAIN); if (ret != 0) { - drm_gem_object_unreference(dev, obj); + drm_gem_object_unreference(obj); return -EFAULT; } @@ -236,14 +236,14 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, read = obj->filp->f_op->read(obj->filp, (char __user *)(uintptr_t)args->data_ptr, args->size, &offset); if (read != args->size) { - drm_gem_object_unreference(dev, obj); + drm_gem_object_unreference(obj); if (read < 0) return read; else return -EINVAL; } - drm_gem_object_unreference(dev, obj); + drm_gem_object_unreference(obj); return 0; } @@ -275,7 +275,7 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, args->offset); up_write(¤t->mm->mmap_sem); - drm_gem_object_unreference(dev, obj); + drm_gem_object_unreference(obj); return 0; } @@ -300,17 +300,17 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, offset = args->offset; - written = obj->filp->f_op->write(obj->filp, (char __user *)args->data_ptr, + written = obj->filp->f_op->write(obj->filp, (char __user *)(uintptr_t) args->data_ptr, args->size, &offset); if (written != args->size) { - drm_gem_object_unreference(dev, obj); + drm_gem_object_unreference(obj); if (written < 0) return written; else return -EINVAL; } - drm_gem_object_unreference(dev, obj); + drm_gem_object_unreference(obj); return 0; } @@ -329,10 +329,9 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private) static int drm_gem_object_release(int id, void *ptr, void *data) { - struct drm_device *dev = data; struct drm_gem_object *obj = ptr; - drm_gem_object_unreference(dev, obj); + drm_gem_object_unreference(obj); return 0; } @@ -345,37 +344,21 @@ drm_gem_object_release(int id, void *ptr, void *data) void drm_gem_release(struct drm_device *dev, struct drm_file *file_private) { - idr_for_each(&file_private->object_idr, &drm_gem_object_release, dev); + idr_for_each(&file_private->object_idr, &drm_gem_object_release, NULL); idr_destroy(&file_private->object_idr); } void -drm_gem_object_reference(struct drm_device *dev, struct drm_gem_object *obj) -{ - kref_get(&obj->refcount); -} -EXPORT_SYMBOL(drm_gem_object_reference); - -static void drm_gem_object_free (struct kref *kref) { struct drm_gem_object *obj = (struct drm_gem_object *) kref; struct drm_device *dev = obj->dev; if (dev->driver->gem_free_object != NULL) - dev->driver->gem_free_object(dev, obj); + dev->driver->gem_free_object(obj); fput(obj->filp); kfree(obj); } - -void -drm_gem_object_unreference(struct drm_device *dev, struct drm_gem_object *obj) -{ - if (obj == NULL) - return; - - kref_put (&obj->refcount, drm_gem_object_free); -} -EXPORT_SYMBOL(drm_gem_object_unreference); +EXPORT_SYMBOL(drm_gem_object_free); -- cgit v1.2.3 From 39e20bcd5f4bf9fedac80188fda2e9fcab2f0360 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 2 May 2008 12:28:49 -0700 Subject: Add name/open ioctls, separate handle and pointer ref counts. Names are just another unique integer set (from another idr object). Names are removed when the user refernces (handles) are all destroyed -- this required that handles for objects be counted separately from internal kernel references (so that we can tell when the handles are all gone). --- linux-core/drm_gem.c | 193 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 164 insertions(+), 29 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 80e8657b..2e963f20 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -81,6 +81,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) } kref_init (&obj->refcount); + kref_init (&obj->handlecount); obj->size = size; if (dev->driver->gem_init_object != NULL && @@ -96,8 +97,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) * Removes the mapping from handle to filp for this object. */ static int -drm_gem_handle_delete(struct drm_device *dev, struct drm_file *filp, - int handle) +drm_gem_handle_delete(struct drm_file *filp, int handle) { struct drm_gem_object *obj; @@ -121,10 +121,45 @@ drm_gem_handle_delete(struct drm_device *dev, struct drm_file *filp, /* Release reference and decrement refcount. */ idr_remove(&filp->object_idr, handle); - drm_gem_object_unreference(obj); - spin_unlock(&filp->table_lock); + drm_gem_object_handle_unreference(obj); + + return 0; +} + +/** + * Create a handle for this object. This adds a handle reference + * to the object, which includes a regular reference count. Callers + * will likely want to dereference the object afterwards. + */ +static int +drm_gem_handle_create (struct drm_file *file_priv, + struct drm_gem_object *obj, + int *handlep) +{ + int ret; + + /* + * Get the user-visible handle using idr. + */ +again: + /* ensure there is space available to allocate a handle */ + if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) { + kfree(obj); + return -ENOMEM; + } + /* do the allocation under our spinlock */ + spin_lock (&file_priv->table_lock); + ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep); + spin_unlock (&file_priv->table_lock); + if (ret == -EAGAIN) + goto again; + + if (ret != 0) + return ret; + + drm_gem_object_handle_reference (obj); return 0; } @@ -171,27 +206,11 @@ drm_gem_alloc_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -ENOMEM; - /* Get the user-visible handle using idr. - * - * I'm not really sure why the idr api needs us to do this in two - * repeating steps. It handles internal locking of its data - * structure, yet insists that we keep its memory allocation step - * separate from its slot-finding step for locking purposes. - */ - do { - if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) { - kfree(obj); - return -EFAULT; - } + ret = drm_gem_handle_create (file_priv, obj, &handle); + drm_gem_object_handle_unreference(obj); - ret = idr_get_new_above(&file_priv->object_idr, obj, 1, - &handle); - } while (ret == -EAGAIN); - - if (ret != 0) { - drm_gem_object_unreference(obj); - return -EFAULT; - } + if (ret) + return ret; args->handle = handle; @@ -208,7 +227,7 @@ drm_gem_unreference_ioctl(struct drm_device *dev, void *data, struct drm_gem_unreference *args = data; int ret; - ret = drm_gem_handle_delete(dev, file_priv, args->handle); + ret = drm_gem_handle_delete(file_priv, args->handle); return ret; } @@ -315,6 +334,87 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, return 0; } +/** + * Create a global name for an object, returning the name. + * + * Note that the name does not hold a reference; when the object + * is freed, the name goes away. + */ +int +drm_gem_name_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_name *args = data; + struct drm_gem_object *obj; + int ret; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + +again: + if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) { + return -ENOMEM; + } + spin_lock(&dev->object_name_lock); + if (obj->name) { + spin_unlock (&dev->object_name_lock); + return -EEXIST; + } + ret = idr_get_new_above (&dev->object_name_idr, obj, 1, + &obj->name); + spin_unlock (&dev->object_name_lock); + if (ret == -EAGAIN) + goto again; + + if (ret != 0) { + drm_gem_object_unreference(obj); + return ret; + } + + /* + * Leave the reference from the lookup around as the + * name table now holds one + */ + args->name = (uint64_t) obj->name; + + return 0; +} + +/** + * Open an object using the global name, returning a handle and the size. + * + * This handle (of course) holds a reference to the object, so the object + * will not go away until the handle is deleted. + */ +int +drm_gem_open_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_open *args = data; + struct drm_gem_object *obj; + int ret; + int handle; + + spin_lock (&dev->object_name_lock); + obj = idr_find (&dev->object_name_idr, (int) args->name); + if (obj) + drm_gem_object_reference (obj); + spin_unlock (&dev->object_name_lock); + if (!obj) + return -ENOENT; + + ret = drm_gem_handle_create (file_priv, obj, &handle); + drm_gem_object_unreference (obj); + if (ret) + return ret; + + args->handle = handle; + args->size = obj->size; + + return 0; +} + /** * Called at device open time, sets up the structure for handling refcounting * of mm objects. @@ -325,13 +425,13 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private) idr_init(&file_private->object_idr); } -/** Called at device close to release the file's references on objects. */ +/** Called at device close to release the file's handle references on objects. */ static int -drm_gem_object_release(int id, void *ptr, void *data) +drm_gem_object_release_handle (int id, void *ptr, void *data) { struct drm_gem_object *obj = ptr; - drm_gem_object_unreference(obj); + drm_gem_object_handle_unreference(obj); return 0; } @@ -344,11 +444,16 @@ drm_gem_object_release(int id, void *ptr, void *data) void drm_gem_release(struct drm_device *dev, struct drm_file *file_private) { - idr_for_each(&file_private->object_idr, &drm_gem_object_release, NULL); + idr_for_each(&file_private->object_idr, &drm_gem_object_release_handle, NULL); idr_destroy(&file_private->object_idr); } +/** + * Called after the last reference to the object has been lost. + * + * Frees the object + */ void drm_gem_object_free (struct kref *kref) { @@ -359,6 +464,36 @@ drm_gem_object_free (struct kref *kref) dev->driver->gem_free_object(obj); fput(obj->filp); + kfree(obj); } EXPORT_SYMBOL(drm_gem_object_free); + +/** + * Called after the last handle to the object has been closed + * + * Removes any name for the object. Note that this must be + * called before drm_gem_object_free or we'll be touching + * freed memory + */ +void +drm_gem_object_handle_free (struct kref *kref) +{ + struct drm_gem_object *obj = container_of (kref, struct drm_gem_object, handlecount); + struct drm_device *dev = obj->dev; + + /* Remove any name for this object */ + spin_lock (&dev->object_name_lock); + if (obj->name) { + idr_remove (&dev->object_name_idr, obj->name); + spin_unlock (&dev->object_name_lock); + /* + * The object name held a reference to this object, drop + * that now. + */ + drm_gem_object_unreference (obj); + } else + spin_unlock (&dev->object_name_lock); + +} +EXPORT_SYMBOL(drm_gem_object_handle_free); -- cgit v1.2.3 From ab3549d1336fc6c08581a9fd14a83513649d9187 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 2 May 2008 16:34:16 -0700 Subject: Add a bit of /proc/dri/*/gem support. Clean up some refcount/pagelock issues. Track named objects in /proc/dri/0/gem_names. Track total object count in /proc/dri/0/gem_objects. Initialize device gem data. return -ENODEV for gem ioctls if the driver doesn't support gem. Call unlock_page when unbinding from gtt. Add numerous misssing calls to drm_gem_object_unreference. --- linux-core/drm_gem.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 2e963f20..db12f9a6 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -64,6 +64,22 @@ * up at a later data, and as our interface with shmfs for memory allocation. */ +/** + * Initialize the GEM device fields + */ + +int +drm_gem_init (struct drm_device *dev) +{ + spin_lock_init (&dev->object_name_lock); + idr_init (&dev->object_name_idr); + atomic_set (&dev->object_count, 0); + return 0; +} + +/** + * Allocate a GEM object of the specified size with shmfs backing store + */ static struct drm_gem_object * drm_gem_object_alloc(struct drm_device *dev, size_t size) { @@ -90,6 +106,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) kfree(obj); return NULL; } + atomic_inc (&dev->object_count); return obj; } @@ -145,10 +162,9 @@ drm_gem_handle_create (struct drm_file *file_priv, */ again: /* ensure there is space available to allocate a handle */ - if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) { - kfree(obj); + if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0) return -ENOMEM; - } + /* do the allocation under our spinlock */ spin_lock (&file_priv->table_lock); ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep); @@ -198,6 +214,9 @@ drm_gem_alloc_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; int handle, ret; + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + /* Round requested size up to page size */ args->size = (args->size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); @@ -227,6 +246,9 @@ drm_gem_unreference_ioctl(struct drm_device *dev, void *data, struct drm_gem_unreference *args = data; int ret; + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + ret = drm_gem_handle_delete(file_priv, args->handle); return ret; @@ -246,6 +268,9 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, ssize_t read; loff_t offset; + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) return -EINVAL; @@ -282,6 +307,9 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; loff_t offset; + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) return -EINVAL; @@ -313,6 +341,9 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, ssize_t written; loff_t offset; + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) return -EINVAL; @@ -348,6 +379,9 @@ drm_gem_name_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; int ret; + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) return -EINVAL; @@ -396,6 +430,9 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, int ret; int handle; + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + spin_lock (&dev->object_name_lock); obj = idr_find (&dev->object_name_idr, (int) args->name); if (obj) @@ -423,6 +460,7 @@ void drm_gem_open(struct drm_device *dev, struct drm_file *file_private) { idr_init(&file_private->object_idr); + spin_lock_init (&file_private->table_lock); } /** Called at device close to release the file's handle references on objects. */ @@ -464,7 +502,7 @@ drm_gem_object_free (struct kref *kref) dev->driver->gem_free_object(obj); fput(obj->filp); - + atomic_dec (&dev->object_count); kfree(obj); } EXPORT_SYMBOL(drm_gem_object_free); -- cgit v1.2.3 From 5f0614b86ff5760016bef87c6f6012fe4f42e14e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 2 May 2008 17:13:11 -0700 Subject: Check for do_mmap errors --- linux-core/drm_gem.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index db12f9a6..80d5a350 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -306,6 +306,7 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, struct drm_gem_mmap *args = data; struct drm_gem_object *obj; loff_t offset; + unsigned long addr; if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; @@ -317,12 +318,15 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, offset = args->offset; down_write(¤t->mm->mmap_sem); - args->addr_ptr = (uint64_t) do_mmap(obj->filp, 0, args->size, - PROT_READ | PROT_WRITE, MAP_SHARED, - args->offset); + addr = do_mmap(obj->filp, 0, args->size, + PROT_READ | PROT_WRITE, MAP_SHARED, + args->offset); up_write(¤t->mm->mmap_sem); - drm_gem_object_unreference(obj); + if (IS_ERR((void *)addr)) + return (int) addr; + + args->addr_ptr = (uint64_t) addr; return 0; } -- cgit v1.2.3 From 631e86c5c4ad9b2cdd40749ea3b351204a362c80 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 6 May 2008 14:43:49 -0700 Subject: Start coding up memory domains --- linux-core/drm_gem.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 80d5a350..929c008f 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -539,3 +539,41 @@ drm_gem_object_handle_free (struct kref *kref) } EXPORT_SYMBOL(drm_gem_object_handle_free); + +/* + * Set the next domain for the specified object. This + * may not actually perform the necessary flushing/invaliding though, + * as that may want to be batched with other set_domain operations + */ +int drm_gem_object_set_domain (struct drm_gem_object *obj, + uint32_t read_domains, + uint32_t write_domain) +{ + struct drm_device *dev = obj->dev; + uint32_t invalidate_domains = 0; + uint32_t flush_domains = 0; + + /* + * Flush the current write domain if + * the new read domains don't match. Invalidate + * any read domains which differ from the old + * write domain + */ + if (obj->write_domain && obj->write_domain != read_domains) + { + flush_domains |= obj->write_domain; + invalidate_domains |= read_domains & ~obj->write_domain; + } + /* + * Invalidate any read caches which may have + * stale data. That is, any new read domains. + */ + invalidate_domains |= read_domains & ~obj->read_domains; + obj->write_domain = write_domain; + obj->read_domain = read_domains; + if ((flush_domains | invalidate_domains) & DRM_GEM_DOMAIN_CPU) + drm_gem_object_clflush (obj); + dev->invalidate_domains |= invalidate_domains & ~DRM_GEM_DOMAIN_CPU; + dev->flush_domains |= flush_domains & ~DRM_GEM_DOMAIN_CPU; +} +EXPORT_SYMBOL(drm_gem_object_set_domain); -- cgit v1.2.3 From 61253f4f677518537368103799c9510b8b5ad1e3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 6 May 2008 20:00:23 -0700 Subject: [intel-GEM] Add memory domain support. Memory domains allow the kernel to track which caches to flush and how to move objects before buffer execution. --- linux-core/drm_gem.c | 41 ++++------------------------------------- 1 file changed, 4 insertions(+), 37 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 929c008f..e2272f27 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -325,6 +325,10 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference(obj); if (IS_ERR((void *)addr)) return (int) addr; + + /* XXX hack until we have a driver callback to make this work */ + obj->read_domains = DRM_GEM_DOMAIN_CPU; + obj->write_domain = DRM_GEM_DOMAIN_CPU; args->addr_ptr = (uint64_t) addr; @@ -540,40 +544,3 @@ drm_gem_object_handle_free (struct kref *kref) } EXPORT_SYMBOL(drm_gem_object_handle_free); -/* - * Set the next domain for the specified object. This - * may not actually perform the necessary flushing/invaliding though, - * as that may want to be batched with other set_domain operations - */ -int drm_gem_object_set_domain (struct drm_gem_object *obj, - uint32_t read_domains, - uint32_t write_domain) -{ - struct drm_device *dev = obj->dev; - uint32_t invalidate_domains = 0; - uint32_t flush_domains = 0; - - /* - * Flush the current write domain if - * the new read domains don't match. Invalidate - * any read domains which differ from the old - * write domain - */ - if (obj->write_domain && obj->write_domain != read_domains) - { - flush_domains |= obj->write_domain; - invalidate_domains |= read_domains & ~obj->write_domain; - } - /* - * Invalidate any read caches which may have - * stale data. That is, any new read domains. - */ - invalidate_domains |= read_domains & ~obj->read_domains; - obj->write_domain = write_domain; - obj->read_domain = read_domains; - if ((flush_domains | invalidate_domains) & DRM_GEM_DOMAIN_CPU) - drm_gem_object_clflush (obj); - dev->invalidate_domains |= invalidate_domains & ~DRM_GEM_DOMAIN_CPU; - dev->flush_domains |= flush_domains & ~DRM_GEM_DOMAIN_CPU; -} -EXPORT_SYMBOL(drm_gem_object_set_domain); -- cgit v1.2.3 From aa0621a19ffcdf2a92eac08fa4950e0423a8dd2b Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Wed, 7 May 2008 15:54:32 -0700 Subject: Apply a few stylistic cleanups to match kernel code. --- linux-core/drm_gem.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index e2272f27..4eaeffcf 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -217,8 +217,7 @@ drm_gem_alloc_ioctl(struct drm_device *dev, void *data, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; - /* Round requested size up to page size */ - args->size = (args->size + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + args->size = roundup(args->size, PAGE_SIZE); /* Allocate the new object */ obj = drm_gem_object_alloc(dev, args->size); @@ -277,8 +276,8 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, offset = args->offset; - read = obj->filp->f_op->read(obj->filp, (char __user *)(uintptr_t)args->data_ptr, - args->size, &offset); + read = vfs_read(obj->filp, (char __user *)(uintptr_t)args->data_ptr, + args->size, &offset); if (read != args->size) { drm_gem_object_unreference(obj); if (read < 0) @@ -324,7 +323,7 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, up_write(¤t->mm->mmap_sem); drm_gem_object_unreference(obj); if (IS_ERR((void *)addr)) - return (int) addr; + return addr; /* XXX hack until we have a driver callback to make this work */ obj->read_domains = DRM_GEM_DOMAIN_CPU; @@ -358,8 +357,9 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, offset = args->offset; - written = obj->filp->f_op->write(obj->filp, (char __user *)(uintptr_t) args->data_ptr, - args->size, &offset); + written = vfs_write(obj->filp, + (char __user *)(uintptr_t) args->data_ptr, + args->size, &offset); if (written != args->size) { drm_gem_object_unreference(obj); if (written < 0) -- cgit v1.2.3 From 9af4c497433398fa4576a7c1c31036448cf4f24c Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 8 May 2008 10:44:02 -0700 Subject: [intel-gem] Move domains to relocation records. add set_domain ioctl. Domain information is about buffer relationships, not buffer contents. That means a relocation contains the domain information as it knows how the source buffer references the target buffer. This also adds the set_domain ioctl so that user space can move buffers to the cpu domain. --- linux-core/drm_gem.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 4eaeffcf..3673c933 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -325,10 +325,6 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, if (IS_ERR((void *)addr)) return addr; - /* XXX hack until we have a driver callback to make this work */ - obj->read_domains = DRM_GEM_DOMAIN_CPU; - obj->write_domain = DRM_GEM_DOMAIN_CPU; - args->addr_ptr = (uint64_t) addr; return 0; @@ -460,6 +456,37 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, return 0; } +/** + * Called when user space prepares to use an object + */ +int +drm_gem_set_domain_ioctl (struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct drm_gem_set_domain *args = data; + struct drm_gem_object *obj; + int ret; + + if (!(dev->driver->driver_features & DRIVER_GEM)) + return -ENODEV; + + obj = drm_gem_object_lookup(dev, file_priv, args->handle); + if (obj == NULL) + return -EINVAL; + + if (dev->driver->gem_set_domain) { + ret = dev->driver->gem_set_domain (obj, + args->read_domains, + args->write_domain); + } else { + obj->read_domains = args->read_domains; + obj->write_domain = args->write_domain; + ret = 0; + } + drm_gem_object_unreference (obj); + return ret; +} + /** * Called at device open time, sets up the structure for handling refcounting * of mm objects. -- cgit v1.2.3 From 07ad5ce1e199ebca1e51a831503f923fa49cc57e Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 8 May 2008 11:13:29 -0700 Subject: Clean up whinging from checkpatch.pl in drm_gem.c Whitespace changes, a few too-long-lines and some extra braces. --- linux-core/drm_gem.c | 92 ++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 43 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 3673c933..c85265ad 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -69,11 +69,11 @@ */ int -drm_gem_init (struct drm_device *dev) +drm_gem_init(struct drm_device *dev) { - spin_lock_init (&dev->object_name_lock); - idr_init (&dev->object_name_idr); - atomic_set (&dev->object_count, 0); + spin_lock_init(&dev->object_name_lock); + idr_init(&dev->object_name_idr); + atomic_set(&dev->object_count, 0); return 0; } @@ -96,8 +96,8 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) return NULL; } - kref_init (&obj->refcount); - kref_init (&obj->handlecount); + kref_init(&obj->refcount); + kref_init(&obj->handlecount); obj->size = size; if (dev->driver->gem_init_object != NULL && @@ -106,7 +106,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) kfree(obj); return NULL; } - atomic_inc (&dev->object_count); + atomic_inc(&dev->object_count); return obj; } @@ -151,7 +151,7 @@ drm_gem_handle_delete(struct drm_file *filp, int handle) * will likely want to dereference the object afterwards. */ static int -drm_gem_handle_create (struct drm_file *file_priv, +drm_gem_handle_create(struct drm_file *file_priv, struct drm_gem_object *obj, int *handlep) { @@ -166,16 +166,16 @@ again: return -ENOMEM; /* do the allocation under our spinlock */ - spin_lock (&file_priv->table_lock); + spin_lock(&file_priv->table_lock); ret = idr_get_new_above(&file_priv->object_idr, obj, 1, handlep); - spin_unlock (&file_priv->table_lock); + spin_unlock(&file_priv->table_lock); if (ret == -EAGAIN) goto again; if (ret != 0) return ret; - - drm_gem_object_handle_reference (obj); + + drm_gem_object_handle_reference(obj); return 0; } @@ -224,7 +224,7 @@ drm_gem_alloc_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -ENOMEM; - ret = drm_gem_handle_create (file_priv, obj, &handle); + ret = drm_gem_handle_create(file_priv, obj, &handle); drm_gem_object_handle_unreference(obj); if (ret) @@ -324,7 +324,7 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, drm_gem_object_unreference(obj); if (IS_ERR((void *)addr)) return addr; - + args->addr_ptr = (uint64_t) addr; return 0; @@ -391,17 +391,17 @@ drm_gem_name_ioctl(struct drm_device *dev, void *data, return -EINVAL; again: - if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) { + if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) return -ENOMEM; - } + spin_lock(&dev->object_name_lock); if (obj->name) { - spin_unlock (&dev->object_name_lock); + spin_unlock(&dev->object_name_lock); return -EEXIST; } - ret = idr_get_new_above (&dev->object_name_idr, obj, 1, + ret = idr_get_new_above(&dev->object_name_idr, obj, 1, &obj->name); - spin_unlock (&dev->object_name_lock); + spin_unlock(&dev->object_name_lock); if (ret == -EAGAIN) goto again; @@ -410,7 +410,7 @@ again: return ret; } - /* + /* * Leave the reference from the lookup around as the * name table now holds one */ @@ -437,16 +437,16 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; - spin_lock (&dev->object_name_lock); - obj = idr_find (&dev->object_name_idr, (int) args->name); + spin_lock(&dev->object_name_lock); + obj = idr_find(&dev->object_name_idr, (int) args->name); if (obj) - drm_gem_object_reference (obj); - spin_unlock (&dev->object_name_lock); + drm_gem_object_reference(obj); + spin_unlock(&dev->object_name_lock); if (!obj) return -ENOENT; - ret = drm_gem_handle_create (file_priv, obj, &handle); - drm_gem_object_unreference (obj); + ret = drm_gem_handle_create(file_priv, obj, &handle); + drm_gem_object_unreference(obj); if (ret) return ret; @@ -460,7 +460,7 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, * Called when user space prepares to use an object */ int -drm_gem_set_domain_ioctl (struct drm_device *dev, void *data, +drm_gem_set_domain_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_gem_set_domain *args = data; @@ -475,7 +475,7 @@ drm_gem_set_domain_ioctl (struct drm_device *dev, void *data, return -EINVAL; if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain (obj, + ret = dev->driver->gem_set_domain(obj, args->read_domains, args->write_domain); } else { @@ -483,7 +483,7 @@ drm_gem_set_domain_ioctl (struct drm_device *dev, void *data, obj->write_domain = args->write_domain; ret = 0; } - drm_gem_object_unreference (obj); + drm_gem_object_unreference(obj); return ret; } @@ -495,12 +495,15 @@ void drm_gem_open(struct drm_device *dev, struct drm_file *file_private) { idr_init(&file_private->object_idr); - spin_lock_init (&file_private->table_lock); + spin_lock_init(&file_private->table_lock); } -/** Called at device close to release the file's handle references on objects. */ +/** + * Called at device close to release the file's + * handle references on objects. + */ static int -drm_gem_object_release_handle (int id, void *ptr, void *data) +drm_gem_object_release_handle(int id, void *ptr, void *data) { struct drm_gem_object *obj = ptr; @@ -517,7 +520,8 @@ drm_gem_object_release_handle (int id, void *ptr, void *data) void drm_gem_release(struct drm_device *dev, struct drm_file *file_private) { - idr_for_each(&file_private->object_idr, &drm_gem_object_release_handle, NULL); + idr_for_each(&file_private->object_idr, + &drm_gem_object_release_handle, NULL); idr_destroy(&file_private->object_idr); } @@ -528,7 +532,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private) * Frees the object */ void -drm_gem_object_free (struct kref *kref) +drm_gem_object_free(struct kref *kref) { struct drm_gem_object *obj = (struct drm_gem_object *) kref; struct drm_device *dev = obj->dev; @@ -537,7 +541,7 @@ drm_gem_object_free (struct kref *kref) dev->driver->gem_free_object(obj); fput(obj->filp); - atomic_dec (&dev->object_count); + atomic_dec(&dev->object_count); kfree(obj); } EXPORT_SYMBOL(drm_gem_object_free); @@ -550,24 +554,26 @@ EXPORT_SYMBOL(drm_gem_object_free); * freed memory */ void -drm_gem_object_handle_free (struct kref *kref) +drm_gem_object_handle_free(struct kref *kref) { - struct drm_gem_object *obj = container_of (kref, struct drm_gem_object, handlecount); + struct drm_gem_object *obj = container_of(kref, + struct drm_gem_object, + handlecount); struct drm_device *dev = obj->dev; /* Remove any name for this object */ - spin_lock (&dev->object_name_lock); + spin_lock(&dev->object_name_lock); if (obj->name) { - idr_remove (&dev->object_name_idr, obj->name); - spin_unlock (&dev->object_name_lock); + idr_remove(&dev->object_name_idr, obj->name); + spin_unlock(&dev->object_name_lock); /* * The object name held a reference to this object, drop * that now. */ - drm_gem_object_unreference (obj); + drm_gem_object_unreference(obj); } else - spin_unlock (&dev->object_name_lock); - + spin_unlock(&dev->object_name_lock); + } EXPORT_SYMBOL(drm_gem_object_handle_free); -- cgit v1.2.3 From 1e26ca44c9f3e8a1a30652aa860b405e0248aae1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 9 May 2008 12:18:09 -0700 Subject: [gem] API cleanup. allocate->create unreference->close name->flink Make the API names a bit more consistent. --- linux-core/drm_gem.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index c85265ad..6c462921 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -204,13 +204,13 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, EXPORT_SYMBOL(drm_gem_object_lookup); /** - * Allocates a new mm object and returns a handle to it. + * Creates a new mm object and returns a handle to it. */ int -drm_gem_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +drm_gem_create_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_gem_alloc *args = data; + struct drm_gem_create *args = data; struct drm_gem_object *obj; int handle, ret; @@ -239,10 +239,10 @@ drm_gem_alloc_ioctl(struct drm_device *dev, void *data, * Releases the handle to an mm object. */ int -drm_gem_unreference_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +drm_gem_close_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_gem_unreference *args = data; + struct drm_gem_close *args = data; int ret; if (!(dev->driver->driver_features & DRIVER_GEM)) @@ -376,10 +376,10 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, * is freed, the name goes away. */ int -drm_gem_name_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) +drm_gem_flink_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) { - struct drm_gem_name *args = data; + struct drm_gem_flink *args = data; struct drm_gem_object *obj; int ret; -- cgit v1.2.3 From ff39db099b9ca6c8feee68101a2269345b7bd798 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 11 May 2008 00:10:16 -0700 Subject: [GEM] Make pread/pwrite manage memory domains. No luck with movnti though. pread and pwrite must update the memory domains to ensure consistency with the GPU. At some point, it should be possible to avoid clflush through this path, but that isn't working for me. --- linux-core/drm_gem.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 6c462921..14cf7e47 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -266,6 +266,7 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; ssize_t read; loff_t offset; + int ret; if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; @@ -274,6 +275,15 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -EINVAL; + if (dev->driver->gem_set_domain) { + ret = dev->driver->gem_set_domain (obj, + DRM_GEM_DOMAIN_CPU, + 0); + if (ret) { + drm_gem_object_unreference(obj); + return ret; + } + } offset = args->offset; read = vfs_read(obj->filp, (char __user *)(uintptr_t)args->data_ptr, @@ -343,6 +353,7 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, struct drm_gem_object *obj; ssize_t written; loff_t offset; + int ret; if (!(dev->driver->driver_features & DRIVER_GEM)) return -ENODEV; @@ -351,11 +362,21 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -EINVAL; + if (dev->driver->gem_set_domain) { + ret = dev->driver->gem_set_domain (obj, + DRM_GEM_DOMAIN_CPU, + 0); + if (ret) { + drm_gem_object_unreference(obj); + return ret; + } + } offset = args->offset; written = vfs_write(obj->filp, (char __user *)(uintptr_t) args->data_ptr, args->size, &offset); + if (written != args->size) { drm_gem_object_unreference(obj); if (written < 0) @@ -364,6 +385,11 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, return -EINVAL; } + if (dev->driver->gem_flush_pwrite) + dev->driver->gem_flush_pwrite(obj, + args->offset, + args->size); + drm_gem_object_unreference(obj); return 0; -- cgit v1.2.3 From 6aeff6b9e32b61beed0d5c3d871968fa6217b79d Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 12 May 2008 13:01:57 -0700 Subject: [gem] Set write domain to CPU when doing pwrite. Leave the flush call in place, which can fix domains up if necessary. --- linux-core/drm_gem.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 14cf7e47..e20cfe07 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -276,9 +276,9 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, return -EINVAL; if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain (obj, - DRM_GEM_DOMAIN_CPU, - 0); + ret = dev->driver->gem_set_domain(obj, + DRM_GEM_DOMAIN_CPU, + 0); if (ret) { drm_gem_object_unreference(obj); return ret; @@ -363,9 +363,9 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, return -EINVAL; if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain (obj, - DRM_GEM_DOMAIN_CPU, - 0); + ret = dev->driver->gem_set_domain(obj, + DRM_GEM_DOMAIN_CPU, + DRM_GEM_DOMAIN_CPU); if (ret) { drm_gem_object_unreference(obj); return ret; @@ -376,7 +376,7 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, written = vfs_write(obj->filp, (char __user *)(uintptr_t) args->data_ptr, args->size, &offset); - + if (written != args->size) { drm_gem_object_unreference(obj); if (written < 0) -- cgit v1.2.3 From aafafe507ba6d073bad25b74c808b73c428db67f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 15 May 2008 09:32:34 -0700 Subject: [gem] typo fix in comment. --- linux-core/drm_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index e20cfe07..ff1a38dc 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -61,7 +61,7 @@ * DRM terminology) to mimic fds, and implement the fd syscalls we need as * ioctls. The objects themselves will still include the struct file so * that we can transition to fds if the required kernel infrastructure shows - * up at a later data, and as our interface with shmfs for memory allocation. + * up at a later date, and as our interface with shmfs for memory allocation. */ /** -- cgit v1.2.3 From 7dced2f33a952ad12aafb7a3e34747156020a3ae Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 15 May 2008 11:21:11 -0700 Subject: [gem] Hold dev->struct_mutex to protect structure data. --- linux-core/drm_gem.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index ff1a38dc..a8253bc5 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -116,6 +116,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) static int drm_gem_handle_delete(struct drm_file *filp, int handle) { + struct drm_device *dev; struct drm_gem_object *obj; /* This is gross. The idr system doesn't let us try a delete and @@ -135,12 +136,15 @@ drm_gem_handle_delete(struct drm_file *filp, int handle) spin_unlock(&filp->table_lock); return -EINVAL; } + dev = obj->dev; /* Release reference and decrement refcount. */ idr_remove(&filp->object_idr, handle); spin_unlock(&filp->table_lock); + mutex_lock(&dev->struct_mutex); drm_gem_object_handle_unreference(obj); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -225,7 +229,9 @@ drm_gem_create_ioctl(struct drm_device *dev, void *data, return -ENOMEM; ret = drm_gem_handle_create(file_priv, obj, &handle); + mutex_lock(&dev->struct_mutex); drm_gem_object_handle_unreference(obj); + mutex_unlock(&dev->struct_mutex); if (ret) return ret; @@ -275,12 +281,14 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -EINVAL; + mutex_lock(&dev->struct_mutex); if (dev->driver->gem_set_domain) { ret = dev->driver->gem_set_domain(obj, DRM_GEM_DOMAIN_CPU, 0); if (ret) { drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return ret; } } @@ -290,6 +298,7 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, args->size, &offset); if (read != args->size) { drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); if (read < 0) return read; else @@ -297,6 +306,7 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, } drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -331,7 +341,9 @@ drm_gem_mmap_ioctl(struct drm_device *dev, void *data, PROT_READ | PROT_WRITE, MAP_SHARED, args->offset); up_write(¤t->mm->mmap_sem); + mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); if (IS_ERR((void *)addr)) return addr; @@ -362,12 +374,14 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -EINVAL; + mutex_lock(&dev->struct_mutex); if (dev->driver->gem_set_domain) { ret = dev->driver->gem_set_domain(obj, DRM_GEM_DOMAIN_CPU, DRM_GEM_DOMAIN_CPU); if (ret) { drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return ret; } } @@ -379,6 +393,7 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, if (written != args->size) { drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); if (written < 0) return written; else @@ -391,6 +406,7 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, args->size); drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return 0; } @@ -432,7 +448,9 @@ again: goto again; if (ret != 0) { + mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -472,7 +490,9 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, return -ENOENT; ret = drm_gem_handle_create(file_priv, obj, &handle); + mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); if (ret) return ret; @@ -500,6 +520,7 @@ drm_gem_set_domain_ioctl(struct drm_device *dev, void *data, if (obj == NULL) return -EINVAL; + mutex_lock(&dev->struct_mutex); if (dev->driver->gem_set_domain) { ret = dev->driver->gem_set_domain(obj, args->read_domains, @@ -510,6 +531,7 @@ drm_gem_set_domain_ioctl(struct drm_device *dev, void *data, ret = 0; } drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return ret; } @@ -546,10 +568,12 @@ drm_gem_object_release_handle(int id, void *ptr, void *data) void drm_gem_release(struct drm_device *dev, struct drm_file *file_private) { + mutex_lock(&dev->struct_mutex); idr_for_each(&file_private->object_idr, &drm_gem_object_release_handle, NULL); idr_destroy(&file_private->object_idr); + mutex_unlock(&dev->struct_mutex); } /** @@ -563,6 +587,8 @@ drm_gem_object_free(struct kref *kref) struct drm_gem_object *obj = (struct drm_gem_object *) kref; struct drm_device *dev = obj->dev; + BUG_ON(!mutex_is_locked(&dev->struct_mutex)); + if (dev->driver->gem_free_object != NULL) dev->driver->gem_free_object(obj); -- cgit v1.2.3 From 44ed693ca6f8d19acb39174c6efada070652a027 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 22 May 2008 11:34:56 -0700 Subject: [gem] Use CPU domain for new or pageable objects Newly allocated objects need to be in the CPU domain as they've just been cleared by the CPU. Also, unmapping objects from the GTT needs to put them into the CPU domain, both to flush rendering as well as to ensure that any paging action gets flushed before we remap to the GTT. --- linux-core/drm_gem.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index a8253bc5..fb175d7d 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -100,6 +100,14 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) kref_init(&obj->handlecount); obj->size = size; + /* + * We've just allocated pages from the kernel, + * so they've just been written by the CPU with + * zeros. They'll need to be clflushed before we + * use them with the GPU. + */ + obj->write_domain = DRM_GEM_DOMAIN_CPU; + obj->read_domains = DRM_GEM_DOMAIN_CPU; if (dev->driver->gem_init_object != NULL && dev->driver->gem_init_object(obj) != 0) { fput(obj->filp); -- cgit v1.2.3 From e10502002f0ebb2b56b19384b2f2eae7a7a84512 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 27 May 2008 17:50:39 -0700 Subject: [intel-gem] Replace idlelock usage with real lock acquisition. --- linux-core/drm_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index fb175d7d..b726e598 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -291,7 +291,7 @@ drm_gem_pread_ioctl(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain(obj, + ret = dev->driver->gem_set_domain(obj, file_priv, DRM_GEM_DOMAIN_CPU, 0); if (ret) { @@ -384,7 +384,7 @@ drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain(obj, + ret = dev->driver->gem_set_domain(obj, file_priv, DRM_GEM_DOMAIN_CPU, DRM_GEM_DOMAIN_CPU); if (ret) { @@ -530,7 +530,7 @@ drm_gem_set_domain_ioctl(struct drm_device *dev, void *data, mutex_lock(&dev->struct_mutex); if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain(obj, + ret = dev->driver->gem_set_domain(obj, file_priv, args->read_domains, args->write_domain); } else { -- cgit v1.2.3 From 2150da5d1a57d25d0f4bc39bb6c883d410f586d1 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 10 Jun 2008 15:30:23 -0700 Subject: [gem] Manage the ringbuffer from the kernel in the GEM case. This requires that the X Server use the execbuf interface for buffer submission, as it no longer has direct access to the ring. This is therefore a flag day for the gem interface. This also adds enter/leavevt ioctls for use by the X Server. These would get stubbed out in a modesetting implementation, but are required while in an environment where the device's state is only managed by the DRM while X has the VT. --- linux-core/drm_gem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index b726e598..a8ecaf76 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -80,7 +80,7 @@ drm_gem_init(struct drm_device *dev) /** * Allocate a GEM object of the specified size with shmfs backing store */ -static struct drm_gem_object * +struct drm_gem_object * drm_gem_object_alloc(struct drm_device *dev, size_t size) { struct drm_gem_object *obj; @@ -117,6 +117,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) atomic_inc(&dev->object_count); return obj; } +EXPORT_SYMBOL(drm_gem_object_alloc); /** * Removes the mapping from handle to filp for this object. -- cgit v1.2.3 From 2655005762b8915d5f44d1d1ee7e6c2eb34841d7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 11 Jun 2008 14:42:40 -0700 Subject: [gem] Move potentially device-specific ioctls to the intel driver. This is the create (may want location flags), pread/pwrite/mmap (performance tuning hints), and set_domain (will 32 bits be enough for everyone?) ioctls. Left in the generic set are just flink/open/close. The 2D driver must be updated for this change, and API but not ABI is broken for 3D. The driver version is bumped to mark this. --- linux-core/drm_gem.c | 231 +-------------------------------------------------- 1 file changed, 2 insertions(+), 229 deletions(-) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index a8ecaf76..47b55434 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -99,15 +99,6 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) kref_init(&obj->refcount); kref_init(&obj->handlecount); obj->size = size; - - /* - * We've just allocated pages from the kernel, - * so they've just been written by the CPU with - * zeros. They'll need to be clflushed before we - * use them with the GPU. - */ - obj->write_domain = DRM_GEM_DOMAIN_CPU; - obj->read_domains = DRM_GEM_DOMAIN_CPU; if (dev->driver->gem_init_object != NULL && dev->driver->gem_init_object(obj) != 0) { fput(obj->filp); @@ -163,7 +154,7 @@ drm_gem_handle_delete(struct drm_file *filp, int handle) * to the object, which includes a regular reference count. Callers * will likely want to dereference the object afterwards. */ -static int +int drm_gem_handle_create(struct drm_file *file_priv, struct drm_gem_object *obj, int *handlep) @@ -191,6 +182,7 @@ again: drm_gem_object_handle_reference(obj); return 0; } +EXPORT_SYMBOL(drm_gem_handle_create); /** Returns a reference to the object named by the handle. */ struct drm_gem_object * @@ -216,40 +208,6 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, } EXPORT_SYMBOL(drm_gem_object_lookup); -/** - * Creates a new mm object and returns a handle to it. - */ -int -drm_gem_create_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_gem_create *args = data; - struct drm_gem_object *obj; - int handle, ret; - - if (!(dev->driver->driver_features & DRIVER_GEM)) - return -ENODEV; - - args->size = roundup(args->size, PAGE_SIZE); - - /* Allocate the new object */ - obj = drm_gem_object_alloc(dev, args->size); - if (obj == NULL) - return -ENOMEM; - - ret = drm_gem_handle_create(file_priv, obj, &handle); - mutex_lock(&dev->struct_mutex); - drm_gem_object_handle_unreference(obj); - mutex_unlock(&dev->struct_mutex); - - if (ret) - return ret; - - args->handle = handle; - - return 0; -} - /** * Releases the handle to an mm object. */ @@ -268,158 +226,6 @@ drm_gem_close_ioctl(struct drm_device *dev, void *data, return ret; } -/** - * Reads data from the object referenced by handle. - * - * On error, the contents of *data are undefined. - */ -int -drm_gem_pread_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_gem_pread *args = data; - struct drm_gem_object *obj; - ssize_t read; - loff_t offset; - int ret; - - if (!(dev->driver->driver_features & DRIVER_GEM)) - return -ENODEV; - - obj = drm_gem_object_lookup(dev, file_priv, args->handle); - if (obj == NULL) - return -EINVAL; - - mutex_lock(&dev->struct_mutex); - if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain(obj, file_priv, - DRM_GEM_DOMAIN_CPU, - 0); - if (ret) { - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - return ret; - } - } - offset = args->offset; - - read = vfs_read(obj->filp, (char __user *)(uintptr_t)args->data_ptr, - args->size, &offset); - if (read != args->size) { - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - if (read < 0) - return read; - else - return -EINVAL; - } - - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - - return 0; -} - -/** - * Maps the contents of an object, returning the address it is mapped - * into. - * - * While the mapping holds a reference on the contents of the object, it doesn't - * imply a ref on the object itself. - */ -int -drm_gem_mmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_gem_mmap *args = data; - struct drm_gem_object *obj; - loff_t offset; - unsigned long addr; - - if (!(dev->driver->driver_features & DRIVER_GEM)) - return -ENODEV; - - obj = drm_gem_object_lookup(dev, file_priv, args->handle); - if (obj == NULL) - return -EINVAL; - - offset = args->offset; - - down_write(¤t->mm->mmap_sem); - addr = do_mmap(obj->filp, 0, args->size, - PROT_READ | PROT_WRITE, MAP_SHARED, - args->offset); - up_write(¤t->mm->mmap_sem); - mutex_lock(&dev->struct_mutex); - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - if (IS_ERR((void *)addr)) - return addr; - - args->addr_ptr = (uint64_t) addr; - - return 0; -} - -/** - * Writes data to the object referenced by handle. - * - * On error, the contents of the buffer that were to be modified are undefined. - */ -int -drm_gem_pwrite_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_gem_pwrite *args = data; - struct drm_gem_object *obj; - ssize_t written; - loff_t offset; - int ret; - - if (!(dev->driver->driver_features & DRIVER_GEM)) - return -ENODEV; - - obj = drm_gem_object_lookup(dev, file_priv, args->handle); - if (obj == NULL) - return -EINVAL; - - mutex_lock(&dev->struct_mutex); - if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain(obj, file_priv, - DRM_GEM_DOMAIN_CPU, - DRM_GEM_DOMAIN_CPU); - if (ret) { - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - return ret; - } - } - offset = args->offset; - - written = vfs_write(obj->filp, - (char __user *)(uintptr_t) args->data_ptr, - args->size, &offset); - - if (written != args->size) { - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - if (written < 0) - return written; - else - return -EINVAL; - } - - if (dev->driver->gem_flush_pwrite) - dev->driver->gem_flush_pwrite(obj, - args->offset, - args->size); - - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - - return 0; -} - /** * Create a global name for an object, returning the name. * @@ -511,39 +317,6 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data, return 0; } -/** - * Called when user space prepares to use an object - */ -int -drm_gem_set_domain_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_gem_set_domain *args = data; - struct drm_gem_object *obj; - int ret; - - if (!(dev->driver->driver_features & DRIVER_GEM)) - return -ENODEV; - - obj = drm_gem_object_lookup(dev, file_priv, args->handle); - if (obj == NULL) - return -EINVAL; - - mutex_lock(&dev->struct_mutex); - if (dev->driver->gem_set_domain) { - ret = dev->driver->gem_set_domain(obj, file_priv, - args->read_domains, - args->write_domain); - } else { - obj->read_domains = args->read_domains; - obj->write_domain = args->write_domain; - ret = 0; - } - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); - return ret; -} - /** * Called at device open time, sets up the structure for handling refcounting * of mm objects. -- cgit v1.2.3 From 217beb9c8de01417ac6219b54bd25046da6d4c7a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Fri, 13 Jun 2008 15:43:02 -0700 Subject: [intel-gem] add gtt and pin counts to /proc/dri/*/gem_objects Not quite portable, but these are useful for intel. Some more general mechanism could be done... --- linux-core/drm_gem.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'linux-core/drm_gem.c') diff --git a/linux-core/drm_gem.c b/linux-core/drm_gem.c index 47b55434..434155b3 100644 --- a/linux-core/drm_gem.c +++ b/linux-core/drm_gem.c @@ -74,6 +74,11 @@ drm_gem_init(struct drm_device *dev) spin_lock_init(&dev->object_name_lock); idr_init(&dev->object_name_idr); atomic_set(&dev->object_count, 0); + atomic_set(&dev->object_memory, 0); + atomic_set(&dev->pin_count, 0); + atomic_set(&dev->pin_memory, 0); + atomic_set(&dev->gtt_count, 0); + atomic_set(&dev->gtt_memory, 0); return 0; } @@ -106,6 +111,7 @@ drm_gem_object_alloc(struct drm_device *dev, size_t size) return NULL; } atomic_inc(&dev->object_count); + atomic_add(obj->size, &dev->object_memory); return obj; } EXPORT_SYMBOL(drm_gem_object_alloc); @@ -376,6 +382,7 @@ drm_gem_object_free(struct kref *kref) fput(obj->filp); atomic_dec(&dev->object_count); + atomic_sub(obj->size, &dev->object_memory); kfree(obj); } EXPORT_SYMBOL(drm_gem_object_free); -- cgit v1.2.3