Merge "disp: msm: dp: address race condition in LM allocation"

This commit is contained in:
qctecmdr
2022-08-09 20:49:21 -07:00
committed by Gerrit - the friendly Code Review server
7 changed files with 81 additions and 17 deletions

View File

@@ -202,6 +202,7 @@ struct dp_display_private {
struct work_struct connect_work; struct work_struct connect_work;
struct work_struct attention_work; struct work_struct attention_work;
struct mutex session_lock; struct mutex session_lock;
struct mutex accounting_lock;
bool hdcp_delayed_off; bool hdcp_delayed_off;
bool no_aux_switch; bool no_aux_switch;
@@ -209,6 +210,7 @@ struct dp_display_private {
struct dp_mst mst; struct dp_mst mst;
u32 tot_dsc_blks_in_use; u32 tot_dsc_blks_in_use;
u32 tot_lm_blks_in_use;
bool process_hpd_connect; bool process_hpd_connect;
struct dev_pm_qos_request pm_qos_req[NR_CPUS]; struct dev_pm_qos_request pm_qos_req[NR_CPUS];
@@ -1483,6 +1485,25 @@ static int dp_display_usbpd_configure_cb(struct device *dev)
return 0; return 0;
} }
static void dp_display_clear_reservation(struct dp_display *dp, struct dp_panel *panel)
{
struct dp_display_private *dp_display;
if (!dp || !panel) {
DP_ERR("invalid params\n");
return;
}
dp_display = container_of(dp, struct dp_display_private, dp_display);
mutex_lock(&dp_display->accounting_lock);
dp_display->tot_lm_blks_in_use -= panel->max_lm;
panel->max_lm = 0;
mutex_unlock(&dp_display->accounting_lock);
}
static void dp_display_clear_dsc_resources(struct dp_display_private *dp, static void dp_display_clear_dsc_resources(struct dp_display_private *dp,
struct dp_panel *panel) struct dp_panel *panel)
{ {
@@ -1562,6 +1583,7 @@ static void dp_display_clean(struct dp_display_private *dp)
dp_display_stream_pre_disable(dp, dp_panel); dp_display_stream_pre_disable(dp, dp_panel);
dp_display_stream_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); dp_panel->deinit(dp_panel, 0);
} }
@@ -1589,6 +1611,8 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp)
dp_display_host_unready(dp); dp_display_host_unready(dp);
dp->tot_lm_blks_in_use = 0;
mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock);
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state);
@@ -2002,6 +2026,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
}; };
mutex_init(&dp->session_lock); mutex_init(&dp->session_lock);
mutex_init(&dp->accounting_lock);
dp->parser = dp_parser_get(dp->pdev); dp->parser = dp_parser_get(dp->pdev);
if (IS_ERR(dp->parser)) { if (IS_ERR(dp->parser)) {
@@ -2172,6 +2197,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
dp->cached_connector_status = connector_status_disconnected; dp->cached_connector_status = connector_status_disconnected;
dp->tot_dsc_blks_in_use = 0; dp->tot_dsc_blks_in_use = 0;
dp->tot_lm_blks_in_use = 0;
dp->debug->hdcp_disabled = hdcp_disabled; dp->debug->hdcp_disabled = hdcp_disabled;
dp_display_update_hdcp_status(dp, true); dp_display_update_hdcp_status(dp, true);
@@ -2809,6 +2835,8 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel)
/* log this as it results from user action of cable dis-connection */ /* log this as it results from user action of cable dis-connection */
DP_INFO("[OK]\n"); DP_INFO("[OK]\n");
end: end:
dp->tot_lm_blks_in_use -= dp_panel->max_lm;
dp_panel->max_lm = 0;
dp_panel->deinit(dp_panel, flags); dp_panel->deinit(dp_panel, flags);
mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock);
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state);
@@ -2867,11 +2895,14 @@ static int dp_display_validate_topology(struct dp_display_private *dp,
u32 num_lm = 0, num_dsc = 0, num_3dmux = 0; u32 num_lm = 0, num_dsc = 0, num_3dmux = 0;
bool dsc_capable = dp_mode->capabilities & DP_PANEL_CAPS_DSC; bool dsc_capable = dp_mode->capabilities & DP_PANEL_CAPS_DSC;
u32 fps = dp_mode->timing.refresh_rate; u32 fps = dp_mode->timing.refresh_rate;
int avail_lm = 0;
mutex_lock(&dp->accounting_lock);
rc = msm_get_mixer_count(priv, mode, avail_res, &num_lm); rc = msm_get_mixer_count(priv, mode, avail_res, &num_lm);
if (rc) { if (rc) {
DP_ERR("error getting mixer count. rc:%d\n", rc); DP_ERR("error getting mixer count. rc:%d\n", rc);
return rc; goto end;
} }
/* Merge using DSC, if enabled */ /* Merge using DSC, if enabled */
@@ -2879,7 +2910,7 @@ static int dp_display_validate_topology(struct dp_display_private *dp,
rc = msm_get_dsc_count(priv, mode->hdisplay, &num_dsc); rc = msm_get_dsc_count(priv, mode->hdisplay, &num_dsc);
if (rc) { if (rc) {
DP_ERR("error getting dsc count. rc:%d\n", rc); DP_ERR("error getting dsc count. rc:%d\n", rc);
return rc; goto end;
} }
num_dsc = max(num_lm, num_dsc); num_dsc = max(num_lm, num_dsc);
@@ -2889,7 +2920,8 @@ static int dp_display_validate_topology(struct dp_display_private *dp,
avail_res->num_lm); avail_res->num_lm);
/* Clear DSC caps and retry */ /* Clear DSC caps and retry */
dp_mode->capabilities &= ~DP_PANEL_CAPS_DSC; dp_mode->capabilities &= ~DP_PANEL_CAPS_DSC;
return -EAGAIN; rc = -EAGAIN;
goto end;
} else { } else {
/* Only DSCMERGE is supported on DP */ /* Only DSCMERGE is supported on DP */
num_lm = num_dsc; num_lm = num_dsc;
@@ -2900,24 +2932,36 @@ static int dp_display_validate_topology(struct dp_display_private *dp,
num_3dmux = 1; num_3dmux = 1;
} }
if (num_lm > avail_res->num_lm) { avail_lm = avail_res->num_lm + avail_res->num_lm_in_use - dp->tot_lm_blks_in_use;
if ((num_lm > dp_panel->max_lm) && (num_lm > avail_lm)) {
DP_DEBUG("mode %sx%d is invalid, not enough lm %d %d\n", DP_DEBUG("mode %sx%d is invalid, not enough lm %d %d\n",
mode->name, fps, num_lm, num_lm, avail_res->num_lm); mode->name, fps, num_lm, avail_res->num_lm);
return -EPERM; rc = -EPERM;
goto end;
} else if (!num_dsc && (num_lm == dual && !num_3dmux)) { } else if (!num_dsc && (num_lm == dual && !num_3dmux)) {
DP_DEBUG("mode %sx%d is invalid, not enough 3dmux %d %d\n", DP_DEBUG("mode %sx%d is invalid, not enough 3dmux %d %d\n",
mode->name, fps, num_3dmux, avail_res->num_3dmux); mode->name, fps, num_3dmux, avail_res->num_3dmux);
return -EPERM; rc = -EPERM;
goto end;
} else if (num_lm == quad && num_dsc != quad) { } else if (num_lm == quad && num_dsc != quad) {
DP_DEBUG("mode %sx%d is invalid, unsupported DP topology lm:%d dsc:%d\n", DP_DEBUG("mode %sx%d is invalid, unsupported DP topology lm:%d dsc:%d\n",
mode->name, fps, num_lm, num_dsc); mode->name, fps, num_lm, num_dsc);
return -EPERM; rc = -EPERM;
goto end;
} }
DP_DEBUG_V("mode %sx%d is valid, supported DP topology lm:%d dsc:%d 3dmux:%d\n", DP_DEBUG_V("mode %sx%d is valid, supported DP topology lm:%d dsc:%d 3dmux:%d\n",
mode->name, fps, num_lm, num_dsc, num_3dmux); mode->name, fps, num_lm, num_dsc, num_3dmux);
return 0; dp->tot_lm_blks_in_use -= dp_panel->max_lm;
dp_panel->max_lm = num_lm > avail_res->num_lm_in_use ? max(dp_panel->max_lm, num_lm) : 0;
dp->tot_lm_blks_in_use += dp_panel->max_lm;
rc = 0;
end:
mutex_unlock(&dp->accounting_lock);
return rc;
} }
static enum drm_mode_status dp_display_validate_mode( static enum drm_mode_status dp_display_validate_mode(
@@ -2973,6 +3017,8 @@ static enum drm_mode_status dp_display_validate_mode(
mode_status = MODE_OK; mode_status = MODE_OK;
end: end:
if (mode_status != MODE_OK)
dp_display_clear_reservation(dp_display, dp_panel);
mutex_unlock(&dp->session_lock); mutex_unlock(&dp->session_lock);
DP_DEBUG_V("[%s] mode is %s\n", mode->name, DP_DEBUG_V("[%s] mode is %s\n", mode->name,
@@ -3645,6 +3691,7 @@ static int dp_display_probe(struct platform_device *pdev)
g_dp_display->set_colorspace = dp_display_setup_colospace; g_dp_display->set_colorspace = dp_display_setup_colospace;
g_dp_display->get_available_dp_resources = g_dp_display->get_available_dp_resources =
dp_display_get_available_dp_resources; dp_display_get_available_dp_resources;
g_dp_display->clear_reservation = dp_display_clear_reservation;
rc = component_add(&pdev->dev, &dp_display_comp_ops); rc = component_add(&pdev->dev, &dp_display_comp_ops);
if (rc) { if (rc) {

View File

@@ -105,6 +105,7 @@ struct dp_display {
int (*get_available_dp_resources)(struct dp_display *dp_display, int (*get_available_dp_resources)(struct dp_display *dp_display,
const struct msm_resource_caps_info *avail_res, const struct msm_resource_caps_info *avail_res,
struct msm_resource_caps_info *max_dp_avail_res); struct msm_resource_caps_info *max_dp_avail_res);
void (*clear_reservation)(struct dp_display *dp, struct dp_panel *panel);
}; };
void *get_ipc_log_context(void); void *get_ipc_log_context(void);

View File

@@ -257,6 +257,8 @@ static void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode, dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode,
&bridge->dp_mode); &bridge->dp_mode);
dp->clear_reservation(dp, bridge->dp_panel);
} }
static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge, static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge,
@@ -290,6 +292,7 @@ static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge,
dp = bridge->display; dp = bridge->display;
dp->convert_to_dp_mode(dp, bridge->dp_panel, mode, &dp_mode); dp->convert_to_dp_mode(dp, bridge->dp_panel, mode, &dp_mode);
dp->clear_reservation(dp, bridge->dp_panel);
convert_to_drm_mode(&dp_mode, adjusted_mode); convert_to_drm_mode(&dp_mode, adjusted_mode);
end: end:
return ret; return ret;

View File

@@ -345,6 +345,7 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge,
dp = bridge->display; dp = bridge->display;
dp->convert_to_dp_mode(dp, bridge_state->dp_panel, mode, &dp_mode); dp->convert_to_dp_mode(dp, bridge_state->dp_panel, mode, &dp_mode);
dp->clear_reservation(dp, bridge_state->dp_panel);
convert_to_drm_mode(&dp_mode, adjusted_mode); convert_to_drm_mode(&dp_mode, adjusted_mode);
DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name); DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name);
@@ -775,6 +776,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge,
memcpy(&bridge->drm_mode, adjusted_mode, sizeof(bridge->drm_mode)); memcpy(&bridge->drm_mode, adjusted_mode, sizeof(bridge->drm_mode));
dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode, dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode,
&bridge->dp_mode); &bridge->dp_mode);
dp->clear_reservation(dp, dp_bridge_state->dp_panel);
DP_MST_INFO("mst bridge:%d conn:%d mode set complete %s\n", bridge->id, DP_MST_INFO("mst bridge:%d conn:%d mode set complete %s\n", bridge->id,
DP_MST_CONN_ID(bridge), mode->name); DP_MST_CONN_ID(bridge), mode->name);

