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

Commit af1ba47f authored by Shubhraprakash Das's avatar Shubhraprakash Das
Browse files

msm: kgsl: Get reference to process private when attaching mem entry



When a memory entry is attached with to a process private list then
increment the refcount of the process private structure so that the
structure is valid as long as the entry is around. The context
structure is also handled in similar manner. Also, the refcount to
the entry needs to be decremented when the handle that created the
entry goes away and not when the process private structure is
destroyed.

Change-Id: I225698ad4081947a93eb553104e5259bbf31f293
Signed-off-by: default avatarShubhraprakash Das <sadas@codeaurora.org>
parent afa92a79
Loading
Loading
Loading
Loading
+39 −27
Original line number Diff line number Diff line
@@ -343,22 +343,29 @@ kgsl_mem_entry_untrack_gpuaddr(struct kgsl_process_private *process,
 */
static int
kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
				   struct kgsl_process_private *process)
				   struct kgsl_device_private *dev_priv)
{
	int id;
	int ret;
	struct kgsl_process_private *process = dev_priv->process_priv;

	ret = kref_get_unless_zero(&process->refcount);
	if (!ret)
		return -EBADF;
	idr_preload(GFP_KERNEL);
	spin_lock(&process->mem_lock);
	id = idr_alloc(&process->mem_idr, entry, 1, 0, GFP_NOWAIT);
	spin_unlock(&process->mem_lock);
	idr_preload_end();

	if (id < 0)
		return id;
	if (id < 0) {
		ret = id;
		goto err_put_proc_priv;
	}

	entry->id = id;
	entry->priv = process;
	entry->dev_priv = dev_priv;

	spin_lock(&process->mem_lock);
	ret = kgsl_mem_entry_track_gpuaddr(process, entry);
@@ -366,14 +373,17 @@ kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
		idr_remove(&process->mem_idr, entry->id);
	spin_unlock(&process->mem_lock);
	if (ret)
		goto err;
		goto err_put_proc_priv;
	/* map the memory after unlocking if gpuaddr has been assigned */
	if (entry->memdesc.gpuaddr) {
		ret = kgsl_mmu_map(process->pagetable, &entry->memdesc);
		if (ret)
			kgsl_mem_entry_detach_process(entry);
	}
err:
	return ret;

err_put_proc_priv:
	kgsl_put_process_private(dev_priv->device, process);
	return ret;
}

@@ -396,6 +406,7 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)

	entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
	spin_unlock(&entry->priv->mem_lock);
	kgsl_put_process_private(entry->dev_priv->device, entry->priv);

	entry->priv = NULL;
}
@@ -748,11 +759,6 @@ EXPORT_SYMBOL(kgsl_resume_driver);
 */
static void kgsl_destroy_process_private(struct kref *kref)
{

	struct kgsl_mem_entry *entry = NULL;
	int next = 0;


	struct kgsl_process_private *private = container_of(kref,
			struct kgsl_process_private, refcount);

@@ -776,20 +782,6 @@ static void kgsl_destroy_process_private(struct kref *kref)
	if (private->debug_root)
		debugfs_remove_recursive(private->debug_root);

	while (1) {
		spin_lock(&private->mem_lock);
		entry = idr_get_next(&private->mem_idr, &next);
		spin_unlock(&private->mem_lock);
		if (entry == NULL)
			break;
		kgsl_mem_entry_put(entry);
		/*
		 * Always start back at the beginning, to
		 * ensure all entries are removed,
		 * like list_for_each_entry_safe.
		 */
		next = 0;
	}
	idr_destroy(&private->mem_idr);
	kgsl_mmu_putpagetable(private->pagetable);

@@ -939,6 +931,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep)
	struct kgsl_process_private *private = dev_priv->process_priv;
	struct kgsl_device *device = dev_priv->device;
	struct kgsl_context *context;
	struct kgsl_mem_entry *entry;
	int next = 0;

	filep->private_data = NULL;
@@ -968,6 +961,25 @@ static int kgsl_release(struct inode *inodep, struct file *filep)

		next = next + 1;
	}
	next = 0;
	while (1) {
		spin_lock(&private->mem_lock);
		entry = idr_get_next(&private->mem_idr, &next);
		spin_unlock(&private->mem_lock);
		if (entry == NULL)
			break;
		/*
		 * If the free pending flag is not set it means that user space
		 * did not free it's reference to this entry, in that case
		 * free a reference to this entry, other references are from
		 * within kgsl so they will be freed eventually by kgsl
		 */
		if (entry->dev_priv == dev_priv && !entry->pending_free) {
			entry->pending_free = 1;
			kgsl_mem_entry_put(entry);
		}
		next = next + 1;
	}
	/*
	 * Clean up any to-be-freed entries that belong to this
	 * process and this device. This is done after the context
@@ -2736,7 +2748,7 @@ static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
	/* echo back flags */
	param->flags = entry->memdesc.flags;

	result = kgsl_mem_entry_attach_process(entry, private);
	result = kgsl_mem_entry_attach_process(entry, dev_priv);
	if (result)
		goto error_attach;

@@ -3024,7 +3036,7 @@ kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv,
	if (result)
		return result;

	result = kgsl_mem_entry_attach_process(entry, private);
	result = kgsl_mem_entry_attach_process(entry, dev_priv);
	if (result != 0)
		goto err;

@@ -3057,7 +3069,7 @@ kgsl_ioctl_gpumem_alloc_id(struct kgsl_device_private *dev_priv,
	if (result != 0)
		goto err;

	result = kgsl_mem_entry_attach_process(entry, private);
	result = kgsl_mem_entry_attach_process(entry, dev_priv);
	if (result != 0)
		goto err;

+1 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ struct kgsl_mem_entry {
	struct kgsl_process_private *priv;
	/* Initialized to 0, set to 1 when entry is marked for freeing */
	int pending_free;
	struct kgsl_device_private *dev_priv;
};

#ifdef CONFIG_MSM_KGSL_MMU_PAGE_FAULT