dpdk/drivers/common/sfc_efx/base/efx_mae.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 *
   3 * Copyright(c) 2019-2021 Xilinx, Inc.
   4 */
   5
   6#include "efx.h"
   7#include "efx_impl.h"
   8
   9
  10#if EFSYS_OPT_MAE
  11
  12static  __checkReturn                   efx_rc_t
  13efx_mae_get_capabilities(
  14        __in                            efx_nic_t *enp)
  15{
  16        efx_mcdi_req_t req;
  17        EFX_MCDI_DECLARE_BUF(payload,
  18            MC_CMD_MAE_GET_CAPS_IN_LEN,
  19            MC_CMD_MAE_GET_CAPS_OUT_LEN);
  20        struct efx_mae_s *maep = enp->en_maep;
  21        efx_rc_t rc;
  22
  23        req.emr_cmd = MC_CMD_MAE_GET_CAPS;
  24        req.emr_in_buf = payload;
  25        req.emr_in_length = MC_CMD_MAE_GET_CAPS_IN_LEN;
  26        req.emr_out_buf = payload;
  27        req.emr_out_length = MC_CMD_MAE_GET_CAPS_OUT_LEN;
  28
  29        efx_mcdi_execute(enp, &req);
  30
  31        if (req.emr_rc != 0) {
  32                rc = req.emr_rc;
  33                goto fail1;
  34        }
  35
  36        if (req.emr_out_length_used < MC_CMD_MAE_GET_CAPS_OUT_LEN) {
  37                rc = EMSGSIZE;
  38                goto fail2;
  39        }
  40
  41        maep->em_max_n_outer_prios =
  42            MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_OUTER_PRIOS);
  43
  44        maep->em_max_n_action_prios =
  45            MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ACTION_PRIOS);
  46
  47        maep->em_encap_types_supported = 0;
  48
  49        if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
  50            MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) != 0) {
  51                maep->em_encap_types_supported |=
  52                    (1U << EFX_TUNNEL_PROTOCOL_VXLAN);
  53        }
  54
  55        if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
  56            MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) != 0) {
  57                maep->em_encap_types_supported |=
  58                    (1U << EFX_TUNNEL_PROTOCOL_GENEVE);
  59        }
  60
  61        if (MCDI_OUT_DWORD_FIELD(req, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED,
  62            MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) != 0) {
  63                maep->em_encap_types_supported |=
  64                    (1U << EFX_TUNNEL_PROTOCOL_NVGRE);
  65        }
  66
  67        maep->em_max_nfields =
  68            MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
  69
  70        return (0);
  71
  72fail2:
  73        EFSYS_PROBE(fail2);
  74fail1:
  75        EFSYS_PROBE1(fail1, efx_rc_t, rc);
  76        return (rc);
  77}
  78
  79static  __checkReturn                   efx_rc_t
  80efx_mae_get_outer_rule_caps(
  81        __in                            efx_nic_t *enp,
  82        __in                            unsigned int field_ncaps,
  83        __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
  84{
  85        efx_mcdi_req_t req;
  86        EFX_MCDI_DECLARE_BUF(payload,
  87            MC_CMD_MAE_GET_OR_CAPS_IN_LEN,
  88            MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2);
  89        unsigned int mcdi_field_ncaps;
  90        unsigned int i;
  91        efx_rc_t rc;
  92
  93        if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) >
  94            MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) {
  95                rc = EINVAL;
  96                goto fail1;
  97        }
  98
  99        req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS;
 100        req.emr_in_buf = payload;
 101        req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN;
 102        req.emr_out_buf = payload;
 103        req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps);
 104
 105        efx_mcdi_execute(enp, &req);
 106
 107        if (req.emr_rc != 0) {
 108                rc = req.emr_rc;
 109                goto fail2;
 110        }
 111
 112        if (req.emr_out_length_used < MC_CMD_MAE_GET_OR_CAPS_OUT_LENMIN) {
 113                rc = EMSGSIZE;
 114                goto fail3;
 115        }
 116
 117        mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT);
 118
 119        if (req.emr_out_length_used <
 120            MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
 121                rc = EMSGSIZE;
 122                goto fail4;
 123        }
 124
 125        if (mcdi_field_ncaps > field_ncaps) {
 126                rc = EMSGSIZE;
 127                goto fail5;
 128        }
 129
 130        for (i = 0; i < mcdi_field_ncaps; ++i) {
 131                uint32_t match_flag;
 132                uint32_t mask_flag;
 133
 134                field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
 135                    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
 136                    MAE_FIELD_FLAGS_SUPPORT_STATUS);
 137
 138                match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
 139                    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
 140                    MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
 141
 142                field_caps[i].emfc_match_affects_class =
 143                    (match_flag != 0) ? B_TRUE : B_FALSE;
 144
 145                mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
 146                    MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i,
 147                    MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
 148
 149                field_caps[i].emfc_mask_affects_class =
 150                    (mask_flag != 0) ? B_TRUE : B_FALSE;
 151        }
 152
 153        return (0);
 154
 155fail5:
 156        EFSYS_PROBE(fail5);
 157fail4:
 158        EFSYS_PROBE(fail4);
 159fail3:
 160        EFSYS_PROBE(fail3);
 161fail2:
 162        EFSYS_PROBE(fail2);
 163fail1:
 164        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 165        return (rc);
 166}
 167
 168static  __checkReturn                   efx_rc_t
 169efx_mae_get_action_rule_caps(
 170        __in                            efx_nic_t *enp,
 171        __in                            unsigned int field_ncaps,
 172        __out_ecount(field_ncaps)       efx_mae_field_cap_t *field_caps)
 173{
 174        efx_mcdi_req_t req;
 175        EFX_MCDI_DECLARE_BUF(payload,
 176            MC_CMD_MAE_GET_AR_CAPS_IN_LEN,
 177            MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2);
 178        unsigned int mcdi_field_ncaps;
 179        unsigned int i;
 180        efx_rc_t rc;
 181
 182        if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) >
 183            MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) {
 184                rc = EINVAL;
 185                goto fail1;
 186        }
 187
 188        req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS;
 189        req.emr_in_buf = payload;
 190        req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN;
 191        req.emr_out_buf = payload;
 192        req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps);
 193
 194        efx_mcdi_execute(enp, &req);
 195
 196        if (req.emr_rc != 0) {
 197                rc = req.emr_rc;
 198                goto fail2;
 199        }
 200
 201        if (req.emr_out_length_used < MC_CMD_MAE_GET_AR_CAPS_OUT_LENMIN) {
 202                rc = EMSGSIZE;
 203                goto fail3;
 204        }
 205
 206        mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_AR_CAPS_OUT_COUNT);
 207
 208        if (req.emr_out_length_used <
 209            MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) {
 210                rc = EMSGSIZE;
 211                goto fail4;
 212        }
 213
 214        if (mcdi_field_ncaps > field_ncaps) {
 215                rc = EMSGSIZE;
 216                goto fail5;
 217        }
 218
 219        for (i = 0; i < mcdi_field_ncaps; ++i) {
 220                uint32_t match_flag;
 221                uint32_t mask_flag;
 222
 223                field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req,
 224                    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
 225                    MAE_FIELD_FLAGS_SUPPORT_STATUS);
 226
 227                match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
 228                    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
 229                    MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS);
 230
 231                field_caps[i].emfc_match_affects_class =
 232                    (match_flag != 0) ? B_TRUE : B_FALSE;
 233
 234                mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req,
 235                    MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i,
 236                    MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS);
 237
 238                field_caps[i].emfc_mask_affects_class =
 239                    (mask_flag != 0) ? B_TRUE : B_FALSE;
 240        }
 241
 242        return (0);
 243
 244fail5:
 245        EFSYS_PROBE(fail5);
 246fail4:
 247        EFSYS_PROBE(fail4);
 248fail3:
 249        EFSYS_PROBE(fail3);
 250fail2:
 251        EFSYS_PROBE(fail2);
 252fail1:
 253        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 254        return (rc);
 255}
 256
 257        __checkReturn                   efx_rc_t
 258efx_mae_init(
 259        __in                            efx_nic_t *enp)
 260{
 261        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
 262        efx_mae_field_cap_t *or_fcaps;
 263        size_t or_fcaps_size;
 264        efx_mae_field_cap_t *ar_fcaps;
 265        size_t ar_fcaps_size;
 266        efx_mae_t *maep;
 267        efx_rc_t rc;
 268
 269        if (encp->enc_mae_supported == B_FALSE) {
 270                rc = ENOTSUP;
 271                goto fail1;
 272        }
 273
 274        EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep);
 275        if (maep == NULL) {
 276                rc = ENOMEM;
 277                goto fail2;
 278        }
 279
 280        enp->en_maep = maep;
 281
 282        rc = efx_mae_get_capabilities(enp);
 283        if (rc != 0)
 284                goto fail3;
 285
 286        or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps);
 287        EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps);
 288        if (or_fcaps == NULL) {
 289                rc = ENOMEM;
 290                goto fail4;
 291        }
 292
 293        maep->em_outer_rule_field_caps_size = or_fcaps_size;
 294        maep->em_outer_rule_field_caps = or_fcaps;
 295
 296        rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps);
 297        if (rc != 0)
 298                goto fail5;
 299
 300        ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps);
 301        EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps);
 302        if (ar_fcaps == NULL) {
 303                rc = ENOMEM;
 304                goto fail6;
 305        }
 306
 307        maep->em_action_rule_field_caps_size = ar_fcaps_size;
 308        maep->em_action_rule_field_caps = ar_fcaps;
 309
 310        rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps);
 311        if (rc != 0)
 312                goto fail7;
 313
 314        return (0);
 315
 316fail7:
 317        EFSYS_PROBE(fail5);
 318        EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps);
 319fail6:
 320        EFSYS_PROBE(fail4);
 321fail5:
 322        EFSYS_PROBE(fail5);
 323        EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps);
 324fail4:
 325        EFSYS_PROBE(fail4);
 326fail3:
 327        EFSYS_PROBE(fail3);
 328        EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep);
 329        enp->en_maep = NULL;
 330fail2:
 331        EFSYS_PROBE(fail2);
 332fail1:
 333        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 334        return (rc);
 335}
 336
 337                                        void
 338efx_mae_fini(
 339        __in                            efx_nic_t *enp)
 340{
 341        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
 342        efx_mae_t *maep = enp->en_maep;
 343
 344        if (encp->enc_mae_supported == B_FALSE)
 345                return;
 346
 347        EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size,
 348            maep->em_action_rule_field_caps);
 349        EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size,
 350            maep->em_outer_rule_field_caps);
 351        EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep);
 352        enp->en_maep = NULL;
 353}
 354
 355        __checkReturn                   efx_rc_t
 356efx_mae_get_limits(
 357        __in                            efx_nic_t *enp,
 358        __out                           efx_mae_limits_t *emlp)
 359{
 360        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
 361        struct efx_mae_s *maep = enp->en_maep;
 362        efx_rc_t rc;
 363
 364        if (encp->enc_mae_supported == B_FALSE) {
 365                rc = ENOTSUP;
 366                goto fail1;
 367        }
 368
 369        emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios;
 370        emlp->eml_max_n_action_prios = maep->em_max_n_action_prios;
 371        emlp->eml_encap_types_supported = maep->em_encap_types_supported;
 372        emlp->eml_encap_header_size_limit =
 373            MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2;
 374
 375        return (0);
 376
 377fail1:
 378        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 379        return (rc);
 380}
 381
 382        __checkReturn                   efx_rc_t
 383efx_mae_match_spec_init(
 384        __in                            efx_nic_t *enp,
 385        __in                            efx_mae_rule_type_t type,
 386        __in                            uint32_t prio,
 387        __out                           efx_mae_match_spec_t **specp)
 388{
 389        efx_mae_match_spec_t *spec;
 390        efx_rc_t rc;
 391
 392        switch (type) {
 393        case EFX_MAE_RULE_OUTER:
 394                break;
 395        case EFX_MAE_RULE_ACTION:
 396                break;
 397        default:
 398                rc = ENOTSUP;
 399                goto fail1;
 400        }
 401
 402        EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
 403        if (spec == NULL) {
 404                rc = ENOMEM;
 405                goto fail2;
 406        }
 407
 408        spec->emms_type = type;
 409        spec->emms_prio = prio;
 410
 411        *specp = spec;
 412
 413        return (0);
 414
 415fail2:
 416        EFSYS_PROBE(fail2);
 417fail1:
 418        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 419        return (rc);
 420}
 421
 422                                        void
 423efx_mae_match_spec_fini(
 424        __in                            efx_nic_t *enp,
 425        __in                            efx_mae_match_spec_t *spec)
 426{
 427        EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
 428}
 429
 430/* Named identifiers which are valid indices to efx_mae_field_cap_t */
 431typedef enum efx_mae_field_cap_id_e {
 432        EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT,
 433        EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE,
 434        EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR,
 435        EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR,
 436        EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI,
 437        EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO,
 438        EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI,
 439        EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO,
 440        EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4,
 441        EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4,
 442        EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO,
 443        EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS,
 444        EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL,
 445        EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6,
 446        EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6,
 447        EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT,
 448        EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT,
 449        EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS,
 450        EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE,
 451        EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR,
 452        EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR,
 453        EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI,
 454        EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO,
 455        EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI,
 456        EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO,
 457        EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4,
 458        EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4,
 459        EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO,
 460        EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS,
 461        EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL,
 462        EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6,
 463        EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6,
 464        EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT,
 465        EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT,
 466        EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID,
 467        EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID,
 468
 469        EFX_MAE_FIELD_CAP_NIDS
 470} efx_mae_field_cap_id_t;
 471
 472typedef enum efx_mae_field_endianness_e {
 473        EFX_MAE_FIELD_LE = 0,
 474        EFX_MAE_FIELD_BE,
 475
 476        EFX_MAE_FIELD_ENDIANNESS_NTYPES
 477} efx_mae_field_endianness_t;
 478
 479/*
 480 * The following structure is a means to describe an MAE field.
 481 * The information in it is meant to be used internally by
 482 * APIs for addressing a given field in a mask-value pairs
 483 * structure and for validation purposes.
 484 *
 485 * A field may have an alternative one. This structure
 486 * has additional members to reference the alternative
 487 * field's mask. See efx_mae_match_spec_is_valid().
 488 */
 489typedef struct efx_mae_mv_desc_s {
 490        efx_mae_field_cap_id_t          emmd_field_cap_id;
 491
 492        size_t                          emmd_value_size;
 493        size_t                          emmd_value_offset;
 494        size_t                          emmd_mask_size;
 495        size_t                          emmd_mask_offset;
 496
 497        /*
 498         * Having the alternative field's mask size set to 0
 499         * means that there's no alternative field specified.
 500         */
 501        size_t                          emmd_alt_mask_size;
 502        size_t                          emmd_alt_mask_offset;
 503
 504        /* Primary field and the alternative one are of the same endianness. */
 505        efx_mae_field_endianness_t      emmd_endianness;
 506} efx_mae_mv_desc_t;
 507
 508/* Indices to this array are provided by efx_mae_field_id_t */
 509static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = {
 510#define EFX_MAE_MV_DESC(_name, _endianness)                             \
 511        [EFX_MAE_FIELD_##_name] =                                       \
 512        {                                                               \
 513                EFX_MAE_FIELD_ID_##_name,                               \
 514                MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN,               \
 515                MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST,              \
 516                MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN,          \
 517                MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST,         \
 518                0, 0 /* no alternative field */,                        \
 519                _endianness                                             \
 520        }
 521
 522        EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
 523        EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
 524        EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE),
 525        EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE),
 526        EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
 527        EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
 528        EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
 529        EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
 530        EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE),
 531        EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE),
 532        EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE),
 533        EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE),
 534        EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE),
 535        EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE),
 536        EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE),
 537        EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE),
 538        EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE),
 539        EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE),
 540        EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE),
 541        EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE),
 542
 543#undef EFX_MAE_MV_DESC
 544};
 545
 546/* Indices to this array are provided by efx_mae_field_id_t */
 547static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = {
 548#define EFX_MAE_MV_DESC(_name, _endianness)                             \
 549        [EFX_MAE_FIELD_##_name] =                                       \
 550        {                                                               \
 551                EFX_MAE_FIELD_ID_##_name,                               \
 552                MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
 553                MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
 554                MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
 555                MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
 556                0, 0 /* no alternative field */,                        \
 557                _endianness                                             \
 558        }
 559
 560/* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */
 561#define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness)              \
 562        [EFX_MAE_FIELD_##_name] =                                       \
 563        {                                                               \
 564                EFX_MAE_FIELD_ID_##_name,                               \
 565                MAE_ENC_FIELD_PAIRS_##_name##_LEN,                      \
 566                MAE_ENC_FIELD_PAIRS_##_name##_OFST,                     \
 567                MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN,                 \
 568                MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST,                \
 569                MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN,             \
 570                MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST,            \
 571                _endianness                                             \
 572        }
 573
 574        EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE),
 575        EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE),
 576        EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE),
 577        EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE),
 578        EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE),
 579        EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE),
 580        EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE),
 581        EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE),
 582        EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE),
 583        EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE),
 584        EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE),
 585        EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE),
 586        EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE),
 587        EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE),
 588        EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE),
 589        EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE),
 590        EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE),
 591
 592#undef EFX_MAE_MV_DESC_ALT
 593#undef EFX_MAE_MV_DESC
 594};
 595
 596        __checkReturn                   efx_rc_t
 597efx_mae_mport_by_phy_port(
 598        __in                            uint32_t phy_port,
 599        __out                           efx_mport_sel_t *mportp)
 600{
 601        efx_dword_t dword;
 602        efx_rc_t rc;
 603
 604        if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) {
 605                rc = EINVAL;
 606                goto fail1;
 607        }
 608
 609        EFX_POPULATE_DWORD_2(dword,
 610            MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
 611            MAE_MPORT_SELECTOR_PPORT_ID, phy_port);
 612
 613        memset(mportp, 0, sizeof (*mportp));
 614        /*
 615         * The constructed DWORD is little-endian,
 616         * but the resulting value is meant to be
 617         * passed to MCDIs, where it will undergo
 618         * host-order to little endian conversion.
 619         */
 620        mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
 621
 622        return (0);
 623
 624fail1:
 625        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 626        return (rc);
 627}
 628
 629        __checkReturn                   efx_rc_t
 630efx_mae_mport_by_pcie_function(
 631        __in                            uint32_t pf,
 632        __in                            uint32_t vf,
 633        __out                           efx_mport_sel_t *mportp)
 634{
 635        efx_dword_t dword;
 636        efx_rc_t rc;
 637
 638        EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID ==
 639            MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
 640
 641        if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) {
 642                rc = EINVAL;
 643                goto fail1;
 644        }
 645
 646        if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) {
 647                rc = EINVAL;
 648                goto fail2;
 649        }
 650
 651        EFX_POPULATE_DWORD_3(dword,
 652            MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
 653            MAE_MPORT_SELECTOR_FUNC_PF_ID, pf,
 654            MAE_MPORT_SELECTOR_FUNC_VF_ID, vf);
 655
 656        memset(mportp, 0, sizeof (*mportp));
 657        /*
 658         * The constructed DWORD is little-endian,
 659         * but the resulting value is meant to be
 660         * passed to MCDIs, where it will undergo
 661         * host-order to little endian conversion.
 662         */
 663        mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
 664
 665        return (0);
 666
 667fail2:
 668        EFSYS_PROBE(fail2);
 669fail1:
 670        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 671        return (rc);
 672}
 673
 674        __checkReturn                   efx_rc_t
 675efx_mae_match_spec_field_set(
 676        __in                            efx_mae_match_spec_t *spec,
 677        __in                            efx_mae_field_id_t field_id,
 678        __in                            size_t value_size,
 679        __in_bcount(value_size)         const uint8_t *value,
 680        __in                            size_t mask_size,
 681        __in_bcount(mask_size)          const uint8_t *mask)
 682{
 683        const efx_mae_mv_desc_t *descp;
 684        unsigned int desc_set_nentries;
 685        uint8_t *mvp;
 686        efx_rc_t rc;
 687
 688        switch (spec->emms_type) {
 689        case EFX_MAE_RULE_OUTER:
 690                desc_set_nentries =
 691                    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
 692                descp = &__efx_mae_outer_rule_mv_desc_set[field_id];
 693                mvp = spec->emms_mask_value_pairs.outer;
 694                break;
 695        case EFX_MAE_RULE_ACTION:
 696                desc_set_nentries =
 697                    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
 698                descp = &__efx_mae_action_rule_mv_desc_set[field_id];
 699                mvp = spec->emms_mask_value_pairs.action;
 700                break;
 701        default:
 702                rc = ENOTSUP;
 703                goto fail1;
 704        }
 705
 706        if ((unsigned int)field_id >= desc_set_nentries) {
 707                rc = EINVAL;
 708                goto fail2;
 709        }
 710
 711        if (descp->emmd_mask_size == 0) {
 712                /* The ID points to a gap in the array of field descriptors. */
 713                rc = EINVAL;
 714                goto fail3;
 715        }
 716
 717        if (value_size != descp->emmd_value_size) {
 718                rc = EINVAL;
 719                goto fail4;
 720        }
 721
 722        if (mask_size != descp->emmd_mask_size) {
 723                rc = EINVAL;
 724                goto fail5;
 725        }
 726
 727        if (descp->emmd_endianness == EFX_MAE_FIELD_BE) {
 728                unsigned int i;
 729
 730                /*
 731                 * The mask/value are in network (big endian) order.
 732                 * The MCDI request field is also big endian.
 733                 */
 734
 735                EFSYS_ASSERT3U(value_size, ==, mask_size);
 736
 737                for (i = 0; i < value_size; ++i) {
 738                        uint8_t *v_bytep = mvp + descp->emmd_value_offset + i;
 739                        uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i;
 740
 741                        /*
 742                         * Apply the mask (which may be all-zeros) to the value.
 743                         *
 744                         * If this API is provided with some value to set for a
 745                         * given field in one specification and with some other
 746                         * value to set for this field in another specification,
 747                         * then, if the two masks are all-zeros, the field will
 748                         * avoid being counted as a mismatch when comparing the
 749                         * specifications using efx_mae_match_specs_equal() API.
 750                         */
 751                        *v_bytep = value[i] & mask[i];
 752                        *m_bytep = mask[i];
 753                }
 754        } else {
 755                efx_dword_t dword;
 756
 757                /*
 758                 * The mask/value are in host byte order.
 759                 * The MCDI request field is little endian.
 760                 */
 761                switch (value_size) {
 762                case 4:
 763                        EFX_POPULATE_DWORD_1(dword,
 764                            EFX_DWORD_0, *(const uint32_t *)value);
 765
 766                        memcpy(mvp + descp->emmd_value_offset,
 767                            &dword, sizeof (dword));
 768                        break;
 769                default:
 770                        EFSYS_ASSERT(B_FALSE);
 771                }
 772
 773                switch (mask_size) {
 774                case 4:
 775                        EFX_POPULATE_DWORD_1(dword,
 776                            EFX_DWORD_0, *(const uint32_t *)mask);
 777
 778                        memcpy(mvp + descp->emmd_mask_offset,
 779                            &dword, sizeof (dword));
 780                        break;
 781                default:
 782                        EFSYS_ASSERT(B_FALSE);
 783                }
 784        }
 785
 786        return (0);
 787
 788fail5:
 789        EFSYS_PROBE(fail5);
 790fail4:
 791        EFSYS_PROBE(fail4);
 792fail3:
 793        EFSYS_PROBE(fail3);
 794fail2:
 795        EFSYS_PROBE(fail2);
 796fail1:
 797        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 798        return (rc);
 799}
 800
 801        __checkReturn                   efx_rc_t
 802efx_mae_match_spec_mport_set(
 803        __in                            efx_mae_match_spec_t *spec,
 804        __in                            const efx_mport_sel_t *valuep,
 805        __in_opt                        const efx_mport_sel_t *maskp)
 806{
 807        uint32_t full_mask = UINT32_MAX;
 808        const uint8_t *vp;
 809        const uint8_t *mp;
 810        efx_rc_t rc;
 811
 812        if (valuep == NULL) {
 813                rc = EINVAL;
 814                goto fail1;
 815        }
 816
 817        vp = (const uint8_t *)&valuep->sel;
 818        if (maskp != NULL)
 819                mp = (const uint8_t *)&maskp->sel;
 820        else
 821                mp = (const uint8_t *)&full_mask;
 822
 823        rc = efx_mae_match_spec_field_set(spec,
 824            EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR,
 825            sizeof (valuep->sel), vp, sizeof (maskp->sel), mp);
 826        if (rc != 0)
 827                goto fail2;
 828
 829        return (0);
 830
 831fail2:
 832        EFSYS_PROBE(fail2);
 833fail1:
 834        EFSYS_PROBE1(fail1, efx_rc_t, rc);
 835        return (rc);
 836}
 837
 838        __checkReturn                   boolean_t
 839efx_mae_match_specs_equal(
 840        __in                            const efx_mae_match_spec_t *left,
 841        __in                            const efx_mae_match_spec_t *right)
 842{
 843        return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE);
 844}
 845
 846#define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit)              \
 847            ((_mask)[(_bit) / (_mask_page_nbits)] &                     \
 848                    (1ULL << ((_bit) & ((_mask_page_nbits) - 1))))
 849
 850static                                  boolean_t
 851efx_mask_is_prefix(
 852        __in                            size_t mask_nbytes,
 853        __in_bcount(mask_nbytes)        const uint8_t *maskp)
 854{
 855        boolean_t prev_bit_is_set = B_TRUE;
 856        unsigned int i;
 857
 858        for (i = 0; i < 8 * mask_nbytes; ++i) {
 859                boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i);
 860
 861                if (!prev_bit_is_set && bit_is_set)
 862                        return B_FALSE;
 863
 864                prev_bit_is_set = bit_is_set;
 865        }
 866
 867        return B_TRUE;
 868}
 869
 870static                                  boolean_t
 871efx_mask_is_all_ones(
 872        __in                            size_t mask_nbytes,
 873        __in_bcount(mask_nbytes)        const uint8_t *maskp)
 874{
 875        unsigned int i;
 876        uint8_t t = ~0;
 877
 878        for (i = 0; i < mask_nbytes; ++i)
 879                t &= maskp[i];
 880
 881        return (t == (uint8_t)(~0));
 882}
 883
 884static                                  boolean_t
 885efx_mask_is_all_zeros(
 886        __in                            size_t mask_nbytes,
 887        __in_bcount(mask_nbytes)        const uint8_t *maskp)
 888{
 889        unsigned int i;
 890        uint8_t t = 0;
 891
 892        for (i = 0; i < mask_nbytes; ++i)
 893                t |= maskp[i];
 894
 895        return (t == 0);
 896}
 897
 898        __checkReturn                   boolean_t
 899efx_mae_match_spec_is_valid(
 900        __in                            efx_nic_t *enp,
 901        __in                            const efx_mae_match_spec_t *spec)
 902{
 903        efx_mae_t *maep = enp->en_maep;
 904        unsigned int field_ncaps = maep->em_max_nfields;
 905        const efx_mae_field_cap_t *field_caps;
 906        const efx_mae_mv_desc_t *desc_setp;
 907        unsigned int desc_set_nentries;
 908        boolean_t is_valid = B_TRUE;
 909        efx_mae_field_id_t field_id;
 910        const uint8_t *mvp;
 911
 912        switch (spec->emms_type) {
 913        case EFX_MAE_RULE_OUTER:
 914                field_caps = maep->em_outer_rule_field_caps;
 915                desc_setp = __efx_mae_outer_rule_mv_desc_set;
 916                desc_set_nentries =
 917                    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
 918                mvp = spec->emms_mask_value_pairs.outer;
 919                break;
 920        case EFX_MAE_RULE_ACTION:
 921                field_caps = maep->em_action_rule_field_caps;
 922                desc_setp = __efx_mae_action_rule_mv_desc_set;
 923                desc_set_nentries =
 924                    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
 925                mvp = spec->emms_mask_value_pairs.action;
 926                break;
 927        default:
 928                return (B_FALSE);
 929        }
 930
 931        if (field_caps == NULL)
 932                return (B_FALSE);
 933
 934        for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
 935             ++field_id) {
 936                const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
 937                efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
 938                const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset;
 939                const uint8_t *m_buf = mvp + descp->emmd_mask_offset;
 940                size_t alt_m_size = descp->emmd_alt_mask_size;
 941                size_t m_size = descp->emmd_mask_size;
 942
 943                if (m_size == 0)
 944                        continue; /* Skip array gap */
 945
 946                if ((unsigned int)field_cap_id >= field_ncaps) {
 947                        /*
 948                         * The FW has not reported capability status for
 949                         * this field. Make sure that its mask is zeroed.
 950                         */
 951                        is_valid = efx_mask_is_all_zeros(m_size, m_buf);
 952                        if (is_valid != B_FALSE)
 953                                continue;
 954                        else
 955                                break;
 956                }
 957
 958                switch (field_caps[field_cap_id].emfc_support) {
 959                case MAE_FIELD_SUPPORTED_MATCH_MASK:
 960                        is_valid = B_TRUE;
 961                        break;
 962                case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
 963                        is_valid = efx_mask_is_prefix(m_size, m_buf);
 964                        break;
 965                case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
 966                        is_valid = (efx_mask_is_all_ones(m_size, m_buf) ||
 967                            efx_mask_is_all_zeros(m_size, m_buf));
 968                        break;
 969                case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
 970                        is_valid = efx_mask_is_all_ones(m_size, m_buf);
 971
 972                        if ((is_valid == B_FALSE) && (alt_m_size != 0)) {
 973                                /*
 974                                 * This field has an alternative one. The FW
 975                                 * reports ALWAYS for both implying that one
 976                                 * of them is required to have all-ones mask.
 977                                 *
 978                                 * The primary field's mask is incorrect; go
 979                                 * on to check that of the alternative field.
 980                                 */
 981                                is_valid = efx_mask_is_all_ones(alt_m_size,
 982                                                                alt_m_buf);
 983                        }
 984                        break;
 985                case MAE_FIELD_SUPPORTED_MATCH_NEVER:
 986                case MAE_FIELD_UNSUPPORTED:
 987                default:
 988                        is_valid = efx_mask_is_all_zeros(m_size, m_buf);
 989                        break;
 990                }
 991
 992                if (is_valid == B_FALSE)
 993                        break;
 994        }
 995
 996        return (is_valid);
 997}
 998
 999        __checkReturn                   efx_rc_t
