msm: rotator: non-blocking rotate
Send request to a work queue and return right away.
Work queue will go through the commit queue to do the
rotation. wait_for_finish can be set to true to make
rotation go back to blocking.
Change-Id: Ifc2e36bd24d9681d42105f4ccbb62a8777af2a6c
Signed-off-by: Ken Zhang <kenz@codeaurora.org>
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index dd9c8cb..20e716e 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -93,6 +93,8 @@
#define INVALID_SESSION -1
#define VERSION_KEY_MASK 0xFFFFFF00
#define MAX_DOWNSCALE_RATIO 3
+#define MAX_COMMIT_QUEUE 4
+#define WAIT_ROT_TIMEOUT 1000
#define MAX_TIMELINE_NAME_LEN 16
#define WAIT_FENCE_FIRST_TIMEOUT MSEC_PER_SEC
@@ -141,13 +143,12 @@
struct rot_sync_info {
u32 initialized;
struct sync_fence *acq_fen;
- int cur_rel_fen_fd;
- struct sync_pt *cur_rel_sync_pt;
- struct sync_fence *cur_rel_fence;
- struct sync_fence *last_rel_fence;
+ struct sync_fence *rel_fen;
+ int rel_fen_fd;
struct sw_sync_timeline *timeline;
int timeline_value;
struct mutex sync_mutex;
+ atomic_t queue_buf_cnt;
};
struct msm_rotator_session {
@@ -156,6 +157,30 @@
int fast_yuv_enable;
};
+struct msm_rotator_commit_info {
+ struct msm_rotator_data_info data_info;
+ struct msm_rotator_img_info img_info;
+ unsigned int format;
+ unsigned int in_paddr;
+ unsigned int out_paddr;
+ unsigned int in_chroma_paddr;
+ unsigned int out_chroma_paddr;
+ unsigned int in_chroma2_paddr;
+ unsigned int out_chroma2_paddr;
+ struct file *srcp0_file;
+ struct file *srcp1_file;
+ struct file *dstp0_file;
+ struct file *dstp1_file;
+ struct ion_handle *srcp0_ihdl;
+ struct ion_handle *srcp1_ihdl;
+ struct ion_handle *dstp0_ihdl;
+ struct ion_handle *dstp1_ihdl;
+ int ps0_need;
+ int session_index;
+ struct sync_fence *acq_fen;
+ int fast_yuv_en;
+};
+
struct msm_rotator_dev {
void __iomem *io_base;
int irq;
@@ -187,6 +212,16 @@
u32 sec_mapped;
u32 mmu_clk_on;
struct rot_sync_info sync_info[MAX_SESSIONS];
+ /* non blocking */
+ struct mutex commit_mutex;
+ struct mutex commit_wq_mutex;
+ struct completion commit_comp;
+ u32 commit_running;
+ struct work_struct commit_work;
+ struct msm_rotator_commit_info commit_info[MAX_COMMIT_QUEUE];
+ atomic_t commit_q_r;
+ atomic_t commit_q_w;
+ atomic_t commit_q_cnt;
};
#define COMPONENT_5BITS 1
@@ -194,6 +229,8 @@
#define COMPONENT_8BITS 3
static struct msm_rotator_dev *msm_rotator_dev;
+#define mrd msm_rotator_dev
+static void rot_wait_for_commit_queue(u32 is_all);
enum {
CLK_EN,
@@ -379,8 +416,25 @@
mutex_lock(&sync_info->sync_mutex);
sw_sync_timeline_inc(sync_info->timeline, 1);
sync_info->timeline_value++;
- sync_info->last_rel_fence = sync_info->cur_rel_fence;
- sync_info->cur_rel_fence = 0;
+ mutex_unlock(&sync_info->sync_mutex);
+}
+
+static void msm_rotator_signal_timeline_done(u32 session_index)
+{
+ struct rot_sync_info *sync_info;
+ sync_info = &msm_rotator_dev->sync_info[session_index];
+
+ if ((sync_info->timeline == NULL) ||
+ (sync_info->initialized == false))
+ return;
+ mutex_lock(&sync_info->sync_mutex);
+ sw_sync_timeline_inc(sync_info->timeline, 1);
+ sync_info->timeline_value++;
+ if (atomic_read(&sync_info->queue_buf_cnt) <= 0)
+ pr_err("%s queue_buf_cnt=%d", __func__,
+ atomic_read(&sync_info->queue_buf_cnt));
+ else
+ atomic_dec(&sync_info->queue_buf_cnt);
mutex_unlock(&sync_info->sync_mutex);
}
@@ -409,52 +463,41 @@
}
}
-static void msm_rotator_wait_for_fence_sub(u32 session_index)
+static void msm_rotator_wait_for_fence(struct sync_fence *acq_fen)
{
- struct rot_sync_info *sync_info;
int ret;
- sync_info = &msm_rotator_dev->sync_info[session_index];
- if (sync_info->acq_fen) {
- ret = sync_fence_wait(sync_info->acq_fen,
+ if (acq_fen) {
+ ret = sync_fence_wait(acq_fen,
WAIT_FENCE_FIRST_TIMEOUT);
if (ret == -ETIME) {
pr_warn("%s: timeout, wait %ld more ms\n",
__func__, WAIT_FENCE_FINAL_TIMEOUT);
- ret = sync_fence_wait(sync_info->acq_fen,
+ ret = sync_fence_wait(acq_fen,
WAIT_FENCE_FINAL_TIMEOUT);
}
if (ret < 0) {
pr_err("%s: sync_fence_wait failed! ret = %x\n",
__func__, ret);
}
- sync_fence_put(sync_info->acq_fen);
- sync_info->acq_fen = NULL;
+ sync_fence_put(acq_fen);
}
}
-static void msm_rotator_wait_for_fence(u32 session_index)
-{
- struct rot_sync_info *sync_info;
- sync_info = &msm_rotator_dev->sync_info[session_index];
- if ((!sync_info->timeline) || (!sync_info->initialized))
- return;
-
- mutex_lock(&sync_info->sync_mutex);
- msm_rotator_wait_for_fence_sub(session_index);
- mutex_unlock(&sync_info->sync_mutex);
-}
-
static int msm_rotator_buf_sync(unsigned long arg)
{
struct msm_rotator_buf_sync buf_sync;
int ret = 0;
struct sync_fence *fence = NULL;
struct rot_sync_info *sync_info;
+ struct sync_pt *rel_sync_pt;
+ struct sync_fence *rel_fence;
+ int rel_fen_fd;
u32 s;
if (copy_from_user(&buf_sync, (void __user *)arg, sizeof(buf_sync)))
return -EFAULT;
+ rot_wait_for_commit_queue(false);
for (s = 0; s < MAX_SESSIONS; s++)
if ((msm_rotator_dev->rot_session[s] != NULL) &&
(buf_sync.session_id ==
@@ -470,6 +513,9 @@
sync_info = &msm_rotator_dev->sync_info[s];
+ if (sync_info->acq_fen)
+ pr_err("%s previous acq_fen will be overwritten", __func__);
+
if ((sync_info->timeline == NULL) ||
(sync_info->initialized == false))
return -EINVAL;
@@ -481,43 +527,45 @@
sync_info->acq_fen = fence;
if (sync_info->acq_fen &&
- (buf_sync.flags & MDP_BUF_SYNC_FLAG_WAIT))
- msm_rotator_wait_for_fence_sub(s);
+ (buf_sync.flags & MDP_BUF_SYNC_FLAG_WAIT)) {
+ msm_rotator_wait_for_fence(sync_info->acq_fen);
+ sync_info->acq_fen = NULL;
+ }
- sync_info->cur_rel_sync_pt = sw_sync_pt_create(sync_info->timeline,
- sync_info->timeline_value + 1);
- if (sync_info->cur_rel_sync_pt == NULL) {
+ rel_sync_pt = sw_sync_pt_create(sync_info->timeline,
+ sync_info->timeline_value +
+ atomic_read(&sync_info->queue_buf_cnt) + 1);
+ if (rel_sync_pt == NULL) {
pr_err("%s: cannot create sync point", __func__);
ret = -ENOMEM;
goto buf_sync_err_1;
}
/* create fence */
- sync_info->cur_rel_fence = sync_fence_create("msm_rotator-fence",
- sync_info->cur_rel_sync_pt);
- if (sync_info->cur_rel_fence == NULL) {
- sync_pt_free(sync_info->cur_rel_sync_pt);
- sync_info->cur_rel_sync_pt = NULL;
+ rel_fence = sync_fence_create("msm_rotator-fence",
+ rel_sync_pt);
+ if (rel_fence == NULL) {
+ sync_pt_free(rel_sync_pt);
pr_err("%s: cannot create fence", __func__);
ret = -ENOMEM;
goto buf_sync_err_1;
}
/* create fd */
- sync_info->cur_rel_fen_fd = get_unused_fd_flags(0);
- if (sync_info->cur_rel_fen_fd < 0) {
+ rel_fen_fd = get_unused_fd_flags(0);
+ if (rel_fen_fd < 0) {
pr_err("%s: get_unused_fd_flags failed", __func__);
ret = -EIO;
goto buf_sync_err_2;
}
- sync_fence_install(sync_info->cur_rel_fence, sync_info->cur_rel_fen_fd);
- buf_sync.rel_fen_fd = sync_info->cur_rel_fen_fd;
+ sync_fence_install(rel_fence, rel_fen_fd);
+ buf_sync.rel_fen_fd = rel_fen_fd;
+ sync_info->rel_fen = rel_fence;
+ sync_info->rel_fen_fd = rel_fen_fd;
ret = copy_to_user((void __user *)arg, &buf_sync, sizeof(buf_sync));
mutex_unlock(&sync_info->sync_mutex);
return ret;
buf_sync_err_2:
- sync_fence_put(sync_info->cur_rel_fence);
- sync_info->cur_rel_fence = NULL;
- sync_info->cur_rel_fen_fd = 0;
+ sync_fence_put(rel_fence);
buf_sync_err_1:
if (sync_info->acq_fen)
sync_fence_put(sync_info->acq_fen);
@@ -843,13 +891,11 @@
unsigned int in_chroma_paddr,
unsigned int out_chroma_paddr,
unsigned int in_chroma2_paddr,
- unsigned int out_chroma2_paddr)
+ unsigned int out_chroma2_paddr,
+ int fast_yuv_en)
{
uint32_t dst_format;
int is_tile = 0;
- struct msm_rotator_session *rot_ssn =
- container_of(info, struct msm_rotator_session, img_info);
- int fast_yuv_en = rot_ssn->fast_yuv_enable;
switch (info->src.format) {
case MDP_Y_CRCB_H2V2_TILE:
@@ -1250,13 +1296,16 @@
}
#endif
}
-static int msm_rotator_do_rotate(unsigned long arg)
+
+static int msm_rotator_rotate_prepare(
+ struct msm_rotator_data_info *data_info,
+ struct msm_rotator_commit_info *commit_info)
{
- unsigned int status, format;
+ unsigned int format;
struct msm_rotator_data_info info;
unsigned int in_paddr, out_paddr;
unsigned long src_len, dst_len;
- int use_imem = 0, rc = 0, s;
+ int rc = 0, s;
struct file *srcp0_file = NULL, *dstp0_file = NULL;
struct file *srcp1_file = NULL, *dstp1_file = NULL;
struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
@@ -1267,10 +1316,9 @@
struct msm_rotator_img_info *img_info;
struct msm_rotator_mem_planes src_planes, dst_planes;
- if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
- return -EFAULT;
-
mutex_lock(&msm_rotator_dev->rotator_lock);
+ info = *data_info;
+
for (s = 0; s < MAX_SESSIONS; s++)
if ((msm_rotator_dev->rot_session[s] != NULL) &&
(info.session_id ==
@@ -1320,7 +1368,7 @@
if (rc) {
pr_err("%s: in get_img() failed id=0x%08x\n",
DRIVER_NAME, info.src.memory_id);
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
rc = get_img(&info.dst, ROTATOR_DST_DOMAIN, (unsigned long *)&out_paddr,
@@ -1329,7 +1377,7 @@
if (rc) {
pr_err("%s: out get_img() failed id=0x%08x\n",
DRIVER_NAME, info.dst.memory_id);
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
format = img_info->src.format;
@@ -1342,7 +1390,7 @@
pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
__func__, src_len, info.src.offset);
rc = -ERANGE;
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
if (checkoffset(info.dst.offset,
dst_planes.plane_size[0],
@@ -1350,7 +1398,7 @@
pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
__func__, dst_len, info.dst.offset);
rc = -ERANGE;
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
rc = get_img(&info.src_chroma, ROTATOR_SRC_DOMAIN,
@@ -1360,7 +1408,7 @@
if (rc) {
pr_err("%s: in chroma get_img() failed id=0x%08x\n",
DRIVER_NAME, info.src_chroma.memory_id);
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
rc = get_img(&info.dst_chroma, ROTATOR_DST_DOMAIN,
@@ -1370,7 +1418,7 @@
if (rc) {
pr_err("%s: out chroma get_img() failed id=0x%08x\n",
DRIVER_NAME, info.dst_chroma.memory_id);
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
if (checkoffset(info.src_chroma.offset,
@@ -1379,7 +1427,7 @@
pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
__func__, src_len, info.src_chroma.offset);
rc = -ERANGE;
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
if (checkoffset(info.dst_chroma.offset,
@@ -1388,7 +1436,7 @@
pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
__func__, dst_len, info.dst_chroma.offset);
rc = -ERANGE;
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
in_chroma_paddr += info.src_chroma.offset;
@@ -1400,7 +1448,7 @@
pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
__func__, src_len, info.src.offset);
rc = -ERANGE;
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
if (checkoffset(info.dst.offset,
dst_planes.total_size,
@@ -1408,7 +1456,7 @@
pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
__func__, dst_len, info.dst.offset);
rc = -ERANGE;
- goto do_rotate_unlock_mutex;
+ goto rotate_prepare_error;
}
}
@@ -1424,7 +1472,88 @@
if (dst_planes.num_planes >= 3)
out_chroma2_paddr = out_chroma_paddr + dst_planes.plane_size[1];
- msm_rotator_wait_for_fence(s);
+ commit_info->data_info = info;
+ commit_info->img_info = *img_info;
+ commit_info->format = format;
+ commit_info->in_paddr = in_paddr;
+ commit_info->out_paddr = out_paddr;
+ commit_info->in_chroma_paddr = in_chroma_paddr;
+ commit_info->out_chroma_paddr = out_chroma_paddr;
+ commit_info->in_chroma2_paddr = in_chroma2_paddr;
+ commit_info->out_chroma2_paddr = out_chroma2_paddr;
+ commit_info->srcp0_file = srcp0_file;
+ commit_info->srcp1_file = srcp1_file;
+ commit_info->srcp0_ihdl = srcp0_ihdl;
+ commit_info->srcp1_ihdl = srcp1_ihdl;
+ commit_info->dstp0_file = dstp0_file;
+ commit_info->dstp0_ihdl = dstp0_ihdl;
+ commit_info->dstp1_file = dstp1_file;
+ commit_info->dstp1_ihdl = dstp1_ihdl;
+ commit_info->ps0_need = ps0_need;
+ commit_info->session_index = s;
+ commit_info->acq_fen = msm_rotator_dev->sync_info[s].acq_fen;
+ commit_info->fast_yuv_en = mrd->rot_session[s]->fast_yuv_enable;
+ mutex_unlock(&msm_rotator_dev->rotator_lock);
+ return 0;
+
+rotate_prepare_error:
+ put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
+ msm_rotator_dev->rot_session[s]->img_info.secure);
+ put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
+ put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
+ msm_rotator_dev->rot_session[s]->img_info.secure);
+
+ /* only source may use frame buffer */
+ if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
+ fput_light(srcp0_file, ps0_need);
+ else
+ put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
+ dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
+ __func__, rc);
+ mutex_unlock(&msm_rotator_dev->rotator_lock);
+ return rc;
+}
+
+static int msm_rotator_do_rotate_sub(
+ struct msm_rotator_commit_info *commit_info)
+{
+ unsigned int status, format;
+ struct msm_rotator_data_info info;
+ unsigned int in_paddr, out_paddr;
+ int use_imem = 0, rc = 0;
+ struct file *srcp0_file, *dstp0_file;
+ struct file *srcp1_file, *dstp1_file;
+ struct ion_handle *srcp0_ihdl, *dstp0_ihdl;
+ struct ion_handle *srcp1_ihdl, *dstp1_ihdl;
+ int s, ps0_need;
+ unsigned int in_chroma_paddr, out_chroma_paddr;
+ unsigned int in_chroma2_paddr, out_chroma2_paddr;
+ struct msm_rotator_img_info *img_info;
+
+ mutex_lock(&msm_rotator_dev->rotator_lock);
+
+ info = commit_info->data_info;
+ img_info = &commit_info->img_info;
+ format = commit_info->format;
+ in_paddr = commit_info->in_paddr;
+ out_paddr = commit_info->out_paddr;
+ in_chroma_paddr = commit_info->in_chroma_paddr;
+ out_chroma_paddr = commit_info->out_chroma_paddr;
+ in_chroma2_paddr = commit_info->in_chroma2_paddr;
+ out_chroma2_paddr = commit_info->out_chroma2_paddr;
+ srcp0_file = commit_info->srcp0_file;
+ srcp1_file = commit_info->srcp1_file;
+ srcp0_ihdl = commit_info->srcp0_ihdl;
+ srcp1_ihdl = commit_info->srcp1_ihdl;
+ dstp0_file = commit_info->dstp0_file;
+ dstp0_ihdl = commit_info->dstp0_ihdl;
+ dstp1_file = commit_info->dstp1_file;
+ dstp1_ihdl = commit_info->dstp1_ihdl;
+ ps0_need = commit_info->ps0_need;
+ s = commit_info->session_index;
+
+ msm_rotator_wait_for_fence(commit_info->acq_fen);
+ commit_info->acq_fen = NULL;
cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
if (msm_rotator_dev->rot_clk_state != CLK_EN) {
@@ -1490,7 +1619,8 @@
in_chroma_paddr,
out_chroma_paddr,
in_chroma2_paddr,
- out_chroma2_paddr);
+ out_chroma2_paddr,
+ commit_info->fast_yuv_en);
break;
case MDP_Y_CBCR_H2V1:
case MDP_Y_CRCB_H2V1:
@@ -1523,9 +1653,10 @@
msm_rotator_dev->processing = 1;
iowrite32(0x1, MSM_ROTATOR_START);
-
+ mutex_unlock(&msm_rotator_dev->rotator_lock);
wait_event(msm_rotator_dev->wq,
(msm_rotator_dev->processing == 0));
+ mutex_lock(&msm_rotator_dev->rotator_lock);
status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
if ((status & 0x03) != 0x01) {
pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
@@ -1541,25 +1672,132 @@
msm_rotator_imem_free(ROTATOR_REQUEST);
#endif
schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
-do_rotate_unlock_mutex:
put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
- msm_rotator_dev->rot_session[s]->img_info.secure);
+ img_info->secure);
put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
- msm_rotator_dev->rot_session[s]->img_info.secure);
+ img_info->secure);
/* only source may use frame buffer */
if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
fput_light(srcp0_file, ps0_need);
else
put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
- msm_rotator_signal_timeline(s);
+ msm_rotator_signal_timeline_done(s);
mutex_unlock(&msm_rotator_dev->rotator_lock);
dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
__func__, rc);
+
return rc;
}
+static void rot_wait_for_commit_queue(u32 is_all)
+{
+ int ret = 0;
+ u32 loop_cnt = 0;
+
+ while (1) {
+ mutex_lock(&mrd->commit_mutex);
+ if (is_all && (atomic_read(&mrd->commit_q_cnt) == 0))
+ break;
+ if ((!is_all) &&
+ (atomic_read(&mrd->commit_q_cnt) < MAX_COMMIT_QUEUE))
+ break;
+ INIT_COMPLETION(mrd->commit_comp);
+ mutex_unlock(&mrd->commit_mutex);
+ ret = wait_for_completion_interruptible_timeout(
+ &mrd->commit_comp,
+ msecs_to_jiffies(WAIT_ROT_TIMEOUT));
+ if ((ret <= 0) ||
+ (atomic_read(&mrd->commit_q_cnt) >= MAX_COMMIT_QUEUE) ||
+ (loop_cnt > MAX_COMMIT_QUEUE)) {
+ pr_err("%s wait for commit queue failed ret=%d pointers:%d %d",
+ __func__, ret, atomic_read(&mrd->commit_q_r),
+ atomic_read(&mrd->commit_q_w));
+ mutex_lock(&mrd->commit_mutex);
+ ret = -ETIME;
+ break;
+ } else {
+ ret = 0;
+ }
+ loop_cnt++;
+ };
+ if (is_all || ret) {
+ atomic_set(&mrd->commit_q_r, 0);
+ atomic_set(&mrd->commit_q_cnt, 0);
+ atomic_set(&mrd->commit_q_w, 0);
+ }
+ mutex_unlock(&mrd->commit_mutex);
+}
+
+static int msm_rotator_do_rotate(unsigned long arg)
+{
+ struct msm_rotator_data_info info;
+ struct rot_sync_info *sync_info;
+ int session_index, ret;
+ int commit_q_w;
+
+ if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
+ return -EFAULT;
+
+ rot_wait_for_commit_queue(false);
+ mutex_lock(&mrd->commit_mutex);
+ commit_q_w = atomic_read(&mrd->commit_q_w);
+ ret = msm_rotator_rotate_prepare(&info,
+ &mrd->commit_info[commit_q_w]);
+ if (ret) {
+ mutex_unlock(&mrd->commit_mutex);
+ return ret;
+ }
+
+ session_index = mrd->commit_info[commit_q_w].session_index;
+ sync_info = &msm_rotator_dev->sync_info[session_index];
+ mutex_lock(&sync_info->sync_mutex);
+ atomic_inc(&sync_info->queue_buf_cnt);
+ sync_info->acq_fen = NULL;
+ mutex_unlock(&sync_info->sync_mutex);
+
+ if (atomic_inc_return(&mrd->commit_q_w) >= MAX_COMMIT_QUEUE)
+ atomic_set(&mrd->commit_q_w, 0);
+ atomic_inc(&mrd->commit_q_cnt);
+
+ schedule_work(&mrd->commit_work);
+ mutex_unlock(&mrd->commit_mutex);
+
+ if (info.wait_for_finish)
+ rot_wait_for_commit_queue(true);
+
+ return 0;
+}
+
+static void rot_commit_wq_handler(struct work_struct *work)
+{
+ mutex_lock(&mrd->commit_wq_mutex);
+ mutex_lock(&mrd->commit_mutex);
+ while (atomic_read(&mrd->commit_q_cnt) > 0) {
+ mrd->commit_running = true;
+ mutex_unlock(&mrd->commit_mutex);
+ msm_rotator_do_rotate_sub(
+ &mrd->commit_info[atomic_read(&mrd->commit_q_r)]);
+ mutex_lock(&mrd->commit_mutex);
+ if (atomic_read(&mrd->commit_q_cnt) > 0) {
+ atomic_dec(&mrd->commit_q_cnt);
+ if (atomic_inc_return(&mrd->commit_q_r) >=
+ MAX_COMMIT_QUEUE)
+ atomic_set(&mrd->commit_q_r, 0);
+ }
+ complete_all(&mrd->commit_comp);
+ }
+ mrd->commit_running = false;
+ if (atomic_read(&mrd->commit_q_r) != atomic_read(&mrd->commit_q_w))
+ pr_err("%s invalid state: r=%d w=%d cnt=%d", __func__,
+ atomic_read(&mrd->commit_q_r),
+ atomic_read(&mrd->commit_q_w),
+ atomic_read(&mrd->commit_q_cnt));
+ mutex_unlock(&mrd->commit_mutex);
+ mutex_unlock(&mrd->commit_wq_mutex);
+}
+
static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
{
u32 perf_level;
@@ -1846,6 +2084,7 @@
sync_info->initialized = true;
}
sync_info->acq_fen = NULL;
+ atomic_set(&sync_info->queue_buf_cnt, 0);
rotator_start_exit:
mutex_unlock(&msm_rotator_dev->rotator_lock);
@@ -1944,7 +2183,6 @@
fd_info = (struct msm_rotator_fd_info *)filp->private_data;
mutex_lock(&msm_rotator_dev->rotator_lock);
- msm_rotator_release_all_timeline();
if (--fd_info->ref_cnt > 0) {
mutex_unlock(&msm_rotator_dev->rotator_lock);
return 0;
@@ -1956,6 +2194,8 @@
pr_debug("%s: freeing rotator session %p (pid %d)\n",
__func__, msm_rotator_dev->rot_session[s],
fd_info->pid);
+ rot_wait_for_commit_queue(true);
+ msm_rotator_signal_timeline(s);
kfree(msm_rotator_dev->rot_session[s]);
msm_rotator_dev->rot_session[s] = NULL;
if (msm_rotator_dev->last_session_idx == s)
@@ -2202,6 +2442,13 @@
}
init_waitqueue_head(&msm_rotator_dev->wq);
+ INIT_WORK(&msm_rotator_dev->commit_work, rot_commit_wq_handler);
+ init_completion(&msm_rotator_dev->commit_comp);
+ mutex_init(&msm_rotator_dev->commit_mutex);
+ mutex_init(&msm_rotator_dev->commit_wq_mutex);
+ atomic_set(&msm_rotator_dev->commit_q_w, 0);
+ atomic_set(&msm_rotator_dev->commit_q_r, 0);
+ atomic_set(&msm_rotator_dev->commit_q_cnt, 0);
dev_dbg(msm_rotator_dev->device, "probe successful\n");
return rc;
@@ -2234,6 +2481,7 @@
{
int i;
+ rot_wait_for_commit_queue(true);
#ifdef CONFIG_MSM_BUS_SCALING
if (msm_rotator_dev->bus_client_handle) {
msm_bus_scale_unregister_client
@@ -2273,6 +2521,7 @@
#ifdef CONFIG_PM
static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
{
+ rot_wait_for_commit_queue(true);
mutex_lock(&msm_rotator_dev->imem_lock);
if (msm_rotator_dev->imem_clk_state == CLK_EN
&& msm_rotator_dev->imem_clk) {
diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h
index 6f85d91..6a8d286 100644
--- a/include/linux/msm_rotator.h
+++ b/include/linux/msm_rotator.h
@@ -50,6 +50,7 @@
unsigned int version_key;
struct msmfb_data src_chroma;
struct msmfb_data dst_chroma;
+ uint32_t wait_for_finish;
};
struct msm_rot_clocks {