Short summary of fixes pull:
dumb-buffer: - remove strict limits on buffer geometry ethosu: - reject unsupported NPU_OP_RESIZE - fix index of IFM region - fix weight index - fix overflows in DMA-size calculations - reject DMA commands with uninitialized length - fix OOB write in ethosu_gem_cmdstream_copy_and_validate imx: - fix kernel-doc warnings ivpu: - add overflow checks in firmware handling and get_info_ioctl v3d: - wait for pending L2T flush before cleaning caches - fix leak of vaddr - skip CSD when it has zeroed workgroups - fix ref counting in performance monitoring -----BEGIN PGP SIGNATURE----- iQFPBAABCgA5FiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmoiedAbFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMiwyAAoJEGgNwR1TC3ojlPgH/3dtzYxSDc/66kxFEdYw RUOemMjs+EbT8+NU9k0H4rI3IWur8IzOEBXvlVSGwe4J2RusqWDnKpbJij34VgZq 524oSLk92Me+VmO3L3QE07OaZ233tOKYKV44CZraBcBVAl4NSnnmf2pV3yrddsBQ 8vKJPmSCRMiQprkFYcyQc6YEbix/MVXMLRUxS0lNZzCtH5594Ft2ugD+4VMl1Bkd sMi8dMYQrsv2qsgRJhvZHOjT7E1mJuH6DLEn7jgvx3oO4ONZWb4kJ7clgozsLcZn hLFgtQMh8AR+lJaDshRVj5P+xlzgoGkM7eLEjSTQWv1VQ9EMw4/orOWpm55U9v17 4gY= =lxiE -----END PGP SIGNATURE----- Merge tag 'drm-misc-fixes-2026-06-05' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes Short summary of fixes pull: dumb-buffer: - remove strict limits on buffer geometry ethosu: - reject unsupported NPU_OP_RESIZE - fix index of IFM region - fix weight index - fix overflows in DMA-size calculations - reject DMA commands with uninitialized length - fix OOB write in ethosu_gem_cmdstream_copy_and_validate imx: - fix kernel-doc warnings ivpu: - add overflow checks in firmware handling and get_info_ioctl v3d: - wait for pending L2T flush before cleaning caches - fix leak of vaddr - skip CSD when it has zeroed workgroups - fix ref counting in performance monitoring Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patch.msgid.link/20260605072602.GA268798@linux.fritz.box
This commit is contained in:
commit
f80cbe57ec
9 changed files with 98 additions and 24 deletions
|
|
@ -2,6 +2,7 @@
|
|||
/* Copyright 2025 Arm, Ltd. */
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/ethosu_accel.h>
|
||||
|
|
@ -163,17 +164,30 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
|
|||
s8 mode = dma_st->mode;
|
||||
u64 len = dma->len;
|
||||
|
||||
if (len == U64_MAX)
|
||||
return U64_MAX;
|
||||
|
||||
if (mode >= 1) {
|
||||
if (dma->stride[0] < 0 && (u64)(-dma->stride[0]) > len)
|
||||
return U64_MAX;
|
||||
len += dma->stride[0];
|
||||
len *= dma_st->size0;
|
||||
if (check_mul_overflow(len, (u64)dma_st->size0, &len))
|
||||
return U64_MAX;
|
||||
}
|
||||
if (mode == 2) {
|
||||
if (dma->stride[1] < 0 && (u64)(-dma->stride[1]) > len)
|
||||
return U64_MAX;
|
||||
len += dma->stride[1];
|
||||
len *= dma_st->size1;
|
||||
if (check_mul_overflow(len, (u64)dma_st->size1, &len))
|
||||
return U64_MAX;
|
||||
}
|
||||
if (dma->region >= 0) {
|
||||
u64 end;
|
||||
|
||||
if (check_add_overflow(len, dma->offset, &end))
|
||||
return U64_MAX;
|
||||
info->region_size[dma->region] = max(info->region_size[dma->region], end);
|
||||
}
|
||||
if (dma->region >= 0)
|
||||
info->region_size[dma->region] = max(info->region_size[dma->region],
|
||||
len + dma->offset);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
|
@ -387,6 +401,8 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
return -EFAULT;
|
||||
|
||||
i++;
|
||||
if (i >= size / 4)
|
||||
return -EINVAL;
|
||||
bocmds[i] = cmds[1];
|
||||
addr = cmd_to_addr(cmds);
|
||||
}
|
||||
|
|
@ -395,6 +411,8 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
case NPU_OP_DMA_START:
|
||||
srclen = dma_length(info, &st.dma, &st.dma.src);
|
||||
dstlen = dma_length(info, &st.dma, &st.dma.dst);
|
||||
if (srclen == U64_MAX || dstlen == U64_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (st.dma.dst.region >= 0)
|
||||
info->output_region[st.dma.dst.region] = true;
|
||||
|
|
@ -431,8 +449,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
return ret;
|
||||
break;
|
||||
case NPU_OP_RESIZE: // U85 only
|
||||
WARN_ON(1); // TODO
|
||||
break;
|
||||
return -EINVAL;
|
||||
case NPU_SET_KERNEL_WIDTH_M1:
|
||||
st.ifm.width = param;
|
||||
break;
|
||||
|
|
@ -464,7 +481,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
st.ifm.broadcast = param;
|
||||
break;
|
||||
case NPU_SET_IFM_REGION:
|
||||
st.ifm.region = param & 0x7f;
|
||||
st.ifm.region = param & 0x7;
|
||||
break;
|
||||
case NPU_SET_IFM_WIDTH0_M1:
|
||||
st.ifm.width0 = param;
|
||||
|
|
@ -599,7 +616,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
|
|||
if (ethosu_is_u65(edev))
|
||||
st.scale[1].length = cmds[1];
|
||||
else
|
||||
st.weight[1].length = cmds[1];
|
||||
st.weight[2].length = cmds[1];
|
||||
break;
|
||||
case NPU_SET_WEIGHT3_BASE:
|
||||
st.weight[3].base = addr;
|
||||
|
|
|
|||
|
|
@ -259,6 +259,22 @@ static int ivpu_fw_parse(struct ivpu_device *vdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!PAGE_ALIGNED(runtime_addr)) {
|
||||
ivpu_err(vdev, "Runtime address 0x%llx not page aligned\n", runtime_addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!PAGE_ALIGNED(runtime_size)) {
|
||||
ivpu_err(vdev, "Runtime size %llu not page aligned\n", runtime_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (runtime_size < image_size) {
|
||||
ivpu_err(vdev, "Runtime size too small: %llu, image size: %llu\n",
|
||||
runtime_size, image_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!ivpu_is_within_range(image_load_addr, image_size, &vdev->hw->ranges.runtime)) {
|
||||
ivpu_err(vdev, "Invalid firmware load address: 0x%llx and size %llu\n",
|
||||
image_load_addr, image_size);
|
||||
|
|
|
|||
|
|
@ -98,6 +98,11 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha
|
|||
u32 log_start = only_new_msgs ? READ_ONCE(log->read_index) : 0;
|
||||
u32 log_end = READ_ONCE(log->write_index);
|
||||
|
||||
if (log_start >= data_size)
|
||||
log_start = 0;
|
||||
if (log_end > data_size)
|
||||
log_end = data_size;
|
||||
|
||||
if (log->wrap_count == log->read_wrap_count) {
|
||||
if (log_end <= log_start) {
|
||||
drm_printf(p, "==== %s \"%s\" log empty ====\n", prefix, log->name);
|
||||
|
|
|
|||
|
|
@ -291,6 +291,13 @@ int ivpu_ms_get_info_ioctl(struct drm_device *dev, void *data, struct drm_file *
|
|||
if (ret)
|
||||
goto unlock;
|
||||
|
||||
if (info_size > ivpu_bo_size(bo)) {
|
||||
ivpu_warn_ratelimited(vdev, "MS info overflow: %#llx > %#zx\n",
|
||||
info_size, ivpu_bo_size(bo));
|
||||
ret = -EOVERFLOW;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (args->buffer_size < info_size) {
|
||||
ret = -ENOSPC;
|
||||
goto unlock;
|
||||
|
|
|
|||
|
|
@ -202,13 +202,6 @@ int drm_mode_create_dumb(struct drm_device *dev,
|
|||
if (!args->width || !args->height || !args->bpp)
|
||||
return -EINVAL;
|
||||
|
||||
/* Reject unreasonable inputs early. Dumb buffers are for software
|
||||
* rendering; nothing legitimate needs more than 8192x8192 at 32bpp.
|
||||
* This prevents overflows in downstream alignment helpers.
|
||||
*/
|
||||
if (args->width >= 8192 || args->height >= 8192 || args->bpp > 32)
|
||||
return -EINVAL;
|
||||
|
||||
/* overflow checks for 32bit size calculations */
|
||||
if (args->bpp > U32_MAX - 8)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ static int exp_approx_q(int x)
|
|||
* dcss_scaler_gaussian_filter() - Generate gaussian prototype filter.
|
||||
* @fc_q: fixed-point cutoff frequency normalized to range [0, 1]
|
||||
* @use_5_taps: indicates whether to use 5 taps or 7 taps
|
||||
* @phase0_identity: whether to override phase 0 coefficients with identity filter
|
||||
* @coef: output filter coefficients
|
||||
*/
|
||||
static void dcss_scaler_gaussian_filter(int fc_q, bool use_5_taps,
|
||||
|
|
@ -262,7 +263,9 @@ static void dcss_scaler_nearest_neighbor_filter(bool use_5_taps,
|
|||
* @src_length: length of input
|
||||
* @dst_length: length of output
|
||||
* @use_5_taps: 0 for 7 taps per phase, 1 for 5 taps
|
||||
* @phase0_identity: whether to override phase 0 coefficients with identity filter
|
||||
* @coef: output coefficients
|
||||
* @nn_interpolation: whether to use nearest neighbor instead of gaussian filter
|
||||
*/
|
||||
static void dcss_scaler_filter_design(int src_length, int dst_length,
|
||||
bool use_5_taps, bool phase0_identity,
|
||||
|
|
|
|||
|
|
@ -213,6 +213,14 @@ v3d_clean_caches(struct v3d_dev *v3d)
|
|||
|
||||
trace_v3d_cache_clean_begin(dev);
|
||||
|
||||
/* GFXH-1897: Ensure pending flushes complete before writing L2TCACTL */
|
||||
if (v3d->ver < V3D_GEN_71) {
|
||||
if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
V3D_L2TCACTL_L2TFLS), 100)) {
|
||||
drm_err(dev, "Timeout waiting for L2T clean\n");
|
||||
}
|
||||
}
|
||||
|
||||
V3D_CORE_WRITE(core, V3D_CTL_L2TCACTL, V3D_L2TCACTL_TMUWCF);
|
||||
if (wait_for(!(V3D_CORE_READ(core, V3D_CTL_L2TCACTL) &
|
||||
V3D_L2TCACTL_TMUWCF), 100)) {
|
||||
|
|
|
|||
|
|
@ -309,8 +309,11 @@ static void v3d_perfmon_delete(struct v3d_file_priv *v3d_priv,
|
|||
if (perfmon == v3d->active_perfmon)
|
||||
v3d_perfmon_stop(v3d, perfmon, false);
|
||||
|
||||
/* If the global perfmon is being destroyed, set it to NULL */
|
||||
cmpxchg(&v3d->global_perfmon, perfmon, NULL);
|
||||
/* If the global perfmon is being destroyed, clean it and release
|
||||
* the reference stashed in v3d_perfmon_set_global_ioctl().
|
||||
*/
|
||||
if (cmpxchg(&v3d->global_perfmon, perfmon, NULL) == perfmon)
|
||||
v3d_perfmon_put(perfmon);
|
||||
|
||||
v3d_perfmon_put(perfmon);
|
||||
}
|
||||
|
|
@ -461,16 +464,27 @@ int v3d_perfmon_set_global_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
/* If the request is to clear the global performance monitor */
|
||||
if (req->flags & DRM_V3D_PERFMON_CLEAR_GLOBAL) {
|
||||
if (!v3d->global_perfmon)
|
||||
struct v3d_perfmon *old;
|
||||
|
||||
/* DRM_V3D_PERFMON_CLEAR_GLOBAL doesn't check if
|
||||
* v3d->global_perfmon == perfmon. Therefore, there
|
||||
* is no need to keep perfmon's reference.
|
||||
*/
|
||||
v3d_perfmon_put(perfmon);
|
||||
|
||||
old = xchg(&v3d->global_perfmon, NULL);
|
||||
if (!old)
|
||||
return -EINVAL;
|
||||
|
||||
xchg(&v3d->global_perfmon, NULL);
|
||||
v3d_perfmon_put(old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmpxchg(&v3d->global_perfmon, NULL, perfmon))
|
||||
if (cmpxchg(&v3d->global_perfmon, NULL, perfmon)) {
|
||||
v3d_perfmon_put(perfmon);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,6 +352,16 @@ v3d_csd_job_run(struct drm_sched_job *sched_job)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* The HW interprets a workgroup size of 0 as 65536; however, the
|
||||
* user-space driver exposes a maximum of 65535. Therefore, a 0 in
|
||||
* any dimension means that we have no workgroups and the compute
|
||||
* shader should not be dispatched.
|
||||
*/
|
||||
if (!V3D_GET_FIELD(job->args.cfg[0], V3D_CSD_QUEUED_CFG0_NUM_WGS_X) ||
|
||||
!V3D_GET_FIELD(job->args.cfg[1], V3D_CSD_QUEUED_CFG1_NUM_WGS_Y) ||
|
||||
!V3D_GET_FIELD(job->args.cfg[2], V3D_CSD_QUEUED_CFG2_NUM_WGS_Z))
|
||||
return NULL;
|
||||
|
||||
v3d->queue[V3D_CSD].active_job = &job->base;
|
||||
|
||||
v3d_invalidate_caches(v3d);
|
||||
|
|
@ -402,13 +412,13 @@ v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job)
|
|||
|
||||
wg_counts = (uint32_t *)(bo->vaddr + indirect_csd->offset);
|
||||
|
||||
if (wg_counts[0] == 0 || wg_counts[1] == 0 || wg_counts[2] == 0)
|
||||
return;
|
||||
|
||||
args->cfg[0] = wg_counts[0] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
|
||||
args->cfg[1] = wg_counts[1] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
|
||||
args->cfg[2] = wg_counts[2] << V3D_CSD_CFG012_WG_COUNT_SHIFT;
|
||||
|
||||
if (wg_counts[0] == 0 || wg_counts[1] == 0 || wg_counts[2] == 0)
|
||||
goto unmap_bo;
|
||||
|
||||
num_batches = DIV_ROUND_UP(indirect_csd->wg_size, 16) *
|
||||
(wg_counts[0] * wg_counts[1] * wg_counts[2]);
|
||||
|
||||
|
|
@ -428,6 +438,7 @@ v3d_rewrite_csd_job_wg_counts_from_indirect(struct v3d_cpu_job *job)
|
|||
}
|
||||
}
|
||||
|
||||
unmap_bo:
|
||||
v3d_put_bo_vaddr(indirect);
|
||||
v3d_put_bo_vaddr(bo);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue