From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-vs1-f98.google.com (mail-vs1-f98.google.com [209.85.217.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80F20402420 for ; Tue, 26 May 2026 14:43:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.217.98 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779806618; cv=none; b=OTsOqbIaXx8lLQeZsouBH/fpcryp7nLftMYoZKI5XW1j5ZhETqEOX9h3M3N7t9mg8jQWshVW8DrgdiubIkKPcufV7eF01Dg05lT1Ofc29wLmaePHPS0FVC5l67YWnMjg2+LeDPm5HES0JMCJqOjMh0Yz8g6SPHKzoxlz8GmrN7E= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779806618; c=relaxed/simple; bh=KK26iTp/+lnPiNjkGCFN7SBRO7prTp3PFZSybIRQwlo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HCuqCa22GLCZ7Sq73rC8M3ON2AlNxhr2QiRyBO+igbzzjVlq2Lz0Xducvd2Byb5lIudhqrLO5nva7752au4Inf0JRzjqToMvthluYPBKdh3u91Ap0wduI0qmFCNCJ8hUO1l9EM4vvVBCd+sCp/aNc1UXyx72Bub5pvVdJgH5cC8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com; spf=fail smtp.mailfrom=broadcom.com; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b=HrG2HQYK; arc=none smtp.client-ip=209.85.217.98 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=broadcom.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=broadcom.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=broadcom.com header.i=@broadcom.com header.b="HrG2HQYK" Received: by mail-vs1-f98.google.com with SMTP id ada2fe7eead31-63130466364so3940359137.2 for ; Tue, 26 May 2026 07:43:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779806615; x=1780411415; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=LBeiC+ZLp2fk+k1EVrfy09At5ceTy0fUR3XTsbPHK4U=; b=h4oCx9p4f8Sbjlbog9xvq3RLkhNS588FPJrqiS2mt2uEGGng/2wbhBkSk93QKo+cjN +GIyP1zzhXHofDFzHqODmP0o41P5BNgzl64x8n0YIuCbz8LdH+A0FVh9zLI+UwY8Ueu1 EKy9BN47Z+Xr0AKJFKmoVo2Nrowuvw3e8ptJxQYUpYd/qvJztHrVOKuu+53sNnyQ79Iq 7g4Id4Z9V9BENSuUWrmAtiyNbJ4bgVg8ZArx3/ktPtA5XNgtTogfhsSQKnmFGcnnYjgz rsvxQ0vAYMSzNqswILoTu/R9pIVgkOjxmjytDzUNL6G5YvRsRDfM5u+CNkrCPnPu0cge 7kaA== X-Gm-Message-State: AOJu0YwxyaOjg206JKbIdISxg5G+UvfDEhCoh9ONecBgtUYVTKhyl/lo vUvRd3+mx/M98Y526KyD/B9WfvOiMW1FdIcO8jNk3senzsGNA+uHLeglhAAITqu2VO1WVI16n+F cLzKh1i6TEZhQR6tT/yrntKR46ehHzvQTz7GfvroyLvsDK2Fw4kv3Gn9dwUkIHTJV9ZCIC/apOd gsYAD0VGJgaDy+CP4GWtKJ16CK6yQxqi+Af9rjYWgy8zKmUYSX8gnu5oZvxiyFENJ3f+rQIFpS+ RYDz8vsQe/rM8XsQDfoPA== X-Gm-Gg: Acq92OG/PmChJKSk3Ie+xNVC6T6sAKNPLaLSSPVI6+qm6VA49VhvwRq7o+U0ndRF9YJ Q8vWi6yQbhVQ7seriko44rlVBG1aeU8KHD9geUyymzbDN1JwmjW+EA1Uo6DaetEzH34AB051Pwp R0o/ny1zCcMoejK8xONGur3l4wtPms/7LuAC2ZBGx7P8SpSP/GoCeYSHJr/USBnnSgm3HPUhVKE qfKurrdQmlODuhscB+2DG6J3g9eMVltfkSak8d2xlLcJGa955JEM+KpzkdIT2Ih5yfWihdI19W0 /yInbhwqg2fZFVRcAsBXv0KHcXSHoF6Si328SAVgheL9fHA1gMxXZQXIMA97fXequp3GZKfWy/j X5yWKRTY25Zqg6D8xBFq0pApJS520sZSVsfXNxxsURX297sH3URsgfUkjFv1yvqP2l/0I7gNqNy DD4/NQ4jjixQJOgHyMqKVYCaYWVkapzADoZnXEfTF9vWndRMOHDwoElfey8aXaP0B6j2DFcQ== X-Received: by 2002:a05:6102:3f8e:b0:607:97b7:c283 with SMTP id ada2fe7eead31-67c7fff0701mr8544320137.14.1779806615287; Tue, 26 May 2026 07:43:35 -0700 (PDT) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-102.dlp.protect.broadcom.com. [144.49.247.102]) by smtp-relay.gmail.com with ESMTPS id ada2fe7eead31-67fdb1b06c3sm810237137.11.2026.05.26.07.43.34 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 26 May 2026 07:43:35 -0700 (PDT) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pl1-f199.google.com with SMTP id d9443c01a7336-2baf7748d0aso107576485ad.1 for ; Tue, 26 May 2026 07:43:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1779806614; x=1780411414; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LBeiC+ZLp2fk+k1EVrfy09At5ceTy0fUR3XTsbPHK4U=; b=HrG2HQYK0Nti+w/LzguKhs/E1WRu88Rb9bpeLT7gt+NV2bvY4TjWJdQCfAGC5lSQAy dazP6wxXE2mSBesf5b6qrtku/HVAJYN0KeVcqAhMWEra7WO7VK0HhKoy/GUDNbp6Yut7 UHBvVzflJxuHwYr0rsjJ7wt8w6tqZKf/Qr8x0= X-Received: by 2002:a17:903:1a07:b0:2bd:8395:fedd with SMTP id d9443c01a7336-2beb06bdfdemr196091595ad.37.1779806613868; Tue, 26 May 2026 07:43:33 -0700 (PDT) X-Received: by 2002:a17:903:1a07:b0:2bd:8395:fedd with SMTP id d9443c01a7336-2beb06bdfdemr196091255ad.37.1779806613245; Tue, 26 May 2026 07:43:33 -0700 (PDT) Received: from pc-hpe-top-git-sendmail-server.dhcp.broadcom.net ([192.19.234.250]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2beb5695b83sm117657605ad.9.2026.05.26.07.43.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 07:43:32 -0700 (PDT) From: Pavan Chebbi 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 Subject: [PATCH v3 fwctl 3/3] fwctl/bnxt: add DMA buffer support for HWRM commands Date: Tue, 26 May 2026 20:15:07 +0530 Message-ID: <20260526144507.822095-4-pavan.chebbi@broadcom.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260526144507.822095-1-pavan.chebbi@broadcom.com> References: <20260526144507.822095-1-pavan.chebbi@broadcom.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-DetectorID-Processed: b00c1d49-9d2e-4205-b15f-d015386d3d5e 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 --- 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 +#include #include #include #include @@ -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