summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Salido-Moreno <adrianm@codeaurora.org>2013-04-01 23:44:39 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:15:52 -0700
commite6a586f0b79be2c4025536a05bbef12ec83ae591 (patch)
tree4e7f5442825734388dc23b9502336deff43700cb
parent00c3fe11919e8cb91b0c810300d0b5311d42fe1d (diff)
msm: mdss: clear vsync interrupt bit before wait for completion
When kickoff happens, MDP needs to ensure that a vsync has happend after flush. To ensure this, MDP driver needs to clear any pending vsync interrupts after writing to flush to ensure that vsync has happened and the shadowed registers have been swapped (at vsync boundary). This addressed possible concurrency issue where vsync interrupt happens just before flush but irq handler does not process it until after, leading to iommu page fault. CRs-Fixed: 465340 Change-Id: I0f8412386c76fc6409e95f316f54999f42b09be5 Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c33
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_video.c20
3 files changed, 41 insertions, 14 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index b122054b8322..0555ab42b375 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -184,14 +184,15 @@ u32 mdss_mdp_fb_stride(u32 fb_index, u32 xres, int bpp)
static inline int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
{
struct mdss_hw *hw;
+ int rc = -ENODEV;
spin_lock(&mdss_lock);
hw = mdss_irq_handlers[hw_ndx];
- spin_unlock(&mdss_lock);
if (hw)
- return hw->irq_handler(irq, hw->ptr);
+ rc = hw->irq_handler(irq, hw->ptr);
+ spin_unlock(&mdss_lock);
- return -ENODEV;
+ return rc;
}
static irqreturn_t mdss_irq_handler(int irq, void *ptr)
@@ -204,8 +205,11 @@ static irqreturn_t mdss_irq_handler(int irq, void *ptr)
mdata->irq_buzy = true;
- if (intr & MDSS_INTR_MDP)
+ if (intr & MDSS_INTR_MDP) {
+ spin_lock(&mdp_lock);
mdss_irq_dispatch(MDSS_HW_MDP, irq, ptr);
+ spin_unlock(&mdp_lock);
+ }
if (intr & MDSS_INTR_DSI0)
mdss_irq_dispatch(MDSS_HW_DSI0, irq, ptr);
@@ -284,6 +288,7 @@ void mdss_disable_irq(struct mdss_hw *hw)
}
EXPORT_SYMBOL(mdss_disable_irq);
+/* called from interrupt context */
void mdss_disable_irq_nosync(struct mdss_hw *hw)
{
u32 ndx_bit;
@@ -296,7 +301,6 @@ void mdss_disable_irq_nosync(struct mdss_hw *hw)
pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
mdss_res->irq_ena, mdss_res->irq_mask);
- spin_lock(&mdss_lock);
if (!(mdss_res->irq_mask & ndx_bit)) {
pr_warn("MDSS HW ndx=%d is NOT set, mask=%x, hist mask=%x\n",
hw->hw_ndx, mdss_res->mdp_irq_mask,
@@ -309,7 +313,6 @@ void mdss_disable_irq_nosync(struct mdss_hw *hw)
disable_irq_nosync(mdss_res->irq);
}
}
- spin_unlock(&mdss_lock);
}
EXPORT_SYMBOL(mdss_disable_irq_nosync);
@@ -390,6 +393,21 @@ static inline u32 mdss_mdp_irq_mask(u32 intr_type, u32 intf_num)
return 1 << (intr_type + intf_num);
}
+/* function assumes that mdp is clocked to access hw registers */
+void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
+ u32 intr_type, u32 intf_num)
+{
+ unsigned long irq_flags;
+ u32 irq;
+
+ irq = mdss_mdp_irq_mask(intr_type, intf_num);
+
+ pr_debug("clearing mdp irq mask=%x\n", irq);
+ spin_lock_irqsave(&mdp_lock, irq_flags);
+ writel_relaxed(irq, mdata->mdp_base + MDSS_MDP_REG_INTR_CLEAR);
+ spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
{
u32 irq;
@@ -482,13 +500,13 @@ void mdss_mdp_hist_irq_disable(u32 irq)
spin_unlock_irqrestore(&mdp_lock, irq_flags);
}
+/* called from interrupt context */
void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
{
u32 irq;
irq = mdss_mdp_irq_mask(intr_type, intf_num);
- spin_lock(&mdp_lock);
if (!(mdss_res->mdp_irq_mask & irq)) {
pr_warn("MDSS MDP IRQ-%x is NOT set, mask=%x\n",
irq, mdss_res->mdp_irq_mask);
@@ -500,7 +518,6 @@ void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
(mdss_res->mdp_hist_irq_mask == 0))
mdss_disable_irq_nosync(&mdss_mdp_hw);
}
- spin_unlock(&mdp_lock);
}
static inline struct clk *mdss_mdp_get_clk(u32 clk_idx)
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index df5e5d300561..07b083a3a9f3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -330,6 +330,8 @@ static inline u32 mdss_mdp_pingpong_read(struct mdss_mdp_mixer *mixer, u32 reg)
irqreturn_t mdss_mdp_isr(int irq, void *ptr);
int mdss_iommu_attach(struct mdss_data_type *mdata);
int mdss_mdp_copy_splash_screen(struct mdss_panel_data *pdata);
+void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
+ u32 intr_type, u32 intf_num);
int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num);
int mdss_mdp_hist_irq_enable(u32 irq);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 8c57c8c569fb..0426784be46d 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -182,6 +182,9 @@ static inline void video_vsync_irq_enable(struct mdss_mdp_ctl *ctl)
if (atomic_inc_return(&ctx->vsync_ref) == 1)
mdss_mdp_irq_enable(MDSS_MDP_IRQ_INTF_VSYNC, ctl->intf_num);
+ else
+ mdss_mdp_irq_clear(ctl->mdata, MDSS_MDP_IRQ_INTF_VSYNC,
+ ctl->intf_num);
}
static inline void video_vsync_irq_disable(struct mdss_mdp_ctl *ctl)
@@ -197,6 +200,7 @@ static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
{
struct mdss_mdp_video_ctx *ctx;
unsigned long flags;
+ int need_update;
ctx = (struct mdss_mdp_video_ctx *) ctl->priv_data;
if (!ctx) {
@@ -205,14 +209,18 @@ static int mdss_mdp_video_set_vsync_handler(struct mdss_mdp_ctl *ctl,
}
spin_lock_irqsave(&ctx->vsync_lock, flags);
- if (!ctx->vsync_handler && vsync_handler)
- video_vsync_irq_enable(ctl);
- else if (ctx->vsync_handler && !vsync_handler)
- video_vsync_irq_disable(ctl);
-
+ need_update = (!ctx->vsync_handler && vsync_handler) ||
+ (ctx->vsync_handler && !vsync_handler);
ctx->vsync_handler = vsync_handler;
spin_unlock_irqrestore(&ctx->vsync_lock, flags);
+ if (need_update) {
+ if (vsync_handler)
+ video_vsync_irq_enable(ctl);
+ else
+ video_vsync_irq_disable(ctl);
+ }
+
return 0;
}
@@ -335,8 +343,8 @@ static int mdss_mdp_video_display(struct mdss_mdp_ctl *ctl, void *arg)
if (!ctx->wait_pending) {
ctx->wait_pending++;
- INIT_COMPLETION(ctx->vsync_comp);
video_vsync_irq_enable(ctl);
+ INIT_COMPLETION(ctx->vsync_comp);
} else {
WARN(1, "commit without wait! ctl=%d", ctl->num);
}