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

Commit 1572d832 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "soc: qcom: use interruptible wait in cdsprm for rpmsg messages"

parents 792cfbee fd2ac41a
Loading
Loading
Loading
Loading
+109 −100
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <linux/pm_qos.h>
#include <linux/delay.h>
@@ -152,9 +153,8 @@ struct cdsprm {
	struct completion		msg_avail;
	struct cdsprm_request		msg_queue[CDSPRM_MSG_QUEUE_DEPTH];
	unsigned int			msg_queue_idx;
	struct workqueue_struct		*work_queue;
	struct task_struct		*cdsprm_wq_task;
	struct workqueue_struct		*delay_work_queue;
	struct work_struct		cdsprm_work;
	struct work_struct		cdsprm_delay_work;
	struct mutex			rm_lock;
	spinlock_t			l3_lock;
@@ -162,7 +162,6 @@ struct cdsprm {
	struct mutex			rpmsg_lock;
	struct rpmsg_device		*rpmsgdev;
	enum delay_state		dt_state;
	enum delay_state		work_state;
	unsigned long long		timestamp;
	struct pm_qos_request		pm_qos_req;
	unsigned int			qos_latency_us;
@@ -200,6 +199,7 @@ struct cdsprm {

static struct cdsprm gcdsprm;
static LIST_HEAD(cdsprm_list);
DECLARE_WAIT_QUEUE_HEAD(cdsprm_wq);

/**
 * cdsprm_register_cdspl3gov() - Register a method to set L3 clock
@@ -620,57 +620,66 @@ static void cdsprm_rpmsg_send_details(void)
	}
}

static void process_cdsp_request(struct work_struct *work)
static struct cdsprm_request *get_next_request(void)
{
	struct cdsprm_request *req = NULL;
	struct sysmon_msg *msg = NULL;
	unsigned int l3_clock_khz;
	unsigned long flags;
	int result = 0;
	struct sysmon_msg_tx rpmsg_msg_tx;

	while (gcdsprm.work_state ==
			CDSP_DELAY_THREAD_STARTED) {
	spin_lock_irqsave(&gcdsprm.list_lock, flags);
	req = list_first_entry_or_null(&cdsprm_list,
				struct cdsprm_request, node);
		if (req) {
			msg = &req->msg;
			if (!msg) {
				spin_lock_irqsave(&gcdsprm.list_lock, flags);
				list_del(&req->node);
				req->busy = false;
	spin_unlock_irqrestore(&gcdsprm.list_lock,
					flags);
				continue;

	return req;
}

static int process_cdsp_request_thread(void *data)
{
	struct cdsprm_request *req = NULL;
	struct sysmon_msg *msg = NULL;
	unsigned int l3_clock_khz;
	unsigned long flags;
	int result = 0;
	struct sysmon_msg_tx rpmsg_msg_tx;

	while (!kthread_should_stop()) {
		result = wait_event_interruptible(cdsprm_wq,
						(req = get_next_request()));

		if (result)
			continue;

		msg = &req->msg;

		if ((msg->feature_id == SYSMON_CDSP_FEATURE_RM_RX) &&
			gcdsprm.b_qosinitdone) {
			process_rm_request(msg);
		} else if (msg->feature_id ==
			SYSMON_CDSP_FEATURE_L3_RX) {
				l3_clock_khz =
				msg->fs.l3_struct.l3_clock_khz;
			l3_clock_khz = msg->fs.l3_struct.l3_clock_khz;

			spin_lock_irqsave(&gcdsprm.l3_lock, flags);
				gcdsprm.set_l3_freq_cached =
							gcdsprm.set_l3_freq;
			gcdsprm.set_l3_freq_cached = gcdsprm.set_l3_freq;
			spin_unlock_irqrestore(&gcdsprm.l3_lock, flags);

			if (gcdsprm.set_l3_freq_cached) {
					gcdsprm.set_l3_freq_cached(
						l3_clock_khz);
				gcdsprm.set_l3_freq_cached(l3_clock_khz);
				pr_debug("Set L3 clock %d done\n",
					l3_clock_khz);
			}
		} else if (msg->feature_id ==
				SYSMON_CDSP_FEATURE_NPU_LIMIT_RX) {
			mutex_lock(&gcdsprm.npu_activity_lock);

			gcdsprm.set_corner_limit_cached =
						gcdsprm.set_corner_limit;

			if (gcdsprm.set_corner_limit_cached) {
				gcdsprm.npu_corner_limit =
					msg->fs.npu_limit.corner;
				gcdsprm.b_applyingNpuLimit = true;
					result =
					gcdsprm.set_corner_limit_cached(
				result = gcdsprm.set_corner_limit_cached(
						gcdsprm.npu_corner_limit);
				gcdsprm.b_applyingNpuLimit = false;
				pr_debug("Set NPU limit to %d\n",
@@ -679,12 +688,14 @@ static void process_cdsp_request(struct work_struct *work)
				result = -ENOMSG;
				pr_debug("NPU limit not registered\n");
			}

			mutex_unlock(&gcdsprm.npu_activity_lock);
			/*
			 * Send Limit ack back to DSP
			 */
			rpmsg_msg_tx.feature_id =
				SYSMON_CDSP_FEATURE_NPU_LIMIT_TX;

			if (result == 0) {
				rpmsg_msg_tx.fs.npu_limit_ack.corner =
					msg->fs.npu_limit.corner;
@@ -692,13 +703,14 @@ static void process_cdsp_request(struct work_struct *work)
				rpmsg_msg_tx.fs.npu_limit_ack.corner =
						CDSPRM_NPU_CLK_OFF;
			}

			rpmsg_msg_tx.size = sizeof(rpmsg_msg_tx);
			result = rpmsg_send(gcdsprm.rpmsgdev->ept,
				&rpmsg_msg_tx,
				sizeof(rpmsg_msg_tx));

			if (result)
					pr_err("rpmsg send failed %d\n",
					result);
				pr_err("rpmsg send failed %d\n", result);
			else
				pr_debug("NPU limit ack sent\n");
		} else if (msg->feature_id ==
@@ -706,14 +718,14 @@ static void process_cdsp_request(struct work_struct *work)
			cdsprm_rpmsg_send_details();
			pr_debug("Sent preserved data to DSP\n");
		}

		spin_lock_irqsave(&gcdsprm.list_lock, flags);
		list_del(&req->node);
		req->busy = false;
		spin_unlock_irqrestore(&gcdsprm.list_lock, flags);
		} else {
			wait_for_completion(&gcdsprm.msg_avail);
		}
	}

	do_exit(0);
}

static int cdsprm_rpmsg_probe(struct rpmsg_device *dev)
@@ -801,6 +813,7 @@ static int cdsprm_rpmsg_callback(struct rpmsg_device *dev, void *data,

	if (b_valid) {
		spin_lock_irqsave(&gcdsprm.list_lock, flags);

		if (!gcdsprm.msg_queue[gcdsprm.msg_queue_idx].busy) {
			req = &gcdsprm.msg_queue[gcdsprm.msg_queue_idx];
			req->busy = true;
@@ -816,17 +829,10 @@ static int cdsprm_rpmsg_callback(struct rpmsg_device *dev, void *data,
				"Unable to queue cdsp request, no memory\n");
			return -ENOMEM;
		}

		list_add_tail(&req->node, &cdsprm_list);
		spin_unlock_irqrestore(&gcdsprm.list_lock, flags);
		if (gcdsprm.work_state ==
				CDSP_DELAY_THREAD_NOT_STARTED) {
			gcdsprm.work_state =
				CDSP_DELAY_THREAD_STARTED;
			queue_work(gcdsprm.work_queue,
					&gcdsprm.cdsprm_work);
		} else {
			complete(&gcdsprm.msg_avail);
		}
		wake_up_interruptible(&cdsprm_wq);
	}

	return 0;
@@ -1063,10 +1069,12 @@ static int __init cdsprm_init(void)
	init_completion(&gcdsprm.msg_avail);
	init_completion(&gcdsprm.npu_activity_complete);
	init_completion(&gcdsprm.npu_corner_complete);
	gcdsprm.work_queue = create_singlethread_workqueue("cdsprm-wq");

	if (!gcdsprm.work_queue) {
		pr_err("Failed to create rm work queue\n");
	gcdsprm.cdsprm_wq_task = kthread_run(process_cdsp_request_thread,
					NULL, "cdsprm-wq");

	if (!gcdsprm.cdsprm_wq_task) {
		pr_err("Failed to create kernel thread\n");
		return -ENOMEM;
	}

@@ -1080,7 +1088,6 @@ static int __init cdsprm_init(void)
	}

	INIT_WORK(&gcdsprm.cdsprm_delay_work, process_delayed_rm_request);
	INIT_WORK(&gcdsprm.cdsprm_work, process_cdsp_request);
	err = platform_driver_register(&cdsp_rm);

	if (err) {
@@ -1113,7 +1120,7 @@ static int __init cdsprm_init(void)
bail:
	destroy_workqueue(gcdsprm.delay_work_queue);
err_wq:
	destroy_workqueue(gcdsprm.work_queue);
	kthread_stop(gcdsprm.cdsprm_wq_task);

	return err;
}
@@ -1126,9 +1133,11 @@ static void __exit cdsprm_exit(void)
	gcdsprm.b_rpmsg_register = false;
	platform_driver_unregister(&cdsp_rm);
	platform_driver_unregister(&hvx_rm);
	gcdsprm.work_state = CDSP_DELAY_THREAD_NOT_STARTED;
	complete(&gcdsprm.msg_avail);
	destroy_workqueue(gcdsprm.work_queue);

	if (gcdsprm.cdsprm_wq_task)
		kthread_stop(gcdsprm.cdsprm_wq_task);

	destroy_workqueue(gcdsprm.delay_work_queue);
	debugfs_remove_recursive(gcdsprm.debugfs_dir);
}