Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next v6 0/3] net: dsa: motorcomm: Add LED support
From: David Yang @ 2026-07-09  1:47 UTC (permalink / raw)
  To: netdev
  Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel

v5: https://lore.kernel.org/r/20260707064752.1030345-1-mmyangfl@gmail.com
  - improve trigger selection
v4: https://lore.kernel.org/r/20260703165241.542195-1-mmyangfl@gmail.com
  - fix some reg op typos
v3: https://lore.kernel.org/r/20260701155519.273212-1-mmyangfl@gmail.com
  - fix null pointer dereference
  - support polarity auto-configuration
v2: https://lore.kernel.org/r/20260629183137.541341-1-mmyangfl@gmail.com
  - allocate LED structures only
  - eliminate double locking
v1: https://lore.kernel.org/r/20260618202716.2166450-1-mmyangfl@gmail.com
  - set up polarity correctly
  - do not set up .brightness_get() to prevent dead lock

David Yang (3):
  net: dsa: motorcomm: Move to subdirectory
  net: dsa: motorcomm: Split SMI module
  net: dsa: motorcomm: Add LED support

 MAINTAINERS                                   |   2 +-
 drivers/net/dsa/Kconfig                       |  10 +-
 drivers/net/dsa/Makefile                      |   2 +-
 drivers/net/dsa/motorcomm/Kconfig             |  17 +
 drivers/net/dsa/motorcomm/Makefile            |   5 +
 .../net/dsa/{yt921x.c => motorcomm/chip.c}    | 222 +-----
 .../net/dsa/{yt921x.h => motorcomm/chip.h}    |  14 +-
 drivers/net/dsa/motorcomm/leds.c              | 630 ++++++++++++++++++
 drivers/net/dsa/motorcomm/leds.h              | 121 ++++
 drivers/net/dsa/motorcomm/smi.c               | 157 +++++
 drivers/net/dsa/motorcomm/smi.h               |  88 +++
 11 files changed, 1048 insertions(+), 220 deletions(-)
 create mode 100644 drivers/net/dsa/motorcomm/Kconfig
 create mode 100644 drivers/net/dsa/motorcomm/Makefile
 rename drivers/net/dsa/{yt921x.c => motorcomm/chip.c} (96%)
 rename drivers/net/dsa/{yt921x.h => motorcomm/chip.h} (99%)
 create mode 100644 drivers/net/dsa/motorcomm/leds.c
 create mode 100644 drivers/net/dsa/motorcomm/leds.h
 create mode 100644 drivers/net/dsa/motorcomm/smi.c
 create mode 100644 drivers/net/dsa/motorcomm/smi.h

-- 
2.53.0


^ permalink raw reply

* [PATCH net-next v6 1/3] net: dsa: motorcomm: Move to subdirectory
From: David Yang @ 2026-07-09  1:47 UTC (permalink / raw)
  To: netdev
  Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260709014812.1158178-1-mmyangfl@gmail.com>

yt921x is already the longest single-file DSA driver, so it's time to
split it into parts.

Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 MAINTAINERS                                    |  2 +-
 drivers/net/dsa/Kconfig                        | 10 ++--------
 drivers/net/dsa/Makefile                       |  2 +-
 drivers/net/dsa/motorcomm/Kconfig              |  8 ++++++++
 drivers/net/dsa/motorcomm/Makefile             |  3 +++
 drivers/net/dsa/{yt921x.c => motorcomm/chip.c} |  2 +-
 drivers/net/dsa/{yt921x.h => motorcomm/chip.h} |  0
 7 files changed, 16 insertions(+), 11 deletions(-)
 create mode 100644 drivers/net/dsa/motorcomm/Kconfig
 create mode 100644 drivers/net/dsa/motorcomm/Makefile
 rename drivers/net/dsa/{yt921x.c => motorcomm/chip.c} (99%)
 rename drivers/net/dsa/{yt921x.h => motorcomm/chip.h} (100%)

diff --git a/MAINTAINERS b/MAINTAINERS
index 06df1171f4cf..b007f20b2763 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18039,7 +18039,7 @@ M:	David Yang <mmyangfl@gmail.com>
 L:	netdev@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml
-F:	drivers/net/dsa/yt921x.*
+F:	drivers/net/dsa/motorcomm/
 F:	net/dsa/tag_yt921x.c
 
 MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 4ab567c5bbaf..98e9bbe47de7 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -72,6 +72,8 @@ config NET_DSA_MV88E6060
 
 source "drivers/net/dsa/microchip/Kconfig"
 
+source "drivers/net/dsa/motorcomm/Kconfig"
+
 source "drivers/net/dsa/mv88e6xxx/Kconfig"
 
 source "drivers/net/dsa/mxl862xx/Kconfig"
@@ -158,12 +160,4 @@ config NET_DSA_VITESSE_VSC73XX_PLATFORM
 	  This enables support for the Vitesse VSC7385, VSC7388, VSC7395
 	  and VSC7398 SparX integrated ethernet switches, connected over
 	  a CPU-attached address bus and work in memory-mapped I/O mode.
-
-config NET_DSA_YT921X
-	tristate "Motorcomm YT9215 ethernet switch chip support"
-	select NET_DSA_TAG_YT921X
-	select NET_IEEE8021Q_HELPERS if DCB
-	help
-	  This enables support for the Motorcomm YT9215 ethernet switch
-	  chip.
 endmenu
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index d2975badffc0..138225baa4d5 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -14,11 +14,11 @@ obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
-obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
 obj-y				+= b53/
 obj-y				+= hirschmann/
 obj-y				+= lantiq/
 obj-y				+= microchip/
+obj-y				+= motorcomm/
 obj-y				+= mv88e6xxx/
 obj-y				+= mxl862xx/
 obj-y				+= netc/
diff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig
new file mode 100644
index 000000000000..1fddd386f866
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/Kconfig
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: ISC
+config NET_DSA_YT921X
+	tristate "Motorcomm YT9215 ethernet switch chip support"
+	select NET_DSA_TAG_YT921X
+	select NET_IEEE8021Q_HELPERS if DCB
+	help
+	  This enables support for the Motorcomm YT9215 ethernet switch
+	  chip.
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
new file mode 100644
index 000000000000..afd03be9fa35
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: ISC
+obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
+yt921x-objs := chip.o
diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/motorcomm/chip.c
similarity index 99%
rename from drivers/net/dsa/yt921x.c
rename to drivers/net/dsa/motorcomm/chip.c
index 159b16606f6c..f070732845eb 100644
--- a/drivers/net/dsa/yt921x.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -26,7 +26,7 @@
 #include <net/ieee8021q.h>
 #include <net/pkt_cls.h>
 
-#include "yt921x.h"
+#include "chip.h"
 
 struct yt921x_mib_desc {
 	unsigned int size;
diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/motorcomm/chip.h
similarity index 100%
rename from drivers/net/dsa/yt921x.h
rename to drivers/net/dsa/motorcomm/chip.h
-- 
2.53.0


^ permalink raw reply related

* [PATCH net-next v6 2/3] net: dsa: motorcomm: Split SMI module
From: David Yang @ 2026-07-09  1:47 UTC (permalink / raw)
  To: netdev
  Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260709014812.1158178-1-mmyangfl@gmail.com>

SMI operations are going to be used across different modules.

Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/dsa/motorcomm/Makefile |   1 +
 drivers/net/dsa/motorcomm/chip.c   | 207 +----------------------------
 drivers/net/dsa/motorcomm/smi.c    | 157 ++++++++++++++++++++++
 drivers/net/dsa/motorcomm/smi.h    |  88 ++++++++++++
 4 files changed, 247 insertions(+), 206 deletions(-)
 create mode 100644 drivers/net/dsa/motorcomm/smi.c
 create mode 100644 drivers/net/dsa/motorcomm/smi.h

diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
index afd03be9fa35..6cea5313a444 100644
--- a/drivers/net/dsa/motorcomm/Makefile
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: ISC
 obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
 yt921x-objs := chip.o
+yt921x-objs += smi.o
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index f070732845eb..6dee25b6754a 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -13,7 +13,6 @@
 #include <linux/if_bridge.h>
 #include <linux/if_hsr.h>
 #include <linux/if_vlan.h>
-#include <linux/iopoll.h>
 #include <linux/mdio.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -27,6 +26,7 @@
 #include <net/pkt_cls.h>
 
 #include "chip.h"
+#include "smi.h"
 
 struct yt921x_mib_desc {
 	unsigned int size;
@@ -155,9 +155,6 @@ static const struct yt921x_info yt921x_infos[] = {
 
 #define YT921X_VID_UNWARE	4095
 
-#define YT921X_POLL_SLEEP_US	10000
-#define YT921X_POLL_TIMEOUT_US	100000
-
 /* The interval should be small enough to avoid overflow of 32bit MIBs.
  *
  * Until we can read MIBs from stats64 call directly (i.e. sleep
@@ -196,208 +193,6 @@ static u32 ethaddr_lo2_to_u32(const unsigned char *addr)
 	return (addr[4] << 8) | addr[5];
 }
 
-static int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
-{
-	WARN_ON(!mutex_is_locked(&priv->reg_lock));
-
-	return priv->reg_ops->read(priv->reg_ctx, reg, valp);
-}
-
-static int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
-{
-	WARN_ON(!mutex_is_locked(&priv->reg_lock));
-
-	return priv->reg_ops->write(priv->reg_ctx, reg, val);
-}
-
-static int
-yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
-{
-	u32 val;
-	int res;
-	int ret;
-
-	ret = read_poll_timeout(yt921x_reg_read, res,
-				res || (val & mask) == *valp,
-				YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
-				false, priv, reg, &val);
-	if (ret)
-		return ret;
-	if (res)
-		return res;
-
-	*valp = val;
-	return 0;
-}
-
-static int
-yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
-{
-	int res;
-	u32 v;
-	u32 u;
-
-	res = yt921x_reg_read(priv, reg, &v);
-	if (res)
-		return res;
-
-	u = v;
-	u &= ~mask;
-	u |= val;
-	if (u == v)
-		return 0;
-
-	return yt921x_reg_write(priv, reg, u);
-}
-
-static int yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
-{
-	return yt921x_reg_update_bits(priv, reg, 0, mask);
-}
-
-static int yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
-{
-	return yt921x_reg_update_bits(priv, reg, mask, 0);
-}
-
-static int
-yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
-{
-	return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
-}
-
-/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
- * long register. More specifically, writes to parts of its words won't become
- * visible, until the last word is written.
- *
- * Here we require full read and write operations over these registers to
- * eliminate potential issues, although partial reads/writes are also possible.
- */
-
-static void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
-{
-	*lo &= ~lower_32_bits(mask);
-	*hi &= ~upper_32_bits(mask);
-	*lo |= lower_32_bits(val);
-	*hi |= upper_32_bits(val);
-}
-
-static int
-yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
-		 unsigned int num_regs)
-{
-	int res;
-
-	for (unsigned int i = 0; i < num_regs; i++) {
-		res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
-		if (res)
-			return res;
-	}
-
-	return 0;
-}
-
-static int
-yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
-		  unsigned int num_regs)
-{
-	int res;
-
-	for (unsigned int i = 0; i < num_regs; i++) {
-		res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
-		if (res)
-			return res;
-	}
-
-	return 0;
-}
-
-static int
-yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
-			const u32 *vals, unsigned int num_regs)
-{
-	bool changed = false;
-	u32 vs[4];
-	int res;
-
-	BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
-
-	res = yt921x_regs_read(priv, reg, vs, num_regs);
-	if (res)
-		return res;
-
-	for (unsigned int i = 0; i < num_regs; i++) {
-		u32 u = vs[i];
-
-		u &= ~masks[i];
-		u |= vals[i];
-		if (u != vs[i])
-			changed = true;
-
-		vs[i] = u;
-	}
-
-	if (!changed)
-		return 0;
-
-	return yt921x_regs_write(priv, reg, vs, num_regs);
-}
-
-static int
-yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
-		       unsigned int num_regs)
-{
-	bool changed = false;
-	u32 vs[4];
-	int res;
-
-	BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
-
-	res = yt921x_regs_read(priv, reg, vs, num_regs);
-	if (res)
-		return res;
-
-	for (unsigned int i = 0; i < num_regs; i++) {
-		u32 u = vs[i];
-
-		u &= ~masks[i];
-		if (u != vs[i])
-			changed = true;
-
-		vs[i] = u;
-	}
-
-	if (!changed)
-		return 0;
-
-	return yt921x_regs_write(priv, reg, vs, num_regs);
-}
-
-static int
-yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
-{
-	return yt921x_regs_write(priv, reg, vals, 2);
-}
-
-static int
-yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
-			 const u32 *vals)
-{
-	return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
-}
-
-static int
-yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
-{
-	return yt921x_regs_clear_bits(priv, reg, masks, 2);
-}
-
-static int
-yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
-{
-	return yt921x_regs_write(priv, reg, vals, 3);
-}
-
 static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)
 {
 	struct yt921x_reg_mdio *mdio = context;
diff --git a/drivers/net/dsa/motorcomm/smi.c b/drivers/net/dsa/motorcomm/smi.c
new file mode 100644
index 000000000000..9054896e4cd1
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/smi.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include <linux/iopoll.h>
+
+#include "chip.h"
+#include "smi.h"
+
+#define YT921X_POLL_SLEEP_US	10000
+#define YT921X_POLL_TIMEOUT_US	100000
+
+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
+{
+	lockdep_assert_held_once(&priv->reg_lock);
+
+	return priv->reg_ops->read(priv->reg_ctx, reg, valp);
+}
+
+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
+{
+	lockdep_assert_held_once(&priv->reg_lock);
+
+	return priv->reg_ops->write(priv->reg_ctx, reg, val);
+}
+
+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
+{
+	u32 val;
+	int res;
+	int ret;
+
+	ret = read_poll_timeout(yt921x_reg_read, res,
+				res || (val & mask) == *valp,
+				YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
+				false, priv, reg, &val);
+	if (ret)
+		return ret;
+	if (res)
+		return res;
+
+	*valp = val;
+	return 0;
+}
+
+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
+{
+	int res;
+	u32 v;
+	u32 u;
+
+	res = yt921x_reg_read(priv, reg, &v);
+	if (res)
+		return res;
+
+	u = v;
+	u &= ~mask;
+	u |= val;
+	if (u == v)
+		return 0;
+
+	return yt921x_reg_write(priv, reg, u);
+}
+
+int
+yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+		 unsigned int num_regs)
+{
+	int res;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+int
+yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+		  unsigned int num_regs)
+{
+	int res;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+int
+yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+			const u32 *vals, unsigned int num_regs)
+{
+	bool changed = false;
+	u32 vs[4];
+	int res;
+
+	if (WARN_ON_ONCE(num_regs > ARRAY_SIZE(vs)))
+		return -EINVAL;
+
+	res = yt921x_regs_read(priv, reg, vs, num_regs);
+	if (res)
+		return res;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		u32 u = vs[i];
+
+		u &= ~masks[i];
+		u |= vals[i];
+		if (u != vs[i])
+			changed = true;
+
+		vs[i] = u;
+	}
+
+	if (!changed)
+		return 0;
+
+	return yt921x_regs_write(priv, reg, vs, num_regs);
+}
+
+int
+yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+		       unsigned int num_regs)
+{
+	bool changed = false;
+	u32 vs[4];
+	int res;
+
+	if (WARN_ON_ONCE(num_regs > ARRAY_SIZE(vs)))
+		return -EINVAL;
+
+	res = yt921x_regs_read(priv, reg, vs, num_regs);
+	if (res)
+		return res;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		u32 u = vs[i];
+
+		u &= ~masks[i];
+		if (u != vs[i])
+			changed = true;
+
+		vs[i] = u;
+	}
+
+	if (!changed)
+		return 0;
+
+	return yt921x_regs_write(priv, reg, vs, num_regs);
+}
diff --git a/drivers/net/dsa/motorcomm/smi.h b/drivers/net/dsa/motorcomm/smi.h
new file mode 100644
index 000000000000..2e956065eb90
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/smi.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_SMI_H
+#define _YT_SMI_H
+
+#include <linux/types.h>
+#include <linux/wordpart.h>
+
+struct yt921x_priv;
+
+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp);
+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val);
+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp);
+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask,
+			   u32 val);
+
+static inline int
+yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
+{
+	return yt921x_reg_update_bits(priv, reg, 0, mask);
+}
+
+static inline int
+yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
+{
+	return yt921x_reg_update_bits(priv, reg, mask, 0);
+}
+
+static inline int
+yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
+{
+	return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
+}
+
+/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
+ * long register. More specifically, writes to parts of its words won't become
+ * visible, until the last word is written.
+ *
+ * Here we require full read and write operations over these registers to
+ * eliminate potential issues, although partial reads/writes are also possible.
+ */
+
+static inline void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
+{
+	*lo &= ~lower_32_bits(mask);
+	*hi &= ~upper_32_bits(mask);
+	*lo |= lower_32_bits(val);
+	*hi |= upper_32_bits(val);
+}
+
+int yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+		     unsigned int num_regs);
+int yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+		      unsigned int num_regs);
+int yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+			    const u32 *vals, unsigned int num_regs);
+int yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+			   unsigned int num_regs);
+
+static inline int
+yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+	return yt921x_regs_write(priv, reg, vals, 2);
+}
+
+static inline int
+yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+			 const u32 *vals)
+{
+	return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
+}
+
+static inline int
+yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
+{
+	return yt921x_regs_clear_bits(priv, reg, masks, 2);
+}
+
+static inline int
+yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+	return yt921x_regs_write(priv, reg, vals, 3);
+}
+
+#endif
-- 
2.53.0


^ permalink raw reply related

* [PATCH net-next v6 3/3] net: dsa: motorcomm: Add LED support
From: David Yang @ 2026-07-09  1:47 UTC (permalink / raw)
  To: netdev
  Cc: David Yang, Andrew Lunn, Vladimir Oltean, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
In-Reply-To: <20260709014812.1158178-1-mmyangfl@gmail.com>

LEDs can be described in the device tree using the same format as qca8k.
Each port can configure up to 3 LEDs.

Currently, only parallel mode and strict 1:1 mapping are supported.

Signed-off-by: David Yang <mmyangfl@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
 drivers/net/dsa/motorcomm/Kconfig  |   9 +
 drivers/net/dsa/motorcomm/Makefile |   1 +
 drivers/net/dsa/motorcomm/chip.c   |  13 +-
 drivers/net/dsa/motorcomm/chip.h   |  14 +-
 drivers/net/dsa/motorcomm/leds.c   | 630 +++++++++++++++++++++++++++++
 drivers/net/dsa/motorcomm/leds.h   | 121 ++++++
 6 files changed, 785 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/dsa/motorcomm/leds.c
 create mode 100644 drivers/net/dsa/motorcomm/leds.h

diff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig
index 1fddd386f866..3438e0b14361 100644
--- a/drivers/net/dsa/motorcomm/Kconfig
+++ b/drivers/net/dsa/motorcomm/Kconfig
@@ -6,3 +6,12 @@ config NET_DSA_YT921X
 	help
 	  This enables support for the Motorcomm YT9215 ethernet switch
 	  chip.
+
+config NET_DSA_YT921X_LEDS
+	bool "LED support for Motorcomm YT9215"
+	default y
+	depends on NET_DSA_YT921X
+	depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_YT921X
+	help
+	  This enables support for controlling the LEDs attached to the
+	  Motorcomm YT9215 switch chips.
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
index 6cea5313a444..5a63db0029ff 100644
--- a/drivers/net/dsa/motorcomm/Makefile
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: ISC
 obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
 yt921x-objs := chip.o
+yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o
 yt921x-objs += smi.o
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index 6dee25b6754a..553efacd4f5e 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -26,6 +26,7 @@
 #include <net/pkt_cls.h>
 
 #include "chip.h"
