diff --git a/drivers/misc/hdcp.c b/drivers/misc/hdcp.c index 74449d8186d9..0a32d11f6161 100644 --- a/drivers/misc/hdcp.c +++ b/drivers/misc/hdcp.c @@ -337,6 +337,7 @@ struct hdcp_lib_handle { void *client_ctx; struct hdcp_client_ops *client_ops; struct mutex hdcp_lock; + struct mutex msg_lock; struct mutex wakeup_mutex; enum hdcp_state hdcp_state; enum hdcp_lib_wakeup_cmd wakeup_cmd; @@ -755,6 +756,77 @@ exit: return supported; } +static void hdcp_lib_check_worker_status(struct hdcp_lib_handle *handle) +{ + if (!list_empty(&handle->init.node)) + pr_debug("init work queued\n"); + + if (handle->worker.current_work == &handle->init) + pr_debug("init work executing\n"); + + if (!list_empty(&handle->msg_sent.node)) + pr_debug("msg_sent work queued\n"); + + if (handle->worker.current_work == &handle->msg_sent) + pr_debug("msg_sent work executing\n"); + + if (!list_empty(&handle->msg_recvd.node)) + pr_debug("msg_recvd work queued\n"); + + if (handle->worker.current_work == &handle->msg_recvd) + pr_debug("msg_recvd work executing\n"); + + if (!list_empty(&handle->timeout.node)) + pr_debug("timeout work queued\n"); + + if (handle->worker.current_work == &handle->timeout) + pr_debug("timeout work executing\n"); + + if (!list_empty(&handle->clean.node)) + pr_debug("clean work queued\n"); + + if (handle->worker.current_work == &handle->clean) + pr_debug("clean work executing\n"); + + if (!list_empty(&handle->topology.node)) + pr_debug("topology work queued\n"); + + if (handle->worker.current_work == &handle->topology) + pr_debug("topology work executing\n"); + + if (!list_empty(&handle->stream.node)) + pr_debug("stream work queued\n"); + + if (handle->worker.current_work == &handle->stream) + pr_debug("stream work executing\n"); +} + +static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle) +{ + int rc = 0; + + if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) { + if (!list_empty(&handle->worker.work_list)) { + hdcp_lib_check_worker_status(handle); + rc = -EBUSY; + goto exit; + } + } else { + if (atomic_read(&handle->hdcp_off)) { + pr_warn("hdcp2.2 session tearing down\n"); + goto exit; + } + + if (!(handle->hdcp_state & HDCP_STATE_APP_LOADED)) { + pr_err("hdcp 2.2 app not loaded\n"); + rc = -EINVAL; + goto exit; + } + } +exit: + return rc; +} + static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) { struct hdcp_lib_handle *handle; @@ -770,22 +842,29 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) mutex_lock(&handle->wakeup_mutex); handle->wakeup_cmd = data->cmd; + pr_debug("%s\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd)); - pr_debug("cmd: %s\n", hdcp_lib_cmd_to_str(handle->wakeup_cmd)); + rc = hdcp_lib_check_valid_state(handle); + if (rc) + goto exit; + mutex_lock(&handle->msg_lock); if (data->recvd_msg_len) { - handle->last_msg_recvd_len = data->recvd_msg_len; + kzfree(handle->last_msg_recvd_buf); + handle->last_msg_recvd_len = data->recvd_msg_len; handle->last_msg_recvd_buf = kzalloc(data->recvd_msg_len, GFP_KERNEL); if (!handle->last_msg_recvd_buf) { rc = -ENOMEM; + mutex_unlock(&handle->msg_lock); goto exit; } memcpy(handle->last_msg_recvd_buf, data->recvd_msg_buf, data->recvd_msg_len); } + mutex_unlock(&handle->msg_lock); if (!completion_done(&handle->topo_wait)) complete_all(&handle->topo_wait); @@ -807,32 +886,27 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data) case HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS: handle->last_msg_sent = handle->listener_buf[0]; - if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->msg_sent); + queue_kthread_work(&handle->worker, &handle->msg_sent); break; case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED: case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED: - if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->clean); + queue_kthread_work(&handle->worker, &handle->clean); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS: - if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->msg_recvd); + queue_kthread_work(&handle->worker, &handle->msg_recvd); break; case HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT: - if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->timeout); + queue_kthread_work(&handle->worker, &handle->timeout); break; case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE: - if (!atomic_read(&handle->hdcp_off)) - queue_kthread_work(&handle->worker, &handle->stream); + queue_kthread_work(&handle->worker, &handle->stream); break; default: pr_err("invalid wakeup command %d\n", handle->wakeup_cmd); } exit: mutex_unlock(&handle->wakeup_mutex); - return 0; + return rc; } static void hdcp_lib_msg_sent_work(struct kthread_work *work) @@ -926,7 +1000,6 @@ exit: if (rc && !atomic_read(&handle->hdcp_off)) queue_kthread_work(&handle->worker, &handle->clean); - return; } static void hdcp_lib_manage_timeout_work(struct kthread_work *work) @@ -1044,18 +1117,29 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) } mutex_lock(&handle->hdcp_lock); - - msg = handle->last_msg_recvd_buf; - msglen = handle->last_msg_recvd_len; - cdata.context = handle->client_ctx; + mutex_lock(&handle->msg_lock); + msglen = handle->last_msg_recvd_len; + if (msglen <= 0) { pr_err("invalid msg len\n"); + mutex_unlock(&handle->msg_lock); rc = -EINVAL; goto exit; } + msg = kzalloc(msglen, GFP_KERNEL); + if (!msg) { + mutex_unlock(&handle->msg_lock); + rc = -ENOMEM; + goto exit; + } + + memcpy(msg, handle->last_msg_recvd_buf, msglen); + + mutex_unlock(&handle->msg_lock); + pr_debug("msg received: %s from sink\n", hdcp_lib_message_name((int)msg[0])); @@ -1140,7 +1224,7 @@ static void hdcp_lib_msg_recvd_work(struct kthread_work *work) } exit: - kzfree(handle->last_msg_recvd_buf); + kzfree(msg); mutex_unlock(&handle->hdcp_lock); hdcp_lib_wakeup_client(handle, &cdata); @@ -1160,7 +1244,6 @@ static void hdcp_lib_topology_work(struct kthread_work *work) return; } - reinit_completion(&handle->topo_wait); timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3); if (!timeout) { @@ -1185,6 +1268,9 @@ bool hdcp1_check_if_supported_load_app(void) } } + pr_debug("hdcp1 app %s loaded\n", + hdcp1_supported ? "successfully" : "not"); + return hdcp1_supported; } @@ -1274,6 +1360,7 @@ int hdcp_library_register(void **pphdcpcontext, atomic_set(&handle->hdcp_off, 0); mutex_init(&handle->hdcp_lock); + mutex_init(&handle->msg_lock); mutex_init(&handle->wakeup_mutex); init_kthread_worker(&handle->worker); @@ -1326,6 +1413,7 @@ void hdcp_library_deregister(void *phdcpcontext) kthread_stop(handle->thread); kzfree(handle->qseecom_handle); + kzfree(handle->last_msg_recvd_buf); mutex_destroy(&handle->hdcp_lock); mutex_destroy(&handle->wakeup_mutex); diff --git a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c index b9e70b042b62..565fa5661bdd 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_hdcp2p2.c @@ -56,6 +56,7 @@ struct hdmi_hdcp2p2_ctrl { enum hdmi_hdcp2p2_sink_status sink_status; /* Is sink connected */ struct hdmi_hdcp_init_data init_data; /* Feature data from HDMI drv */ 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 hdmi_hdcp_ops *ops; void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */ @@ -99,18 +100,24 @@ static int hdmi_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data) ctrl->wakeup_cmd = data->cmd; ctrl->timeout = data->timeout; - if (data->send_msg_len) { + mutex_lock(&ctrl->msg_lock); + if (data->send_msg_len) { ctrl->send_msg_len = data->send_msg_len; + kzfree(ctrl->send_msg_buf); + ctrl->send_msg_buf = kzalloc( data->send_msg_len, GFP_KERNEL); - if (!ctrl->send_msg_buf) + if (!ctrl->send_msg_buf) { + mutex_unlock(&ctrl->msg_lock); goto exit; + } memcpy(ctrl->send_msg_buf, data->send_msg_buf, ctrl->send_msg_len); } + mutex_unlock(&ctrl->msg_lock); switch (ctrl->wakeup_cmd) { case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE: @@ -137,7 +144,7 @@ exit: return 0; } -static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, +static inline int hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, struct hdcp_lib_wakeup_data *data) { int rc = 0; @@ -149,6 +156,8 @@ static inline void hdmi_hdcp2p2_wakeup_lib(struct hdmi_hdcp2p2_ctrl *ctrl, pr_err("error sending %s to lib\n", hdcp_lib_cmd_to_str(data->cmd)); } + + return rc; } static void hdmi_hdcp2p2_reset(struct hdmi_hdcp2p2_ctrl *ctrl) @@ -461,6 +470,8 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) struct hdmi_hdcp2p2_ctrl *ctrl = container_of(work, struct hdmi_hdcp2p2_ctrl, send_msg); struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; + char *msg; + uint32_t msglen; if (!ctrl) { pr_err("invalid input\n"); @@ -476,9 +487,25 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) goto exit; } + mutex_lock(&ctrl->msg_lock); + msglen = ctrl->send_msg_len; + + if (!msglen) { + mutex_unlock(&ctrl->msg_lock); + goto exit; + } + + msg = kzalloc(msglen, GFP_KERNEL); + if (!msg) { + mutex_unlock(&ctrl->msg_lock); + goto exit; + } + + memcpy(msg, ctrl->send_msg_buf, msglen); + mutex_unlock(&ctrl->msg_lock); + /* Forward the message to the sink */ - rc = hdmi_hdcp2p2_ddc_write_message(ctrl, - ctrl->send_msg_buf, (size_t)ctrl->send_msg_len); + rc = hdmi_hdcp2p2_ddc_write_message(ctrl, msg, (size_t)msglen); if (rc) { pr_err("Error sending msg to sink %d\n", rc); cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED; @@ -486,7 +513,7 @@ static void hdmi_hdcp2p2_send_msg_work(struct kthread_work *work) cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS; } exit: - kzfree(ctrl->send_msg_buf); + kzfree(msg); mutex_unlock(&ctrl->mutex); hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); @@ -755,7 +782,8 @@ static void hdmi_hdcp2p2_auth_work(struct kthread_work *work) mutex_unlock(&ctrl->mutex); - hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata); + if (hdmi_hdcp2p2_wakeup_lib(ctrl, &cdata)) + hdmi_hdcp2p2_auth_failed(ctrl); } void hdmi_hdcp2p2_deinit(void *input) @@ -778,6 +806,8 @@ void hdmi_hdcp2p2_deinit(void *input) &hdmi_hdcp2p2_fs_attr_group); mutex_destroy(&ctrl->mutex); + mutex_destroy(&ctrl->msg_lock); + mutex_destroy(&ctrl->wakeup_mutex); kfree(ctrl); } @@ -832,6 +862,7 @@ void *hdmi_hdcp2p2_init(struct hdmi_hdcp_init_data *init_data) ctrl->ops = &ops; mutex_init(&ctrl->mutex); + mutex_init(&ctrl->msg_lock); mutex_init(&ctrl->wakeup_mutex); rc = hdcp_library_register(&ctrl->lib_ctx,