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