disp: msm: sde: fix release fence signaling in error cases
Handle release fence/frame-done error signalling for error case like esd failure, pp_done timeout, interrupt disable on cpu, etc. It fixes the race condition for pending_frame count update and also triggers correct wait function for wr_ptr wait failure. Change-Id: Iad08f20592c97221a1626bb40e607c398a9812b6 Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org> Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
This commit is contained in:

committed by
Dhaval Patel

parent
9081908beb
commit
5a2dfc1e83
@@ -3362,6 +3362,7 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
|
|||||||
sde_enc->phys_encs[i]->cont_splash_enabled = false;
|
sde_enc->phys_encs[i]->cont_splash_enabled = false;
|
||||||
sde_enc->phys_encs[i]->connector = NULL;
|
sde_enc->phys_encs[i]->connector = NULL;
|
||||||
}
|
}
|
||||||
|
atomic_set(&sde_enc->frame_done_cnt[i], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
sde_enc->cur_master = NULL;
|
sde_enc->cur_master = NULL;
|
||||||
@@ -3647,8 +3648,7 @@ static void sde_encoder_frame_done_callback(
|
|||||||
|
|
||||||
/* One of the physical encoders has become idle */
|
/* One of the physical encoders has become idle */
|
||||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||||
if ((sde_enc->phys_encs[i] == ready_phys) ||
|
if (sde_enc->phys_encs[i] == ready_phys) {
|
||||||
(event & SDE_ENCODER_FRAME_EVENT_ERROR)) {
|
|
||||||
SDE_EVT32_VERBOSE(DRMID(drm_enc), i,
|
SDE_EVT32_VERBOSE(DRMID(drm_enc), i,
|
||||||
atomic_read(&sde_enc->frame_done_cnt[i]));
|
atomic_read(&sde_enc->frame_done_cnt[i]));
|
||||||
if (!atomic_add_unless(
|
if (!atomic_add_unless(
|
||||||
|
@@ -365,12 +365,12 @@ struct sde_encoder_phys_cmd_autorefresh {
|
|||||||
* struct sde_encoder_phys_cmd - sub-class of sde_encoder_phys to handle command
|
* struct sde_encoder_phys_cmd - sub-class of sde_encoder_phys to handle command
|
||||||
* mode specific operations
|
* mode specific operations
|
||||||
* @base: Baseclass physical encoder structure
|
* @base: Baseclass physical encoder structure
|
||||||
* @intf_idx: Intf Block index used by this phys encoder
|
|
||||||
* @stream_sel: Stream selection for multi-stream interfaces
|
* @stream_sel: Stream selection for multi-stream interfaces
|
||||||
* @pp_timeout_report_cnt: number of pingpong done irq timeout errors
|
* @pp_timeout_report_cnt: number of pingpong done irq timeout errors
|
||||||
* @autorefresh: autorefresh feature state
|
* @autorefresh: autorefresh feature state
|
||||||
* @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
|
* @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
|
||||||
* @pending_vblank_wq: Wait queue for blocking until VBLANK received
|
* @pending_vblank_wq: Wait queue for blocking until VBLANK received
|
||||||
|
* @wr_ptr_wait_success: log wr_ptr_wait success for release fence trigger
|
||||||
*/
|
*/
|
||||||
struct sde_encoder_phys_cmd {
|
struct sde_encoder_phys_cmd {
|
||||||
struct sde_encoder_phys base;
|
struct sde_encoder_phys base;
|
||||||
@@ -379,6 +379,7 @@ struct sde_encoder_phys_cmd {
|
|||||||
struct sde_encoder_phys_cmd_autorefresh autorefresh;
|
struct sde_encoder_phys_cmd_autorefresh autorefresh;
|
||||||
atomic_t pending_vblank_cnt;
|
atomic_t pending_vblank_cnt;
|
||||||
wait_queue_head_t pending_vblank_wq;
|
wait_queue_head_t pending_vblank_wq;
|
||||||
|
bool wr_ptr_wait_success;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -461,20 +461,18 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
|
|||||||
|
|
||||||
conn = phys_enc->connector;
|
conn = phys_enc->connector;
|
||||||
|
|
||||||
if (atomic_read(&phys_enc->pending_kickoff_cnt) == 0)
|
/* decrement the kickoff_cnt before checking for ESD status */
|
||||||
|
if (!atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cmd_enc->pp_timeout_report_cnt++;
|
cmd_enc->pp_timeout_report_cnt++;
|
||||||
pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
|
pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt) + 1;
|
||||||
|
|
||||||
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
|
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
|
||||||
cmd_enc->pp_timeout_report_cnt,
|
cmd_enc->pp_timeout_report_cnt,
|
||||||
pending_kickoff_cnt,
|
pending_kickoff_cnt,
|
||||||
frame_event);
|
frame_event);
|
||||||
|
|
||||||
/* decrement the kickoff_cnt before checking for ESD status */
|
|
||||||
atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
|
|
||||||
|
|
||||||
/* check if panel is still sending TE signal or not */
|
/* check if panel is still sending TE signal or not */
|
||||||
if (sde_connector_esd_status(phys_enc->connector))
|
if (sde_connector_esd_status(phys_enc->connector))
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -651,13 +649,29 @@ static int _sde_encoder_phys_cmd_wait_for_idle(
|
|||||||
to_sde_encoder_phys_cmd(phys_enc);
|
to_sde_encoder_phys_cmd(phys_enc);
|
||||||
struct sde_encoder_wait_info wait_info;
|
struct sde_encoder_wait_info wait_info;
|
||||||
bool recovery_events;
|
bool recovery_events;
|
||||||
int ret, i, pending_cnt;
|
int ret;
|
||||||
|
struct sde_hw_ctl *ctl;
|
||||||
|
|
||||||
if (!phys_enc) {
|
if (!phys_enc) {
|
||||||
SDE_ERROR("invalid encoder\n");
|
SDE_ERROR("invalid encoder\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctl = phys_enc->hw_ctl;
|
||||||
|
if (cmd_enc->wr_ptr_wait_success &&
|
||||||
|
(phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) &&
|
||||||
|
ctl->ops.get_scheduler_status &&
|
||||||
|
(ctl->ops.get_scheduler_status(ctl) & BIT(0)) &&
|
||||||
|
atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0) &&
|
||||||
|
phys_enc->parent_ops.handle_frame_done) {
|
||||||
|
|
||||||
|
phys_enc->parent_ops.handle_frame_done(
|
||||||
|
phys_enc->parent, phys_enc,
|
||||||
|
SDE_ENCODER_FRAME_EVENT_DONE |
|
||||||
|
SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
wait_info.wq = &phys_enc->pending_kickoff_wq;
|
wait_info.wq = &phys_enc->pending_kickoff_wq;
|
||||||
wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
|
wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
|
||||||
wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
|
wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
|
||||||
@@ -671,9 +685,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle(
|
|||||||
ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG,
|
ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG,
|
||||||
&wait_info);
|
&wait_info);
|
||||||
if (ret == -ETIMEDOUT) {
|
if (ret == -ETIMEDOUT) {
|
||||||
pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
|
_sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc,
|
||||||
for (i = 0; i < pending_cnt; i++)
|
|
||||||
_sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc,
|
|
||||||
recovery_events);
|
recovery_events);
|
||||||
} else if (!ret) {
|
} else if (!ret) {
|
||||||
if (cmd_enc->pp_timeout_report_cnt && recovery_events) {
|
if (cmd_enc->pp_timeout_report_cnt && recovery_events) {
|
||||||
@@ -1368,19 +1380,9 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr(
|
|||||||
phys_enc->parent_ops.handle_frame_done(
|
phys_enc->parent_ops.handle_frame_done(
|
||||||
phys_enc->parent, phys_enc,
|
phys_enc->parent, phys_enc,
|
||||||
SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
|
SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
|
||||||
|
|
||||||
} else if ((ret == 0) &&
|
|
||||||
(phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START)
|
|
||||||
&& ctl->ops.get_scheduler_status
|
|
||||||
&& (ctl->ops.get_scheduler_status(ctl) & BIT(0))
|
|
||||||
&& atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)
|
|
||||||
&& phys_enc->parent_ops.handle_frame_done) {
|
|
||||||
phys_enc->parent_ops.handle_frame_done(
|
|
||||||
phys_enc->parent, phys_enc,
|
|
||||||
SDE_ENCODER_FRAME_EVENT_DONE |
|
|
||||||
SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1408,7 +1410,7 @@ static int sde_encoder_phys_cmd_wait_for_tx_complete(
|
|||||||
static int sde_encoder_phys_cmd_wait_for_commit_done(
|
static int sde_encoder_phys_cmd_wait_for_commit_done(
|
||||||
struct sde_encoder_phys *phys_enc)
|
struct sde_encoder_phys *phys_enc)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0, i, pending_cnt;
|
||||||
struct sde_encoder_phys_cmd *cmd_enc;
|
struct sde_encoder_phys_cmd *cmd_enc;
|
||||||
|
|
||||||
if (!phys_enc)
|
if (!phys_enc)
|
||||||
@@ -1421,11 +1423,11 @@ static int sde_encoder_phys_cmd_wait_for_commit_done(
|
|||||||
rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
|
rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
|
||||||
if (rc == -ETIMEDOUT)
|
if (rc == -ETIMEDOUT)
|
||||||
goto wait_for_idle;
|
goto wait_for_idle;
|
||||||
}
|
|
||||||
|
|
||||||
if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) &&
|
if (cmd_enc->autorefresh.cfg.enable)
|
||||||
cmd_enc->autorefresh.cfg.enable)
|
rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(
|
||||||
rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(phys_enc);
|
phys_enc);
|
||||||
|
}
|
||||||
|
|
||||||
/* wait for posted start or serialize trigger */
|
/* wait for posted start or serialize trigger */
|
||||||
if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) ||
|
if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) ||
|
||||||
@@ -1435,14 +1437,16 @@ static int sde_encoder_phys_cmd_wait_for_commit_done(
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
wait_for_idle:
|
wait_for_idle:
|
||||||
rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc);
|
pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
|
||||||
|
for (i = 0; i < pending_cnt; i++)
|
||||||
|
rc |= sde_encoder_wait_for_event(phys_enc->parent,
|
||||||
|
MSM_ENC_TX_COMPLETE);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
SDE_EVT32(DRMID(phys_enc->parent),
|
SDE_EVT32(DRMID(phys_enc->parent),
|
||||||
phys_enc->hw_pp->idx - PINGPONG_0,
|
phys_enc->hw_pp->idx - PINGPONG_0,
|
||||||
phys_enc->frame_trigger_mode,
|
phys_enc->frame_trigger_mode,
|
||||||
atomic_read(&phys_enc->pending_kickoff_cnt),
|
atomic_read(&phys_enc->pending_kickoff_cnt),
|
||||||
phys_enc->enable_state, rc);
|
phys_enc->enable_state, rc);
|
||||||
atomic_set(&phys_enc->pending_kickoff_cnt, 0);
|
|
||||||
SDE_ERROR("pp:%d failed wait_for_idle: %d\n",
|
SDE_ERROR("pp:%d failed wait_for_idle: %d\n",
|
||||||
phys_enc->hw_pp->idx - PINGPONG_0, rc);
|
phys_enc->hw_pp->idx - PINGPONG_0, rc);
|
||||||
if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET)
|
if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET)
|
||||||
|
Reference in New Issue
Block a user