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

Commit 867efd5e authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: Offload mementry destroy work to separate thread"

parents cdf176a9 bd64cac9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -766,7 +766,7 @@ void a6xx_preemption_context_destroy(struct kgsl_context *context)
	gpumem_free_entry(context->user_ctxt_record);

	/* Put the extra ref from gpumem_alloc_entry() */
	kgsl_mem_entry_put(context->user_ctxt_record);
	kgsl_mem_entry_put_deferred(context->user_ctxt_record);
}

int a6xx_preemption_context_init(struct kgsl_context *context)
+51 −27
Original line number Diff line number Diff line
@@ -223,15 +223,6 @@ int kgsl_readtimestamp(struct kgsl_device *device, void *priv,
}
EXPORT_SYMBOL(kgsl_readtimestamp);

/* Scheduled by kgsl_mem_entry_put_deferred() */
static void _deferred_put(struct work_struct *work)
{
	struct kgsl_mem_entry *entry =
		container_of(work, struct kgsl_mem_entry, work);

	kgsl_mem_entry_put(entry);
}

static struct kgsl_mem_entry *kgsl_mem_entry_create(void)
{
	struct kgsl_mem_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
@@ -317,17 +308,10 @@ static void kgsl_destroy_ion(struct kgsl_dma_buf_meta *meta)
}
#endif

void
kgsl_mem_entry_destroy(struct kref *kref)
static void mem_entry_destroy(struct kgsl_mem_entry *entry)
{
	struct kgsl_mem_entry *entry = container_of(kref,
						    struct kgsl_mem_entry,
						    refcount);
	unsigned int memtype;

	if (entry == NULL)
		return;

	/* pull out the memtype before the flags get cleared */
	memtype = kgsl_memdesc_usermem_type(&entry->memdesc);

@@ -379,8 +363,34 @@ kgsl_mem_entry_destroy(struct kref *kref)

	kfree(entry);
}

static void _deferred_destroy(struct work_struct *work)
{
	struct kgsl_mem_entry *entry =
		container_of(work, struct kgsl_mem_entry, work);

	mem_entry_destroy(entry);
}

void kgsl_mem_entry_destroy(struct kref *kref)
{
	struct kgsl_mem_entry *entry =
		container_of(kref, struct kgsl_mem_entry, refcount);

	mem_entry_destroy(entry);
}
EXPORT_SYMBOL(kgsl_mem_entry_destroy);

void kgsl_mem_entry_destroy_deferred(struct kref *kref)
{
	struct kgsl_mem_entry *entry =
		container_of(kref, struct kgsl_mem_entry, refcount);

	INIT_WORK(&entry->work, _deferred_destroy);
	queue_work(kgsl_driver.mem_workqueue, &entry->work);
}
EXPORT_SYMBOL(kgsl_mem_entry_destroy_deferred);

