msm: mdss: hdcp2p2: fix deadlock during re-authentication

Fix the dead lock happening during re-authentication where
threads were waiting for each other during clearing the last
session and starting a new one.

Change-Id: Ife18adde8349acb92b22e228d0bbc18edbf2c90e
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
This commit is contained in:
Ajay Singh Parmar 2016-10-20 17:13:19 -07:00
parent 821b280d6a
commit 01cb3026c6
6 changed files with 141 additions and 131 deletions

View file

@ -616,32 +616,53 @@ static int hdcp_lib_get_next_message(struct hdcp_lib_handle *handle,
} }
} }
static inline void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle, static void hdcp_lib_wakeup_client(struct hdcp_lib_handle *handle,
struct hdmi_hdcp_wakeup_data *data) struct hdmi_hdcp_wakeup_data *data)
{ {
int rc = 0; int rc = 0, i;
if (handle && handle->client_ops && handle->client_ops->wakeup && if (!handle || !handle->client_ops || !handle->client_ops->wakeup ||
data && (data->cmd != HDMI_HDCP_WKUP_CMD_INVALID)) { !data || (data->cmd == HDMI_HDCP_WKUP_CMD_INVALID))
data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE; return;
if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE || data->abort_mask = REAUTH_REQ | LINK_INTEGRITY_FAILURE;
data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE ||
data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) {
handle->last_msg =
hdcp_lib_get_next_message(handle, data);
if (handle->last_msg > INVALID_MESSAGE_ID && if (data->cmd == HDMI_HDCP_WKUP_CMD_SEND_MESSAGE ||
handle->last_msg < HDCP2P2_MAX_MESSAGES) data->cmd == HDMI_HDCP_WKUP_CMD_RECV_MESSAGE ||
data->message_data = data->cmd == HDMI_HDCP_WKUP_CMD_LINK_POLL) {
&hdcp_msg_lookup[handle->last_msg]; handle->last_msg = hdcp_lib_get_next_message(handle, data);
pr_debug("lib->client: %s (%s)\n",
hdmi_hdcp_cmd_to_str(data->cmd),
hdcp_lib_message_name(handle->last_msg));
if (handle->last_msg > INVALID_MESSAGE_ID &&
handle->last_msg < HDCP2P2_MAX_MESSAGES) {
u32 msg_num, rx_status;
const struct hdcp_msg_part *msg;
data->message_data = &hdcp_msg_lookup[handle->last_msg];
msg_num = data->message_data->num_messages;
msg = data->message_data->messages;
rx_status = data->message_data->rx_status;
pr_debug("rxstatus 0x%x\n", rx_status);
pr_debug("%6s | %4s\n", "offset", "len");
for (i = 0; i < msg_num; i++)
pr_debug("%6x | %4d\n",
msg[i].offset, msg[i].length);
} }
} else {
rc = handle->client_ops->wakeup(data); pr_debug("lib->client: %s\n",
if (rc) hdmi_hdcp_cmd_to_str(data->cmd));
pr_err("error sending %s to client\n",
hdmi_hdcp_cmd_to_str(data->cmd));
} }
rc = handle->client_ops->wakeup(data);
if (rc)
pr_err("error sending %s to client\n",
hdmi_hdcp_cmd_to_str(data->cmd));
} }
static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle) static inline void hdcp_lib_send_message(struct hdcp_lib_handle *handle)
@ -1486,6 +1507,7 @@ static int hdcp_lib_check_valid_state(struct hdcp_lib_handle *handle)
if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) { if (handle->wakeup_cmd == HDCP_LIB_WKUP_CMD_START) {
if (!list_empty(&handle->worker.work_list)) { if (!list_empty(&handle->worker.work_list)) {
pr_debug("error: queue not empty\n");
rc = -EBUSY; rc = -EBUSY;
goto exit; goto exit;
} }
@ -1543,9 +1565,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
handle->wakeup_cmd = data->cmd; handle->wakeup_cmd = data->cmd;
handle->timeout_left = data->timeout; handle->timeout_left = data->timeout;
pr_debug("%s, timeout left: %dms, tethered %d\n", pr_debug("client->lib: %s\n",
hdcp_lib_cmd_to_str(handle->wakeup_cmd), hdcp_lib_cmd_to_str(handle->wakeup_cmd));
handle->timeout_left, handle->tethered);
rc = hdcp_lib_check_valid_state(handle); rc = hdcp_lib_check_valid_state(handle);
if (rc) if (rc)
@ -1599,6 +1620,8 @@ static int hdcp_lib_wakeup(struct hdcp_lib_wakeup_data *data)
break; break;
case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED: case HDCP_LIB_WKUP_CMD_MSG_SEND_FAILED:
case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED: case HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED:
case HDCP_LIB_WKUP_CMD_LINK_FAILED:
handle->hdcp_state |= HDCP_STATE_ERROR;
HDCP_LIB_EXECUTE(clean); HDCP_LIB_EXECUTE(clean);
break; break;
case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS: case HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS:
@ -1825,7 +1848,7 @@ static void hdcp_lib_clean(struct hdcp_lib_handle *handle)
if (!handle) { if (!handle) {
pr_err("invalid input\n"); pr_err("invalid input\n");
return; return;
}; }
hdcp_lib_txmtr_deinit(handle); hdcp_lib_txmtr_deinit(handle);
if (!handle->legacy_app) if (!handle->legacy_app)
@ -1859,6 +1882,7 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
struct hdcp_rcvd_msg_rsp *rsp_buf; struct hdcp_rcvd_msg_rsp *rsp_buf;
uint32_t msglen; uint32_t msglen;
char *msg = NULL; char *msg = NULL;
char msg_name[50];
uint32_t message_id_bytes = 0; uint32_t message_id_bytes = 0;
if (!handle || !handle->qseecom_handle || if (!handle || !handle->qseecom_handle ||
@ -1907,8 +1931,11 @@ static void hdcp_lib_msg_recvd(struct hdcp_lib_handle *handle)
mutex_unlock(&handle->msg_lock); mutex_unlock(&handle->msg_lock);
pr_debug("msg received: %s from sink\n", snprintf(msg_name, sizeof(msg_name), "%s: ",
hdcp_lib_message_name((int)msg[0])); hdcp_lib_message_name((int)msg[0]));
print_hex_dump(KERN_DEBUG, msg_name,
DUMP_PREFIX_NONE, 16, 1, msg, msglen, false);
/* send the message to QSEECOM */ /* send the message to QSEECOM */
req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf); req_buf = (struct hdcp_rcvd_msg_req *)(handle->qseecom_handle->sbuf);
@ -2026,6 +2053,16 @@ static void hdcp_lib_topology_work(struct kthread_work *work)
return; return;
} }
if (atomic_read(&handle->hdcp_off)) {
pr_debug("invalid state: hdcp off\n");
return;
}
if (handle->hdcp_state & HDCP_STATE_ERROR) {
pr_debug("invalid state: hdcp error\n");
return;
}
reinit_completion(&handle->topo_wait); reinit_completion(&handle->topo_wait);
timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3); timeout = wait_for_completion_timeout(&handle->topo_wait, HZ * 3);
if (!timeout) { if (!timeout) {

View file

@ -1620,22 +1620,18 @@ end:
return rc; return rc;
} }
static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status) static void mdss_dp_hdcp_cb_work(struct work_struct *work)
{ {
struct mdss_dp_drv_pdata *dp = ptr; struct mdss_dp_drv_pdata *dp;
struct delayed_work *dw = to_delayed_work(work);
struct hdcp_ops *ops; struct hdcp_ops *ops;
int rc = 0; int rc = 0;
if (!dp) { dp = container_of(dw, struct mdss_dp_drv_pdata, hdcp_cb_work);
pr_debug("invalid input\n");
return;
}
ops = dp->hdcp.ops; ops = dp->hdcp.ops;
mutex_lock(&dp->train_mutex); switch (dp->hdcp_status) {
switch (status) {
case HDCP_STATE_AUTHENTICATED: case HDCP_STATE_AUTHENTICATED:
pr_debug("hdcp authenticated\n"); pr_debug("hdcp authenticated\n");
dp->hdcp.auth_state = true; dp->hdcp.auth_state = true;
@ -1658,8 +1654,20 @@ static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status)
default: default:
break; break;
} }
}
mutex_unlock(&dp->train_mutex); static void mdss_dp_hdcp_cb(void *ptr, enum hdcp_states status)
{
struct mdss_dp_drv_pdata *dp = ptr;
if (!dp) {
pr_err("invalid input\n");
return;
}
dp->hdcp_status = status;
queue_delayed_work(dp->workq, &dp->hdcp_cb_work, HZ/4);
} }
static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata) static int mdss_dp_hdcp_init(struct mdss_panel_data *pdata)
@ -1888,6 +1896,13 @@ static void mdss_dp_update_hdcp_info(struct mdss_dp_drv_pdata *dp)
dp->hdcp.ops = ops; dp->hdcp.ops = ops;
} }
static inline bool dp_is_hdcp_enabled(struct mdss_dp_drv_pdata *dp_drv)
{
return dp_drv->hdcp.feature_enabled &&
(dp_drv->hdcp.hdcp1_present || dp_drv->hdcp.hdcp2_present) &&
dp_drv->hdcp.ops;
}
static int mdss_dp_event_handler(struct mdss_panel_data *pdata, static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
int event, void *arg) int event, void *arg)
{ {
@ -1919,8 +1934,10 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata,
rc = mdss_dp_off(pdata); rc = mdss_dp_off(pdata);
break; break;
case MDSS_EVENT_BLANK: case MDSS_EVENT_BLANK:
if (dp->hdcp.ops && dp->hdcp.ops->off) if (dp_is_hdcp_enabled(dp) && dp->hdcp.ops->off) {
flush_delayed_work(&dp->hdcp_cb_work);
dp->hdcp.ops->off(dp->hdcp.data); dp->hdcp.ops->off(dp->hdcp.data);
}
mdss_dp_mainlink_push_idle(pdata); mdss_dp_mainlink_push_idle(pdata);
break; break;
@ -2197,6 +2214,11 @@ irqreturn_t dp_isr(int irq, void *ptr)
dp_aux_native_handler(dp, isr1); dp_aux_native_handler(dp, isr1);
} }
if (dp->hdcp.ops && dp->hdcp.ops->isr) {
if (dp->hdcp.ops->isr(dp->hdcp.data))
pr_err("dp_hdcp_isr failed\n");
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -2211,6 +2233,7 @@ static int mdss_dp_event_setup(struct mdss_dp_drv_pdata *dp)
} }
INIT_WORK(&dp->work, mdss_dp_event_work); INIT_WORK(&dp->work, mdss_dp_event_work);
INIT_DELAYED_WORK(&dp->hdcp_cb_work, mdss_dp_hdcp_cb_work);
return 0; return 0;
} }
@ -2434,8 +2457,6 @@ static void mdss_dp_process_hpd_irq_high(struct mdss_dp_drv_pdata *dp)
{ {
int ret = 0; int ret = 0;
pr_debug("enter: HPD IRQ High\n");
dp->hpd_irq_on = true; dp->hpd_irq_on = true;
mdss_dp_aux_parse_sink_status_field(dp); mdss_dp_aux_parse_sink_status_field(dp);
@ -2523,6 +2544,12 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
dp_drv->alt_mode.dp_status.hpd_irq; dp_drv->alt_mode.dp_status.hpd_irq;
if (dp_drv->alt_mode.dp_status.hpd_irq) { if (dp_drv->alt_mode.dp_status.hpd_irq) {
pr_debug("Attention: hpd_irq high\n");
if (dp_drv->power_on && dp_drv->hdcp.ops &&
dp_drv->hdcp.ops->cp_irq)
dp_drv->hdcp.ops->cp_irq(dp_drv->hdcp.data);
mdss_dp_process_hpd_irq_high(dp_drv); mdss_dp_process_hpd_irq_high(dp_drv);
break; break;
} }
@ -2552,9 +2579,6 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
else else
dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE); dp_send_events(dp_drv, EV_USBPD_DP_CONFIGURE);
if (dp_drv->alt_mode.dp_status.hpd_irq && dp_drv->power_on &&
dp_drv->hdcp.ops && dp_drv->hdcp.ops->isr)
dp_drv->hdcp.ops->isr(dp_drv->hdcp.data);
break; break;
case DP_VDM_STATUS: case DP_VDM_STATUS:
dp_drv->alt_mode.dp_status.response = *vdos; dp_drv->alt_mode.dp_status.response = *vdos;
@ -2770,13 +2794,6 @@ void *mdss_dp_get_hdcp_data(struct device *dev)
return dp_drv->hdcp.data; return dp_drv->hdcp.data;
} }
static inline bool dp_is_hdcp_enabled(struct mdss_dp_drv_pdata *dp_drv)
{
return dp_drv->hdcp.feature_enabled &&
(dp_drv->hdcp.hdcp1_present || dp_drv->hdcp.hdcp2_present) &&
dp_drv->hdcp.ops;
}
static inline bool dp_is_stream_shareable(struct mdss_dp_drv_pdata *dp_drv) static inline bool dp_is_stream_shareable(struct mdss_dp_drv_pdata *dp_drv)
{ {
bool ret = 0; bool ret = 0;

View file

@ -484,6 +484,7 @@ struct mdss_dp_drv_pdata {
/* event */ /* event */
struct workqueue_struct *workq; struct workqueue_struct *workq;
struct work_struct work; struct work_struct work;
struct delayed_work hdcp_cb_work;
u32 current_event; u32 current_event;
spinlock_t event_lock; spinlock_t event_lock;
spinlock_t lock; spinlock_t lock;
@ -494,6 +495,7 @@ struct mdss_dp_drv_pdata {
u32 vic; u32 vic;
u32 new_vic; u32 new_vic;
int fb_node; int fb_node;
int hdcp_status;
struct dpcd_test_request test_data; struct dpcd_test_request test_data;
struct dpcd_sink_count sink_count; struct dpcd_sink_count sink_count;

View file

@ -53,7 +53,6 @@ struct dp_hdcp2p2_ctrl {
struct kthread_work send_msg; struct kthread_work send_msg;
struct kthread_work recv_msg; struct kthread_work recv_msg;
struct kthread_work link; struct kthread_work link;
struct kthread_work poll;
char *msg_buf; char *msg_buf;
uint32_t send_msg_len; /* length of all parameters in msg */ uint32_t send_msg_len; /* length of all parameters in msg */
uint32_t timeout; uint32_t timeout;
@ -67,26 +66,6 @@ struct dp_hdcp2p2_ctrl {
bool polling; bool polling;
}; };
static inline char *dp_hdcp_cmd_to_str(uint32_t cmd)
{
switch (cmd) {
case HDMI_HDCP_WKUP_CMD_SEND_MESSAGE:
return "HDMI_HDCP_WKUP_CMD_SEND_MESSAGE";
case HDMI_HDCP_WKUP_CMD_RECV_MESSAGE:
return "HDMI_HDCP_WKUP_CMD_RECV_MESSAGE";
case HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS:
return "HDMI_HDCP_WKUP_CMD_STATUS_SUCCESS";
case HDMI_HDCP_WKUP_CMD_STATUS_FAILED:
return "DP_HDCP_WKUP_CMD_STATUS_FAIL";
case HDMI_HDCP_WKUP_CMD_LINK_POLL:
return "HDMI_HDCP_WKUP_CMD_LINK_POLL";
case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
return "HDMI_HDCP_WKUP_CMD_AUTHENTICATE";
default:
return "???";
}
}
static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl) static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl)
{ {
if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE) if (ctrl->wakeup_cmd == HDMI_HDCP_WKUP_CMD_AUTHENTICATE)
@ -193,7 +172,7 @@ static int dp_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
queue_kthread_work(&ctrl->worker, &ctrl->status); queue_kthread_work(&ctrl->worker, &ctrl->status);
break; break;
case HDMI_HDCP_WKUP_CMD_LINK_POLL: case HDMI_HDCP_WKUP_CMD_LINK_POLL:
queue_kthread_work(&ctrl->worker, &ctrl->poll); ctrl->polling = true;
break; break;
case HDMI_HDCP_WKUP_CMD_AUTHENTICATE: case HDMI_HDCP_WKUP_CMD_AUTHENTICATE:
queue_kthread_work(&ctrl->worker, &ctrl->auth); queue_kthread_work(&ctrl->worker, &ctrl->auth);
@ -203,10 +182,11 @@ static int dp_hdcp2p2_wakeup(struct hdmi_hdcp_wakeup_data *data)
} }
exit: exit:
mutex_unlock(&ctrl->wakeup_mutex); mutex_unlock(&ctrl->wakeup_mutex);
return 0; return 0;
} }
static inline int dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl, static inline void dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl,
struct hdcp_lib_wakeup_data *data) struct hdcp_lib_wakeup_data *data)
{ {
int rc = 0; int rc = 0;
@ -218,8 +198,6 @@ static inline int dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl,
pr_err("error sending %s to lib\n", pr_err("error sending %s to lib\n",
hdcp_lib_cmd_to_str(data->cmd)); hdcp_lib_cmd_to_str(data->cmd));
} }
return rc;
} }
static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl)
@ -339,8 +317,6 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
return; return;
} }
atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
/* notify DP about HDCP failure */ /* notify DP about HDCP failure */
ctrl->init_data.notify_status(ctrl->init_data.cb_data, ctrl->init_data.notify_status(ctrl->init_data.cb_data,
HDCP_STATE_AUTH_FAIL); HDCP_STATE_AUTH_FAIL);
@ -349,8 +325,7 @@ static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl)
static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl, static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl,
u8 *buf, int size, int offset, u32 timeout) u8 *buf, int size, int offset, u32 timeout)
{ {
int rc, max_size = 16, read_size, len = size; int rc, max_size = 16, read_size;
u8 *buf_start = buf;
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
pr_err("hdcp is off\n"); pr_err("hdcp is off\n");
@ -378,8 +353,6 @@ static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl,
size -= read_size; size -= read_size;
} while (size > 0); } while (size > 0);
print_hex_dump(KERN_DEBUG, "hdcp2p2: ", DUMP_PREFIX_NONE,
16, 1, buf_start, len, false);
return rc; return rc;
} }
@ -550,7 +523,6 @@ exit:
static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work) static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work)
{ {
int rc = 0;
struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID }; struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID };
struct dp_hdcp2p2_ctrl *ctrl = container_of(work, struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
struct dp_hdcp2p2_ctrl, recv_msg); struct dp_hdcp2p2_ctrl, recv_msg);
@ -559,44 +531,24 @@ static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work)
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) {
pr_err("hdcp is off\n"); pr_err("hdcp is off\n");
goto exit; return;
} }
if (ctrl->sink_rx_status & ctrl->abort_mask) { if (ctrl->rx_status) {
pr_err("reauth or Link fail triggered by sink\n"); if (!ctrl->cp_irq_done) {
pr_debug("waiting for CP_IRQ\n");
ctrl->polling = true;
return;
}
ctrl->sink_rx_status = 0; if (ctrl->rx_status & ctrl->sink_rx_status) {
rc = -ENOLINK; ctrl->cp_irq_done = false;
cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; ctrl->sink_rx_status = 0;
ctrl->rx_status = 0;
goto exit; }
}
if (ctrl->rx_status && !ctrl->sink_rx_status) {
pr_debug("Recv msg for RxStatus, but no CP_IRQ yet\n");
ctrl->polling = true;
goto exit;
} }
dp_hdcp2p2_get_msg_from_sink(ctrl); dp_hdcp2p2_get_msg_from_sink(ctrl);
return;
exit:
if (rc)
dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
}
static void dp_hdcp2p2_poll_work(struct kthread_work *work)
{
struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
struct dp_hdcp2p2_ctrl, poll);
if (ctrl->cp_irq_done) {
ctrl->cp_irq_done = false;
dp_hdcp2p2_get_msg_from_sink(ctrl);
} else {
ctrl->polling = true;
}
} }
static void dp_hdcp2p2_auth_status_work(struct kthread_work *work) static void dp_hdcp2p2_auth_status_work(struct kthread_work *work)
@ -645,44 +597,45 @@ static void dp_hdcp2p2_link_work(struct kthread_work *work)
if (rc) { if (rc) {
pr_err("failed to read rx status\n"); pr_err("failed to read rx status\n");
cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED;
atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
goto exit; goto exit;
} }
if (ctrl->sink_rx_status & ctrl->abort_mask) { if (ctrl->sink_rx_status & ctrl->abort_mask) {
pr_err("reauth or Link fail triggered by sink\n"); if (ctrl->sink_rx_status & BIT(3))
pr_err("reauth_req set by sink\n");
if (ctrl->sink_rx_status & BIT(4))
pr_err("link failure reported by sink\n");
ctrl->sink_rx_status = 0; ctrl->sink_rx_status = 0;
ctrl->rx_status = 0; ctrl->rx_status = 0;
rc = -ENOLINK; rc = -ENOLINK;
cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED;
atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL);
goto exit; goto exit;
} }
/* if polling, get message from sink else let polling start */
if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) { if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) {
ctrl->sink_rx_status = 0; ctrl->sink_rx_status = 0;
ctrl->rx_status = 0; ctrl->rx_status = 0;
rc = dp_hdcp2p2_get_msg_from_sink(ctrl); dp_hdcp2p2_get_msg_from_sink(ctrl);
ctrl->polling = false; ctrl->polling = false;
} else { } else {
ctrl->cp_irq_done = true; ctrl->cp_irq_done = true;
} }
exit: exit:
dp_hdcp2p2_wakeup_lib(ctrl, &cdata); if (rc)
dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
if (rc) {
dp_hdcp2p2_auth_failed(ctrl);
return;
}
} }
static void dp_hdcp2p2_auth_work(struct kthread_work *work) static void dp_hdcp2p2_auth_work(struct kthread_work *work)
{ {
int rc = 0;
struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID};
struct dp_hdcp2p2_ctrl *ctrl = container_of(work, struct dp_hdcp2p2_ctrl *ctrl = container_of(work,
struct dp_hdcp2p2_ctrl, auth); struct dp_hdcp2p2_ctrl, auth);
@ -694,12 +647,10 @@ static void dp_hdcp2p2_auth_work(struct kthread_work *work)
else else
cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; cdata.cmd = HDCP_LIB_WKUP_CMD_STOP;
rc = dp_hdcp2p2_wakeup_lib(ctrl, &cdata); dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
if (rc)
dp_hdcp2p2_auth_failed(ctrl);
} }
static int dp_hdcp2p2_isr(void *input) static int dp_hdcp2p2_cp_irq(void *input)
{ {
struct dp_hdcp2p2_ctrl *ctrl = input; struct dp_hdcp2p2_ctrl *ctrl = input;
@ -748,7 +699,7 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data)
.authenticate = dp_hdcp2p2_authenticate, .authenticate = dp_hdcp2p2_authenticate,
.feature_supported = dp_hdcp2p2_feature_supported, .feature_supported = dp_hdcp2p2_feature_supported,
.off = dp_hdcp2p2_off, .off = dp_hdcp2p2_off,
.isr = dp_hdcp2p2_isr .cp_irq = dp_hdcp2p2_cp_irq,
}; };
static struct hdcp_client_ops client_ops = { static struct hdcp_client_ops client_ops = {
@ -806,7 +757,6 @@ void *dp_hdcp2p2_init(struct hdcp_init_data *init_data)
init_kthread_work(&ctrl->recv_msg, dp_hdcp2p2_recv_msg_work); init_kthread_work(&ctrl->recv_msg, dp_hdcp2p2_recv_msg_work);
init_kthread_work(&ctrl->status, dp_hdcp2p2_auth_status_work); init_kthread_work(&ctrl->status, dp_hdcp2p2_auth_status_work);
init_kthread_work(&ctrl->link, dp_hdcp2p2_link_work); init_kthread_work(&ctrl->link, dp_hdcp2p2_link_work);
init_kthread_work(&ctrl->poll, dp_hdcp2p2_poll_work);
ctrl->thread = kthread_run(kthread_worker_fn, ctrl->thread = kthread_run(kthread_worker_fn,
&ctrl->worker, "dp_hdcp2p2"); &ctrl->worker, "dp_hdcp2p2");

View file

@ -55,6 +55,7 @@ struct hdcp_init_data {
struct hdcp_ops { struct hdcp_ops {
int (*isr)(void *ptr); int (*isr)(void *ptr);
int (*cp_irq)(void *ptr);
int (*reauthenticate)(void *input); int (*reauthenticate)(void *input);
int (*authenticate)(void *hdcp_ctrl); int (*authenticate)(void *hdcp_ctrl);
bool (*feature_supported)(void *input); bool (*feature_supported)(void *input);

View file

@ -26,6 +26,7 @@ enum hdcp_lib_wakeup_cmd {
HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED, HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED,
HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT, HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT,
HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE, HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE,
HDCP_LIB_WKUP_CMD_LINK_FAILED,
}; };
enum hdmi_hdcp_wakeup_cmd { enum hdmi_hdcp_wakeup_cmd {
@ -106,6 +107,8 @@ static inline char *hdcp_lib_cmd_to_str(uint32_t cmd)
return "HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT"; return "HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT";
case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE: case HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE:
return "HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE"; return "HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE";
case HDCP_LIB_WKUP_CMD_LINK_FAILED:
return "HDCP_LIB_WKUP_CMD_LINK_FAILED";
default: default:
return "???"; return "???";
} }