+#include "leds.h"
 #include "smi.h"
 
 struct yt921x_mib_desc {
@@ -151,8 +152,6 @@ static const struct yt921x_info yt921x_infos[] = {
 	{}
 };
 
-#define YT921X_NAME	"yt921x"
-
 #define YT921X_VID_UNWARE	4095
 
 /* The interval should be small enough to avoid overflow of 32bit MIBs.
@@ -4581,6 +4580,12 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)
 	if (res)
 		return res;
 
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+	res = yt921x_leds_setup(priv);
+	if (res)
+		dev_warn(dev, "Failed to setup LEDs: %d\n", res);
+#endif
+
 	return 0;
 }
 
@@ -4681,6 +4686,10 @@ static void yt921x_mdio_remove(struct mdio_device *mdiodev)
 	if (!priv)
 		return;
 
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+	yt921x_leds_remove(priv);
+#endif
+
 	for (size_t i = ARRAY_SIZE(priv->ports); i-- > 0; ) {
 		struct yt921x_port *pp = &priv->ports[i];
 
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index 555046526669..6570ae5902ad 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -850,8 +850,13 @@ enum yt921x_fdb_entry_status {
 #define YT921X_ACL_NUM		(YT921X_ACL_BLK_NUM * YT921X_ACL_ENT_PER_BLK)
 #define YT921X_UDF_NUM		8
 
+#define YT921X_LED_GROUP_NUM	3
+
 /* 8 internal + 2 external + 1 mcu */
-#define YT921X_PORT_NUM			11
+#define YT921X_PORT_NUM		11
+#define YT921X_PORT_MCU		10
+
+#define YT921X_NAME	"yt921x"
 
 #define yt921x_port_is_internal(port) ((port) < 8)
 #define yt921x_port_is_external(port) (8 <= (port) && (port) < 9)
@@ -938,6 +943,13 @@ struct yt921x_port {
 	struct yt921x_mib mib;
 	u64 rx_frames;
 	u64 tx_frames;
+
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+	unsigned char led_duty;
+	unsigned short led_cycle;
+
+	struct yt921x_led *leds[YT921X_LED_GROUP_NUM];
+#endif
 };
 
 struct yt921x_reg_ops {
diff --git a/drivers/net/dsa/motorcomm/leds.c b/drivers/net/dsa/motorcomm/leds.c
new file mode 100644
index 000000000000..46749b57fee3
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/leds.c
@@ -0,0 +1,630 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include <linux/uleds.h>
+
+#include "chip.h"
+#include "leds.h"
+#include "smi.h"
+
+#define to_yt921x_led(led_cdev) \
+	container_of_const((led_cdev), struct yt921x_led, cdev)
+#define to_yt921x_port(led) ((led)->port)
+#define to_yt921x_priv(pp) \
+	container_of_const((pp), struct yt921x_priv, ports[(pp)->index])
+#define to_device(priv) ((priv)->ds.dev)
+
+static u32 yt921x_led_regaddr(struct yt921x_priv *priv, int port, int group)
+{
+	switch (group) {
+	case 0:
+	default:
+		return YT921X_LED0_PORTn(port);
+	case 1:
+		return YT921X_LED1_PORTn(port);
+	case 2:
+		return YT921X_LED2_PORTn(port);
+	}
+}
+
+static int
+yt921x_led_force_get(struct yt921x_priv *priv, int port, int group, bool *onp)
+{
+	u32 val;
+	int res;
+
+	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+	if (res)
+		return res;
+
+	*onp = (val & YT921X_LED2_PORT_FORCEn_M(group)) ==
+	       YT921X_LED2_PORT_FORCEn_ON(group);
+	return 0;
+}
+
+static int
+yt921x_led_force_set(struct yt921x_priv *priv, int port, int group, bool on)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct yt921x_led *led = pp->leds[group];
+	u32 ctrl;
+	u32 mask;
+
+	led->use_cycle = false;
+	led->use_duty = false;
+
+	mask = YT921X_LED2_PORT_FORCEn_M(group);
+	ctrl = on ? YT921X_LED2_PORT_FORCEn_ON(group) :
+	       YT921X_LED2_PORT_FORCEn_OFF(group);
+	return yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port), mask,
+				      ctrl);
+}
+
+static int
+yt921x_led_blink_select(const struct yt921x_priv *priv, unsigned long on,
+			unsigned long off, unsigned short *cyclep,
+			unsigned char *dutyp)
+{
+	static const unsigned char dutys[] = {
+		YT921X_LED_DUTY(1, 6),
+		YT921X_LED_DUTY(1, 4),
+		YT921X_LED_DUTY(1, 3),
+		YT921X_LED_DUTY(1, 2),
+	};
+	unsigned int cycle_upper;
+	unsigned int cycle_req;
+	unsigned int duty_req;
+	unsigned int cycle;
+	unsigned int duty;
+
+	cycle = YT921X_LED_BLINK_MAX;
+	cycle_upper = cycle * 11585 / 8192 + 1;  /* M_SQRT2 * cycle */
+	if (check_add_overflow(on, off, &cycle_req) || cycle_req >= cycle_upper)
+		return -EOPNOTSUPP;
+
+	for (; cycle > YT921X_LED_BLINK_MIN; cycle_upper >>= 1, cycle >>= 1)
+		if (cycle_req >= cycle_upper >> 1)
+			break;
+	*cyclep = cycle;
+
+	duty_req = DIV_ROUND_CLOSEST(YT921X_LED_DUTY_DENOM *
+				     (on > off ? off : on), cycle_req);
+	for (unsigned int i = ARRAY_SIZE(dutys) - 1;; i--)
+		if (i == 0 || duty_req >= (dutys[i - 1] + dutys[i]) / 2) {
+			duty = dutys[i];
+			break;
+		}
+	if (on > off)
+		duty = YT921X_LED_DUTY_DENOM - duty;
+	*dutyp = duty;
+
+	return 0;
+}
+
+static int
+yt921x_led_blink_set(struct yt921x_priv *priv, int port, int group,
+		     unsigned long *onp, unsigned long *offp)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct yt921x_led *led = pp->leds[group];
+	unsigned short cycle;
+	unsigned char duty;
+	bool use_cycle;
+	u32 ctrl;
+	u32 mask;
+	u32 val;
+	int res;
+
+	if (!*onp && !*offp) {
+		cycle = YT921X_LED_BLINK_DEF;
+		duty = YT921X_LED_DUTY(1, 2);
+		for (unsigned int i = 0; i < YT921X_LED_GROUP_NUM; i++)
+			if (i != group && pp->leds[i] &&
+			    pp->leds[i]->use_duty) {
+				duty = pp->led_duty;
+				break;
+			}
+
+		use_cycle = false;
+	} else {
+		bool change_cycle;
+		bool change_duty;
+
+		res = yt921x_led_blink_select(priv, *onp, *offp, &cycle, &duty);
+		if (res)
+			return res;
+
+		use_cycle = cycle < YT921X_LED_BLINK_DEF;
+		change_cycle = use_cycle && cycle != pp->led_cycle;
+		change_duty = duty != pp->led_duty;
+		if (change_cycle || change_duty)
+			for (unsigned int i = 0; i < YT921X_LED_GROUP_NUM;
+			     i++) {
+				if (i == group || !pp->leds[i])
+					continue;
+				if ((change_cycle && pp->leds[i]->use_cycle) ||
+				    (change_duty && pp->leds[i]->use_duty))
+					return -EOPNOTSUPP;
+			}
+	}
+
+	/* The chip seems to jam a while if changing duty directly */
+	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+	if (res)
+		return res;
+
+	ctrl = val & ~YT921X_LED2_PORT_FORCEn_M(group);
+	ctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+	if (val != ctrl) {
+		res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);
+		if (res)
+			return res;
+	}
+
+	mask = YT921X_LED1_PORT_BLINK_DUTY_M | YT921X_LED1_PORT_BLINK_DUTY_COMP;
+	switch (duty >= YT921X_LED_DUTY(1, 2) ? duty :
+		YT921X_LED_DUTY_DENOM - duty) {
+	default:
+		duty = YT921X_LED_DUTY(1, 2);
+		fallthrough;
+	case YT921X_LED_DUTY(1, 2):
+		ctrl = YT921X_LED1_PORT_BLINK_DUTY_1_2;
+		break;
+	case YT921X_LED_DUTY(2, 3):
+		ctrl = YT921X_LED1_PORT_BLINK_DUTY_2_3;
+		break;
+	case YT921X_LED_DUTY(3, 4):
+		ctrl = YT921X_LED1_PORT_BLINK_DUTY_3_4;
+		break;
+	case YT921X_LED_DUTY(5, 6):
+		ctrl = YT921X_LED1_PORT_BLINK_DUTY_5_6;
+		break;
+	}
+	if (duty < YT921X_LED_DUTY(1, 2))
+		ctrl |= YT921X_LED1_PORT_BLINK_DUTY_COMP;
+	if (use_cycle) {
+		mask |= YT921X_LED1_PORT_OTHER_BLINK_M;
+		ctrl |= YT921X_LED1_PORT_OTHER_BLINK(9 - __fls(cycle));
+	}
+	res = yt921x_reg_update_bits(priv, YT921X_LED1_PORTn(port), mask, ctrl);
+	if (res)
+		return res;
+
+	ctrl = val & ~(YT921X_LED2_PORT_FORCEn_M(group) |
+		       YT921X_LED2_PORT_FORCE_BLINKn_M(group));
+	ctrl |= YT921X_LED2_PORT_FORCEn_BLINK(group);
+	if (use_cycle)
+		ctrl |= YT921X_LED2_PORT_FORCE_BLINKn_OTHER(group);
+	else
+		ctrl |= YT921X_LED2_PORT_FORCE_BLINKn(group, __fls(cycle) - 9);
+	res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);
+	if (res)
+		return res;
+
+	led->use_cycle = use_cycle;
+	if (use_cycle)
+		pp->led_cycle = cycle;
+	led->use_duty = true;
+	pp->led_duty = duty;
+
+	*onp = DIV_ROUND_CLOSEST(duty * cycle, YT921X_LED_DUTY_DENOM);
+	*offp = cycle - *onp;
+	return 0;
+}
+
+struct yt921x_led_trigger_map {
+	unsigned long flags;
+	u32 mask;
+};
+
+static const struct yt921x_led_trigger_map yt921x_led_trigger_maps[] = {
+	{BIT(TRIGGER_NETDEV_LINK),
+	 YT921X_LEDx_PORT_ACT_DUPLEX_HALF | YT921X_LEDx_PORT_ACT_DUPLEX_FULL},
+	{BIT(TRIGGER_NETDEV_LINK_10), YT921X_LEDx_PORT_ACT_10M},
+	{BIT(TRIGGER_NETDEV_LINK_100), YT921X_LEDx_PORT_ACT_100M},
+	{BIT(TRIGGER_NETDEV_LINK_1000), YT921X_LEDx_PORT_ACT_1000M},
+	{BIT(TRIGGER_NETDEV_HALF_DUPLEX), YT921X_LEDx_PORT_ACT_DUPLEX_HALF},
+	{BIT(TRIGGER_NETDEV_FULL_DUPLEX), YT921X_LEDx_PORT_ACT_DUPLEX_FULL},
+	{BIT(TRIGGER_NETDEV_TX), YT921X_LEDx_PORT_ACT_TX_BLINK},
+	{BIT(TRIGGER_NETDEV_RX), YT921X_LEDx_PORT_ACT_RX_BLINK},
+	{BIT(TRIGGER_NETDEV_TX_ERR) | BIT(TRIGGER_NETDEV_RX_ERR),
+	 YT921X_LEDx_PORT_ACT_COLLISION_BLINK},
+};
+
+static bool
+yt921x_led_trigger_is_supported(const struct yt921x_priv *priv, int port,
+				int group, unsigned long flags)
+{
+	if (!flags)
+		return true;
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
+		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
+
+		if ((flags & map->flags) == map->flags) {
+			flags &= ~map->flags;
+			if (!flags)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+static int
+yt921x_led_trigger_get(struct yt921x_priv *priv, int port, int group,
+		       unsigned long *flagsp)
+{
+	u32 addr;
+	u32 val;
+	int res;
+
+	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+	if (res)
+		return res;
+
+	if ((val & YT921X_LED2_PORT_FORCEn_M(group)) !=
+	    YT921X_LED2_PORT_FORCEn_DONTCARE(group)) {
+		*flagsp = 0;
+		return 0;
+	}
+
+	if (group != 2) {
+		addr = yt921x_led_regaddr(priv, port, group);
+		res = yt921x_reg_read(priv, addr, &val);
+		if (res)
+			return res;
+	}
+
+	*flagsp = 0;
+	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
+		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
+
+		if ((val & map->mask) == map->mask)
+			*flagsp |= map->flags;
+	}
+
+	return 0;
+}
+
+static int
+yt921x_led_trigger_set(struct yt921x_priv *priv, int port, int group,
+		       unsigned long flags)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct yt921x_led *led = pp->leds[group];
+	u32 addr;
+	u32 ctrl;
+	u32 mask;
+	int res;
+
+	ctrl = 0;
+	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
+		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
+
+		if ((flags & map->flags) == map->flags) {
+			flags &= ~map->flags;
+			ctrl |= map->mask;
+			if (!flags)
+				break;
+		}
+	}
+	if (flags)
+		return -EOPNOTSUPP;
+
+	led->use_cycle = false;
+	led->use_duty = false;
+
+	mask = !group ? YT921X_LED0_PORT_ACT_M : YT921X_LEDx_PORT_ACT_M;
+	if (group == 2) {
+		mask |= YT921X_LED2_PORT_FORCEn_M(group);
+		ctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+	}
+	addr = yt921x_led_regaddr(priv, port, group);
+	res = yt921x_reg_update_bits(priv, addr, mask, ctrl);
+	if (res)
+		return res;
+
+	if (group != 2) {
+		mask = YT921X_LED2_PORT_FORCEn_M(group);
+		ctrl = YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+		res = yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port),
+					     mask, ctrl);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+static int
+yt921x_cled_brightness_set_blocking(struct led_classdev *led_cdev,
+				    enum led_brightness brightness)
+{
+	struct yt921x_led *led = to_yt921x_led(led_cdev);
+	struct yt921x_port *pp = to_yt921x_port(led);
+	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_led_force_set(priv, pp->index, led->group, brightness);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static int
+yt921x_cled_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,
+		      unsigned long *delay_off)
+{
+	struct yt921x_led *led = to_yt921x_led(led_cdev);
+	struct yt921x_port *pp = to_yt921x_port(led);
+	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_led_blink_set(priv, pp->index, led->group, delay_on,
+				   delay_off);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static struct device * __maybe_unused
+yt921x_cled_hw_control_get_device(struct led_classdev *led_cdev)
+{
+	struct yt921x_led *led = to_yt921x_led(led_cdev);
+	struct yt921x_port *pp = to_yt921x_port(led);
+	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	struct dsa_port *dp;
+
+	dp = dsa_to_port(&priv->ds, pp->index);
+	if (!dp || !dp->user)
+		return NULL;
+	return &dp->user->dev;
+}
+
+static int __maybe_unused
+yt921x_cled_hw_control_is_supported(struct led_classdev *led_cdev,
+				    unsigned long flags)
+{
+	struct yt921x_led *led = to_yt921x_led(led_cdev);
+	struct yt921x_port *pp = to_yt921x_port(led);
+	struct yt921x_priv *priv = to_yt921x_priv(pp);
+
+	if (yt921x_led_trigger_is_supported(priv, pp->index, led->group, flags))
+		return 0;
+	return -EOPNOTSUPP;
+}
+
+static int __maybe_unused
+yt921x_cled_hw_control_get(struct led_classdev *led_cdev, unsigned long *flagsp)
+{
+	struct yt921x_led *led = to_yt921x_led(led_cdev);
+	struct yt921x_port *pp = to_yt921x_port(led);
+	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_led_trigger_get(priv, pp->index, led->group, flagsp);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static int __maybe_unused
+yt921x_cled_hw_control_set(struct led_classdev *led_cdev, unsigned long flags)
+{
+	struct yt921x_led *led = to_yt921x_led(led_cdev);
+	struct yt921x_port *pp = to_yt921x_port(led);
+	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_led_trigger_set(priv, pp->index, led->group, flags);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static int
+yt921x_led_setup(struct yt921x_priv *priv, int port,
+		 struct fwnode_handle *fwnode, u32 *inv_maskp, u32 *inv_ctrlp)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct device *dev = to_device(priv);
+	struct led_init_data init_data;
+	struct led_classdev *led_cdev;
+	char name[LED_MAX_NAME_SIZE];
+	enum led_default_state state;
+	struct yt921x_led *led;
+	bool force_high;
+	bool force_low;
+	int polarity;
+	u32 group;
+	bool on;
+	int res;
+
+	if (port == YT921X_PORT_MCU) {
+		dev_err(dev, "No LEDs for port %d\n", port);
+		return -ENODEV;
+	}
+
+	res = fwnode_property_read_u32(fwnode, "reg", &group);
+	if (res)
+		return res;
+	if (group >= YT921X_LED_GROUP_NUM) {
+		dev_err(dev, "Invalid LED reg %u for port %d\n", group, port);
+		return -EINVAL;
+	}
+	if (pp->leds[group])
+		return -EEXIST;
+
+	force_high = fwnode_property_read_bool(fwnode, "active-high");
+	force_low = fwnode_property_read_bool(fwnode, "active-low");
+	if (force_high && force_low) {
+		dev_err(dev, "Duplicate polarities for LED %02d:%02u\n",
+			port, group);
+		return -EINVAL;
+	}
+	polarity = force_high ? 1 : force_low ? -1 : 0;
+
+	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
+	led->port = pp;
+	led->group = group;
+
+	state = led_init_default_state_get(fwnode);
+
+	mutex_lock(&priv->reg_lock);
+	pp->leds[group] = led;
+	switch (state) {
+	case LEDS_DEFSTATE_OFF:
+	case LEDS_DEFSTATE_ON:
+	default:
+		on = state == LEDS_DEFSTATE_ON;
+		res = yt921x_led_force_set(priv, port, group, on);
+		break;
+	case LEDS_DEFSTATE_KEEP:
+		res = yt921x_led_force_get(priv, port, group, &on);
+		break;
+	}
+	mutex_unlock(&priv->reg_lock);
+	if (res)
+		goto err;
+
+	led_cdev = &led->cdev;
+	led_cdev->brightness = on;
+	led_cdev->max_brightness = 1;
+	led_cdev->flags = LED_RETAIN_AT_SHUTDOWN;
+	led_cdev->brightness_set_blocking = yt921x_cled_brightness_set_blocking;
+	led_cdev->blink_set = yt921x_cled_blink_set;
+#ifdef CONFIG_LEDS_TRIGGERS
+	led_cdev->hw_control_trigger = "netdev";
+	led_cdev->hw_control_get_device = yt921x_cled_hw_control_get_device;
+	led_cdev->hw_control_is_supported = yt921x_cled_hw_control_is_supported;
+	led_cdev->hw_control_get = yt921x_cled_hw_control_get;
+	led_cdev->hw_control_set = yt921x_cled_hw_control_set;
+#endif
+
+	snprintf(name, sizeof(name), YT921X_NAME "-%u:%02d:%02u",
+		 priv->ds.index, port, group);
+	init_data = (typeof(init_data)){
+		.fwnode = fwnode,
+		.devicename = name,
+		.devname_mandatory = true,
+	};
+	res = devm_led_classdev_register_ext(dev, led_cdev, &init_data);
+	if (res)
+		goto err;
+
+	if (polarity) {
+		u32 bit = YT921X_LED_PAR_INV_INVnm(group, port);
+
+		*inv_maskp |= bit;
+		if (polarity > 0)
+			*inv_ctrlp |= bit;
+	}
+	return 0;
+
+err:
+	mutex_lock(&priv->reg_lock);
+	pp->leds[group] = NULL;
+	mutex_unlock(&priv->reg_lock);
+
+	devm_kfree(dev, led);
+	return res;
+}
+
+void yt921x_leds_remove(struct yt921x_priv *priv)
+{
+	struct device *dev = to_device(priv);
+
+	for (int port = 0; port < YT921X_PORT_NUM; port++) {
+		struct yt921x_port *pp = &priv->ports[port];
+
+		for (int group = 0; group < YT921X_LED_GROUP_NUM; group++) {
+			struct yt921x_led *led = pp->leds[group];
+
+			if (led)
+				devm_led_classdev_unregister(dev, &led->cdev);
+		}
+
+		for (int group = 0; group < YT921X_LED_GROUP_NUM; group++) {
+			struct yt921x_led *led = pp->leds[group];
+
+			if (led) {
+				pp->leds[group] = NULL;
+				devm_kfree(dev, led);
+			}
+		}
+	}
+}
+
+int yt921x_leds_setup(struct yt921x_priv *priv)
+{
+	struct dsa_switch *ds = &priv->ds;
+	struct dsa_port *dp;
+	u32 inv_ctrl = 0;
+	u32 inv_mask = 0;
+	u32 ctrl;
+	u32 mask;
+	int res;
+
+	dsa_switch_for_each_port(dp, ds) {
+		struct device_node *leds_np;
+		int port = dp->index;
+
+		if (!dp->dn)
+			continue;
+
+		leds_np = of_get_child_by_name(dp->dn, "leds");
+		if (!leds_np)
+			continue;
+
+		for_each_child_of_node_scoped(leds_np, led_np) {
+			res = yt921x_led_setup(priv, port,
+					       of_fwnode_handle(led_np),
+					       &inv_mask, &inv_ctrl);
+			if (res) {
+				of_node_put(leds_np);
+				goto err;
+			}
+		}
+
+		of_node_put(leds_np);
+	}
+
+	mutex_lock(&priv->reg_lock);
+
+	mask = YT921X_LED_CTRL_MODE_M | YT921X_LED_CTRL_PORT_NUM_M |
+	       YT921X_LED_CTRL_EN;
+	ctrl = YT921X_LED_CTRL_MODE_PARALLEL |
+	       YT921X_LED_CTRL_PORT_NUM(YT921X_PORT_NUM - 1) |
+	       YT921X_LED_CTRL_EN;
+	res = yt921x_reg_update_bits(priv, YT921X_LED_CTRL, mask, ctrl);
+	if (res)
+		goto end;
+
+	/* Inversion is internal - force on will give low logic.
+	 * In the rest of the file, treat LEDs as if active-low.
+	 */
+	if (inv_mask)
+		res = yt921x_reg_update_bits(priv, YT921X_LED_PAR_INV, inv_mask,
+					     inv_ctrl);
+
+end:
+	mutex_unlock(&priv->reg_lock);
+
+	if (res)
+		goto err;
+
+	return 0;
+
+err:
+	yt921x_leds_remove(priv);
+	return res;
+}
diff --git a/drivers/net/dsa/motorcomm/leds.h b/drivers/net/dsa/motorcomm/leds.h
new file mode 100644
index 000000000000..67373a190c8f
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/leds.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_LEDS_H
+#define _YT_LEDS_H
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/kconfig.h>
+#include <linux/leds.h>
+
+#define YT921X_LED_CTRL			0xd0000
+#define  YT921X_LED_CTRL_EN			BIT(21)
+#define  YT921X_LED_CTRL_LOOPDETECT_BLINK_M	GENMASK(20, 19)	/* cycle = 512 * x ms */
+#define   YT921X_LED_CTRL_LOOPDETECT_BLINK(x)		FIELD_PREP(YT921X_LED_CTRL_LOOPDETECT_BLINK_M, (x))
+#define  YT921X_LED_CTRL_PORT_NUM_M		GENMASK(16, 13)
+#define   YT921X_LED_CTRL_PORT_NUM(x)			FIELD_PREP(YT921X_LED_CTRL_PORT_NUM_M, (x))
+#define  YT921X_LED_CTRL_MODE_M			GENMASK(1, 0)
+#define   YT921X_LED_CTRL_MODE(x)			FIELD_PREP(YT921X_LED_CTRL_MODE_M, (x))
+#define   YT921X_LED_CTRL_MODE_PARALLEL			YT921X_LED_CTRL_MODE(0)
+#define   YT921X_LED_CTRL_MODE_SERIAL			YT921X_LED_CTRL_MODE(2)
+#define YT921X_LED0_PORTn(port)		(0xd0004 + 4 * (port))
+#define  YT921X_LED0_PORT_ACT_M			GENMASK(17, 0)
+#define  YT921X_LED0_PORT_ACT_LINK_TRY_DIS	BIT(17)
+#define  YT921X_LED0_PORT_ACT_COLLISION_BLINK_INDI	BIT(16)
+#define YT921X_LED1_PORTn(port)		(0xd0040 + 4 * (port))
+#define  YT921X_LED1_PORT_OTHER_BLINK_M		GENMASK(31, 30)	/* cycle = 512 >> x ms */
+#define   YT921X_LED1_PORT_OTHER_BLINK(x)		FIELD_PREP(YT921X_LED1_PORT_OTHER_BLINK_M, (x))
+#define  YT921X_LED1_PORT_EEE_BLINK_M		GENMASK(29, 28)	/* cycle = 512 >> x ms */
+#define   YT921X_LED1_PORT_EEE_BLINK(x)			FIELD_PREP(YT921X_LED1_PORT_EEE_BLINK_M, (x))
+#define  YT921X_LED1_PORT_BLINK_DUTY_COMP	BIT(27)
+#define  YT921X_LED1_PORT_BLINK_DUTY_M		GENMASK(26, 25)
+#define   YT921X_LED1_PORT_BLINK_DUTY(x)		FIELD_PREP(YT921X_LED1_PORT_BLINK_DUTY_M, (x))
+#define   YT921X_LED1_PORT_BLINK_DUTY_1_2		YT921X_LED1_PORT_BLINK_DUTY(0)
+#define   YT921X_LED1_PORT_BLINK_DUTY_2_3		YT921X_LED1_PORT_BLINK_DUTY(1)
+#define   YT921X_LED1_PORT_BLINK_DUTY_3_4		YT921X_LED1_PORT_BLINK_DUTY(2)
+#define   YT921X_LED1_PORT_BLINK_DUTY_5_6		YT921X_LED1_PORT_BLINK_DUTY(3)
+#define YT921X_LED2_PORTn(port)		(0xd0080 + 4 * (port))
+#define  YT921X_LED2_PORT_FORCEn_M(grp)		GENMASK(4 * (grp) + 19, 4 * (grp) + 18)
+#define   YT921X_LED2_PORT_FORCEn(grp, x)		((x) << (4 * (grp) + 18))
+#define   YT921X_LED2_PORT_FORCEn_DONTCARE(grp)		YT921X_LED2_PORT_FORCEn(grp, 0)
+#define   YT921X_LED2_PORT_FORCEn_BLINK(grp)		YT921X_LED2_PORT_FORCEn(grp, 1)
+#define   YT921X_LED2_PORT_FORCEn_ON(grp)		YT921X_LED2_PORT_FORCEn(grp, 2)
+#define   YT921X_LED2_PORT_FORCEn_OFF(grp)		YT921X_LED2_PORT_FORCEn(grp, 3)
+#define  YT921X_LED2_PORT_FORCE_BLINKn_M(grp)	GENMASK(4 * (grp) + 17, 4 * (grp) + 16)	/* cycle = 512 << x ms */
+#define   YT921X_LED2_PORT_FORCE_BLINKn(grp, x)		((x) << (4 * (grp) + 16))
+#define   YT921X_LED2_PORT_FORCE_BLINKn_OTHER(grp)	YT921X_LED2_PORT_FORCE_BLINKn(grp, 3)
+#define  YT921X_LEDx_PORT_ACT_M			GENMASK(15, 0)
+#define  YT921X_LEDx_PORT_ACT_EEE_BLINK		BIT(15)
+#define  YT921X_LEDx_PORT_ACT_LOOPDETECT_BLINK	BIT(14)
+#define  YT921X_LEDx_PORT_ACT_ACTIVE_BLINK	BIT(13)
+#define  YT921X_LEDx_PORT_ACT_DUPLEX_FULL	BIT(12)
+#define  YT921X_LEDx_PORT_ACT_DUPLEX_HALF	BIT(11)
+#define  YT921X_LEDx_PORT_ACT_TX_BLINK		BIT(10)
+#define  YT921X_LEDx_PORT_ACT_RX_BLINK		BIT(9)
+#define  YT921X_LEDx_PORT_ACT_TX		BIT(8)
+#define  YT921X_LEDx_PORT_ACT_RX		BIT(7)
+#define  YT921X_LEDx_PORT_ACT_1000M		BIT(6)
+#define  YT921X_LEDx_PORT_ACT_100M		BIT(5)
+#define  YT921X_LEDx_PORT_ACT_10M		BIT(4)
+#define  YT921X_LEDx_PORT_ACT_COLLISION_BLINK	BIT(3)
+#define  YT921X_LEDx_PORT_ACT_1000M_BLINK	BIT(2)
+#define  YT921X_LEDx_PORT_ACT_100M_BLINK	BIT(1)
+#define  YT921X_LEDx_PORT_ACT_10M_BLINK		BIT(0)
+#define YT921X_LED_SER_CTRL		0xd0100
+#define  YT921X_LED_SER_CTRL_UNK		GENMASK(25, 24)	/* delay? */
+#define  YT921X_LED_SER_CTRL_ACTIVE_LOW		BIT(4)
+#define  YT921X_LED_SER_CTRL_GRP_NUM_M		GENMASK(1, 0)	/* #grp - 1 */
+#define   YT921X_LED_SER_CTRL_GRP_NUM(x)		FIELD_PREP(YT921X_LED_SER_CTRL_GRP_NUM_M, (x))
+#define YT921X_LED_SER_MAPnm(grp, port)	(0xd0104 + 8 * (2 - (grp)) + 4 * ((port) / 5))
+#define  YT921X_LED_SER_MAP_DSTn_PORT_M(port)	GENMASK(6 * ((port) % 5) + 5, 6 * ((port) % 5) + 2)
+#define   YT921X_LED_SER_MAP_DSTn_PORT(port, x)		((x) << (6 * ((port) % 5) + 2))
+#define  YT921X_LED_SER_MAP_DSTn_LED_M(port)	GENMASK(6 * ((port) % 5) + 1, 6 * ((port) % 5))
+#define   YT921X_LED_SER_MAP_DSTn_LED(port, x)		((x) << (6 * ((port) % 5)))
+#define YT921X_LED_PAR_PORTS		0xd01c4
+#define YT921X_LED_PAR_INV		0xd01c8
+#define  YT921X_LED_PAR_INV_INVnm(grp, port)	BIT(10 * (grp) + (port))
+#define YT921X_LED_PAR_MAPn(port)	(0xd01d0 + 4 * (port))
+#define  YT921X_LED_PAR_MAP_DSTn_PORT_M(grp)	GENMASK(6 * (grp) + 5, 6 * (grp) + 2)
+#define   YT921X_LED_PAR_MAP_DSTn_PORT(grp, x)		((x) << (6 * (grp) + 2))
+#define  YT921X_LED_PAR_MAP_DSTn_LED_M(grp)	GENMASK(6 * (grp) + 1, 6 * (grp))
+#define   YT921X_LED_PAR_MAP_DSTn_LED(grp, x)		((x) << (6 * (grp)))
+
+#define YT921X_LED_BLINK_MIN	64
+#define YT921X_LED_BLINK_DEF	512
+#define YT921X_LED_BLINK_MAX	2048
+
+/* 2 * lcm(2, 3, 4, 6) */
+#define YT921X_LED_DUTY_DENOM		24
+#define YT921X_LED_DUTY(nom, denom)	(YT921X_LED_DUTY_DENOM * (nom) / (denom))
+
+struct yt921x_priv;
+
+struct yt921x_led {
+	struct led_classdev cdev;
+	struct yt921x_port *port;
+	unsigned char group;
+
+	bool use_cycle:1;
+	bool use_duty:1;
+};
+
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+
+void yt921x_leds_remove(struct yt921x_priv *priv);
+int yt921x_leds_setup(struct yt921x_priv *priv);
+
+#else
+
+static inline void yt921x_leds_remove(struct yt921x_priv *priv) {}
+
+static inline int yt921x_leds_setup(struct yt921x_priv *priv)
+{
+	return 0;
+}
+
+#endif
+
+#endif
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v7] net: gro: fix double aggregation of flush-marked skbs
From: Willem de Bruijn @ 2026-07-09  2:07 UTC (permalink / raw)
  To: Shiming Cheng, davem, edumazet, kuba, pabeni, horms, matthias.bgg,
	angelogioacchino.delregno, willemb, daniel.zahka, alice, sd,
	eilaimemedsnaimel, imv4bel, nbd, dsahern, netdev, linux-kernel,
	linux-arm-kernel, linux-mediatek
  Cc: stable, steffen.klassert, lena.wang, shiming.cheng
In-Reply-To: <20260709014704.3625-1-shiming.cheng@mediatek.com>

Reminder to mark patches [PATCH net v7]

(or PATCH net-next when targeting that tree)

Shiming Cheng wrote:
> Commit 0ab03f353d36 ("net-gro: Fix GRO flush when receiving a GSO
> packet.") added a flush check to skb_gro_receive(), but
> skb_gro_receive_list() lacks the same validation.
> 
> As a result, packets marked with NAPI_GRO_CB(skb)->flush may still be
> re-aggregated.
> 
> This allows already-GRO'd packets with existing frag_list to be
> re-aggregated into a new GRO session, corrupting the frag_list chain
> structure. When skb_segment() attempts to unpack these malformed packets,
> it encounters invalid state and triggers a kernel panic.
> 
> Scenario (Tethering/Device forwarding):
>   1. Driver: Generated aggregated packet P1 via LRO with frag_list
>   2. Dev A: Receives aggregated fraglist packet and flush flag set
>   3. Dev A: Re-enters GRO, skb_gro_receive_list() is called
>   4. Missing flush check allows re-aggregation despite flush flag
>   5. Frag_list chain becomes corrupted (loops or dangling refs)
>   6. Dev B: TX path calls skb_segment(), crashes on corrupted frag_list
> 
> Root cause in skb_segment():
>   The check at line ~4891:
>     if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) &&
>         (skb_headlen(list_skb) == len || sg)) {
> 
>   When frag_list is corrupted by double aggregation, when list_skb is
>   a NULL pointer from skb->next, skb_headlen(list_skb) dereference
>   NULL/corrupted pointers occurs.
> 
> Call Trace:
>  skb_headlen(NULL skb)
>  skb_segment
>  tcp_gso_segment
>  tcp4_gso_segment
>  inet_gso_segment
>  skb_mac_gso_segment
>  __skb_gso_segment
>  skb_gso_segment
>  validate_xmit_skb
>  validate_xmit_skb_list
>  sch_direct_xmit
>  qdisc_restart
>  __qdisc_run
>  qdisc_run
>  net_tx_action
> 
> Fix: Add NAPI_GRO_CB(skb)->flush validation to the early-return check in
> skb_gro_receive_list(), matching the defensive programming pattern of
> skb_gro_receive().
> 
> Fixes: 3a1296a38d0c ("net: Support GRO/GSO fraglist chaining.")
> Cc: stable@vger.kernel.org
> Signed-off-by: Shiming Cheng <shiming.cheng@mediatek.com>

Reviewed-by: Willem de Bruijn <willemb@google.com>

^ permalink raw reply

* RE: [PATCH net-next v5 10/13] net: phy: add generic helpers for direct C45 MMD access
From: Selvamani Rajagopal @ 2026-07-09  2:29 UTC (permalink / raw)
  To: ciprian.regus@analog.com, Parthiban Veerasooran, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Shuah Khan, Andrew Lunn,
	Heiner Kallweit, Russell King, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-doc@vger.kernel.org, devicetree@vger.kernel.org
In-Reply-To: <20260708-adin1140-driver-v5-10-4aca7b51a58b@analog.com>


> +int genphy_read_mmd_c45(struct phy_device *phydev, int devnum, u16 regnum)
> +{
> + struct mii_bus *bus = phydev->mdio.bus;
> + int addr = phydev->mdio.addr;

You may want to insert the lockdep_assert here. That'll ensure that read/write APIs are called
after the mdio-lock is taken. Andrew's suggestion.

   lockdep_assert_held(&bus->mdio_lock)


> + return __mdiobus_c45_read(bus, addr, devnum, regnum);
> +}


> +int genphy_write_mmd_c45(struct phy_device *phydev, int devnum, u16 regnum,
> + u16 val)
> +{
> + struct mii_bus *bus = phydev->mdio.bus;
> + int addr = phydev->mdio.addr;


And here too.


> + return __mdiobus_c45_write(bus, addr, devnum, regnum, val);
> +}
> +EXPORT_SYMBOL(genphy_write_mmd_c45);
> +


^ permalink raw reply

* Re: [PATCH net] net:ethernet: mtk_wed: setup WDMA_RING_TX(0) for non-DBDC MT7986
From: Zhi-Jun You @ 2026-07-09  2:48 UTC (permalink / raw)
  To: Paolo Abeni; +Cc: lorenzo, nbd, netdev, linux-mediatek
In-Reply-To: <20260706101044.161059-1-pabeni@redhat.com>

On Mon, Jul 6, 2026 at 6:10 PM Paolo Abeni <pabeni@redhat.com> wrote:
>
> From: AI Reviewer <ai@example.com>
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://sashiko.dev/
> ---
> net:ethernet: mtk_wed: setup WDMA_RING_TX(0) for non-DBDC MT7986
>
> This commit updates mtk_wed_start() to configure WDMA_RING_TX(0) on
> non-DBDC MT7986 devices. It adds a call to mtk_wed_wdma_tx_ring_setup()
> for v2 hardware if the descriptor is not yet set up.
>
> > diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
> > index 10d9beaae3721..2420557f6c966 100644
> > --- a/drivers/net/ethernet/mediatek/mtk_wed.c
> > +++ b/drivers/net/ethernet/mediatek/mtk_wed.c
> > @@ -2334,6 +2334,10 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
> >               if (!dev->rx_wdma[i].desc)
> >                       mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
>
> [Severity: High]
> This isn't a bug introduced by this patch, but does this loop need to check
> the return value of mtk_wed_wdma_rx_ring_setup()?
>
> If mtk_wed_wdma_rx_ring_setup() returns -ENOMEM, the hardware registers are
> not programmed, but mtk_wed_start() continues execution and enables DMA.
>
> Could this lead to hardware DMA using an uninitialized ring base address?
Hi,

I am not sure how to proceed with this one.
mtk_wed_start is a void function and both mt7915 and mt7996's dma
function that calls it don't have return value handling either.

>
> >
> > +     if (mtk_wed_is_v2(dev->hw))
> > +             if (!dev->tx_wdma[0].desc)
> > +                     mtk_wed_wdma_tx_ring_setup(dev, 0, MTK_WED_WDMA_RING_SIZE, false);
>
> [Severity: High]
> Are there similar error handling concerns with this new call to
> mtk_wed_wdma_tx_ring_setup()?
>
> Like the RX path, if dma_alloc_coherent() fails inside this setup function,
> it returns -ENOMEM without programming the hardware registers.
>
> Since mtk_wed_start() doesn't check this return value, it will proceed to
> enable hardware DMA, which might attempt to use an uninitialized DMA address.
>
> [Severity: High]
> Does the check for !dev->tx_wdma[0].desc prevent necessary hardware
> initialization after a warm reset?
>
> When the WLAN driver triggers a hardware reset, the WED hardware registers
> are cleared, and mtk_wed_start() is called again.
>
> Because dev->tx_wdma[0].desc was allocated during the initial start, the
> guard will evaluate to false, skipping the hardware register reprogramming
> for tx_wdma[0].
>
> Will the hardware DMA end up using a zeroed ring base address after a reset?

During warm reset, MTK_WDMA_RING_TX(i) + MTK_WED_RING_OFS_CPU_IDX is set to 0.
Other parts are left untouched.
After the warm reset, mtk_wed_rx_ring_setup will be called with
reset=true, which also calls
mtk_wed_wdma_tx_ring_setup with reset=true.

reset=true will skip ring allocation and call an extra mtk_wed_ring_reset
but for non-DBDC mt7986, this path won't happen for the tx_wdma[0].

Usually rx_ring and tx_wdma are paired together but this is a special
case that rx_ring[1] and
tx_wdma[1] are allocated but tx_wdma[0] is still required.
Maybe something like this would work?
Runs only if wed is v2 and rx ring 0 is not allocated, reset only when
tx_wdma[0] was already allocated.

if (mtk_wed_is_v2 && !dev->rx_ring[0].desc)
        mtk_wed_wdma_tx_ring_setup(dev, 0, MTK_WED_WDMA_RING_SIZE,
!!dev->tx_wdma[0].desc);

Best regards,
Zhi-Jun

>
> > +
> >       if (dev->wlan.hw_rro) {
> >               for (i = 0; i < MTK_WED_RX_PAGE_QUEUES; i++) {
> >                       u32 addr = MTK_WED_RRO_MSDU_PG_CTRL0(i) +
> --
> This is an AI-generated review.
>

^ permalink raw reply

* Re: [PATCH net-next v3 04/12] net: mctp: usb: Improve IN endpoint status handling
From: Jeremy Kerr @ 2026-07-09  3:12 UTC (permalink / raw)
  To: Oliver Neukum, Matt Johnston, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Greg Kroah-Hartman
  Cc: netdev, linux-usb
In-Reply-To: <2a0bacab-951a-48b2-8263-bad3088a29b7@suse.com>

Hi Oliver,
Thanks for taking a look.



> What allows the assumption that mctp_usb_open() does not race
> with error handling? What happens if the device is still stalled?

When ndo_open is called, we know that the delayed rx work (which
performs the usb_clear_halt) has been quiesced, so aren't racing with
the actual recovery.

The device may still be stalled; that should be okay though, as we'll
detect that through the subsequent IN urb submission, which will re-set
->clear halt and schedule the rx work to do the clear.

Unless I have missed a case there?

Cheers,


Jeremy


^ permalink raw reply

* Re: [PATCH net] netfilter: nf_nat_masquerade: recalculate TCP TS offset when port is randomized
From: xietangxin @ 2026-07-09  3:37 UTC (permalink / raw)
  To: Florian Westphal
  Cc: Pablo Neira Ayuso, Phil Sutter, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, gaoxingwang, huyizhen,
	netfilter-devel, coreteam, netdev, linux-kernel, stable
In-Reply-To: <ak5riPx5d3rSG6MG@strlen.de>



On 7/8/2026 11:23 PM, Florian Westphal wrote:
> xietangxin <xietangxin@h-partners.com> wrote:
>> Thanks for your guidance. I’ve successfully fix the helper location
>> as you suggested, and it works fine for local traffic.
>>
>> However, I realized that I had completely overlooked the forwarding scenario
>> (where SNAT acts as a middlebox gateway, e.g. Host A -> Gateway B -> Server C).
>> In this gateway scenario, when random-fully is enabled, the test results show
>> a massive performance degradation: the QPS drops from ~19000 down to ~10000.
> 
> I don't think the forwarding case is fixable.
> 
> Host S could be another NAT gateway, so it could be possible that
> the connections originate from different physical machines and
> timestamps differ due to different clocks, not per-connection
> randomisation.
> 
>> Since skb->sk is NULL on the forwarding gateway, my current approach of
>> updating tp->tsoffset in struct tcp_sock cannot be applied here.
> 
> Yes. I think the tp->tsoffset recalc is fine to handle local case.
> 
> For local case we do know that we're the end host and ts recalc is fine.
> 
>> To be honest, I am currently stuck on how to handle this forwarding scenario
>> within the netfilter architecture without adding redundant overhead to the fast path.
>>
>> Could you please give some advice on how the community would prefer to resolve this?
>> For instance, should we look into extending the Conntrack NAT extension to
>> track and adjust the TCP timestamps?
> 
> If we have some guarantee that internal network isn't doing any
> snat at all, then yes, one could implement some TS adjustment
> scheme similar to seqadj extension we already have to deal with
> tcp sequence number adjustments.
> 
> We'd have to keep state and subtract the offset to get back the
> right tsecr again on reverse direction.
> 
> I'm not keen to have something like this, it would breaks PAWS
> as soon as the originating host is itself a nat gateway.
> 
> Is this really a problem to begin with?
Hi Florian,

Thanks for your precise analysis. I completely agree with you that
the forwarding case is theoretically unfixable due to the multi-tier NAT risks.

This is a real and severe problem for us, but the actual issue we encountered
is in the local case, not the forwarding case:

1.Laboratory Test Case Failure:
We noticed a severe HTTP performance regression in our automated Kubernetes testing,
where wrk was used to benchmark Pod client http performance. Through git bisect,
we successfully pinned the commit 165573e41f2f ("tcp: secure_seq: add back ports to TS offset").
The trigger was the default MASQUERADE --random-fully rule configured by kube-proxy on the k8s node.

2.Downstream Production Impact (AI Inference Cluster on Kubernetes):
Shortly after, one of our major downstream product teams reported a massive performance degradation.
After they upgraded their kernel to a version containing commit 165573e41f2f,
they suffered a 40% AI inference performance drop. They confirmed that simply
removing the random-fully flag instantly restored the performance back to normal.

Would it be acceptable to a V2 patch that targets the local case?

-- 
Best regards,
Tangxin Xie


^ permalink raw reply

* [PATCH iproute2-next v5 0/2] devlink: support u64-array devlink parameters
From: Ratheesh Kannoth @ 2026-07-09  3:50 UTC (permalink / raw)
  To: stephen, dsahern, kuba, linux-kernel, netdev
  Cc: rkannoth, andrew+netdev, edumazet, pabeni, jiri

The kernel gained support for devlink parameters of type
DEVLINK_VAR_ATTR_TYPE_U64_ARRAY.  These parameters carry a variable-length
list of u64 values encoded as multiple DEVLINK_ATTR_PARAM_VALUE_DATA
attributes.  This is used by drivers that need to expose ordered lists of
configuration values, such as the Marvell CN20K npc_srch_order parameter.

This series updates the devlink tool to handle the new UAPI and adds
show/set support for u64-array parameters on both device and port params.

Patch 1 switches devlink param show/set to use DEVLINK_VAR_ATTR_TYPE_*
constants instead of generic MNL_TYPE_* values when interpreting
DEVLINK_ATTR_PARAM_TYPE.  The kernel now reports param types using
devlink_var_attr_type, so userspace must use the matching symbols.

Patch 2 adds parsing, display, and configuration support for
DEVLINK_VAR_ATTR_TYPE_U64_ARRAY.  Values are shown as a space-separated
list of u64 elements.  Setting accepts a space- or comma-separated list
and emits one DEVLINK_ATTR_PARAM_VALUE_DATA attribute per element.

Tested on CN20K hardware with npc_srch_order:

  # show search order
  devlink dev param show pci/0002:01:00.0 name npc_srch_order
  pci/0002:01:00.0:
    name npc_srch_order type driver-specific
      values:
        cmode runtime value  value  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

  # set search order
  devlink dev param set pci/0002:01:00.0 name npc_srch_order \
    value 31,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 \
    cmode runtime

Ratheesh Kannoth (2):
  devlink: use DEVLINK_VAR_ATTR_TYPE_* in param show/set
  devlink: support u64-array values in devlink param show/set

 devlink/devlink.c            | 178 ++++++++++++++++++++++++++++++++---
 include/uapi/linux/devlink.h |   1 +
 2 files changed, 164 insertions(+), 15 deletions(-)

--
v4 -> v5: Addressed David comments
	https://lore.kernel.org/netdev/20260702031359.2392868-1-rkannoth@marvell.com/

v3 -> v4: Addressed David comments
	https://lore.kernel.org/netdev/20260701031359.839221-1-rkannoth@marvell.com/

v2 -> v3: Addressed David comments
	https://lore.kernel.org/netdev/akSCBN0N_7ug1-Fy@rkannoth-OptiPlex-7090/

v1 -> v2: Addressed David comments
	https://lore.kernel.org/netdev/20260615041042.549715-1-rkannoth@marvell.com/

2.43.0

^ permalink raw reply

* [PATCH v5 iproute2-next 2/2] devlink: support u64-array values in devlink param show/set
From: Ratheesh Kannoth @ 2026-07-09  3:50 UTC (permalink / raw)
  To: stephen, dsahern, kuba, linux-kernel, netdev
  Cc: rkannoth, andrew+netdev, edumazet, pabeni, jiri
In-Reply-To: <20260709035016.911607-1-rkannoth@marvell.com>

Add support for DEVLINK_VAR_ATTR_TYPE_U64_ARRAY parameters that carry
multiple DEVLINK_ATTR_PARAM_VALUE_DATA attributes. Parse and display
u64 array values in param show, and accept space- or comma-separated
u64 values in devlink and port param set commands.

- Show search order

devlink -jp dev param show pci/0002:01:00.0 name npc_srch_order
{
    "param": {
        "pci/0002:01:00.0": [ {
                "name": "npc_srch_order",
                "type": "driver-specific",
                "values": [ {
                        "cmode": "runtime",
                        "value": [ 15,17,14,18,13,19,12,20,11,21,10,22,9,23,8,24,7,25,6,26,5,27,4,28,3,29,2,30,1,31,0,16 ]
                    } ]
            } ]
    }
}

devlink dev param show pci/0002:01:00.0 name npc_srch_order
pci/0002:01:00.0:
  name npc_srch_order type driver-specific
    values:
      cmode runtime value 15 17 14 18 13 19 12 20 11 21 10 22 9 23 8 24 7 25 6 26 5 27 4 28 3 29 2 30 1 31 0 16

- Set search order

devlink dev param set pci/0002:01:00.0 name npc_srch_order value 31,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,\
                22,23,24,25,26,27,28,29,30 cmode runtime

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 devlink/devlink.c | 246 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 223 insertions(+), 23 deletions(-)

diff --git a/devlink/devlink.c b/devlink/devlink.c
index 803ea5d7..b6b24b49 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -3516,11 +3516,145 @@ static const struct param_val_conv param_val_conv[] = {
 
 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
 
+struct devlink_param_u64_array {
+	uint64_t size;
+	uint64_t *val;
+};
+
+static void param_value_u64_array_free(struct devlink_param_u64_array *arr)
+{
+	free(arr->val);
+	arr->val = NULL;
+	arr->size = 0;
+}
+
+static int param_value_nested_u64_attr_cb(const struct nlattr *attr, void *data)
+{
+	struct devlink_param_u64_array *arr = data;
+	uint64_t *new_val;
+	unsigned int len;
+	uint64_t val;
+
+	if (mnl_attr_get_type(attr) != DEVLINK_ATTR_PARAM_VALUE_DATA)
+		return MNL_CB_OK;
+
+	len = mnl_attr_get_payload_len(attr);
+	if (len == sizeof(uint32_t))
+		val = mnl_attr_get_u32(attr);
+	else if (len == sizeof(uint64_t))
+		val = mnl_attr_get_u64(attr);
+	else
+		return MNL_CB_ERROR;
+
+	new_val = realloc(arr->val, (arr->size + 1) * sizeof(uint64_t));
+	if (!new_val)
+		return MNL_CB_ERROR;
+	arr->val = new_val;
+
+	arr->val[arr->size] = val;
+	arr->size++;
+
+	return MNL_CB_OK;
+}
+
+static int param_value_u64_array_fill(struct nlattr *nl,
+				      struct devlink_param_u64_array *arr)
+{
+	int err;
+
+	param_value_u64_array_free(arr);
+	err = mnl_attr_parse_nested(nl, param_value_nested_u64_attr_cb, arr);
+	if (err != MNL_CB_OK) {
+		param_value_u64_array_free(arr);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static bool param_value_u64_array_equal(const struct devlink_param_u64_array *a,
+					const struct devlink_param_u64_array *b)
+{
+	uint64_t i;
+
+	if (a->size != b->size)
+		return false;
+
+	for (i = 0; i < a->size; i++) {
+		if (a->val[i] != b->val[i])
+			return false;
+	}
+
+	return true;
+}
+
+static int param_value_u64_array_put_from_str(struct nlmsghdr *nlh,
+					      const char *param_value,
+					      const struct devlink_param_u64_array *cur)
+{
+	struct devlink_param_u64_array new_arr = {};
+	char *copy, *token, *saveptr = NULL;
+	uint64_t val, *new_val;
+	char delim[] = " ,";
+	uint64_t i;
+	int err;
+
+	copy = strdup(param_value);
+	if (!copy)
+		return -ENOMEM;
+
+	token = strtok_r(copy, delim, &saveptr);
+	while (token) {
+		err = get_u64((__u64 *)&val, token, 10);
+		if (err) {
+			free(copy);
+			param_value_u64_array_free(&new_arr);
+			pr_err("Value \"%s\" is not a number or not within range\n",
+			       token);
+			return err;
+		}
+
+		new_val = realloc(new_arr.val, (new_arr.size + 1) * sizeof(uint64_t));
+		if (!new_val) {
+			free(copy);
+			param_value_u64_array_free(&new_arr);
+			return -ENOMEM;
+		}
+		new_arr.val = new_val;
+
+		new_arr.val[new_arr.size] = val;
+		new_arr.size++;
+		token = strtok_r(NULL, delim, &saveptr);
+	}
+	free(copy);
+
+	if (!new_arr.size) {
+		param_value_u64_array_free(&new_arr);
+		pr_err("Value must contain at least one element\n");
+		return -EINVAL;
+	}
+
+	/* Check current and new values. If both are equal, bail out */
+	if (cur && param_value_u64_array_equal(&new_arr, cur)) {
+		param_value_u64_array_free(&new_arr);
+		return 1;
+	}
+
+	for (i = 0; i < new_arr.size; i++)
+		mnl_attr_put_u64(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, new_arr.val[i]);
+
+	param_value_u64_array_free(&new_arr);
+	return 0;
+}
+
 static int pr_out_param_value_print(const char *nla_name, int nla_type,
 				     struct nlattr *val_attr, bool conv_exists,
-				     const char *label, bool flag_as_u8)
+				     const char *label, bool flag_as_u8,
+				     struct nlattr *u64_arr_nl)
 {
+	struct devlink_param_u64_array u64_arr = { };
 	const char *vstr;
+	uint64_t i;
 	int err;
 
 	print_string(PRINT_FP, NULL, " %s ", label);
@@ -3582,6 +3716,23 @@ static int pr_out_param_value_print(const char *nla_name, int nla_type,
 		else
 			print_bool(PRINT_ANY, label, "%s", val_attr);
 		break;
+	case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY:
+		err = param_value_u64_array_fill(u64_arr_nl, &u64_arr);
+		if (err)
+			return err;
+
+		if (is_json_context()) {
+			open_json_array(PRINT_JSON, label);
+			for (i = 0; i < u64_arr.size; i++)
+				print_u64(PRINT_JSON, NULL, NULL, u64_arr.val[i]);
+			close_json_array(PRINT_JSON, NULL);
+		} else {
+			for (i = 0; i < u64_arr.size; i++)
+				print_u64(PRINT_FP, NULL, "%llu ", u64_arr.val[i]);
+		}
+
+		param_value_u64_array_free(&u64_arr);
+		break;
 	}
 
 	return 0;
@@ -3601,6 +3752,7 @@ static void pr_out_param_value(struct dl *dl, const char *nla_name,
 
 	if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
 	    (nla_type != MNL_TYPE_FLAG &&
+	     nla_type != DEVLINK_VAR_ATTR_TYPE_U64_ARRAY &&
 	     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
 		return;
 
@@ -3614,14 +3766,15 @@ static void pr_out_param_value(struct dl *dl, const char *nla_name,
 					    nla_name);
 
 	err = pr_out_param_value_print(nla_name, nla_type, val_attr,
-				       conv_exists, "value", false);
+				       conv_exists, "value", false, nl);
 	if (err)
 		return;
 
 	val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DEFAULT];
 	if (val_attr) {
 		err = pr_out_param_value_print(nla_name, nla_type, val_attr,
-					       conv_exists, "default", true);
+					       conv_exists, "default", true,
+					       val_attr);
 		if (err)
 			return;
 	}
@@ -3704,6 +3857,7 @@ struct param_ctx {
 		uint64_t vu64;
 		const char *vstr;
 		bool vbool;
+		struct devlink_param_u64_array u64arr;
 	} value;
 };
 
@@ -3745,6 +3899,7 @@ static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
 
 		if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
 		    (nla_type != MNL_TYPE_FLAG &&
+		     nla_type != DEVLINK_VAR_ATTR_TYPE_U64_ARRAY &&
 		     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
 			return MNL_CB_ERROR;
 
@@ -3771,6 +3926,12 @@ static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
 			case DEVLINK_VAR_ATTR_TYPE_FLAG:
 				ctx->value.vbool = val_attr ? true : false;
 				break;
+			case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY:
+				err = param_value_u64_array_fill(param_value_attr,
+								 &ctx->value.u64arr);
+				if (err)
+					return MNL_CB_ERROR;
+				break;
 			}
 			break;
 		}
@@ -3818,10 +3979,11 @@ static int cmd_dev_param_set(struct dl *dl)
 	ctx.dl = dl;
 	err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
 	if (err)
-		return err;
+		goto out;
 	if (!ctx.cmode_found) {
 		pr_err("Configuration mode not supported\n");
-		return -ENOTSUP;
+		err = -ENOTSUP;
+		goto out;
 	}
 
 	if (dl->opts.present & DL_OPT_PARAM_SET_DEFAULT) {
@@ -3829,7 +3991,8 @@ static int cmd_dev_param_set(struct dl *dl)
 				       NLM_F_REQUEST | NLM_F_ACK);
 		dl_opts_put(nlh, dl);
 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
-		return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
+		err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
+		goto out;
 	}
 
 	nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_SET,
@@ -3855,7 +4018,7 @@ static int cmd_dev_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_u8 == ctx.value.vu8)
-			return 0;
+			goto out;
 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
 		break;
 	case DEVLINK_VAR_ATTR_TYPE_U16:
@@ -3872,7 +4035,7 @@ static int cmd_dev_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_u16 == ctx.value.vu16)
-			return 0;
+			goto out;
 		mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
 		break;
 	case DEVLINK_VAR_ATTR_TYPE_U32:
