From 5043291e1a969c82b76b639f107ac99e56e3be5b Mon Sep 17 00:00:00 2001 From: Rajkumar Subbiah Date: Fri, 26 Aug 2022 15:15:21 -0400 Subject: [PATCH] disp: msm: dp: skip waits when processing usb disconnect in sim mode With real DP over Type-C sinks, DP driver requests access to USB combo PHY from USB driver. But in DP SIM mode, there is no real sink and PD management, so the combo PHY is managed by USB driver and DP driver uses it without actually claiming it. If the USB cable is unplugged in this scenario, USB driver notifies the disconnection through an atomic notifier call. It does not expect the handler to go into sleep, but the disconnect handler inside DP driver has multiple wait for events and also sleeps to wait for HW state updates. This change passes a skip_wait flag to all the disable functions to complete disconnect processing by skipping all processor sleeps and event waits. Change-Id: Ia98de0e7fa6b0573e644615ee59015914a93f4cf Signed-off-by: Rajkumar Subbiah --- msm/dp/dp_audio.c | 11 +++++++---- msm/dp/dp_audio.h | 4 +++- msm/dp/dp_debug.c | 2 ++ msm/dp/dp_display.c | 48 ++++++++++++++++++++++++--------------------- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/msm/dp/dp_audio.c b/msm/dp/dp_audio.c index 680f6d6747..cd665aa44e 100644 --- a/msm/dp/dp_audio.c +++ b/msm/dp/dp_audio.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -769,7 +770,7 @@ end: return rc; } -static int dp_audio_off(struct dp_audio *dp_audio) +static int dp_audio_off(struct dp_audio *dp_audio, bool skip_wait) { int rc = 0; struct dp_audio_private *audio; @@ -794,9 +795,11 @@ static int dp_audio_off(struct dp_audio *dp_audio) if (work_pending) DP_DEBUG("pending notification work completed\n"); - rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT); - if (rc) - goto end; + if (!skip_wait) { + rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT); + if (rc) + goto end; + } DP_DEBUG("success\n"); end: diff --git a/msm/dp/dp_audio.h b/msm/dp/dp_audio.h index 19e207e0e5..f81f0079e4 100644 --- a/msm/dp/dp_audio.h +++ b/msm/dp/dp_audio.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ @@ -41,10 +42,11 @@ struct dp_audio { * playback should be stopped on the external display. * * @dp_audio: an instance of struct dp_audio. + * @skip_wait: flag to skip any waits * * Returns the error code in case of failure, 0 in success case. */ - int (*off)(struct dp_audio *dp_audio); + int (*off)(struct dp_audio *dp_audio, bool skip_wait); }; /** diff --git a/msm/dp/dp_debug.c b/msm/dp/dp_debug.c index 1e1cb53b0e..0696dd5ad9 100644 --- a/msm/dp/dp_debug.c +++ b/msm/dp/dp_debug.c @@ -2466,6 +2466,8 @@ static void dp_debug_abort(struct dp_debug *dp_debug) debug = container_of(dp_debug, struct dp_debug_private, dp_debug); mutex_lock(&debug->lock); + // disconnect has already been handled. so clear hotplug + debug->hotplug = false; dp_debug_set_sim_mode(debug, false); mutex_unlock(&debug->lock); } diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index dad28ce86c..e723997e61 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -293,7 +293,7 @@ static void dp_audio_enable(struct dp_display_private *dp, bool enable) dp->link->link_params.lane_count; dp_panel->audio->on(dp_panel->audio); } else { - dp_panel->audio->off(dp_panel->audio); + dp_panel->audio->off(dp_panel->audio, false); } } } @@ -917,7 +917,7 @@ static bool dp_display_send_hpd_event(struct dp_display_private *dp) return true; } -static int dp_display_send_hpd_notification(struct dp_display_private *dp) +static int dp_display_send_hpd_notification(struct dp_display_private *dp, bool skip_wait) { int ret = 0; bool hpd = !!dp_display_state_is(DP_STATE_CONNECTED); @@ -976,7 +976,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp) goto skip_wait; } - if (hpd && dp->mst.mst_active) + if (skip_wait || (hpd && dp->mst.mst_active)) goto skip_wait; if (!dp->mst.mst_active && @@ -1321,7 +1321,7 @@ end: } if (!rc && !dp_display_state_is(DP_STATE_ABORTED)) - dp_display_send_hpd_notification(dp); + dp_display_send_hpd_notification(dp, false); skip_notify: SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, @@ -1329,7 +1329,7 @@ skip_notify: return rc; } -static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) +static void dp_display_process_mst_hpd_low(struct dp_display_private *dp, bool skip_wait) { int rc = 0; @@ -1346,7 +1346,7 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) || dp_display_state_is(DP_STATE_ENABLED))) - rc = dp_display_send_hpd_notification(dp); + rc = dp_display_send_hpd_notification(dp, skip_wait); dp_display_set_mst_mgr_state(dp, false); dp_display_update_mst_state(dp, false); @@ -1355,7 +1355,7 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp) DP_MST_DEBUG("mst_hpd_low. mst_active:%d\n", dp->mst.mst_active); } -static int dp_display_process_hpd_low(struct dp_display_private *dp) +static int dp_display_process_hpd_low(struct dp_display_private *dp, bool skip_wait) { int rc = 0; @@ -1364,11 +1364,11 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp) dp_audio_enable(dp, false); if (dp->mst.mst_active) { - dp_display_process_mst_hpd_low(dp); + dp_display_process_mst_hpd_low(dp, skip_wait); } else { if ((dp_display_state_is(DP_STATE_CONNECT_NOTIFIED) || dp_display_state_is(DP_STATE_ENABLED))) - rc = dp_display_send_hpd_notification(dp); + rc = dp_display_send_hpd_notification(dp, skip_wait); } mutex_lock(&dp->session_lock); @@ -1551,7 +1551,7 @@ static void dp_display_stream_disable(struct dp_display_private *dp, dp->active_stream_cnt--; } -static void dp_display_clean(struct dp_display_private *dp) +static void dp_display_clean(struct dp_display_private *dp, bool skip_wait) { int idx; struct dp_panel *dp_panel; @@ -1579,9 +1579,10 @@ static void dp_display_clean(struct dp_display_private *dp) dp_panel = dp->active_panels[idx]; if (dp_panel->audio_supported) - dp_panel->audio->off(dp_panel->audio); + dp_panel->audio->off(dp_panel->audio, skip_wait); - dp_display_stream_pre_disable(dp, dp_panel); + if (!skip_wait) + dp_display_stream_pre_disable(dp, dp_panel); dp_display_stream_disable(dp, dp_panel); dp_display_clear_reservation(&dp->dp_display, dp_panel); dp_panel->deinit(dp_panel, 0); @@ -1593,12 +1594,12 @@ static void dp_display_clean(struct dp_display_private *dp) SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); } -static int dp_display_handle_disconnect(struct dp_display_private *dp) +static int dp_display_handle_disconnect(struct dp_display_private *dp, bool skip_wait) { int rc; SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, dp->state); - rc = dp_display_process_hpd_low(dp); + rc = dp_display_process_hpd_low(dp, skip_wait); if (rc) { /* cancel any pending request */ dp->ctrl->abort(dp->ctrl, true); @@ -1607,7 +1608,7 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) mutex_lock(&dp->session_lock); if (dp_display_state_is(DP_STATE_ENABLED)) - dp_display_clean(dp); + dp_display_clean(dp, skip_wait); dp_display_host_unready(dp); @@ -1648,7 +1649,7 @@ static void dp_display_disconnect_sync(struct dp_display_private *dp) DP_DEBUG("disconnect delay = %d ms\n", disconnect_delay_ms); msleep(disconnect_delay_ms); - dp_display_handle_disconnect(dp); + dp_display_handle_disconnect(dp, false); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state, disconnect_delay_ms); } @@ -1764,7 +1765,7 @@ static void dp_display_attention_work(struct work_struct *work) SDE_EVT32_EXTERNAL(dp->state, DS_PORT_STATUS_CHANGED); if (!dp->mst.mst_active) { if (dp_display_is_sink_count_zero(dp)) { - dp_display_handle_disconnect(dp); + dp_display_handle_disconnect(dp, false); } else { /* * connect work should take care of sending @@ -1779,7 +1780,7 @@ static void dp_display_attention_work(struct work_struct *work) if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) { SDE_EVT32_EXTERNAL(dp->state, DP_TEST_LINK_VIDEO_PATTERN); - dp_display_handle_disconnect(dp); + dp_display_handle_disconnect(dp, false); dp->panel->video_test = true; /* @@ -1838,7 +1839,7 @@ cp_irq: * account for that. This is not needed if this * attention work was handling a test request */ - dp_display_send_hpd_notification(dp); + dp_display_send_hpd_notification(dp, false); } mst_attention: @@ -1939,7 +1940,10 @@ static int dp_display_usb_notifier(struct notifier_block *nb, SDE_EVT32_EXTERNAL(dp->state, dp->debug->sim_mode, action); if (!action && dp->debug->sim_mode) { DP_WARN("usb disconnected during simulation\n"); - dp_display_disconnect_sync(dp); + dp_display_state_add(DP_STATE_ABORTED); + dp->ctrl->abort(dp->ctrl, true); + dp->aux->abort(dp->aux, true); + dp_display_handle_disconnect(dp, true); dp->debug->abort(dp->debug); } @@ -1978,7 +1982,7 @@ int dp_display_mmrm_callback(struct mmrm_client_notifier_data *notifier_data) if (notifier_data->cb_type == MMRM_CLIENT_RESOURCE_VALUE_CHANGE && dp_display_state_is(DP_STATE_ENABLED) && !dp_display_state_is(DP_STATE_ABORTED)) { - ret = dp_display_handle_disconnect(dp); + ret = dp_display_handle_disconnect(dp, false); if (ret) DP_ERR("mmrm callback error reducing clk, ret:%d\n", ret); } @@ -2650,7 +2654,7 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) clean: if (dp_panel->audio_supported) - dp_panel->audio->off(dp_panel->audio); + dp_panel->audio->off(dp_panel->audio, false); rc = dp_display_stream_pre_disable(dp, dp_panel);