* [PATCH v3 10/11] vfio: selftests: Add mlx5 driver - data path and memcpy ops
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
In-Reply-To: <0-v3-76f117ad04f1+28a90-mlx5st_jgg@nvidia.com>
Complete the mlx5 driver by adding CQ/QP creation, QP state
transitions, WQE posting, CQ polling, and the
memcpy_start/memcpy_wait callbacks. After this patch the driver is
functional for DMA tests.
The data path implements RDMA Write self-loopback via an RC QP with
force-loopback. WQEs are posted to a 16-entry send queue with an
NC doorbell, and completions are polled from a 16-entry CQ.
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
.../selftests/vfio/lib/drivers/mlx5/mlx5.c | 359 +++++++++++++++++-
1 file changed, 357 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5.c b/tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5.c
index 804801cc564e7a..e5e75adb253166 100644
--- a/tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5.c
+++ b/tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5.c
@@ -1343,6 +1343,354 @@ static void mlx5st_destroy_mkey(struct mlx5st_device *dev)
mlx5st_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
}
+/*
+ * CQ create/destroy
+ */
+
+static void mlx5st_create_cq(struct mlx5st_device *dev)
+{
+ struct vfio_pci_device *device = dev->device;
+ u64 in[MLX5_ST_SZ_QW(create_cq_in) + 1] = {};
+ u32 out[MLX5_ST_SZ_DW(create_cq_out)] = {};
+ struct mlx5_ifc_cqc_bits *cqc;
+ unsigned int i;
+ __be64 *pas;
+
+ /* Initialize CQEs before CREATE_CQ: opcode=0xF, owner=1 */
+ for (i = 0; i < CQ_CQE_CNT; i++) {
+ struct mlx5st_cqe64 *cqe = &dev->cq_buf[i];
+
+ MLX5_SET(cqe64, cqe, opcode, 0xF);
+ MLX5_SET_ONCE(cqe64, cqe, owner, 1);
+ }
+
+ MLX5_SET(create_cq_in, in, opcode, MLX5_CMD_OP_CREATE_CQ);
+
+ cqc = MLX5_ADDR_OF(create_cq_in, in, cq_context);
+ MLX5_SET(cqc, cqc, log_cq_size, LOG_CQ_SIZE);
+ MLX5_SET(cqc, cqc, uar_page, dev->uar_page);
+ MLX5_SET(cqc, cqc, c_eqn_or_apu_element, dev->eqn);
+ MLX5_SET(cqc, cqc, cqe_sz, 0);
+ pas = MLX5_ADDR_OF(create_cq_in, in, pas);
+ MLX5_SET(cqc, cqc, page_offset, mlx5st_fill_pas(device, dev->cq_buf, pas));
+ MLX5_SET(cqc, cqc, log_page_size, 0);
+ MLX5_SET64(cqc, cqc, dbr_addr, to_iova(device, &dev->cq_dbrec));
+
+ mlx5st_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+
+ dev->cqn = MLX5_GET(create_cq_out, out, cqn);
+ dev->cq_ci = 0;
+ dev_dbg(device, "Created CQ: cqn=%u, %d entries\n", dev->cqn,
+ CQ_CQE_CNT);
+}
+
+static void mlx5st_destroy_cq(struct mlx5st_device *dev)
+{
+ u32 out[MLX5_ST_SZ_DW(destroy_cq_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(destroy_cq_in)] = {};
+
+ MLX5_SET(destroy_cq_in, in, opcode, MLX5_CMD_OP_DESTROY_CQ);
+ MLX5_SET(destroy_cq_in, in, cqn, dev->cqn);
+ mlx5st_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+/*
+ * QP create/destroy
+ */
+
+static void mlx5st_create_qp(struct mlx5st_device *dev)
+{
+ struct vfio_pci_device *device = dev->device;
+ u64 in[MLX5_ST_SZ_QW(create_qp_in) + 1] = {};
+ u32 out[MLX5_ST_SZ_DW(create_qp_out)] = {};
+ struct mlx5_ifc_qpc_bits *qpc;
+ __be64 *pas;
+
+ MLX5_SET(create_qp_in, in, opcode, MLX5_CMD_OP_CREATE_QP);
+
+ qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
+ MLX5_SET(qpc, qpc, st, MLX5_QPC_ST_RC);
+ MLX5_SET(qpc, qpc, pm_state, MLX5_QPC_PM_STATE_MIGRATED);
+ MLX5_SET(qpc, qpc, pd, dev->pdn);
+ MLX5_SET(qpc, qpc, uar_page, dev->uar_page);
+ MLX5_SET(qpc, qpc, cqn_snd, dev->cqn);
+ MLX5_SET(qpc, qpc, cqn_rcv, dev->cqn);
+ MLX5_SET(qpc, qpc, log_sq_size, LOG_SQ_SIZE);
+ MLX5_SET(qpc, qpc, log_msg_max, dev->log_max_msg);
+ MLX5_SET(qpc, qpc, rq_type, 0x3);
+ MLX5_SET(qpc, qpc, ts_format, 1);
+ pas = MLX5_ADDR_OF(create_qp_in, in, pas);
+ MLX5_SET(qpc, qpc, page_offset,
+ mlx5st_fill_pas(device, dev->sq_buf, pas));
+ MLX5_SET(qpc, qpc, log_page_size, 0);
+ MLX5_SET64(qpc, qpc, dbr_addr, to_iova(device, &dev->qp_dbrec));
+
+ mlx5st_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+
+ dev->qpn = MLX5_GET(create_qp_out, out, qpn);
+ dev->sq_pi = 0;
+ dev_dbg(device, "Created QP: qpn=%u, RC, sq=%d wqes\n", dev->qpn,
+ SQ_WQE_CNT);
+}
+
+static void mlx5st_destroy_qp(struct mlx5st_device *dev)
+{
+ u32 out[MLX5_ST_SZ_DW(destroy_qp_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(destroy_qp_in)] = {};
+
+ MLX5_SET(destroy_qp_in, in, opcode, MLX5_CMD_OP_DESTROY_QP);
+ MLX5_SET(destroy_qp_in, in, qpn, dev->qpn);
+ mlx5st_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+}
+
+/*
+ * QP state transitions
+ */
+
+static void mlx5st_qp_rst2init(struct mlx5st_device *dev)
+{
+ u32 out[MLX5_ST_SZ_DW(rst2init_qp_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(rst2init_qp_in)] = {};
+ struct mlx5_ifc_qpc_bits *qpc = MLX5_ADDR_OF(rst2init_qp_in, in, qpc);
+
+ MLX5_SET(rst2init_qp_in, in, opcode, MLX5_CMD_OP_RST2INIT_QP);
+ MLX5_SET(rst2init_qp_in, in, qpn, dev->qpn);
+
+ MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, 1);
+ MLX5_SET(qpc, qpc, pm_state, MLX5_QPC_PM_STATE_MIGRATED);
+ MLX5_SET(qpc, qpc, rre, 1);
+ MLX5_SET(qpc, qpc, rwe, 1);
+
+ mlx5st_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ dev_dbg(dev->device, "QP RST->INIT\n");
+}
+
+static void mlx5st_qp_init2rtr(struct mlx5st_device *dev)
+{
+ u32 out[MLX5_ST_SZ_DW(init2rtr_qp_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(init2rtr_qp_in)] = {};
+ struct mlx5_ifc_qpc_bits *qpc = MLX5_ADDR_OF(init2rtr_qp_in, in, qpc);
+
+ MLX5_SET(init2rtr_qp_in, in, opcode, MLX5_CMD_OP_INIT2RTR_QP);
+ MLX5_SET(init2rtr_qp_in, in, qpn, dev->qpn);
+
+ MLX5_SET(qpc, qpc, mtu, 3);
+ MLX5_SET(qpc, qpc, log_msg_max, dev->log_max_msg);
+ MLX5_SET(qpc, qpc, remote_qpn, dev->qpn);
+ MLX5_SET(qpc, qpc, min_rnr_nak, 12);
+ MLX5_SET(qpc, qpc, primary_address_path.vhca_port_num, 1);
+ MLX5_SET(qpc, qpc, primary_address_path.fl, 1);
+
+ mlx5st_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ dev_dbg(dev->device, "QP INIT->RTR (fl=1)\n");
+}
+
+static void mlx5st_qp_rtr2rts(struct mlx5st_device *dev)
+{
+ u32 out[MLX5_ST_SZ_DW(rtr2rts_qp_out)] = {};
+ u32 in[MLX5_ST_SZ_DW(rtr2rts_qp_in)] = {};
+ struct mlx5_ifc_qpc_bits *qpc = MLX5_ADDR_OF(rtr2rts_qp_in, in, qpc);
+
+ MLX5_SET(rtr2rts_qp_in, in, opcode, MLX5_CMD_OP_RTR2RTS_QP);
+ MLX5_SET(rtr2rts_qp_in, in, qpn, dev->qpn);
+
+ MLX5_SET(qpc, qpc, log_ack_req_freq, 0);
+ MLX5_SET(qpc, qpc, retry_count, 7);
+ MLX5_SET(qpc, qpc, rnr_retry, 7);
+ MLX5_SET(qpc, qpc, primary_address_path.ack_timeout, 14);
+
+ mlx5st_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+ dev_dbg(dev->device, "QP RTR->RTS\n");
+}
+
+/*
+ * Post RDMA Write WQE
+ */
+static void mlx5st_post_rdma_write(struct mlx5st_device *dev, u64 src_addr,
+ u32 src_lkey, u64 dst_addr, u32 dst_rkey,
+ u32 length, bool signaled)
+{
+ struct mlx5st_send_wqe *wqe;
+ unsigned int idx;
+
+ idx = dev->sq_pi % SQ_WQE_CNT;
+ wqe = &dev->sq_buf[idx];
+
+ memset(wqe, 0, sizeof(*wqe));
+ MLX5_SET(wqe_ctrl_seg, &wqe->ctrl, opcode, MLX5_OPCODE_RDMA_WRITE);
+ MLX5_SET(wqe_ctrl_seg, &wqe->ctrl, wqe_index, dev->sq_pi);
+ MLX5_SET(wqe_ctrl_seg, &wqe->ctrl, qp_or_sq, dev->qpn);
+ MLX5_SET(wqe_ctrl_seg, &wqe->ctrl, ds, MLX5_RDMA_WRITE_DS);
+ if (signaled)
+ MLX5_SET(wqe_ctrl_seg, &wqe->ctrl, ce, MLX5_WQE_CE_CQE_ALWAYS);
+
+ MLX5_SET64(wqe_raddr_seg, &wqe->raddr, raddr, dst_addr);
+ MLX5_SET(wqe_raddr_seg, &wqe->raddr, rkey, dst_rkey);
+
+ MLX5_SET(wqe_data_seg, &wqe->data, byte_count, length);
+ MLX5_SET(wqe_data_seg, &wqe->data, lkey, src_lkey);
+ MLX5_SET64(wqe_data_seg, &wqe->data, addr, src_addr);
+
+ dev->sq_pi++;
+
+ /* Ensure WQE is visible to device before doorbell record */
+ dma_wmb();
+
+ WRITE_ONCE(dev->qp_dbrec.send_counter,
+ cpu_to_be32(dev->sq_pi & 0xffff));
+
+ /*
+ * Ring doorbell: write first 8 bytes of ctrl to UAR BF register,
+ * iowrite has an internal dma_wmb() so the doorbell record will be
+ * visible.
+ */
+ iowrite64be(be64_to_cpu(*(__be64 *)wqe),
+ (u8 __iomem *)dev->uar_base + dev->uar_bf_offset);
+ dev->uar_bf_offset ^= MLX5_BF_SIZE;
+}
+
+/*
+ * Poll CQ
+ */
+static int mlx5st_poll_cq_batch(struct mlx5st_device *dev,
+ unsigned int max_cqe)
+{
+ unsigned int polled = 0;
+
+ while (polled < max_cqe) {
+ unsigned int idx = dev->cq_ci % CQ_CQE_CNT;
+ struct mlx5st_cqe64 *cqe = &dev->cq_buf[idx];
+ u8 owner, opcode;
+
+ owner = MLX5_GET_ONCE(cqe64, cqe, owner);
+ if (owner != ((dev->cq_ci >> LOG_CQ_SIZE) & 1))
+ break;
+
+ dma_rmb();
+
+ opcode = MLX5_GET(cqe64, cqe, opcode);
+
+ dev->cq_ci++;
+ WRITE_ONCE(dev->cq_dbrec.recv_counter,
+ cpu_to_be32(dev->cq_ci & 0xffffff));
+
+ if (opcode == MLX5_CQE_REQ) {
+ dev->sq_ci =
+ (u16)(MLX5_GET(cqe64, cqe, wqe_counter) + 1);
+ polled++;
+ continue;
+ }
+ if (opcode == MLX5_CQE_REQ_ERR ||
+ opcode == MLX5_CQE_RESP_ERR) {
+ dev_dbg(dev->device,
+ "CQE error: opcode=0x%x syndrome=0x%x vendor=0x%x\n",
+ opcode,
+ MLX5_GET(cqe64, cqe, error_syndrome.syndrome),
+ MLX5_GET(cqe64, cqe,
+ error_syndrome.vendor_error_syndrome));
+ return -1;
+ }
+ dev_err(dev->device, "CQE unexpected opcode=0x%x\n", opcode);
+ return -1;
+ }
+
+ return polled;
+}
+
+static int mlx5st_poll_cq(struct mlx5st_device *dev, unsigned int timeout_ms)
+{
+ struct timespec start, now;
+ unsigned int elapsed;
+ int ret;
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (;;) {
+ ret = mlx5st_poll_cq_batch(dev, 1);
+ if (ret < 0)
+ return -1;
+ if (ret > 0)
+ return 0;
+
+ if (dev->have_eq)
+ mlx5st_process_events(dev);
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ elapsed = (now.tv_sec - start.tv_sec) * 1000 +
+ (now.tv_nsec - start.tv_nsec) / 1000000;
+ if (elapsed > timeout_ms) {
+ dev_err(dev->device, "CQ poll timeout after %u ms\n",
+ timeout_ms);
+ return -1;
+ }
+ }
+}
+
+/*
+ * Data path setup/teardown helpers
+ */
+
+static void mlx5st_setup_datapath(struct mlx5st_device *dev)
+{
+ mlx5st_create_cq(dev);
+ mlx5st_create_qp(dev);
+ mlx5st_qp_rst2init(dev);
+ mlx5st_qp_init2rtr(dev);
+ mlx5st_qp_rtr2rts(dev);
+}
+
+static void mlx5st_teardown_datapath(struct mlx5st_device *dev)
+{
+ if (dev->qpn) {
+ mlx5st_destroy_qp(dev);
+ dev->qpn = 0;
+ }
+ if (dev->cqn) {
+ mlx5st_destroy_cq(dev);
+ dev->cqn = 0;
+ }
+ dev->sq_pi = 0;
+ dev->sq_ci = 0;
+ memset(&dev->qp_dbrec, 0, sizeof(dev->qp_dbrec));
+ memset(&dev->cq_dbrec, 0, sizeof(dev->cq_dbrec));
+}
+
+/*
+ * memcpy callbacks
+ */
+
+#define MLX5ST_MEMCPY_TIMEOUT_MS 60000
+
+static void mlx5st_memcpy_start(struct vfio_pci_device *device,
+ iova_t src, iova_t dst, u64 size, u64 count)
+{
+ struct mlx5st_device *dev = to_mlx5st(device);
+ u64 i;
+
+ for (i = 0; i < count; i++) {
+ bool signaled = (i == count - 1);
+
+ mlx5st_post_rdma_write(dev, src, dev->global_lkey, dst,
+ dev->global_rkey, size, signaled);
+ }
+}
+
+static int mlx5st_memcpy_wait(struct vfio_pci_device *device)
+{
+ struct mlx5st_device *dev = to_mlx5st(device);
+ int ret;
+
+ ret = mlx5st_poll_cq(dev, MLX5ST_MEMCPY_TIMEOUT_MS);
+ if (ret) {
+ /*
+ * CQE error puts the QP in error state. Rebuild the data path
+ * so subsequent operations can succeed.
+ */
+ mlx5st_teardown_datapath(dev);
+ mlx5st_setup_datapath(dev);
+ }
+ return ret;
+}
+
/*
* Driver ops callbacks
*/
@@ -1373,6 +1721,11 @@ static void mlx5st_init(struct vfio_pci_device *device)
mlx5st_alloc_pd(dev);
mlx5st_create_mkey(dev);
+ mlx5st_setup_datapath(dev);
+
+ device->driver.max_memcpy_size = 1ULL << dev->log_max_msg;
+ device->driver.max_memcpy_count = SQ_WQE_CNT - 1;
+
dev_dbg(device, "mlx5 driver initialized\n");
}
@@ -1380,6 +1733,8 @@ static void mlx5st_remove(struct vfio_pci_device *device)
{
struct mlx5st_device *dev = to_mlx5st(device);
+ mlx5st_teardown_datapath(dev);
+
dev_dbg(device, "teardown: destroy_mkey\n");
if (dev->mkey_index) {
mlx5st_destroy_mkey(dev);
@@ -1408,7 +1763,7 @@ struct vfio_pci_driver_ops mlx5st_ops = {
.probe = mlx5st_probe,
.init = mlx5st_init,
.remove = mlx5st_remove,
- .memcpy_start = NULL,
- .memcpy_wait = NULL,
+ .memcpy_start = mlx5st_memcpy_start,
+ .memcpy_wait = mlx5st_memcpy_wait,
.send_msi = NULL,
};
--
2.43.0
^ permalink raw reply related
* [PATCH v3 08/11] vfio: selftests: Add dev_dbg
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
In-Reply-To: <0-v3-76f117ad04f1+28a90-mlx5st_jgg@nvidia.com>
Enable it with a #define DEBUG at the top of the file. Allows leaving
behind debugging prints that are useful in case future changes are
required.
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: David Matlack <dmatlack@google.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
.../vfio/lib/include/libvfio/vfio_pci_device.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
index 3eabead717bbda..2a72b76c0e96bd 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
@@ -40,6 +40,17 @@ struct vfio_pci_device {
struct vfio_pci_device *vfio_pci_device_alloc(const char *bdf, struct iommu *iommu);
void vfio_pci_device_free(struct vfio_pci_device *device);
+
+#ifdef DEBUG
+#define dev_dbg dev_info
+#else
+#define dev_dbg(_dev, _fmt, ...) \
+ do { \
+ if (0) \
+ dev_info(_dev, _fmt, ##__VA_ARGS__); \
+ } while (0)
+#endif
+
struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu);
void vfio_pci_device_cleanup(struct vfio_pci_device *device);
--
2.43.0
^ permalink raw reply related
* [PATCH v3 06/11] selftests: Fix arm64 IO barriers to match kernel
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
In-Reply-To: <0-v3-76f117ad04f1+28a90-mlx5st_jgg@nvidia.com>
The tools/include readl/writel MMIO accessors on arm64 use
inner-shareable barriers (dmb ish) while the kernel uses
outer-shareable (dmb osh). Fix them to match.
Add __io_bw() and __io_ar() definitions matching the kernel's
arch/arm64/include/asm/io.h, including the dummy control dependency
in __io_ar() that orders MMIO reads against all subsequent
instructions.
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
tools/arch/arm64/include/asm/io.h | 20 ++++++++++++++++++++
tools/include/asm/io.h | 2 ++
tools/testing/selftests/lib.mk | 5 +++++
3 files changed, 27 insertions(+)
create mode 100644 tools/arch/arm64/include/asm/io.h
diff --git a/tools/arch/arm64/include/asm/io.h b/tools/arch/arm64/include/asm/io.h
new file mode 100644
index 00000000000000..0d38f75a477682
--- /dev/null
+++ b/tools/arch/arm64/include/asm/io.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _TOOLS_ASM_ARM64_IO_H
+#define _TOOLS_ASM_ARM64_IO_H
+
+#define __io_bw() dma_wmb()
+#define __io_ar(v) \
+({ \
+ unsigned long tmp; \
+ \
+ dma_rmb(); \
+ \
+ asm volatile("eor %0, %1, %1\n" \
+ "cbnz %0, ." \
+ : "=r" (tmp) : "r" ((unsigned long)(v)) \
+ : "memory"); \
+})
+
+#include <asm-generic/io.h>
+
+#endif /* _TOOLS_ASM_ARM64_IO_H */
diff --git a/tools/include/asm/io.h b/tools/include/asm/io.h
index eed5066f25c450..1090a2c387f40d 100644
--- a/tools/include/asm/io.h
+++ b/tools/include/asm/io.h
@@ -4,6 +4,8 @@
#if defined(__i386__) || defined(__x86_64__)
#include "../../arch/x86/include/asm/io.h"
+#elif defined(__aarch64__)
+#include "../../arch/arm64/include/asm/io.h"
#else
#include <asm-generic/io.h>
#endif
diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk
index f02cc8a2e4ae32..fdd22df9174b88 100644
--- a/tools/testing/selftests/lib.mk
+++ b/tools/testing/selftests/lib.mk
@@ -5,9 +5,14 @@ ifneq ($(filter %/,$(LLVM)),)
LLVM_PREFIX := $(LLVM)
else ifneq ($(filter -%,$(LLVM)),)
LLVM_SUFFIX := $(LLVM)
+else ifneq ($(LLVM),1)
+$(error Invalid value for LLVM, see Documentation/kbuild/llvm.rst)
endif
CLANG := $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
+LD := $(LLVM_PREFIX)ld.lld$(LLVM_SUFFIX)
+# Selftests link through $(CC), so point clang at the LLVM linker.
+LDFLAGS += --ld-path=$(LD)
CLANG_TARGET_FLAGS_arm := arm-linux-gnueabi
CLANG_TARGET_FLAGS_arm64 := aarch64-linux-gnu
--
2.43.0
^ permalink raw reply related
* [PATCH v3 04/11] net/mlx5: Add ONCE and MMIO accessor variants to mlx5_ifc_macros.h
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
In-Reply-To: <0-v3-76f117ad04f1+28a90-mlx5st_jgg@nvidia.com>
Add MLX5_GET_ONCE / MLX5_SET_ONCE which include READ_ONCE/WRITE_ONCE
semantics for touching ownership bits that hardware may read or write
at any time. The kernel driver doesn't use the IFC struct for these
ownership bits, but the VFIO driver will and needs these helpers.
Add MLX5_GET_MMIO / MLX5_SET_MMIO for accessing the init seg using
the IFC offsets. They embed a readl/writel using the IFC struct to
generate the addressing.
Add MLX5_ARRAY_GET64(), the missing counterpart to
MLX5_ARRAY_SET64().
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
include/linux/mlx5/mlx5_ifc_macros.h | 52 ++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/include/linux/mlx5/mlx5_ifc_macros.h b/include/linux/mlx5/mlx5_ifc_macros.h
index d357acfd351de2..1b9e39a509495a 100644
--- a/include/linux/mlx5/mlx5_ifc_macros.h
+++ b/include/linux/mlx5/mlx5_ifc_macros.h
@@ -85,6 +85,13 @@ __mlx5_mask(typ, fld))
__MLX5_SET64(typ, p, fld[idx], v); \
} while (0)
+#define MLX5_ARRAY_GET64(typ, p, fld, idx) \
+ ({ \
+ BUILD_BUG_ON(__mlx5_bit_off(typ, fld) % 64); \
+ be64_to_cpu( \
+ *((__be64 *)(p) + __mlx5_64_off(typ, fld) + (idx))); \
+ })
+
#define MLX5_GET64(typ, p, fld) be64_to_cpu(*((__be64 *)(p) + __mlx5_64_off(typ, fld)))
#define MLX5_GET64_PR(typ, p, fld) ({ \
@@ -130,4 +137,49 @@ __mlx5_mask16(typ, fld))
tmp; \
})
+/*
+ * Use READ_ONCE/WRITE_ONCE for a single field that hardware may read/write
+ * unpredictably, mostly owner bits. All other bits in the DW must be stable.
+ * Usually a dma_wmb() will be required before a write and a dma_rmb() after a
+ * read.
+ */
+#define MLX5_GET_ONCE(typ, p, fld) \
+ ((be32_to_cpu(READ_ONCE(*((__be32 *)(p) + __mlx5_dw_off(typ, fld)))) >> \
+ __mlx5_dw_bit_off(typ, fld)) & \
+ __mlx5_mask(typ, fld))
+
+#define MLX5_SET_ONCE(typ, p, fld, v) \
+ do { \
+ u32 _v = v; \
+ __be32 *_dw = (__be32 *)(p) + __mlx5_dw_off(typ, fld); \
+ BUILD_BUG_ON(__mlx5_st_sz_bits(typ) % 32); \
+ WRITE_ONCE(*_dw, \
+ cpu_to_be32((be32_to_cpu(READ_ONCE(*_dw)) & \
+ (~__mlx5_dw_mask(typ, fld))) | \
+ (((_v) & __mlx5_mask(typ, fld)) \
+ << __mlx5_dw_bit_off(typ, fld)))); \
+ } while (0)
+
+/* Access MMIO registers, usually the init segment, using IFC structs. */
+#define MLX5_GET_MMIO(typ, p, fld) \
+ ((ioread32be(((__be32 __iomem *)(p) + __mlx5_dw_off(typ, fld))) >> \
+ __mlx5_dw_bit_off(typ, fld)) & \
+ __mlx5_mask(typ, fld))
+
+/* The set is not relaxed so there is an integrated dma_wmb(). */
+#define MLX5_SET_MMIO(typ, p, fld, v) \
+ do { \
+ u32 _v = v; \
+ void __iomem *_dw = \
+ ((__be32 __iomem *)(p) + __mlx5_dw_off(typ, fld)); \
+ if (__mlx5_bit_sz(typ, fld) == 32) \
+ iowrite32be(_v, _dw); \
+ else \
+ iowrite32be((ioread32be(_dw) & \
+ (~__mlx5_dw_mask(typ, fld))) | \
+ ((_v & __mlx5_mask(typ, fld)) \
+ << __mlx5_dw_bit_off(typ, fld)), \
+ _dw); \
+ } while (0)
+
#endif /* MLX5_IFC_MACROS_H */
--
2.43.0
^ permalink raw reply related
* [PATCH v3 00/11] mlx5 support for VFIO self test
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
Add an mlx5 driver to VFIO self test. This is largely a remix of the
existing VFIO mlx5 driver in rdma-core. It uses an RDMA loopback QP
to issue RDMA WRITE operations which effectively perform memory
copies using DMA. Since mlx5 has a stable programming ABI this
should work on devices from CX5 to current HW. The device FW must
support the QP loopback configuration.
Also support send_msi by arming completion events of the RDMA WRITE
to trigger MSI delivery.
mlx5 device startup is very complex and most of this code is just
booting the device, with a smaller amount for operating the QP.
This entire series was coded by Claude Code in about 4 days. It
used about 4.5M output tokens, 30 individual sessions and 5600 lines
of AI-generated .md files. I spent an annoying amount of time
de-slopping and cleaning its work product to make it presentable.
However, previous VFIO drivers have taken on the order of 1-2
months to write, so getting one in a week is pretty remarkable.
For those interested, the flow I used was broadly a prompt sequence
sort of like:
- Hey Claude, go look at the falcon series, VFIO self test, the
mlx5 driver, rdma-core and some PDF documentation and make a
plan to put mlx5 under the selftest.
- Write an rdma-core application using the built-in VFIO provider
that can do the required memcpy operations that vfio selftests
wants.
(This resulted in a 1k loc C file that compiled and ran the
first time but had a few bugs related to device programming
that the AI resolved.)
- Replace the rdma-core components with open-coded versions to
create a fully stand-alone program that does the DMA memcpy.
- Review and audit the thing.
[Pause and de-slop it]
- Make it work on a PF too (this is surprisingly hard!).
[Move to a kernel tree and copy all the .md files and .c program
it made]
- Hey Claude, look at all this stuff and make a broad plan to
actually build a VFIO self test.
- Here is my 1 sentence advice on what each patch should look
like, make a detailed plan to make a patch for every one.
[Pause and polish the patch plans]
- Execute plan X then commit it [pause and de-slop each patch,
repeat].
[Review and final polish]
v3:
- Move max into vfio_pci_driver_probe()
- Rebase on v7.2-rc3
v2: https://patch.msgid.link/r/0-v2-72e9640932fd+2c64-mlx5st_jgg@nvidia.com
- Rebase on v7.1-rc3, drop falcon patches
- dev_dbg checks the format string even in non debug builds
- Sort includes
- Adjust comments/commit messageas
- Use linux/pci_ids.h
- Compute the driver.max_memcpy_size the same as mlx5 kernel driver, it
should be GBs now on most devices
- Put region_size into all drivers instead of allowing 0
v1: https://patch.msgid.link/r/0-v1-dc5fa250ca1d+3213-mlx5st_jgg@nvidia.com
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Jason Gunthorpe (11):
net/mlx5: Add IFC structures for CQE and WQE
net/mlx5: Move HW constant groups from device.h/cq.h to mlx5_ifc.h
net/mlx5: Extract MLX5_SET/GET macros into mlx5_ifc_macros.h
net/mlx5: Add ONCE and MMIO accessor variants to mlx5_ifc_macros.h
selftests: Add additional kernel functions to tools/include/
selftests: Fix arm64 IO barriers to match kernel
vfio: selftests: Allow drivers to specify required region size
vfio: selftests: Add dev_dbg
vfio: selftests: Add mlx5 driver - HW init and command interface
vfio: selftests: Add mlx5 driver - data path and memcpy ops
vfio: selftests: mlx5 driver - add send_msi support
include/linux/mlx5/cq.h | 10 -
include/linux/mlx5/device.h | 231 +-
include/linux/mlx5/mlx5_ifc.h | 178 ++
include/linux/mlx5/mlx5_ifc_macros.h | 185 ++
tools/arch/arm64/include/asm/barrier.h | 4 +
tools/arch/arm64/include/asm/io.h | 20 +
tools/arch/x86/include/asm/barrier.h | 5 +
tools/include/asm-generic/io.h | 28 +
tools/include/asm/barrier.h | 8 +
tools/include/asm/io.h | 2 +
tools/include/linux/stddef.h | 10 +
tools/testing/selftests/lib.mk | 5 +
.../selftests/vfio/lib/drivers/dsa/dsa.c | 1 +
.../selftests/vfio/lib/drivers/ioat/ioat.c | 1 +
.../selftests/vfio/lib/drivers/mlx5/mlx5.c | 1928 +++++++++++++++++
.../selftests/vfio/lib/drivers/mlx5/mlx5_hw.h | 114 +
.../vfio/lib/drivers/mlx5/mlx5_ifc.h | 1 +
.../vfio/lib/drivers/mlx5/mlx5_ifc_fpga.h | 1 +
.../vfio/lib/drivers/mlx5/mlx5_ifc_macros.h | 1 +
.../lib/include/libvfio/vfio_pci_device.h | 11 +
.../lib/include/libvfio/vfio_pci_driver.h | 6 +
tools/testing/selftests/vfio/lib/libvfio.mk | 2 +
.../selftests/vfio/lib/vfio_pci_driver.c | 10 +
.../selftests/vfio/vfio_pci_driver_test.c | 3 +-
24 files changed, 2525 insertions(+), 240 deletions(-)
create mode 100644 include/linux/mlx5/mlx5_ifc_macros.h
create mode 100644 tools/arch/arm64/include/asm/io.h
create mode 100644 tools/include/linux/stddef.h
create mode 100644 tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5.c
create mode 100644 tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5_hw.h
create mode 120000 tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5_ifc.h
create mode 120000 tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5_ifc_fpga.h
create mode 120000 tools/testing/selftests/vfio/lib/drivers/mlx5/mlx5_ifc_macros.h
base-commit: a13c140cc289c0b7b3770bce5b3ad42ab35074aa
--
2.43.0
^ permalink raw reply
* [PATCH v3 05/11] selftests: Add additional kernel functions to tools/include/
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
In-Reply-To: <0-v3-76f117ad04f1+28a90-mlx5st_jgg@nvidia.com>
These are needed by the VFIO mlx5 selftest in the following patches,
which includes some headers from mlx5 and also needs a few more
MMIO-related features.
- DECLARE_FLEX_ARRAY in new tools/include/linux/stddef.h (wraps
existing __DECLARE_FLEX_ARRAY from uapi/linux/stddef.h)
- dma_wmb/dma_rmb barriers: x86 uses compiler barrier
(DMA-coherent), arm64 uses dmb oshst/oshld (outer-shareable for
device visibility), generic fallback uses wmb/rmb
- ioread32be/iowrite32be in tools/include/asm-generic/io.h for
big-endian MMIO register access
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: David Matlack <dmatlack@google.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
tools/arch/arm64/include/asm/barrier.h | 4 ++++
tools/arch/x86/include/asm/barrier.h | 5 +++++
tools/include/asm-generic/io.h | 28 ++++++++++++++++++++++++++
tools/include/asm/barrier.h | 8 ++++++++
tools/include/linux/stddef.h | 10 +++++++++
5 files changed, 55 insertions(+)
create mode 100644 tools/include/linux/stddef.h
diff --git a/tools/arch/arm64/include/asm/barrier.h b/tools/arch/arm64/include/asm/barrier.h
index 3b9b41331c4f16..abdc64fc3c70f0 100644
--- a/tools/arch/arm64/include/asm/barrier.h
+++ b/tools/arch/arm64/include/asm/barrier.h
@@ -24,6 +24,10 @@
#define smp_wmb() asm volatile("dmb ishst" ::: "memory")
#define smp_rmb() asm volatile("dmb ishld" ::: "memory")
+/* DMA barriers use outer-shareable (osh) for device visibility */
+#define dma_rmb() asm volatile("dmb oshld" ::: "memory")
+#define dma_wmb() asm volatile("dmb oshst" ::: "memory")
+
#define smp_store_release(p, v) \
do { \
union { typeof(*p) __val; char __c[1]; } __u = \
diff --git a/tools/arch/x86/include/asm/barrier.h b/tools/arch/x86/include/asm/barrier.h
index 0adf295dd5b6aa..0b51431fa530ea 100644
--- a/tools/arch/x86/include/asm/barrier.h
+++ b/tools/arch/x86/include/asm/barrier.h
@@ -43,4 +43,9 @@ do { \
___p1; \
})
#endif /* defined(__x86_64__) */
+
+/* x86 is DMA-coherent so DMA barriers are just compiler barriers */
+#define dma_rmb() barrier()
+#define dma_wmb() barrier()
+
#endif /* _TOOLS_LINUX_ASM_X86_BARRIER_H */
diff --git a/tools/include/asm-generic/io.h b/tools/include/asm-generic/io.h
index e5a0b07ad452a6..0d89decdafb818 100644
--- a/tools/include/asm-generic/io.h
+++ b/tools/include/asm-generic/io.h
@@ -479,4 +479,32 @@ static inline void writesq(volatile void __iomem *addr, const void *buffer,
}
#endif
+/*
+ * ioread/iowrite for big-endian MMIO registers.
+ */
+
+#ifndef ioread32be
+#define ioread32be ioread32be
+static inline u32 ioread32be(const volatile void __iomem *addr)
+{
+ return bswap_32(readl(addr));
+}
+#endif
+
+#ifndef iowrite32be
+#define iowrite32be iowrite32be
+static inline void iowrite32be(u32 value, volatile void __iomem *addr)
+{
+ writel(bswap_32(value), addr);
+}
+#endif
+
+#ifndef iowrite64be
+#define iowrite64be iowrite64be
+static inline void iowrite64be(u64 value, volatile void __iomem *addr)
+{
+ writeq(bswap_64(value), addr);
+}
+#endif
+
#endif /* _TOOLS_ASM_GENERIC_IO_H */
diff --git a/tools/include/asm/barrier.h b/tools/include/asm/barrier.h
index 0c21678ac5e65f..e7e0c7de5a2ffe 100644
--- a/tools/include/asm/barrier.h
+++ b/tools/include/asm/barrier.h
@@ -47,6 +47,14 @@
# define smp_mb() mb()
#endif
+#ifndef dma_rmb
+# define dma_rmb() rmb()
+#endif
+
+#ifndef dma_wmb
+# define dma_wmb() wmb()
+#endif
+
#ifndef smp_store_release
# define smp_store_release(p, v) \
do { \
diff --git a/tools/include/linux/stddef.h b/tools/include/linux/stddef.h
new file mode 100644
index 00000000000000..99182ea4a1419b
--- /dev/null
+++ b/tools/include/linux/stddef.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _TOOLS_LINUX_STDDEF_H
+#define _TOOLS_LINUX_STDDEF_H
+
+#include_next <linux/stddef.h>
+
+#define DECLARE_FLEX_ARRAY(TYPE, NAME) \
+ __DECLARE_FLEX_ARRAY(TYPE, NAME)
+
+#endif /* _TOOLS_LINUX_STDDEF_H */
--
2.43.0
^ permalink raw reply related
* [PATCH v3 07/11] vfio: selftests: Allow drivers to specify required region size
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
In-Reply-To: <0-v3-76f117ad04f1+28a90-mlx5st_jgg@nvidia.com>
Add a region_size field to struct vfio_pci_driver_ops so drivers can
declare how much DMA-mapped region they need. The mlx5 driver will need
~18MB for firmware pages. Existing drivers pass in the sizeof their state
struct. The core code will round up and minimize it to SZ_2M so as not to
change any test behavior.
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c | 1 +
tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c | 1 +
.../selftests/vfio/lib/include/libvfio/vfio_pci_driver.h | 6 ++++++
tools/testing/selftests/vfio/lib/vfio_pci_driver.c | 7 +++++++
tools/testing/selftests/vfio/vfio_pci_driver_test.c | 3 ++-
5 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
index 19d9630b24c23f..40b8541b588eee 100644
--- a/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
+++ b/tools/testing/selftests/vfio/lib/drivers/dsa/dsa.c
@@ -418,6 +418,7 @@ static void dsa_send_msi(struct vfio_pci_device *device)
const struct vfio_pci_driver_ops dsa_ops = {
.name = "dsa",
+ .region_size = sizeof(struct dsa_state),
.probe = dsa_probe,
.init = dsa_init,
.remove = dsa_remove,
diff --git a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
index a871b935542bad..c9b28365c5eb6b 100644
--- a/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
+++ b/tools/testing/selftests/vfio/lib/drivers/ioat/ioat.c
@@ -226,6 +226,7 @@ static void ioat_send_msi(struct vfio_pci_device *device)
const struct vfio_pci_driver_ops ioat_ops = {
.name = "ioat",
+ .region_size = sizeof(struct ioat_state),
.probe = ioat_probe,
.init = ioat_init,
.remove = ioat_remove,
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h
index e5ada209b1d102..547369c5cff95a 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_driver.h
@@ -9,6 +9,12 @@ struct vfio_pci_device;
struct vfio_pci_driver_ops {
const char *name;
+ /*
+ * Size of the driver's state structure overlaid on
+ * device->driver.region.vaddr
+ */
+ u64 region_size;
+
/**
* @probe() - Check if the driver supports the given device.
*
diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
index 6827f4a6febe99..e13bbb7ee423dc 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "kselftest.h"
+#include <linux/sizes.h>
+#include <linux/log2.h>
#include <libvfio.h>
#ifdef __x86_64__
@@ -28,6 +30,11 @@ void vfio_pci_driver_probe(struct vfio_pci_device *device)
continue;
device->driver.ops = ops;
+
+ VFIO_ASSERT_NE(ops->region_size, 0);
+ device->driver.region.size =
+ max_t(u64, roundup_pow_of_two(ops->region_size),
+ getpagesize());
}
}
diff --git a/tools/testing/selftests/vfio/vfio_pci_driver_test.c b/tools/testing/selftests/vfio/vfio_pci_driver_test.c
index afa0480ddd9b2a..f68239da574f5a 100644
--- a/tools/testing/selftests/vfio/vfio_pci_driver_test.c
+++ b/tools/testing/selftests/vfio/vfio_pci_driver_test.c
@@ -80,7 +80,8 @@ FIXTURE_SETUP(vfio_pci_driver_test)
driver = &self->device->driver;
region_setup(self->iommu, self->iova_allocator, &self->memcpy_region, SZ_1G);
- region_setup(self->iommu, self->iova_allocator, &driver->region, SZ_2M);
+ region_setup(self->iommu, self->iova_allocator, &driver->region,
+ driver->region.size);
/* Any IOVA that doesn't overlap memcpy_region and driver->region. */
self->unmapped_iova = iova_allocator_alloc(self->iova_allocator, SZ_1G);
--
2.43.0
^ permalink raw reply related
* [PATCH v3 02/11] net/mlx5: Move HW constant groups from device.h/cq.h to mlx5_ifc.h
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
In-Reply-To: <0-v3-76f117ad04f1+28a90-mlx5st_jgg@nvidia.com>
Generally the IFC file should contain enums for the fields it
defines. Move the ones in device.h that are relevant to the VFIO
selftests over to the IFC file:
wqe_ctrl_seg_bits.opcode: all MLX5_OPCODE_* WQE opcodes
wqe_ctrl_seg_bits.ce: new MLX5_WQE_CE_* completion/event modes
cqe64_bits.opcode: all MLX5_CQE_* CQE opcode values
eqe_bits.event_type: enum mlx5_event (all event types)
cmd_out_bits.status: all MLX5_CMD_STAT_* status codes
query_hca_cap_in_bits.op_mod: enum mlx5_cap_mode
Tidy MLX5_PCI_CMD_XPORT which is an alias of
MLX5_CMD_QUEUE_ENTRY_TYPE_PCIE_CMD_IF_TRANSPORT.
No functional change. All existing users of device.h and cq.h
continue to see these constants through the include chain.
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
include/linux/mlx5/cq.h | 10 ---
include/linux/mlx5/device.h | 114 +------------------------------
include/linux/mlx5/mlx5_ifc.h | 123 ++++++++++++++++++++++++++++++++++
3 files changed, 124 insertions(+), 123 deletions(-)
diff --git a/include/linux/mlx5/cq.h b/include/linux/mlx5/cq.h
index 9d47cdc727ad0d..a1c14479e462c2 100644
--- a/include/linux/mlx5/cq.h
+++ b/include/linux/mlx5/cq.h
@@ -81,16 +81,6 @@ enum {
enum {
MLX5_CQE_OWNER_MASK = 1,
- MLX5_CQE_REQ = 0,
- MLX5_CQE_RESP_WR_IMM = 1,
- MLX5_CQE_RESP_SEND = 2,
- MLX5_CQE_RESP_SEND_IMM = 3,
- MLX5_CQE_RESP_SEND_INV = 4,
- MLX5_CQE_RESIZE_CQ = 5,
- MLX5_CQE_SIG_ERR = 12,
- MLX5_CQE_REQ_ERR = 13,
- MLX5_CQE_RESP_ERR = 14,
- MLX5_CQE_INVALID = 15,
};
enum {
diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index 07a25f26429213..c739a1f578dc44 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -172,7 +172,7 @@ enum mlx5_inline_modes {
enum {
MLX5_MAX_COMMANDS = 32,
MLX5_CMD_DATA_BLOCK_SIZE = 512,
- MLX5_PCI_CMD_XPORT = 7,
+ MLX5_PCI_CMD_XPORT = MLX5_CMD_QUEUE_ENTRY_TYPE_PCIE_CMD_IF_TRANSPORT,
MLX5_MKEY_BSF_OCTO_SIZE = 4,
MLX5_MAX_PSVS = 4,
};
@@ -308,63 +308,6 @@ enum {
MLX5_EVENT_QUEUE_TYPE_DCT = 6,
};
-/* mlx5 components can subscribe to any one of these events via
- * mlx5_eq_notifier_register API.
- */
-enum mlx5_event {
- /* Special value to subscribe to any event */
- MLX5_EVENT_TYPE_NOTIFY_ANY = 0x0,
- /* HW events enum start: comp events are not subscribable */
- MLX5_EVENT_TYPE_COMP = 0x0,
- /* HW Async events enum start: subscribable events */
- MLX5_EVENT_TYPE_PATH_MIG = 0x01,
- MLX5_EVENT_TYPE_COMM_EST = 0x02,
- MLX5_EVENT_TYPE_SQ_DRAINED = 0x03,
- MLX5_EVENT_TYPE_SRQ_LAST_WQE = 0x13,
- MLX5_EVENT_TYPE_SRQ_RQ_LIMIT = 0x14,
-
- MLX5_EVENT_TYPE_CQ_ERROR = 0x04,
- MLX5_EVENT_TYPE_WQ_CATAS_ERROR = 0x05,
- MLX5_EVENT_TYPE_PATH_MIG_FAILED = 0x07,
- MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10,
- MLX5_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11,
- MLX5_EVENT_TYPE_SRQ_CATAS_ERROR = 0x12,
- MLX5_EVENT_TYPE_OBJECT_CHANGE = 0x27,
-
- MLX5_EVENT_TYPE_INTERNAL_ERROR = 0x08,
- MLX5_EVENT_TYPE_PORT_CHANGE = 0x09,
- MLX5_EVENT_TYPE_GPIO_EVENT = 0x15,
- MLX5_EVENT_TYPE_PORT_MODULE_EVENT = 0x16,
- MLX5_EVENT_TYPE_TEMP_WARN_EVENT = 0x17,
- MLX5_EVENT_TYPE_XRQ_ERROR = 0x18,
- MLX5_EVENT_TYPE_REMOTE_CONFIG = 0x19,
- MLX5_EVENT_TYPE_GENERAL_EVENT = 0x22,
- MLX5_EVENT_TYPE_MONITOR_COUNTER = 0x24,
- MLX5_EVENT_TYPE_PPS_EVENT = 0x25,
-
- MLX5_EVENT_TYPE_DB_BF_CONGESTION = 0x1a,
- MLX5_EVENT_TYPE_STALL_EVENT = 0x1b,
-
- MLX5_EVENT_TYPE_CMD = 0x0a,
- MLX5_EVENT_TYPE_PAGE_REQUEST = 0xb,
-
- MLX5_EVENT_TYPE_PAGE_FAULT = 0xc,
- MLX5_EVENT_TYPE_NIC_VPORT_CHANGE = 0xd,
-
- MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED = 0xe,
- MLX5_EVENT_TYPE_VHCA_STATE_CHANGE = 0xf,
-
- MLX5_EVENT_TYPE_DCT_DRAINED = 0x1c,
- MLX5_EVENT_TYPE_DCT_KEY_VIOLATION = 0x1d,
-
- MLX5_EVENT_TYPE_FPGA_ERROR = 0x20,
- MLX5_EVENT_TYPE_FPGA_QP_ERROR = 0x21,
-
- MLX5_EVENT_TYPE_DEVICE_TRACER = 0x26,
-
- MLX5_EVENT_TYPE_MAX = 0x100,
-};
-
enum mlx5_driver_event {
MLX5_DRIVER_EVENT_TYPE_TRAP = 0,
MLX5_DRIVER_EVENT_UPLINK_NETDEV,
@@ -420,22 +363,6 @@ enum {
};
enum {
- MLX5_OPCODE_NOP = 0x00,
- MLX5_OPCODE_SEND_INVAL = 0x01,
- MLX5_OPCODE_RDMA_WRITE = 0x08,
- MLX5_OPCODE_RDMA_WRITE_IMM = 0x09,
- MLX5_OPCODE_SEND = 0x0a,
- MLX5_OPCODE_SEND_IMM = 0x0b,
- MLX5_OPCODE_LSO = 0x0e,
- MLX5_OPCODE_RDMA_READ = 0x10,
- MLX5_OPCODE_ATOMIC_CS = 0x11,
- MLX5_OPCODE_ATOMIC_FA = 0x12,
- MLX5_OPCODE_ATOMIC_MASKED_CS = 0x14,
- MLX5_OPCODE_ATOMIC_MASKED_FA = 0x15,
- MLX5_OPCODE_BIND_MW = 0x18,
- MLX5_OPCODE_CONFIG_CMD = 0x1f,
- MLX5_OPCODE_ENHANCED_MPSW = 0x29,
-
MLX5_RECV_OPCODE_RDMA_WRITE_IMM = 0x00,
MLX5_RECV_OPCODE_SEND = 0x01,
MLX5_RECV_OPCODE_SEND_IMM = 0x02,
@@ -443,19 +370,6 @@ enum {
MLX5_CQE_OPCODE_ERROR = 0x1e,
MLX5_CQE_OPCODE_RESIZE = 0x16,
-
- MLX5_OPCODE_SET_PSV = 0x20,
- MLX5_OPCODE_GET_PSV = 0x21,
- MLX5_OPCODE_CHECK_PSV = 0x22,
- MLX5_OPCODE_DUMP = 0x23,
- MLX5_OPCODE_RGET_PSV = 0x26,
- MLX5_OPCODE_RCHECK_PSV = 0x27,
-
- MLX5_OPCODE_UMR = 0x25,
-
- MLX5_OPCODE_FLOW_TBL_ACCESS = 0x2c,
-
- MLX5_OPCODE_ACCESS_ASO = 0x2d,
};
enum {
@@ -1223,12 +1137,6 @@ enum mlx5_flex_parser_protos {
/* MLX5 DEV CAPs */
-/* TODO: EAT.ME */
-enum mlx5_cap_mode {
- HCA_CAP_OPMOD_GET_MAX = 0,
- HCA_CAP_OPMOD_GET_CUR = 1,
-};
-
/* Any new cap addition must update mlx5_hca_caps_alloc() to allocate
* capability memory.
*/
@@ -1506,26 +1414,6 @@ enum mlx5_qcam_feature_groups {
#define MLX5_CAP_PSP(mdev, cap)\
MLX5_GET(psp_cap, (mdev)->caps.hca[MLX5_CAP_PSP]->cur, cap)
-enum {
- MLX5_CMD_STAT_OK = 0x0,
- MLX5_CMD_STAT_INT_ERR = 0x1,
- MLX5_CMD_STAT_BAD_OP_ERR = 0x2,
- MLX5_CMD_STAT_BAD_PARAM_ERR = 0x3,
- MLX5_CMD_STAT_BAD_SYS_STATE_ERR = 0x4,
- MLX5_CMD_STAT_BAD_RES_ERR = 0x5,
- MLX5_CMD_STAT_RES_BUSY = 0x6,
- MLX5_CMD_STAT_NOT_READY = 0x7,
- MLX5_CMD_STAT_LIM_ERR = 0x8,
- MLX5_CMD_STAT_BAD_RES_STATE_ERR = 0x9,
- MLX5_CMD_STAT_IX_ERR = 0xa,
- MLX5_CMD_STAT_NO_RES_ERR = 0xf,
- MLX5_CMD_STAT_BAD_INP_LEN_ERR = 0x50,
- MLX5_CMD_STAT_BAD_OUTP_LEN_ERR = 0x51,
- MLX5_CMD_STAT_BAD_QP_STATE_ERR = 0x10,
- MLX5_CMD_STAT_BAD_PKT_ERR = 0x30,
- MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40,
-};
-
enum {
MLX5_IEEE_802_3_COUNTERS_GROUP = 0x0,
MLX5_RFC_2863_COUNTERS_GROUP = 0x1,
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index a83eb731764a0f..2d4609aaa1068e 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -5999,6 +5999,39 @@ struct mlx5_ifc_wqe_ctrl_seg_bits {
u8 imm[0x20];
};
+/* Values for wqe_ctrl_seg_bits.opcode */
+enum {
+ MLX5_OPCODE_NOP = 0x00,
+ MLX5_OPCODE_SEND_INVAL = 0x01,
+ MLX5_OPCODE_RDMA_WRITE = 0x08,
+ MLX5_OPCODE_RDMA_WRITE_IMM = 0x09,
+ MLX5_OPCODE_SEND = 0x0a,
+ MLX5_OPCODE_SEND_IMM = 0x0b,
+ MLX5_OPCODE_LSO = 0x0e,
+ MLX5_OPCODE_RDMA_READ = 0x10,
+ MLX5_OPCODE_ATOMIC_CS = 0x11,
+ MLX5_OPCODE_ATOMIC_FA = 0x12,
+ MLX5_OPCODE_ATOMIC_MASKED_CS = 0x14,
+ MLX5_OPCODE_ATOMIC_MASKED_FA = 0x15,
+ MLX5_OPCODE_BIND_MW = 0x18,
+ MLX5_OPCODE_CONFIG_CMD = 0x1f,
+ MLX5_OPCODE_SET_PSV = 0x20,
+ MLX5_OPCODE_GET_PSV = 0x21,
+ MLX5_OPCODE_CHECK_PSV = 0x22,
+ MLX5_OPCODE_DUMP = 0x23,
+ MLX5_OPCODE_UMR = 0x25,
+ MLX5_OPCODE_RGET_PSV = 0x26,
+ MLX5_OPCODE_RCHECK_PSV = 0x27,
+ MLX5_OPCODE_ENHANCED_MPSW = 0x29,
+ MLX5_OPCODE_FLOW_TBL_ACCESS = 0x2c,
+ MLX5_OPCODE_ACCESS_ASO = 0x2d,
+};
+
+/* Values for wqe_ctrl_seg_bits.ce */
+enum {
+ MLX5_WQE_CE_CQE_ALWAYS = 2,
+};
+
struct mlx5_ifc_wqe_raddr_seg_bits {
u8 raddr[0x40];
@@ -6034,6 +6067,20 @@ struct mlx5_ifc_cqe64_bits {
u8 owner[0x1];
};
+/* Values for cqe64_bits.opcode */
+enum {
+ MLX5_CQE_REQ = 0,
+ MLX5_CQE_RESP_WR_IMM = 1,
+ MLX5_CQE_RESP_SEND = 2,
+ MLX5_CQE_RESP_SEND_IMM = 3,
+ MLX5_CQE_RESP_SEND_INV = 4,
+ MLX5_CQE_RESIZE_CQ = 5,
+ MLX5_CQE_SIG_ERR = 12,
+ MLX5_CQE_REQ_ERR = 13,
+ MLX5_CQE_RESP_ERR = 14,
+ MLX5_CQE_INVALID = 15,
+};
+
struct mlx5_ifc_qp_context_extension_bits {
u8 reserved_at_0[0x60];
@@ -6530,6 +6577,12 @@ struct mlx5_ifc_query_hca_cap_in_bits {
u8 reserved_at_60[0x20];
};
+/* Values for query_hca_cap_in_bits.op_mod */
+enum mlx5_cap_mode {
+ HCA_CAP_OPMOD_GET_MAX = 0,
+ HCA_CAP_OPMOD_GET_CUR = 1,
+};
+
struct mlx5_ifc_other_hca_cap_bits {
u8 roce[0x1];
u8 reserved_at_1[0x27f];
@@ -11322,6 +11375,55 @@ struct mlx5_ifc_eqe_bits {
u8 owner[0x1];
};
+/* Values for eqe_bits.event_type */
+enum mlx5_event {
+ /* Special value to subscribe to any event */
+ MLX5_EVENT_TYPE_NOTIFY_ANY = 0x0,
+ /* HW events enum start: comp events are not subscribable */
+ MLX5_EVENT_TYPE_COMP = 0x0,
+ /* HW Async events enum start: subscribable events */
+ MLX5_EVENT_TYPE_PATH_MIG = 0x01,
+ MLX5_EVENT_TYPE_COMM_EST = 0x02,
+ MLX5_EVENT_TYPE_SQ_DRAINED = 0x03,
+ MLX5_EVENT_TYPE_SRQ_LAST_WQE = 0x13,
+ MLX5_EVENT_TYPE_SRQ_RQ_LIMIT = 0x14,
+
+ MLX5_EVENT_TYPE_CQ_ERROR = 0x04,
+ MLX5_EVENT_TYPE_WQ_CATAS_ERROR = 0x05,
+ MLX5_EVENT_TYPE_PATH_MIG_FAILED = 0x07,
+ MLX5_EVENT_TYPE_WQ_INVAL_REQ_ERROR = 0x10,
+ MLX5_EVENT_TYPE_WQ_ACCESS_ERROR = 0x11,
+ MLX5_EVENT_TYPE_SRQ_CATAS_ERROR = 0x12,
+ MLX5_EVENT_TYPE_OBJECT_CHANGE = 0x27,
+
+ MLX5_EVENT_TYPE_INTERNAL_ERROR = 0x08,
+ MLX5_EVENT_TYPE_PORT_CHANGE = 0x09,
+ MLX5_EVENT_TYPE_CMD = 0x0a,
+ MLX5_EVENT_TYPE_PAGE_REQUEST = 0x0b,
+ MLX5_EVENT_TYPE_PAGE_FAULT = 0x0c,
+ MLX5_EVENT_TYPE_NIC_VPORT_CHANGE = 0x0d,
+ MLX5_EVENT_TYPE_ESW_FUNCTIONS_CHANGED = 0x0e,
+ MLX5_EVENT_TYPE_VHCA_STATE_CHANGE = 0x0f,
+ MLX5_EVENT_TYPE_GPIO_EVENT = 0x15,
+ MLX5_EVENT_TYPE_PORT_MODULE_EVENT = 0x16,
+ MLX5_EVENT_TYPE_TEMP_WARN_EVENT = 0x17,
+ MLX5_EVENT_TYPE_XRQ_ERROR = 0x18,
+ MLX5_EVENT_TYPE_REMOTE_CONFIG = 0x19,
+ MLX5_EVENT_TYPE_DB_BF_CONGESTION = 0x1a,
+ MLX5_EVENT_TYPE_STALL_EVENT = 0x1b,
+ MLX5_EVENT_TYPE_DCT_DRAINED = 0x1c,
+ MLX5_EVENT_TYPE_DCT_KEY_VIOLATION = 0x1d,
+ MLX5_EVENT_TYPE_FPGA_ERROR = 0x20,
+ MLX5_EVENT_TYPE_FPGA_QP_ERROR = 0x21,
+ MLX5_EVENT_TYPE_GENERAL_EVENT = 0x22,
+ MLX5_EVENT_TYPE_MONITOR_COUNTER = 0x24,
+ MLX5_EVENT_TYPE_PPS_EVENT = 0x25,
+ MLX5_EVENT_TYPE_DEVICE_TRACER = 0x26,
+
+ MLX5_EVENT_TYPE_MAX = 0x100,
+};
+
+/* Values for cmd_queue_entry_bits.type */
enum {
MLX5_CMD_QUEUE_ENTRY_TYPE_PCIE_CMD_IF_TRANSPORT = 0x7,
};
@@ -11364,6 +11466,27 @@ struct mlx5_ifc_cmd_out_bits {
u8 command_output[0x20];
};
+/* Values for cmd_out_bits.status */
+enum {
+ MLX5_CMD_STAT_OK = 0x0,
+ MLX5_CMD_STAT_INT_ERR = 0x1,
+ MLX5_CMD_STAT_BAD_OP_ERR = 0x2,
+ MLX5_CMD_STAT_BAD_PARAM_ERR = 0x3,
+ MLX5_CMD_STAT_BAD_SYS_STATE_ERR = 0x4,
+ MLX5_CMD_STAT_BAD_RES_ERR = 0x5,
+ MLX5_CMD_STAT_RES_BUSY = 0x6,
+ MLX5_CMD_STAT_NOT_READY = 0x7,
+ MLX5_CMD_STAT_LIM_ERR = 0x8,
+ MLX5_CMD_STAT_BAD_RES_STATE_ERR = 0x9,
+ MLX5_CMD_STAT_IX_ERR = 0xa,
+ MLX5_CMD_STAT_NO_RES_ERR = 0xf,
+ MLX5_CMD_STAT_BAD_QP_STATE_ERR = 0x10,
+ MLX5_CMD_STAT_BAD_PKT_ERR = 0x30,
+ MLX5_CMD_STAT_BAD_SIZE_OUTS_CQES_ERR = 0x40,
+ MLX5_CMD_STAT_BAD_INP_LEN_ERR = 0x50,
+ MLX5_CMD_STAT_BAD_OUTP_LEN_ERR = 0x51,
+};
+
struct mlx5_ifc_cmd_in_bits {
u8 opcode[0x10];
u8 reserved_at_10[0x10];
--
2.43.0
^ permalink raw reply related
* [PATCH v3 01/11] net/mlx5: Add IFC structures for CQE and WQE
From: Jason Gunthorpe @ 2026-07-16 17:03 UTC (permalink / raw)
To: Alex Williamson, David Matlack, Justin Stitt, kvm,
Leon Romanovsky, linux-kselftest, linux-rdma, llvm, Mark Bloch,
Bill Wendling, Nathan Chancellor, Nick Desaulniers, netdev,
Saeed Mahameed, Shuah Khan, Tariq Toukan
Cc: patches
In-Reply-To: <0-v3-76f117ad04f1+28a90-mlx5st_jgg@nvidia.com>
Building the WQE and CQE using the IFC system is easier than with a
C layout struct. Add definitions for their layout. Structs for:
- wqe_ctrl_seg_bits (16B): WQE control segment
- wqe_raddr_seg_bits (16B): RDMA remote address segment
- wqe_data_seg_bits (16B): data segment
- cqe64_bits (64B): 64-byte CQE with error syndrome union
The VFIO mlx5 selftest will use these.
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
include/linux/mlx5/mlx5_ifc.h | 55 +++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index 695c86ee6d7a3f..a83eb731764a0f 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -5979,6 +5979,61 @@ struct mlx5_ifc_cqe_error_syndrome_bits {
u8 syndrome[0x8];
};
+struct mlx5_ifc_wqe_ctrl_seg_bits {
+ u8 opmod[0x8];
+ u8 wqe_index[0x10];
+ u8 opcode[0x8];
+
+ u8 qp_or_sq[0x18];
+ u8 reserved_at_38[0x2];
+ u8 ds[0x6];
+
+ u8 signature[0x8];
+ u8 reserved_at_48[0x10];
+ u8 fm[0x3];
+ u8 reserved_at_5b[0x1];
+ u8 ce[0x2];
+ u8 se[0x1];
+ u8 reserved_at_5f[0x1];
+
+ u8 imm[0x20];
+};
+
+struct mlx5_ifc_wqe_raddr_seg_bits {
+ u8 raddr[0x40];
+
+ u8 rkey[0x20];
+ u8 reserved_at_60[0x20];
+};
+
+struct mlx5_ifc_wqe_data_seg_bits {
+ u8 reserved_at_0[0x1];
+ u8 byte_count[0x1f];
+
+ u8 lkey[0x20];
+
+ u8 addr[0x40];
+};
+
+struct mlx5_ifc_cqe64_bits {
+ u8 reserved_at_0[0x1a0];
+
+ union {
+ u8 reserved_at_1a0[0x20];
+ struct mlx5_ifc_cqe_error_syndrome_bits error_syndrome;
+ };
+
+ u8 send_wqe_opcode[0x8];
+ u8 qpn_or_dctn_or_flow_tag[0x18];
+
+ u8 wqe_counter[0x10];
+ u8 signature[0x8];
+ u8 opcode[0x4];
+ u8 cqe_format[0x2];
+ u8 se[0x1];
+ u8 owner[0x1];
+};
+
struct mlx5_ifc_qp_context_extension_bits {
u8 reserved_at_0[0x60];
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net-next v2 2/2] net: phy: add DAPU Telecom DAP8210R(I) Gigabit Ethernet PHY driver
From: Artem Shimko @ 2026-07-16 17:01 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Heiner Kallweit, Russell King, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-kernel, devicetree
In-Reply-To: <f3be1229-1d46-4cb3-a83f-0715d6789651@lunn.ch>
Hi Andrew,
On Thu, Jul 16, 2026 at 4:55 PM Andrew Lunn <andrew@lunn.ch> wrote:
>
> > + /* Wait for reset self-clear */
> > + do {
> > + fsleep(20);
> > + ret = dap8211r_read_ext(phydev, DAP8211R_PHY_CON);
> > + if (ret < 0)
> > + return ret;
> > + } while (!(ret & DAP8211R_PHY_SW_RST) && --retries);
>
> This does not have the usual problem, but it is still better to use
> something from iopoll.h.
Thank you! I will replace the manual loop with read_poll_timeout() in v3.
--
Best Regards,
Artem
^ permalink raw reply
* Re: [PATCH 2/3] mm, treewide: replace __folio_alloc_node() with folio_alloc_node()
From: Brendan Jackman @ 2026-07-16 17:00 UTC (permalink / raw)
To: Brendan Jackman, Andrew Morton, David Hildenbrand,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Johannes Weiner, Zi Yan,
Matthew Wilcox (Oracle), Jan Kara, Joshua Hahn, Byungchul Park,
Gregory Price, Ying Huang, Alistair Popple, Hugh Dickins,
Baolin Wang, Chris Li, Kairui Song, Kemeng Shi, Nhat Pham,
Baoquan He, Barry Song, Youngjun Park, Joerg Roedel (AMD),
Will Deacon, Robin Murphy, Huacai Chen, WANG Xuerui,
Thomas Gleixner, Chuck Lever, Jeff Layton, NeilBrown,
Olga Kornievskaia, Dai Ngo, Tom Talpey, Trond Myklebust,
Anna Schumaker, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman
Cc: linux-kernel, linux-mm, linux-fsdevel, iommu, loongarch,
linux-nfs, netdev
In-Reply-To: <20260716-folio-alloc-cleanups-v1-2-5363b8e92d33@google.com>
On Thu Jul 16, 2026 at 2:30 PM UTC, Brendan Jackman wrote:
> Commit 5b584d2d22dca ("mm: remove __alloc_pages_node()") removed the __
Oh, I just remembered this commit hash is unstable. In fact it's already
wrong.
> variant of alloc_pages_node(), after users had been migrated off it,
> since it just complicates the API (requiring users to handle
> NUMA_NO_NODE, or risking hotplug bugs) for no real benefit.
^ permalink raw reply
* Re: [PATCH 1/3] mm: move internal mempolicy APIs to new internal header
From: Brendan Jackman @ 2026-07-16 16:57 UTC (permalink / raw)
To: Matthew Wilcox, Brendan Jackman
Cc: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Johannes Weiner, Zi Yan,
Jan Kara, Joshua Hahn, Byungchul Park, Gregory Price, Ying Huang,
Alistair Popple, Hugh Dickins, Baolin Wang, Chris Li, Kairui Song,
Kemeng Shi, Nhat Pham, Baoquan He, Barry Song, Youngjun Park,
Joerg Roedel (AMD), Will Deacon, Robin Murphy, Huacai Chen,
WANG Xuerui, Thomas Gleixner, Chuck Lever, Jeff Layton, NeilBrown,
Olga Kornievskaia, Dai Ngo, Tom Talpey, Trond Myklebust,
Anna Schumaker, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, linux-kernel, linux-mm, linux-fsdevel,
iommu, loongarch, linux-nfs, netdev
In-Reply-To: <alkLSzQvzT9zJbY1@casper.infradead.org>
On Thu Jul 16, 2026 at 4:48 PM UTC, Matthew Wilcox wrote:
> On Thu, Jul 16, 2026 at 02:30:10PM +0000, Brendan Jackman wrote:
>> There are no external users for this surface, reduce the scope.
>> -struct folio *folio_alloc_mpol_noprof(gfp_t gfp, unsigned int order,
>> - struct mempolicy *mpol, pgoff_t ilx, int nid);
>
> Hm. So what we're saying is that allocations which respect mempolicy are
> only for core mm and not for, eg, device drivers to do. Is that really
> what we want to say? I don't think so, because that's inconsistent
> with having just widened __filemap_get_folio_mpol to allow guest_memfd
> to specify a mempolicy.
Yeah I agree, mempolicy definitely seems like a "public concept". All
I'm saying here is this specific function doesn't have any external
users so it doesn't need to be an external header.
... With the ulterior motive that I want to add a new parameter to it
that actually _is_ mm-internal. Namely, alloc_flags, so I can add
ALLOC_UNMAPPED to implement AS_NO_DIRECT_MAP, i.e. the next iteration of
[0]. So basically this is
about trying to extend the allocator without creating a GFP flag.
So I'm envisaging if an external user arises for it later, we'd slap two
underscores on the beginning of the internal one, (with the alloc_flags
arg), and then bring back the public one as a wrapper.
Does that make sense?
[0]: https://lore.kernel.org/all/20260410151746.61150-1-kalyazin@amazon.com/
^ permalink raw reply
* Re: [PATCH net-next v2 2/2] net: phy: add DAPU Telecom DAP8210R(I) Gigabit Ethernet PHY driver
From: Artem Shimko @ 2026-07-16 16:57 UTC (permalink / raw)
To: Maxime Chevallier
Cc: netdev, Andrew Lunn, Heiner Kallweit, Russell King,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-kernel,
devicetree
In-Reply-To: <c7193123-72e1-4bf5-85f7-eb68a4000c44@bootlin.com>
Hi Maxime,
On Thu, Jul 16, 2026 at 4:02 PM Maxime Chevallier
<maxime.chevallier@bootlin.com> wrote:
> You can simplify the whole delay parsing a log by using phy_get_internal_delay().
> It will give you the index of the delay from the delay table you have :)
>
> https://elixir.bootlin.com/linux/v7.1.3/source/drivers/net/phy/phy_device.c#L3085
>
> You can take a look at the few drivers that use it (mscc, dp83869) for reference
Oh, great =) Thank you!
--
Best Regards,
Artem
^ permalink raw reply
* [syzbot] [rds?] KCSAN: data-race in rds_sendmsg / rds_sendmsg (3)
From: syzbot @ 2026-07-16 16:50 UTC (permalink / raw)
To: achender, allison.henderson, davem, edumazet, horms, kuba,
linux-kernel, linux-rdma, netdev, pabeni, rds-devel,
syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: 3b029c035b34 Merge tag 'cgroup-for-7.2-rc3-fixes' of git:/..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=1638fb89580000
kernel config: https://syzkaller.appspot.com/x/.config?x=84b3039e8461eef5
dashboard link: https://syzkaller.appspot.com/bug?extid=879c1877016972360186
compiler: Debian clang version 22.1.8 (++20260613092233+e80beda6e255-1~exp1~20260613092250.77), Debian LLD 22.1.8
Unfortunately, I don't have any reproducer for this issue yet.
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/9ab6065d4938/disk-3b029c03.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/7373fbe29535/vmlinux-3b029c03.xz
kernel image: https://storage.googleapis.com/syzbot-assets/938cb90d037d/bzImage-3b029c03.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+879c1877016972360186@syzkaller.appspotmail.com
==================================================================
BUG: KCSAN: data-race in rds_sendmsg / rds_sendmsg
write to 0xffff888101dec818 of 8 bytes by task 30904 on cpu 0:
rds_sendmsg+0xc1f/0x1580 net/rds/send.c:1332
sock_sendmsg_nosec net/socket.c:775 [inline]
__sock_sendmsg net/socket.c:790 [inline]
____sys_sendmsg+0x532/0x580 net/socket.c:2684
___sys_sendmsg+0x195/0x1e0 net/socket.c:2738
__sys_sendmsg net/socket.c:2770 [inline]
__do_sys_sendmsg net/socket.c:2775 [inline]
__se_sys_sendmsg net/socket.c:2773 [inline]
__x64_sys_sendmsg+0xd4/0x160 net/socket.c:2773
x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x136/0x3c0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
write to 0xffff888101dec818 of 8 bytes by task 30905 on cpu 1:
rds_sendmsg+0xc1f/0x1580 net/rds/send.c:1332
sock_sendmsg_nosec net/socket.c:775 [inline]
__sock_sendmsg net/socket.c:790 [inline]
____sys_sendmsg+0x532/0x580 net/socket.c:2684
___sys_sendmsg+0x195/0x1e0 net/socket.c:2738
__sys_sendmsg net/socket.c:2770 [inline]
__do_sys_sendmsg net/socket.c:2775 [inline]
__se_sys_sendmsg net/socket.c:2773 [inline]
__x64_sys_sendmsg+0xd4/0x160 net/socket.c:2773
x64_sys_call+0x194c/0x3020 arch/x86/include/generated/asm/syscalls_64.h:47
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x136/0x3c0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
value changed: 0x0000000000000000 -> 0xffff88811b61faf0
Reported by Kernel Concurrency Sanitizer on:
CPU: 1 UID: 0 PID: 30905 Comm: syz.5.5733 Tainted: G W syzkaller #0 PREEMPT(lazy)
Tainted: [W]=WARN
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/09/2026
==================================================================
atomic_op ffff888118e74d28 conn xmit_atomic 0000000000000000
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply
* Re: [PATCH 1/3] mm: move internal mempolicy APIs to new internal header
From: Matthew Wilcox @ 2026-07-16 16:48 UTC (permalink / raw)
To: Brendan Jackman
Cc: Andrew Morton, David Hildenbrand, Lorenzo Stoakes,
Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Johannes Weiner, Zi Yan,
Jan Kara, Joshua Hahn, Byungchul Park, Gregory Price, Ying Huang,
Alistair Popple, Hugh Dickins, Baolin Wang, Chris Li, Kairui Song,
Kemeng Shi, Nhat Pham, Baoquan He, Barry Song, Youngjun Park,
Joerg Roedel (AMD), Will Deacon, Robin Murphy, Huacai Chen,
WANG Xuerui, Thomas Gleixner, Chuck Lever, Jeff Layton, NeilBrown,
Olga Kornievskaia, Dai Ngo, Tom Talpey, Trond Myklebust,
Anna Schumaker, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, linux-kernel, linux-mm, linux-fsdevel,
iommu, loongarch, linux-nfs, netdev
In-Reply-To: <20260716-folio-alloc-cleanups-v1-1-5363b8e92d33@google.com>
On Thu, Jul 16, 2026 at 02:30:10PM +0000, Brendan Jackman wrote:
> There are no external users for this surface, reduce the scope.
> -struct folio *folio_alloc_mpol_noprof(gfp_t gfp, unsigned int order,
> - struct mempolicy *mpol, pgoff_t ilx, int nid);
Hm. So what we're saying is that allocations which respect mempolicy are
only for core mm and not for, eg, device drivers to do. Is that really
what we want to say? I don't think so, because that's inconsistent
with having just widened __filemap_get_folio_mpol to allow guest_memfd
to specify a mempolicy.
^ permalink raw reply
* Re: [Patch net-next v2 2/2] net: phy: Add driver for Motorcomm Quad 2.5GbE phy
From: Andrew Lunn @ 2026-07-16 16:48 UTC (permalink / raw)
To: Kyle Switch
Cc: Frank.Sae, hkallweit1, linux, davem, edumazet, kuba, pabeni,
netdev, linux-kernel, jianmin.wang, xiaolin.xu, ming.xu, jie.han
In-Reply-To: <20260715121012.1113552-1-kyle.switch@motor-comm.com>
> +static inline int ytphy_top_write(struct phy_device *phydev, u32 regnum,
> + u16 val)
No inline functions in .C files. And this is a PHY driver, it is a
long way from the hot path, optimisations are not needed.
As i said elsewhere, please look at phy_package.c. It might result in
better code, and a more obvious locking model.
> +/**
> + * ytphy_read_top_ext() - read a PHY's top extended register for YT8824
> + * @phydev: a pointer to a &struct phy_device
> + * @regnum: register number to read
> + *
> + * NOTE:The caller must have taken the MDIO bus lock.
Rather that have this comment, use lockdep_assert_held() to prove it
has been taken.
Maybe add a phy_assert_lock_mdio_bus(struct phy_device *phydev) next
to phy_lock_mdio_bus() and phy_unlock_mdio_bus(), to hide away all the
pointer following.
Andrew
---
pw-bot: cr
^ permalink raw reply
* Re: [RFC PATCH net-next v0 6/6] net: apply RCS to GeoNetworking
From: Simon Dietz @ 2026-07-16 16:39 UTC (permalink / raw)
To: simon.dietz
Cc: andrew+netdev, davem, dietz23838, edumazet, johannes, kuniyu,
linux-wireless, netdev
In-Reply-To: <20260716162152.3616762-1-dietz23838@hs-ansbach.de>
I am sorry for the now misformatted patch series tree and for the
partial transmission of this patch series. It turned out that because
I used git send-email --dry-run before actually sending the patch
series, which drained the email send limit per hour of my mail/hosting
provider. I now use(d) my university email address, which enforces a
(much higher) daily email send limit, instead and it worked. I hope
not to have caused too much inconvenience.
Simon
^ permalink raw reply
* [PATCH 6.12] vsock/virtio: fix zerocopy completion for multi-skb sends
From: Alexander Martyniuk @ 2026-07-16 16:35 UTC (permalink / raw)
To: stable, Greg Kroah-Hartman
Cc: Alexander Martyniuk, lvc-project, Michael S. Tsirkin, Jason Wang,
Xuan Zhuo, Eugenio Pérez, Stefan Hajnoczi,
Stefano Garzarella, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman, Arseniy Krasnov, virtualization, kvm,
netdev, linux-kernel, Maher Azzouzi
From: Stefano Garzarella <sgarzare@redhat.com>
commit ae38d9179190a956e2a87a69ef1dd6f451b51c4d upstream.
When a large message is fragmented into multiple skbs, the zerocopy
uarg is only allocated and attached to the last skb in the loop.
Non-final skbs carry pinned user pages with no completion tracking,
so the kernel has no way to notify userspace when those pages are safe
to reuse. If the loop breaks early the uarg is never allocated at all,
leaking pinned pages with no completion notification.
Fix this by following the approach used by TCP: allocate the zerocopy
uarg (if not provided by the caller) before the send loop and attach
it to every skb via skb_zcopy_set(), which takes a reference per skb.
Each skb's completion properly decrements the refcount, and the
notification only fires after the last skb is freed.
On failure, if no data was sent, the uarg is cleanly aborted via
net_zcopy_put_abort().
This issue was initially discovered by sashiko while reviewing commit
1cb36e252211 ("vsock/virtio: fix MSG_ZEROCOPY pinned-pages accounting")
but was pre-existing.
Fixes: 581512a6dc93 ("vsock/virtio: MSG_ZEROCOPY flag support")
Closes: https://sashiko.dev/#/patchset/20260420132051.217589-1-sgarzare%40redhat.com
Reported-by: Maher Azzouzi <maherazz04@gmail.com>
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Acked-by: Arseniy Krasnov <avkrasnov@salutedevices.com>
Link: https://patch.msgid.link/20260514092948.268720-1-sgarzare@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Alexander Martyniuk <alexevgmart@gmail.com>
---
Backport fix for CVE-2026-53365
net/vmw_vsock/virtio_transport_common.c | 78 +++++++++++--------------
1 file changed, 34 insertions(+), 44 deletions(-)
diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
index 95170c7be758..aeb205e84bd3 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -72,35 +72,6 @@ static bool virtio_transport_can_zcopy(const struct virtio_transport *t_ops,
return true;
}
-static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk,
- struct sk_buff *skb,
- struct msghdr *msg,
- bool zerocopy)
-{
- struct ubuf_info *uarg;
-
- if (msg->msg_ubuf) {
- uarg = msg->msg_ubuf;
- net_zcopy_get(uarg);
- } else {
- struct iov_iter *iter = &msg->msg_iter;
- struct ubuf_info_msgzc *uarg_zc;
-
- uarg = msg_zerocopy_realloc(sk_vsock(vsk),
- iter->count,
- NULL);
- if (!uarg)
- return -1;
-
- uarg_zc = uarg_to_msgzc(uarg);
- uarg_zc->zerocopy = zerocopy ? 1 : 0;
- }
-
- skb_zcopy_init(skb, uarg);
-
- return 0;
-}
-
static int virtio_transport_fill_skb(struct sk_buff *skb,
struct virtio_vsock_pkt_info *info,
size_t len,
@@ -321,8 +292,10 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
u32 src_cid, src_port, dst_cid, dst_port;
const struct virtio_transport *t_ops;
struct virtio_vsock_sock *vvs;
+ struct ubuf_info *uarg = NULL;
u32 pkt_len = info->pkt_len;
bool can_zcopy = false;
+ bool have_uref = false;
u32 rest_len;
int ret;
@@ -364,6 +337,25 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
if (can_zcopy)
max_skb_len = min_t(u32, VIRTIO_VSOCK_MAX_PKT_BUF_SIZE,
(MAX_SKB_FRAGS * PAGE_SIZE));
+
+ if (info->msg->msg_flags & MSG_ZEROCOPY &&
+ info->op == VIRTIO_VSOCK_OP_RW) {
+ uarg = info->msg->msg_ubuf;
+
+ if (!uarg) {
+ uarg = msg_zerocopy_realloc(sk_vsock(vsk),
+ pkt_len, NULL);
+ if (!uarg) {
+ virtio_transport_put_credit(vvs, pkt_len);
+ return -ENOMEM;
+ }
+
+ if (!can_zcopy)
+ uarg_to_msgzc(uarg)->zerocopy = 0;
+
+ have_uref = true;
+ }
+ }
}
rest_len = pkt_len;
@@ -382,21 +374,7 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
break;
}
- /* We process buffer part by part, allocating skb on
- * each iteration. If this is last skb for this buffer
- * and MSG_ZEROCOPY mode is in use - we must allocate
- * completion for the current syscall.
- */
- if (info->msg && info->msg->msg_flags & MSG_ZEROCOPY &&
- skb_len == rest_len && info->op == VIRTIO_VSOCK_OP_RW) {
- if (virtio_transport_init_zcopy_skb(vsk, skb,
- info->msg,
- can_zcopy)) {
- kfree_skb(skb);
- ret = -ENOMEM;
- break;
- }
- }
+ skb_zcopy_set(skb, uarg, NULL);
virtio_transport_inc_tx_pkt(vvs, skb);
@@ -420,6 +398,18 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,
virtio_transport_put_credit(vvs, rest_len);
+ /* msg_zerocopy_realloc() initializes the ubuf_info refcnt to 1.
+ * skb_zcopy_set() increases it for each skb, so we can drop that
+ * initial reference to keep it balanced.
+ */
+ if (have_uref) {
+ if (rest_len == pkt_len)
+ /* No data sent, abort the notification. */
+ net_zcopy_put_abort(uarg, true);
+ else
+ net_zcopy_put(uarg);
+ }
+
/* Return number of bytes, if any data has been sent. */
if (rest_len != pkt_len)
ret = pkt_len - rest_len;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net-next 1/2] dt-bindings: net: Add Maxio MAE0621A PHY
From: Andrew Lunn @ 2026-07-16 16:36 UTC (permalink / raw)
To: Liu Changjie
Cc: Heiner Kallweit, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev, Russell King, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel
In-Reply-To: <MN0PR19MB6091ABAD3F4E6AC5FFD44E34ACF92@MN0PR19MB6091.namprd19.prod.outlook.com>
> + maxio,clk-out-frequency-hz:
> + description:
> + Selects a 125 MHz clock on the CLKOUT pin. If the property is absent,
> + the hardware strap or bootloader configuration is preserved.
> + const: 125000000
Not required, but maybe consider the value of 0 meaning the clock
should be disabled? If the MAC does not need it, turning it off can
save a little power.
This is something which can also be added later.
Andrew
^ permalink raw reply
* Re: [PATCH net-next 0/2] net: phy: Add Maxio MAE0621A support
From: Andrew Lunn @ 2026-07-16 16:32 UTC (permalink / raw)
To: Liu Changjie
Cc: Heiner Kallweit, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev, Russell King, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, devicetree, linux-kernel
In-Reply-To: <MN0PR19MB609111152E1C759EC7F13DC6ACC72@MN0PR19MB6091.namprd19.prod.outlook.com>
On Fri, Jul 17, 2026 at 12:14:17AM +0800, Liu Changjie wrote:
> Hi Andrew,
>
> > What happens when 100Mbps or 10Mbps is negotiated? Has that been
> > tested?
>
> Thanks for asking. I had only exercised 1 Gbit/s before sending this
> series.
>
> I have now repeated the test with autonegotiation enabled on both ends,
> restricting the link partner advertisement to one full-duplex mode at a
> time.
Thanks for the extensive testing. There is no need to give the details
in the commit message, just make the current comment indicate that all
link modes have been tested.
Andrew
^ permalink raw reply
* Re: net: rnpgbe: Pass an expression directly in rnpgbe_rm_adapter()
From: Markus Elfring @ 2026-07-16 16:30 UTC (permalink / raw)
To: Jonathan Corbet, netdev, kernel-janitors
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
MD Danish Anwar, Michael Grzeschik, Paolo Abeni,
Uwe Kleine-König, Vadim Fedorenko, Yibo Dong, LKML,
Dan Carpenter
In-Reply-To: <877bmv9fif.fsf@trenco.lwn.net>
>> Does your understanding of programming language details differ from the view
>> by Jonathan Corbet?
>
> I'm not sure why you keep dragging me into this
You are one of the contributors who pointed a specific control flow out as a bug.
> - I have not opined on
> this particular situation,
I got an other impression.
> which is definitely *not* a dereference.
Does such a feedback indicate a questionable communication difficulty?
Regards,
Markus
^ permalink raw reply
* Re: [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO
From: Alice Mikityanska @ 2026-07-16 16:28 UTC (permalink / raw)
To: Simon Horman
Cc: alice.kernel, daniel, davem, edumazet, kuba, pabeni, lucien.xin,
willemdebruijn.kernel, willemb, dsahern, razor, shuah, stfomichev,
andrew+netdev, fw, netdev
In-Reply-To: <20260716144724.333095-2-horms@kernel.org>
On Thu, 16 Jul 2026 at 17:47, Simon Horman <horms@kernel.org> 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.
> Full review at: https://sashiko.dev
> ---
> --- Patch [2]: [PATCH net-next v9 2/9] net: Enable BIG TCP with partial GSO ---
> commit b8199f77774400021642eb53bd60ec1a062a54ef
> Author: Alice Mikityanska <alice@isovalent.com>
>
> net: Enable BIG TCP with partial GSO
>
> This commit removes the 65534-byte clamp on segment length in skb_segment
> for partial GSO. It stores the gso_by_frags flag early to allow BIG TCP
> packets to use larger lengths without accidental resegmentation.
>
> > diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> > index 18dabb4e9cfa0..6ae4c2b205f2e 100644
> > --- a/net/core/skbuff.c
> > +++ b/net/core/skbuff.c
>
> [ ... ]
>
> > @@ -4852,9 +4853,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
> > /* GSO partial only requires that we trim off any excess that
> > * doesn't fit into an MSS sized block, so take care of that
> > * now.
> > - * Cap len to not accidentally hit GSO_BY_FRAGS.
> > */
> > - partial_segs = min(len, GSO_BY_FRAGS - 1) / mss;
> > + partial_segs = len / mss;
>
> [Severity: High]
> When removing the clamp on partial GSO segments, mss is scaled up without any
> upper bound. For BIG TCP packets, could this construct segments that exceed
> MAX_SKB_FRAGS?
>
> If a 512KB packet is passed to skb_segment() for partial GSO, mss is scaled
> up to the full packet length. When attempting to build this single large
> segment by flattening the frag_list into a new frags array, it appears it
> would hit the fragment limit and abort:
>
> net/core/skbuff.c:skb_segment() {
> ...
> if (unlikely(skb_shinfo(nskb)->nr_frags >=
> MAX_SKB_FRAGS)) {
> net_warn_ratelimited(
> "skb_segment: too many frags: %u %u\n",
> pos, mss);
> err = -EINVAL;
> goto err;
> }
> ...
> }
>
> Does this deterministically drop BIG TCP traffic over tunnels that require
> partial GSO?
I already addressed this exact concern here:
https://lore.kernel.org/netdev/1cf2746f-f15b-406d-bb49-2c3f2dee1ec2@app.fastmail.com/
Key points:
1. skb_segment can fail with "too many frags" before my changes, even
without BIG TCP. It's not a new bug that my patch adds.
2. tcp_sendmsg_locked doesn't build frag_list SKBs, and non-frag_list
SKBs never fail in skb_segment with "too many frags".
3. When sending a TCP stream, 32768-byte high order pages are
allocated, so even a 512 KB SKB can be represented without frag_list
(and if such high-order allocation fails, tcp_sendmsg_locked won't use
frag_list anyway).
4. The only scenario I can think of to get "too many frags" with
partial GSO is receiving traffic and forwarding it to a partial GSO
netdev. But again, then it easily hits "too many frags" even without
BIG TCP or my changes (see the repro by the link above).
There is definitely no "deterministic drop of BIG TCP" here, because
of #2, and the selftest shows that it works.
So, I'm open to discussion on how to make skb_segment more reliable (I
wrote one idea by the link above), but I don't think it should block
this series.
> [Severity: Medium]
> Can the partial_segs calculation exceed 65535 for malicious inputs and cause
> a 16-bit truncation?
>
> If a crafted packet with a very small gso_size (for example, mss=1 via an
> untrusted packet socket) and a large payload is segmented, len / mss could
> produce a value greater than 65535.
>
> When this 32-bit value is later assigned to the 16-bit field in skb_segment():
>
> net/core/skbuff.c:skb_segment() {
> ...
> skb_shinfo(iter)->gso_segs = partial_segs;
> ...
> }
I'll clamp partial_segs to GSO_MAX_SEGS=65535 to make sure that
gso_segs doesn't overflow. Worst case, in an extreme scenario of
gso_size=1, partial GSO will produce more than 2 output SKBs, but the
traffic should still flow — this is how BIG TCP SKBs were handled by
skb_segment before this change.
This overflow shouldn't be possible with TCP, because
TCP_MIN_GSO_SIZE=8, but AI suggests that virtio_net_hdr_to_skb can
accept any gso_size, even 1, which makes such overflow possible.
> Could this silent truncation corrupt hardware engine programming or Byte Queue
> Limits?
>
> > if (partial_segs > 1)
> > mss *= partial_segs;
> > else
>
> [ ... ]
^ permalink raw reply
* Re: [PATCH net-next v2 12/14] gpio: tc956x: add TC956x/QPS615 support
From: Alex Elder @ 2026-07-16 16:24 UTC (permalink / raw)
To: Manivannan Sadhasivam
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, maxime.chevallier,
rmk+kernel, andersson, konradybcio, robh, krzk+dt, conor+dt,
linusw, brgl, arnd, gregkh, daniel, mohd.anwar, a0987203069,
alexandre.torgue, ast, boon.khai.ng, chenchuangyu, chenhuacai,
daniel, hawk, hkallweit1, inochiama, john.fastabend, julianbraha,
livelycarpet87, mcoquelin.stm32, me, prabhakar.mahadev-lad.rj,
richardcochran, rohan.g.thomas, sdf, siyanteng, weishangjuan,
wens, netdev, bpf, linux-arm-msm, devicetree, linux-gpio,
linux-stm32, linux-arm-kernel, linux-kernel
In-Reply-To: <dhnylud7o5dhaaq6kvbes4vkml3ppa5ev542j2lyxdijibknzg@pfcy22wz6jav>
On 7/16/26 2:02 AM, Manivannan Sadhasivam wrote:
> On Thu, Jun 04, 2026 at 08:00:19PM -0500, Alex Elder wrote:
>> Toshiba TC956x is an Ethernet-AVB/TSN bridge and is essentially
>> a small and highly-specialized SoC. TC956x includes a GPIO block that
>> can be accessed, alongside several other peripherals, via two PCIe
>> endpoint functions. The PCIe function driver creates an auxiliary
>> device for the GPIO block, and that device gets bound to this auxiliary
>> device driver.
>>
>> This driver is implemented using the generic regmap-based GPIO driver.
>>
>
> While the regmap over the switch BAR works for GPIO access post-enumeration,
> there is a blocker in using these GPIOs to control the power to endpoints.
We're aware of the power control driver and its use of these GPIOs.
I think the point you're making is not about the specific way we
are using GPIOs, but that someone could try to use this GPIO
controller in a way that would lead to a circular dependency
(between the controller and the PCIe device it depends on).
And you suggest a GPIO driver that uses I2C (and would be
used by the pwrctrl driver as well), and I think it's a pretty
reasonable suggestion.
> We have a design [1] where the GPIOs from the switch are used to control power
> and PERST# signals to the EP. With this current design, during the initial PCI
> bus scan, the switch will get enumerated, but the EP will not. Because, power to
> the EP depends on the GPIO Aux driver that will get probed only after the switch
> enumeration.
Yes, on the RB3gen2 platform, reset signals (PERST#) for two of
the TC9563 PCIe switch ports (downstream 1 and downstream 2) are
managed by the GPIO controller that resides within the TC9563
itself. The pwrctl driver takes special care to ensure the GPIO
controller is functional (powered) before trying to use it.
The TC9563 *chip* gets powered when its embedded PCIe switch is
probed--that is, when its upstream port begins its enumeration.
(It's a little unclear to me which of the supplies are required
for the various non-PCIe components on the chip, including I2C
and GPIO, to be functional.)
And so until the switch gets probed (and its pwrctl driver used),
the GPIO controller can't work. So nothing internal to the TC956x
should be dependent on any of the GPIOs supplied by this controller.
(Except the pwrctrl driver, which enables power before using GPIO.)
Two things to note:
- We are working with TC9564 (and there are other successors in
the TC956x series).
- Downstream port 3 (which we are using) on the switch does not
have such a distinct controlled reset line.
> But this creates a chicken-and-egg problem with the PCI Pwrctrl design.
> pcie-qcom driver uses the Pwrctrl framework to power on the PCI endpoints before
> the initial PCI bus scan. It calls pci_pwrctrl_create_devices() and
> pci_pwrctrl_power_on_devices() APIs to create the platform device for all PCI
> devices defined in DT (that require pwrctrl support), waits for their respective
> pwrctrl drivers to get probed and then power ON all of them.
The way I understood it was that certain parameters for the PCIe
links needed to be set before using them, and the pwrctrl framework
made that possible. (I summarize what that driver does at the end
of this message.)
This step is
> required because in DT platforms, many Root Ports are not hotplug capable and
> also BIOS doesn't assign bridge windows during boot. So all the devices has to
> appear during the initial PCI bus scan so that the PCI core can allocate the
> resources properly.
This part I didn't know before. Yes, the bridge windows are
allocated by Linux rather than by firmware. And if this host
bridge doesn't support hotplug, then yes, to correctly assign
address space, all PCIe devices must be available to report
their required memory space.
Are you saying that "setting those parameters" wouldn't be
needed if this particular root port supported hotplug? (I'm
just curious; it's not relevant to the point you're making.)
> Now the issue with this Aux driver design is that, if an EP makes use of the
> switch GPIO for PERST# or power, like:
>
> tc9563: pcie@0,0 {
> compatible = "pci1179,0623";
> reg = <0x10000 0x0 0x0 0x0 0x0>;
> ...
>
> pcie@1,0 {
> compatible = "pciclass,0604";
> reg = <0x20800 0x0 0x0 0x0 0x0>;
> #address-cells = <3>;
> #size-cells = <2>;
>
> device_type = "pci";
> ranges;
> bus-range = <0x3 0xff>;
>
> reset-gpios = <&tc9563 5 GPIO_ACTIVE_LOW>;
> };
> ...
>
> };
>
> Then the pwrctrl driver (pci/pwrctrl/generic.c) will try to acquire the GPIO
> controller during its probe, but will fail with -EPROBE_DEFER as the GPIO
> controller won't be available at that time. So the whole PCIe instance will
> probe defer as the driver requires all pwrctrl drivers to be probed before
> starting the initial bus scan.
The only GPIOs we're using are for asserting reset on the two
Ethernet PHYs. That doesn't occur until after the embedded
endpoint functions are probed, so this should be OK.
However you're right, the lines on this GPIO controller should
be restricted to avoid this circular dependency.
> So we need to make sure that the GPIO controller driver is available before
> enumerating the switch device. One way to achieve is by creating the GPIO Aux
> device in the pci/pwrctrl/pci-pwrctrl-tc9563.c driver and let the GPIO
> controller driver use I2C communication for setting up the GPIOs. Thankfully,
> the switch allows both I2C and BAR MMIO configurations for internal GPIOs.
Daniel and I have talked about this solution exactly, but opted
not to propose using it just yet (not unless someone like you
suggested it...). Our solution for now was just to have the
(PCIe BAR-based) GPIO driver reserve the two GPIO lines used by
the pwrctrl driver, and rely on the fact that the pwrctrl driver
will only touch those shared registers at times the "real" GPIO
driver does not.
We could instead implement a "proper" I2C-based GPIO controller
driver. This would be used by the pwrctrl driver (rather than
that driver just updating the registers directly), as well as
the Ethernet PHY for reset control, and for any other uses on
future platforms.
All uses so far are for managing resets, so the higher I2C
latency wouldn't be much of an issue.
> With this change, the GPIO driver will get probed by the time the pwrctrl
> generic driver acquires the 'reset-gpios' and will turn ON the EP.
One thing I'll point out is that the next version of this
code will define "pci-ep-bus" nodes, and will not use the
auxiliary bus model. However the issue you raise remains
in that model too.
Thank you very much for raising this Mani. Please see my
questions a little further below.
-Alex
> Let me know your thoughts!
>
> - Mani
>
> [1] https://lore.kernel.org/linux-pci/e2inl7k5gsjj6oomv2k5ximuzpb3gfiz66ufet3b4hvov7zqt4@qz4pifbos7yf/
Here's what the pwrctrl driver does:
In drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c, the registers at
offset 0x1208 and 0x1210 from the base of the "SFR" address space
are updated to assert/deassert these two reset signals. It does
so using the I2C interface--out of band from access via PCI BARs.
The reset signals are GPIO02 (for downstream endpoint 1 on the
switch) and GPIO03 (for endpoint 2), which are controlled by
bits 2 and 3 in the two registers, respectively.
The pwrctrl driver enables a set of regulators defined in the
devicetree node for the upstream port of the TC9564 embedded
PCIe switch. It then asserts the main RESX (chip) reset signal,
and after a short delay asserts these other two resets.
At that point it uses properties defined in devicetree to
configure five "ports": upstream, downstream 1-3, and Ethernet.
(I have some questions related to this--but I put them below.)
The properties configured are: ASPM L0s entry delay; ASP L1 entry
delay; TX amplitude; Number of Fast Training Sequences (NTFS); and
Decision Feedback Equalization (DFE).
Finally, the two resets and the main RESX reset are deasserted,
and the driver reports that the device is now ready, with:
devm_pci_pwrctrl_device_set_ready();
Questions related to the "ports" configured by the pwrctrl driver:
- Given that downstream port 3 connects to the internal, embedded
PCIe endpoint, does it still require these settings programmed?
- Does the TC9563 chip have only *one* function on its embedded
endpoint, supporting just one Ethernet?
- If so, this driver will have to be modified to support
the second embedded function and Ethernet controller.
- Why is "Ethernet" configured like the PCIe ports, *in addition*
to the downstream port 3 that it sits behind?
>> Co-developed-by: Daniel Thompson <daniel@riscstar.com>
>> Signed-off-by: Daniel Thompson <daniel@riscstar.com>
>> Signed-off-by: Alex Elder <elder@riscstar.com>
>> ---
>> MAINTAINERS | 1 +
>> drivers/gpio/Kconfig | 12 ++++
>> drivers/gpio/Makefile | 1 +
>> drivers/gpio/gpio-tc956x.c | 130 +++++++++++++++++++++++++++++++++++++
>> 4 files changed, 144 insertions(+)
>> create mode 100644 drivers/gpio/gpio-tc956x.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 0924f7ec43cb0..0439607d1155f 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -27057,6 +27057,7 @@ M: Alex Elder <elder@kernel.org>
>> M: Daniel Thompson <danielt@kernel.org>
>> S: Maintained
>> F: Documentation/devicetree/bindings/net/toshiba,tc956x-dwmac.yaml
>> +F: drivers/gpio/gpio-tc956x.c
>> F: drivers/misc/tc956x_pci.c
>>
>> TOSHIBA WMI HOTKEYS DRIVER
>> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
>> index 020e51e30317a..36631ca722fa3 100644
>> --- a/drivers/gpio/Kconfig
>> +++ b/drivers/gpio/Kconfig
>> @@ -743,6 +743,18 @@ config GPIO_TB10X
>> select GPIO_GENERIC
>> select GENERIC_IRQ_CHIP
>>
>> +config GPIO_TC956X
>> + tristate "Toshiba TC956X GPIO support"
>> + depends on TOSHIBA_TC956X_PCI
>> + select GPIO_REGMAP
>> + default m
>> + help
>> + This enables support for the GPIO controller embedded in the Toshiba
>> + TC956X (and Qualcomm QPS615). This device connects to the host
>> + via PCIe port, which is the upstream port on an internal PCIe
>> + switch. On some platforms, a few of the GPIO lines are used to
>> + manage external resets.
>> +
>> config GPIO_TEGRA
>> tristate "NVIDIA Tegra GPIO support"
>> default ARCH_TEGRA
>> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
>> index b267598b517de..c3584e7cba9b4 100644
>> --- a/drivers/gpio/Makefile
>> +++ b/drivers/gpio/Makefile
>> @@ -178,6 +178,7 @@ obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
>> obj-$(CONFIG_GPIO_TANGIER) += gpio-tangier.o
>> obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
>> obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
>> +obj-$(CONFIG_GPIO_TC956X) += gpio-tc956x.o
>> obj-$(CONFIG_GPIO_TEGRA186) += gpio-tegra186.o
>> obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
>> obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
>> diff --git a/drivers/gpio/gpio-tc956x.c b/drivers/gpio/gpio-tc956x.c
>> new file mode 100644
>> index 0000000000000..0dc6b1028d970
>> --- /dev/null
>> +++ b/drivers/gpio/gpio-tc956x.c
>> @@ -0,0 +1,130 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +/*
>> + * Copyright (C) 2026 by RISCstar Solutions Corporation. All rights reserved.
>> + */
>> +
>> +/*
>> + * The Toshiba TC956X implements a PCIe Gen 3 switch that connects an
>> + * upstream x4 port to two downstream PCIe x2 ports. It incorporates
>> + * an internal endpoint on a internal PCIe port that implements two
>> + * Synopsys XGMAC Ethernet interfaces.
>> + *
>> + * 35 GPIOs are also implemented by an embedded GPIO controller. Three
>> + * registers control the first 32 GPIOs (other than 20 and 21, which are
>> + * reserved). Three other registers control GPIOs 32 through 36. GPIOs
>> + * 22-24, 27-28, 31, and 34 are treated as "input only".
>> + *
>> + * There is a TC956X PCI power controller driver that accesses the
>> + * direction and output value registers for GPIOs 2 and 3. These
>> + * GPIOs control the reset signal for the two downstream PCIe ports.
>> + * Their values will never change during operation of this driver, and
>> + * this driver reserves these two GPIOS.
>> + */
>> +
>> +#include <linux/auxiliary_bus.h>
>> +#include <linux/gpio/driver.h>
>> +#include <linux/module.h>
>> +#include <linux/regmap.h>
>> +#include <linux/gpio/regmap.h>
>> +
>> +#define DRIVER_NAME "tc956x-gpio"
>> +
>> +#define TC956X_GPIO_COUNT 37 /* Number of GPIOs (20-21 reserved) */
>> +
>> +/* The GPIO offsets are relative to 0x1200 in TC956X SFR space. */
>> +#define GPIO_IN0_OFFSET 0x00 /* Input value (0-31) */
>> +#define GPIO_EN0_OFFSET 0x08 /* 0: out; 1: in (0-31) */
>> +#define GPIO_OUT0_OFFSET 0x10 /* Output value (0-31) */
>> +
>> +/*
>> + * There are two sets of registers, each representing (up to) 32 GPIOs with a
>> + * stride of 4 bytes (IN1 is 4 bytes past IN0, EN1 is 4 bytes past EN0, etc.).
>> + */
>> +#define GPIO_PER_REG 32
>> +#define GPIO_REG_STRIDE 4
>> +
>> +static int tc956x_gpio_init_valid_mask(struct gpio_chip *gc,
>> + unsigned long *valid_mask,
>> + unsigned int ngpios)
>> +{
>> + /*
>> + * GPIOs 2 and 3 are used by the PCI power control driver, and
>> + * we don't allow them to be used. GPIOs 20 and 21 are reserved
>> + * (and not usable).
>> + */
>> + bitmap_fill(valid_mask, ngpios);
>> + bitmap_clear(valid_mask, 2, 2);
>> + bitmap_clear(valid_mask, 20, 2);
>> +
>> + return 0;
>> +}
>> +
>> +static int tc956x_gpio_probe(struct auxiliary_device *adev,
>> + const struct auxiliary_device_id *id)
>> +{
>> + DECLARE_BITMAP(zeroes, TC956X_GPIO_COUNT);
>> + DECLARE_BITMAP(fixed, TC956X_GPIO_COUNT);
>> + struct gpio_regmap_config config = { };
>> + struct gpio_regmap *gpio_regmap;
>> + struct device *dev = &adev->dev;
>> +
>> + /* We need the regmap pointer, stored in our platform data */
>> + if (!dev->platform_data)
>> + return -EINVAL;
>> +
>> + /*
>> + * Only some of our GPIOs are fixed direction:
>> + * 22, 23, 24, 27, 28, 31, and 34 (all input-only)
>> + * Set up the fixed bitmap to indicate which are fixed.
>> + */
>> + bitmap_zero(fixed, TC956X_GPIO_COUNT);
>> + bitmap_set(fixed, 22, 3);
>> + bitmap_set(fixed, 27, 2);
>> + set_bit(31, fixed);
>> + set_bit(34, fixed);
>> +
>> + /* All fixed GPIOs are input; the zeroes bitmap indicates that. */
>> + bitmap_zero(zeroes, TC956X_GPIO_COUNT);
>> +
>> + config.parent = dev;
>> + config.regmap = dev->platform_data;
>> + config.label = DRIVER_NAME;
>> + config.ngpio = TC956X_GPIO_COUNT;
>> + config.reg_dat_base = GPIO_REGMAP_ADDR(GPIO_IN0_OFFSET);
>> + config.reg_set_base = GPIO_REGMAP_ADDR(GPIO_OUT0_OFFSET);
>> + config.reg_dir_in_base = GPIO_REGMAP_ADDR(GPIO_EN0_OFFSET);
>> + config.reg_stride = GPIO_REG_STRIDE;
>> + config.ngpio_per_reg = GPIO_PER_REG;
>> + config.init_valid_mask = tc956x_gpio_init_valid_mask;
>> + config.fixed_direction_mask = fixed;
>> + config.fixed_direction_output = zeroes;
>> +
>> + gpio_regmap = devm_gpio_regmap_register(dev, &config);
>> + if (IS_ERR(gpio_regmap))
>> + return PTR_ERR(gpio_regmap);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct auxiliary_device_id tc956x_gpio_ids[] = {
>> + { .name = "tc956x_pci.tc9564-gpio", },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(auxiliary, tc956x_gpio_ids);
>> +
>> +static struct auxiliary_driver tc956x_gpio_driver = {
>> + .name = DRIVER_NAME,
>> + .probe = tc956x_gpio_probe,
>> + .id_table = tc956x_gpio_ids,
>> + .driver = {
>> + .name = DRIVER_NAME,
>> + .owner = THIS_MODULE,
>> + .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>> + },
>> +};
>> +module_auxiliary_driver(tc956x_gpio_driver);
>> +
>> +MODULE_DESCRIPTION("Toshiba TC956X PCIe GPIO Driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("auxiliary:" DRIVER_NAME);
>> --
>> 2.51.0
>>
>
^ permalink raw reply
* [RFC PATCH net-next v0 6/6] net: apply RCS to GeoNetworking
From: Simon Dietz @ 2026-07-16 16:21 UTC (permalink / raw)
To: simon.dietz
Cc: andrew+netdev, davem, dietz23838, edumazet, johannes, kuniyu,
linux-wireless, netdev
In-Reply-To: <20260716161605.3587079-1-dietz23838@hs-ansbach.de>
From: Simon Dietz <simon.dietz@plantwatch.de>
Signed-off-by: Simon Dietz <simon.dietz@plantwatch.de>
---
net/gn/gn_proc.c | 2 +-
net/gn/gn_prot.c | 123 +++++++++++++++++++++++---------------------
net/gn/gn_routing.c | 24 ++++-----
3 files changed, 76 insertions(+), 73 deletions(-)
diff --git a/net/gn/gn_proc.c b/net/gn/gn_proc.c
index ecd2aea446e5..bc1280079695 100644
--- a/net/gn/gn_proc.c
+++ b/net/gn/gn_proc.c
@@ -38,8 +38,8 @@ static void gn_seq_socket_stop(struct seq_file *seq, void *v)
static int gn_seq_socket_show(struct seq_file *seq, void *v)
{
- struct sock *s;
struct gn_sock *gn;
+ struct sock *s;
if (v == SEQ_START_TOKEN) {
seq_puts(seq, "Type Local_addr Remote_addr Tx_queue Rx_queue St UID\n");
diff --git a/net/gn/gn_prot.c b/net/gn/gn_prot.c
index 1599dc0aa185..c8a6d4a78771 100644
--- a/net/gn/gn_prot.c
+++ b/net/gn/gn_prot.c
@@ -99,8 +99,9 @@ static void gn_activate_beacon(void);
static struct gn_iface *gn_if_add_device(struct net_device *dev,
struct sockaddr_gn *sa)
{
+ struct gn_iface *new_gnif = kzalloc_obj(*new_gnif, GFP_KERNEL);
+ struct gn_iface *gnif;
bool was_empty;
- struct gn_iface *gnif, *new_gnif = kzalloc_obj(*new_gnif, GFP_KERNEL);
if (!new_gnif)
return NULL;
@@ -138,8 +139,8 @@ static struct gn_iface *gn_if_add_device(struct net_device *dev,
static void gn_if_drop_device(struct net_device *dev)
{
- struct gn_iface *gnif;
struct hlist_node *tmp;
+ struct gn_iface *gnif;
spin_lock_bh(&gn_interfaces_lock);
hlist_for_each_entry_safe(gnif, tmp, &gn_interfaces, hnode) {
@@ -154,8 +155,8 @@ static void gn_if_drop_device(struct net_device *dev)
static void gn_interfaces_clear(void)
{
- struct gn_iface *gnif;
struct hlist_node *tmp;
+ struct gn_iface *gnif;
spin_lock_bh(&gn_interfaces_lock);
hlist_for_each_entry_safe(gnif, tmp, &gn_interfaces, hnode) {
@@ -341,8 +342,8 @@ try_next_port:;
static struct sock *gn_find_or_insert_socket(struct sock *sk,
struct sockaddr_gn *sgn)
{
- struct sock *s;
struct gn_sock *gn;
+ struct sock *s;
write_lock_bh(&gn_sockets_lock);
sk_for_each(s, &gn_sockets) {
@@ -373,9 +374,11 @@ static int gn_bind(struct socket *sock, struct sockaddr_unsized *uaddr,
{
DECLARE_SOCKADDR(struct sockaddr_gn *, addr, uaddr);
struct sock *sk = sock->sk;
- struct gn_sock *gn = gn_sk(sk);
+ struct gn_sock *gn;
int err;
+ gn = gn_sk(sk);
+
if (!sock_flag(sk, SOCK_ZAPPED) ||
addr_len != sizeof(struct sockaddr_gn))
return -EINVAL;
@@ -413,10 +416,12 @@ static int gn_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
int addr_len, int flags)
{
struct sock *sk = sock->sk;
- struct gn_sock *gn = gn_sk(sk);
struct sockaddr_gn *addr;
+ struct gn_sock *gn;
int err;
+ gn = gn_sk(sk);
+
sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
@@ -450,8 +455,8 @@ static int gn_connect(struct socket *sock, struct sockaddr_unsized *uaddr,
static struct sock *gn_search_socket(struct sockaddr_gn *tosgn,
struct gn_iface *gnif)
{
- struct sock *s;
struct gn_sock *gn;
+ struct sock *s;
read_lock_bh(&gn_sockets_lock);
sk_for_each(s, &gn_sockets) {
@@ -537,11 +542,11 @@ static void gn_fill_bh_ch_nopayload(struct gn_iface *gnif,
static void gn_location_service_req(struct gn_iface *gnif, gn_address_t saddr,
gn_address_t daddr)
{
- int size = 0;
- struct sk_buff *skb;
- struct gn_basic_header *gb_h;
- struct gn_common_header *gc_h;
struct gn_ls_request_header *gls_h;
+ struct gn_common_header *gc_h;
+ struct gn_basic_header *gb_h;
+ struct sk_buff *skb;
+ int size = 0;
size += gn_dl->header_length;
size += gnif->dev->hard_header_len;
@@ -577,11 +582,11 @@ static void gn_location_service_reply(struct gn_spv *depv,
struct gn_iface *gnif, gn_address_t addr,
u64 llc)
{
- int size;
- struct sk_buff *skb;
- struct gn_basic_header *gb_h;
- struct gn_common_header *gc_h;
struct gn_ls_reply_header *gls_h;
+ struct gn_common_header *gc_h;
+ struct gn_basic_header *gb_h;
+ struct sk_buff *skb;
+ int size;
size = 0;
size += gn_dl->header_length;
@@ -616,8 +621,8 @@ static void gn_location_service_reply(struct gn_spv *depv,
static int gn_pass_payload_sock(struct sockaddr_gn *tosgn, struct sk_buff *skb)
{
- struct sock *sock;
int rc = NET_RX_DROP;
+ struct sock *sock;
sock = gn_search_socket(tosgn, NULL);
if (!sock)
@@ -631,9 +636,9 @@ static int gn_pass_payload_sock(struct sockaddr_gn *tosgn, struct sk_buff *skb)
static int gn_forward_guc_packet(struct sk_buff *skb, gn_address_t dest_addr)
{
struct sk_buff *forward_skb;
+ u8 next_hop_mac[ETH_ALEN];
struct gn_header *fwd_gh;
struct gn_iface *gnif;
- u8 next_hop_mac[ETH_ALEN];
fwd_gh = (struct gn_header *)skb_network_header(skb);
if (fwd_gh->gb_h.rhl <= 0)
@@ -684,10 +689,10 @@ static int gn_forward_tsb_packet(struct sk_buff *skb)
static int gn_process_guc_packet(struct sk_buff *skb)
{
- struct gn_header *gh;
struct btp_header *btp_h;
struct sockaddr_gn tosgn;
struct gn_iface *gnif;
+ struct gn_header *gh;
gh = (struct gn_header *)skb_network_header(skb);
GN_SET_BTP(skb, btp_h, struct gn_guc_header);
@@ -764,14 +769,14 @@ static struct gn_geo_scope gn_decode_geo_scope(struct gn_header *gh)
static int gn_process_gxc_packet(struct sk_buff *skb)
{
- struct gn_header *gh;
+ unsigned long long next_hop_addr;
+ struct gn_geo_scope scope;
struct btp_header *btp_h;
struct sockaddr_gn tosgn;
struct gn_iface *gnif;
- s64 f_value;
- struct gn_geo_scope scope;
+ struct gn_header *gh;
bool run_dpd;
- unsigned long long next_hop_addr;
+ s64 f_value;
next_hop_addr = GN_BROADCAST_ADDR;
@@ -821,8 +826,8 @@ static int gn_process_gxc_packet(struct sk_buff *skb)
// Forwarding
if (gh->gb_h.rhl > 0 && ((gh->gc_h.ht == CH_HT_GAC && f_value >= 0) ||
gh->gc_h.ht == CH_HT_GBC)) {
- struct sk_buff *forward_skb;
struct gn_basic_header *fwd_gb_h;
+ struct sk_buff *forward_skb;
u8 dest_addr[ETH_ALEN];
int rc;
@@ -873,9 +878,9 @@ static int gn_process_gxc_packet(struct sk_buff *skb)
static int gn_process_shb_packet(struct sk_buff *skb, const u8 *ll_address)
{
- struct gn_header *gh;
struct btp_header *btp_h;
struct sockaddr_gn tosgn;
+ struct gn_header *gh;
gh = (struct gn_header *)skb_network_header(skb);
GN_SET_BTP(skb, btp_h, struct gn_shb_header);
@@ -905,9 +910,9 @@ static int gn_process_shb_packet(struct sk_buff *skb, const u8 *ll_address)
static int gn_process_tsb_packet(struct sk_buff *skb)
{
- struct gn_header *gh;
struct btp_header *btp_h;
struct sockaddr_gn tosgn;
+ struct gn_header *gh;
gh = (struct gn_header *)skb_network_header(skb);
GN_SET_BTP(skb, btp_h, struct gn_tsb_header);
@@ -955,9 +960,9 @@ static int gn_process_beacon_packet(struct sk_buff *skb, const u8 *llc)
static int gn_process_ls_packet(struct sk_buff *skb)
{
- struct gn_header *gh;
gn_address_t dest_addr;
struct gn_iface *gnif;
+ struct gn_header *gh;
gh = (struct gn_header *)skb_network_header(skb);
@@ -1221,28 +1226,27 @@ static int gn_fill_tsb_header(struct gn_tsb_header *tsb_h,
*/
static int gn_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
{
- int packet_type, packet_subtype, btp_type;
- int err = -EINVAL;
- struct sock *sk = sock->sk;
- struct gn_sock *gn = gn_sk(sk);
-
- /*
- * usgn will contain address and port of the destination
- */
DECLARE_SOCKADDR(struct sockaddr_gn *, usgn, msg->msg_name);
- int flags = msg->msg_flags;
- struct sockaddr_gn local_sgn;
- struct sk_buff *skb;
- struct net_device *dev;
- struct btp_header *btp_h;
- void *gp_h;
+ int packet_type, packet_subtype, btp_type;
struct gn_common_header *gc_h;
struct gn_basic_header *gb_h;
+ struct sockaddr_gn local_sgn;
+ struct gn_spv depv = { 0 };
+ u8 rhl = DEFAULT_HOP_LIMIT;
+ int flags = msg->msg_flags;
+ struct btp_header *btp_h;
+ struct net_device *dev;
struct gn_iface *gnif;
- u32 size;
+ struct sk_buff *skb;
+ struct gn_sock *gn;
+ int err = -EINVAL;
+ struct sock *sk;
u32 eh_size;
- u8 rhl = DEFAULT_HOP_LIMIT;
- struct gn_spv depv = { 0 };
+ void *gp_h;
+ u32 size;
+
+ sk = sock->sk;
+ gn = gn_sk(sk);
if (flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT)) {
pr_warn("unsupported sendmsg flags");
@@ -1514,13 +1518,12 @@ static int gn_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
int flags)
{
struct sock *sk = sock->sk;
+ struct gn_header *gh;
struct sk_buff *skb;
- int err = 0;
u16 copied = 0;
+ int err = 0;
u32 offset;
- struct gn_header *gh;
-
/* It is necessary to find the actual length of the payload, which,
* in case of an unsecured package, resides in the commonheader and
* still has to be calculated without the length of the btp-header
@@ -1562,11 +1565,11 @@ static int gn_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
static int gn_send_beacon(struct gn_iface *gnif)
{
/* Note: Media dependent procedures (e.g. ITS-G5 DCC / DCC Access) evaluated here */
- unsigned int size;
- struct gn_basic_header *gb_h;
- struct gn_common_header *gc_h;
struct gn_beacon_header *gbe_h;
+ struct gn_common_header *gc_h;
+ struct gn_basic_header *gb_h;
struct sk_buff *skb;
+ unsigned int size;
size = gn_dl->header_length;
size += gnif->dev->hard_header_len;
@@ -1660,11 +1663,12 @@ static int validate_scope(struct gn_scope *scope)
static int gn_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsigned int optlen)
{
- struct gn_scope opt;
struct sock *sk = sock->sk;
- struct gn_sock *gn = gn_sk(sk);
-
int rc = -ENOPROTOOPT;
+ struct gn_scope opt;
+ struct gn_sock *gn;
+
+ gn = gn_sk(sk);
if (level != SOL_GN || optname != GN_SCOPE)
goto out;
@@ -1693,9 +1697,11 @@ static int gn_setsockopt(struct socket *sock, int level, int optname,
static int gn_getsockopt(struct socket *sock, int level, int optname,
char __user *optval, int __user *optlen)
{
- struct sock *sk = sock->sk;
- struct gn_sock *gn = gn_sk(sk);
int len, rc = -ENOPROTOOPT;
+ struct sock *sk = sock->sk;
+ struct gn_sock *gn;
+
+ gn = gn_sk(sk);
if (level != SOL_GN || optname != GN_SCOPE)
goto out;
@@ -1737,12 +1743,11 @@ static int gn_validate_pos(struct gn_position *pos)
*/
static int gn_if_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
{
+ struct gn_iface *gnif = NULL;
struct sockaddr_gn *sa;
struct net_device *dev;
- struct ifreq gnreq;
struct gn_position pos;
-
- struct gn_iface *gnif = NULL;
+ struct ifreq gnreq;
if (copy_from_user(&gnreq, argp, sizeof(gnreq)))
return -EFAULT;
@@ -1824,9 +1829,9 @@ static int gn_if_ioctl(struct socket *sock, unsigned int cmd, void __user *argp)
static int gn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
- int rc = -ENOIOCTLCMD;
- struct sock *sk = sock->sk;
void __user *argp = (void __user *)arg;
+ struct sock *sk = sock->sk;
+ int rc = -ENOIOCTLCMD;
switch (cmd) {
/* Protocol layer */
diff --git a/net/gn/gn_routing.c b/net/gn/gn_routing.c
index 3672a345530f..c438c6ab6666 100644
--- a/net/gn/gn_routing.c
+++ b/net/gn/gn_routing.c
@@ -189,9 +189,9 @@ static inline u64 dist(struct gn_coord c)
*/
__s64 gn_F(struct gn_coord self, struct gn_geo_scope scope)
{
+ struct gn_coord coord_diff = gn_coord_diff(self, scope.coord);
s32 a2, b2, x2, y2;
s64 result = -1;
- struct gn_coord coord_diff = gn_coord_diff(self, scope.coord);
/* Note: Scope angle rotation for non-circular geographical areas */
a2 = scope.a * scope.a;
b2 = scope.b * scope.b;
@@ -223,12 +223,11 @@ __s64 gn_F(struct gn_coord self, struct gn_geo_scope scope)
static int greedy_forward(struct gn_iface *gnif, u8 *addr, struct gn_lpv *depv)
{
+ struct gn_coord dest_coord = pv_to_coord(depv);
+ u64 min_dist, curr_dist, ego_dist;
+ u8 *found_addr = NULL;
struct loc_te *curr;
int bkt, rc;
- u8 *found_addr = NULL;
-
- u64 min_dist, curr_dist, ego_dist;
- struct gn_coord dest_coord = pv_to_coord(depv);
ego_dist = dist(gn_coord_diff(dest_coord, gnif->pos.coord));
min_dist = ego_dist;
@@ -279,8 +278,8 @@ int gn_gxc_forward(struct gn_iface *gnif, s64 f, u8 *addr, struct gn_lpv *depv)
static void debug_loc_te(void)
{
- struct loc_te *entry;
struct hlist_node *tmp;
+ struct loc_te *entry;
int bucket;
spin_lock_bh(&gn_loc_t_lock);
@@ -301,11 +300,10 @@ static void debug_loc_te(void)
static void gn_prune(void)
{
+ struct hlist_node *tmp;
struct loc_te *entry;
int bucket;
- struct hlist_node *tmp;
-
spin_lock_bh(&gn_loc_t_lock);
hash_for_each_safe(gn_loc_t, bucket, tmp, entry, hnode) {
if (!GN_TST_VALID(entry->tst_addr)) {
@@ -406,8 +404,8 @@ int gn_update_location_table(struct gn_lpv *pv, bool make_neighbour,
static void __ls_queue(struct sk_buff_head *q, struct sk_buff *skb)
{
- struct sk_buff *curr;
u32 qlen = skb_queue_len(q);
+ struct sk_buff *curr;
while (qlen-- > GN_LSB_SIZE) {
curr = skb_dequeue(q);
@@ -479,9 +477,9 @@ int gn_ls_queue(gn_address_t dest_addr, struct sk_buff *skb)
void gn_ls_flush(gn_address_t dest_addr)
{
- struct loc_te *entry;
struct sk_buff *tmp_skb;
u8 ll_address[ETH_ALEN];
+ struct loc_te *entry;
bool has_mac = false;
spin_lock_bh(&gn_loc_t_lock);
@@ -557,9 +555,9 @@ int gn_query_ll_address(gn_address_t query_addr, u8 *ll_address)
*/
int gn_query_ll_nexthop(struct gn_iface *gnif, gn_address_t query_addr, u8 *ll_address)
{
- struct loc_te *entry;
- struct gn_lpv target_pv;
bool is_neighbor = false;
+ struct gn_lpv target_pv;
+ struct loc_te *entry;
bool found = false;
spin_lock_bh(&gn_loc_t_lock);
@@ -620,9 +618,9 @@ int gn_fill_depv(struct gn_spv *depv, gn_address_t dest_addr)
void gn_routing_exit(void)
{
+ struct hlist_node *tmp;
struct loc_te *entry;
int bucket;
- struct hlist_node *tmp;
spin_lock_bh(&gn_loc_t_lock);
hash_for_each_safe(gn_loc_t, bucket, tmp, entry, hnode) {
--
2.55.0
^ permalink raw reply related
* Re: net: rnpgbe: Pass an expression directly in rnpgbe_rm_adapter()
From: Markus Elfring @ 2026-07-16 16:19 UTC (permalink / raw)
To: Dan Carpenter, netdev, kernel-janitors
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
MD Danish Anwar, Michael Grzeschik, Paolo Abeni,
Uwe Kleine-König, Vadim Fedorenko, Yibo Dong, LKML,
Jonathan Corbet
In-Reply-To: <aljc8RRt8OuYz90H@stanley.mountain>
> Jonathan Corbet's article talks about dereferences.
>
> p = tun->sk;
> ^^^^^^^
> This is a dereference.
>
> p = &tun->sk;
> ^
> This is pointer math. It's not a dereference.
Can such a development view be confusing?
Is the operator “address of” applied only after a pointer dereference attempt in this case?
https://en.cppreference.com/c/language/operator_member_access
Regards,
Markus
^ 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