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

Commit 8872fd10 authored by Ajay Singh Parmar's avatar Ajay Singh Parmar
Browse files

drm/msm/dp: clean up hdcp threads



Currently, sde-hdcp2p2 and dp-hdcp2p2 modules maintain their
own threads and queue different works based on the functionalities
they are going to perform. These threads support executing only
one work at a given time. To simplify the implementation, remove
all the works that these threads execute. Instead implement just
one main work that is run continuously on each of these thread.
The threads go to sleep if not being executed. To support the
asynchronous behavior of these threads, implement a fifo queue.
This queue manages the commands to be executed by the thread.
Every time a command is queued to the queue, the thread is pinged
to execute it.

CRs-Fixed: 2393144d
Change-Id: Iee3522f06934c753cda19d13d9bee65b41d6b407
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent b451b394
Loading
Loading
Loading
Loading
+1 −19
Original line number Diff line number Diff line
@@ -712,28 +712,10 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp)

static int dp_display_process_hpd_low(struct dp_display_private *dp)
{
	int rc = 0, idx;
	struct dp_panel *dp_panel;

	mutex_lock(&dp->session_lock);
	int rc = 0;

	dp->is_connected = false;

	if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off)
		dp->hdcp.ops->off(dp->hdcp.data);

	for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) {
		if (!dp->active_panels[idx])
			continue;

		dp_panel = dp->active_panels[idx];

		if (dp_panel->audio_supported)
			dp_panel->audio->off(dp_panel->audio);
	}

	mutex_unlock(&dp->session_lock);

	dp_display_process_mst_hpd_low(dp);

	rc = dp_display_send_hpd_notification(dp);
+86 −72
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/kthread.h>
#include <linux/msm_hdcp.h>
#include <linux/kfifo.h>
#include <drm/drm_dp_helper.h>

#include "sde_hdcp_2x.h"
@@ -28,24 +29,19 @@ enum dp_hdcp2p2_sink_status {
};

struct dp_hdcp2p2_ctrl {
	DECLARE_KFIFO(cmd_q, enum hdcp_transport_wakeup_cmd, 8);
	wait_queue_head_t wait_q;
	atomic_t auth_state;
	enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */
	struct dp_hdcp2p2_interrupts *intr;
	struct sde_hdcp_init_data init_data;
	struct mutex mutex; /* mutex to protect access to ctrl */
	struct mutex msg_lock; /* mutex to protect access to msg buffer */
	struct mutex wakeup_mutex; /* mutex to protect access to wakeup call*/
	struct sde_hdcp_ops *ops;
	void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */
	struct sde_hdcp_2x_ops *lib; /* Ops for driver to call into TZ */
	enum hdcp_transport_wakeup_cmd wakeup_cmd;

	struct task_struct *thread;
	struct kthread_worker worker;
	struct kthread_work auth;
	struct kthread_work send_msg;
	struct kthread_work recv_msg;
	struct kthread_work link;
	struct hdcp2_buffer response;
	struct hdcp2_buffer request;
	uint32_t total_message_length;
@@ -72,7 +68,10 @@ struct dp_hdcp2p2_interrupts {

static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl)
{
	if (ctrl->wakeup_cmd == HDCP_TRANSPORT_CMD_AUTHENTICATE)
	enum hdcp_transport_wakeup_cmd cmd;

	if (kfifo_peek(&ctrl->cmd_q, &cmd) &&
			cmd == HDCP_TRANSPORT_CMD_AUTHENTICATE)
		return true;

	if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE)
@@ -167,58 +166,28 @@ static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data)
		return -EINVAL;
	}

	mutex_lock(&ctrl->wakeup_mutex);

	ctrl->wakeup_cmd = data->cmd;

	if (data->timeout)
		ctrl->timeout = (data->timeout) * 2;
	else
		ctrl->timeout = default_timeout_us;

	if (!dp_hdcp2p2_is_valid_state(ctrl)) {
		pr_err("invalid state\n");
		goto exit;
	}

	if (dp_hdcp2p2_copy_buf(ctrl, data))
		goto exit;

	pr_debug("%s\n", hdcp_transport_cmd_to_str(ctrl->wakeup_cmd));

	switch (ctrl->wakeup_cmd) {
	case HDCP_TRANSPORT_CMD_SEND_MESSAGE:
		kthread_queue_work(&ctrl->worker, &ctrl->send_msg);
		break;
	case HDCP_TRANSPORT_CMD_RECV_MESSAGE:
		kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
		break;
	switch (data->cmd) {
	case HDCP_TRANSPORT_CMD_STATUS_SUCCESS:
		atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATED);
		dp_hdcp2p2_send_auth_status(ctrl);
		break;
	case HDCP_TRANSPORT_CMD_STATUS_FAILED:
		atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
		kthread_cancel_work_sync(&ctrl->link);
		kthread_cancel_work_sync(&ctrl->recv_msg);
		dp_hdcp2p2_set_interrupts(ctrl, false);
		dp_hdcp2p2_send_auth_status(ctrl);
		break;
	case HDCP_TRANSPORT_CMD_LINK_POLL:
		if (ctrl->cp_irq_done)
			kthread_queue_work(&ctrl->worker, &ctrl->recv_msg);
		else
			ctrl->polling = true;
		break;
	case HDCP_TRANSPORT_CMD_AUTHENTICATE:
		kthread_queue_work(&ctrl->worker, &ctrl->auth);
		break;
	default:
		pr_err("invalid wakeup command %d\n", ctrl->wakeup_cmd);
		break;
	}
exit:
	mutex_unlock(&ctrl->wakeup_mutex);

	kfifo_put(&ctrl->cmd_q, data->cmd);
	wake_up(&ctrl->wait_q);
exit:
	return 0;
}

@@ -267,10 +236,10 @@ static void dp_hdcp2p2_off(void *input)

	dp_hdcp2p2_reset(ctrl);

	kthread_flush_worker(&ctrl->worker);

	cdata.context = input;
	dp_hdcp2p2_wakeup(&cdata);

	kthread_park(ctrl->thread);
}

static int dp_hdcp2p2_authenticate(void *input)
@@ -280,13 +249,13 @@ static int dp_hdcp2p2_authenticate(void *input)
					HDCP_TRANSPORT_CMD_AUTHENTICATE};
	int rc = 0;

	kthread_flush_worker(&ctrl->worker);

	dp_hdcp2p2_set_interrupts(ctrl, true);

	ctrl->sink_status = SINK_CONNECTED;
	atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING);

	kthread_unpark(ctrl->thread);

	cdata.context = input;
	dp_hdcp2p2_wakeup(&cdata);

@@ -348,7 +317,7 @@ static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl)
		goto exit;
	}

	pr_debug("request: offset(0x%x), size(%d)\n", offset, size);
	pr_debug("offset(0x%x), size(%d)\n", offset, size);

	do {
		read_size = min(size, max_size);
@@ -377,6 +346,8 @@ static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl,
	int const max_size = 16;
	int rc = 0, write_size = 0, bytes_written = 0;

	pr_debug("offset(0x%x), size(%d)\n", offset, size);

	do {
		write_size = min(size, max_size);

@@ -441,11 +412,9 @@ static void dp_hdcp2p2_force_encryption(void *data, bool enable)
		lib->force_encryption(ctrl->lib_ctx, enable);
}

static void dp_hdcp2p2_send_msg_work(struct kthread_work *work)
static void dp_hdcp2p2_send_msg(struct dp_hdcp2p2_ctrl *ctrl)
{
	int rc = 0;
	struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
		struct dp_hdcp2p2_ctrl, send_msg);
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};

	if (!ctrl) {
@@ -513,11 +482,9 @@ static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl)
	return rc;
}

static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work)
static void dp_hdcp2p2_recv_msg(struct dp_hdcp2p2_ctrl *ctrl)
{
	struct sde_hdcp_2x_wakeup_data cdata = { HDCP_2X_CMD_INVALID };
	struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
		struct dp_hdcp2p2_ctrl, recv_msg);

	cdata.context = ctrl->lib_ctx;

@@ -543,11 +510,9 @@ static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work)
	dp_hdcp2p2_get_msg_from_sink(ctrl);
}

static void dp_hdcp2p2_link_work(struct kthread_work *work)
static void dp_hdcp2p2_link_check(struct dp_hdcp2p2_ctrl *ctrl)
{
	int rc = 0;
	struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
		struct dp_hdcp2p2_ctrl, link);
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};

	if (!ctrl) {
@@ -595,11 +560,9 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work)
		dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
}

static void dp_hdcp2p2_auth_work(struct kthread_work *work)
static void dp_hdcp2p2_manage_session(struct dp_hdcp2p2_ctrl *ctrl)
{
	struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};
	struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
		struct dp_hdcp2p2_ctrl, auth);

	cdata.context = ctrl->lib_ctx;

@@ -684,7 +647,9 @@ static int dp_hdcp2p2_cp_irq(void *input)
		goto error;
	}

	kthread_queue_work(&ctrl->worker, &ctrl->link);

	kfifo_put(&ctrl->cmd_q, HDCP_TRANSPORT_CMD_LINK_CHECK);
	wake_up(&ctrl->wait_q);

	return 0;
