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

Commit f8d9a466 authored by Benjamin Chan's avatar Benjamin Chan Committed by Gerrit - the friendly Code Review server
Browse files

msm: sde: Convert workq to kernel thread in SDE rotator



Fix performance issue in SDE rotator by coverting workq into kernel
thread. workq priority is not high enough and can be easily preempted.
For sde rotator being used for realtime deadline usecase, it is
necessary to move up the priority of the worker thread, and we need to
move into kernel thread to handle the works.

Change-Id: Id77e80cb69162326a3894a41bec295bb9bd7f5c1
Signed-off-by: default avatarBenjamin Chan <bkchan@codeaurora.org>
parent 20f7009c
Loading
Loading
Loading
Loading
+59 −26
Original line number Diff line number Diff line
@@ -1021,6 +1021,7 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr)
{
	int i, size, ret = 0;
	char name[32];
	struct sched_param param = { .sched_priority = 5 };

	size = sizeof(struct sde_rot_queue) * mgr->queue_count;
	mgr->commitq = devm_kzalloc(mgr->device, size, GFP_KERNEL);
@@ -1031,11 +1032,21 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr)
		snprintf(name, sizeof(name), "rot_commitq_%d_%d",
				mgr->device->id, i);
		SDEROT_DBG("work queue name=%s\n", name);
		mgr->commitq[i].rot_work_queue =
			alloc_ordered_workqueue("%s",
				WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
		if (!mgr->commitq[i].rot_work_queue) {
		kthread_init_worker(&mgr->commitq[i].rot_kw);
		mgr->commitq[i].rot_thread = kthread_run(kthread_worker_fn,
				&mgr->commitq[i].rot_kw, name);
		if (IS_ERR(mgr->commitq[i].rot_thread)) {
			ret = -EPERM;
			mgr->commitq[i].rot_thread = NULL;
			break;
		}

		ret = sched_setscheduler(mgr->commitq[i].rot_thread,
			SCHED_FIFO, &param);
		if (ret) {
			SDEROT_ERR(
				"failed to set kthread priority for commitq %d\n",
				ret);
			break;
		}

@@ -1052,10 +1063,21 @@ static int sde_rotator_init_queue(struct sde_rot_mgr *mgr)
		snprintf(name, sizeof(name), "rot_doneq_%d_%d",
				mgr->device->id, i);
		SDEROT_DBG("work queue name=%s\n", name);
		mgr->doneq[i].rot_work_queue = alloc_ordered_workqueue("%s",
				WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
		if (!mgr->doneq[i].rot_work_queue) {
		kthread_init_worker(&mgr->doneq[i].rot_kw);
		mgr->doneq[i].rot_thread = kthread_run(kthread_worker_fn,
				&mgr->doneq[i].rot_kw, name);
		if (IS_ERR(mgr->doneq[i].rot_thread)) {
			ret = -EPERM;
			mgr->doneq[i].rot_thread = NULL;
			break;
		}

		ret = sched_setscheduler(mgr->doneq[i].rot_thread,
			SCHED_FIFO, &param);
		if (ret) {
			SDEROT_ERR(
				"failed to set kthread priority for doneq %d\n",
				ret);
			break;
		}

@@ -1071,18 +1093,20 @@ static void sde_rotator_deinit_queue(struct sde_rot_mgr *mgr)

	if (mgr->commitq) {
		for (i = 0; i < mgr->queue_count; i++) {
			if (mgr->commitq[i].rot_work_queue)
				destroy_workqueue(
					mgr->commitq[i].rot_work_queue);
			if (mgr->commitq[i].rot_thread) {
				kthread_flush_worker(&mgr->commitq[i].rot_kw);
				kthread_stop(mgr->commitq[i].rot_thread);
			}
		}
		devm_kfree(mgr->device, mgr->commitq);
		mgr->commitq = NULL;
	}
	if (mgr->doneq) {
		for (i = 0; i < mgr->queue_count; i++) {
			if (mgr->doneq[i].rot_work_queue)
				destroy_workqueue(
					mgr->doneq[i].rot_work_queue);
			if (mgr->doneq[i].rot_thread) {
				kthread_flush_worker(&mgr->doneq[i].rot_kw);
				kthread_stop(mgr->doneq[i].rot_thread);
			}
		}
		devm_kfree(mgr->device, mgr->doneq);
		mgr->doneq = NULL;
@@ -1203,7 +1227,7 @@ void sde_rotator_queue_request(struct sde_rot_mgr *mgr,

		if (entry->item.ts)
			entry->item.ts[SDE_ROTATOR_TS_QUEUE] = ktime_get();
		queue_work(queue->rot_work_queue, &entry->commit_work);
		kthread_queue_work(&queue->rot_kw, &entry->commit_work);
	}
}

@@ -1423,12 +1447,13 @@ static void sde_rotator_release_entry(struct sde_rot_mgr *mgr,
 *
 * Note this asynchronous handler is protected by hal lock.
 */
static void sde_rotator_commit_handler(struct work_struct *work)
static void sde_rotator_commit_handler(struct kthread_work *work)
{
	struct sde_rot_entry *entry;
	struct sde_rot_entry_container *request;
	struct sde_rot_hw_resource *hw;
	struct sde_rot_mgr *mgr;
	struct sched_param param = { .sched_priority = 5 };
	int ret;

	entry = container_of(work, struct sde_rot_entry, commit_work);
@@ -1439,6 +1464,12 @@ static void sde_rotator_commit_handler(struct work_struct *work)
		return;
	}

	ret = sched_setscheduler(entry->fenceq->rot_thread, SCHED_FIFO, &param);
	if (ret) {
		SDEROT_WARN("Fail to set kthread priority for fenceq: %d\n",
				ret);
	}

	mgr = entry->private->mgr;

	SDEROT_EVTLOG(
@@ -1514,7 +1545,7 @@ static void sde_rotator_commit_handler(struct work_struct *work)

	SDEROT_EVTLOG(entry->item.session_id, 1);

	queue_work(entry->doneq->rot_work_queue, &entry->done_work);
	kthread_queue_work(&entry->doneq->rot_kw, &entry->done_work);
	sde_rot_mgr_unlock(mgr);
	return;
error:
@@ -1526,8 +1557,8 @@ static void sde_rotator_commit_handler(struct work_struct *work)
	sde_rotator_release_entry(mgr, entry);
	atomic_dec(&request->pending_count);
	atomic_inc(&request->failed_count);
	if (request->retireq && request->retire_work)
		queue_work(request->retireq, request->retire_work);
	if (request->retire_kw && request->retire_work)
		kthread_queue_work(request->retire_kw, request->retire_work);
	sde_rot_mgr_unlock(mgr);
}

@@ -1541,7 +1572,7 @@ static void sde_rotator_commit_handler(struct work_struct *work)
 *
 * Note this asynchronous handler is protected by hal lock.
 */
static void sde_rotator_done_handler(struct work_struct *work)
static void sde_rotator_done_handler(struct kthread_work *work)
{
	struct sde_rot_entry *entry;
	struct sde_rot_entry_container *request;
@@ -1606,8 +1637,8 @@ static void sde_rotator_done_handler(struct work_struct *work)
	ATRACE_INT("sde_rot_done", 1);
	sde_rotator_release_entry(mgr, entry);
	atomic_dec(&request->pending_count);
	if (request->retireq && request->retire_work)
		queue_work(request->retireq, request->retire_work);
	if (request->retire_kw && request->retire_work)
		kthread_queue_work(request->retire_kw, request->retire_work);
	if (entry->item.ts)
		entry->item.ts[SDE_ROTATOR_TS_RETIRE] = ktime_get();
	sde_rot_mgr_unlock(mgr);
@@ -1966,8 +1997,10 @@ static int sde_rotator_add_request(struct sde_rot_mgr *mgr,

		entry->request = req;

		INIT_WORK(&entry->commit_work, sde_rotator_commit_handler);
		INIT_WORK(&entry->done_work, sde_rotator_done_handler);
		kthread_init_work(&entry->commit_work,
				sde_rotator_commit_handler);
		kthread_init_work(&entry->done_work,
				sde_rotator_done_handler);
		SDEROT_DBG(
			"Entry added. wbidx=%u, src{%u,%u,%u,%u}f=%x dst{%u,%u,%u,%u}f=%x session_id=%u\n",
			item->wb_idx,
@@ -2016,8 +2049,8 @@ static void sde_rotator_cancel_request(struct sde_rot_mgr *mgr,
		sde_rot_mgr_unlock(mgr);
		for (i = req->count - 1; i >= 0; i--) {
			entry = req->entries + i;
			cancel_work_sync(&entry->commit_work);
			cancel_work_sync(&entry->done_work);
			kthread_cancel_work_sync(&entry->commit_work);
			kthread_cancel_work_sync(&entry->done_work);
		}
		sde_rot_mgr_lock(mgr);
		SDEROT_DBG("cancel work done\n");
@@ -2134,7 +2167,7 @@ void sde_rotator_commit_request(struct sde_rot_mgr *mgr,

	sde_rot_mgr_unlock(mgr);
	for (i = 0; i < req->count; i++)
		flush_work(&req->entries[i].commit_work);
		kthread_flush_work(&req->entries[i].commit_work);
	sde_rot_mgr_lock(mgr);
}

+7 −6
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/pm_runtime.h>
#include <linux/completion.h>
#include <linux/kthread.h>

#include "sde_rotator_base.h"
#include "sde_rotator_util.h"
@@ -230,7 +230,8 @@ struct sde_rot_hw_resource {
};

struct sde_rot_queue {
	struct workqueue_struct *rot_work_queue;
	struct kthread_worker rot_kw;
	struct task_struct *rot_thread;
	struct sde_rot_timeline *timeline;
	struct sde_rot_hw_resource *hw;
};
@@ -253,8 +254,8 @@ struct sde_rot_entry_container {
	u32 count;
	atomic_t pending_count;
	atomic_t failed_count;
	struct workqueue_struct *retireq;
	struct work_struct *retire_work;
	struct kthread_worker *retire_kw;
	struct kthread_work *retire_work;
	bool finished;
	struct sde_rot_entry *entries;
};
@@ -284,8 +285,8 @@ struct sde_rot_file_private;
 */
struct sde_rot_entry {
	struct sde_rotation_item item;
	struct work_struct commit_work;
	struct work_struct done_work;
	struct kthread_work commit_work;
	struct kthread_work done_work;
	struct sde_rot_queue *commitq;
	struct sde_rot_queue *fenceq;
	struct sde_rot_queue *doneq;
+24 −20
Original line number Diff line number Diff line
@@ -54,8 +54,8 @@
#define SDE_ROTATOR_DEGREE_180		180
#define SDE_ROTATOR_DEGREE_90		90

static void sde_rotator_submit_handler(struct work_struct *work);
static void sde_rotator_retire_handler(struct work_struct *work);
static void sde_rotator_submit_handler(struct kthread_work *work);
static void sde_rotator_retire_handler(struct kthread_work *work);
#ifdef CONFIG_COMPAT
static long sde_rotator_compat_ioctl32(struct file *file,
	unsigned int cmd, unsigned long arg);
@@ -467,8 +467,8 @@ static void sde_rotator_stop_streaming(struct vb2_queue *q)
			SDEDEV_DBG(rot_dev->dev, "cancel request s:%d\n",
					ctx->session_id);
			mutex_unlock(q->lock);
			cancel_work_sync(&request->submit_work);
			cancel_work_sync(&request->retire_work);
			kthread_cancel_work_sync(&request->submit_work);
			kthread_cancel_work_sync(&request->retire_work);
			mutex_lock(q->lock);
			spin_lock(&ctx->list_lock);
			list_del_init(&request->list);
@@ -926,9 +926,9 @@ struct sde_rotator_ctx *sde_rotator_ctx_open(
	for (i = 0 ; i < ARRAY_SIZE(ctx->requests); i++) {
		struct sde_rotator_request *request = &ctx->requests[i];

		INIT_WORK(&request->submit_work,
		kthread_init_work(&request->submit_work,
				sde_rotator_submit_handler);
		INIT_WORK(&request->retire_work,
		kthread_init_work(&request->retire_work,
				sde_rotator_retire_handler);
		request->ctx = ctx;
		INIT_LIST_HEAD(&request->list);
@@ -965,14 +965,16 @@ struct sde_rotator_ctx *sde_rotator_ctx_open(

	snprintf(name, sizeof(name), "rot_fenceq_%d_%d", rot_dev->dev->id,
			ctx->session_id);
	ctx->work_queue.rot_work_queue = alloc_ordered_workqueue("%s",
			WQ_MEM_RECLAIM | WQ_HIGHPRI, name);
	if (!ctx->work_queue.rot_work_queue) {
		SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate workqueue\n");
	kthread_init_worker(&ctx->work_queue.rot_kw);
	ctx->work_queue.rot_thread = kthread_run(kthread_worker_fn,
			&ctx->work_queue.rot_kw, name);
	if (IS_ERR(ctx->work_queue.rot_thread)) {
		SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate kthread\n");
		ret = -EPERM;
		ctx->work_queue.rot_thread = NULL;
		goto error_alloc_workqueue;
	}
	SDEDEV_DBG(ctx->rot_dev->dev, "work queue name=%s\n", name);
	SDEDEV_DBG(ctx->rot_dev->dev, "kthread name=%s\n", name);

	snprintf(name, sizeof(name), "%d_%d", rot_dev->dev->id,
			ctx->session_id);
@@ -1022,7 +1024,8 @@ struct sde_rotator_ctx *sde_rotator_ctx_open(
error_open_session:
	sde_rot_mgr_unlock(rot_dev->mgr);
	sde_rotator_destroy_timeline(ctx->work_queue.timeline);
	destroy_workqueue(ctx->work_queue.rot_work_queue);
	kthread_flush_worker(&ctx->work_queue.rot_kw);
	kthread_stop(ctx->work_queue.rot_thread);
error_alloc_workqueue:
	sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group);
error_create_sysfs:
@@ -1072,7 +1075,7 @@ static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx,

		SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n",
				session_id);
		cancel_work_sync(&request->submit_work);
		kthread_cancel_work_sync(&request->submit_work);
	}
	SDEDEV_DBG(rot_dev->dev, "release session s:%d\n", session_id);
	sde_rot_mgr_lock(rot_dev->mgr);
@@ -1085,12 +1088,13 @@ static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx,

		SDEDEV_DBG(rot_dev->dev, "release retire work s:%d\n",
				session_id);
		cancel_work_sync(&request->retire_work);
		kthread_cancel_work_sync(&request->retire_work);
	}
	mutex_lock(&rot_dev->lock);
	SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id);
	sde_rotator_destroy_timeline(ctx->work_queue.timeline);
	destroy_workqueue(ctx->work_queue.rot_work_queue);
	kthread_flush_worker(&ctx->work_queue.rot_kw);
	kthread_stop(ctx->work_queue.rot_thread);
	sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group);
	kobject_put(&ctx->kobj);
	if (ctx->file) {
@@ -1609,7 +1613,7 @@ int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd,
		} else {
			SDEROT_ERR("invalid stats timestamp\n");
		}
		req->retireq = ctx->work_queue.rot_work_queue;
		req->retire_kw = &ctx->work_queue.rot_kw;
		req->retire_work = &request->retire_work;

		trace_rot_entry_fence(
@@ -2719,7 +2723,7 @@ static const struct v4l2_ioctl_ops sde_rotator_ioctl_ops = {
 *
 * This function is scheduled in work queue context.
 */
static void sde_rotator_retire_handler(struct work_struct *work)
static void sde_rotator_retire_handler(struct kthread_work *work)
{
	struct vb2_v4l2_buffer *src_buf;
	struct vb2_v4l2_buffer *dst_buf;
@@ -2909,7 +2913,7 @@ static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx,
		goto error_init_request;
	}

	req->retireq = ctx->work_queue.rot_work_queue;
	req->retire_kw = &ctx->work_queue.rot_kw;
	req->retire_work = &request->retire_work;

	ret = sde_rotator_handle_request_common(
@@ -2938,7 +2942,7 @@ static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx,
 *
 * This function is scheduled in work queue context.
 */
static void sde_rotator_submit_handler(struct work_struct *work)
static void sde_rotator_submit_handler(struct kthread_work *work)
{
	struct sde_rotator_ctx *ctx;
	struct sde_rotator_device *rot_dev;
@@ -3203,7 +3207,7 @@ static int sde_rotator_job_ready(void *priv)
			list_del_init(&request->list);
			list_add_tail(&request->list, &ctx->pending_list);
			spin_unlock(&ctx->list_lock);
			queue_work(ctx->work_queue.rot_work_queue,
			kthread_queue_work(&ctx->work_queue.rot_kw,
					&request->submit_work);
		}
	} else if (request && !atomic_read(&request->req->pending_count)) {
+3 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/msm-bus.h>
#include <linux/platform_device.h>
#include <linux/soc/qcom/llcc-qcom.h>
#include <linux/kthread.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
@@ -95,8 +96,8 @@ struct sde_rotator_vbinfo {
 */
struct sde_rotator_request {
	struct list_head list;
	struct work_struct submit_work;
	struct work_struct retire_work;
	struct kthread_work submit_work;
	struct kthread_work retire_work;
	struct sde_rot_entry_container *req;
	struct sde_rotator_ctx *ctx;
	bool committed;