AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/09/19 07:21 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch refactors the ConnectX-8 Data Direct feature, moving resource and device management from mlx5_ib to mlx5_core. The modified code resides entirely within the Mellanox mlx5 driver stack (mlx5_core and mlx5_ib) and relies on vendor-specific Mellanox PCIe hardware (e.g., ConnectX-8 PCI ID 0x2100) that is not emulated in standard virtualized fuzzing environments (QEMU/GCE), making the changes structurally unreachable.",
  "WorthFuzzing": false
}

1/1 2026/09/19 07:21 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 57abb4f2f1203b172941c916f83e1f734c977d40\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Sep 19 07:21:11 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/infiniband/hw/mlx5/Makefile b/drivers/infiniband/hw/mlx5/Makefile\nindex dd7bb377f4910..35afc7bc57d2f 100644\n--- a/drivers/infiniband/hw/mlx5/Makefile\n+++ b/drivers/infiniband/hw/mlx5/Makefile\n@@ -6,7 +6,6 @@ mlx5_ib-y := ah.o \\\n \t     cong.o \\\n \t     counters.o \\\n \t     cq.o \\\n-\t     data_direct.o \\\n \t     dm.o \\\n \t     dmah.o \\\n \t     doorbell.o \\\ndiff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c\nindex 7c08e30089277..895b62cc528df 100644\n--- a/drivers/infiniband/hw/mlx5/cmd.c\n+++ b/drivers/infiniband/hw/mlx5/cmd.c\n@@ -245,24 +245,3 @@ int mlx5_cmd_uar_dealloc(struct mlx5_core_dev *dev, u32 uarn, u16 uid)\n \tMLX5_SET(dealloc_uar_in, in, uid, uid);\n \treturn mlx5_cmd_exec_in(dev, dealloc_uar, in);\n }\n-\n-int mlx5_cmd_query_vuid(struct mlx5_core_dev *dev, bool data_direct,\n-\t\t\tchar *out_vuid)\n-{\n-\tu8 out[MLX5_ST_SZ_BYTES(query_vuid_out) +\n-\t\tMLX5_ST_SZ_BYTES(array1024_auto)] = {};\n-\tu8 in[MLX5_ST_SZ_BYTES(query_vuid_in)] = {};\n-\tchar *vuid;\n-\tint err;\n-\n-\tMLX5_SET(query_vuid_in, in, opcode, MLX5_CMD_OPCODE_QUERY_VUID);\n-\tMLX5_SET(query_vuid_in, in, vhca_id, MLX5_CAP_GEN(dev, vhca_id));\n-\tMLX5_SET(query_vuid_in, in, data_direct, data_direct);\n-\terr = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));\n-\tif (err)\n-\t\treturn err;\n-\n-\tvuid = MLX5_ADDR_OF(query_vuid_out, out, vuid);\n-\tmemcpy(out_vuid, vuid, MLX5_ST_SZ_BYTES(array1024_auto));\n-\treturn 0;\n-}\ndiff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h\nindex e6c88b6ebd0da..e5cd31270443d 100644\n--- a/drivers/infiniband/hw/mlx5/cmd.h\n+++ b/drivers/infiniband/hw/mlx5/cmd.h\n@@ -58,6 +58,4 @@ int mlx5_cmd_mad_ifc(struct mlx5_ib_dev *dev, const void *inb, void *outb,\n \t\t     u16 opmod, u8 port);\n int mlx5_cmd_uar_alloc(struct mlx5_core_dev *dev, u32 *uarn, u16 uid);\n int mlx5_cmd_uar_dealloc(struct mlx5_core_dev *dev, u32 uarn, u16 uid);\n-int mlx5_cmd_query_vuid(struct mlx5_core_dev *dev, bool data_direct,\n-\t\t\tchar *out_vuid);\n #endif /* MLX5_IB_CMD_H */\ndiff --git a/drivers/infiniband/hw/mlx5/data_direct.c b/drivers/infiniband/hw/mlx5/data_direct.c\ndeleted file mode 100644\nindex d57484245c382..0000000000000\n--- a/drivers/infiniband/hw/mlx5/data_direct.c\n+++ /dev/null\n@@ -1,227 +0,0 @@\n-// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB\n-/*\n- * Copyright (c) 2024, NVIDIA CORPORATION \u0026 AFFILIATES. All rights reserved\n- */\n-\n-#include \"mlx5_ib.h\"\n-#include \"data_direct.h\"\n-\n-static LIST_HEAD(mlx5_data_direct_dev_list);\n-static LIST_HEAD(mlx5_data_direct_reg_list);\n-\n-/*\n- * This mutex should be held when accessing either of the above lists\n- */\n-static DEFINE_MUTEX(mlx5_data_direct_mutex);\n-\n-struct mlx5_data_direct_registration {\n-\tstruct mlx5_ib_dev *ibdev;\n-\tchar vuid[MLX5_ST_SZ_BYTES(array1024_auto) + 1];\n-\tstruct list_head list;\n-};\n-\n-static const struct pci_device_id mlx5_data_direct_pci_table[] = {\n-\t{ PCI_VDEVICE(MELLANOX, 0x2100) }, /* ConnectX-8 Data Direct */\n-\t{ 0, }\n-};\n-\n-static int mlx5_data_direct_vpd_get_vuid(struct mlx5_data_direct_dev *dev)\n-{\n-\tstruct pci_dev *pdev = dev-\u003epdev;\n-\tunsigned int vpd_size, kw_len;\n-\tu8 *vpd_data;\n-\tint start;\n-\tint ret;\n-\n-\tvpd_data = pci_vpd_alloc(pdev, \u0026vpd_size);\n-\tif (IS_ERR(vpd_data)) {\n-\t\tpci_err(pdev, \"Unable to read VPD, err=%pe\\n\", vpd_data);\n-\t\treturn PTR_ERR(vpd_data);\n-\t}\n-\n-\tstart = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, \"VU\", \u0026kw_len);\n-\tif (start \u003c 0) {\n-\t\tret = start;\n-\t\tpci_err(pdev, \"VU keyword not found, err=%d\\n\", ret);\n-\t\tgoto end;\n-\t}\n-\n-\tdev-\u003evuid = kmemdup_nul(vpd_data + start, kw_len, GFP_KERNEL);\n-\tret = dev-\u003evuid ? 0 : -ENOMEM;\n-\n-end:\n-\tkfree(vpd_data);\n-\treturn ret;\n-}\n-\n-static void mlx5_data_direct_shutdown(struct pci_dev *pdev)\n-{\n-\tpci_disable_device(pdev);\n-}\n-\n-static int mlx5_data_direct_set_dma_caps(struct pci_dev *pdev)\n-{\n-\tint err;\n-\n-\terr = dma_set_mask_and_coherent(\u0026pdev-\u003edev, DMA_BIT_MASK(64));\n-\tif (err) {\n-\t\tdev_warn(\u0026pdev-\u003edev,\n-\t\t\t \"Warning: couldn't set 64-bit PCI DMA mask, err=%d\\n\", err);\n-\t\terr = dma_set_mask_and_coherent(\u0026pdev-\u003edev, DMA_BIT_MASK(32));\n-\t\tif (err) {\n-\t\t\tdev_err(\u0026pdev-\u003edev, \"Can't set PCI DMA mask, err=%d\\n\", err);\n-\t\t\treturn err;\n-\t\t}\n-\t}\n-\n-\tdma_set_max_seg_size(\u0026pdev-\u003edev, SZ_2G);\n-\treturn 0;\n-}\n-\n-int mlx5_data_direct_ib_reg(struct mlx5_ib_dev *ibdev, char *vuid)\n-{\n-\tstruct mlx5_data_direct_registration *reg;\n-\tstruct mlx5_data_direct_dev *dev;\n-\n-\treg = kzalloc_obj(*reg);\n-\tif (!reg)\n-\t\treturn -ENOMEM;\n-\n-\treg-\u003eibdev = ibdev;\n-\tstrscpy(reg-\u003evuid, vuid);\n-\n-\tmutex_lock(\u0026mlx5_data_direct_mutex);\n-\tlist_for_each_entry(dev, \u0026mlx5_data_direct_dev_list, list) {\n-\t\tif (strcmp(dev-\u003evuid, vuid) == 0) {\n-\t\t\tmlx5_ib_data_direct_bind(ibdev, dev);\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\n-\t/* Add the registration to its global list, to be used upon bind/unbind\n-\t * of its affiliated data direct device\n-\t */\n-\tlist_add_tail(\u0026reg-\u003elist, \u0026mlx5_data_direct_reg_list);\n-\tmutex_unlock(\u0026mlx5_data_direct_mutex);\n-\treturn 0;\n-}\n-\n-void mlx5_data_direct_ib_unreg(struct mlx5_ib_dev *ibdev)\n-{\n-\tstruct mlx5_data_direct_registration *reg;\n-\n-\tmutex_lock(\u0026mlx5_data_direct_mutex);\n-\tlist_for_each_entry(reg, \u0026mlx5_data_direct_reg_list, list) {\n-\t\tif (reg-\u003eibdev == ibdev) {\n-\t\t\tlist_del(\u0026reg-\u003elist);\n-\t\t\tkfree(reg);\n-\t\t\tgoto end;\n-\t\t}\n-\t}\n-\n-\tWARN_ON(true);\n-end:\n-\tmutex_unlock(\u0026mlx5_data_direct_mutex);\n-}\n-\n-static void mlx5_data_direct_dev_reg(struct mlx5_data_direct_dev *dev)\n-{\n-\tstruct mlx5_data_direct_registration *reg;\n-\n-\tmutex_lock(\u0026mlx5_data_direct_mutex);\n-\tlist_for_each_entry(reg, \u0026mlx5_data_direct_reg_list, list) {\n-\t\tif (strcmp(dev-\u003evuid, reg-\u003evuid) == 0)\n-\t\t\tmlx5_ib_data_direct_bind(reg-\u003eibdev, dev);\n-\t}\n-\n-\t/* Add the data direct device to the global list, further IB devices may\n-\t * use it later as well\n-\t */\n-\tlist_add_tail(\u0026dev-\u003elist, \u0026mlx5_data_direct_dev_list);\n-\tmutex_unlock(\u0026mlx5_data_direct_mutex);\n-}\n-\n-static void mlx5_data_direct_dev_unreg(struct mlx5_data_direct_dev *dev)\n-{\n-\tstruct mlx5_data_direct_registration *reg;\n-\n-\tmutex_lock(\u0026mlx5_data_direct_mutex);\n-\t/* Prevent any further affiliations */\n-\tlist_del(\u0026dev-\u003elist);\n-\tlist_for_each_entry(reg, \u0026mlx5_data_direct_reg_list, list) {\n-\t\tif (strcmp(dev-\u003evuid, reg-\u003evuid) == 0)\n-\t\t\tmlx5_ib_data_direct_unbind(reg-\u003eibdev);\n-\t}\n-\tmutex_unlock(\u0026mlx5_data_direct_mutex);\n-}\n-\n-static int mlx5_data_direct_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n-{\n-\tstruct mlx5_data_direct_dev *dev;\n-\tint err;\n-\n-\tdev = kzalloc_obj(*dev);\n-\tif (!dev)\n-\t\treturn -ENOMEM;\n-\n-\tdev-\u003edevice = \u0026pdev-\u003edev;\n-\tdev-\u003epdev = pdev;\n-\n-\tpci_set_drvdata(dev-\u003epdev, dev);\n-\terr = pci_enable_device(pdev);\n-\tif (err) {\n-\t\tdev_err(dev-\u003edevice, \"Cannot enable PCI device, err=%d\\n\", err);\n-\t\tgoto err;\n-\t}\n-\n-\tpci_set_master(pdev);\n-\terr = mlx5_data_direct_set_dma_caps(pdev);\n-\tif (err)\n-\t\tgoto err_disable;\n-\n-\tif (pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP32) \u0026\u0026\n-\t    pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP64) \u0026\u0026\n-\t    pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP128))\n-\t\tdev_dbg(dev-\u003edevice, \"Enabling pci atomics failed\\n\");\n-\n-\terr = mlx5_data_direct_vpd_get_vuid(dev);\n-\tif (err)\n-\t\tgoto err_disable;\n-\n-\tmlx5_data_direct_dev_reg(dev);\n-\treturn 0;\n-\n-err_disable:\n-\tpci_disable_device(pdev);\n-err:\n-\tkfree(dev);\n-\treturn err;\n-}\n-\n-static void mlx5_data_direct_remove(struct pci_dev *pdev)\n-{\n-\tstruct mlx5_data_direct_dev *dev = pci_get_drvdata(pdev);\n-\n-\tmlx5_data_direct_dev_unreg(dev);\n-\tpci_disable_device(pdev);\n-\tkfree(dev-\u003evuid);\n-\tkfree(dev);\n-}\n-\n-static struct pci_driver mlx5_data_direct_driver = {\n-\t.name = KBUILD_MODNAME,\n-\t.id_table = mlx5_data_direct_pci_table,\n-\t.probe = mlx5_data_direct_probe,\n-\t.remove = mlx5_data_direct_remove,\n-\t.shutdown = mlx5_data_direct_shutdown,\n-};\n-\n-int mlx5_data_direct_driver_register(void)\n-{\n-\treturn pci_register_driver(\u0026mlx5_data_direct_driver);\n-}\n-\n-void mlx5_data_direct_driver_unregister(void)\n-{\n-\tpci_unregister_driver(\u0026mlx5_data_direct_driver);\n-}\ndiff --git a/drivers/infiniband/hw/mlx5/data_direct.h b/drivers/infiniband/hw/mlx5/data_direct.h\ndeleted file mode 100644\nindex 2fd2bdbe8f692..0000000000000\n--- a/drivers/infiniband/hw/mlx5/data_direct.h\n+++ /dev/null\n@@ -1,23 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */\n-/*\n- * Copyright (c) 2024, NVIDIA CORPORATION \u0026 AFFILIATES. All rights reserved\n- */\n-\n-#ifndef _MLX5_IB_DATA_DIRECT_H\n-#define _MLX5_IB_DATA_DIRECT_H\n-\n-struct mlx5_ib_dev;\n-\n-struct mlx5_data_direct_dev {\n-\tstruct device *device;\n-\tstruct pci_dev *pdev;\n-\tchar *vuid;\n-\tstruct list_head list;\n-};\n-\n-int mlx5_data_direct_ib_reg(struct mlx5_ib_dev *ibdev, char *vuid);\n-void mlx5_data_direct_ib_unreg(struct mlx5_ib_dev *ibdev);\n-int mlx5_data_direct_driver_register(void);\n-void mlx5_data_direct_driver_unregister(void);\n-\n-#endif\ndiff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c\nindex 02809114fc79a..dd2a3996b14e1 100644\n--- a/drivers/infiniband/hw/mlx5/main.c\n+++ b/drivers/infiniband/hw/mlx5/main.c\n@@ -25,6 +25,7 @@\n #include \u003clinux/mlx5/vport.h\u003e\n #include \u003clinux/mlx5/fs.h\u003e\n #include \u003clinux/mlx5/eswitch.h\u003e\n+#include \u003clinux/mlx5/data_direct.h\u003e\n #include \u003clinux/mlx5/driver.h\u003e\n #include \u003clinux/mlx5/lag.h\u003e\n #include \u003clinux/list.h\u003e\n@@ -51,7 +52,6 @@\n #include \u003crdma/mlx5_user_ioctl_cmds.h\u003e\n #include \u003crdma/ib_ucaps.h\u003e\n #include \"macsec.h\"\n-#include \"data_direct.h\"\n #include \"dmah.h\"\n \n #define UVERBS_MODULE_NAME mlx5_ib\n@@ -3473,87 +3473,6 @@ static void mlx5_ib_dev_res_cleanup(struct mlx5_ib_dev *dev)\n \tmutex_destroy(\u0026devr-\u003esrq_lock);\n }\n \n-static int\n-mlx5_ib_create_data_direct_resources(struct mlx5_ib_dev *dev)\n-{\n-\tint inlen = MLX5_ST_SZ_BYTES(create_mkey_in);\n-\tstruct mlx5_core_dev *mdev = dev-\u003emdev;\n-\tbool ro_supp = false;\n-\tvoid *mkc;\n-\tu32 mkey;\n-\tu32 pdn;\n-\tu32 *in;\n-\tint err;\n-\n-\terr = mlx5_core_alloc_pd(mdev, \u0026pdn);\n-\tif (err)\n-\t\treturn err;\n-\n-\tin = kvzalloc(inlen, GFP_KERNEL);\n-\tif (!in) {\n-\t\terr = -ENOMEM;\n-\t\tgoto err;\n-\t}\n-\n-\tMLX5_SET(create_mkey_in, in, data_direct, 1);\n-\tmkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);\n-\tMLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);\n-\tMLX5_SET(mkc, mkc, lw, 1);\n-\tMLX5_SET(mkc, mkc, lr, 1);\n-\tMLX5_SET(mkc, mkc, rw, 1);\n-\tMLX5_SET(mkc, mkc, rr, 1);\n-\tMLX5_SET(mkc, mkc, a, 1);\n-\tMLX5_SET(mkc, mkc, pd, pdn);\n-\tMLX5_SET(mkc, mkc, length64, 1);\n-\tMLX5_SET(mkc, mkc, qpn, 0xffffff);\n-\terr = mlx5_core_create_mkey(mdev, \u0026mkey, in, inlen);\n-\tif (err)\n-\t\tgoto err_mkey;\n-\n-\tdev-\u003eddr.mkey = mkey;\n-\tdev-\u003eddr.pdn = pdn;\n-\n-\t/* create another mkey with RO support */\n-\tif (MLX5_CAP_GEN(dev-\u003emdev, relaxed_ordering_write)) {\n-\t\tMLX5_SET(mkc, mkc, relaxed_ordering_write, 1);\n-\t\tro_supp = true;\n-\t}\n-\n-\tif (MLX5_CAP_GEN(dev-\u003emdev, relaxed_ordering_read)) {\n-\t\tMLX5_SET(mkc, mkc, relaxed_ordering_read, 1);\n-\t\tro_supp = true;\n-\t}\n-\n-\tif (ro_supp) {\n-\t\terr = mlx5_core_create_mkey(mdev, \u0026mkey, in, inlen);\n-\t\t/* RO is defined as best effort */\n-\t\tif (!err) {\n-\t\t\tdev-\u003eddr.mkey_ro = mkey;\n-\t\t\tdev-\u003eddr.mkey_ro_valid = true;\n-\t\t}\n-\t}\n-\n-\tkvfree(in);\n-\treturn 0;\n-\n-err_mkey:\n-\tkvfree(in);\n-err:\n-\tmlx5_core_dealloc_pd(mdev, pdn);\n-\treturn err;\n-}\n-\n-static void\n-mlx5_ib_free_data_direct_resources(struct mlx5_ib_dev *dev)\n-{\n-\n-\tif (dev-\u003eddr.mkey_ro_valid)\n-\t\tmlx5_core_destroy_mkey(dev-\u003emdev, dev-\u003eddr.mkey_ro);\n-\n-\tmlx5_core_destroy_mkey(dev-\u003emdev, dev-\u003eddr.mkey);\n-\tmlx5_core_dealloc_pd(dev-\u003emdev, dev-\u003eddr.pdn);\n-}\n-\n static u32 get_core_cap_flags(struct ib_device *ibdev,\n \t\t\t      struct mlx5_hca_vport_context *rep)\n {\n@@ -4019,39 +3938,42 @@ static bool mlx5_ib_bind_slave_port(struct mlx5_ib_dev *ibdev,\n \treturn false;\n }\n \n+static int mlx5_ib_data_direct_event(struct notifier_block *nb,\n+\t\t\t\t     unsigned long action, void *data)\n+{\n+\tstruct mlx5_ib_dev *dev =\n+\t\tcontainer_of(nb, struct mlx5_ib_dev, data_direct_nb);\n+\n+\tif (action != MLX5_DATA_DIRECT_UNBIND)\n+\t\treturn NOTIFY_DONE;\n+\n+\tmutex_lock(\u0026dev-\u003edata_direct_lock);\n+\tmlx5_ib_revoke_data_direct_mrs(dev);\n+\tmutex_unlock(\u0026dev-\u003edata_direct_lock);\n+\n+\treturn NOTIFY_OK;\n+}\n+\n static int mlx5_ib_data_direct_init(struct mlx5_ib_dev *dev)\n {\n-\tchar vuid[MLX5_ST_SZ_BYTES(array1024_auto) + 1] = {};\n \tint ret;\n \n-\tif (!MLX5_CAP_GEN(dev-\u003emdev, data_direct) ||\n-\t    !MLX5_CAP_GEN_2(dev-\u003emdev, query_vuid))\n+\tif (!mlx5_data_direct_supported(dev-\u003emdev))\n \t\treturn 0;\n \n-\tret = mlx5_cmd_query_vuid(dev-\u003emdev, true, vuid);\n-\tif (ret)\n-\t\treturn ret;\n-\n-\tret = mlx5_ib_create_data_direct_resources(dev);\n-\tif (ret)\n-\t\treturn ret;\n-\n \tINIT_LIST_HEAD(\u0026dev-\u003edata_direct_mr_list);\n-\tret = mlx5_data_direct_ib_reg(dev, vuid);\n-\tif (ret)\n-\t\tmlx5_ib_free_data_direct_resources(dev);\n+\tdev-\u003edata_direct_nb.notifier_call = mlx5_ib_data_direct_event;\n+\tret = mlx5_data_direct_register(dev-\u003emdev, \u0026dev-\u003edata_direct_nb);\n \n \treturn ret;\n }\n \n static void mlx5_ib_data_direct_cleanup(struct mlx5_ib_dev *dev)\n {\n-\tif (!MLX5_CAP_GEN(dev-\u003emdev, data_direct) ||\n-\t    !MLX5_CAP_GEN_2(dev-\u003emdev, query_vuid))\n+\tif (!mlx5_data_direct_supported(dev-\u003emdev))\n \t\treturn;\n \n-\tmlx5_data_direct_ib_unreg(dev);\n-\tmlx5_ib_free_data_direct_resources(dev);\n+\tmlx5_data_direct_unregister(dev-\u003emdev, \u0026dev-\u003edata_direct_nb);\n }\n \n static int mlx5_ib_init_multiport_master(struct mlx5_ib_dev *dev)\n@@ -5077,22 +4999,6 @@ static void mlx5_ib_stage_dev_notifier_cleanup(struct mlx5_ib_dev *dev)\n \t\tcancel_work_sync(\u0026devr-\u003eports[port].pkey_change_work);\n }\n \n-void mlx5_ib_data_direct_bind(struct mlx5_ib_dev *ibdev,\n-\t\t\t      struct mlx5_data_direct_dev *dev)\n-{\n-\tmutex_lock(\u0026ibdev-\u003edata_direct_lock);\n-\tibdev-\u003edata_direct_dev = dev;\n-\tmutex_unlock(\u0026ibdev-\u003edata_direct_lock);\n-}\n-\n-void mlx5_ib_data_direct_unbind(struct mlx5_ib_dev *ibdev)\n-{\n-\tmutex_lock(\u0026ibdev-\u003edata_direct_lock);\n-\tmlx5_ib_revoke_data_direct_mrs(ibdev);\n-\tibdev-\u003edata_direct_dev = NULL;\n-\tmutex_unlock(\u0026ibdev-\u003edata_direct_lock);\n-}\n-\n void __mlx5_ib_remove(struct mlx5_ib_dev *dev,\n \t\t      const struct mlx5_ib_profile *profile,\n \t\t      int stage)\n@@ -5519,9 +5425,6 @@ static int __init mlx5_ib_init(void)\n \tret = mlx5r_rep_init();\n \tif (ret)\n \t\tgoto rep_err;\n-\tret = mlx5_data_direct_driver_register();\n-\tif (ret)\n-\t\tgoto dd_err;\n \tret = auxiliary_driver_register(\u0026mlx5r_mp_driver);\n \tif (ret)\n \t\tgoto mp_err;\n@@ -5534,8 +5437,6 @@ static int __init mlx5_ib_init(void)\n drv_err:\n \tauxiliary_driver_unregister(\u0026mlx5r_mp_driver);\n mp_err:\n-\tmlx5_data_direct_driver_unregister();\n-dd_err:\n \tmlx5r_rep_cleanup();\n rep_err:\n \tmlx5_ib_qp_event_cleanup();\n@@ -5547,7 +5448,6 @@ static int __init mlx5_ib_init(void)\n \n static void __exit mlx5_ib_cleanup(void)\n {\n-\tmlx5_data_direct_driver_unregister();\n \tauxiliary_driver_unregister(\u0026mlx5r_driver);\n \tauxiliary_driver_unregister(\u0026mlx5r_mp_driver);\n \tmlx5r_rep_cleanup();\ndiff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h\nindex 522984d958bbf..1a3b9cb791849 100644\n--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h\n+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h\n@@ -24,6 +24,7 @@\n #include \u003crdma/mlx5_user_ioctl_cmds.h\u003e\n #include \u003crdma/mlx5_user_ioctl_verbs.h\u003e\n \n+#include \u003clinux/mlx5/data_direct.h\u003e\n #include \"srq.h\"\n #include \"qp.h\"\n #include \"macsec.h\"\n@@ -781,13 +782,6 @@ struct mlx5_ib_port_resources {\n \tstruct work_struct pkey_change_work;\n };\n \n-struct mlx5_data_direct_resources {\n-\tu32 pdn;\n-\tu32 mkey;\n-\tu32 mkey_ro;\n-\tu8 mkey_ro_valid :1;\n-};\n-\n struct mlx5_ib_resources {\n \tstruct ib_cq\t*c0;\n \tstruct mutex cq_lock;\n@@ -1097,8 +1091,9 @@ struct mlx5_macsec {\n struct mlx5_ib_dev {\n \tstruct ib_device\t\tib_dev;\n \tstruct mlx5_core_dev\t\t*mdev;\n-\tstruct mlx5_data_direct_dev\t*data_direct_dev;\n-\t/* protect accessing data_direct_dev */\n+\t/* Protects data_direct_mr_list and serializes mr\n+\t * registration/deregistration with data direct device unbind.\n+\t */\n \tstruct mutex\t\t\tdata_direct_lock;\n \tstruct notifier_block\t\tmdev_events;\n \tstruct notifier_block\t\tsys_error_events;\n@@ -1131,6 +1126,7 @@ struct mlx5_ib_dev {\n \tspinlock_t\t\treset_flow_resource_lock;\n \tstruct list_head\tqp_list;\n \tstruct list_head data_direct_mr_list;\n+\tstruct notifier_block data_direct_nb;\n \t/* Array with num_ports elements */\n \tstruct mlx5_ib_port\t*port;\n \tstruct mlx5_sq_bfreg\tbfreg;\n@@ -1155,7 +1151,6 @@ struct mlx5_ib_dev {\n \tu16 pkey_table_len;\n \tu8 lag_ports;\n \tstruct mlx5_special_mkeys mkeys;\n-\tstruct mlx5_data_direct_resources ddr;\n \n #ifdef CONFIG_MLX5_MACSEC\n \tstruct mlx5_macsec macsec;\n@@ -1401,9 +1396,6 @@ int mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *wq_ind_table);\n struct ib_mr *mlx5_ib_reg_dm_mr(struct ib_pd *pd, struct ib_dm *dm,\n \t\t\t\tstruct ib_dm_mr_attr *attr,\n \t\t\t\tstruct uverbs_attr_bundle *attrs);\n-void mlx5_ib_data_direct_bind(struct mlx5_ib_dev *ibdev,\n-\t\t\t      struct mlx5_data_direct_dev *dev);\n-void mlx5_ib_data_direct_unbind(struct mlx5_ib_dev *ibdev);\n void mlx5_ib_revoke_data_direct_mrs(struct mlx5_ib_dev *dev);\n \n #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING\ndiff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c\nindex e6b74955d95dc..7463b36a36b63 100644\n--- a/drivers/infiniband/hw/mlx5/mr.c\n+++ b/drivers/infiniband/hw/mlx5/mr.c\n@@ -44,7 +44,6 @@\n #include \"dm.h\"\n #include \"mlx5_ib.h\"\n #include \"umr.h\"\n-#include \"data_direct.h\"\n #include \"dmah.h\"\n \n static int mkey_max_umr_order(struct mlx5_ib_dev *dev)\n@@ -587,7 +586,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, struct ib_umem *umem,\n \t\t\t\t      populate ? pd : dev-\u003eumrc.pd);\n \t/* In case a data direct flow, overwrite the pdn field by its internal kernel PD */\n \tif (umem-\u003eis_dmabuf \u0026\u0026 ksm_mode)\n-\t\tMLX5_SET(mkc, mkc, pd, dev-\u003eddr.pdn);\n+\t\tMLX5_SET(mkc, mkc, pd, dev-\u003emdev-\u003edata_direct-\u003epdn);\n \n \tMLX5_SET(mkc, mkc, free, !populate);\n \tMLX5_SET(mkc, mkc, access_mode_1_0, access_mode);\n@@ -997,7 +996,7 @@ reg_user_mr_dmabuf_by_data_direct(struct ib_pd *pd, u64 offset,\n \t\treturn ERR_PTR(-EOPNOTSUPP);\n \n \tmutex_lock(\u0026dev-\u003edata_direct_lock);\n-\tdata_direct_dev = dev-\u003edata_direct_dev;\n+\tdata_direct_dev = mlx5_data_direct_get_dev(dev-\u003emdev-\u003edata_direct);\n \tif (!data_direct_dev) {\n \t\tret = -EINVAL;\n \t\tgoto end;\n@@ -1006,7 +1005,7 @@ reg_user_mr_dmabuf_by_data_direct(struct ib_pd *pd, u64 offset,\n \t/* If no device's 'data direct mkey' with RO flags exists\n \t * mask it out accordingly.\n \t */\n-\tif (!dev-\u003eddr.mkey_ro_valid)\n+\tif (!dev-\u003emdev-\u003edata_direct-\u003emkey_ro_valid)\n \t\taccess_flags \u0026= ~IB_ACCESS_RELAXED_ORDERING;\n \tcrossed_mr = reg_user_mr_dmabuf(pd, \u0026data_direct_dev-\u003epdev-\u003edev,\n \t\t\t\t\toffset, length, virt_addr, fd,\ndiff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c\nindex 1badec9bf5270..2e9a704acc44a 100644\n--- a/drivers/infiniband/hw/mlx5/odp.c\n+++ b/drivers/infiniband/hw/mlx5/odp.c\n@@ -952,7 +952,7 @@ int mlx5_ib_init_dmabuf_mr(struct mlx5_ib_mr *mr, struct ib_pd *pd)\n \tint ret;\n \n \tif (mr-\u003edata_direct)\n-\t\tpdn = dev-\u003eddr.pdn;\n+\t\tpdn = dev-\u003emdev-\u003edata_direct-\u003epdn;\n \telse\n \t\tpdn = to_mpd(pd)-\u003epdn;\n \ndiff --git a/drivers/infiniband/hw/mlx5/std_types.c b/drivers/infiniband/hw/mlx5/std_types.c\nindex 1ee31611b4b3f..b705b88dc917b 100644\n--- a/drivers/infiniband/hw/mlx5/std_types.c\n+++ b/drivers/infiniband/hw/mlx5/std_types.c\n@@ -10,7 +10,6 @@\n #include \u003clinux/mlx5/eswitch.h\u003e\n #include \u003clinux/mlx5/vport.h\u003e\n #include \"mlx5_ib.h\"\n-#include \"data_direct.h\"\n \n #define UVERBS_MODULE_NAME mlx5_ib\n #include \u003crdma/uverbs_named_ioctl.h\u003e\n@@ -203,7 +202,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH)(\n \t\treturn PTR_ERR(c);\n \tdev = to_mdev(c-\u003eibucontext.device);\n \tmutex_lock(\u0026dev-\u003edata_direct_lock);\n-\tdata_direct_dev = dev-\u003edata_direct_dev;\n+\tdata_direct_dev = mlx5_data_direct_get_dev(dev-\u003emdev-\u003edata_direct);\n \tif (!data_direct_dev) {\n \t\tret = -ENODEV;\n \t\tgoto end;\ndiff --git a/drivers/infiniband/hw/mlx5/umr.c b/drivers/infiniband/hw/mlx5/umr.c\nindex 48cae5cc1c1be..a3bb8d03fd35f 100644\n--- a/drivers/infiniband/hw/mlx5/umr.c\n+++ b/drivers/infiniband/hw/mlx5/umr.c\n@@ -760,12 +760,14 @@ static int _mlx5r_umr_update_mr_pas(struct mlx5_ib_mr *mr, unsigned int flags,\n \t\t}\n \n \t\tif (dd) {\n+\t\t\tstruct mlx5_data_direct *mdd = dev-\u003emdev-\u003edata_direct;\n+\n \t\t\tcur_ksm-\u003eva = cpu_to_be64(rdma_block_iter_dma_address(\u0026biter));\n \t\t\tif (mr-\u003eaccess_flags \u0026 IB_ACCESS_RELAXED_ORDERING \u0026\u0026\n-\t\t\t    dev-\u003eddr.mkey_ro_valid)\n-\t\t\t\tcur_ksm-\u003ekey = cpu_to_be32(dev-\u003eddr.mkey_ro);\n+\t\t\t    mdd-\u003emkey_ro_valid)\n+\t\t\t\tcur_ksm-\u003ekey = cpu_to_be32(mdd-\u003emkey_ro);\n \t\t\telse\n-\t\t\t\tcur_ksm-\u003ekey = cpu_to_be32(dev-\u003eddr.mkey);\n+\t\t\t\tcur_ksm-\u003ekey = cpu_to_be32(mdd-\u003emkey);\n \t\t\tif (mr-\u003eumem-\u003eis_dmabuf \u0026\u0026\n \t\t\t    (flags \u0026 MLX5_IB_UPD_XLT_ZAP)) {\n \t\t\t\tcur_ksm-\u003eva = 0;\n@@ -810,7 +812,8 @@ int mlx5r_umr_update_data_direct_ksm_pas_range(struct mlx5_ib_mr *mr,\n \t    !(flags \u0026 MLX5_IB_UPD_XLT_KEEP_PGSZ)))\n \t\treturn -EINVAL;\n \n-\treturn _mlx5r_umr_update_mr_pas(mr, flags, mr_to_mdev(mr)-\u003eddr.pdn,\n+\treturn _mlx5r_umr_update_mr_pas(mr, flags,\n+\t\t\t\t\tmr_to_mdev(mr)-\u003emdev-\u003edata_direct-\u003epdn,\n \t\t\t\t\ttrue, start_block, nblocks);\n }\n \ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile\nindex 19e50f0d55af3..a1871259210d6 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile\n@@ -18,7 +18,7 @@ mlx5_core-y :=\tmain.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \\\n \t\tlib/devcom.o lib/pci_vsc.o lib/dm.o lib/fs_ttc.o diag/fs_tracepoint.o \\\n \t\tdiag/fw_tracer.o diag/crdump.o devlink.o sh_devlink.o diag/rsc_dump.o \\\n \t\tdiag/reporter_vnic.o fw_reset.o qos.o lib/tout.o lib/aso.o wc.o fs_pool.o \\\n-\t\tlib/nv_param.o\n+\t\tlib/nv_param.o data_direct.o\n \n #\n # Netdev basic\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/data_direct.c b/drivers/net/ethernet/mellanox/mlx5/core/data_direct.c\nnew file mode 100644\nindex 0000000000000..67717110feab0\n--- /dev/null\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/data_direct.c\n@@ -0,0 +1,402 @@\n+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB\n+/*\n+ * Copyright (c) 2024, NVIDIA CORPORATION \u0026 AFFILIATES. All rights reserved\n+ */\n+\n+#include \u003clinux/list.h\u003e\n+#include \u003clinux/mlx5/driver.h\u003e\n+#include \u003clinux/mlx5/data_direct.h\u003e\n+#include \u003clinux/mlx5/mlx5_ifc.h\u003e\n+#include \u003clinux/pci.h\u003e\n+#include \u003clinux/slab.h\u003e\n+\n+#include \"mlx5_core.h\"\n+\n+static LIST_HEAD(mlx5_data_direct_dev_list);\n+static LIST_HEAD(mlx5_data_direct_reg_list);\n+\n+/*\n+ * This mutex should be held when accessing either of the above lists\n+ */\n+static DEFINE_MUTEX(mlx5_data_direct_mutex);\n+\n+struct mlx5_data_direct_registration {\n+\tchar vuid[MLX5_ST_SZ_BYTES(array1024_auto) + 1];\n+\tstruct list_head list;\n+\tstruct blocking_notifier_head users;\n+\tstruct mlx5_data_direct dd;\n+};\n+\n+static int mlx5_data_direct_query_vuid(struct mlx5_core_dev *dev,\n+\t\t\t\t       char *out_vuid)\n+{\n+\tu8 out[MLX5_ST_SZ_BYTES(query_vuid_out) +\n+\t       MLX5_ST_SZ_BYTES(array1024_auto)] = {};\n+\tu8 in[MLX5_ST_SZ_BYTES(query_vuid_in)] = {};\n+\tchar *vuid;\n+\tint err;\n+\n+\tMLX5_SET(query_vuid_in, in, opcode, MLX5_CMD_OPCODE_QUERY_VUID);\n+\tMLX5_SET(query_vuid_in, in, vhca_id, MLX5_CAP_GEN(dev, vhca_id));\n+\tMLX5_SET(query_vuid_in, in, data_direct, 1);\n+\terr = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));\n+\tif (err)\n+\t\treturn err;\n+\n+\tvuid = MLX5_ADDR_OF(query_vuid_out, out, vuid);\n+\tmemcpy(out_vuid, vuid, MLX5_ST_SZ_BYTES(array1024_auto));\n+\treturn 0;\n+}\n+\n+static const struct pci_device_id mlx5_data_direct_pci_table[] = {\n+\t{ PCI_VDEVICE(MELLANOX, 0x2100) }, /* ConnectX-8 Data Direct */\n+\t{ 0, }\n+};\n+\n+static int mlx5_data_direct_vpd_get_vuid(struct mlx5_data_direct_dev *dev)\n+{\n+\tstruct pci_dev *pdev = dev-\u003epdev;\n+\tunsigned int vpd_size, kw_len;\n+\tu8 *vpd_data;\n+\tint start;\n+\tint ret;\n+\n+\tvpd_data = pci_vpd_alloc(pdev, \u0026vpd_size);\n+\tif (IS_ERR(vpd_data)) {\n+\t\tpci_err(pdev, \"Unable to read VPD, err=%pe\\n\", vpd_data);\n+\t\treturn PTR_ERR(vpd_data);\n+\t}\n+\n+\tstart = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, \"VU\", \u0026kw_len);\n+\tif (start \u003c 0) {\n+\t\tret = start;\n+\t\tpci_err(pdev, \"VU keyword not found, err=%d\\n\", ret);\n+\t\tgoto end;\n+\t}\n+\n+\tdev-\u003evuid = kmemdup_nul(vpd_data + start, kw_len, GFP_KERNEL);\n+\tret = dev-\u003evuid ? 0 : -ENOMEM;\n+\n+end:\n+\tkfree(vpd_data);\n+\treturn ret;\n+}\n+\n+static void mlx5_data_direct_shutdown(struct pci_dev *pdev)\n+{\n+\tpci_disable_device(pdev);\n+}\n+\n+static int mlx5_data_direct_set_dma_caps(struct pci_dev *pdev)\n+{\n+\tint err;\n+\n+\terr = dma_set_mask_and_coherent(\u0026pdev-\u003edev, DMA_BIT_MASK(64));\n+\tif (err) {\n+\t\tdev_warn(\u0026pdev-\u003edev,\n+\t\t\t \"Warning: couldn't set 64-bit PCI DMA mask, err=%d\\n\", err);\n+\t\terr = dma_set_mask_and_coherent(\u0026pdev-\u003edev, DMA_BIT_MASK(32));\n+\t\tif (err) {\n+\t\t\tdev_err(\u0026pdev-\u003edev, \"Can't set PCI DMA mask, err=%d\\n\", err);\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\tdma_set_max_seg_size(\u0026pdev-\u003edev, SZ_2G);\n+\treturn 0;\n+}\n+\n+static int mlx5_data_direct_create_resources(struct mlx5_core_dev *mdev)\n+{\n+\tint inlen = MLX5_ST_SZ_BYTES(create_mkey_in);\n+\tbool ro_supp = false;\n+\tvoid *mkc;\n+\tu32 mkey;\n+\tu32 pdn;\n+\tu32 *in;\n+\tint err;\n+\n+\terr = mlx5_core_alloc_pd(mdev, \u0026pdn);\n+\tif (err)\n+\t\treturn err;\n+\n+\tin = kvzalloc(inlen, GFP_KERNEL);\n+\tif (!in) {\n+\t\terr = -ENOMEM;\n+\t\tgoto err;\n+\t}\n+\n+\tMLX5_SET(create_mkey_in, in, data_direct, 1);\n+\tmkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);\n+\tMLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);\n+\tMLX5_SET(mkc, mkc, lw, 1);\n+\tMLX5_SET(mkc, mkc, lr, 1);\n+\tMLX5_SET(mkc, mkc, rw, 1);\n+\tMLX5_SET(mkc, mkc, rr, 1);\n+\tMLX5_SET(mkc, mkc, a, 1);\n+\tMLX5_SET(mkc, mkc, pd, pdn);\n+\tMLX5_SET(mkc, mkc, length64, 1);\n+\tMLX5_SET(mkc, mkc, qpn, 0xffffff);\n+\terr = mlx5_core_create_mkey(mdev, \u0026mkey, in, inlen);\n+\tif (err)\n+\t\tgoto err_mkey;\n+\n+\tmdev-\u003edata_direct-\u003emkey = mkey;\n+\tmdev-\u003edata_direct-\u003epdn = pdn;\n+\n+\t/* create another mkey with RO support */\n+\tif (MLX5_CAP_GEN(mdev, relaxed_ordering_write)) {\n+\t\tMLX5_SET(mkc, mkc, relaxed_ordering_write, 1);\n+\t\tro_supp = true;\n+\t}\n+\n+\tif (MLX5_CAP_GEN(mdev, relaxed_ordering_read)) {\n+\t\tMLX5_SET(mkc, mkc, relaxed_ordering_read, 1);\n+\t\tro_supp = true;\n+\t}\n+\n+\tif (ro_supp) {\n+\t\terr = mlx5_core_create_mkey(mdev, \u0026mkey, in, inlen);\n+\t\t/* RO is defined as best effort */\n+\t\tif (!err) {\n+\t\t\tmdev-\u003edata_direct-\u003emkey_ro = mkey;\n+\t\t\tmdev-\u003edata_direct-\u003emkey_ro_valid = true;\n+\t\t}\n+\t}\n+\n+\tkvfree(in);\n+\treturn 0;\n+\n+err_mkey:\n+\tkvfree(in);\n+err:\n+\tmlx5_core_dealloc_pd(mdev, pdn);\n+\treturn err;\n+}\n+\n+static void mlx5_data_direct_free_resources(struct mlx5_core_dev *mdev)\n+{\n+\tstruct mlx5_data_direct *data_direct = mdev-\u003edata_direct;\n+\n+\tif (data_direct-\u003emkey_ro_valid)\n+\t\tmlx5_core_destroy_mkey(mdev, data_direct-\u003emkey_ro);\n+\n+\tmlx5_core_destroy_mkey(mdev, data_direct-\u003emkey);\n+\tmlx5_core_dealloc_pd(mdev, data_direct-\u003epdn);\n+}\n+\n+static void mlx5_data_direct_bind(struct mlx5_data_direct_registration *reg,\n+\t\t\t\t  struct mlx5_data_direct_dev *dev)\n+{\n+\tWRITE_ONCE(reg-\u003edd.dev, dev);\n+}\n+\n+static void\n+mlx5_data_direct_do_unbind(struct mlx5_data_direct_registration *reg)\n+{\n+\tWRITE_ONCE(reg-\u003edd.dev, NULL);\n+\tblocking_notifier_call_chain(\u0026reg-\u003eusers, MLX5_DATA_DIRECT_UNBIND,\n+\t\t\t\t     NULL);\n+}\n+\n+int mlx5_data_direct_init(struct mlx5_core_dev *mdev)\n+{\n+\tstruct mlx5_data_direct_registration *reg;\n+\tstruct mlx5_data_direct_dev *dev;\n+\tint err;\n+\n+\tif (!mlx5_data_direct_supported(mdev))\n+\t\treturn 0;\n+\n+\treg = kzalloc_obj(*reg);\n+\tif (!reg)\n+\t\treturn -ENOMEM;\n+\n+\tBLOCKING_INIT_NOTIFIER_HEAD(\u0026reg-\u003eusers);\n+\n+\terr = mlx5_data_direct_query_vuid(mdev, reg-\u003evuid);\n+\tif (err) {\n+\t\tmlx5_core_warn(mdev,\n+\t\t\t       \"Failed to query VUID, disabling data direct, err=%d\\n\",\n+\t\t\t       err);\n+\t\tkfree(reg);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tmdev-\u003edata_direct = \u0026reg-\u003edd;\n+\n+\terr = mlx5_data_direct_create_resources(mdev);\n+\tif (err)\n+\t\tgoto err_resources;\n+\n+\tmutex_lock(\u0026mlx5_data_direct_mutex);\n+\tlist_for_each_entry(dev, \u0026mlx5_data_direct_dev_list, list) {\n+\t\tif (strcmp(dev-\u003evuid, reg-\u003evuid) == 0) {\n+\t\t\tmlx5_data_direct_bind(reg, dev);\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t/* Add the registration to its global list, to be used upon bind/unbind\n+\t * of its affiliated data direct device.\n+\t */\n+\tlist_add_tail(\u0026reg-\u003elist, \u0026mlx5_data_direct_reg_list);\n+\tmutex_unlock(\u0026mlx5_data_direct_mutex);\n+\treturn 0;\n+\n+err_resources:\n+\tmdev-\u003edata_direct = NULL;\n+\tkfree(reg);\n+\treturn err;\n+}\n+\n+void mlx5_data_direct_cleanup(struct mlx5_core_dev *mdev)\n+{\n+\tstruct mlx5_data_direct_registration *reg;\n+\n+\tif (!mlx5_data_direct_supported(mdev))\n+\t\treturn;\n+\n+\treg = container_of(mdev-\u003edata_direct,\n+\t\t\t   struct mlx5_data_direct_registration, dd);\n+\tmutex_lock(\u0026mlx5_data_direct_mutex);\n+\tlist_del(\u0026reg-\u003elist);\n+\tmlx5_data_direct_do_unbind(reg);\n+\tmutex_unlock(\u0026mlx5_data_direct_mutex);\n+\n+\tmlx5_data_direct_free_resources(mdev);\n+\tmdev-\u003edata_direct = NULL;\n+\tkfree(reg);\n+}\n+\n+int mlx5_data_direct_register(struct mlx5_core_dev *mdev,\n+\t\t\t      struct notifier_block *nb)\n+{\n+\tstruct mlx5_data_direct_registration *reg;\n+\n+\tif (!mlx5_data_direct_supported(mdev))\n+\t\treturn 0;\n+\n+\treg = container_of(mdev-\u003edata_direct,\n+\t\t\t   struct mlx5_data_direct_registration, dd);\n+\tblocking_notifier_chain_register(\u0026reg-\u003eusers, nb);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(mlx5_data_direct_register);\n+\n+void mlx5_data_direct_unregister(struct mlx5_core_dev *mdev,\n+\t\t\t\t struct notifier_block *nb)\n+{\n+\tstruct mlx5_data_direct_registration *reg;\n+\n+\tif (!mlx5_data_direct_supported(mdev))\n+\t\treturn;\n+\n+\treg = container_of(mdev-\u003edata_direct,\n+\t\t\t   struct mlx5_data_direct_registration, dd);\n+\tblocking_notifier_chain_unregister(\u0026reg-\u003eusers, nb);\n+}\n+EXPORT_SYMBOL_GPL(mlx5_data_direct_unregister);\n+\n+static void mlx5_data_direct_dev_reg(struct mlx5_data_direct_dev *dev)\n+{\n+\tstruct mlx5_data_direct_registration *reg;\n+\n+\tmutex_lock(\u0026mlx5_data_direct_mutex);\n+\tlist_for_each_entry(reg, \u0026mlx5_data_direct_reg_list, list) {\n+\t\tif (strcmp(dev-\u003evuid, reg-\u003evuid) == 0)\n+\t\t\tmlx5_data_direct_bind(reg, dev);\n+\t}\n+\n+\t/* Add the data direct device to the global list, further mlx5 devices\n+\t * may use it later as well.\n+\t */\n+\tlist_add_tail(\u0026dev-\u003elist, \u0026mlx5_data_direct_dev_list);\n+\tmutex_unlock(\u0026mlx5_data_direct_mutex);\n+}\n+\n+static void mlx5_data_direct_dev_unreg(struct mlx5_data_direct_dev *dev)\n+{\n+\tstruct mlx5_data_direct_registration *reg;\n+\n+\tmutex_lock(\u0026mlx5_data_direct_mutex);\n+\t/* Prevent any further affiliations */\n+\tlist_del(\u0026dev-\u003elist);\n+\tlist_for_each_entry(reg, \u0026mlx5_data_direct_reg_list, list) {\n+\t\tif (strcmp(dev-\u003evuid, reg-\u003evuid) == 0)\n+\t\t\tmlx5_data_direct_do_unbind(reg);\n+\t}\n+\tmutex_unlock(\u0026mlx5_data_direct_mutex);\n+}\n+\n+static int mlx5_data_direct_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n+{\n+\tstruct mlx5_data_direct_dev *dev;\n+\tint err;\n+\n+\tdev = kzalloc_obj(*dev);\n+\tif (!dev)\n+\t\treturn -ENOMEM;\n+\n+\tdev-\u003edevice = \u0026pdev-\u003edev;\n+\tdev-\u003epdev = pdev;\n+\n+\tpci_set_drvdata(dev-\u003epdev, dev);\n+\terr = pci_enable_device(pdev);\n+\tif (err) {\n+\t\tdev_err(dev-\u003edevice, \"Cannot enable PCI device, err=%d\\n\", err);\n+\t\tgoto err;\n+\t}\n+\n+\tpci_set_master(pdev);\n+\terr = mlx5_data_direct_set_dma_caps(pdev);\n+\tif (err)\n+\t\tgoto err_disable;\n+\n+\tif (pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP32) \u0026\u0026\n+\t    pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP64) \u0026\u0026\n+\t    pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP128))\n+\t\tdev_dbg(dev-\u003edevice, \"Enabling pci atomics failed\\n\");\n+\n+\terr = mlx5_data_direct_vpd_get_vuid(dev);\n+\tif (err)\n+\t\tgoto err_disable;\n+\n+\tmlx5_data_direct_dev_reg(dev);\n+\treturn 0;\n+\n+err_disable:\n+\tpci_disable_device(pdev);\n+err:\n+\tkfree(dev);\n+\treturn err;\n+}\n+\n+static void mlx5_data_direct_remove(struct pci_dev *pdev)\n+{\n+\tstruct mlx5_data_direct_dev *dev = pci_get_drvdata(pdev);\n+\n+\tmlx5_data_direct_dev_unreg(dev);\n+\tpci_disable_device(pdev);\n+\tkfree(dev-\u003evuid);\n+\tkfree(dev);\n+}\n+\n+static struct pci_driver mlx5_data_direct_driver = {\n+\t.name = \"mlx5_dd\",\n+\t.id_table = mlx5_data_direct_pci_table,\n+\t.probe = mlx5_data_direct_probe,\n+\t.remove = mlx5_data_direct_remove,\n+\t.shutdown = mlx5_data_direct_shutdown,\n+};\n+\n+int mlx5_data_direct_driver_register(void)\n+{\n+\treturn pci_register_driver(\u0026mlx5_data_direct_driver);\n+}\n+\n+void mlx5_data_direct_driver_unregister(void)\n+{\n+\tpci_unregister_driver(\u0026mlx5_data_direct_driver);\n+}\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c\nindex 643b4aac20336..34f0375b68513 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c\n@@ -40,6 +40,7 @@\n #include \u003clinux/interrupt.h\u003e\n #include \u003clinux/delay.h\u003e\n #include \u003clinux/mlx5/driver.h\u003e\n+#include \u003clinux/mlx5/data_direct.h\u003e\n #include \u003clinux/mlx5/cq.h\u003e\n #include \u003clinux/mlx5/qp.h\u003e\n #include \u003clinux/debugfs.h\u003e\n@@ -1339,8 +1340,14 @@ static int mlx5_load(struct mlx5_core_dev *dev)\n \tif (err)\n \t\tgoto err_traps_reg;\n \n+\terr = mlx5_data_direct_init(dev);\n+\tif (err)\n+\t\tgoto err_data_direct;\n+\n \treturn 0;\n \n+err_data_direct:\n+\tmlx5_devlink_traps_unregister(priv_to_devlink(dev));\n err_traps_reg:\n \tmlx5_sf_dev_table_destroy(dev);\n \tmlx5_sriov_detach(dev);\n@@ -1371,6 +1378,7 @@ static int mlx5_load(struct mlx5_core_dev *dev)\n \n static void mlx5_unload(struct mlx5_core_dev *dev)\n {\n+\tmlx5_data_direct_cleanup(dev);\n \tmlx5_devlink_traps_unregister(priv_to_devlink(dev));\n \tmlx5_vhca_event_stop(dev);\n \tmlx5_sf_dev_table_destroy(dev);\n@@ -2360,6 +2368,10 @@ static int __init mlx5_init(void)\n \tif (err)\n \t\tgoto err_sf;\n \n+\terr = mlx5_data_direct_driver_register();\n+\tif (err)\n+\t\tgoto err_dd;\n+\n \terr = pci_register_driver(\u0026mlx5_core_driver);\n \tif (err)\n \t\tgoto err_pci;\n@@ -2367,6 +2379,8 @@ static int __init mlx5_init(void)\n \treturn 0;\n \n err_pci:\n+\tmlx5_data_direct_driver_unregister();\n+err_dd:\n \tmlx5_sf_driver_unregister();\n err_sf:\n \tmlx5e_cleanup();\n@@ -2378,6 +2392,7 @@ static int __init mlx5_init(void)\n static void __exit mlx5_cleanup(void)\n {\n \tpci_unregister_driver(\u0026mlx5_core_driver);\n+\tmlx5_data_direct_driver_unregister();\n \tmlx5_sf_driver_unregister();\n \tmlx5e_cleanup();\n \tmlx5_unregister_debugfs();\ndiff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h\nindex 09e669f83dba7..fd93530a39380 100644\n--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h\n+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h\n@@ -530,4 +530,9 @@ static inline bool mlx5_pcie_cong_event_supported(struct mlx5_core_dev *dev)\n \n \treturn true;\n }\n+\n+int mlx5_data_direct_init(struct mlx5_core_dev *mdev);\n+void mlx5_data_direct_cleanup(struct mlx5_core_dev *mdev);\n+int mlx5_data_direct_driver_register(void);\n+void mlx5_data_direct_driver_unregister(void);\n #endif /* __MLX5_CORE_H__ */\ndiff --git a/include/linux/mlx5/data_direct.h b/include/linux/mlx5/data_direct.h\nnew file mode 100644\nindex 0000000000000..4cff5ff5489d3\n--- /dev/null\n+++ b/include/linux/mlx5/data_direct.h\n@@ -0,0 +1,47 @@\n+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */\n+/*\n+ * Copyright (c) 2026, NVIDIA CORPORATION \u0026 AFFILIATES. All rights reserved\n+ */\n+\n+#ifndef _MLX5_DATA_DIRECT_H\n+#define _MLX5_DATA_DIRECT_H\n+\n+#include \u003clinux/compiler.h\u003e\n+#include \u003clinux/list.h\u003e\n+\n+struct device;\n+struct mlx5_core_dev;\n+struct notifier_block;\n+struct pci_dev;\n+\n+enum mlx5_data_direct_event {\n+\tMLX5_DATA_DIRECT_UNBIND,\n+};\n+\n+struct mlx5_data_direct_dev {\n+\tstruct device *device;\n+\tstruct pci_dev *pdev;\n+\tchar *vuid;\n+\tstruct list_head list;\n+};\n+\n+struct mlx5_data_direct {\n+\tstruct mlx5_data_direct_dev *dev;\n+\tu32 pdn;\n+\tu32 mkey;\n+\tu32 mkey_ro;\n+\tu8 mkey_ro_valid :1;\n+};\n+\n+static inline struct mlx5_data_direct_dev *\n+mlx5_data_direct_get_dev(struct mlx5_data_direct *dd)\n+{\n+\treturn dd ? READ_ONCE(dd-\u003edev) : NULL;\n+}\n+\n+int mlx5_data_direct_register(struct mlx5_core_dev *mdev,\n+\t\t\t      struct notifier_block *nb);\n+void mlx5_data_direct_unregister(struct mlx5_core_dev *mdev,\n+\t\t\t\t struct notifier_block *nb);\n+\n+#endif\ndiff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h\nindex b1871c0821d0b..ed348a82576eb 100644\n--- a/include/linux/mlx5/driver.h\n+++ b/include/linux/mlx5/driver.h\n@@ -707,6 +707,7 @@ struct mlx5_rsvd_gids {\n \n struct mlx5_clock;\n struct mlx5_clock_dev_state;\n+struct mlx5_data_direct;\n struct mlx5_dm;\n struct mlx5_fw_tracer;\n struct mlx5_vxlan;\n@@ -801,6 +802,7 @@ struct mlx5_core_dev {\n \t/* sync write combining state */\n \tstruct mutex wc_state_lock;\n \tstruct devlink *shd;\n+\tstruct mlx5_data_direct *data_direct;\n };\n \n struct mlx5_db {\n@@ -1395,4 +1397,10 @@ static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev)\n \n #define MLX5_SW_IMAGE_GUID_MAX_BYTES 9\n \n+static inline bool mlx5_data_direct_supported(struct mlx5_core_dev *mdev)\n+{\n+\treturn MLX5_CAP_GEN(mdev, data_direct) \u0026\u0026\n+\t       MLX5_CAP_GEN_2(mdev, query_vuid);\n+}\n+\n #endif /* MLX5_DRIVER_H */\n"
}

2/1 2026/09/19 07:21 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch refactors the ConnectX-8 Data Direct feature, moving resource and device management from mlx5_ib to mlx5_core. The modified code resides entirely within the Mellanox mlx5 driver stack (mlx5_core and mlx5_ib) and relies on vendor-specific Mellanox PCIe hardware (e.g., ConnectX-8 PCI ID 0x2100) that is not emulated in standard virtualized fuzzing environments (QEMU/GCE), making the changes structurally unreachable.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.

================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.

- REACHABILITY IS THE PRIMARY GATE:
  Fuzzing can only discover bugs in code that can actually execute in standard virtualized
  environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
  If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
  regardless of whether it adds assertions or complex logic.

- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
  Patch authors routinely label changes as "cleanups", "refactorings", or state
  "No functional change intended". Do NOT take these claims at face value.
  Code refactorings that rearrange logic, introduce helper functions, or alter state management
  in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
  If reachable executable code is modified or refactored, it MUST be fuzzed.

- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
  When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
  BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
  Even if the author believes the invariant always holds, fuzzing is essential to verify whether
  an unusual sequence of operations can violate it.

================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:

- Non-kernel and non-executable changes:
  * Modifications to Documentation/, comments, or spelling fixes.
  * User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
    that do not affect the compiled kernel image (vmlinux) or kernel modules.
  * Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
    that do not alter control flow or data structures.
  * Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
  * Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
    ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
  * Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
    physical PCI hot-unplug or manual sysfs driver unbinding.
  * Code paths exclusive to architectures other than the target architecture.

================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
  * Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
    BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
  * Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
  * Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
  * Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).

================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:

- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
  Do NOT list generic, ubiquitous functions called by almost every program in the corpus
  (including, but not limited to: general memory allocators and deallocators, page fault
  and trap handlers, or core synchronization primitives; this is not an exhaustive list).
  Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
  which severely dilutes fuzzing effort away from the actual changes.

- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
  List functions that specifically implement the logic being added or altered, or direct API entrypoints
  for the subsystem feature under review.

- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
  Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
  distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
  If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
  functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).

================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 57abb4f2f1203b172941c916f83e1f734c977d40
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Sep 19 07:21:11 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/infiniband/hw/mlx5/Makefile b/drivers/infiniband/hw/mlx5/Makefile
index dd7bb377f4910..35afc7bc57d2f 100644
--- a/drivers/infiniband/hw/mlx5/Makefile
+++ b/drivers/infiniband/hw/mlx5/Makefile
@@ -6,7 +6,6 @@ mlx5_ib-y := ah.o \
 	     cong.o \
 	     counters.o \
 	     cq.o \
-	     data_direct.o \
 	     dm.o \
 	     dmah.o \
 	     doorbell.o \
diff --git a/drivers/infiniband/hw/mlx5/cmd.c b/drivers/infiniband/hw/mlx5/cmd.c
index 7c08e30089277..895b62cc528df 100644
--- a/drivers/infiniband/hw/mlx5/cmd.c
+++ b/drivers/infiniband/hw/mlx5/cmd.c
@@ -245,24 +245,3 @@ int mlx5_cmd_uar_dealloc(struct mlx5_core_dev *dev, u32 uarn, u16 uid)
 	MLX5_SET(dealloc_uar_in, in, uid, uid);
 	return mlx5_cmd_exec_in(dev, dealloc_uar, in);
 }
-
-int mlx5_cmd_query_vuid(struct mlx5_core_dev *dev, bool data_direct,
-			char *out_vuid)
-{
-	u8 out[MLX5_ST_SZ_BYTES(query_vuid_out) +
-		MLX5_ST_SZ_BYTES(array1024_auto)] = {};
-	u8 in[MLX5_ST_SZ_BYTES(query_vuid_in)] = {};
-	char *vuid;
-	int err;
-
-	MLX5_SET(query_vuid_in, in, opcode, MLX5_CMD_OPCODE_QUERY_VUID);
-	MLX5_SET(query_vuid_in, in, vhca_id, MLX5_CAP_GEN(dev, vhca_id));
-	MLX5_SET(query_vuid_in, in, data_direct, data_direct);
-	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
-	if (err)
-		return err;
-
-	vuid = MLX5_ADDR_OF(query_vuid_out, out, vuid);
-	memcpy(out_vuid, vuid, MLX5_ST_SZ_BYTES(array1024_auto));
-	return 0;
-}
diff --git a/drivers/infiniband/hw/mlx5/cmd.h b/drivers/infiniband/hw/mlx5/cmd.h
index e6c88b6ebd0da..e5cd31270443d 100644
--- a/drivers/infiniband/hw/mlx5/cmd.h
+++ b/drivers/infiniband/hw/mlx5/cmd.h
@@ -58,6 +58,4 @@ int mlx5_cmd_mad_ifc(struct mlx5_ib_dev *dev, const void *inb, void *outb,
 		     u16 opmod, u8 port);
 int mlx5_cmd_uar_alloc(struct mlx5_core_dev *dev, u32 *uarn, u16 uid);
 int mlx5_cmd_uar_dealloc(struct mlx5_core_dev *dev, u32 uarn, u16 uid);
