The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Pavan Chebbi <pavan.chebbi@broadcom.com>
To: jgg@ziepe.ca, michael.chan@broadcom.com
Cc: linux-kernel@vger.kernel.org, dave.jiang@intel.com,
	saeedm@nvidia.com, jic23@kernel.org, gospo@broadcom.com,
	selvin.xavier@broadcom.com, leon@kernel.org,
	kalesh-anakkur.purayil@broadcom.com,
	Pavan Chebbi <pavan.chebbi@broadcom.com>
Subject: [PATCH v4 fwctl 3/3] fwctl/bnxt: add DMA buffer support for HWRM commands
Date: Thu,  2 Jul 2026 11:21:25 +0530	[thread overview]
Message-ID: <20260702055125.557963-4-pavan.chebbi@broadcom.com> (raw)
In-Reply-To: <20260702055125.557963-1-pavan.chebbi@broadcom.com>

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


  parent reply	other threads:[~2026-07-02  5:49 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2026-07-03 17:51 ` [PATCH v4 fwctl 0/3] fwctl/bnxt: DMA buffer support for HWRM commands Jason Gunthorpe
2026-07-04  6:04   ` Pavan Chebbi

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20260702055125.557963-4-pavan.chebbi@broadcom.com \
    --to=pavan.chebbi@broadcom.com \
    --cc=dave.jiang@intel.com \
    --cc=gospo@broadcom.com \
    --cc=jgg@ziepe.ca \
    --cc=jic23@kernel.org \
    --cc=kalesh-anakkur.purayil@broadcom.com \
    --cc=leon@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michael.chan@broadcom.com \
    --cc=saeedm@nvidia.com \
    --cc=selvin.xavier@broadcom.com \
    /path/to/YOUR_REPLY

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

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