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

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

Merge "drm/msm/dp: clean up hdcp threads"

parents 58208b76 8872fd10
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 {