@@ -3889,7 +4052,7 @@ static int cmd_dev_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_u32 == ctx.value.vu32)
-			return 0;
+			goto out;
 		mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
 		break;
 	case DEVLINK_VAR_ATTR_TYPE_U64:
@@ -3904,7 +4067,7 @@ static int cmd_dev_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_u64 == ctx.value.vu64)
-			return 0;
+			goto out;
 		mnl_attr_put_u64(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u64);
 		break;
 	case DEVLINK_VAR_ATTR_TYPE_FLAG:
@@ -3912,7 +4075,7 @@ static int cmd_dev_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_bool == ctx.value.vbool)
-			return 0;
+			goto out;
 		if (val_bool)
 			mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
 				     0, NULL);
@@ -3921,17 +4084,32 @@ static int cmd_dev_param_set(struct dl *dl)
 		mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
 				  dl->opts.param_value);
 		if (!strcmp(dl->opts.param_value, ctx.value.vstr))
-			return 0;
+			goto out;
+		break;
+	case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY:
+		err = param_value_u64_array_put_from_str(nlh, dl->opts.param_value,
+							 &ctx.value.u64arr);
+		if (err == 1) {
+			err = 0;
+			goto out;
+		}
+		if (err)
+			goto out;
 		break;
 	default:
 		printf("Value type not supported\n");
