On Thu May 21 00:44:22 2026 +0200, Sven Püschel wrote:
> Check the scaling factor to avoid potential problems. This is relevant
> for the upcoming RGA3 support, as it can hang when the scaling factor
> is exceeded.
> 
> The check is done at streamon when the other side is already streaming
> to avoid incorrectly failing if the application configures the other
> side after calling streamon. As try_fmt shouldn't be state aware,
> it cannot be used to limit the format based on the scaling factor.
> Therefore the check is done just before the actual streaming would be
> started.
> 
> As the driver allows changing the rotation and selection while
> streaming, add additional checks to ensure these changes
> don't exceed the scaling factor.
> 
> Signed-off-by: Sven Püschel <[email protected]>
> Reviewed-by: Nicolas Dufresne <[email protected]>
> Signed-off-by: Nicolas Dufresne <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/platform/rockchip/rga/rga-buf.c | 28 ++++++++++++
 drivers/media/platform/rockchip/rga/rga-hw.c  |  1 +
 drivers/media/platform/rockchip/rga/rga-hw.h  |  1 +
 drivers/media/platform/rockchip/rga/rga.c     | 63 +++++++++++++++++++++++++--
 drivers/media/platform/rockchip/rga/rga.h     |  4 ++
 5 files changed, 94 insertions(+), 3 deletions(-)

---

diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c 
b/drivers/media/platform/rockchip/rga/rga-buf.c
index ffc6162b2e68..dcaba66f5c1f 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -197,6 +197,33 @@ static void rga_buf_return_buffers(struct vb2_queue *q,
        }
 }
 
+static int rga_buf_prepare_streaming(struct vb2_queue *q)
+{
+       struct rga_ctx *ctx = vb2_get_drv_priv(q);
+       const struct rga_hw *hw = ctx->rga->hw;
+       int ret;
+
+       /* It's safe to check the streaming state of the other queue,
+        * as the streamon ioctl's can't race due to the lock set in
+        * the queue_init function.
+        */
+       if ((V4L2_TYPE_IS_OUTPUT(q->type) &&
+            vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx))) ||
+           (V4L2_TYPE_IS_CAPTURE(q->type) &&
+            vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)))) {
+               /*
+                * As the other side is already streaming,
+                * check that the max scaling factor isn't exceeded.
+                */
+               ret = rga_check_scaling(hw, &ctx->in.crop, &ctx->out.crop,
+                                       ctx->rotate);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
 {
        struct rga_ctx *ctx = vb2_get_drv_priv(q);
@@ -232,6 +259,7 @@ const struct vb2_ops rga_qops = {
        .buf_prepare = rga_buf_prepare,
        .buf_queue = rga_buf_queue,
        .buf_cleanup = rga_buf_cleanup,
+       .prepare_streaming = rga_buf_prepare_streaming,
        .start_streaming = rga_buf_start_streaming,
        .stop_streaming = rga_buf_stop_streaming,
 };
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c 
b/drivers/media/platform/rockchip/rga/rga-hw.c
index 567d39e58d33..f2900812ba76 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.c
+++ b/drivers/media/platform/rockchip/rga/rga-hw.c
@@ -584,6 +584,7 @@ const struct rga_hw rga2_hw = {
        .max_width = MAX_WIDTH,
        .min_height = MIN_HEIGHT,
        .max_height = MAX_HEIGHT,
+       .max_scaling_factor = MAX_SCALING_FACTOR,
        .stride_alignment = 4,
 
        .setup_cmdbuf = rga_hw_setup_cmdbuf,
diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h 
b/drivers/media/platform/rockchip/rga/rga-hw.h
index c2e34be75193..805ec23e5e3f 100644
--- a/drivers/media/platform/rockchip/rga/rga-hw.h
+++ b/drivers/media/platform/rockchip/rga/rga-hw.h
@@ -14,6 +14,7 @@
 
 #define MIN_WIDTH 34
 #define MIN_HEIGHT 34
+#define MAX_SCALING_FACTOR 16
 
 #define RGA_TIMEOUT 500
 
diff --git a/drivers/media/platform/rockchip/rga/rga.c 
b/drivers/media/platform/rockchip/rga/rga.c
index 394b14b9469d..22954bbae55f 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -127,7 +127,9 @@ static int rga_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct rga_ctx *ctx = container_of(ctrl->handler, struct rga_ctx,
                                           ctrl_handler);
+       const struct rga_hw *hw = ctx->rga->hw;
        unsigned long flags;
+       int ret = 0;
 
        spin_lock_irqsave(&ctx->rga->ctrl_lock, flags);
        switch (ctrl->id) {
@@ -138,6 +140,13 @@ static int rga_s_ctrl(struct v4l2_ctrl *ctrl)
                ctx->vflip = ctrl->val;
                break;
        case V4L2_CID_ROTATE:
+               if (vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)) &&
+                   vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx))) {
+                       ret = rga_check_scaling(hw, &ctx->in.crop,
+                                               &ctx->out.crop, ctrl->val);
+                       if (ret < 0)
+                               goto s_ctrl_done;
+               }
                ctx->rotate = ctrl->val;
                break;
        case V4L2_CID_BG_COLOR:
