From c1f021890074e6c2f9797cfb8feb053376323f32 Mon Sep 17 00:00:00 2001 From: Andrew Rybchenko Date: Thu, 24 Sep 2020 13:12:17 +0100 Subject: [PATCH] common/sfc_efx/base: choose smallest Rx prefix on Riverhead Riverhead supports many Rx prefixes. The Rx prefix may be chosen based on which information is required. To have better performance choose the smallest Rx prefix which meets our requirements. Right now there is no way to specify requirements on Rx queue creation, but it could be added in the future. Signed-off-by: Andrew Rybchenko Reviewed-by: Andy Moreton --- drivers/common/sfc_efx/base/efx_impl.h | 1 + drivers/common/sfc_efx/base/efx_mcdi.c | 10 +- drivers/common/sfc_efx/base/rhead_rx.c | 333 ++++++++++++++++++++++++- 3 files changed, 338 insertions(+), 6 deletions(-) diff --git a/drivers/common/sfc_efx/base/efx_impl.h b/drivers/common/sfc_efx/base/efx_impl.h index c373192554..fc0a654f80 100644 --- a/drivers/common/sfc_efx/base/efx_impl.h +++ b/drivers/common/sfc_efx/base/efx_impl.h @@ -1439,6 +1439,7 @@ typedef struct efx_mcdi_init_rxq_params_s { uint32_t es_max_dma_len; uint32_t es_buf_stride; uint32_t hol_block_timeout; + uint32_t prefix_id; } efx_mcdi_init_rxq_params_t; LIBEFX_INTERNAL diff --git a/drivers/common/sfc_efx/base/efx_mcdi.c b/drivers/common/sfc_efx/base/efx_mcdi.c index aa19c7c759..b8e45b458d 100644 --- a/drivers/common/sfc_efx/base/efx_mcdi.c +++ b/drivers/common/sfc_efx/base/efx_mcdi.c @@ -2692,8 +2692,8 @@ efx_mcdi_init_rxq( { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_mcdi_req_t req; - EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_RXQ_V4_IN_LEN, - MC_CMD_INIT_RXQ_V4_OUT_LEN); + EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_RXQ_V5_IN_LEN, + MC_CMD_INIT_RXQ_V5_OUT_LEN); int npages = efx_rxq_nbufs(enp, ndescs); int i; efx_qword_t *dma_addr; @@ -2747,9 +2747,9 @@ efx_mcdi_init_rxq( req.emr_cmd = MC_CMD_INIT_RXQ; req.emr_in_buf = payload; - req.emr_in_length = MC_CMD_INIT_RXQ_V4_IN_LEN; + req.emr_in_length = MC_CMD_INIT_RXQ_V5_IN_LEN; req.emr_out_buf = payload; - req.emr_out_length = MC_CMD_INIT_RXQ_V4_OUT_LEN; + req.emr_out_length = MC_CMD_INIT_RXQ_V5_OUT_LEN; MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_SIZE, ndescs); MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_TARGET_EVQ, eep->ee_index); @@ -2787,6 +2787,8 @@ efx_mcdi_init_rxq( MCDI_IN_SET_DWORD(req, INIT_RXQ_V4_IN_BUFFER_SIZE_BYTES, params->buf_size); + MCDI_IN_SET_DWORD(req, INIT_RXQ_V5_IN_RX_PREFIX_ID, params->prefix_id); + dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR); addr = EFSYS_MEM_ADDR(esmp); diff --git a/drivers/common/sfc_efx/base/rhead_rx.c b/drivers/common/sfc_efx/base/rhead_rx.c index 38c905444a..d683f280ce 100644 --- a/drivers/common/sfc_efx/base/rhead_rx.c +++ b/drivers/common/sfc_efx/base/rhead_rx.c @@ -10,6 +10,12 @@ #if EFSYS_OPT_RIVERHEAD +/* + * Maximum number of Rx prefixes supported by Rx prefix choice to be + * returned from firmware. + */ +#define RHEAD_RX_PREFIX_IDS_MAX 16 + /* * Default Rx prefix layout on Riverhead if FW does not support Rx * prefix choice using MC_CMD_GET_RX_PREFIX_ID and query its layout @@ -265,6 +271,312 @@ rhead_rx_qenable( _NOTE(ARGUNUSED(erp)) } +static __checkReturn efx_rc_t +efx_mcdi_get_rx_prefix_ids( + __in efx_nic_t *enp, + __in uint32_t mcdi_fields_mask, + __in unsigned int max_ids, + __out unsigned int *nids, + __out_ecount_part(max_ids, *nids) uint32_t *idsp) +{ + efx_mcdi_req_t req; + EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RX_PREFIX_ID_IN_LEN, + MC_CMD_GET_RX_PREFIX_ID_OUT_LENMAX); + efx_rc_t rc; + uint32_t num; + + req.emr_cmd = MC_CMD_GET_RX_PREFIX_ID; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_GET_RX_PREFIX_ID_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_GET_RX_PREFIX_ID_OUT_LENMAX; + + MCDI_IN_SET_DWORD(req, GET_RX_PREFIX_ID_IN_FIELDS, mcdi_fields_mask); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_GET_RX_PREFIX_ID_OUT_LENMIN) { + rc = EMSGSIZE; + goto fail2; + } + + num = MCDI_OUT_DWORD(req, GET_RX_PREFIX_ID_OUT_NUM_RX_PREFIX_IDS); + + if (req.emr_out_length_used != MC_CMD_GET_RX_PREFIX_ID_OUT_LEN(num)) { + rc = EMSGSIZE; + goto fail3; + } + + *nids = MIN(num, max_ids); + + EFX_STATIC_ASSERT(sizeof (idsp[0]) == + MC_CMD_GET_RX_PREFIX_ID_OUT_RX_PREFIX_ID_LEN); + memcpy(idsp, + MCDI_OUT2(req, uint32_t, GET_RX_PREFIX_ID_OUT_RX_PREFIX_ID), + *nids * sizeof (idsp[0])); + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rx_prefix_field_t +efx_mcdi_rx_prefix_field_map(unsigned int mcdi_idx) +{ + static const efx_rx_prefix_field_t efx_mcdi_to_rx_prefix_field[] = { +#define EFX_MCDI_TO_RX_PREFIX_FIELD(_field) \ + [RX_PREFIX_FIELD_INFO_ ## _field] = EFX_RX_PREFIX_FIELD_ ## _field + + EFX_MCDI_TO_RX_PREFIX_FIELD(LENGTH), + EFX_MCDI_TO_RX_PREFIX_FIELD(RSS_HASH_VALID), + EFX_MCDI_TO_RX_PREFIX_FIELD(USER_FLAG), + EFX_MCDI_TO_RX_PREFIX_FIELD(CLASS), + EFX_MCDI_TO_RX_PREFIX_FIELD(PARTIAL_TSTAMP), + EFX_MCDI_TO_RX_PREFIX_FIELD(RSS_HASH), + EFX_MCDI_TO_RX_PREFIX_FIELD(USER_MARK), + EFX_MCDI_TO_RX_PREFIX_FIELD(INGRESS_VPORT), + EFX_MCDI_TO_RX_PREFIX_FIELD(CSUM_FRAME), + EFX_MCDI_TO_RX_PREFIX_FIELD(VLAN_STRIP_TCI), + +#undef EFX_MCDI_TO_RX_PREFIX_FIELD + }; + + if (mcdi_idx >= EFX_ARRAY_SIZE(efx_mcdi_to_rx_prefix_field)) + return (EFX_RX_PREFIX_NFIELDS); + + return (efx_mcdi_to_rx_prefix_field[mcdi_idx]); +} + +static __checkReturn int +efx_rx_prefix_field_map_to_mcdi( + __in efx_rx_prefix_field_t field) +{ + static const int efx_rx_prefix_field_to_mcdi[] = { + [EFX_RX_PREFIX_FIELD_LENGTH] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_LENGTH), + [EFX_RX_PREFIX_FIELD_ORIG_LENGTH] = -1, + [EFX_RX_PREFIX_FIELD_CLASS] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_CLASS), + [EFX_RX_PREFIX_FIELD_RSS_HASH] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_RSS_HASH), + [EFX_RX_PREFIX_FIELD_RSS_HASH_VALID] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_RSS_HASH_VALID), + [EFX_RX_PREFIX_FIELD_PARTIAL_TSTAMP] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_PARTIAL_TSTAMP), + [EFX_RX_PREFIX_FIELD_VLAN_STRIP_TCI] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_VLAN_STRIP_TCI), + [EFX_RX_PREFIX_FIELD_INNER_VLAN_STRIP_TCI] = -1, + [EFX_RX_PREFIX_FIELD_USER_FLAG] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_USER_FLAG), + [EFX_RX_PREFIX_FIELD_USER_MARK] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_USER_MARK), + [EFX_RX_PREFIX_FIELD_USER_MARK_VALID] = -1, + [EFX_RX_PREFIX_FIELD_CSUM_FRAME] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_CSUM_FRAME), + [EFX_RX_PREFIX_FIELD_INGRESS_VPORT] = + EFX_LOW_BIT(MC_CMD_GET_RX_PREFIX_ID_IN_INGRESS_VPORT), + }; + + if (field >= EFX_ARRAY_SIZE(efx_rx_prefix_field_to_mcdi)) + return (-1); + + return (efx_rx_prefix_field_to_mcdi[field]); +} + +static __checkReturn efx_rc_t +efx_rx_prefix_fields_mask_to_mcdi( + __in uint32_t fields_mask, + __out uint32_t *mcdi_fields_maskp) +{ + uint32_t mcdi_fields_mask = 0; + unsigned int i; + + for (i = 0; i < EFX_RX_PREFIX_NFIELDS; ++i) { + if (fields_mask & (1U << i)) { + int mcdi_field = efx_rx_prefix_field_map_to_mcdi(i); + + if (mcdi_field < 0) + return (EINVAL); + + mcdi_fields_mask |= (1U << mcdi_field); + } + } + + *mcdi_fields_maskp = mcdi_fields_mask; + return (0); +} + +static __checkReturn efx_rc_t +efx_mcdi_query_rx_prefix_id( + __in efx_nic_t *enp, + __in uint32_t prefix_id, + __out efx_rx_prefix_layout_t *erplp) +{ + efx_mcdi_req_t req; + EFX_MCDI_DECLARE_BUF(payload, MC_CMD_QUERY_RX_PREFIX_ID_IN_LEN, + MC_CMD_QUERY_RX_PREFIX_ID_OUT_LENMAX); + efx_rc_t rc; + size_t response_len; + const efx_dword_t *resp; + const efx_dword_t *finfo; + unsigned int num_fields; + unsigned int mcdi_field; + efx_rx_prefix_field_t field; + unsigned int i; + + req.emr_cmd = MC_CMD_QUERY_RX_PREFIX_ID; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_QUERY_RX_PREFIX_ID_IN_LEN; + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_QUERY_RX_PREFIX_ID_OUT_LENMAX; + + MCDI_IN_SET_DWORD(req, QUERY_RX_PREFIX_ID_IN_RX_PREFIX_ID, prefix_id); + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail1; + } + + if (req.emr_out_length_used < MC_CMD_QUERY_RX_PREFIX_ID_OUT_LENMIN) { + rc = EMSGSIZE; + goto fail2; + } + + if (MCDI_OUT_BYTE(req, QUERY_RX_PREFIX_ID_OUT_RESPONSE_TYPE) != + MC_CMD_QUERY_RX_PREFIX_ID_OUT_RESPONSE_TYPE_FIXED) { + rc = ENOTSUP; + goto fail3; + } + + EFX_STATIC_ASSERT(MC_CMD_QUERY_RX_PREFIX_ID_OUT_LENMIN >= + MC_CMD_QUERY_RX_PREFIX_ID_OUT_RESPONSE_OFST); + response_len = req.emr_out_length_used - + MC_CMD_QUERY_RX_PREFIX_ID_OUT_RESPONSE_OFST; + + if (response_len < RX_PREFIX_FIXED_RESPONSE_LENMIN) { + rc = EMSGSIZE; + goto fail4; + } + + resp = MCDI_OUT2(req, efx_dword_t, QUERY_RX_PREFIX_ID_OUT_RESPONSE); + + memset(erplp, 0, sizeof (*erplp)); + erplp->erpl_id = prefix_id; + erplp->erpl_length = + EFX_DWORD_FIELD(*resp, RX_PREFIX_FIXED_RESPONSE_PREFIX_LENGTH_BYTES); + num_fields = + EFX_DWORD_FIELD(*resp, RX_PREFIX_FIXED_RESPONSE_FIELD_COUNT); + + if (response_len < RX_PREFIX_FIXED_RESPONSE_LEN(num_fields)) { + rc = EMSGSIZE; + goto fail5; + } + + finfo = (const efx_dword_t *)((const uint8_t *)resp + + RX_PREFIX_FIXED_RESPONSE_FIELDS_OFST); + + for (i = 0; i < num_fields; ++i, ++finfo) { + mcdi_field = EFX_DWORD_FIELD(*finfo, RX_PREFIX_FIELD_INFO_TYPE); + + field = efx_mcdi_rx_prefix_field_map(mcdi_field); + if (field >= EFX_RX_PREFIX_NFIELDS) + continue; + + erplp->erpl_fields[field].erpfi_offset_bits = + EFX_DWORD_FIELD(*finfo, RX_PREFIX_FIELD_INFO_OFFSET_BITS); + erplp->erpl_fields[field].erpfi_width_bits = + EFX_DWORD_FIELD(*finfo, RX_PREFIX_FIELD_INFO_WIDTH_BITS); + } + + return (0); + +fail5: + EFSYS_PROBE(fail5); +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + +static __checkReturn efx_rc_t +rhead_rx_choose_prefix_id( + __in efx_nic_t *enp, + __in uint32_t fields_mask, + __out efx_rx_prefix_layout_t *erplp) +{ + efx_rx_prefix_layout_t erpl; + uint32_t prefix_ids[RHEAD_RX_PREFIX_IDS_MAX]; + uint32_t mcdi_fields_mask; + unsigned int num = 0; + unsigned int i; + efx_rc_t rc; + + rc = efx_rx_prefix_fields_mask_to_mcdi(fields_mask, &mcdi_fields_mask); + if (rc != 0) + goto fail1; + + memset(erplp, 0, sizeof (*erplp)); + + rc = efx_mcdi_get_rx_prefix_ids(enp, mcdi_fields_mask, + EFX_ARRAY_SIZE(prefix_ids), &num, prefix_ids); + if (rc == ENOTSUP) { + /* Not supported MCDI, use default prefix ID */ + *erplp = rhead_default_rx_prefix_layout; + goto done; + } + if (rc != 0) + goto fail2; + + if (num == 0) { + rc = ENOTSUP; + goto fail3; + } + + for (i = 0; i < num; ++i) { + rc = efx_mcdi_query_rx_prefix_id(enp, prefix_ids[i], &erpl); + if (rc != 0) + goto fail4; + + /* Choose the smallest prefix which meets our requirements */ + if (i == 0 || erpl.erpl_length < erplp->erpl_length) + *erplp = erpl; + } + +done: + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + __checkReturn efx_rc_t rhead_rx_qcreate( __in efx_nic_t *enp, @@ -281,6 +593,7 @@ rhead_rx_qcreate( { const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); efx_mcdi_init_rxq_params_t params; + efx_rx_prefix_layout_t erpl; efx_rc_t rc; _NOTE(ARGUNUSED(id)) @@ -310,6 +623,20 @@ rhead_rx_qcreate( else params.disable_scatter = encp->enc_rx_disable_scatter_supported; + /* + * LENGTH is required in EF100 host interface, as receive events + * do not include the packet length. + * NOTE: Required fields are hard-wired now. Future designs will + * want to allow the client (driver) code to have control over + * which fields are required or may be allow to request so-called + * default Rx prefix (which ID is equal to 0). + */ + if ((rc = rhead_rx_choose_prefix_id(enp, + (1U << EFX_RX_PREFIX_FIELD_LENGTH), &erpl)) != 0) + goto fail3; + + params.prefix_id = erpl.erpl_id; + /* * Ignore EFX_RXQ_FLAG_INNER_CLASSES since in accordance with * EF100 host interface both inner and outer classes are provided @@ -318,15 +645,17 @@ rhead_rx_qcreate( if ((rc = efx_mcdi_init_rxq(enp, ndescs, eep, label, index, esmp, ¶ms)) != 0) - goto fail3; + goto fail4; erp->er_eep = eep; erp->er_label = label; erp->er_buf_size = params.buf_size; - erp->er_prefix_layout = rhead_default_rx_prefix_layout; + erp->er_prefix_layout = erpl; return (0); +fail4: + EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: -- 2.20.1