summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Braga <cbraga@codeaurora.org>2019-04-22 14:33:25 -0400
committerChristopher Braga <cbraga@codeaurora.org>2019-04-24 17:42:07 -0400
commit83af37f1e59df7ae6662c0622f20acb93667d065 (patch)
treeec00836bfcc3be02f243d76571912e1b21619c53
parent9b09b9af71e4860835a967b9d62253c9e5f7dac3 (diff)
downloaddisplay-drivers-83af37f1e59df7ae6662c0622f20acb93667d065.tar.gz
disp: msm: make the HDCP protocol module asynchronous
Commands to the HDCP protocol layer can fail or block if executed when the system enters suspend or shutdown. Protocol layer blockage will occur until the system returns into a power on state, potentially resulting in deadlocks for clients who synchronously wait on protocol layer completion. Asynchronously handle all requests to the protocol module to ensure that clients can make progress regardless of the state of the underlying HDCP handler. When an already queued request is received by the protocol module, that request will be rescheduled to the back of the queue. Change-Id: I658dd09a81f21037cd90bbaa5b7d73363472e0b0 Signed-off-by: Christopher Braga <cbraga@codeaurora.org>
-rw-r--r--msm/dp/dp_hdcp2p2.c24
-rw-r--r--msm/sde_hdcp.h1
-rw-r--r--msm/sde_hdcp_2x.c275
-rw-r--r--msm/sde_hdcp_2x.h6
4 files changed, 159 insertions, 147 deletions
diff --git a/msm/dp/dp_hdcp2p2.c b/msm/dp/dp_hdcp2p2.c
index f71c25e6..61404be5 100644
--- a/msm/dp/dp_hdcp2p2.c
+++ b/msm/dp/dp_hdcp2p2.c
@@ -238,19 +238,22 @@ static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl)
static int dp_hdcp2p2_register(void *input, bool mst_enabled)
{
int rc;
- enum sde_hdcp_2x_device_type device_type;
- struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
+ struct dp_hdcp2p2_ctrl *ctrl = input;
+ struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_ENABLE};
rc = dp_hdcp2p2_valid_handle(ctrl);
if (rc)
return rc;
if (mst_enabled)
- device_type = HDCP_TXMTR_DP_MST;
+ cdata.device_type = HDCP_TXMTR_DP_MST;
else
- device_type = HDCP_TXMTR_DP;
+ cdata.device_type = HDCP_TXMTR_DP;
- return sde_hdcp_2x_enable(ctrl->lib_ctx, device_type);
+ cdata.context = ctrl->lib_ctx;
+ rc = ctrl->lib->wakeup(&cdata);
+
+ return rc;
}
static int dp_hdcp2p2_on(void *input)
@@ -276,25 +279,20 @@ static void dp_hdcp2p2_off(void *input)
{
int rc;
struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input;
- struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_INVALID};
+ struct sde_hdcp_2x_wakeup_data cdata = {HDCP_2X_CMD_DISABLE};
rc = dp_hdcp2p2_valid_handle(ctrl);
if (rc)
return;
- if (atomic_read(&ctrl->auth_state) != HDCP_STATE_AUTH_FAIL) {
- cdata.cmd = HDCP_2X_CMD_STOP;
- cdata.context = ctrl->lib_ctx;
- dp_hdcp2p2_wakeup_lib(ctrl, &cdata);
- }
-
dp_hdcp2p2_set_interrupts(ctrl, false);
dp_hdcp2p2_reset(ctrl);
kthread_park(ctrl->thread);
- sde_hdcp_2x_disable(ctrl->lib_ctx);
+ cdata.context = ctrl->lib_ctx;
+ ctrl->lib->wakeup(&cdata);
}
static int dp_hdcp2p2_authenticate(void *input)
diff --git a/msm/sde_hdcp.h b/msm/sde_hdcp.h
index 5c1dc4af..49a6a951 100644
--- a/msm/sde_hdcp.h
+++ b/msm/sde_hdcp.h
@@ -51,6 +51,7 @@ struct sde_hdcp_stream {
u8 stream_id;
u8 virtual_channel;
u32 stream_handle;
+ bool active;
};
struct sde_hdcp_init_data {
diff --git a/msm/sde_hdcp_2x.c b/msm/sde_hdcp_2x.c
index f578e09c..5131bc3f 100644
--- a/msm/sde_hdcp_2x.c
+++ b/msm/sde_hdcp_2x.c
@@ -49,6 +49,7 @@ struct sde_hdcp_2x_ctrl {
u32 timeout_left;
u32 wait_timeout_ms;
u32 total_message_length;
+ atomic_t enable_pending;
bool no_stored_km;
bool feature_supported;
bool force_encryption;
@@ -66,8 +67,6 @@ struct sde_hdcp_2x_ctrl {
u8 min_enc_level;
struct list_head stream_handles;
u8 stream_count;
- struct stream_info *streams;
- u8 num_streams;
struct task_struct *thread;
struct completion response_completion;
@@ -301,6 +300,9 @@ static bool sde_hdcp_2x_client_feature_supported(void *data)
{
struct sde_hdcp_2x_ctrl *hdcp = data;
+ while (atomic_read(&hdcp->enable_pending))
+ usleep_range(1000, 1500);
+
return hdcp2_feature_supported(hdcp->hdcp2_ctx);
}
@@ -671,62 +673,37 @@ static struct list_head *sde_hdcp_2x_stream_present(
return entry;
}
-static void sde_hdcp_2x_open_stream(struct sde_hdcp_2x_ctrl *hdcp)
+
+static void sde_hdcp_2x_manage_stream(struct sde_hdcp_2x_ctrl *hdcp)
{
- int rc;
- size_t iterations, i;
- u8 stream_id;
- u8 virtual_channel;
- u32 stream_handle = 0;
+ struct list_head *entry;
+ struct list_head *element;
+ struct sde_hdcp_stream *stream_entry;
bool query_streams = false;
- if (!hdcp->streams) {
- pr_err("Array of streams to register is NULL\n");
- return;
- }
-
- iterations = min(hdcp->num_streams, (u8)(MAX_STREAM_COUNT));
-
- for (i = 0; i < iterations; i++) {
- if (hdcp->stream_count == MAX_STREAM_COUNT) {
- pr_debug("Registered the maximum amount of streams\n");
- break;
- }
-
- stream_id = hdcp->streams[i].stream_id;
- virtual_channel = hdcp->streams[i].virtual_channel;
-
- pr_debug("Opening stream %d, virtual channel %d\n",
- stream_id, virtual_channel);
-
- if (sde_hdcp_2x_stream_present(hdcp, stream_id,
- virtual_channel)) {
- pr_debug("Stream %d, virtual channel %d already open\n",
- stream_id, virtual_channel);
- continue;
- }
-
- rc = hdcp2_open_stream(hdcp->hdcp2_ctx, virtual_channel,
- stream_id, &stream_handle);
- if (rc) {
- pr_err("Unable to open stream %d, virtual channel %d\n",
- stream_id, virtual_channel);
- } else {
- struct sde_hdcp_stream *stream =
- kzalloc(sizeof(struct sde_hdcp_stream),
- GFP_KERNEL);
- if (!stream)
- break;
-
- INIT_LIST_HEAD(&stream->list);
- stream->stream_handle = stream_handle;
- stream->stream_id = stream_id;
- stream->virtual_channel = virtual_channel;
-
- list_add(&stream->list, &hdcp->stream_handles);
- hdcp->stream_count++;
-
+ entry = hdcp->stream_handles.next;
+ while (entry != &hdcp->stream_handles) {
+ stream_entry = list_entry(entry, struct sde_hdcp_stream, list);
+ element = entry;
+ entry = entry->next;
+
+ if (!stream_entry->active) {
+ hdcp2_close_stream(hdcp->hdcp2_ctx,
+ stream_entry->stream_handle);
+ hdcp->stream_count--;
+ list_del(element);
+ kzfree(stream_entry);
query_streams = true;
+ } else if (!stream_entry->stream_handle) {
+ if (hdcp2_open_stream(hdcp->hdcp2_ctx,
+ stream_entry->virtual_channel,
+ stream_entry->stream_id,
+ &stream_entry->stream_handle))
+ pr_err("Unable to open stream %d, virtual channel %d\n",
+ stream_entry->stream_id,
+ stream_entry->virtual_channel);
+ else
+ query_streams = true;
}
}
@@ -734,62 +711,78 @@ static void sde_hdcp_2x_open_stream(struct sde_hdcp_2x_ctrl *hdcp)
sde_hdcp_2x_query_stream(hdcp);
}
-static void sde_hdcp_2x_close_stream(struct sde_hdcp_2x_ctrl *hdcp)
+
+static bool sde_hdcp_2x_remove_streams(struct sde_hdcp_2x_ctrl *hdcp,
+ struct stream_info *streams, u8 num_streams)
{
- int rc;
- size_t iterations, i;
+ u8 i;
u8 stream_id;
u8 virtual_channel;
struct list_head *entry;
struct sde_hdcp_stream *stream_entry;
- bool query_streams = false;
+ bool changed = false;
- if (!hdcp->streams) {
- pr_err("Array of streams to register is NULL\n");
- return;
- }
+ for (i = 0 ; i < num_streams; i++) {
+ stream_id = streams[i].stream_id;
+ virtual_channel = streams[i].virtual_channel;
+ entry = sde_hdcp_2x_stream_present(hdcp, stream_id,
+ virtual_channel);
+ if (!entry)
+ continue;
- iterations = min(hdcp->num_streams, (u8)(MAX_STREAM_COUNT));
+ stream_entry = list_entry(entry, struct sde_hdcp_stream,
+ list);
- for (i = 0; i < iterations; i++) {
- if (hdcp->stream_count == 0) {
- pr_debug("No streams are currently registered\n");
- return;
+ if (!stream_entry->stream_handle) {
+ /* Stream wasn't fully initialized so remove it */
+ hdcp->stream_count--;
+ list_del(entry);
+ kzfree(stream_entry);
+ } else {
+ stream_entry->active = false;
}
+ changed = true;
+ }
- stream_id = hdcp->streams[i].stream_id;
- virtual_channel = hdcp->streams[i].virtual_channel;
+ return changed;
+}
- pr_debug("Closing stream %d, virtual channel %d\n",
- stream_id, virtual_channel);
+static bool sde_hdcp_2x_add_streams(struct sde_hdcp_2x_ctrl *hdcp,
+ struct stream_info *streams, u8 num_streams)
+{
+ u8 i;
+ u8 stream_id;
+ u8 virtual_channel;
+ struct sde_hdcp_stream *stream;
+ bool changed = false;
- entry = sde_hdcp_2x_stream_present(hdcp, stream_id,
- virtual_channel);
+ for (i = 0 ; i < num_streams; i++) {
+ stream_id = streams[i].stream_id;
+ virtual_channel = streams[i].virtual_channel;
- if (!entry) {
- pr_err("Unable to find stream %d, virtual channel %d\n"
- , stream_id, virtual_channel);
+ if (sde_hdcp_2x_stream_present(hdcp, stream_id,
+ virtual_channel))
continue;
- }
- stream_entry = list_entry(entry, struct sde_hdcp_stream,
- list);
+ stream = kzalloc(sizeof(struct sde_hdcp_stream), GFP_KERNEL);
+ if (!stream)
+ continue;
- rc = hdcp2_close_stream(hdcp->hdcp2_ctx,
- stream_entry->stream_handle);
- if (rc)
- pr_err("Unable to close stream %d, virtual channel %d\n"
- , stream_id, virtual_channel);
- hdcp->stream_count--;
- list_del(entry);
- kzfree(stream_entry);
- query_streams = true;
+ INIT_LIST_HEAD(&stream->list);
+ stream->stream_handle = 0;
+ stream->stream_id = stream_id;
+ stream->virtual_channel = virtual_channel;
+ stream->active = true;
+
+ list_add(&stream->list, &hdcp->stream_handles);
+ hdcp->stream_count++;
+ changed = true;
}
- if (query_streams && hdcp->authenticated)
- sde_hdcp_2x_query_stream(hdcp);
+ return changed;
}
+
/** sde_hdcp_2x_wakeup() - wakeup the module to execute a requested command
* @data: data required for executing corresponding command.
*
@@ -813,18 +806,22 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)
hdcp->timeout_left = data->timeout;
hdcp->total_message_length = data->total_message_length;
hdcp->min_enc_level = data->min_enc_level;
- hdcp->streams = data->streams;
- hdcp->num_streams = data->num_streams;
if (!completion_done(&hdcp->response_completion))
complete_all(&hdcp->response_completion);
- kfifo_put(&hdcp->cmd_q, data->cmd);
-
switch (data->cmd) {
+ case HDCP_2X_CMD_ENABLE:
+ if (!atomic_cmpxchg(&hdcp->enable_pending, 0, 1)) {
+ hdcp->device_type = data->device_type;
+ kfifo_put(&hdcp->cmd_q, data->cmd);
+ wake_up(&hdcp->wait_q);
+ }
+ break;
case HDCP_2X_CMD_STOP:
atomic_set(&hdcp->hdcp_off, 1);
+ kfifo_put(&hdcp->cmd_q, data->cmd);
kthread_park(hdcp->thread);
break;
case HDCP_2X_CMD_START:
@@ -836,10 +833,26 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)
hdcp->timeout_left = 0;
atomic_set(&hdcp->hdcp_off, 0);
+ kfifo_put(&hdcp->cmd_q, data->cmd);
kthread_unpark(hdcp->thread);
wake_up(&hdcp->wait_q);
break;
+ case HDCP_2X_CMD_OPEN_STREAMS:
+ if (sde_hdcp_2x_add_streams(hdcp, data->streams,
+ data->num_streams)) {
+ kfifo_put(&hdcp->cmd_q, data->cmd);
+ wake_up(&hdcp->wait_q);
+ }
+ break;
+ case HDCP_2X_CMD_CLOSE_STREAMS:
+ if (sde_hdcp_2x_remove_streams(hdcp, data->streams,
+ data->num_streams)) {
+ kfifo_put(&hdcp->cmd_q, data->cmd);
+ wake_up(&hdcp->wait_q);
+ }
+ break;
default:
+ kfifo_put(&hdcp->cmd_q, data->cmd);
wake_up(&hdcp->wait_q);
break;
}
@@ -847,6 +860,30 @@ static int sde_hdcp_2x_wakeup(struct sde_hdcp_2x_wakeup_data *data)
return rc;
}
+static void sde_hdcp_2x_enable(struct sde_hdcp_2x_ctrl *hdcp)
+{
+ if (!hdcp)
+ return;
+
+ if (hdcp->hdcp2_ctx) {
+ pr_debug("HDCP library context already acquired\n");
+ return;
+ }
+
+ hdcp->hdcp2_ctx = hdcp2_init(hdcp->device_type);
+ if (!hdcp->hdcp2_ctx)
+ pr_err("Unable to acquire HDCP library handle\n");
+}
+
+static void sde_hdcp_2x_disable(struct sde_hdcp_2x_ctrl *hdcp)
+{
+ if (!hdcp->hdcp2_ctx)
+ return;
+
+ hdcp2_deinit(hdcp->hdcp2_ctx);
+ hdcp->hdcp2_ctx = NULL;
+}
+
static int sde_hdcp_2x_main(void *data)
{
struct sde_hdcp_2x_ctrl *hdcp = data;
@@ -870,6 +907,15 @@ static int sde_hdcp_2x_main(void *data)
continue;
switch (cmd) {
+ case HDCP_2X_CMD_ENABLE:
+ sde_hdcp_2x_enable(hdcp);
+ atomic_set(&hdcp->enable_pending, 0);
+ break;
+ case HDCP_2X_CMD_DISABLE:
+ if (!atomic_xchg(&hdcp->hdcp_off, 1))
+ sde_hdcp_2x_clean(hdcp);
+ sde_hdcp_2x_disable(hdcp);
+ break;
case HDCP_2X_CMD_START:
sde_hdcp_2x_init(hdcp);
break;
@@ -904,10 +950,8 @@ static int sde_hdcp_2x_main(void *data)
sde_hdcp_2x_query_stream(hdcp);
break;
case HDCP_2X_CMD_OPEN_STREAMS:
- sde_hdcp_2x_open_stream(hdcp);
- break;
case HDCP_2X_CMD_CLOSE_STREAMS:
- sde_hdcp_2x_close_stream(hdcp);
+ sde_hdcp_2x_manage_stream(hdcp);
break;
default:
break;
@@ -961,6 +1005,7 @@ int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data)
init_waitqueue_head(&hdcp->wait_q);
atomic_set(&hdcp->hdcp_off, 1);
+ atomic_set(&hdcp->enable_pending, 0);
init_completion(&hdcp->response_completion);
@@ -985,40 +1030,6 @@ unlock:
return rc;
}
-int sde_hdcp_2x_enable(void *data, enum sde_hdcp_2x_device_type device_type)
-{
- int rc = 0;
- struct sde_hdcp_2x_ctrl *hdcp = data;
-
- if (!hdcp)
- return -EINVAL;
-
- if (hdcp->hdcp2_ctx) {
- pr_debug("HDCP library context already acquired\n");
- return 0;
- }
-
- hdcp->device_type = device_type;
- hdcp->hdcp2_ctx = hdcp2_init(hdcp->device_type);
- if (!hdcp->hdcp2_ctx) {
- pr_err("Unable to acquire HDCP library handle\n");
- return -ENOMEM;
- }
-
- return rc;
-}
-
-void sde_hdcp_2x_disable(void *data)
-{
- struct sde_hdcp_2x_ctrl *hdcp = data;
-
- if (!hdcp->hdcp2_ctx)
- return;
-
- hdcp2_deinit(hdcp->hdcp2_ctx);
- hdcp->hdcp2_ctx = NULL;
-}
-
void sde_hdcp_2x_deregister(void *data)
{
struct sde_hdcp_2x_ctrl *hdcp = data;
@@ -1026,7 +1037,7 @@ void sde_hdcp_2x_deregister(void *data)
if (!hdcp)
return;
- sde_hdcp_2x_disable(data);
kthread_stop(hdcp->thread);
+ sde_hdcp_2x_disable(data);
kzfree(hdcp);
}
diff --git a/msm/sde_hdcp_2x.h b/msm/sde_hdcp_2x.h
index cfcd7ce1..4669564d 100644
--- a/msm/sde_hdcp_2x.h
+++ b/msm/sde_hdcp_2x.h
@@ -32,6 +32,8 @@
*/
enum sde_hdcp_2x_wakeup_cmd {
HDCP_2X_CMD_INVALID,
+ HDCP_2X_CMD_ENABLE,
+ HDCP_2X_CMD_DISABLE,
HDCP_2X_CMD_START,
HDCP_2X_CMD_START_AUTH,
HDCP_2X_CMD_STOP,
@@ -79,6 +81,7 @@ enum sde_hdcp_2x_device_type {
/**
* struct sde_hdcp_2x_lib_wakeup_data - command and data send to HDCP driver
* @cmd: command type
+ * @device_type type of device in use by the HDCP driver
* @context: void pointer to the HDCP driver instance
* @buf: message received from the sink
* @buf_len: length of message received from the sink
@@ -88,6 +91,7 @@ enum sde_hdcp_2x_device_type {
*/
struct sde_hdcp_2x_wakeup_data {
enum sde_hdcp_2x_wakeup_cmd cmd;
+ enum sde_hdcp_2x_device_type device_type;
void *context;
uint32_t total_message_length;
uint32_t timeout;
@@ -211,7 +215,5 @@ struct sde_hdcp_2x_register_data {
/* functions for the HDCP 2.2 state machine module */
int sde_hdcp_2x_register(struct sde_hdcp_2x_register_data *data);
-int sde_hdcp_2x_enable(void *data, enum sde_hdcp_2x_device_type device_type);
-void sde_hdcp_2x_disable(void *data);
void sde_hdcp_2x_deregister(void *data);
#endif