-int mlx5_cmd_query_vuid(struct mlx5_core_dev *dev, bool data_direct,
-			char *out_vuid);
 #endif /* MLX5_IB_CMD_H */
diff --git a/drivers/infiniband/hw/mlx5/data_direct.c b/drivers/infiniband/hw/mlx5/data_direct.c
deleted file mode 100644
index d57484245c382..0000000000000
--- a/drivers/infiniband/hw/mlx5/data_direct.c
+++ /dev/null
@@ -1,227 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
-/*
- * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved
- */
-
-#include "mlx5_ib.h"
-#include "data_direct.h"
-
-static LIST_HEAD(mlx5_data_direct_dev_list);
-static LIST_HEAD(mlx5_data_direct_reg_list);
-
-/*
- * This mutex should be held when accessing either of the above lists
- */
-static DEFINE_MUTEX(mlx5_data_direct_mutex);
-
-struct mlx5_data_direct_registration {
-	struct mlx5_ib_dev *ibdev;
-	char vuid[MLX5_ST_SZ_BYTES(array1024_auto) + 1];
-	struct list_head list;
-};
-
-static const struct pci_device_id mlx5_data_direct_pci_table[] = {
-	{ PCI_VDEVICE(MELLANOX, 0x2100) }, /* ConnectX-8 Data Direct */
-	{ 0, }
-};
-
-static int mlx5_data_direct_vpd_get_vuid(struct mlx5_data_direct_dev *dev)
-{
-	struct pci_dev *pdev = dev->pdev;
-	unsigned int vpd_size, kw_len;
-	u8 *vpd_data;
-	int start;
-	int ret;
-
-	vpd_data = pci_vpd_alloc(pdev, &vpd_size);
-	if (IS_ERR(vpd_data)) {
-		pci_err(pdev, "Unable to read VPD, err=%pe\n", vpd_data);
-		return PTR_ERR(vpd_data);
-	}
-
-	start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, "VU", &kw_len);
-	if (start < 0) {
-		ret = start;
-		pci_err(pdev, "VU keyword not found, err=%d\n", ret);
-		goto end;
-	}
-
-	dev->vuid = kmemdup_nul(vpd_data + start, kw_len, GFP_KERNEL);
-	ret = dev->vuid ? 0 : -ENOMEM;
-
-end:
-	kfree(vpd_data);
-	return ret;
-}
-
-static void mlx5_data_direct_shutdown(struct pci_dev *pdev)
-{
-	pci_disable_device(pdev);
-}
-
-static int mlx5_data_direct_set_dma_caps(struct pci_dev *pdev)
-{
-	int err;
-
-	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
-	if (err) {
-		dev_warn(&pdev->dev,
-			 "Warning: couldn't set 64-bit PCI DMA mask, err=%d\n", err);
-		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-		if (err) {
-			dev_err(&pdev->dev, "Can't set PCI DMA mask, err=%d\n", err);
-			return err;
-		}
-	}
-
-	dma_set_max_seg_size(&pdev->dev, SZ_2G);
-	return 0;
-}
-
-int mlx5_data_direct_ib_reg(struct mlx5_ib_dev *ibdev, char *vuid)
-{
-	struct mlx5_data_direct_registration *reg;
-	struct mlx5_data_direct_dev *dev;
-
-	reg = kzalloc_obj(*reg);
-	if (!reg)
-		return -ENOMEM;
-
-	reg->ibdev = ibdev;
-	strscpy(reg->vuid, vuid);
-
-	mutex_lock(&mlx5_data_direct_mutex);
-	list_for_each_entry(dev, &mlx5_data_direct_dev_list, list) {
-		if (strcmp(dev->vuid, vuid) == 0) {
-			mlx5_ib_data_direct_bind(ibdev, dev);
-			break;
-		}
-	}
-
-	/* Add the registration to its global list, to be used upon bind/unbind
-	 * of its affiliated data direct device
-	 */
-	list_add_tail(&reg->list, &mlx5_data_direct_reg_list);
-	mutex_unlock(&mlx5_data_direct_mutex);
-	return 0;
-}
-
-void mlx5_data_direct_ib_unreg(struct mlx5_ib_dev *ibdev)
-{
-	struct mlx5_data_direct_registration *reg;
-
-	mutex_lock(&mlx5_data_direct_mutex);
-	list_for_each_entry(reg, &mlx5_data_direct_reg_list, list) {
-		if (reg->ibdev == ibdev) {
-			list_del(&reg->list);
-			kfree(reg);
-			goto end;
-		}
-	}
-
-	WARN_ON(true);
-end:
-	mutex_unlock(&mlx5_data_direct_mutex);
-}
-
-static void mlx5_data_direct_dev_reg(struct mlx5_data_direct_dev *dev)
-{
-	struct mlx5_data_direct_registration *reg;
-
-	mutex_lock(&mlx5_data_direct_mutex);
-	list_for_each_entry(reg, &mlx5_data_direct_reg_list, list) {
-		if (strcmp(dev->vuid, reg->vuid) == 0)
-			mlx5_ib_data_direct_bind(reg->ibdev, dev);
-	}
-
-	/* Add the data direct device to the global list, further IB devices may
-	 * use it later as well
-	 */
-	list_add_tail(&dev->list, &mlx5_data_direct_dev_list);
-	mutex_unlock(&mlx5_data_direct_mutex);
-}
-
-static void mlx5_data_direct_dev_unreg(struct mlx5_data_direct_dev *dev)
-{
-	struct mlx5_data_direct_registration *reg;
-
-	mutex_lock(&mlx5_data_direct_mutex);
-	/* Prevent any further affiliations */
-	list_del(&dev->list);
-	list_for_each_entry(reg, &mlx5_data_direct_reg_list, list) {
-		if (strcmp(dev->vuid, reg->vuid) == 0)
-			mlx5_ib_data_direct_unbind(reg->ibdev);
-	}
-	mutex_unlock(&mlx5_data_direct_mutex);
-}
-
-static int mlx5_data_direct_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
-	struct mlx5_data_direct_dev *dev;
-	int err;
-
-	dev = kzalloc_obj(*dev);
-	if (!dev)
-		return -ENOMEM;
-
-	dev->device = &pdev->dev;
-	dev->pdev = pdev;
-
-	pci_set_drvdata(dev->pdev, dev);
-	err = pci_enable_device(pdev);
-	if (err) {
-		dev_err(dev->device, "Cannot enable PCI device, err=%d\n", err);
-		goto err;
-	}
-
-	pci_set_master(pdev);
-	err = mlx5_data_direct_set_dma_caps(pdev);
-	if (err)
-		goto err_disable;
-
-	if (pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP32) &&
-	    pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP64) &&
-	    pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP128))
-		dev_dbg(dev->device, "Enabling pci atomics failed\n");
-
-	err = mlx5_data_direct_vpd_get_vuid(dev);
-	if (err)
-		goto err_disable;
-
-	mlx5_data_direct_dev_reg(dev);
-	return 0;
-
-err_disable:
-	pci_disable_device(pdev);
-err:
-	kfree(dev);
-	return err;
-}
-
-static void mlx5_data_direct_remove(struct pci_dev *pdev)
-{
-	struct mlx5_data_direct_dev *dev = pci_get_drvdata(pdev);
-
-	mlx5_data_direct_dev_unreg(dev);
-	pci_disable_device(pdev);
-	kfree(dev->vuid);
-	kfree(dev);
-}
-
-static struct pci_driver mlx5_data_direct_driver = {
-	.name = KBUILD_MODNAME,
-	.id_table = mlx5_data_direct_pci_table,
-	.probe = mlx5_data_direct_probe,
-	.remove = mlx5_data_direct_remove,
-	.shutdown = mlx5_data_direct_shutdown,
-};
-
-int mlx5_data_direct_driver_register(void)
-{
-	return pci_register_driver(&mlx5_data_direct_driver);
-}
-
-void mlx5_data_direct_driver_unregister(void)
-{
-	pci_unregister_driver(&mlx5_data_direct_driver);
-}
diff --git a/drivers/infiniband/hw/mlx5/data_direct.h b/drivers/infiniband/hw/mlx5/data_direct.h
deleted file mode 100644
index 2fd2bdbe8f692..0000000000000
--- a/drivers/infiniband/hw/mlx5/data_direct.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
-/*
- * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved
- */
-
-#ifndef _MLX5_IB_DATA_DIRECT_H
-#define _MLX5_IB_DATA_DIRECT_H
-
-struct mlx5_ib_dev;
-
-struct mlx5_data_direct_dev {
-	struct device *device;
-	struct pci_dev *pdev;
-	char *vuid;
-	struct list_head list;
-};
-
-int mlx5_data_direct_ib_reg(struct mlx5_ib_dev *ibdev, char *vuid);
-void mlx5_data_direct_ib_unreg(struct mlx5_ib_dev *ibdev);
-int mlx5_data_direct_driver_register(void);
-void mlx5_data_direct_driver_unregister(void);
-
-#endif
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 02809114fc79a..dd2a3996b14e1 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -25,6 +25,7 @@
 #include <linux/mlx5/vport.h>
 #include <linux/mlx5/fs.h>
 #include <linux/mlx5/eswitch.h>
+#include <linux/mlx5/data_direct.h>
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/lag.h>
 #include <linux/list.h>
@@ -51,7 +52,6 @@
 #include <rdma/mlx5_user_ioctl_cmds.h>
 #include <rdma/ib_ucaps.h>
 #include "macsec.h"
-#include "data_direct.h"
 #include "dmah.h"
 
 #define UVERBS_MODULE_NAME mlx5_ib
@@ -3473,87 +3473,6 @@ static void mlx5_ib_dev_res_cleanup(struct mlx5_ib_dev *dev)
 	mutex_destroy(&devr->srq_lock);
 }
 
