diff --git a/msm/msm_drv.c b/msm/msm_drv.c index ede9d2bca7..e1d2093f51 100644 --- a/msm/msm_drv.c +++ b/msm/msm_drv.c @@ -792,6 +792,9 @@ static int msm_drm_component_init(struct device *dev) priv->wq = alloc_ordered_workqueue("msm_drm", 0); init_waitqueue_head(&priv->pending_crtcs_event); + INIT_WORK(&priv->free_work, msm_gem_free_work); + init_llist_head(&priv->free_list); + INIT_LIST_HEAD(&priv->client_event_list); INIT_LIST_HEAD(&priv->inactive_list); INIT_LIST_HEAD(&priv->vm_client_list); diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 09accfe2db..f65fc6e1de 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -891,6 +891,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; /* crtcs pending async atomic updates: */ @@ -1130,6 +1134,7 @@ void *msm_gem_kernel_new_locked(struct drm_device *dev, uint32_t size, struct drm_gem_object **bo, uint64_t *iova); 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, ...); diff --git a/msm/msm_gem.c b/msm/msm_gem.c index 2c6ab4091e..562691b6e4 100644 --- a/msm/msm_gem.c +++ b/msm/msm_gem.c @@ -1007,6 +1007,16 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) void msm_gem_free_object(struct drm_gem_object *obj) { 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; /* object should not be on active list: */ WARN_ON(is_active(msm_obj)); @@ -1048,6 +1058,27 @@ 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, diff --git a/msm/msm_gem.h b/msm/msm_gem.h index 48759fdf96..3e224a5bc2 100644 --- a/msm/msm_gem.h +++ b/msm/msm_gem.h @@ -125,6 +125,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 dma_resv *resv; struct dma_resv _resv; @@ -182,6 +184,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