-		return -ENOTSUP;
+		err = -ENOTSUP;
+		goto out;
 	}
-	return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
+	err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
+	goto out;
 
 err_param_value_parse:
 	pr_err("Value \"%s\" is not a number or not within range\n",
 	       dl->opts.param_value);
+
+out:
+	param_value_u64_array_free(&ctx.value.u64arr);
 	return err;
 }
 
@@ -5369,6 +5547,7 @@ static int cmd_port_param_set_cb(const struct nlmsghdr *nlh, void *data)
 
 		if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
 		    (nla_type != MNL_TYPE_FLAG &&
+		     nla_type != DEVLINK_VAR_ATTR_TYPE_U64_ARRAY &&
 		     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
 			return MNL_CB_ERROR;
 
@@ -5391,6 +5570,12 @@ static int cmd_port_param_set_cb(const struct nlmsghdr *nlh, void *data)
 			case MNL_TYPE_FLAG:
 				ctx->value.vbool = val_attr ? true : false;
 				break;
+			case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY:
+				err = param_value_u64_array_fill(param_value_attr,
+								 &ctx->value.u64arr);
+				if (err)
+					return MNL_CB_ERROR;
+				break;
 			}
 			break;
 		}
@@ -5426,7 +5611,7 @@ static int cmd_port_param_set(struct dl *dl)
 	ctx.dl = dl;
 	err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_set_cb, &ctx);
 	if (err)
-		return err;
+		goto out;
 
 	nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_SET,
 					  NLM_F_REQUEST | NLM_F_ACK);
@@ -5451,7 +5636,7 @@ static int cmd_port_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_u8 == ctx.value.vu8)
-			return 0;
+			goto out;
 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
 		break;
 	case MNL_TYPE_U16:
@@ -5468,7 +5653,7 @@ static int cmd_port_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_u16 == ctx.value.vu16)
-			return 0;
+			goto out;
 		mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
 		break;
 	case MNL_TYPE_U32:
@@ -5485,7 +5670,7 @@ static int cmd_port_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_u32 == ctx.value.vu32)
-			return 0;
+			goto out;
 		mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
 		break;
 	case MNL_TYPE_U64:
@@ -5500,7 +5685,7 @@ static int cmd_port_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_u64 == ctx.value.vu64)
-			return 0;
+			goto out;
 		mnl_attr_put_u64(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u64);
 		break;
 	case MNL_TYPE_FLAG:
@@ -5508,7 +5693,7 @@ static int cmd_port_param_set(struct dl *dl)
 		if (err)
 			goto err_param_value_parse;
 		if (val_bool == ctx.value.vbool)
-			return 0;
+			goto out;
 		if (val_bool)
 			mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
 				     0, NULL);
@@ -5517,17 +5702,32 @@ static int cmd_port_param_set(struct dl *dl)
 		mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
 				  dl->opts.param_value);
 		if (!strcmp(dl->opts.param_value, ctx.value.vstr))
-			return 0;
+			goto out;
+		break;
+	case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY:
+		err = param_value_u64_array_put_from_str(nlh, dl->opts.param_value,
+							 &ctx.value.u64arr);
+		if (err == 1) {
+			err = 0;
+			goto out;
+		}
+		if (err)
+			goto out;
 		break;
 	default:
 		printf("Value type not supported\n");
-		return -ENOTSUP;
+		err = -ENOTSUP;
+		goto out;
 	}
-	return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
+	err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
+	goto out;
 
 err_param_value_parse:
 	pr_err("Value \"%s\" is not a number or not within range\n",
 	       dl->opts.param_value);
+
+out:
+	param_value_u64_array_free(&ctx.value.u64arr);
 	return err;
 }
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v5 iproute2-next 1/2] devlink: use DEVLINK_VAR_ATTR_TYPE_* in param show/set
From: Ratheesh Kannoth @ 2026-07-09  3:50 UTC (permalink / raw)
  To: stephen, dsahern, kuba, linux-kernel, netdev
  Cc: rkannoth, andrew+netdev, edumazet, pabeni, jiri
In-Reply-To: <20260709035016.911607-1-rkannoth@marvell.com>

Replace MNL_TYPE_* constants with DEVLINK_VAR_ATTR_TYPE_* when
handling DEVLINK_ATTR_PARAM_TYPE in param value display and set
paths. The kernel uAPI now exposes these values directly via
devlink_var_attr_type.

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
 devlink/devlink.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/devlink/devlink.c b/devlink/devlink.c
index 434a91fe..803ea5d7 100644
--- a/devlink/devlink.c
+++ b/devlink/devlink.c
@@ -3526,7 +3526,7 @@ static int pr_out_param_value_print(const char *nla_name, int nla_type,
 	print_string(PRINT_FP, NULL, " %s ", label);
 
 	switch (nla_type) {
-	case MNL_TYPE_U8:
+	case DEVLINK_VAR_ATTR_TYPE_U8:
 		if (conv_exists) {
 			err = param_val_conv_str_get(param_val_conv,
 						     PARAM_VAL_CONV_LEN,
@@ -3541,7 +3541,7 @@ static int pr_out_param_value_print(const char *nla_name, int nla_type,
 				   mnl_attr_get_u8(val_attr));
 		}
 		break;
-	case MNL_TYPE_U16:
+	case DEVLINK_VAR_ATTR_TYPE_U16:
 		if (conv_exists) {
 			err = param_val_conv_str_get(param_val_conv,
 						     PARAM_VAL_CONV_LEN,
@@ -3556,7 +3556,7 @@ static int pr_out_param_value_print(const char *nla_name, int nla_type,
 				   mnl_attr_get_u16(val_attr));
 		}
 		break;
-	case MNL_TYPE_U32:
+	case DEVLINK_VAR_ATTR_TYPE_U32:
 		if (conv_exists) {
 			err = param_val_conv_str_get(param_val_conv,
 						     PARAM_VAL_CONV_LEN,
@@ -3571,11 +3571,11 @@ static int pr_out_param_value_print(const char *nla_name, int nla_type,
 				   mnl_attr_get_u32(val_attr));
 		}
 		break;
-	case MNL_TYPE_STRING:
+	case DEVLINK_VAR_ATTR_TYPE_STRING:
 		print_string(PRINT_ANY, label, "%s",
 			     mnl_attr_get_str(val_attr));
 		break;
-	case MNL_TYPE_FLAG:
+	case DEVLINK_VAR_ATTR_TYPE_FLAG:
 		if (flag_as_u8)
 			print_bool(PRINT_ANY, label, "%s",
 				   mnl_attr_get_u8(val_attr));
@@ -3753,22 +3753,22 @@ static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
 			ctx->cmode_found = true;
 			val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
 			switch (nla_type) {
-			case MNL_TYPE_U8:
+			case DEVLINK_VAR_ATTR_TYPE_U8:
 				ctx->value.vu8 = mnl_attr_get_u8(val_attr);
 				break;
-			case MNL_TYPE_U16:
+			case DEVLINK_VAR_ATTR_TYPE_U16:
 				ctx->value.vu16 = mnl_attr_get_u16(val_attr);
 				break;
-			case MNL_TYPE_U32:
+			case DEVLINK_VAR_ATTR_TYPE_U32:
 				ctx->value.vu32 = mnl_attr_get_u32(val_attr);
 				break;
-			case MNL_TYPE_U64:
+			case DEVLINK_VAR_ATTR_TYPE_U64:
 				ctx->value.vu64 = mnl_attr_get_u64(val_attr);
 				break;
-			case MNL_TYPE_STRING:
+			case DEVLINK_VAR_ATTR_TYPE_STRING:
 				ctx->value.vstr = mnl_attr_get_str(val_attr);
 				break;
-			case MNL_TYPE_FLAG:
+			case DEVLINK_VAR_ATTR_TYPE_FLAG:
 				ctx->value.vbool = val_attr ? true : false;
 				break;
 			}
@@ -3841,7 +3841,7 @@ static int cmd_dev_param_set(struct dl *dl)
 
 	mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
 	switch (ctx.nla_type) {
-	case MNL_TYPE_U8:
+	case DEVLINK_VAR_ATTR_TYPE_U8:
 		if (conv_exists) {
 			err = param_val_conv_uint_get(param_val_conv,
 						      PARAM_VAL_CONV_LEN,
@@ -3858,7 +3858,7 @@ static int cmd_dev_param_set(struct dl *dl)
 			return 0;
 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
 		break;
-	case MNL_TYPE_U16:
+	case DEVLINK_VAR_ATTR_TYPE_U16:
 		if (conv_exists) {
 			err = param_val_conv_uint_get(param_val_conv,
 						      PARAM_VAL_CONV_LEN,
@@ -3875,7 +3875,7 @@ static int cmd_dev_param_set(struct dl *dl)
 			return 0;
 		mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
 		break;
-	case MNL_TYPE_U32:
+	case DEVLINK_VAR_ATTR_TYPE_U32:
 		if (conv_exists) {
 			err = param_val_conv_uint_get(param_val_conv,
 						      PARAM_VAL_CONV_LEN,
@@ -3892,7 +3892,7 @@ static int cmd_dev_param_set(struct dl *dl)
 			return 0;
 		mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
 		break;
-	case MNL_TYPE_U64:
+	case DEVLINK_VAR_ATTR_TYPE_U64:
 		if (conv_exists)
 			err = param_val_conv_uint_get(param_val_conv,
 						      PARAM_VAL_CONV_LEN,
@@ -3907,7 +3907,7 @@ static int cmd_dev_param_set(struct dl *dl)
 			return 0;
 		mnl_attr_put_u64(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u64);
 		break;
-	case MNL_TYPE_FLAG:
+	case DEVLINK_VAR_ATTR_TYPE_FLAG:
 		err = str_to_bool(dl->opts.param_value, &val_bool);
 		if (err)
 			goto err_param_value_parse;
@@ -3917,7 +3917,7 @@ static int cmd_dev_param_set(struct dl *dl)
 			mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
 				     0, NULL);
 		break;
-	case MNL_TYPE_STRING:
+	case DEVLINK_VAR_ATTR_TYPE_STRING:
 		mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
 				  dl->opts.param_value);
 		if (!strcmp(dl->opts.param_value, ctx.value.vstr))
-- 
2.43.0


^ permalink raw reply related

* Question: net: phy: realtek: RTL8211FS SGMII bridge mode support
From: Jacky Huang @ 2026-07-09  3:52 UTC (permalink / raw)
  To: Andrew Lunn, Heiner Kallweit
  Cc: Russell King, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Daniel Golle, Vladimir Oltean, netdev, linux-kernel

Hi,

RTL8211FS is the SGMII-capable variant of RTL8211F. Besides the standard
copper/RGMII mode, it supports hardware-strapped RGMII-to-SGMII bridge mode,
where the MAC side uses RGMII and the line side uses SGMII.

The in-tree realtek driver currently does not handle this mode. RTL8211FS
shares the same PHY ID as RTL8211F (0x001cc916), so the driver binds it
as a standard RTL8211F and follows the existing copper/RGMII path. In
RGMII-to-SGMII bridge mode, this means read_status() does not observe the
SGMII-side link and the link stays down.

We have discussed this with Realtek. They confirmed that the current mode
can be detected from a vendor mode-selection register shared by RTL8211F
variants, and that this case is application-dependent rather than generic
copper PHY behavior.

Our plan is to add RTL8211FS bridge mode support inside the realtek
driver, gated on the detected mode. The driver would only read this
register for detection and would not use it to override the hardware
strapping. For that mode, config_init() would program the SGMII side as
needed, and read_status() would read the SGMII-side link status instead
of relying on the copper path. The existing RTL8211F copper/RGMII behavior
would be left unchanged.

Does this approach sound acceptable for upstream? If you prefer a
different model, or if there is already related work that we should build
on, please let me know.

Thanks,
Jacky C. Huang

^ permalink raw reply

* Re: [PATCH net] bnxt_en: Handle partially initialized auxiliary devices
From: Pavan Chebbi @ 2026-07-09  4:25 UTC (permalink / raw)
  To: Ruoyu Wang
  Cc: michael.chan, andrew+netdev, davem, edumazet, kuba, pabeni,
	jacob.e.keller, andrew.gospodarek, vikas.gupta, netdev,
	linux-kernel
In-Reply-To: <20260708143401.3167477-1-ruoyuw560@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3739 bytes --]

On Wed, Jul 8, 2026 at 8:04 PM Ruoyu Wang <ruoyuw560@gmail.com> wrote:
>
> bnxt_aux_devices_init() calls auxiliary_device_init() before allocating
> and attaching the bnxt_en_dev and ULP table.  After
> auxiliary_device_init() succeeds, the auxiliary bus owns the embedded
> device lifetime and the driver must unwind later errors with
> auxiliary_device_uninit(), which runs bnxt_aux_dev_release().
>
> The release callback currently assumes that aux_priv->id, aux_priv->edev
> and edev->net were all populated.  If the bnxt_en_dev allocation fails,
> release dereferences aux_priv->edev while it is still NULL.  If a later
> failure happens before aux_priv->id is assigned, release uses the zeroed
> id field and can clear the wrong auxiliary-device slot while unwinding a
> partially initialized device.
>
> Set aux_priv->id before auxiliary_device_init() so the release path can
> identify the slot, make release tolerate missing partial state, and clear
> bp->aux_priv[idx] on the unwind path where release cannot derive bp from
> an edev.
>
> This issue was found by a static analysis checker and confirmed by manual
> source review.
>
> Fixes: 194fad5b2781 ("bnxt_en: Refactor bnxt_rdma_aux_device_init/uninit functions")
> Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
> ---
>  drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
> index 5c751933da6a9..e85d1b6c9fb1f 100644
> --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
> +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
> @@ -472,12 +472,17 @@ static void bnxt_aux_dev_release(struct device *dev)
>  {
>         struct bnxt_aux_priv *aux_priv =
>                 container_of(dev, struct bnxt_aux_priv, aux_dev.dev);
> -       struct bnxt *bp = netdev_priv(aux_priv->edev->net);
> +       struct bnxt_en_dev *edev = aux_priv->edev;
> +       struct bnxt *bp = edev && edev->net ? netdev_priv(edev->net) : NULL;
>
> -       kfree(aux_priv->edev->ulp_tbl);
> -       bp->edev[aux_priv->id] = NULL;
> -       kfree(aux_priv->edev);
> -       bp->aux_priv[aux_priv->id] = NULL;
> +       if (edev) {

Instead of these checks, just allocate the memory for edev and ulp
before calling auxiliary_device_init().
That would be much cleaner.

> +               kfree(edev->ulp_tbl);
> +               if (bp)
> +                       bp->edev[aux_priv->id] = NULL;
> +               kfree(edev);
> +       }
> +       if (bp)
> +               bp->aux_priv[aux_priv->id] = NULL;
>         kfree(aux_priv);
>  }
>
> @@ -571,6 +576,7 @@ void bnxt_aux_devices_init(struct bnxt *bp)
>                 aux_dev->name = bnxt_aux_devices[idx].name;
>                 aux_dev->dev.parent = &bp->pdev->dev;
>                 aux_dev->dev.release = bnxt_aux_dev_release;
> +               aux_priv->id = idx;
>
>                 rc = auxiliary_device_init(aux_dev);
>                 if (rc) {
> @@ -598,12 +604,12 @@ void bnxt_aux_devices_init(struct bnxt *bp)
>                 bp->edev[idx] = edev;
>                 if (idx == BNXT_AUXDEV_RDMA)
>                         bp->ulp_num_msix_want = bnxt_set_dflt_ulp_msix(bp);
> -               aux_priv->id = idx;
>                 bnxt_auxdev_set_state(bp, idx, BNXT_ADEV_STATE_INIT);
>
>                 continue;
>  aux_dev_uninit:
>                 auxiliary_device_uninit(aux_dev);
> +               bp->aux_priv[idx] = NULL;
>  next_auxdev:
>                 if (idx == BNXT_AUXDEV_RDMA)
>                         bp->flags &= ~BNXT_FLAG_ROCE_CAP;
> --
> 2.51.0

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]

^ permalink raw reply

* [PATCH net] qede: Fix NULL pointer dereference in TPA fragment processing
From: Vaibhav Nagare @ 2026-07-09  4:47 UTC (permalink / raw)
  To: davem, kuba, pabeni, edumazet, andrew+netdev
  Cc: matvey.kovalev, Pavel.Zhigulin, aelior, manishc, netdev,
	linux-kernel, stable, Vaibhav Nagare

  Under memory pressure, the qede driver encounters NULL pointer
  dereferences when processing TPA continuation fragments because:
  1. qede_fill_frag_skb() does not validate the page pointer before use
  2. qede_tpa_end() checks error state AFTER calling qede_fill_frag_skb()

  The crash occurs when:
  1. System experiences memory pressure (GFP_ATOMIC allocations fail)
  2. qede_alloc_rx_buffer() returns -ENOMEM, leaving sw_rx_data->data NULL
  3. qede_tpa_start() sets QEDE_AGG_STATE_ERROR on SKB allocation failure
  4. Hardware delivers TPA_CONT and TPA_END events for this aggregation
  5. qede_tpa_end() calls qede_fill_frag_skb() before checking error state
  6. qede_fill_frag_skb() accesses NULL pointer in skb_fill_page_desc()
  7. Kernel panics with NULL pointer dereference

Example crash from production system:
  BUG: unable to handle kernel NULL pointer dereference at 0x8
  RIP: qede_fill_frag_skb+0x96/0x430 [qede]
  Call Trace:
    qede_rx_int+0xb06/0x1de0
    qede_poll+0x2f4/0x6c0
    __napi_poll+0x2d/0x130

Observed on HPE Synergy 480 Gen11 running RHEL 8.10
(4.18.0-553.134.1.el8_10.x86_64), but the vulnerable code path
exists in mainline.

Fix by:
1. Adding NULL page validation in qede_fill_frag_skb() before dereferencing
2. Checking error state EARLY in qede_tpa_end() before processing fragments
3. Checking error state in qede_tpa_cont() to skip fragment processing

This allows the system to survive memory pressure by dropping packets
instead of crashing.

Fixes: 55482edc25f0 ("qede: Add slowpath/fastpath support and enable hardware GRO")
Cc: stable@vger.kernel.org

Signed-off-by: Vaibhav Nagare <vnagare@redhat.com>
---
 drivers/net/ethernet/qlogic/qede/qede_fp.c | 25 ++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c
index 33e18bb69774..95b5cfcc43c2 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_fp.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c
@@ -670,13 +670,22 @@ static int qede_fill_frag_skb(struct qede_dev *edev,
 							 NUM_RX_BDS_MAX];
 	struct qede_agg_info *tpa_info = &rxq->tpa_info[tpa_agg_index];
 	struct sk_buff *skb = tpa_info->skb;
+	struct page *page = current_bd->data;
 
 	if (unlikely(tpa_info->state != QEDE_AGG_STATE_START))
 		goto out;
 
+	/* Avoid NULL pointer dereference when under severe memory pressure */
+	if (unlikely(!page)) {
+		DP_NOTICE(edev,
+			  "Failed to allocate RX buffer for TPA agg %u\n",
+			  tpa_agg_index);
+		goto out;
+	}
+
 	/* Add one frag and update the appropriate fields in the skb */
 	skb_fill_page_desc(skb, tpa_info->frag_id++,
-			   current_bd->data,
+			   page,
 			   current_bd->page_offset + rxq->rx_headroom,
 			   len_on_bd);
 
@@ -684,7 +693,7 @@ static int qede_fill_frag_skb(struct qede_dev *edev,
 		/* Incr page ref count to reuse on allocation failure
 		 * so that it doesn't get freed while freeing SKB.
 		 */
-		page_ref_inc(current_bd->data);
+		page_ref_inc(page);
 		goto out;
 	}
 
@@ -959,8 +968,16 @@ static inline void qede_tpa_cont(struct qede_dev *edev,
 				 struct qede_rx_queue *rxq,
 				 struct eth_fast_path_rx_tpa_cont_cqe *cqe)
 {
+	struct qede_agg_info *tpa_info = &rxq->tpa_info[cqe->tpa_agg_index];
 	int i;
 
+	/* Don't process fragments if TPA start failed */
+	if (unlikely(tpa_info->state != QEDE_AGG_STATE_START)) {
+		for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++)
+			qede_recycle_rx_bd_ring(rxq, 1);
+		return;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++)
 		qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
 				   le16_to_cpu(cqe->len_list[i]));
@@ -982,6 +999,10 @@ static int qede_tpa_end(struct qede_dev *edev,
 	tpa_info = &rxq->tpa_info[cqe->tpa_agg_index];
 	skb = tpa_info->skb;
 
+	/* Drop the packet if TPA start failed */
+	if (unlikely(tpa_info->state != QEDE_AGG_STATE_START || !skb))
+		goto err;
+
 	if (tpa_info->buffer.page_offset == PAGE_SIZE)
 		dma_unmap_page(rxq->dev, tpa_info->buffer.mapping,
 			       PAGE_SIZE, rxq->data_direction);
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH net-next 1/3] vxlan: pass vxlan_config pointer to helper functions
From: Pavan Chebbi @ 2026-07-09  4:53 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kuniyuki Iwashima, Ido Schimmel, Andrew Lunn, netdev,
	eric.dumazet
In-Reply-To: <20260708160411.1355008-2-edumazet@google.com>

[-- Attachment #1: Type: text/plain, Size: 953 bytes --]

On Wed, Jul 8, 2026 at 9:55 PM Eric Dumazet <edumazet@google.com> wrote:
>
> In preparation for converting vxlan->cfg to an RCU-protected pointer,
> refactor internal helper functions in the RX, TX, MDB, VNIFILTER, and
> OVS paths to accept a pointer to struct vxlan_config (or pass flags/
> saddr_family where appropriate) rather than directly accessing
> vxlan->cfg.

<-->

>  void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
> +                   const struct vxlan_config *cfg,
>                     __be32 default_vni, struct vxlan_rdst *rdst, bool did_rsc)
>  {
> +       unsigned int pkt_len = skb->len;
> +       __be16 src_port = 0, dst_port;
> +       struct dst_entry *ndst = NULL;
> +       enum skb_drop_reason reason;
> +       struct vxlan_dev *vxlan;

nit: Can this be pushed few lines below for the reverse xmas tree order..
otherwise LGTM.
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]

^ permalink raw reply

* Re: [PATCH net-next 2/3] vxlan: convert configuration to RCU protection
From: Pavan Chebbi @ 2026-07-09  4:54 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kuniyuki Iwashima, Ido Schimmel, Andrew Lunn, netdev,
	eric.dumazet
In-Reply-To: <20260708160411.1355008-3-edumazet@google.com>

[-- Attachment #1: Type: text/plain, Size: 1138 bytes --]

On Wed, Jul 8, 2026 at 9:57 PM Eric Dumazet <edumazet@google.com> wrote:
>
> In order to allow lockless readers in future patches, dynamically allocate
> 'struct vxlan_config' and convert 'vxlan->cfg' to an RCU protected pointer.
>
> Updating configuration via vxlan_changelink() or __vxlan_dev_create()
> now allocates a new struct vxlan_config, initializes it, and uses
> rcu_assign_pointer() to publish it, freeing the previous config with
> kfree_rcu().
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---
>  .../mellanox/mlxsw/spectrum_nve_vxlan.c       |  14 +-
>  .../mellanox/mlxsw/spectrum_switchdev.c       |  57 ++-
>  drivers/net/vxlan/vxlan_core.c                | 336 +++++++++++-------
>  drivers/net/vxlan/vxlan_mdb.c                 |  29 +-
>  drivers/net/vxlan/vxlan_multicast.c           |  12 +-
>  drivers/net/vxlan/vxlan_vnifilter.c           |  21 +-
>  include/net/vxlan.h                           |   3 +-
>  net/openvswitch/vport-vxlan.c                 |  31 +-
>  8 files changed, 331 insertions(+), 172 deletions(-)
>

Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]

^ permalink raw reply

* Re: [PATCH net-next 3/3] vxlan: no longer rely on RTNL in vxlan_fill_info()
From: Pavan Chebbi @ 2026-07-09  4:55 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: David S . Miller, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Kuniyuki Iwashima, Ido Schimmel, Andrew Lunn, netdev,
	eric.dumazet
In-Reply-To: <20260708160411.1355008-4-edumazet@google.com>

[-- Attachment #1: Type: text/plain, Size: 519 bytes --]

On Wed, Jul 8, 2026 at 10:01 PM Eric Dumazet <edumazet@google.com> wrote:
>
> Now that vxlan->cfg is RCU-protected, we can update vxlan_fill_info()
> to run under RCU read lock instead of relying on RTNL.
>
> This completes the transition to RTNL-less link info dumping for VXLAN.
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> ---
>  drivers/net/vxlan/vxlan_core.c | 13 +++++++++++--
>  1 file changed, 11 insertions(+), 2 deletions(-)
>

Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]

^ permalink raw reply

* Re: [PATCH net] net: clear transport header during tunnel decapsulation
From: kernel test robot @ 2026-07-09  5:00 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: oe-lkp, lkp, netdev, ltp, David S . Miller, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Ido Schimmel, David Ahern,
	eric.dumazet, Eric Dumazet, syzbot+d5d0d598a4cfdfafdc3b,
	oliver.sang
In-Reply-To: <20260624073209.3703492-1-edumazet@google.com>



Hello,

kernel test robot noticed "KASAN:slab-use-after-free_in_vxlan_rcv[vxlan]" on:

commit: 35913c60d9c1072bf8c8d4e626bde513eeffcc45 ("[PATCH net] net: clear transport header during tunnel decapsulation")
url: https://github.com/intel-lab-lkp/linux/commits/Eric-Dumazet/net-clear-transport-header-during-tunnel-decapsulation/20260624-153313
base: https://git.kernel.org/cgit/linux/kernel/git/davem/net.git d87363b0edfc7504ff2b144fe4cdd8154f90f42e
patch link: https://lore.kernel.org/all/20260624073209.3703492-1-edumazet@google.com/
patch subject: [PATCH net] net: clear transport header during tunnel decapsulation

in testcase: ltp
version: 
with following parameters:

	test: net.features



config: x86_64-rhel-9.4-ltp
compiler: gcc-14
test machine: 8 threads 1 sockets Intel(R) Core(TM) i7-4790T CPU @ 2.70GHz (Haswell) with 16G memory

(please refer to attached dmesg/kmsg for entire log/backtrace)



If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <oliver.sang@intel.com>
| Closes: https://lore.kernel.org/oe-lkp/202607091154.8fb0e88c-lkp@intel.com


The kernel config and materials to reproduce are available at:
https://download.01.org/0day-ci/archive/20260709/202607091154.8fb0e88c-lkp@intel.com


below decoded stack trace FYI:


kern  :err   : [  836.649020] [      C2] ==================================================================
kern  :err   : [  836.657473] [      C2] BUG: KASAN: slab-use-after-free in vxlan_rcv (kbuild/src/drivers/net/vxlan/vxlan_core.c:1567 kbuild/src/drivers/net/vxlan/vxlan_core.c:1745) vxlan
kern  :err   : [  836.665872] [      C2] Read of size 4 at addr ffff888414b94787 by task kworker/u32:14/3114

kern  :err   : [  836.677034] [      C2] CPU: 2 UID: 0 PID: 3114 Comm: kworker/u32:14 Tainted: G S                  7.1.0+ #1 PREEMPT(lazy)
kern  :err   : [  836.677039] [      C2] Tainted: [S]=CPU_OUT_OF_SPEC
kern  :err   : [  836.677041] [      C2] Hardware name: Gigabyte Technology Co., Ltd. Z97X-UD5H/Z97X-UD5H, BIOS F9 04/21/2015
kern  :err   : [  836.677043] [      C2] Workqueue: ipv6_addrconf addrconf_dad_work
kern  :err   : [  836.677051] [      C2] Call Trace:
kern  :err   : [  836.677053] [      C2]  <IRQ>
kern  :err   : [  836.677055] [      C2]  dump_stack_lvl (kbuild/src/lib/dump_stack.c:94 kbuild/src/lib/dump_stack.c:120)
kern  :err   : [  836.677060] [      C2]  print_address_description+0x70/0x300
kern  :err   : [  836.677066] [      C2]  ? vxlan_rcv (kbuild/src/drivers/net/vxlan/vxlan_core.c:1567 kbuild/src/drivers/net/vxlan/vxlan_core.c:1745) vxlan
kern  :err   : [  836.677074] [      C2]  print_report (kbuild/src/mm/kasan/report.c:482)
kern  :err   : [  836.677078] [      C2]  ? __virt_addr_valid (kbuild/src/include/linux/mmzone.h:2198 (discriminator 1) kbuild/src/include/linux/mmzone.h:2280 (discriminator 1) kbuild/src/arch/x86/mm/physaddr.c:54 (discriminator 1))
kern  :err   : [  836.677093] [      C2]  ? vxlan_rcv (kbuild/src/drivers/net/vxlan/vxlan_core.c:1567 kbuild/src/drivers/net/vxlan/vxlan_core.c:1745) vxlan
kern  :err   : [  836.677102] [      C2]  kasan_report (kbuild/src/mm/kasan/report.c:595)
kern  :err   : [  836.677105] [      C2]  ? vxlan_rcv (kbuild/src/drivers/net/vxlan/vxlan_core.c:1567 kbuild/src/drivers/net/vxlan/vxlan_core.c:1745) vxlan
kern  :err   : [  836.677115] [      C2] vxlan_rcv (kbuild/src/drivers/net/vxlan/vxlan_core.c:1567 kbuild/src/drivers/net/vxlan/vxlan_core.c:1745) vxlan
kern  :err   : [  836.677146] [      C2]  ? __pfx_vxlan_rcv (kbuild/src/drivers/net/vxlan/vxlan_core.c:2327) vxlan
kern  :err   : [  836.677153] [      C2]  ? ip6_list_rcv_finish+0x8d2/0xc30
kern  :err   : [  836.677156] [      C2]  ? __pfx_ip6_list_rcv_finish+0x10/0x10
kern  :err   : [  836.677158] [      C2]  ? ip6_parse_tlv (kbuild/src/net/ipv6/exthdrs.c:175)
kern  :err   : [  836.677162] [      C2]  ? __pfx_vxlan_rcv (kbuild/src/drivers/net/vxlan/vxlan_core.c:2327) vxlan
kern  :err   : [  836.677169] [      C2]  udp_queue_rcv_one_skb (kbuild/src/net/ipv4/udp.c:2388)
kern  :err   : [  836.677174] [      C2]  ? ipv6_parse_hopopts (kbuild/src/net/ipv6/exthdrs.c:1081)
kern  :err   : [  836.677177] [      C2]  udp_unicast_rcv_skb (kbuild/src/net/ipv4/udp.c:2574)
kern  :err   : [  836.677180] [      C2]  udp_rcv (kbuild/src/net/ipv4/udp.c:2640)
kern  :err   : [  836.677184] [      C2]  ? __pfx_udp_rcv (kbuild/src/net/ipv4/udp.c:2451 (discriminator 1))
kern  :err   : [  836.677187] [      C2]  ? ip_mc_validate_source (kbuild/src/include/net/ip_fib.h:460 kbuild/src/net/ipv4/route.c:1729 kbuild/src/net/ipv4/route.c:1705)
kern  :err   : [  836.677193] [      C2]  ip_protocol_deliver_rcu (kbuild/src/net/ipv4/ip_input.c:207 (discriminator 4))
kern  :err   : [  836.677196] [      C2]  ip_local_deliver_finish (kbuild/src/net/ipv4/ip_input.c:241 (discriminator 1))
kern  :err   : [  836.677199] [      C2]  ip_local_deliver (kbuild/src/include/linux/netfilter.h:318 kbuild/src/include/linux/netfilter.h:312 kbuild/src/net/ipv4/ip_input.c:262)
kern  :err   : [  836.677201] [      C2]  ? __pfx_ip_local_deliver (kbuild/src/include/linux/skbuff.h:4508 (discriminator 1))
kern  :err   : [  836.677204] [      C2]  ? ip_rcv_finish_core (kbuild/src/net/ipv4/ip_input.c:391)
kern  :err   : [  836.677206] [      C2]  ? netif_receive_skb_list_internal (kbuild/src/include/linux/rcupdate.h:873 kbuild/src/net/core/dev.c:6440)
kern  :err   : [  836.677210] [      C2]  ip_rcv (kbuild/src/include/net/dst.h:480 (discriminator 6) kbuild/src/net/ipv4/ip_input.c:492 (discriminator 6) kbuild/src/include/linux/netfilter.h:318 (discriminator 6) kbuild/src/include/linux/netfilter.h:312 (discriminator 6) kbuild/src/net/ipv4/ip_input.c:612 (discriminator 6))
kern  :err   : [  836.677212] [      C2]  ? __pfx_netif_receive_skb_list_internal (kbuild/src/net/core/dev.c:6662 (discriminator 2))
kern  :err   : [  836.677215] [      C2]  ? __pfx_ip_rcv (kbuild/src/include/net/dst.h:480 (discriminator 1))
kern  :err   : [  836.677218] [      C2]  ? __pfx_ip_rcv (kbuild/src/include/net/dst.h:480 (discriminator 1))
kern  :err   : [  836.677221] [      C2]  __netif_receive_skb_one_core (kbuild/src/net/core/dev.c:6206 (discriminator 4))
kern  :err   : [  836.677223] [      C2]  ? napi_complete_done (kbuild/src/include/linux/instrumented.h:55 kbuild/src/net/core/dev.c:6831)
kern  :err   : [  836.677226] [      C2]  ? __pfx___netif_receive_skb_one_core (kbuild/src/net/core/dev.c:6248)
kern  :err   : [  836.677229] [      C2]  ? _raw_spin_lock_irq (kbuild/src/include/linux/instrumented.h:55 kbuild/src/include/linux/atomic/atomic-instrumented.h:1301 kbuild/src/include/asm-generic/qspinlock.h:111 kbuild/src/include/linux/spinlock.h:187 kbuild/src/include/linux/spinlock_api_smp.h:143 kbuild/src/kernel/locking/spinlock.c:174)
kern  :err   : [  836.677235] [      C2]  process_backlog (kbuild/src/net/core/dev.c:6670)
kern  :err   : [  836.677238] [      C2]  __napi_poll (kbuild/src/net/core/dev.c:7729)
kern  :err   : [  836.677241] [      C2]  net_rx_action (kbuild/src/net/core/dev.c:7792 kbuild/src/net/core/dev.c:7949)
kern  :err   : [  836.677245] [      C2]  ? __pfx_net_rx_action (kbuild/src/include/net/gro.h:525)
kern  :err   : [  836.677248] [      C2]  ? __pfx_hrtimer_update_next_event (kbuild/src/kernel/time/hrtimer.c:195)
kern  :err   : [  836.677253] [      C2]  ? __pfx_sched_clock_cpu (kbuild/src/include/linux/list.h:226)
kern  :err   : [  836.677257] [      C2]  ? sched_clock (kbuild/src/arch/x86/kernel/tsc.c:297)
kern  :err   : [  836.677261] [      C2]  ? sched_clock_cpu (kbuild/src/kernel/sched/clock.c:400)
kern  :err   : [  836.677265] [      C2]  handle_softirqs (kbuild/src/kernel/softirq.c:622)
kern  :err   : [  836.677269] [      C2]  do_softirq (kbuild/src/kernel/softirq.c:523 (discriminator 20) kbuild/src/kernel/softirq.c:510 (discriminator 20))
kern  :err   : [  836.677272] [      C2]  </IRQ>
kern  :err   : [  836.677273] [      C2]  <TASK>
kern  :err   : [  836.677274] [      C2]  __local_bh_enable_ip (kbuild/src/kernel/softirq.c:450)
kern  :err   : [  836.677276] [      C2]  __dev_queue_xmit (kbuild/src/include/linux/bottom_half.h:33 kbuild/src/include/linux/rcupdate.h:914 kbuild/src/net/core/dev.c:4907)
kern  :err   : [  836.677280] [      C2]  ? unwind_next_frame (kbuild/src/include/linux/rcupdate.h:873 kbuild/src/include/linux/rcupdate.h:1183 kbuild/src/arch/x86/kernel/unwind_orc.c:495)
kern  :err   : [  836.677284] [      C2]  ? arch_stack_walk (kbuild/src/arch/x86/include/asm/unwind.h:64 kbuild/src/arch/x86/kernel/stacktrace.c:24)
kern  :err   : [  836.677287] [      C2]  ? kasan_save_track (kbuild/src/mm/kasan/common.c:78)
kern  :err   : [  836.677293] [      C2]  ? __pfx___dev_queue_xmit (kbuild/src/net/core/dev.c:4735)
kern  :err   : [  836.677296] [      C2]  ? __pfx__raw_spin_lock_bh (kbuild/src/kernel/locking/spinlock.c:159)
kern  :err   : [  836.677299] [      C2]  ? _raw_write_lock_bh (kbuild/src/include/linux/instrumented.h:55 kbuild/src/include/linux/atomic/atomic-instrumented.h:1301 kbuild/src/include/asm-generic/qrwlock.h:98 kbuild/src/include/linux/rwlock_api_smp.h:222 kbuild/src/kernel/locking/spinlock.c:338)
kern  :err   : [  836.677302] [      C2]  ? __asan_memcpy (kbuild/src/mm/kasan/shadow.c:106 (discriminator 1))
kern  :err   : [  836.677306] [      C2]  ? eth_header (kbuild/src/net/ethernet/eth.c:99 (discriminator 6))
kern  :err   : [  836.677311] [      C2]  ? neigh_resolve_output (kbuild/src/include/linux/netdevice.h:3493 kbuild/src/net/core/neighbour.c:1611 kbuild/src/net/core/neighbour.c:1596)
kern  :err   : [  836.677316] [      C2]  ip6_finish_output2 (kbuild/src/include/net/neighbour.h:560 (discriminator 2) kbuild/src/net/ipv6/ip6_output.c:136 (discriminator 2))
kern  :err   : [  836.677320] [      C2]  ? __pfx_ip6_finish_output2 (kbuild/src/include/net/xfrm.h:1303)
kern  :err   : [  836.677324] [      C2]  ? kasan_save_track (kbuild/src/mm/kasan/common.c:78)
kern  :err   : [  836.677327] [      C2]  ? __kasan_kmalloc (kbuild/src/mm/kasan/common.c:398 kbuild/src/mm/kasan/common.c:415)
kern  :err   : [  836.677330] [      C2]  ? dst_cow_metrics_generic (kbuild/src/include/linux/slab.h:969 kbuild/src/net/core/dst.c:194)
kern  :err   : [  836.677333] [      C2]  ? icmp6_dst_alloc (kbuild/src/include/net/dst.h:136 kbuild/src/include/net/dst.h:197 kbuild/src/net/ipv6/route.c:3359)
kern  :err   : [  836.677336] [      C2]  ? ndisc_send_skb (kbuild/src/net/ipv6/ndisc.c:491)
kern  :err   : [  836.677339] [      C2]  ? addrconf_dad_completed (kbuild/src/net/ipv6/addrconf.c:4395)
kern  :err   : [  836.677342] [      C2]  ? addrconf_dad_begin (kbuild/src/net/ipv6/addrconf.c:4157)
kern  :err   : [  836.677345] [      C2]  ? addrconf_dad_work (kbuild/src/net/ipv6/addrconf.c:4262)
kern  :err   : [  836.677348] [      C2]  ? process_one_work (kbuild/src/kernel/workqueue.c:3314)
kern  :err   : [  836.677350] [      C2]  ? worker_thread (kbuild/src/kernel/workqueue.c:3397 kbuild/src/kernel/workqueue.c:3478)
kern  :err   : [  836.677352] [      C2]  ? kthread (kbuild/src/kernel/kthread.c:436)
kern  :err   : [  836.677356] [      C2]  ? ret_from_fork (kbuild/src/arch/x86/kernel/process.c:158)
kern  :err   : [  836.677358] [      C2]  ? ret_from_fork_asm (kbuild/src/arch/x86/entry/entry_64.S:245)
kern  :err   : [  836.677361] [      C2]  ? addrconf_dad_work (kbuild/src/net/ipv6/addrconf.c:4262)
kern  :err   : [  836.677364] [      C2]  ? process_one_work (kbuild/src/kernel/workqueue.c:3314)
kern  :err   : [  836.677366] [      C2]  ? worker_thread (kbuild/src/kernel/workqueue.c:3397 kbuild/src/kernel/workqueue.c:3478)
kern  :err   : [  836.677369] [      C2]  ip6_finish_output (kbuild/src/net/ipv6/ip6_output.c:208 kbuild/src/net/ipv6/ip6_output.c:219)
kern  :err   : [  836.677372] [      C2]  ip6_output (kbuild/src/include/linux/netfilter.h:307 kbuild/src/net/ipv6/ip6_output.c:246)
kern  :err   : [  836.677375] [      C2]  ? __pfx_ip6_output (kbuild/src/net/ipv6/ip6_output.c:169)
kern  :err   : [  836.677379] [      C2]  ? _raw_spin_lock_irqsave (kbuild/src/include/linux/instrumented.h:55 kbuild/src/include/linux/atomic/atomic-instrumented.h:1301 kbuild/src/include/asm-generic/qspinlock.h:111 kbuild/src/include/linux/spinlock.h:187 kbuild/src/include/linux/spinlock_api_smp.h:133 kbuild/src/kernel/locking/spinlock.c:166)
kern  :err   : [  836.677382] [      C2]  ? __pfx__raw_spin_lock_irqsave (kbuild/src/kernel/locking/spinlock.c:273)
kern  :err   : [  836.677385] [      C2]  NF_HOOK+0xda/0x1f0
kern  :err   : [  836.677388] [      C2]  ? __pfx_NF_HOOK+0x10/0x10
kern  :err   : [  836.677391] [      C2]  ? rt6_uncached_list_add (kbuild/src/include/linux/list.h:96 kbuild/src/include/linux/list.h:158 kbuild/src/include/linux/list.h:191 kbuild/src/net/ipv6/route.c:145)
kern  :err   : [  836.677394] [      C2]  ndisc_send_skb (kbuild/src/net/ipv6/ndisc.c:512)
kern  :err   : [  836.677396] [      C2]  ? __pfx_ndisc_send_skb (kbuild/src/include/net/dst.h:470 (discriminator 1))
kern  :err   : [  836.677400] [      C2]  ? ndisc_send_rs (kbuild/src/net/ipv6/ndisc.c:171 (discriminator 1) kbuild/src/net/ipv6/ndisc.c:719 (discriminator 1))
kern  :err   : [  836.677402] [      C2]  addrconf_dad_completed (kbuild/src/net/ipv6/addrconf.c:4395)
kern  :err   : [  836.677406] [      C2]  ? __pfx_addrconf_dad_completed (kbuild/src/net/ipv6/addrconf.c:4091 (discriminator 10))
kern  :err   : [  836.677409] [      C2]  ? _raw_spin_lock (kbuild/src/include/linux/instrumented.h:55 kbuild/src/include/linux/atomic/atomic-instrumented.h:1301 kbuild/src/include/asm-generic/qspinlock.h:111 kbuild/src/include/linux/spinlock.h:187 kbuild/src/include/linux/spinlock_api_smp.h:159 kbuild/src/kernel/locking/spinlock.c:158)
kern  :err   : [  836.677412] [      C2]  ? __pfx__raw_spin_lock (kbuild/src/kernel/locking/spinlock.c:331)
kern  :err   : [  836.677416] [      C2]  ? addrconf_dad_begin (kbuild/src/net/ipv6/addrconf.c:4157)
kern  :err   : [  836.677419] [      C2]  addrconf_dad_begin (kbuild/src/net/ipv6/addrconf.c:4157)
kern  :err   : [  836.677422] [      C2]  ? __pfx_sched_balance_newidle (kbuild/src/kernel/sched/fair.c:13237 (discriminator 1))
kern  :err   : [  836.677425] [      C2]  ? __pfx_addrconf_dad_begin (kbuild/src/include/net/ipv6.h:459 (discriminator 2))
kern  :err   : [  836.677428] [      C2]  ? __pfx__raw_spin_lock_bh (kbuild/src/kernel/locking/spinlock.c:159)
kern  :err   : [  836.677432] [      C2]  addrconf_dad_work (kbuild/src/net/ipv6/addrconf.c:4262)
kern  :err   : [  836.677435] [      C2]  ? __pfx_addrconf_dad_work (kbuild/src/net/ipv6/addrconf.c:1568 (discriminator 2))
kern  :err   : [  836.677438] [      C2]  ? __schedule (kbuild/src/kernel/sched/core.c:5507 kbuild/src/kernel/sched/core.c:7228)
kern  :err   : [  836.677443] [      C2]  process_one_work (kbuild/src/kernel/workqueue.c:3314)
kern  :err   : [  836.677446] [      C2]  ? assign_work (kbuild/src/kernel/workqueue.c:1233)
kern  :err   : [  836.677451] [      C2]  worker_thread (kbuild/src/kernel/workqueue.c:3397 kbuild/src/kernel/workqueue.c:3478)
kern  :err   : [  836.677454] [      C2]  ? __pfx_worker_thread (kbuild/src/kernel/workqueue.c:3405 (discriminator 1))
kern  :err   : [  836.677456] [      C2]  kthread (kbuild/src/kernel/kthread.c:436)
kern  :err   : [  836.677459] [      C2]  ? recalc_sigpending (kbuild/src/include/linux/instrumented.h:97 kbuild/src/include/asm-generic/bitops/instrumented-atomic.h:41 kbuild/src/include/linux/thread_info.h:109 kbuild/src/kernel/signal.c:181)
kern  :err   : [  836.677463] [      C2]  ? __pfx_kthread (kbuild/src/include/linux/list.h:404 (discriminator 2))
kern  :err   : [  836.677466] [      C2]  ret_from_fork (kbuild/src/arch/x86/kernel/process.c:158)
kern  :err   : [  836.677468] [      C2]  ? __pfx_ret_from_fork (kbuild/src/arch/x86/include/asm/entry-common.h:54)
kern  :err   : [  836.677470] [      C2]  ? switch_fpu (kbuild/src/include/linux/instrumented.h:82 kbuild/src/include/asm-generic/bitops/instrumented-non-atomic.h:141 kbuild/src/include/linux/thread_info.h:133 kbuild/src/include/linux/sched.h:2084 kbuild/src/arch/x86/include/asm/fpu/sched.h:34)
kern  :err   : [  836.677475] [      C2]  ? __switch_to (kbuild/src/arch/x86/kernel/process_64.c:403 kbuild/src/arch/x86/kernel/process_64.c:663)
kern  :err   : [  836.677478] [      C2]  ? __switch_to_asm (kbuild/src/arch/x86/entry/entry_64.S:206)
kern  :err   : [  836.677481] [      C2]  ? __pfx_kthread (kbuild/src/include/linux/list.h:404 (discriminator 2))
kern  :err   : [  836.677484] [      C2]  ret_from_fork_asm (kbuild/src/arch/x86/entry/entry_64.S:245)
kern  :err   : [  836.677488] [      C2]  </TASK>

kern  :err   : [  837.303842] [      C2] Allocated by task 121763:
kern  :warn  : [  837.308450] [      C2]  kasan_save_stack (kbuild/src/mm/kasan/common.c:57)
kern  :warn  : [  837.313267] [      C2]  kasan_save_track (kbuild/src/mm/kasan/common.c:78)
kern  :warn  : [  837.318040] [      C2]  __kasan_slab_alloc (kbuild/src/mm/kasan/common.c:340 kbuild/src/mm/kasan/common.c:366)
kern  :warn  : [  837.322991] [      C2]  kmem_cache_alloc_node_noprof (kbuild/src/include/linux/kasan.h:253 kbuild/src/mm/slub.c:4610 kbuild/src/mm/slub.c:4939 kbuild/src/mm/slub.c:4991)
kern  :warn  : [  837.328984] [      C2]  __alloc_skb (kbuild/src/net/core/skbuff.c:704 (discriminator 2))
kern  :warn  : [  837.333421] [      C2]  __tcp_send_ack (kbuild/src/net/ipv4/tcp_output.c:4467)
kern  :warn  : [  837.338725] [      C2]  tcp_rcv_established (kbuild/src/net/ipv4/tcp_input.c:6168 kbuild/src/net/ipv4/tcp_input.c:6162 kbuild/src/net/ipv4/tcp_input.c:6662)
kern  :warn  : [  837.344030] [      C2]  tcp_v6_do_rcv (kbuild/src/net/ipv6/tcp_ipv6.c:1625)
kern  :warn  : [  837.348812] [      C2]  tcp_v6_rcv (kbuild/src/net/ipv6/tcp_ipv6.c:1902)
kern  :warn  : [  837.353415] [      C2]  ip6_protocol_deliver_rcu (kbuild/src/net/ipv6/ip6_input.c:479 (discriminator 1))
kern  :warn  : [  837.359180] [      C2]  ip6_input_finish (kbuild/src/net/ipv6/ip6_input.c:534)
kern  :warn  : [  837.364172] [      C2]  ip6_input (kbuild/src/include/linux/netfilter.h:318 kbuild/src/include/linux/netfilter.h:312 kbuild/src/net/ipv6/ip6_input.c:545)
kern  :warn  : [  837.368432] [      C2]  ip6_list_rcv_finish+0x80c/0xc30
kern  :warn  : [  837.374685] [      C2]  ip6_sublist_rcv (kbuild/src/net/ipv6/ip6_input.c:361)
kern  :warn  : [  837.379465] [      C2]  ipv6_list_rcv (kbuild/src/net/ipv6/ip6_input.c:395)
kern  :warn  : [  837.384188] [      C2]  __netif_receive_skb_list_core (kbuild/src/net/core/dev.c:6249 (discriminator 1) kbuild/src/net/core/dev.c:6296 (discriminator 1))
kern  :warn  : [  837.390302] [      C2]  netif_receive_skb_list_internal (kbuild/src/net/core/dev.c:6348 kbuild/src/net/core/dev.c:6439)
kern  :warn  : [  837.396561] [      C2]  napi_complete_done (kbuild/src/include/net/gro.h:523 kbuild/src/include/net/gro.h:519 kbuild/src/include/net/gro.h:531 kbuild/src/net/core/dev.c:6807)
kern  :warn  : [  837.401691] [      C2]  gro_cell_poll (kbuild/src/net/core/gro_cells.c:74)
kern  :warn  : [  837.406397] [      C2]  __napi_poll (kbuild/src/net/core/dev.c:7729)
kern  :warn  : [  837.410830] [      C2]  net_rx_action (kbuild/src/net/core/dev.c:7792 kbuild/src/net/core/dev.c:7949)
kern  :warn  : [  837.415519] [      C2]  handle_softirqs (kbuild/src/kernel/softirq.c:622)
kern  :warn  : [  837.420390] [      C2]  do_softirq (kbuild/src/kernel/softirq.c:523 (discriminator 20) kbuild/src/kernel/softirq.c:510 (discriminator 20))
kern  :warn  : [  837.424643] [      C2]  __local_bh_enable_ip (kbuild/src/kernel/softirq.c:450)
kern  :warn  : [  837.429767] [      C2]  __dev_queue_xmit (kbuild/src/include/linux/bottom_half.h:33 kbuild/src/include/linux/rcupdate.h:914 kbuild/src/net/core/dev.c:4907)
kern  :warn  : [  837.434801] [      C2]  ip6_finish_output2 (kbuild/src/include/net/neighbour.h:558 kbuild/src/net/ipv6/ip6_output.c:136)
kern  :warn  : [  837.440010] [      C2]  ip6_finish_output (kbuild/src/net/ipv6/ip6_output.c:208 kbuild/src/net/ipv6/ip6_output.c:219)
kern  :warn  : [  837.445045] [      C2]  ip6_output (kbuild/src/include/linux/netfilter.h:307 kbuild/src/net/ipv6/ip6_output.c:246)
kern  :warn  : [  837.449472] [      C2]  ip6_xmit (kbuild/src/include/net/dst.h:470 (discriminator 3) kbuild/src/include/linux/netfilter.h:318 (discriminator 3) kbuild/src/include/linux/netfilter.h:312 (discriminator 3) kbuild/src/net/ipv6/ip6_output.c:379 (discriminator 3))
kern  :warn  : [  837.453809] [      C2]  inet6_csk_xmit (kbuild/src/net/ipv6/inet6_connection_sock.c:121 (discriminator 2))
kern  :warn  : [  837.458578] [      C2]  __tcp_transmit_skb (kbuild/src/net/ipv4/tcp_output.c:1716 (discriminator 1))
kern  :warn  : [  837.463872] [      C2]  tcp_write_xmit (kbuild/src/net/ipv4/tcp_output.c:1734 kbuild/src/net/ipv4/tcp_output.c:3062)
kern  :warn  : [  837.468814] [      C2]  __tcp_push_pending_frames (kbuild/src/net/ipv4/tcp_output.c:3245 (discriminator 1))
kern  :warn  : [  837.474459] [      C2]  tcp_sendmsg_locked (kbuild/src/net/ipv4/tcp.c:1414)
kern  :warn  : [  837.479755] [      C2]  tcp_sendmsg (kbuild/src/net/ipv4/tcp.c:1451)
kern  :warn  : [  837.484124] [      C2]  __sys_sendto (kbuild/src/net/socket.c:775 (discriminator 1) kbuild/src/net/socket.c:790 (discriminator 1) kbuild/src/net/socket.c:2252 (discriminator 1))
kern  :warn  : [  837.488724] [      C2]  __x64_sys_sendto (kbuild/src/net/socket.c:2259 kbuild/src/net/socket.c:2255 kbuild/src/net/socket.c:2255)
kern  :warn  : [  837.493587] [      C2]  do_syscall_64 (kbuild/src/arch/x86/entry/syscall_64.c:63 kbuild/src/arch/x86/entry/syscall_64.c:94)
kern  :warn  : [  837.498221] [      C2]  entry_SYSCALL_64_after_hwframe (kbuild/src/arch/x86/entry/entry_64.S:121)

kern  :err   : [  837.506678] [      C2] Freed by task 121763:
kern  :warn  : [  837.510939] [      C2]  kasan_save_stack (kbuild/src/mm/kasan/common.c:57)
kern  :warn  : [  837.515714] [      C2]  kasan_save_track (kbuild/src/mm/kasan/common.c:78)
kern  :warn  : [  837.520491] [      C2]  kasan_save_free_info (kbuild/src/mm/kasan/generic.c:584)
kern  :warn  : [  837.525618] [      C2]  __kasan_slab_free (kbuild/src/mm/kasan/common.c:253 kbuild/src/mm/kasan/common.c:285)
kern  :warn  : [  837.530482] [      C2]  kmem_cache_free (kbuild/src/include/linux/kasan.h:235 kbuild/src/mm/slub.c:2700 kbuild/src/mm/slub.c:6310 kbuild/src/mm/slub.c:6437)
kern  :warn  : [  837.535295] [      C2]  tcp_rcv_established (kbuild/src/net/ipv4/tcp_input.c:6560)
kern  :warn  : [  837.540686] [      C2]  tcp_v6_do_rcv (kbuild/src/net/ipv6/tcp_ipv6.c:1625)
kern  :warn  : [  837.545468] [      C2]  __release_sock (kbuild/src/include/net/sock.h:1190 (discriminator 1) kbuild/src/net/core/sock.c:3258 (discriminator 1))
kern  :warn  : [  837.550288] [      C2]  release_sock (kbuild/src/net/core/sock.c:3857)
kern  :warn  : [  837.554899] [      C2]  tcp_sendmsg (kbuild/src/net/ipv4/tcp.c:1452)
kern  :warn  : [  837.559281] [      C2]  __sys_sendto (kbuild/src/net/socket.c:775 (discriminator 1) kbuild/src/net/socket.c:790 (discriminator 1) kbuild/src/net/socket.c:2252 (discriminator 1))
kern  :warn  : [  837.563883] [      C2]  __x64_sys_sendto (kbuild/src/net/socket.c:2259 kbuild/src/net/socket.c:2255 kbuild/src/net/socket.c:2255)
kern  :warn  : [  837.568744] [      C2]  do_syscall_64 (kbuild/src/arch/x86/entry/syscall_64.c:63 kbuild/src/arch/x86/entry/syscall_64.c:94)
kern  :warn  : [  837.573365] [      C2]  entry_SYSCALL_64_after_hwframe (kbuild/src/arch/x86/entry/entry_64.S:121)

kern  :err   : [  837.581815] [      C2] The buggy address belongs to the object at ffff888414b94780
which belongs to the cache skbuff_head_cache of size 232
kern  :err   : [  837.596736] [      C2] The buggy address is located 7 bytes inside of
freed 232-byte region [ffff888414b94780, ffff888414b94868)

kern  :err   : [  837.613201] [      C2] The buggy address belongs to the physical page:
kern  :warn  : [  837.619738] [      C2] page: refcount:0 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x414b94
kern  :warn  : [  837.628704] [      C2] head: order:1 mapcount:0 entire_mapcount:0 nr_pages_mapped:0 pincount:0
kern  :warn  : [  837.637367] [      C2] flags: 0x17ffffc0000040(head|node=0|zone=2|lastcpupid=0x1fffff)
kern  :warn  : [  837.645332] [      C2] page_type: f5(slab)
kern  :warn  : [  837.649452] [      C2] raw: 0017ffffc0000040 ffff8881003a2000 dead000000000100 dead000000000122
kern  :warn  : [  837.658208] [      C2] raw: 0000000000000000 0000000800190019 00000000f5000000 0000000000000000
kern  :warn  : [  837.666938] [      C2] head: 0017ffffc0000040 ffff8881003a2000 dead000000000100 dead000000000122
kern  :warn  : [  837.675756] [      C2] head: 0000000000000000 0000000800190019 00000000f5000000 0000000000000000
kern  :warn  : [  837.684572] [      C2] head: 0017ffffc0000001 ffffffffffffff81 00000000ffffffff 00000000ffffffff
kern  :warn  : [  837.693424] [      C2] head: ffffffffffffffff 0000000000000000 00000000ffffffff 0000000000000002
kern  :warn  : [  837.702280] [      C2] page dumped because: kasan: bad access detected

kern  :err   : [  837.711381] [      C2] Memory state around the buggy address:
kern  :err   : [  837.717212] [      C2]  ffff888414b94680: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
kern  :err   : [  837.725465] [      C2]  ffff888414b94700: fb fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc
kern  :err   : [  837.733699] [      C2] >ffff888414b94780: fa fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
kern  :err   : [  837.741937] [      C2]                    ^
kern  :err   : [  837.746228] [      C2]  ffff888414b94800: fb fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc
kern  :err   : [  837.754492] [      C2]  ffff888414b94880: fc fc fc fc fc fc fc fc fa fb fb fb fb fb fb fb
kern  :err   : [  837.762743] [      C2] ==================================================================


-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply

* Re: [PATCH v4 1/3] drm/drm_ras: Add drm_ras netlink error event
From: Tauro, Riana @ 2026-07-09  5:15 UTC (permalink / raw)
  To: Rodrigo Vivi, raag.jadav, kuba, aravind.iddamsetty
  Cc: intel-xe, anshuman.gupta, joonas.lahtinen, simona.vetter, airlied,
	pratik.bari, joshua.santosh.ranjan, ashwin.kumar.kulkarni,
	shubham.kumar, ravi.kishore.koppuravuri, maarten.lankhorst,
	mallesh.koujalagi, soham.purkait, Zack McKevitt, Lijo Lazar,
	Hawking Zhang, David S. Miller, Paolo Abeni, Eric Dumazet,
	dri-devel, netdev
In-Reply-To: <ak6xThf9qeB0wqgK@intel.com>


On 09-07-2026 01:51, Rodrigo Vivi wrote:
> On Tue, Jul 07, 2026 at 12:02:11PM +0530, Tauro, Riana wrote:
>> Hi Rodrigo/Jakub/Aravind
>>
>> Please let me know if you have any feedback for this patch or can you please
>> ack this if it looks good to you.
> I looks good to me, but could you please double check the sashiko's comments?

Sashiko has a comment regarding namespaces

[Severity: Medium]Since the generic netlink family explicitly supports 
multiple networknamespaces by setting .netnsok = true,
  will hardcoding init_net hereprevent listeners in non-init namespaces 
from receiving error events

.netnsok = true is auto generated not explicitly added in code.

But from what i see, drm device is present in the host and not 
replicated across namespaces
and most of the non-network implementations use inet.  (ex: Binder)
If this really needs a fix, we can drop the has_listeners suggested by 
raag  in previous patch.
I don't think in an error path, allocating a new buffer would be a big 
overhead if listeners are not present.

@Raag let me know your thoughts.

The 3rd patch can be floated seperately, I can drop it before merging 
and resend if i can get an ack for this
patch

Thanks
Riana



>
> Patch 3 still needs review I believe, then we get Jakub and drm maintainers acks
> to get this through drm-xe-next.
>
> Thanks,
> Rodrigo.
>
>> Thanks
>> Riana
>>
>> On 01-07-2026 15:14, Riana Tauro wrote:
>>> Define a new netlink event 'error-event' and a new multicast group
>>> 'error-report' in drm_ras. Each event contains device name, node and
>>> error information to identify the error triggering the event.
>>>
>>> Add drm_ras_nl_error_event() to trigger an event from the driver.
>>> Userspace must subscribe to 'error-report' to receive 'error-event'
>>> notifications.
>>>
>>> Usage:
>>>
>>> $ sudo ynl --family drm_ras --subscribe error-report
>>>
>>> Cc: Jakub Kicinski <kuba@kernel.org>
>>> Cc: Zack McKevitt <zachary.mckevitt@oss.qualcomm.com>
>>> Cc: Lijo Lazar <lijo.lazar@amd.com>
>>> Cc: Hawking Zhang <Hawking.Zhang@amd.com>
>>> Cc: David S. Miller <davem@davemloft.net>
>>> Cc: Paolo Abeni <pabeni@redhat.com>
>>> Cc: Eric Dumazet <edumazet@google.com>
>>> Signed-off-by: Riana Tauro <riana.tauro@intel.com>
>>> Reviewed-by: Raag Jadav <raag.jadav@intel.com>
>>> ---
>>> v2: remove redundant initialization
>>>       remove unnecessary space
>>>       use ynl in commit message and doc (Raag)
>>>       simplify doc for error-event attrs
>>>
>>> v3: rename error-notify to error-report
>>>       Replace notify with report across the file (Raag)
>>> ---
>>>    Documentation/gpu/drm-ras.rst            | 21 ++++++
>>>    Documentation/netlink/specs/drm_ras.yaml | 48 +++++++++++++
>>>    drivers/gpu/drm/drm_ras.c                | 87 ++++++++++++++++++++++++
>>>    drivers/gpu/drm/drm_ras_nl.c             |  6 ++
>>>    drivers/gpu/drm/drm_ras_nl.h             |  4 ++
>>>    include/drm/drm_ras.h                    |  5 ++
>>>    include/uapi/drm/drm_ras.h               | 15 ++++
>>>    7 files changed, 186 insertions(+)
>>>
>>> diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
>>> index 83c21853b74b..406e4c49bac1 100644
>>> --- a/Documentation/gpu/drm-ras.rst
>>> +++ b/Documentation/gpu/drm-ras.rst
>>> @@ -56,6 +56,7 @@ User space tools can:
>>>      ``node-id`` and ``error-id`` as parameters.
>>>    * Clear specific error counters with the ``clear-error-counter`` command, using both
>>>      ``node-id`` and ``error-id`` as parameters.
>>> +* Subscribe to the ``error-report`` multicast group to receive ``error-event``.
>>>    YAML-based Interface
>>>    --------------------
>>> @@ -111,3 +112,23 @@ Example: Clear an error counter for a given node
>>>        sudo ynl --family drm_ras --do clear-error-counter --json '{"node-id":0, "error-id":1}'
>>>        None
>>> +
>>> +Example: Subscribe to ``error-report`` multicast group
>>> +
>>> +.. code-block:: bash
>>> +
>>> +    sudo ynl --family drm_ras --output-json --subscribe error-report
>>> +
>>> +.. code-block:: json
>>> +
>>> +    {
>>> +        "name": "error-event",
>>> +        "msg": {
>>> +            "device-name": "0000:03:00.0",
>>> +            "node-id": 1,
>>> +            "node-name": "uncorrectable-errors",
>>> +            "error-id": 1,
>>> +            "error-name": "error_name1",
>>> +            "error-value": 1
>>> +        }
>>> +    }
>>> diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
>>> index e113056f8c01..8aed3d4515e5 100644
>>> --- a/Documentation/netlink/specs/drm_ras.yaml
>>> +++ b/Documentation/netlink/specs/drm_ras.yaml
>>> @@ -69,6 +69,33 @@ attribute-sets:
>>>            name: error-value
>>>            type: u32
>>>            doc: Current value of the requested error counter.
>>> +  -
>>> +    name: error-event-attrs
>>> +    attributes:
>>> +      -
>>> +        name: device-name
>>> +        type: string
>>> +        doc: Device (PCI BDF, UUID) that reported the error.
>>> +      -
>>> +        name: node-id
>>> +        type: u32
>>> +        doc: ID of the node that reported the error.
>>> +      -
>>> +        name: node-name
>>> +        type: string
>>> +        doc: Name of the node that reported the error.
>>> +      -
>>> +        name: error-id
>>> +        type: u32
>>> +        doc: ID of the error counter.
>>> +      -
>>> +        name: error-name
>>> +        type: string
>>> +        doc: Name of the error.
>>> +      -
>>> +        name: error-value
>>> +        type: u32
>>> +        doc: Current value of the error counter.
>>>    operations:
>>>      list:
>>> @@ -124,3 +151,24 @@ operations:
>>>          do:
>>>            request:
>>>              attributes: *id-attrs
>>> +    -
>>> +      name: error-event
>>> +      doc: >-
>>> +           Report an error event to userspace.
>>> +           The event includes the device, node and error information
>>> +           of the error that triggered the event.
>>> +      attribute-set: error-event-attrs
>>> +      mcgrp: error-report
>>> +      event:
>>> +        attributes:
>>> +          - device-name
>>> +          - node-id
>>> +          - node-name
>>> +          - error-id
>>> +          - error-name
>>> +          - error-value
>>> +
>>> +mcast-groups:
>>> +  list:
>>> +    -
>>> +      name: error-report
>>> diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
>>> index d6eab29a1394..77f912a4d101 100644
>>> --- a/drivers/gpu/drm/drm_ras.c
>>> +++ b/drivers/gpu/drm/drm_ras.c
>>> @@ -41,6 +41,11 @@
>>>     *    Userspace must provide Node ID, Error ID.
>>>     *    Clears specific error counter of a node if supported.
>>>     *
>>> + * 4. ERROR_REPORT: Subscribe to this multicast group to receive error events
>>> + *
>>> + * 5. ERROR_EVENT: Report an error event to userspace. The event contains device, node
>>> + *    and error information that triggered the event.
>>> + *
>>>     * Node registration:
>>>     *
>>>     * - drm_ras_node_register(): Registers a new node and assigns
>>> @@ -186,6 +191,34 @@ static int msg_reply_value(struct sk_buff *msg, u32 error_id,
>>>    			   value);
>>>    }
>>> +static int msg_put_error_event_attrs(struct sk_buff *msg, struct drm_ras_node *node,
>>> +				     u32 error_id, const char *error_name, u32 value)
>>> +{
>>> +	int ret;
>>> +
>>> +	ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_DEVICE_NAME, node->device_name);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	ret = nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_ID, node->id);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_NAME, node->node_name);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	ret = nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_ID, error_id);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_NAME, error_name);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_VALUE, value);
>>> +}
>>> +
>>>    static int doit_reply_value(struct genl_info *info, u32 node_id,
>>>    			    u32 error_id)
>>>    {
>>> @@ -222,6 +255,60 @@ static int doit_reply_value(struct genl_info *info, u32 node_id,
>>>    	return genlmsg_reply(msg, info);
>>>    }
>>> +/**
>>> + * drm_ras_nl_error_event() - Report an error event
>>> + * @node: Node structure
>>> + * @error_id: ID of the error
>>> + * @error_name: Name of the error
>>> + * @value: Value associated with the error
>>> + * @flags: GFP flags for memory allocation
>>> + *
>>> + * Report an error-event to userspace using the error-report multicast group.
>>> + *
>>> + * Return: 0 on success, or negative errno on failure.
>>> + */
>>> +int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id, const char *error_name,
>>> +			   u32 value, gfp_t flags)
>>> +{
>>> +	struct genl_info info;
>>> +	struct sk_buff *msg;
>>> +	struct nlattr *hdr;
>>> +	int ret;
>>> +
>>> +	if (!error_name)
>>> +		return -EINVAL;
>>> +
>>> +	if (!genl_has_listeners(&drm_ras_nl_family, &init_net, DRM_RAS_NLGRP_ERROR_REPORT))
>>> +		return 0;
>>> +
>>> +	genl_info_init_ntf(&info, &drm_ras_nl_family, DRM_RAS_CMD_ERROR_EVENT);
>>> +
>>> +	msg = genlmsg_new(NLMSG_GOODSIZE, flags);
>>> +	if (!msg)
>>> +		return -ENOMEM;
>>> +
>>> +	hdr = genlmsg_iput(msg, &info);
>>> +	if (!hdr) {
>>> +		ret = -EMSGSIZE;
>>> +		goto free_msg;
>>> +	}
>>> +
>>> +	ret = msg_put_error_event_attrs(msg, node, error_id, error_name, value);
>>> +	if (ret)
>>> +		goto cancel_msg;
>>> +
>>> +	genlmsg_end(msg, hdr);
>>> +	genlmsg_multicast(&drm_ras_nl_family, msg, 0, DRM_RAS_NLGRP_ERROR_REPORT, flags);
>>> +	return 0;
>>> +
>>> +cancel_msg:
>>> +	genlmsg_cancel(msg, hdr);
>>> +free_msg:
>>> +	nlmsg_free(msg);
>>> +	return ret;
>>> +}
>>> +EXPORT_SYMBOL(drm_ras_nl_error_event);
>>> +
>>>    /**
>>>     * drm_ras_nl_get_error_counter_dumpit() - Dump all Error Counters
>>>     * @skb: Netlink message buffer
>>> diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
>>> index dea1c1b2494e..9d3123cc9f9c 100644
>>> --- a/drivers/gpu/drm/drm_ras_nl.c
>>> +++ b/drivers/gpu/drm/drm_ras_nl.c
>>> @@ -58,6 +58,10 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
>>>    	},
>>>    };
>>> +static const struct genl_multicast_group drm_ras_nl_mcgrps[] = {
>>> +	[DRM_RAS_NLGRP_ERROR_REPORT] = { "error-report", },
>>> +};
>>> +
>>>    struct genl_family drm_ras_nl_family __ro_after_init = {
>>>    	.name		= DRM_RAS_FAMILY_NAME,
>>>    	.version	= DRM_RAS_FAMILY_VERSION,
>>> @@ -66,4 +70,6 @@ struct genl_family drm_ras_nl_family __ro_after_init = {
>>>    	.module		= THIS_MODULE,
>>>    	.split_ops	= drm_ras_nl_ops,
>>>    	.n_split_ops	= ARRAY_SIZE(drm_ras_nl_ops),
>>> +	.mcgrps		= drm_ras_nl_mcgrps,
>>> +	.n_mcgrps	= ARRAY_SIZE(drm_ras_nl_mcgrps),
>>>    };
>>> diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
>>> index a398643572a5..03ec275aca92 100644
>>> --- a/drivers/gpu/drm/drm_ras_nl.h
>>> +++ b/drivers/gpu/drm/drm_ras_nl.h
>>> @@ -21,6 +21,10 @@ int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
>>>    int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb,
>>>    					struct genl_info *info);
>>> +enum {
>>> +	DRM_RAS_NLGRP_ERROR_REPORT,
>>> +};
>>> +
>>>    extern struct genl_family drm_ras_nl_family;
>>>    #endif /* _LINUX_DRM_RAS_GEN_H */
>>> diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
>>> index 0beede3ddc4e..8abfb7d2077b 100644
>>> --- a/include/drm/drm_ras.h
>>> +++ b/include/drm/drm_ras.h
>>> @@ -80,9 +80,14 @@ struct drm_device;
>>>    #if IS_ENABLED(CONFIG_DRM_RAS)
>>>    int drm_ras_node_register(struct drm_ras_node *node);
>>>    void drm_ras_node_unregister(struct drm_ras_node *node);
>>> +int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id, const char *error_name,
>>> +			   u32 value, gfp_t flags);
>>>    #else
>>>    static inline int drm_ras_node_register(struct drm_ras_node *node) { return 0; }
>>>    static inline void drm_ras_node_unregister(struct drm_ras_node *node) { }
>>> +static inline int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id,
>>> +					 const char *error_name, u32 value, gfp_t flags)
>>> +{ return 0; }
>>>    #endif
>>>    #endif
>>> diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
>>> index 218a3ee86805..eab8231aa87c 100644
>>> --- a/include/uapi/drm/drm_ras.h
>>> +++ b/include/uapi/drm/drm_ras.h
>>> @@ -38,13 +38,28 @@ enum {
>>>    	DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1)
>>>    };
>>> +enum {
>>> +	DRM_RAS_A_ERROR_EVENT_ATTRS_DEVICE_NAME = 1,
>>> +	DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_ID,
>>> +	DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_NAME,
>>> +	DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_ID,
>>> +	DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_NAME,
>>> +	DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_VALUE,
>>> +
>>> +	__DRM_RAS_A_ERROR_EVENT_ATTRS_MAX,
>>> +	DRM_RAS_A_ERROR_EVENT_ATTRS_MAX = (__DRM_RAS_A_ERROR_EVENT_ATTRS_MAX - 1)
>>> +};
>>> +
>>>    enum {
>>>    	DRM_RAS_CMD_LIST_NODES = 1,
>>>    	DRM_RAS_CMD_GET_ERROR_COUNTER,
>>>    	DRM_RAS_CMD_CLEAR_ERROR_COUNTER,
>>> +	DRM_RAS_CMD_ERROR_EVENT,
>>>    	__DRM_RAS_CMD_MAX,
>>>    	DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
>>>    };
>>> +#define DRM_RAS_MCGRP_ERROR_REPORT	"error-report"
>>> +
>>>    #endif /* _UAPI_LINUX_DRM_RAS_H */

