New upstream version 18.08
[deb_dpdk.git] / drivers / net / sfc / base / ef10_filter.c
index 27b5998..ae87285 100644 (file)
@@ -7,7 +7,7 @@
 #include "efx.h"
 #include "efx_impl.h"
 
-#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
+#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
 
 #if EFSYS_OPT_FILTER
 
@@ -95,7 +95,8 @@ ef10_filter_init(
        ef10_filter_table_t *eftp;
 
        EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
-                   enp->en_family == EFX_FAMILY_MEDFORD);
+           enp->en_family == EFX_FAMILY_MEDFORD ||
+           enp->en_family == EFX_FAMILY_MEDFORD2);
 
 #define        MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match))
        EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST ==
@@ -118,6 +119,10 @@ ef10_filter_init(
            MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN));
        EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
            MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO));
+       EFX_STATIC_ASSERT(EFX_FILTER_MATCH_VNI_OR_VSID ==
+           MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID));
+       EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_LOC_MAC ==
+           MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC));
        EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST ==
            MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST));
        EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST ==
@@ -150,7 +155,8 @@ ef10_filter_fini(
        __in            efx_nic_t *enp)
 {
        EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
-                   enp->en_family == EFX_FAMILY_MEDFORD);
+           enp->en_family == EFX_FAMILY_MEDFORD ||
+           enp->en_family == EFX_FAMILY_MEDFORD2);
 
        if (enp->en_filter.ef_ef10_filter_table != NULL) {
                EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t),
@@ -166,17 +172,24 @@ efx_mcdi_filter_op_add(
        __inout         ef10_filter_handle_t *handle)
 {
        efx_mcdi_req_t req;
-       uint8_t payload[MAX(MC_CMD_FILTER_OP_EXT_IN_LEN,
+       uint8_t payload[MAX(MC_CMD_FILTER_OP_V3_IN_LEN,
                            MC_CMD_FILTER_OP_EXT_OUT_LEN)];
+       efx_filter_match_flags_t match_flags;
        efx_rc_t rc;
 
        memset(payload, 0, sizeof (payload));
        req.emr_cmd = MC_CMD_FILTER_OP;
        req.emr_in_buf = payload;
-       req.emr_in_length = MC_CMD_FILTER_OP_EXT_IN_LEN;
+       req.emr_in_length = MC_CMD_FILTER_OP_V3_IN_LEN;
        req.emr_out_buf = payload;
        req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
 
+       /*
+        * Remove match flag for encapsulated filters that does not correspond
+        * to the MCDI match flags
+        */
+       match_flags = spec->efs_match_flags & ~EFX_FILTER_MATCH_ENCAP_TYPE;
+
        switch (filter_op) {
        case MC_CMD_FILTER_OP_IN_OP_REPLACE:
                MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO,
@@ -197,11 +210,16 @@ efx_mcdi_filter_op_add(
        MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_PORT_ID,
            EVB_PORT_ID_ASSIGNED);
        MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_MATCH_FIELDS,
-           spec->efs_match_flags);
-       MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
-           MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST);
-       MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE,
-           spec->efs_dmaq_id);
+           match_flags);
+       if (spec->efs_dmaq_id == EFX_FILTER_SPEC_RX_DMAQ_ID_DROP) {
+               MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
+                   MC_CMD_FILTER_OP_EXT_IN_RX_DEST_DROP);
+       } else {
+               MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
+                   MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST);
+               MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE,
+                   spec->efs_dmaq_id);
+       }
 
 #if EFSYS_OPT_RX_SCALE
        if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) {
@@ -290,18 +308,45 @@ efx_mcdi_filter_op_add(
                        rc = EINVAL;
                        goto fail2;
                }
+
+               memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_VNI_OR_VSID),
+                   spec->efs_vni_or_vsid, EFX_VNI_OR_VSID_LEN);
+
+               memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_IFRM_DST_MAC),
+                   spec->efs_ifrm_loc_mac, EFX_MAC_ADDR_LEN);
+       }
+
+       /*
+        * Set the "MARK" or "FLAG" action for all packets matching this filter
+        * if necessary (only useful with equal stride packed stream Rx mode
+        * which provide the information in pseudo-header).
+        * These actions require MC_CMD_FILTER_OP_V3_IN msgrequest.
+        */
+       if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
+           (spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG)) {
+               rc = EINVAL;
+               goto fail3;
+       }
+       if (spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) {
+               MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_ACTION,
+                   MC_CMD_FILTER_OP_V3_IN_MATCH_ACTION_MARK);
+               MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_MARK_VALUE,
+                   spec->efs_mark);
+       } else if (spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) {
+               MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_ACTION,
+                   MC_CMD_FILTER_OP_V3_IN_MATCH_ACTION_FLAG);
        }
 
        efx_mcdi_execute(enp, &req);
 
        if (req.emr_rc != 0) {
                rc = req.emr_rc;
-               goto fail3;
+               goto fail4;
        }
 
        if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
                rc = EMSGSIZE;
-               goto fail4;
+               goto fail5;
        }
 
        handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_LO);
