On Tue, Jul 21, 2026 at 1:14 AM Rob Herring (Arm) <[email protected]> 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) <[email protected]>
Acked-by: Tomeu Vizoso <[email protected]> > --- > 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 >