1000efx_mae_action_set_spec_init(
1001        __in                            efx_nic_t *enp,
1002        __out                           efx_mae_actions_t **specp)
1003{
1004        efx_mae_actions_t *spec;
1005        efx_rc_t rc;
1006
1007        EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec);
1008        if (spec == NULL) {
1009                rc = ENOMEM;
1010                goto fail1;
1011        }
1012
1013        spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1014
1015        *specp = spec;
1016
1017        return (0);
1018
1019fail1:
1020        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1021        return (rc);
1022}
1023
1024                                        void
1025efx_mae_action_set_spec_fini(
1026        __in                            efx_nic_t *enp,
1027        __in                            efx_mae_actions_t *spec)
1028{
1029        EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
1030}
1031
1032static  __checkReturn                   efx_rc_t
1033efx_mae_action_set_add_decap(
1034        __in                            efx_mae_actions_t *spec,
1035        __in                            size_t arg_size,
1036        __in_bcount(arg_size)           const uint8_t *arg)
1037{
1038        efx_rc_t rc;
1039
1040        _NOTE(ARGUNUSED(spec))
1041
1042        if (arg_size != 0) {
1043                rc = EINVAL;
1044                goto fail1;
1045        }
1046
1047        if (arg != NULL) {
1048                rc = EINVAL;
1049                goto fail2;
1050        }
1051
1052        /* This action does not have any arguments, so do nothing here. */
1053
1054        return (0);
1055
1056fail2:
1057        EFSYS_PROBE(fail2);
1058fail1:
1059        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1060        return (rc);
1061}
1062
1063static  __checkReturn                   efx_rc_t
1064efx_mae_action_set_add_vlan_pop(
1065        __in                            efx_mae_actions_t *spec,
1066        __in                            size_t arg_size,
1067        __in_bcount(arg_size)           const uint8_t *arg)
1068{
1069        efx_rc_t rc;
1070
1071        if (arg_size != 0) {
1072                rc = EINVAL;
1073                goto fail1;
1074        }
1075
1076        if (arg != NULL) {
1077                rc = EINVAL;
1078                goto fail2;
1079        }
1080
1081        if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) {
1082                rc = ENOTSUP;
1083                goto fail3;
1084        }
1085
1086        ++spec->ema_n_vlan_tags_to_pop;
1087
1088        return (0);
1089
1090fail3:
1091        EFSYS_PROBE(fail3);
1092fail2:
1093        EFSYS_PROBE(fail2);
1094fail1:
1095        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1096        return (rc);
1097}
1098
1099static  __checkReturn                   efx_rc_t
1100efx_mae_action_set_add_vlan_push(
1101        __in                            efx_mae_actions_t *spec,
1102        __in                            size_t arg_size,
1103        __in_bcount(arg_size)           const uint8_t *arg)
1104{
1105        unsigned int n_tags = spec->ema_n_vlan_tags_to_push;
1106        efx_rc_t rc;
1107
1108        if (arg_size != sizeof (*spec->ema_vlan_push_descs)) {
1109                rc = EINVAL;
1110                goto fail1;
1111        }
1112
1113        if (arg == NULL) {
1114                rc = EINVAL;
1115                goto fail2;
1116        }
1117
1118        if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
1119                rc = ENOTSUP;
1120                goto fail3;
1121        }
1122
1123        memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size);
1124        ++(spec->ema_n_vlan_tags_to_push);
1125
1126        return (0);
1127
1128fail3:
1129        EFSYS_PROBE(fail3);
1130fail2:
1131        EFSYS_PROBE(fail2);
1132fail1:
1133        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1134        return (rc);
1135}
1136
1137static  __checkReturn                   efx_rc_t
1138efx_mae_action_set_add_encap(
1139        __in                            efx_mae_actions_t *spec,
1140        __in                            size_t arg_size,
1141        __in_bcount(arg_size)           const uint8_t *arg)
1142{
1143        efx_rc_t rc;
1144
1145        /*
1146         * Adding this specific action to an action set spec and setting encap.
1147         * header ID in the spec are two individual steps. This design allows
1148         * the client driver to avoid encap. header allocation when it simply
1149         * needs to check the order of actions submitted by user ("validate"),
1150         * without actually allocating an action set and inserting a rule.
1151         *
1152         * For now, mark encap. header ID as invalid; the caller will invoke
1153         * efx_mae_action_set_fill_in_eh_id() to override the field prior
1154         * to action set allocation; otherwise, the allocation will fail.
1155         */
1156        spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID;
1157
1158        /*
1159         * As explained above, there are no arguments to handle here.
1160         * efx_mae_action_set_fill_in_eh_id() will take care of them.
1161         */
1162        if (arg_size != 0) {
1163                rc = EINVAL;
1164                goto fail1;
1165        }
1166
1167        if (arg != NULL) {
1168                rc = EINVAL;
1169                goto fail2;
1170        }
1171
1172        return (0);
1173
1174fail2:
1175        EFSYS_PROBE(fail2);
1176fail1:
1177        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1178        return (rc);
1179}
1180
1181static  __checkReturn                   efx_rc_t
1182efx_mae_action_set_add_flag(
1183        __in                            efx_mae_actions_t *spec,
1184        __in                            size_t arg_size,
1185        __in_bcount(arg_size)           const uint8_t *arg)
1186{
1187        efx_rc_t rc;
1188
1189        _NOTE(ARGUNUSED(spec))
1190
1191        if (arg_size != 0) {
1192                rc = EINVAL;
1193                goto fail1;
1194        }
1195
1196        if (arg != NULL) {
1197                rc = EINVAL;
1198                goto fail2;
1199        }
1200
1201        /* This action does not have any arguments, so do nothing here. */
1202
1203        return (0);
1204
1205fail2:
1206        EFSYS_PROBE(fail2);
1207fail1:
1208        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1209        return (rc);
1210}
1211
1212static  __checkReturn                   efx_rc_t
1213efx_mae_action_set_add_mark(
1214        __in                            efx_mae_actions_t *spec,
1215        __in                            size_t arg_size,
1216        __in_bcount(arg_size)           const uint8_t *arg)
1217{
1218        efx_rc_t rc;
1219
1220        if (arg_size != sizeof (spec->ema_mark_value)) {
1221                rc = EINVAL;
1222                goto fail1;
1223        }
1224
1225        if (arg == NULL) {
1226                rc = EINVAL;
1227                goto fail2;
1228        }
1229
1230        memcpy(&spec->ema_mark_value, arg, arg_size);
1231
1232        return (0);
1233
1234fail2:
1235        EFSYS_PROBE(fail2);
1236fail1:
1237        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1238        return (rc);
1239}
1240
1241static  __checkReturn                   efx_rc_t
1242efx_mae_action_set_add_deliver(
1243        __in                            efx_mae_actions_t *spec,
1244        __in                            size_t arg_size,
1245        __in_bcount(arg_size)           const uint8_t *arg)
1246{
1247        efx_rc_t rc;
1248
1249        if (arg_size != sizeof (spec->ema_deliver_mport)) {
1250                rc = EINVAL;
1251                goto fail1;
1252        }
1253
1254        if (arg == NULL) {
1255                rc = EINVAL;
1256                goto fail2;
1257        }
1258
1259        memcpy(&spec->ema_deliver_mport, arg, arg_size);
1260
1261        return (0);
1262
1263fail2:
1264        EFSYS_PROBE(fail2);
1265fail1:
1266        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1267        return (rc);
1268}
1269
1270typedef struct efx_mae_action_desc_s {
1271        /* Action specific handler */
1272        efx_rc_t        (*emad_add)(efx_mae_actions_t *,
1273                                    size_t, const uint8_t *);
1274} efx_mae_action_desc_t;
1275
1276static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = {
1277        [EFX_MAE_ACTION_DECAP] = {
1278                .emad_add = efx_mae_action_set_add_decap
1279        },
1280        [EFX_MAE_ACTION_VLAN_POP] = {
1281                .emad_add = efx_mae_action_set_add_vlan_pop
1282        },
1283        [EFX_MAE_ACTION_VLAN_PUSH] = {
1284                .emad_add = efx_mae_action_set_add_vlan_push
1285        },
1286        [EFX_MAE_ACTION_ENCAP] = {
1287                .emad_add = efx_mae_action_set_add_encap
1288        },
1289        [EFX_MAE_ACTION_FLAG] = {
1290                .emad_add = efx_mae_action_set_add_flag
1291        },
1292        [EFX_MAE_ACTION_MARK] = {
1293                .emad_add = efx_mae_action_set_add_mark
1294        },
1295        [EFX_MAE_ACTION_DELIVER] = {
1296                .emad_add = efx_mae_action_set_add_deliver
1297        }
1298};
1299
1300static const uint32_t efx_mae_action_ordered_map =
1301        (1U << EFX_MAE_ACTION_DECAP) |
1302        (1U << EFX_MAE_ACTION_VLAN_POP) |
1303        (1U << EFX_MAE_ACTION_VLAN_PUSH) |
1304        (1U << EFX_MAE_ACTION_ENCAP) |
1305        (1U << EFX_MAE_ACTION_FLAG) |
1306        (1U << EFX_MAE_ACTION_MARK) |
1307        (1U << EFX_MAE_ACTION_DELIVER);
1308
1309/*
1310 * These actions must not be added after DELIVER, but
1311 * they can have any place among the rest of
1312 * strictly ordered actions.
1313 */
1314static const uint32_t efx_mae_action_nonstrict_map =
1315        (1U << EFX_MAE_ACTION_FLAG) |
1316        (1U << EFX_MAE_ACTION_MARK);
1317
1318static const uint32_t efx_mae_action_repeat_map =
1319        (1U << EFX_MAE_ACTION_VLAN_POP) |
1320        (1U << EFX_MAE_ACTION_VLAN_PUSH);
1321
1322/*
1323 * Add an action to an action set.
1324 *
1325 * This has to be invoked in the desired action order.
1326 * An out-of-order action request will be turned down.
1327 */
1328static  __checkReturn                   efx_rc_t
1329efx_mae_action_set_spec_populate(
1330        __in                            efx_mae_actions_t *spec,
1331        __in                            efx_mae_action_t type,
1332        __in                            size_t arg_size,
1333        __in_bcount(arg_size)           const uint8_t *arg)
1334{
1335        uint32_t action_mask;
1336        efx_rc_t rc;
1337
1338        EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1339            (sizeof (efx_mae_action_ordered_map) * 8));
1340        EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <=
1341            (sizeof (efx_mae_action_repeat_map) * 8));
1342
1343        EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS);
1344        EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK);
1345        EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER);
1346
1347        if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) {
1348                rc = EINVAL;
1349                goto fail1;
1350        }
1351
1352        action_mask = (1U << type);
1353
1354        if ((spec->ema_actions & action_mask) != 0) {
1355                /* The action set already contains this action. */
1356                if ((efx_mae_action_repeat_map & action_mask) == 0) {
1357                        /* Cannot add another non-repeatable action. */
1358                        rc = ENOTSUP;
1359                        goto fail2;
1360                }
1361        }
1362
1363        if ((efx_mae_action_ordered_map & action_mask) != 0) {
1364                uint32_t strict_ordered_map =
1365                    efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map;
1366                uint32_t later_actions_mask =
1367                    strict_ordered_map & ~(action_mask | (action_mask - 1));
1368
1369                if ((spec->ema_actions & later_actions_mask) != 0) {
1370                        /* Cannot add an action after later ordered actions. */
1371                        rc = ENOTSUP;
1372                        goto fail3;
1373                }
1374        }
1375
1376        if (efx_mae_actions[type].emad_add != NULL) {
1377                rc = efx_mae_actions[type].emad_add(spec, arg_size, arg);
1378                if (rc != 0)
1379                        goto fail4;
1380        }
1381
1382        spec->ema_actions |= action_mask;
1383
1384        return (0);
1385
1386fail4:
1387        EFSYS_PROBE(fail4);
1388fail3:
1389        EFSYS_PROBE(fail3);
1390fail2:
1391        EFSYS_PROBE(fail2);
1392fail1:
1393        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1394        return (rc);
1395}
1396
1397        __checkReturn                   efx_rc_t
1398efx_mae_action_set_populate_decap(
1399        __in                            efx_mae_actions_t *spec)
1400{
1401        return (efx_mae_action_set_spec_populate(spec,
1402            EFX_MAE_ACTION_DECAP, 0, NULL));
1403}
1404
1405        __checkReturn                   efx_rc_t
1406efx_mae_action_set_populate_vlan_pop(
1407        __in                            efx_mae_actions_t *spec)
1408{
1409        return (efx_mae_action_set_spec_populate(spec,
1410            EFX_MAE_ACTION_VLAN_POP, 0, NULL));
1411}
1412
1413        __checkReturn                   efx_rc_t
1414efx_mae_action_set_populate_vlan_push(
1415        __in                            efx_mae_actions_t *spec,
1416        __in                            uint16_t tpid_be,
1417        __in                            uint16_t tci_be)
1418{
1419        efx_mae_action_vlan_push_t action;
1420        const uint8_t *arg = (const uint8_t *)&action;
1421
1422        action.emavp_tpid_be = tpid_be;
1423        action.emavp_tci_be = tci_be;
1424
1425        return (efx_mae_action_set_spec_populate(spec,
1426            EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg));
1427}
1428
1429        __checkReturn                   efx_rc_t
1430efx_mae_action_set_populate_encap(
1431        __in                            efx_mae_actions_t *spec)
1432{
1433        /*
1434         * There is no argument to pass encap. header ID, thus, one does not
1435         * need to allocate an encap. header while parsing application input.
1436         * This is useful since building an action set may be done simply to
1437         * validate a rule, whilst resource allocation usually consumes time.
1438         */
1439        return (efx_mae_action_set_spec_populate(spec,
1440            EFX_MAE_ACTION_ENCAP, 0, NULL));
1441}
1442
1443        __checkReturn                   efx_rc_t
1444efx_mae_action_set_populate_flag(
1445        __in                            efx_mae_actions_t *spec)
1446{
1447        return (efx_mae_action_set_spec_populate(spec,
1448            EFX_MAE_ACTION_FLAG, 0, NULL));
1449}
1450
1451        __checkReturn                   efx_rc_t
1452efx_mae_action_set_populate_mark(
1453        __in                            efx_mae_actions_t *spec,
1454        __in                            uint32_t mark_value)
1455{
1456        const uint8_t *arg = (const uint8_t *)&mark_value;
1457
1458        return (efx_mae_action_set_spec_populate(spec,
1459            EFX_MAE_ACTION_MARK, sizeof (mark_value), arg));
1460}
1461
1462        __checkReturn                   efx_rc_t
1463efx_mae_action_set_populate_deliver(
1464        __in                            efx_mae_actions_t *spec,
1465        __in                            const efx_mport_sel_t *mportp)
1466{
1467        const uint8_t *arg;
1468        efx_rc_t rc;
1469
1470        if (mportp == NULL) {
1471                rc = EINVAL;
1472                goto fail1;
1473        }
1474
1475        arg = (const uint8_t *)&mportp->sel;
1476
1477        return (efx_mae_action_set_spec_populate(spec,
1478            EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg));
1479
1480fail1:
1481        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1482        return (rc);
1483}
1484
1485        __checkReturn                   efx_rc_t
1486efx_mae_action_set_populate_drop(
1487        __in                            efx_mae_actions_t *spec)
1488{
1489        efx_mport_sel_t mport;
1490        const uint8_t *arg;
1491        efx_dword_t dword;
1492
1493        EFX_POPULATE_DWORD_1(dword,
1494            MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL);
1495
1496        /*
1497         * The constructed DWORD is little-endian,
1498         * but the resulting value is meant to be
1499         * passed to MCDIs, where it will undergo
1500         * host-order to little endian conversion.
1501         */
1502        mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
1503
1504        arg = (const uint8_t *)&mport.sel;
1505
1506        return (efx_mae_action_set_spec_populate(spec,
1507            EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg));
1508}
1509
1510        __checkReturn                   boolean_t
1511efx_mae_action_set_specs_equal(
1512        __in                            const efx_mae_actions_t *left,
1513        __in                            const efx_mae_actions_t *right)
1514{
1515        size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc);
1516
1517        /*
1518         * An action set specification consists of two parts. The first part
1519         * indicates what actions are included in the action set, as well as
1520         * extra quantitative values (in example, the number of VLAN tags to
1521         * push). The second part comprises resource IDs used by the actions.
1522         *
1523         * A resource, in example, a counter, is allocated from the hardware
1524         * by the client, and it's the client who is responsible for keeping
1525         * track of allocated resources and comparing resource IDs if needed.
1526         *
1527         * In this API, don't compare resource IDs in the two specifications.
1528         */
1529
1530        return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE);
1531}
1532
1533        __checkReturn                   efx_rc_t
1534efx_mae_match_specs_class_cmp(
1535        __in                            efx_nic_t *enp,
1536        __in                            const efx_mae_match_spec_t *left,
1537        __in                            const efx_mae_match_spec_t *right,
1538        __out                           boolean_t *have_same_classp)
1539{
1540        efx_mae_t *maep = enp->en_maep;
1541        unsigned int field_ncaps = maep->em_max_nfields;
1542        const efx_mae_field_cap_t *field_caps;
1543        const efx_mae_mv_desc_t *desc_setp;
1544        unsigned int desc_set_nentries;
1545        boolean_t have_same_class = B_TRUE;
1546        efx_mae_field_id_t field_id;
1547        const uint8_t *mvpl;
1548        const uint8_t *mvpr;
1549        efx_rc_t rc;
1550
1551        switch (left->emms_type) {
1552        case EFX_MAE_RULE_OUTER:
1553                field_caps = maep->em_outer_rule_field_caps;
1554                desc_setp = __efx_mae_outer_rule_mv_desc_set;
1555                desc_set_nentries =
1556                    EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set);
1557                mvpl = left->emms_mask_value_pairs.outer;
1558                mvpr = right->emms_mask_value_pairs.outer;
1559                break;
1560        case EFX_MAE_RULE_ACTION:
1561                field_caps = maep->em_action_rule_field_caps;
1562                desc_setp = __efx_mae_action_rule_mv_desc_set;
1563                desc_set_nentries =
1564                    EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set);
1565                mvpl = left->emms_mask_value_pairs.action;
1566                mvpr = right->emms_mask_value_pairs.action;
1567                break;
1568        default:
1569                rc = ENOTSUP;
1570                goto fail1;
1571        }
1572
1573        if (field_caps == NULL) {
1574                rc = EAGAIN;
1575                goto fail2;
1576        }
1577
1578        if (left->emms_type != right->emms_type ||
1579            left->emms_prio != right->emms_prio) {
1580                /*
1581                 * Rules of different types can never map to the same class.
1582                 *
1583                 * The FW can support some set of match criteria for one
1584                 * priority and not support the very same set for
1585                 * another priority. Thus, two rules which have
1586                 * different priorities can never map to
1587                 * the same class.
1588                 */
1589                *have_same_classp = B_FALSE;
1590                return (0);
1591        }
1592
1593        for (field_id = 0; (unsigned int)field_id < desc_set_nentries;
1594             ++field_id) {
1595                const efx_mae_mv_desc_t *descp = &desc_setp[field_id];
1596                efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id;
1597                const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset;
1598                const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset;
1599                size_t mask_size = descp->emmd_mask_size;
1600                const uint8_t *lvalp = mvpl + descp->emmd_value_offset;
1601                const uint8_t *rvalp = mvpr + descp->emmd_value_offset;
1602                size_t value_size = descp->emmd_value_size;
1603
1604                if (mask_size == 0)
1605                        continue; /* Skip array gap */
1606
1607                if ((unsigned int)field_cap_id >= field_ncaps) {
1608                        /*
1609                         * The FW has not reported capability status for this
1610                         * field. It's unknown whether any difference between
1611                         * the two masks / values affects the class. The only
1612                         * case when the class must be the same is when these
1613                         * mask-value pairs match. Otherwise, report mismatch.
1614                         */
1615                        if ((memcmp(lmaskp, rmaskp, mask_size) == 0) &&
1616                            (memcmp(lvalp, rvalp, value_size) == 0))
1617                                continue;
1618                        else
1619                                break;
1620                }
1621
1622                if (field_caps[field_cap_id].emfc_mask_affects_class) {
1623                        if (memcmp(lmaskp, rmaskp, mask_size) != 0) {
1624                                have_same_class = B_FALSE;
1625                                break;
1626                        }
1627                }
1628
1629                if (field_caps[field_cap_id].emfc_match_affects_class) {
1630                        if (memcmp(lvalp, rvalp, value_size) != 0) {
1631                                have_same_class = B_FALSE;
1632                                break;
1633                        }
1634                }
1635        }
1636
1637        *have_same_classp = have_same_class;
1638
1639        return (0);
1640
1641fail2:
1642        EFSYS_PROBE(fail2);
1643fail1:
1644        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1645        return (rc);
1646}
1647
1648        __checkReturn           efx_rc_t
1649efx_mae_outer_rule_insert(
1650        __in                    efx_nic_t *enp,
1651        __in                    const efx_mae_match_spec_t *spec,
1652        __in                    efx_tunnel_protocol_t encap_type,
1653        __out                   efx_mae_rule_id_t *or_idp)
1654{
1655        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1656        efx_mcdi_req_t req;
1657        EFX_MCDI_DECLARE_BUF(payload,
1658            MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2,
1659            MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1660        uint32_t encap_type_mcdi;
1661        efx_mae_rule_id_t or_id;
1662        size_t offset;
1663        efx_rc_t rc;
1664
1665        EFX_STATIC_ASSERT(sizeof (or_idp->id) ==
1666            MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN);
1667
1668        EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1669            MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL);
1670
1671        if (encp->enc_mae_supported == B_FALSE) {
1672                rc = ENOTSUP;
1673                goto fail1;
1674        }
1675
1676        if (spec->emms_type != EFX_MAE_RULE_OUTER) {
1677                rc = EINVAL;
1678                goto fail2;
1679        }
1680
1681        switch (encap_type) {
1682        case EFX_TUNNEL_PROTOCOL_NONE:
1683                encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1684                break;
1685        case EFX_TUNNEL_PROTOCOL_VXLAN:
1686                encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1687                break;
1688        case EFX_TUNNEL_PROTOCOL_GENEVE:
1689                encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1690                break;
1691        case EFX_TUNNEL_PROTOCOL_NVGRE:
1692                encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1693                break;
1694        default:
1695                rc = ENOTSUP;
1696                goto fail3;
1697        }
1698
1699        req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT;
1700        req.emr_in_buf = payload;
1701        req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2;
1702        req.emr_out_buf = payload;
1703        req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN;
1704
1705        MCDI_IN_SET_DWORD(req,
1706            MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi);
1707
1708        MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio);
1709
1710        /*
1711         * Mask-value pairs have been stored in the byte order needed for the
1712         * MCDI request and are thus safe to be copied directly to the buffer.
1713         * The library cares about byte order in efx_mae_match_spec_field_set().
1714         */
1715        EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >=
1716            MAE_ENC_FIELD_PAIRS_LEN);
1717        offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST;
1718        memcpy(payload + offset, spec->emms_mask_value_pairs.outer,
1719            MAE_ENC_FIELD_PAIRS_LEN);
1720
1721        efx_mcdi_execute(enp, &req);
1722
1723        if (req.emr_rc != 0) {
1724                rc = req.emr_rc;
1725                goto fail4;
1726        }
1727
1728        if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) {
1729                rc = EMSGSIZE;
1730                goto fail5;
1731        }
1732
1733        or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1734        if (or_id.id == EFX_MAE_RSRC_ID_INVALID) {
1735                rc = ENOENT;
1736                goto fail6;
1737        }
1738
1739        or_idp->id = or_id.id;
1740
1741        return (0);
1742
1743fail6:
1744        EFSYS_PROBE(fail6);
1745fail5:
1746        EFSYS_PROBE(fail5);
1747fail4:
1748        EFSYS_PROBE(fail4);
1749fail3:
1750        EFSYS_PROBE(fail3);
1751fail2:
1752        EFSYS_PROBE(fail2);
1753fail1:
1754        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1755        return (rc);
1756}
1757
1758        __checkReturn           efx_rc_t
1759efx_mae_outer_rule_remove(
1760        __in                    efx_nic_t *enp,
1761        __in                    const efx_mae_rule_id_t *or_idp)
1762{
1763        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1764        efx_mcdi_req_t req;
1765        EFX_MCDI_DECLARE_BUF(payload,
1766            MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1),
1767            MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1768        efx_rc_t rc;
1769
1770        if (encp->enc_mae_supported == B_FALSE) {
1771                rc = ENOTSUP;
1772                goto fail1;
1773        }
1774
1775        req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE;
1776        req.emr_in_buf = payload;
1777        req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1);
1778        req.emr_out_buf = payload;
1779        req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1);
1780
1781        MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id);
1782
1783        efx_mcdi_execute(enp, &req);
1784
1785        if (req.emr_rc != 0) {
1786                rc = req.emr_rc;
1787                goto fail2;
1788        }
1789
1790        if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) {
1791                rc = EMSGSIZE;
1792                goto fail3;
1793        }
1794
1795        if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) !=
1796            or_idp->id) {
1797                /* Firmware failed to remove the outer rule. */
1798                rc = EAGAIN;
1799                goto fail4;
1800        }
1801
1802        return (0);
1803
1804fail4:
1805        EFSYS_PROBE(fail4);
1806fail3:
1807        EFSYS_PROBE(fail3);
1808fail2:
1809        EFSYS_PROBE(fail2);
1810fail1:
1811        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1812        return (rc);
1813}
1814
1815        __checkReturn                   efx_rc_t
1816efx_mae_match_spec_outer_rule_id_set(
1817        __in                            efx_mae_match_spec_t *spec,
1818        __in                            const efx_mae_rule_id_t *or_idp)
1819{
1820        uint32_t full_mask = UINT32_MAX;
1821        efx_rc_t rc;
1822
1823        if (spec->emms_type != EFX_MAE_RULE_ACTION) {
1824                rc = EINVAL;
1825                goto fail1;
1826        }
1827
1828        if (or_idp == NULL) {
1829                rc = EINVAL;
1830                goto fail2;
1831        }
1832
1833        rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID,
1834            sizeof (or_idp->id), (const uint8_t *)&or_idp->id,
1835            sizeof (full_mask), (const uint8_t *)&full_mask);
1836        if (rc != 0)
1837                goto fail3;
1838
1839        return (0);
1840
1841fail3:
1842        EFSYS_PROBE(fail3);
1843fail2:
1844        EFSYS_PROBE(fail2);
1845fail1:
1846        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1847        return (rc);
1848}
1849
1850         __checkReturn                  efx_rc_t
1851efx_mae_encap_header_alloc(
1852        __in                            efx_nic_t *enp,
1853        __in                            efx_tunnel_protocol_t encap_type,
1854        __in_bcount(header_size)        uint8_t *header_data,
1855        __in                            size_t header_size,
1856        __out                           efx_mae_eh_id_t *eh_idp)
1857{
1858        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1859        efx_mcdi_req_t req;
1860        EFX_MCDI_DECLARE_BUF(payload,
1861            MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2,
1862            MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
1863        uint32_t encap_type_mcdi;
1864        efx_mae_eh_id_t eh_id;
1865        efx_rc_t rc;
1866
1867        EFX_STATIC_ASSERT(sizeof (eh_idp->id) ==
1868            MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN);
1869
1870        EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
1871            MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
1872
1873        if (encp->enc_mae_supported == B_FALSE) {
1874                rc = ENOTSUP;
1875                goto fail1;
1876        }
1877
1878        switch (encap_type) {
1879        case EFX_TUNNEL_PROTOCOL_NONE:
1880                encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE;
1881                break;
1882        case EFX_TUNNEL_PROTOCOL_VXLAN:
1883                encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN;
1884                break;
1885        case EFX_TUNNEL_PROTOCOL_GENEVE:
1886                encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE;
1887                break;
1888        case EFX_TUNNEL_PROTOCOL_NVGRE:
1889                encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE;
1890                break;
1891        default:
1892                rc = ENOTSUP;
1893                goto fail2;
1894        }
1895
1896        if (header_size >
1897            MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) {
1898                rc = EINVAL;
1899                goto fail3;
1900        }
1901
1902        req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC;
1903        req.emr_in_buf = payload;
1904        req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size);
1905        req.emr_out_buf = payload;
1906        req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN;
1907
1908        MCDI_IN_SET_DWORD(req,
1909            MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi);
1910
1911        memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST,
1912            header_data, header_size);
1913
1914        efx_mcdi_execute(enp, &req);
1915
1916        if (req.emr_rc != 0) {
1917                rc = req.emr_rc;
1918                goto fail4;
1919        }
1920
1921        if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) {
1922                rc = EMSGSIZE;
1923                goto fail5;
1924        }
1925
1926        eh_id.id = MCDI_OUT_DWORD(req,
1927            MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
1928
1929        if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) {
1930                rc = ENOENT;
1931                goto fail6;
1932        }
1933
1934        eh_idp->id = eh_id.id;
1935
1936        return (0);
1937
1938fail6:
1939        EFSYS_PROBE(fail6);
1940fail5:
1941        EFSYS_PROBE(fail5);
1942fail4:
1943        EFSYS_PROBE(fail4);
1944fail3:
1945        EFSYS_PROBE(fail3);
1946fail2:
1947        EFSYS_PROBE(fail2);
1948fail1:
1949        EFSYS_PROBE1(fail1, efx_rc_t, rc);
1950        return (rc);
1951}
1952
1953        __checkReturn                   efx_rc_t
1954efx_mae_encap_header_free(
1955        __in                            efx_nic_t *enp,
1956        __in                            const efx_mae_eh_id_t *eh_idp)
1957{
1958        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
1959        efx_mcdi_req_t req;
1960        EFX_MCDI_DECLARE_BUF(payload,
1961            MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1),
1962            MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
1963        efx_rc_t rc;
1964
1965        if (encp->enc_mae_supported == B_FALSE) {
1966                rc = ENOTSUP;
1967                goto fail1;
1968        }
1969
1970        req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE;
1971        req.emr_in_buf = payload;
1972        req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1);
1973        req.emr_out_buf = payload;
1974        req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1);
1975
1976        MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id);
1977
1978        efx_mcdi_execute(enp, &req);
1979
1980        if (req.emr_rc != 0) {
1981                rc = req.emr_rc;
1982                goto fail2;
1983        }
1984
1985        if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) !=
1986            eh_idp->id) {
1987                /* Firmware failed to remove the encap. header. */
1988                rc = EAGAIN;
1989                goto fail3;
1990        }
1991
1992        return (0);
1993
1994fail3:
1995        EFSYS_PROBE(fail3);
1996fail2:
1997        EFSYS_PROBE(fail2);
1998fail1:
1999        EFSYS_PROBE1(fail1, efx_rc_t, rc);
2000        return (rc);
2001}
2002
2003        __checkReturn                   efx_rc_t
2004efx_mae_action_set_fill_in_eh_id(
2005        __in                            efx_mae_actions_t *spec,
2006        __in                            const efx_mae_eh_id_t *eh_idp)
2007{
2008        efx_rc_t rc;
2009
2010        if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) {
2011                /*
2012                 * The caller has not intended to have action ENCAP originally,
2013                 * hence, this attempt to indicate encap. header ID is invalid.
2014                 */
2015                rc = EINVAL;
2016                goto fail1;
2017        }
2018
2019        if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) {
2020                /* The caller attempts to indicate encap. header ID twice. */
2021                rc = EINVAL;
2022                goto fail2;
2023        }
2024
2025        if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) {
2026                rc = EINVAL;
2027                goto fail3;
2028        }
2029
2030        spec->ema_rsrc.emar_eh_id.id = eh_idp->id;
2031
2032        return (0);
2033
2034fail3:
2035        EFSYS_PROBE(fail3);
2036fail2:
2037        EFSYS_PROBE(fail2);
2038fail1:
2039        EFSYS_PROBE1(fail1, efx_rc_t, rc);
2040        return (rc);
2041}
2042
2043        __checkReturn                   efx_rc_t
2044efx_mae_action_set_alloc(
2045        __in                            efx_nic_t *enp,
2046        __in                            const efx_mae_actions_t *spec,
2047        __out                           efx_mae_aset_id_t *aset_idp)
2048{
2049        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2050        efx_mcdi_req_t req;
2051        EFX_MCDI_DECLARE_BUF(payload,
2052            MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN,
2053            MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
2054        efx_mae_aset_id_t aset_id;
2055        efx_rc_t rc;
2056
2057        if (encp->enc_mae_supported == B_FALSE) {
2058                rc = ENOTSUP;
2059                goto fail1;
2060        }
2061
2062        req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC;
2063        req.emr_in_buf = payload;
2064        req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN;
2065        req.emr_out_buf = payload;
2066        req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN;
2067
2068        /*
2069         * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the
2070         * corresponding resource types are supported by the implementation.
2071         * Use proper resource ID assignments instead.
2072         */
2073        MCDI_IN_SET_DWORD(req,
2074            MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID);
2075        MCDI_IN_SET_DWORD(req,
2076            MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2077
2078        if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) {
2079                MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2080                    MAE_ACTION_SET_ALLOC_IN_DECAP, 1);
2081        }
2082
2083        MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2084            MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop);
2085
2086        if (spec->ema_n_vlan_tags_to_push > 0) {
2087                unsigned int outer_tag_idx;
2088
2089                MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2090                    MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH,
2091                    spec->ema_n_vlan_tags_to_push);
2092
2093                if (spec->ema_n_vlan_tags_to_push ==
2094                    EFX_MAE_VLAN_PUSH_MAX_NTAGS) {
2095                        MCDI_IN_SET_WORD(req,
2096                            MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
2097                            spec->ema_vlan_push_descs[0].emavp_tpid_be);
2098                        MCDI_IN_SET_WORD(req,
2099                            MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
2100                            spec->ema_vlan_push_descs[0].emavp_tci_be);
2101                }
2102
2103                outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1;
2104
2105                MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
2106                    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be);
2107                MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
2108                    spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be);
2109        }
2110
2111        MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
2112            spec->ema_rsrc.emar_eh_id.id);
2113
2114        if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) {
2115                MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2116                    MAE_ACTION_SET_ALLOC_IN_FLAG, 1);
2117        }
2118
2119        if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) {
2120                MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS,
2121                    MAE_ACTION_SET_ALLOC_IN_MARK, 1);
2122
2123                MCDI_IN_SET_DWORD(req,
2124                    MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value);
2125        }
2126
2127        MCDI_IN_SET_DWORD(req,
2128            MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel);
2129
2130        MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
2131            MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2132        MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
2133            MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
2134
2135        efx_mcdi_execute(enp, &req);
2136
2137        if (req.emr_rc != 0) {
2138                rc = req.emr_rc;
2139                goto fail2;
2140        }
2141
2142        if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) {
2143                rc = EMSGSIZE;
2144                goto fail3;
2145        }
2146
2147        aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
2148        if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) {
2149                rc = ENOENT;
2150                goto fail4;
2151        }
2152
2153        aset_idp->id = aset_id.id;
2154
2155        return (0);
2156
2157fail4:
2158        EFSYS_PROBE(fail4);
2159fail3:
2160        EFSYS_PROBE(fail3);
2161fail2:
2162        EFSYS_PROBE(fail2);
2163fail1:
2164        EFSYS_PROBE1(fail1, efx_rc_t, rc);
2165        return (rc);
2166}
2167
2168        __checkReturn                   efx_rc_t
2169efx_mae_action_set_free(
2170        __in                            efx_nic_t *enp,
2171        __in                            const efx_mae_aset_id_t *aset_idp)
2172{
2173        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2174        efx_mcdi_req_t req;
2175        EFX_MCDI_DECLARE_BUF(payload,
2176            MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1),
2177            MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
2178        efx_rc_t rc;
2179
2180        if (encp->enc_mae_supported == B_FALSE) {
2181                rc = ENOTSUP;
2182                goto fail1;
2183        }
2184
2185        req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE;
2186        req.emr_in_buf = payload;
2187        req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1);
2188        req.emr_out_buf = payload;
2189        req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1);
2190
2191        MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id);
2192
2193        efx_mcdi_execute(enp, &req);
2194
2195        if (req.emr_rc != 0) {
2196                rc = req.emr_rc;
2197                goto fail2;
2198        }
2199
2200        if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) {
2201                rc = EMSGSIZE;
2202                goto fail3;
2203        }
2204
2205        if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) !=
2206            aset_idp->id) {
2207                /* Firmware failed to free the action set. */
2208                rc = EAGAIN;
2209                goto fail4;
2210        }
2211
2212        return (0);
2213
2214fail4:
2215        EFSYS_PROBE(fail4);
2216fail3:
2217        EFSYS_PROBE(fail3);
2218fail2:
2219        EFSYS_PROBE(fail2);
2220fail1:
2221        EFSYS_PROBE1(fail1, efx_rc_t, rc);
2222        return (rc);
2223}
2224
2225        __checkReturn                   efx_rc_t
2226efx_mae_action_rule_insert(
2227        __in                            efx_nic_t *enp,
2228        __in                            const efx_mae_match_spec_t *spec,
2229        __in                            const efx_mae_aset_list_id_t *asl_idp,
2230        __in                            const efx_mae_aset_id_t *as_idp,
2231        __out                           efx_mae_rule_id_t *ar_idp)
2232{
2233        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2234        efx_mcdi_req_t req;
2235        EFX_MCDI_DECLARE_BUF(payload,
2236            MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2,
2237            MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2238        efx_oword_t *rule_response;
2239        efx_mae_rule_id_t ar_id;
2240        size_t offset;
2241        efx_rc_t rc;
2242
2243        EFX_STATIC_ASSERT(sizeof (ar_idp->id) ==
2244            MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN);
2245
2246        EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID ==
2247            MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL);
2248
2249        if (encp->enc_mae_supported == B_FALSE) {
2250                rc = ENOTSUP;
2251                goto fail1;
2252        }
2253
2254        if (spec->emms_type != EFX_MAE_RULE_ACTION ||
2255            (asl_idp != NULL && as_idp != NULL) ||
2256            (asl_idp == NULL && as_idp == NULL)) {
2257                rc = EINVAL;
2258                goto fail2;
2259        }
2260
2261        req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT;
2262        req.emr_in_buf = payload;
2263        req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2;
2264        req.emr_out_buf = payload;
2265        req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN;
2266
2267        EFX_STATIC_ASSERT(sizeof (*rule_response) <=
2268            MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN);
2269        offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST;
2270        rule_response = (efx_oword_t *)(payload + offset);
2271        EFX_POPULATE_OWORD_3(*rule_response,
2272            MAE_ACTION_RULE_RESPONSE_ASL_ID,
2273            (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID,
2274            MAE_ACTION_RULE_RESPONSE_AS_ID,
2275            (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID,
2276            MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID);
2277
2278        MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio);
2279
2280        /*
2281         * Mask-value pairs have been stored in the byte order needed for the
2282         * MCDI request and are thus safe to be copied directly to the buffer.
2283         */
2284        EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >=
2285            MAE_FIELD_MASK_VALUE_PAIRS_LEN);
2286        offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST;
2287        memcpy(payload + offset, spec->emms_mask_value_pairs.action,
2288            MAE_FIELD_MASK_VALUE_PAIRS_LEN);
2289
2290        efx_mcdi_execute(enp, &req);
2291
2292        if (req.emr_rc != 0) {
2293                rc = req.emr_rc;
2294                goto fail3;
2295        }
2296
2297        if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) {
2298                rc = EMSGSIZE;
2299                goto fail4;
2300        }
2301
2302        ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2303        if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) {
2304                rc = ENOENT;
2305                goto fail5;
2306        }
2307
2308        ar_idp->id = ar_id.id;
2309
2310        return (0);
2311
2312fail5:
2313        EFSYS_PROBE(fail5);
2314fail4:
2315        EFSYS_PROBE(fail4);
2316fail3:
2317        EFSYS_PROBE(fail3);
2318fail2:
2319        EFSYS_PROBE(fail2);
2320fail1:
2321        EFSYS_PROBE1(fail1, efx_rc_t, rc);
2322        return (rc);
2323}
2324
2325        __checkReturn                   efx_rc_t
2326efx_mae_action_rule_remove(
2327        __in                            efx_nic_t *enp,
2328        __in                            const efx_mae_rule_id_t *ar_idp)
2329{
2330        const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp);
2331        efx_mcdi_req_t req;
2332        EFX_MCDI_DECLARE_BUF(payload,
2333            MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1),
2334            MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2335        efx_rc_t rc;
2336
2337        if (encp->enc_mae_supported == B_FALSE) {
2338                rc = ENOTSUP;
2339                goto fail1;
2340        }
2341
2342        req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE;
2343        req.emr_in_buf = payload;
2344        req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1);
2345        req.emr_out_buf = payload;
2346        req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1);
2347
2348        MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id);
2349
2350        efx_mcdi_execute(enp, &req);
2351
2352        if (req.emr_rc != 0) {
2353                rc = req.emr_rc;
2354                goto fail2;
2355        }
2356
2357        if (req.emr_out_length_used <
2358            MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) {
2359                rc = EMSGSIZE;
2360                goto fail3;
2361        }
2362
2363        if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) !=
2364            ar_idp->id) {
2365                /* Firmware failed to delete the action rule. */
2366                rc = EAGAIN;
2367                goto fail4;
2368        }
2369
2370        return (0);
2371
2372fail4:
2373        EFSYS_PROBE(fail4);
2374fail3:
2375        EFSYS_PROBE(fail3);
2376fail2:
2377        EFSYS_PROBE(fail2);
2378fail1:
2379        EFSYS_PROBE1(fail1, efx_rc_t, rc);
2380        return (rc);
2381}
2382
2383#endif /* EFSYS_OPT_MAE */
2384