-static int
-mlx5_ib_create_data_direct_resources(struct mlx5_ib_dev *dev)
-{
-	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
-	struct mlx5_core_dev *mdev = dev->mdev;
-	bool ro_supp = false;
-	void *mkc;
-	u32 mkey;
-	u32 pdn;
-	u32 *in;
-	int err;
-
-	err = mlx5_core_alloc_pd(mdev, &pdn);
-	if (err)
-		return err;
-
-	in = kvzalloc(inlen, GFP_KERNEL);
-	if (!in) {
-		err = -ENOMEM;
-		goto err;
-	}
-
-	MLX5_SET(create_mkey_in, in, data_direct, 1);
-	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
-	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
-	MLX5_SET(mkc, mkc, lw, 1);
-	MLX5_SET(mkc, mkc, lr, 1);
-	MLX5_SET(mkc, mkc, rw, 1);
-	MLX5_SET(mkc, mkc, rr, 1);
-	MLX5_SET(mkc, mkc, a, 1);
-	MLX5_SET(mkc, mkc, pd, pdn);
-	MLX5_SET(mkc, mkc, length64, 1);
-	MLX5_SET(mkc, mkc, qpn, 0xffffff);
-	err = mlx5_core_create_mkey(mdev, &mkey, in, inlen);
-	if (err)
-		goto err_mkey;
-
-	dev->ddr.mkey = mkey;
-	dev->ddr.pdn = pdn;
-
-	/* create another mkey with RO support */
-	if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_write)) {
-		MLX5_SET(mkc, mkc, relaxed_ordering_write, 1);
-		ro_supp = true;
-	}
-
-	if (MLX5_CAP_GEN(dev->mdev, relaxed_ordering_read)) {
-		MLX5_SET(mkc, mkc, relaxed_ordering_read, 1);
-		ro_supp = true;
-	}
-
-	if (ro_supp) {
-		err = mlx5_core_create_mkey(mdev, &mkey, in, inlen);
-		/* RO is defined as best effort */
-		if (!err) {
-			dev->ddr.mkey_ro = mkey;
-			dev->ddr.mkey_ro_valid = true;
-		}
-	}
-
-	kvfree(in);
-	return 0;
-
-err_mkey:
-	kvfree(in);
-err:
-	mlx5_core_dealloc_pd(mdev, pdn);
-	return err;
-}
-
-static void
-mlx5_ib_free_data_direct_resources(struct mlx5_ib_dev *dev)
-{
-
-	if (dev->ddr.mkey_ro_valid)
-		mlx5_core_destroy_mkey(dev->mdev, dev->ddr.mkey_ro);
-
-	mlx5_core_destroy_mkey(dev->mdev, dev->ddr.mkey);
-	mlx5_core_dealloc_pd(dev->mdev, dev->ddr.pdn);
-}
-
 static u32 get_core_cap_flags(struct ib_device *ibdev,
 			      struct mlx5_hca_vport_context *rep)
 {
@@ -4019,39 +3938,42 @@ static bool mlx5_ib_bind_slave_port(struct mlx5_ib_dev *ibdev,
 	return false;
 }
 
+static int mlx5_ib_data_direct_event(struct notifier_block *nb,
+				     unsigned long action, void *data)
+{
+	struct mlx5_ib_dev *dev =
+		container_of(nb, struct mlx5_ib_dev, data_direct_nb);
+
+	if (action != MLX5_DATA_DIRECT_UNBIND)
+		return NOTIFY_DONE;
+
+	mutex_lock(&dev->data_direct_lock);
+	mlx5_ib_revoke_data_direct_mrs(dev);
+	mutex_unlock(&dev->data_direct_lock);
+
+	return NOTIFY_OK;
+}
+
 static int mlx5_ib_data_direct_init(struct mlx5_ib_dev *dev)
 {
-	char vuid[MLX5_ST_SZ_BYTES(array1024_auto) + 1] = {};
 	int ret;
 
-	if (!MLX5_CAP_GEN(dev->mdev, data_direct) ||
-	    !MLX5_CAP_GEN_2(dev->mdev, query_vuid))
+	if (!mlx5_data_direct_supported(dev->mdev))
 		return 0;
 
-	ret = mlx5_cmd_query_vuid(dev->mdev, true, vuid);
-	if (ret)
-		return ret;
-
-	ret = mlx5_ib_create_data_direct_resources(dev);
-	if (ret)
-		return ret;
-
 	INIT_LIST_HEAD(&dev->data_direct_mr_list);
-	ret = mlx5_data_direct_ib_reg(dev, vuid);
-	if (ret)
-		mlx5_ib_free_data_direct_resources(dev);
+	dev->data_direct_nb.notifier_call = mlx5_ib_data_direct_event;
+	ret = mlx5_data_direct_register(dev->mdev, &dev->data_direct_nb);
 
 	return ret;
 }
 
 static void mlx5_ib_data_direct_cleanup(struct mlx5_ib_dev *dev)
 {
-	if (!MLX5_CAP_GEN(dev->mdev, data_direct) ||
-	    !MLX5_CAP_GEN_2(dev->mdev, query_vuid))
+	if (!mlx5_data_direct_supported(dev->mdev))
 		return;
 
-	mlx5_data_direct_ib_unreg(dev);
-	mlx5_ib_free_data_direct_resources(dev);
+	mlx5_data_direct_unregister(dev->mdev, &dev->data_direct_nb);
 }
 
 static int mlx5_ib_init_multiport_master(struct mlx5_ib_dev *dev)
@@ -5077,22 +4999,6 @@ static void mlx5_ib_stage_dev_notifier_cleanup(struct mlx5_ib_dev *dev)
 		cancel_work_sync(&devr->ports[port].pkey_change_work);
 }
 
-void mlx5_ib_data_direct_bind(struct mlx5_ib_dev *ibdev,
-			      struct mlx5_data_direct_dev *dev)
-{
-	mutex_lock(&ibdev->data_direct_lock);
-	ibdev->data_direct_dev = dev;
-	mutex_unlock(&ibdev->data_direct_lock);
-}
-
-void mlx5_ib_data_direct_unbind(struct mlx5_ib_dev *ibdev)
-{
-	mutex_lock(&ibdev->data_direct_lock);
-	mlx5_ib_revoke_data_direct_mrs(ibdev);
-	ibdev->data_direct_dev = NULL;
-	mutex_unlock(&ibdev->data_direct_lock);
-}
-
 void __mlx5_ib_remove(struct mlx5_ib_dev *dev,
 		      const struct mlx5_ib_profile *profile,
 		      int stage)
@@ -5519,9 +5425,6 @@ static int __init mlx5_ib_init(void)
 	ret = mlx5r_rep_init();
 	if (ret)
 		goto rep_err;
-	ret = mlx5_data_direct_driver_register();
-	if (ret)
-		goto dd_err;
 	ret = auxiliary_driver_register(&mlx5r_mp_driver);
 	if (ret)
 		goto mp_err;
@@ -5534,8 +5437,6 @@ static int __init mlx5_ib_init(void)
 drv_err:
 	auxiliary_driver_unregister(&mlx5r_mp_driver);
 mp_err:
-	mlx5_data_direct_driver_unregister();
-dd_err:
 	mlx5r_rep_cleanup();
 rep_err:
 	mlx5_ib_qp_event_cleanup();
