From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-qt1-f228.google.com (mail-qt1-f228.google.com [209.85.160.228]) (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 B3319363C6C for ; Thu, 2 Jul 2026 05:49:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.228 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782971382; cv=none; b=mzvAoR/bfR628FbuPdCBuIvu04Mq6ezi/0cW9otNKOE3A7jN2ehgY3DPY3LGWQbmnxlo/UObPdUHM09PBg+tpo8ImdnSHHsMPshGnZ1TDz9vdsT6TIVvHRWGMfltOai/LWlPmTD12WkCJNpQswpqs9cpNdeFh5xq4LaBYQbfJc8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782971382; c=relaxed/simple; bh=KK26iTp/+lnPiNjkGCFN7SBRO7prTp3PFZSybIRQwlo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jY5AYDxGk82BnTqS6Dd09LiCZ7X+duRuQWABBgIuzvK76qOM4jgp6GjgpUNAuSn+gkYb4JHixZ8ASoSpR0/4rSGlFrkwxePw22hWKlj0Grbp70letRRKaFIxj1T/xWazGmKD8K/AMuUEmFCftUTcpYcWPS5hag+i86cCCcPpwS4= 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=OOf99YY4; arc=none smtp.client-ip=209.85.160.228 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="OOf99YY4" Received: by mail-qt1-f228.google.com with SMTP id d75a77b69052e-51c0c45c580so8589141cf.0 for ; Wed, 01 Jul 2026 22:49:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1782971379; x=1783576179; 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=oZkqa+fFaP2s0pirb+vm/H3APVBPYJwmPvVesg9SWRRUpCBeSXYu1YuXm3qfXECtQ5 b5oMLTNHbhWTPVvLnJ7zkSS10BtgCoYVM3Rd1AZhN/VrNnoJ3EL1k7n3Abhv2bZEivNv DBCqhw6vMy4Jo6yIH31p9w2v8S5hKcvnGRBEw2BsvsxXc3hyP/iQ58M1TbqkeYbItpZ4 mhAqY9VwRUcZ82DpgrWamh3xUNO7E/fbRqYrr/qz/3XzRAo+wrUtjkS7e3zz3RwMJceO lEHMuP1dKArThI/ChD4GM6KZgaZHXqEnojNwK1uMt+wPwuk9NnntSibOJYrtFMOUtwoM wj7g== X-Gm-Message-State: AOJu0YxryFGx3ZZ8PTNUod/K2hlK2koG5FmBVsInYRLx1rTNF/ypGBHh EugYjwZH0o2yAoPFTlH/yBP/EbGjUl0VJq2BnyzH2q9QhXgEJE6qpuMUmUJdA8puZupH+HaETkX VM+zrMpqjCgc48RObDxA01lpewc0dPrjTVPz1sLmeioRWa7EovoH0KFhCSmrAAGwknW9vYCfNgG gYBr6mkaxMdfdcv/+6NgWYlFBApkgv1OqZugL7v5NGtsJZutXkUgFpHhbf/IlHaR6NabfofY646 VLA1ACZDvGP7HThniQ= X-Gm-Gg: AfdE7ckXKogTtl04/n9NNKP/fwK4HrUA7M0iCL2XR0yfoppKzRuzkPIKqdldUcXYKr/ AmuaDKqHyT0swxgpK9CyAXVxKfKYP9hKMRP1TLObUKeU/a0f1Y02bwXeAZafYh+eH0tzHTghUTR tqwVf3hOhxs5nu/su+wNIFAFpg1qgMSfffK4WTrAW7fjEyEzRM7wRz0+E44y0LafS8cJyNTF6CB Xy75ImiX8fYkkVHB9Vzek3wHjXjCkogQX3UOyRXaz6kRh5XXTYPaTFUcnZQls8ikkTKhYJFKv80 +ts/kCPW3zKJbNoxeb3jkyJ/hpvq+gK6vdkF1VkuWdHxMnJJnIar4We3wiXIBhRUhpC/8e/VDti afrRGul5toVU27PLzuTAtGBOiWn0QFstCPvC8vDBp1zFxGZz+KB/h2LelcnjODVuZR/GbLREkzL XrjyWzSOLrhHP/3BTzfN40VkT5UR8tDIG+QPlbaTLEiRUvFWlA X-Received: by 2002:a05:622a:4d8d:b0:519:f420:d780 with SMTP id d75a77b69052e-51c26a773f3mr58002171cf.30.1782971378482; Wed, 01 Jul 2026 22:49:38 -0700 (PDT) Received: from smtp-us-east1-p01-i01-si01.dlp.protect.broadcom.com (address-144-49-247-101.dlp.protect.broadcom.com. [144.49.247.101]) by smtp-relay.gmail.com with ESMTPS id 6a1803df08f44-8f47133adaasm1410846d6.24.2026.07.01.22.49.38 for (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Wed, 01 Jul 2026 22:49:38 -0700 (PDT) X-Relaying-Domain: broadcom.com X-CFilter-Loop: Reflected Received: by mail-pj1-f70.google.com with SMTP id 98e67ed59e1d1-38001e788d6so1974193a91.3 for ; Wed, 01 Jul 2026 22:49:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; t=1782971377; x=1783576177; 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=OOf99YY4yJHxlhgpWUYriKl4QamHtagbrH3Sn4rOyvCQNkPGY5HoygDdK0UtmHKHJT Dh9MJYfUfjr+cIZjLXr9D0a9Tfe7dZNBN1Xtmks8DI1f42alhN3wMJ+2frcNTlW3GxYh BHcAXBiBenWAnUaUoNdlPIWWUQxkG5Oc/Izyc= X-Received: by 2002:a17:90b:5204:b0:37c:6910:5758 with SMTP id 98e67ed59e1d1-380aa0fd400mr5172435a91.1.1782971376997; Wed, 01 Jul 2026 22:49:36 -0700 (PDT) X-Received: by 2002:a17:90b:5204:b0:37c:6910:5758 with SMTP id 98e67ed59e1d1-380aa0fd400mr5172408a91.1.1782971376509; Wed, 01 Jul 2026 22:49:36 -0700 (PDT) Received: from pc-hpe-top-git-sendmail-server.dhcp.broadcom.net ([192.19.234.250]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-30f0bc38e5fsm4656033eec.29.2026.07.01.22.49.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Jul 2026 22:49:34 -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 v4 fwctl 3/3] fwctl/bnxt: add DMA buffer support for HWRM commands Date: Thu, 2 Jul 2026 11:21:25 +0530 Message-ID: <20260702055125.557963-4-pavan.chebbi@broadcom.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260702055125.557963-1-pavan.chebbi@broadcom.com> References: <20260702055125.557963-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