^ permalink raw reply

* Re: [PATCH v3 4/5] net: qrtr: ns: Limit the total number of nodes
From: Manivannan Sadhasivam @ 2026-07-09  5:20 UTC (permalink / raw)
  To: Youssef Samir
  Cc: Manivannan Sadhasivam, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, linux-arm-msm, netdev,
	linux-kernel, stable, jeff.hugo
In-Reply-To: <c4cb79ac-1f90-499d-98ed-94ec431d9368@oss.qualcomm.com>

On Wed, Jul 08, 2026 at 06:49:39PM +0100, Youssef Samir wrote:
> 
> 
> On 4/9/2026 6:34 PM, Manivannan Sadhasivam wrote:
> > Currently, the nameserver doesn't limit the number of nodes it handles.
> > This can be an attack vector if a malicious client starts registering
> > random nodes, leading to memory exhaustion.
> > 
> > Hence, limit the maximum number of nodes to 64. Note that, limit of 64 is
> > chosen based on the current platform requirements. If requirement changes
> > in the future, this limit can be increased.
> 
> Hi Mani,
> 
> There are AI200 setups that can reach 384 nodes (192 * (AI200PF + AI200VF)).
> I'm not sure about limiting the number of nodes, but if there's a use-case
> that led to enforcing that limit, could we increase it to something like 512?
> 

