diff options
| author | Ajay Singh Parmar <aparmar@codeaurora.org> | 2016-02-02 15:01:12 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 21:17:52 -0700 |
| commit | 88af065f71baa8f7166b399bc5211732cf394b02 (patch) | |
| tree | 58504924ab85aecf055bd6126e0b5f4c42781965 /drivers/video/fbdev | |
| parent | 62be9c73b908d1f335a1844da9236eea4a0f9aa6 (diff) | |
msm: mdss: hdmi: protect hpd power from multi-thread access
HPD (Hot Plug Detect) can be powered on or off by down stream
device like MHL or slimport driver based on cable connection
triggered by user. In response to that, HDMI transmitter power
on and off is triggered in a different thread. There can be
a race condition with transmitter power on/off and HPD power
on and off with fast plug in/out. Protect these functionalities
using mutex to avoid such race conditions and keep the HDMI state
machine in valid state.
Change-Id: I7fa8de10b96ca3cf674a0b7cf83b0f96cc177509
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.c | 45 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_hdmi_tx.h | 1 |
2 files changed, 19 insertions, 27 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index a136da353a47..cdc8cc52f5c7 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -887,6 +887,8 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev, goto end; } + hdmi_ctrl->audio_ack_enabled = false; + hdmi_tx_set_audio_switch_node(hdmi_ctrl, 0); hdmi_tx_wait_for_audio_engine(hdmi_ctrl); hdmi_tx_send_cable_notification(hdmi_ctrl, 0); @@ -1944,7 +1946,7 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) struct dss_io_data *io; hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_int_work); - if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) { + if (!hdmi_ctrl) { DEV_DBG("%s: invalid input\n", __func__); return; } @@ -1952,6 +1954,11 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) mutex_lock(&hdmi_ctrl->tx_lock); + if (!hdmi_ctrl->hpd_initialized) { + DEV_DBG("hpd not initialized\n"); + goto end; + } + DEV_DBG("%s: %s\n", __func__, hdmi_ctrl->hpd_state ? "CONNECT" : "DISCONNECT"); @@ -1978,9 +1985,6 @@ static void hdmi_tx_hpd_int_work(struct work_struct *work) hdmi_tx_send_cable_notification(hdmi_ctrl, false); } end: - if (!completion_done(&hdmi_ctrl->hpd_int_done)) - complete_all(&hdmi_ctrl->hpd_int_done); - mutex_unlock(&hdmi_ctrl->tx_lock); } /* hdmi_tx_hpd_int_work */ @@ -3964,9 +3968,6 @@ static void hdmi_tx_hpd_off(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->hpd_initialized = false; hdmi_ctrl->hpd_off_pending = false; - if (!completion_done(&hdmi_ctrl->hpd_off_done)) - complete_all(&hdmi_ctrl->hpd_off_done); - DEV_DBG("%s: HPD is now OFF\n", __func__); } /* hdmi_tx_hpd_off */ @@ -4039,21 +4040,9 @@ static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on) return -EINVAL; } - DEV_INFO("%s: %d\n", __func__, on); + DEV_DBG("%s: %d\n", __func__, on); if (on) { - if (hdmi_ctrl->hpd_off_pending) { - u32 timeout; - - reinit_completion(&hdmi_ctrl->hpd_off_done); - timeout = wait_for_completion_timeout( - &hdmi_ctrl->hpd_off_done, HZ); - if (!timeout) { - hdmi_ctrl->hpd_off_pending = false; - DEV_ERR("%s: hpd off still pending\n", - __func__); - return 0; - } - } + hdmi_ctrl->hpd_off_pending = false; rc = hdmi_tx_hpd_on(hdmi_ctrl); } else { @@ -4078,6 +4067,8 @@ static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on) return -EINVAL; } + mutex_lock(&hdmi_ctrl->tx_lock); + /* mhl status should override */ hdmi_ctrl->mhl_hpd_on = on; @@ -4088,7 +4079,7 @@ static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on) } else { DEV_DBG("%s: hpd is already '%s'. return\n", __func__, hdmi_ctrl->hpd_feature_on ? "enabled" : "disabled"); - return rc; + goto end; } if (!rc) { @@ -4099,9 +4090,9 @@ static int hdmi_tx_set_mhl_hpd(struct platform_device *pdev, uint8_t on) DEV_ERR("%s: failed to '%s' hpd. rc = %d\n", __func__, on ? "enable" : "disable", rc); } - +end: + mutex_unlock(&hdmi_ctrl->tx_lock); return rc; - } static irqreturn_t hdmi_tx_isr(int irq, void *data) @@ -4131,6 +4122,9 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data) (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1; spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags); + if (!completion_done(&hdmi_ctrl->hpd_int_done)) + complete_all(&hdmi_ctrl->hpd_int_done); + /* * check if this is a spurious interrupt, if yes, reset * interrupts and return @@ -4272,7 +4266,6 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->hpd_initialized = false; hdmi_ctrl->hpd_off_pending = false; init_completion(&hdmi_ctrl->hpd_int_done); - init_completion(&hdmi_ctrl->hpd_off_done); INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work); INIT_WORK(&hdmi_ctrl->cable_notify_work, hdmi_tx_cable_notify_work); @@ -4516,7 +4509,7 @@ static int hdmi_tx_panel_event_handler(struct mdss_panel_data *panel_data, if (!hdmi_ctrl->hpd_feature_on) goto end; - if (!hdmi_ctrl->panel_power_on) + if (!hdmi_ctrl->hpd_state && !hdmi_ctrl->panel_power_on) hdmi_tx_hpd_off(hdmi_ctrl); hdmi_ctrl->panel_suspend = true; diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h index 89f0be0f3143..4507cac30463 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h @@ -157,7 +157,6 @@ struct hdmi_tx_ctrl { struct hdmi_util_ds_data ds_data; struct completion hpd_int_done; - struct completion hpd_off_done; struct work_struct hpd_int_work; struct delayed_work hdcp_cb_work; |