@@ -5547,7 +5448,6 @@ static int __init mlx5_ib_init(void)
 
 static void __exit mlx5_ib_cleanup(void)
 {
-	mlx5_data_direct_driver_unregister();
 	auxiliary_driver_unregister(&mlx5r_driver);
 	auxiliary_driver_unregister(&mlx5r_mp_driver);
 	mlx5r_rep_cleanup();
diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h
index 522984d958bbf..1a3b9cb791849 100644
--- a/drivers/infiniband/hw/mlx5/mlx5_ib.h
+++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h
@@ -24,6 +24,7 @@
 #include <rdma/mlx5_user_ioctl_cmds.h>
 #include <rdma/mlx5_user_ioctl_verbs.h>
 
+#include <linux/mlx5/data_direct.h>
 #include "srq.h"
 #include "qp.h"
 #include "macsec.h"
@@ -781,13 +782,6 @@ struct mlx5_ib_port_resources {
 	struct work_struct pkey_change_work;
 };
 
-struct mlx5_data_direct_resources {
-	u32 pdn;
-	u32 mkey;
-	u32 mkey_ro;
-	u8 mkey_ro_valid :1;
-};
-
 struct mlx5_ib_resources {
 	struct ib_cq	*c0;
 	struct mutex cq_lock;
@@ -1097,8 +1091,9 @@ struct mlx5_macsec {
 struct mlx5_ib_dev {
 	struct ib_device		ib_dev;
 	struct mlx5_core_dev		*mdev;
-	struct mlx5_data_direct_dev	*data_direct_dev;
-	/* protect accessing data_direct_dev */
+	/* Protects data_direct_mr_list and serializes mr
+	 * registration/deregistration with data direct device unbind.
+	 */
 	struct mutex			data_direct_lock;
 	struct notifier_block		mdev_events;
 	struct notifier_block		sys_error_events;
@@ -1131,6 +1126,7 @@ struct mlx5_ib_dev {
 	spinlock_t		reset_flow_resource_lock;
 	struct list_head	qp_list;
 	struct list_head data_direct_mr_list;
+	struct notifier_block data_direct_nb;
 	/* Array with num_ports elements */
 	struct mlx5_ib_port	*port;
 	struct mlx5_sq_bfreg	bfreg;
@@ -1155,7 +1151,6 @@ struct mlx5_ib_dev {
 	u16 pkey_table_len;
 	u8 lag_ports;
 	struct mlx5_special_mkeys mkeys;
-	struct mlx5_data_direct_resources ddr;
 
 #ifdef CONFIG_MLX5_MACSEC
 	struct mlx5_macsec macsec;
@@ -1401,9 +1396,6 @@ int mlx5_ib_destroy_rwq_ind_table(struct ib_rwq_ind_table *wq_ind_table);
 struct ib_mr *mlx5_ib_reg_dm_mr(struct ib_pd *pd, struct ib_dm *dm,
 				struct ib_dm_mr_attr *attr,
 				struct uverbs_attr_bundle *attrs);
-void mlx5_ib_data_direct_bind(struct mlx5_ib_dev *ibdev,
-			      struct mlx5_data_direct_dev *dev);
-void mlx5_ib_data_direct_unbind(struct mlx5_ib_dev *ibdev);
 void mlx5_ib_revoke_data_direct_mrs(struct mlx5_ib_dev *dev);
 
 #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index e6b74955d95dc..7463b36a36b63 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -44,7 +44,6 @@
 #include "dm.h"
 #include "mlx5_ib.h"
 #include "umr.h"
-#include "data_direct.h"
 #include "dmah.h"
 
 static int mkey_max_umr_order(struct mlx5_ib_dev *dev)
@@ -587,7 +586,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, struct ib_umem *umem,
 				      populate ? pd : dev->umrc.pd);
 	/* In case a data direct flow, overwrite the pdn field by its internal kernel PD */
 	if (umem->is_dmabuf && ksm_mode)
-		MLX5_SET(mkc, mkc, pd, dev->ddr.pdn);
+		MLX5_SET(mkc, mkc, pd, dev->mdev->data_direct->pdn);
 
 	MLX5_SET(mkc, mkc, free, !populate);
 	MLX5_SET(mkc, mkc, access_mode_1_0, access_mode);
@@ -997,7 +996,7 @@ reg_user_mr_dmabuf_by_data_direct(struct ib_pd *pd, u64 offset,
 		return ERR_PTR(-EOPNOTSUPP);
 
 	mutex_lock(&dev->data_direct_lock);
-	data_direct_dev = dev->data_direct_dev;
+	data_direct_dev = mlx5_data_direct_get_dev(dev->mdev->data_direct);
 	if (!data_direct_dev) {
 		ret = -EINVAL;
 		goto end;
@@ -1006,7 +1005,7 @@ reg_user_mr_dmabuf_by_data_direct(struct ib_pd *pd, u64 offset,
 	/* If no device's 'data direct mkey' with RO flags exists
 	 * mask it out accordingly.
 	 */
-	if (!dev->ddr.mkey_ro_valid)
+	if (!dev->mdev->data_direct->mkey_ro_valid)
 		access_flags &= ~IB_ACCESS_RELAXED_ORDERING;
 	crossed_mr = reg_user_mr_dmabuf(pd, &data_direct_dev->pdev->dev,
 					offset, length, virt_addr, fd,
diff --git a/drivers/infiniband/hw/mlx5/odp.c b/drivers/infiniband/hw/mlx5/odp.c
index 1badec9bf5270..2e9a704acc44a 100644
--- a/drivers/infiniband/hw/mlx5/odp.c
+++ b/drivers/infiniband/hw/mlx5/odp.c
@@ -952,7 +952,7 @@ int mlx5_ib_init_dmabuf_mr(struct mlx5_ib_mr *mr, struct ib_pd *pd)
 	int ret;
 
 	if (mr->data_direct)
-		pdn = dev->ddr.pdn;
+		pdn = dev->mdev->data_direct->pdn;
 	else
 		pdn = to_mpd(pd)->pdn;
 
diff --git a/drivers/infiniband/hw/mlx5/std_types.c b/drivers/infiniband/hw/mlx5/std_types.c
index 1ee31611b4b3f..b705b88dc917b 100644
--- a/drivers/infiniband/hw/mlx5/std_types.c
+++ b/drivers/infiniband/hw/mlx5/std_types.c
@@ -10,7 +10,6 @@
 #include <linux/mlx5/eswitch.h>
 #include <linux/mlx5/vport.h>
 #include "mlx5_ib.h"
-#include "data_direct.h"
 
 #define UVERBS_MODULE_NAME mlx5_ib
 #include <rdma/uverbs_named_ioctl.h>
@@ -203,7 +202,7 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_GET_DATA_DIRECT_SYSFS_PATH)(
 		return PTR_ERR(c);
 	dev = to_mdev(c->ibucontext.device);
 	mutex_lock(&dev->data_direct_lock);
-	data_direct_dev = dev->data_direct_dev;
+	data_direct_dev = mlx5_data_direct_get_dev(dev->mdev->data_direct);
 	if (!data_direct_dev) {
 		ret = -ENODEV;
 		goto end;
diff --git a/drivers/infiniband/hw/mlx5/umr.c b/drivers/infiniband/hw/mlx5/umr.c
index 48cae5cc1c1be..a3bb8d03fd35f 100644
--- a/drivers/infiniband/hw/mlx5/umr.c
+++ b/drivers/infiniband/hw/mlx5/umr.c
@@ -760,12 +760,14 @@ static int _mlx5r_umr_update_mr_pas(struct mlx5_ib_mr *mr, unsigned int flags,
 		}
 
 		if (dd) {
+			struct mlx5_data_direct *mdd = dev->mdev->data_direct;
+
 			cur_ksm->va = cpu_to_be64(rdma_block_iter_dma_address(&biter));
 			if (mr->access_flags & IB_ACCESS_RELAXED_ORDERING &&
-			    dev->ddr.mkey_ro_valid)
-				cur_ksm->key = cpu_to_be32(dev->ddr.mkey_ro);
+			    mdd->mkey_ro_valid)
+				cur_ksm->key = cpu_to_be32(mdd->mkey_ro);
 			else
-				cur_ksm->key = cpu_to_be32(dev->ddr.mkey);
+				cur_ksm->key = cpu_to_be32(mdd->mkey);
 			if (mr->umem->is_dmabuf &&
 			    (flags & MLX5_IB_UPD_XLT_ZAP)) {
 				cur_ksm->va = 0;
@@ -810,7 +812,8 @@ int mlx5r_umr_update_data_direct_ksm_pas_range(struct mlx5_ib_mr *mr,
 	    !(flags & MLX5_IB_UPD_XLT_KEEP_PGSZ)))
 		return -EINVAL;
 
-	return _mlx5r_umr_update_mr_pas(mr, flags, mr_to_mdev(mr)->ddr.pdn,
+	return _mlx5r_umr_update_mr_pas(mr, flags,
+					mr_to_mdev(mr)->mdev->data_direct->pdn,
 					true, start_block, nblocks);
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 19e50f0d55af3..a1871259210d6 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -18,7 +18,7 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
 		lib/devcom.o lib/pci_vsc.o lib/dm.o lib/fs_ttc.o diag/fs_tracepoint.o \
 		diag/fw_tracer.o diag/crdump.o devlink.o sh_devlink.o diag/rsc_dump.o \
 		diag/reporter_vnic.o fw_reset.o qos.o lib/tout.o lib/aso.o wc.o fs_pool.o \
-		lib/nv_param.o
+		lib/nv_param.o data_direct.o
 
 #
 # Netdev basic
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/data_direct.c b/drivers/net/ethernet/mellanox/mlx5/core/data_direct.c
new file mode 100644
index 0000000000000..67717110feab0
--- /dev/null
+++ b/drivers/net/ethernet/mellanox/mlx5/core/data_direct.c
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
+/*
+ * Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved
+ */
+
+#include <linux/list.h>
+#include <linux/mlx5/driver.h>
+#include <linux/mlx5/data_direct.h>
+#include <linux/mlx5/mlx5_ifc.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include "mlx5_core.h"
+
+static LIST_HEAD(mlx5_data_direct_dev_list);
+static LIST_HEAD(mlx5_data_direct_reg_list);
+
+/*
+ * This mutex should be held when accessing either of the above lists
+ */
+static DEFINE_MUTEX(mlx5_data_direct_mutex);
+
+struct mlx5_data_direct_registration {
+	char vuid[MLX5_ST_SZ_BYTES(array1024_auto) + 1];
+	struct list_head list;
+	struct blocking_notifier_head users;
+	struct mlx5_data_direct dd;
+};
+
+static int mlx5_data_direct_query_vuid(struct mlx5_core_dev *dev,
+				       char *out_vuid)
+{
+	u8 out[MLX5_ST_SZ_BYTES(query_vuid_out) +
+	       MLX5_ST_SZ_BYTES(array1024_auto)] = {};
+	u8 in[MLX5_ST_SZ_BYTES(query_vuid_in)] = {};
+	char *vuid;
+	int err;
+
+	MLX5_SET(query_vuid_in, in, opcode, MLX5_CMD_OPCODE_QUERY_VUID);
+	MLX5_SET(query_vuid_in, in, vhca_id, MLX5_CAP_GEN(dev, vhca_id));
+	MLX5_SET(query_vuid_in, in, data_direct, 1);
+	err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
+	if (err)
+		return err;
+
+	vuid = MLX5_ADDR_OF(query_vuid_out, out, vuid);
+	memcpy(out_vuid, vuid, MLX5_ST_SZ_BYTES(array1024_auto));
+	return 0;
+}
+
+static const struct pci_device_id mlx5_data_direct_pci_table[] = {
+	{ PCI_VDEVICE(MELLANOX, 0x2100) }, /* ConnectX-8 Data Direct */
+	{ 0, }
+};
+
+static int mlx5_data_direct_vpd_get_vuid(struct mlx5_data_direct_dev *dev)
+{
+	struct pci_dev *pdev = dev->pdev;
+	unsigned int vpd_size, kw_len;
+	u8 *vpd_data;
+	int start;
+	int ret;
+
+	vpd_data = pci_vpd_alloc(pdev, &vpd_size);
+	if (IS_ERR(vpd_data)) {
+		pci_err(pdev, "Unable to read VPD, err=%pe\n", vpd_data);
+		return PTR_ERR(vpd_data);
+	}
+
+	start = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, "VU", &kw_len);
+	if (start < 0) {
+		ret = start;
+		pci_err(pdev, "VU keyword not found, err=%d\n", ret);
+		goto end;
+	}
+
+	dev->vuid = kmemdup_nul(vpd_data + start, kw_len, GFP_KERNEL);
+	ret = dev->vuid ? 0 : -ENOMEM;
+
+end:
+	kfree(vpd_data);
+	return ret;
+}
+
+static void mlx5_data_direct_shutdown(struct pci_dev *pdev)
+{
+	pci_disable_device(pdev);
+}
+
+static int mlx5_data_direct_set_dma_caps(struct pci_dev *pdev)
+{
+	int err;
+
+	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+	if (err) {
+		dev_warn(&pdev->dev,
+			 "Warning: couldn't set 64-bit PCI DMA mask, err=%d\n", err);
+		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+		if (err) {
+			dev_err(&pdev->dev, "Can't set PCI DMA mask, err=%d\n", err);
+			return err;
+		}
+	}
+
+	dma_set_max_seg_size(&pdev->dev, SZ_2G);
+	return 0;
+}
+
+static int mlx5_data_direct_create_resources(struct mlx5_core_dev *mdev)
+{
+	int inlen = MLX5_ST_SZ_BYTES(create_mkey_in);
+	bool ro_supp = false;
+	void *mkc;
+	u32 mkey;
+	u32 pdn;
+	u32 *in;
+	int err;
+
+	err = mlx5_core_alloc_pd(mdev, &pdn);
+	if (err)
+		return err;
+
+	in = kvzalloc(inlen, GFP_KERNEL);
+	if (!in) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	MLX5_SET(create_mkey_in, in, data_direct, 1);
+	mkc = MLX5_ADDR_OF(create_mkey_in, in, memory_key_mkey_entry);
+	MLX5_SET(mkc, mkc, access_mode_1_0, MLX5_MKC_ACCESS_MODE_PA);
+	MLX5_SET(mkc, mkc, lw, 1);
+	MLX5_SET(mkc, mkc, lr, 1);
+	MLX5_SET(mkc, mkc, rw, 1);
+	MLX5_SET(mkc, mkc, rr, 1);
+	MLX5_SET(mkc, mkc, a, 1);
+	MLX5_SET(mkc, mkc, pd, pdn);
+	MLX5_SET(mkc, mkc, length64, 1);
+	MLX5_SET(mkc, mkc, qpn, 0xffffff);
+	err = mlx5_core_create_mkey(mdev, &mkey, in, inlen);
+	if (err)
+		goto err_mkey;
+
+	mdev->data_direct->mkey = mkey;
+	mdev->data_direct->pdn = pdn;
+
+	/* create another mkey with RO support */
+	if (MLX5_CAP_GEN(mdev, relaxed_ordering_write)) {
+		MLX5_SET(mkc, mkc, relaxed_ordering_write, 1);
+		ro_supp = true;
+	}
+
+	if (MLX5_CAP_GEN(mdev, relaxed_ordering_read)) {
+		MLX5_SET(mkc, mkc, relaxed_ordering_read, 1);
+		ro_supp = true;
+	}
+
+	if (ro_supp) {
+		err = mlx5_core_create_mkey(mdev, &mkey, in, inlen);
+		/* RO is defined as best effort */
+		if (!err) {
+			mdev->data_direct->mkey_ro = mkey;
+			mdev->data_direct->mkey_ro_valid = true;
+		}
+	}
+
+	kvfree(in);
+	return 0;
+
+err_mkey:
+	kvfree(in);
+err:
+	mlx5_core_dealloc_pd(mdev, pdn);
+	return err;
+}
+
+static void mlx5_data_direct_free_resources(struct mlx5_core_dev *mdev)
+{
+	struct mlx5_data_direct *data_direct = mdev->data_direct;
+
+	if (data_direct->mkey_ro_valid)
+		mlx5_core_destroy_mkey(mdev, data_direct->mkey_ro);
+
+	mlx5_core_destroy_mkey(mdev, data_direct->mkey);
+	mlx5_core_dealloc_pd(mdev, data_direct->pdn);
+}
+
+static void mlx5_data_direct_bind(struct mlx5_data_direct_registration *reg,
+				  struct mlx5_data_direct_dev *dev)
+{
+	WRITE_ONCE(reg->dd.dev, dev);
+}
+
+static void
+mlx5_data_direct_do_unbind(struct mlx5_data_direct_registration *reg)
+{
+	WRITE_ONCE(reg->dd.dev, NULL);
+	blocking_notifier_call_chain(&reg->users, MLX5_DATA_DIRECT_UNBIND,
+				     NULL);
+}
+
+int mlx5_data_direct_init(struct mlx5_core_dev *mdev)
+{
+	struct mlx5_data_direct_registration *reg;
+	struct mlx5_data_direct_dev *dev;
+	int err;
+
+	if (!mlx5_data_direct_supported(mdev))
+		return 0;
+
+	reg = kzalloc_obj(*reg);
+	if (!reg)
+		return -ENOMEM;
+
+	BLOCKING_INIT_NOTIFIER_HEAD(&reg->users);
+
+	err = mlx5_data_direct_query_vuid(mdev, reg->vuid);
+	if (err) {
+		mlx5_core_warn(mdev,
+			       "Failed to query VUID, disabling data direct, err=%d\n",
+			       err);
+		kfree(reg);
+		return -EINVAL;
+	}
+
+	mdev->data_direct = &reg->dd;
+
+	err = mlx5_data_direct_create_resources(mdev);
+	if (err)
+		goto err_resources;
+
+	mutex_lock(&mlx5_data_direct_mutex);
+	list_for_each_entry(dev, &mlx5_data_direct_dev_list, list) {
+		if (strcmp(dev->vuid, reg->vuid) == 0) {
+			mlx5_data_direct_bind(reg, dev);
+			break;
+		}
+	}
+
+	/* Add the registration to its global list, to be used upon bind/unbind
+	 * of its affiliated data direct device.
+	 */
+	list_add_tail(&reg->list, &mlx5_data_direct_reg_list);
+	mutex_unlock(&mlx5_data_direct_mutex);
+	return 0;
+
+err_resources:
+	mdev->data_direct = NULL;
+	kfree(reg);
+	return err;
+}
+
+void mlx5_data_direct_cleanup(struct mlx5_core_dev *mdev)
+{
+	struct mlx5_data_direct_registration *reg;
+
+	if (!mlx5_data_direct_supported(mdev))
+		return;
+
+	reg = container_of(mdev->data_direct,
+			   struct mlx5_data_direct_registration, dd);
+	mutex_lock(&mlx5_data_direct_mutex);
+	list_del(&reg->list);
+	mlx5_data_direct_do_unbind(reg);
+	mutex_unlock(&mlx5_data_direct_mutex);
+
+	mlx5_data_direct_free_resources(mdev);
+	mdev->data_direct = NULL;
+	kfree(reg);
+}
+
+int mlx5_data_direct_register(struct mlx5_core_dev *mdev,
+			      struct notifier_block *nb)
+{
+	struct mlx5_data_direct_registration *reg;
+
+	if (!mlx5_data_direct_supported(mdev))
+		return 0;
+
+	reg = container_of(mdev->data_direct,
+			   struct mlx5_data_direct_registration, dd);
+	blocking_notifier_chain_register(&reg->users, nb);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mlx5_data_direct_register);
+
+void mlx5_data_direct_unregister(struct mlx5_core_dev *mdev,
+				 struct notifier_block *nb)
+{
+	struct mlx5_data_direct_registration *reg;
+
+	if (!mlx5_data_direct_supported(mdev))
+		return;
+
+	reg = container_of(mdev->data_direct,
+			   struct mlx5_data_direct_registration, dd);
+	blocking_notifier_chain_unregister(&reg->users, nb);
+}
+EXPORT_SYMBOL_GPL(mlx5_data_direct_unregister);
+
+static void mlx5_data_direct_dev_reg(struct mlx5_data_direct_dev *dev)
+{
+	struct mlx5_data_direct_registration *reg;
+
+	mutex_lock(&mlx5_data_direct_mutex);
+	list_for_each_entry(reg, &mlx5_data_direct_reg_list, list) {
+		if (strcmp(dev->vuid, reg->vuid) == 0)
+			mlx5_data_direct_bind(reg, dev);
+	}
+
+	/* Add the data direct device to the global list, further mlx5 devices
+	 * may use it later as well.
+	 */
+	list_add_tail(&dev->list, &mlx5_data_direct_dev_list);
+	mutex_unlock(&mlx5_data_direct_mutex);
+}
+
+static void mlx5_data_direct_dev_unreg(struct mlx5_data_direct_dev *dev)
+{
+	struct mlx5_data_direct_registration *reg;
+
+	mutex_lock(&mlx5_data_direct_mutex);
+	/* Prevent any further affiliations */
+	list_del(&dev->list);
+	list_for_each_entry(reg, &mlx5_data_direct_reg_list, list) {
+		if (strcmp(dev->vuid, reg->vuid) == 0)
+			mlx5_data_direct_do_unbind(reg);
+	}
+	mutex_unlock(&mlx5_data_direct_mutex);
+}
+
+static int mlx5_data_direct_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct mlx5_data_direct_dev *dev;
+	int err;
+
+	dev = kzalloc_obj(*dev);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->device = &pdev->dev;
+	dev->pdev = pdev;
+
+	pci_set_drvdata(dev->pdev, dev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(dev->device, "Cannot enable PCI device, err=%d\n", err);
+		goto err;
+	}
+
+	pci_set_master(pdev);
+	err = mlx5_data_direct_set_dma_caps(pdev);
+	if (err)
+		goto err_disable;
+
+	if (pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP32) &&
+	    pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP64) &&
+	    pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP128))
+		dev_dbg(dev->device, "Enabling pci atomics failed\n");
+
+	err = mlx5_data_direct_vpd_get_vuid(dev);
+	if (err)
+		goto err_disable;
+
+	mlx5_data_direct_dev_reg(dev);
+	return 0;
+
+err_disable:
+	pci_disable_device(pdev);
+err:
+	kfree(dev);
+	return err;
+}
+
+static void mlx5_data_direct_remove(struct pci_dev *pdev)
+{
+	struct mlx5_data_direct_dev *dev = pci_get_drvdata(pdev);
+
+	mlx5_data_direct_dev_unreg(dev);
+	pci_disable_device(pdev);
+	kfree(dev->vuid);
+	kfree(dev);
+}
+
+static struct pci_driver mlx5_data_direct_driver = {
+	.name = "mlx5_dd",
+	.id_table = mlx5_data_direct_pci_table,
+	.probe = mlx5_data_direct_probe,
+	.remove = mlx5_data_direct_remove,
+	.shutdown = mlx5_data_direct_shutdown,
+};
+
+int mlx5_data_direct_driver_register(void)
+{
+	return pci_register_driver(&mlx5_data_direct_driver);
+}
+
+void mlx5_data_direct_driver_unregister(void)
+{
+	pci_unregister_driver(&mlx5_data_direct_driver);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 643b4aac20336..34f0375b68513 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -40,6 +40,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/mlx5/driver.h>
+#include <linux/mlx5/data_direct.h>
 #include <linux/mlx5/cq.h>
 #include <linux/mlx5/qp.h>
 #include <linux/debugfs.h>
@@ -1339,8 +1340,14 @@ static int mlx5_load(struct mlx5_core_dev *dev)
 	if (err)
 		goto err_traps_reg;
 
+	err = mlx5_data_direct_init(dev);
+	if (err)
+		goto err_data_direct;
+
 	return 0;
 
+err_data_direct:
+	mlx5_devlink_traps_unregister(priv_to_devlink(dev));
 err_traps_reg:
 	mlx5_sf_dev_table_destroy(dev);
 	mlx5_sriov_detach(dev);
@@ -1371,6 +1378,7 @@ static int mlx5_load(struct mlx5_core_dev *dev)
 
 static void mlx5_unload(struct mlx5_core_dev *dev)
 {
+	mlx5_data_direct_cleanup(dev);
 	mlx5_devlink_traps_unregister(priv_to_devlink(dev));
 	mlx5_vhca_event_stop(dev);
 	mlx5_sf_dev_table_destroy(dev);
@@ -2360,6 +2368,10 @@ static int __init mlx5_init(void)
 	if (err)
 		goto err_sf;
 
+	err = mlx5_data_direct_driver_register();
+	if (err)
+		goto err_dd;
+
 	err = pci_register_driver(&mlx5_core_driver);
 	if (err)
 		goto err_pci;
@@ -2367,6 +2379,8 @@ static int __init mlx5_init(void)
 	return 0;
 
 err_pci:
+	mlx5_data_direct_driver_unregister();
+err_dd:
 	mlx5_sf_driver_unregister();
 err_sf:
 	mlx5e_cleanup();
@@ -2378,6 +2392,7 @@ static int __init mlx5_init(void)
 static void __exit mlx5_cleanup(void)
 {
 	pci_unregister_driver(&mlx5_core_driver);
+	mlx5_data_direct_driver_unregister();
 	mlx5_sf_driver_unregister();
 	mlx5e_cleanup();
 	mlx5_unregister_debugfs();
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 09e669f83dba7..fd93530a39380 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -530,4 +530,9 @@ static inline bool mlx5_pcie_cong_event_supported(struct mlx5_core_dev *dev)
 
 	return true;
 }
+
+int mlx5_data_direct_init(struct mlx5_core_dev *mdev);
+void mlx5_data_direct_cleanup(struct mlx5_core_dev *mdev);
+int mlx5_data_direct_driver_register(void);
+void mlx5_data_direct_driver_unregister(void);
 #endif /* __MLX5_CORE_H__ */
diff --git a/include/linux/mlx5/data_direct.h b/include/linux/mlx5/data_direct.h
new file mode 100644
index 0000000000000..4cff5ff5489d3
--- /dev/null
+++ b/include/linux/mlx5/data_direct.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
+/*
+ * Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved
+ */
+
+#ifndef _MLX5_DATA_DIRECT_H
+#define _MLX5_DATA_DIRECT_H
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+
+struct device;
+struct mlx5_core_dev;
+struct notifier_block;
+struct pci_dev;
+
+enum mlx5_data_direct_event {
+	MLX5_DATA_DIRECT_UNBIND,
+};
+
+struct mlx5_data_direct_dev {
+	struct device *device;
+	struct pci_dev *pdev;
+	char *vuid;
+	struct list_head list;
+};
+
+struct mlx5_data_direct {
+	struct mlx5_data_direct_dev *dev;
+	u32 pdn;
+	u32 mkey;
+	u32 mkey_ro;
+	u8 mkey_ro_valid :1;
+};
+
+static inline struct mlx5_data_direct_dev *
+mlx5_data_direct_get_dev(struct mlx5_data_direct *dd)
+{
+	return dd ? READ_ONCE(dd->dev) : NULL;
+}
+
+int mlx5_data_direct_register(struct mlx5_core_dev *mdev,
+			      struct notifier_block *nb);
+void mlx5_data_direct_unregister(struct mlx5_core_dev *mdev,
+				 struct notifier_block *nb);
+
+#endif
diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h
index b1871c0821d0b..ed348a82576eb 100644
--- a/include/linux/mlx5/driver.h
+++ b/include/linux/mlx5/driver.h
@@ -707,6 +707,7 @@ struct mlx5_rsvd_gids {
 
 struct mlx5_clock;
 struct mlx5_clock_dev_state;
+struct mlx5_data_direct;
 struct mlx5_dm;
 struct mlx5_fw_tracer;
 struct mlx5_vxlan;
@@ -801,6 +802,7 @@ struct mlx5_core_dev {
 	/* sync write combining state */
 	struct mutex wc_state_lock;
 	struct devlink *shd;
+	struct mlx5_data_direct *data_direct;
 };
 
 struct mlx5_db {
@@ -1395,4 +1397,10 @@ static inline struct net *mlx5_core_net(struct mlx5_core_dev *dev)
 
 #define MLX5_SW_IMAGE_GUID_MAX_BYTES 9
 
+static inline bool mlx5_data_direct_supported(struct mlx5_core_dev *mdev)
+{
+	return MLX5_CAP_GEN(mdev, data_direct) &&
+	       MLX5_CAP_GEN_2(mdev, query_vuid);
+}
+
 #endif /* MLX5_DRIVER_H */

3/2 2026/09/19 07:21 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 19673
							output: 40
							thoughts: 844
						

Thoughts:
**Analyzing the Patch for Fuzzing Potential**

Okay, so I need to decide if this patch is a good candidate for syzkaller fuzzing. Let's dig in. First, I'm looking at what's been modified. The diff touches a bunch of files within the `drivers/infiniband/hw/mlx5/` and `drivers/net/ethernet/mellanox/mlx5/core/` directories, along with some related header files in `include/linux/mlx5/`. The files related to "Data Direct" are being moved from `mlx5_ib` to `mlx5_core`, and there's a reference to "ConnectX-8 Data Direct." This is Mellanox/NVIDIA's mlx5 driver, specifically the Data Direct feature, which looks like it's being reorganized.

Now, the crucial question. We've got a set of negative criteria, and one jumps out: "Structurally unreachable hardware... requiring physical ASIC/PCIe cards not emulated in standard QEMU." This is the key. Are these mlx5 NICs emulated in QEMU? Do we need a physical Mellanox/NVIDIA card to instantiate this driver? The answer, as far as I know, is no. ConnectX-4, ConnectX-5, ConnectX-6, and ConnectX-8 NICs are, from what I know, physical hardware. Syzkaller doesn't have any mlx5 emulation or mock driver, and this falls squarely into the "structurally unreachable hardware" category.

To be absolutely certain, I need to confirm whether mlx5 or mlx5_core or mlx5_ib can be instantiated without physical hardware, or if it requires physical PCI devices. I'll need to check the kernel source or syzkaller documentation to be certain. Given what I already suspect, I'm leaning heavily towards *not* fuzzing this patch, unless I can find evidence to the contrary.



4/2 2026/09/19 07:21 tool grepper
0m Args:
{
  "Expression": "pci_register_driver",
  "PathPrefix": "drivers/net/ethernet/mellanox/mlx5/"
}

Results:
{
  "Output": "drivers/net/ethernet/mellanox/mlx5/core/data_direct.c=394=int mlx5_data_direct_driver_register(void)\ndrivers/net/ethernet/mellanox/mlx5/core/data_direct.c-395-{\ndrivers/net/ethernet/mellanox/mlx5/core/data_direct.c:396:\treturn pci_register_driver(\u0026mlx5_data_direct_driver);\ndrivers/net/ethernet/mellanox/mlx5/core/data_direct.c-397-}\n--\ndrivers/net/ethernet/mellanox/mlx5/core/main.c=2351=static int __init mlx5_init(void)\n--\ndrivers/net/ethernet/mellanox/mlx5/core/main.c-2374-\ndrivers/net/ethernet/mellanox/mlx5/core/main.c:2375:\terr = pci_register_driver(\u0026mlx5_core_driver);\ndrivers/net/ethernet/mellanox/mlx5/core/main.c-2376-\tif (err)\n"
}

5/2 2026/09/19 07:21 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 21276
							output: 43
							thoughts: 155
						

Thoughts:
Okay, here's my take on those thoughts, framed as my own mental processing:

**Analyzing Mellanox PCI Drivers**

Right, so we're dealing with PCI drivers here, specifically `mlx5_core_driver` and `mlx5_data_direct_driver`. And, given my expertise, it's immediately clear that "mlx5" refers to the Mellanox ConnectX series – the 4, 5, 6, 7, and 8 series of network adapters and InfiniBand HCAs. Knowing the hardware is the first step, obviously.

Now, let's get down to the specifics. I need to understand the device identification. Let's look at `mlx5_data_direct_pci_table` first. Aha! It's got the standard PCI device ID structure. Seems straightforward. There's a single entry: `PCI_VDEVICE(MELLANOX, 0x2100)`. Which, from memory, is the ConnectX-8 Data Direct. The `0x2100` device ID confirms this. Now, let's take a look at the other pci table. 



6/2 2026/09/19 07:21 tool grepper
0m Args:
{
  "Expression": "mlx5_core_pci_table",
  "PathPrefix": "drivers/net/ethernet/mellanox/mlx5/"
}

Results:
{
  "Output": "drivers/net/ethernet/mellanox/mlx5/core/main.c=2221=static int mlx5_resume(struct pci_dev *pdev)\n--\ndrivers/net/ethernet/mellanox/mlx5/core/main.c-2227-\ndrivers/net/ethernet/mellanox/mlx5/core/main.c:2228:static const struct pci_device_id mlx5_core_pci_table[] = {\ndrivers/net/ethernet/mellanox/mlx5/core/main.c-2229-\t{ PCI_VDEVICE(MELLANOX, PCI_DEVICE_ID_MELLANOX_CONNECTIB) },\n--\ndrivers/net/ethernet/mellanox/mlx5/core/main.c-2264-\ndrivers/net/ethernet/mellanox/mlx5/core/main.c:2265:MODULE_DEVICE_TABLE(pci, mlx5_core_pci_table);\ndrivers/net/ethernet/mellanox/mlx5/core/main.c-2266-\n--\ndrivers/net/ethernet/mellanox/mlx5/core/main.c=2284=static struct pci_driver mlx5_core_driver = {\ndrivers/net/ethernet/mellanox/mlx5/core/main.c-2285-\t.name           = KBUILD_MODNAME,\ndrivers/net/ethernet/mellanox/mlx5/core/main.c:2286:\t.id_table       = mlx5_core_pci_table,\ndrivers/net/ethernet/mellanox/mlx5/core/main.c-2287-\t.probe          = probe_one,\n"
}

7/2 2026/09/19 07:21 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 22168
							output: 145
							thoughts: 1006
						

Thoughts:
**RDMA Fuzzing Applicability Assessment**

Okay, let's analyze this patch series in the context of RDMA fuzzing within syzkaller. My initial thought is to confirm that the patch focuses on hardware drivers like `mlx5`, rather than the soft-RDMA drivers like `rdma_rxe` or `siw`, which syzkaller leverages for RDMA fuzzing. My initial scan confirms this. The patch modifies files specifically related to Mellanox ConnectX hardware drivers: `mlx5_ib` and `mlx5_core`. These are hardware drivers for Mellanox's ConnectX series.

Now, let's carefully consider Section 2 of the provided instructions, specifically the "Structurally unreachable hardware" category. This section explicitly mentions vendor-specific drivers like `mlxsw`, `pds_core`, `qed`, `ionic`, and `amdgpu` that depend on physical ASICs or PCIe cards not emulated in standard QEMU. Immediately, `mlx5` rings a bell: it's a Mellanox driver, and the ConnectX-8 "Data Direct" feature, which this patch series is refactoring, requires a specific Mellanox PCI device, say 0x2100. Without this hardware, neither `mlx5_core`, `mlx5_ib`, or even the data direct management can initialize.

To be certain, I'll review all the modified files in the patch series. A quick glance shows the changes are confined to `drivers/infiniband/hw/mlx5/`, `drivers/net/ethernet/mellanox/mlx5/`, and `include/linux/mlx5/`. This confirms my suspicion: this patch focuses on the Mellanox `mlx5` driver stack, refactoring the management of the "Data Direct" feature from `mlx5_ib` to `mlx5_core` specifically for the ConnectX-8. Therefore, the modified code is indeed structurally unreachable because it requires a physical Mellanox PCIe device, which isn't emulated in the fuzzing environment.

Following the instructions, since all the modified code strictly falls under "Structurally unreachable hardware", I can confidently determine:

*   `WorthFuzzing: false`
*   `EnableConfigs: []`
*   `FocusSymbols: []`
*   `Reasoning: Concise explanation explaining that the patch refactors the Data Direct feature between mlx5_ib and mlx5_core (Mellanox ConnectX-8 PCI network adapters), which requires physical vendor-specific Mellanox ASIC/PCIe hardware not emulated in standard QEMU/virtualized fuzzing environments, making the modified code structurally unreachable.`

Time to call the `set-results` tool with these parameters.



8/2 2026/09/19 07:21 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch refactors the ConnectX-8 Data Direct feature, moving resource and device management from mlx5_ib to mlx5_core. The modified code resides entirely within the Mellanox mlx5 driver stack (mlx5_core and mlx5_ib) and relies on vendor-specific Mellanox PCIe hardware (e.g., ConnectX-8 PCI ID 0x2100) that is not emulated in standard virtualized fuzzing environments (QEMU/GCE), making the changes structurally unreachable.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch refactors the ConnectX-8 Data Direct feature, moving resource and device management from mlx5_ib to mlx5_core. The modified code resides entirely within the Mellanox mlx5 driver stack (mlx5_core and mlx5_ib) and relies on vendor-specific Mellanox PCIe hardware (e.g., ConnectX-8 PCI ID 0x2100) that is not emulated in standard virtualized fuzzing environments (QEMU/GCE), making the changes structurally unreachable.",
  "WorthFuzzing": false
}

9/1 2026/09/19 07:21 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)