View File

@@ -137,6 +137,7 @@ struct dp_panel {
u32 pbn; u32 pbn;
u32 dsc_blks_in_use; u32 dsc_blks_in_use;
u32 max_lm;
/* DRM connector assosiated with this panel */ /* DRM connector assosiated with this panel */
struct drm_connector *connector; struct drm_connector *connector;

View File

@@ -828,6 +828,7 @@ struct msm_mode_info {
/** /**
* struct msm_resource_caps_info - defines hw resources * struct msm_resource_caps_info - defines hw resources
* @num_lm_in_use number of layer mixers allocated to a specified encoder
* @num_lm number of layer mixers available * @num_lm number of layer mixers available
* @num_dsc number of dsc available * @num_dsc number of dsc available
* @num_vdc number of vdc available * @num_vdc number of vdc available
@@ -836,6 +837,7 @@ struct msm_mode_info {
* @max_mixer_width: max width supported by layer mixer * @max_mixer_width: max width supported by layer mixer
*/ */
struct msm_resource_caps_info { struct msm_resource_caps_info {
uint32_t num_lm_in_use;
uint32_t num_lm; uint32_t num_lm;
uint32_t num_dsc; uint32_t num_dsc;
uint32_t num_vdc; uint32_t num_vdc;

View File

@@ -286,27 +286,33 @@ void sde_rm_get_resource_info(struct sde_rm *rm,
{ {
struct sde_rm_hw_blk *blk; struct sde_rm_hw_blk *blk;
enum sde_hw_blk_type type; enum sde_hw_blk_type type;
struct sde_rm_rsvp rsvp;
const struct sde_lm_cfg *lm_cfg; const struct sde_lm_cfg *lm_cfg;
bool is_built_in, is_pref; bool is_built_in, is_pref;
u32 lm_pref = (BIT(SDE_DISP_PRIMARY_PREF) | BIT(SDE_DISP_SECONDARY_PREF)); u32 lm_pref = (BIT(SDE_DISP_PRIMARY_PREF) | BIT(SDE_DISP_SECONDARY_PREF));
mutex_lock(&rm->rm_lock);
/* Get all currently available resources */ /* Get all currently available resources */
memcpy(avail_res, &rm->avail_res, memcpy(avail_res, &rm->avail_res,
sizeof(rm->avail_res)); sizeof(rm->avail_res));
/**
* When the encoder is null, assume display is external in order to return the count of
* availalbe non-preferred LMs
*/
if (!drm_enc) if (!drm_enc)
return; is_built_in = false;
else
is_built_in = sde_encoder_is_built_in_display(drm_enc); is_built_in = sde_encoder_is_built_in_display(drm_enc);
rsvp.enc_id = drm_enc->base.id;
for (type = 0; type < SDE_HW_BLK_MAX; type++) { for (type = 0; type < SDE_HW_BLK_MAX; type++) {
list_for_each_entry(blk, &rm->hw_blks[type], list) { list_for_each_entry(blk, &rm->hw_blks[type], list) {
/* Add back resources allocated to the given encoder */ /* Add back resources allocated to the given encoder */
if (blk->rsvp && blk->rsvp->enc_id == rsvp.enc_id) if (blk->rsvp && drm_enc && blk->rsvp->enc_id == drm_enc->base.id) {
_sde_rm_inc_resource_info(rm, avail_res, blk); _sde_rm_inc_resource_info(rm, avail_res, blk);
if (type == SDE_HW_BLK_LM)
avail_res->num_lm_in_use++;
}
/** /**
* Remove unallocated preferred lms that cannot reserved * Remove unallocated preferred lms that cannot reserved
@@ -316,11 +322,13 @@ void sde_rm_get_resource_info(struct sde_rm *rm,
lm_cfg = to_sde_hw_mixer(blk->hw)->cap; lm_cfg = to_sde_hw_mixer(blk->hw)->cap;
is_pref = lm_cfg->features & lm_pref; is_pref = lm_cfg->features & lm_pref;
if (!blk->rsvp && !is_built_in && is_pref) if (!blk->rsvp && !blk->rsvp_nxt && !is_built_in && is_pref)
_sde_rm_dec_resource_info(rm, avail_res, blk); _sde_rm_dec_resource_info(rm, avail_res, blk);
} }
} }
} }
mutex_unlock(&rm->rm_lock);
} }
static void _sde_rm_print_rsvps( static void _sde_rm_print_rsvps(