@@ -145,8 +154,10 @@ static int rga_s_ctrl(struct v4l2_ctrl *ctrl)
                break;
        }
        ctx->cmdbuf_dirty = true;
+
+s_ctrl_done:
        spin_unlock_irqrestore(&ctx->rga->ctrl_lock, flags);
-       return 0;
+       return ret;
 }
 
 static const struct v4l2_ctrl_ops rga_ctrl_ops = {
@@ -182,6 +193,38 @@ static int rga_setup_ctrls(struct rga_ctx *ctx)
        return 0;
 }
 
+static bool check_scaling_factor(const struct rga_hw *hw, u32 src_size,
+                                u32 dst_size)
+{
+       if (src_size < dst_size)
+               return src_size * hw->max_scaling_factor >= dst_size;
+       else
+               return dst_size * hw->max_scaling_factor >= src_size;
+}
+
+int rga_check_scaling(const struct rga_hw *hw, const struct v4l2_rect *crop_in,
+                     const struct v4l2_rect *crop_out, u32 rotate)
+{
+       u32 scaled_width;
+       u32 scaled_height;
+
+       if (rotate == 90 || rotate == 270) {
+               scaled_width = crop_out->height;
+               scaled_height = crop_out->width;
+       } else {
+               scaled_width = crop_out->width;
+               scaled_height = crop_out->height;
+       }
+
+       if (!check_scaling_factor(hw, crop_in->width, scaled_width))
+               return -EINVAL;
+
+       if (!check_scaling_factor(hw, crop_in->height, scaled_height))
+               return -EINVAL;
+
+       return 0;
+}
+
 static struct rga_fmt *rga_fmt_find(struct rockchip_rga *rga, u32 pixelformat)
 {
        unsigned int i;
@@ -525,7 +568,6 @@ static int vidioc_s_selection(struct file *file, void *priv,
        struct rga_ctx *ctx = file_to_rga_ctx(file);
        struct rockchip_rga *rga = ctx->rga;
        struct rga_frame *f;
-       int ret = 0;
 
        f = rga_get_frame(ctx, s->type);
        if (IS_ERR(f))
@@ -569,10 +611,25 @@ static int vidioc_s_selection(struct file *file, void 
*priv,
                return -EINVAL;
        }
 
+       if (vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)) &&
+           vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx))) {
+               int ret = 0;
+
+               if (V4L2_TYPE_IS_OUTPUT(s->type))
+                       ret = rga_check_scaling(rga->hw, &s->r, &ctx->out.crop,
+                                               ctx->rotate);
+               else
+                       ret = rga_check_scaling(rga->hw, &ctx->in.crop, &s->r,
+                                               ctx->rotate);
+
+               if (ret < 0)
+                       return ret;
+       }
+
        f->crop = s->r;
        ctx->cmdbuf_dirty = true;
 
-       return ret;
+       return 0;
 }
 
 static const struct v4l2_ioctl_ops rga_ioctl_ops = {
diff --git a/drivers/media/platform/rockchip/rga/rga.h 
b/drivers/media/platform/rockchip/rga/rga.h
index 5360f092fecf..df525c6aea8b 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -123,6 +123,9 @@ static inline struct rga_vb_buffer *vb_to_rga(struct 
vb2_v4l2_buffer *vb)
 
 struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type);
 
+int rga_check_scaling(const struct rga_hw *hw, const struct v4l2_rect *crop_in,
+                     const struct v4l2_rect *crop_out, u32 rotate);
+
 /* RGA Buffers Manage */
 extern const struct vb2_ops rga_qops;
 
@@ -151,6 +154,7 @@ struct rga_hw {
        size_t cmdbuf_size;
        u32 min_width, min_height;
        u32 max_width, max_height;
+       u8 max_scaling_factor;
        u8 stride_alignment;
 
        void (*setup_cmdbuf)(struct rga_ctx *ctx);
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to