Loading drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +1 −1 Original line number Diff line number Diff line Loading @@ -617,7 +617,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) goto fail; } aspace = msm_gem_smmu_address_space_create(&pdev->dev, aspace = msm_gem_smmu_address_space_create(dev, mmu, "mdp5"); if (IS_ERR(aspace)) { ret = PTR_ERR(aspace); Loading drivers/gpu/drm/msm/msm_drv.h +45 −1 Original line number Diff line number Diff line Loading @@ -662,13 +662,57 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, /* For SDE display */ struct msm_gem_address_space * msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, msm_gem_smmu_address_space_create(struct drm_device *dev, struct msm_mmu *mmu, const char *name); /** * msm_gem_add_obj_to_aspace_active_list: adds obj to active obj list in aspace */ void msm_gem_add_obj_to_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj); /** * msm_gem_remove_obj_from_aspace_active_list: removes obj from active obj * list in aspace */ void msm_gem_remove_obj_from_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj); /** * msm_gem_smmu_address_space_get: returns the aspace pointer for the requested * domain */ struct msm_gem_address_space * msm_gem_smmu_address_space_get(struct drm_device *dev, unsigned int domain); /** * msm_gem_aspace_domain_attach_detach: function to inform the attach/detach * of the domain for this aspace */ void msm_gem_aspace_domain_attach_detach_update( struct msm_gem_address_space *aspace, bool is_detach); /** * msm_gem_address_space_register_cb: function to register callback for attach * and detach of the domain */ int msm_gem_address_space_register_cb( struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data); /** * msm_gem_address_space_register_cb: function to unregister callback */ int msm_gem_address_space_unregister_cb( struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data); int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); Loading drivers/gpu/drm/msm/msm_gem.c +66 −2 Original line number Diff line number Diff line Loading @@ -311,6 +311,10 @@ put_iova(struct drm_gem_object *obj) if (iommu_present(&platform_bus_type)) { msm_gem_unmap_vma(domain->aspace, domain, msm_obj->sgt, get_dmabuf_ptr(obj)); msm_gem_remove_obj_from_aspace_active_list( domain->aspace, obj); } obj_remove_domain(domain); Loading Loading @@ -390,10 +394,12 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, msm_obj->flags); } if (!ret && domain) if (!ret && domain) { *iova = domain->iova; else msm_gem_add_obj_to_aspace_active_list(aspace, obj); } else { obj_remove_domain(domain); } return ret; } Loading Loading @@ -441,6 +447,63 @@ void msm_gem_put_iova(struct drm_gem_object *obj, // things that are no longer needed.. } void msm_gem_aspace_domain_attach_detach_update( struct msm_gem_address_space *aspace, bool is_detach) { struct msm_gem_object *msm_obj; struct drm_gem_object *obj; struct aspace_client *aclient; int ret; uint32_t iova; if (!aspace) return; mutex_lock(&aspace->dev->struct_mutex); if (is_detach) { /* Indicate to clients domain is getting detached */ list_for_each_entry(aclient, &aspace->clients, list) { if (aclient->cb) aclient->cb(aclient->cb_data, is_detach); } /** * Unmap active buffers, * typically clients should do this when the callback is called, * but this needs to be done for the framebuffers which are not * attached to any planes. (background apps) */ list_for_each_entry(msm_obj, &aspace->active_list, iova_list) { obj = &msm_obj->base; if (obj->import_attach) { put_iova(obj); put_pages(obj); } } } else { /* map active buffers */ list_for_each_entry(msm_obj, &aspace->active_list, iova_list) { obj = &msm_obj->base; ret = msm_gem_get_iova_locked(obj, aspace, &iova); if (ret) { mutex_unlock(&obj->dev->struct_mutex); return; } } /* Indicate to clients domain is attached */ list_for_each_entry(aclient, &aspace->clients, list) { if (aclient->cb) aclient->cb(aclient->cb_data, is_detach); } } mutex_unlock(&aspace->dev->struct_mutex); } int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { Loading Loading @@ -869,6 +932,7 @@ static int msm_gem_new_impl(struct drm_device *dev, INIT_LIST_HEAD(&msm_obj->submit_entry); INIT_LIST_HEAD(&msm_obj->domains); INIT_LIST_HEAD(&msm_obj->iova_list); list_add_tail(&msm_obj->mm_list, &priv->inactive_list); Loading drivers/gpu/drm/msm/msm_gem.h +26 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ #define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */ #define MSM_BO_KEEPATTRS 0x20000000 /* keep h/w bus attributes */ struct msm_gem_object; struct msm_gem_aspace_ops { int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *, struct sg_table *sgt, void *priv, unsigned int flags); Loading @@ -33,12 +35,35 @@ struct msm_gem_aspace_ops { struct sg_table *sgt, void *priv); void (*destroy)(struct msm_gem_address_space *); void (*add_to_active)(struct msm_gem_address_space *, struct msm_gem_object *); void (*remove_from_active)(struct msm_gem_address_space *, struct msm_gem_object *); int (*register_cb)(struct msm_gem_address_space *, void (*cb)(void *, bool), void *); int (*unregister_cb)(struct msm_gem_address_space *, void (*cb)(void *, bool), void *); }; struct aspace_client { void (*cb)(void *, bool); void *cb_data; struct list_head list; }; struct msm_gem_address_space { const char *name; struct msm_mmu *mmu; const struct msm_gem_aspace_ops *ops; bool domain_attached; struct drm_device *dev; /* list of mapped objects */ struct list_head active_list; /* list of clients */ struct list_head clients; }; struct msm_gem_vma { Loading Loading @@ -96,6 +121,7 @@ struct msm_gem_object { * an IOMMU. Also used for stolen/splashscreen buffer. */ struct drm_mm_node *vram_node; struct list_head iova_list; }; #define to_msm_bo(x) container_of(x, struct msm_gem_object, base) Loading drivers/gpu/drm/msm/msm_gem_vma.c +143 −2 Original line number Diff line number Diff line Loading @@ -44,6 +44,9 @@ static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace, struct dma_buf *buf = priv; int ret; if (!aspace || !aspace->domain_attached) return -EINVAL; if (buf) ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf, DMA_BIDIRECTIONAL, flags); Loading @@ -62,15 +65,109 @@ static void smmu_aspace_destroy(struct msm_gem_address_space *aspace) aspace->mmu->funcs->destroy(aspace->mmu); } static void smmu_aspace_add_to_active( struct msm_gem_address_space *aspace, struct msm_gem_object *msm_obj) { WARN_ON(!mutex_is_locked(&aspace->dev->struct_mutex)); list_move_tail(&msm_obj->iova_list, &aspace->active_list); } static void smmu_aspace_remove_from_active( struct msm_gem_address_space *aspace, struct msm_gem_object *obj) { struct msm_gem_object *msm_obj, *next; WARN_ON(!mutex_is_locked(&aspace->dev->struct_mutex)); list_for_each_entry_safe(msm_obj, next, &aspace->active_list, iova_list) { if (msm_obj == obj) { list_del(&msm_obj->iova_list); break; } } } static int smmu_aspace_register_cb( struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data) { struct aspace_client *aclient = NULL; struct aspace_client *temp; if (!aspace) return -EINVAL; if (!aspace->domain_attached) return -EACCES; aclient = kzalloc(sizeof(*aclient), GFP_KERNEL); if (!aclient) return -ENOMEM; aclient->cb = cb; aclient->cb_data = cb_data; INIT_LIST_HEAD(&aclient->list); /* check if callback is already registered */ mutex_lock(&aspace->dev->struct_mutex); list_for_each_entry(temp, &aspace->clients, list) { if ((temp->cb == aclient->cb) && (temp->cb_data == aclient->cb_data)) { kfree(aclient); mutex_unlock(&aspace->dev->struct_mutex); return -EEXIST; } } list_move_tail(&aclient->list, &aspace->clients); mutex_unlock(&aspace->dev->struct_mutex); return 0; } static int smmu_aspace_unregister_cb( struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data) { struct aspace_client *aclient = NULL; int rc = -ENOENT; if (!aspace || !cb) return -EINVAL; mutex_lock(&aspace->dev->struct_mutex); list_for_each_entry(aclient, &aspace->clients, list) { if ((aclient->cb == cb) && (aclient->cb_data == cb_data)) { list_del(&aclient->list); kfree(aclient); rc = 0; break; } } mutex_unlock(&aspace->dev->struct_mutex); return rc; } static const struct msm_gem_aspace_ops smmu_aspace_ops = { .map = smmu_aspace_map_vma, .unmap = smmu_aspace_unmap_vma, .destroy = smmu_aspace_destroy .destroy = smmu_aspace_destroy, .add_to_active = smmu_aspace_add_to_active, .remove_from_active = smmu_aspace_remove_from_active, .register_cb = smmu_aspace_register_cb, .unregister_cb = smmu_aspace_unregister_cb, }; struct msm_gem_address_space * msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, msm_gem_smmu_address_space_create(struct drm_device *dev, struct msm_mmu *mmu, const char *name) { struct msm_gem_address_space *aspace; Loading @@ -82,9 +179,12 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, if (!aspace) return ERR_PTR(-ENOMEM); aspace->dev = dev; aspace->name = name; aspace->mmu = mmu; aspace->ops = &smmu_aspace_ops; INIT_LIST_HEAD(&aspace->active_list); INIT_LIST_HEAD(&aspace->clients); return aspace; } Loading Loading @@ -218,3 +318,44 @@ msm_gem_address_space_destroy(struct msm_gem_address_space *aspace) kfree(aspace); } void msm_gem_add_obj_to_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); if (aspace && aspace->ops && aspace->ops->add_to_active) aspace->ops->add_to_active(aspace, msm_obj); } void msm_gem_remove_obj_from_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); if (aspace && aspace->ops && aspace->ops->remove_from_active) aspace->ops->remove_from_active(aspace, msm_obj); } int msm_gem_address_space_register_cb(struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data) { if (aspace && aspace->ops && aspace->ops->register_cb) return aspace->ops->register_cb(aspace, cb, cb_data); return -EINVAL; } int msm_gem_address_space_unregister_cb(struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data) { if (aspace && aspace->ops && aspace->ops->unregister_cb) return aspace->ops->unregister_cb(aspace, cb, cb_data); return -EINVAL; } Loading
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +1 −1 Original line number Diff line number Diff line Loading @@ -617,7 +617,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) goto fail; } aspace = msm_gem_smmu_address_space_create(&pdev->dev, aspace = msm_gem_smmu_address_space_create(dev, mmu, "mdp5"); if (IS_ERR(aspace)) { ret = PTR_ERR(aspace); Loading
drivers/gpu/drm/msm/msm_drv.h +45 −1 Original line number Diff line number Diff line Loading @@ -662,13 +662,57 @@ msm_gem_address_space_create(struct device *dev, struct iommu_domain *domain, /* For SDE display */ struct msm_gem_address_space * msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, msm_gem_smmu_address_space_create(struct drm_device *dev, struct msm_mmu *mmu, const char *name); /** * msm_gem_add_obj_to_aspace_active_list: adds obj to active obj list in aspace */ void msm_gem_add_obj_to_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj); /** * msm_gem_remove_obj_from_aspace_active_list: removes obj from active obj * list in aspace */ void msm_gem_remove_obj_from_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj); /** * msm_gem_smmu_address_space_get: returns the aspace pointer for the requested * domain */ struct msm_gem_address_space * msm_gem_smmu_address_space_get(struct drm_device *dev, unsigned int domain); /** * msm_gem_aspace_domain_attach_detach: function to inform the attach/detach * of the domain for this aspace */ void msm_gem_aspace_domain_attach_detach_update( struct msm_gem_address_space *aspace, bool is_detach); /** * msm_gem_address_space_register_cb: function to register callback for attach * and detach of the domain */ int msm_gem_address_space_register_cb( struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data); /** * msm_gem_address_space_register_cb: function to unregister callback */ int msm_gem_address_space_unregister_cb( struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data); int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file); Loading
drivers/gpu/drm/msm/msm_gem.c +66 −2 Original line number Diff line number Diff line Loading @@ -311,6 +311,10 @@ put_iova(struct drm_gem_object *obj) if (iommu_present(&platform_bus_type)) { msm_gem_unmap_vma(domain->aspace, domain, msm_obj->sgt, get_dmabuf_ptr(obj)); msm_gem_remove_obj_from_aspace_active_list( domain->aspace, obj); } obj_remove_domain(domain); Loading Loading @@ -390,10 +394,12 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, msm_obj->flags); } if (!ret && domain) if (!ret && domain) { *iova = domain->iova; else msm_gem_add_obj_to_aspace_active_list(aspace, obj); } else { obj_remove_domain(domain); } return ret; } Loading Loading @@ -441,6 +447,63 @@ void msm_gem_put_iova(struct drm_gem_object *obj, // things that are no longer needed.. } void msm_gem_aspace_domain_attach_detach_update( struct msm_gem_address_space *aspace, bool is_detach) { struct msm_gem_object *msm_obj; struct drm_gem_object *obj; struct aspace_client *aclient; int ret; uint32_t iova; if (!aspace) return; mutex_lock(&aspace->dev->struct_mutex); if (is_detach) { /* Indicate to clients domain is getting detached */ list_for_each_entry(aclient, &aspace->clients, list) { if (aclient->cb) aclient->cb(aclient->cb_data, is_detach); } /** * Unmap active buffers, * typically clients should do this when the callback is called, * but this needs to be done for the framebuffers which are not * attached to any planes. (background apps) */ list_for_each_entry(msm_obj, &aspace->active_list, iova_list) { obj = &msm_obj->base; if (obj->import_attach) { put_iova(obj); put_pages(obj); } } } else { /* map active buffers */ list_for_each_entry(msm_obj, &aspace->active_list, iova_list) { obj = &msm_obj->base; ret = msm_gem_get_iova_locked(obj, aspace, &iova); if (ret) { mutex_unlock(&obj->dev->struct_mutex); return; } } /* Indicate to clients domain is attached */ list_for_each_entry(aclient, &aspace->clients, list) { if (aclient->cb) aclient->cb(aclient->cb_data, is_detach); } } mutex_unlock(&aspace->dev->struct_mutex); } int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args) { Loading Loading @@ -869,6 +932,7 @@ static int msm_gem_new_impl(struct drm_device *dev, INIT_LIST_HEAD(&msm_obj->submit_entry); INIT_LIST_HEAD(&msm_obj->domains); INIT_LIST_HEAD(&msm_obj->iova_list); list_add_tail(&msm_obj->mm_list, &priv->inactive_list); Loading
drivers/gpu/drm/msm/msm_gem.h +26 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,8 @@ #define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */ #define MSM_BO_KEEPATTRS 0x20000000 /* keep h/w bus attributes */ struct msm_gem_object; struct msm_gem_aspace_ops { int (*map)(struct msm_gem_address_space *, struct msm_gem_vma *, struct sg_table *sgt, void *priv, unsigned int flags); Loading @@ -33,12 +35,35 @@ struct msm_gem_aspace_ops { struct sg_table *sgt, void *priv); void (*destroy)(struct msm_gem_address_space *); void (*add_to_active)(struct msm_gem_address_space *, struct msm_gem_object *); void (*remove_from_active)(struct msm_gem_address_space *, struct msm_gem_object *); int (*register_cb)(struct msm_gem_address_space *, void (*cb)(void *, bool), void *); int (*unregister_cb)(struct msm_gem_address_space *, void (*cb)(void *, bool), void *); }; struct aspace_client { void (*cb)(void *, bool); void *cb_data; struct list_head list; }; struct msm_gem_address_space { const char *name; struct msm_mmu *mmu; const struct msm_gem_aspace_ops *ops; bool domain_attached; struct drm_device *dev; /* list of mapped objects */ struct list_head active_list; /* list of clients */ struct list_head clients; }; struct msm_gem_vma { Loading Loading @@ -96,6 +121,7 @@ struct msm_gem_object { * an IOMMU. Also used for stolen/splashscreen buffer. */ struct drm_mm_node *vram_node; struct list_head iova_list; }; #define to_msm_bo(x) container_of(x, struct msm_gem_object, base) Loading
drivers/gpu/drm/msm/msm_gem_vma.c +143 −2 Original line number Diff line number Diff line Loading @@ -44,6 +44,9 @@ static int smmu_aspace_map_vma(struct msm_gem_address_space *aspace, struct dma_buf *buf = priv; int ret; if (!aspace || !aspace->domain_attached) return -EINVAL; if (buf) ret = aspace->mmu->funcs->map_dma_buf(aspace->mmu, sgt, buf, DMA_BIDIRECTIONAL, flags); Loading @@ -62,15 +65,109 @@ static void smmu_aspace_destroy(struct msm_gem_address_space *aspace) aspace->mmu->funcs->destroy(aspace->mmu); } static void smmu_aspace_add_to_active( struct msm_gem_address_space *aspace, struct msm_gem_object *msm_obj) { WARN_ON(!mutex_is_locked(&aspace->dev->struct_mutex)); list_move_tail(&msm_obj->iova_list, &aspace->active_list); } static void smmu_aspace_remove_from_active( struct msm_gem_address_space *aspace, struct msm_gem_object *obj) { struct msm_gem_object *msm_obj, *next; WARN_ON(!mutex_is_locked(&aspace->dev->struct_mutex)); list_for_each_entry_safe(msm_obj, next, &aspace->active_list, iova_list) { if (msm_obj == obj) { list_del(&msm_obj->iova_list); break; } } } static int smmu_aspace_register_cb( struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data) { struct aspace_client *aclient = NULL; struct aspace_client *temp; if (!aspace) return -EINVAL; if (!aspace->domain_attached) return -EACCES; aclient = kzalloc(sizeof(*aclient), GFP_KERNEL); if (!aclient) return -ENOMEM; aclient->cb = cb; aclient->cb_data = cb_data; INIT_LIST_HEAD(&aclient->list); /* check if callback is already registered */ mutex_lock(&aspace->dev->struct_mutex); list_for_each_entry(temp, &aspace->clients, list) { if ((temp->cb == aclient->cb) && (temp->cb_data == aclient->cb_data)) { kfree(aclient); mutex_unlock(&aspace->dev->struct_mutex); return -EEXIST; } } list_move_tail(&aclient->list, &aspace->clients); mutex_unlock(&aspace->dev->struct_mutex); return 0; } static int smmu_aspace_unregister_cb( struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data) { struct aspace_client *aclient = NULL; int rc = -ENOENT; if (!aspace || !cb) return -EINVAL; mutex_lock(&aspace->dev->struct_mutex); list_for_each_entry(aclient, &aspace->clients, list) { if ((aclient->cb == cb) && (aclient->cb_data == cb_data)) { list_del(&aclient->list); kfree(aclient); rc = 0; break; } } mutex_unlock(&aspace->dev->struct_mutex); return rc; } static const struct msm_gem_aspace_ops smmu_aspace_ops = { .map = smmu_aspace_map_vma, .unmap = smmu_aspace_unmap_vma, .destroy = smmu_aspace_destroy .destroy = smmu_aspace_destroy, .add_to_active = smmu_aspace_add_to_active, .remove_from_active = smmu_aspace_remove_from_active, .register_cb = smmu_aspace_register_cb, .unregister_cb = smmu_aspace_unregister_cb, }; struct msm_gem_address_space * msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, msm_gem_smmu_address_space_create(struct drm_device *dev, struct msm_mmu *mmu, const char *name) { struct msm_gem_address_space *aspace; Loading @@ -82,9 +179,12 @@ msm_gem_smmu_address_space_create(struct device *dev, struct msm_mmu *mmu, if (!aspace) return ERR_PTR(-ENOMEM); aspace->dev = dev; aspace->name = name; aspace->mmu = mmu; aspace->ops = &smmu_aspace_ops; INIT_LIST_HEAD(&aspace->active_list); INIT_LIST_HEAD(&aspace->clients); return aspace; } Loading Loading @@ -218,3 +318,44 @@ msm_gem_address_space_destroy(struct msm_gem_address_space *aspace) kfree(aspace); } void msm_gem_add_obj_to_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); if (aspace && aspace->ops && aspace->ops->add_to_active) aspace->ops->add_to_active(aspace, msm_obj); } void msm_gem_remove_obj_from_aspace_active_list( struct msm_gem_address_space *aspace, struct drm_gem_object *obj) { struct msm_gem_object *msm_obj = to_msm_bo(obj); if (aspace && aspace->ops && aspace->ops->remove_from_active) aspace->ops->remove_from_active(aspace, msm_obj); } int msm_gem_address_space_register_cb(struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data) { if (aspace && aspace->ops && aspace->ops->register_cb) return aspace->ops->register_cb(aspace, cb, cb_data); return -EINVAL; } int msm_gem_address_space_unregister_cb(struct msm_gem_address_space *aspace, void (*cb)(void *, bool), void *cb_data) { if (aspace && aspace->ops && aspace->ops->unregister_cb) return aspace->ops->unregister_cb(aspace, cb, cb_data); return -EINVAL; }