From 8e0c482762f7a3ec6de524195f7e4e94a7d38042 Mon Sep 17 00:00:00 2001 From: Andrew Rybchenko Date: Thu, 22 Nov 2018 14:31:35 +0000 Subject: [PATCH] sfxge(4): support packed stream Rx mode in libefx Submitted by: Artem V. Andreev Sponsored by: Solarflare Communications, Inc. Differential Revision: https://reviews.freebsd.org/D18022 --- sys/dev/sfxge/common/ef10_ev.c | 137 ++++++++++++++++++- sys/dev/sfxge/common/ef10_impl.h | 48 ++++++- sys/dev/sfxge/common/ef10_nic.c | 11 ++ sys/dev/sfxge/common/ef10_rx.c | 195 ++++++++++++++++++++++++--- sys/dev/sfxge/common/efsys.h | 2 + sys/dev/sfxge/common/efx.h | 69 ++++++++++ sys/dev/sfxge/common/efx_check.h | 6 + sys/dev/sfxge/common/efx_impl.h | 11 ++ sys/dev/sfxge/common/efx_nic.c | 6 +- sys/dev/sfxge/common/efx_regs_ef10.h | 26 +++- sys/dev/sfxge/common/efx_rx.c | 84 ++++++++++++ sys/dev/sfxge/common/siena_nic.c | 2 + 12 files changed, 569 insertions(+), 28 deletions(-) diff --git a/sys/dev/sfxge/common/ef10_ev.c b/sys/dev/sfxge/common/ef10_ev.c index 3e36ca241b52..9a5582b0fe0b 100644 --- a/sys/dev/sfxge/common/ef10_ev.c +++ b/sys/dev/sfxge/common/ef10_ev.c @@ -762,6 +762,88 @@ ef10_ev_qstats_update( } #endif /* EFSYS_OPT_QSTATS */ +#if EFSYS_OPT_RX_PACKED_STREAM + +static __checkReturn boolean_t +ef10_ev_rx_packed_stream( + __in efx_evq_t *eep, + __in efx_qword_t *eqp, + __in const efx_ev_callbacks_t *eecp, + __in_opt void *arg) +{ + uint32_t label; + uint32_t pkt_count_lbits; + uint16_t flags; + boolean_t should_abort; + efx_evq_rxq_state_t *eersp; + unsigned int pkt_count; + unsigned int current_id; + boolean_t new_buffer; + + pkt_count_lbits = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_DSC_PTR_LBITS); + label = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_QLABEL); + new_buffer = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_EV_ROTATE); + + flags = 0; + + eersp = &eep->ee_rxq_state[label]; + + /* + * RX_DSC_PTR_LBITS has least significant bits of the global + * (not per-buffer) packet counter. It is guaranteed that + * maximum number of completed packets fits in lbits-mask. + * So, modulo lbits-mask arithmetic should be used to calculate + * packet counter increment. + */ + pkt_count = (pkt_count_lbits - eersp->eers_rx_stream_npackets) & + EFX_MASK32(ESF_DZ_RX_DSC_PTR_LBITS); + eersp->eers_rx_stream_npackets += pkt_count; + + if (new_buffer) { + flags |= EFX_PKT_PACKED_STREAM_NEW_BUFFER; + eersp->eers_rx_packed_stream_credits++; + eersp->eers_rx_read_ptr++; + } + current_id = eersp->eers_rx_read_ptr & eersp->eers_rx_mask; + + /* Check for errors that invalidate checksum and L3/L4 fields */ + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ECC_ERR) != 0) { + /* RX frame truncated (error flag is misnamed) */ + EFX_EV_QSTAT_INCR(eep, EV_RX_FRM_TRUNC); + flags |= EFX_DISCARD; + goto deliver; + } + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ECRC_ERR) != 0) { + /* Bad Ethernet frame CRC */ + EFX_EV_QSTAT_INCR(eep, EV_RX_ETH_CRC_ERR); + flags |= EFX_DISCARD; + goto deliver; + } + + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_PARSE_INCOMPLETE)) { + flags |= EFX_PKT_PACKED_STREAM_PARSE_INCOMPLETE; + goto deliver; + } + + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_IPCKSUM_ERR)) + EFX_EV_QSTAT_INCR(eep, EV_RX_IPV4_HDR_CHKSUM_ERR); + + if (EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_TCPUDP_CKSUM_ERR)) + EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_UDP_CHKSUM_ERR); + +deliver: + /* If we're not discarding the packet then it is ok */ + if (~flags & EFX_DISCARD) + EFX_EV_QSTAT_INCR(eep, EV_RX_OK); + + EFSYS_ASSERT(eecp->eec_rx_ps != NULL); + should_abort = eecp->eec_rx_ps(arg, label, current_id, pkt_count, + flags); + + return (should_abort); +} + +#endif /* EFSYS_OPT_RX_PACKED_STREAM */ static __checkReturn boolean_t ef10_ev_rx( @@ -792,9 +874,20 @@ ef10_ev_rx( return (B_FALSE); /* Basic packet information */ + label = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_QLABEL); + eersp = &eep->ee_rxq_state[label]; + +#if EFSYS_OPT_RX_PACKED_STREAM + /* + * Packed stream events are very different, + * so handle them separately + */ + if (eersp->eers_rx_packed_stream) + return (ef10_ev_rx_packed_stream(eep, eqp, eecp, arg)); +#endif + size = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_BYTES); next_read_lbits = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_DSC_PTR_LBITS); - label = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_QLABEL); eth_tag_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_ETH_TAG_CLASS); mac_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_MAC_CLASS); l3_class = EFX_QWORD_FIELD(*eqp, ESF_DZ_RX_L3_CLASS); @@ -824,7 +917,6 @@ ef10_ev_rx( flags |= EFX_PKT_UNICAST; /* Increment the count of descriptors read */ - eersp = &eep->ee_rxq_state[label]; desc_count = (next_read_lbits - eersp->eers_rx_read_ptr) & EFX_MASK32(ESF_DZ_RX_DSC_PTR_LBITS); eersp->eers_rx_read_ptr += desc_count; @@ -1246,7 +1338,8 @@ ef10_ev_mcdi( ef10_ev_rxlabel_init( __in efx_evq_t *eep, __in efx_rxq_t *erp, - __in unsigned int label) + __in unsigned int label, + __in boolean_t packed_stream) { efx_evq_rxq_state_t *eersp; @@ -1255,8 +1348,41 @@ ef10_ev_rxlabel_init( EFSYS_ASSERT3U(eersp->eers_rx_mask, ==, 0); +#if EFSYS_OPT_RX_PACKED_STREAM + /* + * For packed stream modes, the very first event will + * have a new buffer flag set, so it will be incremented, + * yielding the correct pointer. That results in a simpler + * code than trying to detect start-of-the-world condition + * in the event handler. + */ + eersp->eers_rx_read_ptr = packed_stream ? ~0 : 0; +#else eersp->eers_rx_read_ptr = 0; +#endif eersp->eers_rx_mask = erp->er_mask; +#if EFSYS_OPT_RX_PACKED_STREAM + eersp->eers_rx_stream_npackets = 0; + eersp->eers_rx_packed_stream = packed_stream; + if (packed_stream) { + eersp->eers_rx_packed_stream_credits = (eep->ee_mask + 1) / + EFX_DIV_ROUND_UP(EFX_RX_PACKED_STREAM_MEM_PER_CREDIT, + EFX_RX_PACKED_STREAM_MIN_PACKET_SPACE); + EFSYS_ASSERT3U(eersp->eers_rx_packed_stream_credits, !=, 0); + /* + * A single credit is allocated to the queue when it is started. + * It is immediately spent by the first packet which has NEW + * BUFFER flag set, though, but still we shall take into + * account, as to not wrap around the maximum number of credits + * accidentally + */ + eersp->eers_rx_packed_stream_credits--; + EFSYS_ASSERT3U(eersp->eers_rx_packed_stream_credits, <=, + EFX_RX_PACKED_STREAM_MAX_CREDITS); + } +#else + EFSYS_ASSERT(!packed_stream); +#endif } void @@ -1273,6 +1399,11 @@ ef10_ev_rxlabel_fini( eersp->eers_rx_read_ptr = 0; eersp->eers_rx_mask = 0; +#if EFSYS_OPT_RX_PACKED_STREAM + eersp->eers_rx_stream_npackets = 0; + eersp->eers_rx_packed_stream = B_FALSE; + eersp->eers_rx_packed_stream_credits = 0; +#endif } #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/ef10_impl.h b/sys/dev/sfxge/common/ef10_impl.h index 358782686789..d3ae1687301c 100644 --- a/sys/dev/sfxge/common/ef10_impl.h +++ b/sys/dev/sfxge/common/ef10_impl.h @@ -118,7 +118,8 @@ ef10_ev_qstats_update( ef10_ev_rxlabel_init( __in efx_evq_t *eep, __in efx_rxq_t *erp, - __in unsigned int label); + __in unsigned int label, + __in boolean_t packed_stream); void ef10_ev_rxlabel_fini( @@ -685,6 +686,22 @@ ef10_tx_qpush( __in unsigned int added, __in unsigned int pushed); +#if EFSYS_OPT_RX_PACKED_STREAM +extern void +ef10_rx_qpush_ps_credits( + __in efx_rxq_t *erp); + +extern __checkReturn uint8_t * +ef10_rx_qps_packet_info( + __in efx_rxq_t *erp, + __in uint8_t *buffer, + __in uint32_t buffer_length, + __in uint32_t current_offset, + __out uint16_t *lengthp, + __out uint32_t *next_offsetp, + __out uint32_t *timestamp); +#endif + extern __checkReturn efx_rc_t ef10_tx_qpace( __in efx_txq_t *etp, @@ -1131,6 +1148,35 @@ ef10_external_port_mapping( __in uint32_t port, __out uint8_t *external_portp); +#if EFSYS_OPT_RX_PACKED_STREAM + +/* Data space per credit in packed stream mode */ +#define EFX_RX_PACKED_STREAM_MEM_PER_CREDIT (1 << 16) + +/* + * Received packets are always aligned at this boundary. Also there always + * exists a gap of this size between packets. + * (see SF-112241-TC, 4.5) + */ +#define EFX_RX_PACKED_STREAM_ALIGNMENT 64 + +/* + * Size of a pseudo-header prepended to received packets + * in packed stream mode + */ +#define EFX_RX_PACKED_STREAM_RX_PREFIX_SIZE 8 + +/* Minimum space for packet in packed stream mode */ +#define EFX_RX_PACKED_STREAM_MIN_PACKET_SPACE \ + P2ROUNDUP(EFX_RX_PACKED_STREAM_RX_PREFIX_SIZE + \ + EFX_MAC_PDU_MIN + \ + EFX_RX_PACKED_STREAM_ALIGNMENT, \ + EFX_RX_PACKED_STREAM_ALIGNMENT) + +/* Maximum number of credits */ +#define EFX_RX_PACKED_STREAM_MAX_CREDITS 127 + +#endif /* EFSYS_OPT_RX_PACKED_STREAM */ #ifdef __cplusplus } diff --git a/sys/dev/sfxge/common/ef10_nic.c b/sys/dev/sfxge/common/ef10_nic.c index b5fde21b25c3..7a715495ae60 100644 --- a/sys/dev/sfxge/common/ef10_nic.c +++ b/sys/dev/sfxge/common/ef10_nic.c @@ -1072,6 +1072,17 @@ ef10_get_datapath_caps( encp->enc_rx_disable_scatter_supported = CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE; + /* Check if the firmware supports packed stream mode */ + encp->enc_rx_packed_stream_supported = + CAP_FLAG(flags, RX_PACKED_STREAM) ? B_TRUE : B_FALSE; + + /* + * Check if the firmware supports configurable buffer sizes + * for packed stream mode (otherwise buffer size is 1Mbyte) + */ + encp->enc_rx_var_packed_stream_supported = + CAP_FLAG(flags, RX_PACKED_STREAM_VAR_BUFFERS) ? B_TRUE : B_FALSE; + /* Check if the firmware supports set mac with running filters */ encp->enc_allow_set_mac_with_installed_filters = CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ? diff --git a/sys/dev/sfxge/common/ef10_rx.c b/sys/dev/sfxge/common/ef10_rx.c index f6c26a42f74c..fb1d953e8c69 100644 --- a/sys/dev/sfxge/common/ef10_rx.c +++ b/sys/dev/sfxge/common/ef10_rx.c @@ -46,41 +46,51 @@ efx_mcdi_init_rxq( __in uint32_t label, __in uint32_t instance, __in efsys_mem_t *esmp, - __in boolean_t disable_scatter) + __in boolean_t disable_scatter, + __in uint32_t ps_bufsize) { efx_mcdi_req_t req; - uint8_t payload[ - MC_CMD_INIT_RXQ_IN_LEN(EFX_RXQ_NBUFS(EFX_RXQ_MAXNDESCS))]; + uint8_t payload[MAX(MC_CMD_INIT_RXQ_EXT_IN_LEN, + MC_CMD_INIT_RXQ_EXT_OUT_LEN)]; int npages = EFX_RXQ_NBUFS(size); int i; efx_qword_t *dma_addr; uint64_t addr; efx_rc_t rc; + uint32_t dma_mode; /* If this changes, then the payload size might need to change. */ EFSYS_ASSERT3U(MC_CMD_INIT_RXQ_OUT_LEN, ==, 0); EFSYS_ASSERT3U(size, <=, EFX_RXQ_MAXNDESCS); + if (ps_bufsize > 0) + dma_mode = MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM; + else + dma_mode = MC_CMD_INIT_RXQ_EXT_IN_SINGLE_PACKET; + (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_INIT_RXQ; req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_INIT_RXQ_IN_LEN(npages); + req.emr_in_length = MC_CMD_INIT_RXQ_EXT_IN_LEN; req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_INIT_RXQ_OUT_LEN; + req.emr_out_length = MC_CMD_INIT_RXQ_EXT_OUT_LEN; - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_SIZE, size); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_TARGET_EVQ, target_evq); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_LABEL, label); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_INSTANCE, instance); - MCDI_IN_POPULATE_DWORD_6(req, INIT_RXQ_IN_FLAGS, - INIT_RXQ_IN_FLAG_BUFF_MODE, 0, - INIT_RXQ_IN_FLAG_HDR_SPLIT, 0, - INIT_RXQ_IN_FLAG_TIMESTAMP, 0, - INIT_RXQ_IN_CRC_MODE, 0, - INIT_RXQ_IN_FLAG_PREFIX, 1, - INIT_RXQ_IN_FLAG_DISABLE_SCATTER, disable_scatter); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_OWNER_ID, 0); - MCDI_IN_SET_DWORD(req, INIT_RXQ_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); + MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_SIZE, size); + MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_TARGET_EVQ, target_evq); + MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_LABEL, label); + MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_INSTANCE, instance); + MCDI_IN_POPULATE_DWORD_8(req, INIT_RXQ_EXT_IN_FLAGS, + INIT_RXQ_EXT_IN_FLAG_BUFF_MODE, 0, + INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT, 0, + INIT_RXQ_EXT_IN_FLAG_TIMESTAMP, 0, + INIT_RXQ_EXT_IN_CRC_MODE, 0, + INIT_RXQ_EXT_IN_FLAG_PREFIX, 1, + INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER, disable_scatter, + INIT_RXQ_EXT_IN_DMA_MODE, + dma_mode, + INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE, ps_bufsize); + MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_OWNER_ID, 0); + MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_PORT_ID, EVB_PORT_ID_ASSIGNED); dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR); addr = EFSYS_MEM_ADDR(esmp); @@ -707,6 +717,95 @@ ef10_rx_qpush( erp->er_index, &dword, B_FALSE); } +#if EFSYS_OPT_RX_PACKED_STREAM + + void +ef10_rx_qpush_ps_credits( + __in efx_rxq_t *erp) +{ + efx_nic_t *enp = erp->er_enp; + efx_dword_t dword; + efx_evq_rxq_state_t *rxq_state = + &erp->er_eep->ee_rxq_state[erp->er_label]; + uint32_t credits; + + EFSYS_ASSERT(rxq_state->eers_rx_packed_stream); + + if (rxq_state->eers_rx_packed_stream_credits == 0) + return; + + /* + * It is a bug if we think that FW has utilized more + * credits than it is allowed to have (maximum). However, + * make sure that we do not credit more than maximum anyway. + */ + credits = MIN(rxq_state->eers_rx_packed_stream_credits, + EFX_RX_PACKED_STREAM_MAX_CREDITS); + EFX_POPULATE_DWORD_3(dword, + ERF_DZ_RX_DESC_MAGIC_DOORBELL, 1, + ERF_DZ_RX_DESC_MAGIC_CMD, + ERE_DZ_RX_DESC_MAGIC_CMD_PS_CREDITS, + ERF_DZ_RX_DESC_MAGIC_DATA, credits); + EFX_BAR_TBL_WRITED(enp, ER_DZ_RX_DESC_UPD_REG, + erp->er_index, &dword, B_FALSE); + + rxq_state->eers_rx_packed_stream_credits = 0; +} + +/* + * In accordance with SF-112241-TC the received data has the following layout: + * - 8 byte pseudo-header which consist of: + * - 4 byte little-endian timestamp + * - 2 byte little-endian captured length in bytes + * - 2 byte little-endian original packet length in bytes + * - captured packet bytes + * - optional padding to align to 64 bytes boundary + * - 64 bytes scratch space for the host software + */ + __checkReturn uint8_t * +ef10_rx_qps_packet_info( + __in efx_rxq_t *erp, + __in uint8_t *buffer, + __in uint32_t buffer_length, + __in uint32_t current_offset, + __out uint16_t *lengthp, + __out uint32_t *next_offsetp, + __out uint32_t *timestamp) +{ + uint16_t buf_len; + uint8_t *pkt_start; + efx_qword_t *qwordp; + efx_evq_rxq_state_t *rxq_state = + &erp->er_eep->ee_rxq_state[erp->er_label]; + + EFSYS_ASSERT(rxq_state->eers_rx_packed_stream); + + buffer += current_offset; + pkt_start = buffer + EFX_RX_PACKED_STREAM_RX_PREFIX_SIZE; + + qwordp = (efx_qword_t *)buffer; + *timestamp = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_TSTAMP); + *lengthp = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_ORIG_LEN); + buf_len = EFX_QWORD_FIELD(*qwordp, ES_DZ_PS_RX_PREFIX_CAP_LEN); + + buf_len = P2ROUNDUP(buf_len + EFX_RX_PACKED_STREAM_RX_PREFIX_SIZE, + EFX_RX_PACKED_STREAM_ALIGNMENT); + *next_offsetp = + current_offset + buf_len + EFX_RX_PACKED_STREAM_ALIGNMENT; + + EFSYS_ASSERT3U(*next_offsetp, <=, buffer_length); + EFSYS_ASSERT3U(current_offset + *lengthp, <, *next_offsetp); + + if ((*next_offsetp ^ current_offset) & + EFX_RX_PACKED_STREAM_MEM_PER_CREDIT) + rxq_state->eers_rx_packed_stream_credits++; + + return (pkt_start); +} + + +#endif + __checkReturn efx_rc_t ef10_rx_qflush( __in efx_rxq_t *erp) @@ -749,6 +848,7 @@ ef10_rx_qcreate( efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_rc_t rc; boolean_t disable_scatter; + unsigned int ps_buf_size; _NOTE(ARGUNUSED(id, erp)) @@ -768,6 +868,51 @@ ef10_rx_qcreate( goto fail2; } + switch (type) { + case EFX_RXQ_TYPE_DEFAULT: + case EFX_RXQ_TYPE_SCATTER: + ps_buf_size = 0; + break; +#if EFSYS_OPT_RX_PACKED_STREAM + case EFX_RXQ_TYPE_PACKED_STREAM_1M: + ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_1M; + break; + case EFX_RXQ_TYPE_PACKED_STREAM_512K: + ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_512K; + break; + case EFX_RXQ_TYPE_PACKED_STREAM_256K: + ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_256K; + break; + case EFX_RXQ_TYPE_PACKED_STREAM_128K: + ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_128K; + break; + case EFX_RXQ_TYPE_PACKED_STREAM_64K: + ps_buf_size = MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_64K; + break; +#endif /* EFSYS_OPT_RX_PACKED_STREAM */ + default: + rc = ENOTSUP; + goto fail3; + } + +#if EFSYS_OPT_RX_PACKED_STREAM + if (ps_buf_size != 0) { + /* Check if datapath firmware supports packed stream mode */ + if (encp->enc_rx_packed_stream_supported == B_FALSE) { + rc = ENOTSUP; + goto fail4; + } + /* Check if packed stream allows configurable buffer sizes */ + if ((type != EFX_RXQ_TYPE_PACKED_STREAM_1M) && + (encp->enc_rx_var_packed_stream_supported == B_FALSE)) { + rc = ENOTSUP; + goto fail5; + } + } +#else /* EFSYS_OPT_RX_PACKED_STREAM */ + EFSYS_ASSERT(ps_buf_size == 0); +#endif /* EFSYS_OPT_RX_PACKED_STREAM */ + /* Scatter can only be disabled if the firmware supports doing so */ if (type == EFX_RXQ_TYPE_SCATTER) disable_scatter = B_FALSE; @@ -775,16 +920,24 @@ ef10_rx_qcreate( disable_scatter = encp->enc_rx_disable_scatter_supported; if ((rc = efx_mcdi_init_rxq(enp, n, eep->ee_index, label, index, - esmp, disable_scatter)) != 0) - goto fail3; + esmp, disable_scatter, ps_buf_size)) != 0) + goto fail6; erp->er_eep = eep; erp->er_label = label; - ef10_ev_rxlabel_init(eep, erp, label); + ef10_ev_rxlabel_init(eep, erp, label, ps_buf_size != 0); return (0); +fail6: + EFSYS_PROBE(fail6); +#if EFSYS_OPT_RX_PACKED_STREAM +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +#endif /* EFSYS_OPT_RX_PACKED_STREAM */ fail3: EFSYS_PROBE(fail3); fail2: diff --git a/sys/dev/sfxge/common/efsys.h b/sys/dev/sfxge/common/efsys.h index 0b4ae1603ca5..6a72894221e4 100644 --- a/sys/dev/sfxge/common/efsys.h +++ b/sys/dev/sfxge/common/efsys.h @@ -281,6 +281,8 @@ sfxge_map_mbuf_fast(bus_dma_tag_t tag, bus_dmamap_t map, #define EFSYS_OPT_ALLOW_UNCONFIGURED_NIC 0 +#define EFSYS_OPT_RX_PACKED_STREAM 0 + /* ID */ typedef struct __efsys_identifier_s efsys_identifier_t; diff --git a/sys/dev/sfxge/common/efx.h b/sys/dev/sfxge/common/efx.h index 1eb647b2f3c5..c5ff48538964 100644 --- a/sys/dev/sfxge/common/efx.h +++ b/sys/dev/sfxge/common/efx.h @@ -52,6 +52,9 @@ extern "C" { #define EFX_FIELD_OFFSET(_type, _field) \ ((size_t) &(((_type *)0)->_field)) +/* The macro expands divider twice */ +#define EFX_DIV_ROUND_UP(_n, _d) (((_n) + (_d) - 1) / (_d)) + /* Return codes */ typedef __success(return == 0) int efx_rc_t; @@ -1086,6 +1089,7 @@ efx_bist_stop( #define EFX_FEATURE_PIO_BUFFERS 0x00000800 #define EFX_FEATURE_FW_ASSISTED_TSO 0x00001000 #define EFX_FEATURE_FW_ASSISTED_TSO_V2 0x00002000 +#define EFX_FEATURE_PACKED_STREAM 0x00004000 typedef struct efx_nic_cfg_s { uint32_t enc_board_type; @@ -1181,6 +1185,8 @@ typedef struct efx_nic_cfg_s { boolean_t enc_allow_set_mac_with_installed_filters; boolean_t enc_enhanced_set_mac_supported; boolean_t enc_init_evq_v2_supported; + boolean_t enc_rx_packed_stream_supported; + boolean_t enc_rx_var_packed_stream_supported; boolean_t enc_pm_and_rxdp_counters; boolean_t enc_mac_stats_40g_tx_size_bins; /* External port identifier */ @@ -1622,6 +1628,16 @@ typedef __checkReturn boolean_t #define EFX_ADDR_MISMATCH 0x4000 #define EFX_DISCARD 0x8000 +/* + * The following flags are used only for packed stream + * mode. The values for the flags are reused to fit into 16 bit, + * since EFX_PKT_START and EFX_PKT_CONT are never used in + * packed stream mode + */ +#define EFX_PKT_PACKED_STREAM_NEW_BUFFER EFX_PKT_START +#define EFX_PKT_PACKED_STREAM_PARSE_INCOMPLETE EFX_PKT_CONT + + #define EFX_EV_RX_NLABELS 32 #define EFX_EV_TX_NLABELS 32 @@ -1633,6 +1649,28 @@ typedef __checkReturn boolean_t __in uint32_t size, __in uint16_t flags); +#if EFSYS_OPT_RX_PACKED_STREAM + +/* + * Packed stream mode is documented in SF-112241-TC. + * The general idea is that, instead of putting each incoming + * packet into a separate buffer which is specified in a RX + * descriptor, a large buffer is provided to the hardware and + * packets are put there in a continuous stream. + * The main advantage of such an approach is that RX queue refilling + * happens much less frequently. + */ + +typedef __checkReturn boolean_t +(*efx_rx_ps_ev_t)( + __in_opt void *arg, + __in uint32_t label, + __in uint32_t id, + __in uint32_t pkt_count, + __in uint16_t flags); + +#endif + typedef __checkReturn boolean_t (*efx_tx_ev_t)( __in_opt void *arg, @@ -1722,6 +1760,9 @@ typedef __checkReturn boolean_t typedef struct efx_ev_callbacks_s { efx_initialized_ev_t eec_initialized; efx_rx_ev_t eec_rx; +#if EFSYS_OPT_RX_PACKED_STREAM + efx_rx_ps_ev_t eec_rx_ps; +#endif efx_tx_ev_t eec_tx; efx_exception_ev_t eec_exception; efx_rxq_flush_done_ev_t eec_rxq_flush_done; @@ -1900,6 +1941,11 @@ efx_pseudo_hdr_pkt_length_get( typedef enum efx_rxq_type_e { EFX_RXQ_TYPE_DEFAULT, EFX_RXQ_TYPE_SCATTER, + EFX_RXQ_TYPE_PACKED_STREAM_1M, + EFX_RXQ_TYPE_PACKED_STREAM_512K, + EFX_RXQ_TYPE_PACKED_STREAM_256K, + EFX_RXQ_TYPE_PACKED_STREAM_128K, + EFX_RXQ_TYPE_PACKED_STREAM_64K, EFX_RXQ_NTYPES } efx_rxq_type_t; @@ -1940,6 +1986,29 @@ efx_rx_qpush( __in unsigned int added, __inout unsigned int *pushedp); +#if EFSYS_OPT_RX_PACKED_STREAM + +/* + * Fake length for RXQ descriptors in packed stream mode + * to make hardware happy + */ +#define EFX_RXQ_PACKED_STREAM_FAKE_BUF_SIZE 32 + +extern void +efx_rx_qpush_ps_credits( + __in efx_rxq_t *erp); + +extern __checkReturn uint8_t * +efx_rx_qps_packet_info( + __in efx_rxq_t *erp, + __in uint8_t *buffer, + __in uint32_t buffer_length, + __in uint32_t current_offset, + __out uint16_t *lengthp, + __out uint32_t *next_offsetp, + __out uint32_t *timestamp); +#endif + extern __checkReturn efx_rc_t efx_rx_qflush( __in efx_rxq_t *erp); diff --git a/sys/dev/sfxge/common/efx_check.h b/sys/dev/sfxge/common/efx_check.h index 60972bf63a03..4d86c2987818 100644 --- a/sys/dev/sfxge/common/efx_check.h +++ b/sys/dev/sfxge/common/efx_check.h @@ -339,5 +339,11 @@ # endif #endif /* EFSYS_OPT_ALLOW_UNCONFIGURED_NIC */ +/* Support packed stream mode */ +#if EFSYS_OPT_RX_PACKED_STREAM +# if !(EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) +# error "PACKED_STREAM requires HUNTINGTON or MEDFORD" +# endif +#endif #endif /* _SYS_EFX_CHECK_H */ diff --git a/sys/dev/sfxge/common/efx_impl.h b/sys/dev/sfxge/common/efx_impl.h index 7d699420aeb8..15717f1721d9 100644 --- a/sys/dev/sfxge/common/efx_impl.h +++ b/sys/dev/sfxge/common/efx_impl.h @@ -170,6 +170,12 @@ typedef struct efx_rx_ops_s { unsigned int, unsigned int, unsigned int); void (*erxo_qpush)(efx_rxq_t *, unsigned int, unsigned int *); +#if EFSYS_OPT_RX_PACKED_STREAM + void (*erxo_qpush_ps_credits)(efx_rxq_t *); + uint8_t * (*erxo_qps_packet_info)(efx_rxq_t *, uint8_t *, + uint32_t, uint32_t, + uint16_t *, uint32_t *, uint32_t *); +#endif efx_rc_t (*erxo_qflush)(efx_rxq_t *); void (*erxo_qenable)(efx_rxq_t *); efx_rc_t (*erxo_qcreate)(efx_nic_t *enp, unsigned int, @@ -694,6 +700,11 @@ typedef boolean_t (*efx_ev_handler_t)(efx_evq_t *, efx_qword_t *, typedef struct efx_evq_rxq_state_s { unsigned int eers_rx_read_ptr; unsigned int eers_rx_mask; +#if EFSYS_OPT_RX_PACKED_STREAM + unsigned int eers_rx_stream_npackets; + boolean_t eers_rx_packed_stream; + unsigned int eers_rx_packed_stream_credits; +#endif } efx_evq_rxq_state_t; struct efx_evq_s { diff --git a/sys/dev/sfxge/common/efx_nic.c b/sys/dev/sfxge/common/efx_nic.c index 9176f88c2267..86356d83461f 100644 --- a/sys/dev/sfxge/common/efx_nic.c +++ b/sys/dev/sfxge/common/efx_nic.c @@ -289,7 +289,8 @@ efx_nic_create( EFX_FEATURE_MCDI_DMA | EFX_FEATURE_PIO_BUFFERS | EFX_FEATURE_FW_ASSISTED_TSO | - EFX_FEATURE_FW_ASSISTED_TSO_V2; + EFX_FEATURE_FW_ASSISTED_TSO_V2 | + EFX_FEATURE_PACKED_STREAM; break; #endif /* EFSYS_OPT_HUNTINGTON */ @@ -308,7 +309,8 @@ efx_nic_create( EFX_FEATURE_MAC_HEADER_FILTERS | EFX_FEATURE_MCDI_DMA | EFX_FEATURE_PIO_BUFFERS | - EFX_FEATURE_FW_ASSISTED_TSO_V2; + EFX_FEATURE_FW_ASSISTED_TSO_V2 | + EFX_FEATURE_PACKED_STREAM; break; #endif /* EFSYS_OPT_MEDFORD */ diff --git a/sys/dev/sfxge/common/efx_regs_ef10.h b/sys/dev/sfxge/common/efx_regs_ef10.h index 7c7e3c8027aa..8cca83f2a5cc 100644 --- a/sys/dev/sfxge/common/efx_regs_ef10.h +++ b/sys/dev/sfxge/common/efx_regs_ef10.h @@ -169,7 +169,6 @@ extern "C" { #define ERF_DZ_RX_DESC_WPTR_LBN 0 #define ERF_DZ_RX_DESC_WPTR_WIDTH 12 - /* * TX_DESC_UPD_REG(96bit): * @@ -543,6 +542,31 @@ extern "C" { #define ERF_DD_EVQ_IND_TIMER_VAL_LBN 0 #define ERF_DD_EVQ_IND_TIMER_VAL_WIDTH 8 +/* Packed stream magic doorbell command */ +#define ERF_DZ_RX_DESC_MAGIC_DOORBELL_LBN 11 +#define ERF_DZ_RX_DESC_MAGIC_DOORBELL_WIDTH 1 + +#define ERF_DZ_RX_DESC_MAGIC_CMD_LBN 8 +#define ERF_DZ_RX_DESC_MAGIC_CMD_WIDTH 3 +#define ERE_DZ_RX_DESC_MAGIC_CMD_PS_CREDITS 0 + +#define ERF_DZ_RX_DESC_MAGIC_DATA_LBN 0 +#define ERF_DZ_RX_DESC_MAGIC_DATA_WIDTH 8 + +/* Packed stream RX packet prefix */ +#define ES_DZ_PS_RX_PREFIX_TSTAMP_LBN 0 +#define ES_DZ_PS_RX_PREFIX_TSTAMP_WIDTH 32 +#define ES_DZ_PS_RX_PREFIX_CAP_LEN_LBN 32 +#define ES_DZ_PS_RX_PREFIX_CAP_LEN_WIDTH 16 +#define ES_DZ_PS_RX_PREFIX_ORIG_LEN_LBN 48 +#define ES_DZ_PS_RX_PREFIX_ORIG_LEN_WIDTH 16 + +/* + * An extra flag for the packed stream mode, + * signalling the start of a new buffer + */ +#define ESF_DZ_RX_EV_ROTATE_LBN 53 +#define ESF_DZ_RX_EV_ROTATE_WIDTH 1 #ifdef __cplusplus } diff --git a/sys/dev/sfxge/common/efx_rx.c b/sys/dev/sfxge/common/efx_rx.c index 2716c32ea3f4..8d6a6cae5be8 100644 --- a/sys/dev/sfxge/common/efx_rx.c +++ b/sys/dev/sfxge/common/efx_rx.c @@ -103,6 +103,22 @@ siena_rx_qpush( __in unsigned int added, __inout unsigned int *pushedp); +#if EFSYS_OPT_RX_PACKED_STREAM +static void +siena_rx_qpush_ps_credits( + __in efx_rxq_t *erp); + +static __checkReturn uint8_t * +siena_rx_qps_packet_info( + __in efx_rxq_t *erp, + __in uint8_t *buffer, + __in uint32_t buffer_length, + __in uint32_t current_offset, + __out uint16_t *lengthp, + __out uint32_t *next_offsetp, + __out uint32_t *timestamp); +#endif + static __checkReturn efx_rc_t siena_rx_qflush( __in efx_rxq_t *erp); @@ -146,6 +162,10 @@ static const efx_rx_ops_t __efx_rx_siena_ops = { siena_rx_prefix_pktlen, /* erxo_prefix_pktlen */ siena_rx_qpost, /* erxo_qpost */ siena_rx_qpush, /* erxo_qpush */ +#if EFSYS_OPT_RX_PACKED_STREAM + siena_rx_qpush_ps_credits, /* erxo_qpush_ps_credits */ + siena_rx_qps_packet_info, /* erxo_qps_packet_info */ +#endif siena_rx_qflush, /* erxo_qflush */ siena_rx_qenable, /* erxo_qenable */ siena_rx_qcreate, /* erxo_qcreate */ @@ -169,6 +189,10 @@ static const efx_rx_ops_t __efx_rx_ef10_ops = { ef10_rx_prefix_pktlen, /* erxo_prefix_pktlen */ ef10_rx_qpost, /* erxo_qpost */ ef10_rx_qpush, /* erxo_qpush */ +#if EFSYS_OPT_RX_PACKED_STREAM + ef10_rx_qpush_ps_credits, /* erxo_qpush_ps_credits */ + ef10_rx_qps_packet_info, /* erxo_qps_packet_info */ +#endif ef10_rx_qflush, /* erxo_qflush */ ef10_rx_qenable, /* erxo_qenable */ ef10_rx_qcreate, /* erxo_qcreate */ @@ -430,6 +454,40 @@ efx_rx_qpost( erxop->erxo_qpost(erp, addrp, size, n, completed, added); } +#if EFSYS_OPT_RX_PACKED_STREAM + + void +efx_rx_qpush_ps_credits( + __in efx_rxq_t *erp) +{ + efx_nic_t *enp = erp->er_enp; + const efx_rx_ops_t *erxop = enp->en_erxop; + + EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC); + + erxop->erxo_qpush_ps_credits(erp); +} + + __checkReturn uint8_t * +efx_rx_qps_packet_info( + __in efx_rxq_t *erp, + __in uint8_t *buffer, + __in uint32_t buffer_length, + __in uint32_t current_offset, + __out uint16_t *lengthp, + __out uint32_t *next_offsetp, + __out uint32_t *timestamp) +{ + efx_nic_t *enp = erp->er_enp; + const efx_rx_ops_t *erxop = enp->en_erxop; + + return (erxop->erxo_qps_packet_info(erp, buffer, + buffer_length, current_offset, lengthp, + next_offsetp, timestamp)); +} + +#endif /* EFSYS_OPT_RX_PACKED_STREAM */ + void efx_rx_qpush( __in efx_rxq_t *erp, @@ -1076,6 +1134,32 @@ siena_rx_qpush( erp->er_index, &dword, B_FALSE); } +#if EFSYS_OPT_RX_PACKED_STREAM +static void +siena_rx_qpush_ps_credits( + __in efx_rxq_t *erp) +{ + /* Not supported by Siena hardware */ + EFSYS_ASSERT(0); +} + +static uint8_t * +siena_rx_qps_packet_info( + __in efx_rxq_t *erp, + __in uint8_t *buffer, + __in uint32_t buffer_length, + __in uint32_t current_offset, + __out uint16_t *lengthp, + __out uint32_t *next_offsetp, + __out uint32_t *timestamp) +{ + /* Not supported by Siena hardware */ + EFSYS_ASSERT(0); + + return (NULL); +} +#endif /* EFSYS_OPT_RX_PACKED_STREAM */ + static __checkReturn efx_rc_t siena_rx_qflush( __in efx_rxq_t *erp) diff --git a/sys/dev/sfxge/common/siena_nic.c b/sys/dev/sfxge/common/siena_nic.c index 55566bf7b8a8..2f2e47c9ceac 100644 --- a/sys/dev/sfxge/common/siena_nic.c +++ b/sys/dev/sfxge/common/siena_nic.c @@ -167,6 +167,8 @@ siena_board_cfg( encp->enc_fw_assisted_tso_v2_enabled = B_FALSE; encp->enc_fw_assisted_tso_v2_n_contexts = 0; encp->enc_allow_set_mac_with_installed_filters = B_TRUE; + encp->enc_rx_packed_stream_supported = B_FALSE; + encp->enc_rx_var_packed_stream_supported = B_FALSE; /* Siena supports two 10G ports, and 8 lanes of PCIe Gen2 */ encp->enc_required_pcie_bandwidth_mbps = 2 * 10000;