* [PATCH net-next v6 1/3] dt-bindings: vendor-prefixes: add Guangdong Dapu Telecom Co., Ltd.
From: Artem Shimko @ 2026-08-05 8:55 UTC (permalink / raw)
To: netdev, Andrew Lunn, Heiner Kallweit, Russell King,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Chevallier
Cc: Artem Shimko, linux-kernel, devicetree
In-Reply-To: <20260805085540.452260-1-a.shimko.dev@gmail.com>
Add vendor prefix for Guangdong Dapu Telecom Co., Ltd. [1], a manufacturer
of Ethernet PHYs, networking and other equipment. The prefix will be
used in the DAP8211R(I) Gigabit Ethernet PHY binding.
[1] https://www.dptel.com/
Signed-off-by: Artem Shimko <a.shimko.dev@gmail.com>
---
Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 396044f368e7..f8efecb560b6 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -457,6 +457,8 @@ patternProperties:
description: Dongwoon Anatech
"^dptechnics,.*":
description: DPTechnics
+ "^dptel,.*":
+ description: Guangdong Dapu Telecom Co., Ltd.
"^dragino,.*":
description: Dragino Technology Co., Limited
"^dream,.*":
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v6 2/3] dt-bindings: net: add DAPU Telecom DAP8211R(I) PHY binding
From: Artem Shimko @ 2026-08-05 8:55 UTC (permalink / raw)
To: netdev, Andrew Lunn, Heiner Kallweit, Russell King,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Chevallier
Cc: Artem Shimko, linux-kernel, devicetree
In-Reply-To: <20260805085540.452260-1-a.shimko.dev@gmail.com>
Add device tree binding documentation for the DAPU Telecom DAP8211R(I)
Gigabit Ethernet PHY.
The PHY supports TX and RX clock delays in 150 ps steps from 0 to 2250 ps,
with a default of 1950 ps if not specified.
Signed-off-by: Artem Shimko <a.shimko.dev@gmail.com>
---
.../bindings/net/dptel,dap8211r.yaml | 62 +++++++++++++++++++
1 file changed, 62 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/dptel,dap8211r.yaml
diff --git a/Documentation/devicetree/bindings/net/dptel,dap8211r.yaml b/Documentation/devicetree/bindings/net/dptel,dap8211r.yaml
new file mode 100644
index 000000000000..4cd0f9730d95
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dptel,dap8211r.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dptel,dap8211r.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY
+
+maintainers:
+ - Artem Shimko <a.shimko.dev@gmail.com>
+
+description: |
+ The DAP8211R(I) is a Gigabit Ethernet PHY with RGMII interface,
+ supporting IEEE 802.3az Energy Efficient Ethernet, IEEE 1588 SyncE,
+ and an internal packet generator for diagnostics.
+
+ Specifications:
+ - 10BASE-Te, 100BASE-TX, 1000BASE-T
+ - RGMII with configurable TX/RX clock delays (150 ps steps, 0-2250 ps)
+ - IEEE 802.3az-2010 Energy Efficient Ethernet
+ - IEEE 1588 SyncE support
+ - Internal packet generator and checker for link diagnostics
+
+allOf:
+ - $ref: ethernet-phy.yaml#
+
+properties:
+ compatible:
+ const: ethernet-phy-id0008.011b
+
+ reg:
+ maxItems: 1
+
+ rx-internal-delay-ps:
+ description:
+ RGMII RX clock delay in picoseconds (0 to maximum).
+ multipleOf: 150
+ maximum: 2250
+ default: 1950
+
+ tx-internal-delay-ps:
+ description:
+ RGMII TX clock delay in picoseconds (0 to maximum).
+ multipleOf: 150
+ maximum: 2250
+ default: 1950
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet-phy@1 {
+ compatible = "ethernet-phy-id0008.011b";
+ reg = <1>;
+ rx-internal-delay-ps = <1950>;
+ tx-internal-delay-ps = <1950>;
+ };
+ };
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v6 3/3] net: phy: add DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY driver
From: Artem Shimko @ 2026-08-05 8:55 UTC (permalink / raw)
To: netdev, Andrew Lunn, Heiner Kallweit, Russell King,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Chevallier
Cc: Artem Shimko, linux-kernel, devicetree
In-Reply-To: <20260805085540.452260-1-a.shimko.dev@gmail.com>
Add a new PHY driver for the DAPU Telecom DAP8211R(I) Gigabit
Ethernet PHY, which is commonly used in enterprise and industrial
networking applications.
The driver implements extended register access via indirect addressing
through corresponding registers, and provides comprehensive device tree
support for RGMII delay configuration. The rx-internal-delay-ps and
tx-internal-delay-ps properties allow precise tuning of clock delays in
150 ps steps from 0 to 2250 ps.
Signed-off-by: Artem Shimko <a.shimko.dev@gmail.com>
---
drivers/net/phy/Kconfig | 9 ++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/dap8211r.c | 220 +++++++++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+)
create mode 100644 drivers/net/phy/dap8211r.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 099f25dceabb..395bcd35bffa 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -232,6 +232,15 @@ config CORTINA_PHY
help
Currently supports the CS4340 phy.
+config DAP8211R_PHY
+ tristate "DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY"
+ depends on OF
+ help
+ Support for the DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY.
+ This PHY is designed for enterprise and industrial networking
+ applications, supporting 10/100/1000 Mbps operation. Supports
+ RGMII interface with configurable TX/RX clock delays.
+
config DAVICOM_PHY
tristate "Davicom PHYs"
help
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index de660ae94945..c72f7730e25d 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_BCM_NET_PHYPTP) += bcm-phy-ptp.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_CICADA_PHY) += cicada.o
obj-$(CONFIG_CORTINA_PHY) += cortina.o
+obj-$(CONFIG_DAP8211R_PHY) += dap8211r.o
obj-$(CONFIG_DAVICOM_PHY) += davicom.o
obj-$(CONFIG_DP83640_PHY) += dp83640.o
obj-$(CONFIG_DP83822_PHY) += dp83822.o
diff --git a/drivers/net/phy/dap8211r.c b/drivers/net/phy/dap8211r.c
new file mode 100644
index 000000000000..0bf770f8ebbb
--- /dev/null
+++ b/drivers/net/phy/dap8211r.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the DAPU Telecom DAP8211R(I) Gigabit Ethernet PHY.
+ *
+ * Specifications:
+ * - IEEE 802.3 10BASE-Te, 100BASE-TX, 1000BASE-T
+ * - IEEE 802.3az-2010 Energy Efficient Ethernet
+ * - IEEE 1588 SyncE support
+ * - RGMII
+ *
+ * Author: Artem Shimko <a.shimko.dev@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/errno.h>
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/iopoll.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+
+#define DAP8211R_PHY_ID 0x0008011B
+#define DAP8211R_PHY_ID_MASK 0xFFFFFFFF
+
+#define DAP8211R_EXT_ADD 0x1E
+#define DAP8211R_EXT_DATA 0x1F
+
+#define DAP8211R_PHY_CON 0xA001
+#define DAP8211R_PHY_SW_RST BIT(15)
+
+#define DAP8211R_RGMII_CON 0xA003
+#define DAP8211R_RGMII_TX_DEL_MASK GENMASK(3, 0)
+#define DAP8211R_RGMII_RX_DEL_MASK GENMASK(13, 10)
+
+#define DAP8211R_RGMII_CONFIG_MASK (DAP8211R_RGMII_RX_DEL_MASK | DAP8211R_RGMII_TX_DEL_MASK)
+
+/*
+ * Hardware reset RX RGMII default delay from the datasheet: 0 * 150ps == 0.00ns
+ * Used when rx-internal-delay-ps is not specified in DT for RGMII mode and
+ * in RGMII_TXID to set rx delay.
+ */
+#define DAP8211R_INITIAL_RX_DEL_VAL 0
+
+/*
+ * Hardware reset TX RGMII default delay from the datasheet: 1 * 150ps == 0.15ns
+ * Used when tx-internal-delay-ps is not specified in DT for RGMII mode and
+ * in RGMII_RXID to set tx delay.
+ */
+#define DAP8211R_INITIAL_TX_DEL_VAL 1
+
+/*
+ * Default RGMII delay: 13 * 150 == 1.95ns
+ * Used when rx-internal-delay-ps or tx-internal-delay-ps are not specified in DT
+ * for RGMII ID modes to set tx or rx delay.
+ */
+#define DAP8211R_DEFAULT_DEL_SEL 0xD
+
+static const int dap8211r_internal_delay[] = {0, 150, 300, 450, 600, 750, 900,
+ 1050, 1200, 1350, 1500, 1650, 1800,
+ 1950, 2100, 2250};
+
+#define DAP8211R_DELAY_SIZE ARRAY_SIZE(dap8211r_internal_delay)
+
+/**
+ * dap8211r_read_ext() - Read extended register
+ * @phydev: PHY device structure
+ * @reg: Extended register address
+ *
+ * Reads a PHY extended register using the indirect access method.
+ * The caller must hold the MDIO bus lock.
+ *
+ * Return: Register value on success, or negative error code
+ */
+static int dap8211r_read_ext(struct phy_device *phydev, u16 reg)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = __phy_write(phydev, DAP8211R_EXT_ADD, reg);
+ if (ret < 0)
+ goto out;
+
+ ret = __phy_read(phydev, DAP8211R_EXT_DATA);
+out:
+ phy_unlock_mdio_bus(phydev);
+ return ret;
+}
+
+/**
+ * dap8211r_modify_ext() - Modify extended register bits
+ * @phydev: PHY device structure
+ * @reg: Extended register address
+ * @mask: Bit mask of bits to clear
+ * @set: Bit mask of bits to set
+ *
+ * Modifies a PHY extended register using the indirect access method.
+ * New value = (old value & ~mask) | set.
+ * The caller must hold the MDIO bus lock.
+ *
+ * Return: 0 on success, or negative error code
+ */
+static int dap8211r_modify_ext(struct phy_device *phydev, u16 reg, u16 mask, u16 set)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = __phy_write(phydev, DAP8211R_EXT_ADD, reg);
+ if (ret < 0)
+ goto out;
+
+ ret = __phy_modify(phydev, DAP8211R_EXT_DATA, mask, set);
+out:
+ phy_unlock_mdio_bus(phydev);
+ return ret;
+}
+
+/**
+ * dap8211r_config_init() - Initialize PHY
+ * @phydev: PHY device structure
+ *
+ * Configures the PHY during initialization:
+ * - RGMII delays based on interface mode
+ * - Software reset to apply settings (low active, self clear)
+ *
+ * Return: 0 on success, or negative error code
+ */
+static int dap8211r_config_init(struct phy_device *phydev)
+{
+ u16 set = 0;
+ int ret, val;
+ s32 rx_internal_delay = DAP8211R_INITIAL_RX_DEL_VAL;
+ s32 tx_internal_delay = DAP8211R_INITIAL_TX_DEL_VAL;
+
+ if (!phy_interface_is_rgmii(phydev))
+ return 0;
+
+ if (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)
+ rx_internal_delay = phy_get_internal_delay(phydev, dap8211r_internal_delay,
+ DAP8211R_DELAY_SIZE, true);
+
+ if (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)
+ tx_internal_delay = phy_get_internal_delay(phydev, dap8211r_internal_delay,
+ DAP8211R_DELAY_SIZE, false);
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ if (rx_internal_delay < 0)
+ rx_internal_delay = DAP8211R_INITIAL_RX_DEL_VAL;
+
+ if (tx_internal_delay < 0)
+ tx_internal_delay = DAP8211R_INITIAL_TX_DEL_VAL;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ if (rx_internal_delay < 0)
+ rx_internal_delay = DAP8211R_DEFAULT_DEL_SEL;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ if (rx_internal_delay < 0)
+ rx_internal_delay = DAP8211R_DEFAULT_DEL_SEL;
+ fallthrough;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ if (tx_internal_delay < 0)
+ tx_internal_delay = DAP8211R_DEFAULT_DEL_SEL;
+ break;
+ default:
+ phydev_err(phydev, "Unsupported interface: %d\n",
+ phydev->interface);
+ return -EINVAL;
+ }
+
+ set |= FIELD_PREP(DAP8211R_RGMII_RX_DEL_MASK, rx_internal_delay);
+ set |= FIELD_PREP(DAP8211R_RGMII_TX_DEL_MASK, tx_internal_delay);
+
+ ret = dap8211r_modify_ext(phydev, DAP8211R_PHY_CON, DAP8211R_PHY_SW_RST, 0);
+ if (ret)
+ return ret;
+
+ /* Wait for reset self-clear (from low active to high) */
+ ret = read_poll_timeout(dap8211r_read_ext, val,
+ (val & DAP8211R_PHY_SW_RST),
+ 20, 200, false, phydev, DAP8211R_PHY_CON);
+ if (ret)
+ return ret;
+ if (val < 0)
+ return val;
+
+ ret = dap8211r_modify_ext(phydev, DAP8211R_RGMII_CON, DAP8211R_RGMII_CONFIG_MASK, set);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct phy_driver dap8211r_driver[] = {
+ {
+ PHY_ID_MATCH_EXACT(DAP8211R_PHY_ID),
+ .name = "DAP8211R Gigabit Ethernet",
+ .soft_reset = genphy_soft_reset,
+ .config_init = dap8211r_config_init,
+ .read_status = genphy_read_status,
+ .set_loopback = genphy_loopback,
+ .config_aneg = genphy_config_aneg,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ },
+};
+module_phy_driver(dap8211r_driver);
+
+MODULE_DESCRIPTION("DAP8211R Gigabit Ethernet PHY driver");
+MODULE_AUTHOR("Artem Shimko <a.shimko.dev@gmail.com>");
+MODULE_LICENSE("GPL");
+
+static const struct mdio_device_id __maybe_unused dap8211r_tb[] = {
+ { DAP8211R_PHY_ID, DAP8211R_PHY_ID_MASK },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(mdio, dap8211r_tb);
+
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] netdevsim: fix deadlock in nsim_bus_dev_max_vfs_write()
From: Slawomir Stepien @ 2026-08-05 8:55 UTC (permalink / raw)
To: Paolo Abeni
Cc: syzbot, syzkaller-bugs, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, netdev, linux-kernel, syzbot
In-Reply-To: <c74a0579-dc37-4f3b-8dba-8380223b361c@redhat.com>
On sie 04, 2026 16:33, Paolo Abeni wrote:
> On 7/31/26 11:55 AM, syzbot wrote:
> > From: Slawomir Stepien <sst@poczta.fm>
> >
> > There is an ABBA deadlock between the devlink instance lock and the debugfs
> > active file reference mechanism.
> >
> > When a device is being removed (e.g., via nsim_drv_remove()), the driver
> > acquires the devlink instance lock and then calls
> > debugfs_remove_recursive(). This function blocks waiting for all active
> > file operations on the debugfs files to complete.
> >
> > Concurrently, if a user writes to the "max_vfs" debugfs file, the VFS layer
> > acquires an active reference to the file. The write handler,
> > nsim_bus_dev_max_vfs_write(), then attempts to acquire the devlink instance
> > lock, which is already held by the removal task.
> >
> > This creates a circular dependency resulting in a deadlock:
> >
> > INFO: task blocked for more than 143 seconds.
> > Call Trace:
> > wait_for_completion+0x2ca/0x5e0 kernel/sched/completion.c:153
> > __debugfs_file_removed fs/debugfs/inode.c:751 [inline]
> > remove_one+0x2df/0x3b0 fs/debugfs/inode.c:758
> > __simple_recursive_removal+0x215/0x520 fs/libfs.c:623
> > debugfs_remove+0x5b/0x70 fs/debugfs/inode.c:781
> > nsim_dev_debugfs_exit drivers/net/netdevsim/dev.c:372 [inline]
> > nsim_drv_remove+0xc0/0x170 drivers/net/netdevsim/dev.c:1803
> >
> > INFO: task blocked for more than 143 seconds.
> > Call Trace:
> > __mutex_lock+0x7bf/0x1550 kernel/locking/mutex.c:821
> > nsim_bus_dev_max_vfs_write+0x229/0x3d0 drivers/net/netdevsim/dev.c:276
> > full_proxy_write+0x127/0x1f0 fs/debugfs/file.c:388
> > vfs_write+0x296/0xba0 fs/read_write.c:685
> >
> > To fix this, use devl_trylock() in nsim_bus_dev_max_vfs_write() instead of
> > devl_lock(). If the lock cannot be acquired, return -EBUSY. This aborts the
> > write operation, releases the debugfs active file reference, and allows the
> > pending debugfs_remove_recursive() to proceed.
> >
> > Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
> > Reported-by: syzbot+3147c5de186107ffc7a1@syzkaller.appspotmail.com
> > Closes: https://syzkaller.appspot.com/bug?extid=3147c5de186107ffc7a1
> > Link: https://syzkaller.appspot.com/ai_job?id=fcdda182-bebf-49ab-ada0-d4d2e814ebf7
> > Signed-off-by: Slawomir Stepien <sst@poczta.fm>
> >
> > ---
> > diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
> > index aed9ad5f1..421cd7327 100644
> > --- a/drivers/net/netdevsim/dev.c
> > +++ b/drivers/net/netdevsim/dev.c
> > @@ -273,7 +273,11 @@ static ssize_t nsim_bus_dev_max_vfs_write(struct file *file,
> > return -ENOMEM;
> >
> > nsim_dev = file->private_data;
> > - devl_lock(priv_to_devlink(nsim_dev));
> > + if (!devl_trylock(priv_to_devlink(nsim_dev))) {
> > + ret = -EBUSY;
>
> I think this should return restart_syscall(). This kind of schema is
> calling for trouble, but for netdevsim should be okish.
Thanks Paolo for your comment!
Can you explain a bit more? What is your reasoning here? Is it, that we expect that we could have
the lock in e.g. 1ns, so it is worth restarting without bothering userspace[1]?
I see a lot of:
if (!rtnl_trylock())
return restart_syscall();
Why this pattern is so popular? Is it for the same reason as above?
[1] https://kernel-internals.org/syscalls/restart-block/
--
Slawomir Stepien
^ permalink raw reply
* Re: [PATCH net] netfilter: nf_dup_netdev: scrub duplicates to preserve the direct path
From: Alexandre Ferrieux @ 2026-08-05 9:02 UTC (permalink / raw)
To: Pablo Neira Ayuso, Alexandre Ferrieux
Cc: coreteam, netfilter-devel, edumazet, netdev
In-Reply-To: <anLzQeYulW2CQItC@chamomile>
On 8/5/26 10:24 AM, Pablo Neira Ayuso wrote:
> Hi,
>
> On Tue, Aug 04, 2026 at 10:11:50PM +0200, Alexandre Ferrieux wrote:
>> The nftables 'dup' action clones the skb with its full glory of
>> metadata, including references to its destination and conntrack
>> information. As a consequence, a link failure on the duplicate's
>> egress path ends up doing the same as it would for the direct path,
>> for example invalidating the original packet's destination, which
>> typically breaks all TCP connections to that address.
>>
>> In other words, the "dup" path has the potential to wreak havoc
>> in the direct path as a consequence of secondary link failures. This
>> is very bad behavior for a monitoring tool, which is the most
>> obvious application of 'dup'.
>
> Can you describe your use-case a bit and how it breaks?
Sure:
- assume hosts A.eth0 and B.eth0 have active production traffic (say TCP)
- assume we have a monitoring tool on A that dups eth0's egress to some other
interface $MON
nft add chain netdev ta ch '{type filter hook egress device "eth0" priority
filter ; policy accept ; }'
nft add rule netdev ta ch dup to $MON
- assume something goes wrong on $MON generating link failures. In my case it
was a GRETAP with L3 destination suddenly unreachable.
- The next A->B packet goes through normally, but its duplicate hits
ipv4_link_failure(), hence the dst (which is B) is expired.
- As a result, (say) TCP disruptions occur. The thermometer killed the patient :)
Note: as a straightforward repro, you can simply witness "noise" in simple ping
sessions, with ghost unreach reports muxed with normal measurement:
ip link add gre1 type gretap remote 192.168.1.99 ;# on the LAN, nonexistent
IP => will generate link failures
ip link set dev gre1 up
nft add table netdev ta
nft add chain netdev ta ch '{type filter hook egress device "eth0" priority
filter ; policy accept ; }'
nft add rule netdev ta ch counter dup to gre1
ping -n 8.8.8.8
=>
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=115 time=19.9 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=115 time=12.8 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=115 time=36.0 ms
64 bytes from 8.8.8.8: icmp_seq=4 ttl=115 time=30.3 ms
From 192.168.1.13 icmp_seq=5 Destination Host Unreachable
64 bytes from 8.8.8.8: icmp_seq=5 ttl=115 time=31.0 ms
From 192.168.1.13 icmp_seq=6 Destination Host Unreachable
64 bytes from 8.8.8.8: icmp_seq=6 ttl=115 time=38.0 ms
From 192.168.1.13 icmp_seq=7 Destination Host Unreachable
64 bytes from 8.8.8.8: icmp_seq=7 ttl=115 time=36.8 ms
From 192.168.1.13 icmp_seq=8 Destination Host Unreachable
64 bytes from 8.8.8.8: icmp_seq=8 ttl=115 time=23.5 ms
^C
>
>> This patch fixes all similar scenarii by calling skb_scrub_pkt()
>> on the clone, severing its link to precious direct-path state.
>
> This patch is targetted at the net tree, but nf.git is preferred.
Okay, will retarget :)
> As for the conntrack and dst, you have to explain what it breaks on
> your end.
Dst as shown above. Conntrack is more speculation, but my take is that in any
case the dup path should *never* have any kind of retroaction on the observed
path, so any "complex state" attached to the direct path should be absolutely
isolated from "whatever happens on the dup path". Am I mistaken ?
-Alex
^ permalink raw reply
* Re: [PATCH] netdevsim: fix deadlock in nsim_bus_dev_max_vfs_write()
From: Paolo Abeni @ 2026-08-05 9:05 UTC (permalink / raw)
To: Slawomir Stepien
Cc: syzbot, syzkaller-bugs, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, netdev, linux-kernel, syzbot
In-Reply-To: <anL6nNIJDqWOynzw@nr200>
On 8/5/26 10:55 AM, Slawomir Stepien wrote:
> On sie 04, 2026 16:33, Paolo Abeni wrote:
>> On 7/31/26 11:55 AM, syzbot wrote:
>>> From: Slawomir Stepien <sst@poczta.fm>
>>>
>>> There is an ABBA deadlock between the devlink instance lock and the debugfs
>>> active file reference mechanism.
>>>
>>> When a device is being removed (e.g., via nsim_drv_remove()), the driver
>>> acquires the devlink instance lock and then calls
>>> debugfs_remove_recursive(). This function blocks waiting for all active
>>> file operations on the debugfs files to complete.
>>>
>>> Concurrently, if a user writes to the "max_vfs" debugfs file, the VFS layer
>>> acquires an active reference to the file. The write handler,
>>> nsim_bus_dev_max_vfs_write(), then attempts to acquire the devlink instance
>>> lock, which is already held by the removal task.
>>>
>>> This creates a circular dependency resulting in a deadlock:
>>>
>>> INFO: task blocked for more than 143 seconds.
>>> Call Trace:
>>> wait_for_completion+0x2ca/0x5e0 kernel/sched/completion.c:153
>>> __debugfs_file_removed fs/debugfs/inode.c:751 [inline]
>>> remove_one+0x2df/0x3b0 fs/debugfs/inode.c:758
>>> __simple_recursive_removal+0x215/0x520 fs/libfs.c:623
>>> debugfs_remove+0x5b/0x70 fs/debugfs/inode.c:781
>>> nsim_dev_debugfs_exit drivers/net/netdevsim/dev.c:372 [inline]
>>> nsim_drv_remove+0xc0/0x170 drivers/net/netdevsim/dev.c:1803
>>>
>>> INFO: task blocked for more than 143 seconds.
>>> Call Trace:
>>> __mutex_lock+0x7bf/0x1550 kernel/locking/mutex.c:821
>>> nsim_bus_dev_max_vfs_write+0x229/0x3d0 drivers/net/netdevsim/dev.c:276
>>> full_proxy_write+0x127/0x1f0 fs/debugfs/file.c:388
>>> vfs_write+0x296/0xba0 fs/read_write.c:685
>>>
>>> To fix this, use devl_trylock() in nsim_bus_dev_max_vfs_write() instead of
>>> devl_lock(). If the lock cannot be acquired, return -EBUSY. This aborts the
>>> write operation, releases the debugfs active file reference, and allows the
>>> pending debugfs_remove_recursive() to proceed.
>>>
>>> Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
>>> Reported-by: syzbot+3147c5de186107ffc7a1@syzkaller.appspotmail.com
>>> Closes: https://syzkaller.appspot.com/bug?extid=3147c5de186107ffc7a1
>>> Link: https://syzkaller.appspot.com/ai_job?id=fcdda182-bebf-49ab-ada0-d4d2e814ebf7
>>> Signed-off-by: Slawomir Stepien <sst@poczta.fm>
>>>
>>> ---
>>> diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c
>>> index aed9ad5f1..421cd7327 100644
>>> --- a/drivers/net/netdevsim/dev.c
>>> +++ b/drivers/net/netdevsim/dev.c
>>> @@ -273,7 +273,11 @@ static ssize_t nsim_bus_dev_max_vfs_write(struct file *file,
>>> return -ENOMEM;
>>>
>>> nsim_dev = file->private_data;
>>> - devl_lock(priv_to_devlink(nsim_dev));
>>> + if (!devl_trylock(priv_to_devlink(nsim_dev))) {
>>> + ret = -EBUSY;
>>
>> I think this should return restart_syscall(). This kind of schema is
>> calling for trouble, but for netdevsim should be okish.
>
> Thanks Paolo for your comment!
>
> Can you explain a bit more? What is your reasoning here? Is it, that we expect that we could have
> the lock in e.g. 1ns, so it is worth restarting without bothering userspace[1]?
>
> I see a lot of:
>
> if (!rtnl_trylock())
> return restart_syscall();
>
> Why this pattern is so popular? Is it for the same reason as above?
>
> [1] https://kernel-internals.org/syscalls/restart-block/
If you don't restart, the write will randomly fail when the lock is
contended, as reported by sashiko gemini:
https://sashiko.dev/#/patchset/b7bf56ea-7522-4163-acd5-aaa69ad03b3a%40mail.kernel.org
the user-experience will be terrible at best.
Also, I missed this other report initially:
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/b7bf56ea-7522-4163-acd5-aaa69ad03b3a%40mail.kernel.org
it looks like the above is not a complete fix.
/P
^ permalink raw reply
* Re: [PATCH net 1/1] ip6_tunnel: use skb_cow_head() in ip6_tnl_xmit()
From: Ido Schimmel @ 2026-08-05 9:07 UTC (permalink / raw)
To: Zhiling Zou
Cc: netdev, dsahern, davem, edumazet, kuba, pabeni, horms, tom, vega
In-Reply-To: <7f099879785257f4d57d6caf9b6308fc76c7aaea.1785734738.git.zhilinz@nebusec.ai>
On Mon, Aug 03, 2026 at 01:34:46PM +0800, Zhiling Zou wrote:
> ip6_tnl_xmit() may need to expand headroom before it can push the
> outer IPv6 and optional encap headers. It currently does that with
> skb_realloc_headroom(), copies skb->sk ownership, consumes the original
> skb, and then continues processing with the replacement skb kept only in
> its local variable.
>
> That is safe only if the helper cannot fail afterwards. But this helper
> still has post-reallocation error exits. collect_md tunnels reject
> non-NONE encap after the replacement, and ip6_tnl_encap() can also fail
> later. In those cases the helper returns an error to its callers while
> the caller still only has the original skb pointer.
>
> Both ip6_tnl_start_xmit() and the IPv6 GRE paths free the caller skb on
> error, so they can end up freeing an skb that ip6_tnl_xmit() already
> consumed.
>
> Use skb_cow_head() instead. It provides the required headroom and
> writability without privately replacing the caller-owned skb, so later
> error returns cannot leave callers with a stale pointer.
>
> Fixes: 058214a4d1df ("ip6_tun: Add infrastructure for doing encapsulation")
> Cc: stable@vger.kernel.org
> Reported-by: Vega <vega@nebusec.ai>
> Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>
I read the feedback from Sashiko [1], but nothing there seems actionable
other than adding a note to the commit message about the removal of the
skb_shared() handling, but I think we can live without it.
__gre6_xmit() and ip6erspan_tunnel_xmit() already call skb_cow_head()
before calling ip6_tnl_xmit().
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
[1] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/7f099879785257f4d57d6caf9b6308fc76c7aaea.1785734738.git.zhilinz%40nebusec.ai
^ permalink raw reply
* Re: [PATCH 4/4] net: stmmac: manage error case during stmmac_dvr_probe
From: Christophe ROULLIER @ 2026-08-05 9:08 UTC (permalink / raw)
To: Maxime Chevallier, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue,
Russell King, linusw, antonio.borneo, Vladimir Oltean
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel
In-Reply-To: <807166df-2de0-4176-aad6-6bf632670528@bootlin.com>
Hi Maxime,
The pb comes from an error during ethernet probe (deferred because
IOExpander used for Reset Ethernet of STM32MP13-DK is not ready), The pb
is the Ethernet probe initialize pm-runtime but when error occur and
exit from probe there is no deinit of pm-runtime so when the reprobe is
called (after init of IOExpander) pm-runtime is already enable and the
balance between "put" and "get" is not symetric, so Ethernet genpd is
always active.
Ok I will remove this commit from my series and repush this commit on
net-next.
Regards,
Christophe.
Le 04/08/2026 à 16:16, Maxime Chevallier a écrit :
> Hi Christophe,
>
> On 8/4/26 15:20, Christophe Roullier wrote:
>> In case of error during stmmac_mdio_register, pm_runtime is not
>> cleaning before exit probe.
>>
>> Signed-off-by: Christophe Roullier <christophe.roullier@foss.st.com>
>> Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
> Can you send this path to the proper networking tree ? Is it a bug you've
> encountered in the wild (like, eprobedefer or something ?) or just
> something you've noticed ?
>
> If this is something you encountered, let's send it to -net (and it would
> need a Fixes tag), otherwise just target that to net-next
>
> Thanks :)
>
> Maxime
>
>> ---
>> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> index 0de4bc949913..852de0f51c09 100644
>> --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
>> @@ -8062,6 +8062,8 @@ static int __stmmac_dvr_probe(struct device *device,
>> error_pcs_setup:
>> stmmac_mdio_unregister(ndev);
>> error_mdio_register:
>> + pm_runtime_put_sync(device);
>> + pm_runtime_disable(device);
>> stmmac_napi_del(ndev);
>> error_hw_init:
>> destroy_workqueue(priv->wq);
^ permalink raw reply
* Re: [PATCH] w5100: restore GPIO-based link detection
From: Arnd Bergmann @ 2026-08-05 9:11 UTC (permalink / raw)
To: Arthur Crépin Leblond, Andrew Lunn
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Netdev, devicetree, linux-kernel
In-Reply-To: <anLzkNOBMvn7_0d3@pc-du-fromage>
On Wed, Aug 5, 2026, at 10:25, Arthur Crépin Leblond wrote:
> On Tue, Aug 04, 2026 at 07:54:29PM +0200, Andrew Lunn wrote:
>>
>>https://wiznet.io/products/ethernet-chips/w5100
>>
>>suggests it has an integrated PHY. So why is a GPIO needed to report
>>link?
>
> the W5100/W5500 exposes directly a LINKLED pin for the carrier status.
> On my board (RPi), that pin is wired to a GPIO to detect changes on the host
> directly via an interrupt.
The datasheet says
LINKLED O 66 Link LED
Active low in link state indicates a good status for
10/100M.
It is always ON when the link is OK and it flashes
while in a TX or RX state.
which sounds like this is not a great way to do it, since any
data transfer would drop the link status. Are you sure the
gpio line as you connect it actually only reports link status
and not RX/TX? Which chip/revision specifically are you using?
With the W5300 driver (now removed) that was trying to use the
link gpio, the LINKLED description in the datasheet is different
and does not mention flashing, so on that one, the gpio link
interrupt was more likely to actually work.
Arnd
^ permalink raw reply
* RE: [EXTERNAL] [PATCH net v2] net: prestera: validate firmware header length
From: Elad Nachman @ 2026-08-05 9:17 UTC (permalink / raw)
To: Pengpeng Hou
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20260731141500.1-prestera-v2-pengpeng@iscas.ac.cn>
>
>
> From: Pengpeng Hou <pengpeng@iscas.ac.cn>
> Sent: Friday, July 31, 2026 5:19 PM
> To: Elad Nachman <enachman@marvell.com>
> Cc: Andrew Lunn <andrew+netdev@lunn.ch>; David S. Miller <davem@davemloft.net>; Eric Dumazet <edumazet@google.com>; Jakub Kicinski <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>; netdev@vger.kernel.org; linux-kernel@vger.kernel.org; Pengpeng Hou <pengpeng@iscas.ac.cn>
> Subject: [EXTERNAL] [PATCH net v2] net: prestera: validate firmware header length
>
> prestera_fw_hdr_parse() reads the firmware header before checking
> that the firmware image contains that header.
>
> Reject images shorter than struct prestera_fw_header before decoding the
> magic and version fields.
>
> Signed-off-by: Pengpeng Hou <mailto:pengpeng@iscas.ac.cn>
> ---
> Changes since v1
> - target the net tree in the Subject as requested by Andrew Lunn
> - rebase onto the current tree
>
> drivers/net/ethernet/marvell/prestera/prestera_pci.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
> index 2989a77e3b42..1ad0e62a8433 100644
> --- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c
> +++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c
> @@ -684,6 +684,9 @@ static int prestera_fw_hdr_parse(struct prestera_fw *fw)
> struct prestera_fw_header *hdr;
> u32 magic;
>
> + if (fw->bin->size < sizeof(*hdr))
> + return -EINVAL;
> +
> hdr = (struct prestera_fw_header *)fw->bin->data;
>
> magic = be32_to_cpu(hdr->magic_number);
> --
> 2.50.1
>
Acked-by: Elad Nachman <enachman@marvell.com>
^ permalink raw reply
* [PATCH net] net/sched: cls_api: fix tp_created race losing existing tcf_proto
From: Aohan Mei @ 2026-08-05 9:29 UTC (permalink / raw)
To: jhs, jiri
Cc: davem, edumazet, kuba, pabeni, horms, netdev, corvus, henrymei,
stable
tc_new_tfilter() attaches a filter to a chain. When no
tcf_proto (tp) exists for the given (protocol, prio), it creates one
with tcf_proto_create(), marks tp_created so the error path can clean
it up, and inserts it with tcf_chain_tp_insert_unique().
However, tcf_proto_create() can sleep, opening a race window in which a
concurrent thread may insert a tp with the same (protocol, prio). In
that case tcf_chain_tp_insert_unique() destroys tp_new and returns the
*existing* tp, but tp_created is never reset. If the request then fails
(e.g. kind mismatch), the errout path calls
tcf_chain_tp_delete_empty() on a tp this thread never created. For
classifiers without a delete_empty callback (all but cls_flower),
tcf_proto_check_delete() removes the tp unconditionally: a live tp and
all its filters are silently lost while the owner's change() still
reports success. The race is reachable because cls_flower on
ingress/clsact qdiscs runs without rtnl_lock and can interleave with
rtnl_lock-holding classifiers such as u32.
Fix this by making tcf_chain_tp_insert_unique() report through a new
"inserted" out-parameter whether tp_new was actually inserted, and
gate the errout delete_empty call on it instead of tp_created.
tp_created itself must stay set on this path: the chain reference was
consumed by the destroyed tp_new, and errout_tp relies on tp_created
to decide whether to tcf_chain_put(), so resetting it would underflow
the chain refcount.
Fixes: 8b64678e0af8 ("net: sched: refactor tp insert/delete for concurrent execution")
Cc: stable@vger.kernel.org
Reported-by: TencentOS Corvus AI <corvus@tencent.com>
Signed-off-by: Aohan Mei <henrymei@tencent.com>
---
net/sched/cls_api.c | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index fee4524ad..9ceb2b538 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -1937,7 +1937,8 @@ static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
struct tcf_proto *tp_new,
u32 protocol, u32 prio,
- bool rtnl_held)
+ bool rtnl_held,
+ bool *inserted)
{
struct tcf_chain_info chain_info;
struct tcf_proto *tp;
@@ -1948,6 +1949,7 @@ static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
if (tcf_proto_exists_destroying(chain, tp_new)) {
mutex_unlock(&chain->filter_chain_lock);
tcf_proto_destroy(tp_new, rtnl_held, false, NULL);
+ *inserted = false;
return ERR_PTR(-EAGAIN);
}
@@ -1964,6 +1966,11 @@ static struct tcf_proto *tcf_chain_tp_insert_unique(struct tcf_chain *chain,
tp_new = ERR_PTR(err);
}
+ /* Tell the caller whether tp_new was actually inserted, or an
+ * already existing tp is being returned instead.
+ */
+ *inserted = !tp && !err;
+
return tp_new;
}
@@ -2254,11 +2261,13 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
void *fh;
int err;
int tp_created;
+ bool tp_inserted;
bool rtnl_held = false;
u32 flags;
replay:
tp_created = 0;
+ tp_inserted = false;
err = nlmsg_parse_deprecated(n, sizeof(*t), tca, TCA_MAX,
rtm_tca_policy, extack);
@@ -2382,7 +2391,7 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
tp_created = 1;
tp = tcf_chain_tp_insert_unique(chain, tp_new, protocol, prio,
- rtnl_held);
+ rtnl_held, &tp_inserted);
if (IS_ERR(tp)) {
err = PTR_ERR(tp);
goto errout_tp;
@@ -2440,7 +2449,13 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
}
errout:
- if (err && tp_created)
+ /* Only delete a tp that we actually inserted ourselves. When
+ * tcf_chain_tp_insert_unique() raced with a concurrent insertion
+ * it returns the existing tp; tp_created must stay set then (the
+ * chain reference was consumed by the destroyed tp_new), but the
+ * existing tp must not be deleted.
+ */
+ if (err && tp_inserted)
tcf_chain_tp_delete_empty(chain, tp, rtnl_held, NULL);
errout_tp:
if (chain) {
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* Re: [PATCH net-next v8 1/4] net: rnpgbe: Add interrupt handling
From: Simon Horman @ 2026-08-05 9:34 UTC (permalink / raw)
To: Dong Yibo
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, vadim.fedorenko,
netdev, linux-kernel, yaojun
In-Reply-To: <20260731120322.895955-2-dong100@mucse.com>
On Fri, Jul 31, 2026 at 08:03:19PM +0800, Dong Yibo wrote:
...
> diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c
...
> @@ -50,6 +68,11 @@ static int rnpgbe_open(struct net_device *netdev)
> **/
> static int rnpgbe_close(struct net_device *netdev)
> {
> + struct mucse *mucse = netdev_priv(netdev);
> +
> + rnpgbe_down(mucse);
> + rnpgbe_free_irq(mucse);
> +
> return 0;
> }
Hi Dong,
There is an AI-generated review of this patch-set available at
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260731120322.895955-1-dong100%40mucse.com
I would appreciate it if you could take a look over it.
In particular, the following issue does seem to be of concern.
I take the last portion regarding ixgbe to be a template for a solution to
the problem raised, not that the __IXGBE_DOWN bit should litteraly be used
in the rnpgbe driver.
Is ndo_stop now safe to call twice?
rnpgbe_dev_shutdown() in this same file calls rnpgbe_close() directly rather
than going through dev_close():
rtnl_lock();
netif_device_detach(netdev);
if (netif_running(netdev))
rnpgbe_close(netdev);
rtnl_unlock();
netif_device_detach() only clears __LINK_STATE_PRESENT, so IFF_UP and
__LINK_STATE_START stay set and the core still believes the interface is up.
A later dev_close() (device_shutdown() runs before migrate_to_reboot_cpu(),
so an "ip link set dev X down" on another CPU can still get through), or an
unbind/unregister_netdev() after a shutdown, would call ndo_stop again:
dev_close() -> __dev_close_many() -> ops->ndo_stop() -> rnpgbe_close()
On that second pass rnpgbe_down() runs again:
void rnpgbe_down(struct mucse *mucse)
{
set_bit(__MUCSE_DOWN, &mucse->state);
rnpgbe_napi_disable_all(mucse);
rnpgbe_irq_disable(mucse);
}
With plain set_bit() there is nothing to detect the re-entry, so
napi_disable() runs on an already-disabled NAPI. In napi_disable_locked():
while (val & (NAPIF_STATE_SCHED | NAPIF_STATE_NPSVC)) {
usleep_range(20, 200);
val = READ_ONCE(n->state);
}
The irq is already freed and NAPI was never re-enabled, so can anything
clear those bits? That loop has no timeout, and it runs under rtnl_lock().
The second rnpgbe_free_irq() would also call free_irq() on vectors already
released, giving the "Trying to free already-free IRQ" warning.
Before this patch rnpgbe_close() was just "return 0;", so the double call
was harmless.
Would the ixgbe guard fit here?
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c:ixgbe_down() {
/* signal that we are down to the interrupt handler */
if (test_and_set_bit(__IXGBE_DOWN, &adapter->state))
return; /* do nothing if already down */
...
}
Alternatively, should rnpgbe_dev_shutdown() call dev_close() so the core
state stays consistent?
...
^ permalink raw reply
* Re: [PATCH net-next v8 4/4] net: rnpgbe: Add link status handling support
From: Simon Horman @ 2026-08-05 9:39 UTC (permalink / raw)
To: dong100
Cc: Simon Horman, andrew+netdev, davem, edumazet, kuba, pabeni,
vadim.fedorenko, netdev, linux-kernel, yaojun
In-Reply-To: <20260731120322.895955-5-dong100@mucse.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/#/patchset/20260731120322.895955-2-dong100@mucse.com?part=4
---
--- Patch [4]: [PATCH net-next v8 4/4] net: rnpgbe: Add link status handling support ---
commit aaed18098b5cbd048578a3cab86657b190d37796
Author: Dong Yibo <dong100@mucse.com>
net: rnpgbe: Add link status handling support
Add link status management infrastructure to the rnpgbe driver:
- Add link status related data structures (speed, duplex, link state)
- Implement firmware link event handling via mailbox
(fw controls link states, does not support phylink)
- Add service task for periodic link status monitoring
- Implement carrier status management (netif_carrier_on/off)
- Add port up/down notification to firmware
This enables the driver to properly track and report link status changes.
diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.c
--- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.c
+++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_lib.c
[ ... ]
> +static int rnpgbe_process_link_event(struct mucse *mucse)
> +{
> + struct mucse_hw *hw = &mucse->hw;
> + unsigned long flags;
> + bool link;
> +
> + /* Only event consumption needs a consistent link-state snapshot. */
> + if (!atomic_read(&mucse->link_pending) ||
> + !atomic_xchg(&mucse->link_pending, 0))
> + return READ_ONCE(hw->link);
> +
> + spin_lock_irqsave(&mucse->link_lock, flags);
> +
> + link = hw->link;
> + spin_unlock_irqrestore(&mucse->link_lock, flags);
> +
> + return link;
> +}
> +
> +/**
> + * rnpgbe_link_is_up - Update netif_carrier status and
> + * print link up message
> + * @mucse: pointer to the device private structure
> + **/
> +static void rnpgbe_link_is_up(struct mucse *mucse)
> +{
> + struct net_device *netdev = mucse->netdev;
> + struct mucse_hw *hw = &mucse->hw;
> + unsigned long flags;
> + int speed;
> + u8 duplex;
> +
> + /* Only continue if link was previously down */
> + if (netif_carrier_ok(netdev))
> + return;
> + spin_lock_irqsave(&mucse->link_lock, flags);
> + speed = hw->speed;
> + duplex = hw->duplex;
> + spin_unlock_irqrestore(&mucse->link_lock, flags);
[Severity: Medium]
Could this cause a torn link state snapshot if an interrupt fires between
these critical sections?
In rnpgbe_process_link_subtask(), the worker thread first reads the link state
in rnpgbe_process_link_event() under the lock, and then drops the lock.
If the link is true, it calls rnpgbe_link_is_up(), which re-acquires the lock
to read the speed and duplex values.
If a link-down event triggers an interrupt between these two lock acquisitions,
could the worker thread end up reading newly zeroed speed and duplex values,
incorrectly reporting "NIC Link is Up 0 Mbps", and turning the netif carrier
ON while the physical link is actually DOWN?
diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c
--- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c
+++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c
[ ... ]
> @@ -243,6 +249,8 @@ static int rnpgbe_add_adapter(struct pci_dev *pdev,
> if (err)
> goto err_remove_mbx;
>
> + netif_carrier_off(netdev);
> +
> return 0;
[Severity: Medium]
Does calling netif_carrier_off() after register_netdev() expose a transient
carrier up state to userspace?
By default, the networking core assumes the carrier state is OK when a new
network device is created. When register_netdev() is called earlier in
rnpgbe_add_adapter(), the device is exposed to userspace and an RTM_NEWLINK
netlink event is broadcast indicating the link is UP.
Immediately calling netif_carrier_off() right after will emit another event
indicating the carrier is DOWN. Can this spurious UP-then-DOWN transition
confuse userspace network management daemons?
^ permalink raw reply
* [PATCH net] bnge: Fix resource leak in bnge_init_nic() error path
From: Bhargava Marreddy @ 2026-08-05 9:40 UTC (permalink / raw)
To: davem, edumazet, kuba, pabeni, andrew+netdev, horms
Cc: netdev, linux-kernel, michael.chan, pavan.chebbi,
vsrama-krishna.nemani, vikas.gupta, Bhargava Marreddy,
Dharmender Garg, Rajashekar Hudumula
If bnge_init_chip() fails, bnge_init_nic() jumps to err_free_ring_grps
and returns immediately, skipping cleanup for RX ring pair buffers.
Remove the early return so execution falls through to
err_free_rx_ring_pair_bufs to properly free resources on error.
Fixes: 23df6aebf803 ("bng_en: Allocate stat contexts")
Signed-off-by: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
Reviewed-by: Dharmender Garg <dharmender.garg@broadcom.com>
Reviewed-by: Rajashekar Hudumula <rajashekar.hudumula@broadcom.com>
---
drivers/net/ethernet/broadcom/bnge/bnge_netdev.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
index c2e865f8d9c..a4288f0258f 100644
--- a/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
+++ b/drivers/net/ethernet/broadcom/bnge/bnge_netdev.c
@@ -2820,8 +2820,6 @@ static int bnge_init_nic(struct bnge_net *bn)
err_free_ring_grps:
bnge_free_ring_grps(bn);
- return rc;
-
err_free_rx_ring_pair_bufs:
bnge_free_rx_ring_pair_bufs(bn);
return rc;
--
2.47.3
^ permalink raw reply related
* Re: [PATCH] w5100: restore GPIO-based link detection
From: Arthur Crépin Leblond @ 2026-08-05 9:44 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Andrew Lunn, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Netdev, devicetree, linux-kernel
In-Reply-To: <5d9c865e-a9a2-4756-a27b-a5af60ef3bad@app.fastmail.com>
On Wed, Aug 05, 2026 at 11:11:53AM +0200, Arnd Bergmann wrote:
>On Wed, Aug 5, 2026, at 10:25, Arthur Crépin Leblond wrote:
>> On Tue, Aug 04, 2026 at 07:54:29PM +0200, Andrew Lunn wrote:
>>>
>>>https://wiznet.io/products/ethernet-chips/w5100
>>>
>>>suggests it has an integrated PHY. So why is a GPIO needed to report
>>>link?
>>
>> the W5100/W5500 exposes directly a LINKLED pin for the carrier status.
>> On my board (RPi), that pin is wired to a GPIO to detect changes on the host
>> directly via an interrupt.
>
>The datasheet says
>
> LINKLED O 66 Link LED
> Active low in link state indicates a good status for
> 10/100M.
> It is always ON when the link is OK and it flashes
> while in a TX or RX state.
>
>which sounds like this is not a great way to do it, since any
>data transfer would drop the link status. Are you sure the
>gpio line as you connect it actually only reports link status
>and not RX/TX? Which chip/revision specifically are you using?
>
>With the W5300 driver (now removed) that was trying to use the
>link gpio, the LINKLED description in the datasheet is different
>and does not mention flashing, so on that one, the gpio link
>interrupt was more likely to actually work.
>
> Arnd
You're right for the W5100 that would not make any sense during data
transfers it would trigger the interrupt. That's unreliable.
I am using the W5500, and in the datasheet it says
Link LED
This shows the Link status.
Low: Link is established
High: Link is not established
I can confirm it is what is happening, I don't see any changes
of state during TX/RX.
Arthur
^ permalink raw reply
* Re: [PATCH] net: sysfs: cleanup coding style
From: kernel test robot @ 2026-08-05 9:47 UTC (permalink / raw)
To: Lucas Poupeau, davem, edumazet, kuba, pabeni
Cc: oe-kbuild-all, horms, kuniyu, sdf, brauner, krikku, netdev,
linux-kernel, Lucas Poupeau
In-Reply-To: <20260628185824.231250-1-lucasp.linux@gmail.com>
Hi Lucas,
kernel test robot noticed the following build errors:
[auto build test ERROR on net-next/main]
[also build test ERROR on net/main brauner-vfs/vfs.all linus/master v7.2-rc6 next-20260804]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Lucas-Poupeau/net-sysfs-cleanup-coding-style/20260805-152318
base: net-next/main
patch link: https://lore.kernel.org/r/20260628185824.231250-1-lucasp.linux%40gmail.com
patch subject: [PATCH] net: sysfs: cleanup coding style
config: alpha-allmodconfig (https://download.01.org/0day-ci/archive/20260805/202608051723.zyzTXXX2-lkp@intel.com/config)
compiler: alpha-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260805/202608051723.zyzTXXX2-lkp@intel.com/reproduce)
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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608051723.zyzTXXX2-lkp@intel.com/
All error/warnings (new ones prefixed by >>):
In file included from include/linux/dma-mapping.h:5,
from include/linux/skbuff.h:28,
from include/net/net_namespace.h:44,
from include/linux/netdevice.h:38,
from net/core/net-sysfs.c:10:
>> net/core/net-sysfs.c:622:23: error: 'netdev_group_show' undeclared here (not in a function); did you mean 'netdev_show'?
622 | static DEVICE_ATTR_RW(netdev_group);
| ^~~~~~~~~~~~
include/linux/device.h:173:36: note: in definition of macro '__DEVICE_ATTR_SHOW_STORE'
173 | .show = _Generic(_show, \
| ^~~~~
include/linux/device.h:201:9: note: in expansion of macro '__DEVICE_ATTR'
201 | __DEVICE_ATTR(_name, _mode, _name##_show, _name##_store)
| ^~~~~~~~~~~~~
include/linux/device.h:204:9: note: in expansion of macro '__DEVICE_ATTR_RW_MODE'
204 | __DEVICE_ATTR_RW_MODE(_name, 0644)
| ^~~~~~~~~~~~~~~~~~~~~
include/linux/device.h:246:52: note: in expansion of macro '__DEVICE_ATTR_RW'
246 | struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RW(_name)
| ^~~~~~~~~~~~~~~~
net/core/net-sysfs.c:622:8: note: in expansion of macro 'DEVICE_ATTR_RW'
622 | static DEVICE_ATTR_RW(netdev_group);
| ^~~~~~~~~~~~~~
>> net/core/net-sysfs.c:622:23: error: 'netdev_group_store' undeclared here (not in a function); did you mean 'netdev_lock_store'?
622 | static DEVICE_ATTR_RW(netdev_group);
| ^~~~~~~~~~~~
include/linux/device.h:177:36: note: in definition of macro '__DEVICE_ATTR_SHOW_STORE'
177 | .store = _Generic(_store, \
| ^~~~~~
include/linux/device.h:201:9: note: in expansion of macro '__DEVICE_ATTR'
201 | __DEVICE_ATTR(_name, _mode, _name##_show, _name##_store)
| ^~~~~~~~~~~~~
include/linux/device.h:204:9: note: in expansion of macro '__DEVICE_ATTR_RW_MODE'
204 | __DEVICE_ATTR_RW_MODE(_name, 0644)
| ^~~~~~~~~~~~~~~~~~~~~
include/linux/device.h:246:52: note: in expansion of macro '__DEVICE_ATTR_RW'
246 | struct device_attribute dev_attr_##_name = __DEVICE_ATTR_RW(_name)
| ^~~~~~~~~~~~~~~~
net/core/net-sysfs.c:622:8: note: in expansion of macro 'DEVICE_ATTR_RW'
622 | static DEVICE_ATTR_RW(netdev_group);
| ^~~~~~~~~~~~~~
>> net/core/net-sysfs.c:621:16: warning: 'group_show' defined but not used [-Wunused-function]
621 | NETDEVICE_SHOW(group, fmt_dec);
| ^~~~~
net/core/net-sysfs.c:143:16: note: in definition of macro 'NETDEVICE_SHOW'
143 | static ssize_t field##_show(struct device *dev, \
| ^~~~~
>> net/core/net-sysfs.c:615:16: warning: 'group_store' defined but not used [-Wunused-function]
615 | static ssize_t group_store(struct device *dev, struct device_attribute *attr,
| ^~~~~~~~~~~
vim +622 net/core/net-sysfs.c
614
> 615 static ssize_t group_store(struct device *dev, struct device_attribute *attr,
616 const char *buf, size_t len)
617 {
618 return netdev_store(dev, attr, buf, len, change_group);
619 }
620
> 621 NETDEVICE_SHOW(group, fmt_dec);
> 622 static DEVICE_ATTR_RW(netdev_group);
623
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH net-next v4 1/2] dpll: zl3073x: add channel ToD, phase step and TIE operations
From: Ivan Vecera @ 2026-08-05 9:48 UTC (permalink / raw)
To: Vadim Fedorenko, netdev
Cc: Petr Oros, Chris du Quesnay, Arkadiusz Kubalewski, Jakub Kicinski,
Jiri Pirko, Paolo Abeni, Prathosh Satish, Richard Cochran,
linux-kernel
In-Reply-To: <bc5060c8-7709-4354-aa48-7f64b857c00c@linux.dev>
On 8/5/26 1:07 AM, Vadim Fedorenko wrote:
> On 03/08/2026 15:06, Ivan Vecera wrote:
>> Add low-level DPLL channel operations for ToD read/write/adjust,
>> output phase step, delta frequency offset write and TIE (Time
>> Interval Error) write. These serve as building blocks for the PTP
>> clock callbacks added in the next patch.
>>
>> ToD operations use a wait-before-write pattern to avoid blocking
>> after each operation.
>>
>> The tod_ready_wait helper selects the poll timeout based on the
>> current ToD command - write operations use a longer timeout (1000 ms)
>> than reads (30 ms).
>>
>> The ToD read captures system timestamps (ptp_system_timestamp) around
>> the HW command and completion poll to support cross-timestamping.
>>
>> The TIE write operation provides sub-picosecond resolution phase
>> adjustment for modes where the DPLL is tracking a reference
>> (AUTO and REFLOCK).
>>
>> Add output step-time mask to struct zl3073x_dev and
>> zl3073x_dev_out_is_stepped() helper to check if an output
>> participates in step-time operations.
>>
>> Reviewed-by: Petr Oros <poros@redhat.com>
>> Tested-by: Chris du Quesnay <Chris.duQuesnay@microchip.com>
>> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
>> ---
>> drivers/dpll/zl3073x/chan.c | 310 +++++++++++++++++++++++++++++++++++-
>> drivers/dpll/zl3073x/chan.h | 32 ++++
>> drivers/dpll/zl3073x/core.c | 13 ++
>> drivers/dpll/zl3073x/core.h | 23 +++
>> drivers/dpll/zl3073x/regs.h | 52 ++++++
>> 5 files changed, 428 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/dpll/zl3073x/chan.c b/drivers/dpll/zl3073x/chan.c
>> index 4ec2cf53dad468..79874a9fdb4962 100644
>> --- a/drivers/dpll/zl3073x/chan.c
>> +++ b/drivers/dpll/zl3073x/chan.c
>> @@ -3,6 +3,7 @@
>> #include <linux/cleanup.h>
>> #include <linux/delay.h>
>> #include <linux/dev_printk.h>
>> +#include <linux/ptp_clock_kernel.h>
>> #include <linux/string.h>
>> #include <linux/types.h>
>> @@ -162,8 +163,8 @@ int zl3073x_chan_nco_mode_set(struct zl3073x_dev
>> *zldev, u8 index)
>> * @zldev: pointer to zl3073x_dev structure
>> * @index: DPLL channel index to fetch state for
>> *
>> - * Reads the mode_refsel register and reference priority registers for
>> - * the given DPLL channel and stores the raw values for later use.
>> + * Reads the mode_refsel, status and reference priority registers for
>> + * the given DPLL channel and stores the values for later use.
>> *
>> * Return: 0 on success, <0 on error
>> */
>> @@ -234,6 +235,311 @@ const struct zl3073x_chan
>> *zl3073x_chan_state_get(struct zl3073x_dev *zldev,
>> return &zldev->chan[index];
>> }
>> +/**
>> + * zl3073x_chan_tod_ready_wait - wait for ToD semaphore to clear
>> + * @zldev: pointer to zl3073x device
>> + * @ch: DPLL channel index
>> + *
>> + * Polls the ToD control register until the semaphore bit is cleared,
>> + * indicating the device has completed the previous ToD operation.
>> + *
>> + * Return: 0 on success, -EBUSY if semaphore not cleared, <0 on error
>> + */
>> +int zl3073x_chan_tod_ready_wait(struct zl3073x_dev *zldev, u8 ch)
>> +{
>> + unsigned int timeout;
>> + u8 tod_ctrl;
>> + int rc;
>> +
>> + rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch), &tod_ctrl);
>> + if (rc)
>> + return rc;
>> +
>> + switch (FIELD_GET(ZL_DPLL_TOD_CTRL_CMD, tod_ctrl)) {
>> + case ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ:
>> + timeout = ZL_POLL_TOD_WR_TIMEOUT_US;
>> + break;
>> + default:
>> + timeout = ZL_POLL_TOD_RD_TIMEOUT_US;
>> + break;
>> + }
>
> there are 3 cmds defined, but FIELD_GET(ZL_DPLL_TOD_CTRL_CMD) can return
> up to 16 possible values. I would explicitly put defined commands in
> cases and make default to ENOTSUPP..
Hi Vadim,
the ZL_DPLL_TOD_CTRL_CMD bits are never filled by firmware (only the
semaphore bit) so the driver knows what it writes. So such check is not
necessary but if you want it I can add something like:
...
case ZL_DPLL_TOD_CTRL_CMD_RD_CURRENT:
case ZL_DPLL_TOD_CTRL_CMD_RD_NEXT_1HZ:
timeout = ZL_POLL_TOD_RD_TIMEOUT_US;
break;
default:
WARN_ON(1); /* this is really unexpected */
return -ENOTSUPP;
...
Let me know.
Thanks,
Ivan
^ permalink raw reply
* Re: [PATCH iwl-net v1] i40e: fix races in PTP external timestamp work handling
From: Vadim Fedorenko @ 2026-08-05 9:49 UTC (permalink / raw)
To: luoxuanqiang, intel-wired-lan
Cc: anthony.l.nguyen, przemyslaw.kitszel, richardcochran,
piotr.kwapulinski, arkadiusz.kubalewski, aleksandr.loktionov,
andrew+netdev, davem, edumazet, kuba, pabeni, netdev,
Xuanqiang Luo
In-Reply-To: <ea295e13-6a35-4ce5-b289-f9f37b67dcf8@linux.dev>
On 05/08/2026 08:13, luoxuanqiang wrote:
>
> 在 2026/8/5 05:33, Vadim Fedorenko 写道:
>> On 24/07/2026 10:34, xuanqiang.luo@linux.dev wrote:
>>>
>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/
>>> net/ethernet/intel/i40e/i40e_ptp.c
>>> index ff62b5f2c8150..fd51ab8c10c20 100644
>>> --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
>>> @@ -169,6 +169,17 @@ static void i40e_ptp_extts0_work(struct
>>> work_struct *work)
>>> ptp_clock_event(pf->ptp_clock, &event);
>>> }
>>> +/**
>>> + * i40e_ptp_init_work - Initialize PTP work for a PF
>>> + * @pf: Board private structure
>>> + *
>>> + * Initialize work which must remain valid for the lifetime of the PF.
>>> + */
>>> +void i40e_ptp_init_work(struct i40e_pf *pf)
>>> +{
>>> + INIT_WORK(&pf->ptp_extts0_work, i40e_ptp_extts0_work);
>>> +}
>>> +
>>
>> why do you need extra function for a single line of code? why cannot
>> you put it into i40e_ptp_init?
>>
>>
> Thanks for pointing this out.
>
> i40e_ptp_init() is also called from the reset/rebuild path:
>
> i40e_service_task()
> -> i40e_reset_subtask()
> -> i40e_reset_and_rebuild()
> -> i40e_rebuild()
> -> i40e_setup_pf_switch()
> -> i40e_ptp_init()
>
> Putting INIT_WORK() there would reinitialize the work item during reset or
> recovery. If the work is pending or running, this races with the workqueue,
> resets its bookkeeping, and breaks the workqueue's non-reentrance
> guarantee.
ok, but then this driver has bigger problem. the same i40e_ptp_init()
re-inits tmreg_lock mutex and ptp_rx_lock spinlock. While latter might
be ok during reset (hopefully no traffic processed while the nic is in
reset), tmreg_lock mutex can be used for adjfine/adjtime/gettimex64/
settime64 callbacks as ptp device is still visible to user space.
I believe ptp part of the driver has to be redesigned properly.
>
> The work item is therefore initialized once per PF from i40e_sw_init().
> The helper also keeps the work callback private to i40e_ptp.c.
^ permalink raw reply
* Re: [PATCH net] net: dsa: b53: be VLAN unaware when not filtering
From: Semih Baskan @ 2026-08-05 9:50 UTC (permalink / raw)
To: Jonas Gorski
Cc: florian.fainelli, andrew, olteanv, davem, edumazet, kuba, pabeni,
vladimir.oltean, netdev, linux-kernel
In-Reply-To: <CAOiHx==-d_nzO+TQO+4UD4GfoLSOBUyfLuO+hfj8rQ1if4sZ4A@mail.gmail.com>
On 8/5/26 09:44, Jonas Gorski wrote:
> Unfortunately what this does is break modifying ARL entries with VID
> != 0, which is why I haven't added this.
Thank you for the review, your concerns are justified. I will drop this
patch and let you know if I find a way to address them.
Best regards,
Semih
^ permalink raw reply
* [PATCH] MAINTAINERS: Add entries for drm_ras
From: Rodrigo Vivi @ 2026-08-05 9:49 UTC (permalink / raw)
To: netdev, linux-kernel, dri-devel
Cc: Rodrigo Vivi, Simona Vetter, David Airlie, Donald Hunter,
Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, Raag Jadav, Riana Tauro, Aravind Iddamsetty,
Zack McKevitt
DRM RAS interface provides a standardized way for GPU/accelerator
drivers to expose error counters and other reliability nodes to
user space via Generic Netlink.
Since this is cross-driver infrastructure carrying its own uAPI, add a
dedicated MAINTAINERS entry covering the implementation, headers,
netlink spec and documentation, maintained through drm-misc.
Cc: Simona Vetter <simona@ffwll.ch>
Cc: David Airlie <airlied@redhat.com>
Cc: Donald Hunter <donald.hunter@gmail.com>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>
Cc: Raag Jadav <raag.jadav@intel.com>
Cc: Riana Tauro <riana.tauro@intel.com>
Cc: Aravind Iddamsetty <aravind.iddamsetty@linux.intel.com>
Cc: Zack McKevitt <zachary.mckevitt@oss.qualcomm.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
---
MAINTAINERS | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 5114e6db7307..51be7ad24528 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9039,6 +9039,19 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: drivers/gpu/drm/drm_privacy_screen*
F: include/drm/drm_privacy_screen*
+DRM RAS
+M: Raag Jadav <raag.jadav@intel.com>
+M: Riana Tauro <riana.tauro@intel.com>
+M: Rodrigo Vivi <rodrigo.vivi@intel.com>
+R: Aravind Iddamsetty <aravind.iddamsetty@linux.intel.com>
+L: dri-devel@lists.freedesktop.org
+S: Supported
+T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
+F: Documentation/netlink/specs/drm_ras.yaml
+F: Documentation/gpu/drm-ras.rst
+F: drivers/gpu/drm/drm_ras*
+F: include/drm/drm_ras*
+
DRM TTM SUBSYSTEM
M: Christian Koenig <christian.koenig@amd.com>
M: Huang Rui <ray.huang@amd.com>
--
2.55.0
^ permalink raw reply related
* Re: [PATCH v5 2/5] drm/ras: Introduce error threshold
From: Rodrigo Vivi @ 2026-08-05 9:53 UTC (permalink / raw)
To: Raag Jadav
Cc: Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni,
Simon Horman, Donald Hunter, intel-xe, dri-devel, netdev,
simona.vetter, airlied, lijo.lazar, Hawking.Zhang, dev,
zachary.mckevitt, riana.tauro, michal.wajdeczko, matthew.d.roper,
mallesh.koujalagi
In-Reply-To: <amymMwoSOxpHhEvX@black.igk.intel.com>
On Fri, Jul 31, 2026 at 03:42:11PM +0200, Raag Jadav wrote:
> Hi net maintainers,
>
> On Wed, Jul 22, 2026 at 01:30:49PM -0400, Rodrigo Vivi wrote:
> > On Wed, Jul 22, 2026 at 09:11:12AM +0530, Raag Jadav wrote:
> > > Add get-error-threshold and set-error-threshold command support which
> > > allows querying/setting error threshold of the counter. Threshold in RAS
> > > context means the number of errors the hardware is expected to accumulate
> > > before it raises them to software. This is to have a fine grained control
> > > over error notifications that are raised by the hardware.
> > >
> > > Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> > > Reviewed-by: Riana Tauro <riana.tauro@intel.com>
> > > ---
> > > v2: Document threshold definition (Riana)
> > > Return -EOPNOTSUPP on threshold callbacks absence (Riana)
> > > Cancel and free genlmsg on failure (Riana)
> > > Document threshold bounds checking responsibility (Riana)
> > > v3: Move documentation from yaml to rst file (Riana)
> > > s/value/threshold (Riana)
> > > Use goto for error handling (Riana)
> > > v4: Clarify 0 threshold expectations (Riana)
> > > Drop redundant wrapping (Riana)
> > > v5: Drop redundant documentation (Riana)
> > > Aesthetic adjustment (Riana)
> > > ---
> > > Documentation/gpu/drm-ras.rst | 18 +++
> > > Documentation/netlink/specs/drm_ras.yaml | 32 +++++
> >
> > Jakub and other net maintainers, ack on getting this through drm trees?
>
> Can you please provide guidance?
Even better, could you please ack the MAINTAINERS change [1] so we can stop
bothering you with these asks?
[1] https://lore.kernel.org/all/20260805094949.536651-2-rodrigo.vivi@intel.com/T/#u
>
> Raag
>
> > > drivers/gpu/drm/drm_ras.c | 158 +++++++++++++++++++++++
> > > drivers/gpu/drm/drm_ras_nl.c | 27 ++++
> > > drivers/gpu/drm/drm_ras_nl.h | 4 +
> > > include/drm/drm_ras.h | 29 +++++
> > > include/uapi/drm/drm_ras.h | 3 +
> > > 7 files changed, 271 insertions(+)
> > >
> > > diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst
> > > index 83c21853b74b..2718f8aee09d 100644
> > > --- a/Documentation/gpu/drm-ras.rst
> > > +++ b/Documentation/gpu/drm-ras.rst
> > > @@ -56,6 +56,10 @@ 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.
> > > +* Query specific error counter threshold with the ``get-error-threshold`` command, using both
> > > + ``node-id`` and ``error-id`` as parameters.
> > > +* Set specific error counter threshold with the ``set-error-threshold`` command, using
> > > + ``node-id``, ``error-id`` and ``error-threshold`` as parameters.
> > >
> > > YAML-based Interface
> > > --------------------
> > > @@ -111,3 +115,17 @@ 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: Query error threshold of a given counter
> > > +
> > > +.. code-block:: bash
> > > +
> > > + sudo ynl --family drm_ras --do get-error-threshold --json '{"node-id":0, "error-id":1}'
> > > + {'error-id': 1, 'error-name': 'error_name1', 'error-threshold': 16}
> > > +
> > > +Example: Set error threshold of a given counter
> > > +
> > > +.. code-block:: bash
> > > +
> > > + sudo ynl --family drm_ras --do set-error-threshold --json '{"node-id":0, "error-id":1, "error-threshold":8}'
> > > + None
> > > diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
> > > index e113056f8c01..9cf7f9cde242 100644
> > > --- a/Documentation/netlink/specs/drm_ras.yaml
> > > +++ b/Documentation/netlink/specs/drm_ras.yaml
> > > @@ -69,6 +69,10 @@ attribute-sets:
> > > name: error-value
> > > type: u32
> > > doc: Current value of the requested error counter.
> > > + -
> > > + name: error-threshold
> > > + type: u32
> > > + doc: Error threshold of the counter.
> > >
> > > operations:
> > > list:
> > > @@ -124,3 +128,31 @@ operations:
> > > do:
> > > request:
> > > attributes: *id-attrs
> > > + -
> > > + name: get-error-threshold
> > > + doc: >-
> > > + Retrieve error threshold of a given counter.
> > > + The response includes the id, the name, and current threshold
> > > + of the counter.
> > > + attribute-set: error-counter-attrs
> > > + flags: [admin-perm]
> > > + do:
> > > + request:
> > > + attributes: *id-attrs
> > > + reply:
> > > + attributes:
> > > + - error-id
> > > + - error-name
> > > + - error-threshold
> > > + -
> > > + name: set-error-threshold
> > > + doc: >-
> > > + Set error threshold of a given counter.
> > > + attribute-set: error-counter-attrs
> > > + flags: [admin-perm]
> > > + do:
> > > + request:
> > > + attributes:
> > > + - node-id
> > > + - error-id
> > > + - error-threshold
> > > diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
> > > index 467a169026fc..9a7b3d2acd25 100644
> > > --- a/drivers/gpu/drm/drm_ras.c
> > > +++ b/drivers/gpu/drm/drm_ras.c
> > > @@ -41,6 +41,13 @@
> > > * Userspace must provide Node ID, Error ID.
> > > * Clears specific error counter of a node if supported.
> > > *
> > > + * 4. GET_ERROR_THRESHOLD: Query error threshold of a given counter.
> > > + * Userspace must provide Node ID and Error ID.
> > > + * Returns the error threshold of a specific counter.
> > > + *
> > > + * 5. SET_ERROR_THRESHOLD: Set error threshold of a given counter.
> > > + * Userspace must provide Node ID, Error ID and threshold to be set.
> > > + *
> > > * Node registration:
> > > *
> > > * - drm_ras_node_register(): Registers a new node and assigns
> > > @@ -61,6 +68,13 @@
> > > * + The error counters in the driver doesn't need to be contiguous, but the
> > > * driver must return -ENOENT to the query_error_counter as an indication
> > > * that the ID should be skipped and not listed in the netlink API.
> > > + * + The driver can optionally implement query_error_threshold() and
> > > + * set_error_threshold() callbacks to facilitate getting/setting error
> > > + * threshold of the counter. Threshold in RAS context means the number of
> > > + * errors the hardware is expected to accumulate before it raises them to
> > > + * software. This is to have a fine grained control over error notifications
> > > + * that are raised by the hardware.
> > > + * + The driver is responsible for error threshold bounds checking.
> > > *
> > > * Netlink handlers:
> > > *
> > > @@ -72,6 +86,10 @@
> > > * operation, fetching a counter value from a specific node.
> > > * - drm_ras_nl_clear_error_counter_doit(): Implements the CLEAR_ERROR_COUNTER doit
> > > * operation, clearing a counter value from a specific node.
> > > + * - drm_ras_nl_get_error_threshold_doit(): Implements the GET_ERROR_THRESHOLD doit
> > > + * operation, fetching the error threshold of a specific counter.
> > > + * - drm_ras_nl_set_error_threshold_doit(): Implements the SET_ERROR_THRESHOLD doit
> > > + * operation, setting the error threshold of a specific counter.
> > > */
> > >
> > > static DEFINE_XARRAY_ALLOC(drm_ras_xa);
> > > @@ -168,6 +186,40 @@ static int get_node_error_counter(u32 node_id, u32 error_id,
> > > return node->query_error_counter(node, error_id, name, value);
> > > }
> > >
> > > +static int get_node_error_threshold(u32 node_id, u32 error_id, const char **name, u32 *threshold)
> > > +{
> > > + struct drm_ras_node *node;
> > > +
> > > + node = xa_load(&drm_ras_xa, node_id);
> > > + if (!node)
> > > + return -ENOENT;
> > > +
> > > + if (!node->query_error_threshold)
> > > + return -EOPNOTSUPP;
> > > +
> > > + if (error_id < node->error_counter_range.first || error_id > node->error_counter_range.last)
> > > + return -EINVAL;
> > > +
> > > + return node->query_error_threshold(node, error_id, name, threshold);
> > > +}
> > > +
> > > +static int set_node_error_threshold(u32 node_id, u32 error_id, u32 threshold)
> > > +{
> > > + struct drm_ras_node *node;
> > > +
> > > + node = xa_load(&drm_ras_xa, node_id);
> > > + if (!node)
> > > + return -ENOENT;
> > > +
> > > + if (!node->set_error_threshold)
> > > + return -EOPNOTSUPP;
> > > +
> > > + if (error_id < node->error_counter_range.first || error_id > node->error_counter_range.last)
> > > + return -EINVAL;
> > > +
> > > + return node->set_error_threshold(node, error_id, threshold);
> > > +}
> > > +
> > > static int msg_reply_value(struct sk_buff *msg, u32 error_id,
> > > const char *error_name, u32 value)
> > > {
> > > @@ -186,6 +238,22 @@ static int msg_reply_value(struct sk_buff *msg, u32 error_id,
> > > value);
> > > }
> > >
> > > +static int msg_reply_threshold(struct sk_buff *msg, u32 error_id, const char *error_name,
> > > + u32 threshold)
> > > +{
> > > + int ret;
> > > +
> > > + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID, error_id);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + ret = nla_put_string(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_NAME, error_name);
> > > + if (ret)
> > > + return ret;
> > > +
> > > + return nla_put_u32(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD, threshold);
> > > +}
> > > +
> > > static int doit_reply_value(struct genl_info *info, u32 node_id,
> > > u32 error_id)
> > > {
> > > @@ -225,6 +293,43 @@ static int doit_reply_value(struct genl_info *info, u32 node_id,
> > > return ret;
> > > }
> > >
> > > +static int doit_reply_threshold(struct genl_info *info, u32 node_id, u32 error_id)
> > > +{
> > > + const char *error_name;
> > > + struct sk_buff *msg;
> > > + struct nlattr *hdr;
> > > + u32 threshold;
> > > + int ret;
> > > +
> > > + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> > > + if (!msg)
> > > + return -ENOMEM;
> > > +
> > > + hdr = genlmsg_iput(msg, info);
> > > + if (!hdr) {
> > > + ret = -EMSGSIZE;
> > > + goto free_msg;
> > > + }
> > > +
> > > + ret = get_node_error_threshold(node_id, error_id, &error_name, &threshold);
> > > + if (ret)
> > > + goto cancel_msg;
> > > +
> > > + ret = msg_reply_threshold(msg, error_id, error_name, threshold);
> > > + if (ret)
> > > + goto cancel_msg;
> > > +
> > > + genlmsg_end(msg, hdr);
> > > +
> > > + return genlmsg_reply(msg, info);
> > > +
> > > +cancel_msg:
> > > + genlmsg_cancel(msg, hdr);
> > > +free_msg:
> > > + nlmsg_free(msg);
> > > + return ret;
> > > +}
> > > +
> > > /**
> > > * drm_ras_nl_get_error_counter_dumpit() - Dump all Error Counters
> > > * @skb: Netlink message buffer
> > > @@ -358,6 +463,59 @@ int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb,
> > > return node->clear_error_counter(node, error_id);
> > > }
> > >
> > > +/**
> > > + * drm_ras_nl_get_error_threshold_doit() - Query error threshold of a counter
> > > + * @skb: Netlink message buffer
> > > + * @info: Generic Netlink info containing attributes of the request
> > > + *
> > > + * Extracts the Node ID and Error ID from the netlink attributes and retrieves
> > > + * the error threshold of the corresponding counter. Sends the result back to
> > > + * the requesting user via the standard Genl reply.
> > > + *
> > > + * Return: 0 on success, or negative errno on failure.
> > > + */
> > > +int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb, struct genl_info *info)
> > > +{
> > > + u32 node_id, error_id;
> > > +
> > > + if (!info->attrs ||
> > > + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID) ||
> > > + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID))
> > > + return -EINVAL;
> > > +
> > > + node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID]);
> > > + error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID]);
> > > +
> > > + return doit_reply_threshold(info, node_id, error_id);
> > > +}
> > > +
> > > +/**
> > > + * drm_ras_nl_set_error_threshold_doit() - Set error threshold of a counter
> > > + * @skb: Netlink message buffer
> > > + * @info: Generic Netlink info containing attributes of the request
> > > + *
> > > + * Extracts the Node ID, Error ID and threshold from the netlink attributes and
> > > + * sets the error threshold of the corresponding counter.
> > > + *
> > > + * Return: 0 on success, or negative errno on failure.
> > > + */
> > > +int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb, struct genl_info *info)
> > > +{
> > > + u32 node_id, error_id, threshold;
> > > +
> > > + if (!info->attrs ||
> > > + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID) ||
> > > + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID) ||
> > > + GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD))
> > > + return -EINVAL;
> > > +
> > > + node_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID]);
> > > + error_id = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID]);
> > > + threshold = nla_get_u32(info->attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD]);
> > > +
> > > + return set_node_error_threshold(node_id, error_id, threshold);
> > > +}
> > > +
> > > /**
> > > * drm_ras_node_register() - Register a new RAS node
> > > * @node: Node structure to register
> > > diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
> > > index dea1c1b2494e..02e8e5054d05 100644
> > > --- a/drivers/gpu/drm/drm_ras_nl.c
> > > +++ b/drivers/gpu/drm/drm_ras_nl.c
> > > @@ -28,6 +28,19 @@ static const struct nla_policy drm_ras_clear_error_counter_nl_policy[DRM_RAS_A_E
> > > [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> > > };
> > >
> > > +/* DRM_RAS_CMD_GET_ERROR_THRESHOLD - do */
> > > +static const struct nla_policy drm_ras_get_error_threshold_nl_policy[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID + 1] = {
> > > + [DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, },
> > > + [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> > > +};
> > > +
> > > +/* DRM_RAS_CMD_SET_ERROR_THRESHOLD - do */
> > > +static const struct nla_policy drm_ras_set_error_threshold_nl_policy[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD + 1] = {
> > > + [DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID] = { .type = NLA_U32, },
> > > + [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID] = { .type = NLA_U32, },
> > > + [DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD] = { .type = NLA_U32, },
> > > +};
> > > +
> > > /* Ops table for drm_ras */
> > > static const struct genl_split_ops drm_ras_nl_ops[] = {
> > > {
> > > @@ -56,6 +69,20 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
> > > .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID,
> > > .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> > > },
> > > + {
> > > + .cmd = DRM_RAS_CMD_GET_ERROR_THRESHOLD,
> > > + .doit = drm_ras_nl_get_error_threshold_doit,
> > > + .policy = drm_ras_get_error_threshold_nl_policy,
> > > + .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID,
> > > + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> > > + },
> > > + {
> > > + .cmd = DRM_RAS_CMD_SET_ERROR_THRESHOLD,
> > > + .doit = drm_ras_nl_set_error_threshold_doit,
> > > + .policy = drm_ras_set_error_threshold_nl_policy,
> > > + .maxattr = DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD,
> > > + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> > > + },
> > > };
> > >
> > > struct genl_family drm_ras_nl_family __ro_after_init = {
> > > diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
> > > index a398643572a5..57b1e647d833 100644
> > > --- a/drivers/gpu/drm/drm_ras_nl.h
> > > +++ b/drivers/gpu/drm/drm_ras_nl.h
> > > @@ -20,6 +20,10 @@ int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb,
> > > struct netlink_callback *cb);
> > > int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb,
> > > struct genl_info *info);
> > > +int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
> > > + struct genl_info *info);
> > > +int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb,
> > > + struct genl_info *info);
> > >
> > > extern struct genl_family drm_ras_nl_family;
> > >
> > > diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
> > > index 0beede3ddc4e..b1fa87975cc5 100644
> > > --- a/include/drm/drm_ras.h
> > > +++ b/include/drm/drm_ras.h
> > > @@ -71,6 +71,35 @@ struct drm_ras_node {
> > > */
> > > int (*clear_error_counter)(struct drm_ras_node *node, u32 error_id);
> > >
> > > + /**
> > > + * @query_error_threshold:
> > > + *
> > > + * This callback is used by drm-ras to query error threshold of a
> > > + * specific counter.
> > > + *
> > > + * Driver should expect query_error_threshold() to be called with
> > > + * error_id from `error_counter_range.first` to
> > > + * `error_counter_range.last`.
> > > + *
> > > + * Returns: 0 on success, negative error code on failure.
> > > + */
> > > + int (*query_error_threshold)(struct drm_ras_node *node, u32 error_id, const char **name,
> > > + u32 *threshold);
> > > +
> > > + /**
> > > + * @set_error_threshold:
> > > + *
> > > + * This callback is used by drm-ras to set error threshold of a specific
> > > + * counter.
> > > + *
> > > + * Driver should expect set_error_threshold() to be called with error_id
> > > + * from `error_counter_range.first` to `error_counter_range.last`.
> > > + * Driver is responsible for error threshold bounds checking.
> > > + *
> > > + * Returns: 0 on success, negative error code on failure.
> > > + */
> > > + int (*set_error_threshold)(struct drm_ras_node *node, u32 error_id, u32 threshold);
> > > +
> > > /** @priv: Driver private data */
> > > void *priv;
> > > };
> > > diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
> > > index 218a3ee86805..27c68956495f 100644
> > > --- a/include/uapi/drm/drm_ras.h
> > > +++ b/include/uapi/drm/drm_ras.h
> > > @@ -33,6 +33,7 @@ enum {
> > > DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID,
> > > DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_NAME,
> > > DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_VALUE,
> > > + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD,
> > >
> > > __DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX,
> > > DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1)
> > > @@ -42,6 +43,8 @@ enum {
> > > DRM_RAS_CMD_LIST_NODES = 1,
> > > DRM_RAS_CMD_GET_ERROR_COUNTER,
> > > DRM_RAS_CMD_CLEAR_ERROR_COUNTER,
> > > + DRM_RAS_CMD_GET_ERROR_THRESHOLD,
> > > + DRM_RAS_CMD_SET_ERROR_THRESHOLD,
> > >
> > > __DRM_RAS_CMD_MAX,
> > > DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
> > > --
> > > 2.43.0
> > >
^ permalink raw reply
* [PATCH net] net/sched: act_gact, act_police: range check the fallback control action
From: hyunjungg @ 2026-08-05 9:55 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jamal Hadi Salim, Jiri Pirko, John Hurley, netdev,
linux-kernel
Cc: Hyunjung Ko, stable
From: Hyunjung Ko <hj351016@gmail.com>
tcf_action_check_ctrlact() range checks the primary control action:
if (!opcode)
ret = action > TC_ACT_VALUE_MAX ? -EINVAL : 0;
TC_ACT_VALUE_MAX is TC_ACT_TRAP, so kernel-internal verdicts above it
cannot be set that way. But act_gact and act_police each carry a second,
independent control action supplied by user space that never reaches that
helper - TCA_GACT_PROB.paction and TCA_POLICE_RESULT. Both only reject
TC_ACT_GOTO_CHAIN, so any other value is stored verbatim and returned
verbatim from the action.
In particular user space can store TC_ACT_CONSUMED, which is
TC_ACT_VALUE_MAX + 1 and is deliberately not part of the UAPI value
range. That verdict tells every caller the action took ownership of the
skb, so nobody frees it: sch_handle_ingress(), sch_handle_egress() and
tcf_qevent_handle() all deliberately skip the free for it. The result is
one leaked sk_buff plus its data buffer per packet traversing the filter,
unbounded, for all traffic on the chain including kernel-generated
packets.
Both are trivially deterministic. act_gact clamps tcfg_pval to >= 1, so
with pval = 1 gact_determ() returns the fallback for every packet.
act_police has no mandatory rate, so rate = 0 leaves tcfp_mtu = ~0 and
tcf_police_mtu_check() always passes.
TC_ACT_CONSUMED was added by commit 720f22fed81b, after both goto-chain
guards were written (9469f375ab09 and c08f5ed5d625, Oct 2018); neither
guard was widened when the new verdict appeared.
Factor the existing range test out of tcf_action_check_ctrlact() as
tcf_action_valid() and apply it to both fallbacks. The helper cannot call
tcf_action_check_ctrlact() directly because that also allocates a
goto_chain, which is exactly what these two sites must not do.
Reproduced on v7.2-rc6: kmemleak reports one leaked 232-byte
skbuff_head_cache object plus its 704-byte data buffer per packet. With
this patch both configurations are rejected with -EINVAL and kmemleak
reports none.
Fixes: 720f22fed81b ("net: sched: refactor reinsert action")
Cc: stable@vger.kernel.org # v5.3+
Signed-off-by: Hyunjung Ko <hj351016@gmail.com>
---
include/net/act_api.h | 19 +++++++++++++++++++
net/sched/act_gact.c | 5 +++++
net/sched/act_police.c | 6 ++++++
3 files changed, 30 insertions(+)
Reproducer needs CONFIG_NET_ACT_GACT + CONFIG_GACT_PROB and
CONFIG_NET_ACT_POLICE, plus CONFIG_DEBUG_KMEMLEAK and kmemleak=on to
observe it.
The bad value cannot be set with tc(8) - iproute2 only parses symbolic
action names - so the fallback has to be planted over raw netlink:
TCA_GACT_PROB.paction = 9 with ptype = PGACT_DETERM and pval = 1, or
TCA_POLICE_RESULT = 9 with rate = 0. Attach either to a clsact ingress
chain and every packet leaks its skb.
Before, one sk_buff plus its data buffer per packet:
kmemleak: 166 new suspected memory leaks
unreferenced object 0xffff888103baadc0 (size 232):
kmem_cache_alloc_node_noprof+0x2f1/0x3e0
__alloc_skb+0xe5/0x860
alloc_skb_with_frags+0x82/0x750
sock_alloc_send_pskb+0x658/0x7e0
packet_sendmsg+0x1833/0x4860
__x64_sys_sendto+0xe0/0x1c0
do_syscall_64+0x102/0x5a0
After: both configurations are rejected at netlink time with -EINVAL
and "invalid fallback control action", and kmemleak reports no
unreferenced objects.
For the same reason tdc cannot express the bad configuration, so no
selftest accompanies this patch. A self-contained C reproducer is
available on request.
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 20d9e55f8564..fd03f6319e88 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -270,6 +270,25 @@ int tcf_action_check_ctrlact(int action, struct tcf_proto *tp,
struct tcf_chain *tcf_action_set_ctrlact(struct tc_action *a, int action,
struct tcf_chain *newchain);
+/* Range check for a control action supplied by user space.
+ *
+ * This is the same test tcf_action_check_ctrlact() applies to the primary
+ * control action, factored out for the *fallback* control actions
+ * (act_gact's TCA_GACT_PROB.paction and act_police's TCA_POLICE_RESULT),
+ * which must not reach tcf_action_check_ctrlact() because they have no
+ * goto_chain to allocate. Without it, user space can store kernel-internal
+ * verdicts such as TC_ACT_CONSUMED, which is TC_ACT_VALUE_MAX + 1 and is
+ * deliberately not part of the UAPI value range.
+ */
+static inline bool tcf_action_valid(int action)
+{
+ int opcode = TC_ACT_EXT_OPCODE(action);
+
+ if (!opcode)
+ return action <= TC_ACT_VALUE_MAX;
+ return opcode <= TC_ACT_EXT_OPCODE_MAX || action == TC_ACT_UNSPEC;
+}
+
#ifdef CONFIG_INET
DECLARE_STATIC_KEY_FALSE(tcf_frag_xmit_count);
#endif
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index e949280eb800..565860cccba6 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -89,6 +89,11 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla,
p_parm = nla_data(tb[TCA_GACT_PROB]);
if (p_parm->ptype >= MAX_RAND)
return -EINVAL;
+ if (!tcf_action_valid(p_parm->paction)) {
+ NL_SET_ERR_MSG(extack,
+ "invalid fallback control action");
+ return -EINVAL;
+ }
if (TC_ACT_EXT_CMP(p_parm->paction, TC_ACT_GOTO_CHAIN)) {
NL_SET_ERR_MSG(extack,
"goto chain not allowed on fallback");
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index b16468a98c55..ce08f6840ef7 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -128,6 +128,12 @@ static int tcf_police_init(struct net *net, struct nlattr *nla,
if (tb[TCA_POLICE_RESULT]) {
tcfp_result = nla_get_u32(tb[TCA_POLICE_RESULT]);
+ if (!tcf_action_valid(tcfp_result)) {
+ NL_SET_ERR_MSG(extack,
+ "invalid fallback control action");
+ err = -EINVAL;
+ goto failure;
+ }
if (TC_ACT_EXT_CMP(tcfp_result, TC_ACT_GOTO_CHAIN)) {
NL_SET_ERR_MSG(extack,
"goto chain not allowed on fallback");
--
2.43.0
^ permalink raw reply related
* [PATCH net] net/sched: act_ct: fix sk_buff leak when the header checks reject a packet
From: hyunjungg @ 2026-08-05 9:55 UTC (permalink / raw)
To: Jamal Hadi Salim, Jiri Pirko, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Tao Liu, netdev,
linux-kernel
Cc: Hyunjung Ko, stable
From: Hyunjung Ko <hj351016@gmail.com>
tcf_ct_handle_fragments() runs its header sanity checks before handing
anything to the defragmentation engine:
if (family == NFPROTO_IPV4)
err = tcf_ct_ipv4_is_fragment(skb, &frag);
else
err = tcf_ct_ipv6_is_fragment(skb, &frag);
if (err || !frag)
return err;
tcf_ct_ipv4_is_fragment() returns -EINVAL or -ENOMEM;
tcf_ct_ipv6_is_fragment() adds -EPROTO when ipv6_find_hdr() fails. None of
them frees or queues the skb, so on that path the caller still owns it.
tcf_ct_act() however funnels every non-zero return into the
ownership-transfer exit:
err = tcf_ct_handle_fragments(net, skb, family, p->zone, &defrag);
if (err)
goto out_frag;
...
out_frag:
if (err != -EINPROGRESS)
tcf_action_inc_drop_qstats(&c->common);
return TC_ACT_CONSUMED;
TC_ACT_CONSUMED means the action took ownership of the skb, so no caller
frees it - sch_handle_ingress(), sch_handle_egress() and
tcf_qevent_handle() all deliberately skip the free for that verdict. The
skb is therefore orphaned: one sk_buff plus its data buffer is leaked per
malformed packet, unbounded. Note the drop counter is already incremented
for these errors, so the statistics claim a drop that never happens.
Three different ownership states reach out_frag: today - the skb may be
queued by the defrag engine (-EINPROGRESS), already freed by
nf_ct_handle_fragments(), or still owned by us. Tell the caller which of
those it is, and free the packet ourselves in the last case, which
restores the TC_ACT_SHOT behaviour that predated the Fixes: commit.
Reproduced on v7.2-rc6 with a 54-byte frame carrying a 40-byte IPv6
header with nexthdr = 0 (hop-by-hop) and nothing after it, on a
clsact ingress chain with "action ct". kmemleak reports one leaked
232-byte skbuff_head_cache object plus its 704-byte data buffer per
packet; with this patch it reports none.
Fixes: 3f14b377d01d ("net/sched: act_ct: fix skb leak and crash on ooo frags")
Cc: stable@vger.kernel.org # v6.8+
Signed-off-by: Hyunjung Ko <hj351016@gmail.com>
---
net/sched/act_ct.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)
Reproducer needs CONFIG_NET_ACT_CT, plus CONFIG_DEBUG_KMEMLEAK and
kmemleak=on to observe it:
ip link add veth0 type veth peer name veth1
ip link set veth0 up; ip link set veth1 up
tc qdisc add dev veth0 clsact
tc filter add dev veth0 ingress matchall action ct
then inject at veth1 a 54-byte frame: ethertype 0x86DD, a 40-byte IPv6
header with nexthdr = 0 (hop-by-hop) and nothing after it, so
ipv6_find_hdr() fails with -EBADMSG and tcf_ct_ipv6_is_fragment()
returns -EPROTO.
Before, one sk_buff plus its data buffer per packet:
kmemleak: 50 new suspected memory leaks
unreferenced object 0xffff888103ed13c0 (size 232):
kmem_cache_alloc_node_noprof+0x2f1/0x3e0
__alloc_skb+0xe5/0x860
alloc_skb_with_frags+0x82/0x750
sock_alloc_send_pskb+0x658/0x7e0
packet_sendmsg+0x1833/0x4860
__x64_sys_sendto+0xe0/0x1c0
do_syscall_64+0x102/0x5a0
After: kmemleak reports no unreferenced objects.
Note /proc/slabinfo is not a usable check here on a KASAN build -
skbuff_head_cache active_objs still grows because the quarantine holds
the freed objects. kmemleak is the reliable signal.
No selftest accompanies this: tdc drives tc(8) only and cannot inject
the malformed frame. A self-contained C reproducer is available on
request.
diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
index be535a261fa0..e250969c84ac 100644
--- a/net/sched/act_ct.c
+++ b/net/sched/act_ct.c
@@ -840,8 +840,15 @@ static int tcf_ct_ipv6_is_fragment(struct sk_buff *skb, bool *frag)
return 0;
}
+/* On error, tells the caller whether it still owns @skb and must free it
+ * itself. @skb is ours only when the header checks below reject the packet
+ * before it is handed to the defragmentation engine; once nf_ct_handle_
+ * fragments() has been called the skb is either queued (-EINPROGRESS) or has
+ * already been freed by it.
+ */
static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
- u8 family, u16 zone, bool *defrag)
+ u8 family, u16 zone, bool *defrag,
+ bool *skb_is_ours)
{
enum ip_conntrack_info ctinfo;
struct tc_skb_cb cb;
@@ -859,8 +866,12 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
err = tcf_ct_ipv4_is_fragment(skb, &frag);
else
err = tcf_ct_ipv6_is_fragment(skb, &frag);
- if (err || !frag)
+ if (err) {
+ *skb_is_ours = true;
return err;
+ }
+ if (!frag)
+ return 0;
cb = *tc_skb_cb(skb);
err = nf_ct_handle_fragments(net, skb, zone, family, &proto, &cb.mru);
@@ -977,6 +988,7 @@ TC_INDIRECT_SCOPE int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
int nh_ofs, err, retval;
struct tcf_ct_params *p;
bool add_helper = false;
+ bool skb_is_ours = false;
bool skip_add = false;
bool defrag = false;
struct nf_conn *ct;
@@ -1012,9 +1024,18 @@ TC_INDIRECT_SCOPE int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
*/
nh_ofs = skb_network_offset(skb);
skb_pull_rcsum(skb, nh_ofs);
- err = tcf_ct_handle_fragments(net, skb, family, p->zone, &defrag);
- if (err)
+ err = tcf_ct_handle_fragments(net, skb, family, p->zone, &defrag,
+ &skb_is_ours);
+ if (err) {
+ /* The skb is still ours only when the header checks rejected
+ * it; returning TC_ACT_CONSUMED for such a packet would leak
+ * it, since no caller frees an skb it was told it no longer
+ * owns.
+ */
+ if (skb_is_ours)
+ goto drop;
goto out_frag;
+ }
err = nf_ct_skb_network_trim(skb, family);
if (err)
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net-next 1/2] netconsole: publish the userdata payload with RCU
From: Breno Leitao @ 2026-08-05 9:56 UTC (permalink / raw)
To: Gustavo Luiz Duarte
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Shuah Khan, netdev, linux-kernel, linux-kselftest,
asantostc, kernel-team
In-Reply-To: <CAGSyskVKAwf8nb_3uFDbYUugR+dtO-cwSef8C9nSEgKZt_K=CQ@mail.gmail.com>
On Tue, Aug 04, 2026 at 06:09:44PM +0100, Gustavo Luiz Duarte wrote:
> > @@ -176,8 +190,7 @@ struct netconsole_target {
> > #ifdef CONFIG_NETCONSOLE_DYNAMIC
> > struct config_group group;
> > struct config_group userdata_group;
> > - char *userdata;
> > - size_t userdata_length;
> > + struct netcons_userdata __rcu *userdata;
>
> With userdata now annotated with __rcu, it should be freed with
> kfree(rcu_access_pointer(nt->userdata)) to avoid a sparse warning:
Good catch, thanks. I will fix in v2 in both netconsole_target_release()
and free_param_target().
I willthe plain kfree() instead of kfree_rcu(): both callers free nt
itself on the next line, and the target is already unlinked from
target_list at that point, so the payload cannot outlive the target.
Thanks for the review,
--breno
^ permalink raw reply
* Re: [PATCH] net: 8390: pcnet_cs: release PCMCIA window on setup_shmem_window() error
From: Simon Horman @ 2026-08-05 9:57 UTC (permalink / raw)
To: Myeonghun Pak
Cc: Dominik Brodowski, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, netdev, linux-kernel, stable,
Ijae Kim
In-Reply-To: <20260731161740.44955-1-mhun512@gmail.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://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260731161740.44955-1-mhun512@gmail.com?part=1
---
--- Patch [1]: [PATCH] net: 8390: pcnet_cs: release PCMCIA window on setup_shmem_window() error ---
commit 74f57c39e62b4fcd24846cf9fc7fe9cbcd03cfe3
Author: Myeonghun Pak <mhun512@gmail.com>
net: 8390: pcnet_cs: release PCMCIA window on setup_shmem_window() error
This routes the post-pcmcia_request_window() error paths in
setup_shmem_window() through a new "release" label that calls
pcmcia_release_window(), and folds the existing buffer-verification
cleanup into it. The pcmcia_request_window() failure path is left
returning directly.
A few questions below, mostly about the changelog and about the
surrounding code in the function being reworked.
[Severity: Low]
[Finding: main-1-0]
[Sources: opus-5]
The changelog states:
The requested window is leaked.
and carries Cc: stable. Is "leaked" the right description here? On the
success path pcmcia_request_window() stamps the map bits into the
resource flags:
res->flags |= (win->map << 2) | IORESOURCE_MEM;
and pcmcia_disable_device() then walks every window resource and
releases the ones still carrying those bits:
for (i = 0; i < MAX_WIN; i++) {
struct resource *res = p_dev->resource[MAX_IO_WIN + i];
if (res->flags & WIN_FLAGS_REQ)
pcmcia_release_window(p_dev, res);
}
Both the pcnet_config() failure path and pcnet_detach() reach
pcnet_release() -> pcmcia_disable_device(), so the window looks like it
is reclaimed at device teardown rather than lost for good.
Would it be more accurate to say socket window 3 and its reserved iomem
range stay held for the whole bound lifetime of the device even though
the driver has fallen back to setup_dma_config()? That wording would
also help stable backport triage, since the current text reads like an
unbounded leak that survives card removal or module unload.
> diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c
> index 19f9c5db3f3ba..a913674be60ac 100644
> --- a/drivers/net/ethernet/8390/pcnet_cs.c
> +++ b/drivers/net/ethernet/8390/pcnet_cs.c
> @@ -1434,14 +1434,14 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
> offset -= offset % window_size;
> ret = pcmcia_map_mem_page(link, link->resource[3], offset);
> if (ret)
> - goto failed;
> + goto release;
>
> /* Try scribbling on the buffer */
> info->base = ioremap(link->resource[3]->start,
> resource_size(link->resource[3]));
> if (unlikely(!info->base)) {
> ret = -ENOMEM;
> + goto release;
> }
[Severity: Low]
[Finding: main-1-1]
[Sources: opus-5]
This isn't a bug, but the indentation of the two new goto statements
differs from the code they replace and from the statements around them.
The file uses tab+4 spaces at this depth, and the new gotos use a single
tab. In the ioremap() block the two statements of the same brace block
now sit at different columns:
if (unlikely(!info->base)) {
ret = -ENOMEM;
goto release;
}
which makes the goto read as if it were outside the if block. Could
these keep the surrounding style?
>
> for (i = 0; i < (TX_PAGES<<8); i += 2)
> @@ -1452,9 +1452,8 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
> pcnet_reset_8390(dev);
> if (i != (TX_PAGES<<8)) {
> iounmap(info->base);
> - pcmcia_release_window(link, link->resource[3]);
> info->base = NULL;
> - goto failed;
> + goto release;
> }
[Severity: High]
[Finding: main-7-3]
[Sources: opus-5]
This is a pre-existing issue and not introduced by this patch, but it is
in the function being reworked, so it seems worth raising.
Does setup_shmem_window() mix up the card-side window base with the
host-side displacement into the ioremap() mapping? offset is computed as
a card address rounded down to a window boundary:
offset = (start_pg << 8) + cm_offset;
offset -= offset % window_size;
ret = pcmcia_map_mem_page(link, link->resource[3], offset);
That is correct for pcmcia_map_mem_page(), which stores it as
s->win[w].card_start. But the same value is then used as a byte offset
inside the host mapping:
for (i = 0; i < (TX_PAGES<<8); i += 2)
__raw_writew((i>>1), info->base+offset+i);
udelay(100);
for (i = 0; i < (TX_PAGES<<8); i += 2)
if (__raw_readw(info->base+offset+i) != (i>>1)) break;
With the default parameters (start_pg == PCNET_START_PG == 0x40,
cm_offset == 0) window_size is 0x4000 and offset stays 0x4000, while the
ioremap() covers exactly resource_size(link->resource[3]) == 0x4000
bytes. Doesn't that put the whole scribble loop at info->base + 0x4000
through +0x4bff, entirely past the end of the mapping, so the write
either faults on the ioremap guard page or lands in a neighbouring
device mapping?
Should the host displacement be the remainder instead, i.e.
((start_pg << 8) + cm_offset) % window_size?
The derived values look affected the same way:
ei_status.mem = info->base + offset;
ei_status.priv = resource_size(link->resource[3]);
...
ei_status.stop_page = start_pg + (
(resource_size(link->resource[3]) - offset) >> 8);
In the default case that gives stop_page == start_pg, and for
USE_BIG_BUF (start_pg 0x01, cm_offset 0x10000, window_size 0x8000)
offset becomes 0x10000 so resource_size() - offset underflows in
unsigned resource_size_t arithmetic.
Reaching this needs use_shmem=1 on the module line plus a supported
card, since has_shmem is always 0 (pcnet_confcheck() does *priv &= 0x10
on a value that is only ever 0 or 1). Given that, is the shared-memory
path here exercised at all, and does that change how the changelog's
"probe can continue and even succeed" claim should be phrased?
>
> ei_status.mem = info->base + offset;
> @@ -1475,6 +1474,8 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
> info->flags |= USE_SHMEM;
> return 0;
>
> +release:
> + pcmcia_release_window(link, link->resource[3]);
> failed:
> return 1;
> }
Simon says: I think the pre-existing problem described below
is out of scope for your patch.
[Severity: Medium]
[Finding: main-2-2]
[Sources: opus-5]
This is a pre-existing problem in the PCMCIA core rather than something
this patch introduces, but it touches the assumption stated in the
changelog:
The pcmcia_request_window() failure path still returns
directly, as no window is held there.
Is that always true? pcmcia_request_window() allocates the system memory
region and sets the client bit before programming the mapping:
p_dev->_win |= CLIENT_WIN_REQ(w);
/* Configure the socket controller */
win->map = w+1;
...
if (s->ops->set_mem_map(s, win) != 0) {
dev_dbg(&p_dev->dev, "failed to set memory mapping\n");
mutex_unlock(&s->ops_mutex);
return -EIO;
}
On that -EIO return win->res stays allocated, the _win bit stays set,
and res->flags never receives the (win->map << 2) marker that is only
written on the success path. Both cleanup helpers key off exactly that
marker:
w = ((res->flags & IORESOURCE_BITS & WIN_FLAGS_REQ) >> 2) - 1;
if (w >= MAX_WIN)
return -EINVAL;
and in pcmcia_disable_device():
if (res->flags & WIN_FLAGS_REQ)
pcmcia_release_window(p_dev, res);
WIN_FLAGS_REQ is 0x1c, and the flags pcnet_cs sets here
(WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT)
contain none of those bits, so the half-held window would be invisible
to pcnet_release() -> pcmcia_disable_device() too.
This looks reachable from pcnet_cs with mem_speed above 1000, where
yenta_set_mem_map() rejects the mapping on mem->speed > 1000 and
pcmcia_request_window() takes that -EIO path. Does that mean the
struct resource from pcmcia_find_mem_region() and the reserved host
iomem range can no longer be released by any in-tree caller, and that
window index w can later be reused with win->res overwritten?
Adding a release label for that branch would not help while res->flags
lacks the marker bits, so it may be worth noting that the core is where
this one has to be fixed.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox