Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next 0/4] RDMA/net/ionic: Misc updates
@ 2026-05-06  4:19 Eric Joyner
  2026-05-06  4:19 ` [PATCH net-next 1/4] RDMA/ionic: Update copyright year to 2026 Eric Joyner
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Eric Joyner @ 2026-05-06  4:19 UTC (permalink / raw)
  To: netdev, linux-rdma
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Abhijit Gangurde, Allen Hubbe,
	Jason Gunthorpe, Leon Romanovsky, Eric Joyner

The big addition in this set is a dedicated debugfs directory under the
main ionic driver's debugfs tree for RDMA-related entries and querying
queue information; a separate patch on top of that adds the ability to
configure DCQCN parameters using debugfs when the firmware is in a mode
that allows it.

Other smaller additions add a devlink parameter to the ionic ethernet
driver for enabling and disabling RDMA, as well as updating the
copyright years for the ionic RDMA driver all in one go.

Abhijit Gangurde (1):
  net/ionic: Add devlink parameter for RDMA

Allen Hubbe (2):
  RDMA/ionic: Add debugfs support
  RDMA/ionic: Add DCQCN parameter configuration via debugfs

Eric Joyner (1):
  RDMA/ionic: Update copyright year to 2026

 drivers/infiniband/hw/ionic/Kconfig           |   2 +-
 drivers/infiniband/hw/ionic/Makefile          |   3 +-
 drivers/infiniband/hw/ionic/ionic_admin.c     |   6 +-
 .../infiniband/hw/ionic/ionic_controlpath.c   |  21 +-
 drivers/infiniband/hw/ionic/ionic_datapath.c  |   2 +-
 drivers/infiniband/hw/ionic/ionic_dcqcn.c     | 629 +++++++++++++++
 drivers/infiniband/hw/ionic/ionic_debugfs.c   | 750 ++++++++++++++++++
 drivers/infiniband/hw/ionic/ionic_fw.h        |  33 +-
 drivers/infiniband/hw/ionic/ionic_hw_stats.c  |   2 +-
 drivers/infiniband/hw/ionic/ionic_ibdev.c     |   9 +-
 drivers/infiniband/hw/ionic/ionic_ibdev.h     |  43 +-
 drivers/infiniband/hw/ionic/ionic_lif_cfg.c   |   6 +-
 drivers/infiniband/hw/ionic/ionic_lif_cfg.h   |   6 +-
 drivers/infiniband/hw/ionic/ionic_pgtbl.c     |   2 +-
 drivers/infiniband/hw/ionic/ionic_profiles.h  |  86 ++
 drivers/infiniband/hw/ionic/ionic_queue.c     |   2 +-
 drivers/infiniband/hw/ionic/ionic_queue.h     |   2 +-
 drivers/infiniband/hw/ionic/ionic_res.h       |   2 +-
 .../net/ethernet/pensando/ionic/ionic_aux.c   |   3 +-
 .../ethernet/pensando/ionic/ionic_devlink.c   |  75 ++
 20 files changed, 1668 insertions(+), 16 deletions(-)
 create mode 100644 drivers/infiniband/hw/ionic/ionic_dcqcn.c
 create mode 100644 drivers/infiniband/hw/ionic/ionic_debugfs.c
 create mode 100644 drivers/infiniband/hw/ionic/ionic_profiles.h


base-commit: 8c699be3dad7bba87cdda485dc099226cfc2f706
-- 
2.17.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net-next 1/4] RDMA/ionic: Update copyright year to 2026
  2026-05-06  4:19 [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Eric Joyner
@ 2026-05-06  4:19 ` Eric Joyner
  2026-05-06  4:19 ` [PATCH net-next 2/4] net/ionic: Add devlink parameter for RDMA Eric Joyner
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-05-06  4:19 UTC (permalink / raw)
  To: netdev, linux-rdma
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Abhijit Gangurde, Allen Hubbe,
	Jason Gunthorpe, Leon Romanovsky, Eric Joyner

Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 drivers/infiniband/hw/ionic/Kconfig             | 2 +-
 drivers/infiniband/hw/ionic/ionic_admin.c       | 2 +-
 drivers/infiniband/hw/ionic/ionic_controlpath.c | 2 +-
 drivers/infiniband/hw/ionic/ionic_datapath.c    | 2 +-
 drivers/infiniband/hw/ionic/ionic_fw.h          | 2 +-
 drivers/infiniband/hw/ionic/ionic_hw_stats.c    | 2 +-
 drivers/infiniband/hw/ionic/ionic_ibdev.c       | 2 +-
 drivers/infiniband/hw/ionic/ionic_ibdev.h       | 2 +-
 drivers/infiniband/hw/ionic/ionic_lif_cfg.c     | 2 +-
 drivers/infiniband/hw/ionic/ionic_lif_cfg.h     | 2 +-
 drivers/infiniband/hw/ionic/ionic_pgtbl.c       | 2 +-
 drivers/infiniband/hw/ionic/ionic_queue.c       | 2 +-
 drivers/infiniband/hw/ionic/ionic_queue.h       | 2 +-
 drivers/infiniband/hw/ionic/ionic_res.h         | 2 +-
 14 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/infiniband/hw/ionic/Kconfig b/drivers/infiniband/hw/ionic/Kconfig
index de6f10e9b6e9..3fda9c46ee73 100644
--- a/drivers/infiniband/hw/ionic/Kconfig
+++ b/drivers/infiniband/hw/ionic/Kconfig
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-# Copyright (C) 2018-2025, Advanced Micro Devices, Inc.
+# Copyright (C) 2018-2026, Advanced Micro Devices, Inc.
 
 config INFINIBAND_IONIC
 	tristate "AMD Pensando DSC RDMA/RoCE Support"
diff --git a/drivers/infiniband/hw/ionic/ionic_admin.c b/drivers/infiniband/hw/ionic/ionic_admin.c
index 37e24450d129..6e3cf87025b6 100644
--- a/drivers/infiniband/hw/ionic/ionic_admin.c
+++ b/drivers/infiniband/hw/ionic/ionic_admin.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #include <linux/interrupt.h>
 #include <linux/module.h>
diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c
index 7051a81cca94..850435ec0072 100644
--- a/drivers/infiniband/hw/ionic/ionic_controlpath.c
+++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #include <linux/module.h>
 #include <linux/printk.h>
diff --git a/drivers/infiniband/hw/ionic/ionic_datapath.c b/drivers/infiniband/hw/ionic/ionic_datapath.c
index aa2944887f23..4ca4ec2eebd4 100644
--- a/drivers/infiniband/hw/ionic/ionic_datapath.c
+++ b/drivers/infiniband/hw/ionic/ionic_datapath.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #include <linux/module.h>
 #include <linux/printk.h>
diff --git a/drivers/infiniband/hw/ionic/ionic_fw.h b/drivers/infiniband/hw/ionic/ionic_fw.h
index adfbb89d856c..0806c148faf2 100644
--- a/drivers/infiniband/hw/ionic/ionic_fw.h
+++ b/drivers/infiniband/hw/ionic/ionic_fw.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #ifndef _IONIC_FW_H_
 #define _IONIC_FW_H_
diff --git a/drivers/infiniband/hw/ionic/ionic_hw_stats.c b/drivers/infiniband/hw/ionic/ionic_hw_stats.c
index f72c9837e135..3c845d8b1be1 100644
--- a/drivers/infiniband/hw/ionic/ionic_hw_stats.c
+++ b/drivers/infiniband/hw/ionic/ionic_hw_stats.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #include <linux/dma-mapping.h>
 
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.c b/drivers/infiniband/hw/ionic/ionic_ibdev.c
index 0382a64839d2..356ad9fe150f 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.c
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #include <linux/module.h>
 #include <linux/printk.h>
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.h b/drivers/infiniband/hw/ionic/ionic_ibdev.h
index 63828240d659..7a8e4b59da1c 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.h
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #ifndef _IONIC_IBDEV_H_
 #define _IONIC_IBDEV_H_
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
index f3cd281c3a2f..800555eb47ac 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #include <linux/kernel.h>
 
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
index 20853429f623..18e7c7f13579 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #ifndef _IONIC_LIF_CFG_H_
 
diff --git a/drivers/infiniband/hw/ionic/ionic_pgtbl.c b/drivers/infiniband/hw/ionic/ionic_pgtbl.c
index e74db73c9246..40ac3b703862 100644
--- a/drivers/infiniband/hw/ionic/ionic_pgtbl.c
+++ b/drivers/infiniband/hw/ionic/ionic_pgtbl.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #include <linux/mman.h>
 #include <linux/dma-mapping.h>
diff --git a/drivers/infiniband/hw/ionic/ionic_queue.c b/drivers/infiniband/hw/ionic/ionic_queue.c
index aa897ed2a412..c8fea41c0363 100644
--- a/drivers/infiniband/hw/ionic/ionic_queue.c
+++ b/drivers/infiniband/hw/ionic/ionic_queue.c
@@ -1,5 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #include <linux/dma-mapping.h>
 
diff --git a/drivers/infiniband/hw/ionic/ionic_queue.h b/drivers/infiniband/hw/ionic/ionic_queue.h
index d18020d4cad5..3db1fc664184 100644
--- a/drivers/infiniband/hw/ionic/ionic_queue.h
+++ b/drivers/infiniband/hw/ionic/ionic_queue.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #ifndef _IONIC_QUEUE_H_
 #define _IONIC_QUEUE_H_
diff --git a/drivers/infiniband/hw/ionic/ionic_res.h b/drivers/infiniband/hw/ionic/ionic_res.h
index 46c8c584bd9a..bfb9dcf5851b 100644
--- a/drivers/infiniband/hw/ionic/ionic_res.h
+++ b/drivers/infiniband/hw/ionic/ionic_res.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* Copyright (C) 2018-2025, Advanced Micro Devices, Inc. */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
 
 #ifndef _IONIC_RES_H_
 #define _IONIC_RES_H_
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net-next 2/4] net/ionic: Add devlink parameter for RDMA
  2026-05-06  4:19 [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Eric Joyner
  2026-05-06  4:19 ` [PATCH net-next 1/4] RDMA/ionic: Update copyright year to 2026 Eric Joyner
@ 2026-05-06  4:19 ` Eric Joyner
  2026-05-06  4:19 ` [PATCH net-next 3/4] RDMA/ionic: Add debugfs support Eric Joyner
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-05-06  4:19 UTC (permalink / raw)
  To: netdev, linux-rdma
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Abhijit Gangurde, Allen Hubbe,
	Jason Gunthorpe, Leon Romanovsky, Eric Joyner

From: Abhijit Gangurde <abhijit.gangurde@amd.com>

Provides a devlink parameter to the ionic Ethernet driver to
enable/disable the RDMA feature.

Signed-off-by: Abhijit Gangurde <abhijit.gangurde@amd.com>
Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 .../net/ethernet/pensando/ionic/ionic_aux.c   |  3 +-
 .../ethernet/pensando/ionic/ionic_devlink.c   | 75 +++++++++++++++++++
 2 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/pensando/ionic/ionic_aux.c b/drivers/net/ethernet/pensando/ionic/ionic_aux.c
index 4f193d0ee87a..689624f19f45 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_aux.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_aux.c
@@ -23,7 +23,8 @@ int ionic_auxbus_register(struct ionic_lif *lif)
 	struct auxiliary_device *aux_dev;
 	int err, id;
 
-	if (!(le64_to_cpu(lif->ionic->ident.lif.capabilities) & IONIC_LIF_CAP_RDMA))
+	if (!IS_ENABLED(CONFIG_INFINIBAND_IONIC) ||
+	    !(le64_to_cpu(lif->ionic->ident.lif.capabilities) & IONIC_LIF_CAP_RDMA))
 		return 0;
 
 	ionic_adev = kzalloc_obj(*ionic_adev);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c
index 4ec66a6be073..ab4f6a37c7f8 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_devlink.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_devlink.c
@@ -8,6 +8,7 @@
 #include "ionic_bus.h"
 #include "ionic_lif.h"
 #include "ionic_devlink.h"
+#include "ionic_aux.h"
 
 static int ionic_dl_flash_update(struct devlink *dl,
 				 struct devlink_flash_update_params *params,
@@ -56,6 +57,72 @@ static const struct devlink_ops ionic_dl_ops = {
 	.flash_update	= ionic_dl_flash_update,
 };
 
+static bool is_aux_enabled(struct ionic *ionic)
+{
+	return !!ionic->lif->ionic_adev;
+}
+
+static int ionic_devlink_enable_rdma_get(struct devlink *dl, u32 id,
+					 struct devlink_param_gset_ctx *ctx,
+					 struct netlink_ext_ack *extack)
+{
+	ctx->val.vbool = is_aux_enabled(devlink_priv(dl));
+	return 0;
+}
+
+static int ionic_devlink_enable_rdma_set(struct devlink *dl, u32 id,
+					 struct devlink_param_gset_ctx *ctx,
+					 struct netlink_ext_ack *extack)
+{
+	struct ionic *ionic = devlink_priv(dl);
+	int err = 0;
+
+	if (ctx->val.vbool == is_aux_enabled(ionic))
+		return err;
+
+	if (ctx->val.vbool)
+		err = ionic_auxbus_register(ionic->lif);
+	else
+		ionic_auxbus_unregister(ionic->lif);
+
+	return err;
+}
+
+static int ionic_devlink_enable_rdma_validate(struct devlink *dl, u32 id,
+					      union devlink_param_value val,
+					      struct netlink_ext_ack *extack)
+{
+	struct ionic *ionic = devlink_priv(dl);
+	bool new_state = val.vbool;
+
+	if (new_state &&
+	    !(le64_to_cpu(ionic->ident.lif.capabilities) & IONIC_LIF_CAP_RDMA))
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static const struct devlink_param ionic_dl_rdma_params[] = {
+	DEVLINK_PARAM_GENERIC(ENABLE_RDMA, BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+			      ionic_devlink_enable_rdma_get, ionic_devlink_enable_rdma_set,
+			      ionic_devlink_enable_rdma_validate),
+};
+
+static int ionic_dl_rdma_params_register(struct devlink *dl)
+{
+	if (!IS_ENABLED(CONFIG_INFINIBAND_IONIC))
+		return 0;
+
+	return devlink_params_register(dl, ionic_dl_rdma_params,
+				       ARRAY_SIZE(ionic_dl_rdma_params));
+}
+
+static void ionic_devlink_rdma_params_unregister(struct devlink *dl)
+{
+	devlink_params_unregister(dl, ionic_dl_rdma_params,
+				  ARRAY_SIZE(ionic_dl_rdma_params));
+}
+
 struct ionic *ionic_devlink_alloc(struct device *dev)
 {
 	struct devlink *dl;
@@ -82,9 +149,17 @@ int ionic_devlink_register(struct ionic *ionic)
 
 	attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL;
 	devlink_port_attrs_set(&ionic->dl_port, &attrs);
+
+	err = ionic_dl_rdma_params_register(dl);
+	if (err) {
+		dev_err(ionic->dev, "ionic_dl_rdma_params_register failed: %d\n", err);
+		return err;
+	}
+
 	err = devlink_port_register(dl, &ionic->dl_port, 0);
 	if (err) {
 		dev_err(ionic->dev, "devlink_port_register failed: %d\n", err);
+		ionic_devlink_rdma_params_unregister(dl);
 		return err;
 	}
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net-next 3/4] RDMA/ionic: Add debugfs support
  2026-05-06  4:19 [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Eric Joyner
  2026-05-06  4:19 ` [PATCH net-next 1/4] RDMA/ionic: Update copyright year to 2026 Eric Joyner
  2026-05-06  4:19 ` [PATCH net-next 2/4] net/ionic: Add devlink parameter for RDMA Eric Joyner
@ 2026-05-06  4:19 ` Eric Joyner
  2026-05-06  4:19 ` [PATCH net-next 4/4] RDMA/ionic: Add DCQCN parameter configuration via debugfs Eric Joyner
  2026-05-06 22:59 ` [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Jakub Kicinski
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-05-06  4:19 UTC (permalink / raw)
  To: netdev, linux-rdma
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Abhijit Gangurde, Allen Hubbe,
	Jason Gunthorpe, Leon Romanovsky, Eric Joyner

From: Allen Hubbe <allen.hubbe@amd.com>

Adds a per-RDMA device debugfs folder under the parent ionic ethernet
device's folder for the LIF. Exports RDMA-specific debug information and
various queue information.

Signed-off-by: Allen Hubbe <allen.hubbe@amd.com>
Co-developed-by: Eric Joyner <eric.joyner@amd.com>
Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 drivers/infiniband/hw/ionic/Makefile          |   2 +-
 drivers/infiniband/hw/ionic/ionic_admin.c     |   4 +
 .../infiniband/hw/ionic/ionic_controlpath.c   |  14 +
 drivers/infiniband/hw/ionic/ionic_debugfs.c   | 750 ++++++++++++++++++
 drivers/infiniband/hw/ionic/ionic_ibdev.c     |   3 +
 drivers/infiniband/hw/ionic/ionic_ibdev.h     |  29 +
 drivers/infiniband/hw/ionic/ionic_lif_cfg.c   |   3 +
 drivers/infiniband/hw/ionic/ionic_lif_cfg.h   |   2 +
 8 files changed, 806 insertions(+), 1 deletion(-)
 create mode 100644 drivers/infiniband/hw/ionic/ionic_debugfs.c

diff --git a/drivers/infiniband/hw/ionic/Makefile b/drivers/infiniband/hw/ionic/Makefile
index 957973742820..65bb4eaf0c13 100644
--- a/drivers/infiniband/hw/ionic/Makefile
+++ b/drivers/infiniband/hw/ionic/Makefile
@@ -6,4 +6,4 @@ obj-$(CONFIG_INFINIBAND_IONIC)	+= ionic_rdma.o
 
 ionic_rdma-y :=	\
 	ionic_ibdev.o ionic_lif_cfg.o ionic_queue.o ionic_pgtbl.o ionic_admin.o \
-	ionic_controlpath.o ionic_datapath.o ionic_hw_stats.o
+	ionic_controlpath.o ionic_datapath.o ionic_hw_stats.o ionic_debugfs.o
diff --git a/drivers/infiniband/hw/ionic/ionic_admin.c b/drivers/infiniband/hw/ionic/ionic_admin.c
index 6e3cf87025b6..3ef8bcdf8095 100644
--- a/drivers/infiniband/hw/ionic/ionic_admin.c
+++ b/drivers/infiniband/hw/ionic/ionic_admin.c
@@ -586,6 +586,7 @@ static struct ionic_aq *__ionic_create_rdma_adminq(struct ionic_ibdev *dev,
 
 	INIT_WORK(&aq->work, ionic_admin_work);
 	aq->armed = false;
+	ionic_dbg_add_aq(dev, aq);
 
 	return aq;
 
@@ -600,6 +601,7 @@ static struct ionic_aq *__ionic_create_rdma_adminq(struct ionic_ibdev *dev,
 static void __ionic_destroy_rdma_adminq(struct ionic_ibdev *dev,
 					struct ionic_aq *aq)
 {
+	ionic_dbg_rm_aq(aq);
 	kfree(aq->q_wr);
 	ionic_queue_destroy(&aq->q, dev->lif_cfg.hwdev);
 	kfree(aq);
@@ -1032,6 +1034,7 @@ static struct ionic_eq *ionic_create_eq(struct ionic_ibdev *dev, int eqid)
 		goto err_cmd;
 
 	ionic_intr_mask(dev->lif_cfg.intr_ctrl, eq->intr, IONIC_INTR_MASK_CLEAR);
+	ionic_dbg_add_eq(dev, eq);
 
 	return eq;
 
@@ -1053,6 +1056,7 @@ static void ionic_destroy_eq(struct ionic_eq *eq)
 {
 	struct ionic_ibdev *dev = eq->dev;
 
+	ionic_dbg_rm_eq(eq);
 	eq->enable = false;
 	free_irq(eq->irq, eq);
 	flush_work(&eq->work);
diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c
index 850435ec0072..0ea053369cba 100644
--- a/drivers/infiniband/hw/ionic/ionic_controlpath.c
+++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c
@@ -153,6 +153,8 @@ int ionic_create_cq_common(struct ionic_vcq *vcq,
 		goto err_xa;
 	}
 
+	ionic_dbg_add_cq(dev, cq);
+
 	return 0;
 
 err_xa:
@@ -176,6 +178,7 @@ void ionic_destroy_cq_common(struct ionic_ibdev *dev, struct ionic_cq *cq)
 	if (!cq->vcq)
 		return;
 
+	ionic_dbg_rm_cq(cq);
 	xa_erase_irq(&dev->cq_tbl, cq->cqid);
 
 	kref_put(&cq->cq_kref, ionic_cq_complete);
@@ -918,6 +921,7 @@ struct ib_mr *ionic_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 length,
 		goto err_cmd;
 
 	ionic_pgtbl_unbuf(dev, &mr->buf);
+	ionic_dbg_add_mr(dev, mr);
 
 	return &mr->ibmr;
 
@@ -988,6 +992,7 @@ struct ib_mr *ionic_reg_user_mr_dmabuf(struct ib_pd *ibpd, u64 offset,
 		goto err_cmd;
 
 	ionic_pgtbl_unbuf(dev, &mr->buf);
+	ionic_dbg_add_mr(dev, mr);
 
 	return &mr->ibmr;
 
@@ -1017,6 +1022,7 @@ int ionic_dereg_mr(struct ib_mr *ibmr, struct ib_udata *udata)
 			return rc;
 	}
 
+	ionic_dbg_rm_mr(mr);
 	ionic_pgtbl_unbuf(dev, &mr->buf);
 
 	if (mr->umem)
@@ -1064,6 +1070,8 @@ struct ib_mr *ionic_alloc_mr(struct ib_pd *ibpd, enum ib_mr_type type,
 	if (rc)
 		goto err_cmd;
 
+	ionic_dbg_add_mr(dev, mr);
+
 	return &mr->ibmr;
 
 err_cmd:
@@ -1135,6 +1143,8 @@ int ionic_alloc_mw(struct ib_mw *ibmw, struct ib_udata *udata)
 	if (rc)
 		goto err_cmd;
 
+	ionic_dbg_add_mr(dev, mr);
+
 	return 0;
 
 err_cmd:
@@ -1152,6 +1162,7 @@ int ionic_dealloc_mw(struct ib_mw *ibmw)
 	if (rc)
 		return rc;
 
+	ionic_dbg_rm_mr(mr);
 	ionic_put_mrid(dev, mr->mrid);
 
 	return 0;
@@ -2364,6 +2375,8 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
 		qp->rq_cqid = cq->cqid;
 	}
 
+	ionic_dbg_add_qp(dev, qp);
+
 	return 0;
 
 err_resp:
@@ -2643,6 +2656,7 @@ int ionic_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
 	if (rc)
 		return rc;
 
+	ionic_dbg_rm_qp(qp);
 	xa_erase_irq(&dev->qp_tbl, qp->qpid);
 
 	kref_put(&qp->qp_kref, ionic_qp_complete);
diff --git a/drivers/infiniband/hw/ionic/ionic_debugfs.c b/drivers/infiniband/hw/ionic/ionic_debugfs.c
new file mode 100644
index 000000000000..bff110f6d553
--- /dev/null
+++ b/drivers/infiniband/hw/ionic/ionic_debugfs.c
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
+
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include "ionic_ibdev.h"
+
+static void ionic_umem_show(struct seq_file *s, const char *w,
+			    struct ib_umem *umem, u8 page_size_log2)
+{
+	seq_printf(s, "%sumem.length:\t%#lx\n", w, umem->length);
+	seq_printf(s, "%sumem.address:\t%#lx\n", w, umem->address);
+	seq_printf(s, "%sumem.page_size:\t%llu\n", w, 1ULL << page_size_log2);
+	seq_printf(s, "%sumem.writable:\t%d\n", w, umem->writable);
+	seq_printf(s, "%sumem.nmap:\t%d\n", w, umem->sgt_append.sgt.nents);
+	seq_printf(s, "%sumem.offset():\t%#x\n", w, ib_umem_offset(umem));
+	seq_printf(s, "%sumem.num_pages():\t%lu\n",
+		   w, ib_umem_num_pages(umem));
+}
+
+static void ionic_umem_dump(struct seq_file *s, struct ib_umem *umem,
+			    u8 page_size_log2)
+{
+	int sg_i, page_i, page_count;
+	struct scatterlist *sg;
+	u64 page_dma, pg_sz;
+
+	pg_sz = 1 << page_size_log2;
+	for_each_sgtable_dma_sg(&umem->sgt_append.sgt, sg, sg_i) {
+		page_dma = sg_dma_address(sg);
+		page_count = sg_dma_len(sg) >> page_size_log2;
+
+		for (page_i = 0; page_i < page_count; ++page_i) {
+			seq_printf(s, "%#llx\n", page_dma);
+			page_dma += pg_sz;
+		}
+	}
+}
+
+static void ionic_tbl_buf_show(struct seq_file *s, const char *w,
+			       struct ionic_tbl_buf *buf)
+{
+	seq_printf(s, "%stbl_limit:\t%u\n", w, buf->tbl_limit);
+	seq_printf(s, "%stbl_pages:\t%u\n", w, buf->tbl_pages);
+	seq_printf(s, "%stbl_size:\t%zu\n", w, buf->tbl_size);
+	seq_printf(s, "%stbl_dma:\t%#llx\n", w, buf->tbl_dma);
+	seq_printf(s, "%spage_size_log2:\t%u\n", w, buf->page_size_log2);
+}
+
+static void ionic_tbl_buf_dump(struct seq_file *s, struct ionic_tbl_buf *buf)
+{
+	int page_i;
+
+	if (!buf->tbl_buf)
+		return;
+
+	for (page_i = 0; page_i < buf->tbl_pages; ++page_i)
+		seq_printf(s, "%llx\n", buf->tbl_buf[page_i]);
+}
+
+static void ionic_q_show(struct seq_file *s, const char *w,
+			 struct ionic_queue *q)
+{
+	seq_printf(s, "%ssize:\t%#llx\n", w, (u64)q->size);
+	seq_printf(s, "%sdma:\t%#llx\n", w, (u64)q->dma);
+	seq_printf(s, "%sprod:\t%#06x (%#llx)\n",
+		   w, q->prod, (u64)q->prod << q->stride_log2);
+	seq_printf(s, "%scons:\t%#06x (%#llx)\n",
+		   w, q->cons, (u64)q->cons << q->stride_log2);
+	seq_printf(s, "%smask:\t%#06x\n", w, q->mask);
+	seq_printf(s, "%sdepth_log2:\t%u\n", w, q->depth_log2);
+	seq_printf(s, "%sstride_log2:\t%u\n", w, q->stride_log2);
+	seq_printf(s, "%sdbell:\t%#llx\n", w, q->dbell);
+}
+
+static void ionic_q_dump(struct seq_file *s, struct ionic_queue *q)
+{
+	seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 16, 1, q->ptr, q->size, true);
+}
+
+static int ionic_dev_info_show(struct seq_file *s, void *v)
+{
+	struct ionic_ibdev *dev = s->private;
+	struct ionic_lif_cfg *lif_cfg;
+
+	lif_cfg = &dev->lif_cfg;
+
+	seq_printf(s, "lif_index:\t%d\n", lif_cfg->lif_index);
+	seq_printf(s, "dbid:\t%u\n", lif_cfg->dbid);
+
+	seq_printf(s, "rdma_version:\t%u\n", lif_cfg->rdma_version);
+	seq_printf(s, "rdma_minor_version:\t%u\n", lif_cfg->minor_version);
+	seq_printf(s, "qp_opcodes:\t%u\n", lif_cfg->qp_opcodes);
+	seq_printf(s, "admin_opcodes:\t%u\n", lif_cfg->admin_opcodes);
+	seq_printf(s, "reset_cnt:\t%u\n", dev->reset_cnt);
+
+	seq_printf(s, "aq_base:\t%u\n", lif_cfg->aq_base);
+	seq_printf(s, "cq_base:\t%u\n", lif_cfg->cq_base);
+	seq_printf(s, "eq_base:\t%u\n", lif_cfg->eq_base);
+
+	seq_printf(s, "aq_count:\t%u\n", lif_cfg->aq_count);
+	seq_printf(s, "eq_count:\t%u\n", lif_cfg->eq_count);
+
+	seq_printf(s, "aq_qtype:\t%u\n", lif_cfg->aq_qtype);
+	seq_printf(s, "sq_qtype:\t%u\n", lif_cfg->sq_qtype);
+	seq_printf(s, "rq_qtype:\t%u\n", lif_cfg->rq_qtype);
+	seq_printf(s, "cq_qtype:\t%u\n", lif_cfg->cq_qtype);
+	seq_printf(s, "eq_qtype:\t%u\n", lif_cfg->eq_qtype);
+
+	seq_printf(s, "max_stride:\t%u\n", lif_cfg->max_stride);
+
+	seq_printf(s, "sq_expdb:\t%u\n", lif_cfg->sq_expdb);
+	seq_printf(s, "rq_expdb:\t%u\n", lif_cfg->rq_expdb);
+	seq_printf(s, "expdb_mask:\t%u\n", lif_cfg->expdb_mask);
+
+	seq_printf(s, "udma_count:\t%u\n", lif_cfg->udma_count);
+	seq_printf(s, "udma_qgrp_shift:\t%u\n", lif_cfg->udma_qgrp_shift);
+
+	if (dev->aq_vec[0])
+		seq_printf(s, "AQ[0] admin_state:\t%u\n",
+			   atomic_read(&dev->aq_vec[0]->admin_state));
+
+	seq_printf(s, "size_pdid:\t%u\n", dev->inuse_pdid.inuse_size);
+	seq_printf(s, "size_mrid:\t%u\n", dev->inuse_mrid.inuse_size);
+	seq_printf(s, "next_mrkey:\t%u\n", dev->next_mrkey);
+	seq_printf(s, "size_cqid:\t%u\n", dev->lif_cfg.cq_count);
+	seq_printf(s, "size_qpid:\t%u\n", dev->lif_cfg.qp_count);
+
+	seq_printf(s, "page_size_supported:\t0x%llX\n",
+		   lif_cfg->page_size_supported);
+	seq_printf(s, "stats_type:\t0x%0X\n", lif_cfg->stats_type);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_dev_info);
+
+static int ionic_eq_info_show(struct seq_file *s, void *v)
+{
+	struct ionic_eq *eq = s->private;
+	struct ionic_intr __iomem *intr;
+
+	seq_printf(s, "eqid:\t%u\n", eq->eqid);
+	seq_printf(s, "intr:\t%u\n", eq->intr);
+
+	ionic_q_show(s, "q.",  &eq->q);
+	seq_printf(s, "enable:\t%u\n", eq->enable);
+	seq_printf(s, "armed:\t%u\n", eq->armed);
+	seq_printf(s, "irq:\t%u\n", eq->irq);
+	seq_printf(s, "name:\t%s\n", eq->name);
+
+	/* interrupt control readback */
+	intr = &eq->dev->lif_cfg.intr_ctrl[eq->intr];
+	seq_printf(s, "intr_coalesce_init:\t%#x\n", ioread32(&intr->coal_init));
+	seq_printf(s, "intr_mask:\t%#x\n", ioread32(&intr->mask));
+	seq_printf(s, "intr_credits:\t%#x\n", ioread32(&intr->credits));
+	seq_printf(s, "intr_mask_assert:\t%#x\n", ioread32(&intr->mask_assert));
+	seq_printf(s, "intr_coalesce:\t%#x\n", ioread32(&intr->coal));
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_eq_info);
+
+static int ionic_eq_q_show(struct seq_file *s, void *v)
+{
+	struct ionic_eq *eq = s->private;
+
+	ionic_q_dump(s, &eq->q);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_eq_q);
+
+static int ionic_mr_info_show(struct seq_file *s, void *v)
+{
+	struct ionic_mr *mr = s->private;
+
+	seq_printf(s, "mrid:\t%u\n", mr->mrid);
+
+	ionic_tbl_buf_show(s, "", &mr->buf);
+
+	if (mr->umem)
+		ionic_umem_show(s, "", mr->umem, mr->buf.page_size_log2);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_mr_info);
+
+static int ionic_mr_umem_show(struct seq_file *s, void *v)
+{
+	struct ionic_mr *mr = s->private;
+
+	ionic_umem_dump(s, mr->umem, mr->buf.page_size_log2);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_mr_umem);
+
+static int ionic_mr_tbl_buf_show(struct seq_file *s, void *v)
+{
+	struct ionic_mr *mr = s->private;
+
+	ionic_tbl_buf_dump(s, &mr->buf);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_mr_tbl_buf);
+
+static int ionic_cq_info_show(struct seq_file *s, void *v)
+{
+	struct ionic_cq *cq = s->private;
+
+	seq_printf(s, "cqid:\t%u\n", cq->cqid);
+	seq_printf(s, "eqid:\t%u\n", cq->eqid);
+
+	if (cq->q.ptr) {
+		ionic_q_show(s, "", &cq->q);
+		seq_printf(s, "arm_any_prod:\t%#06x\n", cq->arm_any_prod);
+		seq_printf(s, "arm_sol_prod:\t%#06x\n", cq->arm_sol_prod);
+	}
+
+	if (cq->umem)
+		ionic_umem_show(s, "", cq->umem, PAGE_SHIFT);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_cq_info);
+
+static int ionic_cq_q_show(struct seq_file *s, void *v)
+{
+	struct ionic_cq *cq = s->private;
+
+	ionic_q_dump(s, &cq->q);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_cq_q);
+
+static int ionic_cq_umem_show(struct seq_file *s, void *v)
+{
+	struct ionic_cq *cq = s->private;
+
+	ionic_umem_dump(s, cq->umem, PAGE_SHIFT);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_cq_umem);
+
+static int ionic_aq_info_show(struct seq_file *s, void *v)
+{
+	struct ionic_aq *aq = s->private;
+
+	seq_printf(s, "armed:\t%u\n", aq->armed);
+	seq_printf(s, "aqid:\t%u\n", aq->aqid);
+	seq_printf(s, "cqid:\t%u\n", aq->cqid);
+
+	if (aq->q.ptr)
+		ionic_q_show(s, "", &aq->q);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_aq_info);
+
+static int ionic_aq_q_show(struct seq_file *s, void *v)
+{
+	struct ionic_aq *aq = s->private;
+
+	ionic_q_dump(s, &aq->q);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_aq_q);
+
+static int ionic_aq_wqe_show(struct seq_file *s, void *v)
+{
+	struct ionic_aq *aq = s->private;
+	struct ionic_v1_admin_wqe *wqe;
+
+	wqe = &aq->debug_wr->wqe;
+
+	seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 16, 1, wqe, sizeof(*wqe),
+		     true);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_aq_wqe);
+
+static int ionic_aq_cqe_show(struct seq_file *s, void *v)
+{
+	struct ionic_aq *aq = s->private;
+	struct ionic_v1_cqe *cqe;
+
+	cqe = &aq->debug_wr->cqe;
+
+	seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 16, 1, cqe, sizeof(*cqe),
+		     true);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_aq_cqe);
+
+struct ionic_dbg_admin_wr {
+	struct ionic_aq *aq;
+	struct ionic_admin_wr wr;
+	void *data;
+	dma_addr_t dma;
+};
+
+static int ionic_aq_data_show(struct seq_file *s, void *v)
+{
+	struct ionic_aq *aq = s->private;
+	struct ionic_dbg_admin_wr *wr;
+
+	wr = container_of(aq->debug_wr, struct ionic_dbg_admin_wr, wr);
+
+	dma_sync_single_for_cpu(aq->dev->lif_cfg.hwdev, wr->dma, PAGE_SIZE,
+				DMA_FROM_DEVICE);
+
+	seq_hex_dump(s, "", DUMP_PREFIX_OFFSET, 16, 1,
+		     wr->data, PAGE_SIZE, true);
+
+	dma_sync_single_for_device(aq->dev->lif_cfg.hwdev, wr->dma, PAGE_SIZE,
+				   DMA_FROM_DEVICE);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_aq_data);
+
+static int ionic_qp_info_show(struct seq_file *s, void *v)
+{
+	struct ionic_qp *qp = s->private;
+
+	seq_printf(s, "qpid:\t%u\n", qp->qpid);
+	seq_printf(s, "udma_idx:\t%u\n", qp->udma_idx);
+	seq_printf(s, "state:\t%d\n", qp->state);
+
+	if (qp->sq.ptr) {
+		ionic_q_show(s, "sq.", &qp->sq);
+		seq_printf(s, "sq_msn_prod:\t%#06x\n",
+			   qp->sq_msn_prod);
+		seq_printf(s, "sq_msn_cons:\t%#06x\n",
+			   qp->sq_msn_cons);
+	}
+
+	if (qp->sq_umem)
+		ionic_umem_show(s, "sq.", qp->sq_umem, PAGE_SHIFT);
+
+	seq_printf(s, "sq_is_cmb:\t%d\n", !!(qp->sq_cmb & IONIC_CMB_ENABLE));
+	if (qp->sq_cmb & IONIC_CMB_ENABLE) {
+		seq_printf(s, "sq_is_expdb:\t%d\n",
+			   !!(qp->sq_cmb & IONIC_CMB_EXPDB));
+		seq_printf(s, "sq_cmb_order:\t%d\n", qp->sq_cmb_order);
+		seq_printf(s, "sq_cmb_pgid:\t%d\n", qp->sq_cmb_pgid);
+		seq_printf(s, "sq_cmb_addr:\t%#llx\n",
+			   (u64)qp->sq_cmb_addr);
+	}
+
+	seq_printf(s, "sq_flush:\t%d\n", qp->sq_flush);
+	seq_printf(s, "sq_flush_rcvd:\t%d\n", qp->sq_flush_rcvd);
+	seq_printf(s, "sq_spec:\t%d\n", qp->sq_spec);
+	seq_printf(s, "sq_cqid:\t%u\n", qp->sq_cqid);
+
+	if (qp->rq.ptr)
+		ionic_q_show(s, "rq.", &qp->rq);
+
+	if (qp->rq_umem)
+		ionic_umem_show(s, "rq.", qp->rq_umem, PAGE_SHIFT);
+
+	seq_printf(s, "rq_is_cmb:\t%d\n", !!(qp->rq_cmb & IONIC_CMB_ENABLE));
+	if (qp->rq_cmb & IONIC_CMB_ENABLE) {
+		seq_printf(s, "rq_is_expdb:\t%d\n",
+			   !!(qp->rq_cmb & IONIC_CMB_EXPDB));
+		seq_printf(s, "rq_cmb_order:\t%d\n", qp->rq_cmb_order);
+		seq_printf(s, "rq_cmb_pgid:\t%d\n", qp->rq_cmb_pgid);
+		seq_printf(s, "rq_cmb_addr:\t%#llx\n",
+			   (u64)qp->rq_cmb_addr);
+	}
+
+	seq_printf(s, "rq_flush:\t%d\n", qp->rq_flush);
+	seq_printf(s, "rq_spec:\t%d\n", qp->rq_spec);
+	seq_printf(s, "rq_cqid:\t%u\n", qp->rq_cqid);
+
+	if (qp->has_ah) {
+		bool is_ip4 = false, is_ip6 = false;
+		struct ib_ud_header *hdr = qp->hdr;
+
+		seq_printf(s, "hdr_eth_smac:\t%pM\n", hdr->eth.smac_h);
+		seq_printf(s, "hdr_eth_dmac:\t%pM\n", hdr->eth.dmac_h);
+
+		if (hdr->eth.type == cpu_to_be16(ETH_P_8021Q)) {
+			seq_printf(s, "hdr_eth_vlan:\t%u\n",
+				   be16_to_cpu(hdr->vlan.tag));
+			is_ip4 = hdr->vlan.type == cpu_to_be16(ETH_P_IP);
+			is_ip6 = hdr->vlan.type == cpu_to_be16(ETH_P_IPV6);
+		} else {
+			is_ip4 = hdr->eth.type == cpu_to_be16(ETH_P_IP);
+			is_ip6 = hdr->eth.type == cpu_to_be16(ETH_P_IPV6);
+		}
+
+		if (is_ip4) {
+			seq_printf(s, "hdr_ip4_saddr:\t%pI4\n", &hdr->ip4.saddr);
+			seq_printf(s, "hdr_ip4_daddr:\t%pI4\n", &hdr->ip4.daddr);
+			seq_printf(s, "hdr_ip4_ttl:\t%u\n", hdr->ip4.ttl);
+			seq_printf(s, "hdr_ip4_tos:\t%u\n", hdr->ip4.tos);
+		}
+
+		if (is_ip6) {
+			seq_printf(s, "hdr_ip6_saddr:\t%pI6\n",
+				   hdr->grh.source_gid.raw);
+			seq_printf(s, "hdr_ip6_daddr:\t%pI6\n",
+				   hdr->grh.destination_gid.raw);
+			seq_printf(s, "hdr_ip6_flow_label:\t%u\n",
+				   be32_to_cpu(hdr->grh.flow_label));
+			seq_printf(s, "hdr_ip6_hop_limit:\t%u\n",
+				   hdr->grh.hop_limit);
+			seq_printf(s, "hdr_ip6_traffic_class:\t%u\n",
+				   hdr->grh.traffic_class);
+		}
+
+		seq_printf(s, "hdr_udp_sport:\t%u\n", be16_to_cpu(hdr->udp.sport));
+		seq_printf(s, "hdr_udp_dport:\t%u\n", be16_to_cpu(hdr->udp.dport));
+	}
+
+	seq_printf(s, "dcqcn_profile:\t%d\n", qp->dcqcn_profile);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_qp_info);
+
+static int ionic_qp_sq_show(struct seq_file *s, void *v)
+{
+	struct ionic_qp *qp = s->private;
+
+	ionic_q_dump(s, &qp->sq);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_qp_sq);
+
+static int ionic_qp_sq_umem_show(struct seq_file *s, void *v)
+{
+	struct ionic_qp *qp = s->private;
+
+	ionic_umem_dump(s, qp->sq_umem, PAGE_SHIFT);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_qp_sq_umem);
+
+static int ionic_qp_rq_show(struct seq_file *s, void *v)
+{
+	struct ionic_qp *qp = s->private;
+
+	ionic_q_dump(s, &qp->rq);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_qp_rq);
+
+static int ionic_qp_rq_umem_show(struct seq_file *s, void *v)
+{
+	struct ionic_qp *qp = s->private;
+
+	ionic_umem_dump(s, qp->rq_umem, PAGE_SHIFT);
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ionic_qp_rq_umem);
+
+void ionic_dbg_add_eq(struct ionic_ibdev *dev, struct ionic_eq *eq)
+{
+	char name[8];
+
+	eq->debug = NULL;
+
+	if (!dev->debug_eq)
+		return;
+
+	snprintf(name, sizeof(name), "%u", eq->eqid);
+
+	eq->debug = debugfs_create_dir(name, dev->debug_eq);
+	if (IS_ERR(eq->debug))
+		eq->debug = NULL;
+	if (!eq->debug)
+		return;
+
+	debugfs_create_file("info", 0440, eq->debug, eq,
+			    &ionic_eq_info_fops);
+
+	debugfs_create_file("q", 0440, eq->debug, eq,
+			    &ionic_eq_q_fops);
+}
+
+void ionic_dbg_rm_eq(struct ionic_eq *eq)
+{
+	debugfs_remove_recursive(eq->debug);
+
+	eq->debug = NULL;
+}
+
+void ionic_dbg_add_cq(struct ionic_ibdev *dev, struct ionic_cq *cq)
+{
+	char name[8];
+
+	cq->debug = NULL;
+
+	if (!dev->debug_cq)
+		return;
+
+	snprintf(name, sizeof(name), "%u", cq->cqid);
+
+	cq->debug = debugfs_create_dir(name, dev->debug_cq);
+	if (IS_ERR(cq->debug))
+		cq->debug = NULL;
+	if (!cq->debug)
+		return;
+
+	debugfs_create_file("info", 0440, cq->debug, cq,
+			    &ionic_cq_info_fops);
+
+	if (cq->q.ptr)
+		debugfs_create_file("q", 0440, cq->debug, cq,
+				    &ionic_cq_q_fops);
+
+	if (cq->umem)
+		debugfs_create_file("umem", 0440, cq->debug, cq,
+				    &ionic_cq_umem_fops);
+}
+
+void ionic_dbg_rm_cq(struct ionic_cq *cq)
+{
+	debugfs_remove_recursive(cq->debug);
+
+	cq->debug = NULL;
+}
+
+void ionic_dbg_add_aq(struct ionic_ibdev *dev, struct ionic_aq *aq)
+{
+	struct ionic_dbg_admin_wr *wr;
+	char name[8];
+
+	mutex_init(&aq->debug_mutex);
+
+	aq->debug = NULL;
+
+	if (!dev->debug_aq)
+		return;
+
+	snprintf(name, sizeof(name), "%u", aq->aqid);
+
+	aq->debug = debugfs_create_dir(name, dev->debug_aq);
+	if (IS_ERR(aq->debug))
+		aq->debug = NULL;
+	if (!aq->debug)
+		return;
+
+	debugfs_create_file("info", 0440, aq->debug, aq,
+			    &ionic_aq_info_fops);
+
+	if (aq->q.ptr)
+		debugfs_create_file("q", 0440, aq->debug, aq,
+				    &ionic_aq_q_fops);
+
+	wr = kzalloc_obj(*wr);
+	if (!wr)
+		goto err_wr;
+
+	wr->data = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!wr->data)
+		goto err_data;
+
+	wr->dma = dma_map_single(dev->lif_cfg.hwdev, wr->data, PAGE_SIZE,
+				 DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev->lif_cfg.hwdev, wr->dma))
+		goto err_dma;
+
+	wr->wr.wqe.op = IONIC_V1_ADMIN_DEBUG;
+	wr->wr.wqe.cmd.stats.dma_addr = cpu_to_le64(wr->dma);
+	wr->wr.wqe.cmd.stats.length = cpu_to_le32(PAGE_SIZE);
+
+	init_completion(&wr->wr.work);
+
+	aq->debug_wr = &wr->wr;
+
+	debugfs_create_file("dbg_wr_wqe", 0440, aq->debug, aq,
+			    &ionic_aq_wqe_fops);
+
+	debugfs_create_file("dbg_wr_cqe", 0440, aq->debug, aq,
+			    &ionic_aq_cqe_fops);
+
+	debugfs_create_file("dbg_wr_data", 0440, aq->debug, aq,
+			    &ionic_aq_data_fops);
+
+	return;
+
+err_dma:
+	kfree(wr->data);
+err_data:
+	kfree(wr);
+err_wr:
+	return;
+}
+
+void ionic_dbg_rm_aq(struct ionic_aq *aq)
+{
+	struct ionic_ibdev *dev = aq->dev;
+	struct ionic_dbg_admin_wr *wr;
+
+	debugfs_remove_recursive(aq->debug);
+
+	aq->debug = NULL;
+
+	mutex_destroy(&aq->debug_mutex);
+
+	if (!aq->debug_wr)
+		return;
+
+	wr = container_of(aq->debug_wr, struct ionic_dbg_admin_wr, wr);
+
+	dma_unmap_single(dev->lif_cfg.hwdev, wr->dma, PAGE_SIZE, DMA_FROM_DEVICE);
+	kfree(wr->data);
+	kfree(wr);
+}
+
+void ionic_dbg_add_qp(struct ionic_ibdev *dev, struct ionic_qp *qp)
+{
+	char name[8];
+
+	qp->debug = NULL;
+
+	if (!dev->debug_qp)
+		return;
+
+	snprintf(name, sizeof(name), "%u", qp->qpid);
+
+	qp->debug = debugfs_create_dir(name, dev->debug_qp);
+	if (IS_ERR(qp->debug))
+		qp->debug = NULL;
+	if (!qp->debug)
+		return;
+
+	debugfs_create_file("info", 0440, qp->debug, qp,
+			    &ionic_qp_info_fops);
+
+	if (qp->sq.ptr)
+		debugfs_create_file("sq", 0440, qp->debug, qp,
+				    &ionic_qp_sq_fops);
+
+	if (qp->sq_umem)
+		debugfs_create_file("sq_umem", 0440, qp->debug, qp,
+				    &ionic_qp_sq_umem_fops);
+
+	if (qp->rq.ptr)
+		debugfs_create_file("rq", 0440, qp->debug, qp,
+				    &ionic_qp_rq_fops);
+
+	if (qp->rq_umem)
+		debugfs_create_file("rq_umem", 0440, qp->debug, qp,
+				    &ionic_qp_rq_umem_fops);
+}
+
+void ionic_dbg_rm_qp(struct ionic_qp *qp)
+{
+	debugfs_remove_recursive(qp->debug);
+
+	qp->debug = NULL;
+}
+
+void ionic_dbg_add_mr(struct ionic_ibdev *dev, struct ionic_mr *mr)
+{
+	char name[8];
+
+	mr->debug = NULL;
+
+	if (!dev->debug_mr)
+		return;
+
+	snprintf(name, sizeof(name), "%u", ionic_mrid_index(mr->mrid));
+
+	mr->debug = debugfs_create_dir(name, dev->debug_mr);
+	if (IS_ERR(mr->debug))
+		mr->debug = NULL;
+	if (!mr->debug)
+		return;
+
+	debugfs_create_file("info", 0440, mr->debug, mr,
+			    &ionic_mr_info_fops);
+
+	if (mr->umem)
+		debugfs_create_file("umem", 0440, mr->debug, mr,
+				    &ionic_mr_umem_fops);
+
+	if (mr->buf.tbl_buf)
+		debugfs_create_file("buf", 0440, mr->debug, mr,
+				    &ionic_mr_tbl_buf_fops);
+}
+
+void ionic_dbg_rm_mr(struct ionic_mr *mr)
+{
+	debugfs_remove_recursive(mr->debug);
+
+	mr->debug = NULL;
+}
+
+void ionic_dbg_add_dev(struct ionic_ibdev *dev, struct dentry *parent)
+{
+	if (IS_ERR_OR_NULL(parent))
+		return;
+
+	dev->debug = debugfs_create_dir("rdma", parent);
+	if (IS_ERR(dev->debug))
+		dev->debug = NULL;
+	if (!dev->debug)
+		return;
+
+	debugfs_create_file("info", 0440, dev->debug, dev,
+			    &ionic_dev_info_fops);
+
+	dev->debug_aq = debugfs_create_dir("aq", dev->debug);
+	if (IS_ERR(dev->debug_aq))
+		dev->debug_aq = NULL;
+
+	dev->debug_cq = debugfs_create_dir("cq", dev->debug);
+	if (IS_ERR(dev->debug_cq))
+		dev->debug_cq = NULL;
+
+	dev->debug_eq = debugfs_create_dir("eq", dev->debug);
+	if (IS_ERR(dev->debug_eq))
+		dev->debug_eq = NULL;
+
+	dev->debug_mr = debugfs_create_dir("mr", dev->debug);
+	if (IS_ERR(dev->debug_mr))
+		dev->debug_mr = NULL;
+
+	dev->debug_qp = debugfs_create_dir("qp", dev->debug);
+	if (IS_ERR(dev->debug_qp))
+		dev->debug_qp = NULL;
+}
+
+void ionic_dbg_rm_dev(struct ionic_ibdev *dev)
+{
+	debugfs_remove_recursive(dev->debug);
+
+	dev->debug = NULL;
+	dev->debug_cq = NULL;
+	dev->debug_eq = NULL;
+	dev->debug_mr = NULL;
+	dev->debug_qp = NULL;
+}
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.c b/drivers/infiniband/hw/ionic/ionic_ibdev.c
index 356ad9fe150f..69e6164e0f1e 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.c
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.c
@@ -294,6 +294,7 @@ static void ionic_destroy_ibdev(struct ionic_ibdev *dev)
 	ionic_stats_cleanup(dev);
 	ionic_destroy_rdma_admin(dev);
 	ionic_destroy_resids(dev);
+	ionic_dbg_rm_dev(dev);
 	WARN_ON(!xa_empty(&dev->qp_tbl));
 	xa_destroy(&dev->qp_tbl);
 	WARN_ON(!xa_empty(&dev->cq_tbl));
@@ -318,6 +319,7 @@ static struct ionic_ibdev *ionic_create_ibdev(struct ionic_aux_dev *ionic_adev)
 	xa_init_flags(&dev->cq_tbl, GFP_ATOMIC);
 
 	ionic_init_resids(dev);
+	ionic_dbg_add_dev(dev, dev->lif_cfg.dbg_ctx);
 
 	rc = ionic_rdma_reset_devcmd(dev);
 	if (rc)
@@ -364,6 +366,7 @@ static struct ionic_ibdev *ionic_create_ibdev(struct ionic_aux_dev *ionic_adev)
 	ionic_destroy_rdma_admin(dev);
 err_reset:
 	ionic_destroy_resids(dev);
+	ionic_dbg_rm_dev(dev);
 	xa_destroy(&dev->qp_tbl);
 	xa_destroy(&dev->cq_tbl);
 	ib_dealloc_device(&dev->ibdev);
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.h b/drivers/infiniband/hw/ionic/ionic_ibdev.h
index 7a8e4b59da1c..300d17882db5 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.h
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.h
@@ -115,6 +115,13 @@ struct ionic_ibdev {
 	void			*hw_stats_buf;
 	struct rdma_stat_desc	*hw_stats_hdrs;
 	struct ionic_counter_stats *counter_stats;
+	struct dentry		*debug;
+	struct dentry		*debug_aq;
+	struct dentry		*debug_cq;
+	struct dentry		*debug_eq;
+	struct dentry		*debug_mr;
+	struct dentry		*debug_qp;
+
 	int			hw_stats_count;
 };
 
@@ -133,6 +140,7 @@ struct ionic_eq {
 
 	int			irq;
 	char			name[32];
+	struct dentry		*debug;
 };
 
 struct ionic_admin_wr {
@@ -167,6 +175,9 @@ struct ionic_aq {
 	struct ionic_admin_wr_q	*q_wr;
 	struct list_head	wr_prod;
 	struct list_head	wr_post;
+	struct dentry		*debug;
+	struct ionic_admin_wr	*debug_wr;
+	struct mutex		debug_mutex; /* for debug_wr */
 };
 
 struct ionic_ctx {
@@ -215,6 +226,7 @@ struct ionic_cq {
 
 	/* infrequently accessed, keep at end */
 	struct ib_umem		*umem;
+	struct dentry		*debug;
 };
 
 struct ionic_vcq {
@@ -304,6 +316,7 @@ struct ionic_qp {
 	int			dcqcn_profile;
 
 	struct ib_ud_header	*hdr;
+	struct dentry		*debug;
 };
 
 struct ionic_ah {
@@ -323,6 +336,7 @@ struct ionic_mr {
 	int			flags;
 
 	struct ib_umem		*umem;
+	struct dentry		*debug;
 	struct ionic_tbl_buf	buf;
 	bool			created;
 };
@@ -514,4 +528,19 @@ int ionic_pgtbl_init(struct ionic_ibdev *dev,
 		     int limit,
 		     u64 page_size);
 void ionic_pgtbl_unbuf(struct ionic_ibdev *dev, struct ionic_tbl_buf *buf);
+
+/* ionic_debugfs.c */
+void ionic_dbg_add_dev(struct ionic_ibdev *dev, struct dentry *parent);
+void ionic_dbg_rm_dev(struct ionic_ibdev *dev);
+void ionic_dbg_add_eq(struct ionic_ibdev *dev, struct ionic_eq *eq);
+void ionic_dbg_rm_eq(struct ionic_eq *eq);
+void ionic_dbg_add_cq(struct ionic_ibdev *dev, struct ionic_cq *cq);
+void ionic_dbg_rm_cq(struct ionic_cq *cq);
+void ionic_dbg_add_aq(struct ionic_ibdev *dev, struct ionic_aq *aq);
+void ionic_dbg_rm_aq(struct ionic_aq *aq);
+void ionic_dbg_add_mr(struct ionic_ibdev *dev, struct ionic_mr *mr);
+void ionic_dbg_rm_mr(struct ionic_mr *mr);
+void ionic_dbg_add_qp(struct ionic_ibdev *dev, struct ionic_qp *qp);
+void ionic_dbg_rm_qp(struct ionic_qp *qp);
+
 #endif /* _IONIC_IBDEV_H_ */
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
index 800555eb47ac..53e41b1b3e8d 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
@@ -51,6 +51,7 @@ void ionic_fill_lif_cfg(struct ionic_lif *lif, struct ionic_lif_cfg *cfg)
 		cfg->page_size_supported = IONIC_PAGE_SIZE_SUPPORTED;
 
 	cfg->rdma_version = ident->rdma.version;
+	cfg->minor_version = ident->rdma.minor_version;
 	cfg->qp_opcodes = ident->rdma.qp_opcodes;
 	cfg->admin_opcodes = ident->rdma.admin_opcodes;
 
@@ -90,6 +91,8 @@ void ionic_fill_lif_cfg(struct ionic_lif *lif, struct ionic_lif_cfg *cfg)
 	    !!(lif->qtype_info[IONIC_QTYPE_TXQ].features & IONIC_QIDENT_F_EXPDB);
 	cfg->rq_expdb =
 	    !!(lif->qtype_info[IONIC_QTYPE_RXQ].features & IONIC_QIDENT_F_EXPDB);
+
+	cfg->dbg_ctx = lif->dentry;
 }
 
 struct net_device *ionic_lif_netdev(struct ionic_lif *lif)
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
index 18e7c7f13579..500925c429f6 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
@@ -14,6 +14,7 @@
 struct ionic_lif_cfg {
 	struct device *hwdev;
 	struct ionic_lif *lif;
+	struct dentry *dbg_ctx;
 
 	int lif_index;
 	int lif_hw_index;
@@ -49,6 +50,7 @@ struct ionic_lif_cfg {
 	u8 udma_qgrp_shift;
 
 	u8 rdma_version;
+	u8 minor_version;
 	u8 qp_opcodes;
 	u8 admin_opcodes;
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net-next 4/4] RDMA/ionic: Add DCQCN parameter configuration via debugfs
  2026-05-06  4:19 [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Eric Joyner
                   ` (2 preceding siblings ...)
  2026-05-06  4:19 ` [PATCH net-next 3/4] RDMA/ionic: Add debugfs support Eric Joyner
@ 2026-05-06  4:19 ` Eric Joyner
  2026-05-06 22:59 ` [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Jakub Kicinski
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-05-06  4:19 UTC (permalink / raw)
  To: netdev, linux-rdma
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Abhijit Gangurde, Allen Hubbe,
	Jason Gunthorpe, Leon Romanovsky, Eric Joyner

From: Allen Hubbe <allen.hubbe@amd.com>

The HCA supports DCQCN with multiple profiles; these are normally
configured through a userspace utility, but expose these profiles and
their parameters for debug purposes via debugfs.

To use these, the firmware must be configured in the mode that expects
DCQCN settings to be programmed by the driver, otherwise the firmware
will silently fail and indicate success without any changes actually
occurring.

Signed-off-by: Allen Hubbe <allen.hubbe@amd.com>
Co-developed-by: Eric Joyner <eric.joyner@amd.com>
Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 drivers/infiniband/hw/ionic/Makefile          |   3 +-
 .../infiniband/hw/ionic/ionic_controlpath.c   |   5 +
 drivers/infiniband/hw/ionic/ionic_dcqcn.c     | 629 ++++++++++++++++++
 drivers/infiniband/hw/ionic/ionic_fw.h        |  31 +
 drivers/infiniband/hw/ionic/ionic_ibdev.c     |   4 +
 drivers/infiniband/hw/ionic/ionic_ibdev.h     |  12 +
 drivers/infiniband/hw/ionic/ionic_lif_cfg.c   |   1 +
 drivers/infiniband/hw/ionic/ionic_lif_cfg.h   |   2 +
 drivers/infiniband/hw/ionic/ionic_profiles.h  |  86 +++
 9 files changed, 772 insertions(+), 1 deletion(-)
 create mode 100644 drivers/infiniband/hw/ionic/ionic_dcqcn.c
 create mode 100644 drivers/infiniband/hw/ionic/ionic_profiles.h

diff --git a/drivers/infiniband/hw/ionic/Makefile b/drivers/infiniband/hw/ionic/Makefile
index 65bb4eaf0c13..1ad2c3d12b36 100644
--- a/drivers/infiniband/hw/ionic/Makefile
+++ b/drivers/infiniband/hw/ionic/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_INFINIBAND_IONIC)	+= ionic_rdma.o
 
 ionic_rdma-y :=	\
 	ionic_ibdev.o ionic_lif_cfg.o ionic_queue.o ionic_pgtbl.o ionic_admin.o \
-	ionic_controlpath.o ionic_datapath.o ionic_hw_stats.o ionic_debugfs.o
+	ionic_controlpath.o ionic_datapath.o ionic_hw_stats.o ionic_debugfs.o \
+	ionic_dcqcn.o
diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c
index 0ea053369cba..4daca85c4fb3 100644
--- a/drivers/infiniband/hw/ionic/ionic_controlpath.c
+++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c
@@ -1512,6 +1512,7 @@ static int ionic_modify_qp_cmd(struct ionic_ibdev *dev,
 			cpu_to_le32(qp->ahid | (hdr_len << 24));
 		wr.wqe.cmd.mod_qp.dma_addr = cpu_to_le64(hdr_dma);
 
+		wr.wqe.cmd.mod_qp.dcqcn_profile = qp->dcqcn_profile;
 		wr.wqe.cmd.mod_qp.en_pcp = attr->ah_attr.sl;
 		wr.wqe.cmd.mod_qp.ip_dscp = grh->traffic_class >> 2;
 	}
@@ -2586,6 +2587,10 @@ int ionic_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int mask,
 	if (mask & IB_QP_CAP)
 		return -EINVAL;
 
+	if (mask & IB_QP_AV)
+		qp->dcqcn_profile =
+		    ionic_dcqcn_select_profile(dev, &attr->ah_attr);
+
 	rc = ionic_modify_qp_cmd(dev, pd, qp, attr, mask);
 	if (rc)
 		return rc;
diff --git a/drivers/infiniband/hw/ionic/ionic_dcqcn.c b/drivers/infiniband/hw/ionic/ionic_dcqcn.c
new file mode 100644
index 000000000000..80fa79cfd951
--- /dev/null
+++ b/drivers/infiniband/hw/ionic/ionic_dcqcn.c
@@ -0,0 +1,629 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
+
+#include <linux/debugfs.h>
+
+#include "ionic_ibdev.h"
+#include "ionic_profiles.h"
+
+static const struct ionic_profile_vals dcqcn_defaults[] = {
+	{
+		.v[NP_ICNP_802P_PRIO]			= 6,
+		.v[NP_CNP_DSCP]				= 46,
+		.v[RP_TOKEN_BUCKET_SIZE]		= 800000,
+		.v[RP_INITIAL_ALPHA_VALUE]		= 64,
+		.v[RP_DCE_TCP_G]			= 512,
+		.v[RP_DCE_TCP_RTT]			= 1,
+		.v[RP_RATE_REDUCE_MONITOR_PERIOD]	= 1,
+		.v[RP_MIN_RATE]				= 1,
+		.v[RP_GD]				= 11,
+		.v[RP_MIN_DEC_FAC]			= 50,
+		.v[RP_CLAMP_TGT_RATE_ATI]		= 1,
+		.v[RP_THRESHOLD]			= 1,
+		.v[RP_TIME_RESET]			= 1,
+		.v[RP_QP_RATE]				= 100000,
+		.v[RP_BYTE_RESET]			= 431068,
+		.v[RP_AI_RATE]				= 160,
+		.v[RP_HAI_RATE]				= 300,
+	},
+};
+
+#define DCQCN_INT_ATTR(_min, _max, _name) \
+	{ .min = (_min), .max = (_max), .name = (_name) }
+
+#define DCQCN_BOOL_ATTR(_name) \
+	DCQCN_INT_ATTR(0, 1, _name)
+
+static const struct ionic_dcqcn_param_attr dcqcn_attrs[] = {
+	/* under "roce_np" */
+	DCQCN_INT_ATTR(0, 7, "icnp_802p_prio"),
+	DCQCN_INT_ATTR(0, 63, "cnp_dscp"),
+	/* under "roce_rp" */
+	DCQCN_INT_ATTR(100, 200000000, "token_bucket_size"),
+	DCQCN_INT_ATTR(0, 1023, "initial_alpha_value"),
+	DCQCN_INT_ATTR(0, 1023, "dce_tcp_g"),
+	DCQCN_INT_ATTR(1, 131071, "dce_tcp_rtt"),
+	DCQCN_INT_ATTR(1, INT_MAX, "rate_reduce_monitor_period"),
+	DCQCN_INT_ATTR(1, INT_MAX, "rate_to_set_on_first_cnp"),
+	DCQCN_INT_ATTR(1, INT_MAX, "min_rate"),
+	DCQCN_INT_ATTR(1, 11, "gd"),
+	DCQCN_INT_ATTR(0, 100, "min_dec_fac"),
+	DCQCN_BOOL_ATTR("clamp_tgt_rate"),
+	DCQCN_BOOL_ATTR("clamp_tgt_rate_ati"),
+	DCQCN_INT_ATTR(1, 31, "threshold"),
+	DCQCN_INT_ATTR(1, 32767, "time_reset"),
+	DCQCN_INT_ATTR(1, INT_MAX, "qp_rate"),
+	DCQCN_INT_ATTR(1, INT_MAX, "byte_reset"),
+	DCQCN_INT_ATTR(1, INT_MAX, "ai_rate"),
+	DCQCN_INT_ATTR(1, INT_MAX, "hai_rate"),
+};
+
+static void dcqcn_set_profile(struct ionic_profile *profile)
+{
+	struct ionic_ibdev *dev = profile->dev;
+	struct ionic_admin_wr wr = {
+		.work = COMPLETION_INITIALIZER_ONSTACK(wr.work),
+		.wqe = {
+			.op = IONIC_V1_ADMIN_MODIFY_DCQCN,
+			.len = cpu_to_le16(IONIC_ADMIN_MODIFY_DCQCN_IN_V1_LEN),
+			.cmd.mod_dcqcn = {
+				.id_ver = cpu_to_le32(profile->idx + 1),
+			}
+		}
+	};
+	int rc;
+
+	wr.wqe.cmd.mod_dcqcn.np_incp_802p_prio =
+		profile->vals.v[NP_ICNP_802P_PRIO];
+
+	wr.wqe.cmd.mod_dcqcn.np_cnp_dscp =
+		profile->vals.v[NP_CNP_DSCP];
+
+	wr.wqe.cmd.mod_dcqcn.rp_token_bucket_size =
+		cpu_to_be64(profile->vals.v[RP_TOKEN_BUCKET_SIZE]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_initial_alpha_value =
+		cpu_to_be16(profile->vals.v[RP_INITIAL_ALPHA_VALUE]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_dce_tcp_g =
+		cpu_to_be16(profile->vals.v[RP_DCE_TCP_G]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_dce_tcp_rtt =
+		cpu_to_be32(profile->vals.v[RP_DCE_TCP_RTT]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_rate_reduce_monitor_period =
+		cpu_to_be32(profile->vals.v[RP_RATE_REDUCE_MONITOR_PERIOD]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_rate_to_set_on_first_cnp =
+		cpu_to_be32(profile->vals.v[RP_RATE_TO_SET_ON_FIRST_CNP]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_min_rate =
+		cpu_to_be32(profile->vals.v[RP_MIN_RATE]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_gd =
+		profile->vals.v[RP_GD];
+
+	wr.wqe.cmd.mod_dcqcn.rp_min_dec_fac =
+		profile->vals.v[RP_MIN_DEC_FAC];
+
+	if (profile->vals.v[RP_CLAMP_TGT_RATE])
+		wr.wqe.cmd.mod_dcqcn.rp_clamp_flags |= IONIC_RPF_CLAMP_TGT_RATE;
+
+	if (profile->vals.v[RP_CLAMP_TGT_RATE_ATI])
+		wr.wqe.cmd.mod_dcqcn.rp_clamp_flags |=
+			IONIC_RPF_CLAMP_TGT_RATE_ATI;
+
+	wr.wqe.cmd.mod_dcqcn.rp_threshold =
+		profile->vals.v[RP_THRESHOLD];
+
+	wr.wqe.cmd.mod_dcqcn.rp_time_reset =
+		cpu_to_be32(profile->vals.v[RP_TIME_RESET]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_qp_rate =
+		cpu_to_be32(profile->vals.v[RP_QP_RATE]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_byte_reset =
+		cpu_to_be32(profile->vals.v[RP_BYTE_RESET]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_ai_rate =
+		cpu_to_be32(profile->vals.v[RP_AI_RATE]);
+
+	wr.wqe.cmd.mod_dcqcn.rp_hai_rate =
+		cpu_to_be32(profile->vals.v[RP_HAI_RATE]);
+
+	ionic_admin_post(dev, &wr);
+	rc = ionic_admin_wait(dev, &wr, IONIC_ADMIN_F_INTERRUPT);
+	if (rc)
+		ibdev_warn(&dev->ibdev, "dcqcn profile %d not set, error %d\n",
+			   profile->idx + 1, rc);
+}
+
+static int dcqcn_param_show(struct seq_file *s, void *v)
+{
+	struct ionic_dcqcn_param_entry *entry = s->private;
+	struct ionic_profile *profile = entry->profile;
+	int val = profile->vals.v[entry->var];
+
+	seq_printf(s, "%d\n", val);
+	return 0;
+}
+
+static ssize_t dcqcn_param_write(struct file *fp, const char __user *ubuf,
+				 size_t count, loff_t *ppos)
+{
+	struct seq_file *s = fp->private_data;
+	struct ionic_dcqcn_param_entry *entry;
+	struct ionic_profile *profile;
+	int rc, val;
+	char *buf;
+
+	entry = s->private;
+	profile = entry->profile;
+
+	buf = memdup_user_nul(ubuf, count);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+
+	rc = kstrtoint(buf, 0, &val);
+	if (rc < 0)
+		goto out;
+
+	if (val < dcqcn_attrs[entry->var].min ||
+	    val > dcqcn_attrs[entry->var].max) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	profile->vals.v[entry->var] = val;
+
+	dcqcn_set_profile(profile);
+out:
+	kfree(buf);
+	return rc ?: count;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(dcqcn_param);
+
+static const struct ionic_profile_vals *dcqcn_get_defaults(int prof_i)
+{
+	if (prof_i < 0 || prof_i >= ARRAY_SIZE(dcqcn_defaults))
+		return &dcqcn_defaults[0];
+
+	return &dcqcn_defaults[prof_i];
+}
+
+static int dcqcn_match_default_show(struct seq_file *s, void *v)
+{
+	struct ionic_profile_root *profile_root = s->private;
+	int val = profile_root->profiles_default;
+
+	seq_printf(s, "%d\n", val);
+	return 0;
+}
+
+static ssize_t dcqcn_match_default_write(struct file *fp, const char __user *ubuf,
+					 size_t count, loff_t *ppos)
+{
+	struct ionic_profile_root *profile_root;
+	struct seq_file *s = fp->private_data;
+	int rc, val;
+	char *buf;
+
+	profile_root = s->private;
+
+	buf = memdup_user_nul(ubuf, count);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+
+	rc = kstrtoint(buf, 0, &val);
+	if (rc < 0)
+		goto out;
+
+	if (val < 0 || val > profile_root->profiles_count) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	profile_root->profiles_default = val;
+
+out:
+	kfree(buf);
+	return rc ?: count;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(dcqcn_match_default);
+
+static int dcqcn_match_rules_show(struct seq_file *s, void *v)
+{
+	struct ionic_profile_root *profile_root = s->private;
+	struct ionic_match_rule *rule, *rules;
+	unsigned long irqflags;
+	int i, rules_count;
+
+	spin_lock_irqsave(&profile_root->rules_lock, irqflags);
+
+	rules = profile_root->rules;
+	rules_count = profile_root->rules_count;
+	for (i = 0; i < rules_count; ++i) {
+		rule = &rules[i];
+		seq_printf(s, "%s %d %d\n", rule->name, rule->cond, rule->prof);
+	}
+
+	spin_unlock_irqrestore(&profile_root->rules_lock, irqflags);
+
+	return 0;
+}
+
+static bool ionic_match_prio(struct rdma_ah_attr *attr, int cond)
+{
+	int prio = attr->sl;
+
+	return prio >= 0 && prio < 8 && (cond & BIT(prio));
+}
+
+static bool ionic_match_gid(struct rdma_ah_attr *attr, int cond)
+{
+	int gid = rdma_ah_read_grh(attr)->sgid_index;
+
+	return gid == cond;
+}
+
+static bool ionic_parse_rule_name(const char *name, const char *buf, int count)
+{
+	return !strncmp(name, buf, count) && !name[count];
+}
+
+static int ionic_parse_match_rules(const char *buf, size_t count,
+				   int prof_count, int rules_count,
+				   struct ionic_match_rule *rules)
+{
+	bool (*match)(struct rdma_ah_attr *attr, int cond);
+	struct ionic_match_rule *rule;
+	int cmd, cond, prof, end;
+	int rc, rule_i = 0;
+	const char *name;
+
+	for (;; ++rule_i) {
+		/* skip leading whitespace */
+
+		rc = sscanf(buf, " %n", &end);
+		if (rc != 0)
+			return -EINVAL;
+
+		buf += end;
+		count -= end;
+
+		/* break at end of buffer */
+
+		if (!count)
+			break;
+
+		/* Parse one rule, as:
+		 * <name> <condition> <profile>
+		 *
+		 * Name and condition determine when a rule will be a match.
+		 * If a rule is a match, then use the inidcated DCQCN profile.
+		 *
+		 * If name eq "gid":
+		 * then condition is a gid index.
+		 *
+		 * eg: gid 5 3 -> for gid index 5, use profile 3.
+		 *
+		 * If name eq "prio":
+		 * then condition is a bitmask of 802.1p priorities.
+		 *
+		 * eg: prio 0xc 1 -> for 802.1p priority 2 or 3, use profile 1.
+		 */
+
+		rc = sscanf(buf, "%*s%n%i%i%n", &cmd, &cond, &prof, &end);
+		if (rc != 2)
+			return -EINVAL;
+
+		/* rule name in first `cmd` chars of `buf` */
+
+		if (ionic_parse_rule_name("gid", buf, cmd)) {
+			match = ionic_match_gid;
+			name = "gid";
+		} else if (ionic_parse_rule_name("prio", buf, cmd)) {
+			match = ionic_match_prio;
+			name = "prio";
+		} else {
+			return -EINVAL;
+		}
+
+		if (prof < 0 || prof > prof_count)
+			return -EINVAL;
+
+		if (rule_i < rules_count) {
+			rule = &rules[rule_i];
+			rule->match = match;
+			rule->name = name;
+			rule->cond = cond;
+			rule->prof = prof;
+		}
+
+		buf += end;
+		count -= end;
+	}
+
+	return rule_i;
+}
+
+static ssize_t dcqcn_match_rules_write(struct file *fp,
+				       const char __user *ubuf,
+				       size_t count, loff_t *ppos)
+{
+	struct ionic_profile_root *profile_root;
+	struct seq_file *s = fp->private_data;
+	unsigned long irqflags;
+	int rc, rules_count;
+	char *buf;
+
+	profile_root = s->private;
+
+	buf = memdup_user_nul(ubuf, count);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+
+	/* validate and count rules */
+	rc = ionic_parse_match_rules(buf, count, profile_root->profiles_count,
+				     0, NULL);
+	if (rc < 0)
+		goto out;
+
+	rules_count = rc;
+	rc = 0;
+
+	/* clear previous rules */
+	spin_lock_irqsave(&profile_root->rules_lock, irqflags);
+	profile_root->rules_count = 0;
+	spin_unlock_irqrestore(&profile_root->rules_lock, irqflags);
+
+	kfree(profile_root->rules);
+	profile_root->rules = NULL;
+
+	/* assign new rules */
+	if (rules_count) {
+		profile_root->rules = kzalloc_objs(*profile_root->rules,
+						   rules_count);
+		if (!profile_root->rules) {
+			rc = -ENOMEM;
+			goto out;
+		}
+
+		ionic_parse_match_rules(buf, count, profile_root->profiles_count,
+					rules_count, profile_root->rules);
+
+		spin_lock_irqsave(&profile_root->rules_lock, irqflags);
+		profile_root->rules_count = rules_count;
+		spin_unlock_irqrestore(&profile_root->rules_lock, irqflags);
+	}
+out:
+	kfree(buf);
+	return rc ?: count;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(dcqcn_match_rules);
+
+static ssize_t dcqcn_profile_reset(struct file *fp, const char __user *ubuf,
+				   size_t count, loff_t *ppos)
+{
+	struct ionic_profile *profile = fp->private_data;
+	int rc = 0;
+	char *buf;
+
+	buf = memdup_user_nul(ubuf, 2);
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+
+	if (strcmp(buf, "1") && strcmp(buf, "1\n")) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	profile->vals = *dcqcn_get_defaults(profile->idx);
+	dcqcn_set_profile(profile);
+
+out:
+	kfree(buf);
+	return rc ?: count;
+}
+
+static const struct file_operations dcqcn_profile_reset_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.write = dcqcn_profile_reset,
+};
+
+static void ionic_dcqcn_add_profile_params(struct ionic_profile *profile)
+{
+	struct ionic_dcqcn_param_entry *entry;
+	struct dentry *dentry;
+	int i;
+
+	for (i = 0; i < DCQCN_VAR_COUNT; i++) {
+		entry = &profile->entries[i];
+
+		entry->profile = profile;
+		entry->var = i;
+
+		if (i <= NP_CNP_DSCP)
+			dentry = profile->roce_np_debug;
+		else
+			dentry = profile->roce_rp_debug;
+
+		debugfs_create_file(dcqcn_attrs[i].name, 0640, dentry, entry,
+				    &dcqcn_param_fops);
+	}
+}
+
+int ionic_dcqcn_init(struct ionic_ibdev *dev, int prof_count)
+{
+	const enum ionic_profile_type type = IONIC_PROFILE_TYPE_DCQCN;
+	struct ionic_profile_root *profile_root;
+	int rc, i;
+
+	if (!prof_count)
+		return 0;
+
+	dev->profile[type] = kzalloc_obj(*dev->profile[type]);
+	if (!dev->profile[type]) {
+		rc = -ENOMEM;
+		goto err_cb_alloc;
+	}
+
+	profile_root = dev->profile[type];
+	profile_root->dev = dev;
+
+	spin_lock_init(&profile_root->rules_lock);
+
+	profile_root->debug = debugfs_create_dir("dcqcn", dev->debug);
+	if (IS_ERR(profile_root->debug)) {
+		profile_root->debug = NULL;
+		goto err_cb_dentry;
+	}
+
+	debugfs_create_file("match_default", 0640, profile_root->debug,
+			    profile_root, &dcqcn_match_default_fops);
+	debugfs_create_file("match_rules", 0640, profile_root->debug,
+			    profile_root, &dcqcn_match_rules_fops);
+
+	profile_root->profiles_debug = debugfs_create_dir("profiles",
+							  profile_root->debug);
+	if (IS_ERR(profile_root->profiles_debug)) {
+		profile_root->profiles_debug = NULL;
+		goto err_prof_dentry;
+	}
+
+	profile_root->profiles = kzalloc_objs(*profile_root->profiles,
+					      prof_count);
+	if (!profile_root->profiles) {
+		rc = -ENOMEM;
+		goto err_prof_alloc;
+	}
+
+	profile_root->profiles_default = 0;
+
+	for (i = 0; i < prof_count; ++i) {
+		struct ionic_profile *profile = &profile_root->profiles[i];
+		char name[8];
+
+		profile->dev = dev;
+		profile->vals = *dcqcn_get_defaults(i);
+		profile->idx = i;
+
+		dcqcn_set_profile(profile);
+
+		snprintf(name, sizeof(name), "%d", i + 1);
+		profile->debug = debugfs_create_dir(name,
+						 profile_root->profiles_debug);
+		if (IS_ERR(profile->debug)) {
+			profile->debug = NULL;
+			break;
+		}
+
+		debugfs_create_file("reset", 0640, profile->debug, profile,
+				    &dcqcn_profile_reset_fops);
+
+		profile->entries = kzalloc_objs(*profile->entries,
+						DCQCN_VAR_COUNT);
+
+		profile->roce_np_debug = debugfs_create_dir("roce_np",
+							    profile->debug);
+		if (IS_ERR(profile->roce_np_debug)) {
+			profile->roce_np_debug = NULL;
+			break;
+		}
+
+		profile->roce_rp_debug = debugfs_create_dir("roce_rp",
+							    profile->debug);
+		if (IS_ERR(profile->roce_rp_debug)) {
+			profile->roce_rp_debug = NULL;
+			break;
+		}
+
+		ionic_dcqcn_add_profile_params(profile);
+	}
+
+	if (!i)
+		goto err_prof_init;
+
+	profile_root->profiles_count = i;
+	if (i != prof_count) {
+		ibdev_warn(&dev->ibdev,
+			   "dcqcn initialized %d out of %d profiles\n",
+			   i, prof_count);
+	}
+	return 0;
+
+err_prof_init:
+	kfree(profile_root->profiles);
+err_prof_alloc:
+	debugfs_remove_recursive(profile_root->profiles_debug);
+err_prof_dentry:
+	debugfs_remove_recursive(profile_root->debug);
+err_cb_dentry:
+	kfree(dev->profile[type]);
+	dev->profile[type] = NULL;
+err_cb_alloc:
+	ibdev_warn(&dev->ibdev, "dcqcn failed init, error %d\n", rc);
+	return rc;
+}
+
+void ionic_dcqcn_destroy(struct ionic_ibdev *dev)
+{
+	struct ionic_profile_root *profile_root;
+	int i, prof_count;
+
+	profile_root = dev->profile[IONIC_PROFILE_TYPE_DCQCN];
+
+	if (!profile_root)
+		return;
+	prof_count = profile_root->profiles_count;
+	for (i = 0; i < prof_count; ++i) {
+		struct ionic_profile *profile;
+
+		profile = &profile_root->profiles[i];
+
+		kfree(profile->entries);
+		debugfs_remove_recursive(profile->debug);
+	}
+
+	debugfs_remove_recursive(profile_root->profiles_debug);
+	kfree(profile_root->rules);
+	kfree(profile_root->profiles);
+
+	debugfs_remove_recursive(profile_root->debug);
+
+	kfree(profile_root);
+	dev->profile[IONIC_PROFILE_TYPE_DCQCN] = NULL;
+}
+
+int ionic_dcqcn_select_profile(struct ionic_ibdev *dev,
+			       struct rdma_ah_attr *attr)
+{
+	struct ionic_profile_root *profile_root;
+	struct ionic_match_rule *rule, *rules;
+	int i, rules_count, prof;
+	unsigned long irqflags;
+
+	if (!dev->profile[IONIC_PROFILE_TYPE_DCQCN])
+		return 0;
+
+	profile_root = dev->profile[IONIC_PROFILE_TYPE_DCQCN];
+
+	spin_lock_irqsave(&profile_root->rules_lock, irqflags);
+
+	prof = profile_root->profiles_default;
+	rules = profile_root->rules;
+	rules_count = profile_root->rules_count;
+
+	for (i = 0; i < rules_count; ++i) {
+		rule = &rules[i];
+		if (rule->match(attr, rule->cond)) {
+			prof = rule->prof;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&profile_root->rules_lock, irqflags);
+
+	return prof;
+}
diff --git a/drivers/infiniband/hw/ionic/ionic_fw.h b/drivers/infiniband/hw/ionic/ionic_fw.h
index 0806c148faf2..eb463afe2305 100644
--- a/drivers/infiniband/hw/ionic/ionic_fw.h
+++ b/drivers/infiniband/hw/ionic/ionic_fw.h
@@ -838,6 +838,36 @@ struct ionic_admin_query_qp {
 static_assert(sizeof(struct ionic_admin_query_qp) ==
 	       IONIC_ADMIN_QUERY_QP_IN_V1_LEN);
 
+enum ionic_v1_dcqcn_flags {
+	IONIC_RPF_CLAMP_TGT_RATE	= BIT(0),
+	IONIC_RPF_CLAMP_TGT_RATE_ATI	= BIT(1),
+};
+
+struct ionic_admin_mod_dcqcn {
+	__u8		np_incp_802p_prio;
+	__u8		np_cnp_dscp;
+	__be16		rp_dce_tcp_g;
+	__be32		rp_dce_tcp_rtt;
+	__be32		rp_rate_reduce_monitor_period;
+	__be32		rp_rate_to_set_on_first_cnp;
+	__be32		rp_min_rate;
+	__be16		rp_initial_alpha_value;
+	__u8		rp_gd;
+	__u8		rp_min_dec_fac;
+	__u8		rp_clamp_flags;
+	__u8		rp_threshold;
+	__be16		rp_time_reset;
+	__be32		rp_qp_rate;
+	__be32		rp_byte_reset;
+	__be32		rp_ai_rate;
+	__be32		rp_hai_rate;
+	__le32		id_ver;
+	__be64		rp_token_bucket_size;
+} __packed;
+
+#define IONIC_ADMIN_MODIFY_DCQCN_IN_V1_LEN 56
+static_assert(sizeof(struct ionic_admin_mod_dcqcn) == IONIC_ADMIN_MODIFY_DCQCN_IN_V1_LEN);
+
 #define ADMIN_WQE_STRIDE	64
 #define ADMIN_WQE_HDR_LEN	4
 
@@ -860,6 +890,7 @@ struct ionic_v1_admin_wqe {
 		struct ionic_admin_destroy_qp destroy_qp;
 		struct ionic_admin_mod_qp mod_qp;
 		struct ionic_admin_query_qp query_qp;
+		struct ionic_admin_mod_dcqcn mod_dcqcn;
 	} cmd;
 };
 
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.c b/drivers/infiniband/hw/ionic/ionic_ibdev.c
index 69e6164e0f1e..2d89a4139d5a 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.c
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.c
@@ -290,6 +290,8 @@ static void ionic_destroy_resids(struct ionic_ibdev *dev)
 static void ionic_destroy_ibdev(struct ionic_ibdev *dev)
 {
 	ionic_kill_rdma_admin(dev, false);
+
+	ionic_dcqcn_destroy(dev);
 	ib_unregister_device(&dev->ibdev);
 	ionic_stats_cleanup(dev);
 	ionic_destroy_rdma_admin(dev);
@@ -357,6 +359,8 @@ static struct ionic_ibdev *ionic_create_ibdev(struct ionic_aux_dev *ionic_adev)
 	if (rc)
 		goto err_register;
 
+	ionic_dcqcn_init(dev, dev->lif_cfg.dcqcn_profiles);
+
 	return dev;
 
 err_register:
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.h b/drivers/infiniband/hw/ionic/ionic_ibdev.h
index 300d17882db5..cf909b14395a 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.h
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.h
@@ -74,6 +74,11 @@ enum ionic_mmap_flag {
 	IONIC_MMAP_WC = BIT(0),
 };
 
+enum ionic_profile_type {
+	IONIC_PROFILE_TYPE_DCQCN,
+	IONIC_PROFILE_TYPE_MAX,
+};
+
 struct ionic_mmap_entry {
 	struct rdma_user_mmap_entry rdma_entry;
 	unsigned long size;
@@ -123,6 +128,7 @@ struct ionic_ibdev {
 	struct dentry		*debug_qp;
 
 	int			hw_stats_count;
+	struct ionic_profile_root	*profile[IONIC_PROFILE_TYPE_MAX];
 };
 
 struct ionic_eq {
@@ -543,4 +549,10 @@ void ionic_dbg_rm_mr(struct ionic_mr *mr);
 void ionic_dbg_add_qp(struct ionic_ibdev *dev, struct ionic_qp *qp);
 void ionic_dbg_rm_qp(struct ionic_qp *qp);
 
+/* ionic_dcqcn.c */
+int ionic_dcqcn_init(struct ionic_ibdev *dev, int prof_count);
+void ionic_dcqcn_destroy(struct ionic_ibdev *dev);
+int ionic_dcqcn_select_profile(struct ionic_ibdev *dev,
+			       struct rdma_ah_attr *attr);
+
 #endif /* _IONIC_IBDEV_H_ */
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
index 53e41b1b3e8d..71aaf8d83f9c 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
@@ -93,6 +93,7 @@ void ionic_fill_lif_cfg(struct ionic_lif *lif, struct ionic_lif_cfg *cfg)
 	    !!(lif->qtype_info[IONIC_QTYPE_RXQ].features & IONIC_QIDENT_F_EXPDB);
 
 	cfg->dbg_ctx = lif->dentry;
+	cfg->dcqcn_profiles = ident->rdma.dcqcn_profiles;
 }
 
 struct net_device *ionic_lif_netdev(struct ionic_lif *lif)
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
index 500925c429f6..1e005400a0fa 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
@@ -58,6 +58,8 @@ struct ionic_lif_cfg {
 	bool sq_expdb;
 	bool rq_expdb;
 	u8 expdb_mask;
+
+	u8 dcqcn_profiles;
 };
 
 void ionic_fill_lif_cfg(struct ionic_lif *lif, struct ionic_lif_cfg *cfg);
diff --git a/drivers/infiniband/hw/ionic/ionic_profiles.h b/drivers/infiniband/hw/ionic/ionic_profiles.h
new file mode 100644
index 000000000000..a6cdd5992460
--- /dev/null
+++ b/drivers/infiniband/hw/ionic/ionic_profiles.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2018-2026, Advanced Micro Devices, Inc. */
+
+#ifndef _IONIC_PROFILES_H_
+#define _IONIC_PROFILES_H_
+
+#include "ionic_ibdev.h"
+
+enum ionic_dcqcn_var {
+	/* notification point */
+	NP_ICNP_802P_PRIO,		/* 0..7 (prio) */
+	NP_CNP_DSCP,			/* 0..63 (dscp) */
+
+	RP_TOKEN_BUCKET_SIZE,		/* 100..200000000 (100kb - 200gb) */
+	/* reaction point alpha update */
+	RP_INITIAL_ALPHA_VALUE,		/* 0..1023 */
+	RP_DCE_TCP_G,			/* 0..1023 */
+	RP_DCE_TCP_RTT,			/* 1..131071 (us) */
+
+	/* reaction point rate decrease */
+	RP_RATE_REDUCE_MONITOR_PERIOD,	/* 1.. (us) */
+	RP_RATE_TO_SET_ON_FIRST_CNP,	/* 0 disable, 1.. (Mbps) */
+	RP_MIN_RATE,			/* 1.. (Mbps) */
+	RP_GD,				/* 1..11 */
+	RP_MIN_DEC_FAC,			/* 0..100 (%) */
+
+	/* reaction point rate increase */
+	RP_CLAMP_TGT_RATE,		/* 0..1 (bool) */
+	RP_CLAMP_TGT_RATE_ATI,		/* 0..1 (bool) */
+	RP_THRESHOLD,			/* 1..31 */
+	RP_TIME_RESET,			/* 1..32767 (x RP_DCE_TCP_RTT) */
+	RP_QP_RATE,			/* 1.. (Mbps) */
+	RP_BYTE_RESET,			/* 1..4294967296 (B) */
+	RP_AI_RATE,			/* 1.. (Mbps) */
+	RP_HAI_RATE,			/* 1.. (Mbps) */
+
+	DCQCN_VAR_COUNT
+};
+
+struct ionic_match_rule {
+	bool			(*match)(struct rdma_ah_attr *attr, int cond);
+	const char		*name;
+	int			cond;
+	int			prof;
+};
+
+struct ionic_profile_vals {
+	int			v[DCQCN_VAR_COUNT];
+};
+
+struct ionic_dcqcn_param_attr {
+	char			*name;
+	int			min;
+	int			max;
+};
+
+struct ionic_dcqcn_param_entry {
+	struct ionic_profile	*profile;
+	enum ionic_dcqcn_var	var;
+};
+
+struct ionic_profile {
+	struct ionic_ibdev		*dev;
+	struct ionic_profile_vals	vals;
+	struct ionic_dcqcn_param_entry	*entries;
+	int idx;
+
+	struct dentry			*debug;
+	struct dentry			*roce_np_debug;
+	struct dentry			*roce_rp_debug;
+};
+
+struct ionic_profile_root {
+	struct ionic_ibdev	*dev;
+	int			profiles_default;
+	int			profiles_count;
+	struct ionic_profile	*profiles;
+	spinlock_t		rules_lock;	/* lock to atomic update the rules */
+	int			rules_count;
+	struct ionic_match_rule	*rules;
+
+	struct dentry		*debug;
+	struct dentry		*profiles_debug;
+};
+
+#endif /* _IONIC_PROFILES_H_ */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH net-next 0/4] RDMA/net/ionic: Misc updates
  2026-05-06  4:19 [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Eric Joyner
                   ` (3 preceding siblings ...)
  2026-05-06  4:19 ` [PATCH net-next 4/4] RDMA/ionic: Add DCQCN parameter configuration via debugfs Eric Joyner
@ 2026-05-06 22:59 ` Jakub Kicinski
  4 siblings, 0 replies; 6+ messages in thread
From: Jakub Kicinski @ 2026-05-06 22:59 UTC (permalink / raw)
  To: Eric Joyner
  Cc: netdev, linux-rdma, Brett Creeley, Andrew Lunn, David S. Miller,
	Eric Dumazet, Paolo Abeni, Abhijit Gangurde, Allen Hubbe,
	Jason Gunthorpe, Leon Romanovsky

On Tue, 5 May 2026 21:19:31 -0700 Eric Joyner wrote:
> Other smaller additions add a devlink parameter to the ionic ethernet
> driver for enabling and disabling RDMA,

My understanding is that the devlink param was expected to change 
the configuration of the device. IOW user can enable/disable RDMA
to save internal device resources. You seem to be purely preventing
the auxbus device to be added. So there's nothing gained here compared
to simply not loading the RDMA driver. What am I missing?

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-05-06 22:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-06  4:19 [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Eric Joyner
2026-05-06  4:19 ` [PATCH net-next 1/4] RDMA/ionic: Update copyright year to 2026 Eric Joyner
2026-05-06  4:19 ` [PATCH net-next 2/4] net/ionic: Add devlink parameter for RDMA Eric Joyner
2026-05-06  4:19 ` [PATCH net-next 3/4] RDMA/ionic: Add debugfs support Eric Joyner
2026-05-06  4:19 ` [PATCH net-next 4/4] RDMA/ionic: Add DCQCN parameter configuration via debugfs Eric Joyner
2026-05-06 22:59 ` [PATCH net-next 0/4] RDMA/net/ionic: Misc updates Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox