]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
accel: ethosu: Handle U85 internal chaining buffer
authorRob Herring (Arm) <robh@kernel.org>
Mon, 20 Jul 2026 23:14:48 +0000 (18:14 -0500)
committerRob Herring (Arm) <robh@kernel.org>
Tue, 21 Jul 2026 20:21:56 +0000 (15:21 -0500)
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")
Acked-by: Tomeu Vizoso <tomeu@tomeuvizoso.net>
Link: https://patch.msgid.link/20260720231450.485221-2-robh@kernel.org
Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
drivers/accel/ethosu/ethosu_gem.c

index 1daff32610c71b8d0d3644c374d562dfc82047a1..d50fed64d4d937cef8e7d79707f22fac00b1cfa6 100644 (file)
@@ -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;
 }