Commit 48e7f183 authored by Kristian H. Kristensen's avatar Kristian H. Kristensen Committed by Rob Clark
Browse files

drm/msm: Implement .gem_free_object_unlocked



We use a llist and a worker to delay the object cleanup. This avoids
taking mmap_sem and struct_mutex in the wrong order when calling
drm_gem_object_put_unlocked() from drm_gem_mmap().

Fixes lockdep problem with copy_from_user() in msm_ioctl_gem_submit().

Signed-off-by: default avatarKristian H. Kristensen <hoegsberg@chromium.org>
Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent fb076b15
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -458,6 +458,9 @@ static int msm_drm_init(struct device *dev, struct drm_driver *drv)

	priv->wq = alloc_ordered_workqueue("msm", 0);

	INIT_WORK(&priv->free_work, msm_gem_free_work);
	init_llist_head(&priv->free_list);

	INIT_LIST_HEAD(&priv->inactive_list);

	drm_mode_config_init(ddev);
@@ -1026,7 +1029,7 @@ static struct drm_driver msm_driver = {
	.irq_uninstall      = msm_irq_uninstall,
	.enable_vblank      = msm_enable_vblank,
	.disable_vblank     = msm_disable_vblank,
	.gem_free_object    = msm_gem_free_object,
	.gem_free_object_unlocked = msm_gem_free_object,
	.gem_vm_ops         = &vm_ops,
	.dumb_create        = msm_gem_dumb_create,
	.dumb_map_offset    = msm_gem_dumb_map_offset,
+5 −0
Original line number Diff line number Diff line
@@ -185,6 +185,10 @@ struct msm_drm_private {
	/* list of GEM objects: */
	struct list_head inactive_list;

	/* worker for delayed free of objects: */
	struct work_struct free_work;
	struct llist_head free_list;

	struct workqueue_struct *wq;

	unsigned int num_planes;
@@ -325,6 +329,7 @@ void msm_gem_kernel_put(struct drm_gem_object *bo,
		struct msm_gem_address_space *aspace, bool locked);
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
		struct dma_buf *dmabuf, struct sg_table *sgt);
void msm_gem_free_work(struct work_struct *work);

__printf(2, 3)
void msm_gem_object_set_name(struct drm_gem_object *bo, const char *fmt, ...);
+34 −1
Original line number Diff line number Diff line
@@ -853,8 +853,18 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m)
/* don't call directly!  Use drm_gem_object_put() and friends */
void msm_gem_free_object(struct drm_gem_object *obj)
{
	struct drm_device *dev = obj->dev;
	struct msm_gem_object *msm_obj = to_msm_bo(obj);
	struct drm_device *dev = obj->dev;
	struct msm_drm_private *priv = dev->dev_private;

	if (llist_add(&msm_obj->freed, &priv->free_list))
		queue_work(priv->wq, &priv->free_work);
}

static void free_object(struct msm_gem_object *msm_obj)
{
	struct drm_gem_object *obj = &msm_obj->base;
	struct drm_device *dev = obj->dev;

	WARN_ON(!mutex_is_locked(&dev->struct_mutex));

@@ -892,6 +902,29 @@ void msm_gem_free_object(struct drm_gem_object *obj)
	kfree(msm_obj);
}

void msm_gem_free_work(struct work_struct *work)
{
	struct msm_drm_private *priv =
		container_of(work, struct msm_drm_private, free_work);
	struct drm_device *dev = priv->dev;
	struct llist_node *freed;
	struct msm_gem_object *msm_obj, *next;

	while ((freed = llist_del_all(&priv->free_list))) {

		mutex_lock(&dev->struct_mutex);

		llist_for_each_entry_safe(msm_obj, next,
					  freed, freed)
			free_object(msm_obj);

		mutex_unlock(&dev->struct_mutex);

		if (need_resched())
			break;
	}
}

/* convenience method to construct a GEM buffer object, and userspace handle */
int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
		uint32_t size, uint32_t flags, uint32_t *handle,
+3 −0
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@ struct msm_gem_object {

	struct list_head vmas;    /* list of msm_gem_vma */

	struct llist_node freed;

	/* normally (resv == &_resv) except for imported bo's */
	struct reservation_object *resv;
	struct reservation_object _resv;
@@ -133,6 +135,7 @@ enum msm_gem_lock {

void msm_gem_purge(struct drm_gem_object *obj, enum msm_gem_lock subclass);
void msm_gem_vunmap(struct drm_gem_object *obj, enum msm_gem_lock subclass);
void msm_gem_free_work(struct work_struct *work);

/* Created per submit-ioctl, to track bo's and cmdstream bufs, etc,
 * associated with the cmdstream submission for synchronization (and