* [PATCH net] net: airoha: Fix TX scheduler queue mask loop upper bound
From: Wayen Yan @ 2026-06-17 3:20 UTC (permalink / raw)
To: netdev
Cc: lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In airoha_qdma_set_chan_tx_sched(), the loop clearing queue mask was
using AIROHA_NUM_TX_RING (32) instead of AIROHA_NUM_QOS_QUEUES (8).
Each channel has 8 queues, and TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i)
computes BIT(i + (channel * 8)). With i ranging 0..31, this causes:
- channel 0: clears bit 0..31 (all 4 channels) instead of 0..7
- channel 1: clears bit 8..31 (channels 1-3) instead of 8..15
- channel 2: clears bit 16..31 (channels 2-3) instead of 16..23
- channel 3: clears bit 24..31 (channel 3 only) - correct by accident
While BIT(32+) on arm64 produces 64-bit values truncated to 0 in u32
mask parameter, the loop still incorrectly clears queues within the
same channel beyond queue 7.
Fix by using AIROHA_NUM_QOS_QUEUES (8) as the loop upper bound.
Fixes: ef1ca9271313 ("net: airoha: Add sched HTB offload support")
Signed-off-by: Wayen Yan <win847@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 31cdb11cd7..a1eda13400 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2217,7 +2217,7 @@ static int airoha_qdma_set_chan_tx_sched(struct net_device *dev,
struct airoha_gdm_port *port = netdev_priv(dev);
int i;
- for (i = 0; i < AIROHA_NUM_TX_RING; i++)
+ for (i = 0; i < AIROHA_NUM_QOS_QUEUES; i++)
airoha_qdma_clear(port->qdma, REG_QUEUE_CLOSE_CFG(channel),
TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i));
--
2.51.0
^ permalink raw reply related
* [PATCH] net: airoha: Fix off-by-one error in HTB rate-limit channel removal
From: Wayen Yan @ 2026-06-17 2:51 UTC (permalink / raw)
To: netdev
Cc: lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In airoha_tc_remove_htb_queue(), the rate-limit was being cleared
using (queue + 1) instead of queue, causing:
- The original channel rate-limit configuration to remain active
- The next channel to be incorrectly disabled
- Potential out-of-bounds access when queue == 3 (channel 4)
The alloc path (airoha_tc_htb_alloc_leaf_queue) correctly uses
channel (0..3), but the remove path incorrectly added 1.
Fix by using queue directly to match the alloc and rollback paths.
Fixes: ef1ca9271313 ("net: airoha: Add sched HTB offload support")
Signed-off-by: Wayen Yan <win847@gmail.com>
---
drivers/net/ethernet/airoha/airoha_eth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 31cdb11cd7..02807b3967 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2805,7 +2805,7 @@ static void airoha_tc_remove_htb_queue(struct net_device *dev, int queue)
struct airoha_gdm_port *port = netdev_priv(dev);
netif_set_real_num_tx_queues(dev, dev->real_num_tx_queues - 1);
- airoha_qdma_set_tx_rate_limit(dev, queue + 1, 0, 0);
+ airoha_qdma_set_tx_rate_limit(dev, queue, 0, 0);
clear_bit(queue, port->qos_sq_bmap);
}
--
2.51.0
^ permalink raw reply related
* [PATCH 3/5] ARM: dts: mediatek: Add basic support for Amazon ford board
From: Zakariya Hadrami via B4 Relay @ 2026-06-17 2:20 UTC (permalink / raw)
To: Matthias Brugger, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sean Wang, Wim Van Sebroeck,
Guenter Roeck
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, devicetree,
linux-watchdog, Zakariya Hadrami
In-Reply-To: <20260617-mt8127-amazon-ford-basic-v1-0-d02ad15ac359@proton.me>
From: Zakariya Hadrami <zkh1@proton.me>
This tablet uses a MediaTek MT8127 system-on-chip with 1GB of RAM.
It can currently boot into initramfs with a working UART and
Simple Framebuffer using already initialized panel by the bootloader.
Signed-off-by: Zakariya Hadrami <zkh1@proton.me>
---
arch/arm/boot/dts/mediatek/Makefile | 1 +
arch/arm/boot/dts/mediatek/mt8127-amazon-ford.dts | 46 +++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/arch/arm/boot/dts/mediatek/Makefile b/arch/arm/boot/dts/mediatek/Makefile
index 37c4cded0eae..a610bc75c7d9 100644
--- a/arch/arm/boot/dts/mediatek/Makefile
+++ b/arch/arm/boot/dts/mediatek/Makefile
@@ -14,5 +14,6 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += \
mt7623n-rfb-emmc.dtb \
mt7623n-bananapi-bpi-r2.dtb \
mt7629-rfb.dtb \
+ mt8127-amazon-ford.dtb \
mt8127-moose.dtb \
mt8135-evbp1.dtb
diff --git a/arch/arm/boot/dts/mediatek/mt8127-amazon-ford.dts b/arch/arm/boot/dts/mediatek/mt8127-amazon-ford.dts
new file mode 100644
index 000000000000..21bdab0e43f8
--- /dev/null
+++ b/arch/arm/boot/dts/mediatek/mt8127-amazon-ford.dts
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/dts-v1/;
+#include "mt8127.dtsi"
+
+/ {
+ model = "MediaTek MT8127 Amazon Ford";
+ compatible = "amazon,ford", "mediatek,mt8127";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:921600n8";
+
+ framebuffer0: framebuffer@b7a00000 {
+ compatible = "simple-framebuffer";
+ memory-region = <&framebuffer_reserved>;
+ width = <1024>;
+ height = <600>;
+ stride = <(1024 * 2)>;
+ format = "r5g6b5";
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0 0x80000000 0 0x40000000>;
+ };
+
+ reserved-memory {
+ framebuffer_reserved: framebuffer@b7a00000 {
+ reg = <0 0xb7a00000 0 0x1000000>;
+ no-map;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&watchdog {
+ status = "okay";
+};
--
2.54.0
^ permalink raw reply related
* [PATCH 2/5] ARM: dts: mediatek: mt8127: Add watchdog support
From: Zakariya Hadrami via B4 Relay @ 2026-06-17 2:20 UTC (permalink / raw)
To: Matthias Brugger, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sean Wang, Wim Van Sebroeck,
Guenter Roeck
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, devicetree,
linux-watchdog, Zakariya Hadrami
In-Reply-To: <20260617-mt8127-amazon-ford-basic-v1-0-d02ad15ac359@proton.me>
From: Zakariya Hadrami <zkh1@proton.me>
Add watchdog node and disable it by default as it was not present
initially.
Signed-off-by: Zakariya Hadrami <zkh1@proton.me>
---
arch/arm/boot/dts/mediatek/mt8127.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/mediatek/mt8127.dtsi b/arch/arm/boot/dts/mediatek/mt8127.dtsi
index bd61ec7e70c0..1855dda42710 100644
--- a/arch/arm/boot/dts/mediatek/mt8127.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt8127.dtsi
@@ -159,5 +159,12 @@ uart3: serial@11005000 {
clocks = <&uart_clk>;
status = "disabled";
};
+
+ watchdog: watchdog@10007000 {
+ compatible = "mediatek,mt8127-wdt","mediatek,mt6589-wdt";
+ reg = <0 0x10007000 0 0x100>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_LOW>;
+ status = "disabled";
+ };
};
};
--
2.54.0
^ permalink raw reply related
* [PATCH 5/5] dt-bindings: watchdog: mediatek: Add MT8127
From: Zakariya Hadrami via B4 Relay @ 2026-06-17 2:20 UTC (permalink / raw)
To: Matthias Brugger, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sean Wang, Wim Van Sebroeck,
Guenter Roeck
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, devicetree,
linux-watchdog, Zakariya Hadrami
In-Reply-To: <20260617-mt8127-amazon-ford-basic-v1-0-d02ad15ac359@proton.me>
From: Zakariya Hadrami <zkh1@proton.me>
Add entry for MT8127 SoC's watchdog which is compatible with MT6589's
one.
Signed-off-by: Zakariya Hadrami <zkh1@proton.me>
---
Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml
index 953629cb9558..e6e4546da0aa 100644
--- a/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml
+++ b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml
@@ -40,6 +40,7 @@ properties:
- mediatek,mt7622-wdt
- mediatek,mt7623-wdt
- mediatek,mt7629-wdt
+ - mediatek,mt8127-wdt
- mediatek,mt8173-wdt
- mediatek,mt8188-wdt
- mediatek,mt8189-wdt
--
2.54.0
^ permalink raw reply related
* [PATCH 1/5] ARM: dts: mediatek: mt8127: Fix indentation error
From: Zakariya Hadrami via B4 Relay @ 2026-06-17 2:20 UTC (permalink / raw)
To: Matthias Brugger, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sean Wang, Wim Van Sebroeck,
Guenter Roeck
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, devicetree,
linux-watchdog, Zakariya Hadrami
In-Reply-To: <20260617-mt8127-amazon-ford-basic-v1-0-d02ad15ac359@proton.me>
From: Zakariya Hadrami <zkh1@proton.me>
Fix an indentation error caused by a space at the start of a line.
Signed-off-by: Zakariya Hadrami <zkh1@proton.me>
---
arch/arm/boot/dts/mediatek/mt8127.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/mediatek/mt8127.dtsi b/arch/arm/boot/dts/mediatek/mt8127.dtsi
index aced173c2a52..bd61ec7e70c0 100644
--- a/arch/arm/boot/dts/mediatek/mt8127.dtsi
+++ b/arch/arm/boot/dts/mediatek/mt8127.dtsi
@@ -75,7 +75,7 @@ uart_clk: dummy26m {
compatible = "fixed-clock";
clock-frequency = <26000000>;
#clock-cells = <0>;
- };
+ };
};
timer {
--
2.54.0
^ permalink raw reply related
* [PATCH 4/5] dt-bindings: arm: mediatek: Add MT8127 Amazon ford
From: Zakariya Hadrami via B4 Relay @ 2026-06-17 2:20 UTC (permalink / raw)
To: Matthias Brugger, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sean Wang, Wim Van Sebroeck,
Guenter Roeck
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, devicetree,
linux-watchdog, Zakariya Hadrami
In-Reply-To: <20260617-mt8127-amazon-ford-basic-v1-0-d02ad15ac359@proton.me>
From: Zakariya Hadrami <zkh1@proton.me>
Add entry for the MT8127 based Amazon ford tablet.
Signed-off-by: Zakariya Hadrami <zkh1@proton.me>
---
Documentation/devicetree/bindings/arm/mediatek.yaml | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml
index 382d0eb4d0af..5ddc79689df9 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.yaml
+++ b/Documentation/devicetree/bindings/arm/mediatek.yaml
@@ -124,6 +124,10 @@ properties:
- enum:
- mediatek,mt8127-moose
- const: mediatek,mt8127
+ - items:
+ - enum:
+ - amazon,ford
+ - const: mediatek,mt8127
- items:
- enum:
- mediatek,mt8135-evbp1
--
2.54.0
^ permalink raw reply related
* [PATCH 0/5] ARM: Basic support for Amazon ford tablet (MT8127)
From: Zakariya Hadrami via B4 Relay @ 2026-06-17 2:20 UTC (permalink / raw)
To: Matthias Brugger, AngeloGioacchino Del Regno, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sean Wang, Wim Van Sebroeck,
Guenter Roeck
Cc: linux-kernel, linux-arm-kernel, linux-mediatek, devicetree,
linux-watchdog, Zakariya Hadrami
This series of patches adds basic support for MT8127 SoC based Amazon ford
tablet and fixes a small indentation error in the dtsi file.
Signed-off-by: Zakariya Hadrami <zkh1@proton.me>
---
Zakariya Hadrami (5):
ARM: dts: mediatek: mt8127: Fix indentation error
ARM: dts: mediatek: mt8127: Add watchdog support
ARM: dts: mediatek: Add basic support for Amazon ford board
dt-bindings: arm: mediatek: Add MT8127 Amazon ford
dt-bindings: watchdog: mediatek: Add MT8127
.../devicetree/bindings/arm/mediatek.yaml | 4 ++
.../bindings/watchdog/mediatek,mtk-wdt.yaml | 1 +
arch/arm/boot/dts/mediatek/Makefile | 1 +
arch/arm/boot/dts/mediatek/mt8127-amazon-ford.dts | 46 ++++++++++++++++++++++
arch/arm/boot/dts/mediatek/mt8127.dtsi | 9 ++++-
5 files changed, 60 insertions(+), 1 deletion(-)
---
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
change-id: 20260616-mt8127-amazon-ford-basic-1509d7052f7e
Best regards,
--
Zakariya Hadrami <zkh1@proton.me>
^ permalink raw reply
* [PATCH v3 9/9] media: v4l2-ctrls: add KUnit tests for compound control tile validation
From: Michael Bommarito @ 2026-06-17 2:19 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
Add KUnit coverage for the HEVC and AV1 tile-count checks in
std_validate_compound(): in-range counts pass, out-of-range per-dimension
counts and an AV1 grid whose product exceeds V4L2_AV1_MAX_TILE_COUNT are
rejected, and the zero-initialised AV1 frame control that userspace
submits still passes.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
drivers/media/v4l2-core/Kconfig | 12 ++
.../media/v4l2-core/v4l2-ctrls-core-test.c | 145 ++++++++++++++++++
drivers/media/v4l2-core/v4l2-ctrls-core.c | 4 +
3 files changed, 161 insertions(+)
create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core-test.c
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index d50ccac9733cc..52c00dfe9322f 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -3,6 +3,18 @@
# Generic video config states
#
+config V4L2_CTRLS_KUNIT_TEST
+ bool "KUnit tests for V4L2 compound control validation" if !KUNIT_ALL_TESTS
+ depends on VIDEO_DEV && KUNIT=y
+ default KUNIT_ALL_TESTS
+ help
+ This builds KUnit tests for the stateless-codec compound control
+ validation in std_validate_compound(). They check that out-of-range
+ HEVC and AV1 tile counts are rejected before the stateless decoders
+ consume them as loop bounds and array indices.
+
+ If unsure, say N.
+
config VIDEO_V4L2_I2C
bool
depends on I2C && VIDEO_DEV
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core-test.c b/drivers/media/v4l2-core/v4l2-ctrls-core-test.c
new file mode 100644
index 0000000000000..c0141f3defa82
--- /dev/null
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core-test.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit tests for HEVC/AV1 tile-count validation in std_validate_compound().
+ * #included at the end of v4l2-ctrls-core.c to reach the static helper.
+ */
+
+#include <kunit/test.h>
+
+static int call_validate_compound(enum v4l2_ctrl_type type, void *payload,
+ u32 elem_size)
+{
+ struct v4l2_ctrl ctrl = {
+ .type = type,
+ .elem_size = elem_size,
+ };
+ union v4l2_ctrl_ptr ptr = { .p = payload };
+
+ return std_validate_compound(&ctrl, 0, ptr);
+}
+
+/* HEVC PPS: num_tile_columns_minus1 / num_tile_rows_minus1 bounds. */
+static void v4l2_ctrls_hevc_pps_tile_cols(struct kunit *test)
+{
+ struct v4l2_ctrl_hevc_pps *pps;
+
+ pps = kunit_kzalloc(test, sizeof(*pps), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, pps);
+
+ pps->flags = V4L2_HEVC_PPS_FLAG_TILES_ENABLED;
+
+ /* In range: count == array capacity (minus1 == capacity - 1). */
+ pps->num_tile_columns_minus1 = ARRAY_SIZE(pps->column_width_minus1) - 1;
+ pps->num_tile_rows_minus1 = ARRAY_SIZE(pps->row_height_minus1) - 1;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+ sizeof(*pps)),
+ 0);
+
+ /* Out of range: one past the column array. */
+ pps->num_tile_columns_minus1 = ARRAY_SIZE(pps->column_width_minus1);
+ pps->num_tile_rows_minus1 = 0;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+ sizeof(*pps)),
+ -EINVAL);
+
+ /* Out of range: maximal attacker value. */
+ pps->num_tile_columns_minus1 = 0xff;
+ pps->num_tile_rows_minus1 = 0xff;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_HEVC_PPS, pps,
+ sizeof(*pps)),
+ -EINVAL);
+}
+
+/* AV1 frame: tile_cols / tile_rows upper bounds. */
+static void v4l2_ctrls_av1_frame_tile(struct kunit *test)
+{
+ struct v4l2_ctrl_av1_frame *f;
+
+ f = kunit_kzalloc(test, sizeof(*f), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, f);
+
+ /*
+ * Benign control: a zero-initialised frame (tile_cols == 0) must
+ * still pass. Userspace and v4l2-compliance set the zeroed default,
+ * and the divisor that a zero tile_cols would feed is guarded in the
+ * consuming driver rather than rejected here.
+ */
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+ sizeof(*f)),
+ 0);
+
+ /* In range: a 1x1 tiling. */
+ f->tile_info.tile_cols = 1;
+ f->tile_info.tile_rows = 1;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+ sizeof(*f)),
+ 0);
+
+ /*
+ * In range: total tiles == V4L2_AV1_MAX_TILE_COUNT with each
+ * dimension at or below its per-dimension maximum (64 * 8 == 512).
+ */
+ f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS;
+ f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_COUNT / V4L2_AV1_MAX_TILE_COLS;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+ sizeof(*f)),
+ 0);
+
+ /*
+ * Out of range: each dimension is legal on its own but the product
+ * exceeds V4L2_AV1_MAX_TILE_COUNT (64 * 64 == 4096 > 512), which would
+ * overflow the per-tile descriptor buffers.
+ */
+ f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS;
+ f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_ROWS;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+ sizeof(*f)),
+ -EINVAL);
+
+ /* Out of range: tile_cols past the array. */
+ f->tile_info.tile_cols = V4L2_AV1_MAX_TILE_COLS + 1;
+ f->tile_info.tile_rows = 1;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+ sizeof(*f)),
+ -EINVAL);
+
+ /* Out of range: maximal attacker value. */
+ f->tile_info.tile_cols = 0xff;
+ f->tile_info.tile_rows = 0xff;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+ sizeof(*f)),
+ -EINVAL);
+
+ /* Out of range: tile_rows past the array. */
+ f->tile_info.tile_cols = 1;
+ f->tile_info.tile_rows = V4L2_AV1_MAX_TILE_ROWS + 1;
+ KUNIT_EXPECT_EQ(test,
+ call_validate_compound(V4L2_CTRL_TYPE_AV1_FRAME, f,
+ sizeof(*f)),
+ -EINVAL);
+}
+
+static struct kunit_case v4l2_ctrls_test_cases[] = {
+ KUNIT_CASE(v4l2_ctrls_hevc_pps_tile_cols),
+ KUNIT_CASE(v4l2_ctrls_av1_frame_tile),
+ {}
+};
+
+static struct kunit_suite v4l2_ctrls_test_suite = {
+ .name = "v4l2-ctrls-compound",
+ .test_cases = v4l2_ctrls_test_cases,
+};
+
+kunit_test_suite(v4l2_ctrls_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for V4L2 stateless-codec compound control validation");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index fb20ad13dfec7..1409b06eee0a8 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -2860,3 +2860,7 @@ int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
return hdl->error;
}
EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
+
+#if IS_ENABLED(CONFIG_V4L2_CTRLS_KUNIT_TEST)
+#include "v4l2-ctrls-core-test.c"
+#endif
--
2.53.0
^ permalink raw reply related
* [PATCH v3 8/9] media: mediatek: vcodec: bound AV1 tile-start copy to the array capacity
From: Michael Bommarito @ 2026-06-17 2:19 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
vdec_av1_slice_setup_tile() copies tile_cols + 1 / tile_rows + 1 entries
into mi_col_starts[] / mi_row_starts[] from the bitstream tile_info. Bound
the copy to the array capacity.
Fixes: 0934d3759615 ("media: mediatek: vcodec: separate decoder and encoder")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
.../mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
index 2d622e85f8271..49d9b4a72387e 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c
@@ -1299,11 +1299,12 @@ static void vdec_av1_slice_setup_tile(struct vdec_av1_slice_frame *frame,
tile->uniform_tile_spacing_flag =
BIT_FLAG(ctrl_tile, V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING);
- for (i = 0; i < tile->tile_cols + 1; i++)
+ /* Bound the copy to the mi_col_starts[]/mi_row_starts[] capacity. */
+ for (i = 0; i < tile->tile_cols + 1 && i < V4L2_AV1_MAX_TILE_COLS + 1; i++)
tile->mi_col_starts[i] =
ALIGN(ctrl_tile->mi_col_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
- for (i = 0; i < tile->tile_rows + 1; i++)
+ for (i = 0; i < tile->tile_rows + 1 && i < V4L2_AV1_MAX_TILE_ROWS + 1; i++)
tile->mi_row_starts[i] =
ALIGN(ctrl_tile->mi_row_starts[i], BIT(mib_size_log2)) >> mib_size_log2;
}
--
2.53.0
^ permalink raw reply related
* [PATCH v3 7/9] media: verisilicon: rockchip: reject AV1 frames exceeding the tile capacity
From: Michael Bommarito @ 2026-06-17 2:19 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
rockchip_vpu981_av1_dec_set_tile_info() indexes the tile group entry
array by tile1 * tile_cols + tile0, reading up to tile_cols * tile_rows
entries, lays out one descriptor per tile in the AV1_MAX_TILES tile_info
buffer, and programs the real tile_cols / tile_rows into the hardware.
The tile group entry control is a dynamic array sized to the number of
entries userspace submitted, independent of tile_cols / tile_rows, so a
frame that claims more tiles than entries reads past the array. A frame
that claims more than AV1_MAX_TILES tiles also leaves the hardware
programmed for more tiles than the descriptor buffer holds.
Reject both in prepare_run(): tile_cols * tile_rows must not exceed the
submitted entry count or AV1_MAX_TILES. The entry count is read via
v4l2_ctrl_find() (ctrl->elems). This mirrors the bound the mediatek AV1
decoder already enforces.
Fixes: 727a400686a2 ("media: verisilicon: Add Rockchip AV1 decoder")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
.../verisilicon/rockchip_vpu981_hw_av1_dec.c | 25 ++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index fd00dbd79fe46..00aa566a4ccdb 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -431,20 +431,39 @@ static int rockchip_vpu981_av1_dec_prepare_run(struct hantro_ctx *ctx)
{
struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
+ const struct v4l2_av1_tile_info *tile_info;
+ struct v4l2_ctrl *tge;
+ u32 num_tiles;
ctrls->sequence = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
if (WARN_ON(!ctrls->sequence))
return -EINVAL;
- ctrls->tile_group_entry =
- hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
- if (WARN_ON(!ctrls->tile_group_entry))
+ tge = v4l2_ctrl_find(&ctx->ctrl_handler,
+ V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
+ if (WARN_ON(!tge))
return -EINVAL;
+ ctrls->tile_group_entry = tge->p_cur.p;
ctrls->frame = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FRAME);
if (WARN_ON(!ctrls->frame))
return -EINVAL;
+ /*
+ * rockchip_vpu981_av1_dec_set_tile_info() indexes the tile group
+ * entry array by tile1 * tile_cols + tile0, so it reads up to
+ * tile_cols * tile_rows entries, and lays out one descriptor per tile
+ * in the AV1_MAX_TILES tile_info buffer while programming the real
+ * tile geometry into the hardware. Reject a frame that claims more
+ * tiles than userspace submitted, or more than the hardware tile
+ * buffer holds, so the read stays in bounds and the programmed
+ * geometry matches the descriptors written.
+ */
+ tile_info = &ctrls->frame->tile_info;
+ num_tiles = (u32)tile_info->tile_cols * tile_info->tile_rows;
+ if (num_tiles > tge->elems || num_tiles > AV1_MAX_TILES)
+ return -EINVAL;
+
ctrls->film_grain =
hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN);
--
2.53.0
^ permalink raw reply related
* [PATCH v3 6/9] media: verisilicon: rockchip: guard VPU981 AV1 divisor and tile buffer
From: Michael Bommarito @ 2026-06-17 2:19 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
rockchip_vpu981_av1_dec_set_tile_info() divides context_update_tile_id by
tile_info->tile_cols and writes one descriptor per tile into the tile_info
DMA buffer, which holds AV1_MAX_TILES entries; tile_cols and tile_rows
come from the bitstream. Guard the division against a zero tile_cols by
initialising the context-update values to zero and computing them only
when tile_cols is non-zero, and stop the descriptor writes once the
tile_info buffer is full. The tile geometry written to the hardware
registers is left unmodified; the per-dimension and total tile bounds are
enforced by the control validation.
Fixes: 727a400686a2 ("media: verisilicon: Add Rockchip AV1 decoder")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
.../verisilicon/rockchip_vpu981_hw_av1_dec.c | 32 +++++++++++++++----
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index e4e21ad373233..fd00dbd79fe46 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -578,16 +578,30 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
ctrls->tile_group_entry;
- int context_update_y =
- tile_info->context_update_tile_id / tile_info->tile_cols;
- int context_update_x =
- tile_info->context_update_tile_id % tile_info->tile_cols;
- int context_update_tile_id =
- context_update_x * tile_info->tile_rows + context_update_y;
+ int context_update_y = 0;
+ int context_update_x = 0;
+ int context_update_tile_id = 0;
u8 *dst = av1_dec->tile_info.cpu;
+ u8 *dst_end = dst + av1_dec->tile_info.size;
struct hantro_dev *vpu = ctx->dev;
int tile0, tile1;
+ /*
+ * tile_cols and tile_rows are bounded by the V4L2 control validation
+ * (V4L2_AV1_MAX_TILE_{COLS,ROWS} and V4L2_AV1_MAX_TILE_COUNT). Guard
+ * the divisor here, and keep the descriptor writes within the
+ * AV1_MAX_TILES tile_info buffer below; the register values use the
+ * unmodified tile geometry.
+ */
+ if (tile_info->tile_cols) {
+ context_update_y =
+ tile_info->context_update_tile_id / tile_info->tile_cols;
+ context_update_x =
+ tile_info->context_update_tile_id % tile_info->tile_cols;
+ context_update_tile_id =
+ context_update_x * tile_info->tile_rows + context_update_y;
+ }
+
memset(dst, 0, av1_dec->tile_info.size);
for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
@@ -598,6 +612,10 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
tile_info->height_in_sbs_minus_1[tile1] + 1;
u32 x0 = tile_info->width_in_sbs_minus_1[tile0] + 1;
+ /* Stop once the tile_info descriptor buffer is full. */
+ if (dst + 16 > dst_end)
+ break;
+
/* tile size in SB units (width,height) */
*dst++ = x0;
*dst++ = 0;
@@ -622,6 +640,8 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx)
*dst++ = (end >> 16) & 255;
*dst++ = (end >> 24) & 255;
}
+ if (dst + 16 > dst_end)
+ break;
}
hantro_reg_write(vpu, &av1_multicore_expect_context_update, !!(context_update_x == 0));
--
2.53.0
^ permalink raw reply related
* [PATCH v3 4/9] media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
From: Michael Bommarito @ 2026-06-17 2:19 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
compute_tiles_uniform() and compute_tiles_non_uniform() loop over
num_tile_columns_minus1 + 1 / num_tile_rows_minus1 + 1 entries, and
assemble_hw_pps() writes one COLUMN_WIDTH / ROW_HEIGHT register per tile
and indexes priv_tbl->param_set[] by pic_parameter_set_id, all taken from
the untrusted PPS. Use the bounded v4l2_hevc_pps_num_tile_columns() /
v4l2_hevc_pps_num_tile_rows() helpers for the tile loops, and bail out of
assemble_hw_pps() before indexing priv_tbl->param_set[] with an
out-of-range pic_parameter_set_id, so the writes stay within the hardware
tables.
Fixes: 3595375c2301 ("media: rkvdec: Add HEVC backend")
Fixes: c9a59dc2acc7 ("media: rkvdec: Add HEVC support for the VDPU381 variant")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
.../platform/rockchip/rkvdec/rkvdec-hevc-common.c | 14 ++++++++++----
.../media/platform/rockchip/rkvdec/rkvdec-hevc.c | 7 +++++--
.../platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c | 2 ++
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
index 3119f3bc9f98b..753aef3aee51e 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c
@@ -16,6 +16,7 @@
*/
#include <linux/v4l2-common.h>
+#include <media/v4l2-hevc.h>
#include <media/v4l2-mem2mem.h>
#include "rkvdec.h"
@@ -37,15 +38,17 @@ void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size,
s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
{
const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ unsigned int num_cols = v4l2_hevc_pps_num_tile_columns(pps);
+ unsigned int num_rows = v4l2_hevc_pps_num_tile_rows(pps);
int i;
- for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++)
+ for (i = 0; i < num_cols; i++)
column_width[i] = ((i + 1) * pic_in_cts_width) /
(pps->num_tile_columns_minus1 + 1) -
(i * pic_in_cts_width) /
(pps->num_tile_columns_minus1 + 1);
- for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++)
+ for (i = 0; i < num_rows; i++)
row_height[i] = ((i + 1) * pic_in_cts_height) /
(pps->num_tile_rows_minus1 + 1) -
(i * pic_in_cts_height) /
@@ -57,17 +60,20 @@ void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size
s32 pic_in_cts_height, u16 *column_width, u16 *row_height)
{
const struct v4l2_ctrl_hevc_pps *pps = run->pps;
+ unsigned int num_cols = v4l2_hevc_pps_num_tile_columns(pps);
+ unsigned int num_rows = v4l2_hevc_pps_num_tile_rows(pps);
s32 sum = 0;
int i;
- for (i = 0; i < pps->num_tile_columns_minus1; i++) {
+ /* The last tile entry is written after the loop, so iterate one less. */
+ for (i = 0; i < num_cols - 1; i++) {
column_width[i] = pps->column_width_minus1[i] + 1;
sum += column_width[i];
}
column_width[i] = pic_in_cts_width - sum;
sum = 0;
- for (i = 0; i < pps->num_tile_rows_minus1; i++) {
+ for (i = 0; i < num_rows - 1; i++) {
row_height[i] = pps->row_height_minus1[i] + 1;
sum += row_height[i];
}
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
index ac8b825d080a2..568746dae9a61 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c
@@ -12,6 +12,7 @@
* Jeffy Chen <jeffy.chen@rock-chips.com>
*/
+#include <media/v4l2-hevc.h>
#include <media/v4l2-mem2mem.h>
#include "rkvdec.h"
@@ -156,6 +157,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
* packet unit). so the driver copy SPS/PPS information to the exact PPS
* packet unit for HW accessing.
*/
+ if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
+ return;
hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
memset(hw_ps, 0, sizeof(*hw_ps));
@@ -274,9 +277,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) {
/* Userspace also provide column width and row height for uniform spacing */
- for (i = 0; i <= pps->num_tile_columns_minus1; i++)
+ for (i = 0; i < v4l2_hevc_pps_num_tile_columns(pps); i++)
WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i));
- for (i = 0; i <= pps->num_tile_rows_minus1; i++)
+ for (i = 0; i < v4l2_hevc_pps_num_tile_rows(pps); i++)
WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i));
} else {
WRITE_PPS(((sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1,
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
index fe6414a175510..6dafa1dd28507 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c
@@ -145,6 +145,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
* packet unit). so the driver copy SPS/PPS information to the exact PPS
* packet unit for HW accessing.
*/
+ if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set))
+ return;
hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id];
memset(hw_ps, 0, sizeof(*hw_ps));
--
2.53.0
^ permalink raw reply related
* [PATCH v3 5/9] media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer capacity
From: Michael Bommarito @ 2026-06-17 2:19 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
prepare_tile_info_buffer() writes one entry per tile into the tile_sizes
DMA buffer, sized for a grid equal to the PPS uAPI array capacity. Use the
bounded v4l2_hevc_pps_num_tile_columns() / v4l2_hevc_pps_num_tile_rows()
helpers so the loops stay inside the buffer.
Fixes: cb5dd5a0fa51 ("media: hantro: Introduce G2/HEVC decoder")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
index e8c2e83379def..e7a7c7a42467a 100644
--- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
+++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c
@@ -5,6 +5,8 @@
* Copyright (C) 2020 Safran Passenger Innovations LLC
*/
+#include <media/v4l2-hevc.h>
+
#include "hantro_hw.h"
#include "hantro_g2_regs.h"
@@ -15,8 +17,8 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
u16 *p = (u16 *)((u8 *)ctx->hevc_dec.tile_sizes.cpu);
- unsigned int num_tile_rows = pps->num_tile_rows_minus1 + 1;
- unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1;
+ unsigned int num_tile_rows = v4l2_hevc_pps_num_tile_rows(pps);
+ unsigned int num_tile_cols = v4l2_hevc_pps_num_tile_columns(pps);
unsigned int pic_width_in_ctbs, pic_height_in_ctbs;
unsigned int max_log2_ctb_size, ctb_size;
bool tiles_enabled, uniform_spacing;
--
2.53.0
^ permalink raw reply related
* [PATCH v3 3/9] media: hevc: add bounded tile-count helpers
From: Michael Bommarito @ 2026-06-17 2:19 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
The stateless HEVC decoders compute the number of tile columns and rows
from num_tile_columns_minus1 / num_tile_rows_minus1 and clamp it to the
column_width_minus1[] / row_height_minus1[] capacity before using it as a
loop bound. Add shared helpers in a new <media/v4l2-hevc.h> so the rkvdec
and hantro drivers do not each open-code the min_t() clamp.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
include/media/v4l2-hevc.h | 41 +++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 include/media/v4l2-hevc.h
diff --git a/include/media/v4l2-hevc.h b/include/media/v4l2-hevc.h
new file mode 100644
index 0000000000000..973c96be16be4
--- /dev/null
+++ b/include/media/v4l2-hevc.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Helper functions for HEVC stateless codecs.
+ */
+
+#ifndef _MEDIA_V4L2_HEVC_H
+#define _MEDIA_V4L2_HEVC_H
+
+#include <linux/minmax.h>
+#include <media/v4l2-ctrls.h>
+
+/**
+ * v4l2_hevc_pps_num_tile_columns - number of HEVC tile columns, bounded
+ * @pps: the V4L2 HEVC PPS control
+ *
+ * Return the number of tile columns (num_tile_columns_minus1 + 1) clamped to
+ * the capacity of column_width_minus1[]. The control validation already
+ * rejects out-of-range counts; this keeps the consuming drivers bounded too.
+ */
+static inline unsigned int
+v4l2_hevc_pps_num_tile_columns(const struct v4l2_ctrl_hevc_pps *pps)
+{
+ return min_t(unsigned int, pps->num_tile_columns_minus1 + 1,
+ ARRAY_SIZE(pps->column_width_minus1));
+}
+
+/**
+ * v4l2_hevc_pps_num_tile_rows - number of HEVC tile rows, bounded
+ * @pps: the V4L2 HEVC PPS control
+ *
+ * Return the number of tile rows (num_tile_rows_minus1 + 1) clamped to the
+ * capacity of row_height_minus1[].
+ */
+static inline unsigned int
+v4l2_hevc_pps_num_tile_rows(const struct v4l2_ctrl_hevc_pps *pps)
+{
+ return min_t(unsigned int, pps->num_tile_rows_minus1 + 1,
+ ARRAY_SIZE(pps->row_height_minus1));
+}
+
+#endif /* _MEDIA_V4L2_HEVC_H */
--
2.53.0
^ permalink raw reply related
* [PATCH v3 2/9] media: v4l2-ctrls: validate AV1 tile counts
From: Michael Bommarito @ 2026-06-17 2:18 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
The stateless AV1 decoders use tile_info.tile_cols and tile_rows as loop
bounds and as indices into the mi_*_starts[] and *_in_sbs_minus_1[]
arrays, as the divisor for context_update_tile_id, and their product
bounds the per-tile descriptor buffers, but std_validate_compound() does
not bound these u8 fields. Reject a V4L2_CTRL_TYPE_AV1_FRAME whose
tile_cols or tile_rows exceeds V4L2_AV1_MAX_TILE_COLS / _ROWS, or whose
product exceeds V4L2_AV1_MAX_TILE_COUNT. A zero tile count is left to the
consuming driver so the zero-initialised control that existing userspace
submits is still accepted.
Fixes: 9de30f579980 ("media: Add AV1 uAPI")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
drivers/media/v4l2-core/v4l2-ctrls-core.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 6d478e1a5ef22..fb20ad13dfec7 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -790,10 +790,30 @@ static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg)
return 0;
}
+static int validate_av1_tile_info(struct v4l2_av1_tile_info *t)
+{
+ /*
+ * tile_cols and tile_rows index the per-tile descriptor arrays and
+ * bound the tile loops in the stateless AV1 drivers; the product
+ * bounds the total tile descriptor count.
+ */
+ if (t->tile_cols > V4L2_AV1_MAX_TILE_COLS ||
+ t->tile_rows > V4L2_AV1_MAX_TILE_ROWS)
+ return -EINVAL;
+
+ if ((u32)t->tile_cols * t->tile_rows > V4L2_AV1_MAX_TILE_COUNT)
+ return -EINVAL;
+
+ return 0;
+}
+
static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f)
{
int ret = 0;
+ ret = validate_av1_tile_info(&f->tile_info);
+ if (ret)
+ return ret;
ret = validate_av1_quantization(&f->quantization);
if (ret)
return ret;
--
2.53.0
^ permalink raw reply related
* [PATCH v3 1/9] media: v4l2-ctrls: validate HEVC tile counts
From: Michael Bommarito @ 2026-06-17 2:18 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
In-Reply-To: <20260617021906.2746743-1-michael.bommarito@gmail.com>
The stateless HEVC decoders read num_tile_columns_minus1 + 1 entries from
column_width_minus1[] and num_tile_rows_minus1 + 1 from row_height_minus1[]
and use them as tile-loop bounds, but std_validate_compound() does not
bound these u8 counts. Reject a V4L2_CTRL_TYPE_HEVC_PPS with tiling
enabled whose tile counts exceed the uAPI array capacity, mirroring the
existing compound-control range checks.
Fixes: 256fa3920874 ("media: v4l: Add definitions for HEVC stateless decoding")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
drivers/media/v4l2-core/v4l2-ctrls-core.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 6b375720e395c..6d478e1a5ef22 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -1242,6 +1242,18 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
p_hevc_pps->flags &=
~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
+ } else {
+ /*
+ * These count the entries the stateless HEVC drivers
+ * read from column_width_minus1[] / row_height_minus1[]
+ * and use as tile-loop bounds.
+ */
+ if (p_hevc_pps->num_tile_columns_minus1 >=
+ ARRAY_SIZE(p_hevc_pps->column_width_minus1))
+ return -EINVAL;
+ if (p_hevc_pps->num_tile_rows_minus1 >=
+ ARRAY_SIZE(p_hevc_pps->row_height_minus1))
+ return -EINVAL;
}
if (p_hevc_pps->flags &
--
2.53.0
^ permalink raw reply related
* [PATCH v3 0/9] media: bound stateless HEVC/AV1 tile counts
From: Michael Bommarito @ 2026-06-17 2:18 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Sakari Ailus,
Nicolas Dufresne
Cc: Laurent Pinchart, Benjamin Gaignard, Detlev Casanova,
Ezequiel Garcia, Yunfei Dong, Jonas Karlman, Heiko Stuebner,
Kees Cook, linux-media, linux-rockchip, linux-mediatek,
linux-kernel
The stateless HEVC and AV1 controls carry tile counts that several SoC
decoder drivers consume as loop bounds and array indices when laying out
fixed-size hardware descriptor buffers. std_validate_compound() does not
bound them, so a crafted HEVC PPS or AV1 frame control can drive
out-of-bounds writes and an AV1 divide-by-zero in the rkvdec, hantro,
rockchip and mediatek decoders.
1-2 reject out-of-range HEVC and AV1 tile counts in
std_validate_compound() (one patch per codec). For AV1 the per-
dimension bound is V4L2_AV1_MAX_TILE_{COLS,ROWS} and the total is
V4L2_AV1_MAX_TILE_COUNT.
3 add <media/v4l2-hevc.h> with bounded tile-count helpers.
4-5 use the helpers in rkvdec and hantro instead of open-coding the
clamp; rkvdec also bails before indexing the hardware
parameter-set table with an out-of-range HEVC PPS id.
6 guard the rockchip VPU981 AV1 divisor against tile_cols == 0 and
keep the descriptor writes inside the AV1_MAX_TILES buffer.
7 reject a rockchip AV1 frame whose tile_cols * tile_rows exceeds the
submitted tile group entry count or the AV1_MAX_TILES descriptor
capacity, which set_tile_info() would otherwise read past or leave
under-described while programming the larger geometry.
8 bound the mediatek AV1 tile-start copy.
9 KUnit coverage for the tile-count validation.
Changes since v2:
- Split the combined HEVC+AV1 validation into one patch per codec, each
with a single Fixes tag (Benjamin Gaignard).
- Move the AV1 total-tile bound into validate_av1_tile_info() using the
uAPI V4L2_AV1_MAX_TILE_COUNT, instead of clamping tile_cols/tile_rows
in the rockchip driver, which would have corrupted the values written
to the hardware registers (Benjamin Gaignard's NACK on v2 4/6).
- Add <media/v4l2-hevc.h> with shared bounded tile-count helpers so
rkvdec and hantro no longer duplicate the clamp (Benjamin Gaignard).
- New patch 7: reject a rockchip AV1 frame that claims more tiles than
the submitted tile group entry array holds (set_tile_info() indexes
it by tile_cols * tile_rows) or more than AV1_MAX_TILES (the hardware
descriptor buffer), which would otherwise leave the hardware
programmed for more tiles than the buffer describes. mediatek already
guards the entry count; rockchip now guards both.
checkpatch --strict: 0 errors on all nine. Patches 3 and 9 each carry one
"added file ... does MAINTAINERS need updating?" warning for the new
<media/v4l2-hevc.h> and the KUnit test file; both already fall under the
existing include/media/ and drivers/media/v4l2-core/ MAINTAINERS entries,
so no MAINTAINERS change is needed. (checkpatch's SPDX sub-check did not
run in my environment -- spdxcheck.py needs python3-ply -- but the SPDX
headers are present on both new files.)
The tile-count validation is exercised with KUnit (patch 9): in-range
HEVC/AV1 counts pass, out-of-range per-dimension counts and an AV1 grid
whose product exceeds V4L2_AV1_MAX_TILE_COUNT are rejected, and the
zero-initialised AV1 frame control that v4l2-compliance and existing
userspace submit still passes.
v2: https://lore.kernel.org/all/20260614155609.3107600-1-michael.bommarito@gmail.com/
Michael Bommarito (9):
media: v4l2-ctrls: validate HEVC tile counts
media: v4l2-ctrls: validate AV1 tile counts
media: hevc: add bounded tile-count helpers
media: rkvdec: bound HEVC tile loops and PPS id to the array capacity
media: verisilicon: hantro: bound G2 HEVC tile loop to the buffer
capacity
media: verisilicon: rockchip: guard VPU981 AV1 divisor and tile buffer
media: verisilicon: rockchip: reject AV1 frames exceeding the tile
capacity
media: mediatek: vcodec: bound AV1 tile-start copy to the array
capacity
media: v4l2-ctrls: add KUnit tests for compound control tile
validation
.../vcodec/decoder/vdec/vdec_av1_req_lat_if.c | 5 +-
.../rockchip/rkvdec/rkvdec-hevc-common.c | 14 +-
.../platform/rockchip/rkvdec/rkvdec-hevc.c | 7 +-
.../rockchip/rkvdec/rkvdec-vdpu381-hevc.c | 2 +
.../platform/verisilicon/hantro_g2_hevc_dec.c | 6 +-
.../verisilicon/rockchip_vpu981_hw_av1_dec.c | 57 +++++--
drivers/media/v4l2-core/Kconfig | 12 ++
.../media/v4l2-core/v4l2-ctrls-core-test.c | 145 ++++++++++++++++++
drivers/media/v4l2-core/v4l2-ctrls-core.c | 36 +++++
include/media/v4l2-hevc.h | 41 +++++
10 files changed, 306 insertions(+), 19 deletions(-)
create mode 100644 drivers/media/v4l2-core/v4l2-ctrls-core-test.c
create mode 100644 include/media/v4l2-hevc.h
base-commit: e24a98d6884a6e4203a77a94f070a59fcab95208
--
2.53.0
^ permalink raw reply
* Re: [PATCH v1] Bluetooth: btmtk: Add MT7928 support
From: Chris Lu (陸稚泓) @ 2026-06-17 2:16 UTC (permalink / raw)
To: pmenzel@molgen.mpg.de
Cc: Will-CY Lee (李政穎),
Steve Lee (李視誠), luiz.dentz@gmail.com,
marcel@holtmann.org, SS Wu (巫憲欣),
linux-kernel@vger.kernel.org, johan.hedberg@gmail.com, Sean Wang,
linux-bluetooth@vger.kernel.org,
linux-mediatek@lists.infradead.org
In-Reply-To: <6b29b553-d703-448d-9275-62912a62e356@molgen.mpg.de>
Hi Paul,
On Tue, 2026-06-16 at 12:24 +0200, Paul Menzel wrote:
>
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> Dear Chris,
>
>
> Thank you for your patch.
>
> Am 16.06.26 um 05:01 schrieb Chris Lu:
> > Add support for MT7928 (device ID 0x7935) which requires additional
> > firmware (CBMCU firmware) loading before Bluetooth firmware.
>
> Please detail what CBMCU firmware is.
CBMCU is a new component on MT7928 to handle common part shared across
the combo chip (Wi-Fi/Bluetooth's subsystem), providing a better user
experience through improved coordination between subsystems.
>
> > Implement two-phase CBMCU firmware download: Phase 1 loads
> > section with type 0x5 containing global descriptor,
> > section maps and signature data; Phase 2 loads remaining
> > firmware sections. Add retry mechanism for concurrent download
> > protection.
>
> What is type 0x5? How big is the firmware, and how long does it take?
>
> > After CBMCU firmware loads successfully, the driver continues
> > to load corresponding BT firmware based on device ID through
> > fallthrough to case 0x7922/0x7925.
>
> Please add the new log message to the commit message.
>
> > Signed-off-by: Chris Lu <chris.lu@mediatek.com>
> > ---
> > drivers/bluetooth/btmtk.c | 342
> > +++++++++++++++++++++++++++++++++++++-
> > drivers/bluetooth/btmtk.h | 3 +
> > 2 files changed, 344 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c
> > index 02a96342e964..a68c67d1df4b 100644
> > --- a/drivers/bluetooth/btmtk.c
> > +++ b/drivers/bluetooth/btmtk.c
> > @@ -21,6 +21,7 @@
> > #define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64
> > #define MTK_SEC_MAP_COMMON_SIZE 12
> > #define MTK_SEC_MAP_NEED_SEND_SIZE 52
> > +#define MTK_SEC_MAP_LENGTH_SIZE 4
> >
> > /* It is for mt79xx iso data transmission setting */
> > #define MTK_ISO_THRESHOLD 264
> > @@ -120,6 +121,10 @@ void btmtk_fw_get_filename(char *buf, size_t
> > size, u32 dev_id, u32 fw_ver,
> > snprintf(buf, size,
> >
> > "mediatek/mt%04x/BT_RAM_CODE_MT%04x_1_%x_hdr.bin",
> > dev_id & 0xffff, dev_id & 0xffff, (fw_ver &
> > 0xff) + 1);
> > + else if (dev_id == 0x7935)
> > + snprintf(buf, size,
> > +
> > "mediatek/mt7928/BT_RAM_CODE_MT%04x_1_1_hdr.bin",
> > + dev_id & 0xffff);
> > else if (dev_id == 0x7961 && fw_flavor)
> > snprintf(buf, size,
> > "mediatek/BT_RAM_CODE_MT%04x_1a_%x_hdr.bin",
> > @@ -734,6 +739,7 @@ static int btmtk_usb_hci_wmt_sync(struct
> > hci_dev *hdev,
> > status = BTMTK_WMT_ON_UNDONE;
> > break;
> > case BTMTK_WMT_PATCH_DWNLD:
> > + case BTMTK_WMT_CBMCU_DWNLD:
> > if (wmt_evt->whdr.flag == 2)
> > status = BTMTK_WMT_PATCH_DONE;
> > else if (wmt_evt->whdr.flag == 1)
> > @@ -870,6 +876,329 @@ static u32 btmtk_usb_reset_done(struct
> > hci_dev *hdev)
> > return val & MTK_BT_RST_DONE;
> > }
> >
> > +static int btmtk_cbmcu_patch_status(struct hci_dev *hdev,
> > + wmt_cmd_sync_func_t wmt_cmd_sync,
> > + u8 *patch_status)
> > +{
> > + struct btmtk_hci_wmt_params wmt_params;
> > + int status, err, retry = 20;
> > +
> > + do {
> > + wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
> > + wmt_params.flag = 0xF0;
> > + wmt_params.dlen = 0;
> > + wmt_params.data = NULL;
> > + wmt_params.status = &status;
> > +
> > + err = wmt_cmd_sync(hdev, &wmt_params);
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to query CBMCU patch
> > status (%d)", err);
> > + return err;
> > + }
> > +
> > + *patch_status = (u8)status;
> > +
> > + if (*patch_status == BTMTK_WMT_PATCH_PROGRESS) {
> > + msleep(100);
> > + retry--;
> > + } else {
> > + break;
> > + }
> > + } while (retry > 0);
> > +
> > + return 0;
> > +}
> > +
> > +static int btmtk_query_cbmcu_section(struct hci_dev *hdev,
> > + wmt_cmd_sync_func_t
> > wmt_cmd_sync,
> > + u8 cbmcu_type,
> > + const u8 *section_map,
> > + u32 cert_len)
> > +{
> > + struct btmtk_hci_wmt_params wmt_params;
> > + u8 cmd[64];
> > + int status, err;
> > +
> > + cmd[0] = 0;
> > + cmd[1] = cbmcu_type;
> > +
> > + if (cbmcu_type == 0)
> > + put_unaligned_le32(cert_len, &cmd[2]);
> > + else
> > + memcpy(&cmd[2], section_map,
> > MTK_SEC_MAP_NEED_SEND_SIZE);
> > +
> > + wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
> > + wmt_params.flag = 0;
> > + wmt_params.dlen = cbmcu_type ?
> > + MTK_SEC_MAP_NEED_SEND_SIZE + 2 :
> > + MTK_SEC_MAP_LENGTH_SIZE + 2;
> > + wmt_params.data = cmd;
> > + wmt_params.status = &status;
> > +
> > + err = wmt_cmd_sync(hdev, &wmt_params);
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to query CBMCU section
> > (%d)", err);
> > + return err;
> > + }
> > +
> > + /* Query should return UNDONE status for successful section
> > query */
> > + if (status != BTMTK_WMT_PATCH_UNDONE) {
> > + bt_dev_err(hdev, "CBMCU section query status error
> > (%d)", status);
> > + return -EIO;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int btmtk_download_cbmcu_section(struct hci_dev *hdev,
> > + wmt_cmd_sync_func_t
> > wmt_cmd_sync,
> > + const u8 *fw_data,
> > + u32 dl_size)
> > +{
> > + struct btmtk_hci_wmt_params wmt_params;
> > + u32 sent_len, total_size = dl_size;
> > + int err;
> > +
> > + wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
> > + wmt_params.status = NULL;
> > +
> > + while (dl_size > 0) {
> > + sent_len = min_t(u32, 250, dl_size);
> > +
> > + if (dl_size == total_size)
> > + wmt_params.flag = 1;
> > + else if (dl_size == sent_len)
> > + wmt_params.flag = 3;
> > + else
> > + wmt_params.flag = 2;
> > +
> > + wmt_params.dlen = sent_len;
> > + wmt_params.data = fw_data;
> > +
> > + err = wmt_cmd_sync(hdev, &wmt_params);
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to send CBMCU
> > section data (%d)", err);
> > + return err;
> > + }
> > +
> > + dl_size -= sent_len;
> > + fw_data += sent_len;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int btmtk_enable_cbmcu_patch(struct hci_dev *hdev,
> > + wmt_cmd_sync_func_t wmt_cmd_sync)
> > +{
> > + struct btmtk_hci_wmt_params wmt_params;
> > + int err;
> > +
> > + wmt_params.op = BTMTK_WMT_CBMCU_DWNLD;
> > + wmt_params.flag = 0xF1;
> > + wmt_params.dlen = 0;
> > + wmt_params.data = NULL;
> > + wmt_params.status = NULL;
> > +
> > + err = wmt_cmd_sync(hdev, &wmt_params);
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to enable CBMCU patch (%d)",
> > err);
> > + return err;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int btmtk_load_cbmcu_firmware(struct hci_dev *hdev,
> > + const char *fwname,
> > + wmt_cmd_sync_func_t
> > wmt_cmd_sync)
> > +{
> > + struct btmtk_patch_header *hdr;
> > + struct btmtk_global_desc *globaldesc;
> > + struct btmtk_section_map *sectionmap;
> > + const struct firmware *fw;
> > + const u8 *fw_ptr;
> > + u8 *cert_buf = NULL;
> > + u32 section_num, section_offset, dl_size, cert_len;
> > + int i, err;
> > +
> > + err = request_firmware(&fw, fwname, &hdev->dev);
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to load CBMCU firmware file
> > (%d)", err);
>
> Please add fwname to the error message.
>
> > + return err;
> > + }
> > +
> > + if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE +
> > MTK_FW_ROM_PATCH_GD_SIZE) {
> > + bt_dev_err(hdev, "CBMCU firmware too small (%zu
> > bytes)", fw->size);
>
> Please add the limit to the error message.
>
> > + err = -EINVAL;
> > + goto err_release_fw;
> > + }
> > +
> > + fw_ptr = fw->data;
> > + hdr = (struct btmtk_patch_header *)fw_ptr;
> > + globaldesc = (struct btmtk_global_desc *)(fw_ptr +
> > MTK_FW_ROM_PATCH_HEADER_SIZE);
> > + section_num = le32_to_cpu(globaldesc->section_num);
> > +
> > + if (fw->size < MTK_FW_ROM_PATCH_HEADER_SIZE +
> > MTK_FW_ROM_PATCH_GD_SIZE +
> > + (size_t)MTK_FW_ROM_PATCH_SEC_MAP_SIZE *
> > section_num) {
> > + bt_dev_err(hdev, "CBMCU firmware truncated
> > (section_num=%u)", section_num);
>
> Please log the values from the if condition.
>
> > + err = -EINVAL;
> > + goto err_release_fw;
> > + }
> > +
> > + bt_dev_info(hdev, "CBMCU Version: 0x%04x%04x, Build Time:
> > %s",
> > + le16_to_cpu(hdr->hwver), le16_to_cpu(hdr->swver),
> > hdr->datetime);
> > +
> > + /* Phase 1: Download section type 0x5 */
>
> Please define a macro or enum for 0x5.
>
> > + for (i = 0; i < section_num; i++) {
> > + sectionmap = (struct btmtk_section_map *)
> > + (fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
> > + MTK_FW_ROM_PATCH_GD_SIZE +
> > + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
> > +
> > + /* Only process type 0x5 section in Phase 1 */
> > + if ((le32_to_cpu(sectionmap->sectype) & 0xFFFF) !=
> > 0x5)
> > + continue;
> > +
> > + section_offset = le32_to_cpu(sectionmap->secoffset);
> > + dl_size = le32_to_cpu(sectionmap->secsize);
> > +
> > + if (dl_size == 0)
> > + continue;
> > +
> > + if (section_offset > fw->size ||
> > + dl_size > fw->size - section_offset) {
> > + bt_dev_err(hdev, "CBMCU Phase 1 section out
> > of bounds");
> > + err = -EINVAL;
> > + goto err_release_fw;
> > + }
> > +
> > + cert_len = MTK_FW_ROM_PATCH_GD_SIZE +
> > + MTK_FW_ROM_PATCH_SEC_MAP_SIZE *
> > section_num +
> > + dl_size;
> > +
> > + /* Query cbmcu section */
> > + err = btmtk_query_cbmcu_section(hdev, wmt_cmd_sync,
> > 0, NULL,
> > + cert_len);
> > + if (err < 0)
> > + goto err_release_fw;
> > +
> > + cert_buf = kmalloc(cert_len, GFP_KERNEL);
> > + if (!cert_buf) {
> > + err = -ENOMEM;
> > + goto err_release_fw;
> > + }
> > +
> > + /* Copy Global Descriptor + All Section Maps */
> > + memcpy(cert_buf,
> > + fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE,
> > + MTK_FW_ROM_PATCH_GD_SIZE +
> > MTK_FW_ROM_PATCH_SEC_MAP_SIZE * section_num);
> > +
> > + /* Copy Phase 1 section data */
> > + memcpy(cert_buf + MTK_FW_ROM_PATCH_GD_SIZE +
> > + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * section_num,
> > + fw_ptr + section_offset,
> > + dl_size);
> > +
> > + /* Download Phase 1 section */
> > + err = btmtk_download_cbmcu_section(hdev,
> > wmt_cmd_sync,
> > + cert_buf,
> > cert_len);
> > + kfree(cert_buf);
> > + cert_buf = NULL;
> > +
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to download CBMCU
> > Phase 1 section (%d)", err);
> > + goto err_release_fw;
> > + }
> > +
> > + break;
> > + }
> > +
> > + /* Phase 2: Download other sections (type != 0x5) */
> > + for (i = 0; i < section_num; i++) {
> > + sectionmap = (struct btmtk_section_map *)
> > + (fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
> > + MTK_FW_ROM_PATCH_GD_SIZE +
> > + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
> > +
> > + /* Skip type 0x5 section in Phase 2 */
> > + if ((le32_to_cpu(sectionmap->sectype) & 0xFFFF) ==
> > 0x5)
> > + continue;
> > +
> > + section_offset = le32_to_cpu(sectionmap->secoffset);
> > + dl_size = le32_to_cpu(sectionmap-
> > >bin_info_spec.dlsize);
> > +
> > + if (dl_size == 0)
> > + continue;
> > +
> > + if (section_offset > fw->size ||
> > + dl_size > fw->size - section_offset) {
> > + bt_dev_err(hdev, "CBMCU Phase 2 section %d
> > out of bounds", i);
> > + err = -EINVAL;
> > + goto err_release_fw;
> > + }
> > +
> > + /* Query cbmcu section */
> > + err = btmtk_query_cbmcu_section(hdev, wmt_cmd_sync,
> > 1,
> > + (u8 *)§ionmap-
> > >bin_info_spec,
> > + 0);
> > + if (err < 0)
> > + goto err_release_fw;
> > +
> > + /* Download section data */
> > + err = btmtk_download_cbmcu_section(hdev,
> > wmt_cmd_sync,
> > + fw_ptr +
> > section_offset,
> > + dl_size);
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to download CBMCU
> > section %d (%d)", i, err);
> > + goto err_release_fw;
> > + }
> > + }
> > +
> > + /* Wait for firmware activation */
> > + usleep_range(100000, 120000);
> > +
> > + bt_dev_info(hdev, "CBMCU firmware download completed");
> > +
> > +err_release_fw:
> > + release_firmware(fw);
> > + return err;
> > +}
> > +
> > +static int btmtk_setup_cbmcu_firmware(struct hci_dev *hdev,
> > + wmt_cmd_sync_func_t
> > wmt_cmd_sync,
> > + u32 dev_id)
> > +{
> > + char cbmcu_fwname[64];
> > + u8 patch_status;
> > + int err;
> > +
> > + err = btmtk_cbmcu_patch_status(hdev, wmt_cmd_sync,
> > &patch_status);
> > + if (err < 0)
> > + return err;
> > +
> > + bt_dev_dbg(hdev, "CBMCU patch status: 0x%02x", patch_status);
> > +
> > + if (patch_status != BTMTK_WMT_PATCH_UNDONE)
> > + return 0;
> > +
> > + snprintf(cbmcu_fwname, sizeof(cbmcu_fwname),
> > + "mediatek/mt7928/CBMCU_CODE_MT%04x_1_1.bin",
> > + dev_id & 0xffff);
> > +
> > + err = btmtk_load_cbmcu_firmware(hdev, cbmcu_fwname,
> > wmt_cmd_sync);
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to download CBMCU firmware
> > (%d)", err);
> > + return err;
> > + }
> > +
> > + err = btmtk_enable_cbmcu_patch(hdev, wmt_cmd_sync);
> > + if (err < 0)
> > + return err;
> > +
> > + return 0;
> > +}
> > +
> > int btmtk_usb_subsys_reset(struct hci_dev *hdev, u32 dev_id)
> > {
> > u32 val;
> > @@ -894,7 +1223,7 @@ int btmtk_usb_subsys_reset(struct hci_dev
> > *hdev, u32 dev_id)
> > if (err < 0)
> > return err;
> > msleep(100);
> > - } else if (dev_id == 0x7925 || dev_id == 0x6639) {
> > + } else if (dev_id == 0x7925 || dev_id == 0x6639 || dev_id ==
> > 0x7935) {
> > err = btmtk_usb_uhw_reg_read(hdev,
> > MTK_BT_RESET_REG_CONNV3, &val);
> > if (err < 0)
> > return err;
> > @@ -1379,6 +1708,15 @@ int btmtk_usb_setup(struct hci_dev *hdev)
> > case 0x7668:
> > fwname = FIRMWARE_MT7668;
> > break;
> > + case 0x7935:
> > + /* Requires CBMCU firmware before BT firmware */
> > + err = btmtk_setup_cbmcu_firmware(hdev,
> > btmtk_usb_hci_wmt_sync,
> > + dev_id);
> > + if (err < 0) {
> > + bt_dev_err(hdev, "Failed to set up CBMCU
> > firmware (%d)", err);
> > + return err;
> > + }
> > + fallthrough;
> > case 0x7922:
> > case 0x7925:
> > /*
> > @@ -1596,3 +1934,5 @@ MODULE_FIRMWARE(FIRMWARE_MT7922);
> > MODULE_FIRMWARE(FIRMWARE_MT7961);
> > MODULE_FIRMWARE(FIRMWARE_MT7925);
> > MODULE_FIRMWARE(FIRMWARE_MT7927);
> > +MODULE_FIRMWARE(FIRMWARE_MT7928);
> > +MODULE_FIRMWARE(FIRMWARE_MT7928_CBMCU);
> > diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
> > index c83c24897c95..6d3bf6b74a1d 100644
> > --- a/drivers/bluetooth/btmtk.h
> > +++ b/drivers/bluetooth/btmtk.h
> > @@ -9,6 +9,8 @@
> > #define FIRMWARE_MT7961
> > "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
> > #define FIRMWARE_MT7925
> > "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
> > #define FIRMWARE_MT7927
> > "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
> > +#define FIRMWARE_MT7928
> > "mediatek/mt7928/BT_RAM_CODE_MT7935_1_1_hdr.bin"
> > +#define FIRMWARE_MT7928_CBMCU
> > "mediatek/mt7928/CBMCU_CODE_MT7935_1_1.bin"
> >
> > #define HCI_EV_WMT 0xe4
> > #define HCI_WMT_MAX_EVENT_SIZE 64
> > @@ -54,6 +56,7 @@ enum {
> > BTMTK_WMT_RST = 0x7,
> > BTMTK_WMT_REGISTER = 0x8,
> > BTMTK_WMT_SEMAPHORE = 0x17,
> > + BTMTK_WMT_CBMCU_DWNLD = 0x58,
> > };
> >
> > enum {
>
>
> Kind regards,
>
> Paul
Thanks for the review, I'll revise the error message to be more
informative and replace the magic number with proper macro. A v2 will
be sent out shortly.
Chris Lu
^ permalink raw reply
* Re: [PATCH v1] Bluetooth: btmtk: Add MT7928 support
From: Chris Lu (陸稚泓) @ 2026-06-17 1:53 UTC (permalink / raw)
To: luiz.dentz@gmail.com, johan.hedberg@gmail.com,
marcel@holtmann.org, pav@iki.fi
Cc: Sean Wang, linux-mediatek@lists.infradead.org,
SS Wu (巫憲欣),
Steve Lee (李視誠),
Will-CY Lee (李政穎),
linux-bluetooth@vger.kernel.org
In-Reply-To: <cb14eaa1c566ed30119ca66bff0484192f852e91.camel@iki.fi>
Hi Pauli,
On Tue, 2026-06-16 at 17:38 +0300, Pauli Virtanen wrote:
>
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
>
>
> Hi,
>
> ti, 2026-06-16 kello 11:01 +0800, Chris Lu kirjoitti:
> > Add support for MT7928 (device ID 0x7935) which requires additional
> > firmware (CBMCU firmware) loading before Bluetooth firmware.
> >
> > Implement two-phase CBMCU firmware download: Phase 1 loads
> > section with type 0x5 containing global descriptor,
> > section maps and signature data; Phase 2 loads remaining
> > firmware sections. Add retry mechanism for concurrent download
> > protection.
> >
> > After CBMCU firmware loads successfully, the driver continues
> > to load corresponding BT firmware based on device ID through
> > fallthrough to case 0x7922/0x7925.
> >
> > Signed-off-by: Chris Lu <chris.lu@mediatek.com>
> > ---
> [clip]
> > diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h
> > index c83c24897c95..6d3bf6b74a1d 100644
> > --- a/drivers/bluetooth/btmtk.h
> > +++ b/drivers/bluetooth/btmtk.h
> > @@ -9,6 +9,8 @@
> > #define FIRMWARE_MT7961
> > "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
> > #define FIRMWARE_MT7925
> > "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"
> > #define FIRMWARE_MT7927
> > "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
> > +#define FIRMWARE_MT7928
> > "mediatek/mt7928/BT_RAM_CODE_MT7935_1_1_hdr.bin"
> > +#define FIRMWARE_MT7928_CBMCU
> > "mediatek/mt7928/CBMCU_CODE_MT7935_1_1.bin"
>
> Are these firmware names correct?
>
> The above names for MT7928 say MT79**35** not MT7928?
The naming is intentional,
MT7928 is the external/marketing name, while MT7935 is MediaTek's
internal codename for same chip. The firmware filename follows and
generate with internal codename. Windows PC paired with MT7928 also
follows this rule.
>
> >
> > #define HCI_EV_WMT 0xe4
> > #define HCI_WMT_MAX_EVENT_SIZE 64
> > @@ -54,6 +56,7 @@ enum {
> > BTMTK_WMT_RST = 0x7,
> > BTMTK_WMT_REGISTER = 0x8,
> > BTMTK_WMT_SEMAPHORE = 0x17,
> > + BTMTK_WMT_CBMCU_DWNLD = 0x58,
> > };
> >
> > enum {
>
> --
> Pauli Virtanen
Chris Lu
^ permalink raw reply
* Re: [PATCH v2 3/3] Bluetooth: btmtksdio: call cancel_work_sync() outside of host lock scope
From: Sean Wang @ 2026-06-17 0:56 UTC (permalink / raw)
To: Sergey Senozhatsky
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Mark-yw Chen, Sean Wang,
Tomasz Figa, linux-bluetooth, linux-kernel, linux-arm-kernel,
linux-mediatek, stable
In-Reply-To: <20260616111224.152140-4-senozhatsky@chromium.org>
Hi,
On Tue, Jun 16, 2026 at 6:15 AM Sergey Senozhatsky
<senozhatsky@chromium.org> wrote:
>
> cancel_work_sync() should be called outside of host lock scope
> in order to avoid circular locking scenario:
>
> CPU0 CPU1
> close()/reset()
> sdio_claim_host()
> txrx_work
> sdio_claim_host() // sleeps
> cancel_work_sync() // sleeps
>
> In addition, when txrx_work() runs concurrently with close()/reset()
> it better not to re-enable interrupts by testing for BTMTKSDIO_FUNC_ENABLED
> and not BTMTKSDIO_HW_RESET_ACTIVE before C_INT_EN_SET write. However,
> btmtksdio_close() clears the BTMTKSDIO_FUNC_ENABLED too late (after
> cancel_work_sync() call). Move BTMTKSDIO_FUNC_ENABLED bit-clear earlier
> so that txrx_work can see concurrent close().
>
> Fixes: 26270bc189ea4 ("Bluetooth: btmtksdio: move interrupt service to work")
> Cc: stable@vger.kernel.org
> Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
> ---
> drivers/bluetooth/btmtksdio.c | 12 ++++++++++--
> 1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
> index d8c8d2857527..207d04cc2282 100644
> --- a/drivers/bluetooth/btmtksdio.c
> +++ b/drivers/bluetooth/btmtksdio.c
> @@ -625,7 +625,9 @@ static void btmtksdio_txrx_work(struct work_struct *work)
> } while (int_status && time_is_after_jiffies(txrx_timeout));
>
> /* Enable interrupt */
> - if (bdev->func->irq_handler)
> + if (bdev->func->irq_handler &&
> + test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state) &&
> + !test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
> sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
>
> sdio_release_host(bdev->func);
> @@ -741,6 +743,8 @@ static int btmtksdio_close(struct hci_dev *hdev)
> if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
> return 0;
>
> + clear_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state);
> +
> sdio_claim_host(bdev->func);
>
> /* Disable interrupt */
> @@ -748,11 +752,12 @@ static int btmtksdio_close(struct hci_dev *hdev)
>
> sdio_release_irq(bdev->func);
>
> + sdio_release_host(bdev->func);
> cancel_work_sync(&bdev->txrx_work);
> + sdio_claim_host(bdev->func);
>
> btmtksdio_fw_pmctrl(bdev);
>
> - clear_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state);
> sdio_disable_func(bdev->func);
>
> sdio_release_host(bdev->func);
> @@ -1295,7 +1300,10 @@ static void btmtksdio_reset(struct hci_dev *hdev)
>
> sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
> skb_queue_purge(&bdev->txq);
> +
> + sdio_release_host(bdev->func);
> cancel_work_sync(&bdev->txrx_work);
> + sdio_claim_host(bdev->func);
>
> gpiod_set_value_cansleep(bdev->reset, 1);
> msleep(100);
The patch looks good to me. Inspired by your patch,
do you think should we add another patch to keep txrx_work out of the
reset window by rejecting TX during reset,
ignoring reset-time interrupts, and making queued workers exit early?
Some code like:
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -567,6 +567,8 @@ static void btmtksdio_txrx_work(struct work_struct *work)
pm_runtime_get_sync(bdev->dev);
sdio_claim_host(bdev->func);
+ if (test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
+ goto out;
/* Disable interrupt */
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
@@ -628,6 +630,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
!test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
sdio_writel(bdev->func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
+out:
sdio_release_host(bdev->func);
pm_runtime_put_autosuspend(bdev->dev);
@@ -646,6 +649,9 @@ static void btmtksdio_interrupt(struct sdio_func *func)
/* Disable interrupt */
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
+ if (test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
+ return;
+
schedule_work(&bdev->txrx_work);
}
@@ -1250,6 +1256,9 @@ static int btmtksdio_send_frame(struct hci_dev
*hdev, struct sk_buff *skb)
{
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
+ if (test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
+ return -EBUSY;
+
switch (hci_skb_pkt_type(skb)) {
case HCI_COMMAND_PKT:
hdev->stat.cmd_tx++;
> --
> 2.54.0.1136.gdb2ca164c4-goog
>
>
^ permalink raw reply
* Re: [PATCH v2 1/3] Bluetooth: btmtksdio: correct btmtksdio_txrx_work() loop timeout check
From: Sean Wang @ 2026-06-17 0:40 UTC (permalink / raw)
To: Sergey Senozhatsky
Cc: Marcel Holtmann, Luiz Augusto von Dentz, Mark-yw Chen, Sean Wang,
Tomasz Figa, linux-bluetooth, linux-kernel, linux-arm-kernel,
linux-mediatek, stable
In-Reply-To: <20260616111224.152140-2-senozhatsky@chromium.org>
Hi,
On Tue, Jun 16, 2026 at 6:15 AM Sergey Senozhatsky
<senozhatsky@chromium.org> wrote:
>
> The btmtksdio_txrx_work() loop is expected to be terminated if running
> for longer than 5*HZ. However the timeout check is reversed:
> time_is_before_jiffies(old_jiffies + 5*HZ) evaluates to true when
> old_jiffies + 5*HZ is in the past i.e. when a timeout has occurred.
> Using OR with time_is_before_jiffies(txrx_timeout) means that:
> - before the 5-second timeout: the condition is `int_status || false`,
> so it loops as long as there are pending interrupts.
> - after the 5-second timeout: the condition becomes `int_status || true`,
> which is always true.
>
> Fix loop termination condition to actually enforce a 5*HZ timeout.
>
> Fixes: 26270bc189ea4 ("Bluetooth: btmtksdio: move interrupt service to work")
> Cc: stable@vger.kernel.org
> Signed-off-by: Sergey Senozhatsky <senozhatsky@chromium.org>
> ---
> drivers/bluetooth/btmtksdio.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c
> index 5b0fab7b89b5..c6f80c419e90 100644
> --- a/drivers/bluetooth/btmtksdio.c
> +++ b/drivers/bluetooth/btmtksdio.c
> @@ -620,7 +620,7 @@ static void btmtksdio_txrx_work(struct work_struct *work)
> if (btmtksdio_rx_packet(bdev, rx_size) < 0)
> bdev->hdev->stat.err_rx++;
> }
> - } while (int_status || time_is_before_jiffies(txrx_timeout));
> + } while (int_status && time_is_after_jiffies(txrx_timeout));
>
This patch has already been merged, so I think the series should be
respun based on the latest code.
> /* Enable interrupt */
> if (bdev->func->irq_handler)
> --
> 2.54.0.1136.gdb2ca164c4-goog
>
>
^ permalink raw reply
* Re: [PATCH v2] [net] net: airoha: Fix QoS counter configuration for Tx-fwd channels
From: patchwork-bot+netdevbpf @ 2026-06-16 22:11 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <178161132384.2164449.18407700117859190327@gmail.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 16 Jun 2026 18:50:29 +0800 you wrote:
> In airoha_qdma_init_qos_stats(), the Tx-fwd counter was incorrectly
> using register index (i << 1) instead of ((i << 1) + 1). This caused
> the Tx-fwd configuration to overwrite the Tx-cpu configuration for
> each QoS channel, resulting in incorrect QoS statistics.
>
> Fix by using the correct register index ((i << 1) + 1) for Tx-fwd
> counter configuration.
>
> [...]
Here is the summary with links:
- [v2,net] net: airoha: Fix QoS counter configuration for Tx-fwd channels
https://git.kernel.org/netdev/net-next/c/1402ecccf563
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH] net: airoha: Fix QoS counter configuration for Tx-fwd channels
From: patchwork-bot+netdevbpf @ 2026-06-16 22:11 UTC (permalink / raw)
To: Wayen Yan
Cc: netdev, lorenzo, horms, pabeni, kuba, edumazet, andrew+netdev,
angelogioacchino.delregno, matthias.bgg, linux-arm-kernel,
linux-mediatek
In-Reply-To: <178160712947.2156222.3765685889775458986@gmail.com>
Hello:
This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 16 Jun 2026 18:50:29 +0800 you wrote:
> In airoha_qdma_init_qos_stats(), the Tx-fwd counter was incorrectly
> using register index (i << 1) instead of ((i << 1) + 1). This caused
> the Tx-fwd configuration to overwrite the Tx-cpu configuration for
> each QoS channel, resulting in incorrect QoS statistics.
>
> Fix by using the correct register index ((i << 1) + 1) for Tx-fwd
> counter configuration.
>
> [...]
Here is the summary with links:
- net: airoha: Fix QoS counter configuration for Tx-fwd channels
https://git.kernel.org/netdev/net-next/c/1402ecccf563
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v7 9/9] arm64: dts: mediatek: Add MediaTek MT6392 PMIC dtsi
From: Rob Herring @ 2026-06-16 18:57 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Val Packett, Dmitry Torokhov, Krzysztof Kozlowski,
Conor Dooley, Sen Chu, Sean Wang, Macpaul Lin, Lee Jones,
Matthias Brugger, AngeloGioacchino Del Regno, Liam Girdwood,
Mark Brown, Linus Walleij, Louis-Alexis Eyraud, Julien Massot,
Fabien Parent, Akari Tsuyukusa, Chen Zhong, linux-input,
devicetree, linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <CAORyz2LiMHnaTK6QnsLxJDtw0fZ_N9LELw0iCorOZwHuWXus0g@mail.gmail.com>
On Tue, Jun 16, 2026 at 10:32 AM Luca Leonardo Scorcia
<l.scorcia@gmail.com> wrote:
>
> > > arch/arm64/boot/dts/mediatek/mt6392.dtsi | 75 ++++++++++++++++++++++++
> >
> > Nothing is using this so it is a dead file that doesn't get tested.
>
> Hi, it's not referenced as the dtsi inclusion was removed in the
> original patch from 2019 for an easier merging of support for mt8516
> pumpkin boards [1][2].
> If you prefer in the next revision I can add another patch to readd it
> to the existing pumpkin board.
That or move this patch to the series for the board(s). If the board
is already upstream, then add the include in *this* patch.
Rob
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox