common/sfc_efx/base: add MAE VLAN presence match bits
authorIvan Malov <ivan.malov@oktetlabs.ru>
Mon, 24 May 2021 11:48:32 +0000 (14:48 +0300)
committerDavid Marchand <david.marchand@redhat.com>
Wed, 7 Jul 2021 09:54:21 +0000 (11:54 +0200)
Introduce necessary infrastructure for these fields to
be set, validated and compared during class comparison.
Enumeration and mappings envisaged are MCDI-compatible.

Signed-off-by: Ivan Malov <ivan.malov@oktetlabs.ru>
Reviewed-by: Andrew Rybchenko <andrew.rybchenko@oktetlabs.ru>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
Acked-by: Ray Kinsella <mdr@ashroe.eu>
drivers/common/sfc_efx/base/efx.h
drivers/common/sfc_efx/base/efx_impl.h
drivers/common/sfc_efx/base/efx_mae.c
drivers/common/sfc_efx/version.map

index 771fe5a..8e13075 100644 (file)
@@ -4103,6 +4103,10 @@ efx_mae_match_spec_fini(
        __in                            efx_mae_match_spec_t *spec);
 
 typedef enum efx_mae_field_id_e {
+       /*
+        * Fields which can be set by efx_mae_match_spec_field_set()
+        * or by using dedicated field-specific helper APIs.
+        */
        EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR = 0,
        EFX_MAE_FIELD_ETHER_TYPE_BE,
        EFX_MAE_FIELD_ETH_SADDR_BE,
@@ -4140,6 +4144,12 @@ typedef enum efx_mae_field_id_e {
        EFX_MAE_FIELD_ENC_VNET_ID_BE,
        EFX_MAE_FIELD_OUTER_RULE_ID,
 
+       /* Single bits which can be set by efx_mae_match_spec_bit_set(). */
+       EFX_MAE_FIELD_HAS_OVLAN,
+       EFX_MAE_FIELD_HAS_IVLAN,
+       EFX_MAE_FIELD_ENC_HAS_OVLAN,
+       EFX_MAE_FIELD_ENC_HAS_IVLAN,
+
        EFX_MAE_FIELD_NIDS
 } efx_mae_field_id_t;
 
@@ -4198,6 +4208,14 @@ efx_mae_match_spec_field_set(
        __in                            size_t mask_size,
        __in_bcount(mask_size)          const uint8_t *mask);
 
+/* The corresponding mask will be set to B_TRUE. */
+LIBEFX_API
+extern __checkReturn                   efx_rc_t
+efx_mae_match_spec_bit_set(
+       __in                            efx_mae_match_spec_t *spec,
+       __in                            efx_mae_field_id_t field_id,
+       __in                            boolean_t value);
+
 /* If the mask argument is NULL, the API will use full mask by default. */
 LIBEFX_API
 extern __checkReturn                   efx_rc_t
index 4a51317..8b63cfb 100644 (file)
@@ -1720,7 +1720,8 @@ 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];
+               uint8_t                 action[
+                                           MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN];
                uint8_t                 outer[MAE_ENC_FIELD_PAIRS_LEN];
        } emms_mask_value_pairs;
 };
index c178421..5697488 100644 (file)
@@ -465,6 +465,10 @@ typedef enum efx_mae_field_cap_id_e {
        EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
        EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
        EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
+       EFX_MAE_FIELD_ID_HAS_OVLAN = MAE_FIELD_HAS_OVLAN,
+       EFX_MAE_FIELD_ID_HAS_IVLAN = MAE_FIELD_HAS_IVLAN,
+       EFX_MAE_FIELD_ID_ENC_HAS_OVLAN = MAE_FIELD_ENC_HAS_OVLAN,
+       EFX_MAE_FIELD_ID_ENC_HAS_IVLAN = MAE_FIELD_ENC_HAS_IVLAN,
 
        EFX_MAE_FIELD_CAP_NIDS
 } efx_mae_field_cap_id_t;
@@ -591,6 +595,65 @@ static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
 
 #undef EFX_MAE_MV_DESC_ALT
 #undef EFX_MAE_MV_DESC
+};
+
+/*
+ * The following structure is a means to describe an MAE bit.
+ * The information in it is meant to be used internally by
+ * APIs for addressing a given flag in a mask-value pairs
+ * structure and for validation purposes.
+ */
+typedef struct efx_mae_mv_bit_desc_s {
+       /*
+        * Arrays using this struct are indexed by field IDs.
+        * Fields which aren't meant to be referenced by these
+        * arrays comprise gaps (invalid entries). Below field
+        * helps to identify such entries.
+        */
+       boolean_t                       emmbd_entry_is_valid;
+       efx_mae_field_cap_id_t          emmbd_bit_cap_id;
+       size_t                          emmbd_value_ofst;
+       unsigned int                    emmbd_value_lbn;
+       size_t                          emmbd_mask_ofst;
+       unsigned int                    emmbd_mask_lbn;
+} efx_mae_mv_bit_desc_t;
+
+static const efx_mae_mv_bit_desc_t __efx_mae_outer_rule_mv_bit_desc_set[] = {
+#define        EFX_MAE_MV_BIT_DESC(_name)                                      \
+       [EFX_MAE_FIELD_##_name] =                                       \
+       {                                                               \
+               B_TRUE,                                                 \
+               EFX_MAE_FIELD_ID_##_name,                               \
+               MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
+               MAE_ENC_FIELD_PAIRS_##_name##_LBN,                      \
+               MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
+               MAE_ENC_FIELD_PAIRS_##_name##_MASK_LBN,                 \
+       }
+
+       EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
+       EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
+
+#undef EFX_MAE_MV_BIT_DESC
+};
+
+static const efx_mae_mv_bit_desc_t __efx_mae_action_rule_mv_bit_desc_set[] = {
+#define        EFX_MAE_MV_BIT_DESC(_name)                                      \
+       [EFX_MAE_FIELD_##_name] =                                       \
+       {                                                               \
+               B_TRUE,                                                 \
+               EFX_MAE_FIELD_ID_##_name,                               \
+               MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_OFST,               \
+               MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,            \
+               MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK_OFST,          \
+               MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN,            \
+       }
+
+       EFX_MAE_MV_BIT_DESC(HAS_OVLAN),
+       EFX_MAE_MV_BIT_DESC(HAS_IVLAN),
+       EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN),
+       EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN),
+
+#undef EFX_MAE_MV_BIT_DESC
 };
 
        __checkReturn                   efx_rc_t
@@ -789,6 +852,70 @@ 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);
+}
+
+       __checkReturn                   efx_rc_t
+efx_mae_match_spec_bit_set(
+       __in                            efx_mae_match_spec_t *spec,
+       __in                            efx_mae_field_id_t field_id,
+       __in                            boolean_t value)
+{
+       const efx_mae_mv_bit_desc_t *bit_descp;
+       unsigned int bit_desc_set_nentries;
+       unsigned int byte_idx;
+       unsigned int bit_idx;
+       uint8_t *mvp;
+       efx_rc_t rc;
+
+       switch (spec->emms_type) {
+       case EFX_MAE_RULE_OUTER:
+               bit_desc_set_nentries =
+                   EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
+               bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id];
+               mvp = spec->emms_mask_value_pairs.outer;
+               break;
+       case EFX_MAE_RULE_ACTION:
+               bit_desc_set_nentries =
+                   EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
+               bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id];
+               mvp = spec->emms_mask_value_pairs.action;
+               break;
+       default:
+               rc = ENOTSUP;
+               goto fail1;
+       }
+
+       if ((unsigned int)field_id >= bit_desc_set_nentries) {
+               rc = EINVAL;
+               goto fail2;
+       }
+
+       if (bit_descp->emmbd_entry_is_valid == B_FALSE) {
+               rc = EINVAL;
+               goto fail3;
+       }
+
+       byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8;
+       bit_idx = bit_descp->emmbd_value_lbn % 8;
+
+       if (value != B_FALSE)
+               mvp[byte_idx] |= (1U << bit_idx);
+       else
+               mvp[byte_idx] &= ~(1U << bit_idx);
+
+       byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8;
+       bit_idx = bit_descp->emmbd_mask_lbn % 8;
+       mvp[byte_idx] |= (1U << bit_idx);
+
+       return (0);
+
 fail3:
        EFSYS_PROBE(fail3);
 fail2:
@@ -905,6 +1032,8 @@ efx_mae_match_spec_is_valid(
        const efx_mae_field_cap_t *field_caps;
        const efx_mae_mv_desc_t *desc_setp;
        unsigned int desc_set_nentries;
+       const efx_mae_mv_bit_desc_t *bit_desc_setp;
+       unsigned int bit_desc_set_nentries;
        boolean_t is_valid = B_TRUE;
        efx_mae_field_id_t field_id;
        const uint8_t *mvp;
@@ -915,6 +1044,9 @@ efx_mae_match_spec_is_valid(
                desc_setp = __efx_mae_outer_rule_mv_desc_set;
                desc_set_nentries =
                    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
+               bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
+               bit_desc_set_nentries =
+                   EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
                mvp = spec->emms_mask_value_pairs.outer;
                break;
        case EFX_MAE_RULE_ACTION:
@@ -922,6 +1054,9 @@ efx_mae_match_spec_is_valid(
                desc_setp = __efx_mae_action_rule_mv_desc_set;
                desc_set_nentries =
                    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
+               bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
+               bit_desc_set_nentries =
+                   EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
                mvp = spec->emms_mask_value_pairs.action;
                break;
        default:
@@ -989,6 +1124,48 @@ efx_mae_match_spec_is_valid(
                        break;
                }
 
+               if (is_valid == B_FALSE)
+                       return (B_FALSE);
+       }
+
+       for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
+            ++field_id) {
+               const efx_mae_mv_bit_desc_t *bit_descp =
+                   &bit_desc_setp[field_id];
+               unsigned int byte_idx =
+                   bit_descp->emmbd_mask_ofst +
+                   bit_descp->emmbd_mask_lbn / 8;
+               unsigned int bit_idx =
+                   bit_descp->emmbd_mask_lbn % 8;
+               efx_mae_field_cap_id_t bit_cap_id =
+                   bit_descp->emmbd_bit_cap_id;
+
+               if (bit_descp->emmbd_entry_is_valid == B_FALSE)
+                       continue; /* Skip array gap */
+
+               if ((unsigned int)bit_cap_id >= field_ncaps) {
+                       /* No capability for this bit = unsupported. */
+                       is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
+                       if (is_valid == B_FALSE)
+                               break;
+                       else
+                               continue;
+               }
+
+               switch (field_caps[bit_cap_id].emfc_support) {
+               case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
+                       is_valid = B_TRUE;
+                       break;
+               case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
+                       is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0);
+                       break;
+               case MAE_FIELD_SUPPORTED_MATCH_NEVER:
+               case MAE_FIELD_UNSUPPORTED:
+               default:
+                       is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0);
+                       break;
+               }
+
                if (is_valid == B_FALSE)
                        break;
        }