@@ -309,6 +354,8 @@ efx_mcdi_filter_op_add(
 
        return (0);
 
+fail5:
+       EFSYS_PROBE(fail5);
 fail4:
        EFSYS_PROBE(fail4);
 fail3:
@@ -413,6 +460,12 @@ ef10_filter_equal(
                return (B_FALSE);
        if (left->efs_encap_type != right->efs_encap_type)
                return (B_FALSE);
+       if (memcmp(left->efs_vni_or_vsid, right->efs_vni_or_vsid,
+           EFX_VNI_OR_VSID_LEN))
+               return (B_FALSE);
+       if (memcmp(left->efs_ifrm_loc_mac, right->efs_ifrm_loc_mac,
+           EFX_MAC_ADDR_LEN))
+               return (B_FALSE);
 
        return (B_TRUE);
 
@@ -495,7 +548,8 @@ ef10_filter_restore(
        efx_rc_t rc;
 
        EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
-                   enp->en_family == EFX_FAMILY_MEDFORD);
+           enp->en_family == EFX_FAMILY_MEDFORD ||
+           enp->en_family == EFX_FAMILY_MEDFORD2);
 
        for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) {
 
@@ -570,7 +624,8 @@ ef10_filter_add_internal(
        boolean_t locked = B_FALSE;
 
        EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
-                   enp->en_family == EFX_FAMILY_MEDFORD);
+           enp->en_family == EFX_FAMILY_MEDFORD ||
+           enp->en_family == EFX_FAMILY_MEDFORD2);
 
        hash = ef10_filter_hash(spec);
 
@@ -842,7 +897,8 @@ ef10_filter_delete(
        boolean_t locked = B_FALSE;
 
        EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
-                   enp->en_family == EFX_FAMILY_MEDFORD);
+           enp->en_family == EFX_FAMILY_MEDFORD ||
+           enp->en_family == EFX_FAMILY_MEDFORD2);
 
        hash = ef10_filter_hash(spec);
 
@@ -890,6 +946,7 @@ efx_mcdi_get_parser_disp_info(
        __in                            efx_nic_t *enp,
        __out_ecount(buffer_length)     uint32_t *buffer,
        __in                            size_t buffer_length,
+       __in                            boolean_t encap,
        __out                           size_t *list_lengthp)
 {
        efx_mcdi_req_t req;
@@ -906,7 +963,8 @@ efx_mcdi_get_parser_disp_info(
        req.emr_out_buf = payload;
        req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;
 
-       MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP,
+       MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, encap ?
+           MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_ENCAP_RX_MATCHES :
            MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
 
        efx_mcdi_execute(enp, &req);
@@ -966,28 +1024,76 @@ ef10_filter_supported_filters(
        __in                            size_t buffer_length,
        __out                           size_t *list_lengthp)
 {
-
+       efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
        size_t mcdi_list_length;
+       size_t mcdi_encap_list_length;
        size_t list_length;
        uint32_t i;
+       uint32_t next_buf_idx;
+       size_t next_buf_length;
        efx_rc_t rc;
+       boolean_t no_space = B_FALSE;
        efx_filter_match_flags_t all_filter_flags =
            (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST |
            EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT |
            EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
            EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
            EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
+           EFX_FILTER_MATCH_VNI_OR_VSID |
+           EFX_FILTER_MATCH_IFRM_LOC_MAC |
+           EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
+           EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
+           EFX_FILTER_MATCH_ENCAP_TYPE |
            EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
            EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
 
-       rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length,
-                                           &mcdi_list_length);
+       /*
+        * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
+        * list of supported filters for ordinary packets, and then another to
+        * get the list of supported filters for encapsulated packets. To
+        * distinguish the second list from the first, the
+        * EFX_FILTER_MATCH_ENCAP_TYPE flag is added to each filter for
+        * encapsulated packets.
+        */
+       rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
+           &mcdi_list_length);
        if (rc != 0) {
-               if (rc == ENOSPC) {
-                       /* Pass through mcdi_list_length for the list length */
-                       *list_lengthp = mcdi_list_length;
+               if (rc == ENOSPC)
+                       no_space = B_TRUE;
+               else
+                       goto fail1;
+       }
+
+       if (no_space) {
+               next_buf_idx = 0;
+               next_buf_length = 0;
+       } else {
+               EFSYS_ASSERT(mcdi_list_length <= buffer_length);
+               next_buf_idx = mcdi_list_length;
+               next_buf_length = buffer_length - mcdi_list_length;
+       }
+
+       if (encp->enc_tunnel_encapsulations_supported != 0) {
+               rc = efx_mcdi_get_parser_disp_info(enp, &buffer[next_buf_idx],
+                   next_buf_length, B_TRUE, &mcdi_encap_list_length);
+               if (rc != 0) {
+                       if (rc == ENOSPC)
+                               no_space = B_TRUE;
+                       else
+                               goto fail2;
+               } else {
+                       for (i = next_buf_idx;
+                           i < next_buf_idx + mcdi_encap_list_length; i++)
+                               buffer[i] |= EFX_FILTER_MATCH_ENCAP_TYPE;
                }
-               goto fail1;
+       } else {
+               mcdi_encap_list_length = 0;
+       }
+
+       if (no_space) {
+               *list_lengthp = mcdi_list_length + mcdi_encap_list_length;
+               rc = ENOSPC;
+               goto fail3;
        }
 
        /*
@@ -1000,9 +1106,10 @@ ef10_filter_supported_filters(
         * of the matches is preserved as they are ordered from highest to
         * lowest priority.
         */
-       EFSYS_ASSERT(mcdi_list_length <= buffer_length);
+       EFSYS_ASSERT(mcdi_list_length + mcdi_encap_list_length <=
+           buffer_length);
        list_length = 0;
-       for (i = 0; i < mcdi_list_length; i++) {
+       for (i = 0; i < mcdi_list_length + mcdi_encap_list_length; i++) {
                if ((buffer[i] & ~all_filter_flags) == 0) {
                        buffer[list_length] = buffer[i];
                        list_length++;
@@ -1013,6 +1120,10 @@ ef10_filter_supported_filters(
 
        return (0);
 
+fail3:
+       EFSYS_PROBE(fail3);
+fail2:
+       EFSYS_PROBE(fail2);
 fail1:
        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 
@@ -1636,4 +1747,4 @@ ef10_filter_default_rxq_clear(
 
 #endif /* EFSYS_OPT_FILTER */
 
-#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
+#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */