Merge "disp: msm: dp: address race condition in LM allocation"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
5a5adbba9f
@@ -202,6 +202,7 @@ struct dp_display_private {
|
||||
struct work_struct connect_work;
|
||||
struct work_struct attention_work;
|
||||
struct mutex session_lock;
|
||||
struct mutex accounting_lock;
|
||||
bool hdcp_delayed_off;
|
||||
bool no_aux_switch;
|
||||
|
||||
@@ -209,6 +210,7 @@ struct dp_display_private {
|
||||
struct dp_mst mst;
|
||||
|
||||
u32 tot_dsc_blks_in_use;
|
||||
u32 tot_lm_blks_in_use;
|
||||
|
||||
bool process_hpd_connect;
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
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_disable(dp, dp_panel);
|
||||
dp_display_clear_reservation(&dp->dp_display, dp_panel);
|
||||
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->tot_lm_blks_in_use = 0;
|
||||
|
||||
mutex_unlock(&dp->session_lock);
|
||||
|
||||
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->accounting_lock);
|
||||
|
||||
dp->parser = dp_parser_get(dp->pdev);
|
||||
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->tot_dsc_blks_in_use = 0;
|
||||
dp->tot_lm_blks_in_use = 0;
|
||||
|
||||
dp->debug->hdcp_disabled = hdcp_disabled;
|
||||
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 */
|
||||
DP_INFO("[OK]\n");
|
||||
end:
|
||||
dp->tot_lm_blks_in_use -= dp_panel->max_lm;
|
||||
dp_panel->max_lm = 0;
|
||||
dp_panel->deinit(dp_panel, flags);
|
||||
mutex_unlock(&dp->session_lock);
|
||||
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;
|
||||
bool dsc_capable = dp_mode->capabilities & DP_PANEL_CAPS_DSC;
|
||||
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);
|
||||
if (rc) {
|
||||
DP_ERR("error getting mixer count. rc:%d\n", rc);
|
||||
return rc;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (rc) {
|
||||
DP_ERR("error getting dsc count. rc:%d\n", rc);
|
||||
return rc;
|
||||
goto end;
|
||||
}
|
||||
|
||||
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);
|
||||
/* Clear DSC caps and retry */
|
||||
dp_mode->capabilities &= ~DP_PANEL_CAPS_DSC;
|
||||
return -EAGAIN;
|
||||
rc = -EAGAIN;
|
||||
goto end;
|
||||
} else {
|
||||
/* Only DSCMERGE is supported on DP */
|
||||
num_lm = num_dsc;
|
||||
@@ -2900,24 +2932,36 @@ static int dp_display_validate_topology(struct dp_display_private *dp,
|
||||
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",
|
||||
mode->name, fps, num_lm, num_lm, avail_res->num_lm);
|
||||
return -EPERM;
|
||||
mode->name, fps, num_lm, avail_res->num_lm);
|
||||
rc = -EPERM;
|
||||
goto end;
|
||||
} else if (!num_dsc && (num_lm == dual && !num_3dmux)) {
|
||||
DP_DEBUG("mode %sx%d is invalid, not enough 3dmux %d %d\n",
|
||||
mode->name, fps, num_3dmux, avail_res->num_3dmux);
|
||||
return -EPERM;
|
||||
rc = -EPERM;
|
||||
goto end;
|
||||
} else if (num_lm == quad && num_dsc != quad) {
|
||||
DP_DEBUG("mode %sx%d is invalid, unsupported DP topology lm:%d dsc:%d\n",
|
||||
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",
|
||||
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(
|
||||
@@ -2973,6 +3017,8 @@ static enum drm_mode_status dp_display_validate_mode(
|
||||
|
||||
mode_status = MODE_OK;
|
||||
end:
|
||||
if (mode_status != MODE_OK)
|
||||
dp_display_clear_reservation(dp_display, dp_panel);
|
||||
mutex_unlock(&dp->session_lock);
|
||||
|
||||
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->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);
|
||||
if (rc) {
|
||||
|
@@ -105,6 +105,7 @@ struct dp_display {
|
||||
int (*get_available_dp_resources)(struct dp_display *dp_display,
|
||||
const struct msm_resource_caps_info *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);
|
||||
|
@@ -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,
|
||||
&bridge->dp_mode);
|
||||
|
||||
dp->clear_reservation(dp, bridge->dp_panel);
|
||||
}
|
||||
|
||||
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->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);
|
||||
end:
|
||||
return ret;
|
||||
|
@@ -345,6 +345,7 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge,
|
||||
dp = bridge->display;
|
||||
|
||||
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);
|
||||
|
||||
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));
|
||||
dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_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_CONN_ID(bridge), mode->name);
|
||||
|
@@ -137,6 +137,7 @@ struct dp_panel {
|
||||
u32 pbn;
|
||||
|
||||
u32 dsc_blks_in_use;
|
||||
u32 max_lm;
|
||||
/* DRM connector assosiated with this panel */
|
||||
struct drm_connector *connector;
|
||||
|
||||
|
@@ -828,6 +828,7 @@ struct msm_mode_info {
|
||||
|
||||
/**
|
||||
* 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_dsc number of dsc available
|
||||
* @num_vdc number of vdc available
|
||||
@@ -836,6 +837,7 @@ struct msm_mode_info {
|
||||
* @max_mixer_width: max width supported by layer mixer
|
||||
*/
|
||||
struct msm_resource_caps_info {
|
||||
uint32_t num_lm_in_use;
|
||||
uint32_t num_lm;
|
||||
uint32_t num_dsc;
|
||||
uint32_t num_vdc;
|
||||
|
@@ -286,27 +286,33 @@ void sde_rm_get_resource_info(struct sde_rm *rm,
|
||||
{
|
||||
struct sde_rm_hw_blk *blk;
|
||||
enum sde_hw_blk_type type;
|
||||
struct sde_rm_rsvp rsvp;
|
||||
const struct sde_lm_cfg *lm_cfg;
|
||||
bool is_built_in, is_pref;
|
||||
u32 lm_pref = (BIT(SDE_DISP_PRIMARY_PREF) | BIT(SDE_DISP_SECONDARY_PREF));
|
||||
|
||||
mutex_lock(&rm->rm_lock);
|
||||
|
||||
/* Get all currently available resources */
|
||||
memcpy(avail_res, &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)
|
||||
return;
|
||||
|
||||
is_built_in = false;
|
||||
else
|
||||
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++) {
|
||||
list_for_each_entry(blk, &rm->hw_blks[type], list) {
|
||||
/* 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);
|
||||
if (type == SDE_HW_BLK_LM)
|
||||
avail_res->num_lm_in_use++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&rm->rm_lock);
|
||||
}
|
||||
|
||||
static void _sde_rm_print_rsvps(
|
||||
|
Reference in New Issue
Block a user