common/sfc_efx/base: support encap header provisioning
authorIvan Malov <ivan.malov@oktetlabs.ru>
Fri, 12 Mar 2021 11:07:40 +0000 (14:07 +0300)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 22 Mar 2021 16:19:16 +0000 (17:19 +0100)
Let the client allocate / free encap. headers.

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

index ff5091a..76d8799 100644 (file)
@@ -4070,6 +4070,7 @@ typedef struct efx_mae_limits_s {
        uint32_t                        eml_max_n_action_prios;
        uint32_t                        eml_max_n_outer_prios;
        uint32_t                        eml_encap_types_supported;
+       uint32_t                        eml_encap_header_size_limit;
 } efx_mae_limits_t;
 
 LIBEFX_API
@@ -4324,6 +4325,26 @@ efx_mae_match_spec_outer_rule_id_set(
        __in                            efx_mae_match_spec_t *spec,
        __in                            const efx_mae_rule_id_t *or_idp);
 
+/* Encap. header ID */
+typedef struct efx_mae_eh_id_s {
+       uint32_t id;
+} efx_mae_eh_id_t;
+
+LIBEFX_API
+extern __checkReturn                   efx_rc_t
+efx_mae_encap_header_alloc(
+       __in                            efx_nic_t *enp,
+       __in                            efx_tunnel_protocol_t encap_type,
+       __in_bcount(header_size)        uint8_t *header_data,
+       __in                            size_t header_size,
+       __out                           efx_mae_eh_id_t *eh_idp);
+
+LIBEFX_API
+extern __checkReturn                   efx_rc_t
+efx_mae_encap_header_free(
+       __in                            efx_nic_t *enp,
+       __in                            const efx_mae_eh_id_t *eh_idp);
+
 /* Action set ID */
 typedef struct efx_mae_aset_id_s {
        uint32_t id;
index b1e4b98..834e8f9 100644 (file)
@@ -352,6 +352,8 @@ efx_mae_get_limits(
        emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
        emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
        emlp->eml_encap_types_supported = maep->em_encap_types_supported;
+       emlp->eml_encap_header_size_limit =
+           MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2;
 
        return (0);
 
@@ -1690,6 +1692,159 @@ efx_mae_match_spec_outer_rule_id_set(
 
        return (0);
 
+fail3:
+       EFSYS_PROBE(fail3);
+fail2:
+       EFSYS_PROBE(fail2);
+fail1:
+       EFSYS_PROBE1(fail1, efx_rc_t, rc);
+       return (rc);
+}
+
+        __checkReturn                  efx_rc_t
+efx_mae_encap_header_alloc(
+       __in                            efx_nic_t *enp,
+       __in                            efx_tunnel_protocol_t encap_type,
+       __in_bcount(header_size)        uint8_t *header_data,
+       __in                            size_t header_size,
+       __out                           efx_mae_eh_id_t *eh_idp)
+{
+       const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+       efx_mcdi_req_t req;
+       EFX_MCDI_DECLARE_BUF(payload,
+           MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
+           MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
+       uint32_t encap_type_mcdi;
+       efx_mae_eh_id_t eh_id;
+       efx_rc_t rc;
+
+       EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
+           MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
+
+       EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
+           MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
+
+       if (encp->enc_mae_supported == B_FALSE) {
+               rc = ENOTSUP;
+               goto fail1;
+       }
+
+       switch (encap_type) {
+       case EFX_TUNNEL_PROTOCOL_NONE:
+               encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
+               break;
+       case EFX_TUNNEL_PROTOCOL_VXLAN:
+               encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
+               break;
+       case EFX_TUNNEL_PROTOCOL_GENEVE:
+               encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
+               break;
+       case EFX_TUNNEL_PROTOCOL_NVGRE:
+               encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
+               break;
+       default:
+               rc = ENOTSUP;
+               goto fail2;
+       }
+
+       if (header_size >
+           MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
+               rc = EINVAL;
+               goto fail3;
+       }
+
+       req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
+       req.emr_in_buf = payload;
+       req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
+       req.emr_out_buf = payload;
+       req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
+
+       MCDI_IN_SET_DWORD(req,
+           MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
+
+       memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
+           header_data, header_size);
+
+       efx_mcdi_execute(enp, &req);
+
+       if (req.emr_rc != 0) {
+               rc = req.emr_rc;
+               goto fail4;
+       }
+
+       if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
+               rc = EMSGSIZE;
+               goto fail5;
+       }
+
+       eh_id.id = MCDI_OUT_DWORD(req,
+           MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
+
+       if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
+               rc = ENOENT;
+               goto fail6;
+       }
+
+       eh_idp->id = eh_id.id;
+
+       return (0);
+
+fail6:
+       EFSYS_PROBE(fail6);
+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_encap_header_free(
+       __in                            efx_nic_t *enp,
+       __in                            const efx_mae_eh_id_t *eh_idp)
+{
+       const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
+       efx_mcdi_req_t req;
+       EFX_MCDI_DECLARE_BUF(payload,
+           MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
+           MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
+       efx_rc_t rc;
+
+       if (encp->enc_mae_supported == B_FALSE) {
+               rc = ENOTSUP;
+               goto fail1;
+       }
+
+       req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
+       req.emr_in_buf = payload;
+       req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
+       req.emr_out_buf = payload;
+       req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
+
+       MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
+
+       efx_mcdi_execute(enp, &req);
+
+       if (req.emr_rc != 0) {
+               rc = req.emr_rc;
+               goto fail2;
+       }
+
+       if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
+           eh_idp->id) {
+               /* Firmware failed to remove the encap. header. */
+               rc = EAGAIN;
+               goto fail3;
+       }
+
+       return (0);
+
 fail3:
        EFSYS_PROBE(fail3);
 fail2:
index c3414b7..49a380c 100644 (file)
@@ -98,6 +98,8 @@ INTERNAL {
        efx_mae_action_set_spec_fini;
        efx_mae_action_set_spec_init;
        efx_mae_action_set_specs_equal;
+       efx_mae_encap_header_alloc;
+       efx_mae_encap_header_free;
        efx_mae_fini;
        efx_mae_get_limits;
        efx_mae_init;