Commit 4ecbf5d1 authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab

[media] s5p-fimc: Prevent hanging on device close and fix the locking

Rework the locking in m2m driver to assure proper operation on SMP systems.

When job_abort or stop_streaming was called to immediately shutdown
a memory-to-memory transaction video buffers scheduled for processing
were never returned to vb2 and v4l2_m2m_job_finish was not called
which led to hanging.

Correct this and also return the unprocessed buffers to vb2 marking
them as erroneous, in case the end of frame interrupt do not occur.
Reported-by: default avatarSewoon Park <seuni.park@samsung.com>
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a0f8caef
......@@ -252,14 +252,9 @@ static int stop_streaming(struct vb2_queue *q)
{
struct fimc_ctx *ctx = q->drv_priv;
struct fimc_dev *fimc = ctx->fimc_dev;
unsigned long flags;
spin_lock_irqsave(&fimc->slock, flags);
if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) {
spin_unlock_irqrestore(&fimc->slock, flags);
if (!fimc_capture_active(fimc))
return -EINVAL;
}
spin_unlock_irqrestore(&fimc->slock, flags);
return fimc_stop_capture(fimc);
}
......@@ -773,7 +768,7 @@ static int fimc_cap_s_crop(struct file *file, void *fh,
ctx->d_frame.width, ctx->d_frame.height,
ctx->rotation);
if (ret) {
v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range\n");
return ret;
}
......
This diff is collapsed.
......@@ -14,6 +14,7 @@
/*#define DEBUG*/
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <linux/io.h>
......@@ -57,7 +58,6 @@ enum fimc_dev_flags {
ST_IDLE,
ST_OUTDMA_RUN,
ST_M2M_PEND,
ST_M2M_SHUT,
/* for capture node */
ST_CAPT_PEND,
ST_CAPT_RUN,
......@@ -71,13 +71,6 @@ enum fimc_dev_flags {
#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
#define fimc_capture_active(dev) \
(test_bit(ST_CAPT_RUN, &(dev)->state) || \
test_bit(ST_CAPT_PEND, &(dev)->state))
#define fimc_capture_streaming(dev) \
test_bit(ST_CAPT_STREAM, &(dev)->state)
enum fimc_datapath {
FIMC_CAMERA,
FIMC_DMA,
......@@ -119,6 +112,7 @@ enum fimc_color_fmt {
#define FIMC_DST_FMT (1 << 4)
#define FIMC_CTX_M2M (1 << 5)
#define FIMC_CTX_CAP (1 << 6)
#define FIMC_CTX_SHUT (1 << 7)
/* Image conversion flags */
#define FIMC_IN_DMA_ACCESS_TILED (1 << 0)
......@@ -476,6 +470,38 @@ struct fimc_ctx {
struct v4l2_m2m_ctx *m2m_ctx;
};
static inline bool fimc_capture_active(struct fimc_dev *fimc)
{
unsigned long flags;
bool ret;
spin_lock_irqsave(&fimc->slock, flags);
ret = !!(fimc->state & (1 << ST_CAPT_RUN) ||
fimc->state & (1 << ST_CAPT_PEND));
spin_unlock_irqrestore(&fimc->slock, flags);
return ret;
}
static inline void fimc_ctx_state_lock_set(u32 state, struct fimc_ctx *ctx)
{
unsigned long flags;
spin_lock_irqsave(&ctx->slock, flags);
ctx->state |= state;
spin_unlock_irqrestore(&ctx->slock, flags);
}
static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx)
{
unsigned long flags;
bool ret;
spin_lock_irqsave(&ctx->slock, flags);
ret = (ctx->state & mask) == mask;
spin_unlock_irqrestore(&ctx->slock, flags);
return ret;
}
static inline int tiled_fmt(struct fimc_fmt *fmt)
{
return fmt->fourcc == V4L2_PIX_FMT_NV12MT;
......@@ -535,7 +561,7 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
struct fimc_frame *frame;
if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) {
if (ctx->state & FIMC_CTX_M2M)
if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx))
frame = &ctx->s_frame;
else
return ERR_PTR(-EINVAL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment