{
DRM_DEBUG_DRIVER("enter\n");
+ mutex_destroy(&comm->mutex);
vigs_comm_exit(comm);
if (comm->execbuffer) {
drm_gem_object_unreference_unlocked(&comm->execbuffer->gem.base);
mutex_lock(&vigs_dev->drm_dev->struct_mutex);
+ mutex_lock(&vigs_dev->surface_idr_mutex);
+
sfc = idr_find(&vigs_dev->surface_idr, sfc_id);
if (sfc) {
- drm_gem_object_reference(&sfc->gem.base);
+ if (vigs_gem_freed(&sfc->gem)) {
+ sfc = NULL;
+ } else {
+ drm_gem_object_reference(&sfc->gem.base);
+ }
}
+ mutex_unlock(&vigs_dev->surface_idr_mutex);
+
mutex_unlock(&vigs_dev->drm_dev->struct_mutex);
return sfc;
vigs_dev->io_size = pci_resource_len(pci_dev, 2);
idr_init(&vigs_dev->surface_idr);
+ mutex_init(&vigs_dev->surface_idr_mutex);
if (!vigs_dev->vram_base || !vigs_dev->ram_base || !vigs_dev->io_base) {
DRM_ERROR("VRAM, RAM or IO bar not found on device\n");
drm_rmmap(vigs_dev->drm_dev, vigs_dev->io_map);
fail1:
idr_destroy(&vigs_dev->surface_idr);
+ mutex_destroy(&vigs_dev->surface_idr_mutex);
return ret;
}
vigs_mman_destroy(vigs_dev->mman);
drm_rmmap(vigs_dev->drm_dev, vigs_dev->io_map);
idr_destroy(&vigs_dev->surface_idr);
+ mutex_destroy(&vigs_dev->surface_idr_mutex);
}
int vigs_device_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret, tmp_id = 0;
+ mutex_lock(&vigs_dev->surface_idr_mutex);
+
do {
if (unlikely(idr_pre_get(&vigs_dev->surface_idr, GFP_KERNEL) == 0)) {
+ mutex_unlock(&vigs_dev->surface_idr_mutex);
return -ENOMEM;
}
*id = tmp_id;
+ mutex_unlock(&vigs_dev->surface_idr_mutex);
+
return ret;
}
void vigs_device_remove_surface(struct vigs_device *vigs_dev,
vigsp_surface_id sfc_id)
{
+ mutex_lock(&vigs_dev->surface_idr_mutex);
idr_remove(&vigs_dev->surface_idr, sfc_id);
+ mutex_unlock(&vigs_dev->surface_idr_mutex);
}
int vigs_device_add_surface_unlocked(struct vigs_device *vigs_dev,
resource_size_t io_size;
struct idr surface_idr;
+ struct mutex surface_idr_mutex;
/* Map of IO BAR. */
drm_local_map_t *io_map;
int vigs_device_mmap(struct file *filp, struct vm_area_struct *vma);
-/*
- * Must be called with drm_device::struct_mutex held.
- * @{
- */
int vigs_device_add_surface(struct vigs_device *vigs_dev,
struct vigs_surface *sfc,
vigsp_surface_id* id);
void vigs_device_remove_surface(struct vigs_device *vigs_dev,
vigsp_surface_id sfc_id);
+
/*
- * @}
+ * Locks drm_device::struct_mutex.
+ * @{
*/
int vigs_device_add_surface_unlocked(struct vigs_device *vigs_dev,
vigsp_surface_id sfc_id);
/*
+ * @}
+ */
+
+/*
* IOCTLs
* @{
*/
static void vigs_execbuffer_destroy(struct vigs_gem_object *gem)
{
- struct vigs_execbuffer *execbuffer = vigs_gem_to_vigs_execbuffer(gem);
-
- vigs_gem_cleanup(&execbuffer->gem);
}
int vigs_execbuffer_create(struct vigs_device *vigs_dev,
{
struct vigs_gem_object *vigs_gem = bo_to_vigs_gem(bo);
+ if (vigs_gem->destroy) {
+ vigs_gem->destroy(vigs_gem);
+ }
+
+ drm_gem_object_release(&vigs_gem->base);
kfree(vigs_gem);
}
vigs_dev->mman->bo_dev.dev_mapping = vigs_dev->drm_dev->dev_mapping;
}
+ ret = drm_gem_object_init(vigs_dev->drm_dev, &vigs_gem->base, size);
+
+ if (ret != 0) {
+ kfree(vigs_gem);
+ return ret;
+ }
+
ret = ttm_bo_init(&vigs_dev->mman->bo_dev, &vigs_gem->bo, size, bo_type,
&placement, 0, 0,
false, NULL, 0,
vigs_gem->pin_count = 0;
vigs_gem->destroy = destroy;
- ret = drm_gem_object_init(vigs_dev->drm_dev, &vigs_gem->base, size);
-
- if (ret != 0) {
- struct ttm_buffer_object *bo = &vigs_gem->bo;
- ttm_bo_unref(&bo);
- return ret;
- }
-
DRM_DEBUG_DRIVER("GEM created (type = %u, off = 0x%llX, sz = %lu)\n",
type,
vigs_gem_mmap_offset(vigs_gem),
{
struct ttm_buffer_object *bo = &vigs_gem->bo;
- vigs_gem_reserve(vigs_gem);
-
- vigs_gem_kunmap(vigs_gem);
-
- vigs_gem_unreserve(vigs_gem);
-
- DRM_DEBUG_DRIVER("GEM destroyed (type = %u, off = 0x%llX, sz = %lu)\n",
- vigs_gem->type,
- vigs_gem_mmap_offset(vigs_gem),
- vigs_gem_size(vigs_gem));
-
- drm_gem_object_release(&vigs_gem->base);
ttm_bo_unref(&bo);
}
{
struct vigs_gem_object *vigs_gem = gem_to_vigs_gem(gem);
- vigs_gem->destroy(vigs_gem);
+ vigs_gem_reserve(vigs_gem);
+
+ vigs_gem_kunmap(vigs_gem);
+
+ vigs_gem_unreserve(vigs_gem);
+
+ vigs_gem->freed = true;
+
+ DRM_DEBUG_DRIVER("GEM free (type = %u, off = 0x%llX, sz = %lu)\n",
+ vigs_gem->type,
+ vigs_gem_mmap_offset(vigs_gem),
+ vigs_gem_size(vigs_gem));
+
+ vigs_gem_cleanup(vigs_gem);
}
int vigs_gem_init_object(struct drm_gem_object *gem)
struct ttm_buffer_object bo;
/*
+ * Indicates that drm_driver::gem_free_object was called.
+ */
+ bool freed;
+
+ /*
* Use it only when this GEM is reserved. This makes it easier
* to reserve a set of GEMs and then unreserve them later.
*/
}
/*
+ * Must be called with drm_device::struct_mutex held.
+ * @{
+ */
+
+static inline bool vigs_gem_freed(struct vigs_gem_object *vigs_gem)
+{
+ return vigs_gem->freed;
+}
+
+/*
+ * @}
+ */
+
+/*
* Initializes a gem object. 'size' is automatically rounded up to page size.
* 'vigs_gem' is kfree'd on failure.
*/
struct vigs_surface *sfc = vigs_gem_to_vigs_surface(gem);
struct vigs_device *vigs_dev = gem->base.dev->dev_private;
- vigs_comm_destroy_surface(vigs_dev->comm, sfc->id);
+ if (sfc->id) {
+ vigs_comm_destroy_surface(vigs_dev->comm, sfc->id);
- vigs_device_remove_surface(vigs_dev, sfc->id);
+ vigs_device_remove_surface(vigs_dev, sfc->id);
- vigs_gem_cleanup(&sfc->gem);
+ DRM_DEBUG_DRIVER("Surface destroyed (id = %u)\n", sfc->id);
+ }
}
int vigs_surface_create(struct vigs_device *vigs_dev,
fail3:
vigs_device_remove_surface_unlocked(vigs_dev, (*sfc)->id);
fail2:
+ (*sfc)->id = 0;
vigs_gem_cleanup(&(*sfc)->gem);
fail1:
*sfc = NULL;