net/sfc/base: add Medford2 head-of-line blocking stats
[dpdk.git] / drivers / net / sfc / base / ef10_nic.c
index cd871c4..7dbf843 100644 (file)
@@ -996,7 +996,7 @@ ef10_get_datapath_caps(
        efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
        efx_mcdi_req_t req;
        uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN,
-                           MC_CMD_GET_CAPABILITIES_V4_OUT_LEN)];
+                           MC_CMD_GET_CAPABILITIES_V5_OUT_LEN)];
        efx_rc_t rc;
 
        if ((rc = ef10_mcdi_get_pf_count(enp, &encp->enc_hw_pf_count)) != 0)
@@ -1008,7 +1008,7 @@ ef10_get_datapath_caps(
        req.emr_in_buf = payload;
        req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN;
        req.emr_out_buf = payload;
-       req.emr_out_length = MC_CMD_GET_CAPABILITIES_V4_OUT_LEN;
+       req.emr_out_length = MC_CMD_GET_CAPABILITIES_V5_OUT_LEN;
 
        efx_mcdi_execute_quiet(enp, &req);
 
@@ -1041,6 +1041,12 @@ ef10_get_datapath_caps(
        }
        encp->enc_rx_prefix_size = 14;
 
+       /* Check if the firmware supports additional RSS modes */
+       if (CAP_FLAGS1(req, ADDITIONAL_RSS_MODES))
+               encp->enc_rx_scale_additional_modes_supported = B_TRUE;
+       else
+               encp->enc_rx_scale_additional_modes_supported = B_FALSE;
+
        /* Check if the firmware supports TSO */
        if (CAP_FLAGS1(req, TX_TSO))
                encp->enc_fw_assisted_tso_enabled = B_TRUE;
@@ -1057,6 +1063,12 @@ ef10_get_datapath_caps(
                encp->enc_fw_assisted_tso_v2_n_contexts = 0;
        }
 
+       /* Check if the firmware supports FATSOv2 encap */
+       if (CAP_FLAGS2(req, TX_TSO_V2_ENCAP))
+               encp->enc_fw_assisted_tso_v2_encap_enabled = B_TRUE;
+       else
+               encp->enc_fw_assisted_tso_v2_encap_enabled = B_FALSE;
+
        /* Check if the firmware has vadapter/vport/vswitch support */
        if (CAP_FLAGS1(req, EVB))
                encp->enc_datapath_cap_evb = B_TRUE;
@@ -1102,6 +1114,18 @@ ef10_get_datapath_caps(
        else
                encp->enc_rx_var_packed_stream_supported = B_FALSE;
 
+       /* Check if the firmware supports equal stride super-buffer mode */
+       if (CAP_FLAGS2(req, EQUAL_STRIDE_SUPER_BUFFER))
+               encp->enc_rx_es_super_buffer_supported = B_TRUE;
+       else
+               encp->enc_rx_es_super_buffer_supported = B_FALSE;
+
+       /* Check if the firmware supports FW subvariant w/o Tx checksumming */
+       if (CAP_FLAGS2(req, FW_SUBVARIANT_NO_TX_CSUM))
+               encp->enc_fw_subvariant_no_tx_csum_supported = B_TRUE;
+       else
+               encp->enc_fw_subvariant_no_tx_csum_supported = B_FALSE;
+
        /* Check if the firmware supports set mac with running filters */
        if (CAP_FLAGS1(req, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED))
                encp->enc_allow_set_mac_with_installed_filters = B_TRUE;
@@ -1221,11 +1245,86 @@ ef10_get_datapath_caps(
        else
                encp->enc_fec_counters = B_FALSE;
 
+       /* Check if the firmware provides head-of-line blocking counters */
+       if (CAP_FLAGS2(req, RXDP_HLB_IDLE))
+               encp->enc_hlb_counters = B_TRUE;
+       else
+               encp->enc_hlb_counters = B_FALSE;
+
+       if (CAP_FLAGS1(req, RX_RSS_LIMITED)) {
+               /* Only one exclusive RSS context is available per port. */
+               encp->enc_rx_scale_max_exclusive_contexts = 1;
+
+               switch (enp->en_family) {
+               case EFX_FAMILY_MEDFORD2:
+                       encp->enc_rx_scale_hash_alg_mask =
+                           (1U << EFX_RX_HASHALG_TOEPLITZ);
+                       break;
+
+               case EFX_FAMILY_MEDFORD:
+               case EFX_FAMILY_HUNTINGTON:
+                       /*
+                        * Packed stream firmware variant maintains a
+                        * non-standard algorithm for hash computation.
+                        * It implies explicit XORing together
+                        * source + destination IP addresses (or last
+                        * four bytes in the case of IPv6) and using the
+                        * resulting value as the input to a Toeplitz hash.
+                        */
+                       encp->enc_rx_scale_hash_alg_mask =
+                           (1U << EFX_RX_HASHALG_PACKED_STREAM);
+                       break;
+
+               default:
+                       rc = EINVAL;
+                       goto fail5;
+               }
+
+               /* Port numbers cannot contribute to the hash value */
+               encp->enc_rx_scale_l4_hash_supported = B_FALSE;
+       } else {
+               /*
+                * Maximum number of exclusive RSS contexts.
+                * EF10 hardware supports 64 in total, but 6 are reserved
+                * for shared contexts. They are a global resource so
+                * not all may be available.
+                */
+               encp->enc_rx_scale_max_exclusive_contexts = 64 - 6;
+
+               encp->enc_rx_scale_hash_alg_mask =
+                   (1U << EFX_RX_HASHALG_TOEPLITZ);
+
+               /*
+                * It is possible to use port numbers as
+                * the input data for hash computation.
+                */
+               encp->enc_rx_scale_l4_hash_supported = B_TRUE;
+       }
+       /* Check if the firmware supports "FLAG" and "MARK" filter actions */
+       if (CAP_FLAGS2(req, FILTER_ACTION_FLAG))
+               encp->enc_filter_action_flag_supported = B_TRUE;
+       else
+               encp->enc_filter_action_flag_supported = B_FALSE;
+
+       if (CAP_FLAGS2(req, FILTER_ACTION_MARK))
+               encp->enc_filter_action_mark_supported = B_TRUE;
+       else
+               encp->enc_filter_action_mark_supported = B_FALSE;
+
+       /* Get maximum supported value for "MARK" filter action */
+       if (req.emr_out_length_used >= MC_CMD_GET_CAPABILITIES_V5_OUT_LEN)
+               encp->enc_filter_action_mark_max = MCDI_OUT_DWORD(req,
+                   GET_CAPABILITIES_V5_OUT_FILTER_ACTION_MARK_MAX);
+       else
+               encp->enc_filter_action_mark_max = 0;
+
 #undef CAP_FLAGS1
 #undef CAP_FLAGS2
 
        return (0);
 
+fail5:
+       EFSYS_PROBE(fail5);
 fail4:
        EFSYS_PROBE(fail4);
 fail3:
@@ -1345,11 +1444,29 @@ static struct ef10_external_port_map_s {
         */
        {
                EFX_FAMILY_HUNTINGTON,
-               (1 << TLV_PORT_MODE_10G) |
-               (1 << TLV_PORT_MODE_10G_10G) |
-               (1 << TLV_PORT_MODE_10G_10G_10G_10G),
-               1,
-               1
+               (1U << TLV_PORT_MODE_10G) |                     /* mode 0 */
+               (1U << TLV_PORT_MODE_10G_10G) |                 /* mode 2 */
+               (1U << TLV_PORT_MODE_10G_10G_10G_10G),          /* mode 4 */
+               1,      /* ports per cage */
+               1       /* first cage */
+       },
+       /*
+        * Modes which for Huntington identify a chip variant where 2
+        * adjacent port numbers map to each cage.
+        * SFN7x42Q (Monza):
+        *      port 0 -> cage 1
+        *      port 1 -> cage 1
+        *      port 2 -> cage 2
+        *      port 3 -> cage 2
+        */
+       {
+               EFX_FAMILY_HUNTINGTON,
+               (1U << TLV_PORT_MODE_40G) |                     /* mode 1 */
+               (1U << TLV_PORT_MODE_40G_40G) |                 /* mode 3 */
+               (1U << TLV_PORT_MODE_40G_10G_10G) |             /* mode 6 */
+               (1U << TLV_PORT_MODE_10G_10G_40G),              /* mode 7 */
+               2,      /* ports per cage */
+               1       /* first cage */
        },
        /*
         * Modes that on Medford allocate each port number to a separate
@@ -1361,49 +1478,120 @@ static struct ef10_external_port_map_s {
         */
        {
                EFX_FAMILY_MEDFORD,
-               (1 << TLV_PORT_MODE_10G) |
-               (1 << TLV_PORT_MODE_10G_10G),
-               1,
-               1
+               (1U << TLV_PORT_MODE_10G) |                     /* mode 0 */
+               (1U << TLV_PORT_MODE_10G_10G),                  /* mode 2 */
+               1,      /* ports per cage */
+               1       /* first cage */
        },
        /*
-        * Modes which for Huntington identify a chip variant where 2
-        * adjacent port numbers map to each cage.
-        * SFN7x42Q (Monza):
+        * Modes that on Medford allocate 2 adjacent port numbers to each
+        * cage.
         *      port 0 -> cage 1
         *      port 1 -> cage 1
         *      port 2 -> cage 2
         *      port 3 -> cage 2
         */
        {
-               EFX_FAMILY_HUNTINGTON,
-               (1 << TLV_PORT_MODE_40G) |
-               (1 << TLV_PORT_MODE_40G_40G) |
-               (1 << TLV_PORT_MODE_40G_10G_10G) |
-               (1 << TLV_PORT_MODE_10G_10G_40G),
-               2,
-               1
+               EFX_FAMILY_MEDFORD,
+               (1U << TLV_PORT_MODE_40G) |                     /* mode 1 */
+               (1U << TLV_PORT_MODE_40G_40G) |                 /* mode 3 */
+               (1U << TLV_PORT_MODE_40G_10G_10G) |             /* mode 6 */
+               (1U << TLV_PORT_MODE_10G_10G_40G) |             /* mode 7 */
+               /* Do not use 10G_10G_10G_10G_Q1_Q2 (see bug63270) */
+               (1U << TLV_PORT_MODE_10G_10G_10G_10G_Q1_Q2),    /* mode 9 */
+               2,      /* ports per cage */
+               1       /* first cage */
        },
        /*
-        * Modes that on Medford allocate 2 adjacent port numbers to each
-        * cage.
+        * Modes that on Medford allocate 4 adjacent port numbers to each
+        * connector, starting on cage 1.
         *      port 0 -> cage 1
         *      port 1 -> cage 1
+        *      port 2 -> cage 1
+        *      port 3 -> cage 1
+        */
+       {
+               EFX_FAMILY_MEDFORD,
+               (1U << TLV_PORT_MODE_10G_10G_10G_10G_Q) |       /* mode 5 */
+               /* Do not use 10G_10G_10G_10G_Q1 (see bug63270) */
+               (1U << TLV_PORT_MODE_10G_10G_10G_10G_Q1),       /* mode 4 */
+               4,      /* ports per cage */
+               1       /* first cage */
+       },
+       /*
+        * Modes that on Medford allocate 4 adjacent port numbers to each
+        * connector, starting on cage 2.
+        *      port 0 -> cage 2
+        *      port 1 -> cage 2
         *      port 2 -> cage 2
         *      port 3 -> cage 2
         */
        {
                EFX_FAMILY_MEDFORD,
-               (1 << TLV_PORT_MODE_40G) |
-               (1 << TLV_PORT_MODE_40G_40G) |
-               (1 << TLV_PORT_MODE_40G_10G_10G) |
-               (1 << TLV_PORT_MODE_10G_10G_40G) |
-               (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q1_Q2),
-               2,
-               1
+               (1U << TLV_PORT_MODE_10G_10G_10G_10G_Q2),       /* mode 8 */
+               4,      /* ports per cage */
+               2       /* first cage */
        },
        /*
-        * Modes that on Medford allocate 4 adjacent port numbers to each
+        * Modes that on Medford2 allocate each port number to a separate
+        * cage.
+        *      port 0 -> cage 1
+        *      port 1 -> cage 2
+        *      port 2 -> cage 3
+        *      port 3 -> cage 4
+        */
+       {
+               EFX_FAMILY_MEDFORD2,
+               (1U << TLV_PORT_MODE_1x1_NA) |                  /* mode 0 */
+               (1U << TLV_PORT_MODE_1x4_NA) |                  /* mode 1 */
+               (1U << TLV_PORT_MODE_1x1_1x1) |                 /* mode 2 */
+               (1U << TLV_PORT_MODE_1x2_NA) |                  /* mode 10 */
+               (1U << TLV_PORT_MODE_1x2_1x2) |                 /* mode 12 */
+               (1U << TLV_PORT_MODE_1x4_1x2) |                 /* mode 15 */
+               (1U << TLV_PORT_MODE_1x2_1x4),                  /* mode 16 */
+               1,      /* ports per cage */
+               1       /* first cage */
+       },
+       /*
+        * FIXME: Some port modes are not representable in this mapping:
+        *  - TLV_PORT_MODE_1x2_2x1 (mode 17):
+        *      port 0 -> cage 1
+        *      port 1 -> cage 2
+        *      port 2 -> cage 2
+        */
+       /*
+        * Modes that on Medford2 allocate 2 adjacent port numbers to each
+        * cage, starting on cage 1.
+        *      port 0 -> cage 1
+        *      port 1 -> cage 1
+        *      port 2 -> cage 2
+        *      port 3 -> cage 2
+        */
+       {
+               EFX_FAMILY_MEDFORD2,
+               (1U << TLV_PORT_MODE_1x4_1x4) |                 /* mode 3 */
+               (1U << TLV_PORT_MODE_2x1_2x1) |                 /* mode 4 */
+               (1U << TLV_PORT_MODE_1x4_2x1) |                 /* mode 6 */
+               (1U << TLV_PORT_MODE_2x1_1x4) |                 /* mode 7 */
+               (1U << TLV_PORT_MODE_2x2_NA) |                  /* mode 13 */
+               (1U << TLV_PORT_MODE_2x1_1x2),                  /* mode 18 */
+               2,      /* ports per cage */
+               1       /* first cage */
+       },
+       /*
+        * Modes that on Medford2 allocate 2 adjacent port numbers to each
+        * cage, starting on cage 2.
+        *      port 0 -> cage 2
+        *      port 1 -> cage 2
+        */
+       {
+               EFX_FAMILY_MEDFORD2,
+               (1U << TLV_PORT_MODE_NA_2x2),                   /* mode 14 */
+               2,      /* ports per cage */
+               2       /* first cage */
+       },
+       /*
+        * Modes that on Medford2 allocate 4 adjacent port numbers to each
         * connector, starting on cage 1.
         *      port 0 -> cage 1
         *      port 1 -> cage 1
@@ -1411,14 +1599,13 @@ static struct ef10_external_port_map_s {
         *      port 3 -> cage 1
         */
        {
-               EFX_FAMILY_MEDFORD,
-               (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) |
-               (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q1),
-               4,
-               1,
+               EFX_FAMILY_MEDFORD2,
+               (1U << TLV_PORT_MODE_4x1_NA),                   /* mode 5 */
+               4,      /* ports per cage */
+               1       /* first cage */
        },
        /*
-        * Modes that on Medford allocate 4 adjacent port numbers to each
+        * Modes that on Medford2 allocate 4 adjacent port numbers to each
         * connector, starting on cage 2.
         *      port 0 -> cage 2
         *      port 1 -> cage 2
@@ -1426,10 +1613,11 @@ static struct ef10_external_port_map_s {
         *      port 3 -> cage 2
         */
        {
-               EFX_FAMILY_MEDFORD,
-               (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2),
-               4,
-               2
+               EFX_FAMILY_MEDFORD2,
+               (1U << TLV_PORT_MODE_NA_4x1) |                  /* mode 8 */
+               (1U << TLV_PORT_MODE_NA_1x2),                   /* mode 11 */
+               4,      /* ports per cage */
+               2       /* first cage */
        },
 };
 
@@ -1606,13 +1794,6 @@ ef10_nic_board_cfg(
        /* Alignment for WPTR updates */
        encp->enc_rx_push_align = EF10_RX_WPTR_ALIGN;
 
-       /*
-        * Maximum number of exclusive RSS contexts. EF10 hardware supports 64
-        * in total, but 6 are reserved for shared contexts. They are a global
-        * resource so not all may be available.
-        */
-       encp->enc_rx_scale_max_exclusive_contexts = 64 - 6;
-
        encp->enc_tx_dma_desc_size_max = EFX_MASK32(ESF_DZ_RX_KER_BYTE_CNT);
        /* No boundary crossing limits */
        encp->enc_tx_dma_desc_boundary = 0;
@@ -2196,5 +2377,87 @@ fail1:
 
 #endif /* EFSYS_OPT_DIAG */
 
+#if EFSYS_OPT_FW_SUBVARIANT_AWARE
+
+       __checkReturn   efx_rc_t
+efx_mcdi_get_nic_global(
+       __in            efx_nic_t *enp,
+       __in            uint32_t key,
+       __out           uint32_t *valuep)
+{
+       efx_mcdi_req_t req;
+       uint8_t payload[MAX(MC_CMD_GET_NIC_GLOBAL_IN_LEN,
+                           MC_CMD_GET_NIC_GLOBAL_OUT_LEN)];
+       efx_rc_t rc;
+
+       (void) memset(payload, 0, sizeof (payload));
+       req.emr_cmd = MC_CMD_GET_NIC_GLOBAL;
+       req.emr_in_buf = payload;
+       req.emr_in_length = MC_CMD_GET_NIC_GLOBAL_IN_LEN;
+       req.emr_out_buf = payload;
+       req.emr_out_length = MC_CMD_GET_NIC_GLOBAL_OUT_LEN;
+
+       MCDI_IN_SET_DWORD(req, GET_NIC_GLOBAL_IN_KEY, key);
+
+       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_NIC_GLOBAL_OUT_LEN) {
+               rc = EMSGSIZE;
+               goto fail2;
+       }
+
+       *valuep = MCDI_OUT_DWORD(req, GET_NIC_GLOBAL_OUT_VALUE);
+
+       return (0);
+
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+       __checkReturn   efx_rc_t
+efx_mcdi_set_nic_global(
+       __in            efx_nic_t *enp,
+       __in            uint32_t key,
+       __in            uint32_t value)
+{
+       efx_mcdi_req_t req;
+       uint8_t payload[MC_CMD_SET_NIC_GLOBAL_IN_LEN];
+       efx_rc_t rc;
+
+       (void) memset(payload, 0, sizeof (payload));
+       req.emr_cmd = MC_CMD_SET_NIC_GLOBAL;
+       req.emr_in_buf = payload;
+       req.emr_in_length = MC_CMD_SET_NIC_GLOBAL_IN_LEN;
+       req.emr_out_buf = NULL;
+       req.emr_out_length = 0;
+
+       MCDI_IN_SET_DWORD(req, SET_NIC_GLOBAL_IN_KEY, key);
+       MCDI_IN_SET_DWORD(req, SET_NIC_GLOBAL_IN_VALUE, value);
+
+       efx_mcdi_execute(enp, &req);
+
+       if (req.emr_rc != 0) {
+               rc = req.emr_rc;
+               goto fail1;
+       }
+
+       return (0);
+
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+
+       return (rc);
+}
+
+#endif /* EFSYS_OPT_FW_SUBVARIANT_AWARE */
 
 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */