Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4657b1e authored by Abhijit Kulkarni's avatar Abhijit Kulkarni
Browse files

drm/msm/sde: unmap buffers when context is detached



When a context bank is detached all the gem objects iova
becomes invalid, so there is need to unmap all the gem objects.
After attach of the context bank, the buffers can be mapped again
properly. This change adds support of maintaining an active list
for the address space and unmaps the buffers when the domain is
detached. Before unmapping the buffers all the clients need to
be informed that detach is pending or reattach has happened so
that they can take necessary steps before the domain change
condition.
This change is required for switching between secure and non
secure state in Secure display and secure camera use case.

CRs-Fixed: 2064272
Change-Id: I33022e15a369ac7d42b7965d97b4b14d86e6b0fa
Signed-off-by: default avatarAbhijit Kulkarni <kabhijit@codeaurora.org>
parent 329a94d9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+45 −1
Original line number Diff line number Diff line
@@ -660,13 +660,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);

+66 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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;
}
@@ -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)
{
@@ -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);

+25 −0
Original line number Diff line number Diff line
@@ -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);
@@ -33,13 +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 {
@@ -97,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)

+143 −2
Original line number Diff line number Diff line
@@ -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);
@@ -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;
@@ -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;
}
@@ -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