error:
@@ -774,10 +739,65 @@ void sde_dp_hdcp2p2_deinit(void *input)

	mutex_destroy(&ctrl->mutex);
	mutex_destroy(&ctrl->msg_lock);
	mutex_destroy(&ctrl->wakeup_mutex);
	kfree(ctrl);
}

static int dp_hdcp2p2_main(void *data)
{
	struct dp_hdcp2p2_ctrl *ctrl = data;
	enum hdcp_transport_wakeup_cmd cmd;

	while (1) {
		wait_event(ctrl->wait_q,
			!kfifo_is_empty(&ctrl->cmd_q) ||
			kthread_should_stop() ||
			kthread_should_park());

		if (kthread_should_stop())
			break;

		if (kfifo_is_empty(&ctrl->cmd_q) && kthread_should_park()) {
			kthread_parkme();
			continue;
		}

		if (!kfifo_get(&ctrl->cmd_q, &cmd))
			continue;

		switch (cmd) {
		case HDCP_TRANSPORT_CMD_SEND_MESSAGE:
			dp_hdcp2p2_send_msg(ctrl);
			break;
		case HDCP_TRANSPORT_CMD_RECV_MESSAGE:
			dp_hdcp2p2_recv_msg(ctrl);
			break;
		case HDCP_TRANSPORT_CMD_STATUS_SUCCESS:
			dp_hdcp2p2_send_auth_status(ctrl);
			break;
		case HDCP_TRANSPORT_CMD_STATUS_FAILED:
			dp_hdcp2p2_set_interrupts(ctrl, false);
			dp_hdcp2p2_send_auth_status(ctrl);
			break;
		case HDCP_TRANSPORT_CMD_LINK_POLL:
			if (ctrl->cp_irq_done)
				dp_hdcp2p2_recv_msg(ctrl);
			else
				ctrl->polling = true;
			break;
		case HDCP_TRANSPORT_CMD_LINK_CHECK:
			dp_hdcp2p2_link_check(ctrl);
			break;
		case HDCP_TRANSPORT_CMD_AUTHENTICATE:
			dp_hdcp2p2_manage_session(ctrl);
			break;
		default:
			break;
		}
	}

	return 0;
}

void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
{
	int rc;
@@ -833,12 +853,14 @@ void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
	ctrl->sink_status = SINK_DISCONNECTED;
	ctrl->intr = intr;

	INIT_KFIFO(ctrl->cmd_q);

	init_waitqueue_head(&ctrl->wait_q);
	atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE);

	ctrl->ops = &ops;
	mutex_init(&ctrl->mutex);
	mutex_init(&ctrl->msg_lock);
	mutex_init(&ctrl->wakeup_mutex);

	register_data.hdcp_data = &ctrl->lib_ctx;
	register_data.client_ops = &client_ops;
