Re: [PATCH 2/2] accel: ethosu: Handle U85 internal chaining buffer
From: Tomeu Vizoso
Date: Tue Jul 21 2026 - 14:09:44 EST
On Tue, Jul 21, 2026 at 1:14 AM Rob Herring (Arm) <robh@xxxxxxxxxx> 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@xxxxxxxxxx>
Acked-by: Tomeu Vizoso <tomeu@xxxxxxxxxxxxxxx>
> ---
> 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
>