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