@@ -856,15 +878,7 @@ void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
		msm_hdcp_register_cb(init_data->msm_hdcp_dev, ctrl,
				dp_hdcp2p2_min_level_change);

	kthread_init_worker(&ctrl->worker);

	kthread_init_work(&ctrl->auth,     dp_hdcp2p2_auth_work);
	kthread_init_work(&ctrl->send_msg, dp_hdcp2p2_send_msg_work);
	kthread_init_work(&ctrl->recv_msg, dp_hdcp2p2_recv_msg_work);
	kthread_init_work(&ctrl->link,     dp_hdcp2p2_link_work);

	ctrl->thread = kthread_run(kthread_worker_fn,
		&ctrl->worker, "dp_hdcp2p2");
	ctrl->thread = kthread_run(dp_hdcp2p2_main, ctrl, "dp_hdcp2p2");

	if (IS_ERR(ctrl->thread)) {
		pr_err("unable to start DP hdcp2p2 thread\n");
+132 −269
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>

#include "sde_hdcp_2x.h"

@@ -41,11 +42,9 @@
#define REAUTH_REQ BIT(3)
#define LINK_INTEGRITY_FAILURE BIT(4)

#define HDCP_2X_EXECUTE(x) { \
		kthread_queue_work(&hdcp->worker, &hdcp->wk_##x); \
}

struct sde_hdcp_2x_ctrl {
	DECLARE_KFIFO(cmd_q, enum sde_hdcp_2x_wakeup_cmd, 8);
	wait_queue_head_t wait_q;
	struct hdcp2_app_data app_data;
	u32 timeout_left;
	u32 wait_timeout_ms;
@@ -59,8 +58,6 @@ struct sde_hdcp_2x_ctrl {
	void *client_data;
	void *hdcp2_ctx;
	struct hdcp_transport_ops *client_ops;
	struct mutex wakeup_mutex;
	enum sde_hdcp_2x_wakeup_cmd wakeup_cmd;
	bool repeater_flag;
	bool update_stream;
	int last_msg;
@@ -70,18 +67,10 @@ struct sde_hdcp_2x_ctrl {

	struct task_struct *thread;
	struct completion response_completion;

	struct kthread_worker worker;
	struct kthread_work wk_init;
	struct kthread_work wk_msg_sent;
	struct kthread_work wk_msg_recvd;
	struct kthread_work wk_timeout;
	struct kthread_work wk_clean;
	struct kthread_work wk_stream;
	struct kthread_work wk_wait;
	struct kthread_work wk_send_type;
};

static void sde_hdcp_2x_clean(struct sde_hdcp_2x_ctrl *hdcp);

static const char *sde_hdcp_2x_message_name(int msg_id)
{
	switch (msg_id) {
@@ -99,7 +88,8 @@ static const char *sde_hdcp_2x_message_name(int msg_id)
	case REP_STREAM_MANAGE:     return TO_STR(REP_STREAM_MANAGE);
	case REP_STREAM_READY:      return TO_STR(REP_STREAM_READY);
	case SKE_SEND_TYPE_ID:      return TO_STR(SKE_SEND_TYPE_ID);
	default: return "UNKNOWN";
	default:
		return "UNKNOWN";
	}
}

@@ -152,45 +142,6 @@ static const struct sde_hdcp_2x_msg_data
		0 },
};

static void sde_hdcp_2x_check_worker_status(struct sde_hdcp_2x_ctrl *hdcp)
{
	if (!list_empty(&hdcp->wk_init.node))
		pr_debug("init work queued\n");

	if (hdcp->worker.current_work == &hdcp->wk_init)
		pr_debug("init work executing\n");

	if (!list_empty(&hdcp->wk_msg_sent.node))
		pr_debug("msg_sent work queued\n");

	if (hdcp->worker.current_work == &hdcp->wk_msg_sent)
		pr_debug("msg_sent work executing\n");

	if (!list_empty(&hdcp->wk_msg_recvd.node))
		pr_debug("msg_recvd work queued\n");

	if (hdcp->worker.current_work == &hdcp->wk_msg_recvd)
		pr_debug("msg_recvd work executing\n");

	if (!list_empty(&hdcp->wk_timeout.node))
		pr_debug("timeout work queued\n");

	if (hdcp->worker.current_work == &hdcp->wk_timeout)
		pr_debug("timeout work executing\n");

	if (!list_empty(&hdcp->wk_clean.node))
		pr_debug("clean work queued\n");

	if (hdcp->worker.current_work == &hdcp->wk_clean)
		pr_debug("clean work executing\n");

	if (!list_empty(&hdcp->wk_stream.node))
		pr_debug("stream work queued\n");

	if (hdcp->worker.current_work == &hdcp->wk_stream)
		pr_debug("stream work executing\n");
}

static int sde_hdcp_2x_get_next_message(struct sde_hdcp_2x_ctrl *hdcp,
				     struct hdcp_transport_wakeup_data *data)
{
@@ -251,6 +202,8 @@ static int sde_hdcp_2x_get_next_message(struct sde_hdcp_2x_ctrl *hdcp,

static void sde_hdcp_2x_wait_for_response(struct sde_hdcp_2x_ctrl *hdcp)
{
	u32 timeout;

	switch (hdcp->last_msg) {
	case AKE_SEND_H_PRIME:
		if (hdcp->no_stored_km)
@@ -271,8 +224,26 @@ static void sde_hdcp_2x_wait_for_response(struct sde_hdcp_2x_ctrl *hdcp)
		hdcp->wait_timeout_ms = 0;
	}

	if (hdcp->wait_timeout_ms)
		HDCP_2X_EXECUTE(wait);
	if (!hdcp->wait_timeout_ms)
		return;

	if (atomic_read(&hdcp->hdcp_off)) {
		pr_debug("invalid state: hdcp off\n");
		return;
	}

	reinit_completion(&hdcp->response_completion);
	timeout = wait_for_completion_timeout(&hdcp->response_completion,
			hdcp->wait_timeout_ms);
	if (!timeout) {
		pr_err("completion expired, last message = %s\n",
				sde_hdcp_2x_message_name(hdcp->last_msg));

		if (!atomic_read(&hdcp->hdcp_off))
			sde_hdcp_2x_clean(hdcp);
	}

	hdcp->wait_timeout_ms = 0;
}

static void sde_hdcp_2x_wakeup_client(struct sde_hdcp_2x_ctrl *hdcp,
@@ -319,9 +290,6 @@ static inline void sde_hdcp_2x_send_message(struct sde_hdcp_2x_ctrl *hdcp)
	/* ignore the first byte as it contains the message id */
	cdata.buf = hdcp->app_data.response.data + 1;

	pr_debug("%s\n",
		sde_hdcp_2x_message_name(hdcp->app_data.response.data[0]));

	sde_hdcp_2x_wakeup_client(hdcp, &cdata);
}

@@ -345,32 +313,9 @@ static void sde_hdcp_2x_force_encryption(void *data, bool enable)
	pr_info("force_encryption=%d\n", hdcp->force_encryption);
}

static int sde_hdcp_2x_check_valid_state(struct sde_hdcp_2x_ctrl *hdcp)
{
	int rc = 0;

	if (!list_empty(&hdcp->worker.work_list))
		sde_hdcp_2x_check_worker_status(hdcp);

	if (hdcp->wakeup_cmd == HDCP_2X_CMD_START) {
		if (!list_empty(&hdcp->worker.work_list)) {
			rc = -EBUSY;
			goto exit;
		}
	} else {
		if (atomic_read(&hdcp->hdcp_off)) {
			pr_debug("hdcp2.2 session tearing down\n");
			goto exit;
		}
	}
exit:
	return rc;
}

static void sde_hdcp_2x_clean(struct sde_hdcp_2x_ctrl *hdcp)
{
	struct hdcp_transport_wakeup_data cdata = {
						HDCP_TRANSPORT_CMD_INVALID };
	struct hdcp_transport_wakeup_data cdata = {HDCP_TRANSPORT_CMD_INVALID};

	hdcp->authenticated = false;

@@ -385,15 +330,6 @@ static void sde_hdcp_2x_clean(struct sde_hdcp_2x_ctrl *hdcp)
	hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_STOP, &hdcp->app_data);
}

static void sde_hdcp_2x_cleanup_work(struct kthread_work *work)
{

	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_clean);

	sde_hdcp_2x_clean(hdcp);
}

