summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/msm_gem.c
diff options
context:
space:
mode:
authorKristian H. Kristensen <hoegsberg@gmail.com>2019-03-20 10:09:08 -0700
committerRob Clark <robdclark@chromium.org>2019-04-19 11:50:06 -0700
commit48e7f18392c66f9b69ebac11c54f1a2e033ced54 (patch)
treecf683d683a70b760650865d44656a699cccf9def /drivers/gpu/drm/msm/msm_gem.c
parentfb076b15d50dee36c75eb6c447c1b1026ad12e2e (diff)
downloadlinux-48e7f18392c66f9b69ebac11c54f1a2e033ced54.tar.bz2
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: Kristian H. Kristensen <hoegsberg@chromium.org> Signed-off-by: Rob Clark <robdclark@chromium.org>
Diffstat (limited to 'drivers/gpu/drm/msm/msm_gem.c')
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c35
1 files changed, 34 insertions, 1 deletions
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 76940a9da980..d4dae0f0238e 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -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,