Re: [PATCH v5 fwctl 3/3] fwctl/bnxt: add DMA buffer support for HWRM commands

Pavan Chebbi <[email protected]>
Newsgroups org.kernel.vger.linux-kernel
Message-ID <CALs4sv3MshxHdQKR33NZvBUQGyfU+AsMJ5tP4KkfTtt-YmY6jg@mail.gmail.com>
On Thu, Aug 6, 2026 at 11:27 PM Jason Gunthorpe <[email protected]> wrote:
>
> On Tue, Jul 07, 2026 at 03:30:19PM +0530, Pavan Chebbi wrote:
>
> > +struct bnxtctl_dma_field {
> > +     size_t offset;          /* offsetof(hwrm_xxx_input, addr_field) */
> > +     u8     dir;
> > +     size_t len_offset;      /* offsetof(hwrm_xxx_input, len_field); 0 if the
> > +                              * command carries no transfer-length field
> > +                              */
> > +     u8     len_width;       /* byte width of the length field: 2 or 4 */
> > +     u8     len_unit;        /* bytes represented by one unit of the length field */
> > +     u32    buf_len;         /* for commands with no length in payload */
> > +};
> > +
> > +struct bnxtctl_cmd_dma_desc {
> > +     u16                      req_type;
> > +     u8                       num_fields;
> > +     u8                       scope_min;
>
> This is a good idea, but it is never used, I think you should search
> for this in the validate function instead of adding all the case
> statements?
>

Yes, agree. Will do.

> Two things worth your eye, both pre-existing rather than introduced
> here: pdi_cmd_buf_addr/pdi_resp_buf_addr are declared __le32 [2] in
> hsi.h, not __le64, so bnxtctl_zero_dma_fields() and
> bnxtctl_map_dma_bufs() are doing a __le64 write through a __le32[2]
> — correct on little-endian but type-punned. And
> HWRM_DBG_PTRACE uses pdi_req_buf_len to size both the to-device and
> from-device buffers, which is what the original literal did but looks
> like it may want a separate response length.
>

Yes will fix the casting to __le64 *. But the assumption of
pdi_req_buf_len for both req and resp is deliberate.
I need to work with FW team to change to change it to have specific
lengths. For now I am confirming the assumption is deliberate.

> > +     { HWRM_DBG_PTRACE, 2, FWCTL_RPC_DEBUG_WRITE,
> > +       sizeof(struct hwrm_dbg_ptrace_input),
> > +       {{ .offset = offsetof(struct hwrm_dbg_ptrace_input, pdi_cmd_buf_addr),
> > +          .dir = FWCTL_BNXT_BUF_TO_DEVICE,
> > +          .len_offset = offsetof(struct hwrm_dbg_ptrace_input, pdi_req_buf_len),
> > +          .len_width = 4, .len_unit = 1 },
> > +        { .offset = offsetof(struct hwrm_dbg_ptrace_input, pdi_resp_buf_addr),
> > +          .dir = FWCTL_BNXT_BUF_FROM_DEVICE,
> > +          .len_offset = offsetof(struct hwrm_dbg_ptrace_input, pdi_req_buf_len),
> > +          .len_width = 4, .len_unit = 1 }} },
>
> AI pointed out that:
>
> 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];
>                                  ^^^
>
> This is really sketchy to cast an array to a __le64. If it really
> means a __le64 then the struct should say that, if it doesn't mean a
> __le64 then this is broken right?
>

Since hsi.h is generated from the HWRM spec rather than hand authored,
it'd need to be fixed at that source.
I will take this as a follow up change that we need to do internally..

>
> > +static const struct bnxtctl_cmd_dma_desc *
> > +bnxtctl_find_dma_desc(u16 req_type)
> > +{
> > +     int i;
>
> unsigned for things that can't be negative
>

Sure,

> > +static int bnxtctl_check_dma_lens(void *cmd, const struct bnxtctl_cmd_dma_desc *desc,
> > +                               const struct fwctl_bnxt_driver_data *dd, u32 *lens)
> > +{
> > +     unsigned int i;
> > +
> > +     for (i = 0; i < dd->num_bufs; i++) {
> > +             const struct bnxtctl_dma_field *f = &desc->fields[i];
> > +             u64 len;
> > +
> > +             if (dd->bufs[i].dir != f->dir)
> > +                     return -EINVAL;
> > +
> > +             if (f->len_offset)
> > +                     len = (u64)bnxtctl_read_len_field(cmd, f) * f->len_unit;
>
> check_mul_overflow is probably nicer than this cast to u64
>

Ok

> > @@ -178,21 +589,59 @@ 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;
> > +     u32 dma_lens[FWCTL_BNXT_MAX_BUFS];
> >       struct bnxt_fw_msg rpc_in = {0};
> > +     unsigned int num_mapped = 0;
> > +     struct input *req = in;
> >       int rc;
>
> Just use {}, the {0} is actually subtly a different thing.
>

Ok

> >       if (desc) {
> >               if (in_len < desc->req_size)
> >                       return ERR_PTR(-EINVAL);
>
> Sadly I don't think you can do this, or perhaps you have to have a
> very clear contract with your FW team.
>
> If they make the struct longer and the longer struct happens to have
> another DMA address in it then it is security broken on old
> kernels. So I suggest you check for exact size for every permitted
> command.
>

Ok, yes, entire purpose we are doing this patch.. Thanks for catching this

> > +/**
> > + * struct fwctl_bnxt_buf - one indirect DMA buffer descriptor
> > + * @addr: Userspace pointer to the payload data.
> > + * @dir:  One of enum fwctl_bnxt_buf_dir.
> > + * @rsvd: Must be zero.
> > + */
> > +struct fwctl_bnxt_buf {
> > +     __aligned_u64 addr;
> > +     __u32         dir;
> > +     __u32         rsvd[3];
> > +};
>
> This is a little weird now, you are taking the length from the data
> buffer itself but passing the u64 through this array?
>
> I feel like it should be consistent and since you have have a nice
> description of the struct layout and DMA direction why not just have
> the kernel get everything from the data buffer itself and do away with
> this driver data?
>

Actually true, once the length got obtained from the main buffer I can
actually do away with driver_data

> Also that table is quite hard to read, I suggest some macros:
>

Ok, yea it does make it look better.

>
> /* Struct has an addr/len pair, but len is multiplied by _unit */
> #define CMD_DATA_UNIT(_struct, _dir, _data, _len, _unit) \
>         { .offset = offsetof(_struct, _data),            \
>           .dir = _dir,                                   \
>           .len_offset = offsetof(_struct, _len),         \
>           .len_width = sizeof(((_struct *)0)->_len),     \
>           .len_unit = _unit }
>
> /* Struct has an addr/len pair with byte length */
> #define CMD_DATA_SIMPLE(_struct, _dir, _data, _len) \
>         CMD_DATA_UNIT(_struct, _dir, _data, _len, 1)
>
> /* Struct has an addr but the length is fixed */
> #define CMD_DATA_FIXED(_struct, _dir, _data, _len) \
>         { .offset = offsetof(_struct, _data), .dir = _dir, .buf_len = _len }
>
> #define CMD_DMAS(_req_type, _scope_min, _struct, _num_fields, ...) \
>         {                                                          \
>                 .req_type = _req_type,                             \
>                 .scope_min = _scope_min,                           \
>                 .req_size = sizeof(_struct),                       \
>                 .num_fields = _num_fields,                         \
>                 .fields = { __VA_ARGS__ },                         \
>         }
>
> #define CMD_DMA_LEN(_req_type, _scope_min, _dir, _struct, _data, _len) \
>         CMD_DMAS(_req_type, _scope_min, _struct, 1,                    \
>                  CMD_DATA_SIMPLE(_struct, _dir, _data, _len))
>
> I fed the macros to AI and it converted thusly:
>
>
> /*
>  * 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[] = {
>         CMD_DMA_LEN(HWRM_NVM_SET_VARIABLE, FWCTL_RPC_CONFIGURATION,
>                     FWCTL_BNXT_BUF_TO_DEVICE,
>                     struct hwrm_nvm_set_variable_input, src_data_addr,
>                     data_len),
>         CMD_DMA_LEN(HWRM_NVM_GET_VARIABLE, FWCTL_RPC_CONFIGURATION,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_nvm_get_variable_input, dest_data_addr,
>                     data_len),
>         CMD_DMA_LEN(HWRM_NVM_READ, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE, struct hwrm_nvm_read_input,
>                     host_dest_addr, len),
>         CMD_DMAS(HWRM_NVM_GET_DIR_ENTRIES, FWCTL_RPC_DEBUG_READ_ONLY,
>                  struct hwrm_nvm_get_dir_entries_input, 1,
>                  CMD_DATA_FIXED(struct hwrm_nvm_get_dir_entries_input,
>                                 FWCTL_BNXT_BUF_FROM_DEVICE, host_dest_addr,
>                                 FWCTL_BNXT_MAX_DMABUF)),
>         CMD_DMA_LEN(HWRM_NVM_WRITE, FWCTL_RPC_DEBUG_WRITE,
>                     FWCTL_BNXT_BUF_TO_DEVICE, struct hwrm_nvm_write_input,
>                     host_src_addr, dir_data_length),
>         CMD_DMA_LEN(HWRM_NVM_MODIFY, FWCTL_RPC_DEBUG_WRITE,
>                     FWCTL_BNXT_BUF_TO_DEVICE, struct hwrm_nvm_modify_input,
>                     host_src_addr, len),
>         CMD_DMA_LEN(HWRM_NVM_RAW_WRITE_BLK, FWCTL_RPC_DEBUG_WRITE_FULL,
>                     FWCTL_BNXT_BUF_TO_DEVICE,
>                     struct hwrm_nvm_raw_write_blk_input, host_src_addr, len),
>         CMD_DMA_LEN(HWRM_NVM_RAW_DUMP, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE, struct hwrm_nvm_raw_dump_input,
>                     host_dest_addr, len),
>
>         CMD_DMA_LEN(HWRM_FW_GET_STRUCTURED_DATA, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_fw_get_structured_data_input, dest_data_addr,
>                     data_len),
>         CMD_DMA_LEN(HWRM_FW_SET_STRUCTURED_DATA, FWCTL_RPC_DEBUG_WRITE,
>                     FWCTL_BNXT_BUF_TO_DEVICE,
>                     struct hwrm_fw_set_structured_data_input, src_data_addr,
>                     data_len),
>         CMD_DMA_LEN(HWRM_FW_LIVEPATCH, FWCTL_RPC_DEBUG_WRITE_FULL,
>                     FWCTL_BNXT_BUF_TO_DEVICE, struct hwrm_fw_livepatch_input,
>                     host_addr, patch_len),
>
>         CMD_DMA_LEN(HWRM_DBG_COREDUMP_LIST, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_dbg_coredump_list_input, host_dest_addr,
>                     host_buf_len),
>         CMD_DMA_LEN(HWRM_DBG_COREDUMP_RETRIEVE, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_dbg_coredump_retrieve_input, host_dest_addr,
>                     host_buf_len),
>         /* read_len32 counts 32-bit words, not bytes (see bnxt_dbg_hwrm_rd_reg()). */
>         CMD_DMAS(HWRM_DBG_READ_DIRECT, FWCTL_RPC_DEBUG_READ_ONLY,
>                  struct hwrm_dbg_read_direct_input, 1,
>                  CMD_DATA_UNIT(struct hwrm_dbg_read_direct_input,
>                                FWCTL_BNXT_BUF_FROM_DEVICE,
>                                host_dest_addr, read_len32, 4)),
>         CMD_DMA_LEN(HWRM_DBG_READ_INDIRECT, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_dbg_read_indirect_input, host_dest_addr,
>                     host_dest_addr_len),
>         CMD_DMA_LEN(HWRM_DBG_SERDES_TEST, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_dbg_serdes_test_input, resp_data_addr,
>                     data_len),
>         CMD_DMA_LEN(HWRM_DBG_TOKEN_CFG, FWCTL_RPC_DEBUG_WRITE_FULL,
>                     FWCTL_BNXT_BUF_TO_DEVICE, struct hwrm_dbg_token_cfg_input,
>                     host_src_addr, dbg_token_len),
>
>         CMD_DMA_LEN(HWRM_QUEUE_DSCP2PRI_QCFG, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_queue_dscp2pri_qcfg_input, dest_data_addr,
>                     dest_data_buffer_size),
>
>         CMD_DMAS(HWRM_PORT_QSTATS, FWCTL_RPC_DEBUG_READ_ONLY,
>                  struct hwrm_port_qstats_input, 2,
>                  CMD_DATA_FIXED(struct hwrm_port_qstats_input,
>                                 FWCTL_BNXT_BUF_FROM_DEVICE, tx_stat_host_addr,
>                                 sizeof(struct tx_port_stats)),
>                  CMD_DATA_FIXED(struct hwrm_port_qstats_input,
>                                 FWCTL_BNXT_BUF_FROM_DEVICE, rx_stat_host_addr,
>                                 sizeof(struct rx_port_stats))),
>         CMD_DMAS(HWRM_PORT_QSTATS_EXT, FWCTL_RPC_DEBUG_READ_ONLY,
>                  struct hwrm_port_qstats_ext_input, 2,
>                  CMD_DATA_SIMPLE(struct hwrm_port_qstats_ext_input,
>                                  FWCTL_BNXT_BUF_FROM_DEVICE, tx_stat_host_addr,
>                                  tx_stat_size),
>                  CMD_DATA_SIMPLE(struct hwrm_port_qstats_ext_input,
>                                  FWCTL_BNXT_BUF_FROM_DEVICE, rx_stat_host_addr,
>                                  rx_stat_size)),
>         CMD_DMAS(HWRM_PORT_QSTATS_EXT_PFC_ADV, FWCTL_RPC_DEBUG_READ_ONLY,
>                  struct hwrm_port_qstats_ext_pfc_adv_input, 2,
>                  CMD_DATA_SIMPLE(struct hwrm_port_qstats_ext_pfc_adv_input,
>                                  FWCTL_BNXT_BUF_FROM_DEVICE,
>                                  tx_pfc_adv_stat_host_addr, pfc_adv_stat_size),
>                  CMD_DATA_SIMPLE(struct hwrm_port_qstats_ext_pfc_adv_input,
>                                  FWCTL_BNXT_BUF_FROM_DEVICE,
>                                  rx_pfc_adv_stat_host_addr, pfc_adv_stat_size)),
>         CMD_DMA_LEN(HWRM_PCIE_QSTATS, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE, struct hwrm_pcie_qstats_input,
>                     pcie_stat_host_addr, pcie_stat_size),
>         CMD_DMA_LEN(HWRM_STAT_GENERIC_QSTATS, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_stat_generic_qstats_input,
>                     generic_stat_host_addr, generic_stat_size),
>         CMD_DMA_LEN(HWRM_STAT_QUERY_ROCE_STATS, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_stat_query_roce_stats_input,
>                     roce_stat_host_addr, roce_stat_size),
>         CMD_DMA_LEN(HWRM_STAT_QUERY_ROCE_STATS_EXT, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_stat_query_roce_stats_ext_input,
>                     roce_stat_host_addr, roce_stat_size),
>
>         CMD_DMA_LEN(HWRM_PORT_EVENTS_LOG, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_port_events_log_input, host_dest_addr,
>                     host_dest_addr_len),
>         CMD_DMA_LEN(HWRM_PORT_PRBS_TEST, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_port_prbs_test_input, resp_data_addr, data_len),
>         CMD_DMA_LEN(HWRM_PORT_DSC_DUMP, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE, struct hwrm_port_dsc_dump_input,
>                     resp_data_addr, data_len),
>
>         /* num_fids counts 16-bit FIDs, not bytes. */
>         CMD_DMAS(HWRM_SCH_GRP_CFG, FWCTL_RPC_DEBUG_WRITE,
>                  struct hwrm_sch_grp_cfg_input, 1,
>                  CMD_DATA_UNIT(struct hwrm_sch_grp_cfg_input,
>                                FWCTL_BNXT_BUF_TO_DEVICE, fid_table_addr,
>                                num_fids, 2)),
>         CMD_DMA_LEN(HWRM_SCH_GRP_QCFG, FWCTL_RPC_DEBUG_READ_ONLY,
>                     FWCTL_BNXT_BUF_FROM_DEVICE, struct hwrm_sch_grp_qcfg_input,
>                     fid_table_addr, fid_table_len),
>
>         CMD_DMA_LEN(HWRM_SELFTEST_RETRIEVE_SERDES_DATA,
>                     FWCTL_RPC_DEBUG_READ_ONLY, FWCTL_BNXT_BUF_FROM_DEVICE,
>                     struct hwrm_selftest_retrieve_serdes_data_input,
>                     resp_data_addr, data_len),
>
>         CMD_DMAS(HWRM_DBG_PTRACE, FWCTL_RPC_DEBUG_WRITE,
>                  struct hwrm_dbg_ptrace_input, 2,
>                  CMD_DATA_SIMPLE(struct hwrm_dbg_ptrace_input,
>                                  FWCTL_BNXT_BUF_TO_DEVICE, pdi_cmd_buf_addr,
>                                  pdi_req_buf_len),
>                  CMD_DATA_SIMPLE(struct hwrm_dbg_ptrace_input,
>                                  FWCTL_BNXT_BUF_FROM_DEVICE, pdi_resp_buf_addr,
>                                  pdi_req_buf_len)),
> };
>
> Can you respin this really fast please to make this cycle?
>

Yes, I will do my best to send in next 12-24 hours. Thanks

> Jason
smime.p7s (application/pkcs7-signature, 5.3 KB) - not displayed
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.