summaryrefslogtreecommitdiff
path: root/drivers/video/tegra
diff options
context:
space:
mode:
authorMatt Wagner <mwagner@nvidia.com>2012-08-02 15:49:50 -0700
committerLokesh Pathak <lpathak@nvidia.com>2012-08-09 08:29:46 -0700
commita7eb6356009a8e7423a200b49654a883117f282f (patch)
tree1d90c82b3149a129080b2f0ced5b1705d3682f8b /drivers/video/tegra
parent57716f1d1f8381ff50874cb81c326e203909b4f3 (diff)
video: tegra: hdcp: Fix Locking Issue
Locking in nvhdcp was set up in such a way that we couldn't change the state of the HDMI plug while negotiating the HDCP connection. Another lock was added that is only taken when the state of the plug or hdcp session are changed. This enables correct failure if the plug is removed during negotiation. Bug 1024031 Reviewed-on: http://git-master/r/120546 (cherry picked from commit 51f746421b73f8f378bd7908b35fd6c79687e239) Change-Id: Id9a9b09f2cd03a1b51e7334391f35fc076a1e1dd Signed-off-by: Matt Wagner <mwagner@nvidia.com> Reviewed-on: http://git-master/r/121399 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Jon Mayo <jmayo@nvidia.com>
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r--drivers/video/tegra/dc/nvhdcp.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/drivers/video/tegra/dc/nvhdcp.c b/drivers/video/tegra/dc/nvhdcp.c
index 3566e2b..b509a6c 100644
--- a/drivers/video/tegra/dc/nvhdcp.c
+++ b/drivers/video/tegra/dc/nvhdcp.c
@@ -78,6 +78,7 @@ struct tegra_nvhdcp {
struct tegra_dc_hdmi_data *hdmi;
struct workqueue_struct *downstream_wq;
struct mutex lock;
+ struct mutex state_lock;
struct miscdevice miscdev;
char name[12];
unsigned id;
@@ -980,7 +981,9 @@ static void nvhdcp_downstream_worker(struct work_struct *work)
nvhdcp_vdbg("CRYPT enabled\n");
+ mutex_lock(&nvhdcp->state_lock);
nvhdcp->state = STATE_LINK_VERIFY;
+ mutex_unlock(&nvhdcp->state_lock);
nvhdcp_info("link verified!\n");
while (1) {
@@ -1007,30 +1010,39 @@ failure:
if(nvhdcp->fail_count > 5) {
nvhdcp_err("nvhdcp failure - too many failures, giving up!\n");
} else {
- nvhdcp_err("nvhdcp failure - renegotiating in 1 second\n");
- if (!nvhdcp_is_plugged(nvhdcp))
+ if (!nvhdcp_is_plugged(nvhdcp)) {
+ nvhdcp_err("nvhdcp failure\n");
goto lost_hdmi;
+ }
+ nvhdcp_err("nvhdcp failure - renegotiating in 1 second\n");
queue_delayed_work(nvhdcp->downstream_wq, &nvhdcp->work,
msecs_to_jiffies(1000));
}
lost_hdmi:
+ mutex_lock(&nvhdcp->state_lock);
nvhdcp->state = STATE_UNAUTHENTICATED;
+ mutex_unlock(&nvhdcp->state_lock);
hdcp_ctrl_run(hdmi, 0);
err:
mutex_unlock(&nvhdcp->lock);
return;
disable:
+ mutex_lock(&nvhdcp->state_lock);
nvhdcp->state = STATE_OFF;
nvhdcp_set_plugged(nvhdcp, false);
+ mutex_unlock(&nvhdcp->state_lock);
mutex_unlock(&nvhdcp->lock);
return;
}
static int tegra_nvhdcp_on(struct tegra_nvhdcp *nvhdcp)
{
+ mutex_lock(&nvhdcp->state_lock);
+ nvhdcp_set_plugged(nvhdcp, true);
nvhdcp->state = STATE_UNAUTHENTICATED;
+ mutex_unlock(&nvhdcp->state_lock);
if (nvhdcp_is_plugged(nvhdcp)) {
nvhdcp->fail_count = 0;
queue_delayed_work(nvhdcp->downstream_wq, &nvhdcp->work,
@@ -1041,10 +1053,10 @@ static int tegra_nvhdcp_on(struct tegra_nvhdcp *nvhdcp)
static int tegra_nvhdcp_off(struct tegra_nvhdcp *nvhdcp)
{
- mutex_lock(&nvhdcp->lock);
+ mutex_lock(&nvhdcp->state_lock);
nvhdcp->state = STATE_OFF;
nvhdcp_set_plugged(nvhdcp, false);
- mutex_unlock(&nvhdcp->lock);
+ mutex_unlock(&nvhdcp->state_lock);
wake_up_interruptible(&wq_worker);
flush_workqueue(nvhdcp->downstream_wq);
return 0;
@@ -1055,7 +1067,6 @@ void tegra_nvhdcp_set_plug(struct tegra_nvhdcp *nvhdcp, bool hpd)
nvhdcp_debug("hdmi hotplug detected (hpd = %d)\n", hpd);
if (hpd) {
- nvhdcp_set_plugged(nvhdcp, true);
tegra_nvhdcp_on(nvhdcp);
} else {
tegra_nvhdcp_off(nvhdcp);
@@ -1080,9 +1091,9 @@ int tegra_nvhdcp_set_policy(struct tegra_nvhdcp *nvhdcp, int pol)
static int tegra_nvhdcp_renegotiate(struct tegra_nvhdcp *nvhdcp)
{
- mutex_lock(&nvhdcp->lock);
+ mutex_lock(&nvhdcp->state_lock);
nvhdcp->state = STATE_RENEGOTIATE;
- mutex_unlock(&nvhdcp->lock);
+ mutex_unlock(&nvhdcp->state_lock);
tegra_nvhdcp_on(nvhdcp);
return 0;
}
@@ -1201,6 +1212,7 @@ struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi,
snprintf(nvhdcp->name, sizeof(nvhdcp->name), "nvhdcp%u", id);
nvhdcp->hdmi = hdmi;
mutex_init(&nvhdcp->lock);
+ mutex_init(&nvhdcp->state_lock);
strlcpy(nvhdcp->info.type, nvhdcp->name, sizeof(nvhdcp->info.type));
nvhdcp->bus = bus;
@@ -1224,7 +1236,9 @@ struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi,
goto free_nvhdcp;
}
+ mutex_lock(&nvhdcp->state_lock);
nvhdcp->state = STATE_UNAUTHENTICATED;
+ mutex_unlock(&nvhdcp->state_lock);
nvhdcp->downstream_wq = create_singlethread_workqueue(nvhdcp->name);
INIT_DELAYED_WORK(&nvhdcp->work, nvhdcp_downstream_worker);