mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
drm/tegra: Ensure BOs are not freed before display is updated
Occasionally, there are cases where the BO is being freed before the display has been updated to use the next BO. If the SMMU is enabled this causes SMMU faults to occur. This problem occurs when the vertical blanking interrupt occurs at the same time the BO used by the display is updated. In this case, the interrupt handler, tegra_dc_irq(), is called to handle the vertial blanking interrupt, which in turn calls drm_crtc_handle_vblank() to discard the previous BO. However, the programming of the display controller did not actually complete before the vertical blanking and the display is still using the previous BO. Hence, the display continues to use the prevoius BO which is then freed. Fix this by disabling the vertical blanking interrupt during the time where the display is updated and then in the Tegra interrupt handler ensure that we only handle interrupts that are currently enabled. Finally, before calling drm_crtc_handle_vblank() in the interrupt handler, check that the programming of the display controller has completed and it is safe to release the BO. JIRA LS-128 Change-Id: I1c9523f2b0a3ea406d651c2d1988e452d412e204 Signed-off-by: Jon Hunter <jonathanh@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2660852 Reviewed-by: Thierry Reding <treding@nvidia.com> Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com> Reviewed-by: svc_kernel_abi <svc_kernel_abi@nvidia.com> GVS: Gerrit_Virtual_Submit
This commit is contained in:
committed by
Laxman Dewangan
parent
02b028d02a
commit
881ea5294c
@@ -2289,6 +2289,8 @@ static void tegra_crtc_atomic_begin(struct drm_crtc *crtc,
|
|||||||
|
|
||||||
crtc->state->event = NULL;
|
crtc->state->event = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tegra_dc_disable_vblank(crtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
|
static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
|
||||||
@@ -2315,6 +2317,8 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc,
|
|||||||
value = dc_state->planes | GENERAL_ACT_REQ;
|
value = dc_state->planes | GENERAL_ACT_REQ;
|
||||||
tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
|
tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
|
||||||
value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
|
value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
|
||||||
|
|
||||||
|
tegra_dc_enable_vblank(crtc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tegra_plane_is_cursor(const struct drm_plane_state *state)
|
static bool tegra_plane_is_cursor(const struct drm_plane_state *state)
|
||||||
@@ -2527,9 +2531,10 @@ static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
|
|||||||
static irqreturn_t tegra_dc_irq(int irq, void *data)
|
static irqreturn_t tegra_dc_irq(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct tegra_dc *dc = data;
|
struct tegra_dc *dc = data;
|
||||||
unsigned long status;
|
u32 status, value, mask;
|
||||||
|
|
||||||
status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
|
mask = tegra_dc_readl(dc, DC_CMD_INT_MASK);
|
||||||
|
status = tegra_dc_readl(dc, DC_CMD_INT_STATUS) & mask;
|
||||||
tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
|
tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
|
||||||
|
|
||||||
if (status & FRAME_END_INT) {
|
if (status & FRAME_END_INT) {
|
||||||
@@ -2544,6 +2549,8 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
|
|||||||
/*
|
/*
|
||||||
dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
|
dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
|
||||||
*/
|
*/
|
||||||
|
value = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
|
||||||
|
if (!value)
|
||||||
drm_crtc_handle_vblank(&dc->base);
|
drm_crtc_handle_vblank(&dc->base);
|
||||||
dc->stats.vblank_total++;
|
dc->stats.vblank_total++;
|
||||||
dc->stats.vblank++;
|
dc->stats.vblank++;
|
||||||
|
|||||||
Reference in New Issue
Block a user