Merge tag 'media/v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media fixes from Mauro Carvalho Chehab:
 "Core:
   - add bounded tile-count helpers for HEVC stateless decoders
   - validate AV1 tile counts fits in array size
   - validate HEVC tile counts fits in array size
   - fix memcmp() size in B1 reference list comparison

  mediatek:
   - bound AV1 tile-start copy to fit in array size

  rockchip:
   - reject AV1 frames exceeding the tile size
   - guard VPU981 AV1 divisor and tile buffer

  hantro and rkvdec:
    - bound G2 HEVC tile loops and PPS id to the buffer size

  rppx1:
   - read the raw pattern from the PRE2 acquisition module
   - describe the MAIN_POST white balance gains block"

* tag 'media/v7.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media:
  media: mediatek: vcodec: bound AV1 tile-start copy to the array capacity
  media: verisilicon: rockchip: reject AV1 frames exceeding the tile capacity
  media: verisilicon: rockchip: guard VPU981 AV1 divisor and tile buffer
  media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer capacity
  media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
  media: hevc: add bounded tile-count helpers
  media: v4l2-ctrls: validate AV1 tile counts
  media: v4l2-ctrls: validate HEVC tile counts
  media: v4l2-h264: Fix memcmp() size in B1 reference list comparison
  media: rppx1: bls: read the raw pattern from the PRE2 acquisition module
  media: rppx1: describe the MAIN_POST white balance gains block
This commit is contained in:
Linus Torvalds
2026-09-11 09:49:40 -07:00
11 changed files with 149 additions and 21 deletions
@@ -25,6 +25,7 @@ rppx1_ext_params_blocks_info[] = {
RPPX1_PARAMS_BLOCK_INFO(LSC_PRE2, lsc),
RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE1, awbg),
RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE2, awbg),
RPPX1_PARAMS_BLOCK_INFO(AWBG_POST, awbg),
RPPX1_PARAMS_BLOCK_INFO(CCOR_POST, ccor),
RPPX1_PARAMS_BLOCK_INFO(HIST_PRE1, hist),
RPPX1_PARAMS_BLOCK_INFO(HIST_PRE2, hist),
@@ -70,7 +70,7 @@ rppx1_bls_swap_regs(struct rpp_module *mod, const u32 input[4], u32 output[4])
/* Swap to pattern used in our path, PRE1 or PRE2. */
struct rpp_module *acq = mod == &mod->rpp->pre1.bls ?
&mod->rpp->pre1.acq : &mod->rpp->pre2.bls;
&mod->rpp->pre1.acq : &mod->rpp->pre2.acq;
enum rpp_raw_pattern pattern = acq->info.acq.raw_pattern;
for (unsigned int i = 0; i < 4; ++i)
@@ -1299,11 +1299,12 @@ static void vdec_av1_slice_setup_tile(struct vdec_av1_slice_frame *frame,
tile->uniform_tile_spacing_flag =
BIT_FLAG(ctrl_tile, V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING);
for (i = 0; i < tile->tile_cols + 1; i++)
/* Bound the copy to the mi_col_starts[]/mi_row_starts[] capacity. */
for (i = 0; i < tile->tile_cols + 1 && i < V4L2_AV1_MAX_TILE_COLS + 1; i++)
tile->mi_col_starts[i] =
ALIGN(ctrl_tile->mi_col_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
for (i = 0; i < tile->tile_rows + 1; i++)
for (i = 0; i < tile->tile_rows + 1 && i < V4L2_AV1_MAX_TILE_ROWS + 1; i++)
tile->mi_row_starts[i] =
ALIGN(ctrl_tile->mi_row_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
}
@@ -16,6 +16,7 @@
*/
#include <linux/v4l2-common.h>
#include <media/v4l2-hevc.h>
#include <media/v4l2-mem2mem.h>
#include "rkvdec.h"
@@ -37,15 +38,17 @@ void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
{
const struct v4l2_ctrl_hevc_pps *pps = run->pps;
unsigned int num_cols = v4l2_hevc_pps_num_tile_columns(pps);
unsigned int num_rows = v4l2_hevc_pps_num_tile_rows(pps);
int i;
for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
for (i = 0; i < num_cols; i++)
column_width[i] = ((i + 1) * pic_in_cts_width) /
(pps->num_tile_columns_minus1 + 1) -
(i * pic_in_cts_width) /
(pps->num_tile_columns_minus1 + 1);
for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++)
for (i = 0; i < num_rows; i++)
row_height[i] = ((i + 1) * pic_in_cts_height) /
(pps->num_tile_rows_minus1 + 1) -
(i * pic_in_cts_height) /
@@ -57,17 +60,20 @@ void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size
s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
{
const struct v4l2_ctrl_hevc_pps *pps = run->pps;
unsigned int num_cols = v4l2_hevc_pps_num_tile_columns(pps);
unsigned int num_rows = v4l2_hevc_pps_num_tile_rows(pps);
s32 sum = 0;
int i;
for (i = 0; i < pps->num_tile_columns_minus1; i++) {
/* The last tile entry is written after the loop, so iterate one less. */
for (i = 0; i < num_cols - 1; i++) {
column_width[i] = pps->column_width_minus1[i] + 1;
sum += column_width[i];
}
column_width[i] = pic_in_cts_width - sum;
sum = 0;
for (i = 0; i < pps->num_tile_rows_minus1; i++) {
for (i = 0; i < num_rows - 1; i++) {
row_height[i] = pps->row_height_minus1[i] + 1;
sum += row_height[i];
}
@@ -12,6 +12,7 @@
* Jeffy Chen <jeffy.chen@rock-chips.com>
*/
#include <media/v4l2-hevc.h>
#include <media/v4l2-mem2mem.h>
#include "rkvdec.h"
@@ -135,6 +136,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
* packet unit). so the driver copy SPS/PPS information to the exact PPS
* packet unit for HW accessing.
*/
if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
return;
hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
memset(hw_ps, 0, sizeof(*hw_ps));
@@ -253,9 +256,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
/* Userspace also provide column width and row height for uniform spacing */
for (i = 0; i <= pps->num_tile_columns_minus1; i++)
for (i = 0; i < v4l2_hevc_pps_num_tile_columns(pps); i++)
WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i));
for (i = 0; i <= pps->num_tile_rows_minus1; i++)
for (i = 0; i < v4l2_hevc_pps_num_tile_rows(pps); i++)
WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i));
} else {
WRITE_PPS(DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_y) - 1,
@@ -145,6 +145,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
* packet unit). so the driver copy SPS/PPS information to the exact PPS
* packet unit for HW accessing.
*/
if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
return;
hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
memset(hw_ps, 0, sizeof(*hw_ps));
@@ -5,6 +5,8 @@
* Copyright (C) 2020 Safran Passenger Innovations LLC
*/
#include <media/v4l2-hevc.h>
#include "hantro_hw.h"
#include "hantro_g2_regs.h"
@@ -15,8 +17,8 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
u16 *p = (u16 *)((u8 *)ctx->hevc_dec.tile_sizes.cpu);
unsigned int num_tile_rows = pps->num_tile_rows_minus1 + 1;
unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1;
unsigned int num_tile_rows = v4l2_hevc_pps_num_tile_rows(pps);
unsigned int num_tile_cols = v4l2_hevc_pps_num_tile_columns(pps);
unsigned int pic_width_in_ctbs, pic_height_in_ctbs;
unsigned int max_log2_ctb_size, ctb_size;
bool tiles_enabled, uniform_spacing;
@@ -431,20 +431,39 @@ static int rockchip_vpu981_av1_dec_prepare_run(struct hantro_ctx *ctx)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
const struct v4l2_av1_tile_info *tile_info;
struct v4l2_ctrl *tge;
u32 num_tiles;
ctrls->sequence = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
if (WARN_ON(!ctrls->sequence))
return -EINVAL;
ctrls->tile_group_entry =
hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
if (WARN_ON(!ctrls->tile_group_entry))
tge = v4l2_ctrl_find(&ctx->ctrl_handler,
V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
if (WARN_ON(!tge))
return -EINVAL;
ctrls->tile_group_entry = tge->p_cur.p;
ctrls->frame = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FRAME);
if (WARN_ON(!ctrls->frame))
return -EINVAL;
/*
* rockchip_vpu981_av1_dec_set_tile_info() indexes the tile group
* entry array by tile1 * tile_cols + tile0, so it reads up to
* tile_cols * tile_rows entries, and lays out one descriptor per tile
* in the AV1_MAX_TILES tile_info buffer while programming the real
* tile geometry into the hardware. Reject a frame that claims more
* tiles than userspace submitted, or more than the hardware tile
* buffer holds, so the read stays in bounds and the programmed
* geometry matches the descriptors written.
*/
tile_info = &ctrls->frame->tile_info;
num_tiles = (u32)tile_info->tile_cols * tile_info->tile_rows;
if (num_tiles > tge->elems || num_tiles > AV1_MAX_TILES)
return -EINVAL;
ctrls->film_grain =
hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN);
@@ -578,16 +597,30 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
ctrls->tile_group_entry;
int context_update_y =
tile_info->context_update_tile_id / tile_info->tile_cols;
int context_update_x =
tile_info->context_update_tile_id % tile_info->tile_cols;
int context_update_tile_id =
context_update_x * tile_info->tile_rows + context_update_y;
int context_update_y = 0;
int context_update_x = 0;
int context_update_tile_id = 0;
u8 *dst = av1_dec->tile_info.cpu;
u8 *dst_end = dst + av1_dec->tile_info.size;
struct hantro_dev *vpu = ctx->dev;
int tile0, tile1;
/*
* tile_cols and tile_rows are bounded by the V4L2 control validation
* (V4L2_AV1_MAX_TILE_{COLS,ROWS} and V4L2_AV1_MAX_TILE_COUNT). Guard
* the divisor here, and keep the descriptor writes within the
* AV1_MAX_TILES tile_info buffer below; the register values use the
* unmodified tile geometry.
*/
if (tile_info->tile_cols) {
context_update_y =
tile_info->context_update_tile_id / tile_info->tile_cols;
context_update_x =
tile_info->context_update_tile_id % tile_info->tile_cols;
context_update_tile_id =
context_update_x * tile_info->tile_rows + context_update_y;
}
memset(dst, 0, av1_dec->tile_info.size);
for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
@@ -598,6 +631,10 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
tile_info->height_in_sbs_minus_1[tile1] + 1;
u32 x0 = tile_info->width_in_sbs_minus_1[tile0] + 1;
/* Stop once the tile_info descriptor buffer is full. */
if (dst + 16 > dst_end)
break;
/* tile size in SB units (width,height) */
*dst++ = x0;
*dst++ = 0;
@@ -622,6 +659,8 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
*dst++ = (end >> 16) & 255;
*dst++ = (end >> 24) & 255;
}
if (dst + 16 > dst_end)
break;
}
hantro_reg_write(vpu, &av1_multicore_expect_context_update, !!(context_update_x == 0));
+32
View File
@@ -793,10 +793,30 @@ static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg)
return 0;
}
static int validate_av1_tile_info(struct v4l2_av1_tile_info *t)
{
/*
* tile_cols and tile_rows index the per-tile descriptor arrays and
* bound the tile loops in the stateless AV1 drivers; the product
* bounds the total tile descriptor count.
*/
if (t->tile_cols > V4L2_AV1_MAX_TILE_COLS ||
t->tile_rows > V4L2_AV1_MAX_TILE_ROWS)
return -EINVAL;
if ((u32)t->tile_cols * t->tile_rows > V4L2_AV1_MAX_TILE_COUNT)
return -EINVAL;
return 0;
}
static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f)
{
int ret = 0;
ret = validate_av1_tile_info(&f->tile_info);
if (ret)
return ret;
ret = validate_av1_quantization(&f->quantization);
if (ret)
return ret;
@@ -1253,6 +1273,18 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
p_hevc_pps->flags &=
~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
} else {
/*
* These count the entries the stateless HEVC drivers
* read from column_width_minus1[] / row_height_minus1[]
* and use as tile-loop bounds.
*/
if (p_hevc_pps->num_tile_columns_minus1 >=
ARRAY_SIZE(p_hevc_pps->column_width_minus1))
return -EINVAL;
if (p_hevc_pps->num_tile_rows_minus1 >=
ARRAY_SIZE(p_hevc_pps->row_height_minus1))
return -EINVAL;
}
if (p_hevc_pps->flags &
+2 -1
View File
@@ -440,7 +440,8 @@ v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
}
if (builder->num_valid > 1 &&
!memcmp(b1_reflist, b0_reflist, builder->num_valid))
!memcmp(b1_reflist, b0_reflist,
sizeof(b1_reflist[0]) * builder->num_valid))
swap(b1_reflist[0], b1_reflist[1]);
print_ref_list_b(builder, b0_reflist, 0);
+41
View File
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Helper functions for HEVC stateless codecs.
*/
#ifndef _MEDIA_V4L2_HEVC_H
#define _MEDIA_V4L2_HEVC_H
#include <linux/minmax.h>
#include <media/v4l2-ctrls.h>
/**
* v4l2_hevc_pps_num_tile_columns - number of HEVC tile columns, bounded
* @pps: the V4L2 HEVC PPS control
*
* Return the number of tile columns (num_tile_columns_minus1 + 1) clamped to
* the capacity of column_width_minus1[]. The control validation already
* rejects out-of-range counts; this keeps the consuming drivers bounded too.
*/
static inline unsigned int
v4l2_hevc_pps_num_tile_columns(const struct v4l2_ctrl_hevc_pps *pps)
{
return min_t(unsigned int, pps->num_tile_columns_minus1 + 1,
ARRAY_SIZE(pps->column_width_minus1));
}
/**
* v4l2_hevc_pps_num_tile_rows - number of HEVC tile rows, bounded
* @pps: the V4L2 HEVC PPS control
*
* Return the number of tile rows (num_tile_rows_minus1 + 1) clamped to the
* capacity of row_height_minus1[].
*/
static inline unsigned int
v4l2_hevc_pps_num_tile_rows(const struct v4l2_ctrl_hevc_pps *pps)
{
return min_t(unsigned int, pps->num_tile_rows_minus1 + 1,
ARRAY_SIZE(pps->row_height_minus1));
}
#endif /* _MEDIA_V4L2_HEVC_H */