static u8 sde_hdcp_2x_stream_type(u8 min_enc_level)
{
	u8 stream_type = 0;
@@ -441,15 +377,7 @@ static void sde_hdcp_2x_send_type(struct sde_hdcp_2x_ctrl *hdcp)
		sde_hdcp_2x_send_message(hdcp);
}

static void sde_hdcp_2x_send_type_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_send_type);

	sde_hdcp_2x_send_type(hdcp);
}

static void sde_hdcp_2x_stream(struct sde_hdcp_2x_ctrl *hdcp)
static void sde_hdcp_2x_query_stream(struct sde_hdcp_2x_ctrl *hdcp)
{
	int rc = 0;

@@ -474,21 +402,13 @@ static void sde_hdcp_2x_stream(struct sde_hdcp_2x_ctrl *hdcp)
		goto exit;
	}

	pr_debug("message received from TZ: %s\n",
		 sde_hdcp_2x_message_name(hdcp->app_data.response.data[0]));
	pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name(
		hdcp->app_data.response.data[0]));
exit:
	if (!rc && !atomic_read(&hdcp->hdcp_off))
		sde_hdcp_2x_send_message(hdcp);
}

static void sde_hdcp_2x_query_stream_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_stream);

	sde_hdcp_2x_stream(hdcp);
}

static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp,
		enum hdcp_transport_wakeup_cmd cmd,
		struct hdcp_transport_wakeup_data *cdata)
@@ -501,8 +421,8 @@ static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp,
static void sde_hdcp_2x_msg_sent(struct sde_hdcp_2x_ctrl *hdcp)
{
	struct hdcp_transport_wakeup_data cdata = {
						HDCP_TRANSPORT_CMD_INVALID };
	cdata.context = hdcp->client_data;
		HDCP_TRANSPORT_CMD_INVALID,
		hdcp->client_data};

	switch (hdcp->app_data.response.data[0]) {
	case SKE_SEND_TYPE_ID:
@@ -541,7 +461,7 @@ static void sde_hdcp_2x_msg_sent(struct sde_hdcp_2x_ctrl *hdcp)
				hdcp->update_stream);

		if (hdcp->update_stream) {
			HDCP_2X_EXECUTE(stream);
			sde_hdcp_2x_query_stream(hdcp);
			hdcp->update_stream = false;
		} else {
			sde_hdcp_2x_initialize_command(hdcp,
@@ -557,48 +477,22 @@ static void sde_hdcp_2x_msg_sent(struct sde_hdcp_2x_ctrl *hdcp)
	sde_hdcp_2x_wakeup_client(hdcp, &cdata);
}

static void sde_hdcp_2x_msg_sent_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_msg_sent);

	if (hdcp->wakeup_cmd != HDCP_2X_CMD_MSG_SEND_SUCCESS) {
		pr_err("invalid wakeup command %d\n", hdcp->wakeup_cmd);
		return;
	}

	sde_hdcp_2x_msg_sent(hdcp);
}

static void sde_hdcp_2x_init(struct sde_hdcp_2x_ctrl *hdcp)
{
	int rc = 0;

	if (hdcp->wakeup_cmd != HDCP_2X_CMD_START) {
		pr_err("invalid wakeup command %d\n", hdcp->wakeup_cmd);
		return;
	}
	int rc;

	rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_START, &hdcp->app_data);
	if (rc)
		goto exit;

	pr_debug("message received from TZ: %s\n",
		 sde_hdcp_2x_message_name(hdcp->app_data.response.data[0]));
	pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name(
		hdcp->app_data.response.data[0]));

	sde_hdcp_2x_send_message(hdcp);

	return;
exit:
	HDCP_2X_EXECUTE(clean);
}

static void sde_hdcp_2x_init_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_init);

	sde_hdcp_2x_init(hdcp);
	sde_hdcp_2x_clean(hdcp);
}

static void sde_hdcp_2x_timeout(struct sde_hdcp_2x_ctrl *hdcp)
@@ -622,15 +516,7 @@ static void sde_hdcp_2x_timeout(struct sde_hdcp_2x_ctrl *hdcp)
	return;
error:
	if (!atomic_read(&hdcp->hdcp_off))
		HDCP_2X_EXECUTE(clean);
}

static void sde_hdcp_2x_timeout_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_timeout);

	sde_hdcp_2x_timeout(hdcp);
		sde_hdcp_2x_clean(hdcp);
}

static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
@@ -639,8 +525,7 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
	char *msg = NULL;
	u32 message_id_bytes = 0;
	u32 request_length, out_msg;
	struct hdcp_transport_wakeup_data cdata = {
						HDCP_TRANSPORT_CMD_INVALID };
	struct hdcp_transport_wakeup_data cdata = {HDCP_TRANSPORT_CMD_INVALID};

	if (atomic_read(&hdcp->hdcp_off)) {
		pr_debug("invalid state, hdcp off\n");
@@ -664,8 +549,7 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)

	request_length += message_id_bytes;

	pr_debug("message received from SINK: %s\n",
			sde_hdcp_2x_message_name(msg[0]));
	pr_debug("[sink]: %s\n", sde_hdcp_2x_message_name(msg[0]));

	hdcp->app_data.request.length = request_length;
	rc = hdcp2_app_comm(hdcp->hdcp2_ctx, HDCP2_CMD_PROCESS_MSG,
@@ -686,8 +570,7 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)

	out_msg = (u32)hdcp->app_data.response.data[0];

	pr_debug("message received from TZ: %s\n",
			sde_hdcp_2x_message_name(out_msg));
	pr_debug("[tz]: %s\n", sde_hdcp_2x_message_name(out_msg));

	if (msg[0] == REP_STREAM_READY && out_msg != REP_STREAM_MANAGE) {
		if (!hdcp->authenticated) {
@@ -715,16 +598,12 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
	}

	hdcp->resend_lc_init = false;
	if (msg[0] == LC_SEND_L_PRIME && out_msg == LC_INIT) {
		pr_debug("resend %s\n", sde_hdcp_2x_message_name(out_msg));
	if (msg[0] == LC_SEND_L_PRIME && out_msg == LC_INIT)
		hdcp->resend_lc_init = true;
	}

	hdcp->resend_stream_manage = false;
	if (msg[0] == REP_STREAM_READY && out_msg == REP_STREAM_MANAGE) {
		pr_debug("resend %s\n", sde_hdcp_2x_message_name(out_msg));
	if (msg[0] == REP_STREAM_READY && out_msg == REP_STREAM_MANAGE)
		hdcp->resend_stream_manage = true;
	}

	if (out_msg == AKE_NO_STORED_KM)
		hdcp->no_stored_km = true;
@@ -737,8 +616,6 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
	}

	if (!atomic_read(&hdcp->hdcp_off)) {
		pr_debug("creating client data for: %s\n",
				sde_hdcp_2x_message_name(out_msg));
		cdata.cmd = HDCP_TRANSPORT_CMD_SEND_MESSAGE;
		cdata.buf = hdcp->app_data.response.data + 1;
		cdata.buf_len = hdcp->app_data.response.length;
@@ -748,47 +625,17 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
	sde_hdcp_2x_wakeup_client(hdcp, &cdata);

	if (rc && !atomic_read(&hdcp->hdcp_off))
		HDCP_2X_EXECUTE(clean);
}

