X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fcommon%2Fsfc_efx%2Fbase%2Fefx_mae.c;h=b1e4b98184dd130a11d44af6d65f6d5df346dfa7;hb=672386c1e9e1f64f7aa3b1360ad22dc737ea8d72;hp=2f5b167275d6cb0a83d2080b8a4b1bd61219c307;hpb=a0f0b03c817ce14e9dc337c8d9d8770760173dfe;p=dpdk.git diff --git a/drivers/common/sfc_efx/base/efx_mae.c b/drivers/common/sfc_efx/base/efx_mae.c index 2f5b167275..b1e4b98184 100644 --- a/drivers/common/sfc_efx/base/efx_mae.c +++ b/drivers/common/sfc_efx/base/efx_mae.c @@ -1,7 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * - * Copyright(c) 2019 Xilinx, Inc. All rights reserved. - * All rights reserved. + * Copyright(c) 2019-2021 Xilinx, Inc. */ #include "efx.h" @@ -463,6 +462,10 @@ typedef enum efx_mae_field_endianness_e { * The information in it is meant to be used internally by * APIs for addressing a given field in a mask-value pairs * structure and for validation purposes. + * + * A field may have an alternative one. This structure + * has additional members to reference the alternative + * field's mask. See efx_mae_match_spec_is_valid(). */ typedef struct efx_mae_mv_desc_s { efx_mae_field_cap_id_t emmd_field_cap_id; @@ -472,6 +475,14 @@ typedef struct efx_mae_mv_desc_s { size_t emmd_mask_size; size_t emmd_mask_offset; + /* + * Having the alternative field's mask size set to 0 + * means that there's no alternative field specified. + */ + size_t emmd_alt_mask_size; + size_t emmd_alt_mask_offset; + + /* Primary field and the alternative one are of the same endianness. */ efx_mae_field_endianness_t emmd_endianness; } efx_mae_mv_desc_t; @@ -485,6 +496,7 @@ static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = { MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST, \ MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN, \ MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST, \ + 0, 0 /* no alternative field */, \ _endianness \ } @@ -522,6 +534,21 @@ static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = { MAE_ENC_FIELD_PAIRS_##_name##_OFST, \ MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN, \ MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \ + 0, 0 /* no alternative field */, \ + _endianness \ + } + +/* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */ +#define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness) \ + [EFX_MAE_FIELD_##_name] = \ + { \ + EFX_MAE_FIELD_ID_##_name, \ + MAE_ENC_FIELD_PAIRS_##_name##_LEN, \ + MAE_ENC_FIELD_PAIRS_##_name##_OFST, \ + MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN, \ + MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \ + MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN, \ + MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST, \ _endianness \ } @@ -533,16 +560,17 @@ static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = { EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE), EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE), EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE), - EFX_MAE_MV_DESC(ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE), - EFX_MAE_MV_DESC(ENC_DST_IP4_BE, EFX_MAE_FIELD_BE), + EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE), + EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE), EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE), EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE), EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE), - EFX_MAE_MV_DESC(ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE), - EFX_MAE_MV_DESC(ENC_DST_IP6_BE, EFX_MAE_FIELD_BE), + EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE), + EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE), EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE), EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE), +#undef EFX_MAE_MV_DESC_ALT #undef EFX_MAE_MV_DESC }; @@ -564,7 +592,13 @@ efx_mae_mport_by_phy_port( MAE_MPORT_SELECTOR_PPORT_ID, phy_port); memset(mportp, 0, sizeof (*mportp)); - mportp->sel = dword.ed_u32[0]; + /* + * The constructed DWORD is little-endian, + * but the resulting value is meant to be + * passed to MCDIs, where it will undergo + * host-order to little endian conversion. + */ + mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); return (0); @@ -601,7 +635,13 @@ efx_mae_mport_by_pcie_function( MAE_MPORT_SELECTOR_FUNC_VF_ID, vf); memset(mportp, 0, sizeof (*mportp)); - mportp->sel = dword.ed_u32[0]; + /* + * The constructed DWORD is little-endian, + * but the resulting value is meant to be + * passed to MCDIs, where it will undergo + * host-order to little endian conversion. + */ + mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); return (0); @@ -649,23 +689,49 @@ efx_mae_match_spec_field_set( goto fail2; } - if (value_size != descp->emmd_value_size) { + if (descp->emmd_mask_size == 0) { + /* The ID points to a gap in the array of field descriptors. */ rc = EINVAL; goto fail3; } - if (mask_size != descp->emmd_mask_size) { + if (value_size != descp->emmd_value_size) { rc = EINVAL; goto fail4; } + if (mask_size != descp->emmd_mask_size) { + rc = EINVAL; + goto fail5; + } + if (descp->emmd_endianness == EFX_MAE_FIELD_BE) { + unsigned int i; + /* * The mask/value are in network (big endian) order. * The MCDI request field is also big endian. */ - memcpy(mvp + descp->emmd_value_offset, value, value_size); - memcpy(mvp + descp->emmd_mask_offset, mask, mask_size); + + EFSYS_ASSERT3U(value_size, ==, mask_size); + + for (i = 0; i < value_size; ++i) { + uint8_t *v_bytep = mvp + descp->emmd_value_offset + i; + uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i; + + /* + * Apply the mask (which may be all-zeros) to the value. + * + * If this API is provided with some value to set for a + * given field in one specification and with some other + * value to set for this field in another specification, + * then, if the two masks are all-zeros, the field will + * avoid being counted as a mismatch when comparing the + * specifications using efx_mae_match_specs_equal() API. + */ + *v_bytep = value[i] & mask[i]; + *m_bytep = mask[i]; + } } else { efx_dword_t dword; @@ -700,6 +766,8 @@ efx_mae_match_spec_field_set( return (0); +fail5: + EFSYS_PROBE(fail5); fail4: EFSYS_PROBE(fail4); fail3: @@ -848,14 +916,25 @@ efx_mae_match_spec_is_valid( ++field_id) { const efx_mae_mv_desc_t *descp = &desc_setp[field_id]; efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id; + const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset; const uint8_t *m_buf = mvp + descp->emmd_mask_offset; + size_t alt_m_size = descp->emmd_alt_mask_size; size_t m_size = descp->emmd_mask_size; if (m_size == 0) continue; /* Skip array gap */ - if ((unsigned int)field_cap_id >= field_ncaps) - break; + if ((unsigned int)field_cap_id >= field_ncaps) { + /* + * The FW has not reported capability status for + * this field. Make sure that its mask is zeroed. + */ + is_valid = efx_mask_is_all_zeros(m_size, m_buf); + if (is_valid != B_FALSE) + continue; + else + break; + } switch (field_caps[field_cap_id].emfc_support) { case MAE_FIELD_SUPPORTED_MATCH_MASK: @@ -870,6 +949,19 @@ efx_mae_match_spec_is_valid( break; case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: is_valid = efx_mask_is_all_ones(m_size, m_buf); + + if ((is_valid == B_FALSE) && (alt_m_size != 0)) { + /* + * This field has an alternative one. The FW + * reports ALWAYS for both implying that one + * of them is required to have all-ones mask. + * + * The primary field's mask is incorrect; go + * on to check that of the alternative field. + */ + is_valid = efx_mask_is_all_ones(alt_m_size, + alt_m_buf); + } break; case MAE_FIELD_SUPPORTED_MATCH_NEVER: case MAE_FIELD_UNSUPPORTED: @@ -1275,7 +1367,13 @@ efx_mae_action_set_populate_drop( EFX_POPULATE_DWORD_1(dword, MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL); - mport.sel = dword.ed_u32[0]; + /* + * The constructed DWORD is little-endian, + * but the resulting value is meant to be + * passed to MCDIs, where it will undergo + * host-order to little endian conversion. + */ + mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); arg = (const uint8_t *)&mport.sel; @@ -1355,18 +1453,32 @@ efx_mae_match_specs_class_cmp( ++field_id) { const efx_mae_mv_desc_t *descp = &desc_setp[field_id]; efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id; - - if (descp->emmd_mask_size == 0) + const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset; + const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset; + size_t mask_size = descp->emmd_mask_size; + const uint8_t *lvalp = mvpl + descp->emmd_value_offset; + const uint8_t *rvalp = mvpr + descp->emmd_value_offset; + size_t value_size = descp->emmd_value_size; + + if (mask_size == 0) continue; /* Skip array gap */ - if ((unsigned int)field_cap_id >= field_ncaps) - break; + if ((unsigned int)field_cap_id >= field_ncaps) { + /* + * The FW has not reported capability status for this + * field. It's unknown whether any difference between + * the two masks / values affects the class. The only + * case when the class must be the same is when these + * mask-value pairs match. Otherwise, report mismatch. + */ + if ((memcmp(lmaskp, rmaskp, mask_size) == 0) && + (memcmp(lvalp, rvalp, value_size) == 0)) + continue; + else + break; + } if (field_caps[field_cap_id].emfc_mask_affects_class) { - const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset; - const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset; - size_t mask_size = descp->emmd_mask_size; - if (memcmp(lmaskp, rmaskp, mask_size) != 0) { have_same_class = B_FALSE; break; @@ -1374,10 +1486,6 @@ efx_mae_match_specs_class_cmp( } if (field_caps[field_cap_id].emfc_match_affects_class) { - const uint8_t *lvalp = mvpl + descp->emmd_value_offset; - const uint8_t *rvalp = mvpr + descp->emmd_value_offset; - size_t value_size = descp->emmd_value_size; - if (memcmp(lvalp, rvalp, value_size) != 0) { have_same_class = B_FALSE; break;