Commit d2aa1356 authored by Aurabindo Pillai's avatar Aurabindo Pillai Committed by Alex Deucher

drm/amd/display: take dc_lock in short pulse handler only

[Why]
Conditions that end up modifying the global dc state must be locked.
However, during mst allocate payload sequence, lock is already taken.
With StarTech 1.2 DP hub, we get an HPD RX interrupt for a reason other
than to indicate down reply availability right after sending payload
allocation. The handler again takes dc lock before calling the
dc's HPD RX handler. Due to this contention, the DRM thread which waits
for MST down reply never gets a chance to finish its waiting
successfully and ends up timing out. Once the lock is released, the hpd
rx handler fires and goes ahead to read from the MST HUB, but now its
too late and the HUB doesnt lightup all displays since DRM lacks error
handling when payload allocation fails.

[How]
Take lock only if there is a change in link status or if automated test
pattern bit is set. The latter fixes the null pointer dereference when
running certain DP Link Layer Compliance test.

Fixes: c8ea79a8 ("drm/amd/display: NULL pointer error during compliance test")
Signed-off-by: default avatarAurabindo Pillai <aurabindo.pillai@amd.com>
Reviewed-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 9a91e5e0
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "dm_services_types.h" #include "dm_services_types.h"
#include "dc.h" #include "dc.h"
#include "dc_link_dp.h"
#include "dc/inc/core_types.h" #include "dc/inc/core_types.h"
#include "dal_asic_id.h" #include "dal_asic_id.h"
#include "dmub/dmub_srv.h" #include "dmub/dmub_srv.h"
...@@ -2739,6 +2740,7 @@ static void handle_hpd_rx_irq(void *param) ...@@ -2739,6 +2740,7 @@ static void handle_hpd_rx_irq(void *param)
enum dc_connection_type new_connection_type = dc_connection_none; enum dc_connection_type new_connection_type = dc_connection_none;
struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_device *adev = drm_to_adev(dev);
union hpd_irq_data hpd_irq_data; union hpd_irq_data hpd_irq_data;
bool lock_flag = 0;
memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); memset(&hpd_irq_data, 0, sizeof(hpd_irq_data));
...@@ -2768,15 +2770,28 @@ static void handle_hpd_rx_irq(void *param) ...@@ -2768,15 +2770,28 @@ static void handle_hpd_rx_irq(void *param)
} }
} }
if (!amdgpu_in_reset(adev)) { /*
* TODO: We need the lock to avoid touching DC state while it's being
* modified during automated compliance testing, or when link loss
* happens. While this should be split into subhandlers and proper
* interfaces to avoid having to conditionally lock like this in the
* outer layer, we need this workaround temporarily to allow MST
* lightup in some scenarios to avoid timeout.
*/
if (!amdgpu_in_reset(adev) &&
(hpd_rx_irq_check_link_loss_status(dc_link, &hpd_irq_data) ||
hpd_irq_data.bytes.device_service_irq.bits.AUTOMATED_TEST)) {
mutex_lock(&adev->dm.dc_lock); mutex_lock(&adev->dm.dc_lock);
lock_flag = 1;
}
#ifdef CONFIG_DRM_AMD_DC_HDCP #ifdef CONFIG_DRM_AMD_DC_HDCP
result = dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data, NULL); result = dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data, NULL);
#else #else
result = dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL); result = dc_link_handle_hpd_rx_irq(dc_link, NULL, NULL);
#endif #endif
if (!amdgpu_in_reset(adev) && lock_flag)
mutex_unlock(&adev->dm.dc_lock); mutex_unlock(&adev->dm.dc_lock);
}
out: out:
if (result && !is_mst_root_connector) { if (result && !is_mst_root_connector) {
......
...@@ -2070,7 +2070,7 @@ enum dc_status read_hpd_rx_irq_data( ...@@ -2070,7 +2070,7 @@ enum dc_status read_hpd_rx_irq_data(
return retval; return retval;
} }
static bool hpd_rx_irq_check_link_loss_status( bool hpd_rx_irq_check_link_loss_status(
struct dc_link *link, struct dc_link *link,
union hpd_irq_data *hpd_irq_dpcd_data) union hpd_irq_data *hpd_irq_dpcd_data)
{ {
......
...@@ -68,6 +68,10 @@ bool perform_link_training_with_retries( ...@@ -68,6 +68,10 @@ bool perform_link_training_with_retries(
enum signal_type signal, enum signal_type signal,
bool do_fallback); bool do_fallback);
bool hpd_rx_irq_check_link_loss_status(
struct dc_link *link,
union hpd_irq_data *hpd_irq_dpcd_data);
bool is_mst_supported(struct dc_link *link); bool is_mst_supported(struct dc_link *link);
bool detect_dp_sink_caps(struct dc_link *link); bool detect_dp_sink_caps(struct dc_link *link);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment