* [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation
@ 2026-07-20 23:14 Rob Herring (Arm)
2026-07-20 23:14 ` [PATCH 2/2] accel: ethosu: Handle U85 internal chaining buffer Rob Herring (Arm)
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Rob Herring (Arm) @ 2026-07-20 23:14 UTC (permalink / raw)
To: Tomeu Vizoso, Oded Gabbay, Thomas Zimmermann, Frank Li
Cc: dri-devel, linux-kernel
There are 2 issues with the element size handling in the command stream
validation which result in too small of a size calculated when the
element size is 16/32/64 bits.
For NHWC format, the element size is simply missing from the
calculation.
The bitfield for the element size is different between IFM/IFM2 and
OFM. IFM and IFM2 encode the precision in parameter bits 2:3, while OFM
uses bits 1:2.
Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver")
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
---
drivers/accel/ethosu/ethosu_gem.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/accel/ethosu/ethosu_gem.c b/drivers/accel/ethosu/ethosu_gem.c
index 3401883e207f..1daff32610c7 100644
--- a/drivers/accel/ethosu/ethosu_gem.c
+++ b/drivers/accel/ethosu/ethosu_gem.c
@@ -194,7 +194,7 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
struct feat_matrix *fm,
- u32 x, u32 y, u32 c)
+ u32 x, u32 y, u32 c, bool ofm)
{
u32 element_size, storage = fm->precision >> 14;
int tile = 0;
@@ -231,10 +231,11 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
switch ((fm->precision >> 6) & 0x3) { // format
case 0: //nhwc:
- addr += x * fm->stride_x + c;
+ element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
+ addr += x * fm->stride_x + c * element_size;
break;
case 1: //nhcwb16:
- element_size = BIT((fm->precision >> 1) & 0x3);
+ element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
addr += (c / 16) * fm->stride_c + (16 * x + (c & 0xf)) * element_size;
break;
@@ -268,7 +269,7 @@ static int calc_sizes(struct drm_device *ddev,
return -EINVAL;
len = feat_matrix_length(info, &st->ifm, ifm_width,
- ifm_height, st->ifm.depth);
+ ifm_height, st->ifm.depth, false);
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
op, st->ifm.region, st->ifm.base[0], len);
if (len == U64_MAX)
@@ -277,7 +278,7 @@ static int calc_sizes(struct drm_device *ddev,
if (ifm2) {
len = feat_matrix_length(info, &st->ifm2, st->ifm.depth,
- 0, st->ofm.depth);
+ 0, st->ofm.depth, false);
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
op, st->ifm2.region, st->ifm2.base[0], len);
if (len == U64_MAX)
@@ -309,7 +310,7 @@ static int calc_sizes(struct drm_device *ddev,
}
len = feat_matrix_length(info, &st->ofm, st->ofm.width,
- st->ofm.height[2], st->ofm.depth);
+ st->ofm.height[2], st->ofm.depth, true);
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
op, st->ofm.region, st->ofm.base[0], len);
if (len == U64_MAX)
@@ -333,7 +334,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
depth = st->ifm.broadcast & 0x4 ? 0 : st->ofm.depth;
len = feat_matrix_length(info, &st->ifm, width,
- height, depth);
+ height, depth, false);
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
op, st->ifm.region, st->ifm.base[0], len);
if (len == U64_MAX)
@@ -346,7 +347,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
depth = st->ifm2.broadcast & 0x4 ? 0 : st->ofm.depth;
len = feat_matrix_length(info, &st->ifm2, width,
- height, depth);
+ height, depth, false);
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
op, st->ifm2.region, st->ifm2.base[0], len);
if (len == U64_MAX)
@@ -354,7 +355,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
}
len = feat_matrix_length(info, &st->ofm, st->ofm.width,
- st->ofm.height[2], st->ofm.depth);
+ st->ofm.height[2], st->ofm.depth, true);
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
op, st->ofm.region, st->ofm.base[0], len);
if (len == U64_MAX)
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/2] accel: ethosu: Handle U85 internal chaining buffer
2026-07-20 23:14 [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation Rob Herring (Arm)
@ 2026-07-20 23:14 ` Rob Herring (Arm)
2026-07-21 16:49 ` Tomeu Vizoso
2026-07-20 23:34 ` [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation sashiko-bot
2026-07-21 16:50 ` Tomeu Vizoso
2 siblings, 1 reply; 5+ messages in thread
From: Rob Herring (Arm) @ 2026-07-20 23:14 UTC (permalink / raw)
To: Tomeu Vizoso, Oded Gabbay, Thomas Zimmermann, Frank Li
Cc: dri-devel, linux-kernel
The Ethos-U85 supports an internal chaining buffer as temporary storage
between some operations. When chaining is activated, the IFM/OFM region
setting selects a chaining buffer rather than a region, and the IFM/OFM
base addresses don't matter. In this case, the feature matrix size
calculations should be skipped. Otherwise, the command stream will be
intermittently rejected depending on prior feature matrix base
addresses.
Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver")
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
---
drivers/accel/ethosu/ethosu_gem.c | 35 +++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/accel/ethosu/ethosu_gem.c b/drivers/accel/ethosu/ethosu_gem.c
index 1daff32610c7..d50fed64d4d9 100644
--- a/drivers/accel/ethosu/ethosu_gem.c
+++ b/drivers/accel/ethosu/ethosu_gem.c
@@ -192,7 +192,15 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
return len;
}
-static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
+static bool feat_matrix_chained(struct ethosu_device *edev, struct feat_matrix *fm)
+{
+ u32 storage = fm->precision >> 14;
+
+ return !ethosu_is_u65(edev) && storage == 2;
+}
+
+static u64 feat_matrix_length(struct ethosu_device *edev,
+ struct ethosu_validated_cmdstream_info *info,
struct feat_matrix *fm,
u32 x, u32 y, u32 c, bool ofm)
{
@@ -203,6 +211,9 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
if (fm->region < 0)
return U64_MAX;
+ if (feat_matrix_chained(edev, fm))
+ return 0;
+
switch (storage) {
case 0:
if (x >= fm->width0 + 1) {
@@ -223,6 +234,8 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
tile = 1;
}
break;
+ default:
+ return U64_MAX;
}
if (fm->base[tile] == U64_MAX)
return U64_MAX;
@@ -251,6 +264,7 @@ static int calc_sizes(struct drm_device *ddev,
u16 op, struct cmd_state *st,
bool ifm, bool ifm2, bool weight, bool scale)
{
+ struct ethosu_device *edev = to_ethosu_device(ddev);
u64 len;
if (ifm) {
@@ -268,7 +282,7 @@ static int calc_sizes(struct drm_device *ddev,
if (ifm_height < 0 || ifm_width < 0)
return -EINVAL;
- len = feat_matrix_length(info, &st->ifm, ifm_width,
+ len = feat_matrix_length(edev, info, &st->ifm, ifm_width,
ifm_height, st->ifm.depth, false);
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
op, st->ifm.region, st->ifm.base[0], len);
@@ -277,7 +291,7 @@ static int calc_sizes(struct drm_device *ddev,
}
if (ifm2) {
- len = feat_matrix_length(info, &st->ifm2, st->ifm.depth,
+ len = feat_matrix_length(edev, info, &st->ifm2, st->ifm.depth,
0, st->ofm.depth, false);
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
op, st->ifm2.region, st->ifm2.base[0], len);
@@ -309,13 +323,14 @@ static int calc_sizes(struct drm_device *ddev,
st->scale[0].base + st->scale[0].length);
}
- len = feat_matrix_length(info, &st->ofm, st->ofm.width,
+ len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
st->ofm.height[2], st->ofm.depth, true);
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
op, st->ofm.region, st->ofm.base[0], len);
if (len == U64_MAX)
return -EINVAL;
- info->output_region[st->ofm.region] = true;
+ if (!feat_matrix_chained(edev, &st->ofm))
+ info->output_region[st->ofm.region] = true;
return 0;
}
@@ -325,6 +340,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
u16 op, struct cmd_state *st,
bool ifm, bool ifm2)
{
+ struct ethosu_device *edev = to_ethosu_device(ddev);
u32 height, width, depth;
u64 len;
@@ -333,7 +349,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
width = st->ifm.broadcast & 0x2 ? 0 : st->ofm.width;
depth = st->ifm.broadcast & 0x4 ? 0 : st->ofm.depth;
- len = feat_matrix_length(info, &st->ifm, width,
+ len = feat_matrix_length(edev, info, &st->ifm, width,
height, depth, false);
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
op, st->ifm.region, st->ifm.base[0], len);
@@ -346,7 +362,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
width = st->ifm2.broadcast & 0x2 ? 0 : st->ofm.width;
depth = st->ifm2.broadcast & 0x4 ? 0 : st->ofm.depth;
- len = feat_matrix_length(info, &st->ifm2, width,
+ len = feat_matrix_length(edev, info, &st->ifm2, width,
height, depth, false);
dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
op, st->ifm2.region, st->ifm2.base[0], len);
@@ -354,13 +370,14 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
return -EINVAL;
}
- len = feat_matrix_length(info, &st->ofm, st->ofm.width,
+ len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
st->ofm.height[2], st->ofm.depth, true);
dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
op, st->ofm.region, st->ofm.base[0], len);
if (len == U64_MAX)
return -EINVAL;
- info->output_region[st->ofm.region] = true;
+ if (!feat_matrix_chained(edev, &st->ofm))
+ info->output_region[st->ofm.region] = true;
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation
2026-07-20 23:14 [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation Rob Herring (Arm)
2026-07-20 23:14 ` [PATCH 2/2] accel: ethosu: Handle U85 internal chaining buffer Rob Herring (Arm)
@ 2026-07-20 23:34 ` sashiko-bot
2026-07-21 16:50 ` Tomeu Vizoso
2 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-07-20 23:34 UTC (permalink / raw)
To: Rob Herring (Arm); +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [Critical] The command stream validation silently ignores unsupported/unknown formats (values 2 and 3), under-calculating the required buffer size and allowing out-of-bounds memory accesses.
- [Critical] Buffer bounds validation incorrectly evaluates the memory footprint only at the maximum dimension indices, missing active tiles and failing on negative strides or overflows.
--
--- Patch [1]: [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation ---
commit 295d16016ba05ed08c0ba3586bc6d83af9ebb17a
Author: Rob Herring (Arm) <robh@kernel.org>
accel: ethosu: Fix element size accounting for cmd stream validation
There are 2 issues with the element size handling in the command stream
validation which result in too small of a size calculated when the
element size is 16/32/64 bits.
For NHWC format, the element size is simply missing from the
calculation.
> diff --git a/drivers/accel/ethosu/ethosu_gem.c b/drivers/accel/ethosu/ethosu_gem.c
> index 3401883e207fc..1daff32610c71 100644
> --- a/drivers/accel/ethosu/ethosu_gem.c
> +++ b/drivers/accel/ethosu/ethosu_gem.c
> @@ -194,7 +194,7 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
[Severity: Critical]
This is a pre-existing issue, but does the buffer bounds validation in
feat_matrix_length() correctly evaluate the memory footprint for all tiles
and negative strides?
Looking at the calculation earlier in the function:
switch (storage) {
case 0:
if (x >= fm->width0 + 1) {
x -= fm->width0 + 1;
tile += 1;
}
if (y >= fm->height[tile] + 1) {
y -= fm->height[tile] + 1;
tile += 2;
}
break;
case 1:
if (y >= fm->height[1] + 1) {
y -= fm->height[1] + 1;
tile = 2;
} else if (y >= fm->height[0] + 1) {
y -= fm->height[0] + 1;
tile = 1;
}
break;
By evaluating the maximum memory requirement only at the maximum y dimension,
the driver seems to fail validating accesses at y=0, which would result in a
higher address if stride_y is negative.
Additionally, when a tensor spans multiple tiles (e.g. tile = 2), the
validation logic checks only the last tile, entirely skipping bounds checks
for the earlier tiles. Could a userspace process bypass validation by
setting these unchecked bases to out-of-bounds addresses, leading to
out-of-bounds DMA?
> static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
> struct feat_matrix *fm,
> - u32 x, u32 y, u32 c)
> + u32 x, u32 y, u32 c, bool ofm)
> {
> u32 element_size, storage = fm->precision >> 14;
> int tile = 0;
[ ... ]
> @@ -231,10 +231,11 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
>
> switch ((fm->precision >> 6) & 0x3) { // format
[Severity: Critical]
This isn't a bug introduced by this patch, but what happens here if a
userspace process submits a command stream with a precision format of
2 or 3?
Since the switch lacks handling for cases 2 and 3, it seems to silently fall
through and bypass adding the x and c components to the address offset.
Does this cause the validation routine to compute a falsely small memory
footprint, potentially allowing the command to execute on a
smaller-than-required buffer and perform out-of-bounds DMA access?
> case 0: //nhwc:
> - addr += x * fm->stride_x + c;
> + element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
> + addr += x * fm->stride_x + c * element_size;
> break;
> case 1: //nhcwb16:
> - element_size = BIT((fm->precision >> 1) & 0x3);
> + element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
>
> addr += (c / 16) * fm->stride_c + (16 * x + (c & 0xf)) * element_size;
> break;
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260720231450.485221-1-robh@kernel.org?part=1
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 2/2] accel: ethosu: Handle U85 internal chaining buffer
2026-07-20 23:14 ` [PATCH 2/2] accel: ethosu: Handle U85 internal chaining buffer Rob Herring (Arm)
@ 2026-07-21 16:49 ` Tomeu Vizoso
0 siblings, 0 replies; 5+ messages in thread
From: Tomeu Vizoso @ 2026-07-21 16:49 UTC (permalink / raw)
To: Rob Herring (Arm)
Cc: Oded Gabbay, Thomas Zimmermann, Frank Li, dri-devel, linux-kernel
On Tue, Jul 21, 2026 at 1:14 AM Rob Herring (Arm) <robh@kernel.org> wrote:
>
> The Ethos-U85 supports an internal chaining buffer as temporary storage
> between some operations. When chaining is activated, the IFM/OFM region
> setting selects a chaining buffer rather than a region, and the IFM/OFM
> base addresses don't matter. In this case, the feature matrix size
> calculations should be skipped. Otherwise, the command stream will be
> intermittently rejected depending on prior feature matrix base
> addresses.
>
> Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver")
> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Acked-by: Tomeu Vizoso <tomeu@tomeuvizoso.net>
> ---
> drivers/accel/ethosu/ethosu_gem.c | 35 +++++++++++++++++++++++--------
> 1 file changed, 26 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/accel/ethosu/ethosu_gem.c b/drivers/accel/ethosu/ethosu_gem.c
> index 1daff32610c7..d50fed64d4d9 100644
> --- a/drivers/accel/ethosu/ethosu_gem.c
> +++ b/drivers/accel/ethosu/ethosu_gem.c
> @@ -192,7 +192,15 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
> return len;
> }
>
> -static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
> +static bool feat_matrix_chained(struct ethosu_device *edev, struct feat_matrix *fm)
> +{
> + u32 storage = fm->precision >> 14;
> +
> + return !ethosu_is_u65(edev) && storage == 2;
> +}
> +
> +static u64 feat_matrix_length(struct ethosu_device *edev,
> + struct ethosu_validated_cmdstream_info *info,
> struct feat_matrix *fm,
> u32 x, u32 y, u32 c, bool ofm)
> {
> @@ -203,6 +211,9 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
> if (fm->region < 0)
> return U64_MAX;
>
> + if (feat_matrix_chained(edev, fm))
> + return 0;
> +
> switch (storage) {
> case 0:
> if (x >= fm->width0 + 1) {
> @@ -223,6 +234,8 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
> tile = 1;
> }
> break;
> + default:
> + return U64_MAX;
> }
> if (fm->base[tile] == U64_MAX)
> return U64_MAX;
> @@ -251,6 +264,7 @@ static int calc_sizes(struct drm_device *ddev,
> u16 op, struct cmd_state *st,
> bool ifm, bool ifm2, bool weight, bool scale)
> {
> + struct ethosu_device *edev = to_ethosu_device(ddev);
> u64 len;
>
> if (ifm) {
> @@ -268,7 +282,7 @@ static int calc_sizes(struct drm_device *ddev,
> if (ifm_height < 0 || ifm_width < 0)
> return -EINVAL;
>
> - len = feat_matrix_length(info, &st->ifm, ifm_width,
> + len = feat_matrix_length(edev, info, &st->ifm, ifm_width,
> ifm_height, st->ifm.depth, false);
> dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
> op, st->ifm.region, st->ifm.base[0], len);
> @@ -277,7 +291,7 @@ static int calc_sizes(struct drm_device *ddev,
> }
>
> if (ifm2) {
> - len = feat_matrix_length(info, &st->ifm2, st->ifm.depth,
> + len = feat_matrix_length(edev, info, &st->ifm2, st->ifm.depth,
> 0, st->ofm.depth, false);
> dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
> op, st->ifm2.region, st->ifm2.base[0], len);
> @@ -309,13 +323,14 @@ static int calc_sizes(struct drm_device *ddev,
> st->scale[0].base + st->scale[0].length);
> }
>
> - len = feat_matrix_length(info, &st->ofm, st->ofm.width,
> + len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
> st->ofm.height[2], st->ofm.depth, true);
> dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
> op, st->ofm.region, st->ofm.base[0], len);
> if (len == U64_MAX)
> return -EINVAL;
> - info->output_region[st->ofm.region] = true;
> + if (!feat_matrix_chained(edev, &st->ofm))
> + info->output_region[st->ofm.region] = true;
>
> return 0;
> }
> @@ -325,6 +340,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
> u16 op, struct cmd_state *st,
> bool ifm, bool ifm2)
> {
> + struct ethosu_device *edev = to_ethosu_device(ddev);
> u32 height, width, depth;
> u64 len;
>
> @@ -333,7 +349,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
> width = st->ifm.broadcast & 0x2 ? 0 : st->ofm.width;
> depth = st->ifm.broadcast & 0x4 ? 0 : st->ofm.depth;
>
> - len = feat_matrix_length(info, &st->ifm, width,
> + len = feat_matrix_length(edev, info, &st->ifm, width,
> height, depth, false);
> dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
> op, st->ifm.region, st->ifm.base[0], len);
> @@ -346,7 +362,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
> width = st->ifm2.broadcast & 0x2 ? 0 : st->ofm.width;
> depth = st->ifm2.broadcast & 0x4 ? 0 : st->ofm.depth;
>
> - len = feat_matrix_length(info, &st->ifm2, width,
> + len = feat_matrix_length(edev, info, &st->ifm2, width,
> height, depth, false);
> dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
> op, st->ifm2.region, st->ifm2.base[0], len);
> @@ -354,13 +370,14 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
> return -EINVAL;
> }
>
> - len = feat_matrix_length(info, &st->ofm, st->ofm.width,
> + len = feat_matrix_length(edev, info, &st->ofm, st->ofm.width,
> st->ofm.height[2], st->ofm.depth, true);
> dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
> op, st->ofm.region, st->ofm.base[0], len);
> if (len == U64_MAX)
> return -EINVAL;
> - info->output_region[st->ofm.region] = true;
> + if (!feat_matrix_chained(edev, &st->ofm))
> + info->output_region[st->ofm.region] = true;
>
> return 0;
> }
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation
2026-07-20 23:14 [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation Rob Herring (Arm)
2026-07-20 23:14 ` [PATCH 2/2] accel: ethosu: Handle U85 internal chaining buffer Rob Herring (Arm)
2026-07-20 23:34 ` [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation sashiko-bot
@ 2026-07-21 16:50 ` Tomeu Vizoso
2 siblings, 0 replies; 5+ messages in thread
From: Tomeu Vizoso @ 2026-07-21 16:50 UTC (permalink / raw)
To: Rob Herring (Arm)
Cc: Oded Gabbay, Thomas Zimmermann, Frank Li, dri-devel, linux-kernel
On Tue, Jul 21, 2026 at 1:14 AM Rob Herring (Arm) <robh@kernel.org> wrote:
>
> There are 2 issues with the element size handling in the command stream
> validation which result in too small of a size calculated when the
> element size is 16/32/64 bits.
>
> For NHWC format, the element size is simply missing from the
> calculation.
>
> The bitfield for the element size is different between IFM/IFM2 and
> OFM. IFM and IFM2 encode the precision in parameter bits 2:3, while OFM
> uses bits 1:2.
>
> Fixes: 5a5e9c0228e6 ("accel: Add Arm Ethos-U NPU driver")
> Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Acked-by: Tomeu Vizoso <tomeu@tomeuvizoso.net>
> ---
> drivers/accel/ethosu/ethosu_gem.c | 19 ++++++++++---------
> 1 file changed, 10 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/accel/ethosu/ethosu_gem.c b/drivers/accel/ethosu/ethosu_gem.c
> index 3401883e207f..1daff32610c7 100644
> --- a/drivers/accel/ethosu/ethosu_gem.c
> +++ b/drivers/accel/ethosu/ethosu_gem.c
> @@ -194,7 +194,7 @@ static u64 dma_length(struct ethosu_validated_cmdstream_info *info,
>
> static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
> struct feat_matrix *fm,
> - u32 x, u32 y, u32 c)
> + u32 x, u32 y, u32 c, bool ofm)
> {
> u32 element_size, storage = fm->precision >> 14;
> int tile = 0;
> @@ -231,10 +231,11 @@ static u64 feat_matrix_length(struct ethosu_validated_cmdstream_info *info,
>
> switch ((fm->precision >> 6) & 0x3) { // format
> case 0: //nhwc:
> - addr += x * fm->stride_x + c;
> + element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
> + addr += x * fm->stride_x + c * element_size;
> break;
> case 1: //nhcwb16:
> - element_size = BIT((fm->precision >> 1) & 0x3);
> + element_size = BIT((fm->precision >> (ofm ? 1 : 2)) & 0x3);
>
> addr += (c / 16) * fm->stride_c + (16 * x + (c & 0xf)) * element_size;
> break;
> @@ -268,7 +269,7 @@ static int calc_sizes(struct drm_device *ddev,
> return -EINVAL;
>
> len = feat_matrix_length(info, &st->ifm, ifm_width,
> - ifm_height, st->ifm.depth);
> + ifm_height, st->ifm.depth, false);
> dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
> op, st->ifm.region, st->ifm.base[0], len);
> if (len == U64_MAX)
> @@ -277,7 +278,7 @@ static int calc_sizes(struct drm_device *ddev,
>
> if (ifm2) {
> len = feat_matrix_length(info, &st->ifm2, st->ifm.depth,
> - 0, st->ofm.depth);
> + 0, st->ofm.depth, false);
> dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
> op, st->ifm2.region, st->ifm2.base[0], len);
> if (len == U64_MAX)
> @@ -309,7 +310,7 @@ static int calc_sizes(struct drm_device *ddev,
> }
>
> len = feat_matrix_length(info, &st->ofm, st->ofm.width,
> - st->ofm.height[2], st->ofm.depth);
> + st->ofm.height[2], st->ofm.depth, true);
> dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
> op, st->ofm.region, st->ofm.base[0], len);
> if (len == U64_MAX)
> @@ -333,7 +334,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
> depth = st->ifm.broadcast & 0x4 ? 0 : st->ofm.depth;
>
> len = feat_matrix_length(info, &st->ifm, width,
> - height, depth);
> + height, depth, false);
> dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
> op, st->ifm.region, st->ifm.base[0], len);
> if (len == U64_MAX)
> @@ -346,7 +347,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
> depth = st->ifm2.broadcast & 0x4 ? 0 : st->ofm.depth;
>
> len = feat_matrix_length(info, &st->ifm2, width,
> - height, depth);
> + height, depth, false);
> dev_dbg(ddev->dev, "op %d: IFM2:%d:0x%llx-0x%llx\n",
> op, st->ifm2.region, st->ifm2.base[0], len);
> if (len == U64_MAX)
> @@ -354,7 +355,7 @@ static int calc_sizes_elemwise(struct drm_device *ddev,
> }
>
> len = feat_matrix_length(info, &st->ofm, st->ofm.width,
> - st->ofm.height[2], st->ofm.depth);
> + st->ofm.height[2], st->ofm.depth, true);
> dev_dbg(ddev->dev, "op %d: OFM:%d:0x%llx-0x%llx\n",
> op, st->ofm.region, st->ofm.base[0], len);
> if (len == U64_MAX)
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-07-21 16:50 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20 23:14 [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation Rob Herring (Arm)
2026-07-20 23:14 ` [PATCH 2/2] accel: ethosu: Handle U85 internal chaining buffer Rob Herring (Arm)
2026-07-21 16:49 ` Tomeu Vizoso
2026-07-20 23:34 ` [PATCH 1/2] accel: ethosu: Fix element size accounting for cmd stream validation sashiko-bot
2026-07-21 16:50 ` Tomeu Vizoso
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.