@@ -1542,6 +1719,8 @@ efx_mae_match_specs_class_cmp(
        const efx_mae_field_cap_t *field_caps;
        const efx_mae_mv_desc_t *desc_setp;
        unsigned int desc_set_nentries;
+       const efx_mae_mv_bit_desc_t *bit_desc_setp;
+       unsigned int bit_desc_set_nentries;
        boolean_t have_same_class = B_TRUE;
        efx_mae_field_id_t field_id;
        const uint8_t *mvpl;
@@ -1554,6 +1733,9 @@ efx_mae_match_specs_class_cmp(
                desc_setp = __efx_mae_outer_rule_mv_desc_set;
                desc_set_nentries =
                    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
+               bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set;
+               bit_desc_set_nentries =
+                   EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set);
                mvpl = left->emms_mask_value_pairs.outer;
                mvpr = right->emms_mask_value_pairs.outer;
                break;
@@ -1562,6 +1744,9 @@ efx_mae_match_specs_class_cmp(
                desc_setp = __efx_mae_action_rule_mv_desc_set;
                desc_set_nentries =
                    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
+               bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set;
+               bit_desc_set_nentries =
+                   EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set);
                mvpl = left->emms_mask_value_pairs.action;
                mvpr = right->emms_mask_value_pairs.action;
                break;
@@ -1634,6 +1819,52 @@ efx_mae_match_specs_class_cmp(
                }
        }
 
+       if (have_same_class == B_FALSE)
+               goto done;
+
+       for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries;
+            ++field_id) {
+               const efx_mae_mv_bit_desc_t *bit_descp =
+                   &bit_desc_setp[field_id];
+               efx_mae_field_cap_id_t bit_cap_id =
+                   bit_descp->emmbd_bit_cap_id;
+               unsigned int byte_idx;
+               unsigned int bit_idx;
+
+               if (bit_descp->emmbd_entry_is_valid == B_FALSE)
+                       continue; /* Skip array gap */
+
+               if ((unsigned int)bit_cap_id >= field_ncaps)
+                       break;
+
+               byte_idx =
+                   bit_descp->emmbd_mask_ofst +
+                   bit_descp->emmbd_mask_lbn / 8;
+               bit_idx =
+                   bit_descp->emmbd_mask_lbn % 8;
+
+               if (field_caps[bit_cap_id].emfc_mask_affects_class &&
+                   (mvpl[byte_idx] & (1U << bit_idx)) !=
+                   (mvpr[byte_idx] & (1U << bit_idx))) {
+                       have_same_class = B_FALSE;
+                       break;
+               }
+
+               byte_idx =
+                   bit_descp->emmbd_value_ofst +
+                   bit_descp->emmbd_value_lbn / 8;
+               bit_idx =
+                   bit_descp->emmbd_value_lbn % 8;
+
+               if (field_caps[bit_cap_id].emfc_match_affects_class &&
+                   (mvpl[byte_idx] & (1U << bit_idx)) !=
+                   (mvpr[byte_idx] & (1U << bit_idx))) {
+                       have_same_class = B_FALSE;
+                       break;
+               }
+       }
+
+done:
        *have_same_classp = have_same_class;
 
        return (0);
@@ -2282,10 +2513,10 @@ efx_mae_action_rule_insert(
         * MCDI request and are thus safe to be copied directly to the buffer.
         */
        EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
-           MAE_FIELD_MASK_VALUE_PAIRS_LEN);
+           MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
        offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
        memcpy(payload + offset, spec->emms_mask_value_pairs.action,
-           MAE_FIELD_MASK_VALUE_PAIRS_LEN);
+           MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN);
 
        efx_mcdi_execute(enp, &req);
 
index 5e724fd..75da5aa 100644 (file)
@@ -106,6 +106,7 @@ INTERNAL {
        efx_mae_fini;
        efx_mae_get_limits;
        efx_mae_init;
+       efx_mae_match_spec_bit_set;
        efx_mae_match_spec_field_set;
        efx_mae_match_spec_fini;
        efx_mae_match_spec_init;