X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fcommon%2Fsfc_efx%2Fbase%2Frhead_rx.c;h=b6f9d51fef9e4af99b3df44a1ee2d2369531dda2;hb=40f94ce9fa6217ba33cda0c42fd732b77aaf4791;hp=38c905444ae6874603ca4104974ca31b96b645d2;hpb=7640543f4c4f684dee99df343fc51403d60bd181;p=dpdk.git diff --git a/drivers/common/sfc_efx/base/rhead_rx.c b/drivers/common/sfc_efx/base/rhead_rx.c index 38c905444a..b6f9d51fef 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,8 @@ 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; + uint32_t fields_mask = 0; efx_rc_t rc; _NOTE(ARGUNUSED(id)) @@ -310,6 +624,21 @@ rhead_rx_qcreate( else params.disable_scatter = encp->enc_rx_disable_scatter_supported; + if (flags & EFX_RXQ_FLAG_RSS_HASH) { + fields_mask |= 1U << EFX_RX_PREFIX_FIELD_RSS_HASH; + fields_mask |= 1U << EFX_RX_PREFIX_FIELD_RSS_HASH_VALID; + } + + /* + * LENGTH is required in EF100 host interface, as receive events + * do not include the packet length. + */ + fields_mask |= 1U << EFX_RX_PREFIX_FIELD_LENGTH; + if ((rc = rhead_rx_choose_prefix_id(enp, fields_mask, &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 +647,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: