[PATCH net-next v5 10/15] bnxt_en: Add MPC transmit and completion functions
From: Michael Chan <michael.chan@broadcom.com>
Date: 2026-07-10 04:25:02
Subsystem:
broadcom bnxt_en 50 gigabit ethernet driver, networking drivers, the rest · Maintainers:
Michael Chan, Pavan Chebbi, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Add transmit, ring selection, and completion functions for midpath rings. These will be used to send control data to the crypto engines. All TCE/RCE completions are short (16-byte) completions. The long completions logic in bnxt_mpc_cmp() is added for completeness only. Reviewed-by: Andy Gospodarek <redacted> Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com> Signed-off-by: Michael Chan <michael.chan@broadcom.com> --- v5: Add description in commit log that crypto engines use short completions only. v3: https://lore.kernel.org/netdev/20260614072407.2761092-11-michael.chan@broadcom.com/ (local) Use WRITE_ONCE() for TX prod/cons. v2: https://lore.kernel.org/netdev/20260512212105.3488258-11-michael.chan@broadcom.com/ (local) Fix unused variable warnings v1: https://lore.kernel.org/netdev/20260504235836.3019499-11-michael.chan@broadcom.com/ (local) --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 + drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 + drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.c | 157 ++++++++++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.h | 65 ++++++++ 4 files changed, 227 insertions(+)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 4f7042d91078..d8b9c39dda5c 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c@@ -3115,6 +3115,9 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, rx_pkts++; else if (rc == -EBUSY) /* partial completion */ break; + } else if (cmp_type == CMP_TYPE_MPC_CMP) { + if (bnxt_mpc_cmp(bp, cpr, &raw_cons)) + break; } else if (unlikely(cmp_type == CMPL_BASE_TYPE_HWRM_DONE || cmp_type == CMPL_BASE_TYPE_HWRM_FWD_REQ || cmp_type == CMPL_BASE_TYPE_HWRM_ASYNC_EVENT)) {
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 1302c39a7af9..e62b856e78f9 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h@@ -47,6 +47,7 @@ struct tx_bd { __le32 tx_bd_len_flags_type; #define TX_BD_TYPE (0x3f << 0) #define TX_BD_TYPE_SHORT_TX_BD (0x00 << 0) + #define TX_BD_TYPE_MPC_TX_BD (0x08 << 0) #define TX_BD_TYPE_LONG_TX_BD (0x10 << 0) #define TX_BD_FLAGS_PACKET_END (1 << 6) #define TX_BD_FLAGS_NO_CMPL (1 << 7)
@@ -160,6 +161,7 @@ struct tx_cmp { #define CMP_TYPE_RX_TPA_AGG_CMP 22 #define CMP_TYPE_RX_L2_V3_CMP 23 #define CMP_TYPE_RX_L2_TPA_START_V3_CMP 25 + #define CMP_TYPE_MPC_CMP 30 #define CMP_TYPE_STATUS_CMP 32 #define CMP_TYPE_REMOTE_DRIVER_REQ 34 #define CMP_TYPE_REMOTE_DRIVER_RESP 36
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.c
index 40351b7c0b82..a8d757712b38 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.c@@ -418,3 +418,160 @@ void bnxt_hwrm_mpc_ring_free(struct bnxt *bp, bool close_path) } } } + +struct bnxt_tx_ring_info *bnxt_select_mpc_ring(struct bnxt *bp, int ring_type) +{ + struct bnxt_mpc_info *mpc = bp->mpc_info; + int n; + + if (!mpc || ring_type >= BNXT_MPC_TYPE_MAX || + !mpc->mpc_ring_count[ring_type]) + return NULL; + + n = raw_smp_processor_id() % mpc->mpc_ring_count[ring_type]; + return &mpc->mpc_rings[ring_type][n]; +} + +/** + * bnxt_start_xmit_mpc - Transmit message on an MPC ring + * @bp: pointer to bnxt device + * @txr: MPC TX ring structure pointer + * @data: MPC message pointer + * @len: MPC message length + * @handle: Non-zero handle passed back for the completion + * + * This function is called to transmit an MPC message on an MPC TX ring. + * The caller must hold txr->tx_lock. When successful, the HW will return + * a completion and bnxt_crypto_mpc_cmp() will be called with the handle + * passed back. + * + * Return: zero on success, negative error code otherwise: + * ENODEV: MPC TX ring is shutting down. + * EBUSY: MPC TX ring is full + */ +int bnxt_start_xmit_mpc(struct bnxt *bp, struct bnxt_tx_ring_info *txr, + void *data, unsigned int len, unsigned long handle) +{ + u32 bds, total_bds, bd_space, free_size; + struct bnxt_sw_mpc_tx_bd *tx_buf; + struct tx_bd *txbd; + u16 prod; + + if (READ_ONCE(txr->dev_state) == BNXT_DEV_STATE_CLOSING) + return -ENODEV; + + bds = DIV_ROUND_UP(len, sizeof(*txbd)); + total_bds = bds + 1; + free_size = bnxt_tx_avail(bp, txr); + if (free_size < total_bds) + return -EBUSY; + + prod = txr->tx_prod; + txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; + tx_buf = &txr->tx_mpc_buf_ring[RING_TX(bp, prod)]; + tx_buf->handle = handle; + tx_buf->inline_bds = total_bds; + + txbd->tx_bd_len_flags_type = + cpu_to_le32((len << TX_BD_LEN_SHIFT) | TX_BD_TYPE_MPC_TX_BD | + TX_BD_CNT(total_bds)); + txbd->tx_bd_opaque = SET_TX_OPAQUE(bp, txr, prod, total_bds); + + prod = NEXT_TX(prod); + txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; + bd_space = TX_DESC_CNT - TX_IDX(prod); + if (bd_space < bds) { + unsigned int len0 = bd_space * sizeof(*txbd); + + memcpy(txbd, data, len0); + prod += bd_space; + txbd = &txr->tx_desc_ring[TX_RING(bp, prod)][TX_IDX(prod)]; + bds -= bd_space; + len -= len0; + data += len0; + } + memcpy(txbd, data, len); + prod += bds; + WRITE_ONCE(txr->tx_prod, prod); + + /* Sync BD data before updating doorbell */ + wmb(); + bnxt_db_write(bp, &txr->tx_db, prod); + + return 0; +} + +static bool bnxt_mpc_unsolicit(struct mpc_cmp *mpcmp) +{ + u32 client = MPC_CMP_CLIENT_TYPE(mpcmp); + + if (client != MPC_CMP_CLIENT_TCE && client != MPC_CMP_CLIENT_RCE) + return false; + return MPC_CMP_UNSOLICIT_SUBTYPE(mpcmp); +} + +int bnxt_mpc_cmp(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, u32 *raw_cons) +{ + struct bnxt_cmpl_entry cmpl_entry_arr[2]; + struct bnxt_napi *bnapi = cpr->bnapi; + u16 cons = RING_CMP(*raw_cons); + struct mpc_cmp *mpcmp, *mpcmp1; + u32 tmp_raw_cons = *raw_cons; + u32 client, cmpl_num; + u8 type; + + mpcmp = (struct mpc_cmp *) + &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; + type = MPC_CMP_CMP_TYPE(mpcmp); + cmpl_entry_arr[0].cmpl = mpcmp; + cmpl_entry_arr[0].len = sizeof(*mpcmp); + cmpl_num = 1; + if (type == MPC_CMP_TYPE_MID_PATH_LONG) { + tmp_raw_cons = NEXT_RAW_CMP(tmp_raw_cons); + cons = RING_CMP(tmp_raw_cons); + mpcmp1 = (struct mpc_cmp *) + &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]; + + if (!MPC_CMP_VALID(bp, mpcmp1, tmp_raw_cons)) + return -EBUSY; + /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); + if (mpcmp1 == mpcmp + 1) { + cmpl_entry_arr[cmpl_num - 1].len += sizeof(*mpcmp1); + } else { + cmpl_entry_arr[cmpl_num].cmpl = mpcmp1; + cmpl_entry_arr[cmpl_num].len = sizeof(*mpcmp1); + cmpl_num++; + } + } + client = MPC_CMP_CLIENT_TYPE(mpcmp) >> MPC_CMP_CLIENT_SFT; + if (client >= BNXT_MPC_TYPE_MAX) + goto cmp_done; + + if (!bnxt_mpc_unsolicit(mpcmp)) { + struct bnxt_sw_mpc_tx_bd *mpc_buf; + struct bnxt_tx_ring_info *txr; + u16 tx_cons; + u32 opaque; + + opaque = mpcmp->mpc_cmp_opaque; + txr = bnapi->tx_mpc_ring[client]; + tx_cons = txr->tx_cons; + if (TX_OPAQUE_RING(opaque) != txr->tx_napi_idx) { + netdev_warn(bp->dev, "Wrong opaque %x, expected ring %x, cons idx %x\n", + opaque, txr->tx_napi_idx, txr->tx_cons); + goto cmp_done; + } + mpc_buf = &txr->tx_mpc_buf_ring[RING_TX(bp, tx_cons)]; + mpc_buf->handle = 0; + tx_cons += mpc_buf->inline_bds; + WRITE_ONCE(txr->tx_cons, tx_cons); + txr->tx_hw_cons = RING_TX(bp, tx_cons); + } + +cmp_done: + *raw_cons = tmp_raw_cons; + return 0; +}
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.h
index 3210ecf29c76..91fb27ba8090 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_mpc.h@@ -30,11 +30,53 @@ struct bnxt_mpc_info { }; struct bnxt_sw_mpc_tx_bd { + u8 inline_bds; unsigned long handle; }; #define SW_MPC_TXBD_RING_SIZE (sizeof(struct bnxt_sw_mpc_tx_bd) * TX_DESC_CNT) +struct bnxt_cmpl_entry { + void *cmpl; + u32 len; +}; + +struct mpc_cmp { + __le32 mpc_cmp_client_subtype_type; + #define MPC_CMP_TYPE (0x3f << 0) + #define MPC_CMP_TYPE_MID_PATH_SHORT 0x1e + #define MPC_CMP_TYPE_MID_PATH_LONG 0x1f + #define MPC_CMP_SUBTYPE 0xf00 + #define MPC_CMP_SUBTYPE_SFT 8 + #define MPC_CMP_SUBTYPE_SOLICITED (0x0 << 8) + #define MPC_CMP_SUBTYPE_ERR (0x1 << 8) + #define MPC_CMP_SUBTYPE_RESYNC (0x2 << 8) + #define MPC_CMP_CLIENT (0xf << 12) + #define MPC_CMP_CLIENT_SFT 12 + #define MPC_CMP_CLIENT_TCE (0x0 << 12) + #define MPC_CMP_CLIENT_RCE (0x1 << 12) + #define MPC_CMP_CLIENT_TE_CFA (0x2 << 12) + #define MPC_CMP_CLIENT_RE_CFA (0x3 << 12) + u32 mpc_cmp_opaque; + __le32 mpc_cmp_v; + #define MPC_CMP_V (1 << 0) + __le32 mpc_cmp_filler; +}; + +#define MPC_CMP_CMP_TYPE(mpcmp) \ + (le32_to_cpu((mpcmp)->mpc_cmp_client_subtype_type) & MPC_CMP_TYPE) + +#define MPC_CMP_CLIENT_TYPE(mpcmp) \ + (le32_to_cpu((mpcmp)->mpc_cmp_client_subtype_type) & MPC_CMP_CLIENT) + +#define MPC_CMP_UNSOLICIT_SUBTYPE(mpcmp) \ + ((le32_to_cpu((mpcmp)->mpc_cmp_client_subtype_type) & \ + MPC_CMP_SUBTYPE) != MPC_CMP_SUBTYPE_SOLICITED) + +#define MPC_CMP_VALID(bp, mpcmp, raw_cons) \ + (!!((mpcmp)->mpc_cmp_v & cpu_to_le32(MPC_CMP_V)) == \ + !((raw_cons) & (bp)->cp_bit)) + #define BNXT_MPC_CRYPTO_CAP \ (FUNC_QCAPS_RESP_MPC_CHNLS_CAP_TCE | FUNC_QCAPS_RESP_MPC_CHNLS_CAP_RCE)
@@ -64,6 +106,10 @@ void bnxt_free_mpc_rings(struct bnxt *bp); void bnxt_init_mpc_rings(struct bnxt *bp); int bnxt_hwrm_mpc_ring_alloc(struct bnxt *bp); void bnxt_hwrm_mpc_ring_free(struct bnxt *bp, bool close_path); +struct bnxt_tx_ring_info *bnxt_select_mpc_ring(struct bnxt *bp, int ring_type); +int bnxt_start_xmit_mpc(struct bnxt *bp, struct bnxt_tx_ring_info *txr, + void *data, unsigned int len, unsigned long handle); +int bnxt_mpc_cmp(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, u32 *raw_cons); #else static inline void bnxt_alloc_mpc_info(struct bnxt *bp, u8 mpc_chnls_cap) {
@@ -144,5 +190,24 @@ static inline int bnxt_hwrm_mpc_ring_alloc(struct bnxt *bp) static inline void bnxt_hwrm_mpc_ring_free(struct bnxt *bp, bool close_path) { } + +static inline struct bnxt_tx_ring_info *bnxt_select_mpc_ring(struct bnxt *bp, + int ring_type) +{ + return NULL; +} + +static inline int bnxt_start_xmit_mpc(struct bnxt *bp, + struct bnxt_tx_ring_info *txr, void *data, + unsigned int len, unsigned long handle) +{ + return -EOPNOTSUPP; +} + +static inline int bnxt_mpc_cmp(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, + u32 *raw_cons) +{ + return 0; +} #endif /* CONFIG_BNXT_TLS */ #endif /* BNXT_MPC_H */
--
2.51.0