The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands
@ 2026-07-02  5:51 Pavan Chebbi
  2026-07-02  5:51 ` [PATCH v4 fwctl 1/3] fwctl: Add driver_data field to fwctl_rpc Pavan Chebbi
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Pavan Chebbi @ 2026-07-02  5:51 UTC (permalink / raw)
  To: jgg, michael.chan
  Cc: linux-kernel, dave.jiang, saeedm, jic23, gospo, selvin.xavier,
	leon, kalesh-anakkur.purayil, Pavan Chebbi

Several HWRM (HardWare Resource Manager) commands used for diagnostics,
firmware management, and NVM access carry one or more DMA address fields
in their input structures.  Until now these commands could not be issued
through the fwctl interface because the driver had no mechanism to safely
broker the host-side DMA buffers on userspace's behalf.

This series adds that mechanism in three steps.

In patch #1, the fwctl core UAPI adds a new driver_data field in struct
fwctl_rpc.  Drivers that need a driver_data payload receive the value and
are free to interpret it. Drivers that do not define one will reject any
non-zero value with -EOPNOTSUPP.  Existing mlx5 and pds fwctl drivers are
updated accordingly.

In patch #2, the bnxt HSI header is updated to add the missing struct
definitions for the HWRM commands that the bnxt fwctl driver will support.

In patch #3, the bnxt fwctl driver consumes driver_data as a pointer to
a new bnxt UAPI struct fwctl_bnxt_driver_data, which describes indirect
DMA buffers.

v4: Collected Rb tag from Dave for patch #1. Thanks Dave

v3: In patch #3, remove include of linux/sizes.h from UAPI header bnxt.h

v2: In patch #1, update all the drivers that implement fw_rpc to check
driver_data. In patch #2, add another HWRM command that I had missed in v1.
In patch #3, update the allow-list and timeout tables for the additional
commands.

Pavan Chebbi (3):
  fwctl: Add driver_data field to fwctl_rpc
  bnxt_en: Update bnxt firmware spec
  fwctl/bnxt: add DMA buffer support for HWRM commands

 drivers/cxl/core/features.c |   6 +-
 drivers/fwctl/bnxt/main.c   | 340 ++++++++++++++++++++-
 drivers/fwctl/main.c        |   3 +-
 drivers/fwctl/mlx5/main.c   |   6 +-
 drivers/fwctl/pds/main.c    |   6 +-
 include/linux/bnxt/hsi.h    | 585 ++++++++++++++++++++++++++++++++++++
 include/linux/fwctl.h       |   8 +-
 include/uapi/fwctl/bnxt.h   |  37 +++
 include/uapi/fwctl/fwctl.h  |   3 +
 9 files changed, 986 insertions(+), 8 deletions(-)

-- 
2.52.0


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

* [PATCH v4 fwctl 1/3] fwctl: Add driver_data field to fwctl_rpc
  2026-07-02  5:51 [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands Pavan Chebbi
@ 2026-07-02  5:51 ` Pavan Chebbi
  2026-07-02  5:51 ` [PATCH v4 fwctl 2/3] bnxt_en: Update bnxt firmware spec Pavan Chebbi
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Pavan Chebbi @ 2026-07-02  5:51 UTC (permalink / raw)
  To: jgg, michael.chan
  Cc: linux-kernel, dave.jiang, saeedm, jic23, gospo, selvin.xavier,
	leon, kalesh-anakkur.purayil, Pavan Chebbi

Add a driver_data field to struct fwctl_rpc in the UAPI and thread the
value through the fw_rpc() ops callback as a new __u64 parameter.  The
field is opaque and driver-defined.

Drivers that do not define a driver_data format may return -EOPNOTSUPP.
Update the existing drivers' fw_rpc implementations to enforce this.

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
---
 drivers/cxl/core/features.c | 6 +++++-
 drivers/fwctl/bnxt/main.c   | 6 +++++-
 drivers/fwctl/main.c        | 3 ++-
 drivers/fwctl/mlx5/main.c   | 6 +++++-
 drivers/fwctl/pds/main.c    | 6 +++++-
 include/linux/fwctl.h       | 8 ++++++--
 include/uapi/fwctl/fwctl.h  | 3 +++
 7 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/drivers/cxl/core/features.c b/drivers/cxl/core/features.c
index 3435db9ea6b1..a0d7f26c5b6d 100644
--- a/drivers/cxl/core/features.c
+++ b/drivers/cxl/core/features.c
@@ -643,7 +643,8 @@ static void *cxlctl_handle_commands(struct cxl_features_state *cxlfs,
 }
 
 static void *cxlctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
-			   void *in, size_t in_len, size_t *out_len)
+			   void *in, size_t in_len, size_t *out_len,
+			   __u64 driver_data)
 {
 	struct fwctl_device *fwctl_dev = uctx->fwctl;
 	struct cxl_memdev *cxlmd = fwctl_to_memdev(fwctl_dev);
@@ -651,6 +652,9 @@ static void *cxlctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
 	const struct fwctl_rpc_cxl *rpc_in = in;
 	u16 opcode = rpc_in->opcode;
 
+	if (driver_data)
+		return ERR_PTR(-EOPNOTSUPP);
+
 	if (!cxlctl_validate_hw_command(cxlfs, rpc_in, scope, opcode))
 		return ERR_PTR(-EINVAL);
 
diff --git a/drivers/fwctl/bnxt/main.c b/drivers/fwctl/bnxt/main.c
index 951c8ac2e0a1..5eb3651a1784 100644
--- a/drivers/fwctl/bnxt/main.c
+++ b/drivers/fwctl/bnxt/main.c
@@ -172,7 +172,8 @@ static unsigned int bnxtctl_get_timeout(struct input *req)
 
 static void *bnxtctl_fw_rpc(struct fwctl_uctx *uctx,
 			    enum fwctl_rpc_scope scope,
-			    void *in, size_t in_len, size_t *out_len)
+			    void *in, size_t in_len, size_t *out_len,
+			    __u64 driver_data)
 {
 	struct bnxtctl_dev *bnxtctl =
 		container_of(uctx->fwctl, struct bnxtctl_dev, fwctl);
@@ -180,6 +181,9 @@ static void *bnxtctl_fw_rpc(struct fwctl_uctx *uctx,
 	struct bnxt_fw_msg rpc_in = {0};
 	int rc;
 
+	if (driver_data)
+		return ERR_PTR(-EOPNOTSUPP);
+
 	if (in_len < sizeof(struct input) || in_len > HWRM_MAX_REQ_LEN)
 		return ERR_PTR(-EINVAL);
 
diff --git a/drivers/fwctl/main.c b/drivers/fwctl/main.c
index 098c3824ad75..32c4c66dd7d5 100644
--- a/drivers/fwctl/main.c
+++ b/drivers/fwctl/main.c
@@ -122,7 +122,8 @@ static int fwctl_cmd_rpc(struct fwctl_ucmd *ucmd)
 
 	out_len = cmd->out_len;
 	void *outbuf __free(kvfree) = fwctl->ops->fw_rpc(
-		ucmd->uctx, cmd->scope, inbuf, cmd->in_len, &out_len);
+		ucmd->uctx, cmd->scope, inbuf, cmd->in_len, &out_len,
+		cmd->driver_data);
 	if (IS_ERR(outbuf))
 		return PTR_ERR(outbuf);
 	if (outbuf == inbuf) {
diff --git a/drivers/fwctl/mlx5/main.c b/drivers/fwctl/mlx5/main.c
index e86ab703c767..2a5105769126 100644
--- a/drivers/fwctl/mlx5/main.c
+++ b/drivers/fwctl/mlx5/main.c
@@ -304,7 +304,8 @@ static bool mlx5ctl_validate_rpc(const void *in, enum fwctl_rpc_scope scope)
 }
 
 static void *mlx5ctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
-			    void *rpc_in, size_t in_len, size_t *out_len)
+			    void *rpc_in, size_t in_len, size_t *out_len,
+			    __u64 driver_data)
 {
 	struct mlx5ctl_dev *mcdev =
 		container_of(uctx->fwctl, struct mlx5ctl_dev, fwctl);
@@ -313,6 +314,9 @@ static void *mlx5ctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
 	void *rpc_out;
 	int ret;
 
+	if (driver_data)
+		return ERR_PTR(-EOPNOTSUPP);
+
 	if (in_len < MLX5_ST_SZ_BYTES(mbox_in_hdr) ||
 	    *out_len < MLX5_ST_SZ_BYTES(mbox_out_hdr))
 		return ERR_PTR(-EMSGSIZE);
diff --git a/drivers/fwctl/pds/main.c b/drivers/fwctl/pds/main.c
index 08872ee8422f..bb61e60843cf 100644
--- a/drivers/fwctl/pds/main.c
+++ b/drivers/fwctl/pds/main.c
@@ -348,7 +348,8 @@ static int pdsfc_validate_rpc(struct pdsfc_dev *pdsfc,
 }
 
 static void *pdsfc_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
-			  void *in, size_t in_len, size_t *out_len)
+			  void *in, size_t in_len, size_t *out_len,
+			  __u64 driver_data)
 {
 	struct pdsfc_dev *pdsfc = container_of(uctx->fwctl, struct pdsfc_dev, fwctl);
 	struct device *dev = &uctx->fwctl->dev;
@@ -362,6 +363,9 @@ static void *pdsfc_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
 	void *out = NULL;
 	int err;
 
+	if (driver_data)
+		return ERR_PTR(-EOPNOTSUPP);
+
 	err = pdsfc_validate_rpc(pdsfc, rpc, scope);
 	if (err)
 		return ERR_PTR(err);
diff --git a/include/linux/fwctl.h b/include/linux/fwctl.h
index 5d61fc8a6871..afb7f72d0cb1 100644
--- a/include/linux/fwctl.h
+++ b/include/linux/fwctl.h
@@ -51,10 +51,14 @@ struct fwctl_ops {
 	 * @fw_rpc: Implement FWCTL_RPC. Deliver rpc_in/in_len to the FW and
 	 * return the response and set out_len. rpc_in can be returned as the
 	 * response pointer. Otherwise the returned pointer is freed with
-	 * kvfree().
+	 * kvfree(). driver_data is the opaque value from fwctl_rpc, passed
+	 * verbatim from userspace. The driver is responsible for interpreting
+	 * and validating it. Drivers that do not define a driver_data format
+	 * must return -EOPNOTSUPP if driver_data is non-zero.
 	 */
 	void *(*fw_rpc)(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
-			void *rpc_in, size_t in_len, size_t *out_len);
+			void *rpc_in, size_t in_len, size_t *out_len,
+			__u64 driver_data);
 };
 
 /**
diff --git a/include/uapi/fwctl/fwctl.h b/include/uapi/fwctl/fwctl.h
index 2d6d4049c205..2e07425402a3 100644
--- a/include/uapi/fwctl/fwctl.h
+++ b/include/uapi/fwctl/fwctl.h
@@ -120,6 +120,8 @@ enum fwctl_rpc_scope {
  * @out_len: Length of the out memory
  * @in: Request message in device specific format
  * @out: Response message in device specific format
+ * @driver_data: Opaque userspace pointer passed verbatim to the driver.
+ *   Must be 0 for drivers that do not define a driver_data format.
  *
  * Deliver a Remote Procedure Call to the device FW and return the response. The
  * call's parameters and return are marshaled into linear buffers of memory. Any
@@ -136,6 +138,7 @@ struct fwctl_rpc {
 	__u32 out_len;
 	__aligned_u64 in;
 	__aligned_u64 out;
+	__aligned_u64 driver_data;
 };
 #define FWCTL_RPC _IO(FWCTL_TYPE, FWCTL_CMD_RPC)
 
-- 
2.52.0


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

* [PATCH v4 fwctl 2/3] bnxt_en: Update bnxt firmware spec
  2026-07-02  5:51 [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands Pavan Chebbi
  2026-07-02  5:51 ` [PATCH v4 fwctl 1/3] fwctl: Add driver_data field to fwctl_rpc Pavan Chebbi
@ 2026-07-02  5:51 ` Pavan Chebbi
  2026-07-02  5:51 ` [PATCH v4 fwctl 3/3] fwctl/bnxt: add DMA buffer support for HWRM commands Pavan Chebbi
  2026-07-03 17:51 ` [PATCH v4 fwctl 0/3] fwctl/bnxt: " Jason Gunthorpe
  3 siblings, 0 replies; 6+ messages in thread
From: Pavan Chebbi @ 2026-07-02  5:51 UTC (permalink / raw)
  To: jgg, michael.chan
  Cc: linux-kernel, dave.jiang, saeedm, jic23, gospo, selvin.xavier,
	leon, kalesh-anakkur.purayil, Pavan Chebbi

Since bnxt_fwctl is going to support additional commands in the next
patch,  add their missing definitions from the firmware spec.

Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
---
 include/linux/bnxt/hsi.h | 585 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 585 insertions(+)

diff --git a/include/linux/bnxt/hsi.h b/include/linux/bnxt/hsi.h
index 74a6bf278d88..2f17dbd02185 100644
--- a/include/linux/bnxt/hsi.h
+++ b/include/linux/bnxt/hsi.h
@@ -191,6 +191,8 @@ struct cmd_nums {
 	#define HWRM_PORT_EVENTS_LOG                      0x67UL
 	#define HWRM_VNIC_RSS_COS_LB_CTX_ALLOC            0x70UL
 	#define HWRM_VNIC_RSS_COS_LB_CTX_FREE             0x71UL
+	#define HWRM_SCH_GRP_CFG                          0x73UL
+	#define HWRM_SCH_GRP_QCFG                         0x74UL
 	#define HWRM_QUEUE_MPLS_QCAPS                     0x80UL
 	#define HWRM_QUEUE_MPLSTC2PRI_QCFG                0x81UL
 	#define HWRM_QUEUE_MPLSTC2PRI_CFG                 0x82UL
@@ -4911,6 +4913,29 @@ struct hwrm_port_phy_qcfg_output {
 	u8	valid;
 };
 
+/* hwrm_port_events_log_input (size:256b/32B) */
+struct hwrm_port_events_log_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le64	host_dest_addr;
+	__le32	host_dest_addr_len;
+	u8	unused_0[4];
+};
+
+/* hwrm_port_events_log_output (size:128b/16B) */
+struct hwrm_port_events_log_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	data_len;
+	u8	unused_0[5];
+	u8	valid;
+};
+
 /* hwrm_port_mac_cfg_input (size:448b/56B) */
 struct hwrm_port_mac_cfg_input {
 	__le16	req_type;
@@ -5418,6 +5443,40 @@ struct port_stats_ecn {
 	__le64	mark_cnt_cos7;
 };
 
+/* port_stats_ext_pfc_adv (size:1536b/192B) */
+struct port_stats_ext_pfc_adv {
+	__le64	pfc_min_duration_time[8];
+	__le64	pfc_max_duration_time[8];
+	__le64	pfc_weighted_duration_time[8];
+};
+
+/* hwrm_port_qstats_ext_pfc_adv_input (size:320b/40B) */
+struct hwrm_port_qstats_ext_pfc_adv_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le16	port_id;
+	__le16	pfc_adv_stat_size;
+	u8	flags;
+	#define PORT_QSTATS_EXT_PFC_ADV_REQ_FLAGS_COUNTER_MASK     0x1UL
+	u8	unused_0[3];
+	__le64	tx_pfc_adv_stat_host_addr;
+	__le64	rx_pfc_adv_stat_host_addr;
+};
+
+/* hwrm_port_qstats_ext_pfc_adv_output (size:128b/16B) */
+struct hwrm_port_qstats_ext_pfc_adv_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	pfc_adv_stat_size;
+	u8	unused_0[5];
+	u8	valid;
+};
+
 /* hwrm_port_clr_stats_input (size:192b/24B) */
 struct hwrm_port_clr_stats_input {
 	__le16	req_type;
@@ -6095,6 +6154,61 @@ struct hwrm_port_led_qcaps_output {
 	u8	valid;
 };
 
+/* hwrm_port_prbs_test_input (size:384b/48B) */
+struct hwrm_port_prbs_test_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le64	resp_data_addr;
+	__le16	data_len;
+	__le16	flags;
+	#define PORT_PRBS_TEST_REQ_FLAGS_INTERNAL     0x1UL
+	__le32	unused_1;
+	__le16	port_id;
+	__le16	poly;
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS7   0x0UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS9   0x1UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS11  0x2UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS15  0x3UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS23  0x4UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS31  0x5UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS58  0x6UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS49  0x7UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS10  0x8UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS20  0x9UL
+	#define PORT_PRBS_TEST_REQ_POLY_PRBS13  0xaUL
+	#define PORT_PRBS_TEST_REQ_POLY_INVALID 0xffUL
+	#define PORT_PRBS_TEST_REQ_POLY_LAST   PORT_PRBS_TEST_REQ_POLY_INVALID
+	__le16	prbs_config;
+	#define PORT_PRBS_TEST_REQ_PRBS_CONFIG_START_STOP            0x1UL
+	#define PORT_PRBS_TEST_REQ_PRBS_CONFIG_TX_LANE_MAP_VALID     0x2UL
+	#define PORT_PRBS_TEST_REQ_PRBS_CONFIG_RX_LANE_MAP_VALID     0x4UL
+	#define PORT_PRBS_TEST_REQ_PRBS_CONFIG_FEC_STAT_T0_T7        0x8UL
+	#define PORT_PRBS_TEST_REQ_PRBS_CONFIG_FEC_STAT_T8_T15       0x10UL
+	#define PORT_PRBS_TEST_REQ_PRBS_CONFIG_T_CODE                0x20UL
+	__le16	timeout;
+	__le32	tx_lane_map;
+	__le32	rx_lane_map;
+};
+
+/* hwrm_port_prbs_test_output (size:128b/16B) */
+struct hwrm_port_prbs_test_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	total_data_len;
+	u8	ber_format;
+	#define PORT_PRBS_TEST_RESP_BER_FORMAT_PRBS 0x0UL
+	#define PORT_PRBS_TEST_RESP_BER_FORMAT_FEC  0x1UL
+	#define PORT_PRBS_TEST_RESP_BER_FORMAT_LAST PORT_PRBS_TEST_RESP_BER_FORMAT_FEC
+	u8	unused_0;
+	u8	unused_1[3];
+	u8	valid;
+};
+
 /* hwrm_port_phy_fdrstat_input (size:192b/24B) */
 struct hwrm_port_phy_fdrstat_input {
 	__le16	req_type;
@@ -6147,6 +6261,54 @@ struct hwrm_port_phy_fdrstat_cmd_err {
 	u8	unused_0[7];
 };
 
+/* hwrm_port_dsc_dump_input (size:320b/40B) */
+struct hwrm_port_dsc_dump_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le64	resp_data_addr;
+	__le16	data_len;
+	__le16	unused_0;
+	__le32	data_offset;
+	__le16	port_id;
+	__le16	diag_level;
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_LANE       0x0UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_CORE       0x1UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_EVENT      0x2UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_EYE        0x3UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_REG_CORE   0x4UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_REG_LANE   0x5UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_UC_CORE    0x6UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_UC_LANE    0x7UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_LANE_DEBUG 0x8UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_BER_VERT   0x9UL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_BER_HORZ   0xaUL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_EVENT_SAFE 0xbUL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_TIMESTAMP  0xcUL
+	#define PORT_DSC_DUMP_REQ_DIAG_LEVEL_LAST                PORT_DSC_DUMP_REQ_DIAG_LEVEL_SRDS_DIAG_TIMESTAMP
+	__le16	lane_number;
+	__le16	dsc_dump_config;
+	#define PORT_DSC_DUMP_REQ_DSC_DUMP_CONFIG_START_RETRIEVE     0x1UL
+	#define PORT_DSC_DUMP_REQ_DSC_DUMP_CONFIG_BIG_BUFFER         0x2UL
+	#define PORT_DSC_DUMP_REQ_DSC_DUMP_CONFIG_DEFER_CLOSE        0x4UL
+};
+
+/* hwrm_port_dsc_dump_output (size:128b/16B) */
+struct hwrm_port_dsc_dump_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	total_data_len;
+	__le16	total_data_len_high;
+	u8	unused_1[2];
+	u8	flags;
+	#define PORT_DSC_DUMP_RESP_FLAGS_BIG_BUFFER     0x1UL
+	u8	valid;
+};
+
 /* hwrm_port_mac_qcaps_input (size:192b/24B) */
 struct hwrm_port_mac_qcaps_input {
 	__le16	req_type;
@@ -9559,6 +9721,62 @@ struct hwrm_stat_generic_qstats_output {
 	u8	valid;
 };
 
+/* hwrm_stat_query_roce_stats_input (size:256b/32B) */
+struct hwrm_stat_query_roce_stats_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le16	roce_stat_size;
+	u8	flags;
+	#define STAT_QUERY_ROCE_STATS_REQ_FLAGS_PORT_AGGREGATED     0x1UL
+	u8	port_id;
+	u8	unused_0[4];
+	__le64	roce_stat_host_addr;
+};
+
+/* hwrm_stat_query_roce_stats_output (size:128b/16B) */
+struct hwrm_stat_query_roce_stats_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	roce_stat_size;
+	u8	flags;
+	#define STAT_QUERY_ROCE_STATS_RESP_FLAGS_PORT_AGGREGATED     0x1UL
+	u8	unused_0[4];
+	u8	valid;
+};
+
+/* hwrm_stat_query_roce_stats_ext_input (size:256b/32B) */
+struct hwrm_stat_query_roce_stats_ext_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le16	roce_stat_size;
+	u8	flags;
+	#define STAT_QUERY_ROCE_STATS_EXT_REQ_FLAGS_PORT_AGGREGATED     0x1UL
+	u8	port_id;
+	u8	unused_0[4];
+	__le64	roce_stat_host_addr;
+};
+
+/* hwrm_stat_query_roce_stats_ext_output (size:128b/16B) */
+struct hwrm_stat_query_roce_stats_ext_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	roce_stat_size;
+	u8	flags;
+	#define STAT_QUERY_ROCE_STATS_EXT_RESP_FLAGS_PORT_AGGREGATED     0x1UL
+	u8	unused_0[4];
+	u8	valid;
+};
+
 /* generic_sw_hw_stats (size:1472b/184B) */
 struct generic_sw_hw_stats {
 	__le64	pcie_statistics_tx_tlp;
@@ -10207,6 +10425,57 @@ struct hwrm_dbg_read_direct_output {
 	u8	valid;
 };
 
+/* hwrm_dbg_read_indirect_input (size:640b/80B) */
+struct hwrm_dbg_read_indirect_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le64	host_dest_addr;
+	__le32	host_dest_addr_len;
+	u8	indirect_access_type;
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_TE_MGMT_FILTERS_L2         0x0UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_TE_MGMT_FILTERS_L3L4       0x1UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_RE_MGMT_FILTERS_L2         0x2UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_RE_MGMT_FILTERS_L3L4       0x3UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_STAT_CTXS                  0x4UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_TX_L2_TCAM             0x5UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_RX_L2_TCAM             0x6UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_TX_IPV6_SUBNET_TCAM    0x7UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_RX_IPV6_SUBNET_TCAM    0x8UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_TX_SRC_PROPERTIES_TCAM 0x9UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_RX_SRC_PROPERTIES_TCAM 0xaUL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_VEB_LOOKUP_TCAM        0xbUL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_TX_PROFILE_LOOKUP_TCAM 0xcUL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_RX_PROFILE_LOOKUP_TCAM 0xdUL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_TX_LOOKUP_TCAM         0xeUL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CFA_RX_LOOKUP_TCAM         0xfUL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_MHB                        0x10UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_PCIE_GBL                   0x11UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_MULTI_HOST_SOC             0x12UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_PCIE_PRIVATE               0x13UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_HOST_DMA                   0x14UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_SOC_ELOG                   0x15UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_CTX                        0x16UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_STATS                      0x17UL
+	#define DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_LAST      DBG_READ_INDIRECT_REQ_INDIRECT_ACCESS_TYPE_STATS
+	u8	unused_0[3];
+	__le32	start_index;
+	__le32	num_of_entries;
+	__le32	opaque[10];
+};
+
+/* hwrm_dbg_read_indirect_output (size:128b/16B) */
+struct hwrm_dbg_read_indirect_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	u8	unused_0[7];
+	u8	valid;
+};
+
 /* hwrm_dbg_qcaps_input (size:192b/24B) */
 struct hwrm_dbg_qcaps_input {
 	__le16	req_type;
@@ -10518,6 +10787,154 @@ struct hwrm_dbg_log_buffer_flush_output {
 	u8	valid;
 };
 
+/* hwrm_dbg_serdes_test_input (size:320b/40B) */
+struct hwrm_dbg_serdes_test_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le64	resp_data_addr;
+	__le32	resp_data_offset;
+	__le16	data_len;
+	u8	flags;
+	#define DBG_SERDES_TEST_REQ_FLAGS_UNUSED_TEST_MASK         0x7UL
+	#define DBG_SERDES_TEST_REQ_FLAGS_UNUSED_TEST_SFT          0
+	#define DBG_SERDES_TEST_REQ_FLAGS_EYE_PROJECTION           0x8UL
+	#define DBG_SERDES_TEST_REQ_FLAGS_PCIE_SERDES_TEST         0x10UL
+	#define DBG_SERDES_TEST_REQ_FLAGS_ETHERNET_SERDES_TEST     0x20UL
+	u8	options;
+	#define DBG_SERDES_TEST_REQ_OPTIONS_LANE_NO_MASK          0xfUL
+	#define DBG_SERDES_TEST_REQ_OPTIONS_LANE_NO_SFT           0
+	#define DBG_SERDES_TEST_REQ_OPTIONS_DIRECTION             0x10UL
+	#define DBG_SERDES_TEST_REQ_OPTIONS_DIRECTION_HORIZONTAL    (0x0UL << 4)
+	#define DBG_SERDES_TEST_REQ_OPTIONS_DIRECTION_VERTICAL      (0x1UL << 4)
+	#define DBG_SERDES_TEST_REQ_OPTIONS_DIRECTION_LAST         DBG_SERDES_TEST_REQ_OPTIONS_DIRECTION_VERTICAL
+	#define DBG_SERDES_TEST_REQ_OPTIONS_PROJ_TYPE             0x20UL
+	#define DBG_SERDES_TEST_REQ_OPTIONS_PROJ_TYPE_LEFT_TOP      (0x0UL << 5)
+	#define DBG_SERDES_TEST_REQ_OPTIONS_PROJ_TYPE_RIGHT_BOTTOM  (0x1UL << 5)
+	#define DBG_SERDES_TEST_REQ_OPTIONS_PROJ_TYPE_LAST         DBG_SERDES_TEST_REQ_OPTIONS_PROJ_TYPE_RIGHT_BOTTOM
+	#define DBG_SERDES_TEST_REQ_OPTIONS_RSVD_MASK             0xc0UL
+	#define DBG_SERDES_TEST_REQ_OPTIONS_RSVD_SFT              6
+	u8	targetBER;
+	#define DBG_SERDES_TEST_REQ_TARGETBER_BER_1E8  0x0UL
+	#define DBG_SERDES_TEST_REQ_TARGETBER_BER_1E9  0x1UL
+	#define DBG_SERDES_TEST_REQ_TARGETBER_BER_1E10 0x2UL
+	#define DBG_SERDES_TEST_REQ_TARGETBER_BER_1E11 0x3UL
+	#define DBG_SERDES_TEST_REQ_TARGETBER_BER_1E12 0x4UL
+	#define DBG_SERDES_TEST_REQ_TARGETBER_LAST    DBG_SERDES_TEST_REQ_TARGETBER_BER_1E12
+	u8	action;
+	#define DBG_SERDES_TEST_REQ_ACTION_SYNCHRONOUS 0x0UL
+	#define DBG_SERDES_TEST_REQ_ACTION_START       0x1UL
+	#define DBG_SERDES_TEST_REQ_ACTION_PROGRESS    0x2UL
+	#define DBG_SERDES_TEST_REQ_ACTION_STOP        0x3UL
+	#define DBG_SERDES_TEST_REQ_ACTION_LAST       DBG_SERDES_TEST_REQ_ACTION_STOP
+	u8	unused[6];
+};
+
+/* hwrm_dbg_serdes_test_output (size:192b/24B) */
+struct hwrm_dbg_serdes_test_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	total_data_len;
+	__le16	copied_data_len;
+	__le16	progress_percent;
+	__le16	timeout;
+	u8	flags;
+	#define DBG_SERDES_TEST_RESP_FLAGS_BIT_COUNT_TYPE                0x1UL
+	#define DBG_SERDES_TEST_RESP_FLAGS_BIT_COUNT_TYPE_BIT_COUNT_TOTAL  (0x0UL << 0)
+	#define DBG_SERDES_TEST_RESP_FLAGS_BIT_COUNT_TYPE_BIT_COUNT_POW2   (0x1UL << 0)
+	#define DBG_SERDES_TEST_RESP_FLAGS_BIT_COUNT_TYPE_LAST            DBG_SERDES_TEST_RESP_FLAGS_BIT_COUNT_TYPE_BIT_COUNT_POW2
+	#define DBG_SERDES_TEST_RESP_FLAGS_RSVD_MASK                     0xfeUL
+	#define DBG_SERDES_TEST_RESP_FLAGS_RSVD_SFT                      1
+	u8	unused_0;
+	__le16	hdr_size;
+	u8	unused_1[3];
+	u8	valid;
+};
+
+/* hwrm_dbg_ptrace_input (size:320b/40B) */
+struct hwrm_dbg_ptrace_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le32	pdi_cmd_buf_addr[2];
+	__le32	pdi_resp_buf_addr[2];
+	__le32	pdi_req_buf_len;
+	__le16	seq_no;
+	__le16	flags;
+	#define DBG_PTRACE_REQ_FLAGS_SELECT_IN        0x1UL
+	#define DBG_PTRACE_REQ_FLAGS_SELECT_OUT       0x2UL
+	#define DBG_PTRACE_REQ_FLAGS_GLOBAL_START     0x4UL
+	#define DBG_PTRACE_REQ_FLAGS_GLOBAL_STOP      0x8UL
+};
+
+/* hwrm_dbg_ptrace_output (size:128b/16B) */
+struct hwrm_dbg_ptrace_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	flags;
+	#define DBG_PTRACE_RESP_FLAGS_MORE     0x1UL
+	__le16	data_len;
+	u8	unused_0[3];
+	u8	valid;
+};
+
+/* hwrm_dbg_token_cfg_input (size:256b/32B) */
+struct hwrm_dbg_token_cfg_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	u8	flags;
+	#define DBG_TOKEN_CFG_REQ_FLAGS_ENABLE     0x1UL
+	u8	unused_0[3];
+	__le32	dbg_token_len;
+	__le64	host_src_addr;
+};
+
+/* hwrm_dbg_token_cfg_output (size:128b/16B) */
+struct hwrm_dbg_token_cfg_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	u8	unused_0[7];
+	u8	valid;
+};
+
+/* hwrm_nvm_raw_write_blk_input (size:320b/40B) */
+struct hwrm_nvm_raw_write_blk_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le64	host_src_addr;
+	__le32	dest_addr;
+	__le32	len;
+	u8	flags;
+	#define NVM_RAW_WRITE_BLK_REQ_FLAGS_SECURITY_SOC_NVM     0x1UL
+	u8	unused_0[7];
+};
+
+/* hwrm_nvm_raw_write_blk_output (size:128b/16B) */
+struct hwrm_nvm_raw_write_blk_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	u8	unused_0[7];
+	u8	valid;
+};
+
 /* hwrm_nvm_read_input (size:320b/40B) */
 struct hwrm_nvm_read_input {
 	__le16	req_type;
@@ -10543,6 +10960,31 @@ struct hwrm_nvm_read_output {
 	u8	valid;
 };
 
+/* hwrm_nvm_raw_dump_input (size:320b/40B) */
+struct hwrm_nvm_raw_dump_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le64	host_dest_addr;
+	__le32	offset;
+	__le32	len;
+	u8	flags;
+	#define NVM_RAW_DUMP_REQ_FLAGS_SECURITY_SOC_NVM     0x1UL
+	u8	unused_0[7];
+};
+
+/* hwrm_nvm_raw_dump_output (size:128b/16B) */
+struct hwrm_nvm_raw_dump_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	u8	unused_0[7];
+	u8	valid;
+};
+
 /* hwrm_nvm_get_dir_entries_input (size:192b/24B) */
 struct hwrm_nvm_get_dir_entries_input {
 	__le16	req_type;
@@ -11166,6 +11608,149 @@ struct hwrm_selftest_irq_output {
 	u8	valid;
 };
 
+/* hwrm_selftest_retrieve_serdes_data_input (size:320b/40B) */
+struct hwrm_selftest_retrieve_serdes_data_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le64	resp_data_addr;
+	__le32	resp_data_offset;
+	__le16	data_len;
+	u8	flags;
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_FLAGS_UNUSED_TEST_MASK         0x7UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_FLAGS_UNUSED_TEST_SFT          0
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_FLAGS_EYE_PROJECTION           0x8UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_FLAGS_PCIE_SERDES_TEST         0x10UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_FLAGS_ETHERNET_SERDES_TEST     0x20UL
+	u8	options;
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_PCIE_LANE_NO_MASK     0xfUL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_PCIE_LANE_NO_SFT      0
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_DIRECTION             0x10UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_DIRECTION_HORIZONTAL    (0x0UL << 4)
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_DIRECTION_VERTICAL      (0x1UL << 4)
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_DIRECTION_LAST         SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_DIRECTION_VERTICAL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_PROJ_TYPE             0x20UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_PROJ_TYPE_LEFT_TOP      (0x0UL << 5)
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_PROJ_TYPE_RIGHT_BOTTOM  (0x1UL << 5)
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_PROJ_TYPE_LAST         SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_PROJ_TYPE_RIGHT_BOTTOM
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_RSVD_MASK             0xc0UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_OPTIONS_RSVD_SFT              6
+	u8	targetBER;
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_TARGETBER_BER_1E8  0x0UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_TARGETBER_BER_1E9  0x1UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_TARGETBER_BER_1E10 0x2UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_TARGETBER_BER_1E11 0x3UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_TARGETBER_BER_1E12 0x4UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_TARGETBER_LAST    SELFTEST_RETRIEVE_SERDES_DATA_REQ_TARGETBER_BER_1E12
+	u8	action;
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_ACTION_SYNCHRONOUS 0x0UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_ACTION_START       0x1UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_ACTION_PROGRESS    0x2UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_ACTION_STOP        0x3UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_REQ_ACTION_LAST       SELFTEST_RETRIEVE_SERDES_DATA_REQ_ACTION_STOP
+	u8	unused[6];
+};
+
+/* hwrm_selftest_retrieve_serdes_data_output (size:192b/24B) */
+struct hwrm_selftest_retrieve_serdes_data_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le16	total_data_len;
+	__le16	copied_data_len;
+	__le16	progress_percent;
+	__le16	timeout;
+	u8	flags;
+	#define SELFTEST_RETRIEVE_SERDES_DATA_RESP_FLAGS_BIT_COUNT_TYPE                0x1UL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_RESP_FLAGS_BIT_COUNT_TYPE_BIT_COUNT_TOTAL  (0x0UL << 0)
+	#define SELFTEST_RETRIEVE_SERDES_DATA_RESP_FLAGS_BIT_COUNT_TYPE_BIT_COUNT_POW2   (0x1UL << 0)
+	#define SELFTEST_RETRIEVE_SERDES_DATA_RESP_FLAGS_BIT_COUNT_TYPE_LAST            SELFTEST_RETRIEVE_SERDES_DATA_RESP_FLAGS_BIT_COUNT_TYPE_BIT_COUNT_POW2
+	#define SELFTEST_RETRIEVE_SERDES_DATA_RESP_FLAGS_RSVD_MASK                     0xfeUL
+	#define SELFTEST_RETRIEVE_SERDES_DATA_RESP_FLAGS_RSVD_SFT                      1
+	u8	unused_0;
+	__le16	hdr_size;
+	u8	unused_1[3];
+	u8	valid;
+};
+
+/* hwrm_sch_grp_cfg_input (size:704b/88B) */
+struct hwrm_sch_grp_cfg_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le16	sch_grp_id;
+	__le16	num_fids;
+	__le32	enables;
+	#define SCH_GRP_CFG_REQ_ENABLES_QUEUE_ID0_VALID     0x1UL
+	#define SCH_GRP_CFG_REQ_ENABLES_QUEUE_ID1_VALID     0x2UL
+	#define SCH_GRP_CFG_REQ_ENABLES_QUEUE_ID2_VALID     0x4UL
+	#define SCH_GRP_CFG_REQ_ENABLES_QUEUEID3_VALID      0x8UL
+	#define SCH_GRP_CFG_REQ_ENABLES_QUEUE_ID4_VALID     0x10UL
+	#define SCH_GRP_CFG_REQ_ENABLES_QUEUE_ID5_VALID     0x20UL
+	#define SCH_GRP_CFG_REQ_ENABLES_QUEUE_ID6_VALID     0x40UL
+	#define SCH_GRP_CFG_REQ_ENABLES_QUEUE_ID7_VALID     0x80UL
+	#define SCH_GRP_CFG_REQ_ENABLES_MAX_BW              0x100UL
+	#define SCH_GRP_CFG_REQ_ENABLES_FID_MAP             0x200UL
+	__le64	fid_table_addr;
+	__le32	max_bw;
+	u8	unused_0[4];
+	u8	queue_id[8];
+	u8	queue_tsa_assign[8];
+	#define SCH_GRP_CFG_REQ_QUEUE_TSA_ASSIGN_SP   0x0UL
+	#define SCH_GRP_CFG_REQ_QUEUE_TSA_ASSIGN_ETS  0x1UL
+	#define SCH_GRP_CFG_REQ_QUEUE_TSA_ASSIGN_LAST SCH_GRP_CFG_REQ_QUEUE_TSA_ASSIGN_ETS
+	__le32	queue_min_bw_percent[8];
+};
+
+/* hwrm_sch_grp_cfg_output (size:128b/16B) */
+struct hwrm_sch_grp_cfg_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	u8	unused_0[7];
+	u8	valid;
+};
+
+/* hwrm_sch_grp_qcfg_input (size:256b/32B) */
+struct hwrm_sch_grp_qcfg_input {
+	__le16	req_type;
+	__le16	cmpl_ring;
+	__le16	seq_id;
+	__le16	target_id;
+	__le64	resp_addr;
+	__le16	sch_grp_id;
+	__le16	fid_table_len;
+	u8	unused_0[4];
+	__le64	fid_table_addr;
+};
+
+/* hwrm_sch_grp_qcfg_output (size:576b/72B) */
+struct hwrm_sch_grp_qcfg_output {
+	__le16	error_code;
+	__le16	req_type;
+	__le16	seq_id;
+	__le16	resp_len;
+	__le32	max_bw;
+	u8	unused_0[2];
+	__le16	num_fids;
+	u8	queue_id[8];
+	#define SCH_GRP_QCFG_RESP_QUEUE_ID_INVALID_QUEUE_ID 0xffUL
+	#define SCH_GRP_QCFG_RESP_QUEUE_ID_LAST            SCH_GRP_QCFG_RESP_QUEUE_ID_INVALID_QUEUE_ID
+	u8	queue_tsa_assign[8];
+	#define SCH_GRP_QCFG_RESP_QUEUE_TSA_ASSIGN_SP   0x0UL
+	#define SCH_GRP_QCFG_RESP_QUEUE_TSA_ASSIGN_ETS  0x1UL
+	#define SCH_GRP_QCFG_RESP_QUEUE_TSA_ASSIGN_LAST SCH_GRP_QCFG_RESP_QUEUE_TSA_ASSIGN_ETS
+	__le32	queue_min_bw_percent[8];
+	u8	unused_1[7];
+	u8	valid;
+};
+
 /* dbc_dbc (size:64b/8B) */
 struct dbc_dbc {
 	__le32	index;
-- 
2.52.0


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

* [PATCH v4 fwctl 3/3] fwctl/bnxt: add DMA buffer support for HWRM commands
  2026-07-02  5:51 [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands Pavan Chebbi
  2026-07-02  5:51 ` [PATCH v4 fwctl 1/3] fwctl: Add driver_data field to fwctl_rpc Pavan Chebbi
  2026-07-02  5:51 ` [PATCH v4 fwctl 2/3] bnxt_en: Update bnxt firmware spec Pavan Chebbi
@ 2026-07-02  5:51 ` Pavan Chebbi
  2026-07-03 17:51 ` [PATCH v4 fwctl 0/3] fwctl/bnxt: " Jason Gunthorpe
  3 siblings, 0 replies; 6+ messages in thread
From: Pavan Chebbi @ 2026-07-02  5:51 UTC (permalink / raw)
  To: jgg, michael.chan
  Cc: linux-kernel, dave.jiang, saeedm, jic23, gospo, selvin.xavier,
	leon, kalesh-anakkur.purayil, Pavan Chebbi

Several HWRM commands carry __le64 DMA address fields in their input
structures; firmware reads from or writes to the memory those addresses
point to.  Because the kernel must own all DMA mappings, userspace
shall describe the indirect buffers via fwctl_rpc.driver_data and the
driver shall map and patch the commands before sending to firmware.

Introduce UAPI types for bnxt_fwctl that help userspace describe the
DMA buffers.  Have a static per-command descriptor table in the driver
that records the details of the DMA fields in each supported HWRM
input struct. When a DMA-bearing HWRM command arrives, the driver
validates it using the descriptor table.  Scope-gated allow-list and
timeout value list are updated with the new the commands.

Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
---
 drivers/fwctl/bnxt/main.c | 340 +++++++++++++++++++++++++++++++++++++-
 include/uapi/fwctl/bnxt.h |  37 +++++
 2 files changed, 373 insertions(+), 4 deletions(-)

diff --git a/drivers/fwctl/bnxt/main.c b/drivers/fwctl/bnxt/main.c
index 5eb3651a1784..b9b05efc0875 100644
--- a/drivers/fwctl/bnxt/main.c
+++ b/drivers/fwctl/bnxt/main.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/auxiliary_bus.h>
+#include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/fwctl.h>
@@ -31,7 +32,8 @@ static int bnxtctl_open_uctx(struct fwctl_uctx *uctx)
 
 	bnxtctl_uctx->uctx_caps = BIT(FWCTL_BNXT_INLINE_COMMANDS) |
 				  BIT(FWCTL_BNXT_QUERY_COMMANDS) |
-				  BIT(FWCTL_BNXT_SEND_COMMANDS);
+				  BIT(FWCTL_BNXT_SEND_COMMANDS) |
+				  BIT(FWCTL_BNXT_DMA_COMMANDS);
 	return 0;
 }
 
@@ -55,6 +57,243 @@ static void *bnxtctl_info(struct fwctl_uctx *uctx, size_t *length)
 	return info;
 }
 
+struct bnxtctl_dma_field {
+	size_t offset;	/* offsetof(hwrm_xxx_input, field_name) */
+	u8     dir;
+};
+
+struct bnxtctl_cmd_dma_desc {
+	u16                      req_type;
+	u8                       num_fields;
+	u8                       scope_min;
+	struct bnxtctl_dma_field fields[FWCTL_BNXT_MAX_BUFS];
+};
+
+/*
+ * Per-command DMA buffer descriptor table for HWRM commands that
+ * carry __le64 DMA address fields in their input
+ */
+static const struct bnxtctl_cmd_dma_desc bnxtctl_dma_cmds[] = {
+	{ HWRM_NVM_SET_VARIABLE, 1, FWCTL_RPC_CONFIGURATION,
+	  {{ offsetof(struct hwrm_nvm_set_variable_input, src_data_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE }} },
+	{ HWRM_NVM_GET_VARIABLE, 1, FWCTL_RPC_CONFIGURATION,
+	  {{ offsetof(struct hwrm_nvm_get_variable_input, dest_data_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_NVM_READ, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_nvm_read_input, host_dest_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_NVM_GET_DIR_ENTRIES, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_nvm_get_dir_entries_input, host_dest_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_NVM_WRITE, 1, FWCTL_RPC_DEBUG_WRITE,
+	  {{ offsetof(struct hwrm_nvm_write_input, host_src_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE }} },
+	{ HWRM_NVM_MODIFY, 1, FWCTL_RPC_DEBUG_WRITE,
+	  {{ offsetof(struct hwrm_nvm_modify_input, host_src_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE }} },
+	{ HWRM_NVM_RAW_WRITE_BLK, 1, FWCTL_RPC_DEBUG_WRITE_FULL,
+	  {{ offsetof(struct hwrm_nvm_raw_write_blk_input, host_src_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE }} },
+	{ HWRM_NVM_RAW_DUMP, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_nvm_raw_dump_input, host_dest_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+
+	{ HWRM_FW_GET_STRUCTURED_DATA, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_fw_get_structured_data_input, dest_data_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_FW_SET_STRUCTURED_DATA, 1, FWCTL_RPC_DEBUG_WRITE,
+	  {{ offsetof(struct hwrm_fw_set_structured_data_input, src_data_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE }} },
+	{ HWRM_FW_LIVEPATCH, 1, FWCTL_RPC_DEBUG_WRITE_FULL,
+	  {{ offsetof(struct hwrm_fw_livepatch_input, host_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE }} },
+
+	{ HWRM_DBG_COREDUMP_LIST, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_dbg_coredump_list_input, host_dest_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_DBG_COREDUMP_RETRIEVE, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_dbg_coredump_retrieve_input, host_dest_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_DBG_READ_DIRECT, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_dbg_read_direct_input, host_dest_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_DBG_READ_INDIRECT, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_dbg_read_indirect_input, host_dest_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_DBG_SERDES_TEST, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_dbg_serdes_test_input, resp_data_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_DBG_TOKEN_CFG, 1, FWCTL_RPC_DEBUG_WRITE_FULL,
+	  {{ offsetof(struct hwrm_dbg_token_cfg_input, host_src_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE }} },
+
+	{ HWRM_QUEUE_DSCP2PRI_QCFG, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_queue_dscp2pri_qcfg_input, dest_data_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+
+	{ HWRM_PORT_QSTATS, 2, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_port_qstats_input, tx_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE },
+	   { offsetof(struct hwrm_port_qstats_input, rx_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_PORT_QSTATS_EXT, 2, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_port_qstats_ext_input, tx_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE },
+	   { offsetof(struct hwrm_port_qstats_ext_input, rx_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_PORT_QSTATS_EXT_PFC_ADV, 2, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_port_qstats_ext_pfc_adv_input,
+		      tx_pfc_adv_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE },
+	   { offsetof(struct hwrm_port_qstats_ext_pfc_adv_input,
+		      rx_pfc_adv_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_PCIE_QSTATS, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_pcie_qstats_input, pcie_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_STAT_GENERIC_QSTATS, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_stat_generic_qstats_input,
+		      generic_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_STAT_QUERY_ROCE_STATS, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_stat_query_roce_stats_input,
+		      roce_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_STAT_QUERY_ROCE_STATS_EXT, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_stat_query_roce_stats_ext_input,
+		      roce_stat_host_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+
+	{ HWRM_PORT_EVENTS_LOG, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_port_events_log_input, host_dest_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_PORT_PRBS_TEST, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_port_prbs_test_input, resp_data_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+	{ HWRM_PORT_DSC_DUMP, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_port_dsc_dump_input, resp_data_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+
+	{ HWRM_SCH_GRP_CFG, 1, FWCTL_RPC_DEBUG_WRITE,
+	  {{ offsetof(struct hwrm_sch_grp_cfg_input, fid_table_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE }} },
+	{ HWRM_SCH_GRP_QCFG, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_sch_grp_qcfg_input, fid_table_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+
+	{ HWRM_SELFTEST_RETRIEVE_SERDES_DATA, 1, FWCTL_RPC_DEBUG_READ_ONLY,
+	  {{ offsetof(struct hwrm_selftest_retrieve_serdes_data_input, resp_data_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+
+	{ HWRM_DBG_PTRACE, 2, FWCTL_RPC_DEBUG_WRITE,
+	  {{ offsetof(struct hwrm_dbg_ptrace_input, pdi_cmd_buf_addr),
+	     FWCTL_BNXT_BUF_TO_DEVICE },
+	   { offsetof(struct hwrm_dbg_ptrace_input, pdi_resp_buf_addr),
+	     FWCTL_BNXT_BUF_FROM_DEVICE }} },
+};
+
+static const struct bnxtctl_cmd_dma_desc *
+bnxtctl_find_dma_desc(u16 req_type)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(bnxtctl_dma_cmds); i++)
+		if (bnxtctl_dma_cmds[i].req_type == req_type)
+			return &bnxtctl_dma_cmds[i];
+	return NULL;
+}
+
+static void bnxtctl_zero_dma_fields(void *cmd,
+				    const struct bnxtctl_cmd_dma_desc *desc)
+{
+	int i;
+
+	for (i = 0; i < desc->num_fields; i++) {
+		__le64 *field = cmd + desc->fields[i].offset;
+
+		*field = 0;
+	}
+}
+
+static int bnxtctl_map_dma_bufs(struct device *dev, void *cmd,
+				const struct bnxtctl_cmd_dma_desc *desc,
+				const struct fwctl_bnxt_driver_data *dd,
+				void **kbufs, dma_addr_t *dma_addrs,
+				unsigned int *num_mapped)
+{
+	unsigned int i;
+
+	*num_mapped = 0;
+	for (i = 0; i < dd->num_bufs; i++) {
+		enum dma_data_direction dma_dir;
+		__le64 *field;
+
+		if (dd->bufs[i].dir != desc->fields[i].dir)
+			return -EINVAL;
+
+		if (!dd->bufs[i].len || dd->bufs[i].len > FWCTL_BNXT_MAX_DMABUF)
+			return -EINVAL;
+
+		dma_dir = (dd->bufs[i].dir == FWCTL_BNXT_BUF_TO_DEVICE) ?
+			DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+		kbufs[i] = kvzalloc(dd->bufs[i].len, GFP_KERNEL);
+		if (!kbufs[i])
+			return -ENOMEM;
+
+		if (dma_dir == DMA_TO_DEVICE &&
+		    copy_from_user(kbufs[i],
+				   u64_to_user_ptr(dd->bufs[i].addr),
+				   dd->bufs[i].len)) {
+			kvfree(kbufs[i]);
+			kbufs[i] = NULL;
+			return -EFAULT;
+		}
+
+		dma_addrs[i] = dma_map_single(dev, kbufs[i],
+					      dd->bufs[i].len, dma_dir);
+		if (dma_mapping_error(dev, dma_addrs[i])) {
+			kvfree(kbufs[i]);
+			kbufs[i] = NULL;
+			return -ENOMEM;
+		}
+
+		(*num_mapped)++;
+
+		field = cmd + desc->fields[i].offset;
+		*field = cpu_to_le64(dma_addrs[i]);
+	}
+	return 0;
+}
+
+static int bnxtctl_unmap_dma_bufs(struct device *dev,
+				  const struct bnxtctl_cmd_dma_desc *desc,
+				  const struct fwctl_bnxt_driver_data *dd,
+				  void **kbufs, dma_addr_t *dma_addrs,
+				  unsigned int num_mapped)
+{
+	unsigned int i;
+	int rc = 0;
+
+	for (i = 0; i < num_mapped; i++) {
+		enum dma_data_direction dma_dir;
+
+		dma_dir = (dd->bufs[i].dir == FWCTL_BNXT_BUF_TO_DEVICE) ?
+			DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+		dma_unmap_single(dev, dma_addrs[i], dd->bufs[i].len, dma_dir);
+
+		if (dma_dir == DMA_FROM_DEVICE &&
+		    copy_to_user(u64_to_user_ptr(dd->bufs[i].addr),
+				 kbufs[i], dd->bufs[i].len))
+			rc = -EFAULT;
+
+		kvfree(kbufs[i]);
+	}
+	return rc;
+}
+
 /* Caller must hold edev->en_dev_lock */
 static bool bnxtctl_validate_rpc(struct bnxt_en_dev *edev,
 				 struct bnxt_fw_msg *hwrm_in,
@@ -82,6 +321,8 @@ static bool bnxtctl_validate_rpc(struct bnxt_en_dev *edev,
 	case HWRM_NVM_ERASE_DIR_ENTRY:
 	case HWRM_NVM_MOD_DIR_ENTRY:
 	case HWRM_NVM_FIND_DIR_ENTRY:
+	case HWRM_NVM_SET_VARIABLE:
+	case HWRM_NVM_GET_VARIABLE:
 		return scope >= FWCTL_RPC_CONFIGURATION;
 
 	case HWRM_VER_GET:
@@ -138,12 +379,45 @@ static bool bnxtctl_validate_rpc(struct bnxt_en_dev *edev,
 	case HWRM_NVM_GET_DEV_INFO:
 	case HWRM_NVM_GET_DIR_INFO:
 	case HWRM_SELFTEST_QLIST:
+	case HWRM_NVM_READ:
+	case HWRM_NVM_GET_DIR_ENTRIES:
+	case HWRM_FW_GET_STRUCTURED_DATA:
+	case HWRM_DBG_COREDUMP_LIST:
+	case HWRM_DBG_COREDUMP_RETRIEVE:
+	case HWRM_DBG_COREDUMP_INITIATE:
+	case HWRM_DBG_READ_DIRECT:
+	case HWRM_QUEUE_DSCP2PRI_QCFG:
+	case HWRM_PORT_QSTATS:
+	case HWRM_PORT_QSTATS_EXT:
+	case HWRM_PORT_QSTATS_EXT_PFC_ADV:
+	case HWRM_PCIE_QSTATS:
+	case HWRM_STAT_GENERIC_QSTATS:
+	case HWRM_STAT_QUERY_ROCE_STATS:
+	case HWRM_STAT_QUERY_ROCE_STATS_EXT:
+	case HWRM_PORT_EVENTS_LOG:
+	case HWRM_PORT_PRBS_TEST:
+	case HWRM_PORT_DSC_DUMP:
+	case HWRM_DBG_READ_INDIRECT:
+	case HWRM_DBG_SERDES_TEST:
+	case HWRM_SCH_GRP_QCFG:
+	case HWRM_SELFTEST_RETRIEVE_SERDES_DATA:
+	case HWRM_NVM_RAW_DUMP:
 		return scope >= FWCTL_RPC_DEBUG_READ_ONLY;
 
 	case HWRM_PORT_PHY_I2C_WRITE:
 	case HWRM_PORT_PHY_MDIO_WRITE:
+	case HWRM_NVM_WRITE:
+	case HWRM_NVM_MODIFY:
+	case HWRM_FW_SET_STRUCTURED_DATA:
+	case HWRM_SCH_GRP_CFG:
+	case HWRM_DBG_PTRACE:
 		return scope >= FWCTL_RPC_DEBUG_WRITE;
 
+	case HWRM_FW_LIVEPATCH:
+	case HWRM_NVM_RAW_WRITE_BLK:
+	case HWRM_DBG_TOKEN_CFG:
+		return scope >= FWCTL_RPC_DEBUG_WRITE_FULL;
+
 	default:
 		return false;
 	}
@@ -162,6 +436,15 @@ static unsigned int bnxtctl_get_timeout(struct input *req)
 	case HWRM_NVM_VERIFY_UPDATE:
 	case HWRM_NVM_ERASE_DIR_ENTRY:
 	case HWRM_NVM_MOD_DIR_ENTRY:
+	case HWRM_NVM_WRITE:
+	case HWRM_FW_SYNC:
+	case HWRM_DBG_COREDUMP_LIST:
+	case HWRM_DBG_COREDUMP_RETRIEVE:
+	case HWRM_DBG_COREDUMP_INITIATE:
+	case HWRM_SELFTEST_RETRIEVE_SERDES_DATA:
+	case HWRM_DBG_SERDES_TEST:
+	case HWRM_NVM_RAW_WRITE_BLK:
+	case HWRM_FW_HEALTH_CHECK:
 		return BNXTCTL_HWRM_CMD_TIMEOUT_LONG;
 	case HWRM_FUNC_RESET:
 		return BNXTCTL_HWRM_CMD_TIMEOUT_MEDM;
@@ -178,18 +461,45 @@ static void *bnxtctl_fw_rpc(struct fwctl_uctx *uctx,
 	struct bnxtctl_dev *bnxtctl =
 		container_of(uctx->fwctl, struct bnxtctl_dev, fwctl);
 	struct bnxt_en_dev *edev = bnxtctl->aux_priv->edev;
+	dma_addr_t dma_addrs[FWCTL_BNXT_MAX_BUFS];
+	const struct bnxtctl_cmd_dma_desc *desc;
+	void *kbufs[FWCTL_BNXT_MAX_BUFS] = {0};
+	struct fwctl_bnxt_driver_data dd = {0};
+	struct device *dev = &edev->pdev->dev;
 	struct bnxt_fw_msg rpc_in = {0};
+	unsigned int num_mapped = 0;
+	struct input *req = in;
 	int rc;
 
-	if (driver_data)
-		return ERR_PTR(-EOPNOTSUPP);
-
 	if (in_len < sizeof(struct input) || in_len > HWRM_MAX_REQ_LEN)
 		return ERR_PTR(-EINVAL);
 
 	if (*out_len < sizeof(struct output))
 		return ERR_PTR(-EINVAL);
 
+	desc = bnxtctl_find_dma_desc(le16_to_cpu(req->req_type));
+
+	if (desc) {
+		if (!driver_data)
+			return ERR_PTR(-EINVAL);
+		if (copy_from_user(&dd, u64_to_user_ptr(driver_data),
+				   sizeof(dd)))
+			return ERR_PTR(-EFAULT);
+		if (dd.rsvd || !dd.num_bufs || dd.num_bufs > desc->num_fields)
+			return ERR_PTR(-EINVAL);
+
+		for (unsigned int i = 0; i < dd.num_bufs; i++) {
+			if (memchr_inv(dd.bufs[i].rsvd, 0,
+				       sizeof(dd.bufs[i].rsvd)))
+				return ERR_PTR(-EINVAL);
+		}
+		bnxtctl_zero_dma_fields(in, desc);
+	} else {
+		/* Non-DMA command: driver_data must be absent. */
+		if (driver_data)
+			return ERR_PTR(-EOPNOTSUPP);
+	}
+
 	rpc_in.msg = in;
 	rpc_in.msg_len = in_len;
 	rpc_in.resp = kzalloc(*out_len, GFP_KERNEL);
@@ -206,6 +516,17 @@ static void *bnxtctl_fw_rpc(struct fwctl_uctx *uctx,
 		return ERR_PTR(-EPERM);
 	}
 
+	if (desc) {
+		rc = bnxtctl_map_dma_bufs(dev, in, desc, &dd,
+					  kbufs, dma_addrs, &num_mapped);
+		if (rc) {
+			bnxtctl_unmap_dma_bufs(dev, desc, &dd,
+					       kbufs, dma_addrs, num_mapped);
+			kfree(rpc_in.resp);
+			return ERR_PTR(rc);
+		}
+	}
+
 	rc = bnxt_send_msg(edev, &rpc_in);
 	if (rc) {
 		struct output *resp = rpc_in.resp;
@@ -220,6 +541,17 @@ static void *bnxtctl_fw_rpc(struct fwctl_uctx *uctx,
 			resp->error_code = cpu_to_le16(rc);
 	}
 
+	if (desc) {
+		int unmap_rc;
+
+		unmap_rc = bnxtctl_unmap_dma_bufs(dev, desc, &dd, kbufs,
+						  dma_addrs, num_mapped);
+		if (unmap_rc) {
+			kfree(rpc_in.resp);
+			return ERR_PTR(unmap_rc);
+		}
+	}
+
 	return rpc_in.resp;
 }
 
diff --git a/include/uapi/fwctl/bnxt.h b/include/uapi/fwctl/bnxt.h
index 32e0bfb9a836..5ad6bf250dde 100644
--- a/include/uapi/fwctl/bnxt.h
+++ b/include/uapi/fwctl/bnxt.h
@@ -12,6 +12,7 @@ enum fwctl_bnxt_commands {
 	FWCTL_BNXT_INLINE_COMMANDS = 0,
 	FWCTL_BNXT_QUERY_COMMANDS,
 	FWCTL_BNXT_SEND_COMMANDS,
+	FWCTL_BNXT_DMA_COMMANDS,
 };
 
 /**
@@ -23,4 +24,40 @@ enum fwctl_bnxt_commands {
 struct fwctl_info_bnxt {
 	__u32 uctx_caps;
 };
+
+enum fwctl_bnxt_buf_dir {
+	FWCTL_BNXT_BUF_TO_DEVICE   = 0,
+	FWCTL_BNXT_BUF_FROM_DEVICE = 1,
+};
+
+/**
+ * struct fwctl_bnxt_buf - one indirect DMA buffer descriptor
+ * @addr: Userspace pointer to the payload data.
+ * @len:  Byte length of the buffer.
+ * @dir:  One of enum fwctl_bnxt_buf_dir.
+ * @rsvd: Must be zero.
+ */
+struct fwctl_bnxt_buf {
+	__aligned_u64 addr;
+	__u32         len;
+	__u32         dir;
+	__u32         rsvd[2];
+};
+
+#define FWCTL_BNXT_MAX_BUFS	4
+#define FWCTL_BNXT_MAX_DMABUF	0x400000  /* 4 MiB */
+
+/**
+ * struct fwctl_bnxt_driver_data - pointed to by fwctl_rpc::driver_data for bnxt
+ * @num_bufs: Number of valid entries in @bufs. Must be non-zero and no greater
+ *   than the number of DMA address fields the specific HWRM command supports
+ * @rsvd:     Must be zero.
+ * @bufs:     Array of buffer descriptors.
+ */
+struct fwctl_bnxt_driver_data {
+	__u32                 num_bufs;
+	__u32                 rsvd;
+	struct fwctl_bnxt_buf bufs[FWCTL_BNXT_MAX_BUFS];
+};
+
 #endif
-- 
2.52.0


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

* Re: [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands
  2026-07-02  5:51 [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands Pavan Chebbi
                   ` (2 preceding siblings ...)
  2026-07-02  5:51 ` [PATCH v4 fwctl 3/3] fwctl/bnxt: add DMA buffer support for HWRM commands Pavan Chebbi
@ 2026-07-03 17:51 ` Jason Gunthorpe
  2026-07-04  6:04   ` Pavan Chebbi
  3 siblings, 1 reply; 6+ messages in thread
From: Jason Gunthorpe @ 2026-07-03 17:51 UTC (permalink / raw)
  To: Pavan Chebbi
  Cc: michael.chan, linux-kernel, dave.jiang, saeedm, jic23, gospo,
	selvin.xavier, leon, kalesh-anakkur.purayil

On Thu, Jul 02, 2026 at 11:21:22AM +0530, Pavan Chebbi wrote:
> Several HWRM (HardWare Resource Manager) commands used for diagnostics,
> firmware management, and NVM access carry one or more DMA address fields
> in their input structures.  Until now these commands could not be issued
> through the fwctl interface because the driver had no mechanism to safely
> broker the host-side DMA buffers on userspace's behalf.
> 
> This series adds that mechanism in three steps.
> 
> In patch #1, the fwctl core UAPI adds a new driver_data field in struct
> fwctl_rpc.  Drivers that need a driver_data payload receive the value and
> are free to interpret it. Drivers that do not define one will reject any
> non-zero value with -EOPNOTSUPP.  Existing mlx5 and pds fwctl drivers are
> updated accordingly.
> 
> In patch #2, the bnxt HSI header is updated to add the missing struct
> definitions for the HWRM commands that the bnxt fwctl driver will support.
> 
> In patch #3, the bnxt fwctl driver consumes driver_data as a pointer to
> a new bnxt UAPI struct fwctl_bnxt_driver_data, which describes indirect
> DMA buffers.
> 
> v4: Collected Rb tag from Dave for patch #1. Thanks Dave

Sashiko had several things to say about v3:

https://sashiko.dev/#/patchset/20260526144507.822095-1-pavan.chebbi%40broadcom.com

For some reason v4 is mangled and it couldn't apply it.

And this one raises my eyebrows considering what we talked about before:

 How is dd.bufs[i].len ensured to match the actual transfer size expected
 by the firmware?
 If a small dd.bufs[i].len is provided while the HWRM command payload
 specifies a larger transfer size, could the firmware write past the end
 of the mapped bounce buffer into adjacent physical memory?

Seems like it needs a comment if it is actually safe somehow, but I
don't see how it is safe and it seems like Sashiko has hit on a
critical flaw.

Heh Sashiko also pointed out the broken device failure flow I
mentioned before too :)

Jason

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

* Re: [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands
  2026-07-03 17:51 ` [PATCH v4 fwctl 0/3] fwctl/bnxt: " Jason Gunthorpe
@ 2026-07-04  6:04   ` Pavan Chebbi
  0 siblings, 0 replies; 6+ messages in thread
From: Pavan Chebbi @ 2026-07-04  6:04 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: michael.chan, linux-kernel, dave.jiang, saeedm, jic23, gospo,
	selvin.xavier, leon, kalesh-anakkur.purayil

[-- Attachment #1: Type: text/plain, Size: 722 bytes --]

> And this one raises my eyebrows considering what we talked about before:
>
>  How is dd.bufs[i].len ensured to match the actual transfer size expected
>  by the firmware?
>  If a small dd.bufs[i].len is provided while the HWRM command payload
>  specifies a larger transfer size, could the firmware write past the end
>  of the mapped bounce buffer into adjacent physical memory?
>
> Seems like it needs a comment if it is actually safe somehow, but I
> don't see how it is safe and it seems like Sashiko has hit on a
> critical flaw.

Thanks for the review.
Yes, a valid concern. I may need to do an additional length validation
for dd.bufs[i] based on what is specified inside the cmd payload.
I will be back with v5.

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5469 bytes --]

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

end of thread, other threads:[~2026-07-04  6:05 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-02  5:51 [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands Pavan Chebbi
2026-07-02  5:51 ` [PATCH v4 fwctl 1/3] fwctl: Add driver_data field to fwctl_rpc Pavan Chebbi
2026-07-02  5:51 ` [PATCH v4 fwctl 2/3] bnxt_en: Update bnxt firmware spec Pavan Chebbi
2026-07-02  5:51 ` [PATCH v4 fwctl 3/3] fwctl/bnxt: add DMA buffer support for HWRM commands Pavan Chebbi
2026-07-03 17:51 ` [PATCH v4 fwctl 0/3] fwctl/bnxt: " Jason Gunthorpe
2026-07-04  6:04   ` Pavan Chebbi

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