diff options
| author | Xiaoming Zhou <zhoux@codeaurora.org> | 2013-04-30 14:24:32 -0400 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:17:01 -0700 |
| commit | 562bbf3ff744426b7a6e5d46e9e7dfac2d1aea5a (patch) | |
| tree | 1c73583989ecfb83c45fb6268148363dd6e394e6 | |
| parent | 8b76a8380ee19ee8d8260658f111d8b3eb4bb87d (diff) | |
msm: mdss: fix vsync control synchronization issue
Fix the race condition when user vsync control thread turns on/off
the vsync interrupt, while frame thread updates at the same time.
Change-Id: I4e9f6df2a58702a5b2db62a7fd989e51503825aa
Signed-off-by: Xiaoming Zhou <zhoux@codeaurora.org>
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3.c | 42 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3.h | 3 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3_ctrl.c | 38 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3_ctrl.h | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3_dma.c | 21 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdp3_dma.h | 4 |
6 files changed, 57 insertions, 53 deletions
diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c index 902e5a6be0cb..1afb8448f52c 100644 --- a/drivers/video/fbdev/msm/mdp3.c +++ b/drivers/video/fbdev/msm/mdp3.c @@ -125,7 +125,7 @@ static irqreturn_t mdp3_irq_handler(int irq, void *ptr) pr_debug("mdp3_irq_handler irq=%d\n", mdp_interrupt); spin_lock(&mdata->irq_lock); - mdp_interrupt &= mdata->irqMask; + mdp_interrupt &= mdata->irq_mask; while (mdp_interrupt && i < MDP3_MAX_INTR) { if ((mdp_interrupt & 0x1) && mdata->callbacks[i].cb) @@ -145,14 +145,15 @@ void mdp3_irq_enable(int type) pr_debug("mdp3_irq_enable type=%d\n", type); spin_lock_irqsave(&mdp3_res->irq_lock, flag); - if (mdp3_res->irqMask & BIT(type)) { + mdp3_res->irq_ref_count[type] += 1; + if (mdp3_res->irq_ref_count[type] > 1) { pr_debug("interrupt %d already enabled\n", type); spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); return; } - irqEnabled = mdp3_res->irqMask; - mdp3_res->irqMask |= BIT(type); - MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask); + irqEnabled = mdp3_res->irq_mask; + mdp3_res->irq_mask |= BIT(type); + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask); if (!irqEnabled) enable_irq(mdp3_res->irq); spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); @@ -163,26 +164,33 @@ void mdp3_irq_disable(int type) unsigned long flag; spin_lock_irqsave(&mdp3_res->irq_lock, flag); - if (mdp3_res->irqMask & BIT(type)) { - mdp3_res->irqMask &= ~BIT(type); - MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask); - if (!mdp3_res->irqMask) - disable_irq(mdp3_res->irq); - } else { + if (mdp3_res->irq_ref_count[type] <= 0) { pr_debug("interrupt %d not enabled\n", type); + spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); + return; + } + mdp3_res->irq_ref_count[type] -= 1; + if (mdp3_res->irq_ref_count[type] == 0) { + mdp3_res->irq_mask &= ~BIT(type); + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask); + if (!mdp3_res->irq_mask) + disable_irq(mdp3_res->irq); } spin_unlock_irqrestore(&mdp3_res->irq_lock, flag); } void mdp3_irq_disable_nosync(int type) { - if (mdp3_res->irqMask & BIT(type)) { - mdp3_res->irqMask &= ~BIT(type); - MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irqMask); - if (!mdp3_res->irqMask) - disable_irq_nosync(mdp3_res->irq); - } else { + if (mdp3_res->irq_ref_count[type] <= 0) { pr_debug("interrupt %d not enabled\n", type); + return; + } + mdp3_res->irq_ref_count[type] -= 1; + if (mdp3_res->irq_ref_count[type] == 0) { + mdp3_res->irq_mask &= ~BIT(type); + MDP3_REG_WRITE(MDP3_REG_INTR_ENABLE, mdp3_res->irq_mask); + if (!mdp3_res->irq_mask) + disable_irq_nosync(mdp3_res->irq); } } diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h index ea9913749181..a90b23380d7d 100644 --- a/drivers/video/fbdev/msm/mdp3.h +++ b/drivers/video/fbdev/msm/mdp3.h @@ -99,7 +99,8 @@ struct mdp3_hw_resource { struct mdp3_intf intf[MDP3_DMA_OUTPUT_SEL_MAX]; spinlock_t irq_lock; - u32 irqMask; + u32 irq_ref_count[MDP3_MAX_INTR]; + u32 irq_mask; struct mdp3_intr_cb callbacks[MDP3_MAX_INTR]; }; diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index 929e5f857356..fbaac8fcefc3 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -29,34 +29,48 @@ void vsync_notify_handler(void *arg) { struct mdp3_session_data *session = (struct mdp3_session_data *)arg; + spin_lock(&session->vsync_lock); + session->vsync_time = ktime_get(); complete(&session->vsync_comp); + spin_unlock(&session->vsync_lock); } static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable) { struct mdp3_session_data *mdp3_session; struct mdp3_vsync_notification vsync_client; + struct mdp3_vsync_notification *arg = NULL; + unsigned long flag; + pr_debug("mdp3_ctrl_vsync_enable =%d\n", enable); mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; if (!mdp3_session || !mdp3_session->panel || !mdp3_session->dma || !mdp3_session->intf) return -ENODEV; - vsync_client.handler = vsync_notify_handler; - vsync_client.arg = mdp3_session; - - mutex_lock(&mdp3_session->lock); if (!mdp3_session->status) { pr_debug("fb%d is not on yet", mfd->index); - mutex_unlock(&mdp3_session->lock); return -EINVAL; } + if (enable) { + vsync_client.handler = vsync_notify_handler; + vsync_client.arg = mdp3_session; + arg = &vsync_client; + } - mdp3_session->dma->vsync_enable(mdp3_session->dma, &vsync_client); + mutex_lock(&mdp3_session->lock); + mdp3_session->dma->vsync_enable(mdp3_session->dma, arg); mutex_unlock(&mdp3_session->lock); + spin_lock_irqsave(&mdp3_session->vsync_lock, flag); + if (enable) + INIT_COMPLETION(mdp3_session->vsync_comp); + else + complete_all(&mdp3_session->vsync_comp); + spin_unlock_irqrestore(&mdp3_session->vsync_lock, flag); return 0; } + static ssize_t mdp3_vsync_show_event(struct device *dev, struct device_attribute *attr, char *buf) { @@ -64,8 +78,8 @@ static ssize_t mdp3_vsync_show_event(struct device *dev, struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdp3_session_data *mdp3_session = NULL; u64 vsync_ticks; - ktime_t vsync_time; int rc; + unsigned long flag; if (!mfd || !mfd->mdp.private1) return 0; @@ -78,11 +92,11 @@ static ssize_t mdp3_vsync_show_event(struct device *dev, if (rc <= 0) { pr_warn("vsync wait on fb%d interrupted (%d)\n", mfd->index, rc); - return -EBUSY; } - vsync_time = mdp3_session->dma->get_vsync_time(mdp3_session->dma); - vsync_ticks = ktime_to_ns(vsync_time); + spin_lock_irqsave(&mdp3_session->vsync_lock, flag); + vsync_ticks = ktime_to_ns(mdp3_session->vsync_time); + spin_unlock_irqrestore(&mdp3_session->vsync_lock, flag); pr_debug("fb%d vsync=%llu", mfd->index, vsync_ticks); rc = snprintf(buf, PAGE_SIZE, "VSYNC=%llu", vsync_ticks); @@ -478,8 +492,6 @@ static int mdp3_ctrl_ioctl_handler(struct msm_fb_data_type *mfd, case MSMFB_OVERLAY_VSYNC_CTRL: if (!copy_from_user(&val, argp, sizeof(val))) { rc = mdp3_ctrl_vsync_enable(mfd, val); - if (!val) - init_completion(&mdp3_session->vsync_comp); } else { pr_err("MSMFB_OVERLAY_VSYNC_CTRL failed\n"); rc = -EFAULT; @@ -525,6 +537,7 @@ int mdp3_ctrl_init(struct msm_fb_data_type *mfd) memset(mdp3_session, 0, sizeof(struct mdp3_session_data)); mutex_init(&mdp3_session->lock); init_completion(&mdp3_session->vsync_comp); + spin_lock_init(&mdp3_session->vsync_lock); mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL); if (!mdp3_session->dma) { rc = -ENODEV; @@ -540,7 +553,6 @@ int mdp3_ctrl_init(struct msm_fb_data_type *mfd) mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev); mdp3_session->status = 0; - mfd->mdp.private1 = mdp3_session; rc = sysfs_create_group(&dev->kobj, &vsync_fs_attr_group); diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.h b/drivers/video/fbdev/msm/mdp3_ctrl.h index d42ece70f209..af5139b50d89 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.h +++ b/drivers/video/fbdev/msm/mdp3_ctrl.h @@ -29,6 +29,8 @@ struct mdp3_session_data { struct mdss_panel_data *panel; struct mdp3_intf *intf; struct msm_fb_data_type *mfd; + ktime_t vsync_time; + spinlock_t vsync_lock; struct completion vsync_comp; }; diff --git a/drivers/video/fbdev/msm/mdp3_dma.c b/drivers/video/fbdev/msm/mdp3_dma.c index 69e3d7e5e8cf..a09f503eab14 100644 --- a/drivers/video/fbdev/msm/mdp3_dma.c +++ b/drivers/video/fbdev/msm/mdp3_dma.c @@ -20,17 +20,6 @@ #define DMA_STOP_POLL_SLEEP_US 1000 #define DMA_STOP_POLL_TIMEOUT_US 16000 -static ktime_t mdp3_get_vsync_time(struct mdp3_dma *dma) -{ - unsigned long flag; - ktime_t time; - - spin_lock_irqsave(&dma->dma_lock, flag); - time = dma->vsync_time; - spin_unlock_irqrestore(&dma->dma_lock, flag); - return time; -} - static void mdp3_vsync_intr_handler(int type, void *arg) { struct mdp3_dma *dma = (struct mdp3_dma *)arg; @@ -41,13 +30,11 @@ static void mdp3_vsync_intr_handler(int type, void *arg) vsync_client = dma->vsync_client; if (!vsync_client.handler) dma->cb_type &= ~MDP3_DMA_CALLBACK_TYPE_VSYNC; - dma->vsync_time = ktime_get(); complete(&dma->vsync_comp); + spin_unlock(&dma->dma_lock); if (vsync_client.handler) vsync_client.handler(vsync_client.arg); - spin_unlock(&dma->dma_lock); - - if (!vsync_client.handler) + else mdp3_irq_disable_nosync(type); } @@ -186,7 +173,7 @@ static void mdp3_dma_vsync_enable(struct mdp3_dma *dma, updated = 1; } } else { - if (!dma->vsync_client.handler) { + if (dma->vsync_client.handler) { dma->vsync_client.handler = NULL; dma->vsync_client.arg = NULL; updated = 1; @@ -696,7 +683,6 @@ int mdp3_dma_init(struct mdp3_dma *dma, dma->histo_intr_enable = mdp3_dmap_histo_intr_enable; dma->histo_intr_clear = mdp3_dmap_histo_intr_clear; dma->vsync_enable = mdp3_dma_vsync_enable; - dma->get_vsync_time = mdp3_get_vsync_time; dma->start = mdp3_dma_start; dma->stop = mdp3_dma_stop; break; @@ -717,7 +703,6 @@ int mdp3_dma_init(struct mdp3_dma *dma, dma->histo_intr_enable = NULL; dma->histo_intr_clear = NULL; dma->vsync_enable = mdp3_dma_vsync_enable; - dma->get_vsync_time = mdp3_get_vsync_time; dma->start = mdp3_dma_start; dma->stop = mdp3_dma_stop; break; diff --git a/drivers/video/fbdev/msm/mdp3_dma.h b/drivers/video/fbdev/msm/mdp3_dma.h index 2fb8427f0f9a..cef749bc0f50 100644 --- a/drivers/video/fbdev/msm/mdp3_dma.h +++ b/drivers/video/fbdev/msm/mdp3_dma.h @@ -231,7 +231,6 @@ struct mdp3_dma { spinlock_t dma_lock; struct completion vsync_comp; struct completion dma_comp; - ktime_t vsync_time; struct mdp3_vsync_notification vsync_client; u32 cb_type; @@ -275,9 +274,6 @@ struct mdp3_dma { void (*vsync_enable)(struct mdp3_dma *dma, struct mdp3_vsync_notification *vsync_client); - - ktime_t (*get_vsync_time)(struct mdp3_dma *dma); - }; struct mdp3_video_intf_cfg { |
