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

Commit 734cd7d0 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 1996ec83 f4657b1e
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
@@ -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);

+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);

+26 −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,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 {
@@ -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)

+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