disp: msm: sde: remove fb's attached to a drm_file in preclose
This change avoids upstream drm issuing drm_atomic_commit in drm_fb_release which is leading to artifacts on screen or atomic_check failures due to atomically unstaging each fb from plane_state and committing remaining planes on hardware. a) This patch moves the state operations for setting crtc to connector state to a helper api. b) This patch clears any dim_layers present in the crtc_state as part of null commit. c) This patch removes any framebuffers attached to a drm_file in msm_preclose whose refcount is not managed by composer kill inadvertently and issues null flush to hardware in such cases. d) This patch handles msm_preclose as part of msm_release operation since legacy feature is not supported for msm_driver. Change-Id: Ib2068d74d4b23b73b7c84544858c9f6bb6adfa67 Signed-off-by: Jayaprakash Madisetty <jmadiset@codeaurora.org> Signed-off-by: Samantha Tran <samtran@codeaurora.org>
This commit is contained in:

committed by
Samantha Tran

parent
2df01bf3aa
commit
0e3d422520
@@ -45,6 +45,7 @@
|
|||||||
#include <drm/drm_ioctl.h>
|
#include <drm/drm_ioctl.h>
|
||||||
#include <drm/drm_vblank.h>
|
#include <drm/drm_vblank.h>
|
||||||
#include <drm/drm_drv.h>
|
#include <drm/drm_drv.h>
|
||||||
|
#include <drm/drm_auth.h>
|
||||||
#include <drm/drm_probe_helper.h>
|
#include <drm/drm_probe_helper.h>
|
||||||
|
|
||||||
#include "msm_drv.h"
|
#include "msm_drv.h"
|
||||||
@@ -1480,6 +1481,14 @@ static int msm_release(struct inode *inode, struct file *filp)
|
|||||||
kfree(node);
|
kfree(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle preclose operation here for removing fb's whose
|
||||||
|
* refcount > 1. This operation is not triggered from upstream
|
||||||
|
* drm as msm_driver does not support DRIVER_LEGACY feature.
|
||||||
|
*/
|
||||||
|
if (drm_is_current_master(file_priv))
|
||||||
|
msm_preclose(dev, file_priv);
|
||||||
|
|
||||||
return drm_release(inode, filp);
|
return drm_release(inode, filp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1684,7 +1693,6 @@ static struct drm_driver msm_driver = {
|
|||||||
DRIVER_ATOMIC |
|
DRIVER_ATOMIC |
|
||||||
DRIVER_MODESET,
|
DRIVER_MODESET,
|
||||||
.open = msm_open,
|
.open = msm_open,
|
||||||
.preclose = msm_preclose,
|
|
||||||
.postclose = msm_postclose,
|
.postclose = msm_postclose,
|
||||||
.lastclose = msm_lastclose,
|
.lastclose = msm_lastclose,
|
||||||
.irq_handler = msm_irq,
|
.irq_handler = msm_irq,
|
||||||
|
@@ -2831,17 +2831,16 @@ static void _sde_crtc_set_input_fence_timeout(struct sde_crtc_state *cstate)
|
|||||||
cstate->input_fence_timeout_ns *= NSEC_PER_MSEC;
|
cstate->input_fence_timeout_ns *= NSEC_PER_MSEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state)
|
||||||
* _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings
|
|
||||||
* @cstate: Pointer to sde crtc state
|
|
||||||
*/
|
|
||||||
static void _sde_crtc_clear_dim_layers_v1(struct sde_crtc_state *cstate)
|
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
struct sde_crtc_state *cstate;
|
||||||
|
|
||||||
if (!cstate)
|
if (!state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
cstate = to_sde_crtc_state(state);
|
||||||
|
|
||||||
for (i = 0; i < cstate->num_dim_layers; i++)
|
for (i = 0; i < cstate->num_dim_layers; i++)
|
||||||
memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i]));
|
memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i]));
|
||||||
|
|
||||||
@@ -2870,7 +2869,7 @@ static void _sde_crtc_set_dim_layer_v1(struct drm_crtc *crtc,
|
|||||||
|
|
||||||
if (!usr_ptr) {
|
if (!usr_ptr) {
|
||||||
/* usr_ptr is null when setting the default property value */
|
/* usr_ptr is null when setting the default property value */
|
||||||
_sde_crtc_clear_dim_layers_v1(cstate);
|
_sde_crtc_clear_dim_layers_v1(&cstate->base);
|
||||||
SDE_DEBUG("dim_layer data removed\n");
|
SDE_DEBUG("dim_layer data removed\n");
|
||||||
goto clear;
|
goto clear;
|
||||||
}
|
}
|
||||||
|
@@ -1022,4 +1022,10 @@ void sde_crtc_reset_sw_state(struct drm_crtc *crtc);
|
|||||||
*/
|
*/
|
||||||
void sde_crtc_disable_cp_features(struct drm_crtc *crtc);
|
void sde_crtc_disable_cp_features(struct drm_crtc *crtc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings
|
||||||
|
* @cstate: Pointer to drm crtc state
|
||||||
|
*/
|
||||||
|
void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state);
|
||||||
|
|
||||||
#endif /* _SDE_CRTC_H_ */
|
#endif /* _SDE_CRTC_H_ */
|
||||||
|
@@ -2396,6 +2396,71 @@ static void sde_kms_destroy(struct msm_kms *kms)
|
|||||||
kfree(sde_kms);
|
kfree(sde_kms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sde_kms_helper_clear_dim_layers(struct drm_atomic_state *state, struct drm_crtc *crtc)
|
||||||
|
{
|
||||||
|
struct drm_crtc_state *crtc_state = NULL;
|
||||||
|
struct sde_crtc_state *c_state;
|
||||||
|
|
||||||
|
if (!state || !crtc) {
|
||||||
|
SDE_ERROR("invalid params\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
|
||||||
|
c_state = to_sde_crtc_state(crtc_state);
|
||||||
|
|
||||||
|
_sde_crtc_clear_dim_layers_v1(crtc_state);
|
||||||
|
set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, c_state->dirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sde_kms_set_crtc_for_conn(struct drm_device *dev,
|
||||||
|
struct drm_encoder *enc, struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct drm_connector *conn = NULL;
|
||||||
|
struct drm_connector *tmp_conn = NULL;
|
||||||
|
struct drm_connector_list_iter conn_iter;
|
||||||
|
struct drm_crtc_state *crtc_state = NULL;
|
||||||
|
struct drm_connector_state *conn_state = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
drm_connector_list_iter_begin(dev, &conn_iter);
|
||||||
|
drm_for_each_connector_iter(tmp_conn, &conn_iter) {
|
||||||
|
if (enc == tmp_conn->state->best_encoder) {
|
||||||
|
conn = tmp_conn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drm_connector_list_iter_end(&conn_iter);
|
||||||
|
|
||||||
|
if (!conn || !enc->crtc) {
|
||||||
|
SDE_ERROR("invalid params for enc:%d\n", DRMID(enc));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
crtc_state = drm_atomic_get_crtc_state(state, enc->crtc);
|
||||||
|
if (IS_ERR(crtc_state)) {
|
||||||
|
ret = PTR_ERR(crtc_state);
|
||||||
|
SDE_ERROR("error %d getting crtc %d state\n",
|
||||||
|
ret, DRMID(enc->crtc));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn_state = drm_atomic_get_connector_state(state, conn);
|
||||||
|
if (IS_ERR(conn_state)) {
|
||||||
|
ret = PTR_ERR(conn_state);
|
||||||
|
SDE_ERROR("error %d getting connector %d state\n",
|
||||||
|
ret, DRMID(conn));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
crtc_state->active = true;
|
||||||
|
ret = drm_atomic_set_crtc_for_connector(conn_state, enc->crtc);
|
||||||
|
if (ret)
|
||||||
|
SDE_ERROR("error %d setting the crtc\n", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void _sde_kms_plane_force_remove(struct drm_plane *plane,
|
static void _sde_kms_plane_force_remove(struct drm_plane *plane,
|
||||||
struct drm_atomic_state *state)
|
struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
@@ -2429,8 +2494,9 @@ static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file,
|
|||||||
struct drm_framebuffer *fb, *tfb;
|
struct drm_framebuffer *fb, *tfb;
|
||||||
struct list_head fbs;
|
struct list_head fbs;
|
||||||
struct drm_plane *plane;
|
struct drm_plane *plane;
|
||||||
|
struct drm_crtc *crtc = NULL;
|
||||||
|
unsigned int crtc_mask = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 plane_mask = 0;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&fbs);
|
INIT_LIST_HEAD(&fbs);
|
||||||
|
|
||||||
@@ -2439,11 +2505,10 @@ static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file,
|
|||||||
list_move_tail(&fb->filp_head, &fbs);
|
list_move_tail(&fb->filp_head, &fbs);
|
||||||
|
|
||||||
drm_for_each_plane(plane, dev) {
|
drm_for_each_plane(plane, dev) {
|
||||||
if (plane->fb == fb) {
|
if (plane->state && plane->state->fb == fb) {
|
||||||
plane_mask |=
|
if (plane->state->crtc)
|
||||||
1 << drm_plane_index(plane);
|
crtc_mask |= drm_crtc_mask(plane->state->crtc);
|
||||||
_sde_kms_plane_force_remove(
|
_sde_kms_plane_force_remove(plane, state);
|
||||||
plane, state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -2454,13 +2519,28 @@ static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file,
|
|||||||
|
|
||||||
if (list_empty(&fbs)) {
|
if (list_empty(&fbs)) {
|
||||||
SDE_DEBUG("skip commit as no fb(s)\n");
|
SDE_DEBUG("skip commit as no fb(s)\n");
|
||||||
drm_atomic_state_put(state);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDE_DEBUG("committing after removing all the pipes\n");
|
drm_for_each_crtc(crtc, dev) {
|
||||||
|
if ((crtc_mask & drm_crtc_mask(crtc)) && crtc->state->active) {
|
||||||
|
struct drm_encoder *drm_enc;
|
||||||
|
|
||||||
|
drm_for_each_encoder_mask(drm_enc, crtc->dev,
|
||||||
|
crtc->state->encoder_mask) {
|
||||||
|
ret = sde_kms_set_crtc_for_conn(dev, drm_enc, state);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
sde_kms_helper_clear_dim_layers(state, crtc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDE_EVT32(state, crtc_mask);
|
||||||
|
SDE_DEBUG("null commit after removing all the pipes\n");
|
||||||
ret = drm_atomic_commit(state);
|
ret = drm_atomic_commit(state);
|
||||||
|
|
||||||
|
error:
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/*
|
/*
|
||||||
* move the fbs back to original list, so it would be
|
* move the fbs back to original list, so it would be
|
||||||
@@ -3584,12 +3664,7 @@ static void _sde_kms_null_commit(struct drm_device *dev,
|
|||||||
struct drm_encoder *enc)
|
struct drm_encoder *enc)
|
||||||
{
|
{
|
||||||
struct drm_modeset_acquire_ctx ctx;
|
struct drm_modeset_acquire_ctx ctx;
|
||||||
struct drm_connector *conn = NULL;
|
|
||||||
struct drm_connector *tmp_conn = NULL;
|
|
||||||
struct drm_connector_list_iter conn_iter;
|
|
||||||
struct drm_atomic_state *state = NULL;
|
struct drm_atomic_state *state = NULL;
|
||||||
struct drm_crtc_state *crtc_state = NULL;
|
|
||||||
struct drm_connector_state *conn_state = NULL;
|
|
||||||
int retry_cnt = 0;
|
int retry_cnt = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@@ -3613,32 +3688,10 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
state->acquire_ctx = &ctx;
|
state->acquire_ctx = &ctx;
|
||||||
drm_connector_list_iter_begin(dev, &conn_iter);
|
|
||||||
drm_for_each_connector_iter(tmp_conn, &conn_iter) {
|
|
||||||
if (enc == tmp_conn->state->best_encoder) {
|
|
||||||
conn = tmp_conn;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drm_connector_list_iter_end(&conn_iter);
|
|
||||||
|
|
||||||
if (!conn) {
|
ret = sde_kms_set_crtc_for_conn(dev, enc, state);
|
||||||
SDE_ERROR("error in finding conn for enc:%d\n", DRMID(enc));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
crtc_state = drm_atomic_get_crtc_state(state, enc->crtc);
|
|
||||||
conn_state = drm_atomic_get_connector_state(state, conn);
|
|
||||||
if (IS_ERR(conn_state)) {
|
|
||||||
SDE_ERROR("error %d getting connector %d state\n",
|
|
||||||
ret, DRMID(conn));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
crtc_state->active = true;
|
|
||||||
ret = drm_atomic_set_crtc_for_connector(conn_state, enc->crtc);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
SDE_ERROR("error %d setting the crtc\n", ret);
|
goto end;
|
||||||
|
|
||||||
ret = drm_atomic_commit(state);
|
ret = drm_atomic_commit(state);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
Reference in New Issue
Block a user