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:
parent
821b280d6a
commit
01cb3026c6
6 changed files with 141 additions and 131 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 "???";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue