mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Doug Ledford <doug.ledford@hpe.com>
To: Jason Gunthorpe <jgg@ziepe.ca>, Leon Romanovsky <leon@kernel.org>,
	Slingshot Open Source Team <slingshot-os-team@groups.ext.hpe.com>
Cc: <linux-rdma@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	Doug Ledford <doug.ledford@hpe.com>,
	Iraimani P <iraimani.pavadai@hpe.com>
Subject: [PATCH 05/11] RDMA/cxi: add the auxiliary device and driver ops
Date: Fri, 30 Oct 2026 21:35:33 -0700	[thread overview]
Message-ID: <20261030-cxi-for-next-v1-5-bc6e49e07037@hpe.com> (raw)
In-Reply-To: <20261030-cxi-for-next-v1-0-bc6e49e07037@hpe.com>

Bind to the cxi-ss1 auxiliary device and register an ib_device for
it: probe and remove, the NID notifier that updates the device NID and
node GUID when the core driver changes the NIC address, and creation
and the device ops table, including the telemetry counters ops added
later in the series.

If ib_register_device() fails after the NID notifier is registered,
the notifier is unregistered before the device is freed, so the
notifier chain is not left holding a pointer to freed memory.

checkpatch --strict (100 columns) still reports the following in this
patch. They need coordination with the internal repositories this code
is maintained in and will be fixed in V2:
- CHECK: PARENTHESIS_ALIGNMENT (3)

Co-developed-by: Iraimani P <iraimani.pavadai@hpe.com>
Signed-off-by: Iraimani P <iraimani.pavadai@hpe.com>
Signed-off-by: Doug Ledford <doug.ledford@hpe.com>
---
 drivers/infiniband/hw/cxi/cxiverbs_drv.c | 270 +++++++++++++++++++++++++++++++
 1 file changed, 270 insertions(+)

diff --git a/drivers/infiniband/hw/cxi/cxiverbs_drv.c b/drivers/infiniband/hw/cxi/cxiverbs_drv.c
new file mode 100644
index 000000000000..9472ff896c80
--- /dev/null
+++ b/drivers/infiniband/hw/cxi/cxiverbs_drv.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * cxi-ib: InfiniBand RDMA driver for the Cassini CXI NIC.
+ * Copyright 2022-2025 Hewlett Packard Enterprise Development LP
+ *
+ * Registers as an auxiliary driver that consumes the "cxi_ss1.rdma"
+ * auxiliary device published by the cxi-driver.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include "cxiverbs.h"
+
+MODULE_AUTHOR("Hewlett Packard Enterprise Development LP");
+MODULE_DESCRIPTION("Cassini CXI RDMA verbs driver");
+MODULE_LICENSE("GPL");
+
+/* -----------------------------------------------------------------------
+ * Device operations table
+ * -----------------------------------------------------------------------
+ */
+static const struct ib_device_ops cxiverbs_dev_ops = {
+	.owner           = THIS_MODULE,
+	.driver_id       = RDMA_DRIVER_CXI,
+	.uverbs_abi_ver  = CXI_IB_UVERBS_ABI_VERSION,
+
+	/* Phase 0 – device and port query */
+	.query_device        = cxiverbs_query_device,
+	.query_port          = cxiverbs_query_port,
+	.get_port_immutable  = cxiverbs_get_port_immutable,
+	.get_netdev           = cxiverbs_get_netdev,
+	.query_pkey          = cxiverbs_query_pkey,
+	.query_gid           = cxiverbs_query_gid,
+
+	/* Phase 1 – user context and protection domain */
+	.alloc_ucontext   = cxiverbs_alloc_ucontext,
+	.dealloc_ucontext = cxiverbs_dealloc_ucontext,
+	.alloc_pd         = cxiverbs_alloc_pd,
+	.dealloc_pd       = cxiverbs_dealloc_pd,
+	.alloc_job        = cxiverbs_alloc_job,
+	.dealloc_job      = cxiverbs_dealloc_job,
+	.query_job        = cxiverbs_query_job,
+	.job_addr_insert  = cxiverbs_job_addr_insert,
+	.job_addr_remove  = cxiverbs_job_addr_remove,
+	.job_addr_query   = cxiverbs_job_addr_query,
+	.query_qp_semantics = cxiverbs_query_qp_semantics,
+	.create_jkey      = cxiverbs_create_jkey,
+	.destroy_jkey     = cxiverbs_destroy_jkey,
+
+	/* Telemetry counters */
+	.create_counters   = cxiverbs_create_counters,
+	.destroy_counters  = cxiverbs_destroy_counters,
+	.read_counters_ex  = cxiverbs_read_counters_ex,
+
+	/* Phase 2 – memory registration */
+	.reg_user_mr = cxiverbs_reg_user_mr,
+	.dereg_mr    = cxiverbs_dereg_mr,
+
+	/* Phase 3 – completion queues and mmap */
+	.create_cq      = cxiverbs_create_cq,
+	.destroy_cq     = cxiverbs_destroy_cq,
+	.poll_cq        = cxiverbs_poll_cq,
+	.req_notify_cq  = cxiverbs_req_notify_cq,
+	.mmap           = cxiverbs_mmap,
+	.mmap_free      = cxiverbs_mmap_free,
+
+	/* Phase 4 – queue pairs */
+	.create_qp  = cxiverbs_create_qp,
+	.modify_qp  = cxiverbs_modify_qp,
+	.query_qp   = cxiverbs_query_qp,
+	.destroy_qp = cxiverbs_destroy_qp,
+	.post_send  = cxiverbs_post_send,
+	.post_recv  = cxiverbs_post_recv,
+
+	/* Phase 5 – address handles and GID management */
+	.create_ah  = cxiverbs_create_ah,
+	.create_user_ah = cxiverbs_create_ah,
+	.destroy_ah = cxiverbs_destroy_ah,
+	.add_gid    = cxiverbs_add_gid,
+	.del_gid    = cxiverbs_del_gid,
+
+	/* Pre-allocated slab sizes for RDMA core object allocator */
+	INIT_RDMA_OBJ_SIZE(ib_ah,        cxiverbs_ah,        ibah),
+	INIT_RDMA_OBJ_SIZE(ib_counters,  cxiverbs_counters,  ibcounters),
+	INIT_RDMA_OBJ_SIZE(ib_cq,        cxiverbs_cq,        ibcq),
+	INIT_RDMA_OBJ_SIZE(ib_pd,        cxiverbs_pd,        ibpd),
+	INIT_RDMA_OBJ_SIZE(ib_job,       cxiverbs_job_entry, ibjob),
+	INIT_RDMA_OBJ_SIZE(ib_jkey,      cxiverbs_jkey,      ibjkey),
+	INIT_RDMA_OBJ_SIZE(ib_qp,        cxiverbs_qp,        ibqp),
+	INIT_RDMA_OBJ_SIZE(ib_ucontext,  cxiverbs_ucontext,  ibucontext),
+};
+
+static void cxiverbs_tc_entries_destroy(struct cxiverbs_dev *dev)
+{
+	struct cxiverbs_job_tc_binding *binding, *tmp;
+	struct cxiverbs_tc_entry *tc_entry;
+	unsigned long index;
+
+	mutex_lock(&dev->jobs_lock);
+	xa_for_each(&dev->tcs, index, tc_entry) {
+		list_for_each_entry_safe(binding, tmp, &tc_entry->job_list, entry) {
+			list_del(&binding->entry);
+			kfree(binding);
+		}
+		kfree(tc_entry);
+	}
+	xa_destroy(&dev->tcs);
+	mutex_unlock(&dev->jobs_lock);
+}
+
+static void cxiverbs_gid_change_event(struct cxiverbs_dev *dev)
+{
+	struct ib_event event = {
+		.device = &dev->ib_dev,
+		.element.port_num = 1,
+		.event = IB_EVENT_GID_CHANGE,
+	};
+
+	ib_dispatch_event(&event);
+}
+
+static __be64 cxiverbs_nid_to_node_guid(u32 nid)
+{
+	if (nid == CXI_INVALID_NID)
+		return cpu_to_be64(U64_MAX);
+
+	return cpu_to_be64(nid);
+}
+
+static int cxiverbs_nid_event(struct notifier_block *nb, unsigned long nid,
+			      void *data)
+{
+	struct cxiverbs_dev *dev = container_of(nb, struct cxiverbs_dev,
+					      nid_notifier);
+
+	WRITE_ONCE(dev->nid, nid);
+	WRITE_ONCE(dev->devinfo.nid, nid);
+	WRITE_ONCE(dev->ib_dev.node_guid, cxiverbs_nid_to_node_guid(nid));
+
+	/*
+	 * The NID is only known once the link trains, which is usually after
+	 * probe, so the cached GID still holds the placeholder read at
+	 * registration. Make the core re-read it via query_gid.
+	 */
+	if (READ_ONCE(dev->ib_registered))
+		cxiverbs_gid_change_event(dev);
+
+	return NOTIFY_OK;
+}
+
+/* -----------------------------------------------------------------------
+ * Auxiliary driver probe / remove
+ * -----------------------------------------------------------------------
+ */
+static int cxiverbs_probe(struct auxiliary_device *adev,
+			const struct auxiliary_device_id *id)
+{
+	struct cxi_adev *cxiadev = container_of(adev, struct cxi_adev, adev);
+	struct cxi_dev_info_use info = {};
+	struct cxiverbs_dev *dev;
+	int ret;
+
+	dev = ib_alloc_device(cxiverbs_dev, ib_dev);
+	if (!dev)
+		return -ENOMEM;
+
+	/* Link to the CXI public API and the PCI device.
+	 * cxi_adev->cxi_dev is set by the cxi-driver before publishing
+	 * the auxiliary device.
+	 */
+	dev->cadev = cxiadev;
+	dev->cdev    = (struct cxi_dev *)cxiadev->cxi_dev;
+	if (!dev->cdev) {
+		dev_err(&adev->dev, "cxiverbs: no cxi_dev in cxi_adev\n");
+		ret = -ENODEV;
+		goto err_dealloc;
+	}
+
+	/* Cache device geometry so individual verbs ops can read it
+	 * without calling cxi_dev_info_get() on every request.
+	 */
+	ret = cxiadev->dev_info_get(dev->cdev, &info);
+	if (ret) {
+		dev_err(&adev->dev, "cxiverbs: cxi_dev_info_get failed: %d\n", ret);
+		goto err_dealloc;
+	}
+	dev->nid         = info.nid;
+	dev->pid_bits    = info.pid_bits;
+	dev->pid_count   = info.pid_count;
+	dev->pid_granule = info.pid_granule;
+	dev->devinfo     = info;
+	xa_init(&dev->jobs);
+	xa_init(&dev->tcs);
+	mutex_init(&dev->jobs_lock);
+	dev->nid_notifier.notifier_call = cxiverbs_nid_event;
+	ret = blocking_notifier_chain_register(&cxiadev->nid_notifier,
+					      &dev->nid_notifier);
+	if (ret)
+		goto err_destroy_jobs_lock;
+
+	ib_set_device_ops(&dev->ib_dev, &cxiverbs_dev_ops);
+
+	dev->ib_dev.node_type       = RDMA_NODE_SLINGSHOT;
+	dev->ib_dev.phys_port_cnt   = 1;
+	dev->ib_dev.num_comp_vectors = 1;
+	dev->ib_dev.local_dma_lkey  = 0;
+	dev->ib_dev.dev.parent      = &cxiadev->pdev->dev;
+
+	dev->ib_dev.node_guid = cxiverbs_nid_to_node_guid(dev->nid);
+
+	/* Expose custom uverbs objects (Counting Triggers, Phase 6). */
+	dev->ib_dev.driver_def = cxiverbs_defs;
+
+	ret = ib_register_device(&dev->ib_dev, "cxi%d", cxiadev->dev);
+	if (ret) {
+		dev_err(&adev->dev, "cxiverbs: ib_register_device failed: %d\n", ret);
+		blocking_notifier_chain_unregister(&cxiadev->nid_notifier,
+						   &dev->nid_notifier);
+		goto err_destroy_jobs_lock;
+	}
+
+	dev_set_drvdata(&adev->dev, dev);
+	WRITE_ONCE(dev->ib_registered, true);
+	cxiverbs_gid_change_event(dev);
+	dev_info(&adev->dev, "CXI RDMA device registered as %s\n",
+		 dev_name(&dev->ib_dev.dev));
+	return 0;
+
+err_dealloc:
+	ib_dealloc_device(&dev->ib_dev);
+	return ret;
+
+err_destroy_jobs_lock:
+	cxiverbs_tc_entries_destroy(dev);
+	xa_destroy(&dev->jobs);
+	mutex_destroy(&dev->jobs_lock);
+	goto err_dealloc;
+}
+
+static void cxiverbs_remove(struct auxiliary_device *adev)
+{
+	struct cxiverbs_dev *dev = dev_get_drvdata(&adev->dev);
+
+	blocking_notifier_chain_unregister(&dev->cadev->nid_notifier,
+					  &dev->nid_notifier);
+	ib_unregister_device(&dev->ib_dev);
+	cxiverbs_tc_entries_destroy(dev);
+	xa_destroy(&dev->jobs);
+	mutex_destroy(&dev->jobs_lock);
+	ib_dealloc_device(&dev->ib_dev);
+}
+
+/* -----------------------------------------------------------------------
+ * Auxiliary device ID table and driver registration
+ * -----------------------------------------------------------------------
+ */
+static const struct auxiliary_device_id cxiverbs_auxiliary_ids[] = {
+	{ .name = "cxi_ss1.rdma", },
+	{},
+};
+MODULE_DEVICE_TABLE(auxiliary, cxiverbs_auxiliary_ids);
+
+static struct auxiliary_driver cxiverbs_driver = {
+	.probe    = cxiverbs_probe,
+	.remove   = cxiverbs_remove,
+	.id_table = cxiverbs_auxiliary_ids,
+};
+module_auxiliary_driver(cxiverbs_driver);

-- 
2.56.0


  parent reply	other threads:[~2026-10-31  4:36 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-31  4:35 [PATCH 00/11] Subject: [PATCH for-next 00/11] RDMA/cxi: add the HPE Cassini verbs driver Doug Ledford
2026-10-31  4:35 ` [PATCH 01/11] RDMA/core: read selected counters with timestamps Doug Ledford
2026-10-31  4:35 ` [PATCH 02/11] RDMA/core: allow jobs without an address table Doug Ledford
2026-10-31  4:35 ` [PATCH 03/11] RDMA/core: add Slingshot identifiers and driver-owned GIDs Doug Ledford
2026-10-31  4:35 ` [PATCH 04/11] RDMA/cxi: add the native ABI and resource definitions Doug Ledford
2026-10-31  4:35 ` Doug Ledford [this message]
2026-10-31  4:35 ` [PATCH 06/11] RDMA/cxi: add explicit context LNI and PID lifetimes Doug Ledford
2026-10-31  4:35 ` [PATCH 07/11] RDMA/cxi: add VNI-isolated queue pairs Doug Ledford
2026-10-31  4:35 ` [PATCH 08/11] RDMA/cxi: add native memory registration Doug Ledford
2026-10-31  4:35 ` [PATCH 09/11] RDMA/cxi: add services jobs profiles queues and counting triggers Doug Ledford
2026-10-31  4:35 ` [PATCH 10/11] RDMA/cxi: read the NIC telemetry through counters Doug Ledford
2026-10-31  4:35 ` [PATCH 11/11] RDMA/cxi: wire the driver into the build Doug Ledford
2026-11-03 14:28 ` [PATCH 00/11] Subject: [PATCH for-next 00/11] RDMA/cxi: add the HPE Cassini verbs driver Leon Romanovsky
2026-11-03 14:30   ` Jason Gunthorpe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261030-cxi-for-next-v1-5-bc6e49e07037@hpe.com \
    --to=doug.ledford@hpe.com \
    --cc=iraimani.pavadai@hpe.com \
    --cc=jgg@ziepe.ca \
    --cc=leon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=slingshot-os-team@groups.ext.hpe.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®