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 maep->em_max_ncounters = 71 MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_COUNTERS); 72 73 return (0); 74 75 fail2: 76 EFSYS_PROBE(fail2); 77 fail1: 78 EFSYS_PROBE1(fail1, efx_rc_t, rc); 79 return (rc); 80 } 81 82 static __checkReturn efx_rc_t 83 efx_mae_get_outer_rule_caps( 84 __in efx_nic_t *enp, 85 __in unsigned int field_ncaps, 86 __out_ecount(field_ncaps) efx_mae_field_cap_t *field_caps) 87 { 88 efx_mcdi_req_t req; 89 EFX_MCDI_DECLARE_BUF(payload, 90 MC_CMD_MAE_GET_OR_CAPS_IN_LEN, 91 MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2); 92 unsigned int mcdi_field_ncaps; 93 unsigned int i; 94 efx_rc_t rc; 95 96 if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) > 97 MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) { 98 rc = EINVAL; 99 goto fail1; 100 } 101 102 req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS; 103 req.emr_in_buf = payload; 104 req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN; 105 req.emr_out_buf = payload; 106 req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps); 107 108 efx_mcdi_execute(enp, &req); 109 110 if (req.emr_rc != 0) { 111 rc = req.emr_rc; 112 goto fail2; 113 } 114 115 if (req.emr_out_length_used < MC_CMD_MAE_GET_OR_CAPS_OUT_LENMIN) { 116 rc = EMSGSIZE; 117 goto fail3; 118 } 119 120 mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT); 121 122 if (req.emr_out_length_used < 123 MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) { 124 rc = EMSGSIZE; 125 goto fail4; 126 } 127 128 if (mcdi_field_ncaps > field_ncaps) { 129 rc = EMSGSIZE; 130 goto fail5; 131 } 132 133 for (i = 0; i < mcdi_field_ncaps; ++i) { 134 uint32_t match_flag; 135 uint32_t mask_flag; 136 137 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req, 138 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i, 139 MAE_FIELD_FLAGS_SUPPORT_STATUS); 140 141 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req, 142 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i, 143 MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS); 144 145 field_caps[i].emfc_match_affects_class = 146 (match_flag != 0) ? B_TRUE : B_FALSE; 147 148 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req, 149 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i, 150 MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS); 151 152 field_caps[i].emfc_mask_affects_class = 153 (mask_flag != 0) ? B_TRUE : B_FALSE; 154 } 155 156 return (0); 157 158 fail5: 159 EFSYS_PROBE(fail5); 160 fail4: 161 EFSYS_PROBE(fail4); 162 fail3: 163 EFSYS_PROBE(fail3); 164 fail2: 165 EFSYS_PROBE(fail2); 166 fail1: 167 EFSYS_PROBE1(fail1, efx_rc_t, rc); 168 return (rc); 169 } 170 171 static __checkReturn efx_rc_t 172 efx_mae_get_action_rule_caps( 173 __in efx_nic_t *enp, 174 __in unsigned int field_ncaps, 175 __out_ecount(field_ncaps) efx_mae_field_cap_t *field_caps) 176 { 177 efx_mcdi_req_t req; 178 EFX_MCDI_DECLARE_BUF(payload, 179 MC_CMD_MAE_GET_AR_CAPS_IN_LEN, 180 MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2); 181 unsigned int mcdi_field_ncaps; 182 unsigned int i; 183 efx_rc_t rc; 184 185 if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) > 186 MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) { 187 rc = EINVAL; 188 goto fail1; 189 } 190 191 req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS; 192 req.emr_in_buf = payload; 193 req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN; 194 req.emr_out_buf = payload; 195 req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps); 196 197 efx_mcdi_execute(enp, &req); 198 199 if (req.emr_rc != 0) { 200 rc = req.emr_rc; 201 goto fail2; 202 } 203 204 if (req.emr_out_length_used < MC_CMD_MAE_GET_AR_CAPS_OUT_LENMIN) { 205 rc = EMSGSIZE; 206 goto fail3; 207 } 208 209 mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_AR_CAPS_OUT_COUNT); 210 211 if (req.emr_out_length_used < 212 MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) { 213 rc = EMSGSIZE; 214 goto fail4; 215 } 216 217 if (mcdi_field_ncaps > field_ncaps) { 218 rc = EMSGSIZE; 219 goto fail5; 220 } 221 222 for (i = 0; i < mcdi_field_ncaps; ++i) { 223 uint32_t match_flag; 224 uint32_t mask_flag; 225 226 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req, 227 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i, 228 MAE_FIELD_FLAGS_SUPPORT_STATUS); 229 230 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req, 231 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i, 232 MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS); 233 234 field_caps[i].emfc_match_affects_class = 235 (match_flag != 0) ? B_TRUE : B_FALSE; 236 237 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req, 238 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i, 239 MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS); 240 241 field_caps[i].emfc_mask_affects_class = 242 (mask_flag != 0) ? B_TRUE : B_FALSE; 243 } 244 245 return (0); 246 247 fail5: 248 EFSYS_PROBE(fail5); 249 fail4: 250 EFSYS_PROBE(fail4); 251 fail3: 252 EFSYS_PROBE(fail3); 253 fail2: 254 EFSYS_PROBE(fail2); 255 fail1: 256 EFSYS_PROBE1(fail1, efx_rc_t, rc); 257 return (rc); 258 } 259 260 __checkReturn efx_rc_t 261 efx_mae_init( 262 __in efx_nic_t *enp) 263 { 264 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 265 efx_mae_field_cap_t *or_fcaps; 266 size_t or_fcaps_size; 267 efx_mae_field_cap_t *ar_fcaps; 268 size_t ar_fcaps_size; 269 efx_mae_t *maep; 270 efx_rc_t rc; 271 272 if (encp->enc_mae_supported == B_FALSE) { 273 rc = ENOTSUP; 274 goto fail1; 275 } 276 277 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep); 278 if (maep == NULL) { 279 rc = ENOMEM; 280 goto fail2; 281 } 282 283 enp->en_maep = maep; 284 285 rc = efx_mae_get_capabilities(enp); 286 if (rc != 0) 287 goto fail3; 288 289 or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps); 290 EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps); 291 if (or_fcaps == NULL) { 292 rc = ENOMEM; 293 goto fail4; 294 } 295 296 maep->em_outer_rule_field_caps_size = or_fcaps_size; 297 maep->em_outer_rule_field_caps = or_fcaps; 298 299 rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps); 300 if (rc != 0) 301 goto fail5; 302 303 ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps); 304 EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps); 305 if (ar_fcaps == NULL) { 306 rc = ENOMEM; 307 goto fail6; 308 } 309 310 maep->em_action_rule_field_caps_size = ar_fcaps_size; 311 maep->em_action_rule_field_caps = ar_fcaps; 312 313 rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps); 314 if (rc != 0) 315 goto fail7; 316 317 return (0); 318 319 fail7: 320 EFSYS_PROBE(fail5); 321 EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps); 322 fail6: 323 EFSYS_PROBE(fail4); 324 fail5: 325 EFSYS_PROBE(fail5); 326 EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps); 327 fail4: 328 EFSYS_PROBE(fail4); 329 fail3: 330 EFSYS_PROBE(fail3); 331 EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep); 332 enp->en_maep = NULL; 333 fail2: 334 EFSYS_PROBE(fail2); 335 fail1: 336 EFSYS_PROBE1(fail1, efx_rc_t, rc); 337 return (rc); 338 } 339 340 void 341 efx_mae_fini( 342 __in efx_nic_t *enp) 343 { 344 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 345 efx_mae_t *maep = enp->en_maep; 346 347 if (encp->enc_mae_supported == B_FALSE) 348 return; 349 350 EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size, 351 maep->em_action_rule_field_caps); 352 EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size, 353 maep->em_outer_rule_field_caps); 354 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep); 355 enp->en_maep = NULL; 356 } 357 358 __checkReturn efx_rc_t 359 efx_mae_get_limits( 360 __in efx_nic_t *enp, 361 __out efx_mae_limits_t *emlp) 362 { 363 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 364 struct efx_mae_s *maep = enp->en_maep; 365 efx_rc_t rc; 366 367 if (encp->enc_mae_supported == B_FALSE) { 368 rc = ENOTSUP; 369 goto fail1; 370 } 371 372 emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios; 373 emlp->eml_max_n_action_prios = maep->em_max_n_action_prios; 374 emlp->eml_encap_types_supported = maep->em_encap_types_supported; 375 emlp->eml_encap_header_size_limit = 376 MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2; 377 emlp->eml_max_n_counters = maep->em_max_ncounters; 378 379 return (0); 380 381 fail1: 382 EFSYS_PROBE1(fail1, efx_rc_t, rc); 383 return (rc); 384 } 385 386 __checkReturn efx_rc_t 387 efx_mae_match_spec_init( 388 __in efx_nic_t *enp, 389 __in efx_mae_rule_type_t type, 390 __in uint32_t prio, 391 __out efx_mae_match_spec_t **specp) 392 { 393 efx_mae_match_spec_t *spec; 394 efx_rc_t rc; 395 396 switch (type) { 397 case EFX_MAE_RULE_OUTER: 398 break; 399 case EFX_MAE_RULE_ACTION: 400 break; 401 default: 402 rc = ENOTSUP; 403 goto fail1; 404 } 405 406 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec); 407 if (spec == NULL) { 408 rc = ENOMEM; 409 goto fail2; 410 } 411 412 spec->emms_type = type; 413 spec->emms_prio = prio; 414 415 *specp = spec; 416 417 return (0); 418 419 fail2: 420 EFSYS_PROBE(fail2); 421 fail1: 422 EFSYS_PROBE1(fail1, efx_rc_t, rc); 423 return (rc); 424 } 425 426 void 427 efx_mae_match_spec_fini( 428 __in efx_nic_t *enp, 429 __in efx_mae_match_spec_t *spec) 430 { 431 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 432 } 433 434 /* Named identifiers which are valid indices to efx_mae_field_cap_t */ 435 typedef enum efx_mae_field_cap_id_e { 436 EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT, 437 EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE, 438 EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR, 439 EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR, 440 EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI, 441 EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO, 442 EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI, 443 EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO, 444 EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4, 445 EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4, 446 EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO, 447 EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS, 448 EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL, 449 EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6, 450 EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6, 451 EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT, 452 EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT, 453 EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS, 454 EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE, 455 EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR, 456 EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR, 457 EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI, 458 EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO, 459 EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI, 460 EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO, 461 EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4, 462 EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4, 463 EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO, 464 EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS, 465 EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL, 466 EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6, 467 EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6, 468 EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT, 469 EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT, 470 EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID, 471 EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID, 472 EFX_MAE_FIELD_ID_HAS_OVLAN = MAE_FIELD_HAS_OVLAN, 473 EFX_MAE_FIELD_ID_HAS_IVLAN = MAE_FIELD_HAS_IVLAN, 474 EFX_MAE_FIELD_ID_ENC_HAS_OVLAN = MAE_FIELD_ENC_HAS_OVLAN, 475 EFX_MAE_FIELD_ID_ENC_HAS_IVLAN = MAE_FIELD_ENC_HAS_IVLAN, 476 EFX_MAE_FIELD_ID_RECIRC_ID = MAE_FIELD_RECIRC_ID, 477 478 EFX_MAE_FIELD_CAP_NIDS 479 } efx_mae_field_cap_id_t; 480 481 typedef enum efx_mae_field_endianness_e { 482 EFX_MAE_FIELD_LE = 0, 483 EFX_MAE_FIELD_BE, 484 485 EFX_MAE_FIELD_ENDIANNESS_NTYPES 486 } efx_mae_field_endianness_t; 487 488 /* 489 * The following structure is a means to describe an MAE field. 490 * The information in it is meant to be used internally by 491 * APIs for addressing a given field in a mask-value pairs 492 * structure and for validation purposes. 493 * 494 * A field may have an alternative one. This structure 495 * has additional members to reference the alternative 496 * field's mask. See efx_mae_match_spec_is_valid(). 497 */ 498 typedef struct efx_mae_mv_desc_s { 499 efx_mae_field_cap_id_t emmd_field_cap_id; 500 501 size_t emmd_value_size; 502 size_t emmd_value_offset; 503 size_t emmd_mask_size; 504 size_t emmd_mask_offset; 505 506 /* 507 * Having the alternative field's mask size set to 0 508 * means that there's no alternative field specified. 509 */ 510 size_t emmd_alt_mask_size; 511 size_t emmd_alt_mask_offset; 512 513 /* Primary field and the alternative one are of the same endianness. */ 514 efx_mae_field_endianness_t emmd_endianness; 515 } efx_mae_mv_desc_t; 516 517 /* Indices to this array are provided by efx_mae_field_id_t */ 518 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = { 519 #define EFX_MAE_MV_DESC(_name, _endianness) \ 520 [EFX_MAE_FIELD_##_name] = \ 521 { \ 522 EFX_MAE_FIELD_ID_##_name, \ 523 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LEN, \ 524 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_OFST, \ 525 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_MASK_LEN, \ 526 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_MASK_OFST, \ 527 0, 0 /* no alternative field */, \ 528 _endianness \ 529 } 530 531 EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE), 532 EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE), 533 EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE), 534 EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE), 535 EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE), 536 EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE), 537 EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE), 538 EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE), 539 EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE), 540 EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE), 541 EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE), 542 EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE), 543 EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE), 544 EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE), 545 EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE), 546 EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE), 547 EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE), 548 EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE), 549 EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE), 550 EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE), 551 EFX_MAE_MV_DESC(RECIRC_ID, EFX_MAE_FIELD_LE), 552 553 #undef EFX_MAE_MV_DESC 554 }; 555 556 /* Indices to this array are provided by efx_mae_field_id_t */ 557 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = { 558 #define EFX_MAE_MV_DESC(_name, _endianness) \ 559 [EFX_MAE_FIELD_##_name] = \ 560 { \ 561 EFX_MAE_FIELD_ID_##_name, \ 562 MAE_ENC_FIELD_PAIRS_##_name##_LEN, \ 563 MAE_ENC_FIELD_PAIRS_##_name##_OFST, \ 564 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN, \ 565 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \ 566 0, 0 /* no alternative field */, \ 567 _endianness \ 568 } 569 570 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */ 571 #define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness) \ 572 [EFX_MAE_FIELD_##_name] = \ 573 { \ 574 EFX_MAE_FIELD_ID_##_name, \ 575 MAE_ENC_FIELD_PAIRS_##_name##_LEN, \ 576 MAE_ENC_FIELD_PAIRS_##_name##_OFST, \ 577 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN, \ 578 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \ 579 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN, \ 580 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST, \ 581 _endianness \ 582 } 583 584 EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE), 585 EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE), 586 EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE), 587 EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE), 588 EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE), 589 EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE), 590 EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE), 591 EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE), 592 EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE), 593 EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE), 594 EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE), 595 EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE), 596 EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE), 597 EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE), 598 EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE), 599 EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE), 600 EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE), 601 602 #undef EFX_MAE_MV_DESC_ALT 603 #undef EFX_MAE_MV_DESC 604 }; 605 606 /* 607 * The following structure is a means to describe an MAE bit. 608 * The information in it is meant to be used internally by 609 * APIs for addressing a given flag in a mask-value pairs 610 * structure and for validation purposes. 611 */ 612 typedef struct efx_mae_mv_bit_desc_s { 613 /* 614 * Arrays using this struct are indexed by field IDs. 615 * Fields which aren't meant to be referenced by these 616 * arrays comprise gaps (invalid entries). Below field 617 * helps to identify such entries. 618 */ 619 boolean_t emmbd_entry_is_valid; 620 efx_mae_field_cap_id_t emmbd_bit_cap_id; 621 size_t emmbd_value_ofst; 622 unsigned int emmbd_value_lbn; 623 size_t emmbd_mask_ofst; 624 unsigned int emmbd_mask_lbn; 625 } efx_mae_mv_bit_desc_t; 626 627 static const efx_mae_mv_bit_desc_t __efx_mae_outer_rule_mv_bit_desc_set[] = { 628 #define EFX_MAE_MV_BIT_DESC(_name) \ 629 [EFX_MAE_FIELD_##_name] = \ 630 { \ 631 B_TRUE, \ 632 EFX_MAE_FIELD_ID_##_name, \ 633 MAE_ENC_FIELD_PAIRS_##_name##_OFST, \ 634 MAE_ENC_FIELD_PAIRS_##_name##_LBN, \ 635 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \ 636 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LBN, \ 637 } 638 639 EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN), 640 EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN), 641 642 #undef EFX_MAE_MV_BIT_DESC 643 }; 644 645 static const efx_mae_mv_bit_desc_t __efx_mae_action_rule_mv_bit_desc_set[] = { 646 #define EFX_MAE_MV_BIT_DESC(_name) \ 647 [EFX_MAE_FIELD_##_name] = \ 648 { \ 649 B_TRUE, \ 650 EFX_MAE_FIELD_ID_##_name, \ 651 MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_OFST, \ 652 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN, \ 653 MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK_OFST, \ 654 MAE_FIELD_MASK_VALUE_PAIRS_V2_##_name##_LBN, \ 655 } 656 657 EFX_MAE_MV_BIT_DESC(HAS_OVLAN), 658 EFX_MAE_MV_BIT_DESC(HAS_IVLAN), 659 EFX_MAE_MV_BIT_DESC(ENC_HAS_OVLAN), 660 EFX_MAE_MV_BIT_DESC(ENC_HAS_IVLAN), 661 662 #undef EFX_MAE_MV_BIT_DESC 663 }; 664 665 __checkReturn efx_rc_t 666 efx_mae_mport_invalid( 667 __out efx_mport_sel_t *mportp) 668 { 669 efx_dword_t dword; 670 efx_rc_t rc; 671 672 if (mportp == NULL) { 673 rc = EINVAL; 674 goto fail1; 675 } 676 677 EFX_POPULATE_DWORD_1(dword, 678 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_INVALID); 679 680 memset(mportp, 0, sizeof (*mportp)); 681 mportp->sel = dword.ed_u32[0]; 682 683 return (0); 684 685 fail1: 686 EFSYS_PROBE1(fail1, efx_rc_t, rc); 687 return (rc); 688 } 689 690 __checkReturn efx_rc_t 691 efx_mae_mport_by_phy_port( 692 __in uint32_t phy_port, 693 __out efx_mport_sel_t *mportp) 694 { 695 efx_dword_t dword; 696 efx_rc_t rc; 697 698 if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) { 699 rc = EINVAL; 700 goto fail1; 701 } 702 703 EFX_POPULATE_DWORD_2(dword, 704 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT, 705 MAE_MPORT_SELECTOR_PPORT_ID, phy_port); 706 707 memset(mportp, 0, sizeof (*mportp)); 708 /* 709 * The constructed DWORD is little-endian, 710 * but the resulting value is meant to be 711 * passed to MCDIs, where it will undergo 712 * host-order to little endian conversion. 713 */ 714 mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 715 716 return (0); 717 718 fail1: 719 EFSYS_PROBE1(fail1, efx_rc_t, rc); 720 return (rc); 721 } 722 723 __checkReturn efx_rc_t 724 efx_mae_mport_by_pcie_function( 725 __in uint32_t pf, 726 __in uint32_t vf, 727 __out efx_mport_sel_t *mportp) 728 { 729 efx_dword_t dword; 730 efx_rc_t rc; 731 732 rc = efx_mae_mport_by_pcie_mh_function(EFX_PCIE_INTERFACE_CALLER, 733 pf, vf, mportp); 734 if (rc != 0) 735 goto fail1; 736 737 return (0); 738 739 fail1: 740 EFSYS_PROBE1(fail1, efx_rc_t, rc); 741 return (rc); 742 } 743 744 static __checkReturn efx_rc_t 745 efx_mae_intf_to_selector( 746 __in efx_pcie_interface_t intf, 747 __out uint32_t *selector_intfp) 748 { 749 efx_rc_t rc; 750 751 switch (intf) { 752 case EFX_PCIE_INTERFACE_HOST_PRIMARY: 753 EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_HOST_PRIMARY <= 754 EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID)); 755 *selector_intfp = MAE_MPORT_SELECTOR_HOST_PRIMARY; 756 break; 757 case EFX_PCIE_INTERFACE_NIC_EMBEDDED: 758 EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_NIC_EMBEDDED <= 759 EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID)); 760 *selector_intfp = MAE_MPORT_SELECTOR_NIC_EMBEDDED; 761 break; 762 case EFX_PCIE_INTERFACE_CALLER: 763 EFX_STATIC_ASSERT(MAE_MPORT_SELECTOR_CALLER_INTF <= 764 EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_INTF_ID)); 765 *selector_intfp = MAE_MPORT_SELECTOR_CALLER_INTF; 766 break; 767 default: 768 rc = EINVAL; 769 goto fail1; 770 } 771 772 return (0); 773 774 fail1: 775 EFSYS_PROBE1(fail1, efx_rc_t, rc); 776 return (rc); 777 } 778 779 __checkReturn efx_rc_t 780 efx_mae_mport_by_pcie_mh_function( 781 __in efx_pcie_interface_t intf, 782 __in uint32_t pf, 783 __in uint32_t vf, 784 __out efx_mport_sel_t *mportp) 785 { 786 uint32_t selector_intf; 787 efx_dword_t dword; 788 efx_rc_t rc; 789 790 EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID == 791 MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL); 792 793 rc = efx_mae_intf_to_selector(intf, &selector_intf); 794 if (rc != 0) 795 goto fail1; 796 797 if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_MH_PF_ID)) { 798 rc = EINVAL; 799 goto fail2; 800 } 801 802 if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) { 803 rc = EINVAL; 804 goto fail3; 805 } 806 807 808 EFX_POPULATE_DWORD_4(dword, 809 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MH_FUNC, 810 MAE_MPORT_SELECTOR_FUNC_INTF_ID, selector_intf, 811 MAE_MPORT_SELECTOR_FUNC_MH_PF_ID, pf, 812 MAE_MPORT_SELECTOR_FUNC_VF_ID, vf); 813 814 memset(mportp, 0, sizeof (*mportp)); 815 mportp->sel = dword.ed_u32[0]; 816 817 return (0); 818 819 fail3: 820 EFSYS_PROBE(fail3); 821 fail2: 822 EFSYS_PROBE(fail2); 823 fail1: 824 EFSYS_PROBE1(fail1, efx_rc_t, rc); 825 return (rc); 826 } 827 828 static __checkReturn efx_rc_t 829 efx_mcdi_mae_mport_lookup( 830 __in efx_nic_t *enp, 831 __in const efx_mport_sel_t *mport_selectorp, 832 __out efx_mport_id_t *mport_idp) 833 { 834 efx_mcdi_req_t req; 835 EFX_MCDI_DECLARE_BUF(payload, 836 MC_CMD_MAE_MPORT_LOOKUP_IN_LEN, 837 MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN); 838 efx_rc_t rc; 839 840 req.emr_cmd = MC_CMD_MAE_MPORT_LOOKUP; 841 req.emr_in_buf = payload; 842 req.emr_in_length = MC_CMD_MAE_MPORT_LOOKUP_IN_LEN; 843 req.emr_out_buf = payload; 844 req.emr_out_length = MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN; 845 846 MCDI_IN_SET_DWORD(req, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR, 847 mport_selectorp->sel); 848 849 efx_mcdi_execute(enp, &req); 850 851 if (req.emr_rc != 0) { 852 rc = req.emr_rc; 853 goto fail1; 854 } 855 856 mport_idp->id = MCDI_OUT_DWORD(req, MAE_MPORT_LOOKUP_OUT_MPORT_ID); 857 858 return (0); 859 860 fail1: 861 EFSYS_PROBE1(fail1, efx_rc_t, rc); 862 return (rc); 863 } 864 865 __checkReturn efx_rc_t 866 efx_mae_mport_id_by_selector( 867 __in efx_nic_t *enp, 868 __in const efx_mport_sel_t *mport_selectorp, 869 __out efx_mport_id_t *mport_idp) 870 { 871 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 872 efx_rc_t rc; 873 874 if (encp->enc_mae_supported == B_FALSE) { 875 rc = ENOTSUP; 876 goto fail1; 877 } 878 879 rc = efx_mcdi_mae_mport_lookup(enp, mport_selectorp, mport_idp); 880 if (rc != 0) 881 goto fail2; 882 883 return (0); 884 885 fail2: 886 EFSYS_PROBE(fail2); 887 fail1: 888 EFSYS_PROBE1(fail1, efx_rc_t, rc); 889 return (rc); 890 } 891 892 __checkReturn efx_rc_t 893 efx_mae_match_spec_recirc_id_set( 894 __in efx_mae_match_spec_t *spec, 895 __in uint8_t recirc_id) 896 { 897 uint8_t full_mask = UINT8_MAX; 898 const uint8_t *vp; 899 const uint8_t *mp; 900 efx_rc_t rc; 901 902 vp = (const uint8_t *)&recirc_id; 903 mp = (const uint8_t *)&full_mask; 904 905 rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_RECIRC_ID, 906 sizeof (recirc_id), vp, 907 sizeof (full_mask), mp); 908 if (rc != 0) 909 goto fail1; 910 911 return (0); 912 913 fail1: 914 EFSYS_PROBE1(fail1, efx_rc_t, rc); 915 return (rc); 916 } 917 918 __checkReturn efx_rc_t 919 efx_mae_mport_by_id( 920 __in const efx_mport_id_t *mport_idp, 921 __out efx_mport_sel_t *mportp) 922 { 923 efx_dword_t dword; 924 925 EFX_POPULATE_DWORD_2(dword, 926 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID, 927 MAE_MPORT_SELECTOR_MPORT_ID, mport_idp->id); 928 929 memset(mportp, 0, sizeof (*mportp)); 930 mportp->sel = __LE_TO_CPU_32(dword.ed_u32[0]); 931 932 return (0); 933 } 934 935 __checkReturn efx_rc_t 936 efx_mae_match_spec_field_set( 937 __in efx_mae_match_spec_t *spec, 938 __in efx_mae_field_id_t field_id, 939 __in size_t value_size, 940 __in_bcount(value_size) const uint8_t *value, 941 __in size_t mask_size, 942 __in_bcount(mask_size) const uint8_t *mask) 943 { 944 const efx_mae_mv_desc_t *descp; 945 unsigned int desc_set_nentries; 946 uint8_t *mvp; 947 efx_rc_t rc; 948 949 switch (spec->emms_type) { 950 case EFX_MAE_RULE_OUTER: 951 desc_set_nentries = 952 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set); 953 descp = &__efx_mae_outer_rule_mv_desc_set[field_id]; 954 mvp = spec->emms_mask_value_pairs.outer; 955 break; 956 case EFX_MAE_RULE_ACTION: 957 desc_set_nentries = 958 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set); 959 descp = &__efx_mae_action_rule_mv_desc_set[field_id]; 960 mvp = spec->emms_mask_value_pairs.action; 961 break; 962 default: 963 rc = ENOTSUP; 964 goto fail1; 965 } 966 967 if ((unsigned int)field_id >= desc_set_nentries) { 968 rc = EINVAL; 969 goto fail2; 970 } 971 972 if (descp->emmd_mask_size == 0) { 973 /* The ID points to a gap in the array of field descriptors. */ 974 rc = EINVAL; 975 goto fail3; 976 } 977 978 if (value_size != descp->emmd_value_size) { 979 rc = EINVAL; 980 goto fail4; 981 } 982 983 if (mask_size != descp->emmd_mask_size) { 984 rc = EINVAL; 985 goto fail5; 986 } 987 988 if (descp->emmd_endianness == EFX_MAE_FIELD_BE) { 989 unsigned int i; 990 991 /* 992 * The mask/value are in network (big endian) order. 993 * The MCDI request field is also big endian. 994 */ 995 996 EFSYS_ASSERT3U(value_size, ==, mask_size); 997 998 for (i = 0; i < value_size; ++i) { 999 uint8_t *v_bytep = mvp + descp->emmd_value_offset + i; 1000 uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i; 1001 1002 /* 1003 * Apply the mask (which may be all-zeros) to the value. 1004 * 1005 * If this API is provided with some value to set for a 1006 * given field in one specification and with some other 1007 * value to set for this field in another specification, 1008 * then, if the two masks are all-zeros, the field will 1009 * avoid being counted as a mismatch when comparing the 1010 * specifications using efx_mae_match_specs_equal() API. 1011 */ 1012 *v_bytep = value[i] & mask[i]; 1013 *m_bytep = mask[i]; 1014 } 1015 } else { 1016 efx_dword_t dword; 1017 1018 /* 1019 * The mask/value are in host byte order. 1020 * The MCDI request field is little endian. 1021 */ 1022 switch (value_size) { 1023 case 4: 1024 EFX_POPULATE_DWORD_1(dword, 1025 EFX_DWORD_0, *(const uint32_t *)value); 1026 1027 memcpy(mvp + descp->emmd_value_offset, 1028 &dword, sizeof (dword)); 1029 break; 1030 default: 1031 EFSYS_ASSERT(B_FALSE); 1032 } 1033 1034 switch (mask_size) { 1035 case 4: 1036 EFX_POPULATE_DWORD_1(dword, 1037 EFX_DWORD_0, *(const uint32_t *)mask); 1038 1039 memcpy(mvp + descp->emmd_mask_offset, 1040 &dword, sizeof (dword)); 1041 break; 1042 default: 1043 EFSYS_ASSERT(B_FALSE); 1044 } 1045 } 1046 1047 return (0); 1048 1049 fail5: 1050 EFSYS_PROBE(fail5); 1051 fail4: 1052 EFSYS_PROBE(fail4); 1053 fail3: 1054 EFSYS_PROBE(fail3); 1055 fail2: 1056 EFSYS_PROBE(fail2); 1057 fail1: 1058 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1059 return (rc); 1060 } 1061 1062 __checkReturn efx_rc_t 1063 efx_mae_match_spec_bit_set( 1064 __in efx_mae_match_spec_t *spec, 1065 __in efx_mae_field_id_t field_id, 1066 __in boolean_t value) 1067 { 1068 const efx_mae_mv_bit_desc_t *bit_descp; 1069 unsigned int bit_desc_set_nentries; 1070 unsigned int byte_idx; 1071 unsigned int bit_idx; 1072 uint8_t *mvp; 1073 efx_rc_t rc; 1074 1075 switch (spec->emms_type) { 1076 case EFX_MAE_RULE_OUTER: 1077 bit_desc_set_nentries = 1078 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set); 1079 bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id]; 1080 mvp = spec->emms_mask_value_pairs.outer; 1081 break; 1082 case EFX_MAE_RULE_ACTION: 1083 bit_desc_set_nentries = 1084 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set); 1085 bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id]; 1086 mvp = spec->emms_mask_value_pairs.action; 1087 break; 1088 default: 1089 rc = ENOTSUP; 1090 goto fail1; 1091 } 1092 1093 if ((unsigned int)field_id >= bit_desc_set_nentries) { 1094 rc = EINVAL; 1095 goto fail2; 1096 } 1097 1098 if (bit_descp->emmbd_entry_is_valid == B_FALSE) { 1099 rc = EINVAL; 1100 goto fail3; 1101 } 1102 1103 byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8; 1104 bit_idx = bit_descp->emmbd_value_lbn % 8; 1105 1106 if (value != B_FALSE) 1107 mvp[byte_idx] |= (1U << bit_idx); 1108 else 1109 mvp[byte_idx] &= ~(1U << bit_idx); 1110 1111 byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8; 1112 bit_idx = bit_descp->emmbd_mask_lbn % 8; 1113 mvp[byte_idx] |= (1U << bit_idx); 1114 1115 return (0); 1116 1117 fail3: 1118 EFSYS_PROBE(fail3); 1119 fail2: 1120 EFSYS_PROBE(fail2); 1121 fail1: 1122 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1123 return (rc); 1124 } 1125 1126 __checkReturn efx_rc_t 1127 efx_mae_match_spec_mport_set( 1128 __in efx_mae_match_spec_t *spec, 1129 __in const efx_mport_sel_t *valuep, 1130 __in_opt const efx_mport_sel_t *maskp) 1131 { 1132 uint32_t full_mask = UINT32_MAX; 1133 const uint8_t *vp; 1134 const uint8_t *mp; 1135 efx_rc_t rc; 1136 1137 if (valuep == NULL) { 1138 rc = EINVAL; 1139 goto fail1; 1140 } 1141 1142 vp = (const uint8_t *)&valuep->sel; 1143 if (maskp != NULL) 1144 mp = (const uint8_t *)&maskp->sel; 1145 else 1146 mp = (const uint8_t *)&full_mask; 1147 1148 rc = efx_mae_match_spec_field_set(spec, 1149 EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR, 1150 sizeof (valuep->sel), vp, sizeof (maskp->sel), mp); 1151 if (rc != 0) 1152 goto fail2; 1153 1154 return (0); 1155 1156 fail2: 1157 EFSYS_PROBE(fail2); 1158 fail1: 1159 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1160 return (rc); 1161 } 1162 1163 __checkReturn boolean_t 1164 efx_mae_match_specs_equal( 1165 __in const efx_mae_match_spec_t *left, 1166 __in const efx_mae_match_spec_t *right) 1167 { 1168 return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE); 1169 } 1170 1171 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit) \ 1172 ((_mask)[(_bit) / (_mask_page_nbits)] & \ 1173 (1ULL << ((_bit) & ((_mask_page_nbits) - 1)))) 1174 1175 static boolean_t 1176 efx_mask_is_prefix( 1177 __in size_t mask_nbytes, 1178 __in_bcount(mask_nbytes) const uint8_t *maskp) 1179 { 1180 boolean_t prev_bit_is_set = B_TRUE; 1181 unsigned int i; 1182 1183 for (i = 0; i < 8 * mask_nbytes; ++i) { 1184 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i); 1185 1186 if (!prev_bit_is_set && bit_is_set) 1187 return B_FALSE; 1188 1189 prev_bit_is_set = bit_is_set; 1190 } 1191 1192 return B_TRUE; 1193 } 1194 1195 static boolean_t 1196 efx_mask_is_all_ones( 1197 __in size_t mask_nbytes, 1198 __in_bcount(mask_nbytes) const uint8_t *maskp) 1199 { 1200 unsigned int i; 1201 uint8_t t = ~0; 1202 1203 for (i = 0; i < mask_nbytes; ++i) 1204 t &= maskp[i]; 1205 1206 return (t == (uint8_t)(~0)); 1207 } 1208 1209 static boolean_t 1210 efx_mask_is_all_zeros( 1211 __in size_t mask_nbytes, 1212 __in_bcount(mask_nbytes) const uint8_t *maskp) 1213 { 1214 unsigned int i; 1215 uint8_t t = 0; 1216 1217 for (i = 0; i < mask_nbytes; ++i) 1218 t |= maskp[i]; 1219 1220 return (t == 0); 1221 } 1222 1223 __checkReturn boolean_t 1224 efx_mae_match_spec_is_valid( 1225 __in efx_nic_t *enp, 1226 __in const efx_mae_match_spec_t *spec) 1227 { 1228 efx_mae_t *maep = enp->en_maep; 1229 unsigned int field_ncaps = maep->em_max_nfields; 1230 const efx_mae_field_cap_t *field_caps; 1231 const efx_mae_mv_desc_t *desc_setp; 1232 unsigned int desc_set_nentries; 1233 const efx_mae_mv_bit_desc_t *bit_desc_setp; 1234 unsigned int bit_desc_set_nentries; 1235 boolean_t is_valid = B_TRUE; 1236 efx_mae_field_id_t field_id; 1237 const uint8_t *mvp; 1238 1239 switch (spec->emms_type) { 1240 case EFX_MAE_RULE_OUTER: 1241 field_caps = maep->em_outer_rule_field_caps; 1242 desc_setp = __efx_mae_outer_rule_mv_desc_set; 1243 desc_set_nentries = 1244 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set); 1245 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set; 1246 bit_desc_set_nentries = 1247 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set); 1248 mvp = spec->emms_mask_value_pairs.outer; 1249 break; 1250 case EFX_MAE_RULE_ACTION: 1251 field_caps = maep->em_action_rule_field_caps; 1252 desc_setp = __efx_mae_action_rule_mv_desc_set; 1253 desc_set_nentries = 1254 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set); 1255 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set; 1256 bit_desc_set_nentries = 1257 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set); 1258 mvp = spec->emms_mask_value_pairs.action; 1259 break; 1260 default: 1261 return (B_FALSE); 1262 } 1263 1264 if (field_caps == NULL) 1265 return (B_FALSE); 1266 1267 for (field_id = 0; (unsigned int)field_id < desc_set_nentries; 1268 ++field_id) { 1269 const efx_mae_mv_desc_t *descp = &desc_setp[field_id]; 1270 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id; 1271 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset; 1272 const uint8_t *m_buf = mvp + descp->emmd_mask_offset; 1273 size_t alt_m_size = descp->emmd_alt_mask_size; 1274 size_t m_size = descp->emmd_mask_size; 1275 1276 if (m_size == 0) 1277 continue; /* Skip array gap */ 1278 1279 if ((unsigned int)field_cap_id >= field_ncaps) { 1280 /* 1281 * The FW has not reported capability status for 1282 * this field. Make sure that its mask is zeroed. 1283 */ 1284 is_valid = efx_mask_is_all_zeros(m_size, m_buf); 1285 if (is_valid != B_FALSE) 1286 continue; 1287 else 1288 break; 1289 } 1290 1291 switch (field_caps[field_cap_id].emfc_support) { 1292 case MAE_FIELD_SUPPORTED_MATCH_MASK: 1293 is_valid = B_TRUE; 1294 break; 1295 case MAE_FIELD_SUPPORTED_MATCH_PREFIX: 1296 is_valid = efx_mask_is_prefix(m_size, m_buf); 1297 break; 1298 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL: 1299 is_valid = (efx_mask_is_all_ones(m_size, m_buf) || 1300 efx_mask_is_all_zeros(m_size, m_buf)); 1301 break; 1302 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: 1303 is_valid = efx_mask_is_all_ones(m_size, m_buf); 1304 1305 if ((is_valid == B_FALSE) && (alt_m_size != 0)) { 1306 /* 1307 * This field has an alternative one. The FW 1308 * reports ALWAYS for both implying that one 1309 * of them is required to have all-ones mask. 1310 * 1311 * The primary field's mask is incorrect; go 1312 * on to check that of the alternative field. 1313 */ 1314 is_valid = efx_mask_is_all_ones(alt_m_size, 1315 alt_m_buf); 1316 } 1317 break; 1318 case MAE_FIELD_SUPPORTED_MATCH_NEVER: 1319 case MAE_FIELD_UNSUPPORTED: 1320 default: 1321 is_valid = efx_mask_is_all_zeros(m_size, m_buf); 1322 break; 1323 } 1324 1325 if (is_valid == B_FALSE) 1326 return (B_FALSE); 1327 } 1328 1329 for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries; 1330 ++field_id) { 1331 const efx_mae_mv_bit_desc_t *bit_descp = 1332 &bit_desc_setp[field_id]; 1333 unsigned int byte_idx = 1334 bit_descp->emmbd_mask_ofst + 1335 bit_descp->emmbd_mask_lbn / 8; 1336 unsigned int bit_idx = 1337 bit_descp->emmbd_mask_lbn % 8; 1338 efx_mae_field_cap_id_t bit_cap_id = 1339 bit_descp->emmbd_bit_cap_id; 1340 1341 if (bit_descp->emmbd_entry_is_valid == B_FALSE) 1342 continue; /* Skip array gap */ 1343 1344 if ((unsigned int)bit_cap_id >= field_ncaps) { 1345 /* No capability for this bit = unsupported. */ 1346 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0); 1347 if (is_valid == B_FALSE) 1348 break; 1349 else 1350 continue; 1351 } 1352 1353 switch (field_caps[bit_cap_id].emfc_support) { 1354 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL: 1355 is_valid = B_TRUE; 1356 break; 1357 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: 1358 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0); 1359 break; 1360 case MAE_FIELD_SUPPORTED_MATCH_NEVER: 1361 case MAE_FIELD_UNSUPPORTED: 1362 default: 1363 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0); 1364 break; 1365 } 1366 1367 if (is_valid == B_FALSE) 1368 break; 1369 } 1370 1371 return (is_valid); 1372 } 1373 1374 __checkReturn efx_rc_t 1375 efx_mae_action_set_spec_init( 1376 __in efx_nic_t *enp, 1377 __out efx_mae_actions_t **specp) 1378 { 1379 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 1380 efx_mae_actions_t *spec; 1381 efx_rc_t rc; 1382 1383 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec); 1384 if (spec == NULL) { 1385 rc = ENOMEM; 1386 goto fail1; 1387 } 1388 1389 spec->ema_rsrc.emar_dst_mac_id.id = EFX_MAE_RSRC_ID_INVALID; 1390 spec->ema_rsrc.emar_src_mac_id.id = EFX_MAE_RSRC_ID_INVALID; 1391 spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID; 1392 spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID; 1393 1394 /* 1395 * Helpers which populate v2 actions must reject them when v2 is not 1396 * supported. As they have no EFX NIC argument, save v2 status here. 1397 */ 1398 spec->ema_v2_is_supported = encp->enc_mae_aset_v2_supported; 1399 1400 *specp = spec; 1401 1402 return (0); 1403 1404 fail1: 1405 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1406 return (rc); 1407 } 1408 1409 void 1410 efx_mae_action_set_spec_fini( 1411 __in efx_nic_t *enp, 1412 __in efx_mae_actions_t *spec) 1413 { 1414 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 1415 } 1416 1417 static __checkReturn efx_rc_t 1418 efx_mae_action_set_no_op( 1419 __in efx_mae_actions_t *spec, 1420 __in size_t arg_size, 1421 __in_bcount(arg_size) const uint8_t *arg) 1422 { 1423 efx_rc_t rc; 1424 1425 _NOTE(ARGUNUSED(spec)) 1426 1427 if (arg_size != 0) { 1428 rc = EINVAL; 1429 goto fail1; 1430 } 1431 1432 if (arg != NULL) { 1433 rc = EINVAL; 1434 goto fail2; 1435 } 1436 1437 /* This action does not have any arguments, so do nothing here. */ 1438 1439 return (0); 1440 1441 fail2: 1442 EFSYS_PROBE(fail2); 1443 fail1: 1444 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1445 return (rc); 1446 } 1447 1448 static __checkReturn efx_rc_t 1449 efx_mae_action_set_add_vlan_pop( 1450 __in efx_mae_actions_t *spec, 1451 __in size_t arg_size, 1452 __in_bcount(arg_size) const uint8_t *arg) 1453 { 1454 efx_rc_t rc; 1455 1456 if (arg_size != 0) { 1457 rc = EINVAL; 1458 goto fail1; 1459 } 1460 1461 if (arg != NULL) { 1462 rc = EINVAL; 1463 goto fail2; 1464 } 1465 1466 if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) { 1467 rc = ENOTSUP; 1468 goto fail3; 1469 } 1470 1471 ++spec->ema_n_vlan_tags_to_pop; 1472 1473 return (0); 1474 1475 fail3: 1476 EFSYS_PROBE(fail3); 1477 fail2: 1478 EFSYS_PROBE(fail2); 1479 fail1: 1480 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1481 return (rc); 1482 } 1483 1484 static __checkReturn efx_rc_t 1485 efx_mae_action_set_add_vlan_push( 1486 __in efx_mae_actions_t *spec, 1487 __in size_t arg_size, 1488 __in_bcount(arg_size) const uint8_t *arg) 1489 { 1490 unsigned int n_tags = spec->ema_n_vlan_tags_to_push; 1491 efx_rc_t rc; 1492 1493 if (arg_size != sizeof (*spec->ema_vlan_push_descs)) { 1494 rc = EINVAL; 1495 goto fail1; 1496 } 1497 1498 if (arg == NULL) { 1499 rc = EINVAL; 1500 goto fail2; 1501 } 1502 1503 if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) { 1504 rc = ENOTSUP; 1505 goto fail3; 1506 } 1507 1508 memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size); 1509 ++(spec->ema_n_vlan_tags_to_push); 1510 1511 return (0); 1512 1513 fail3: 1514 EFSYS_PROBE(fail3); 1515 fail2: 1516 EFSYS_PROBE(fail2); 1517 fail1: 1518 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1519 return (rc); 1520 } 1521 1522 static __checkReturn efx_rc_t 1523 efx_mae_action_set_add_count( 1524 __in efx_mae_actions_t *spec, 1525 __in size_t arg_size, 1526 __in_bcount(arg_size) const uint8_t *arg) 1527 { 1528 efx_rc_t rc; 1529 1530 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 1531 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 1532 1533 /* 1534 * Preparing an action set spec to update a counter requires 1535 * two steps: first add this action to the action spec, and then 1536 * add the counter ID to the spec. This allows validity checking 1537 * and resource allocation to be done separately. 1538 * 1539 * In order to fill in the counter ID, the caller is supposed to invoke 1540 * efx_mae_action_set_fill_in_counter_id(). If they do not do that, 1541 * efx_mae_action_set_alloc() invocation will throw an error. 1542 * 1543 * For now, no arguments are supposed to be handled. 1544 */ 1545 1546 if (arg_size != 0) { 1547 rc = EINVAL; 1548 goto fail1; 1549 } 1550 1551 if (arg != NULL) { 1552 rc = EINVAL; 1553 goto fail2; 1554 } 1555 1556 ++(spec->ema_n_count_actions); 1557 1558 return (0); 1559 1560 fail2: 1561 EFSYS_PROBE(fail2); 1562 fail1: 1563 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1564 return (rc); 1565 } 1566 1567 static __checkReturn efx_rc_t 1568 efx_mae_action_set_add_mark( 1569 __in efx_mae_actions_t *spec, 1570 __in size_t arg_size, 1571 __in_bcount(arg_size) const uint8_t *arg) 1572 { 1573 efx_rc_t rc; 1574 1575 if (arg_size != sizeof (spec->ema_mark_value)) { 1576 rc = EINVAL; 1577 goto fail1; 1578 } 1579 1580 if (arg == NULL) { 1581 rc = EINVAL; 1582 goto fail2; 1583 } 1584 1585 memcpy(&spec->ema_mark_value, arg, arg_size); 1586 1587 return (0); 1588 1589 fail2: 1590 EFSYS_PROBE(fail2); 1591 fail1: 1592 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1593 return (rc); 1594 } 1595 1596 static __checkReturn efx_rc_t 1597 efx_mae_action_set_add_deliver( 1598 __in efx_mae_actions_t *spec, 1599 __in size_t arg_size, 1600 __in_bcount(arg_size) const uint8_t *arg) 1601 { 1602 efx_rc_t rc; 1603 1604 if (arg_size != sizeof (spec->ema_deliver_mport)) { 1605 rc = EINVAL; 1606 goto fail1; 1607 } 1608 1609 if (arg == NULL) { 1610 rc = EINVAL; 1611 goto fail2; 1612 } 1613 1614 memcpy(&spec->ema_deliver_mport, arg, arg_size); 1615 1616 return (0); 1617 1618 fail2: 1619 EFSYS_PROBE(fail2); 1620 fail1: 1621 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1622 return (rc); 1623 } 1624 1625 typedef struct efx_mae_action_desc_s { 1626 /* Action specific handler */ 1627 efx_rc_t (*emad_add)(efx_mae_actions_t *, 1628 size_t, const uint8_t *); 1629 } efx_mae_action_desc_t; 1630 1631 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = { 1632 [EFX_MAE_ACTION_DECAP] = { 1633 .emad_add = efx_mae_action_set_no_op 1634 }, 1635 [EFX_MAE_ACTION_VLAN_POP] = { 1636 .emad_add = efx_mae_action_set_add_vlan_pop 1637 }, 1638 [EFX_MAE_ACTION_SET_DST_MAC] = { 1639 .emad_add = efx_mae_action_set_no_op 1640 }, 1641 [EFX_MAE_ACTION_SET_SRC_MAC] = { 1642 .emad_add = efx_mae_action_set_no_op 1643 }, 1644 [EFX_MAE_ACTION_DECR_IP_TTL] = { 1645 .emad_add = efx_mae_action_set_no_op 1646 }, 1647 [EFX_MAE_ACTION_VLAN_PUSH] = { 1648 .emad_add = efx_mae_action_set_add_vlan_push 1649 }, 1650 [EFX_MAE_ACTION_ENCAP] = { 1651 .emad_add = efx_mae_action_set_no_op 1652 }, 1653 [EFX_MAE_ACTION_COUNT] = { 1654 .emad_add = efx_mae_action_set_add_count 1655 }, 1656 [EFX_MAE_ACTION_FLAG] = { 1657 .emad_add = efx_mae_action_set_no_op 1658 }, 1659 [EFX_MAE_ACTION_MARK] = { 1660 .emad_add = efx_mae_action_set_add_mark 1661 }, 1662 [EFX_MAE_ACTION_DELIVER] = { 1663 .emad_add = efx_mae_action_set_add_deliver 1664 } 1665 }; 1666 1667 static const uint32_t efx_mae_action_ordered_map = 1668 (1U << EFX_MAE_ACTION_DECAP) | 1669 (1U << EFX_MAE_ACTION_VLAN_POP) | 1670 (1U << EFX_MAE_ACTION_SET_DST_MAC) | 1671 (1U << EFX_MAE_ACTION_SET_SRC_MAC) | 1672 (1U << EFX_MAE_ACTION_DECR_IP_TTL) | 1673 (1U << EFX_MAE_ACTION_VLAN_PUSH) | 1674 /* 1675 * HW will conduct action COUNT after 1676 * the matching packet has been modified by 1677 * length-affecting actions except for ENCAP. 1678 */ 1679 (1U << EFX_MAE_ACTION_COUNT) | 1680 (1U << EFX_MAE_ACTION_ENCAP) | 1681 (1U << EFX_MAE_ACTION_FLAG) | 1682 (1U << EFX_MAE_ACTION_MARK) | 1683 (1U << EFX_MAE_ACTION_DELIVER); 1684 1685 /* 1686 * These actions must not be added after DELIVER, but 1687 * they can have any place among the rest of 1688 * strictly ordered actions. 1689 */ 1690 static const uint32_t efx_mae_action_nonstrict_map = 1691 (1U << EFX_MAE_ACTION_COUNT) | 1692 (1U << EFX_MAE_ACTION_FLAG) | 1693 (1U << EFX_MAE_ACTION_MARK); 1694 1695 static const uint32_t efx_mae_action_repeat_map = 1696 (1U << EFX_MAE_ACTION_VLAN_POP) | 1697 (1U << EFX_MAE_ACTION_VLAN_PUSH) | 1698 (1U << EFX_MAE_ACTION_COUNT); 1699 1700 /* 1701 * Add an action to an action set. 1702 * 1703 * This has to be invoked in the desired action order. 1704 * An out-of-order action request will be turned down. 1705 */ 1706 static __checkReturn efx_rc_t 1707 efx_mae_action_set_spec_populate( 1708 __in efx_mae_actions_t *spec, 1709 __in efx_mae_action_t type, 1710 __in size_t arg_size, 1711 __in_bcount(arg_size) const uint8_t *arg) 1712 { 1713 uint32_t action_mask; 1714 efx_rc_t rc; 1715 1716 EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <= 1717 (sizeof (efx_mae_action_ordered_map) * 8)); 1718 EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <= 1719 (sizeof (efx_mae_action_repeat_map) * 8)); 1720 1721 EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS); 1722 EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK); 1723 EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER); 1724 1725 if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) { 1726 rc = EINVAL; 1727 goto fail1; 1728 } 1729 1730 action_mask = (1U << type); 1731 1732 if ((spec->ema_actions & action_mask) != 0) { 1733 /* The action set already contains this action. */ 1734 if ((efx_mae_action_repeat_map & action_mask) == 0) { 1735 /* Cannot add another non-repeatable action. */ 1736 rc = ENOTSUP; 1737 goto fail2; 1738 } 1739 } 1740 1741 if ((efx_mae_action_ordered_map & action_mask) != 0) { 1742 uint32_t strict_ordered_map = 1743 efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map; 1744 uint32_t later_actions_mask = 1745 strict_ordered_map & ~(action_mask | (action_mask - 1)); 1746 1747 if ((spec->ema_actions & later_actions_mask) != 0) { 1748 /* Cannot add an action after later ordered actions. */ 1749 rc = ENOTSUP; 1750 goto fail3; 1751 } 1752 } 1753 1754 if (efx_mae_actions[type].emad_add != NULL) { 1755 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg); 1756 if (rc != 0) 1757 goto fail4; 1758 } 1759 1760 spec->ema_actions |= action_mask; 1761 1762 return (0); 1763 1764 fail4: 1765 EFSYS_PROBE(fail4); 1766 fail3: 1767 EFSYS_PROBE(fail3); 1768 fail2: 1769 EFSYS_PROBE(fail2); 1770 fail1: 1771 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1772 return (rc); 1773 } 1774 1775 __checkReturn efx_rc_t 1776 efx_mae_action_set_populate_decap( 1777 __in efx_mae_actions_t *spec) 1778 { 1779 return (efx_mae_action_set_spec_populate(spec, 1780 EFX_MAE_ACTION_DECAP, 0, NULL)); 1781 } 1782 1783 __checkReturn efx_rc_t 1784 efx_mae_action_set_populate_vlan_pop( 1785 __in efx_mae_actions_t *spec) 1786 { 1787 return (efx_mae_action_set_spec_populate(spec, 1788 EFX_MAE_ACTION_VLAN_POP, 0, NULL)); 1789 } 1790 1791 __checkReturn efx_rc_t 1792 efx_mae_action_set_populate_set_dst_mac( 1793 __in efx_mae_actions_t *spec) 1794 { 1795 efx_rc_t rc; 1796 1797 if (spec->ema_v2_is_supported == B_FALSE) { 1798 rc = ENOTSUP; 1799 goto fail1; 1800 } 1801 1802 return (efx_mae_action_set_spec_populate(spec, 1803 EFX_MAE_ACTION_SET_DST_MAC, 0, NULL)); 1804 1805 fail1: 1806 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1807 return (rc); 1808 } 1809 1810 __checkReturn efx_rc_t 1811 efx_mae_action_set_populate_set_src_mac( 1812 __in efx_mae_actions_t *spec) 1813 { 1814 efx_rc_t rc; 1815 1816 if (spec->ema_v2_is_supported == B_FALSE) { 1817 rc = ENOTSUP; 1818 goto fail1; 1819 } 1820 1821 return (efx_mae_action_set_spec_populate(spec, 1822 EFX_MAE_ACTION_SET_SRC_MAC, 0, NULL)); 1823 1824 fail1: 1825 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1826 return (rc); 1827 } 1828 1829 __checkReturn efx_rc_t 1830 efx_mae_action_set_populate_decr_ip_ttl( 1831 __in efx_mae_actions_t *spec) 1832 { 1833 efx_rc_t rc; 1834 1835 if (spec->ema_v2_is_supported == B_FALSE) { 1836 rc = ENOTSUP; 1837 goto fail1; 1838 } 1839 1840 return (efx_mae_action_set_spec_populate(spec, 1841 EFX_MAE_ACTION_DECR_IP_TTL, 0, NULL)); 1842 1843 fail1: 1844 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1845 return (rc); 1846 } 1847 1848 __checkReturn efx_rc_t 1849 efx_mae_action_set_populate_vlan_push( 1850 __in efx_mae_actions_t *spec, 1851 __in uint16_t tpid_be, 1852 __in uint16_t tci_be) 1853 { 1854 efx_mae_action_vlan_push_t action; 1855 const uint8_t *arg = (const uint8_t *)&action; 1856 1857 action.emavp_tpid_be = tpid_be; 1858 action.emavp_tci_be = tci_be; 1859 1860 return (efx_mae_action_set_spec_populate(spec, 1861 EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg)); 1862 } 1863 1864 __checkReturn efx_rc_t 1865 efx_mae_action_set_populate_encap( 1866 __in efx_mae_actions_t *spec) 1867 { 1868 /* 1869 * There is no argument to pass encap. header ID, thus, one does not 1870 * need to allocate an encap. header while parsing application input. 1871 * This is useful since building an action set may be done simply to 1872 * validate a rule, whilst resource allocation usually consumes time. 1873 */ 1874 return (efx_mae_action_set_spec_populate(spec, 1875 EFX_MAE_ACTION_ENCAP, 0, NULL)); 1876 } 1877 1878 __checkReturn efx_rc_t 1879 efx_mae_action_set_populate_count( 1880 __in efx_mae_actions_t *spec) 1881 { 1882 /* 1883 * There is no argument to pass counter ID, thus, one does not 1884 * need to allocate a counter while parsing application input. 1885 * This is useful since building an action set may be done simply to 1886 * validate a rule, whilst resource allocation usually consumes time. 1887 */ 1888 return (efx_mae_action_set_spec_populate(spec, 1889 EFX_MAE_ACTION_COUNT, 0, NULL)); 1890 } 1891 1892 __checkReturn efx_rc_t 1893 efx_mae_action_set_populate_flag( 1894 __in efx_mae_actions_t *spec) 1895 { 1896 return (efx_mae_action_set_spec_populate(spec, 1897 EFX_MAE_ACTION_FLAG, 0, NULL)); 1898 } 1899 1900 __checkReturn efx_rc_t 1901 efx_mae_action_set_populate_mark( 1902 __in efx_mae_actions_t *spec, 1903 __in uint32_t mark_value) 1904 { 1905 const uint8_t *arg = (const uint8_t *)&mark_value; 1906 1907 return (efx_mae_action_set_spec_populate(spec, 1908 EFX_MAE_ACTION_MARK, sizeof (mark_value), arg)); 1909 } 1910 1911 __checkReturn efx_rc_t 1912 efx_mae_action_set_populate_deliver( 1913 __in efx_mae_actions_t *spec, 1914 __in const efx_mport_sel_t *mportp) 1915 { 1916 const uint8_t *arg; 1917 efx_rc_t rc; 1918 1919 if (mportp == NULL) { 1920 rc = EINVAL; 1921 goto fail1; 1922 } 1923 1924 arg = (const uint8_t *)&mportp->sel; 1925 1926 return (efx_mae_action_set_spec_populate(spec, 1927 EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg)); 1928 1929 fail1: 1930 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1931 return (rc); 1932 } 1933 1934 __checkReturn efx_rc_t 1935 efx_mae_action_set_populate_drop( 1936 __in efx_mae_actions_t *spec) 1937 { 1938 efx_mport_sel_t mport; 1939 const uint8_t *arg; 1940 efx_dword_t dword; 1941 1942 EFX_POPULATE_DWORD_1(dword, 1943 MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL); 1944 1945 /* 1946 * The constructed DWORD is little-endian, 1947 * but the resulting value is meant to be 1948 * passed to MCDIs, where it will undergo 1949 * host-order to little endian conversion. 1950 */ 1951 mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 1952 1953 arg = (const uint8_t *)&mport.sel; 1954 1955 return (efx_mae_action_set_spec_populate(spec, 1956 EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg)); 1957 } 1958 1959 __checkReturn boolean_t 1960 efx_mae_action_set_specs_equal( 1961 __in const efx_mae_actions_t *left, 1962 __in const efx_mae_actions_t *right) 1963 { 1964 size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc); 1965 1966 /* 1967 * An action set specification consists of two parts. The first part 1968 * indicates what actions are included in the action set, as well as 1969 * extra quantitative values (in example, the number of VLAN tags to 1970 * push). The second part comprises resource IDs used by the actions. 1971 * 1972 * A resource, in example, a counter, is allocated from the hardware 1973 * by the client, and it's the client who is responsible for keeping 1974 * track of allocated resources and comparing resource IDs if needed. 1975 * 1976 * In this API, don't compare resource IDs in the two specifications. 1977 */ 1978 1979 return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE); 1980 } 1981 1982 __checkReturn efx_rc_t 1983 efx_mae_match_specs_class_cmp( 1984 __in efx_nic_t *enp, 1985 __in const efx_mae_match_spec_t *left, 1986 __in const efx_mae_match_spec_t *right, 1987 __out boolean_t *have_same_classp) 1988 { 1989 efx_mae_t *maep = enp->en_maep; 1990 unsigned int field_ncaps = maep->em_max_nfields; 1991 const efx_mae_field_cap_t *field_caps; 1992 const efx_mae_mv_desc_t *desc_setp; 1993 unsigned int desc_set_nentries; 1994 const efx_mae_mv_bit_desc_t *bit_desc_setp; 1995 unsigned int bit_desc_set_nentries; 1996 boolean_t have_same_class = B_TRUE; 1997 efx_mae_field_id_t field_id; 1998 const uint8_t *mvpl; 1999 const uint8_t *mvpr; 2000 efx_rc_t rc; 2001 2002 switch (left->emms_type) { 2003 case EFX_MAE_RULE_OUTER: 2004 field_caps = maep->em_outer_rule_field_caps; 2005 desc_setp = __efx_mae_outer_rule_mv_desc_set; 2006 desc_set_nentries = 2007 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set); 2008 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set; 2009 bit_desc_set_nentries = 2010 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set); 2011 mvpl = left->emms_mask_value_pairs.outer; 2012 mvpr = right->emms_mask_value_pairs.outer; 2013 break; 2014 case EFX_MAE_RULE_ACTION: 2015 field_caps = maep->em_action_rule_field_caps; 2016 desc_setp = __efx_mae_action_rule_mv_desc_set; 2017 desc_set_nentries = 2018 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set); 2019 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set; 2020 bit_desc_set_nentries = 2021 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set); 2022 mvpl = left->emms_mask_value_pairs.action; 2023 mvpr = right->emms_mask_value_pairs.action; 2024 break; 2025 default: 2026 rc = ENOTSUP; 2027 goto fail1; 2028 } 2029 2030 if (field_caps == NULL) { 2031 rc = EAGAIN; 2032 goto fail2; 2033 } 2034 2035 if (left->emms_type != right->emms_type || 2036 left->emms_prio != right->emms_prio) { 2037 /* 2038 * Rules of different types can never map to the same class. 2039 * 2040 * The FW can support some set of match criteria for one 2041 * priority and not support the very same set for 2042 * another priority. Thus, two rules which have 2043 * different priorities can never map to 2044 * the same class. 2045 */ 2046 *have_same_classp = B_FALSE; 2047 return (0); 2048 } 2049 2050 for (field_id = 0; (unsigned int)field_id < desc_set_nentries; 2051 ++field_id) { 2052 const efx_mae_mv_desc_t *descp = &desc_setp[field_id]; 2053 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id; 2054 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset; 2055 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset; 2056 size_t mask_size = descp->emmd_mask_size; 2057 const uint8_t *lvalp = mvpl + descp->emmd_value_offset; 2058 const uint8_t *rvalp = mvpr + descp->emmd_value_offset; 2059 size_t value_size = descp->emmd_value_size; 2060 2061 if (mask_size == 0) 2062 continue; /* Skip array gap */ 2063 2064 if ((unsigned int)field_cap_id >= field_ncaps) { 2065 /* 2066 * The FW has not reported capability status for this 2067 * field. It's unknown whether any difference between 2068 * the two masks / values affects the class. The only 2069 * case when the class must be the same is when these 2070 * mask-value pairs match. Otherwise, report mismatch. 2071 */ 2072 if ((memcmp(lmaskp, rmaskp, mask_size) == 0) && 2073 (memcmp(lvalp, rvalp, value_size) == 0)) 2074 continue; 2075 else 2076 break; 2077 } 2078 2079 if (field_caps[field_cap_id].emfc_mask_affects_class) { 2080 if (memcmp(lmaskp, rmaskp, mask_size) != 0) { 2081 have_same_class = B_FALSE; 2082 break; 2083 } 2084 } 2085 2086 if (field_caps[field_cap_id].emfc_match_affects_class) { 2087 if (memcmp(lvalp, rvalp, value_size) != 0) { 2088 have_same_class = B_FALSE; 2089 break; 2090 } 2091 } 2092 } 2093 2094 if (have_same_class == B_FALSE) 2095 goto done; 2096 2097 for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries; 2098 ++field_id) { 2099 const efx_mae_mv_bit_desc_t *bit_descp = 2100 &bit_desc_setp[field_id]; 2101 efx_mae_field_cap_id_t bit_cap_id = 2102 bit_descp->emmbd_bit_cap_id; 2103 unsigned int byte_idx; 2104 unsigned int bit_idx; 2105 2106 if (bit_descp->emmbd_entry_is_valid == B_FALSE) 2107 continue; /* Skip array gap */ 2108 2109 if ((unsigned int)bit_cap_id >= field_ncaps) 2110 break; 2111 2112 byte_idx = 2113 bit_descp->emmbd_mask_ofst + 2114 bit_descp->emmbd_mask_lbn / 8; 2115 bit_idx = 2116 bit_descp->emmbd_mask_lbn % 8; 2117 2118 if (field_caps[bit_cap_id].emfc_mask_affects_class && 2119 (mvpl[byte_idx] & (1U << bit_idx)) != 2120 (mvpr[byte_idx] & (1U << bit_idx))) { 2121 have_same_class = B_FALSE; 2122 break; 2123 } 2124 2125 byte_idx = 2126 bit_descp->emmbd_value_ofst + 2127 bit_descp->emmbd_value_lbn / 8; 2128 bit_idx = 2129 bit_descp->emmbd_value_lbn % 8; 2130 2131 if (field_caps[bit_cap_id].emfc_match_affects_class && 2132 (mvpl[byte_idx] & (1U << bit_idx)) != 2133 (mvpr[byte_idx] & (1U << bit_idx))) { 2134 have_same_class = B_FALSE; 2135 break; 2136 } 2137 } 2138 2139 done: 2140 *have_same_classp = have_same_class; 2141 2142 return (0); 2143 2144 fail2: 2145 EFSYS_PROBE(fail2); 2146 fail1: 2147 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2148 return (rc); 2149 } 2150 2151 __checkReturn efx_rc_t 2152 efx_mae_outer_rule_recirc_id_set( 2153 __in efx_mae_match_spec_t *spec, 2154 __in uint8_t recirc_id) 2155 { 2156 efx_rc_t rc; 2157 2158 if (spec->emms_type != EFX_MAE_RULE_OUTER) { 2159 rc = EINVAL; 2160 goto fail1; 2161 } 2162 2163 spec->emms_outer_rule_recirc_id = recirc_id; 2164 2165 return (0); 2166 2167 fail1: 2168 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2169 return (rc); 2170 } 2171 2172 __checkReturn efx_rc_t 2173 efx_mae_outer_rule_insert( 2174 __in efx_nic_t *enp, 2175 __in const efx_mae_match_spec_t *spec, 2176 __in efx_tunnel_protocol_t encap_type, 2177 __out efx_mae_rule_id_t *or_idp) 2178 { 2179 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2180 efx_mcdi_req_t req; 2181 EFX_MCDI_DECLARE_BUF(payload, 2182 MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2, 2183 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 2184 uint32_t encap_type_mcdi; 2185 efx_mae_rule_id_t or_id; 2186 size_t offset; 2187 efx_rc_t rc; 2188 2189 EFX_STATIC_ASSERT(sizeof (or_idp->id) == 2190 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN); 2191 2192 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 2193 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL); 2194 2195 if (encp->enc_mae_supported == B_FALSE) { 2196 rc = ENOTSUP; 2197 goto fail1; 2198 } 2199 2200 if (spec->emms_type != EFX_MAE_RULE_OUTER) { 2201 rc = EINVAL; 2202 goto fail2; 2203 } 2204 2205 switch (encap_type) { 2206 case EFX_TUNNEL_PROTOCOL_NONE: 2207 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE; 2208 break; 2209 case EFX_TUNNEL_PROTOCOL_VXLAN: 2210 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN; 2211 break; 2212 case EFX_TUNNEL_PROTOCOL_GENEVE: 2213 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE; 2214 break; 2215 case EFX_TUNNEL_PROTOCOL_NVGRE: 2216 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE; 2217 break; 2218 default: 2219 rc = ENOTSUP; 2220 goto fail3; 2221 } 2222 2223 req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT; 2224 req.emr_in_buf = payload; 2225 req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2; 2226 req.emr_out_buf = payload; 2227 req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN; 2228 2229 MCDI_IN_SET_DWORD(req, 2230 MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi); 2231 2232 MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio); 2233 2234 /* 2235 * Mask-value pairs have been stored in the byte order needed for the 2236 * MCDI request and are thus safe to be copied directly to the buffer. 2237 * The library cares about byte order in efx_mae_match_spec_field_set(). 2238 */ 2239 EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >= 2240 MAE_ENC_FIELD_PAIRS_LEN); 2241 offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST; 2242 memcpy(payload + offset, spec->emms_mask_value_pairs.outer, 2243 MAE_ENC_FIELD_PAIRS_LEN); 2244 2245 MCDI_IN_SET_BYTE(req, MAE_OUTER_RULE_INSERT_IN_RECIRC_ID, 2246 spec->emms_outer_rule_recirc_id); 2247 2248 efx_mcdi_execute(enp, &req); 2249 2250 if (req.emr_rc != 0) { 2251 rc = req.emr_rc; 2252 goto fail4; 2253 } 2254 2255 if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) { 2256 rc = EMSGSIZE; 2257 goto fail5; 2258 } 2259 2260 or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 2261 if (or_id.id == EFX_MAE_RSRC_ID_INVALID) { 2262 rc = ENOENT; 2263 goto fail6; 2264 } 2265 2266 or_idp->id = or_id.id; 2267 2268 return (0); 2269 2270 fail6: 2271 EFSYS_PROBE(fail6); 2272 fail5: 2273 EFSYS_PROBE(fail5); 2274 fail4: 2275 EFSYS_PROBE(fail4); 2276 fail3: 2277 EFSYS_PROBE(fail3); 2278 fail2: 2279 EFSYS_PROBE(fail2); 2280 fail1: 2281 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2282 return (rc); 2283 } 2284 2285 __checkReturn efx_rc_t 2286 efx_mae_outer_rule_remove( 2287 __in efx_nic_t *enp, 2288 __in const efx_mae_rule_id_t *or_idp) 2289 { 2290 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2291 efx_mcdi_req_t req; 2292 EFX_MCDI_DECLARE_BUF(payload, 2293 MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1), 2294 MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 2295 efx_rc_t rc; 2296 2297 if (encp->enc_mae_supported == B_FALSE) { 2298 rc = ENOTSUP; 2299 goto fail1; 2300 } 2301 2302 req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE; 2303 req.emr_in_buf = payload; 2304 req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1); 2305 req.emr_out_buf = payload; 2306 req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1); 2307 2308 MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id); 2309 2310 efx_mcdi_execute(enp, &req); 2311 2312 if (req.emr_rc != 0) { 2313 rc = req.emr_rc; 2314 goto fail2; 2315 } 2316 2317 if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) { 2318 rc = EMSGSIZE; 2319 goto fail3; 2320 } 2321 2322 if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != 2323 or_idp->id) { 2324 /* Firmware failed to remove the outer rule. */ 2325 rc = EAGAIN; 2326 goto fail4; 2327 } 2328 2329 return (0); 2330 2331 fail4: 2332 EFSYS_PROBE(fail4); 2333 fail3: 2334 EFSYS_PROBE(fail3); 2335 fail2: 2336 EFSYS_PROBE(fail2); 2337 fail1: 2338 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2339 return (rc); 2340 } 2341 2342 __checkReturn efx_rc_t 2343 efx_mae_match_spec_outer_rule_id_set( 2344 __in efx_mae_match_spec_t *spec, 2345 __in const efx_mae_rule_id_t *or_idp) 2346 { 2347 uint32_t full_mask = UINT32_MAX; 2348 efx_rc_t rc; 2349 2350 if (spec->emms_type != EFX_MAE_RULE_ACTION) { 2351 rc = EINVAL; 2352 goto fail1; 2353 } 2354 2355 if (or_idp == NULL) { 2356 rc = EINVAL; 2357 goto fail2; 2358 } 2359 2360 rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID, 2361 sizeof (or_idp->id), (const uint8_t *)&or_idp->id, 2362 sizeof (full_mask), (const uint8_t *)&full_mask); 2363 if (rc != 0) 2364 goto fail3; 2365 2366 return (0); 2367 2368 fail3: 2369 EFSYS_PROBE(fail3); 2370 fail2: 2371 EFSYS_PROBE(fail2); 2372 fail1: 2373 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2374 return (rc); 2375 } 2376 2377 __checkReturn efx_rc_t 2378 efx_mae_mac_addr_alloc( 2379 __in efx_nic_t *enp, 2380 __in uint8_t addr_bytes[EFX_MAC_ADDR_LEN], 2381 __out efx_mae_mac_id_t *mac_idp) 2382 { 2383 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2384 efx_mcdi_req_t req; 2385 EFX_MCDI_DECLARE_BUF(payload, 2386 MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN, 2387 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN); 2388 efx_mae_mac_id_t mac_id; 2389 efx_rc_t rc; 2390 2391 EFX_STATIC_ASSERT(sizeof (mac_idp->id) == 2392 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_LEN); 2393 2394 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 2395 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 2396 2397 if (encp->enc_mae_supported == B_FALSE) { 2398 rc = ENOTSUP; 2399 goto fail1; 2400 } 2401 2402 if (encp->enc_mae_aset_v2_supported == B_FALSE) { 2403 rc = ENOTSUP; 2404 goto fail2; 2405 } 2406 2407 req.emr_cmd = MC_CMD_MAE_MAC_ADDR_ALLOC; 2408 req.emr_in_buf = payload; 2409 req.emr_in_length = MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN; 2410 req.emr_out_buf = payload; 2411 req.emr_out_length = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN; 2412 2413 memcpy(payload + MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_OFST, 2414 addr_bytes, EFX_MAC_ADDR_LEN); 2415 2416 efx_mcdi_execute(enp, &req); 2417 2418 if (req.emr_rc != 0) { 2419 rc = req.emr_rc; 2420 goto fail3; 2421 } 2422 2423 if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN) { 2424 rc = EMSGSIZE; 2425 goto fail4; 2426 } 2427 2428 mac_id.id = MCDI_OUT_DWORD(req, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID); 2429 if (mac_id.id == EFX_MAE_RSRC_ID_INVALID) { 2430 rc = ENOENT; 2431 goto fail5; 2432 } 2433 2434 mac_idp->id = mac_id.id; 2435 2436 return (0); 2437 2438 fail5: 2439 EFSYS_PROBE(fail5); 2440 fail4: 2441 EFSYS_PROBE(fail4); 2442 fail3: 2443 EFSYS_PROBE(fail3); 2444 fail2: 2445 EFSYS_PROBE(fail2); 2446 fail1: 2447 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2448 return (rc); 2449 } 2450 2451 __checkReturn efx_rc_t 2452 efx_mae_mac_addr_free( 2453 __in efx_nic_t *enp, 2454 __in const efx_mae_mac_id_t *mac_idp) 2455 { 2456 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2457 efx_mcdi_req_t req; 2458 EFX_MCDI_DECLARE_BUF(payload, 2459 MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1), 2460 MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1)); 2461 efx_rc_t rc; 2462 2463 if (encp->enc_mae_supported == B_FALSE) { 2464 rc = ENOTSUP; 2465 goto fail1; 2466 } 2467 2468 if (encp->enc_mae_aset_v2_supported == B_FALSE) { 2469 rc = ENOTSUP; 2470 goto fail2; 2471 } 2472 2473 req.emr_cmd = MC_CMD_MAE_MAC_ADDR_FREE; 2474 req.emr_in_buf = payload; 2475 req.emr_in_length = MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1); 2476 req.emr_out_buf = payload; 2477 req.emr_out_length = MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1); 2478 2479 MCDI_IN_SET_DWORD(req, MAE_MAC_ADDR_FREE_IN_MAC_ID, mac_idp->id); 2480 2481 efx_mcdi_execute(enp, &req); 2482 2483 if (req.emr_rc != 0) { 2484 rc = req.emr_rc; 2485 goto fail3; 2486 } 2487 2488 if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1)) { 2489 rc = EMSGSIZE; 2490 goto fail4; 2491 } 2492 2493 if (MCDI_OUT_DWORD(req, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) != 2494 mac_idp->id) { 2495 /* Firmware failed to remove the MAC address entry. */ 2496 rc = EAGAIN; 2497 goto fail5; 2498 } 2499 2500 return (0); 2501 2502 fail5: 2503 EFSYS_PROBE(fail5); 2504 fail4: 2505 EFSYS_PROBE(fail4); 2506 fail3: 2507 EFSYS_PROBE(fail3); 2508 fail2: 2509 EFSYS_PROBE(fail2); 2510 fail1: 2511 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2512 return (rc); 2513 } 2514 2515 __checkReturn efx_rc_t 2516 efx_mae_action_set_fill_in_dst_mac_id( 2517 __in efx_mae_actions_t *spec, 2518 __in const efx_mae_mac_id_t *mac_idp) 2519 { 2520 efx_rc_t rc; 2521 2522 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) == 0) { 2523 /* 2524 * The caller has not intended to have this action originally, 2525 * hence, they cannot indicate the MAC address entry ID. 2526 */ 2527 rc = EINVAL; 2528 goto fail1; 2529 } 2530 2531 if (spec->ema_rsrc.emar_dst_mac_id.id != EFX_MAE_RSRC_ID_INVALID) { 2532 /* An attempt to indicate the MAC address entry ID twice. */ 2533 rc = EINVAL; 2534 goto fail2; 2535 } 2536 2537 if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) { 2538 rc = EINVAL; 2539 goto fail3; 2540 } 2541 2542 spec->ema_rsrc.emar_dst_mac_id.id = mac_idp->id; 2543 2544 return (0); 2545 2546 fail3: 2547 EFSYS_PROBE(fail3); 2548 fail2: 2549 EFSYS_PROBE(fail2); 2550 fail1: 2551 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2552 return (rc); 2553 } 2554 2555 __checkReturn efx_rc_t 2556 efx_mae_action_set_fill_in_src_mac_id( 2557 __in efx_mae_actions_t *spec, 2558 __in const efx_mae_mac_id_t *mac_idp) 2559 { 2560 efx_rc_t rc; 2561 2562 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) == 0) { 2563 /* 2564 * The caller has not intended to have this action originally, 2565 * hence, they cannot indicate the MAC address entry ID. 2566 */ 2567 rc = EINVAL; 2568 goto fail1; 2569 } 2570 2571 if (spec->ema_rsrc.emar_src_mac_id.id != EFX_MAE_RSRC_ID_INVALID) { 2572 /* An attempt to indicate the MAC address entry ID twice. */ 2573 rc = EINVAL; 2574 goto fail2; 2575 } 2576 2577 if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) { 2578 rc = EINVAL; 2579 goto fail3; 2580 } 2581 2582 spec->ema_rsrc.emar_src_mac_id.id = mac_idp->id; 2583 2584 return (0); 2585 2586 fail3: 2587 EFSYS_PROBE(fail3); 2588 fail2: 2589 EFSYS_PROBE(fail2); 2590 fail1: 2591 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2592 return (rc); 2593 } 2594 2595 __checkReturn efx_rc_t 2596 efx_mae_encap_header_alloc( 2597 __in efx_nic_t *enp, 2598 __in efx_tunnel_protocol_t encap_type, 2599 __in_bcount(header_size) uint8_t *header_data, 2600 __in size_t header_size, 2601 __out efx_mae_eh_id_t *eh_idp) 2602 { 2603 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2604 efx_mcdi_req_t req; 2605 EFX_MCDI_DECLARE_BUF(payload, 2606 MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2, 2607 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN); 2608 uint32_t encap_type_mcdi; 2609 efx_mae_eh_id_t eh_id; 2610 efx_rc_t rc; 2611 2612 EFX_STATIC_ASSERT(sizeof (eh_idp->id) == 2613 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN); 2614 2615 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 2616 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); 2617 2618 if (encp->enc_mae_supported == B_FALSE) { 2619 rc = ENOTSUP; 2620 goto fail1; 2621 } 2622 2623 switch (encap_type) { 2624 case EFX_TUNNEL_PROTOCOL_NONE: 2625 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE; 2626 break; 2627 case EFX_TUNNEL_PROTOCOL_VXLAN: 2628 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN; 2629 break; 2630 case EFX_TUNNEL_PROTOCOL_GENEVE: 2631 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE; 2632 break; 2633 case EFX_TUNNEL_PROTOCOL_NVGRE: 2634 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE; 2635 break; 2636 default: 2637 rc = ENOTSUP; 2638 goto fail2; 2639 } 2640 2641 if (header_size > 2642 MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) { 2643 rc = EINVAL; 2644 goto fail3; 2645 } 2646 2647 req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC; 2648 req.emr_in_buf = payload; 2649 req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size); 2650 req.emr_out_buf = payload; 2651 req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN; 2652 2653 MCDI_IN_SET_DWORD(req, 2654 MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi); 2655 2656 memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST, 2657 header_data, header_size); 2658 2659 efx_mcdi_execute(enp, &req); 2660 2661 if (req.emr_rc != 0) { 2662 rc = req.emr_rc; 2663 goto fail4; 2664 } 2665 2666 if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) { 2667 rc = EMSGSIZE; 2668 goto fail5; 2669 } 2670 2671 eh_id.id = MCDI_OUT_DWORD(req, 2672 MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID); 2673 2674 if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) { 2675 rc = ENOENT; 2676 goto fail6; 2677 } 2678 2679 eh_idp->id = eh_id.id; 2680 2681 return (0); 2682 2683 fail6: 2684 EFSYS_PROBE(fail6); 2685 fail5: 2686 EFSYS_PROBE(fail5); 2687 fail4: 2688 EFSYS_PROBE(fail4); 2689 fail3: 2690 EFSYS_PROBE(fail3); 2691 fail2: 2692 EFSYS_PROBE(fail2); 2693 fail1: 2694 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2695 return (rc); 2696 } 2697 2698 __checkReturn efx_rc_t 2699 efx_mae_encap_header_free( 2700 __in efx_nic_t *enp, 2701 __in const efx_mae_eh_id_t *eh_idp) 2702 { 2703 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2704 efx_mcdi_req_t req; 2705 EFX_MCDI_DECLARE_BUF(payload, 2706 MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1), 2707 MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1)); 2708 efx_rc_t rc; 2709 2710 if (encp->enc_mae_supported == B_FALSE) { 2711 rc = ENOTSUP; 2712 goto fail1; 2713 } 2714 2715 req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE; 2716 req.emr_in_buf = payload; 2717 req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1); 2718 req.emr_out_buf = payload; 2719 req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1); 2720 2721 MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id); 2722 2723 efx_mcdi_execute(enp, &req); 2724 2725 if (req.emr_rc != 0) { 2726 rc = req.emr_rc; 2727 goto fail2; 2728 } 2729 2730 if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) != 2731 eh_idp->id) { 2732 /* Firmware failed to remove the encap. header. */ 2733 rc = EAGAIN; 2734 goto fail3; 2735 } 2736 2737 return (0); 2738 2739 fail3: 2740 EFSYS_PROBE(fail3); 2741 fail2: 2742 EFSYS_PROBE(fail2); 2743 fail1: 2744 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2745 return (rc); 2746 } 2747 2748 __checkReturn efx_rc_t 2749 efx_mae_action_set_fill_in_eh_id( 2750 __in efx_mae_actions_t *spec, 2751 __in const efx_mae_eh_id_t *eh_idp) 2752 { 2753 efx_rc_t rc; 2754 2755 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) { 2756 /* 2757 * The caller has not intended to have action ENCAP originally, 2758 * hence, this attempt to indicate encap. header ID is invalid. 2759 */ 2760 rc = EINVAL; 2761 goto fail1; 2762 } 2763 2764 if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) { 2765 /* The caller attempts to indicate encap. header ID twice. */ 2766 rc = EINVAL; 2767 goto fail2; 2768 } 2769 2770 if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) { 2771 rc = EINVAL; 2772 goto fail3; 2773 } 2774 2775 spec->ema_rsrc.emar_eh_id.id = eh_idp->id; 2776 2777 return (0); 2778 2779 fail3: 2780 EFSYS_PROBE(fail3); 2781 fail2: 2782 EFSYS_PROBE(fail2); 2783 fail1: 2784 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2785 return (rc); 2786 } 2787 2788 __checkReturn efx_rc_t 2789 efx_mae_action_set_alloc( 2790 __in efx_nic_t *enp, 2791 __in const efx_mae_actions_t *spec, 2792 __out efx_mae_aset_id_t *aset_idp) 2793 { 2794 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2795 efx_mcdi_req_t req; 2796 EFX_MCDI_DECLARE_BUF(payload, 2797 MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN, 2798 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 2799 efx_mae_aset_id_t aset_id; 2800 efx_rc_t rc; 2801 2802 if (encp->enc_mae_supported == B_FALSE) { 2803 rc = ENOTSUP; 2804 goto fail1; 2805 } 2806 2807 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) != 0 && 2808 spec->ema_rsrc.emar_dst_mac_id.id == EFX_MAE_RSRC_ID_INVALID) { 2809 rc = EINVAL; 2810 goto fail2; 2811 } 2812 2813 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) != 0 && 2814 spec->ema_rsrc.emar_src_mac_id.id == EFX_MAE_RSRC_ID_INVALID) { 2815 rc = EINVAL; 2816 goto fail3; 2817 } 2818 2819 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) != 0 && 2820 spec->ema_rsrc.emar_eh_id.id == EFX_MAE_RSRC_ID_INVALID) { 2821 rc = EINVAL; 2822 goto fail4; 2823 } 2824 2825 if (spec->ema_n_count_actions == 1 && 2826 spec->ema_rsrc.emar_counter_id.id == EFX_MAE_RSRC_ID_INVALID) { 2827 rc = EINVAL; 2828 goto fail5; 2829 } 2830 2831 req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC; 2832 req.emr_in_buf = payload; 2833 req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN; 2834 req.emr_out_buf = payload; 2835 req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN; 2836 2837 /* 2838 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the 2839 * corresponding resource types are supported by the implementation. 2840 * Use proper resource ID assignments instead. 2841 */ 2842 MCDI_IN_SET_DWORD(req, 2843 MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID); 2844 2845 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) { 2846 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2847 MAE_ACTION_SET_ALLOC_IN_DECAP, 1); 2848 } 2849 2850 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2851 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop); 2852 2853 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 2854 spec->ema_rsrc.emar_dst_mac_id.id); 2855 2856 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 2857 spec->ema_rsrc.emar_src_mac_id.id); 2858 2859 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECR_IP_TTL)) != 0) { 2860 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2861 MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL, 1); 2862 } 2863 2864 if (spec->ema_n_vlan_tags_to_push > 0) { 2865 unsigned int outer_tag_idx; 2866 2867 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2868 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, 2869 spec->ema_n_vlan_tags_to_push); 2870 2871 if (spec->ema_n_vlan_tags_to_push == 2872 EFX_MAE_VLAN_PUSH_MAX_NTAGS) { 2873 MCDI_IN_SET_WORD(req, 2874 MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE, 2875 spec->ema_vlan_push_descs[0].emavp_tpid_be); 2876 MCDI_IN_SET_WORD(req, 2877 MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE, 2878 spec->ema_vlan_push_descs[0].emavp_tci_be); 2879 } 2880 2881 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1; 2882 2883 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE, 2884 spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be); 2885 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE, 2886 spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be); 2887 } 2888 2889 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 2890 spec->ema_rsrc.emar_eh_id.id); 2891 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 2892 spec->ema_rsrc.emar_counter_id.id); 2893 2894 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) { 2895 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2896 MAE_ACTION_SET_ALLOC_IN_FLAG, 1); 2897 } 2898 2899 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) { 2900 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2901 MAE_ACTION_SET_ALLOC_IN_MARK, 1); 2902 2903 MCDI_IN_SET_DWORD(req, 2904 MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value); 2905 } 2906 2907 MCDI_IN_SET_DWORD(req, 2908 MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel); 2909 2910 efx_mcdi_execute(enp, &req); 2911 2912 if (req.emr_rc != 0) { 2913 rc = req.emr_rc; 2914 goto fail6; 2915 } 2916 2917 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) { 2918 rc = EMSGSIZE; 2919 goto fail7; 2920 } 2921 2922 aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 2923 if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) { 2924 rc = ENOENT; 2925 goto fail8; 2926 } 2927 2928 aset_idp->id = aset_id.id; 2929 2930 return (0); 2931 2932 fail8: 2933 EFSYS_PROBE(fail8); 2934 fail7: 2935 EFSYS_PROBE(fail7); 2936 fail6: 2937 EFSYS_PROBE(fail6); 2938 fail5: 2939 EFSYS_PROBE(fail5); 2940 fail4: 2941 EFSYS_PROBE(fail4); 2942 fail3: 2943 EFSYS_PROBE(fail3); 2944 fail2: 2945 EFSYS_PROBE(fail2); 2946 fail1: 2947 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2948 return (rc); 2949 } 2950 2951 __checkReturn unsigned int 2952 efx_mae_action_set_get_nb_count( 2953 __in const efx_mae_actions_t *spec) 2954 { 2955 return (spec->ema_n_count_actions); 2956 } 2957 2958 __checkReturn efx_rc_t 2959 efx_mae_action_set_fill_in_counter_id( 2960 __in efx_mae_actions_t *spec, 2961 __in const efx_counter_t *counter_idp) 2962 { 2963 efx_rc_t rc; 2964 2965 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) { 2966 /* 2967 * Invalid to add counter ID if spec does not have COUNT action. 2968 */ 2969 rc = EINVAL; 2970 goto fail1; 2971 } 2972 2973 if (spec->ema_n_count_actions != 1) { 2974 /* 2975 * Having multiple COUNT actions in the spec requires a counter 2976 * list to be used. This API must only be used for a single 2977 * counter per spec. Turn down the request as inappropriate. 2978 */ 2979 rc = EINVAL; 2980 goto fail2; 2981 } 2982 2983 if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) { 2984 /* The caller attempts to indicate counter ID twice. */ 2985 rc = EALREADY; 2986 goto fail3; 2987 } 2988 2989 if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) { 2990 rc = EINVAL; 2991 goto fail4; 2992 } 2993 2994 spec->ema_rsrc.emar_counter_id.id = counter_idp->id; 2995 2996 return (0); 2997 2998 fail4: 2999 EFSYS_PROBE(fail4); 3000 fail3: 3001 EFSYS_PROBE(fail3); 3002 fail2: 3003 EFSYS_PROBE(fail2); 3004 fail1: 3005 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3006 return (rc); 3007 } 3008 3009 __checkReturn efx_rc_t 3010 efx_mae_counters_alloc( 3011 __in efx_nic_t *enp, 3012 __in uint32_t n_counters, 3013 __out uint32_t *n_allocatedp, 3014 __out_ecount(n_counters) efx_counter_t *countersp, 3015 __out_opt uint32_t *gen_countp) 3016 { 3017 EFX_MCDI_DECLARE_BUF(payload, 3018 MC_CMD_MAE_COUNTER_ALLOC_IN_LEN, 3019 MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2); 3020 efx_mae_t *maep = enp->en_maep; 3021 uint32_t n_allocated; 3022 efx_mcdi_req_t req; 3023 unsigned int i; 3024 efx_rc_t rc; 3025 3026 if (n_counters > maep->em_max_ncounters || 3027 n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM || 3028 n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) { 3029 rc = EINVAL; 3030 goto fail1; 3031 } 3032 3033 req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC; 3034 req.emr_in_buf = payload; 3035 req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN; 3036 req.emr_out_buf = payload; 3037 req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters); 3038 3039 MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT, 3040 n_counters); 3041 3042 efx_mcdi_execute(enp, &req); 3043 3044 if (req.emr_rc != 0) { 3045 rc = req.emr_rc; 3046 goto fail2; 3047 } 3048 3049 if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) { 3050 rc = EMSGSIZE; 3051 goto fail3; 3052 } 3053 3054 n_allocated = MCDI_OUT_DWORD(req, 3055 MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT); 3056 if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) { 3057 rc = EFAULT; 3058 goto fail4; 3059 } 3060 3061 for (i = 0; i < n_allocated; i++) { 3062 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req, 3063 MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i); 3064 } 3065 3066 if (gen_countp != NULL) { 3067 *gen_countp = MCDI_OUT_DWORD(req, 3068 MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT); 3069 } 3070 3071 *n_allocatedp = n_allocated; 3072 3073 return (0); 3074 3075 fail4: 3076 EFSYS_PROBE(fail4); 3077 fail3: 3078 EFSYS_PROBE(fail3); 3079 fail2: 3080 EFSYS_PROBE(fail2); 3081 fail1: 3082 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3083 3084 return (rc); 3085 } 3086 3087 __checkReturn efx_rc_t 3088 efx_mae_counters_free( 3089 __in efx_nic_t *enp, 3090 __in uint32_t n_counters, 3091 __out uint32_t *n_freedp, 3092 __in_ecount(n_counters) const efx_counter_t *countersp, 3093 __out_opt uint32_t *gen_countp) 3094 { 3095 EFX_MCDI_DECLARE_BUF(payload, 3096 MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2, 3097 MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2); 3098 efx_mae_t *maep = enp->en_maep; 3099 efx_mcdi_req_t req; 3100 uint32_t n_freed; 3101 unsigned int i; 3102 efx_rc_t rc; 3103 3104 if (n_counters > maep->em_max_ncounters || 3105 n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM || 3106 n_counters > 3107 MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) { 3108 rc = EINVAL; 3109 goto fail1; 3110 } 3111 3112 req.emr_cmd = MC_CMD_MAE_COUNTER_FREE; 3113 req.emr_in_buf = payload; 3114 req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters); 3115 req.emr_out_buf = payload; 3116 req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters); 3117 3118 for (i = 0; i < n_counters; i++) { 3119 MCDI_IN_SET_INDEXED_DWORD(req, 3120 MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id); 3121 } 3122 MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT, 3123 n_counters); 3124 3125 efx_mcdi_execute(enp, &req); 3126 3127 if (req.emr_rc != 0) { 3128 rc = req.emr_rc; 3129 goto fail2; 3130 } 3131 3132 if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) { 3133 rc = EMSGSIZE; 3134 goto fail3; 3135 } 3136 3137 n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT); 3138 3139 if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) { 3140 rc = EFAULT; 3141 goto fail4; 3142 } 3143 3144 if (gen_countp != NULL) { 3145 *gen_countp = MCDI_OUT_DWORD(req, 3146 MAE_COUNTER_FREE_OUT_GENERATION_COUNT); 3147 } 3148 3149 *n_freedp = n_freed; 3150 3151 return (0); 3152 3153 fail4: 3154 EFSYS_PROBE(fail4); 3155 fail3: 3156 EFSYS_PROBE(fail3); 3157 fail2: 3158 EFSYS_PROBE(fail2); 3159 fail1: 3160 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3161 3162 return (rc); 3163 } 3164 3165 __checkReturn efx_rc_t 3166 efx_mae_counters_stream_start( 3167 __in efx_nic_t *enp, 3168 __in uint16_t rxq_id, 3169 __in uint16_t packet_size, 3170 __in uint32_t flags_in, 3171 __out uint32_t *flags_out) 3172 { 3173 efx_mcdi_req_t req; 3174 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN, 3175 MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN); 3176 efx_rc_t rc; 3177 3178 EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE == 3179 1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN); 3180 3181 EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS == 3182 1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN); 3183 3184 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START; 3185 req.emr_in_buf = payload; 3186 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN; 3187 req.emr_out_buf = payload; 3188 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN; 3189 3190 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id); 3191 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE, 3192 packet_size); 3193 MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in); 3194 3195 efx_mcdi_execute(enp, &req); 3196 3197 if (req.emr_rc != 0) { 3198 rc = req.emr_rc; 3199 goto fail1; 3200 } 3201 3202 if (req.emr_out_length_used < 3203 MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) { 3204 rc = EMSGSIZE; 3205 goto fail2; 3206 } 3207 3208 *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS); 3209 3210 return (0); 3211 3212 fail2: 3213 EFSYS_PROBE(fail2); 3214 fail1: 3215 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3216 3217 return (rc); 3218 } 3219 3220 __checkReturn efx_rc_t 3221 efx_mae_counters_stream_stop( 3222 __in efx_nic_t *enp, 3223 __in uint16_t rxq_id, 3224 __out_opt uint32_t *gen_countp) 3225 { 3226 efx_mcdi_req_t req; 3227 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN, 3228 MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN); 3229 efx_rc_t rc; 3230 3231 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP; 3232 req.emr_in_buf = payload; 3233 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN; 3234 req.emr_out_buf = payload; 3235 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN; 3236 3237 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id); 3238 3239 efx_mcdi_execute(enp, &req); 3240 3241 if (req.emr_rc != 0) { 3242 rc = req.emr_rc; 3243 goto fail1; 3244 } 3245 3246 if (req.emr_out_length_used < 3247 MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) { 3248 rc = EMSGSIZE; 3249 goto fail2; 3250 } 3251 3252 if (gen_countp != NULL) { 3253 *gen_countp = MCDI_OUT_DWORD(req, 3254 MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT); 3255 } 3256 3257 return (0); 3258 3259 fail2: 3260 EFSYS_PROBE(fail2); 3261 fail1: 3262 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3263 3264 return (rc); 3265 } 3266 3267 __checkReturn efx_rc_t 3268 efx_mae_counters_stream_give_credits( 3269 __in efx_nic_t *enp, 3270 __in uint32_t n_credits) 3271 { 3272 efx_mcdi_req_t req; 3273 EFX_MCDI_DECLARE_BUF(payload, 3274 MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN, 3275 MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN); 3276 efx_rc_t rc; 3277 3278 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS; 3279 req.emr_in_buf = payload; 3280 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN; 3281 req.emr_out_buf = payload; 3282 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN; 3283 3284 MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS, 3285 n_credits); 3286 3287 efx_mcdi_execute(enp, &req); 3288 3289 if (req.emr_rc != 0) { 3290 rc = req.emr_rc; 3291 goto fail1; 3292 } 3293 3294 return (0); 3295 3296 fail1: 3297 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3298 3299 return (rc); 3300 } 3301 3302 __checkReturn efx_rc_t 3303 efx_mae_action_set_free( 3304 __in efx_nic_t *enp, 3305 __in const efx_mae_aset_id_t *aset_idp) 3306 { 3307 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3308 efx_mcdi_req_t req; 3309 EFX_MCDI_DECLARE_BUF(payload, 3310 MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1), 3311 MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 3312 efx_rc_t rc; 3313 3314 if (encp->enc_mae_supported == B_FALSE) { 3315 rc = ENOTSUP; 3316 goto fail1; 3317 } 3318 3319 req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE; 3320 req.emr_in_buf = payload; 3321 req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1); 3322 req.emr_out_buf = payload; 3323 req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1); 3324 3325 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id); 3326 3327 efx_mcdi_execute(enp, &req); 3328 3329 if (req.emr_rc != 0) { 3330 rc = req.emr_rc; 3331 goto fail2; 3332 } 3333 3334 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) { 3335 rc = EMSGSIZE; 3336 goto fail3; 3337 } 3338 3339 if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != 3340 aset_idp->id) { 3341 /* Firmware failed to free the action set. */ 3342 rc = EAGAIN; 3343 goto fail4; 3344 } 3345 3346 return (0); 3347 3348 fail4: 3349 EFSYS_PROBE(fail4); 3350 fail3: 3351 EFSYS_PROBE(fail3); 3352 fail2: 3353 EFSYS_PROBE(fail2); 3354 fail1: 3355 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3356 return (rc); 3357 } 3358 3359 __checkReturn efx_rc_t 3360 efx_mae_action_rule_insert( 3361 __in efx_nic_t *enp, 3362 __in const efx_mae_match_spec_t *spec, 3363 __in const efx_mae_aset_list_id_t *asl_idp, 3364 __in const efx_mae_aset_id_t *as_idp, 3365 __out efx_mae_rule_id_t *ar_idp) 3366 { 3367 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3368 efx_mcdi_req_t req; 3369 EFX_MCDI_DECLARE_BUF(payload, 3370 MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2, 3371 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 3372 efx_oword_t *rule_response; 3373 efx_mae_rule_id_t ar_id; 3374 size_t offset; 3375 efx_rc_t rc; 3376 3377 EFX_STATIC_ASSERT(sizeof (ar_idp->id) == 3378 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN); 3379 3380 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 3381 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 3382 3383 if (encp->enc_mae_supported == B_FALSE) { 3384 rc = ENOTSUP; 3385 goto fail1; 3386 } 3387 3388 if (spec->emms_type != EFX_MAE_RULE_ACTION || 3389 (asl_idp != NULL && as_idp != NULL) || 3390 (asl_idp == NULL && as_idp == NULL)) { 3391 rc = EINVAL; 3392 goto fail2; 3393 } 3394 3395 req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT; 3396 req.emr_in_buf = payload; 3397 req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2; 3398 req.emr_out_buf = payload; 3399 req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN; 3400 3401 EFX_STATIC_ASSERT(sizeof (*rule_response) <= 3402 MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN); 3403 offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST; 3404 rule_response = (efx_oword_t *)(payload + offset); 3405 EFX_POPULATE_OWORD_3(*rule_response, 3406 MAE_ACTION_RULE_RESPONSE_ASL_ID, 3407 (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID, 3408 MAE_ACTION_RULE_RESPONSE_AS_ID, 3409 (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID, 3410 MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID); 3411 3412 MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio); 3413 3414 /* 3415 * Mask-value pairs have been stored in the byte order needed for the 3416 * MCDI request and are thus safe to be copied directly to the buffer. 3417 */ 3418 EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >= 3419 MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN); 3420 offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST; 3421 memcpy(payload + offset, spec->emms_mask_value_pairs.action, 3422 MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN); 3423 3424 efx_mcdi_execute(enp, &req); 3425 3426 if (req.emr_rc != 0) { 3427 rc = req.emr_rc; 3428 goto fail3; 3429 } 3430 3431 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) { 3432 rc = EMSGSIZE; 3433 goto fail4; 3434 } 3435 3436 ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 3437 if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) { 3438 rc = ENOENT; 3439 goto fail5; 3440 } 3441 3442 ar_idp->id = ar_id.id; 3443 3444 return (0); 3445 3446 fail5: 3447 EFSYS_PROBE(fail5); 3448 fail4: 3449 EFSYS_PROBE(fail4); 3450 fail3: 3451 EFSYS_PROBE(fail3); 3452 fail2: 3453 EFSYS_PROBE(fail2); 3454 fail1: 3455 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3456 return (rc); 3457 } 3458 3459 __checkReturn efx_rc_t 3460 efx_mae_action_rule_remove( 3461 __in efx_nic_t *enp, 3462 __in const efx_mae_rule_id_t *ar_idp) 3463 { 3464 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3465 efx_mcdi_req_t req; 3466 EFX_MCDI_DECLARE_BUF(payload, 3467 MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1), 3468 MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 3469 efx_rc_t rc; 3470 3471 if (encp->enc_mae_supported == B_FALSE) { 3472 rc = ENOTSUP; 3473 goto fail1; 3474 } 3475 3476 req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE; 3477 req.emr_in_buf = payload; 3478 req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1); 3479 req.emr_out_buf = payload; 3480 req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1); 3481 3482 MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id); 3483 3484 efx_mcdi_execute(enp, &req); 3485 3486 if (req.emr_rc != 0) { 3487 rc = req.emr_rc; 3488 goto fail2; 3489 } 3490 3491 if (req.emr_out_length_used < 3492 MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) { 3493 rc = EMSGSIZE; 3494 goto fail3; 3495 } 3496 3497 if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != 3498 ar_idp->id) { 3499 /* Firmware failed to delete the action rule. */ 3500 rc = EAGAIN; 3501 goto fail4; 3502 } 3503 3504 return (0); 3505 3506 fail4: 3507 EFSYS_PROBE(fail4); 3508 fail3: 3509 EFSYS_PROBE(fail3); 3510 fail2: 3511 EFSYS_PROBE(fail2); 3512 fail1: 3513 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3514 return (rc); 3515 } 3516 3517 __checkReturn efx_rc_t 3518 efx_mcdi_mport_alloc_alias( 3519 __in efx_nic_t *enp, 3520 __out efx_mport_id_t *mportp, 3521 __out_opt uint32_t *labelp) 3522 { 3523 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3524 efx_mcdi_req_t req; 3525 EFX_MCDI_DECLARE_BUF(payload, 3526 MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN, 3527 MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN); 3528 efx_rc_t rc; 3529 3530 if (encp->enc_mae_supported == B_FALSE) { 3531 rc = ENOTSUP; 3532 goto fail1; 3533 } 3534 3535 req.emr_cmd = MC_CMD_MAE_MPORT_ALLOC; 3536 req.emr_in_buf = payload; 3537 req.emr_in_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN; 3538 req.emr_out_buf = payload; 3539 req.emr_out_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN; 3540 3541 MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_IN_TYPE, 3542 MC_CMD_MAE_MPORT_ALLOC_IN_MPORT_TYPE_ALIAS); 3543 MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT, 3544 MAE_MPORT_SELECTOR_ASSIGNED); 3545 3546 efx_mcdi_execute(enp, &req); 3547 3548 if (req.emr_rc != 0) { 3549 rc = req.emr_rc; 3550 goto fail2; 3551 } 3552 3553 mportp->id = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_OUT_MPORT_ID); 3554 if (labelp != NULL) 3555 *labelp = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL); 3556 3557 return (0); 3558 3559 fail2: 3560 EFSYS_PROBE(fail2); 3561 fail1: 3562 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3563 return (rc); 3564 } 3565 3566 __checkReturn efx_rc_t 3567 efx_mae_mport_free( 3568 __in efx_nic_t *enp, 3569 __in const efx_mport_id_t *mportp) 3570 { 3571 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3572 efx_mcdi_req_t req; 3573 EFX_MCDI_DECLARE_BUF(payload, 3574 MC_CMD_MAE_MPORT_FREE_IN_LEN, 3575 MC_CMD_MAE_MPORT_FREE_OUT_LEN); 3576 efx_rc_t rc; 3577 3578 if (encp->enc_mae_supported == B_FALSE) { 3579 rc = ENOTSUP; 3580 goto fail1; 3581 } 3582 3583 req.emr_cmd = MC_CMD_MAE_MPORT_FREE; 3584 req.emr_in_buf = payload; 3585 req.emr_in_length = MC_CMD_MAE_MPORT_FREE_IN_LEN; 3586 req.emr_out_buf = payload; 3587 req.emr_out_length = MC_CMD_MAE_MPORT_FREE_OUT_LEN; 3588 3589 MCDI_IN_SET_DWORD(req, MAE_MPORT_FREE_IN_MPORT_ID, mportp->id); 3590 3591 efx_mcdi_execute(enp, &req); 3592 3593 if (req.emr_rc != 0) { 3594 rc = req.emr_rc; 3595 goto fail2; 3596 } 3597 3598 return (0); 3599 3600 fail2: 3601 EFSYS_PROBE(fail2); 3602 fail1: 3603 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3604 return (rc); 3605 } 3606 3607 static __checkReturn efx_rc_t 3608 efx_mae_read_mport_journal_single( 3609 __in uint8_t *entry_buf, 3610 __out efx_mport_desc_t *desc) 3611 { 3612 uint32_t pcie_intf; 3613 efx_rc_t rc; 3614 3615 memset(desc, 0, sizeof (*desc)); 3616 3617 desc->emd_id.id = MCDI_STRUCT_DWORD(entry_buf, 3618 MAE_MPORT_DESC_V2_MPORT_ID); 3619 3620 desc->emd_can_receive_on = MCDI_STRUCT_DWORD_FIELD(entry_buf, 3621 MAE_MPORT_DESC_V2_FLAGS, 3622 MAE_MPORT_DESC_V2_CAN_RECEIVE_ON); 3623 3624 desc->emd_can_deliver_to = MCDI_STRUCT_DWORD_FIELD(entry_buf, 3625 MAE_MPORT_DESC_V2_FLAGS, 3626 MAE_MPORT_DESC_V2_CAN_DELIVER_TO); 3627 3628 desc->emd_can_delete = MCDI_STRUCT_DWORD_FIELD(entry_buf, 3629 MAE_MPORT_DESC_V2_FLAGS, 3630 MAE_MPORT_DESC_V2_CAN_DELETE); 3631 3632 desc->emd_zombie = MCDI_STRUCT_DWORD_FIELD(entry_buf, 3633 MAE_MPORT_DESC_V2_FLAGS, 3634 MAE_MPORT_DESC_V2_IS_ZOMBIE); 3635 3636 desc->emd_type = MCDI_STRUCT_DWORD(entry_buf, 3637 MAE_MPORT_DESC_V2_MPORT_TYPE); 3638 3639 /* 3640 * We can't check everything here. If some additional checks are 3641 * required, they should be performed by the callback function. 3642 */ 3643 switch (desc->emd_type) { 3644 case EFX_MPORT_TYPE_NET_PORT: 3645 desc->emd_net_port.ep_index = 3646 MCDI_STRUCT_DWORD(entry_buf, 3647 MAE_MPORT_DESC_V2_NET_PORT_IDX); 3648 break; 3649 case EFX_MPORT_TYPE_ALIAS: 3650 desc->emd_alias.ea_target_mport_id.id = 3651 MCDI_STRUCT_DWORD(entry_buf, 3652 MAE_MPORT_DESC_V2_ALIAS_DELIVER_MPORT_ID); 3653 break; 3654 case EFX_MPORT_TYPE_VNIC: 3655 desc->emd_vnic.ev_client_type = 3656 MCDI_STRUCT_DWORD(entry_buf, 3657 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE); 3658 if (desc->emd_vnic.ev_client_type != 3659 EFX_MPORT_VNIC_CLIENT_FUNCTION) 3660 break; 3661 3662 pcie_intf = MCDI_STRUCT_DWORD(entry_buf, 3663 MAE_MPORT_DESC_V2_VNIC_FUNCTION_INTERFACE); 3664 rc = efx_mcdi_intf_from_pcie(pcie_intf, 3665 &desc->emd_vnic.ev_intf); 3666 if (rc != 0) 3667 goto fail1; 3668 3669 desc->emd_vnic.ev_pf = MCDI_STRUCT_WORD(entry_buf, 3670 MAE_MPORT_DESC_V2_VNIC_FUNCTION_PF_IDX); 3671 desc->emd_vnic.ev_vf = MCDI_STRUCT_WORD(entry_buf, 3672 MAE_MPORT_DESC_V2_VNIC_FUNCTION_VF_IDX); 3673 desc->emd_vnic.ev_handle = MCDI_STRUCT_DWORD(entry_buf, 3674 MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE); 3675 break; 3676 default: 3677 rc = EINVAL; 3678 goto fail2; 3679 } 3680 3681 return (0); 3682 3683 fail2: 3684 EFSYS_PROBE(fail2); 3685 fail1: 3686 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3687 return (rc); 3688 } 3689 3690 static __checkReturn efx_rc_t 3691 efx_mae_read_mport_journal_batch( 3692 __in efx_nic_t *enp, 3693 __in efx_mae_read_mport_journal_cb *cbp, 3694 __in void *cb_datap, 3695 __out uint32_t *morep) 3696 { 3697 efx_mcdi_req_t req; 3698 EFX_MCDI_DECLARE_BUF(payload, 3699 MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN, 3700 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2); 3701 uint32_t n_entries; 3702 uint32_t entry_sz; 3703 uint8_t *entry_buf; 3704 unsigned int i; 3705 efx_rc_t rc; 3706 3707 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_NET_PORT == 3708 MAE_MPORT_DESC_V2_MPORT_TYPE_NET_PORT); 3709 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_ALIAS == 3710 MAE_MPORT_DESC_V2_MPORT_TYPE_ALIAS); 3711 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_VNIC == 3712 MAE_MPORT_DESC_V2_MPORT_TYPE_VNIC); 3713 3714 EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_FUNCTION == 3715 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_FUNCTION); 3716 EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_PLUGIN == 3717 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_PLUGIN); 3718 3719 if (cbp == NULL) { 3720 rc = EINVAL; 3721 goto fail1; 3722 } 3723 3724 req.emr_cmd = MC_CMD_MAE_MPORT_READ_JOURNAL; 3725 req.emr_in_buf = payload; 3726 req.emr_in_length = MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN; 3727 req.emr_out_buf = payload; 3728 req.emr_out_length = MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2; 3729 3730 MCDI_IN_SET_DWORD(req, MAE_MPORT_READ_JOURNAL_IN_FLAGS, 0); 3731 3732 efx_mcdi_execute(enp, &req); 3733 3734 if (req.emr_rc != 0) { 3735 rc = req.emr_rc; 3736 goto fail2; 3737 } 3738 3739 if (req.emr_out_length_used < 3740 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN) { 3741 rc = EMSGSIZE; 3742 goto fail3; 3743 } 3744 3745 if (morep != NULL) { 3746 *morep = MCDI_OUT_DWORD_FIELD(req, 3747 MAE_MPORT_READ_JOURNAL_OUT_FLAGS, 3748 MAE_MPORT_READ_JOURNAL_OUT_MORE); 3749 } 3750 n_entries = MCDI_OUT_DWORD(req, 3751 MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT); 3752 entry_sz = MCDI_OUT_DWORD(req, 3753 MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC); 3754 entry_buf = MCDI_OUT2(req, uint8_t, 3755 MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA); 3756 3757 if (entry_sz < MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_OFST + 3758 MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_LEN) { 3759 rc = EINVAL; 3760 goto fail4; 3761 } 3762 if (n_entries * entry_sz / entry_sz != n_entries) { 3763 rc = EINVAL; 3764 goto fail5; 3765 } 3766 if (req.emr_out_length_used != 3767 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN + n_entries * entry_sz) { 3768 rc = EINVAL; 3769 goto fail6; 3770 } 3771 3772 for (i = 0; i < n_entries; i++) { 3773 efx_mport_desc_t desc; 3774 3775 rc = efx_mae_read_mport_journal_single(entry_buf, &desc); 3776 if (rc != 0) 3777 continue; 3778 3779 (*cbp)(cb_datap, &desc, sizeof (desc)); 3780 entry_buf += entry_sz; 3781 } 3782 3783 return (0); 3784 3785 fail6: 3786 EFSYS_PROBE(fail6); 3787 fail5: 3788 EFSYS_PROBE(fail5); 3789 fail4: 3790 EFSYS_PROBE(fail4); 3791 fail3: 3792 EFSYS_PROBE(fail3); 3793 fail2: 3794 EFSYS_PROBE(fail2); 3795 fail1: 3796 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3797 return (rc); 3798 } 3799 3800 __checkReturn efx_rc_t 3801 efx_mae_read_mport_journal( 3802 __in efx_nic_t *enp, 3803 __in efx_mae_read_mport_journal_cb *cbp, 3804 __in void *cb_datap) 3805 { 3806 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3807 uint32_t more = 0; 3808 efx_rc_t rc; 3809 3810 if (encp->enc_mae_supported == B_FALSE) { 3811 rc = ENOTSUP; 3812 goto fail1; 3813 } 3814 3815 do { 3816 rc = efx_mae_read_mport_journal_batch(enp, cbp, cb_datap, 3817 &more); 3818 if (rc != 0) 3819 goto fail2; 3820 } while (more != 0); 3821 3822 return (0); 3823 3824 fail2: 3825 EFSYS_PROBE(fail2); 3826 fail1: 3827 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3828 return (rc); 3829 } 3830 3831 #endif /* EFSYS_OPT_MAE */ 3832