static void sde_hdcp_2x_msg_recvd_work(struct kthread_work *work)
{
	struct sde_hdcp_2x_ctrl *hdcp =
		container_of(work, struct sde_hdcp_2x_ctrl, wk_msg_recvd);

	sde_hdcp_2x_msg_recvd(hdcp);
}

static void sde_hdcp_2x_wait_for_response_work(struct kthread_work *work)
{
	u32 timeout;
	struct sde_hdcp_2x_ctrl *hdcp = container_of(work,
			struct sde_hdcp_2x_ctrl, wk_wait);

	if (!hdcp) {
		pr_err("invalid input\n");
		return;
	}

	if (atomic_read(&hdcp->hdcp_off)) {
		pr_debug("invalid state: hdcp off\n");
		return;
	}

	reinit_completion(&hdcp->response_completion);
	timeout = wait_for_completion_timeout(&hdcp->response_completion,
			hdcp->wait_timeout_ms);
	if (!timeout) {
		pr_err("completion expired, last message = %s\n",
				sde_hdcp_2x_message_name(hdcp->last_msg));

		if (!atomic_read(&hdcp->hdcp_off))
			HDCP_2X_EXECUTE(clean);
	}

	hdcp->wait_timeout_ms = 0;
		sde_hdcp_2x_clean(hdcp);
}

/** sde_hdcp_2x_wakeup() - wakeup the module to execute a requested command
 * @data: data required for executing corresponding command.
 *
 * This function is executed on caller's thread. Update the local data
 * and wakeup the local thread to execute the command. Once the local
 * thread is activated, caller's thread is returned and this function
 * is ready to receive next command.
 */
static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)
{
	struct sde_hdcp_2x_ctrl *hdcp;
@@ -801,72 +648,100 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)
	if (!hdcp)
		return -EINVAL;

	mutex_lock(&hdcp->wakeup_mutex);

	hdcp->wakeup_cmd = data->cmd;
	hdcp->timeout_left = data->timeout;
	hdcp->total_message_length = data->total_message_length;

	pr_debug("%s\n", sde_hdcp_2x_cmd_to_str(hdcp->wakeup_cmd));

	rc = sde_hdcp_2x_check_valid_state(hdcp);
	if (rc) {
		pr_err("invalid state for command=%s\n",
				sde_hdcp_2x_cmd_to_str(hdcp->wakeup_cmd));
		goto exit;
	}
	hdcp->min_enc_level = data->min_enc_level;

	if (!completion_done(&hdcp->response_completion))
		complete_all(&hdcp->response_completion);

	switch (hdcp->wakeup_cmd) {
	kfifo_put(&hdcp->cmd_q, data->cmd);

	switch (data->cmd) {
	case HDCP_2X_CMD_STOP:
		atomic_set(&hdcp->hdcp_off, 1);

		kthread_park(hdcp->thread);
		break;
	case HDCP_2X_CMD_START:
		hdcp->no_stored_km = false;
		hdcp->repeater_flag = false;
		hdcp->update_stream = false;
		hdcp->authenticated = false;
		hdcp->last_msg = INVALID_MESSAGE;
		hdcp->timeout_left = 0;
		atomic_set(&hdcp->hdcp_off, 0);

		HDCP_2X_EXECUTE(init);
		kthread_unpark(hdcp->thread);
		wake_up(&hdcp->wait_q);
		break;
	default:
		wake_up(&hdcp->wait_q);
		break;
	}

	return rc;
}

