* [PATCH net-next v3 0/3] Add ZTE DingHai Ethernet PF driver
From: Junyang Han @ 2026-04-30 15:11 UTC (permalink / raw)
To: andrew+netdev
Cc: netdev, vadim.fedorenko, davem, edumazet, kuba, pabeni,
han.junyang, ran.ming, han.chengfei, zhang.yanze
[-- Attachment #1.1.1: Type: text/plain, Size: 2851 bytes --]
This series adds initial support for the ZTE DingHai Ethernet controller,
a high-performance PCIe Ethernet device supporting SR-IOV, hardware
offloading, and advanced virtualization features.
Changes from v2:
- Address maintainer feedback from v2 review:
* Remove meaningless initialization
* Change dh_pf_pci_table to static const for better encapsulation
* Simplify MODULE_DESCRIPTION for brevity
- Coding style improvements:
* Ensure all lines are within 80-column limit
* Use kernel types (u32/u8) consistently throughout
* Improve code readability with better formatting
Changes from v1 (addressing feedback from AndrewLunn):
- Update copyright years to 2022-2026
- Remove DRV_VERSION, MODULE_VERSION and related boilerplate
- Fix MODULE_AUTHOR to use person with email address
- Use module_pci_driver() instead of manual init/exit
- Remove empty suspend/resume callbacks
- Replace char priv[] flexible array with void *priv + kzalloc
- Switch logging from printk wrappers to dev_*() based macros
- Remove dh_helper.h and dh_log.c, simplify to dh_log.h only
- Fix variable declaration ordering (reverse Christmas tree)
- Remove unnecessary NULL check in remove and pf_dev=NULL in probe
- Fix indentation and remove unnecessary type casts
- Use kernel idiomatic "if (ret)" style
This is the initial submission and only includes the PF (Physical Function)
driver. The VF (Virtual Function) driver will be submitted separately.
Junyang Han (3):
net/ethernet: add ZTE network driver support
net/ethernet/zte/dinghai: add logging infrastructure
net/ethernet/zte/dinghai: add hardware register access and PCI
capability scanning
MAINTAINERS | 6 +
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/zte/Kconfig | 20 +
drivers/net/ethernet/zte/Makefile | 6 +
drivers/net/ethernet/zte/dinghai/Kconfig | 34 ++
drivers/net/ethernet/zte/dinghai/Makefile | 10 +
drivers/net/ethernet/zte/dinghai/dh_log.h | 64 ++
drivers/net/ethernet/zte/dinghai/dh_queue.h | 71 +++
drivers/net/ethernet/zte/dinghai/en_pf.c | 637 ++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.h | 102 ++++
11 files changed, 952 insertions(+)
create mode 100644 drivers/net/ethernet/zte/Kconfig
create mode 100644 drivers/net/ethernet/zte/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/Kconfig
create mode 100644 drivers/net/ethernet/zte/dinghai/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/dh_log.h
create mode 100644 drivers/net/ethernet/zte/dinghai/dh_queue.h
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.c
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.h
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 5150 bytes --]
^ permalink raw reply
* [PATCH net-next v3 1/3] net/ethernet: add ZTE network driver support
From: Junyang Han @ 2026-04-30 15:11 UTC (permalink / raw)
To: andrew+netdev
Cc: netdev, vadim.fedorenko, davem, edumazet, kuba, pabeni,
han.junyang, ran.ming, han.chengfei, zhang.yanze
In-Reply-To: <20260430151138.2813381-1-han.junyang@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 11300 bytes --]
Add basic framework for ZTE DingHai ethernet PF driver, including
Kconfig/Makefile build support and PCIe device probe/remove skeleton.
Signed-off-by: Junyang Han <han.junyang@zte.com.cn>
---
MAINTAINERS | 6 +
drivers/net/ethernet/Kconfig | 1 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/zte/Kconfig | 20 +++
drivers/net/ethernet/zte/Makefile | 6 +
drivers/net/ethernet/zte/dinghai/Kconfig | 34 +++++
drivers/net/ethernet/zte/dinghai/Makefile | 10 ++
drivers/net/ethernet/zte/dinghai/en_pf.c | 164 ++++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.h | 64 +++++++++
9 files changed, 306 insertions(+)
create mode 100644 drivers/net/ethernet/zte/Kconfig
create mode 100644 drivers/net/ethernet/zte/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/Kconfig
create mode 100644 drivers/net/ethernet/zte/dinghai/Makefile
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.c
create mode 100644 drivers/net/ethernet/zte/dinghai/en_pf.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..73692b09bf7b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29440,6 +29440,12 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
F: sound/hda/codecs/senarytech.c
+ZTE DINGHAI ETHERNET DRIVER
+M: Junyang Han <han.junyang@zte.com.cn>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/zte/
+
THE REST
M: Linus Torvalds <torvalds@linux-foundation.org>
L: linux-kernel@vger.kernel.org
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index b8f70e2a1763..c2b6996b0cfe 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -188,5 +188,6 @@ source "drivers/net/ethernet/wangxun/Kconfig"
source "drivers/net/ethernet/wiznet/Kconfig"
source "drivers/net/ethernet/xilinx/Kconfig"
source "drivers/net/ethernet/xircom/Kconfig"
+source "drivers/net/ethernet/zte/Kconfig"
endif # ETHERNET
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 57344fec6ce0..a34bcbd4df4e 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -104,3 +104,4 @@ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/
obj-$(CONFIG_OA_TC6) += oa_tc6.o
+obj-$(CONFIG_NET_VENDOR_ZTE) += zte/
diff --git a/drivers/net/ethernet/zte/Kconfig b/drivers/net/ethernet/zte/Kconfig
new file mode 100644
index 000000000000..b95c2fc7db77
--- /dev/null
+++ b/drivers/net/ethernet/zte/Kconfig
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# ZTE driver configuration
+#
+
+config NET_VENDOR_ZTE
+ bool "ZTE devices"
+ default y
+ help
+ If you have a network (Ethernet) card belonging to this class, say Y.
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ the questions about Zte cards. If you say Y, you will be asked
+ for your specific card in the following questions.
+
+if NET_VENDOR_ZTE
+
+source "drivers/net/ethernet/zte/dinghai/Kconfig"
+
+endif # NET_VENDOR_ZTE
diff --git a/drivers/net/ethernet/zte/Makefile b/drivers/net/ethernet/zte/Makefile
new file mode 100644
index 000000000000..cd9929b61559
--- /dev/null
+++ b/drivers/net/ethernet/zte/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the ZTE device drivers
+#
+
+obj-$(CONFIG_DINGHAI) += dinghai/
diff --git a/drivers/net/ethernet/zte/dinghai/Kconfig b/drivers/net/ethernet/zte/dinghai/Kconfig
new file mode 100644
index 000000000000..94b5bd9b3c50
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/Kconfig
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# ZTE DingHai Ethernet driver configuration
+#
+
+config DINGHAI
+ bool "ZTE DingHai Ethernet driver"
+ depends on NET_VENDOR_ZTE && PCI
+ select NET_DEVLINK
+ help
+ This driver supports ZTE DingHai Ethernet devices.
+
+ DingHai is a high-performance Ethernet controller that supports
+ multiple features including hardware offloading, SR-IOV, and
+ advanced virtualization capabilities.
+
+ If you say Y here, you can select specific driver variants below.
+
+ If unsure, say N.
+
+if DINGHAI
+
+config DINGHAI_PF
+ tristate "ZTE DingHai PF (Physical Function) driver"
+ help
+ This driver supports ZTE DingHai PCI Express Ethernet
+ adapters (PF).
+
+ To compile this driver as a module, choose M here. The module
+ will be named dinghai10e.
+
+ If unsure, say N.
+
+endif # DINGHAI
diff --git a/drivers/net/ethernet/zte/dinghai/Makefile b/drivers/net/ethernet/zte/dinghai/Makefile
new file mode 100644
index 000000000000..f55a8de518be
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for ZTE DingHai Ethernet driver
+#
+
+ccflags-y += -I$(src)
+
+obj-$(CONFIG_DINGHAI_PF) += dinghai10e.o
+dinghai10e-y := en_pf.o
+
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c
new file mode 100644
index 000000000000..d56bd4ea3259
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ZTE DingHai Ethernet driver
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <net/devlink.h>
+#include "en_pf.h"
+
+MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
+MODULE_DESCRIPTION("ZTE DingHai series Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static const struct devlink_ops dh_pf_devlink_ops = {};
+
+static const struct pci_device_id dh_pf_pci_table[] = {
+ { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_PF_DEVICE_ID), 0 },
+ { PCI_DEVICE(ZXDH_PF_VENDOR_ID, ZXDH_VF_DEVICE_ID), 0 },
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, dh_pf_pci_table);
+
+static int dh_pf_pci_init(struct dh_core_dev *dev)
+{
+ struct zxdh_pf_device *pf_dev = NULL;
+ int ret;
+
+ pci_set_drvdata(dev->pdev, dev);
+
+ ret = pci_enable_device(dev->pdev);
+ if (ret)
+ return -ENOMEM;
+
+ ret = dma_set_mask_and_coherent(dev->device, DMA_BIT_MASK(64));
+ if (ret) {
+ ret = dma_set_mask_and_coherent(dev->device, DMA_BIT_MASK(32));
+ if (ret)
+ goto err_pci;
+ }
+
+ ret = pci_request_selected_regions(dev->pdev,
+ pci_select_bars(dev->pdev, IORESOURCE_MEM),
+ "dh-pf");
+ if (ret)
+ goto err_pci;
+
+ pci_set_master(dev->pdev);
+ ret = pci_save_state(dev->pdev);
+ if (ret)
+ goto err_pci_save_state;
+
+ pf_dev = dev->priv;
+ pf_dev->pci_ioremap_addr[0] =
+ ioremap(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
+ if (!pf_dev->pci_ioremap_addr[0]) {
+ ret = -ENOMEM;
+ goto err_pci_save_state;
+ }
+
+ return 0;
+
+err_pci_save_state:
+ pci_release_selected_regions(dev->pdev,
+ pci_select_bars(dev->pdev, IORESOURCE_MEM));
+err_pci:
+ pci_disable_device(dev->pdev);
+ return ret;
+}
+
+void dh_pf_pci_close(struct dh_core_dev *dev)
+{
+ struct zxdh_pf_device *pf_dev = NULL;
+
+ pf_dev = dev->priv;
+ iounmap(pf_dev->pci_ioremap_addr[0]);
+ pci_release_selected_regions(dev->pdev,
+ pci_select_bars(dev->pdev, IORESOURCE_MEM));
+ pci_disable_device(dev->pdev);
+}
+
+static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct dh_core_dev *dh_dev;
+ struct zxdh_pf_device *pf_dev;
+ struct devlink *devlink;
+ int ret;
+
+ devlink = devlink_alloc(&dh_pf_devlink_ops, sizeof(struct dh_core_dev),
+ &pdev->dev);
+ if (!devlink)
+ return -ENOMEM;
+
+ dh_dev = devlink_priv(devlink);
+ dh_dev->device = &pdev->dev;
+ dh_dev->pdev = pdev;
+ dh_dev->devlink = devlink;
+
+ pf_dev = dh_core_alloc_priv(dh_dev, sizeof(*pf_dev));
+ if (!pf_dev)
+ return -ENOMEM;
+
+ pf_dev->bar_chan_valid = false;
+ pf_dev->vepa = false;
+ mutex_init(&dh_dev->lock);
+ mutex_init(&pf_dev->irq_lock);
+
+ dh_dev->coredev_type = GET_COREDEV_TYPE(pdev);
+
+ ret = dh_pf_pci_init(dh_dev);
+ if (ret)
+ goto err_cfg_init;
+
+ return 0;
+
+err_cfg_init:
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&dh_dev->lock);
+ dh_core_free_priv(dh_dev);
+ devlink_free(devlink);
+ return -EPERM;
+}
+
+static void dh_pf_remove(struct pci_dev *pdev)
+{
+ struct dh_core_dev *dh_dev = pci_get_drvdata(pdev);
+ struct devlink *devlink = priv_to_devlink(dh_dev);
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ dh_pf_pci_close(dh_dev);
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&dh_dev->lock);
+ dh_core_free_priv(dh_dev);
+ devlink_free(devlink);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static void dh_pf_shutdown(struct pci_dev *pdev)
+{
+ struct dh_core_dev *dh_dev = pci_get_drvdata(pdev);
+ struct devlink *devlink = priv_to_devlink(dh_dev);
+ struct zxdh_pf_device *pf_dev = dh_dev->priv;
+
+ dh_pf_pci_close(dh_dev);
+ mutex_destroy(&pf_dev->irq_lock);
+ mutex_destroy(&dh_dev->lock);
+ dh_core_free_priv(dh_dev);
+ devlink_free(devlink);
+
+ pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver dh_pf_driver = {
+ .name = "dinghai10e",
+ .id_table = dh_pf_pci_table,
+ .probe = dh_pf_probe,
+ .remove = dh_pf_remove,
+ .shutdown = dh_pf_shutdown,
+};
+
+module_pci_driver(dh_pf_driver);
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.h b/drivers/net/ethernet/zte/dinghai/en_pf.h
new file mode 100644
index 000000000000..0c47f3a38a9d
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ZTE DingHai Ethernet driver - PF header
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#ifndef __ZXDH_EN_PF_H__
+#define __ZXDH_EN_PF_H__
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#define ZXDH_PF_VENDOR_ID 0x1cf2
+#define ZXDH_PF_DEVICE_ID 0x8040
+#define ZXDH_VF_DEVICE_ID 0x8041
+
+enum dh_coredev_type {
+ DH_COREDEV_PF,
+ DH_COREDEV_VF,
+ DH_COREDEV_SF,
+ DH_COREDEV_MPF
+};
+
+struct devlink;
+
+struct dh_core_dev {
+ struct device *device;
+ enum dh_coredev_type coredev_type;
+ struct pci_dev *pdev;
+ struct devlink *devlink;
+ struct mutex lock; /* Protects device configuration */
+ void *priv;
+};
+
+struct zxdh_pf_device {
+ void __iomem *pci_ioremap_addr[6];
+ bool bar_chan_valid;
+ bool vepa;
+ struct mutex irq_lock; /* Protects IRQ operations */
+};
+
+static inline void *dh_core_alloc_priv(struct dh_core_dev *dh_dev,
+ size_t size)
+{
+ void *priv = kzalloc(size, GFP_KERNEL);
+
+ if (priv)
+ dh_dev->priv = priv;
+ return priv;
+}
+
+static inline void dh_core_free_priv(struct dh_core_dev *dh_dev)
+{
+ kfree(dh_dev->priv);
+ dh_dev->priv = NULL;
+}
+
+#define GET_COREDEV_TYPE(pdev) \
+ ((pdev)->device == ZXDH_VF_DEVICE_ID ? DH_COREDEV_VF : DH_COREDEV_PF)
+
+#endif
+
+void dh_pf_pci_close(struct dh_core_dev *dev);
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 21753 bytes --]
^ permalink raw reply related
* Re: [PATCH net 2/3] net/sched: sch_sfb: Replace direct dequeue call with peek and qdisc_dequeue_peeked
From: Eric Dumazet @ 2026-04-30 15:42 UTC (permalink / raw)
To: Jamal Hadi Salim
Cc: netdev, Victor Nogueria, davem, kuba, pabeni, horms, jiri,
pctammela, ghandatmanas, rakshitawasthi17, security
In-Reply-To: <20260430152957.194015-3-jhs@mojatatu.com>
On Thu, Apr 30, 2026 at 8:30 AM Jamal Hadi Salim <jhs@mojatatu.com> wrote:
>
> From: Victor Nogueria <victor@mojatatu.com>
>
> When sfb has children (eg qfq qdisc) whose peek() callback is
> qdisc_peek_dequeued(), we could get a kernel panic. When the parent of such
> qdiscs (eg illustrated in patch #3 as tbf) wants to retrieve an skb from
> its child (sfb in this case), it will do the following:
> 1a. do a peek() - and when sensing there's an skb the child can offer, then
> - the child in this case(sfb) calls its child's (qfq) peek.
> qfq does the right thing and will return the gso_skb queue packet.
> Note: if there wasnt a gso_skb entry then qfq will store it there.
> 1b. invoke a dequeue() on the child (sfb). And herein lies the problem.
> - sfb will call the child's dequeue() which will essentially just
> try to grab something of qfq's queue.
>
> The right thing to do in #1b is to grab the skb off gso_skb queue.
> This patchset fixes that issue by changing #1b to use qdisc_dequeue_peeked()
> method instead.
>
> Fixes: e13e02a3c68d ("net_sched: SFB flow scheduler")
> Signed-off-by: Victor Nogueria <victor@mojatatu.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* [PATCH net-next v3 2/3] net/ethernet/zte/dinghai: add logging infrastructure
From: Junyang Han @ 2026-04-30 15:11 UTC (permalink / raw)
To: andrew+netdev
Cc: netdev, vadim.fedorenko, davem, edumazet, kuba, pabeni,
han.junyang, ran.ming, han.chengfei, zhang.yanze
In-Reply-To: <20260430151138.2813381-1-han.junyang@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 7371 bytes --]
Introduce logging macros (DH_LOG_EMERG/ALERT/CRIT/ERR/WARN/INFO/DBG)
and helper definitions for ZTE DingHai driver debugging.
Signed-off-by: Junyang Han <han.junyang@zte.com.cn>
---
drivers/net/ethernet/zte/dinghai/dh_log.h | 64 +++++++++++++++++++++++
drivers/net/ethernet/zte/dinghai/en_pf.c | 49 ++++++++++++++---
2 files changed, 105 insertions(+), 8 deletions(-)
create mode 100644 drivers/net/ethernet/zte/dinghai/dh_log.h
diff --git a/drivers/net/ethernet/zte/dinghai/dh_log.h b/drivers/net/ethernet/zte/dinghai/dh_log.h
new file mode 100644
index 000000000000..ae93596bcaef
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/dh_log.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ZTE DingHai Ethernet driver - logging infrastructure
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#ifndef __DH_LOG_H__
+#define __DH_LOG_H__
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+
+#define MODULE_CMD "zxdh_cmd"
+#define MODULE_NP "zxdh_np"
+#define MODULE_PF "zxdh_pf"
+#define MODULE_PTP "zxdh_ptp"
+#define MODULE_TSN "zxdh_tsn"
+#define MODULE_LAG "zxdh_lag"
+#define MODULE_DHTOOLS "zxdh_tool"
+#define MODULE_SEC "zxdh_sec"
+#define MODULE_MPF "zxdh_mpf"
+#define MODULE_FUC_HP "zxdh_func_hp"
+#define MODULE_UACCE "zxdh_uacce"
+#define MODULE_HEAL "zxdh_health"
+
+#define DH_LOG_EMERG(module, __dev, fmt, arg...) \
+ dev_emerg((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_ALERT(module, __dev, fmt, arg...) \
+ dev_alert((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_CRIT(module, __dev, fmt, arg...) \
+ dev_crit((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_ERR(module, __dev, fmt, arg...) \
+ dev_err((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_WARNING(module, __dev, fmt, arg...) \
+ dev_warn((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_INFO(module, __dev, fmt, arg...) \
+ dev_info((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define DH_LOG_DEBUG(module, __dev, fmt, arg...) \
+ dev_dbg((__dev)->device, "[%s][%s][%d] " fmt, \
+ module, __func__, __LINE__, ##arg)
+
+#define LOG_ERR(__dev, fmt, arg...) \
+ DH_LOG_ERR(MODULE_PF, __dev, fmt, ##arg)
+#define LOG_INFO(__dev, fmt, arg...) \
+ DH_LOG_INFO(MODULE_PF, __dev, fmt, ##arg)
+#define LOG_DEBUG(__dev, fmt, arg...) \
+ DH_LOG_DEBUG(MODULE_PF, __dev, fmt, ##arg)
+#define LOG_WARN(__dev, fmt, arg...) \
+ DH_LOG_WARNING(MODULE_PF, __dev, fmt, ##arg)
+
+#endif /* __DH_LOG_H__ */
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c
index d56bd4ea3259..f4a923b76037 100644
--- a/drivers/net/ethernet/zte/dinghai/en_pf.c
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -8,6 +8,7 @@
#include <linux/pci.h>
#include <net/devlink.h>
#include "en_pf.h"
+#include "dh_log.h"
MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
MODULE_DESCRIPTION("ZTE DingHai series Ethernet driver");
@@ -31,26 +32,34 @@ static int dh_pf_pci_init(struct dh_core_dev *dev)
pci_set_drvdata(dev->pdev, dev);
ret = pci_enable_device(dev->pdev);
- if (ret)
+ if (ret) {
+ LOG_ERR(dev, "pci_enable_device failed: %d\n", ret);
return -ENOMEM;
+ }
ret = dma_set_mask_and_coherent(dev->device, DMA_BIT_MASK(64));
if (ret) {
ret = dma_set_mask_and_coherent(dev->device, DMA_BIT_MASK(32));
- if (ret)
+ if (ret) {
+ LOG_ERR(dev, "dma_set_mask_and_coherent failed: %d\n", ret);
goto err_pci;
+ }
}
ret = pci_request_selected_regions(dev->pdev,
pci_select_bars(dev->pdev, IORESOURCE_MEM),
"dh-pf");
- if (ret)
+ if (ret) {
+ LOG_ERR(dev, "pci_request_selected_regions failed: %d\n", ret);
goto err_pci;
+ }
pci_set_master(dev->pdev);
ret = pci_save_state(dev->pdev);
- if (ret)
+ if (ret) {
+ LOG_ERR(dev, "pci_save_state failed: %d\n", ret);
goto err_pci_save_state;
+ }
pf_dev = dev->priv;
pf_dev->pci_ioremap_addr[0] =
@@ -58,6 +67,9 @@ static int dh_pf_pci_init(struct dh_core_dev *dev)
pci_resource_len(dev->pdev, 0));
if (!pf_dev->pci_ioremap_addr[0]) {
ret = -ENOMEM;
+ LOG_ERR(dev, "ioremap(0x%llx, 0x%llx) failed\n",
+ pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
goto err_pci_save_state;
}
@@ -89,10 +101,13 @@ static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct devlink *devlink;
int ret;
+ dev_info(&pdev->dev, "pf level start\n");
devlink = devlink_alloc(&dh_pf_devlink_ops, sizeof(struct dh_core_dev),
&pdev->dev);
- if (!devlink)
+ if (!devlink) {
+ dev_err(&pdev->dev, "devlink alloc failed\n");
return -ENOMEM;
+ }
dh_dev = devlink_priv(devlink);
dh_dev->device = &pdev->dev;
@@ -100,8 +115,10 @@ static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dh_dev->devlink = devlink;
pf_dev = dh_core_alloc_priv(dh_dev, sizeof(*pf_dev));
- if (!pf_dev)
- return -ENOMEM;
+ if (!pf_dev) {
+ LOG_ERR(dh_dev, "zxdh_pf_dev alloc failed\n");
+ goto err_pf_dev;
+ }
pf_dev->bar_chan_valid = false;
pf_dev->vepa = false;
@@ -109,10 +126,17 @@ static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&pf_dev->irq_lock);
dh_dev->coredev_type = GET_COREDEV_TYPE(pdev);
+ LOG_DEBUG(dh_dev, "%s device: %s\n",
+ (dh_dev->coredev_type == DH_COREDEV_PF) ? "PF" : "VF",
+ pci_name(pdev));
ret = dh_pf_pci_init(dh_dev);
- if (ret)
+ if (ret) {
+ LOG_ERR(dh_dev, "dh_pf_pci_init failed: %d\n", ret);
goto err_cfg_init;
+ }
+
+ LOG_INFO(dh_dev, "pf level completed\n");
return 0;
@@ -120,6 +144,7 @@ static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_destroy(&pf_dev->irq_lock);
mutex_destroy(&dh_dev->lock);
dh_core_free_priv(dh_dev);
+err_pf_dev:
devlink_free(devlink);
return -EPERM;
}
@@ -130,12 +155,16 @@ static void dh_pf_remove(struct pci_dev *pdev)
struct devlink *devlink = priv_to_devlink(dh_dev);
struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ LOG_INFO(dh_dev, "pf level start\n");
+
dh_pf_pci_close(dh_dev);
mutex_destroy(&pf_dev->irq_lock);
mutex_destroy(&dh_dev->lock);
dh_core_free_priv(dh_dev);
devlink_free(devlink);
pci_set_drvdata(pdev, NULL);
+
+ LOG_INFO(dh_dev, "pf level completed\n");
}
static void dh_pf_shutdown(struct pci_dev *pdev)
@@ -144,6 +173,8 @@ static void dh_pf_shutdown(struct pci_dev *pdev)
struct devlink *devlink = priv_to_devlink(dh_dev);
struct zxdh_pf_device *pf_dev = dh_dev->priv;
+ LOG_INFO(dh_dev, "pf level start\n");
+
dh_pf_pci_close(dh_dev);
mutex_destroy(&pf_dev->irq_lock);
mutex_destroy(&dh_dev->lock);
@@ -151,6 +182,8 @@ static void dh_pf_shutdown(struct pci_dev *pdev)
devlink_free(devlink);
pci_set_drvdata(pdev, NULL);
+
+ LOG_INFO(dh_dev, "pf level completed\n");
}
static struct pci_driver dh_pf_driver = {
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 17344 bytes --]
^ permalink raw reply related
* [PATCH net-next v3 3/3] net/ethernet/zte/dinghai: add hardware register access and PCI capability scanning
From: Junyang Han @ 2026-04-30 15:11 UTC (permalink / raw)
To: andrew+netdev
Cc: netdev, vadim.fedorenko, davem, edumazet, kuba, pabeni,
han.junyang, ran.ming, han.chengfei, zhang.yanze
In-Reply-To: <20260430151138.2813381-1-han.junyang@zte.com.cn>
[-- Attachment #1.1.1: Type: text/plain, Size: 19448 bytes --]
Implement PCI configuration space access, BAR mapping, capability
scanning (common/notify/device), and hardware queue register
definitions for DingHai PF device.
Signed-off-by: Junyang Han <han.junyang@zte.com.cn>
---
drivers/net/ethernet/zte/dinghai/dh_queue.h | 71 ++++
drivers/net/ethernet/zte/dinghai/en_pf.c | 446 +++++++++++++++++++-
drivers/net/ethernet/zte/dinghai/en_pf.h | 38 ++
3 files changed, 552 insertions(+), 3 deletions(-)
create mode 100644 drivers/net/ethernet/zte/dinghai/dh_queue.h
diff --git a/drivers/net/ethernet/zte/dinghai/dh_queue.h b/drivers/net/ethernet/zte/dinghai/dh_queue.h
new file mode 100644
index 000000000000..5067c73fed33
--- /dev/null
+++ b/drivers/net/ethernet/zte/dinghai/dh_queue.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ZTE DingHai Ethernet driver - PCI capability definitions
+ * Copyright (c) 2022-2026, ZTE Corporation.
+ */
+
+#ifndef __DH_QUEUE_H__
+#define __DH_QUEUE_H__
+
+/* Vector value used to disable MSI for queue */
+#define ZXDH_MSI_NO_VECTOR 0xff
+
+/* Status byte for guest to report progress, and synchronize features */
+/* We have seen device and processed generic fields */
+#define ZXDH_CONFIG_S_ACKNOWLEDGE 1
+/* We have found a driver for the device. */
+#define ZXDH_CONFIG_S_DRIVER 2
+/* Driver has used its parts of the config, and is happy */
+#define ZXDH_CONFIG_S_DRIVER_OK 4
+/* Driver has finished configuring features */
+#define ZXDH_CONFIG_S_FEATURES_OK 8
+/* Device entered invalid state, driver must reset it */
+#define ZXDH_CONFIG_S_NEEDS_RESET 0x40
+/* We've given up on this device */
+#define ZXDH_CONFIG_S_FAILED 0x80
+
+/* This is the PCI capability header: */
+struct zxdh_pf_pci_cap {
+ __u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
+ __u8 cap_next; /* Generic PCI field: next ptr. */
+ __u8 cap_len; /* Generic PCI field: capability length */
+ __u8 cfg_type; /* Identifies the structure. */
+ __u8 bar; /* Where to find it. */
+ __u8 id; /* Multiple capabilities of the same type */
+ __u8 padding[2]; /* Pad to full dword. */
+ __le32 offset; /* Offset within bar. */
+ __le32 length; /* Length of the structure, in bytes. */
+};
+
+/* Fields in ZXDH_PF_PCI_CAP_COMMON_CFG: */
+struct zxdh_pf_pci_common_cfg {
+ /* About the whole device. */
+ __le32 device_feature_select; /* read-write */
+ __le32 device_feature; /* read-only */
+ __le32 guest_feature_select; /* read-write */
+ __le32 guest_feature; /* read-write */
+ __le16 msix_config; /* read-write */
+ __le16 num_queues; /* read-only */
+ __u8 device_status; /* read-write */
+ __u8 config_generation; /* read-only */
+
+ /* About a specific virtqueue. */
+ __le16 queue_select; /* read-write */
+ __le16 queue_size; /* read-write, power of 2. */
+ __le16 queue_msix_vector; /* read-write */
+ __le16 queue_enable; /* read-write */
+ __le16 queue_notify_off; /* read-only */
+ __le32 queue_desc_lo; /* read-write */
+ __le32 queue_desc_hi; /* read-write */
+ __le32 queue_avail_lo; /* read-write */
+ __le32 queue_avail_hi; /* read-write */
+ __le32 queue_used_lo; /* read-write */
+ __le32 queue_used_hi; /* read-write */
+};
+
+struct zxdh_pf_pci_notify_cap {
+ struct zxdh_pf_pci_cap cap;
+ __le32 notify_off_multiplier; /* Multiplier for queue_notify_off. */
+};
+
+#endif /* __DH_QUEUE_H__ */
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.c b/drivers/net/ethernet/zte/dinghai/en_pf.c
index f4a923b76037..211893b2f8e3 100644
--- a/drivers/net/ethernet/zte/dinghai/en_pf.c
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.c
@@ -9,6 +9,7 @@
#include <net/devlink.h>
#include "en_pf.h"
#include "dh_log.h"
+#include "dh_queue.h"
MODULE_AUTHOR("Junyang Han <han.junyang@zte.com.cn>");
MODULE_DESCRIPTION("ZTE DingHai series Ethernet driver");
@@ -64,7 +65,7 @@ static int dh_pf_pci_init(struct dh_core_dev *dev)
pf_dev = dev->priv;
pf_dev->pci_ioremap_addr[0] =
ioremap(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0));
+ pci_resource_len(dev->pdev, 0));
if (!pf_dev->pci_ioremap_addr[0]) {
ret = -ENOMEM;
LOG_ERR(dev, "ioremap(0x%llx, 0x%llx) failed\n",
@@ -77,7 +78,7 @@ static int dh_pf_pci_init(struct dh_core_dev *dev)
err_pci_save_state:
pci_release_selected_regions(dev->pdev,
- pci_select_bars(dev->pdev, IORESOURCE_MEM));
+ pci_select_bars(dev->pdev, IORESOURCE_MEM));
err_pci:
pci_disable_device(dev->pdev);
return ret;
@@ -90,10 +91,449 @@ void dh_pf_pci_close(struct dh_core_dev *dev)
pf_dev = dev->priv;
iounmap(pf_dev->pci_ioremap_addr[0]);
pci_release_selected_regions(dev->pdev,
- pci_select_bars(dev->pdev, IORESOURCE_MEM));
+ pci_select_bars(dev->pdev, IORESOURCE_MEM));
pci_disable_device(dev->pdev);
}
+int zxdh_pf_pci_find_capability(struct pci_dev *pdev, u8 cfg_type,
+ u32 ioresource_types, int *bars)
+{
+ int pos;
+ u8 type;
+ u8 bar;
+
+ for (pos = pci_find_capability(pdev, PCI_CAP_ID_VNDR); pos > 0;
+ pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_VNDR)) {
+ pci_read_config_byte(pdev,
+ pos + offsetof(struct zxdh_pf_pci_cap,
+ cfg_type), &type);
+ pci_read_config_byte(pdev,
+ pos + offsetof(struct zxdh_pf_pci_cap, bar), &bar);
+
+ /* ignore structures with reserved BAR values */
+ if (bar > ZXDH_PF_MAX_BAR_VAL)
+ continue;
+
+ if (type == cfg_type) {
+ if (pci_resource_len(pdev, bar) &&
+ pci_resource_flags(pdev, bar) & ioresource_types) {
+ *bars |= (1 << bar);
+ return pos;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void __iomem *zxdh_pf_map_capability(struct dh_core_dev *dh_dev, int off,
+ size_t minlen, u32 align,
+ u32 start, u32 size,
+ size_t *len, resource_size_t *pa,
+ u32 *bar_off)
+{
+ struct pci_dev *pdev = dh_dev->pdev;
+ void __iomem *p;
+ u32 offset;
+ u32 length;
+ u8 bar;
+
+ pci_read_config_byte(pdev,
+ off + offsetof(struct zxdh_pf_pci_cap, bar), &bar);
+ pci_read_config_dword(pdev,
+ off + offsetof(struct zxdh_pf_pci_cap,
+ offset), &offset);
+ pci_read_config_dword(pdev,
+ off + offsetof(struct zxdh_pf_pci_cap,
+ length), &length);
+
+ if (bar_off)
+ *bar_off = offset;
+
+ if (length <= start) {
+ LOG_ERR(dh_dev, "bad capability len %u (>%u expected)\n",
+ length, start);
+ return NULL;
+ }
+
+ if (length - start < minlen) {
+ LOG_ERR(dh_dev, "bad capability len %u (>=%zu expected)\n",
+ length, minlen);
+ return NULL;
+ }
+
+ length -= start;
+ if (start + offset < offset) {
+ LOG_ERR(dh_dev, "map wrap-around %u+%u\n", start, offset);
+ return NULL;
+ }
+
+ offset += start;
+ if (offset & (align - 1)) {
+ LOG_ERR(dh_dev, "offset %u not aligned to %u\n", offset, align);
+ return NULL;
+ }
+
+ if (length > size)
+ length = size;
+
+ if (len)
+ *len = length;
+
+ if (minlen + offset < minlen ||
+ minlen + offset > pci_resource_len(pdev, bar)) {
+ LOG_ERR(dh_dev,
+ "map custom queue %zu@%u out of range on bar %i length %lu\n",
+ minlen, offset, bar,
+ (unsigned long)pci_resource_len(pdev, bar));
+ return NULL;
+ }
+
+ p = pci_iomap_range(pdev, bar, offset, length);
+ if (!p) {
+ LOG_ERR(dh_dev, "unable to map custom queue %u@%u on bar %i\n",
+ length, offset, bar);
+ } else if (pa) {
+ *pa = pci_resource_start(pdev, bar) + offset;
+ }
+
+ return p;
+}
+
+int zxdh_pf_common_cfg_init(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+ int common;
+
+ /* check for a common config: if not, use legacy mode (bar 0). */
+ common = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_COMMON_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM,
+ &pf_dev->modern_bars);
+ if (common == 0) {
+ LOG_ERR(dh_dev,
+ "missing capabilities %i, leaving for legacy driver\n",
+ common);
+ return -ENODEV;
+ }
+
+ pf_dev->common = zxdh_pf_map_capability(dh_dev, common,
+ sizeof(struct zxdh_pf_pci_common_cfg),
+ ZXDH_PF_ALIGN4, 0,
+ sizeof(struct zxdh_pf_pci_common_cfg),
+ NULL, NULL, NULL);
+ if (!pf_dev->common) {
+ LOG_ERR(dh_dev, "pf_dev->common is null\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int zxdh_pf_notify_cfg_init(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+ size_t notify_length;
+ size_t notify_offset;
+ int notify;
+
+ /* If common is there, these should be too... */
+ notify = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_NOTIFY_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM,
+ &pf_dev->modern_bars);
+ if (notify == 0) {
+ LOG_ERR(dh_dev, "missing capabilities %i\n", notify);
+ return -EINVAL;
+ }
+
+ pci_read_config_dword(pdev,
+ notify + offsetof(struct zxdh_pf_pci_notify_cap,
+ notify_off_multiplier),
+ &pf_dev->notify_offset_multiplier);
+ pci_read_config_dword(pdev,
+ notify + offsetof(struct zxdh_pf_pci_notify_cap,
+ cap.length), ¬ify_length);
+ pci_read_config_dword(pdev,
+ notify + offsetof(struct zxdh_pf_pci_notify_cap,
+ cap.offset), ¬ify_offset);
+
+ /* We don't know how many VQs we'll map, ahead of the time.
+ * If notify length is small, map it all now. Otherwise,
+ * map each VQ individually later.
+ */
+ if (notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) {
+ pf_dev->notify_base = zxdh_pf_map_capability(dh_dev, notify,
+ ZXDH_PF_MAP_MINLEN2,
+ ZXDH_PF_ALIGN2, 0,
+ notify_length,
+ &pf_dev->notify_len,
+ &pf_dev->notify_pa, NULL);
+ if (!pf_dev->notify_base) {
+ LOG_ERR(dh_dev, "pf_dev->notify_base is null\n");
+ return -EINVAL;
+ }
+ } else {
+ pf_dev->notify_map_cap = notify;
+ }
+
+ return 0;
+}
+
+int zxdh_pf_device_cfg_init(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+ int device;
+
+ /* Device capability is only mandatory for
+ * devices that have device-specific configuration.
+ */
+ device = zxdh_pf_pci_find_capability(pdev, ZXDH_PCI_CAP_DEVICE_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM,
+ &pf_dev->modern_bars);
+
+ /* we don't know how much we should map,
+ * but PAGE_SIZE is more than enough for all existing devices.
+ */
+ if (device) {
+ pf_dev->device = zxdh_pf_map_capability(dh_dev, device, 0,
+ ZXDH_PF_ALIGN4, 0, PAGE_SIZE,
+ &pf_dev->device_len, NULL,
+ &pf_dev->dev_cfg_bar_off);
+ if (!pf_dev->device) {
+ LOG_ERR(dh_dev, "pf_dev->device is null\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+void zxdh_pf_modern_cfg_uninit(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+
+ if (pf_dev->device)
+ pci_iounmap(pdev, pf_dev->device);
+ if (pf_dev->notify_base)
+ pci_iounmap(pdev, pf_dev->notify_base);
+ pci_iounmap(pdev, pf_dev->common);
+}
+
+int zxdh_pf_modern_cfg_init(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ struct pci_dev *pdev = dh_dev->pdev;
+ int ret;
+
+ ret = zxdh_pf_common_cfg_init(dh_dev);
+ if (ret) {
+ LOG_ERR(dh_dev, "zxdh_pf_common_cfg_init failed: %d\n", ret);
+ return -EINVAL;
+ }
+
+ ret = zxdh_pf_notify_cfg_init(dh_dev);
+ if (ret) {
+ LOG_ERR(dh_dev, "zxdh_pf_notify_cfg_init failed: %d\n", ret);
+ goto err_map_notify;
+ }
+
+ ret = zxdh_pf_device_cfg_init(dh_dev);
+ if (ret) {
+ LOG_ERR(dh_dev, "zxdh_pf_device_cfg_init failed: %d\n", ret);
+ goto err_map_device;
+ }
+
+ return 0;
+
+err_map_device:
+ if (pf_dev->notify_base)
+ pci_iounmap(pdev, pf_dev->notify_base);
+err_map_notify:
+ pci_iounmap(pdev, pf_dev->common);
+ return -EINVAL;
+}
+
+u16 zxdh_pf_get_queue_notify_off(struct dh_core_dev *dh_dev,
+ u16 phy_index, u16 index)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ if (pf_dev->packed_status)
+ iowrite16(phy_index, &pf_dev->common->queue_select);
+ else
+ iowrite16(index, &pf_dev->common->queue_select);
+
+ return ioread16(&pf_dev->common->queue_notify_off);
+}
+
+void __iomem *zxdh_pf_map_vq_notify(struct dh_core_dev *dh_dev,
+ u16 phy_index, u16 index,
+ resource_size_t *pa)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ u16 off;
+
+ off = zxdh_pf_get_queue_notify_off(dh_dev, phy_index, index);
+
+ if (pf_dev->notify_base) {
+ /* offset should not wrap */
+ if ((u64)off *
+ pf_dev->notify_offset_multiplier + 2 > pf_dev->notify_len) {
+ LOG_ERR(dh_dev,
+ "bad notification offset %u (x %u) for queue %u > %zd",
+ off, pf_dev->notify_offset_multiplier, phy_index,
+ pf_dev->notify_len);
+ return NULL;
+ }
+
+ if (pa)
+ *pa = pf_dev->notify_pa + off * pf_dev->notify_offset_multiplier;
+
+ return pf_dev->notify_base + off * pf_dev->notify_offset_multiplier;
+ } else {
+ return zxdh_pf_map_capability(dh_dev, pf_dev->notify_map_cap, 2, 2,
+ off * pf_dev->notify_offset_multiplier,
+ 2, NULL, pa, NULL);
+ }
+}
+
+void zxdh_pf_unmap_vq_notify(struct dh_core_dev *dh_dev, void *priv)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ if (!pf_dev->notify_base)
+ pci_iounmap(dh_dev->pdev, priv);
+}
+
+void zxdh_pf_set_status(struct dh_core_dev *dh_dev, u8 status)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ iowrite8(status, &pf_dev->common->device_status);
+}
+
+u8 zxdh_pf_get_status(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ return ioread8(&pf_dev->common->device_status);
+}
+
+static u8 zxdh_pf_get_cfg_gen(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ u8 config_generation;
+
+ config_generation = ioread8(&pf_dev->common->config_generation);
+ LOG_INFO(dh_dev, "config_generation is %d\n", config_generation);
+
+ return config_generation;
+}
+
+void zxdh_pf_get_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ u32 DEV_MAC_L;
+ u16 DEV_MAC_H;
+
+ if (pf_dev->pf_sriov_cap_base) {
+ DEV_MAC_L = ioread32(pf_dev->pf_sriov_cap_base +
+ (pf_dev->sriov_bar_size) * vf_id +
+ pf_dev->dev_cfg_bar_off);
+ mac[0] = DEV_MAC_L & 0xff;
+ mac[1] = (DEV_MAC_L >> 8) & 0xff;
+ mac[2] = (DEV_MAC_L >> 16) & 0xff;
+ mac[3] = (DEV_MAC_L >> 24) & 0xff;
+ DEV_MAC_H = ioread16(pf_dev->pf_sriov_cap_base +
+ (pf_dev->sriov_bar_size) * vf_id +
+ pf_dev->dev_cfg_bar_off +
+ ZXDH_DEV_MAC_HIGH_OFFSET);
+ mac[4] = DEV_MAC_H & 0xff;
+ mac[5] = (DEV_MAC_H >> 8) & 0xff;
+ }
+}
+
+void zxdh_pf_set_vf_mac_reg(struct zxdh_pf_device *pf_dev,
+ u8 *mac, int vf_id)
+{
+ u32 DEV_MAC_L;
+ u16 DEV_MAC_H;
+
+ if (pf_dev->pf_sriov_cap_base) {
+ DEV_MAC_L = mac[0] | (mac[1] << 8) |
+ (mac[2] << 16) | (mac[3] << 24);
+ DEV_MAC_H = mac[4] | (mac[5] << 8);
+ iowrite32(DEV_MAC_L, (pf_dev->pf_sriov_cap_base +
+ (pf_dev->sriov_bar_size) * vf_id +
+ pf_dev->dev_cfg_bar_off));
+ iowrite16(DEV_MAC_H, (pf_dev->pf_sriov_cap_base +
+ (pf_dev->sriov_bar_size) * vf_id +
+ pf_dev->dev_cfg_bar_off +
+ ZXDH_DEV_MAC_HIGH_OFFSET));
+ }
+}
+
+void zxdh_pf_set_vf_mac(struct dh_core_dev *dh_dev, u8 *mac, int vf_id)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ zxdh_pf_set_vf_mac_reg(pf_dev, mac, vf_id);
+}
+
+void zxdh_set_mac(struct dh_core_dev *dh_dev, u8 *mac)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ u32 DEV_MAC_L;
+ u16 DEV_MAC_H;
+
+ DEV_MAC_L = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
+ DEV_MAC_H = mac[4] | (mac[5] << 8);
+ iowrite32(DEV_MAC_L, pf_dev->device);
+ iowrite16(DEV_MAC_H, pf_dev->device + ZXDH_DEV_MAC_HIGH_OFFSET);
+}
+
+void zxdh_get_mac(struct dh_core_dev *dh_dev, u8 *mac)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ u32 DEV_MAC_L;
+ u16 DEV_MAC_H;
+
+ DEV_MAC_L = ioread32(pf_dev->device);
+ mac[0] = DEV_MAC_L & 0xff;
+ mac[1] = (DEV_MAC_L >> 8) & 0xff;
+ mac[2] = (DEV_MAC_L >> 16) & 0xff;
+ mac[3] = (DEV_MAC_L >> 24) & 0xff;
+ DEV_MAC_H = ioread16(pf_dev->device + ZXDH_DEV_MAC_HIGH_OFFSET);
+ mac[4] = DEV_MAC_H & 0xff;
+ mac[5] = (DEV_MAC_H >> 8) & 0xff;
+}
+
+u64 zxdh_pf_get_features(struct dh_core_dev *dh_dev)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+ u64 device_feature;
+
+ iowrite32(0, &pf_dev->common->device_feature_select);
+ device_feature = ioread32(&pf_dev->common->device_feature);
+ iowrite32(1, &pf_dev->common->device_feature_select);
+ device_feature |= ((u64)ioread32(&pf_dev->common->device_feature)
+ << 32);
+
+ return device_feature;
+}
+
+void zxdh_pf_set_features(struct dh_core_dev *dh_dev, u64 features)
+{
+ struct zxdh_pf_device *pf_dev = dh_core_priv(dh_dev);
+
+ iowrite32(0, &pf_dev->common->guest_feature_select);
+ iowrite32((u32)features, &pf_dev->common->guest_feature);
+ iowrite32(1, &pf_dev->common->guest_feature_select);
+ iowrite32(features >> 32, &pf_dev->common->guest_feature);
+}
+
static int dh_pf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct dh_core_dev *dh_dev;
diff --git a/drivers/net/ethernet/zte/dinghai/en_pf.h b/drivers/net/ethernet/zte/dinghai/en_pf.h
index 0c47f3a38a9d..33e3c957e3a3 100644
--- a/drivers/net/ethernet/zte/dinghai/en_pf.h
+++ b/drivers/net/ethernet/zte/dinghai/en_pf.h
@@ -15,6 +15,24 @@
#define ZXDH_PF_DEVICE_ID 0x8040
#define ZXDH_VF_DEVICE_ID 0x8041
+/* Common configuration */
+#define ZXDH_PCI_CAP_COMMON_CFG 1
+/* Notifications */
+#define ZXDH_PCI_CAP_NOTIFY_CFG 2
+/* ISR access */
+#define ZXDH_PCI_CAP_ISR_CFG 3
+/* Device specific configuration */
+#define ZXDH_PCI_CAP_DEVICE_CFG 4
+/* PCI configuration access */
+#define ZXDH_PCI_CAP_PCI_CFG 5
+
+#define ZXDH_PF_MAX_BAR_VAL 0x5
+#define ZXDH_PF_ALIGN4 4
+#define ZXDH_PF_ALIGN2 2
+#define ZXDH_PF_MAP_MINLEN2 2
+
+#define ZXDH_DEV_MAC_HIGH_OFFSET 4
+
enum dh_coredev_type {
DH_COREDEV_PF,
DH_COREDEV_VF,
@@ -34,7 +52,27 @@ struct dh_core_dev {
};
struct zxdh_pf_device {
+ struct zxdh_pf_pci_common_cfg __iomem *common;
+ /* Device-specific data (non-legacy mode) */
+ /* Base of vq notifications (non-legacy mode). */
+ void __iomem *device;
+ void __iomem *notify_base;
+ void __iomem *pf_sriov_cap_base;
+ /* Physical base of vq notifications */
+ resource_size_t notify_pa;
+ /* So we can sanity-check accesses. */
+ size_t notify_len;
+ size_t device_len;
+ /* Capability for when we need to map notifications per-vq. */
+ s32 notify_map_cap;
+ u32 notify_offset_multiplier;
+ /* Multiply queue_notify_off by this value. (non-legacy mode). */
+ s32 modern_bars;
+
void __iomem *pci_ioremap_addr[6];
+ u64 sriov_bar_size;
+ u32 dev_cfg_bar_off;
+ bool packed_status;
bool bar_chan_valid;
bool vepa;
struct mutex irq_lock; /* Protects IRQ operations */
--
2.27.0
[-- Attachment #1.1.2: Type: text/html , Size: 49437 bytes --]
^ permalink raw reply related
* Re: [PATCH iwl-net v1 2/2] ice: use NETIF_F_HW_CSUM instead of IP/IPV6
From: Simon Horman @ 2026-04-30 15:29 UTC (permalink / raw)
To: michal.swiatkowski
Cc: 'Simon Horman', intel-wired-lan, netdev, jramaseu,
anthony.l.nguyen, przemyslaw.kitszel, aleksandr.loktionov
In-Reply-To: <20260428070647.777141-3-michal.swiatkowski@linux.intel.com>
From: 'Simon Horman' <horms@kernel.org>
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
---
ice: use NETIF_F_HW_CSUM instead of IP/IPV6
This commit replaces the IP and IPV6 checksum offload flags with HW_CSUM
in the ice driver to allow hardware checksumming for IPv6 packets with
extension headers. It also removes the mutual exclusivity check between
TSO and GCS.
> diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
> index 5f92377d4dfc..33f252a6a22f 100644
> --- a/drivers/net/ethernet/intel/ice/ice_main.c
> +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> @@ -3491,9 +3491,8 @@ void ice_set_netdev_features(struct net_device *netdev)
> NETIF_F_RXHASH;
>
> csumo_features = NETIF_F_RXCSUM |
> - NETIF_F_IP_CSUM |
> NETIF_F_SCTP_CRC |
> - NETIF_F_IPV6_CSUM;
> + NETIF_F_HW_CSUM;
By advertising NETIF_F_HW_CSUM, the network stack assumes the driver can handle
checksums for any protocol and passes non-IP packets (e.g., from AF_PACKET
injected frames) to the driver with CHECKSUM_PARTIAL.
Since ice_tx_csum() strictly parses the L3 header and expects IPv4 or IPv6,
returning -1 for other protocols, will this regression cause non-IP packets to
be silently dropped instead of falling back to software checksums in the kernel?
Additionally, skb_csum_hwoffload_help() relies on NETIF_F_IPV6_CSUM to
safely fall back to software checksums when IPv6 extension headers are
present.
Does using NETIF_F_HW_CSUM bypass this safeguard, potentially causing
legacy hardware (like E810) or E830 without GCS descriptors to compute
incorrect pseudo-headers and silently corrupt IPv6 packets with extension
headers?
Finally, for protocols other than TCP, UDP, or SCTP, the driver falls back to
calling skb_checksum_help(skb) in the default case of ice_tx_csum().
However, the driver appears to ignore the return value of skb_checksum_help().
If skb_checksum_help() fails (e.g., due to -ENOMEM during pskb_expand_head()),
could this result in the packet being transmitted with an uncomputed checksum?
^ permalink raw reply
* Re: [RFC PATCH net-next 0/3] netns: optionally inherit IPv4 TCP sysctls from old net
From: Nicolas Dichtel @ 2026-04-30 15:44 UTC (permalink / raw)
To: nmreadelf, davem, edumazet, kuba, pabeni, corbet, dsahern
Cc: horms, chia-yu.chang, idosch, ij, brauner, jack, kuniyu, jlayton,
netdev, linux-doc, linux-kernel, lance.yang, leon.hwang
In-Reply-To: <TY7PR01MB172057C053E8D550485A29A08E0352@TY7PR01MB17205.jpnprd01.prod.outlook.com>
Le 30/04/2026 à 03:30, nmreadelf a écrit :
> a new network namespace starts with built-in TCP defaults.
> In container-heavy setups, operators often tune TCP sysctls in init_net and then
> need to re-apply the same values for each new netns.
>
> This series adds an opt-in mechanism to initialize per-netns IPv4 TCP sysctl
> settings from init_net at netns creation time.
>
> Behavior:
>
> Default is unchanged.
> When net.ipv4.netns_inherit_tcp_sysctls=1, new netns inherit
> TCP sysctl from old_net.
There is the same kind of sysctl for net.{ipv4,ipv6}.conf.{all,default}.*:
net.core.devconf_inherit_init_net.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/sysctl/net.rst#n401
I'm not sure if it's acceptable to use this existing entry to control the TCP
sysctl.
At least, putting the new one in the same place + using the same template for
the name + the same values would be nice. Something like
net.core.tcp_inherit_init_net.
Regards,
Nicolas
^ permalink raw reply
* Re: [PATCH iproute2-next] tc: use ll_init_map() only when needed
From: Jamal Hadi Salim @ 2026-04-30 15:45 UTC (permalink / raw)
To: David Ahern
Cc: Eric Dumazet, Stephen Hemminger, David S . Miller, Jakub Kicinski,
Paolo Abeni, netdev, eric.dumazet
In-Reply-To: <18134b6e-8944-49f4-9bb0-2903aa00d28a@kernel.org>
On Thu, Apr 30, 2026 at 11:36 AM David Ahern <dsahern@kernel.org> wrote:
>
> Jamal: waiting for your review ...
>
Looks good - running tdc on it to make sure nothing breaks...
cheers,
jamal
> On 4/28/26 2:28 AM, Eric Dumazet wrote:
> > Some setups can have thousands of devices.
> >
> > ll_init_map() is rather expensive for them.
> >
> > Only call ll_init_map() in the following cases:
> >
> > 1) tc runs in batch mode.
> > 2) tc runs in monitor mode.
> > 3) tc dumps qdiscs/classes/filters for all netdev.
> >
> > This greatly reduces RTNL pressure on common operations.
> >
> > Signed-off-by: Eric Dumazet <edumazet@google.com>
> > ---
> > tc/f_route.c | 1 -
> > tc/m_mirred.c | 2 --
> > tc/tc.c | 1 +
> > tc/tc_class.c | 6 ++----
> > tc/tc_filter.c | 32 ++++++++++++++++----------------
> > tc/tc_qdisc.c | 5 ++---
> > 6 files changed, 21 insertions(+), 26 deletions(-)
> >
> > diff --git a/tc/f_route.c b/tc/f_route.c
> > index 96b99b06be179c90dfb0d24d9577b5206dd98ef1..c234ddf0cb9309556844c85047d0f9ef53a2fd7b 100644
> > --- a/tc/f_route.c
> > +++ b/tc/f_route.c
> > @@ -76,7 +76,6 @@ static int route_parse_opt(const struct filter_util *qu, char *handle, int argc,
> > __u32 id;
> >
> > NEXT_ARG();
> > - ll_init_map(&rth);
> > if ((id = ll_name_to_index(*argv)) <= 0) {
> > fprintf(stderr, "Illegal \"fromif\"\n");
> > return -1;
> > diff --git a/tc/m_mirred.c b/tc/m_mirred.c
> > index f4da3c76284460d7f4bb73c7c3c172732f054632..e9ae5199432e828026f15ce226c5f5f84998c660 100644
> > --- a/tc/m_mirred.c
> > +++ b/tc/m_mirred.c
> > @@ -213,8 +213,6 @@ parse_direction(const struct action_util *a, int *argc_p, char ***argv_p,
> > if (d[0]) {
> > int idx;
> >
> > - ll_init_map(&rth);
> > -
> > idx = ll_name_to_index(d);
> > if (!idx)
> > return nodev(d);
> > diff --git a/tc/tc.c b/tc/tc.c
> > index 0fc658c881f0f553f1f1f8d87b46943d4d0eed8f..7d69e4d533a98b9c071cb954443a049a52252f2c 100644
> > --- a/tc/tc.c
> > +++ b/tc/tc.c
> > @@ -243,6 +243,7 @@ static int batch(const char *name)
> > return -1;
> > }
> >
> > + ll_init_map(&rth);
> > ret = do_batch(name, force, tc_batch_cmd, NULL);
> >
> > rtnl_close(&rth);
> > diff --git a/tc/tc_class.c b/tc/tc_class.c
> > index 6d707d8c924f4b5e90201d4de8e9779f82ce17f3..9aace019e6c8b96fb51edb4fe89bea5b7469beed 100644
> > --- a/tc/tc_class.c
> > +++ b/tc/tc_class.c
> > @@ -136,11 +136,11 @@ static int tc_class_modify(int cmd, unsigned int flags, int argc, char **argv)
> > }
> >
> > if (d[0]) {
> > - ll_init_map(&rth);
> > -
> > req.t.tcm_ifindex = ll_name_to_index(d);
> > if (!req.t.tcm_ifindex)
> > return -nodev(d);
> > + } else {
> > + ll_init_map(&rth);
> > }
> >
> > if (rtnl_talk(&rth, &req.n, NULL) < 0)
> > @@ -437,8 +437,6 @@ static int tc_class_list(int argc, char **argv)
> > argc--; argv++;
> > }
> >
> > - ll_init_map(&rth);
> > -
> > if (d[0]) {
> > t.tcm_ifindex = ll_name_to_index(d);
> > if (!t.tcm_ifindex)
> > diff --git a/tc/tc_filter.c b/tc/tc_filter.c
> > index 7db850bda11a3408ec66b457c9fc590f3a734f65..be70e360849e5058192640da0f061810a99e2ea8 100644
> > --- a/tc/tc_filter.c
> > +++ b/tc/tc_filter.c
> > @@ -188,16 +188,17 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
> > addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
> >
> > if (d[0]) {
> > - ll_init_map(&rth);
> > -
> > req.t.tcm_ifindex = ll_name_to_index(d);
> > if (req.t.tcm_ifindex == 0) {
> > fprintf(stderr, "Cannot find device \"%s\"\n", d);
> > return 1;
> > }
> > - } else if (block_index) {
> > - req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
> > - req.t.tcm_block_index = block_index;
> > + } else {
> > + ll_init_map(&rth);
> > + if (block_index) {
> > + req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
> > + req.t.tcm_block_index = block_index;
> > + }
> > }
> >
> > if (q) {
> > @@ -539,8 +540,6 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
> > }
> >
> > if (d[0]) {
> > - ll_init_map(&rth);
> > -
> > req.t.tcm_ifindex = ll_name_to_index(d);
> > if (!req.t.tcm_ifindex)
> > return -nodev(d);
> > @@ -704,21 +703,22 @@ static int tc_filter_list(int cmd, int argc, char **argv)
> >
> > req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
> >
> > - ll_init_map(&rth);
> > -
> > if (d[0]) {
> > req.t.tcm_ifindex = ll_name_to_index(d);
> > if (!req.t.tcm_ifindex)
> > return -nodev(d);
> > filter_ifindex = req.t.tcm_ifindex;
> > - } else if (block_index) {
> > - if (!tc_qdisc_block_exists(block_index)) {
> > - fprintf(stderr, "Cannot find block \"%u\"\n", block_index);
> > - return 1;
> > + } else {
> > + ll_init_map(&rth);
> > + if (block_index) {
> > + if (!tc_qdisc_block_exists(block_index)) {
> > + fprintf(stderr, "Cannot find block \"%u\"\n", block_index);
> > + return 1;
> > + }
> > + req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
> > + req.t.tcm_block_index = block_index;
> > + filter_block_index = block_index;
> > }
> > - req.t.tcm_ifindex = TCM_IFINDEX_MAGIC_BLOCK;
> > - req.t.tcm_block_index = block_index;
> > - filter_block_index = block_index;
> > }
> >
> > if (filter_chain_index_set)
> > diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c
> > index 7eb9a31baa31fb91a8141c9eca1135e76a52fa8b..252ea861f249a5a71cf782389776e68c3e48c6cc 100644
> > --- a/tc/tc_qdisc.c
> > +++ b/tc/tc_qdisc.c
> > @@ -193,8 +193,6 @@ static int tc_qdisc_modify(int cmd, unsigned int flags, int argc, char **argv)
> > if (d[0]) {
> > int idx;
> >
> > - ll_init_map(&rth);
> > -
> > idx = ll_name_to_index(d);
> > if (!idx)
> > return -nodev(d);
> > @@ -411,13 +409,14 @@ static int tc_qdisc_list(int argc, char **argv)
> > argc--; argv++;
> > }
> >
> > - ll_init_map(&rth);
> >
> > if (d[0]) {
> > req.t.tcm_ifindex = ll_name_to_index(d);
> > if (!req.t.tcm_ifindex)
> > return -nodev(d);
> > filter_ifindex = req.t.tcm_ifindex;
> > + } else {
> > + ll_init_map(&rth);
> > }
> >
> > if (dump_invisible) {
>
^ permalink raw reply
* Re: [RFC PATCH net-next v6 1/2] net: pppoe: implement GRO/GSO support
From: Qingfang Deng @ 2026-04-30 15:47 UTC (permalink / raw)
To: Paolo Abeni, Felix Fietkau
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
David Ahern, Simon Horman, netdev, linux-kernel, linux-ppp,
Pablo Neira Ayuso
In-Reply-To: <9d7f1bbc-155d-4c18-bcf7-732ebe4cbf67@redhat.com>
On Thu, Apr 30, 2026 at 5:34 PM Paolo Abeni <pabeni@redhat.com> wrote:
>
> AFAICS, when the computed len is >= 64K, and the above min() will
> truncate it, later pppoe_rcv() will drop the packet.
pppoe_rcv() does _not_ drop such packets.
The drop condition is "skb->len < ntohs(ph->length)", not the other way around.
> > + skb = segs;
> > + do {
> > + phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + nhoff);
> > + len = skb->len - (nhoff + sizeof(*phdr));
> > + phdr->length = cpu_to_be16(len);
> > + skb->network_header = (u8 *)phdr - skb->head;
>
> I understand is quite late for the following question, but...
> The network headers points to the pppoe hdr. Should it point to the
> actual IP hdr?
>
> Why not? A comment in the code or in the commit message would be
> appreciated.
I'm not sure about the GSO stuff. This code is carried over from
Felix's v3 patch unmodified and I haven't noticed any issues. Maybe he
has the answer.
FYI, Pablo Neira Ayuso is adding the "inline PPPoE GSO" to Netfilter
flowtable: https://lore.kernel.org/netfilter-devel/20260430055836.223494-2-pablo@netfilter.org/
to work around missing GSO support in PPPoE driver, prior to this
patch.
^ permalink raw reply
* Re: [PATCH RESEND net-next] net/sun: Fix multiple typos in comments
From: Jakub Raczynski @ 2026-04-30 15:49 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev, linux-kernel, kernel-janitors
In-Reply-To: <20260430010322.2326574-1-kuba@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1064 bytes --]
On Wed, Apr 29, 2026 at 06:03:22PM -0700, Jakub Kicinski wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
I should also implement any basic tools or AI to verify my writing skills.
This patch was basically prepared with help of 'typos' script and yet has
errors.
> The "autonogotiation" to "autonegotiation" change looks correct, but
> the neighbouring "in enabled" in the same sentence appears to be a
> leftover grammar slip (should it read "is enabled"?). Since this
> sentence is already being touched as part of the typo cleanup, would
> it make sense to fix that at the same time?
Probably, no reason to not do that. Might be good to also change double spaces
> Neither "imperical" nor "emperical" is a correct English word; the
> intended word is "empirical". Was the replacement here meant to be
> "empirical"?
Writing fail. Funny enough, I had someone read/check this before sending and
it slipped.
Will resend whole patch soon.
Regards
Jakub Raczynski
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [PATCH iproute2-next] man: remove libnetlink man page
From: patchwork-bot+netdevbpf @ 2026-04-30 15:50 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20260427172827.300214-1-stephen@networkplumber.org>
Hello:
This patch was applied to iproute2/iproute2-next.git (main)
by David Ahern <dsahern@kernel.org>:
On Mon, 27 Apr 2026 10:28:27 -0700 you wrote:
> The iproute2 libnetlink is not a public and stable API.
> Having a man page encourages users to think it is available.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> man/Makefile | 2 +-
> man/man3/Makefile | 18 ----
> man/man3/libnetlink.3 | 200 ------------------------------------------
> 3 files changed, 1 insertion(+), 219 deletions(-)
> delete mode 100644 man/man3/Makefile
> delete mode 100644 man/man3/libnetlink.3
Here is the summary with links:
- [iproute2-next] man: remove libnetlink man page
https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=fa2309a9e91e
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH iproute2] lib: add input validation for time, rate, and size parsing functions
From: patchwork-bot+netdevbpf @ 2026-04-30 15:50 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20260421202359.632074-1-stephen@networkplumber.org>
Hello:
This patch was applied to iproute2/iproute2-next.git (main)
by David Ahern <dsahern@kernel.org>:
On Tue, 21 Apr 2026 13:23:59 -0700 you wrote:
> The parsing functions get_time(), get_time64(), get_rate(), get_rate64(),
> and get_size64() use strtod() to convert user input but don't validate
> the parsed values. This allows negative numbers and overflow values to
> be passed through, which can cause unexpected behavior or security issues
> when these values reach the kernel as unsigned integers.
>
> Add validation to reject:
> - Negative values (which make no sense for time, rate, or size)
> - Overflow conditions (when strtod() returns HUGE_VAL with ERANGE)
> - Empty strings (already checked, but now with explicit comments)
>
> [...]
Here is the summary with links:
- [iproute2] lib: add input validation for time, rate, and size parsing functions
https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=c99a85a7c8eb
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [GIT PULL] wireless-2026-04-30
From: Johannes Berg @ 2026-04-30 15:51 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev, linux-wireless
In-Reply-To: <20260430071239.36b0e5f0@kernel.org>
On Thu, 2026-04-30 at 07:12 -0700, Jakub Kicinski wrote:
> On Thu, 30 Apr 2026 13:17:52 +0200 Johannes Berg wrote:
> > So the LLM floodgates are starting to open ;-) But I'm somewhat
> > happy that so far we haven't gotten any really critical reports.
> > Here's a couple of first fixes though.
> >
> > Please pull and let us know if there's any problem.
>
> Looks like this breaks kunit:
>
> ok 70 mac80211-tpe
> KTAP version 1
> # Subtest: mac80211-mlme-chan-mode
> # module: mac80211_tests
> 1..1
> KTAP version 1
> # Subtest: test_determine_chan_mode
> ok 1 Normal case, EHT is working
> ok 2 Requiring EHT support is fine
> ok 3 Lowering the mode limits us
> kunit: required basic rate or BSS membership selectors not supported or disabled, rejecting connection
> ok 4 Requesting a basic rate/selector that we do not support
> ok 5 As before, but userspace says it is taking care of it
> # test_determine_chan_mode: ASSERTION FAILED at net/mac80211/tests/chan-mode.c:258
> Expected conn.mode == params->expected_mode, but
> conn.mode == 5 (0x5)
> params->expected_mode == 1 (0x1)
> not ok 6 Masking out a supported rate in HT capabilities
>
D'oh. Yeah, that's the AP workaround, we'll need to adjust the test. I'm
on my way out right now, so I guess that'll have to wait for next week.
johannes
^ permalink raw reply
* Re: [RFC PATCH net-next v6 1/2] net: pppoe: implement GRO/GSO support
From: Pablo Neira Ayuso @ 2026-04-30 15:57 UTC (permalink / raw)
To: Qingfang Deng
Cc: Paolo Abeni, Felix Fietkau, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, David Ahern, Simon Horman, netdev,
linux-kernel, linux-ppp
In-Reply-To: <CALW65jYB1jWS5LnSxRCrEeCpPfhA8saqbYYfU-LkPh_25gWfsw@mail.gmail.com>
Hi Paolo,
On Thu, Apr 30, 2026 at 11:47:57PM +0800, Qingfang Deng wrote:
> On Thu, Apr 30, 2026 at 5:34 PM Paolo Abeni <pabeni@redhat.com> wrote:
> >
> > AFAICS, when the computed len is >= 64K, and the above min() will
> > truncate it, later pppoe_rcv() will drop the packet.
>
> pppoe_rcv() does _not_ drop such packets.
> The drop condition is "skb->len < ntohs(ph->length)", not the other way around.
>
> > > + skb = segs;
> > > + do {
> > > + phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + nhoff);
> > > + len = skb->len - (nhoff + sizeof(*phdr));
> > > + phdr->length = cpu_to_be16(len);
> > > + skb->network_header = (u8 *)phdr - skb->head;
> >
> > I understand is quite late for the following question, but...
> > The network headers points to the pppoe hdr. Should it point to the
> > actual IP hdr?
This is the same with double-tagged-vlan, the network header also
points to the inner vlan in the skb payload. Changing this would
require to revisit all users in the tree that are already assuming
this.
> > Why not? A comment in the code or in the commit message would be
> > appreciated.
>
> I'm not sure about the GSO stuff. This code is carried over from
> Felix's v3 patch unmodified and I haven't noticed any issues. Maybe he
> has the answer.
>
> FYI, Pablo Neira Ayuso is adding the "inline PPPoE GSO" to Netfilter
> flowtable: https://lore.kernel.org/netfilter-devel/20260430055836.223494-2-pablo@netfilter.org/
> to work around missing GSO support in PPPoE driver, prior to this
> patch.
^ permalink raw reply
* Re: [PATCH net] net: phy: micrel: fix LAN8814 QSGMII soft reset
From: Simon Horman @ 2026-04-30 16:06 UTC (permalink / raw)
To: Robert Marko
Cc: andrew, hkallweit1, linux, davem, edumazet, kuba, pabeni,
Divya.Koppera, horatiu.vultur, netdev, linux-kernel
In-Reply-To: <20260428134138.1741253-1-robert.marko@sartura.hr>
On Tue, Apr 28, 2026 at 03:41:01PM +0200, Robert Marko wrote:
> LAN8814 QSGMII soft reset was moved into the probe function to avoid
> triggering it for each of 4 PHY-s in the package.
>
> However, that broke QSGMII link between the MAC and PHY on most LAN8814
> PHY-s, specificaly for us on the Microchip LAN969x switch.
> Reading the QSGMII status registers it was visible that lanes were only
> partially synced.
>
> It looks like the reset timing is crucial, so lets move the reset back
> into the .config_init function but guard it with phy_package_init_once()
> to avoid it being triggered on each of 4 PHY-s in the package.
> Change the probe function to use phy_package_probe_once() for coma and PtP
> setup.
>
> Fixes: 96a9178a29a6 ("net: phy: micrel: lan8814 fix reset of the QSGMII interface")
> Signed-off-by: Robert Marko <robert.marko@sartura.hr>
FTR: an AI generated review of this patch is available at sashiko.dev.
I believe that both issues flagged there pre-date this patch
and should not block progress of it.
^ permalink raw reply
* Re: [PATCH net] ipvs: fix shift-out-of-bounds in ip_vs_rht_desired_size
From: Simon Horman @ 2026-04-30 16:14 UTC (permalink / raw)
To: Julian Anastasov; +Cc: pablo, fw, lvs-devel, netfilter-devel, netdev
In-Reply-To: <fec8dc99-9611-7311-5ec0-0d5d3895b1cc@ssi.bg>
On Thu, Apr 30, 2026 at 04:10:16PM +0300, Julian Anastasov wrote:
>
> Hello,
>
> On Thu, 30 Apr 2026, Simon Horman wrote:
>
> > From: 'Simon Horman' <horms@kernel.org>
> >
> > 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
> > ---
> > ipvs: fix shift-out-of-bounds in ip_vs_rht_desired_size
> >
> > This commit addresses a shift-out-of-bounds issue when roundup_pow_of_two()
> > is called with 0 in ip_vs_rht_desired_size. It updates the assignment to fall
> > back to 1 if n is 0.
> >
> > > diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
> > > index f5b7a2047291..ea450944465f 100644
> > > --- a/net/netfilter/ipvs/ip_vs_core.c
> > > +++ b/net/netfilter/ipvs/ip_vs_core.c
> > > @@ -237,7 +237,7 @@ int ip_vs_rht_desired_size(struct netns_ipvs *ipvs, struct ip_vs_rht *t, int n,
> > > {
> > > if (!t)
> > > return 1 << min_bits;
> > > - n = roundup_pow_of_two(n);
> > > + n = n ? roundup_pow_of_two(n) : 1;
>
> To overflow it on 64-bit we need 600GB+ memory, the
> conns are ~300 bytes.
>
> In v2 I changed it to n > 0. To solve it completely
> we may need to introduce some kind of "conn_max" sysctl,
> now per-netns. It can help to limit the conns which are
> created GFP_ATOMIC while for other structures we will switch
> to GFP_KERNEL_ACCOUNT.
Thanks, I agree with this approach.
>
> > The parameter n is a signed int. If n happens to be negative, it will evaluate
> > to true and be passed to roundup_pow_of_two().
> >
> > Because roundup_pow_of_two() casts the input to unsigned long, a negative
> > value like -1 becomes ULONG_MAX. This results in a shift exponent of 64,
> > triggering a shift-out-of-bounds regression. Would it be safer to check
> > for n <= 0 instead?
> >
> > Additionally, if n exceeds 1.07 billion (1 << 30) on systems with large
> > amounts of RAM, roundup_pow_of_two(n) evaluates to 1UL << 31. Since n is
> > a 32-bit signed int, assigning 1UL << 31 back to n overflows and results
> > in a negative number.
> >
> > Since subsequent bounds checks use signed comparisons:
> >
> > > if (lfactor < 0) {
> > > int factor = min(-lfactor, max_bits);
> > >
> > > n = min(n, 1 << (max_bits - factor));
> >
> > These checks will fail to constrain the size correctly.
> >
> > [ ... ]
> >
> > > /* Shrink but keep it n * 2 to prevent frequent resizing */
> > > return clamp(n << 1, 1 << min_bits, 1 << max_bits);
> > > }
> >
> > Eventually, the function returns clamp(n << 1, 1 << min_bits, 1 << max_bits).
> > Shifting a negative number causes undefined behavior, and the clamp operation
> > will force the hash table to its absolute minimum size.
> >
> > Could this cause millions of connections to be placed into a minimally sized
> > hash table, causing severe collisions during RCU hash lookups?
>
> All that is valid without conn/mem limits.
Sorry, my previous email was supposed to come with some commentary
that I think that this is a pre-existing issue that can be treated
separately from this patch.
^ permalink raw reply
* Re: [PATCH net-next 0/2] netfilter: conntrack: validate parsed port values in IRC and Amanda helpers
From: Pablo Neira Ayuso @ 2026-04-30 16:18 UTC (permalink / raw)
To: HACKE-RC
Cc: Florian Westphal, Phil Sutter, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, netfilter-devel,
coreteam, netdev, linux-kernel
In-Reply-To: <20260430161230.3438973-1-rc@rexion.ai>
On Thu, Apr 30, 2026 at 09:42:28PM +0530, HACKE-RC wrote:
> Both nf_conntrack_irc and nf_conntrack_amanda parse port numbers from
> application-layer protocol data using simple_strtoul(), which returns
> unsigned long. The results are stored in u16 variables without range
> checks, silently truncating values above 65535.
>
> This series adds explicit upper-bound validation in both helpers.
>
> Note: checkpatch warns about simple_strtoul being obsolete. Both
> call sites use the endptr output parameter to advance the parse
> position, which kstrtoul does not provide. Converting to kstrtoul
> would require restructuring the parsers, which is out of scope for
> this fix.
>
> HACKE-RC (2):
HAHA, this nickname is funny, it is making my day here. Thanks!
> netfilter: nf_conntrack_irc: reject DCC port values above 65535
> netfilter: nf_conntrack_amanda: reject port values above 65535
>
> net/netfilter/nf_conntrack_amanda.c | 10 ++++++----
> net/netfilter/nf_conntrack_irc.c | 7 ++++++-
> 2 files changed, 12 insertions(+), 5 deletions(-)
>
> --
> 2.54.0
>
^ permalink raw reply
* [PATCH net-next 1/2] netfilter: nf_conntrack_irc: reject DCC port values above 65535
From: HACKE-RC @ 2026-04-30 16:12 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal
Cc: Phil Sutter, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, netfilter-devel, coreteam, netdev,
linux-kernel, HACKE-RC
In-Reply-To: <20260430161230.3438973-1-rc@rexion.ai>
parse_dcc() stores the return value of simple_strtoul() directly into
a u_int16_t pointer. simple_strtoul() returns unsigned long, so values
above 65535 are silently truncated when assigned to the u16 output
parameter.
Use an intermediate unsigned long variable and reject out-of-range
values by returning -1, which causes the caller in help() to skip
the DCC command via the existing error path.
The dcc_port == 0 check in help() already rejects port 0, so this
change only adds the upper-bound check in the parser.
Fixes: 869f37d8e48f ("[NETFILTER]: nf_conntrack/nf_nat: add IRC helper port")
Signed-off-by: HACKE-RC <rc@rexion.ai>
---
net/netfilter/nf_conntrack_irc.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 522183b9a..ffaa7ab84 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -68,6 +68,7 @@ static const char *const dccprotos[] = {
static int parse_dcc(char *data, const char *data_end, __be32 *ip,
u_int16_t *port, char **ad_beg_p, char **ad_end_p)
{
+ unsigned long parsed_port;
char *tmp;
/* at least 12: "AAAAAAAA P\1\n" */
@@ -93,7 +94,11 @@ static int parse_dcc(char *data, const char *data_end, __be32 *ip,
data++;
}
- *port = simple_strtoul(data, &data, 10);
+ parsed_port = simple_strtoul(data, &data, 10);
+ if (parsed_port > 65535)
+ return -1;
+
+ *port = parsed_port;
*ad_end_p = data;
return 0;
--
2.54.0
^ permalink raw reply related
* [PATCH net-next 0/2] netfilter: conntrack: validate parsed port values in IRC and Amanda helpers
From: HACKE-RC @ 2026-04-30 16:12 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal
Cc: Phil Sutter, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, netfilter-devel, coreteam, netdev,
linux-kernel, HACKE-RC
Both nf_conntrack_irc and nf_conntrack_amanda parse port numbers from
application-layer protocol data using simple_strtoul(), which returns
unsigned long. The results are stored in u16 variables without range
checks, silently truncating values above 65535.
This series adds explicit upper-bound validation in both helpers.
Note: checkpatch warns about simple_strtoul being obsolete. Both
call sites use the endptr output parameter to advance the parse
position, which kstrtoul does not provide. Converting to kstrtoul
would require restructuring the parsers, which is out of scope for
this fix.
HACKE-RC (2):
netfilter: nf_conntrack_irc: reject DCC port values above 65535
netfilter: nf_conntrack_amanda: reject port values above 65535
net/netfilter/nf_conntrack_amanda.c | 10 ++++++----
net/netfilter/nf_conntrack_irc.c | 7 ++++++-
2 files changed, 12 insertions(+), 5 deletions(-)
--
2.54.0
^ permalink raw reply
* Re: [PATCH net v2 2/4] net: macb: drop in-flight Tx SKBs on close
From: Théo Lebrun @ 2026-04-30 16:20 UTC (permalink / raw)
To: Jakub Kicinski
Cc: Nicolas Ferre, Claudiu Beznea, Andrew Lunn, David S. Miller,
Eric Dumazet, Paolo Abeni, Haavard Skinnemoen, Jeff Garzik,
Paolo Valerio, Conor Dooley, Nicolai Buchwitz, netdev,
linux-kernel, Vladimir Kondratiev, Gregory CLEMENT,
Benoît Monin, Tawfik Bayouk, Thomas Petazzoni,
Maxime Chevallier, stable
In-Reply-To: <20260429193446.5985abea@kernel.org>
Hello Jakub,
On Thu Apr 30, 2026 at 4:34 AM CEST, Jakub Kicinski wrote:
> On Tue, 28 Apr 2026 18:32:58 +0200 Théo Lebrun wrote:
>> for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
>> - kfree(queue->tx_skb);
>> - queue->tx_skb = NULL;
>> + if (queue->tx_skb) {
>> + unsigned int dropped = 0, tail;
>> +
>> + for (tail = queue->tx_tail; tail != queue->tx_head;
>> + tail++) {
>> + if (macb_tx_skb(queue, tail)->skb)
>> + dropped++;
>> + macb_tx_unmap(bp, macb_tx_skb(queue, tail), 0,
>> + SKB_DROP_REASON_NOT_SPECIFIED);
>> + }
>> +
>> + queue->stats.tx_dropped += dropped;
>> + bp->dev->stats.tx_dropped += dropped;
>
> I'm slightly baffled by the stats in this driver.
>
> Incrementing of both device and queue stats is highly unusual.
> The driver seems to already have the values for the per-queue drops
> but currently never increments it (did I miss it?) It does for Rx
> stats but not for Tx stats.
>
> As sashiko correctly points out incrementing dev stats will lead
> to races and lass of increments for multi-queue devices.
>
> Since there are no increments for tx_dropped stat today - could you
> please delete it from ethtool -S, migrate the only existing
> dev->stats.tx_dropped++; to increment the per-queue stat and make
> macb_get_stats() collect the tx_dropped from all queues, instead
> of relying on the device-level stat?
>
> This should be patch 2 in this series, and then subsequent patches
> don't have to do this double-counting dance.
>
> I suppose you may want to migrate the byte and packet counters
> while at it, and add a u64 sync...
Agreed. Here is the plan for next revision. It goes further than your
proposal on some aspects and less so on others.
- Stop using `netdev->stats`. Not even on MACB (single queue) or from
at91 code (single queue, custom functions for a lot of things). This
will drop all the double-counting; I added some in this series but
there is lot in the driver to drop.
sed 's/netdev->stats/queue->stats/' **/macb_main.c # -ish
- All stats that used to land in netdev->stats will instead land in
queue->stats. For that we need to add two fields:
- multicast, incremented by at91ether_rx()
- tx_errors, incremented by at91ether_interrupt()
- Make queue->stats u64 values (getting inspiration from nstat).
- In macb_get_stats(), replace:
netdev_stats_to_stats64(nstat, &bp->dev->stats);
by:
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
u64_stats_fetch_begin(...);
nstat->rx_packets += queue->stats.rx_packets;
nstat->tx_packets += queue->stats.tx_packets;
// ... same for all stats ...
}
- Also the struct name (struct queue_stats) deserves a driver prefix.
Notice we don't drop tx_dropped from `ethtool -S`. It might be useful to
get per-queue stats and it doesn't cost much. We need per-queue
counters anyway, let's keep exposing them.
I don't have time to test enough, next revision will wait next week.
Thanks,
--
Théo Lebrun, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH net-next 2/2] netfilter: nf_conntrack_amanda: reject port values above 65535
From: Pablo Neira Ayuso @ 2026-04-30 16:21 UTC (permalink / raw)
To: HACKE-RC
Cc: Florian Westphal, Phil Sutter, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, netfilter-devel,
coreteam, netdev, linux-kernel
In-Reply-To: <20260430161515.3449513-3-rc@rexion.ai>
Hi,
On Thu, Apr 30, 2026 at 09:45:15PM +0530, HACKE-RC wrote:
> amanda_help() converts the result of simple_strtoul() to __be16 via
> htons() without checking the parsed value fits in 16 bits. The
> existing len > 5 guard limits strings to five digits, capping the
> parseable range at 99999, but values 65536-99999 still silently
> truncate on the htons() conversion.
>
> Use an intermediate unsigned long and reject out-of-range values
> before converting to network byte order.
>
> Fixes: 16958900578b ("[NETFILTER]: nf_conntrack/nf_nat: add amanda helper port")
> Signed-off-by: HACKE-RC <rc@rexion.ai>
> ---
> net/netfilter/nf_conntrack_amanda.c | 10 ++++++----
> 1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
> index d2c09e8dd..58d6c9f29 100644
> --- a/net/netfilter/nf_conntrack_amanda.c
> +++ b/net/netfilter/nf_conntrack_amanda.c
> @@ -88,11 +88,12 @@ static int amanda_help(struct sk_buff *skb,
> struct nf_conntrack_expect *exp;
> struct nf_conntrack_tuple *tuple;
> unsigned int dataoff, start, stop, off, i;
> + nf_nat_amanda_hook_fn *nf_nat_amanda;
> char pbuf[sizeof("65535")], *tmp;
> + unsigned long parsed_port;
> + int ret = NF_ACCEPT;
> u_int16_t len;
> __be16 port;
> - int ret = NF_ACCEPT;
> - nf_nat_amanda_hook_fn *nf_nat_amanda;
>
> /* Only look at packets from the Amanda server */
> if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
> @@ -132,10 +133,11 @@ static int amanda_help(struct sk_buff *skb,
> break;
> pbuf[len] = '\0';
>
> - port = htons(simple_strtoul(pbuf, &tmp, 10));
> + parsed_port = simple_strtoul(pbuf, &tmp, 10);
While being here, I would replace this simple_strtoul by a parser
which does not rely on nul-terminated strings.
A similar patch went in for the sip helper recently, maybe you can
just take such function to parse ports, move it to the
nf_conntrack_helper core so it can be shared by helpers.
> len = tmp - pbuf;
> - if (port == 0 || len > 5)
> + if (parsed_port == 0 || parsed_port > 65535 || len > 5)
> break;
> + port = htons(parsed_port);
>
> exp = nf_ct_expect_alloc(ct);
> if (exp == NULL) {
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH iwl-net v1 2/2] ice: use NETIF_F_HW_CSUM instead of IP/IPV6
From: Simon Horman @ 2026-04-30 16:21 UTC (permalink / raw)
To: michal.swiatkowski
Cc: intel-wired-lan, netdev, jramaseu, anthony.l.nguyen,
przemyslaw.kitszel, aleksandr.loktionov
In-Reply-To: <20260430152948.1683359-2-horms@kernel.org>
On Thu, Apr 30, 2026 at 04:29:49PM +0100, Simon Horman wrote:
> From: 'Simon Horman' <horms@kernel.org>
>
> 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
Sorry, the email I am responding to was supposed to come with
some commentary - it seems my method for adding it is broken :(
So I'm adding it below (as best as I can remember what it was).
> ---
> ice: use NETIF_F_HW_CSUM instead of IP/IPV6
>
> This commit replaces the IP and IPV6 checksum offload flags with HW_CSUM
> in the ice driver to allow hardware checksumming for IPv6 packets with
> extension headers. It also removes the mutual exclusivity check between
> TSO and GCS.
>
> > diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
> > index 5f92377d4dfc..33f252a6a22f 100644
> > --- a/drivers/net/ethernet/intel/ice/ice_main.c
> > +++ b/drivers/net/ethernet/intel/ice/ice_main.c
> > @@ -3491,9 +3491,8 @@ void ice_set_netdev_features(struct net_device *netdev)
> > NETIF_F_RXHASH;
> >
> > csumo_features = NETIF_F_RXCSUM |
> > - NETIF_F_IP_CSUM |
> > NETIF_F_SCTP_CRC |
> > - NETIF_F_IPV6_CSUM;
> > + NETIF_F_HW_CSUM;
>
> By advertising NETIF_F_HW_CSUM, the network stack assumes the driver can handle
> checksums for any protocol and passes non-IP packets (e.g., from AF_PACKET
> injected frames) to the driver with CHECKSUM_PARTIAL.
>
> Since ice_tx_csum() strictly parses the L3 header and expects IPv4 or IPv6,
> returning -1 for other protocols, will this regression cause non-IP packets to
> be silently dropped instead of falling back to software checksums in the kernel?
The problem above seems to be a legitimate concern, if a corner case.
It seems to also exist in i40e.
> Additionally, skb_csum_hwoffload_help() relies on NETIF_F_IPV6_CSUM to
> safely fall back to software checksums when IPv6 extension headers are
> present.
>
> Does using NETIF_F_HW_CSUM bypass this safeguard, potentially causing
> legacy hardware (like E810) or E830 without GCS descriptors to compute
> incorrect pseudo-headers and silently corrupt IPv6 packets with extension
> headers?
The issue above seems to be a false positive as the ice driver
doesn't rely on the behaviour described. Rather ice_tx_csum()
uses ipv6_skip_exthdr() to correctly handle extension headers.
>
> Finally, for protocols other than TCP, UDP, or SCTP, the driver falls back to
> calling skb_checksum_help(skb) in the default case of ice_tx_csum().
>
> However, the driver appears to ignore the return value of skb_checksum_help().
>
> If skb_checksum_help() fails (e.g., due to -ENOMEM during pskb_expand_head()),
> could this result in the packet being transmitted with an uncomputed checksum?
The problem above seems real to me, but it also seems to be pre-existing.
So I don't think it should delay progress of this patch.
If it is a problem, it also seems to be present in i40e.
^ permalink raw reply
* Re: [RFC PATCH net-next v6 1/2] net: pppoe: implement GRO/GSO support
From: Paolo Abeni @ 2026-04-30 16:22 UTC (permalink / raw)
To: Pablo Neira Ayuso, Qingfang Deng
Cc: Felix Fietkau, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, David Ahern, Simon Horman, netdev, linux-kernel,
linux-ppp
In-Reply-To: <afN7_oBICMZ_45Zh@chamomile>
On 4/30/26 5:57 PM, Pablo Neira Ayuso wrote:
> On Thu, Apr 30, 2026 at 11:47:57PM +0800, Qingfang Deng wrote:
>> On Thu, Apr 30, 2026 at 5:34 PM Paolo Abeni <pabeni@redhat.com> wrote:
>>>
>>> AFAICS, when the computed len is >= 64K, and the above min() will
>>> truncate it, later pppoe_rcv() will drop the packet.
>>
>> pppoe_rcv() does _not_ drop such packets.
>> The drop condition is "skb->len < ntohs(ph->length)", not the other way around.
>>
>>>> + skb = segs;
>>>> + do {
>>>> + phdr = (struct pppoe_hdr *)(skb_mac_header(skb) + nhoff);
>>>> + len = skb->len - (nhoff + sizeof(*phdr));
>>>> + phdr->length = cpu_to_be16(len);
>>>> + skb->network_header = (u8 *)phdr - skb->head;
>>>
>>> I understand is quite late for the following question, but...
>>> The network headers points to the pppoe hdr. Should it point to the
>>> actual IP hdr?
>
> This is the same with double-tagged-vlan, the network header also
> points to the inner vlan in the skb payload. Changing this would
> require to revisit all users in the tree that are already assuming
> this.
Ah right, the relevant GRO stage is running on top of an ethernet device
and the RX path there resets the NH just after the ethernet one.
I got lost in the relevant hooking.
This patch (and v7) LGTM, thanks.
Paolo
^ permalink raw reply
* [PATCH net-next 2/2] netfilter: nf_conntrack_amanda: reject port values above 65535
From: HACKE-RC @ 2026-04-30 16:15 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal
Cc: Phil Sutter, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, netfilter-devel, coreteam, netdev,
linux-kernel, HACKE-RC
amanda_help() converts the result of simple_strtoul() to __be16 via
htons() without checking the parsed value fits in 16 bits. The
existing len > 5 guard limits strings to five digits, capping the
parseable range at 99999, but values 65536-99999 still silently
truncate on the htons() conversion.
Use an intermediate unsigned long and reject out-of-range values
before converting to network byte order.
Fixes: 16958900578b ("[NETFILTER]: nf_conntrack/nf_nat: add amanda helper port")
Signed-off-by: HACKE-RC <rc@rexion.ai>
---
net/netfilter/nf_conntrack_amanda.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index d2c09e8dd..58d6c9f29 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -88,11 +88,12 @@ static int amanda_help(struct sk_buff *skb,
struct nf_conntrack_expect *exp;
struct nf_conntrack_tuple *tuple;
unsigned int dataoff, start, stop, off, i;
+ nf_nat_amanda_hook_fn *nf_nat_amanda;
char pbuf[sizeof("65535")], *tmp;
+ unsigned long parsed_port;
+ int ret = NF_ACCEPT;
u_int16_t len;
__be16 port;
- int ret = NF_ACCEPT;
- nf_nat_amanda_hook_fn *nf_nat_amanda;
/* Only look at packets from the Amanda server */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
@@ -132,10 +133,11 @@ static int amanda_help(struct sk_buff *skb,
break;
pbuf[len] = '\0';
- port = htons(simple_strtoul(pbuf, &tmp, 10));
+ parsed_port = simple_strtoul(pbuf, &tmp, 10);
len = tmp - pbuf;
- if (port == 0 || len > 5)
+ if (parsed_port == 0 || parsed_port > 65535 || len > 5)
break;
+ port = htons(parsed_port);
exp = nf_ct_expect_alloc(ct);
if (exp == NULL) {
--
2.54.0
^ permalink raw reply related
* Re: [PATCH net-next v19 00/15] Begin upstreaming Homa transport protocol
From: John Ousterhout @ 2026-04-30 16:24 UTC (permalink / raw)
To: netdev; +Cc: pabeni, edumazet, horms, kuba
In-Reply-To: <20260428231520.1857-1-ouster@cs.stanford.edu>
The sashiki-gemini review has found a bunch of issues, which look
super-helpful (and a little sobering at how many there are :-(). I
will of course address all of these, but I'm wondering if there is a
recommended way for me to respond to these "on the record" (analogous
to responding to emails sent by humans)? In particular, there are a
couple that are false alarms, so I'd like to do something to keep
these from reappearing in future AI reviews. Any suggestions?
-John-
^ 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