summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiaoming Zhou <zhoux@codeaurora.org>2013-04-30 14:24:32 -0400
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:17:01 -0700
commit562bbf3ff744426b7a6e5d46e9e7dfac2d1aea5a (patch)
tree1c73583989ecfb83c45fb6268148363dd6e394e6
parent8b76a8380ee19ee8d8260658f111d8b3eb4bb87d (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.c42
-rw-r--r--drivers/video/fbdev/msm/mdp3.h3
-rw-r--r--drivers/video/fbdev/msm/mdp3_ctrl.c38
-rw-r--r--drivers/video/fbdev/msm/mdp3_ctrl.h2
-rw-r--r--drivers/video/fbdev/msm/mdp3_dma.c21
-rw-r--r--drivers/video/fbdev/msm/mdp3_dma.h4
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 {