Sure. As mentioned in the comment, we can increase the numbers based on the
requirements.

- Mani

-- 
மணிவண்ணன் சதாசிவம்

^ permalink raw reply

* Re: [PATCH net v2] net/mlx5e: Use sender devcom for MPV master-up
From: Tariq Toukan @ 2026-07-09  5:28 UTC (permalink / raw)
  To: Manjunath Patil, Saeed Mahameed, Tariq Toukan, Mark Bloch,
	Leon Romanovsky, netdev
  Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Patrisious Haddad, linux-rdma, linux-kernel, stable
In-Reply-To: <20260707233911.3651139-1-manjunath.b.patil@oracle.com>



On 08/07/2026 2:39, Manjunath Patil wrote:
> After PCIe DPC recovery, mlx5 reloads the affected functions and
> replays multiport affiliation events. In the reported failure, the
> first relevant device error was:
> 
>    pcieport 0000:10:01.1: DPC: containment event
>    pcieport 0000:10:01.1: PCIe Bus Error: severity=Uncorrected (Fatal)
>    pcieport 0000:10:01.1:    [ 5] SDES                   (First)
> 
> mlx5 recovered the PCI functions and resumed 0000:11:00.1. During
> that resume, RDMA multiport binding replayed
> MLX5_DRIVER_EVENT_AFFILIATION_DONE and mlx5e sent
> MPV_DEVCOM_MASTER_UP. The host then panicked with:
> 
>    BUG: kernel NULL pointer dereference, address: 0000000000000010
>    RIP: mlx5_devcom_comp_set_ready+0x5/0x40 [mlx5_core]
>    RDI: 0000000000000000
> 
> Call trace included:
> 
>    mlx5_devcom_comp_set_ready
>    mlx5e_devcom_event_mpv
>    mlx5_devcom_send_event
>    mlx5_ib_bind_slave_port
>    mlx5r_mp_probe
>    mlx5_pci_resume
> 
> MPV devcom registration publishes mlx5e private data to the component
> peer list before mlx5e_devcom_init_mpv() stores the returned component
> device in priv->devcom. A concurrent master-up event can therefore
> reach a peer whose private data is visible but whose priv->devcom
> backpointer is still NULL.
> 
> MPV_DEVCOM_MASTER_UP already carries the sender/master mlx5e private
> data as event_data. The ready bit is stored on the shared devcom
> component, not on an individual peer. Use the sender devcom when
> marking the MPV component ready.
> 
> This preserves the readiness transition while avoiding a NULL
> dereference of the peer devcom pointer during affiliation replay after
> PCI error recovery.
> 
> Fixes: bf11485f8419 ("net/mlx5: Register mlx5e priv to devcom in MPV mode")
> Assisted-by: Codex:gpt-5
> Signed-off-by: Manjunath Patil <manjunath.b.patil@oracle.com>
> Cc: stable@vger.kernel.org # 6.7+
> ---
> v2:
> - Drop defensive master_priv/master_priv->devcom check as suggested by Tariq.
> - Resend as an independent thread per netdev posting rules.
> 
>   drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> index 8f2b3abe0092..9b27afeb9b12 100644
> --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
> @@ -211,11 +211,11 @@ static void mlx5e_disable_async_events(struct mlx5e_priv *priv)
>   
>   static int mlx5e_devcom_event_mpv(int event, void *my_data, void *event_data)
>   {
> -	struct mlx5e_priv *slave_priv = my_data;
> +	struct mlx5e_priv *master_priv = event_data;
>   
>   	switch (event) {
>   	case MPV_DEVCOM_MASTER_UP:
> -		mlx5_devcom_comp_set_ready(slave_priv->devcom, true);
> +		mlx5_devcom_comp_set_ready(master_priv->devcom, true);
>   		break;
>   	case MPV_DEVCOM_MASTER_DOWN:
>   		/* no need for comp set ready false since we unregister after
> 
> base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8

Reviewed-by: Tariq Toukan <tariqt@nvidia.com>

Thanks for your patch.

^ permalink raw reply

* Re: (subset) [PATCH 0/37] PCI/MSI: Enforce explicit IRQ vector management by removing devres auto-free
From: Manivannan Sadhasivam @ 2026-07-09  5:40 UTC (permalink / raw)
  To: Bjorn Helgaas, Vaibhaav Ram T . L, Kumaravel Thiagarajan, Even Xu,
	Xinpeng Sun, Srinivas Pandruvada, Jiri Kosina, Alexandre Belloni,
	Zhou Wang, Longfang Liu, Vinod Koul, Lee Jones, Jijie Shao,
	Jian Shen, Sunil Goutham, Andrew Lunn, Heiner Kallweit,
	David S . Miller, Jeff Hugo, Oded Gabbay, Maciej Falkowski,
	Karol Wachowski, Min Ma, Lizhi Hou, Andreas Noever,
	Mika Westerberg, Will Deacon, Xinliang Liu, Tian Tao,
	Davidlohr Bueso, Srujana Challa, Bharat Bhushan, Antoine Tenart,
	Herbert Xu, Raag Jadav, Hans de Goede, Greg Kroah-Hartman,
	Jiri Slaby, Andy Shevchenko, Mika Westerberg, Andi Shyti,
	Robert Richter, Mark Brown, Nirmal Patel, Kurt Schwemmer,
	Logan Gunthorpe, Linus Walleij, Bartosz Golaszewski, Sakari Ailus,
	Bingbu Cao, Tomasz Jeznach, Jonathan Cameron, Ulf Hansson,
	Shawn Lin
  Cc: Arnd Bergmann, Benjamin Tissoires, linux-input, linux-i3c,
	dmaengine, Philipp Stanner, netdev, nic_swsd, linux-arm-msm,
	dri-devel, linux-usb, iommu, linux-riscv, David Airlie,
	Simona Vetter, linux-cxl, linux-crypto, platform-driver-x86,
	linux-serial, mhi, Andy Shevchenko, Jan Dabros, linux-i2c,
	Daniel Mack, Haojian Zhuang, linux-spi, Jonathan Derrick,
	linux-pci, linux-gpio, Mauro Carvalho Chehab, linux-media,
	linux-mmc
In-Reply-To: <1771860581-82092-1-git-send-email-shawn.lin@rock-chips.com>


On Mon, 23 Feb 2026 23:29:39 +0800, Shawn Lin wrote:
> This patch series addresses a long-standing design issue in the PCI/MSI
> subsystem where the implicit, automatic management of IRQ vectors by
> the devres framework conflicts with explicit driver cleanup, creating
> ambiguity and potential resource management bugs.
> 
> ==== The Problem: Implicit vs. Explicit Management ====
> Historically, `pcim_enable_device()` not only manages standard PCI resources
> (BARs) via devres but also implicitly triggers automatic IRQ vector management
> by setting a flag that registers `pcim_msi_release()` as a cleanup action.
> 
> [...]

Applied, thanks!

[13/37] bus: mhi: host: Replace pci_alloc_irq_vectors() with pcim_alloc_irq_vectors()
        commit: 256995e80fcd39cab94eee8135dd90f6da6ac744

Best regards,
-- 
மணிவண்ணன் சதாசிவம்



^ permalink raw reply

* Re: [PATCH v2] mptcp: only set DATA_FIN when a mapping is present
From: gang.yan @ 2026-07-09  5:43 UTC (permalink / raw)
  To: Michael Bommarito, Matthieu Baerts, Mat Martineau
  Cc: Geliang Tang, Paolo Abeni, Eric Dumazet, Jakub Kicinski, mptcp,
	netdev, linux-kernel
In-Reply-To: <20260707171730.2679013-1-michael.bommarito@gmail.com>

July 8, 2026 at 1:17 AM, "Michael Bommarito" <michael.bommarito@gmail.com mailto:michael.bommarito@gmail.com?to=%22Michael%20Bommarito%22%20%3Cmichael.bommarito%40gmail.com%3E > wrote:

Hi Michael

Thanks for the patch.


> 
> mptcp_get_options() clears only the status group of struct
> mptcp_options_received; data_seq, subflow_seq and data_len are filled in
> by mptcp_parse_option() exclusively inside the DSS mapping block, which
> runs only when the DSS M (mapping present) bit is set.
> 
> A peer can send a DSS option with the DATA_FIN flag set but the mapping
> bit clear. The parser then records mp_opt->data_fin while leaving
> data_len and data_seq uninitialized. For a zero-length segment
> mptcp_incoming_options() evaluates
> 
>  if (mp_opt.data_fin && mp_opt.data_len == 1 &&
>  mptcp_update_rcv_data_fin(msk, mp_opt.data_seq, mp_opt.dsn64))
> 
> which reads the uninitialized data_len and data_seq; KMSAN reports an
> uninit-value in mptcp_incoming_options(). The stale data_seq can also be
> fed into the receive-side DATA_FIN sequence tracking.
> 
> Record the DATA_FIN flag only when the DSS option carries a mapping, so
> data_fin is never set without data_seq and data_len also being present.
> data_fin is part of the status group that mptcp_get_options() clears up
> front, so on the no-map path it stays zero and the zero-length DATA_FIN
> branch is simply skipped. A DATA_FIN is always transmitted together with
> a mapping (mptcp_write_data_fin() sets use_map along with data_seq and
> data_len), so legitimate DATA_FIN handling is unaffected.
> 
> Fixes: 43b54c6ee382 ("mptcp: Use full MPTCP-level disconnect state machine")
> Suggested-by: Paolo Abeni <pabeni@redhat.com>
> Cc: stable@vger.kernel.org
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
> ---
> v2: adopt Paolo Abeni's suggested approach - do not set mp_opt->data_fin
>  at all unless a mapping is present, rather than gating the consumer in
>  mptcp_incoming_options() (v1). data_fin then defaults to the value
>  mptcp_get_options() already clears it to (0) on the no-map path, so
>  the uninitialized data_len/data_seq are never read.
> 
>  net/mptcp/options.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/net/mptcp/options.c b/net/mptcp/options.c
> index dff3fd5d3b559..6d003b24b969f 100644
> --- a/net/mptcp/options.c
> +++ b/net/mptcp/options.c
> @@ -157,7 +157,6 @@ static void mptcp_parse_option(const struct sk_buff *skb,
>  ptr++;
> 
>  flags = (*ptr++) & MPTCP_DSS_FLAG_MASK;
> - mp_opt->data_fin = (flags & MPTCP_DSS_DATA_FIN) != 0;
>  mp_opt->dsn64 = (flags & MPTCP_DSS_DSN64) != 0;
>  mp_opt->use_map = (flags & MPTCP_DSS_HAS_MAP) != 0;
>  mp_opt->ack64 = (flags & MPTCP_DSS_ACK64) != 0;
> @@ -178,6 +177,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
>  }
> 
>  if (mp_opt->use_map) {
> + mp_opt->data_fin = (flags & MPTCP_DSS_DATA_FIN) != 0;
>  if (mp_opt->dsn64)
>  expected_opsize += TCPOLEN_MPTCP_DSS_MAP64;
>  else

One minor thing I noticed while reviewing: Sashiko previously pointed out
in a comment that the 'pr_debug' logging 'mp_opt->data_fin' might be
problematic because it's printed before data_fin is actually assigned
(since data_fin is now set only inside the if (mp_opt->use_map) block). 

I think it would be cleaner to move the pr_debug call after the data_fin
assignment, so the logged value is always meaningful and consistent with
the actual parsed state, like:

'''
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index b924209a9b74..f58eb24f4d35 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -162,11 +162,6 @@ static void mptcp_parse_option(const struct sk_buff *skb,
                mp_opt->ack64 = (flags & MPTCP_DSS_ACK64) != 0;
                mp_opt->use_ack = (flags & MPTCP_DSS_HAS_ACK);
 
-               pr_debug("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d\n",
-                        mp_opt->data_fin, mp_opt->dsn64,
-                        mp_opt->use_map, mp_opt->ack64,
-                        mp_opt->use_ack);
-
                expected_opsize = TCPOLEN_MPTCP_DSS_BASE;
 
                if (mp_opt->use_ack) {
@@ -184,6 +179,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
                                expected_opsize += TCPOLEN_MPTCP_DSS_MAP32;
                }
 
+               pr_debug("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d\n",
+                        mp_opt->data_fin, mp_opt->dsn64,
+                        mp_opt->use_map, mp_opt->ack64,
+                        mp_opt->use_ack);
+
                /* Always parse any csum presence combination, we will enforce
                 * RFC 8684 Section 3.3.0 checks later in subflow_data_ready
                 */
'''

This change isn't critical to the fix itself, so feel free to let Paolo/Matt and
other Maintainers decide if it should go in now, later, or not at all.

A couple of additional notes for future submissions (just friendly reminders):

- The subject-prefix convention for MPTCP patches is typically [PATCH mptcp-net]
  for bug fixes targeting the net tree, or [PATCH mptcp-next] for new features.
  Since this is a fix, something like [PATCH mptcp-net v2] would be more appropriate.

- It's also helpful to include a Link: to the previous version (v1) in the changelog,
  so reviewers can easily track the discussion history.

Looking forward to seeing more of your work on the MPTCP mailing list!

Thanks,
Gang
> --
> 2.53.0
>

^ permalink raw reply related

* Re: (subset) [PATCH 0/37] PCI/MSI: Enforce explicit IRQ vector management by removing devres auto-free
From: Manivannan Sadhasivam @ 2026-07-09  5:43 UTC (permalink / raw)
  To: Bjorn Helgaas, Vaibhaav Ram T . L, Kumaravel Thiagarajan, Even Xu,
	Xinpeng Sun, Srinivas Pandruvada, Jiri Kosina, Alexandre Belloni,
	Zhou Wang, Longfang Liu, Vinod Koul, Lee Jones, Jijie Shao,
	Jian Shen, Sunil Goutham, Andrew Lunn, Heiner Kallweit,
	David S . Miller, Jeff Hugo, Oded Gabbay, Maciej Falkowski,
	Karol Wachowski, Min Ma, Lizhi Hou, Andreas Noever,
	Mika Westerberg, Will Deacon, Xinliang Liu, Tian Tao,
	Davidlohr Bueso, Srujana Challa, Bharat Bhushan, Antoine Tenart,
	Herbert Xu, Raag Jadav, Hans de Goede, Greg Kroah-Hartman,
	Jiri Slaby, Andy Shevchenko, Mika Westerberg, Andi Shyti,
	Robert Richter, Mark Brown, Nirmal Patel, Kurt Schwemmer,
	Logan Gunthorpe, Linus Walleij, Bartosz Golaszewski, Sakari Ailus,
	Bingbu Cao, Tomasz Jeznach, Jonathan Cameron, Ulf Hansson,
	Shawn Lin
  Cc: Arnd Bergmann, Benjamin Tissoires, linux-input, linux-i3c,
	dmaengine, Philipp Stanner, netdev, nic_swsd, linux-arm-msm,
	dri-devel, linux-usb, iommu, linux-riscv, David Airlie,
	Simona Vetter, linux-cxl, linux-crypto, platform-driver-x86,
	linux-serial, mhi, Andy Shevchenko, Jan Dabros, linux-i2c,
	Daniel Mack, Haojian Zhuang, linux-spi, Jonathan Derrick,
	linux-pci, linux-gpio, Mauro Carvalho Chehab, linux-media,
	linux-mmc
In-Reply-To: <178357565325.731734.7291964273199898845.b4-ty@b4>

On Thu, Jul 09, 2026 at 07:40:53AM +0200, Manivannan Sadhasivam wrote:
> 
> On Mon, 23 Feb 2026 23:29:39 +0800, Shawn Lin wrote:
> > This patch series addresses a long-standing design issue in the PCI/MSI
> > subsystem where the implicit, automatic management of IRQ vectors by
> > the devres framework conflicts with explicit driver cleanup, creating
> > ambiguity and potential resource management bugs.
> > 
> > ==== The Problem: Implicit vs. Explicit Management ====
> > Historically, `pcim_enable_device()` not only manages standard PCI resources
> > (BARs) via devres but also implicitly triggers automatic IRQ vector management
> > by setting a flag that registers `pcim_msi_release()` as a cleanup action.
> > 
> > [...]
> 
> Applied, thanks!
> 
> [13/37] bus: mhi: host: Replace pci_alloc_irq_vectors() with pcim_alloc_irq_vectors()
>         commit: 256995e80fcd39cab94eee8135dd90f6da6ac744
> 

Sorry, this is a mistake. This patch is not applied.

- Mani

-- 
மணிவண்ணன் சதாசிவம்

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox