Page MenuHomeFreeBSD

D58606.1794279800.diff
No OneTemporary

Authored By
Unknown
Size
100 KB
Referenced Files
None
Subscribers
None

D58606.1794279800.diff

Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -1334,6 +1334,7 @@
dev/bnxt/bnxt_en/bnxt_coredump.c optional bnxt iflib pci compile-with "${BNXT_C}"
dev/bnxt/bnxt_en/bnxt_ptp.c optional bnxt iflib pci compile-with "${BNXT_C}"
dev/bnxt/bnxt_en/bnxt_mpc.c optional bnxt iflib pci compile-with "${BNXT_C}"
+dev/bnxt/bnxt_en/bnxt_ktls.c optional bnxt iflib pci compile-with "${BNXT_C}"
dev/bnxt/bnxt_en/if_bnxt.c optional bnxt iflib pci compile-with "${BNXT_C}"
dev/bwi/bwimac.c optional bwi
dev/bwi/bwiphy.c optional bwi
Index: sys/dev/bnxt/bnxt_en/bnxt.h
===================================================================
--- sys/dev/bnxt/bnxt_en/bnxt.h
+++ sys/dev/bnxt/bnxt_en/bnxt.h
@@ -238,6 +238,11 @@
#define BNXT_MAX_NUM_QUEUES (BNXT_MAX_L2_QUEUES + BNXT_ROCE_IRQ_COUNT)
+#define BNXT_DEBUG(dev, fmt, ...) do { \
+ if (bootverbose) \
+ device_printf(dev, "" fmt, ##__VA_ARGS__); \
+} while (0)
+
/* Completion related defines */
#define CMP_VALID(cmp, v_bit) \
((!!(((struct cmpl_base *)(cmp))->info3_v & htole32(CMPL_BASE_V))) == !!(v_bit) )
@@ -322,6 +327,7 @@
(offsetof(struct tx_port_stats_ext, counter) / 8)
extern const char bnxt_driver_version[];
+extern const uint16_t bnxt_tx_lhint[];
typedef void (*bnxt_doorbell_tx)(void *, uint16_t idx);
typedef void (*bnxt_doorbell_rx)(void *, uint16_t idx);
typedef void (*bnxt_doorbell_rx_cq)(void *, bool);
@@ -609,11 +615,47 @@
#define TX_RING_MASK(txr) ((txr)->ring_size - 1)
+#define SET_TX_OPAQUE_KTLS(opq, txr, replay, prod, segs) \
+ do { \
+ opq->ktls_replay = (replay); \
+ opq->idx = (prod) & TX_RING_MASK(txr); \
+ opq->bds = (segs); \
+ } while(0);
+
+#define KID_HIGH(kid) ((kid & 0x000fff80) >> 7) /*Upper 13 bits of KID*/
+#define KID_LOW(kid) (kid & 0x0000007f) /*Lower 7 bits of KID*/
+#define TX_BD_FLAGS_CRYPTO_EN (1 << 15)
+
+/* Hand-rolled generic BD views used only for byte-addressable copies of
+ * the kTLS presync command (see bnxt_ktls_pre_xmit()); distinct from the
+ * full HSI tx_bd_short/tx_bd_long types used for normal TX BDs. */
+struct tx_bd {
+ uint32_t tx_bd_len_flags_type;
+#define TX_BD_TYPE (0x3f << 0)
+#define TX_BD_FLAGS_BD_CNT_SHIFT 8
+#define TX_BD_LEN_SHIFT 16
+ uint32_t tx_bd_opaque;
+ uint64_t tx_bd_haddr;
+} __packed;
+
+struct tx_bd_presync {
+ uint32_t tx_bd_len_flags_type;
+#define TX_BD_TYPE_PRESYNC_TX_BD (0x09 << 0)
+ uint32_t tx_bd_opaque;
+ uint32_t tx_bd_kid;
+ uint32_t tx_bd_unused;
+} __packed;
+
struct bnxt_sw_mpc_tx_bd {
uint8_t inline_bds;
unsigned long handle;
};
+struct bnxt_sw_tx_bd {
+ uint8_t is_replay;
+ uint8_t inline_bds;
+};
+
struct bnxt_ring {
uint64_t paddr;
vm_offset_t doorbell;
@@ -632,7 +674,11 @@
uint16_t prod; /* MPC TX ring producer index */
uint16_t cons; /* MPC TX ring consumer index */
struct mtx tx_lock; /* MPC TX ring lock */
- struct bnxt_sw_mpc_tx_bd *tx_mpc_buf_ring;
+ union {
+ struct bnxt_sw_tx_bd *tx_buf_ring;
+ struct bnxt_sw_mpc_tx_bd *tx_mpc_buf_ring;
+ };
+ struct bnxt_replay_pkt *replay_pkt;
struct bnxt_full_tpa_start *tpa_start;
union {
u64 db_key64;
@@ -861,6 +907,7 @@
#define BNXT_CTX_FTQM HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_FP_TQM_RING
#define BNXT_CTX_MRAV HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_MRAV
#define BNXT_CTX_TIM HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_TIM
+#define BNXT_CTX_TCK HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_TX_CK
#define BNXT_CTX_TKC HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_TKC
#define BNXT_CTX_RKC HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_RKC
#define BNXT_CTX_MTQM HWRM_FUNC_BACKING_STORE_CFG_V2_INPUT_TYPE_MP_TQM_RING
@@ -910,6 +957,20 @@
struct bnxt_ctx_mem_type ctx_arr[BNXT_CTX_V2_MAX];
};
+enum bnxt_tls_rtpe {
+ BNXT_CRYPTO_TYPE_KTLS = 0,
+ BNXT_CRYPTO_TYPE_QUIC,
+};
+
+struct bnxt_hw_tls_resc {
+ uint32_t min_tx_key_ctxs;
+ uint32_t max_tx_key_ctxs;
+ uint32_t resv_tx_key_ctxs;
+ uint32_t min_rx_key_ctxs;
+ uint32_t max_rx_key_ctxs;
+ uint32_t resv_rx_key_ctxs;
+};
+
struct bnxt_hw_resc {
uint16_t min_rsscos_ctxs;
uint16_t max_rsscos_ctxs;
@@ -937,6 +998,7 @@
uint16_t max_nqs;
uint16_t max_irqs;
uint16_t resv_irqs;
+ struct bnxt_hw_tls_resc tls_resc[2];
};
enum bnxt_type_ets {
@@ -1350,6 +1412,7 @@
#define BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO BIT_ULL(47)
#define BNXT_FW_CAP_ENABLE_RDMA_SRIOV BIT_ULL(48)
#define BNXT_FW_CAP_RSS_TCAM BIT_ULL(49)
+ #define BNXT_FW_CAP_KTLS_SUPPORTED BIT_ULL(50)
#define BNXT_FLAG_TX_COAL_CMPL BIT_ULL(51)
#define BNXT_FW_CAP_SW_MAX_RESOURCE_LIMITS BIT_ULL(61)
@@ -1455,6 +1518,12 @@
bool rx_ts_enabled;
struct bnxt_mpc_info *mpc_info;
+ struct bnxt_tls_info *ktls_info;
+ struct sysctl_ctx_list ktls_stats;
+ struct sysctl_oid *ktls_stats_oid;
+ struct sysctl_ctx_list mpc_cmp_time_stats;
+ struct sysctl_oid *mpc_cmp_time_stats_oid;
+ uint32_t max_ktls_entries;
#define BNXT_CAGR_CQCOAL_OFFSET 0xc00
#define BNXT_CAGR_NQAGG_MAXTIMER 0x5930000
@@ -1608,4 +1677,10 @@
bit_clear(bmap, nr);
return (1);
}
+
+int bnxt_tls_snd_tag_alloc(if_t ifp,
+ union if_snd_tag_alloc_params *params,
+ struct m_snd_tag **ppmt);
+int bnxt_ktls_xmit(struct bnxt_softc* softc, struct bnxt_ring* txr,
+ struct mbuf** ppmb, uint16_t* lflags, uint32_t* kid, if_pkt_info_t pi);
#endif /* _BNXT_H */
Index: sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
===================================================================
--- sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
+++ sys/dev/bnxt/bnxt_en/bnxt_hwrm.c
@@ -30,9 +30,12 @@
#include <sys/endian.h>
#include <linux/pci.h>
+#include "opt_kern_tls.h"
+
#include "bnxt.h"
#include "bnxt_hwrm.h"
#include "bnxt_mpc.h"
+#include "bnxt_ktls.h"
#include "hsi_struct_def.h"
#include "bnxt_coredump.h"
@@ -789,11 +792,21 @@
hw_resc->min_stat_ctxs = le16toh(resp->min_stat_ctx);
hw_resc->max_stat_ctxs = le16toh(resp->max_stat_ctx);
+ {
+ struct bnxt_hw_tls_resc *tls_resc =
+ &hw_resc->tls_resc[BNXT_CRYPTO_TYPE_KTLS];
+
+ tls_resc->min_tx_key_ctxs = le32toh(resp->min_ktls_tx_key_ctxs);
+ tls_resc->max_tx_key_ctxs = le32toh(resp->max_ktls_tx_key_ctxs);
+ tls_resc->min_rx_key_ctxs = le32toh(resp->min_ktls_rx_key_ctxs);
+ tls_resc->max_rx_key_ctxs = le32toh(resp->max_ktls_rx_key_ctxs);
+ }
+
if (BNXT_CHIP_P5_PLUS(softc)) {
hw_resc->max_nqs = hw_resc->max_irqs = le16toh(resp->max_msix);
hw_resc->max_hw_ring_grps = hw_resc->max_rx_rings;
}
-
+
if (BNXT_PF(softc)) {
struct bnxt_pf_info *pf = &softc->pf;
@@ -1206,6 +1219,11 @@
(void *)softc->hwrm_cmd_resp.idi_vaddr;
struct bnxt_func_info *func = &softc->func;
uint32_t flags, flags_ext, flags_ext2;
+#if defined(KERN_TLS) && defined(KTLS_IFLIB_SUPPORT)
+ bool ktls_fw_supported = false;
+ uint16_t ktls_max_keys = 0, ktls_ctxs_per_partition = 0;
+ bool ktls_partition_cap = false;
+#endif
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCAPS);
req.fid = htole16(0xffff);
@@ -1258,6 +1276,21 @@
if (BNXT_PF(softc) && (flags_ext & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT_ECN_STATS_SUPPORTED))
softc->fw_cap |= BNXT_FW_CAP_ECN_STATS;
+#if defined(KERN_TLS) && defined(KTLS_IFLIB_SUPPORT)
+ if (flags_ext & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT_KTLS_SUPPORTED) {
+ softc->fw_cap |= BNXT_FW_CAP_KTLS_SUPPORTED;
+ /*
+ * Only extract the fields needed here; the actual alloc/free
+ * work happens after BNXT_HWRM_UNLOCK() below, since
+ * bnxt_free_ktls_info() can sleep (taskqueue_quiesce(),
+ * uma_zdestroy()) and must not run with hwrm_lock held.
+ */
+ ktls_fw_supported = true;
+ ktls_max_keys = le16toh(resp->max_key_ctxs_alloc);
+ ktls_partition_cap = BNXT_PARTITION_CAP(resp);
+ ktls_ctxs_per_partition = le16toh(resp->ctxs_per_partition);
+ }
+#endif
if (flags_ext & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT_PTP_PPS_SUPPORTED)
softc->fw_cap |= BNXT_FW_CAP_PTP_PPS;
if (flags_ext & HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT_PTP_PTM_SUPPORTED)
@@ -1358,6 +1391,23 @@
if (BNXT_PF(softc))
bnxt_alloc_mpc_info(softc, resp->mpc_chnls_cap);
+ BNXT_HWRM_UNLOCK(softc);
+#if defined(KERN_TLS) && defined(KTLS_IFLIB_SUPPORT)
+ if (ktls_fw_supported) {
+ bnxt_alloc_ktls_info(softc, ktls_max_keys, ktls_partition_cap,
+ ktls_ctxs_per_partition);
+ /*
+ * HW Tx completion coalescing is not used with HW KTLS; the
+ * driver expects ordinary per-packet TX completions on that path.
+ */
+ if (softc->ktls_info != NULL)
+ softc->fw_cap &= ~BNXT_FLAG_TX_COAL_CMPL;
+ } else {
+ bnxt_free_ktls_info(softc);
+ }
+#endif
+ return rc;
+
fail:
BNXT_HWRM_UNLOCK(softc);
return rc;
@@ -1453,6 +1503,8 @@
struct hwrm_func_qcfg_output *resp =
(void *)softc->hwrm_cmd_resp.idi_vaddr;
struct bnxt_func_qcfg *fn_qcfg = &softc->fn_qcfg;
+ struct bnxt_hw_resc *hw_resc = &softc->hw_resc;
+ struct bnxt_hw_tls_resc *tls_resc;
bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_QCFG);
req.fid = htole16(0xffff);
@@ -1519,6 +1571,10 @@
if (flags & HWRM_FUNC_QCFG_OUTPUT_FLAGS_ENABLE_RDMA_SRIOV)
softc->fw_cap |= BNXT_FW_CAP_ENABLE_RDMA_SRIOV;
+ tls_resc = &hw_resc->tls_resc[BNXT_CRYPTO_TYPE_KTLS];
+ tls_resc->resv_tx_key_ctxs = le32toh(resp->num_ktls_tx_key_ctxs);
+ tls_resc->resv_rx_key_ctxs = le32toh(resp->num_ktls_rx_key_ctxs);
+
if (softc->db_size)
goto end;
@@ -2470,6 +2526,7 @@
req.num_rx_rings = htole16(BNXT_MAX_NUM_QUEUES);
req.num_vnics = htole16(BNXT_MAX_NUM_QUEUES);
req.num_stat_ctxs = htole16(BNXT_MAX_NUM_QUEUES * 2);
+ bnxt_hwrm_reserve_pf_key_ctxs(softc, &req, BNXT_CRYPTO_TYPE_KTLS);
return hwrm_send_message(softc, &req, sizeof(req));
}
Index: sys/dev/bnxt/bnxt_en/bnxt_ktls.h
===================================================================
--- /dev/null
+++ sys/dev/bnxt/bnxt_en/bnxt_ktls.h
@@ -0,0 +1,414 @@
+/*
+ * Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2026 Broadcom, All Rights Reserved.
+ * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BNXT_KTLS_H
+#define BNXT_KTLS_H
+
+#include <sys/ktls.h>
+#include <sys/queue.h>
+#include <sys/bitstring.h>
+#include <sys/condvar.h>
+#include <sys/taskqueue.h>
+#include <machine/atomic.h>
+
+#include "bnxt.h"
+#include "bnxt_mpc.h"
+
+#define BNXT_TX_CRYPTO_KEY_TYPE HWRM_FUNC_KEY_CTX_ALLOC_INPUT_KEY_CTX_TYPE_TX
+#define BNXT_RX_CRYPTO_KEY_TYPE HWRM_FUNC_KEY_CTX_ALLOC_INPUT_KEY_CTX_TYPE_RX
+
+#define BNXT_PARTITION_CAP_BITS \
+ (HWRM_FUNC_QCAPS_OUTPUT_XID_PARTITION_CAP_TX_CK | \
+ HWRM_FUNC_QCAPS_OUTPUT_XID_PARTITION_CAP_RX_CK)
+
+#define BNXT_PARTITION_CAP(resp) \
+ ((le32toh((resp)->flags_ext2) & \
+ HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT2_KEY_XID_PARTITION_SUPPORTED) && \
+ ((le16toh((resp)->xid_partition_cap) & \
+ BNXT_PARTITION_CAP_BITS) == BNXT_PARTITION_CAP_BITS))
+
+#define BNXT_KID_BATCH_SIZE 128
+
+
+#define bnxt_u64_set(counter, val) \
+ do { \
+ counter_u64_zero(counter); \
+ counter_u64_add(counter, val); \
+ } while (0)
+
+#define BNXT_KTLS_ENTRIES_DEFAULT 102400
+#define BNXT_KTLS_MAX_ENTRIES 512000
+
+struct bnxt_kid_info {
+ TAILQ_ENTRY(bnxt_kid_info) list;
+ uint32_t start_id;
+ uint32_t count;
+ bitstr_t *ids;
+};
+
+struct bnxt_kctx {
+ TAILQ_HEAD(, bnxt_kid_info) list;
+ /* to serialize update to the linked list and total_alloc */
+ struct mtx lock;
+ struct cv alloc_pending_cv;
+ uint8_t type;
+ uint32_t total_alloc;
+ uint32_t max_ctx;
+ volatile uint32_t alloc_pending;
+#define BNXT_KCTX_ALLOC_PENDING_MAX 8
+ bitstr_t *partition_bmap;
+ int partition_bmap_nbits; /* number of bits in partition_bmap */
+ unsigned int next;
+};
+
+#define BNXT_KCTX_ALLOC_OK(kctx) \
+ (atomic_load_32(&((kctx)->alloc_pending)) < BNXT_KCTX_ALLOC_PENDING_MAX)
+
+#define BNXT_MAX_CRYPTO_KEY_TYPE (BNXT_RX_CRYPTO_KEY_TYPE + 1)
+
+enum bnxt_ktls_counters {
+ BNXT_KTLS_TX_ADD = 0,
+ BNXT_KTLS_TX_DEL,
+ BNXT_KTLS_TX_HW_PKT,
+ BNXT_KTLS_TX_FAILED,
+ BNXT_KTLS_TX_OOO,
+ BNXT_KTLS_TX_RETRANS,
+ BNXT_KTLS_TX_REPLAY,
+ BNXT_KTLS_TX_SEQ_FWD,
+ BNXT_KTLS_TX_SEQ_FWD_TLS_HDR,
+ BNXT_KTLS_TX_SEQ_FWD_SILENT_DROPS,
+ BNXT_KTLS_TX_SEQ_FWD_REPLAY,
+ BNXT_KTLS_TX_MBUF_ALLOCS,
+ BNXT_KTLS_TX_MBUF_FREES,
+ BNXT_KTLS_TX_MBUF_ERRORS,
+ BNXT_KTLS_RX_ADD,
+ BNXT_KTLS_RX_DEL,
+ BNXT_KTLS_RX_HW_PKT,
+ BNXT_KTLS_RX_SW_PKT,
+ BNXT_KTLS_RX_RESYNC_REQ,
+ BNXT_KTLS_RX_RESYNC_ACK,
+ BNXT_KTLS_RX_RESYNC_DISCARD,
+ BNXT_KTLS_RX_RESYNC_NAK,
+ BNXT_KTLS_MAX_COUNTERS,
+};
+
+enum bnxt_mpc_cmp_time_counters {
+ BNXT_MPC_CMP_TIME_1US = 0,
+ BNXT_MPC_CMP_TIME_1_5US,
+ BNXT_MPC_CMP_TIME_5_10US,
+ BNXT_MPC_CMP_TIME_10_15US,
+ BNXT_MPC_CMP_TIME_15_20US,
+ BNXT_MPC_CMP_TIME_20_25US,
+ BNXT_MPC_CMP_TIME_25_50US,
+ BNXT_MPC_CMP_TIME_50_100US,
+ BNXT_MPC_CMP_TIME_100_200US,
+ BNXT_MPC_CMP_TIME_200_500US,
+ BNXT_MPC_CMP_TIME_500_1000US,
+ BNXT_MPC_CMP_TIME_1000_1500US,
+ BNXT_MPC_CMP_TIME_1500_2000US,
+ BNXT_MPC_CMP_TIME_2000_2500US,
+ BNXT_MPC_CMP_TIME_2500_3000US,
+ BNXT_MPC_CMP_TIME_3000_3500US,
+ BNXT_MPC_CMP_TIME_3500_4000US,
+ BNXT_MPC_CMP_TIME_4000_4500US,
+ BNXT_MPC_CMP_TIME_4500_5000US,
+ BNXT_MPC_CMP_TIME_5000_PLUS_US,
+ BNXT_MPC_CMP_TIME_MAX_COUNTERS,
+};
+
+enum bnxt_ktls_err_counters {
+ BNXT_KTLS_TX_DEV_ADD_FAILED = 0,
+ BNXT_KTLS_TX_MPC_TIMEOUT,
+ BNXT_KTLS_TX_UNINITIALIZED,
+ BNXT_KTLS_TX_CTX_ALLOC_FAILED,
+ BNXT_KTLS_TX_MPC_FAILED,
+ BNXT_KTLS_TX_TCE_NOT_READY,
+ BNXT_KTLS_TX_TCE_READY_DELAYED,
+ BNXT_KTLS_TX_TCE_BAD,
+ BNXT_KTLS_TX_UNSUPPORTED_TLS_HDR,
+ BNXT_KTLS_TX_INVALID_TAG,
+ BNXT_KTLS_TX_ZERO_TCP_PAYLEN,
+ BNXT_KTLS_TX_INVALID_REC_SN,
+ BNXT_KTLS_TX_TCE_FREE,
+ BNXT_KTLS_ERR_MAX_COUNTERS,
+};
+
+struct bnxt_tls_info
+{
+ uint16_t max_key_ctxs_alloc;
+ uint16_t ctxs_per_partition;
+ uint8_t partition_mode : 1;
+
+ struct bnxt_kctx kctx[BNXT_MAX_CRYPTO_KEY_TYPE];
+
+ uma_zone_t mpc_zone;
+
+ volatile uint32_t pending;
+ volatile uint32_t snd_tag_alloc_ref; /* threads inside bnxt_tls_snd_tag_alloc() */
+
+#define BNXT_MAX_TLS_FILTER 460
+
+ bus_dma_tag_t dma_tag;
+
+ struct taskqueue *tq;
+ uma_zone_t zone;
+ uint32_t max_resources; /* max number of resources */
+ volatile uint32_t num_resources; /* current number of resources */
+ int init; /* set when ready */
+ char zname[32];
+
+ counter_u64_t counters[BNXT_KTLS_MAX_COUNTERS];
+ counter_u64_t err_counters[BNXT_KTLS_ERR_MAX_COUNTERS];
+
+ counter_u64_t mpc_cmp_time[BNXT_MPC_CMP_TIME_MAX_COUNTERS];
+};
+
+#define tck kctx[BNXT_TX_CRYPTO_KEY_TYPE]
+#define rck kctx[BNXT_RX_CRYPTO_KEY_TYPE]
+
+#define BNXT_TLS_TAG_LOCK(tag) mtx_lock(&(tag)->lock)
+#define BNXT_TLS_TAG_UNLOCK(tag) mtx_unlock(&(tag)->lock)
+
+struct bnxt_replay_pkt {
+ bus_dmamap_t dma_map;
+ struct mbuf *mbuf;
+};
+
+struct bnxt_ktls_offload_ctx_tx
+{
+ struct m_snd_tag tag;
+ uint32_t tcp_seq_no;
+ uint64_t rec_seq;
+ uint32_t kid;
+ struct mtx lock;
+ uint8_t state;
+#define BNXT_TLS_STATE_INIT 0
+#define BNXT_TLS_STATE_READY 1
+#define BNXT_TLS_STATE_BAD 2
+#define BNXT_TLS_STATE_FREE 3
+#define BNXT_TLS_STATE_FREED 4
+ struct bnxt_tls_info *ktls;
+ uint64_t inorder_rec_sn;
+ uint32_t inorder_paylen;
+ uint32_t inorder_seq;
+ struct tls_session_params crypto_info;
+ int enobufs;
+#define MAX_MPC_RETRY 3
+ int mpc_retry;
+ struct timeval start;
+ struct timeval end;
+ struct task work_task;
+};
+
+/* Resync timeout: 2500 ms in ticks */
+#define BNXT_KTLS_RESYNC_TMO ((2500 * hz) / 1000)
+#define BNXT_KTLS_MAX_RESYNC_BYTES 32768
+
+#define BNXT_KTLS_MAX_REPLAY_MSS 9000
+
+struct ce_add_cmd
+{
+ uint32_t ver_algo_kid_opcode;
+#define CE_ADD_CMD_OPCODE_MASK 0xfUL
+#define CE_ADD_CMD_OPCODE_SFT 0
+#define CE_ADD_CMD_OPCODE_ADD 0x1UL
+#define CE_ADD_CMD_KID_MASK 0xfffff0UL
+#define CE_ADD_CMD_KID_SFT 4
+#define CE_ADD_CMD_ALGORITHM_MASK 0xf000000UL
+#define CE_ADD_CMD_ALGORITHM_SFT 24
+#define CE_ADD_CMD_ALGORITHM_AES_GCM_128 0x1000000UL
+#define CE_ADD_CMD_ALGORITHM_AES_GCM_256 0x2000000UL
+#define CE_ADD_CMD_VERSION_MASK 0xf0000000UL
+#define CE_ADD_CMD_VERSION_SFT 28
+#define CE_ADD_CMD_VERSION_TLS1_2 (0x0UL << 28)
+#define CE_ADD_CMD_VERSION_TLS1_3 (0x1UL << 28)
+ uint8_t ctx_kind;
+#define CE_ADD_CMD_CTX_KIND_MASK 0x1fUL
+#define CE_ADD_CMD_CTX_KIND_SFT 0
+#define CE_ADD_CMD_CTX_KIND_CK_TX 0x11UL
+#define CE_ADD_CMD_CTX_KIND_CK_RX 0x12UL
+ uint8_t unused0[3];
+ uint8_t salt[4];
+ uint8_t unused1[4];
+ uint32_t pkt_tcp_seq_num;
+ uint32_t tls_header_tcp_seq_num;
+ uint8_t record_seq_num[8];
+ uint8_t session_key[32];
+ uint8_t addl_iv[8];
+};
+
+struct ce_delete_cmd
+{
+ uint32_t ctx_kind_kid_opcode;
+#define CE_DELETE_CMD_OPCODE_MASK 0xfUL
+#define CE_DELETE_CMD_OPCODE_SFT 0
+#define CE_DELETE_CMD_OPCODE_DEL 0x2UL
+#define CE_DELETE_CMD_KID_MASK 0xfffff0UL
+#define CE_DELETE_CMD_KID_SFT 4
+#define CE_DELETE_CMD_CTX_KIND_MASK 0x1f000000UL
+#define CE_DELETE_CMD_CTX_KIND_SFT 24
+#define CE_DELETE_CMD_CTX_KIND_CK_TX (0x11UL << 24)
+#define CE_DELETE_CMD_CTX_KIND_CK_RX (0x12UL << 24)
+};
+
+struct ce_resync_resp_ack_cmd
+{
+ uint32_t resync_status_kid_opcode;
+#define CE_RESYNC_RESP_ACK_CMD_OPCODE_MASK 0xfUL
+#define CE_RESYNC_RESP_ACK_CMD_OPCODE_SFT 0
+#define CE_RESYNC_RESP_ACK_CMD_OPCODE_RESYNC 0x3UL
+#define CE_RESYNC_RESP_ACK_CMD_KID_MASK 0xfffff0UL
+#define CE_RESYNC_RESP_ACK_CMD_KID_SFT 4
+#define CE_RESYNC_RESP_ACK_CMD_RESYNC_STATUS 0x1000000UL
+#define CE_RESYNC_RESP_ACK_CMD_RESYNC_STATUS_ACK (0x0UL << 24)
+#define CE_RESYNC_RESP_ACK_CMD_RESYNC_STATUS_NAK (0x1UL << 24)
+ uint32_t resync_record_tcp_seq_num;
+ uint8_t resync_record_seq_num[8];
+};
+
+#define resync_record_seq_num_end resync_record_seq_num[7]
+
+#define CE_CMD_KID_MASK 0xfffff0UL
+#define CE_CMD_KID_SFT 4
+
+#define CE_CMD_KID(cmd_p) \
+ ((*(uint32_t*)(cmd_p)&CE_CMD_KID_MASK) >> CE_CMD_KID_SFT)
+
+#define BNXT_KMPC_OPAQUE(client, kid) (((client) << 24) | (kid))
+
+#define BNXT_INV_KMPC_OPAQUE 0xffffffff
+
+struct ce_cmpl
+{
+ uint16_t client_subtype_type;
+#define CE_CMPL_TYPE_MASK 0x3fUL
+#define CE_CMPL_TYPE_SFT 0
+#define CE_CMPL_TYPE_MID_PATH_SHORT 0x1eUL
+#define CE_CMPL_SUBTYPE_MASK 0xf00UL
+#define CE_CMPL_SUBTYPE_SFT 8
+#define CE_CMPL_SUBTYPE_SOLICITED (0x0UL << 8)
+#define CE_CMPL_SUBTYPE_ERR (0x1UL << 8)
+#define CE_CMPL_SUBTYPE_RESYNC (0x2UL << 8)
+#define CE_CMPL_MP_CLIENT_MASK 0xf000UL
+#define CE_CMPL_MP_CLIENT_SFT 12
+#define CE_CMPL_MP_CLIENT_TCE (0x0UL << 12)
+#define CE_CMPL_MP_CLIENT_RCE (0x1UL << 12)
+ uint16_t status;
+#define CE_CMPL_STATUS_MASK 0xfUL
+#define CE_CMPL_STATUS_SFT 0
+#define CE_CMPL_STATUS_OK 0x0UL
+#define CE_CMPL_STATUS_CTX_LD_ERR 0x1UL
+#define CE_CMPL_STATUS_FID_CHK_ERR 0x2UL
+#define CE_CMPL_STATUS_CTX_VER_ERR 0x3UL
+#define CE_CMPL_STATUS_DST_ID_ERR 0x4UL
+#define CE_CMPL_STATUS_MP_CMD_ERR 0x5UL
+ uint32_t opaque;
+ uint32_t v;
+#define CE_CMPL_V 0x1UL
+ uint32_t kid;
+#define CE_CMPL_KID_MASK 0xfffffUL
+#define CE_CMPL_KID_SFT 0
+};
+
+#define CE_CMPL_STATUS(ce_cmpl) \
+ (le16toh((ce_cmpl)->status) & CE_CMPL_STATUS_MASK)
+
+#define CE_CMPL_KID(ce_cmpl) (le32toh((ce_cmpl)->kid) & CE_CMPL_KID_MASK)
+
+#define BNXT_SALT_LEN 4
+#define BNXT_ADDL_IV_LEN_TLS1_3 8
+#define BNXT_EXPLICIT_NONCE_LEN 8
+
+struct crypto_prefix_cmd
+{
+ uint32_t flags;
+#define CRYPTO_PREFIX_CMD_FLAGS_UPDATE_IN_ORDER_VAR 0x1UL
+#define CRYPTO_PREFIX_CMD_FLAGS_FULL_REPLAY_RETRAN 0x2UL
+ uint32_t header_tcp_seq_num;
+ uint32_t start_tcp_seq_num;
+ uint32_t end_tcp_seq_num;
+ uint8_t explicit_nonce[8];
+ uint8_t record_seq_num[8];
+};
+
+#define CRYPTO_PREFIX_CMD_SIZE ((uint32_t)sizeof(struct crypto_prefix_cmd))
+#define CRYPTO_PREFIX_CMD_BDS (CRYPTO_PREFIX_CMD_SIZE / sizeof(struct tx_bd))
+#define CRYPTO_PRESYNC_BDS (CRYPTO_PREFIX_CMD_BDS + 1)
+
+#define CRYPTO_PRESYNC_BD_CMD \
+ (htole32((CRYPTO_PREFIX_CMD_SIZE << TX_BD_LEN_SHIFT) | \
+ (CRYPTO_PRESYNC_BDS << TX_BD_FLAGS_BD_CNT_SHIFT) | \
+ TX_BD_TYPE_PRESYNC_TX_BD))
+
+#define BNXT_METADATA_OFF(len) ALIGN(len, 32)
+
+struct bnxt_crypto_cmd_ctx
+{
+ struct ce_cmpl ce_cmp;
+ struct bnxt_ktls_offload_ctx_tx *kctx_tx;
+};
+
+static inline bool before(uint32_t seq1, uint32_t seq2)
+{
+ return (int32_t)(seq1 - seq2) < 0;
+}
+#define after(seq2, seq1) before(seq1, seq2)
+
+static inline bool bnxt_ktls_busy(struct bnxt_softc* bp)
+{
+ return bp->ktls_info && atomic_load_32(&bp->ktls_info->pending) > 0;
+}
+
+void bnxt_alloc_ktls_info(struct bnxt_softc* bp, uint16_t max_keys,
+ bool partition_cap, uint16_t ctxs_per_partition);
+void bnxt_free_ktls_info(struct bnxt_softc* bp);
+void bnxt_free_ktls_counters(struct bnxt_softc* softc);
+void bnxt_alloc_ktls_counters(struct bnxt_softc* softc);
+void bnxt_hwrm_reserve_pf_key_ctxs(struct bnxt_softc* bp,
+ struct hwrm_func_cfg_input* req,
+ uint8_t type);
+int bnxt_ktls_init(struct bnxt_softc* bp);
+int bnxt_xmit_crypto_cmd(struct bnxt_softc* softc,
+ void* cmd, uint len,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx);
+int bnxt_key_ctx_alloc_one(struct bnxt_softc* bp, struct bnxt_kctx* kctx,
+ uint32_t* id, uint8_t type);
+void bnxt_free_one_kctx(struct bnxt_kctx* kctx, uint32_t id, device_t dev);
+int bnxt_set_partition_mode(struct bnxt_softc* bp);
+int bnxt_hwrm_key_ctx_alloc(struct bnxt_softc* bp, struct bnxt_kctx* kctx,
+ uint16_t num, uint32_t* id, uint8_t type);
+void bnxt_ktls_mpc_cmp(struct bnxt_softc* bp, uint32_t client,
+ unsigned long handle, struct bnxt_cmpl_entry cmpl[],
+ uint32_t entries);
+void bnxt_ktls_del_all(struct bnxt_softc *bp);
+void bnxt_clear_ktls(struct bnxt_softc *bp);
+int
+bnxt_alloc_ktls_rexmit_mbuf(struct bnxt_softc *softc, struct bnxt_ring *txr);
+void
+bnxt_free_ktls_rexmit_mbuf(struct bnxt_ring *txr);
+#endif
Index: sys/dev/bnxt/bnxt_en/bnxt_ktls.c
===================================================================
--- /dev/null
+++ sys/dev/bnxt/bnxt_en/bnxt_ktls.c
@@ -0,0 +1,2066 @@
+/*
+ * Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2026 Broadcom, All Rights Reserved.
+ * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/stdatomic.h>
+#include <sys/ktls.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/kernel.h>
+#include <sys/counter.h>
+#include <sys/kthread.h>
+#include <sys/bitstring.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <machine/atomic.h>
+#include <vm/uma.h>
+
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/pfil.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_lro.h>
+#include <netinet/in_pcb.h>
+#include <netinet/tcp_var.h>
+
+#include "opt_kern_tls.h"
+#include "opt_rss.h"
+#include "opt_ratelimit.h"
+
+#include "bnxt.h"
+#include "bnxt_hwrm.h"
+#include "bnxt_ktls.h"
+#include "bnxt_mpc.h"
+
+#include <opencrypto/cryptodev.h>
+
+#ifdef KERN_TLS
+
+static if_snd_tag_free_t bnxt_tls_snd_tag_free;
+
+static const struct if_snd_tag_sw bnxt_tls_snd_tag_sw = {
+ .snd_tag_free = bnxt_tls_snd_tag_free,
+ .type = IF_SND_TAG_TYPE_TLS
+};
+static int bnxt_ktls_dev_add(struct bnxt_softc* softc,
+ const struct tls_session_params* en,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx);
+static void bnxt_ktls_dev_del(struct bnxt_softc* softc,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx);
+static int bnxt_crypto_del(struct bnxt_softc* softc,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx,
+ uint8_t type);
+static void bnxt_tls_work(void *context, int pending);
+static inline void
+bnxt_calc_mpc_cmp_time(struct bnxt_softc* softc, unsigned long rtt);
+
+static int
+bnxt_tls_tag_import(void *arg, void **store, int cnt, int domain, int flags)
+{
+ struct bnxt_ktls_offload_ctx_tx *kctx_tx;
+ int i;
+
+ for (i = 0; i != cnt; i++) {
+ kctx_tx = malloc(sizeof(*kctx_tx), M_DEVBUF, flags | M_ZERO);
+ if (kctx_tx == NULL)
+ return (i);
+ TASK_INIT(&kctx_tx->work_task, 0, bnxt_tls_work, kctx_tx);
+ store[i] = kctx_tx;
+ }
+ return (i);
+}
+
+static void
+bnxt_tls_tag_release(void *arg, void **store, int cnt)
+{
+ struct bnxt_ktls_offload_ctx_tx *kctx_tx;
+ if_ctx_t ctx;
+ struct bnxt_softc* priv;
+ int i;
+
+ for (i = 0; i != cnt; i++) {
+ kctx_tx = store[i];
+ if (kctx_tx->tag.ifp) {
+ ctx = if_getsoftc(kctx_tx->tag.ifp);
+ priv = iflib_get_softc(ctx);
+ if (priv->ktls_info->tq)
+ taskqueue_drain(priv->ktls_info->tq, &kctx_tx->work_task);
+ }
+ free(kctx_tx, M_DEVBUF);
+ }
+}
+
+static void
+bnxt_tls_tag_zfree(struct bnxt_ktls_offload_ctx_tx *kctx_tx)
+{
+ /* make sure any unhandled taskqueue events are ignored */
+ kctx_tx->state = BNXT_TLS_STATE_FREED;
+
+ /* avoid leaking keys */
+ memset(&kctx_tx->crypto_info, 0, sizeof(kctx_tx->crypto_info));
+
+ /* return tag to UMA */
+ uma_zfree(kctx_tx->ktls->zone, kctx_tx);
+}
+
+static void bnxt_tls_snd_tag_free(struct m_snd_tag* pmt)
+{
+ if_ctx_t ctx;
+ struct bnxt_softc* priv;
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx =
+ __containerof(pmt, struct bnxt_ktls_offload_ctx_tx, tag);
+
+ kctx_tx->state = BNXT_TLS_STATE_FREE;
+
+ ctx = if_getsoftc(kctx_tx->tag.ifp);
+ priv = iflib_get_softc(ctx);
+ bnxt_ktls_dev_del(priv, kctx_tx);
+
+ taskqueue_enqueue(priv->ktls_info->tq, &kctx_tx->work_task);
+}
+
+static void
+bnxt_tls_work(void *context, int pending)
+{
+ struct bnxt_ktls_offload_ctx_tx *kctx_tx = context;
+
+ if (kctx_tx->state == BNXT_TLS_STATE_FREE) {
+ /* free tag */
+ bnxt_tls_tag_zfree(kctx_tx);
+ }
+}
+
+int bnxt_tls_snd_tag_alloc(if_t ifp, union if_snd_tag_alloc_params* params,
+ struct m_snd_tag** ppmt)
+{
+ union if_snd_tag_alloc_params tag_params;
+ const struct if_snd_tag_sw* snd_tag_sw;
+ struct bnxt_softc* priv;
+ struct bnxt_tls_info* ktls;
+ if_ctx_t ctx;
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx = NULL;
+ const struct tls_session_params* en;
+ int error;
+
+ ctx = if_getsoftc(ifp);
+ priv = iflib_get_softc(ctx);
+ ktls = priv->ktls_info;
+
+ if (!test_bit(BNXT_STATE_OPEN, &priv->state))
+ return (EPROTONOSUPPORT);
+
+ atomic_add_32(&priv->ktls_info->snd_tag_alloc_ref, 1);
+
+ if (priv->ktls_info->init == 0) {
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_UNINITIALIZED], 1);
+ atomic_subtract_32(&priv->ktls_info->snd_tag_alloc_ref, 1);
+ BNXT_DEBUG(priv->dev, "%s:%d: ifp:(%pa) ktls is not initialized\n",
+ __func__, __LINE__, ifp);
+ return (EPROTONOSUPPORT);
+ }
+
+ /* allocate new tag from zone, if any */
+ kctx_tx = uma_zalloc(priv->ktls_info->zone, M_NOWAIT);
+ if (kctx_tx == NULL) {
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_CTX_ALLOC_FAILED], 1);
+ atomic_subtract_32(&priv->ktls_info->snd_tag_alloc_ref, 1);
+ BNXT_DEBUG(priv->dev, "%s:%d: ifp:(%pa) kctx_tx uma_zalloc failed\n",
+ __func__, __LINE__, ifp);
+ return (ENOMEM);
+ }
+
+ en = &params->tls.tls->params;
+
+ /* only TLS v1.2 and v1.3 is currently supported */
+ if (en->tls_vmajor != TLS_MAJOR_VER_ONE ||
+ (en->tls_vminor != TLS_MINOR_VER_TWO
+#ifdef TLS_MINOR_VER_THREE
+ && en->tls_vminor != TLS_MINOR_VER_THREE
+#endif
+ )) {
+ BNXT_DEBUG(priv->dev, "kTLS snd_tag_alloc: unsupported TLS version %u.%u\n",
+ en->tls_vmajor, en->tls_vminor);
+ error = EPROTONOSUPPORT;
+ goto failure;
+ }
+
+ switch (en->cipher_algorithm) {
+ case CRYPTO_AES_NIST_GCM_16:
+ if ((en->cipher_key_len != 128 / 8) &&
+ (en->cipher_key_len != 256 / 8)) {
+ BNXT_DEBUG(priv->dev, "kTLS snd_tag_alloc: unsupported cipher key len %u\n",
+ en->cipher_key_len * 8);
+ error = EPROTONOSUPPORT;
+ goto failure;
+ }
+ break;
+
+ default:
+ BNXT_DEBUG(priv->dev, "kTLS snd_tag_alloc: unsupported cipher algorithm %u\n",
+ en->cipher_algorithm);
+ error = EPROTONOSUPPORT;
+ goto failure;
+ }
+
+ /* Fetch TCP seq number from struct tcpcb */
+ kctx_tx->tcp_seq_no = intotcpcb(params->tls.tls->inp)->snd_nxt;
+
+ /*
+ * Fetch record seq number from struct ktls_session.
+ * So far 'next_seqno' provided TLS seq number for TLS v1.0 only.
+ * It requires changes in the kernel to use 'next_seqno' for all
+ * TLS versions as the driver needs TLS record sequence number
+ * to setup a crypto connection in HW.
+ */
+#ifdef KTLS_REC_SEQ_NUMBER
+ kctx_tx->rec_seq = params->tls.tls->next_seqno;
+#endif
+
+ kctx_tx->state = BNXT_TLS_STATE_INIT;
+
+ error = bnxt_ktls_dev_add(priv, en, kctx_tx);
+ if (error) {
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_DEV_ADD_FAILED], 1);
+ error = EINVAL;
+ goto failure;
+ }
+
+ memset(&tag_params, 0, sizeof(tag_params));
+ tag_params.hdr = params->hdr;
+
+ if (params->hdr.type == IF_SND_TAG_TYPE_TLS) {
+ tag_params.hdr.type = IF_SND_TAG_TYPE_UNLIMITED;
+ snd_tag_sw = &bnxt_tls_snd_tag_sw;
+ } else {
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_UNSUPPORTED_TLS_HDR], 1);
+ BNXT_DEBUG(priv->dev, "kTLS snd_tag_alloc: unsupported snd_tag type %u\n",
+ params->hdr.type);
+ bnxt_ktls_dev_del(priv, kctx_tx);
+ error = EOPNOTSUPP;
+ goto failure;
+ }
+
+ MPASS(kctx_tx->tag.refcount == 0);
+ m_snd_tag_init(&kctx_tx->tag, ifp, snd_tag_sw);
+ *ppmt = &kctx_tx->tag;
+ kctx_tx->ktls = priv->ktls_info;
+ atomic_subtract_32(&priv->ktls_info->snd_tag_alloc_ref, 1);
+ BNXT_DEBUG(priv->dev, "[KID:%u]: TAG_ALLOC: tcp_seqno: %u"
+ " record_no: %lu\n", kctx_tx->kid, kctx_tx->tcp_seq_no, kctx_tx->rec_seq);
+
+ return (0);
+
+failure:
+ kctx_tx->state = BNXT_TLS_STATE_FREE;
+ uma_zfree(priv->ktls_info->zone, kctx_tx);
+ atomic_subtract_32(&priv->ktls_info->snd_tag_alloc_ref, 1);
+ return (error);
+}
+
+void bnxt_alloc_ktls_info(struct bnxt_softc* softc, uint16_t max_keys,
+ bool partition_cap, uint16_t ctxs_per_partition)
+{
+ struct bnxt_tls_info* ktls = softc->ktls_info;
+
+ if (BNXT_VF(softc))
+ return;
+
+ if (!ktls) {
+ bool partition_mode = false;
+ struct bnxt_kctx* kctx;
+ uint16_t batch_sz = 0;
+ int i;
+
+ ktls = malloc(sizeof(*ktls), M_DEVBUF, M_NOWAIT | M_ZERO);
+
+ if (ktls == NULL) {
+ device_printf(softc->dev, "kTLS info alloc failed\n");
+ return;
+ }
+
+ if (partition_cap) {
+ batch_sz = ctxs_per_partition;
+ if (batch_sz && batch_sz <= BNXT_KID_BATCH_SIZE)
+ partition_mode = true;
+ }
+ for (i = 0; i < BNXT_MAX_CRYPTO_KEY_TYPE; i++) {
+ kctx = &ktls->kctx[i];
+ kctx->type = i;
+ kctx->max_ctx = softc->max_ktls_entries;
+ TAILQ_INIT(&kctx->list);
+ mtx_init(&kctx->lock, "BNXT KCTL LOCK", NULL,
+ MTX_DEF | MTX_NOWITNESS);
+ cv_init(&kctx->alloc_pending_cv, "bnxt_ktls_alloc");
+ atomic_store_32(&kctx->alloc_pending, 0);
+ if (partition_mode) {
+ int bmap_sz;
+
+ bmap_sz = howmany(kctx->max_ctx, batch_sz);
+ kctx->partition_bmap_nbits = bmap_sz;
+ kctx->partition_bmap =
+ bit_alloc(bmap_sz, M_DEVBUF, M_NOWAIT);
+ if (kctx->partition_bmap == NULL) {
+ BNXT_DEBUG(softc->dev,
+ "kTLS partition_bmap alloc failed, disabling partition mode\n");
+ partition_mode = false;
+ }
+ }
+ }
+ atomic_store_32(&ktls->snd_tag_alloc_ref, 0);
+ ktls->partition_mode = partition_mode;
+ ktls->ctxs_per_partition = batch_sz;
+
+ atomic_store_32(&ktls->pending, 0);
+
+ softc->ktls_info = ktls;
+
+ /* Create DMA descriptor TAG */
+ if ((bus_dma_tag_create(
+ bus_get_dma_tag(softc->dev),
+ 1, /* any alignment */
+ 0, /* no boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ 65536,
+ BNXT_MAX_NUM_SEGS,
+ 16384,
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockfuncarg */
+ &ktls->dma_tag)))
+ device_printf(softc->dev, "kTLS dma tag alloc failed\n");
+ }
+ ktls->max_key_ctxs_alloc = max_keys;
+}
+
+void bnxt_ktls_del_all(struct bnxt_softc *softc)
+{
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ struct bnxt_kid_info *kid;
+ struct bnxt_kctx *kctx;
+ int i, j;
+
+ if (!ktls)
+ return;
+
+ /*
+ * Called during FW reset (with BNXT_STATE_IN_FW_RESET already set)
+ * before bnxt_clear_ktls() tears down the software state. The FW
+ * reinitialises its key-context table during recovery, and
+ * FreeBSD's async MPC path cannot safely wait for completions here
+ * (pci_disable_busmaster() follows shortly), so there is no crypto
+ * delete to send: every in-use KID is simply marked free in
+ * software. bnxt_crypto_del() would no-op here anyway, since
+ * BNXT_STATE_IN_FW_RESET is always set on this path, but skip
+ * calling it rather than build a stack-local dummy kctx_tx just to
+ * feed a no-op.
+ */
+ /* Shutting down; no need to hold kctx locks. */
+ for (i = 0; i < BNXT_MAX_CRYPTO_KEY_TYPE; i++) {
+ kctx = &ktls->kctx[i];
+ TAILQ_FOREACH(kid, &kctx->list, list) {
+ for (j = 0; j < (int)kid->count; j++)
+ bit_set(kid->ids, j);
+ }
+ }
+}
+
+void bnxt_clear_ktls(struct bnxt_softc *softc)
+{
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ struct bnxt_kid_info *kid, *tmp;
+ struct bnxt_kctx *kctx;
+ int i;
+
+ if (!ktls)
+ return;
+
+ /* Shutting down or FW reset, no need to protect the lists. */
+ for (i = 0; i < BNXT_MAX_CRYPTO_KEY_TYPE; i++) {
+ kctx = &ktls->kctx[i];
+ TAILQ_FOREACH_SAFE(kid, &kctx->list, list, tmp) {
+ TAILQ_REMOVE(&kctx->list, kid, list);
+ if (kid->ids != NULL)
+ free(kid->ids, M_DEVBUF);
+ free(kid, M_DEVBUF);
+ }
+ if (kctx->partition_bmap != NULL) {
+ free(kctx->partition_bmap, M_DEVBUF);
+ kctx->partition_bmap = NULL;
+ }
+ kctx->total_alloc = 0;
+ }
+}
+
+void bnxt_free_ktls_counters(struct bnxt_softc* softc)
+{
+ uint8_t i;
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+
+ if (!ktls)
+ return;
+
+ for (i = 0; i < BNXT_MPC_CMP_TIME_MAX_COUNTERS; i++) {
+ if (ktls->mpc_cmp_time[i]) {
+ counter_u64_free(ktls->mpc_cmp_time[i]);
+ ktls->mpc_cmp_time[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < BNXT_KTLS_MAX_COUNTERS; i++) {
+ if (ktls->counters[i]) {
+ counter_u64_free(ktls->counters[i]);
+ ktls->counters[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < BNXT_KTLS_ERR_MAX_COUNTERS; i++) {
+ if (ktls->err_counters[i]) {
+ counter_u64_free(ktls->err_counters[i]);
+ ktls->err_counters[i] = NULL;
+ }
+ }
+}
+
+void bnxt_alloc_ktls_counters(struct bnxt_softc* softc)
+{
+ uint8_t i;
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+
+ if (!ktls)
+ return;
+
+ for (i = 0; i < BNXT_MPC_CMP_TIME_MAX_COUNTERS; i++) {
+ if (!ktls->mpc_cmp_time[i])
+ ktls->mpc_cmp_time[i] = counter_u64_alloc(M_WAITOK);
+ }
+
+ for (i = 0; i < BNXT_KTLS_MAX_COUNTERS; i++) {
+ if (!ktls->counters[i])
+ ktls->counters[i] = counter_u64_alloc(M_WAITOK);
+ }
+
+ for (i = 0; i < BNXT_KTLS_ERR_MAX_COUNTERS; i++) {
+ if (!ktls->err_counters[i])
+ ktls->err_counters[i] = counter_u64_alloc(M_WAITOK);
+ }
+
+}
+
+void bnxt_free_ktls_info(struct bnxt_softc* softc)
+{
+ struct bnxt_tls_info* ktls = softc->ktls_info;
+ int i;
+
+ if (!ktls)
+ return;
+
+ bnxt_clear_ktls(softc);
+ bus_dma_tag_destroy(ktls->dma_tag);
+ if (ktls->mpc_zone != NULL)
+ uma_zdestroy(ktls->mpc_zone);
+
+ if (ktls->init) {
+ ktls->init = 0;
+ if (ktls->tq != NULL) {
+ taskqueue_quiesce(ktls->tq);
+ taskqueue_free(ktls->tq);
+ ktls->tq = NULL;
+ }
+ uma_zdestroy(ktls->zone);
+ }
+
+ for (i = 0; i < BNXT_MAX_CRYPTO_KEY_TYPE; i++) {
+ cv_destroy(&ktls->kctx[i].alloc_pending_cv);
+ if (mtx_initialized(&ktls->kctx[i].lock))
+ mtx_destroy(&ktls->kctx[i].lock);
+ }
+
+ free(ktls, M_DEVBUF);
+ softc->ktls_info = NULL;
+}
+
+void bnxt_hwrm_reserve_pf_key_ctxs(struct bnxt_softc* softc,
+ struct hwrm_func_cfg_input* req,
+ uint8_t type)
+{
+ struct bnxt_tls_info* tls = softc->ktls_info;
+ struct bnxt_hw_resc* hw_resc = &softc->hw_resc;
+ struct bnxt_hw_tls_resc* tls_resc;
+ uint32_t tx, rx;
+
+ if (!tls)
+ return;
+
+ tls_resc = &hw_resc->tls_resc[type];
+ tx = min(tls->tck.max_ctx, tls_resc->max_tx_key_ctxs);
+ rx = min(tls->rck.max_ctx, tls_resc->max_rx_key_ctxs);
+ if (type == BNXT_CRYPTO_TYPE_KTLS) {
+ req->num_ktls_tx_key_ctxs = htole32(tx);
+ req->num_ktls_rx_key_ctxs = htole32(rx);
+ req->enables |= htole32(
+ HWRM_FUNC_CFG_INPUT_ENABLES_KTLS_TX_KEY_CTXS |
+ HWRM_FUNC_CFG_INPUT_ENABLES_KTLS_RX_KEY_CTXS);
+ }
+}
+
+static int __bnxt_partition_alloc(struct bnxt_kctx* kctx, uint32_t* id)
+{
+ int max = kctx->partition_bmap_nbits;
+ ssize_t next;
+
+ bit_ffc_at(kctx->partition_bmap, kctx->next, max, &next);
+ if (next == -1)
+ bit_ffc(kctx->partition_bmap, max, &next);
+ if (next == -1)
+ return ENOSPC;
+ *id = next;
+ kctx->next = next;
+ return 0;
+}
+
+static int bnxt_partition_alloc(struct bnxt_kctx* kctx, uint32_t* id)
+{
+ int rc;
+
+ mtx_lock(&kctx->lock);
+ do {
+ rc = __bnxt_partition_alloc(kctx, id);
+ if (rc) {
+ mtx_unlock(&kctx->lock);
+ return rc;
+ }
+ } while (bnxt_test_and_set_bit_nonatomic(*id, kctx->partition_bmap));
+ mtx_unlock(&kctx->lock);
+ return 0;
+}
+
+static int bnxt_key_ctx_store(struct bnxt_softc* softc, __le32* key_buf,
+ uint32_t num, bool contig, struct bnxt_kctx* kctx,
+ uint32_t* id)
+{
+ struct bnxt_kid_info* kid;
+ uint32_t i;
+ int j;
+
+ for (i = 0; i < num;) {
+ kid = malloc(sizeof(*kid), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (kid == NULL) {
+ device_printf(softc->dev, "kTLS kid alloc failed\n");
+ return ENOMEM;
+ }
+ kid->ids = bit_alloc(BNXT_KID_BATCH_SIZE, M_DEVBUF, M_NOWAIT);
+ if (kid->ids == NULL) {
+ free(kid, M_DEVBUF);
+ device_printf(softc->dev, "kTLS kid ids alloc failed\n");
+ return ENOMEM;
+ }
+ kid->start_id = le32toh(key_buf[i]);
+ if (contig)
+ kid->count = (num > BNXT_KID_BATCH_SIZE) ? BNXT_KID_BATCH_SIZE : num;
+ else
+ kid->count = 1;
+ for (j = 0; j < kid->count; j++)
+ bit_set(kid->ids, j);
+ if (id != NULL && i == 0) {
+ bit_clear(kid->ids, 0);
+ *id = kid->start_id;
+ }
+ mtx_lock(&kctx->lock);
+ TAILQ_INSERT_TAIL(&kctx->list, kid, list);
+ kctx->total_alloc += kid->count;
+ mtx_unlock(&kctx->lock);
+ i += kid->count;
+ }
+ return 0;
+}
+
+int bnxt_hwrm_key_ctx_alloc(struct bnxt_softc* softc, struct bnxt_kctx* kctx,
+ uint16_t num, uint32_t* id, uint8_t type)
+{
+ struct bnxt_tls_info* tls = softc->ktls_info;
+ struct hwrm_func_key_ctx_alloc_output* resp =
+ (void*)softc->hwrm_cmd_resp.idi_vaddr;
+ struct hwrm_func_key_ctx_alloc_input req = {0};
+ int pending_count;
+ __le32* key_buf;
+ bool contig;
+ int rc;
+ struct iflib_dma_info dma_data = {};
+ bool dma_valid = false;
+ uint32_t partition_id = 0;
+ bool partition_allocated = false;
+
+ num = min(num, tls->max_key_ctxs_alloc);
+ bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_KEY_CTX_ALLOC);
+
+ if (tls->partition_mode) {
+ num = tls->ctxs_per_partition;
+ rc = bnxt_partition_alloc(kctx, &partition_id);
+ if (rc)
+ return rc;
+ partition_allocated = true;
+ req.partition_start_xid = htole32(partition_id * num);
+ } else {
+ rc = iflib_dma_alloc(softc->ctx, num * 4, &dma_data,
+ BUS_DMA_NOWAIT);
+ if (rc) {
+ device_printf(softc->dev, "kTLS key ctx DMA alloc failed, rc=%d\n", rc);
+ return rc;
+ }
+ dma_valid = true;
+ bus_dmamap_sync(dma_data.idi_tag, dma_data.idi_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ key_buf = (__le32*)dma_data.idi_vaddr;
+ if (!key_buf) {
+ device_printf(softc->dev, "kTLS key ctx DMA vaddr NULL after alloc\n");
+ iflib_dma_free(&dma_data);
+ dma_valid = false;
+ return ENOMEM;
+ }
+ req.dma_bufr_size_bytes = htole32(num * 4);
+ req.host_dma_addr = htole64(dma_data.idi_paddr);
+ }
+
+ req.key_ctx_type = kctx->type;
+ req.num_key_ctxs = htole16(num);
+
+ pending_count = atomic_fetchadd_32(&kctx->alloc_pending, 1) + 1;
+ BNXT_HWRM_LOCK(softc);
+ rc = _hwrm_send_message(softc, &req, sizeof(req));
+ atomic_subtract_32(&kctx->alloc_pending, 1);
+ if (rc) {
+ device_printf(softc->dev, "kTLS HWRM key ctx alloc failed, rc=%d\n", rc);
+ goto key_alloc_exit_wake;
+ }
+
+ num = le16toh(resp->num_key_ctxs_allocated);
+ contig = resp->flags &
+ HWRM_FUNC_KEY_CTX_ALLOC_OUTPUT_FLAGS_KEY_CTXS_CONTIGUOUS;
+ if (tls->partition_mode)
+ key_buf = &resp->partition_start_xid;
+ rc = bnxt_key_ctx_store(softc, key_buf, num, contig, kctx, id);
+ if (rc)
+ BNXT_DEBUG(softc->dev, "kTLS key_ctx_store failed, rc=%d\n", rc);
+
+key_alloc_exit_wake:
+ /*
+ * Lock ordering: BNXT_HWRM_LOCK (outer) -> kctx->lock (inner).
+ * No code path may acquire kctx->lock before calling a HWRM function,
+ * as that would invert this ordering and risk deadlock.
+ */
+ if (rc && partition_allocated) {
+ mtx_lock(&kctx->lock);
+ bit_clear(kctx->partition_bmap, partition_id);
+ mtx_unlock(&kctx->lock);
+ }
+
+ if (pending_count >= BNXT_KCTX_ALLOC_PENDING_MAX) {
+ mtx_lock(&kctx->lock);
+ cv_broadcast(&kctx->alloc_pending_cv);
+ mtx_unlock(&kctx->lock);
+ }
+
+ BNXT_HWRM_UNLOCK(softc);
+ if (dma_valid)
+ iflib_dma_free(&dma_data);
+ return rc;
+}
+
+static int bnxt_alloc_one_kctx(struct bnxt_kctx* kctx, uint32_t* id)
+{
+ struct bnxt_kid_info* kid;
+ int rc = ENOMEM;
+
+ mtx_lock(&kctx->lock);
+ TAILQ_FOREACH(kid, &kctx->list, list) {
+ ssize_t idx = 0;
+
+ do {
+ bit_ffs_at(kid->ids, idx, kid->count, &idx);
+ if (idx == -1)
+ break;
+ if (bnxt_test_and_clear_bit_nonatomic(idx, kid->ids)) {
+ *id = kid->start_id + idx;
+ rc = 0;
+ goto alloc_done;
+ }
+ } while (1);
+ }
+
+alloc_done:
+ mtx_unlock(&kctx->lock);
+ return (rc);
+}
+
+void bnxt_free_one_kctx(struct bnxt_kctx* kctx, uint32_t id, device_t dev)
+{
+ struct bnxt_kid_info* kid;
+
+ mtx_lock(&kctx->lock);
+ TAILQ_FOREACH(kid, &kctx->list, list) {
+ if (id >= kid->start_id && id < kid->start_id + kid->count) {
+ bit_set(kid->ids, id - kid->start_id);
+ break;
+ }
+ }
+ mtx_unlock(&kctx->lock);
+}
+
+#define BNXT_KCTX_ALLOC_RETRY_MAX 3
+
+int bnxt_key_ctx_alloc_one(struct bnxt_softc* softc, struct bnxt_kctx* kctx,
+ uint32_t* id, uint8_t type)
+{
+ int rc, retry = 0;
+
+ while (retry++ < BNXT_KCTX_ALLOC_RETRY_MAX) {
+ rc = bnxt_alloc_one_kctx(kctx, id);
+ if (!rc)
+ return 0;
+
+ if ((kctx->total_alloc + BNXT_KID_BATCH_SIZE) > kctx->max_ctx) {
+ BNXT_DEBUG(softc->dev, "kTLS key_ctx_alloc_one: max_ctx reached\n");
+ return ENOSPC;
+ }
+
+ if (!BNXT_KCTX_ALLOC_OK(kctx)) {
+ mtx_lock(&kctx->lock);
+ while (!BNXT_KCTX_ALLOC_OK(kctx))
+ cv_wait(&kctx->alloc_pending_cv, &kctx->lock);
+ mtx_unlock(&kctx->lock);
+ continue;
+ }
+ rc = bnxt_hwrm_key_ctx_alloc(softc, kctx, BNXT_KID_BATCH_SIZE,
+ id, type);
+ if (!rc)
+ return 0;
+ }
+ BNXT_DEBUG(softc->dev, "kTLS key_ctx_alloc_one: retries exhausted\n");
+ return EAGAIN;
+}
+
+static inline void
+bnxt_calc_mpc_cmp_time(struct bnxt_softc* softc, unsigned long rtt)
+{
+ struct bnxt_tls_info* ktls = softc->ktls_info;
+
+ if (rtt <= 1)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_1US], 1);
+ else if (rtt <= 5)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_1_5US], 1);
+ else if (rtt <= 10)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_5_10US], 1);
+ else if (rtt <= 15)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_10_15US], 1);
+ else if (rtt <= 20)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_15_20US], 1);
+ else if (rtt <= 25)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_20_25US], 1);
+ else if (rtt <= 50)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_25_50US], 1);
+ else if (rtt <= 100)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_50_100US], 1);
+ else if (rtt <= 200)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_100_200US], 1);
+ else if (rtt <= 500)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_200_500US], 1);
+ else if (rtt <= 1000)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_500_1000US], 1);
+ else if (rtt <= 1500)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_1000_1500US], 1);
+ else if (rtt <= 2000)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_1500_2000US], 1);
+ else if (rtt <= 2500)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_2000_2500US], 1);
+ else if (rtt <= 3000)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_2500_3000US], 1);
+ else if (rtt <= 3500)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_3000_3500US], 1);
+ else if (rtt <= 4000)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_3500_4000US], 1);
+ else if (rtt <= 4500)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_4000_4500US], 1);
+ else if (rtt <= 5000)
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_4500_5000US], 1);
+ else
+ counter_u64_add(ktls->mpc_cmp_time[BNXT_MPC_CMP_TIME_5000_PLUS_US], 1);
+}
+
+
+int bnxt_xmit_crypto_cmd(struct bnxt_softc* softc,
+ void* cmd, uint len,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx)
+{
+ struct bnxt_mpc_info* mpc = softc->mpc_info;
+ struct bnxt_tls_info* ktls = softc->ktls_info;
+ struct bnxt_crypto_cmd_ctx* ctx = NULL;
+ unsigned long handle = 0;
+ struct bnxt_ring* txr;
+ int rc;
+
+ txr = bnxt_select_mpc_ring(mpc);
+
+ uint32_t kid = CE_CMD_KID(cmd);
+
+ ctx = uma_zalloc(ktls->mpc_zone, M_NOWAIT);
+ if (ctx == NULL) {
+ device_printf(softc->dev, "kTLS MPC ctx alloc failed\n");
+ return ENOMEM;
+ }
+
+ handle = (unsigned long)ctx;
+ ctx->ce_cmp.opaque = BNXT_KMPC_OPAQUE(
+ txr->mpc_chnl_type, kid);
+
+ ctx->kctx_tx = kctx_tx;
+
+ getmicrotime(&kctx_tx->start);
+
+ mtx_lock_spin(&txr->tx_lock);
+ rc = bnxt_start_xmit_mpc(softc, txr, cmd, len, handle);
+ mtx_unlock_spin(&txr->tx_lock);
+ if (rc) {
+ BNXT_DEBUG(softc->dev, "kTLS MPC xmit failed, kid=%u rc=%d\n", kid, rc);
+ uma_zfree(ktls->mpc_zone, ctx);
+ }
+
+ return rc;
+}
+
+static int bnxt_crypto_add(struct bnxt_softc* softc,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx,
+ uint8_t type)
+{
+ struct tls_session_params* crypto_info = &kctx_tx->crypto_info;
+ uint32_t tcp_seq_no = kctx_tx->tcp_seq_no;
+ uint64_t rec_seq = kctx_tx->rec_seq;
+ uint32_t kid = kctx_tx->kid;
+ struct ce_add_cmd cmd = {0};
+ uint32_t data;
+ int rc;
+
+ cmd.ctx_kind = CE_ADD_CMD_CTX_KIND_CK_TX;
+
+ data = CE_ADD_CMD_OPCODE_ADD | (kid << CE_ADD_CMD_KID_SFT);
+ switch (crypto_info->cipher_key_len) {
+ case 128 / 8:
+ data |= CE_ADD_CMD_ALGORITHM_AES_GCM_128;
+#ifdef TLS_MINOR_VER_THREE
+ if (crypto_info->tls_vminor == TLS_MINOR_VER_THREE) {
+ data |= CE_ADD_CMD_VERSION_TLS1_3;
+ memcpy(&cmd.addl_iv, crypto_info->iv + BNXT_SALT_LEN,
+ BNXT_ADDL_IV_LEN_TLS1_3);
+ }
+#endif
+ memcpy(&cmd.session_key, crypto_info->cipher_key,
+ crypto_info->cipher_key_len);
+ memcpy(&cmd.salt, crypto_info->iv, BNXT_SALT_LEN);
+ memcpy(&cmd.record_seq_num[0], &rec_seq, sizeof(rec_seq));
+ break;
+ case 256 / 8:
+ data |= CE_ADD_CMD_ALGORITHM_AES_GCM_256;
+#ifdef TLS_MINOR_VER_THREE
+ if (crypto_info->tls_vminor == TLS_MINOR_VER_THREE) {
+ data |= CE_ADD_CMD_VERSION_TLS1_3;
+ memcpy(&cmd.addl_iv, crypto_info->iv + BNXT_SALT_LEN,
+ BNXT_ADDL_IV_LEN_TLS1_3);
+ }
+#endif
+ memcpy(&cmd.session_key, crypto_info->cipher_key,
+ crypto_info->cipher_key_len);
+ memcpy(&cmd.salt, crypto_info->iv, BNXT_SALT_LEN);
+ memcpy(&cmd.record_seq_num[0], &rec_seq, sizeof(rec_seq));
+ break;
+ }
+ cmd.ver_algo_kid_opcode = htole32(data);
+ cmd.pkt_tcp_seq_num = htole32(tcp_seq_no);
+ cmd.tls_header_tcp_seq_num = cmd.pkt_tcp_seq_num;
+ rc = bnxt_xmit_crypto_cmd(softc, &cmd, sizeof(cmd), kctx_tx);
+ explicit_bzero(&cmd, sizeof(cmd));
+ return rc;
+}
+
+static int bnxt_crypto_del(struct bnxt_softc* softc,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx, uint8_t type)
+{
+ struct ce_delete_cmd cmd = {0};
+ uint32_t data;
+ uint32_t kid;
+
+ if (test_bit(BNXT_STATE_IN_FW_RESET, &softc->state) &&
+ test_bit(BNXT_STATE_FW_FATAL_COND, &softc->state))
+ return 0;
+
+ kid = kctx_tx->kid;
+ data = CE_DELETE_CMD_CTX_KIND_CK_TX;
+
+ data |= CE_DELETE_CMD_OPCODE_DEL | (kid << CE_DELETE_CMD_KID_SFT);
+
+ cmd.ctx_kind_kid_opcode = htole32(data);
+ return bnxt_xmit_crypto_cmd(softc, &cmd, sizeof(cmd),
+ kctx_tx);
+}
+
+static int bnxt_ktls_dev_add(struct bnxt_softc* softc,
+ const struct tls_session_params* crypto_info,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx)
+{
+ struct bnxt_tls_info* ktls;
+ struct bnxt_kctx* kctx;
+ uint32_t kid;
+ int rc = 0;
+
+ ktls = softc->ktls_info;
+ atomic_add_32(&ktls->pending, 1);
+
+ atomic_thread_fence_seq_cst();
+ if (!test_bit(BNXT_STATE_OPEN, &softc->state)) {
+ BNXT_DEBUG(softc->dev, "kTLS dev_add: device not open\n");
+ rc = ENODEV;
+ goto exit;
+ }
+
+ memcpy(&kctx_tx->crypto_info, crypto_info, sizeof(*crypto_info));
+
+ kctx = &ktls->tck;
+ rc = bnxt_key_ctx_alloc_one(softc, kctx, &kid, BNXT_CRYPTO_TYPE_KTLS);
+ if (rc) {
+ BNXT_DEBUG(softc->dev, "kTLS dev_add: key_ctx_alloc_one failed, rc=%d\n", rc);
+ goto exit;
+ }
+
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_ADD], 1);
+
+ BNXT_DEBUG(softc->dev, "[KID:%d] KTLS device add is successful\n", kid);
+
+ kctx_tx->kid = kid;
+ kctx_tx->enobufs = 0;
+
+ rc = bnxt_crypto_add(softc, kctx_tx, BNXT_CRYPTO_TYPE_KTLS);
+
+ if (rc) {
+ device_printf(softc->dev, "kTLS crypto add failed for KID %u, rc=%d\n", kid, rc);
+ bnxt_free_one_kctx(kctx, kid, softc->dev);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_DEL], 1);
+ goto exit;
+ }
+
+exit:
+ atomic_subtract_32(&ktls->pending, 1);
+ return rc;
+}
+
+#define BNXT_RETRY_MAX 20
+
+static void bnxt_ktls_dev_del(struct bnxt_softc* softc,
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx)
+{
+ struct bnxt_tls_info* ktls;
+ struct bnxt_kctx* kctx;
+ int retry_cnt = 0;
+ uint32_t kid;
+ int rc;
+
+ ktls = softc->ktls_info;
+ kid = kctx_tx->kid;
+ kctx = &ktls->tck;
+
+ /* BNXT_STATE_OPEN bit is cleared in bnxt_stop() and where
+ * all the rings (including MPC rings) are freed with fw.
+ * So, return from here when BNXT_STATE_OPEN is cleared
+ * otherwise MPC command timeouts will be observed while
+ * unloading the driver.
+ */
+ if (!test_bit(BNXT_STATE_OPEN, &softc->state)) {
+ BNXT_DEBUG(softc->dev, "[KID:%u]: KTLS dev_del: device not up, freeing KID\n", kid);
+ bnxt_free_one_kctx(kctx, kid, softc->dev);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_DEL], 1);
+ return;
+ }
+
+retry:
+ atomic_add_32(&ktls->pending, 1);
+ /* Make sure bnxt_close_nic() sees pending before we check the
+ * BNXT_STATE_OPEN flag.
+ */
+ atomic_thread_fence_seq_cst();
+ while (!test_bit(BNXT_STATE_OPEN, &softc->state)) {
+ atomic_subtract_32(&ktls->pending, 1);
+ if (retry_cnt > BNXT_RETRY_MAX) {
+ device_printf(softc->dev,
+ "%s retry max %d exceeded, state %lx\n",
+ __func__, retry_cnt, softc->state);
+ bnxt_free_one_kctx(kctx, kid, softc->dev);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_DEL], 1);
+ return;
+ }
+ retry_cnt++;
+ DELAY(1000 * 100);
+ goto retry;
+ }
+
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_DEL], 1);
+ rc = bnxt_crypto_del(softc, kctx_tx, BNXT_CRYPTO_TYPE_KTLS);
+ if (!rc) {
+ bnxt_free_one_kctx(kctx, kid, softc->dev);
+ } else {
+ device_printf(softc->dev, "kTLS crypto delete failed for KID %u, rc=%d\n", kid, rc);
+ }
+
+ atomic_subtract_32(&ktls->pending, 1);
+ BNXT_DEBUG(softc->dev, "[KID:%d]: KTLS device delete is successful\n", kid);
+}
+
+int bnxt_set_partition_mode(struct bnxt_softc* softc)
+{
+ struct hwrm_func_cfg_input req = {0};
+ int rc;
+
+ bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_FUNC_CFG);
+ req.fid = htole16(0xffff);
+ req.enables2 =
+ htole32(HWRM_FUNC_CFG_INPUT_ENABLES2_XID_PARTITION_CFG);
+ req.xid_partition_cfg =
+ htole16(HWRM_FUNC_CFG_INPUT_XID_PARTITION_CFG_TX_CK |
+ HWRM_FUNC_CFG_INPUT_XID_PARTITION_CFG_RX_CK);
+ rc = hwrm_send_message(softc, &req, sizeof(req));
+ if (rc)
+ device_printf(softc->dev, "kTLS set partition mode failed, rc=%d\n", rc);
+ return rc;
+}
+
+static int bnxt_pre_alloc_tx_crypto_keys(struct bnxt_softc* softc)
+{
+ struct bnxt_tls_info* ktls = softc->ktls_info;
+ uint32_t alloc_keys = softc->max_ktls_entries;
+ uint32_t allocated_keys_count = 0;
+ uint16_t batch_sz;
+ int rc = 0;
+ unsigned long start_ticks, elapsed_ticks;
+
+ start_ticks = ticks;
+ while (alloc_keys > 0) {
+ batch_sz = (uint16_t)min(alloc_keys, (uint32_t)BNXT_KID_BATCH_SIZE);
+
+ rc = bnxt_hwrm_key_ctx_alloc(softc, &ktls->tck, batch_sz,
+ NULL, BNXT_CRYPTO_TYPE_KTLS);
+
+
+ if (rc) {
+ if (!allocated_keys_count) {
+ device_printf(softc->dev,
+ "kTLS Tx keys allocation is failed, disable the HW kTLS tx\n");
+ return rc;
+ } else {
+ rc = 0;
+ device_printf(softc->dev,
+ "HWRM key ctx allocation is failed\n");
+ break;
+ }
+ }
+
+ allocated_keys_count += batch_sz;
+ alloc_keys -= batch_sz;
+ }
+
+ elapsed_ticks = ticks - start_ticks;
+
+ device_printf(softc->dev,
+ "allocated kTLS Tx crypto keys count: %d time to alloc: (%d msecs)\n",
+ allocated_keys_count, (int)((elapsed_ticks * 1000) / hz));
+
+ return rc;
+}
+
+int bnxt_ktls_init(struct bnxt_softc* softc)
+{
+ struct bnxt_tls_info* ktls = softc->ktls_info;
+ struct bnxt_hw_resc* hw_resc = &softc->hw_resc;
+ struct bnxt_hw_tls_resc* tls_resc;
+ int rc = 0;
+
+ if (!ktls)
+ return 0;
+
+ tls_resc = &hw_resc->tls_resc[BNXT_CRYPTO_TYPE_KTLS];
+ ktls->tck.max_ctx = tls_resc->resv_tx_key_ctxs;
+
+ if (!ktls->tck.max_ctx) {
+ device_printf(softc->dev,
+ "max Tx ctx count is zero, disable HW kTLS\n");
+ return EINVAL;
+ }
+
+ if (ktls->partition_mode) {
+ rc = bnxt_set_partition_mode(softc);
+ if (rc) {
+ BNXT_DEBUG(softc->dev, "kTLS set partition mode failed, disabling partition mode\n");
+ ktls->partition_mode = false;
+ }
+ }
+
+ rc = bnxt_pre_alloc_tx_crypto_keys(softc);
+
+ if (rc)
+ return rc;
+
+ ktls->mpc_zone = uma_zcreate("bnxt_ktls_mpc",
+ sizeof(struct bnxt_crypto_cmd_ctx), NULL, NULL, NULL, NULL,
+ UMA_ALIGN_PTR, 0);
+ if (ktls->mpc_zone == NULL) {
+ device_printf(softc->dev, "kTLS mpc_zone create failed\n");
+ return ENOMEM;
+ }
+
+ ktls->tq = taskqueue_create("bnxt_tls", M_NOWAIT,
+ taskqueue_thread_enqueue, &ktls->tq);
+ if (ktls->tq == NULL) {
+ device_printf(softc->dev, "kTLS taskqueue create failed\n");
+ uma_zdestroy(ktls->mpc_zone);
+ ktls->mpc_zone = NULL;
+ return (ENOMEM);
+ }
+ rc = taskqueue_start_threads(&ktls->tq, 1, PWAIT, "bnxt_tls");
+ if (rc != 0) {
+ device_printf(softc->dev, "kTLS taskqueue thread start failed, rc=%d\n", rc);
+ taskqueue_free(ktls->tq);
+ ktls->tq = NULL;
+ uma_zdestroy(ktls->mpc_zone);
+ ktls->mpc_zone = NULL;
+ return (rc);
+ }
+
+ snprintf(ktls->zname, sizeof(ktls->zname),
+ "bnxt_%u_tls", device_get_unit(softc->dev));
+
+ ktls->zone = uma_zcache_create(ktls->zname,
+ sizeof(struct bnxt_ktls_offload_ctx_tx), NULL, NULL, NULL, NULL,
+ bnxt_tls_tag_import, bnxt_tls_tag_release, softc,
+ UMA_ZONE_UNMANAGED);
+ if (ktls->zone == NULL) {
+ device_printf(softc->dev, "kTLS UMA zone create failed\n");
+ taskqueue_free(ktls->tq);
+ ktls->tq = NULL;
+ uma_zdestroy(ktls->mpc_zone);
+ ktls->mpc_zone = NULL;
+ return (ENOMEM);
+ }
+
+ ktls->init = 1;
+
+ return 0;
+}
+
+void bnxt_ktls_mpc_cmp(struct bnxt_softc* softc, uint32_t client,
+ unsigned long handle, struct bnxt_cmpl_entry cmpl[],
+ uint32_t entries)
+{
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx = NULL;
+ struct bnxt_tls_info* tls = softc->ktls_info;
+ struct bnxt_crypto_cmd_ctx* ctx;
+ unsigned long rtt_us;
+ struct ce_cmpl* cmp;
+ uint32_t len, kid;
+
+ cmp = cmpl[0].cmpl;
+ if (!handle || entries != 1) {
+ if (!handle)
+ device_printf(softc->dev,
+ "kTLS MPC cmp: invalid handle 0\n");
+ else if (entries != 1) {
+ device_printf(softc->dev,
+ "Invalid entries %d with handle %lx cmpl "
+ "%08x in %s()\n",
+ entries, handle, *(uint32_t*)cmp,
+ __func__);
+ }
+ return;
+ }
+ ctx = (void*)handle;
+ kid = CE_CMPL_KID(cmp);
+ if (ctx->ce_cmp.opaque != BNXT_KMPC_OPAQUE(client, kid)) {
+ device_printf(softc->dev,
+ "Invalid CE cmpl software opaque %08x, cmpl "
+ "%08x, kid %x\n",
+ ctx->ce_cmp.opaque, *(uint32_t*)cmp, kid);
+
+ kctx_tx = ctx->kctx_tx;
+ uma_zfree(tls->mpc_zone, ctx);
+
+ switch (kctx_tx->state) {
+ case BNXT_TLS_STATE_INIT:
+ if (kctx_tx->mpc_retry < MAX_MPC_RETRY) {
+ kctx_tx->mpc_retry++;
+ BNXT_DEBUG(softc->dev, "[KID: %u]: retry(%u) crypto add\n",
+ kctx_tx->kid, kctx_tx->mpc_retry);
+ if (bnxt_crypto_add(softc, kctx_tx, BNXT_CRYPTO_TYPE_KTLS))
+ kctx_tx->state = BNXT_TLS_STATE_BAD;
+ } else
+ kctx_tx->state = BNXT_TLS_STATE_BAD;
+ break;
+ case BNXT_TLS_STATE_FREE:
+ if (kctx_tx->mpc_retry < MAX_MPC_RETRY) {
+ kctx_tx->mpc_retry++;
+ BNXT_DEBUG(softc->dev, "[KID: %u]: retry(%u) crypto delete\n",
+ kctx_tx->kid, kctx_tx->mpc_retry);
+ if (bnxt_crypto_del(softc, kctx_tx, BNXT_CRYPTO_TYPE_KTLS))
+ kctx_tx->state = BNXT_TLS_STATE_BAD;
+ } else
+ kctx_tx->state = BNXT_TLS_STATE_BAD;
+ break;
+ }
+
+ return;
+ }
+
+ len = min(cmpl[0].len, (uint32_t)sizeof(ctx->ce_cmp));
+ memcpy(&ctx->ce_cmp, cmpl[0].cmpl, len);
+ kctx_tx = ctx->kctx_tx;
+
+ if (CE_CMPL_STATUS(&ctx->ce_cmp) == CE_CMPL_STATUS_OK) {
+ if (kctx_tx->state == BNXT_TLS_STATE_INIT)
+ kctx_tx->state = BNXT_TLS_STATE_READY;
+ } else {
+ counter_u64_add(softc->ktls_info->err_counters[BNXT_KTLS_TX_MPC_FAILED], 1);
+ BNXT_DEBUG(softc->dev, "[KID: %u]: MPC failed: current state: %u cmpl_status: %lu\n",
+ kctx_tx->kid, kctx_tx->state, CE_CMPL_STATUS(&ctx->ce_cmp));
+ kctx_tx->state = BNXT_TLS_STATE_BAD;
+ }
+
+ getmicrotime(&kctx_tx->end);
+ timevalsub(&kctx_tx->end, &kctx_tx->start);
+ rtt_us = kctx_tx->end.tv_sec * 1000000 + kctx_tx->end.tv_usec;
+ bnxt_calc_mpc_cmp_time(softc, rtt_us);
+
+ kctx_tx->start.tv_sec = 0;
+ kctx_tx->start.tv_usec = 0;
+ kctx_tx->end.tv_sec = 0;
+ kctx_tx->end.tv_usec = 0;
+
+ /*
+ * Reset MPC retry counter for a KID once one successful
+ * MPC completion is received for a KID.
+ */
+ kctx_tx->mpc_retry = 0;
+ uma_zfree(tls->mpc_zone, ctx);
+}
+
+static int bnxt_get_tls_seq(struct mbuf* mb, uint64_t* seq)
+{
+
+ for (; mb != NULL; mb = mb->m_next) {
+ if (!(mb->m_flags & M_EXTPG))
+ continue;
+ *seq = mb->m_epg_seqno;
+ return (1);
+ }
+ return (0);
+}
+
+int
+bnxt_alloc_ktls_rexmit_mbuf(struct bnxt_softc *softc, struct bnxt_ring *txr)
+{
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ int ring_sz = softc->scctx->isc_ntxd[1];
+ struct bnxt_replay_pkt *pkt;
+ int i, err;
+
+ txr->replay_pkt = malloc(sizeof(struct bnxt_replay_pkt) * ring_sz,
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+
+ if (!txr->replay_pkt) {
+ BNXT_DEBUG(softc->dev, "kTLS replay_pkt malloc failed\n");
+ return ENOMEM;
+ }
+
+ for (i = 0; i < ring_sz; i++) {
+ pkt = &txr->replay_pkt[i];
+
+ err = bus_dmamap_create(ktls->dma_tag, 0, &pkt->dma_map);
+ if (err != 0) {
+ device_printf(softc->dev,
+ "kTLS replay_pkt dmamap create failed for entry %d\n", i);
+ goto err;
+ }
+ }
+
+ return (0);
+err:
+ for (i = i - 1; i >= 0; i--) {
+ pkt = &txr->replay_pkt[i];
+ bus_dmamap_destroy(ktls->dma_tag, pkt->dma_map);
+ }
+
+ free(txr->replay_pkt, M_DEVBUF);
+ txr->replay_pkt = NULL;
+
+ return ENOMEM;
+}
+
+void inline
+bnxt_free_ktls_rexmit_mbuf(struct bnxt_ring *txr)
+{
+ struct bnxt_softc *softc = txr->softc;
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ int ring_sz = softc->scctx->isc_ntxd[1];
+ struct bnxt_replay_pkt *pkt;
+ int i;
+
+ for (i = 0; i < ring_sz; i++) {
+ pkt = &txr->replay_pkt[i];
+ if (pkt->mbuf) {
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+
+ bus_dmamap_sync(ktls->dma_tag, pkt->dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ktls->dma_tag, pkt->dma_map);
+ m_freem(pkt->mbuf);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_FREES], 1);
+ pkt->mbuf = NULL;
+ }
+ bus_dmamap_destroy(ktls->dma_tag, pkt->dma_map);
+ }
+
+
+ free(txr->replay_pkt, M_DEVBUF);
+}
+
+#define BNXT_REPLAY_PACKET_MSS 9000
+
+static int bnxt_ktls_submit_mbuf(struct bnxt_softc *softc, struct bnxt_ring *txr,
+ struct mbuf **mbp, struct bnxt_ktls_offload_ctx_tx *kctx_tx, int length, uint16_t hsz)
+{
+ bus_dma_segment_t segs[BNXT_MAX_NUM_SEGS];
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ struct bnxt_sw_tx_bd *tx_buf;
+ struct tx_bd_long_hi *tbdh;
+ struct tx_bd_opaque *opq;
+ struct tx_bd_long *tbd;
+ struct bnxt_replay_pkt *pkt;
+ uint32_t kid = kctx_tx->kid;
+ uint16_t flags_type;
+ uint16_t lflags = 0;
+ uint16_t pkt_size, i;
+ uint32_t cfa_meta;
+ struct mbuf *mb;
+ uint32_t prod;
+ int seg = 0;
+ int nsegs;
+ int xsegs;
+ int err;
+
+ pkt_size = length + hsz;
+ prod = txr->prod;
+ mb = *mbp;
+
+ if (!txr->replay_pkt) {
+ BNXT_DEBUG(softc->dev, "kTLS submit_mbuf: no replay_pkt\n");
+ m_freem(mb);
+ return ENOMEM;
+ }
+
+ pkt = &txr->replay_pkt[prod];
+ tx_buf = &txr->tx_buf_ring[prod];
+
+ if (__predict_false(tx_buf->is_replay == 1)) {
+ BNXT_DEBUG(softc->dev, "kTLS submit_mbuf: replay slot busy KID %u\n", kid);
+ m_freem(mb);
+ return EINVAL;
+ }
+
+ pkt->mbuf = mb;
+ /* check number of segments in mbuf */
+ err = bus_dmamap_load_mbuf_sg(ktls->dma_tag, pkt->dma_map,
+ mb, segs, &nsegs, BUS_DMA_NOWAIT);
+
+ if (err == EFBIG) {
+ /* too many mbuf fragments */
+ mb = m_defrag(*mbp, M_NOWAIT);
+ if (mb == NULL) {
+ mb = *mbp;
+ pkt->mbuf = NULL;
+ m_freem(mb);
+ return err;
+ }
+
+ pkt->mbuf = mb;
+ *mbp = mb;
+ /* try again */
+ err = bus_dmamap_load_mbuf_sg(ktls->dma_tag, pkt->dma_map,
+ mb, segs, &nsegs, BUS_DMA_NOWAIT);
+ }
+
+ if (err != 0) {
+ BNXT_DEBUG(softc->dev, "kTLS submit_mbuf: dmamap load failed, err=%d KID %u\n",
+ err, kid);
+ m_freem(mb);
+ pkt->mbuf = NULL;
+ return err;
+ }
+
+ bus_dmamap_sync(ktls->dma_tag, pkt->dma_map,
+ BUS_DMASYNC_PREWRITE);
+
+ /* Calculate segments to be re-played */
+ int rep_len = pkt_size;
+ int max_seg = 0;
+ for (i = xsegs = 0; i != nsegs; i++) {
+ if (rep_len <= 0)
+ break;
+
+ /* Prevent underflow - adjust segment length if needed */
+ if (segs[i].ds_len > rep_len) {
+ /* Use only remaining length, then break */
+ break;
+ }
+ rep_len = rep_len - (uint32_t)segs[i].ds_len;
+
+ if (max_seg < segs[i].ds_len)
+ max_seg = segs[i].ds_len;
+ xsegs++;
+ }
+
+ /* check if there are no segments */
+ if (__predict_false(xsegs == 0)) {
+ BNXT_DEBUG(softc->dev, "kTLS submit_mbuf: no segments after len adjustment KID %u\n",
+ kid);
+ bus_dmamap_unload(ktls->dma_tag, pkt->dma_map);
+ m_freem(mb);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_FREES], 1);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_ERRORS], 1);
+ pkt->mbuf = NULL;
+ *mbp = NULL; /* safety clear */
+ return (0);
+ }
+
+ tx_buf->is_replay = 1;
+ lflags = htole16(TX_BD_FLAGS_CRYPTO_EN);
+
+ /* First(header) BD of the packet*/
+ tbd = &((struct tx_bd_long *)txr->vaddr)[prod];
+
+ opq = (struct tx_bd_opaque *)&tbd->opaque;
+ /* No need to byte-swap the opaque value */
+ SET_TX_OPAQUE_KTLS(opq, txr, 1, prod, txr->running_bds + xsegs + 1);
+ tbd->len = htole16(segs[seg].ds_len);
+ tbd->addr = htole64(segs[seg++].ds_addr);
+ flags_type = ((xsegs + 1) << TX_BD_SHORT_FLAGS_BD_CNT_SFT) & TX_BD_SHORT_FLAGS_BD_CNT_MASK;
+ if (length >= 2048)
+ flags_type |= TX_BD_SHORT_FLAGS_LHINT_GTE2K;
+ else
+ flags_type |= bnxt_tx_lhint[length >> 9];
+
+ /*Meta BD of the packet*/
+ flags_type |= TX_BD_LONG_TYPE_TX_BD_LONG;
+
+ if (softc->tx_host_coal_enable) {
+ /*
+ * Must generate Tx completion for replay packet, so do not set
+ * TX_BD_LONG_FLAGS_NO_CMPL flag for replay packets.
+ */
+ flags_type |= TX_BD_LONG_FLAGS_COAL_NOW;
+ txr->running_bds = 0;
+ }
+
+ prod = RING_NEXT(txr, prod);
+
+ if (length >= BNXT_REPLAY_PACKET_MSS) {
+ mb->m_pkthdr.tso_segsz = BNXT_REPLAY_PACKET_MSS;
+ mb->m_pkthdr.csum_flags |= CSUM_TSO;
+ } else if (xsegs > 1) {
+ mb->m_pkthdr.tso_segsz = max_seg;
+ mb->m_pkthdr.csum_flags |= CSUM_TSO;
+ }
+
+ tbdh = &((struct tx_bd_long_hi *)txr->vaddr)[prod];
+ tbdh->kid_or_ts_high_mss = htole32((mb->m_pkthdr.tso_segsz & TX_BD_LONG_MSS_MASK) |
+ ((KID_HIGH(kid) << TX_BD_LONG_KID_OR_TS_HIGH_SFT) &
+ TX_BD_LONG_KID_OR_TS_HIGH_MASK));
+
+ tbdh->kid_or_ts_low_hdr_size = htole16(((hsz >> 1) & TX_BD_LONG_HDR_SIZE_MASK) |
+ ((KID_LOW(kid) << TX_BD_LONG_KID_OR_TS_LOW_SFT) &
+ TX_BD_LONG_KID_OR_TS_LOW_MASK));
+ tbdh->cfa_action = 0;
+
+ cfa_meta = 0;
+
+ if (mb->m_flags & M_VLANTAG) {
+ /* TODO: Do we need to byte-swap the vtag here? */
+ cfa_meta = TX_BD_LONG_CFA_META_KEY_VLAN_TAG |
+ mb->m_pkthdr.ether_vtag;
+ cfa_meta |= TX_BD_LONG_CFA_META_VLAN_TPID_TPID8100;
+ }
+ tbdh->cfa_meta = htole32(cfa_meta);
+
+ if (mb->m_pkthdr.csum_flags & CSUM_TSO) {
+ lflags |= TX_BD_LONG_LFLAGS_LSO |
+ TX_BD_LONG_LFLAGS_T_IPID;
+ }
+ else if(mb->m_pkthdr.csum_flags & CSUM_OFFLOAD) {
+ lflags |= TX_BD_LONG_LFLAGS_TCP_UDP_CHKSUM |
+ TX_BD_LONG_LFLAGS_IP_CHKSUM;
+ }
+ else if(mb->m_pkthdr.csum_flags & CSUM_IP) {
+ lflags |= TX_BD_LONG_LFLAGS_IP_CHKSUM;
+ }
+
+ tbdh->lflags = htole16(lflags);
+
+ /* Payload BD*/
+ for (; seg < xsegs; seg++) {
+ tbd->flags_type = htole16(flags_type);
+
+ prod = RING_NEXT(txr, prod);
+
+ tbd = &((struct tx_bd_long *)txr->vaddr)[prod];
+ tbd->len = htole16(segs[seg].ds_len);
+ tbd->addr = htole64(segs[seg].ds_addr);
+ flags_type = TX_BD_SHORT_TYPE_TX_BD_SHORT;
+ }
+
+ flags_type |= TX_BD_SHORT_FLAGS_PACKET_END;
+ tbd->flags_type = htole16(flags_type);
+
+ prod = RING_NEXT(txr, prod);
+
+ txr->prod = prod;
+
+ softc->db_ops.bnxt_db_tx(txr, prod);
+
+ return 0;
+}
+
+static void bnxt_ktls_pre_xmit(struct bnxt_softc *bp, struct bnxt_ring *txr,
+ uint32_t kid, struct crypto_prefix_cmd *pre_cmd)
+{
+ struct bnxt_sw_tx_bd *tx_buf;
+ uint32_t bd_space, space;
+ uint8_t *pcmd;
+ struct tx_bd *pcmd1;
+ uint16_t prod;
+ struct tx_bd_presync *psbd;
+ struct tx_bd_opaque *opq;
+ bool need_cpl = false;
+
+ prod = txr->prod;
+
+ tx_buf = &txr->tx_buf_ring[prod];
+
+ if (bp->tx_host_coal_enable) {
+ /* BD field of opaque is only 15 bits; respect tx_host_coal_bds threshold */
+ if ((txr->running_bds + CRYPTO_PREFIX_CMD_BDS + 1) >
+ (bp->tx_host_coal_bds - (BNXT_MAX_NUM_SEGS + 1)))
+ need_cpl = true;
+ }
+
+ /* presync TX BD prep */
+ psbd = &((struct tx_bd_presync *)txr->vaddr)[prod];
+ psbd->tx_bd_len_flags_type = CRYPTO_PRESYNC_BD_CMD;
+ psbd->tx_bd_kid = htole32(kid);
+
+ opq = (struct tx_bd_opaque *)&psbd->tx_bd_opaque;
+ SET_TX_OPAQUE_KTLS(opq, txr, 0, prod,
+ txr->running_bds + CRYPTO_PREFIX_CMD_BDS + 1);
+
+ if (bp->tx_host_coal_enable) {
+ psbd->tx_bd_len_flags_type |= TX_BD_LONG_FLAGS_COAL_NOW;
+ if (need_cpl) {
+ txr->running_bds = 0;
+ } else {
+ txr->running_bds += (CRYPTO_PREFIX_CMD_BDS + 1);
+ psbd->tx_bd_len_flags_type |= TX_BD_LONG_FLAGS_NO_CMPL;
+ }
+ }
+
+ prod = RING_NEXT(txr, prod);
+
+ /* Copy pre-cmd to TX desc ring*/
+ pcmd1 = &((struct tx_bd *)txr->vaddr)[prod];
+ pcmd = (uint8_t *)pcmd1;
+ bd_space = txr->ring_size - prod;
+ space = bd_space * sizeof(struct tx_bd);
+ if (space >= CRYPTO_PREFIX_CMD_SIZE) {
+ memcpy(pcmd, pre_cmd, CRYPTO_PREFIX_CMD_SIZE);
+ prod += CRYPTO_PREFIX_CMD_BDS - 1;
+ } else {
+ memcpy(pcmd, pre_cmd, space);
+ prod = 0;
+ pcmd1 = &((struct tx_bd *)txr->vaddr)[prod];
+ pcmd = (uint8_t *)pcmd1;
+ memcpy((uint8_t *)pcmd, (uint8_t *)pre_cmd + space,
+ CRYPTO_PREFIX_CMD_SIZE - space);
+ prod += CRYPTO_PREFIX_CMD_BDS - bd_space - 1;
+ }
+
+ prod = RING_NEXT(txr, prod);
+ tx_buf->inline_bds = CRYPTO_PREFIX_CMD_BDS - 1;
+ txr->prod = prod;
+}
+
+static int bnxt_get_tls_record_len(struct mbuf *m)
+{
+ uint32_t rec_len = 0;
+
+ /*
+ * A single-page record has no "middle" or trailing page: the whole
+ * payload is m_epg_last_len bytes starting at m_epg_1st_off, per
+ * m_epg_pagelen()'s treatment of pidx == m_epg_npgs - 1 == 0.
+ */
+ if (m->m_epg_npgs == 1)
+ return m->m_epg_last_len;
+
+ rec_len += PAGE_SIZE - m->m_epg_1st_off;
+ if (m->m_epg_npgs > 2)
+ rec_len += PAGE_SIZE * (m->m_epg_npgs - 2);
+
+ rec_len += m->m_epg_last_len;
+
+ return rec_len;
+}
+
+static struct mbuf *bnxt_get_tls_record(struct mbuf *m0, device_t dev)
+{
+ struct mbuf *m = m0;
+
+ /* find TLS record */
+ for (; m != NULL; m = m->m_next) {
+ if (!(m->m_flags & M_EXTPG))
+ continue;
+ else
+ break;
+ }
+
+ if (__predict_false((m == NULL))) {
+ /* should never happen; means we got a non-TLS mbuf */
+ device_printf(dev, "kTLS: non-TLS packet in %s\n", __func__);
+ return NULL;
+ }
+ return m;
+}
+
+static struct tcphdr *bnxt_get_tcp_seq(if_pkt_info_t pi, struct mbuf *m, struct mbuf **mp)
+{
+ struct tcphdr *th = NULL;
+ uint32_t hlen;
+
+ hlen = pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen;
+ if (m->m_len < hlen) {
+ m = m_pullup(m, hlen);
+ if (m == NULL)
+ return NULL;
+ *mp = m;
+ }
+
+ th = mtodo(m, pi->ipi_ehdrlen + pi->ipi_ip_hlen);
+
+ return th;
+}
+
+
+static int bnxt_ktls_tx_replay(struct bnxt_softc *bp, struct bnxt_ring *txr,
+ struct mbuf *mb, struct bnxt_ktls_offload_ctx_tx *kctx_tx, uint32_t seq,
+ uint32_t hdr_tcp_seq, if_pkt_info_t pi)
+{
+ struct bnxt_tls_info *ktls;
+ struct mbuf *r_mb, *mp;
+ struct tcphdr *th;
+ int hsz;
+ uint32_t replay_len;
+ uint32_t tcp_seq = hdr_tcp_seq;
+
+ replay_len = seq - hdr_tcp_seq;
+
+ ktls = bp->ktls_info;
+
+ r_mb = m_copypacket(mb, M_NOWAIT);
+
+ if (r_mb == NULL) {
+ BNXT_DEBUG(bp->dev, "[KID:%u]: kTLS replay m_copypacket failed\n", kctx_tx->kid);
+ return EINVAL;
+ }
+
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_ALLOCS], 1);
+ hsz = (pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen);
+
+ mp = r_mb;
+
+ th = bnxt_get_tcp_seq(pi, r_mb, &mp);
+
+ r_mb = mp;
+
+ if (th == NULL) {
+ /* m_pullup() already called m_freem on r_mb on failure.
+ * so no m_freem(r_mb) is needed again.
+ */
+ BNXT_DEBUG(bp->dev, "[KID:%u]: kTLS replay get_tcp_seq failed\n", kctx_tx->kid);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_FREES], 1);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_ERRORS], 1);
+ return EINVAL;
+ }
+
+ th->th_seq = htonl(tcp_seq);
+
+ if (r_mb->m_next == NULL) {
+ BNXT_DEBUG(bp->dev, "[KID:%u]: kTLS replay missing payload mbuf\n", kctx_tx->kid);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_ERRORS], 1);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_FREES], 1);
+ m_freem(r_mb);
+ return EINVAL;
+ }
+
+ r_mb->m_next->m_data -= replay_len;
+ r_mb->m_next->m_len = replay_len;
+
+ r_mb->m_pkthdr.len = replay_len + hsz;
+
+ if (bnxt_ktls_submit_mbuf(bp, txr, &r_mb, kctx_tx, replay_len, hsz) != 0) {
+ BNXT_DEBUG(bp->dev, "[KID:%u]: kTLS replay submit_mbuf failed\n", kctx_tx->kid);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_FREES], 1);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_ERRORS], 1);
+ return ENOSPC;
+ }
+
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_REPLAY], 1);
+
+ return 0;
+}
+
+static int bnxt_ktls_tx_ooo(struct bnxt_softc *bp, struct bnxt_ring *txr,
+ struct mbuf *mbuf, uint32_t payload_len, uint32_t seq,
+ struct bnxt_ktls_offload_ctx_tx *kctx_tx, if_pkt_info_t pi)
+{
+ struct tls_record_layer *tlshdr;
+ struct crypto_prefix_cmd pcmd = {0};
+ struct bnxt_tls_info *ktls;
+ uint32_t presync_flags = 0;
+ struct mbuf *m;
+ uint32_t hdr_tcp_seq;
+ uint8_t *hdr = NULL;
+ bool fwd = false;
+ int rc = 0;
+ uint64_t rec_sn = 0;
+ uint32_t rec_len;
+ uint32_t record_end_seq;
+ uint32_t offset;
+ uint32_t nonce_bytes;
+ uint32_t end_seq;
+ bool is_replay = false;
+ bool update_inorder = false;
+ uint32_t tx_prod;
+ uint16_t running_bds;
+
+ ktls = bp->ktls_info;
+
+ m = bnxt_get_tls_record(mbuf, bp->dev);
+ if (m == NULL) {
+ device_printf(bp->dev, "kTLS OOO: no TLS record in mbuf\n");
+ return EINVAL;
+ }
+
+ bnxt_get_tls_seq(m, &rec_sn);
+ rec_len = bnxt_get_tls_record_len(m);
+
+ offset = (uintptr_t)m->m_data;
+ tlshdr = (void *)m->m_epg_hdr;
+ hdr_tcp_seq = seq - offset;
+ hdr = (uint8_t*)tlshdr;
+
+ record_end_seq =
+ (hdr_tcp_seq + rec_len + m->m_epg_hdrlen + m->m_epg_trllen) - 1;
+
+ end_seq = seq + payload_len - 1;
+
+ if (__predict_false(after(seq, kctx_tx->tcp_seq_no) ||
+ after(end_seq, kctx_tx->tcp_seq_no))) {
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_SEQ_FWD], 1);
+ fwd = true;
+
+ /* Check if the seq forward packet has a TLS header*/
+ if (seq <= hdr_tcp_seq && end_seq >= hdr_tcp_seq) {
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_SEQ_FWD_TLS_HDR], 1);
+ presync_flags = CRYPTO_PREFIX_CMD_FLAGS_UPDATE_IN_ORDER_VAR;
+ update_inorder = true;
+ } else {
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_SEQ_FWD_SILENT_DROPS], 1);
+ }
+ } else
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_RETRANS], 1);
+
+ pcmd.header_tcp_seq_num = htole32(hdr_tcp_seq);
+ pcmd.start_tcp_seq_num = htole32(seq);
+ pcmd.end_tcp_seq_num = htole32(end_seq);
+
+ if ((kctx_tx->crypto_info.tls_vmajor ==
+ TLS_MAJOR_VER_ONE) &&
+ (kctx_tx->crypto_info.tls_vminor ==
+ TLS_MINOR_VER_TWO)) {
+ nonce_bytes = BNXT_EXPLICIT_NONCE_LEN;
+
+ if (offset > 5 && (offset < (5 + nonce_bytes)))
+ nonce_bytes = offset - 5;
+
+ /* Verify we don't exceed TLS header bounds */
+ if ((hdr + 5 + nonce_bytes) > ((uint8_t*)tlshdr + m->m_epg_hdrlen)) {
+ BNXT_DEBUG(bp->dev, "kTLS OOO: TLS header bounds exceeded\n");
+ return EINVAL;
+ }
+
+ memcpy(pcmd.explicit_nonce, hdr + 5, nonce_bytes);
+ }
+
+ /* Out-of-sequence packet includes tag(trailer) */
+ if (offset && (record_end_seq - m->m_epg_trllen) <
+ (seq + payload_len)) {
+ is_replay = true;
+ }
+
+ memcpy(&pcmd.record_seq_num[0], &rec_sn, sizeof(rec_sn));
+
+ if (update_inorder)
+ presync_flags = CRYPTO_PREFIX_CMD_FLAGS_UPDATE_IN_ORDER_VAR;
+ else if (is_replay)
+ presync_flags = CRYPTO_PREFIX_CMD_FLAGS_FULL_REPLAY_RETRAN;
+ else
+ presync_flags = 0;
+
+ pcmd.flags = htole32(presync_flags);
+
+ /*
+ * Save tx ring producer index and running_bds accumulator before
+ * writing presync command, it will be used to move the producer
+ * index backwards to discard presync command and restore running_bds
+ * to the state of before sending presync command, if replay packet fails.
+ */
+ tx_prod = txr->prod;
+ running_bds = txr->running_bds;
+
+ bnxt_ktls_pre_xmit(bp, txr, kctx_tx->kid, &pcmd);
+
+ if (is_replay) {
+ rc = bnxt_ktls_tx_replay(bp, txr, mbuf, kctx_tx, seq, hdr_tcp_seq, pi);
+
+ if (fwd)
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_SEQ_FWD_REPLAY], 1);
+ /*
+ * If replay failed, discard presync BD by rolling back both the
+ * producer index and restore running_bds accumulator.
+ */
+ if (rc) {
+ txr->prod = tx_prod;
+ txr->running_bds = running_bds;
+ }
+ }
+
+ if (update_inorder && !rc)
+ kctx_tx->tcp_seq_no = end_seq + 1;
+
+ return rc;
+}
+
+int bnxt_ktls_xmit(struct bnxt_softc* softc, struct bnxt_ring* txr,
+ struct mbuf** ppmb, uint16_t* lflags, uint32_t* kid, if_pkt_info_t pi)
+{
+ struct bnxt_ktls_offload_ctx_tx* kctx_tx;
+ struct bnxt_tls_info* ktls = softc->ktls_info;
+ struct m_snd_tag* ptag;
+ struct mbuf* mb = *ppmb;
+ uint64_t rec_sn;
+ uint32_t header_size;
+ uint32_t mb_seq;
+ int rc;
+
+ if ((mb->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0)
+ return (0);
+
+ ptag = mb->m_pkthdr.snd_tag;
+
+ if (ptag == NULL || ptag->sw == NULL ||
+ ptag->sw->type != IF_SND_TAG_TYPE_TLS) {
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_INVALID_TAG], 1);
+ return (0);
+ }
+
+ kctx_tx = __containerof(ptag, struct bnxt_ktls_offload_ctx_tx, tag);
+
+ header_size = (pi->ipi_ehdrlen + pi->ipi_ip_hlen + pi->ipi_tcp_hlen);
+
+
+ if (__predict_false(header_size == 0)) {
+ BNXT_DEBUG(softc->dev, "kTLS xmit: zero header size\n");
+ return EINVAL;
+ }
+
+ if (header_size == mb->m_pkthdr.len) {
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_ZERO_TCP_PAYLEN], 1);
+ BNXT_DEBUG(softc->dev, "kTLS xmit: zero TCP payload\n");
+ return (0);
+ }
+
+ if (bnxt_get_tls_seq(mb, &rec_sn) == 0) {
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_INVALID_REC_SN], 1);
+ BNXT_DEBUG(softc->dev, "kTLS xmit: invalid record seq\n");
+ return (0);
+ }
+
+ mb_seq = ntohl(pi->ipi_tcp_seq);
+
+ switch(kctx_tx->state) {
+ /* Add crypto MPC is not yet completed*/
+ case BNXT_TLS_STATE_INIT:
+ if (!kctx_tx->enobufs)
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_TCE_NOT_READY], 1);
+
+ kctx_tx->enobufs++;
+
+ BNXT_DEBUG(softc->dev, "[KID:%u]: TCE INIT:"
+ " tcp_seqno: %u record_no: %lu enobufs: %u\n",
+ kctx_tx->kid, mb_seq, rec_sn, kctx_tx->enobufs);
+
+ return ENOBUFS;
+ /* Crypto connection is setup and ready to use */
+ case BNXT_TLS_STATE_READY:
+ if (kctx_tx->enobufs) {
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_TCE_READY_DELAYED], 1);
+ BNXT_DEBUG(softc->dev, "[KID:%u]: TCE READY:"
+ " tcp_seqno: %u record_no: %lu enobufs: %u\n",
+ kctx_tx->kid, mb_seq, rec_sn, kctx_tx->enobufs);
+ kctx_tx->enobufs = 0;
+ }
+ break;
+ /* Crypto connection is in bad state */
+ case BNXT_TLS_STATE_BAD:
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_TCE_BAD], 1);
+ BNXT_DEBUG(softc->dev, "[KID:%u]: TCE BAD:"
+ " tcp_seqno: %u record_no: %lu enobufs: %u\n",
+ kctx_tx->kid, mb_seq, rec_sn, kctx_tx->enobufs);
+ return EINVAL;
+ case BNXT_TLS_STATE_FREE:
+ case BNXT_TLS_STATE_FREED:
+ counter_u64_add(ktls->err_counters[BNXT_KTLS_TX_TCE_FREE], 1);
+ /* FALLTHROUGH */
+ default:
+ return EINVAL;
+ }
+
+ *kid = kctx_tx->kid;
+ *lflags |= TX_BD_LONG_LFLAGS_CRYPTO_EN;
+
+ if (kctx_tx->tcp_seq_no == mb_seq) {
+ kctx_tx->inorder_rec_sn = rec_sn;
+ kctx_tx->inorder_paylen = mb->m_pkthdr.len - header_size;
+ kctx_tx->inorder_seq = kctx_tx->tcp_seq_no;
+ kctx_tx->tcp_seq_no += mb->m_pkthdr.len - header_size;
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_HW_PKT], 1);
+ } else {
+ uint32_t payload_len;
+
+ payload_len = mb->m_pkthdr.len - header_size;
+
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_OOO], 1);
+
+ rc = bnxt_ktls_tx_ooo(softc, txr, mb, payload_len, mb_seq, kctx_tx, pi);
+ if (rc) {
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_FAILED], 1);
+ BNXT_DEBUG(softc->dev, "[KID:%u]: kTLS OOO failed, rc=%d\n", kctx_tx->kid, rc);
+ return EAGAIN;
+ }
+ }
+
+ return (0);
+}
+
+#else /* KERN_TLS */
+
+void bnxt_free_ktls_counters(struct bnxt_softc* softc)
+{
+}
+
+void bnxt_alloc_ktls_counters(struct bnxt_softc* softc)
+{
+}
+
+void bnxt_alloc_ktls_info(struct bnxt_softc* softc, uint16_t max_keys,
+ bool partition_cap, uint16_t ctxs_per_partition)
+{
+}
+
+void bnxt_free_ktls_info(struct bnxt_softc* softc)
+{
+}
+
+void bnxt_hwrm_reserve_pf_key_ctxs(struct bnxt_softc* softc,
+ struct hwrm_func_cfg_input* req,
+ uint8_t type)
+{
+}
+
+int bnxt_ktls_init(struct bnxt_softc* softc)
+{
+ return 0;
+}
+
+void bnxt_ktls_mpc_cmp(struct bnxt_softc* softc, uint32_t client,
+ unsigned long handle, struct bnxt_cmpl_entry cmpl[],
+ uint32_t entries)
+{
+}
+
+int bnxt_ktls_xmit(struct bnxt_softc* softc, struct bnxt_ring* txr,
+ struct mbuf** ppmb, uint16_t* lflags, uint32_t* kid, if_pkt_info_t pi)
+{
+ return 0;
+}
+
+void bnxt_ktls_del_all(struct bnxt_softc *softc)
+{
+}
+
+void bnxt_clear_ktls(struct bnxt_softc *softc)
+{
+}
+
+int
+bnxt_alloc_ktls_rexmit_mbuf(struct bnxt_softc *softc, struct bnxt_ring *txr)
+{
+ return 0;
+}
+
+void inline
+bnxt_free_ktls_rexmit_mbuf(struct bnxt_ring *txr)
+{
+}
+
+#endif /* KERN_TLS */
Index: sys/dev/bnxt/bnxt_en/bnxt_sysctl.h
===================================================================
--- sys/dev/bnxt/bnxt_en/bnxt_sysctl.h
+++ sys/dev/bnxt/bnxt_en/bnxt_sysctl.h
@@ -42,3 +42,6 @@
int bnxt_create_pause_fc_sysctls(struct bnxt_softc *softc);
int bnxt_create_dcb_sysctls(struct bnxt_softc *softc);
int bnxt_create_dcb_ets_sysctls(struct bnxt_softc *softc);
+int bnxt_create_ktls_sysctls(struct bnxt_softc *softc);
+int bnxt_ktls_sysctls(struct bnxt_softc *softc);
+int bnxt_create_mpc_cmp_time_sysctls(struct bnxt_softc *softc);
Index: sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
===================================================================
--- sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
+++ sys/dev/bnxt/bnxt_en/bnxt_sysctl.c
@@ -34,6 +34,82 @@
#include "bnxt.h"
#include "bnxt_hwrm.h"
#include "bnxt_sysctl.h"
+#include "bnxt_ktls.h"
+
+struct bnxt_ktls_counters_list {
+ enum bnxt_ktls_counters id;
+ const char *label;
+ const char *desc;
+};
+static const struct bnxt_ktls_counters_list ktls_counters[] = {
+ { BNXT_KTLS_TX_ADD, "add_tx_session", "KTLS sessions add count" },
+ { BNXT_KTLS_TX_DEL, "delete_tx_session", "KTLS sessions delete count" },
+ { BNXT_KTLS_TX_HW_PKT, "hw_tx_pkts", "HW KTLS TX count" },
+ { BNXT_KTLS_TX_FAILED, "failed_tx_pkts", "SW KTLS TX count" },
+ { BNXT_KTLS_TX_OOO, "ooo_tx_pkts", "OOO KTLS TX count" },
+ { BNXT_KTLS_TX_RETRANS, "retrans_tx_pkts", "Retransmitted KTLS TX count" },
+ { BNXT_KTLS_TX_REPLAY, "replay_tx_pkts", "Replay KTLS TX count" },
+ { BNXT_KTLS_TX_SEQ_FWD, "seq_fwd_tx_pkts", "Seq forward KTLS Tx count" },
+ { BNXT_KTLS_TX_SEQ_FWD_TLS_HDR, "seq_fwd_tx_tls_hdr_pkts", "Seq forward Tx packets with TLS header" },
+ { BNXT_KTLS_TX_SEQ_FWD_SILENT_DROPS, "seq_fwd_tx_silent_drops_pkts", "Silently dropped seq forward packets" },
+ { BNXT_KTLS_TX_SEQ_FWD, "seq_fwd_tx_replay_pkts", "Replayed Seq forward packets" },
+ { BNXT_KTLS_TX_MBUF_ALLOCS, "mbuf_allocs", "Alloc mbufs count" },
+ { BNXT_KTLS_TX_MBUF_FREES, "mbuf_frees", "Free mbufs count" },
+ { BNXT_KTLS_TX_MBUF_ERRORS, "mbuf_errors", "Error mbufs count" },
+};
+static const int ktls_counters_count = sizeof(ktls_counters) / sizeof(ktls_counters[0]);
+
+struct bnxt_ktls_err_counters_list {
+ enum bnxt_ktls_err_counters id;
+ const char *label;
+ const char *desc;
+};
+static const struct bnxt_ktls_err_counters_list ktls_err_counters[] = {
+ { BNXT_KTLS_TX_DEV_ADD_FAILED, "add_tx_session_failure", "Tx KTLS device add failure count" },
+ { BNXT_KTLS_TX_MPC_TIMEOUT, "mpc_cmd_timeout", "Timeout MPC commands count" },
+ { BNXT_KTLS_TX_UNINITIALIZED, "ktls_tx_uninit", "snd_tag alloc failure due to ktls not initialized" },
+ { BNXT_KTLS_TX_CTX_ALLOC_FAILED, "ctx_alloc_failures", "snd_tag alloc failure due to ctx alloc failed" },
+ { BNXT_KTLS_TX_MPC_FAILED, "mpc_failures", "MPC command failures count" },
+ { BNXT_KTLS_TX_TCE_NOT_READY, "tce_not_ready", "Tx crypto engine(TCE) is not ready" },
+ { BNXT_KTLS_TX_TCE_READY_DELAYED, "tce_ready_delayed", "TCE getting ready with delay" },
+ { BNXT_KTLS_TX_TCE_BAD, "tce_bad", "TCE is in bad state" },
+ { BNXT_KTLS_TX_UNSUPPORTED_TLS_HDR, "unsupported_tls_hdr", "snd_tag alloc failure due to unsupported TLS header" },
+ { BNXT_KTLS_TX_INVALID_TAG, "invalid_tag", "Invalid snd_tag" },
+ { BNXT_KTLS_TX_ZERO_TCP_PAYLEN, "zero_payload", "Packet/s with zero TCP payload" },
+ { BNXT_KTLS_TX_INVALID_REC_SN, "invalid_rec_sn", "Invalid Record" },
+ { BNXT_KTLS_TX_TCE_FREE, "tce_free", "Packets received when crypto delete is ongoing"},
+};
+
+static const int ktls_err_counters_count = sizeof(ktls_err_counters) / sizeof(ktls_err_counters[0]);
+
+struct bnxt_mpc_cmp_time_counters_list {
+ enum bnxt_mpc_cmp_time_counters id;
+ const char *label;
+ const char *desc;
+};
+static const struct bnxt_mpc_cmp_time_counters_list mpc_cmp_counters[] = {
+ { BNXT_MPC_CMP_TIME_1US, "<=1us", "MPC command completion <= 1us" },
+ { BNXT_MPC_CMP_TIME_1_5US, "1-5us", "MPC command completion between 1-5us" },
+ { BNXT_MPC_CMP_TIME_5_10US, "5-10us", "MPC command completion between 5-10us" },
+ { BNXT_MPC_CMP_TIME_10_15US, "10-15us", "MPC command completion between 10-15us" },
+ { BNXT_MPC_CMP_TIME_15_20US, "15-20us", "MPC command completion between 15-20us" },
+ { BNXT_MPC_CMP_TIME_20_25US, "20-25us", "MPC command completion between 20-25us" },
+ { BNXT_MPC_CMP_TIME_25_50US, "25-50us", "MPC command completion between 25-50us" },
+ { BNXT_MPC_CMP_TIME_50_100US, "50-100us", "MPC command completion between 50-100us" },
+ { BNXT_MPC_CMP_TIME_100_200US, "100-200us", "MPC command completion between 100-200us" },
+ { BNXT_MPC_CMP_TIME_200_500US, "200-500us", "MPC command completion between 200-500us" },
+ { BNXT_MPC_CMP_TIME_500_1000US, "500-1000us", "MPC command completion between 500-1000us" },
+ { BNXT_MPC_CMP_TIME_1000_1500US, "1000-1500us", "MPC command completion between 1000-1500us" },
+ { BNXT_MPC_CMP_TIME_1500_2000US, "1500-2000us", "MPC command completion between 1500-2000us" },
+ { BNXT_MPC_CMP_TIME_2000_2500US, "2000-2500us", "MPC command completion between 2000-2500us" },
+ { BNXT_MPC_CMP_TIME_2500_3000US, "2500-3000us", "MPC command completion between 2500-3000us" },
+ { BNXT_MPC_CMP_TIME_3000_3500US, "3000-3500us", "MPC command completion between 3000-3500us" },
+ { BNXT_MPC_CMP_TIME_3500_4000US, "3500-4000us", "MPC command completion between 3500-4000us" },
+ { BNXT_MPC_CMP_TIME_4000_4500US, "4000-4500us", "MPC command completion between 4000-4500us" },
+ { BNXT_MPC_CMP_TIME_4500_5000US, "4500-5000us", "MPC command completion between 4500-5000us" },
+ { BNXT_MPC_CMP_TIME_5000_PLUS_US, "5000+us", "MPC command completion >= 5000us" },
+};
+static const int mpc_cmp_counters_count = sizeof(mpc_cmp_counters) / sizeof(mpc_cmp_counters[0]);
DEFINE_MUTEX(tmp_mutex); /* mutex lock for driver */
extern void bnxt_fw_reset(struct bnxt_softc *bp);
@@ -121,6 +197,27 @@
return ENOMEM;
}
+ sysctl_ctx_init(&softc->ktls_stats);
+ ctx = device_get_sysctl_ctx(softc->dev);
+ softc->ktls_stats_oid = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev)), OID_AUTO,
+ "ktls_stats", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "kTLS statistics");
+ if (!softc->ktls_stats_oid) {
+ sysctl_ctx_free(&softc->ktls_stats);
+ return ENOMEM;
+ }
+
+ sysctl_ctx_init(&softc->mpc_cmp_time_stats);
+ ctx = device_get_sysctl_ctx(softc->dev);
+ softc->mpc_cmp_time_stats_oid = SYSCTL_ADD_NODE(ctx,
+ SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev)), OID_AUTO,
+ "mpc_cmp_time_stats", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "MPC completion time statistics");
+ if (!softc->mpc_cmp_time_stats_oid) {
+ sysctl_ctx_free(&softc->mpc_cmp_time_stats);
+ return ENOMEM;
+ }
+
return 0;
}
@@ -175,6 +272,22 @@
softc->dcb_oid = NULL;
}
+ if (softc->ktls_stats_oid != NULL) {
+ orc = sysctl_ctx_free(&softc->ktls_stats);
+ if (orc)
+ rc = orc;
+ else
+ softc->ktls_stats_oid = NULL;
+ }
+
+ if (softc->mpc_cmp_time_stats_oid != NULL) {
+ orc = sysctl_ctx_free(&softc->mpc_cmp_time_stats);
+ if (orc)
+ rc = orc;
+ else
+ softc->mpc_cmp_time_stats_oid = NULL;
+ }
+
return rc;
}
@@ -2245,3 +2358,107 @@
/* Nothing for now, meant for future expansion */
return 0;
}
+
+static int
+sysctl_counter_u64_handler(SYSCTL_HANDLER_ARGS)
+{
+ counter_u64_t *counter = (counter_u64_t *)arg1;
+ uint64_t val = counter_u64_fetch(*counter);
+
+ return sysctl_handle_64(oidp, &val, 0, req);
+}
+
+int
+bnxt_create_ktls_sysctls(struct bnxt_softc *softc)
+{
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ struct sysctl_oid *oid;
+
+ if (!ktls)
+ return 0;
+
+ oid = SYSCTL_ADD_NODE(&softc->ktls_stats,
+ SYSCTL_CHILDREN(softc->ktls_stats_oid), OID_AUTO,
+ "ktls_stats", CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "In-kernel TLS statistics");
+ if (!oid)
+ return ENOMEM;
+
+ for (int i = 0; i < ktls_counters_count; i++) {
+ const struct bnxt_ktls_counters_list *counters = &ktls_counters[i];
+
+ SYSCTL_ADD_PROC(&softc->ktls_stats,
+ SYSCTL_CHILDREN(oid), OID_AUTO,
+ counters->label,
+ CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ &ktls->counters[counters->id],
+ 0,
+ sysctl_counter_u64_handler,
+ "Q",
+ counters->desc);
+ }
+
+ for (int i = 0; i < ktls_err_counters_count; i++) {
+ const struct bnxt_ktls_err_counters_list *err_counters = &ktls_err_counters[i];
+
+ SYSCTL_ADD_PROC(&softc->ktls_stats, SYSCTL_CHILDREN(oid), OID_AUTO,
+ err_counters->label,
+ CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ &ktls->err_counters[i], 0,
+ sysctl_counter_u64_handler, "Q",
+ err_counters->desc);
+ }
+
+ return 0;
+}
+
+int
+bnxt_ktls_sysctls(struct bnxt_softc *softc)
+{
+ struct sysctl_ctx_list *ctx;
+ struct sysctl_oid_list *children;
+ struct sysctl_oid *oid;
+
+ ctx = device_get_sysctl_ctx(softc->dev);
+ children = SYSCTL_CHILDREN(device_get_sysctl_tree(softc->dev));
+
+ oid = SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "max_ktls_entries",
+ CTLFLAG_RDTUN, &softc->max_ktls_entries, 0,
+ "Maximum number of TLS offload entries to preallocate (default: 102400, max: 512000)");
+ if (!oid)
+ return ENOMEM;
+
+ return 0;
+}
+
+int
+bnxt_create_mpc_cmp_time_sysctls(struct bnxt_softc *softc)
+{
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ struct sysctl_oid *oid;
+
+ if (!ktls)
+ return 0;
+
+ oid = SYSCTL_ADD_NODE(&softc->mpc_cmp_time_stats,
+ SYSCTL_CHILDREN(softc->mpc_cmp_time_stats_oid), OID_AUTO,
+ "mpc_cmp_stats", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "MPC CMP time statistics");
+ if (!oid)
+ return ENOMEM;
+
+ for (int i = 0; i < mpc_cmp_counters_count; i++) {
+ const struct bnxt_mpc_cmp_time_counters_list *mpc_counters = &mpc_cmp_counters[i];
+
+ SYSCTL_ADD_PROC(&softc->mpc_cmp_time_stats,
+ SYSCTL_CHILDREN(oid), OID_AUTO,
+ mpc_counters->label,
+ CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_MPSAFE,
+ &ktls->mpc_cmp_time[i],
+ 0,
+ sysctl_counter_u64_handler,
+ "Q",
+ mpc_counters->desc);
+ }
+
+ return 0;
+}
Index: sys/dev/bnxt/bnxt_en/bnxt_txrx.c
===================================================================
--- sys/dev/bnxt/bnxt_en/bnxt_txrx.c
+++ sys/dev/bnxt/bnxt_en/bnxt_txrx.c
@@ -37,10 +37,13 @@
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_rss.h"
+#include "opt_kern_tls.h"
#include <machine/atomic.h>
#include "bnxt.h"
#include "bnxt_ptp.h"
+#include "bnxt_ktls.h"
+#include "bnxt_log.h"
/*
* Function prototypes
@@ -79,7 +82,7 @@
* Device Dependent Packet Transmit and Receive Functions
*/
-static const uint16_t bnxt_tx_lhint[] = {
+const uint16_t bnxt_tx_lhint[] = {
TX_BD_SHORT_FLAGS_LHINT_LT512,
TX_BD_SHORT_FLAGS_LHINT_LT1K,
TX_BD_SHORT_FLAGS_LHINT_LT2K,
@@ -97,12 +100,27 @@
bool need_cpl = false;
bool need_hi = false;
uint16_t flags_type;
- uint16_t lflags;
+ uint16_t lflags = 0;
uint32_t cfa_meta;
int seg = 0;
uint8_t wrap = 0;
struct tx_bd_opaque *opq;
+ txr->prod = pi->ipi_pidx;
+#ifdef KTLS_IFLIB_SUPPORT
+ uint32_t kid = 0;
+ int ret;
+
+ if (pi->ipi_mbuf != NULL) {
+ ret = bnxt_ktls_xmit(softc, txr, &pi->ipi_mbuf, &lflags, &kid, pi);
+
+ if (ret) {
+ BNXT_DEBUG(softc->dev, "kTLS xmit failed, ret=%d\n", ret);
+ return ret;
+ }
+ }
+#endif
+
if ((pi->ipi_flags & IPI_TX_INTR) != 0)
need_cpl = true;
@@ -121,7 +139,7 @@
/* TODO: Devices before Cu+B1 need to not mix long and short BDs */
need_hi = true;
- pi->ipi_new_pidx = pi->ipi_pidx;
+ pi->ipi_new_pidx = txr->prod;
tbd = &((struct tx_bd_long *)txr->vaddr)[pi->ipi_new_pidx];
pi->ipi_ndescs = 0;
opq = (struct tx_bd_opaque *)&tbd->opaque;
@@ -165,11 +183,21 @@
txr->epoch_arr[pi->ipi_new_pidx] = txr->epoch_bit;
tbdh = &((struct tx_bd_long_hi *)txr->vaddr)[pi->ipi_new_pidx];
+#ifdef KTLS_IFLIB_SUPPORT
+ tbdh->kid_or_ts_high_mss = htole32((pi->ipi_tso_segsz & TX_BD_LONG_MSS_MASK) |
+ ((KID_HIGH(kid) << TX_BD_LONG_KID_OR_TS_HIGH_SFT) &
+ TX_BD_LONG_KID_OR_TS_HIGH_MASK));
+
+ tbdh->kid_or_ts_low_hdr_size = htole16((((pi->ipi_ehdrlen + pi->ipi_ip_hlen +
+ pi->ipi_tcp_hlen) >> 1) & TX_BD_LONG_HDR_SIZE_MASK) |
+ ((KID_LOW(kid) << TX_BD_LONG_KID_OR_TS_LOW_SFT) &
+ TX_BD_LONG_KID_OR_TS_LOW_MASK));
+#else
tbdh->kid_or_ts_high_mss = htole16(pi->ipi_tso_segsz);
tbdh->kid_or_ts_low_hdr_size = htole16((pi->ipi_ehdrlen + pi->ipi_ip_hlen +
pi->ipi_tcp_hlen) >> 1);
+#endif
tbdh->cfa_action = 0;
- lflags = 0;
cfa_meta = 0;
if (pi->ipi_mflags & M_VLANTAG) {
/* TODO: Do we need to byte-swap the vtag here? */
@@ -231,6 +259,7 @@
if (pi->ipi_new_pidx < EPOCH_ARR_SZ)
txr->epoch_arr[pi->ipi_new_pidx] = txr->epoch_bit;
+ txr->prod = pi->ipi_new_pidx;
return 0;
}
@@ -252,6 +281,7 @@
struct bnxt_cp_ring *cpr = &softc->tx_cp_rings[txqid];
struct tx_cmpl *cmpl = (struct tx_cmpl *)cpr->ring.vaddr;
struct bnxt_ring *txr;
+ struct bnxt_sw_tx_bd *tx_buf;
int avail = 0;
uint32_t cons = cpr->cons;
uint32_t raw_cons = cpr->raw_cons;
@@ -294,6 +324,32 @@
*/
if (!clear)
goto done;
+
+ if (__predict_false(opq->ktls_replay)) {
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ struct bnxt_replay_pkt *pkt;
+ uint32_t idx = opq->idx;
+
+ txr = &softc->tx_rings[txqid];
+ if (idx >= txr->ring_size) {
+ bnxt_log_live(softc, BNXT_LOGGER_L2,
+ "%s: Invalid replay idx %u (ring_size=%u) "
+ "on TXQ %u, opaque 0x%x\n",
+ __func__, idx, txr->ring_size, txqid,
+ cmpl[cons].opaque);
+ break;
+ }
+ tx_buf = &txr->tx_buf_ring[idx];
+ pkt = &txr->replay_pkt[idx];
+ MPASS(tx_buf->is_replay);
+ bus_dmamap_sync(ktls->dma_tag, pkt->dma_map,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(ktls->dma_tag, pkt->dma_map);
+ m_freem(pkt->mbuf);
+ counter_u64_add(ktls->counters[BNXT_KTLS_TX_MBUF_FREES], 1);
+ pkt->mbuf = NULL;
+ tx_buf->is_replay = 0;
+ }
break;
case TX_CMPL_COAL_TYPE_TX_L2_COAL:
if (softc->fw_cap & BNXT_FLAG_TX_COAL_CMPL) {
Index: sys/dev/bnxt/bnxt_en/if_bnxt.c
===================================================================
--- sys/dev/bnxt/bnxt_en/if_bnxt.c
+++ sys/dev/bnxt/bnxt_en/if_bnxt.c
@@ -60,6 +60,7 @@
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_rss.h"
+#include "opt_kern_tls.h"
#include "ifdi_if.h"
@@ -76,6 +77,7 @@
#include "bnxt_coredump.h"
#include "bnxt_ptp.h"
#include "bnxt_mpc.h"
+#include "bnxt_ktls.h"
/*
* PCI Device ID Table
@@ -648,6 +650,12 @@
softc->tx_rings[i].db_ring_mask = softc->tx_rings[i].ring_size - 1;
softc->tx_rings[i].vaddr = vaddrs[i * ntxqs + 1];
softc->tx_rings[i].paddr = paddrs[i * ntxqs + 1];
+ softc->tx_rings[i].tx_buf_ring =
+ malloc(softc->tx_rings[i].ring_size * sizeof(struct bnxt_sw_tx_bd),
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+
+ if (!softc->tx_rings[i].tx_buf_ring)
+ return -ENOMEM;
bnxt_create_tx_sysctls(softc, i);
@@ -666,6 +674,27 @@
softc->nq_rings[i].ring.vaddr = vaddrs[i * ntxqs + 2];
softc->nq_rings[i].ring.paddr = paddrs[i * ntxqs + 2];
softc->nq_rings[i].type = Q_TYPE_TX;
+
+#if defined(KERN_TLS)
+ int j;
+ int err;
+
+ if (softc->ktls_info) {
+ err = bnxt_alloc_ktls_rexmit_mbuf(softc, &softc->tx_rings[i]);
+ if (err) {
+ /* Disable KTLs entirely when enough memory is not avaiable */
+ for (j = i - 1; j >=0; j--)
+ bnxt_free_ktls_rexmit_mbuf(&softc->tx_rings[j]);
+
+ device_printf(softc->dev,
+ "Error:%d, kTLS support is disabled\n", err);
+
+ if_setcapenablebit(iflib_get_ifp(ctx), 0,
+ (IFCAP_TXTLS4 | IFCAP_TXTLS6));
+ bnxt_free_ktls_info(softc);
+ }
+ }
+#endif
}
}
@@ -700,8 +729,10 @@
int i;
// Free TX queues
- for (i=0; i<softc->ntxqsets; i++)
+ for (i=0; i<softc->ntxqsets; i++) {
iflib_dma_free(&softc->tx_stats[i]);
+ free(softc->tx_rings[i].tx_buf_ring, M_DEVBUF);
+ }
free(softc->tx_rings, M_DEVBUF);
softc->tx_rings = NULL;
free(softc->tx_cp_rings, M_DEVBUF);
@@ -1325,6 +1356,22 @@
last_type = BNXT_CTX_MTQM;
}
+ if (BNXT_PF(softc)) {
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ uint32_t max_tx_ctx = 0;
+
+ if (ktls)
+ max_tx_ctx = ktls->tck.max_ctx;
+
+ if (max_tx_ctx) {
+ ctxm = &ctx->ctx_arr[BNXT_CTX_TCK];
+ rc = bnxt_setup_ctxm_pg_tbls(softc, ctxm, max_tx_ctx, 1);
+ if (rc)
+ return rc;
+ last_type = BNXT_CTX_TCK;
+ }
+ }
+
if (BNXT_PF(softc)) {
for (type = BNXT_CTX_SRT_TRACE; type <= BNXT_CTX_ROCE_HWRM_TRACE; type++) {
ctxm = &ctx->ctx_arr[type];
@@ -1923,7 +1970,9 @@
}
if (pci_is_enabled(bp->pdev))
pci_disable_device(bp->pdev);
+ bnxt_ktls_del_all(bp);
pci_disable_busmaster(bp->dev);
+ bnxt_clear_ktls(bp);
bnxt_free_ctx_mem(bp);
}
@@ -2761,6 +2810,28 @@
memcpy(softc->rx_q_ids, softc->tx_q_ids, sizeof(softc->rx_q_ids));
}
+#if defined(KERN_TLS)
+ if (BNXT_CHIP_P7(softc)) {
+ rc = bnxt_ktls_sysctls(softc);
+ if (rc) {
+ device_printf(softc->dev, "attach: max_ktls_entries sysctl creation failed\n");
+ goto failed;
+ }
+
+ if (softc->max_ktls_entries == 0 ||
+ softc->max_ktls_entries > BNXT_KTLS_MAX_ENTRIES ) {
+
+ if (softc->max_ktls_entries > BNXT_KTLS_MAX_ENTRIES)
+ device_printf(softc->dev,
+ "attach: max_ktls_entries (%d) exceeds allowed max (%d), resetting to default (%d)\n",
+ softc->max_ktls_entries, BNXT_KTLS_MAX_ENTRIES, BNXT_KTLS_ENTRIES_DEFAULT);
+
+ softc->max_ktls_entries = BNXT_KTLS_ENTRIES_DEFAULT;
+ }
+
+ }
+#endif
+
/* Get the HW capabilities */
rc = bnxt_hwrm_func_qcaps(softc);
if (rc)
@@ -2840,6 +2911,26 @@
if (rc)
goto failed;
+#if defined(KERN_TLS)
+ /* Initialize KTLS */
+ rc = bnxt_ktls_init(softc);
+ if (!rc && softc->ktls_info) {
+ if_t ifp = iflib_get_ifp(ctx);
+
+ bnxt_alloc_ktls_counters(softc);
+ if_setsndtagallocfn(ifp, bnxt_tls_snd_tag_alloc);
+ device_printf(softc->dev, "kTLS is supported ifp:%p ctx:%p dev: %p softc: %p\n",
+ ifp, ctx, iflib_get_dev(ctx), softc);
+
+ scctx->isc_capabilities |= IFCAP_TXTLS4 | IFCAP_TXTLS6;
+ scctx->isc_capenable |= IFCAP_TXTLS4 | IFCAP_TXTLS6;
+#ifdef KTLS_IFLIB_SUPPORT
+ scctx->isc_tx_pad = BNXT_MAX_NUM_SEGS + 5;
+#endif
+ } else
+ bnxt_free_ktls_info(softc);
+#endif
+
/* Now set up iflib sc */
scctx->isc_tx_nsegments = 31,
scctx->isc_tx_tso_segments_max = 31;
@@ -2957,6 +3048,16 @@
if (rc)
goto failed;
+ if (softc->fw_cap & BNXT_FW_CAP_KTLS_SUPPORTED) {
+ rc = bnxt_create_ktls_sysctls(softc);
+ if (rc)
+ goto failed;
+
+ rc = bnxt_create_mpc_cmp_time_sysctls(softc);
+ if (rc)
+ goto failed;
+ }
+
if (softc->fw_cap & BNXT_FW_CAP_PTP) {
rc = bnxt_hwrm_ptp_qcfg(softc);
if (!rc) {
@@ -3076,12 +3177,48 @@
cancel_delayed_work_sync(&softc->fw_reset_task);
cancel_work_sync(&softc->sp_task);
bnxt_dcb_free(softc);
+
+#ifdef KERN_TLS
+ {
+ struct bnxt_tls_info *ktls = softc->ktls_info;
+ int wait;
+
+ if (ktls) {
+ for (i = 0; i < softc->ntxqsets; i++)
+ bnxt_free_ktls_rexmit_mbuf(&softc->tx_rings[i]);
+
+ /* wait for all threads in bnxt_tls_snd_tag_alloc() to exit */
+ while (atomic_load_32(&ktls->snd_tag_alloc_ref) != 0) {
+ pause("W", hz);
+ }
+
+ device_printf(softc->dev, "Active sessions before wait: %u\n",
+ uma_zone_get_cur(ktls->zone));
+ /* wait for all TLS tags to get freed */
+ while (ktls->init != 0 &&
+ uma_zone_get_cur(ktls->zone) != 0) {
+ pause("W", hz);
+ }
+
+ wait = 30;
+ while (wait && atomic_load_32(&ktls->pending)) {
+ device_printf(softc->dev, "KTLS device add/delete pending: %u"
+ " waittime[%d]\n", wait, atomic_load_32(&ktls->pending));
+ pause_sbt("bnxt_detach_sleep", mstosbt(1000 * 2), 0, C_HARDCLOCK);
+ wait--;
+ }
+ }
+ }
+#endif
+
SLIST_REMOVE(&pf_list, &softc->list, bnxt_softc_list, next);
bnxt_num_pfs--;
bnxt_wol_config(ctx);
bnxt_do_disable_intr(&softc->def_cp_ring);
bnxt_ptp_free(softc);
bnxt_free_sysctl_ctx(softc);
+ bnxt_free_ktls_counters(softc);
+ bnxt_free_ktls_info(softc);
bnxt_free_crash_dump_mem(softc);
bnxt_hwrm_func_reset(softc);
/*
@@ -3127,8 +3264,10 @@
bnxt_unregister_logger(softc, BNXT_LOGGER_L2);
mtx_destroy(&softc->log_lock);
- if (!bnxt_num_pfs && bnxt_pf_wq)
+ if (!bnxt_num_pfs && bnxt_pf_wq) {
destroy_workqueue(bnxt_pf_wq);
+ bnxt_pf_wq = NULL;
+ }
if (softc->pdev)
linux_pci_detach_device(softc->pdev);
Index: sys/modules/bnxt/bnxt_en/Makefile
===================================================================
--- sys/modules/bnxt/bnxt_en/Makefile
+++ sys/modules/bnxt/bnxt_en/Makefile
@@ -2,7 +2,7 @@
KMOD = if_bnxt
SRCS = device_if.h bus_if.h pci_if.h pci_iov_if.h ifdi_if.h
-SRCS += opt_inet.h opt_inet6.h opt_rss.h
+SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_ratelimit.h opt_kern_tls.h
SRCS += bnxt_txrx.c if_bnxt.c
SRCS += bnxt_hwrm.c
SRCS += bnxt_sysctl.c
@@ -16,6 +16,7 @@
SRCS += bnxt_coredump.c bnxt_coredump.h
SRCS += bnxt_ptp.c bnxt_ptp.h
SRCS += bnxt_mpc.c bnxt_mpc.h
+SRCS += bnxt_ktls.c bnxt_ktls.h
SRCS += bnxt_compat.h
SRCS += ${LINUXKPI_GENSRCS}

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 10, 3:03 AM (5 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41625240
Default Alt Text
D58606.1794279800.diff (100 KB)

Event Timeline