static int sde_hdcp_2x_main(void *data)
{
	struct sde_hdcp_2x_ctrl *hdcp = data;
	enum sde_hdcp_2x_wakeup_cmd cmd;

	while (1) {
		wait_event(hdcp->wait_q,
			!kfifo_is_empty(&hdcp->cmd_q) ||
			kthread_should_stop() ||
			kthread_should_park());

		if (kthread_should_stop())
			break;

		if (kfifo_is_empty(&hdcp->cmd_q) && kthread_should_park()) {
			kthread_parkme();
			continue;
		}

		if (!kfifo_get(&hdcp->cmd_q, &cmd))
			continue;

		switch (cmd) {
		case HDCP_2X_CMD_START:
			sde_hdcp_2x_init(hdcp);
			break;
		case HDCP_2X_CMD_STOP:
		atomic_set(&hdcp->hdcp_off, 1);
		HDCP_2X_EXECUTE(clean);
			sde_hdcp_2x_clean(hdcp);
			break;
		case HDCP_2X_CMD_MSG_SEND_SUCCESS:
		HDCP_2X_EXECUTE(msg_sent);
			sde_hdcp_2x_msg_sent(hdcp);
			break;
		case HDCP_2X_CMD_MSG_SEND_FAILED:
		case HDCP_2X_CMD_MSG_RECV_FAILED:
		case HDCP_2X_CMD_LINK_FAILED:
		HDCP_2X_EXECUTE(clean);
			sde_hdcp_2x_clean(hdcp);
			break;
		case HDCP_2X_CMD_MSG_RECV_SUCCESS:
		HDCP_2X_EXECUTE(msg_recvd);
			sde_hdcp_2x_msg_recvd(hdcp);
			break;
		case HDCP_2X_CMD_MSG_RECV_TIMEOUT:
		HDCP_2X_EXECUTE(timeout);
			sde_hdcp_2x_timeout(hdcp);
			break;
		case HDCP_2X_CMD_QUERY_STREAM_TYPE:
		HDCP_2X_EXECUTE(stream);
			sde_hdcp_2x_query_stream(hdcp);
			break;
		case HDCP_2X_CMD_MIN_ENC_LEVEL:
		hdcp->min_enc_level = data->min_enc_level;
			if (!hdcp->repeater_flag) {
			HDCP_2X_EXECUTE(send_type);
				sde_hdcp_2x_send_type(hdcp);
				break;
			}

		HDCP_2X_EXECUTE(stream);
			sde_hdcp_2x_query_stream(hdcp);
			break;
		default:
		pr_err("invalid wakeup command %d\n", hdcp->wakeup_cmd);
			break;
		}
	}
exit:
	mutex_unlock(&hdcp->wakeup_mutex);

	return rc;
	return 0;
}

int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data)
@@ -911,27 +786,16 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data)

	hdcp->hdcp2_ctx = hdcp2_init(hdcp->device_type);

	atomic_set(&hdcp->hdcp_off, 0);

	mutex_init(&hdcp->wakeup_mutex);
	INIT_KFIFO(hdcp->cmd_q);

	kthread_init_worker(&hdcp->worker);

	kthread_init_work(&hdcp->wk_init,      sde_hdcp_2x_init_work);
	kthread_init_work(&hdcp->wk_msg_sent,  sde_hdcp_2x_msg_sent_work);
	kthread_init_work(&hdcp->wk_msg_recvd, sde_hdcp_2x_msg_recvd_work);
	kthread_init_work(&hdcp->wk_timeout,   sde_hdcp_2x_timeout_work);
	kthread_init_work(&hdcp->wk_clean,     sde_hdcp_2x_cleanup_work);
	kthread_init_work(&hdcp->wk_stream,    sde_hdcp_2x_query_stream_work);
	kthread_init_work(&hdcp->wk_wait, sde_hdcp_2x_wait_for_response_work);
	kthread_init_work(&hdcp->wk_send_type,    sde_hdcp_2x_send_type_work);
	init_waitqueue_head(&hdcp->wait_q);
	atomic_set(&hdcp->hdcp_off, 0);

	init_completion(&hdcp->response_completion);

	*data->hdcp_data = hdcp;

	hdcp->thread = kthread_run(kthread_worker_fn,
			     &hdcp->worker, "hdcp_tz_lib");
	hdcp->thread = kthread_run(sde_hdcp_2x_main, hdcp, "hdcp_2x");

	if (IS_ERR(hdcp->thread)) {
		pr_err("unable to start lib thread\n");
@@ -958,7 +822,6 @@ void sde_hdcp_2x_deregister(void *data)
		return;

	kthread_stop(hdcp->thread);
	mutex_destroy(&hdcp->wakeup_mutex);
	hdcp2_deinit(hdcp->hdcp2_ctx);
	kzfree(hdcp);
}
+3 −1
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ enum sde_hdcp_2x_wakeup_cmd {
 * @HDCP_TRANSPORT_CMD_STATUS_SUCCESS: successfully communicated with TrustZone
 * @HDCP_TRANSPORT_CMD_STATUS_FAILED:  failed to communicate with TrustZone
 * @HDCP_TRANSPORT_CMD_LINK_POLL:      poll the HDCP link
 * @HDCP_TRANSPORT_CMD_LINK_CHECK:     check link status in response to cp_irq
 * @HDCP_TRANSPORT_CMD_AUTHENTICATE:   start authentication
 */
enum hdcp_transport_wakeup_cmd {
@@ -59,7 +60,8 @@ enum hdcp_transport_wakeup_cmd {
	HDCP_TRANSPORT_CMD_STATUS_SUCCESS,
	HDCP_TRANSPORT_CMD_STATUS_FAILED,
	HDCP_TRANSPORT_CMD_LINK_POLL,
	HDCP_TRANSPORT_CMD_AUTHENTICATE
	HDCP_TRANSPORT_CMD_LINK_CHECK,
	HDCP_TRANSPORT_CMD_AUTHENTICATE,
};

enum sde_hdcp_2x_device_type {