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.
main
Keith Packard 2008-05-02 16:34:16 -07:00
parent 39e20bcd5f
commit ab3549d133
6 changed files with 160 additions and 16 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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:

View File

@ -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,

View File

@ -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;
}