/* Allocate a IOVA for memory objects that don't use SVM */
static int kgsl_mem_entry_track_gpuaddr(struct kgsl_device *device,
		struct kgsl_process_private *process,
@@ -936,6 +946,13 @@ static struct kgsl_process_private *kgsl_process_private_new(
	struct kgsl_process_private *private;
	pid_t tgid = task_tgid_nr(current);

	/*
	 * Flush mem_workqueue to make sure that any lingering
	 * structs (process pagetable etc) are released before
	 * starting over again.
	 */
	flush_workqueue(kgsl_driver.mem_workqueue);

	/* Search in the process list */
	list_for_each_entry(private, &kgsl_driver.process_list, list) {
		if (private->pid == tgid) {
@@ -998,7 +1015,7 @@ static void process_release_memory(struct kgsl_process_private *private)
		if (!entry->pending_free) {
			entry->pending_free = 1;
			spin_unlock(&private->mem_lock);
			kgsl_mem_entry_put(entry);
			kgsl_mem_entry_put_deferred(entry);
		} else {
			spin_unlock(&private->mem_lock);
		}
@@ -2197,7 +2214,7 @@ long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
		return -EINVAL;

	ret = gpumem_free_entry(entry);
	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put_deferred(entry);

	return ret;
}
@@ -2215,7 +2232,7 @@ long kgsl_ioctl_gpumem_free_id(struct kgsl_device_private *dev_priv,
		return -EINVAL;

	ret = gpumem_free_entry(entry);
	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put_deferred(entry);

	return ret;
}
@@ -2259,8 +2276,7 @@ static bool gpuobj_free_fence_func(void *priv)
			entry->memdesc.gpuaddr, entry->memdesc.size,
			entry->memdesc.flags);

	INIT_WORK(&entry->work, _deferred_put);
	queue_work(kgsl_driver.mem_workqueue, &entry->work);
	kgsl_mem_entry_put_deferred(entry);
	return true;
}

@@ -2325,7 +2341,7 @@ long kgsl_ioctl_gpuobj_free(struct kgsl_device_private *dev_priv,
	else
		ret = -EINVAL;

	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put_deferred(entry);
	return ret;
}

@@ -2355,7 +2371,7 @@ long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid(
	ret = gpumem_free_entry_on_timestamp(dev_priv->device, entry,
		context, param->timestamp);

	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put_deferred(entry);
	kgsl_context_put(context);

	return ret;
@@ -3740,7 +3756,7 @@ long kgsl_ioctl_sparse_phys_free(struct kgsl_device_private *dev_priv,

	/* One put for find_id(), one put for the kgsl_mem_entry_create() */
	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put_deferred(entry);

	return 0;
}
@@ -3824,7 +3840,7 @@ long kgsl_ioctl_sparse_virt_free(struct kgsl_device_private *dev_priv,

	/* One put for find_id(), one put for the kgsl_mem_entry_create() */
	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put_deferred(entry);

	return 0;
}
@@ -4486,7 +4502,7 @@ kgsl_gpumem_vm_close(struct vm_area_struct *vma)
		return;

	entry->memdesc.useraddr = 0;
	kgsl_mem_entry_put(entry);
	kgsl_mem_entry_put_deferred(entry);
}

static const struct vm_operations_struct kgsl_gpumem_vm_ops = {
@@ -5163,6 +5179,12 @@ void kgsl_device_platform_remove(struct kgsl_device *device)
}
EXPORT_SYMBOL(kgsl_device_platform_remove);

static void
_flush_mem_workqueue(struct work_struct *work)
{
	flush_workqueue(kgsl_driver.mem_workqueue);
}

static void kgsl_core_exit(void)
{
	kgsl_events_exit();
@@ -5264,6 +5286,8 @@ static int __init kgsl_core_init(void)
	kgsl_driver.mem_workqueue = alloc_workqueue("kgsl-mementry",
		WQ_UNBOUND | WQ_MEM_RECLAIM, 0);

	INIT_WORK(&kgsl_driver.mem_work, _flush_mem_workqueue);

	kthread_init_worker(&kgsl_driver.worker);

	kgsl_driver.worker_thread = kthread_run(kthread_worker_fn,
+18 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ struct kgsl_context;
 * @full_cache_threshold: the threshold that triggers a full cache flush
 * @workqueue: Pointer to a single threaded workqueue
 * @mem_workqueue: Pointer to a workqueue for deferring memory entries
 * @mem_work: Work struct to schedule mem_workqueue flush
 */
struct kgsl_driver {
	struct cdev cdev;
@@ -150,6 +151,7 @@ struct kgsl_driver {
	unsigned int full_cache_threshold;
	struct workqueue_struct *workqueue;
	struct workqueue_struct *mem_workqueue;
	struct work_struct mem_work;
	struct kthread_worker worker;
	struct task_struct *worker_thread;
};
@@ -425,6 +427,7 @@ long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data);

void kgsl_mem_entry_destroy(struct kref *kref);
void kgsl_mem_entry_destroy_deferred(struct kref *kref);

void kgsl_get_egl_counts(struct kgsl_mem_entry *entry,
			int *egl_surface_count, int *egl_image_count);
@@ -542,6 +545,21 @@ kgsl_mem_entry_put(struct kgsl_mem_entry *entry)
		kref_put(&entry->refcount, kgsl_mem_entry_destroy);
}

/**
 * kgsl_mem_entry_put_deferred - Puts refcount and triggers deferred
 *  mem_entry destroy when refcount goes to zero.
 * @entry: memory entry to be put.
 *
 * Use this to put a memory entry when we don't want to block
 * the caller while destroying memory entry.
 */
static inline void
kgsl_mem_entry_put_deferred(struct kgsl_mem_entry *entry)
{
	if (entry)
		kref_put(&entry->refcount, kgsl_mem_entry_destroy_deferred);
}

/*
 * kgsl_addr_range_overlap() - Checks if 2 ranges overlap
 * @gpuaddr1: Start of first address range
+30 −16
Original line number Diff line number Diff line
@@ -2443,13 +2443,37 @@ static int kgsl_iommu_set_svm_region(struct kgsl_pagetable *pagetable,
	return ret;
}

static int get_gpuaddr(struct kgsl_pagetable *pagetable,
		struct kgsl_memdesc *memdesc, u64 start, u64 end,
		u64 size, unsigned int align)
{
	u64 addr;
	int ret;

	spin_lock(&pagetable->lock);
	addr = _get_unmapped_area(pagetable, start, end, size, align);
	if (addr == (u64) -ENOMEM) {
		spin_unlock(&pagetable->lock);
		return -ENOMEM;
	}

	ret = _insert_gpuaddr(pagetable, addr, size);
	spin_unlock(&pagetable->lock);

	if (ret == 0) {
		memdesc->gpuaddr = addr;
		memdesc->pagetable = pagetable;
	}

	return ret;
}

static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable,
		struct kgsl_memdesc *memdesc)
{
	struct kgsl_iommu_pt *pt = pagetable->priv;
	int ret = 0;
	uint64_t addr, start, end, size;
	u64 start, end, size;
	unsigned int align;

	if (WARN_ON(kgsl_memdesc_use_cpu_map(memdesc)))
@@ -2479,23 +2503,13 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable,
	if (kgsl_memdesc_is_secured(memdesc))
		start += secure_global_size;

	spin_lock(&pagetable->lock);

	addr = _get_unmapped_area(pagetable, start, end, size, align);

	if (addr == (uint64_t) -ENOMEM) {
		ret = -ENOMEM;
		goto out;
	}

	ret = _insert_gpuaddr(pagetable, addr, size);
	if (ret == 0) {
		memdesc->gpuaddr = addr;
		memdesc->pagetable = pagetable;
	ret = get_gpuaddr(pagetable, memdesc, start, end, size, align);
	/* if OoM, retry once after flushing mem_wq */
	if (ret == -ENOMEM) {
		flush_workqueue(kgsl_driver.mem_workqueue);
		ret = get_gpuaddr(pagetable, memdesc, start, end, size, align);
	}

out:
	spin_unlock(&pagetable->lock);
	return ret;
}

+3 −0
Original line number Diff line number Diff line
@@ -508,6 +508,9 @@ static unsigned long
kgsl_pool_shrink_count_objects(struct shrinker *shrinker,
					struct shrink_control *sc)
{
	/* Trigger mem_workqueue flush to free memory */
	kgsl_schedule_work(&kgsl_driver.mem_work);

	/* Return total pool size as everything in pool can be freed */
	return kgsl_pool_size_total();
}
Loading