common/sfc_efx/base: add match spec validate API
MAE has restrictions on what kind of mask a particular field can have in a match specification. Add an API for client drivers to check specifications. The patch defines a field description list, whilst the list itself is left empty. This is to provide a general idea of how field properties will be used to validate a match specification. Particular fields will be added to the list by follow-up patches. Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru> Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com> Reviewed-by: Andy Moreton <amoreton@xilinx.com>
This commit is contained in:
parent
7a25bc9871
commit
34285fd089
@ -4080,6 +4080,24 @@ efx_mae_match_spec_fini(
|
||||
__in efx_nic_t *enp,
|
||||
__in efx_mae_match_spec_t *spec);
|
||||
|
||||
typedef enum efx_mae_field_id_e {
|
||||
EFX_MAE_FIELD_NIDS
|
||||
} efx_mae_field_id_t;
|
||||
|
||||
/*
|
||||
* Make sure that match fields known by EFX have proper masks set
|
||||
* in the match specification as per requirements of SF-122526-TC.
|
||||
*
|
||||
* In the case efx_mae_field_id_t lacks named identifiers for any
|
||||
* fields which the FW maintains with support status MATCH_ALWAYS,
|
||||
* the validation result may not be accurate.
|
||||
*/
|
||||
LIBEFX_API
|
||||
extern __checkReturn boolean_t
|
||||
efx_mae_match_spec_is_valid(
|
||||
__in efx_nic_t *enp,
|
||||
__in const efx_mae_match_spec_t *spec);
|
||||
|
||||
#endif /* EFSYS_OPT_MAE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -782,8 +782,22 @@ typedef struct efx_proxy_ops_s {
|
||||
|
||||
#if EFSYS_OPT_MAE
|
||||
|
||||
typedef struct efx_mae_field_cap_s {
|
||||
uint32_t emfc_support;
|
||||
boolean_t emfc_mask_affects_class;
|
||||
boolean_t emfc_match_affects_class;
|
||||
} efx_mae_field_cap_t;
|
||||
|
||||
typedef struct efx_mae_s {
|
||||
uint32_t em_max_n_action_prios;
|
||||
/*
|
||||
* The number of MAE field IDs recognised by the FW implementation.
|
||||
* Any field ID greater than or equal to this value is unsupported.
|
||||
*/
|
||||
uint32_t em_max_nfields;
|
||||
/** Action rule match field capabilities. */
|
||||
efx_mae_field_cap_t *em_action_rule_field_caps;
|
||||
size_t em_action_rule_field_caps_size;
|
||||
} efx_mae_t;
|
||||
|
||||
#endif /* EFSYS_OPT_MAE */
|
||||
@ -1680,6 +1694,9 @@ efx_pci_xilinx_cap_tbl_find(
|
||||
struct efx_mae_match_spec_s {
|
||||
efx_mae_rule_type_t emms_type;
|
||||
uint32_t emms_prio;
|
||||
union emms_mask_value_pairs {
|
||||
uint8_t action[MAE_FIELD_MASK_VALUE_PAIRS_LEN];
|
||||
} emms_mask_value_pairs;
|
||||
};
|
||||
|
||||
#endif /* EFSYS_OPT_MAE */
|
||||
|
@ -42,6 +42,9 @@ efx_mae_get_capabilities(
|
||||
maep->em_max_n_action_prios =
|
||||
MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
|
||||
|
||||
maep->em_max_nfields =
|
||||
MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
|
||||
|
||||
return (0);
|
||||
|
||||
fail2:
|
||||
@ -51,11 +54,95 @@ efx_mae_get_capabilities(
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static __checkReturn efx_rc_t
|
||||
efx_mae_get_action_rule_caps(
|
||||
__in efx_nic_t *enp,
|
||||
__in unsigned int field_ncaps,
|
||||
__out_ecount(field_ncaps) efx_mae_field_cap_t *field_caps)
|
||||
{
|
||||
efx_mcdi_req_t req;
|
||||
EFX_MCDI_DECLARE_BUF(payload,
|
||||
MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
|
||||
MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
|
||||
unsigned int mcdi_field_ncaps;
|
||||
unsigned int i;
|
||||
efx_rc_t rc;
|
||||
|
||||
if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
|
||||
MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
|
||||
rc = EINVAL;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
|
||||
req.emr_in_buf = payload;
|
||||
req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
|
||||
req.emr_out_buf = payload;
|
||||
req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
|
||||
|
||||
efx_mcdi_execute(enp, &req);
|
||||
|
||||
if (req.emr_rc != 0) {
|
||||
rc = req.emr_rc;
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
|
||||
|
||||
if (req.emr_out_length_used <
|
||||
MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
|
||||
rc = EMSGSIZE;
|
||||
goto fail3;
|
||||
}
|
||||
|
||||
if (mcdi_field_ncaps > field_ncaps) {
|
||||
rc = EMSGSIZE;
|
||||
goto fail4;
|
||||
}
|
||||
|
||||
for (i = 0; i < mcdi_field_ncaps; ++i) {
|
||||
uint32_t match_flag;
|
||||
uint32_t mask_flag;
|
||||
|
||||
field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
|
||||
MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
|
||||
MAE_FIELD_FLAGS_SUPPORT_STATUS);
|
||||
|
||||
match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
|
||||
MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
|
||||
MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
|
||||
|
||||
field_caps[i].emfc_match_affects_class =
|
||||
(match_flag != 0) ? B_TRUE : B_FALSE;
|
||||
|
||||
mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
|
||||
MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
|
||||
MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
|
||||
|
||||
field_caps[i].emfc_mask_affects_class =
|
||||
(mask_flag != 0) ? B_TRUE : B_FALSE;
|
||||
}
|
||||
|
||||
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
|
||||
efx_mae_init(
|
||||
__in efx_nic_t *enp)
|
||||
{
|
||||
const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
|
||||
efx_mae_field_cap_t *ar_fcaps;
|
||||
size_t ar_fcaps_size;
|
||||
efx_mae_t *maep;
|
||||
efx_rc_t rc;
|
||||
|
||||
@ -76,8 +163,27 @@ efx_mae_init(
|
||||
if (rc != 0)
|
||||
goto fail3;
|
||||
|
||||
ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
|
||||
EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
|
||||
if (ar_fcaps == NULL) {
|
||||
rc = ENOMEM;
|
||||
goto fail4;
|
||||
}
|
||||
|
||||
maep->em_action_rule_field_caps_size = ar_fcaps_size;
|
||||
maep->em_action_rule_field_caps = ar_fcaps;
|
||||
|
||||
rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
|
||||
if (rc != 0)
|
||||
goto fail5;
|
||||
|
||||
return (0);
|
||||
|
||||
fail5:
|
||||
EFSYS_PROBE(fail5);
|
||||
EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
|
||||
fail4:
|
||||
EFSYS_PROBE(fail4);
|
||||
fail3:
|
||||
EFSYS_PROBE(fail3);
|
||||
EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
|
||||
@ -99,6 +205,8 @@ efx_mae_fini(
|
||||
if (encp->enc_mae_supported == B_FALSE)
|
||||
return;
|
||||
|
||||
EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
|
||||
maep->em_action_rule_field_caps);
|
||||
EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
|
||||
enp->en_maep = NULL;
|
||||
}
|
||||
@ -172,4 +280,158 @@ efx_mae_match_spec_fini(
|
||||
EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
|
||||
}
|
||||
|
||||
/* Named identifiers which are valid indices to efx_mae_field_cap_t */
|
||||
typedef enum efx_mae_field_cap_id_e {
|
||||
EFX_MAE_FIELD_CAP_NIDS
|
||||
} efx_mae_field_cap_id_t;
|
||||
|
||||
typedef enum efx_mae_field_endianness_e {
|
||||
EFX_MAE_FIELD_LE = 0,
|
||||
EFX_MAE_FIELD_BE,
|
||||
|
||||
EFX_MAE_FIELD_ENDIANNESS_NTYPES
|
||||
} efx_mae_field_endianness_t;
|
||||
|
||||
/*
|
||||
* The following structure is a means to describe an MAE field.
|
||||
* 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.
|
||||
*/
|
||||
typedef struct efx_mae_mv_desc_s {
|
||||
efx_mae_field_cap_id_t emmd_field_cap_id;
|
||||
|
||||
size_t emmd_value_size;
|
||||
size_t emmd_value_offset;
|
||||
size_t emmd_mask_size;
|
||||
size_t emmd_mask_offset;
|
||||
|
||||
efx_mae_field_endianness_t emmd_endianness;
|
||||
} efx_mae_mv_desc_t;
|
||||
|
||||
/* Indices to this array are provided by efx_mae_field_id_t */
|
||||
static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
|
||||
};
|
||||
|
||||
#define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit) \
|
||||
((_mask)[(_bit) / (_mask_page_nbits)] & \
|
||||
(1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
|
||||
|
||||
static inline boolean_t
|
||||
efx_mask_is_prefix(
|
||||
__in size_t mask_nbytes,
|
||||
__in_bcount(mask_nbytes) const uint8_t *maskp)
|
||||
{
|
||||
boolean_t prev_bit_is_set = B_TRUE;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 8 * mask_nbytes; ++i) {
|
||||
boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
|
||||
|
||||
if (!prev_bit_is_set && bit_is_set)
|
||||
return B_FALSE;
|
||||
|
||||
prev_bit_is_set = bit_is_set;
|
||||
}
|
||||
|
||||
return B_TRUE;
|
||||
}
|
||||
|
||||
static inline boolean_t
|
||||
efx_mask_is_all_ones(
|
||||
__in size_t mask_nbytes,
|
||||
__in_bcount(mask_nbytes) const uint8_t *maskp)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t t = ~0;
|
||||
|
||||
for (i = 0; i < mask_nbytes; ++i)
|
||||
t &= maskp[i];
|
||||
|
||||
return (t == (uint8_t)(~0));
|
||||
}
|
||||
|
||||
static inline boolean_t
|
||||
efx_mask_is_all_zeros(
|
||||
__in size_t mask_nbytes,
|
||||
__in_bcount(mask_nbytes) const uint8_t *maskp)
|
||||
{
|
||||
unsigned int i;
|
||||
uint8_t t = 0;
|
||||
|
||||
for (i = 0; i < mask_nbytes; ++i)
|
||||
t |= maskp[i];
|
||||
|
||||
return (t == 0);
|
||||
}
|
||||
|
||||
__checkReturn boolean_t
|
||||
efx_mae_match_spec_is_valid(
|
||||
__in efx_nic_t *enp,
|
||||
__in const efx_mae_match_spec_t *spec)
|
||||
{
|
||||
efx_mae_t *maep = enp->en_maep;
|
||||
unsigned int field_ncaps = maep->em_max_nfields;
|
||||
const efx_mae_field_cap_t *field_caps;
|
||||
const efx_mae_mv_desc_t *desc_setp;
|
||||
unsigned int desc_set_nentries;
|
||||
boolean_t is_valid = B_TRUE;
|
||||
efx_mae_field_id_t field_id;
|
||||
const uint8_t *mvp;
|
||||
|
||||
switch (spec->emms_type) {
|
||||
case EFX_MAE_RULE_ACTION:
|
||||
field_caps = maep->em_action_rule_field_caps;
|
||||
desc_setp = __efx_mae_action_rule_mv_desc_set;
|
||||
desc_set_nentries =
|
||||
EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
|
||||
mvp = spec->emms_mask_value_pairs.action;
|
||||
break;
|
||||
default:
|
||||
return (B_FALSE);
|
||||
}
|
||||
|
||||
if (field_caps == NULL)
|
||||
return (B_FALSE);
|
||||
|
||||
for (field_id = 0; field_id < desc_set_nentries; ++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 *m_buf = mvp + descp->emmd_mask_offset;
|
||||
size_t m_size = descp->emmd_mask_size;
|
||||
|
||||
if (m_size == 0)
|
||||
continue; /* Skip array gap */
|
||||
|
||||
if (field_cap_id >= field_ncaps)
|
||||
break;
|
||||
|
||||
switch (field_caps[field_cap_id].emfc_support) {
|
||||
case MAE_FIELD_SUPPORTED_MATCH_MASK:
|
||||
is_valid = B_TRUE;
|
||||
break;
|
||||
case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
|
||||
is_valid = efx_mask_is_prefix(m_size, m_buf);
|
||||
break;
|
||||
case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
|
||||
is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
|
||||
efx_mask_is_all_zeros(m_size, m_buf));
|
||||
break;
|
||||
case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
|
||||
is_valid = efx_mask_is_all_ones(m_size, m_buf);
|
||||
break;
|
||||
case MAE_FIELD_SUPPORTED_MATCH_NEVER:
|
||||
case MAE_FIELD_UNSUPPORTED:
|
||||
default:
|
||||
is_valid = efx_mask_is_all_zeros(m_size, m_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_valid == B_FALSE)
|
||||
break;
|
||||
}
|
||||
|
||||
return (is_valid);
|
||||
}
|
||||
|
||||
#endif /* EFSYS_OPT_MAE */
|
||||
|
@ -421,6 +421,10 @@ efx_mcdi_phy_module_get_info(
|
||||
EFX_DWORD_FIELD(*MCDI_OUT2(_emr, efx_dword_t, _ofst), \
|
||||
MC_CMD_ ## _field)
|
||||
|
||||
#define MCDI_OUT_INDEXED_DWORD_FIELD(_emr, _ofst, _idx, _field) \
|
||||
EFX_DWORD_FIELD(*(MCDI_OUT2(_emr, efx_dword_t, _ofst) + \
|
||||
(_idx)), _field)
|
||||
|
||||
#define MCDI_EV_FIELD(_eqp, _field) \
|
||||
EFX_QWORD_FIELD(*_eqp, MCDI_EVENT_ ## _field)
|
||||
|
||||
|
@ -90,6 +90,7 @@ INTERNAL {
|
||||
efx_mae_init;
|
||||
efx_mae_match_spec_fini;
|
||||
efx_mae_match_spec_init;
|
||||
efx_mae_match_spec_is_valid;
|
||||
|
||||
efx_mcdi_fini;
|
||||
efx_mcdi_get_proxy_handle;
|
||||
|
Loading…
Reference in New Issue
Block a user