summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2008-05-02 16:34:16 -0700
committerKeith Packard <keithp@keithp.com>2008-05-02 16:34:16 -0700
commitab3549d1336fc6c08581a9fd14a83513649d9187 (patch)
treed267f50992fa987d8aca0aa19d2af015134c8cc9
parent39e20bcd5f4bf9fedac80188fda2e9fcab2f0360 (diff)
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.
-rw-r--r--linux-core/drmP.h4
-rw-r--r--linux-core/drm_gem.c46
-rw-r--r--linux-core/drm_proc.c79
-rw-r--r--linux-core/drm_stub.c9
-rw-r--r--linux-core/i915_drv.c2
-rw-r--r--linux-core/i915_gem.c36
6 files changed, 160 insertions, 16 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index ebbbfa8a..12e093e3 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -937,6 +937,7 @@ struct drm_device {
/*@{ */
spinlock_t object_name_lock;
struct idr object_name_idr;
+ atomic_t object_count;
/*@} */
};
@@ -1320,6 +1321,9 @@ static inline struct drm_memrange *drm_get_mm(struct drm_memrange_node *block)
return block->mm;
}
+int
+drm_gem_init (struct drm_device *dev);
+
void
drm_gem_object_free (struct kref *kref);
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);
diff --git a/linux-core/drm_proc.c b/linux-core/drm_proc.c
index 42da5c69..b1b976b2 100644
--- a/linux-core/drm_proc.c
+++ b/linux-core/drm_proc.c
@@ -51,6 +51,10 @@ 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);
+static int drm_gem_name_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data);
+static int drm_gem_object_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);
@@ -70,6 +74,8 @@ static struct drm_proc_list {
{"queues", drm_queues_info},
{"bufs", drm_bufs_info},
{"objects", drm_objects_info},
+ {"gem_names", drm_gem_name_info},
+ {"gem_objects", drm_gem_object_info},
#if DRM_DEBUG_CODE
{"vma", drm_vma_info},
#endif
@@ -582,6 +588,79 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
return ret;
}
+struct drm_gem_name_info_data {
+ int len;
+ char *buf;
+ int eof;
+};
+
+static int drm_gem_one_name_info (int id, void *ptr, void *data)
+{
+ struct drm_gem_object *obj = ptr;
+ struct drm_gem_name_info_data *nid = data;
+
+ DRM_INFO ("name %d size %d\n", obj->name, obj->size);
+ if (nid->eof)
+ return 0;
+
+ nid->len += sprintf (&nid->buf[nid->len],
+ "%6d%9d%8d%9d\n",
+ obj->name, obj->size,
+ atomic_read(&obj->handlecount.refcount),
+ atomic_read(&obj->refcount.refcount));
+ if (nid->len > DRM_PROC_LIMIT) {
+ nid->eof = 1;
+ return 0;
+ }
+ return 0;
+}
+
+static int drm_gem_name_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ struct drm_gem_name_info_data nid;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ nid.len = sprintf (buf, " name size handles refcount\n");
+ nid.buf = buf;
+ nid.eof = 0;
+ idr_for_each (&dev->object_name_idr, drm_gem_one_name_info, &nid);
+
+ *start = &buf[offset];
+ *eof = 0;
+ if (nid.len > request + offset)
+ return request;
+ *eof = 1;
+ return nid.len - offset;
+}
+
+static int drm_gem_object_info(char *buf, char **start, off_t offset,
+ int request, int *eof, void *data)
+{
+ struct drm_minor *minor = (struct drm_minor *) data;
+ struct drm_device *dev = minor->dev;
+ int len = 0;
+
+ if (offset > DRM_PROC_LIMIT) {
+ *eof = 1;
+ return 0;
+ }
+
+ *start = &buf[offset];
+ *eof = 0;
+ DRM_PROC_PRINT ("%d objects\n", atomic_read (&dev->object_count));
+ if (len > request + offset)
+ return request;
+ *eof = 1;
+ return len - offset;
+}
+
#if DRM_DEBUG_CODE
static int drm__vma_info(char *buf, char **start, off_t offset, int request,
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
index 030fea54..55841826 100644
--- a/linux-core/drm_stub.c
+++ b/linux-core/drm_stub.c
@@ -163,7 +163,16 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
goto error_out_unreg;
}
+ if (driver->driver_features & DRIVER_GEM) {
+ retcode = drm_gem_init (dev);
+ if (retcode) {
+ DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
+ goto error_out_unreg;
+ }
+ }
+
drm_fence_manager_init(dev);
+
return 0;
error_out_unreg:
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index c77c329f..3e788d25 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -566,7 +566,7 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR | */
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
.load = i915_driver_load,
.unload = i915_driver_unload,
.firstopen = i915_driver_firstopen,
diff --git a/linux-core/i915_gem.c b/linux-core/i915_gem.c
index 2ac74b4b..747cc45c 100644
--- a/linux-core/i915_gem.c
+++ b/linux-core/i915_gem.c
@@ -58,11 +58,13 @@ i915_gem_object_free_page_list(struct drm_gem_object *obj)
if (obj_priv->page_list == NULL)
return;
- for (i = 0; i < obj->size / PAGE_SIZE; i++) {
- if (obj_priv->page_list[i] == NULL)
- put_page(obj_priv->page_list[i]);
+
+ for (i = 0; i < page_count; i++) {
+ if (obj_priv->page_list[i] != NULL) {
+ unlock_page (obj_priv->page_list[i]);
+ page_cache_release (obj_priv->page_list[i]);
+ }
}
-
drm_free(obj_priv->page_list,
page_count * sizeof(struct page *),
DRM_MEM_DRIVER);
@@ -212,15 +214,18 @@ i915_gem_reloc_and_validate_object(struct drm_gem_object *obj,
if (target_obj_priv->gtt_space == NULL) {
DRM_ERROR("No GTT space found for object %d\n",
reloc.target_handle);
+ drm_gem_object_unreference (target_obj);
return -EINVAL;
}
if (reloc.offset > obj->size - 4) {
DRM_ERROR("Relocation beyond object bounds.\n");
+ drm_gem_object_unreference (target_obj);
return -EINVAL;
}
if (reloc.offset & 3) {
DRM_ERROR("Relocation not 4-byte aligned.\n");
+ drm_gem_object_unreference (target_obj);
return -EINVAL;
}
@@ -231,7 +236,10 @@ i915_gem_reloc_and_validate_object(struct drm_gem_object *obj,
(reloc.offset & ~(PAGE_SIZE - 1)),
PAGE_SIZE);
if (reloc_page == NULL)
+ {
+ drm_gem_object_unreference (target_obj);
return -ENOMEM;
+ }
reloc_entry = (uint32_t *)((char *)reloc_page +
(reloc.offset & (PAGE_SIZE - 1)));
@@ -242,6 +250,7 @@ i915_gem_reloc_and_validate_object(struct drm_gem_object *obj,
*reloc_entry = reloc_val;
iounmap(reloc_page);
+ drm_gem_object_unreference (target_obj);
}
return 0;
@@ -372,16 +381,21 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
- ret = i915_gem_object_bind_to_gtt(obj, (unsigned) args->alignment);
- if (ret != 0) {
- DRM_ERROR("Failure to bind in i915_gem_pin_ioctl(): %d\n",
- ret);
- return ret;
+ obj_priv = obj->driver_private;
+ if (obj_priv->gtt_space == NULL)
+ {
+ ret = i915_gem_object_bind_to_gtt(obj, (unsigned) args->alignment);
+ if (ret != 0) {
+ DRM_ERROR("Failure to bind in i915_gem_pin_ioctl(): %d\n",
+ ret);
+ drm_gem_object_unreference (obj);
+ return ret;
+ }
}
- obj_priv = obj->driver_private;
obj_priv->pin_count++;
args->offset = obj_priv->gtt_offset;
+ drm_gem_object_unreference (obj);
return 0;
}
@@ -403,7 +417,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
obj_priv = obj->driver_private;
obj_priv->pin_count--;
-
+ drm_gem_object_unreference (obj);
return 0;
}