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 case 1: 1031 memcpy(mvp + descp->emmd_value_offset, 1032 value, 1); 1033 break; 1034 default: 1035 EFSYS_ASSERT(B_FALSE); 1036 } 1037 1038 switch (mask_size) { 1039 case 4: 1040 EFX_POPULATE_DWORD_1(dword, 1041 EFX_DWORD_0, *(const uint32_t *)mask); 1042 1043 memcpy(mvp + descp->emmd_mask_offset, 1044 &dword, sizeof (dword)); 1045 break; 1046 case 1: 1047 memcpy(mvp + descp->emmd_mask_offset, 1048 mask, 1); 1049 break; 1050 default: 1051 EFSYS_ASSERT(B_FALSE); 1052 } 1053 } 1054 1055 return (0); 1056 1057 fail5: 1058 EFSYS_PROBE(fail5); 1059 fail4: 1060 EFSYS_PROBE(fail4); 1061 fail3: 1062 EFSYS_PROBE(fail3); 1063 fail2: 1064 EFSYS_PROBE(fail2); 1065 fail1: 1066 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1067 return (rc); 1068 } 1069 1070 __checkReturn efx_rc_t 1071 efx_mae_match_spec_bit_set( 1072 __in efx_mae_match_spec_t *spec, 1073 __in efx_mae_field_id_t field_id, 1074 __in boolean_t value) 1075 { 1076 const efx_mae_mv_bit_desc_t *bit_descp; 1077 unsigned int bit_desc_set_nentries; 1078 unsigned int byte_idx; 1079 unsigned int bit_idx; 1080 uint8_t *mvp; 1081 efx_rc_t rc; 1082 1083 switch (spec->emms_type) { 1084 case EFX_MAE_RULE_OUTER: 1085 bit_desc_set_nentries = 1086 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set); 1087 bit_descp = &__efx_mae_outer_rule_mv_bit_desc_set[field_id]; 1088 mvp = spec->emms_mask_value_pairs.outer; 1089 break; 1090 case EFX_MAE_RULE_ACTION: 1091 bit_desc_set_nentries = 1092 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set); 1093 bit_descp = &__efx_mae_action_rule_mv_bit_desc_set[field_id]; 1094 mvp = spec->emms_mask_value_pairs.action; 1095 break; 1096 default: 1097 rc = ENOTSUP; 1098 goto fail1; 1099 } 1100 1101 if ((unsigned int)field_id >= bit_desc_set_nentries) { 1102 rc = EINVAL; 1103 goto fail2; 1104 } 1105 1106 if (bit_descp->emmbd_entry_is_valid == B_FALSE) { 1107 rc = EINVAL; 1108 goto fail3; 1109 } 1110 1111 byte_idx = bit_descp->emmbd_value_ofst + bit_descp->emmbd_value_lbn / 8; 1112 bit_idx = bit_descp->emmbd_value_lbn % 8; 1113 1114 if (value != B_FALSE) 1115 mvp[byte_idx] |= (1U << bit_idx); 1116 else 1117 mvp[byte_idx] &= ~(1U << bit_idx); 1118 1119 byte_idx = bit_descp->emmbd_mask_ofst + bit_descp->emmbd_mask_lbn / 8; 1120 bit_idx = bit_descp->emmbd_mask_lbn % 8; 1121 mvp[byte_idx] |= (1U << bit_idx); 1122 1123 return (0); 1124 1125 fail3: 1126 EFSYS_PROBE(fail3); 1127 fail2: 1128 EFSYS_PROBE(fail2); 1129 fail1: 1130 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1131 return (rc); 1132 } 1133 1134 __checkReturn efx_rc_t 1135 efx_mae_match_spec_mport_set( 1136 __in efx_mae_match_spec_t *spec, 1137 __in const efx_mport_sel_t *valuep, 1138 __in_opt const efx_mport_sel_t *maskp) 1139 { 1140 uint32_t full_mask = UINT32_MAX; 1141 const uint8_t *vp; 1142 const uint8_t *mp; 1143 efx_rc_t rc; 1144 1145 if (valuep == NULL) { 1146 rc = EINVAL; 1147 goto fail1; 1148 } 1149 1150 vp = (const uint8_t *)&valuep->sel; 1151 if (maskp != NULL) 1152 mp = (const uint8_t *)&maskp->sel; 1153 else 1154 mp = (const uint8_t *)&full_mask; 1155 1156 rc = efx_mae_match_spec_field_set(spec, 1157 EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR, 1158 sizeof (valuep->sel), vp, sizeof (maskp->sel), mp); 1159 if (rc != 0) 1160 goto fail2; 1161 1162 return (0); 1163 1164 fail2: 1165 EFSYS_PROBE(fail2); 1166 fail1: 1167 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1168 return (rc); 1169 } 1170 1171 __checkReturn boolean_t 1172 efx_mae_match_specs_equal( 1173 __in const efx_mae_match_spec_t *left, 1174 __in const efx_mae_match_spec_t *right) 1175 { 1176 return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE); 1177 } 1178 1179 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit) \ 1180 ((_mask)[(_bit) / (_mask_page_nbits)] & \ 1181 (1ULL << ((_bit) & ((_mask_page_nbits) - 1)))) 1182 1183 static boolean_t 1184 efx_mask_is_prefix( 1185 __in size_t mask_nbytes, 1186 __in_bcount(mask_nbytes) const uint8_t *maskp) 1187 { 1188 boolean_t prev_bit_is_set = B_TRUE; 1189 unsigned int i; 1190 1191 for (i = 0; i < 8 * mask_nbytes; ++i) { 1192 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i); 1193 1194 if (!prev_bit_is_set && bit_is_set) 1195 return B_FALSE; 1196 1197 prev_bit_is_set = bit_is_set; 1198 } 1199 1200 return B_TRUE; 1201 } 1202 1203 static boolean_t 1204 efx_mask_is_all_ones( 1205 __in size_t mask_nbytes, 1206 __in_bcount(mask_nbytes) const uint8_t *maskp) 1207 { 1208 unsigned int i; 1209 uint8_t t = ~0; 1210 1211 for (i = 0; i < mask_nbytes; ++i) 1212 t &= maskp[i]; 1213 1214 return (t == (uint8_t)(~0)); 1215 } 1216 1217 static boolean_t 1218 efx_mask_is_all_zeros( 1219 __in size_t mask_nbytes, 1220 __in_bcount(mask_nbytes) const uint8_t *maskp) 1221 { 1222 unsigned int i; 1223 uint8_t t = 0; 1224 1225 for (i = 0; i < mask_nbytes; ++i) 1226 t |= maskp[i]; 1227 1228 return (t == 0); 1229 } 1230 1231 __checkReturn boolean_t 1232 efx_mae_match_spec_is_valid( 1233 __in efx_nic_t *enp, 1234 __in const efx_mae_match_spec_t *spec) 1235 { 1236 efx_mae_t *maep = enp->en_maep; 1237 unsigned int field_ncaps = maep->em_max_nfields; 1238 const efx_mae_field_cap_t *field_caps; 1239 const efx_mae_mv_desc_t *desc_setp; 1240 unsigned int desc_set_nentries; 1241 const efx_mae_mv_bit_desc_t *bit_desc_setp; 1242 unsigned int bit_desc_set_nentries; 1243 boolean_t is_valid = B_TRUE; 1244 efx_mae_field_id_t field_id; 1245 const uint8_t *mvp; 1246 1247 switch (spec->emms_type) { 1248 case EFX_MAE_RULE_OUTER: 1249 field_caps = maep->em_outer_rule_field_caps; 1250 desc_setp = __efx_mae_outer_rule_mv_desc_set; 1251 desc_set_nentries = 1252 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set); 1253 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set; 1254 bit_desc_set_nentries = 1255 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set); 1256 mvp = spec->emms_mask_value_pairs.outer; 1257 break; 1258 case EFX_MAE_RULE_ACTION: 1259 field_caps = maep->em_action_rule_field_caps; 1260 desc_setp = __efx_mae_action_rule_mv_desc_set; 1261 desc_set_nentries = 1262 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set); 1263 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set; 1264 bit_desc_set_nentries = 1265 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set); 1266 mvp = spec->emms_mask_value_pairs.action; 1267 break; 1268 default: 1269 return (B_FALSE); 1270 } 1271 1272 if (field_caps == NULL) 1273 return (B_FALSE); 1274 1275 for (field_id = 0; (unsigned int)field_id < desc_set_nentries; 1276 ++field_id) { 1277 const efx_mae_mv_desc_t *descp = &desc_setp[field_id]; 1278 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id; 1279 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset; 1280 const uint8_t *m_buf = mvp + descp->emmd_mask_offset; 1281 size_t alt_m_size = descp->emmd_alt_mask_size; 1282 size_t m_size = descp->emmd_mask_size; 1283 1284 if (m_size == 0) 1285 continue; /* Skip array gap */ 1286 1287 if ((unsigned int)field_cap_id >= field_ncaps) { 1288 /* 1289 * The FW has not reported capability status for 1290 * this field. Make sure that its mask is zeroed. 1291 */ 1292 is_valid = efx_mask_is_all_zeros(m_size, m_buf); 1293 if (is_valid != B_FALSE) 1294 continue; 1295 else 1296 break; 1297 } 1298 1299 switch (field_caps[field_cap_id].emfc_support) { 1300 case MAE_FIELD_SUPPORTED_MATCH_MASK: 1301 is_valid = B_TRUE; 1302 break; 1303 case MAE_FIELD_SUPPORTED_MATCH_PREFIX: 1304 is_valid = efx_mask_is_prefix(m_size, m_buf); 1305 break; 1306 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL: 1307 is_valid = (efx_mask_is_all_ones(m_size, m_buf) || 1308 efx_mask_is_all_zeros(m_size, m_buf)); 1309 break; 1310 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: 1311 is_valid = efx_mask_is_all_ones(m_size, m_buf); 1312 1313 if ((is_valid == B_FALSE) && (alt_m_size != 0)) { 1314 /* 1315 * This field has an alternative one. The FW 1316 * reports ALWAYS for both implying that one 1317 * of them is required to have all-ones mask. 1318 * 1319 * The primary field's mask is incorrect; go 1320 * on to check that of the alternative field. 1321 */ 1322 is_valid = efx_mask_is_all_ones(alt_m_size, 1323 alt_m_buf); 1324 } 1325 break; 1326 case MAE_FIELD_SUPPORTED_MATCH_NEVER: 1327 case MAE_FIELD_UNSUPPORTED: 1328 default: 1329 is_valid = efx_mask_is_all_zeros(m_size, m_buf); 1330 break; 1331 } 1332 1333 if (is_valid == B_FALSE) 1334 return (B_FALSE); 1335 } 1336 1337 for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries; 1338 ++field_id) { 1339 const efx_mae_mv_bit_desc_t *bit_descp = 1340 &bit_desc_setp[field_id]; 1341 unsigned int byte_idx = 1342 bit_descp->emmbd_mask_ofst + 1343 bit_descp->emmbd_mask_lbn / 8; 1344 unsigned int bit_idx = 1345 bit_descp->emmbd_mask_lbn % 8; 1346 efx_mae_field_cap_id_t bit_cap_id = 1347 bit_descp->emmbd_bit_cap_id; 1348 1349 if (bit_descp->emmbd_entry_is_valid == B_FALSE) 1350 continue; /* Skip array gap */ 1351 1352 if ((unsigned int)bit_cap_id >= field_ncaps) { 1353 /* No capability for this bit = unsupported. */ 1354 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0); 1355 if (is_valid == B_FALSE) 1356 break; 1357 else 1358 continue; 1359 } 1360 1361 switch (field_caps[bit_cap_id].emfc_support) { 1362 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL: 1363 is_valid = B_TRUE; 1364 break; 1365 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: 1366 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) != 0); 1367 break; 1368 case MAE_FIELD_SUPPORTED_MATCH_NEVER: 1369 case MAE_FIELD_UNSUPPORTED: 1370 default: 1371 is_valid = ((mvp[byte_idx] & (1U << bit_idx)) == 0); 1372 break; 1373 } 1374 1375 if (is_valid == B_FALSE) 1376 break; 1377 } 1378 1379 return (is_valid); 1380 } 1381 1382 __checkReturn efx_rc_t 1383 efx_mae_action_set_spec_init( 1384 __in efx_nic_t *enp, 1385 __out efx_mae_actions_t **specp) 1386 { 1387 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 1388 efx_mae_actions_t *spec; 1389 efx_rc_t rc; 1390 1391 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec); 1392 if (spec == NULL) { 1393 rc = ENOMEM; 1394 goto fail1; 1395 } 1396 1397 spec->ema_rsrc.emar_dst_mac_id.id = EFX_MAE_RSRC_ID_INVALID; 1398 spec->ema_rsrc.emar_src_mac_id.id = EFX_MAE_RSRC_ID_INVALID; 1399 spec->ema_rsrc.emar_eh_id.id = EFX_MAE_RSRC_ID_INVALID; 1400 spec->ema_rsrc.emar_counter_id.id = EFX_MAE_RSRC_ID_INVALID; 1401 1402 /* 1403 * Helpers which populate v2 actions must reject them when v2 is not 1404 * supported. As they have no EFX NIC argument, save v2 status here. 1405 */ 1406 spec->ema_v2_is_supported = encp->enc_mae_aset_v2_supported; 1407 1408 *specp = spec; 1409 1410 return (0); 1411 1412 fail1: 1413 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1414 return (rc); 1415 } 1416 1417 void 1418 efx_mae_action_set_spec_fini( 1419 __in efx_nic_t *enp, 1420 __in efx_mae_actions_t *spec) 1421 { 1422 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 1423 } 1424 1425 static __checkReturn efx_rc_t 1426 efx_mae_action_set_no_op( 1427 __in efx_mae_actions_t *spec, 1428 __in size_t arg_size, 1429 __in_bcount(arg_size) const uint8_t *arg) 1430 { 1431 efx_rc_t rc; 1432 1433 _NOTE(ARGUNUSED(spec)) 1434 1435 if (arg_size != 0) { 1436 rc = EINVAL; 1437 goto fail1; 1438 } 1439 1440 if (arg != NULL) { 1441 rc = EINVAL; 1442 goto fail2; 1443 } 1444 1445 /* This action does not have any arguments, so do nothing here. */ 1446 1447 return (0); 1448 1449 fail2: 1450 EFSYS_PROBE(fail2); 1451 fail1: 1452 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1453 return (rc); 1454 } 1455 1456 static __checkReturn efx_rc_t 1457 efx_mae_action_set_add_vlan_pop( 1458 __in efx_mae_actions_t *spec, 1459 __in size_t arg_size, 1460 __in_bcount(arg_size) const uint8_t *arg) 1461 { 1462 efx_rc_t rc; 1463 1464 if (arg_size != 0) { 1465 rc = EINVAL; 1466 goto fail1; 1467 } 1468 1469 if (arg != NULL) { 1470 rc = EINVAL; 1471 goto fail2; 1472 } 1473 1474 if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) { 1475 rc = ENOTSUP; 1476 goto fail3; 1477 } 1478 1479 ++spec->ema_n_vlan_tags_to_pop; 1480 1481 return (0); 1482 1483 fail3: 1484 EFSYS_PROBE(fail3); 1485 fail2: 1486 EFSYS_PROBE(fail2); 1487 fail1: 1488 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1489 return (rc); 1490 } 1491 1492 static __checkReturn efx_rc_t 1493 efx_mae_action_set_add_vlan_push( 1494 __in efx_mae_actions_t *spec, 1495 __in size_t arg_size, 1496 __in_bcount(arg_size) const uint8_t *arg) 1497 { 1498 unsigned int n_tags = spec->ema_n_vlan_tags_to_push; 1499 efx_rc_t rc; 1500 1501 if (arg_size != sizeof (*spec->ema_vlan_push_descs)) { 1502 rc = EINVAL; 1503 goto fail1; 1504 } 1505 1506 if (arg == NULL) { 1507 rc = EINVAL; 1508 goto fail2; 1509 } 1510 1511 if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) { 1512 rc = ENOTSUP; 1513 goto fail3; 1514 } 1515 1516 memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size); 1517 ++(spec->ema_n_vlan_tags_to_push); 1518 1519 return (0); 1520 1521 fail3: 1522 EFSYS_PROBE(fail3); 1523 fail2: 1524 EFSYS_PROBE(fail2); 1525 fail1: 1526 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1527 return (rc); 1528 } 1529 1530 static __checkReturn efx_rc_t 1531 efx_mae_action_set_add_count( 1532 __in efx_mae_actions_t *spec, 1533 __in size_t arg_size, 1534 __in_bcount(arg_size) const uint8_t *arg) 1535 { 1536 efx_rc_t rc; 1537 1538 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 1539 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 1540 1541 /* 1542 * Preparing an action set spec to update a counter requires 1543 * two steps: first add this action to the action spec, and then 1544 * add the counter ID to the spec. This allows validity checking 1545 * and resource allocation to be done separately. 1546 * 1547 * In order to fill in the counter ID, the caller is supposed to invoke 1548 * efx_mae_action_set_fill_in_counter_id(). If they do not do that, 1549 * efx_mae_action_set_alloc() invocation will throw an error. 1550 * 1551 * For now, no arguments are supposed to be handled. 1552 */ 1553 1554 if (arg_size != 0) { 1555 rc = EINVAL; 1556 goto fail1; 1557 } 1558 1559 if (arg != NULL) { 1560 rc = EINVAL; 1561 goto fail2; 1562 } 1563 1564 ++(spec->ema_n_count_actions); 1565 1566 return (0); 1567 1568 fail2: 1569 EFSYS_PROBE(fail2); 1570 fail1: 1571 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1572 return (rc); 1573 } 1574 1575 static __checkReturn efx_rc_t 1576 efx_mae_action_set_add_mark( 1577 __in efx_mae_actions_t *spec, 1578 __in size_t arg_size, 1579 __in_bcount(arg_size) const uint8_t *arg) 1580 { 1581 efx_rc_t rc; 1582 1583 if (arg_size != sizeof (spec->ema_mark_value)) { 1584 rc = EINVAL; 1585 goto fail1; 1586 } 1587 1588 if (arg == NULL) { 1589 rc = EINVAL; 1590 goto fail2; 1591 } 1592 1593 memcpy(&spec->ema_mark_value, arg, arg_size); 1594 1595 return (0); 1596 1597 fail2: 1598 EFSYS_PROBE(fail2); 1599 fail1: 1600 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1601 return (rc); 1602 } 1603 1604 static __checkReturn efx_rc_t 1605 efx_mae_action_set_add_deliver( 1606 __in efx_mae_actions_t *spec, 1607 __in size_t arg_size, 1608 __in_bcount(arg_size) const uint8_t *arg) 1609 { 1610 efx_rc_t rc; 1611 1612 if (arg_size != sizeof (spec->ema_deliver_mport)) { 1613 rc = EINVAL; 1614 goto fail1; 1615 } 1616 1617 if (arg == NULL) { 1618 rc = EINVAL; 1619 goto fail2; 1620 } 1621 1622 memcpy(&spec->ema_deliver_mport, arg, arg_size); 1623 1624 return (0); 1625 1626 fail2: 1627 EFSYS_PROBE(fail2); 1628 fail1: 1629 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1630 return (rc); 1631 } 1632 1633 typedef struct efx_mae_action_desc_s { 1634 /* Action specific handler */ 1635 efx_rc_t (*emad_add)(efx_mae_actions_t *, 1636 size_t, const uint8_t *); 1637 } efx_mae_action_desc_t; 1638 1639 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = { 1640 [EFX_MAE_ACTION_DECAP] = { 1641 .emad_add = efx_mae_action_set_no_op 1642 }, 1643 [EFX_MAE_ACTION_VLAN_POP] = { 1644 .emad_add = efx_mae_action_set_add_vlan_pop 1645 }, 1646 [EFX_MAE_ACTION_SET_DST_MAC] = { 1647 .emad_add = efx_mae_action_set_no_op 1648 }, 1649 [EFX_MAE_ACTION_SET_SRC_MAC] = { 1650 .emad_add = efx_mae_action_set_no_op 1651 }, 1652 [EFX_MAE_ACTION_DECR_IP_TTL] = { 1653 .emad_add = efx_mae_action_set_no_op 1654 }, 1655 [EFX_MAE_ACTION_VLAN_PUSH] = { 1656 .emad_add = efx_mae_action_set_add_vlan_push 1657 }, 1658 [EFX_MAE_ACTION_ENCAP] = { 1659 .emad_add = efx_mae_action_set_no_op 1660 }, 1661 [EFX_MAE_ACTION_COUNT] = { 1662 .emad_add = efx_mae_action_set_add_count 1663 }, 1664 [EFX_MAE_ACTION_FLAG] = { 1665 .emad_add = efx_mae_action_set_no_op 1666 }, 1667 [EFX_MAE_ACTION_MARK] = { 1668 .emad_add = efx_mae_action_set_add_mark 1669 }, 1670 [EFX_MAE_ACTION_DELIVER] = { 1671 .emad_add = efx_mae_action_set_add_deliver 1672 } 1673 }; 1674 1675 static const uint32_t efx_mae_action_ordered_map = 1676 (1U << EFX_MAE_ACTION_DECAP) | 1677 (1U << EFX_MAE_ACTION_VLAN_POP) | 1678 (1U << EFX_MAE_ACTION_SET_DST_MAC) | 1679 (1U << EFX_MAE_ACTION_SET_SRC_MAC) | 1680 (1U << EFX_MAE_ACTION_DECR_IP_TTL) | 1681 (1U << EFX_MAE_ACTION_VLAN_PUSH) | 1682 /* 1683 * HW will conduct action COUNT after 1684 * the matching packet has been modified by 1685 * length-affecting actions except for ENCAP. 1686 */ 1687 (1U << EFX_MAE_ACTION_COUNT) | 1688 (1U << EFX_MAE_ACTION_ENCAP) | 1689 (1U << EFX_MAE_ACTION_FLAG) | 1690 (1U << EFX_MAE_ACTION_MARK) | 1691 (1U << EFX_MAE_ACTION_DELIVER); 1692 1693 /* 1694 * These actions must not be added after DELIVER, but 1695 * they can have any place among the rest of 1696 * strictly ordered actions. 1697 */ 1698 static const uint32_t efx_mae_action_nonstrict_map = 1699 (1U << EFX_MAE_ACTION_COUNT) | 1700 (1U << EFX_MAE_ACTION_FLAG) | 1701 (1U << EFX_MAE_ACTION_MARK); 1702 1703 static const uint32_t efx_mae_action_repeat_map = 1704 (1U << EFX_MAE_ACTION_VLAN_POP) | 1705 (1U << EFX_MAE_ACTION_VLAN_PUSH) | 1706 (1U << EFX_MAE_ACTION_COUNT); 1707 1708 /* 1709 * Add an action to an action set. 1710 * 1711 * This has to be invoked in the desired action order. 1712 * An out-of-order action request will be turned down. 1713 */ 1714 static __checkReturn efx_rc_t 1715 efx_mae_action_set_spec_populate( 1716 __in efx_mae_actions_t *spec, 1717 __in efx_mae_action_t type, 1718 __in size_t arg_size, 1719 __in_bcount(arg_size) const uint8_t *arg) 1720 { 1721 uint32_t action_mask; 1722 efx_rc_t rc; 1723 1724 EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <= 1725 (sizeof (efx_mae_action_ordered_map) * 8)); 1726 EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <= 1727 (sizeof (efx_mae_action_repeat_map) * 8)); 1728 1729 EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS); 1730 EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK); 1731 EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER); 1732 1733 if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) { 1734 rc = EINVAL; 1735 goto fail1; 1736 } 1737 1738 action_mask = (1U << type); 1739 1740 if ((spec->ema_actions & action_mask) != 0) { 1741 /* The action set already contains this action. */ 1742 if ((efx_mae_action_repeat_map & action_mask) == 0) { 1743 /* Cannot add another non-repeatable action. */ 1744 rc = ENOTSUP; 1745 goto fail2; 1746 } 1747 } 1748 1749 if ((efx_mae_action_ordered_map & action_mask) != 0) { 1750 uint32_t strict_ordered_map = 1751 efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map; 1752 uint32_t later_actions_mask = 1753 strict_ordered_map & ~(action_mask | (action_mask - 1)); 1754 1755 if ((spec->ema_actions & later_actions_mask) != 0) { 1756 /* Cannot add an action after later ordered actions. */ 1757 rc = ENOTSUP; 1758 goto fail3; 1759 } 1760 } 1761 1762 if (efx_mae_actions[type].emad_add != NULL) { 1763 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg); 1764 if (rc != 0) 1765 goto fail4; 1766 } 1767 1768 spec->ema_actions |= action_mask; 1769 1770 return (0); 1771 1772 fail4: 1773 EFSYS_PROBE(fail4); 1774 fail3: 1775 EFSYS_PROBE(fail3); 1776 fail2: 1777 EFSYS_PROBE(fail2); 1778 fail1: 1779 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1780 return (rc); 1781 } 1782 1783 __checkReturn efx_rc_t 1784 efx_mae_action_set_populate_decap( 1785 __in efx_mae_actions_t *spec) 1786 { 1787 return (efx_mae_action_set_spec_populate(spec, 1788 EFX_MAE_ACTION_DECAP, 0, NULL)); 1789 } 1790 1791 __checkReturn efx_rc_t 1792 efx_mae_action_set_populate_vlan_pop( 1793 __in efx_mae_actions_t *spec) 1794 { 1795 return (efx_mae_action_set_spec_populate(spec, 1796 EFX_MAE_ACTION_VLAN_POP, 0, NULL)); 1797 } 1798 1799 __checkReturn efx_rc_t 1800 efx_mae_action_set_populate_set_dst_mac( 1801 __in efx_mae_actions_t *spec) 1802 { 1803 efx_rc_t rc; 1804 1805 if (spec->ema_v2_is_supported == B_FALSE) { 1806 rc = ENOTSUP; 1807 goto fail1; 1808 } 1809 1810 return (efx_mae_action_set_spec_populate(spec, 1811 EFX_MAE_ACTION_SET_DST_MAC, 0, NULL)); 1812 1813 fail1: 1814 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1815 return (rc); 1816 } 1817 1818 __checkReturn efx_rc_t 1819 efx_mae_action_set_populate_set_src_mac( 1820 __in efx_mae_actions_t *spec) 1821 { 1822 efx_rc_t rc; 1823 1824 if (spec->ema_v2_is_supported == B_FALSE) { 1825 rc = ENOTSUP; 1826 goto fail1; 1827 } 1828 1829 return (efx_mae_action_set_spec_populate(spec, 1830 EFX_MAE_ACTION_SET_SRC_MAC, 0, NULL)); 1831 1832 fail1: 1833 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1834 return (rc); 1835 } 1836 1837 __checkReturn efx_rc_t 1838 efx_mae_action_set_populate_decr_ip_ttl( 1839 __in efx_mae_actions_t *spec) 1840 { 1841 efx_rc_t rc; 1842 1843 if (spec->ema_v2_is_supported == B_FALSE) { 1844 rc = ENOTSUP; 1845 goto fail1; 1846 } 1847 1848 return (efx_mae_action_set_spec_populate(spec, 1849 EFX_MAE_ACTION_DECR_IP_TTL, 0, NULL)); 1850 1851 fail1: 1852 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1853 return (rc); 1854 } 1855 1856 __checkReturn efx_rc_t 1857 efx_mae_action_set_populate_vlan_push( 1858 __in efx_mae_actions_t *spec, 1859 __in uint16_t tpid_be, 1860 __in uint16_t tci_be) 1861 { 1862 efx_mae_action_vlan_push_t action; 1863 const uint8_t *arg = (const uint8_t *)&action; 1864 1865 action.emavp_tpid_be = tpid_be; 1866 action.emavp_tci_be = tci_be; 1867 1868 return (efx_mae_action_set_spec_populate(spec, 1869 EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg)); 1870 } 1871 1872 __checkReturn efx_rc_t 1873 efx_mae_action_set_populate_encap( 1874 __in efx_mae_actions_t *spec) 1875 { 1876 /* 1877 * There is no argument to pass encap. header ID, thus, one does not 1878 * need to allocate an encap. header while parsing application input. 1879 * This is useful since building an action set may be done simply to 1880 * validate a rule, whilst resource allocation usually consumes time. 1881 */ 1882 return (efx_mae_action_set_spec_populate(spec, 1883 EFX_MAE_ACTION_ENCAP, 0, NULL)); 1884 } 1885 1886 __checkReturn efx_rc_t 1887 efx_mae_action_set_populate_count( 1888 __in efx_mae_actions_t *spec) 1889 { 1890 /* 1891 * There is no argument to pass counter ID, thus, one does not 1892 * need to allocate a counter while parsing application input. 1893 * This is useful since building an action set may be done simply to 1894 * validate a rule, whilst resource allocation usually consumes time. 1895 */ 1896 return (efx_mae_action_set_spec_populate(spec, 1897 EFX_MAE_ACTION_COUNT, 0, NULL)); 1898 } 1899 1900 __checkReturn efx_rc_t 1901 efx_mae_action_set_populate_flag( 1902 __in efx_mae_actions_t *spec) 1903 { 1904 return (efx_mae_action_set_spec_populate(spec, 1905 EFX_MAE_ACTION_FLAG, 0, NULL)); 1906 } 1907 1908 __checkReturn efx_rc_t 1909 efx_mae_action_set_populate_mark( 1910 __in efx_mae_actions_t *spec, 1911 __in uint32_t mark_value) 1912 { 1913 const uint8_t *arg = (const uint8_t *)&mark_value; 1914 1915 return (efx_mae_action_set_spec_populate(spec, 1916 EFX_MAE_ACTION_MARK, sizeof (mark_value), arg)); 1917 } 1918 1919 __checkReturn efx_rc_t 1920 efx_mae_action_set_populate_deliver( 1921 __in efx_mae_actions_t *spec, 1922 __in const efx_mport_sel_t *mportp) 1923 { 1924 const uint8_t *arg; 1925 efx_rc_t rc; 1926 1927 if (mportp == NULL) { 1928 rc = EINVAL; 1929 goto fail1; 1930 } 1931 1932 arg = (const uint8_t *)&mportp->sel; 1933 1934 return (efx_mae_action_set_spec_populate(spec, 1935 EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg)); 1936 1937 fail1: 1938 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1939 return (rc); 1940 } 1941 1942 __checkReturn efx_rc_t 1943 efx_mae_action_set_populate_drop( 1944 __in efx_mae_actions_t *spec) 1945 { 1946 efx_mport_sel_t mport; 1947 const uint8_t *arg; 1948 efx_dword_t dword; 1949 1950 EFX_POPULATE_DWORD_1(dword, 1951 MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL); 1952 1953 /* 1954 * The constructed DWORD is little-endian, 1955 * but the resulting value is meant to be 1956 * passed to MCDIs, where it will undergo 1957 * host-order to little endian conversion. 1958 */ 1959 mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 1960 1961 arg = (const uint8_t *)&mport.sel; 1962 1963 return (efx_mae_action_set_spec_populate(spec, 1964 EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg)); 1965 } 1966 1967 __checkReturn boolean_t 1968 efx_mae_action_set_specs_equal( 1969 __in const efx_mae_actions_t *left, 1970 __in const efx_mae_actions_t *right) 1971 { 1972 size_t cmp_size = EFX_FIELD_OFFSET(efx_mae_actions_t, ema_rsrc); 1973 1974 /* 1975 * An action set specification consists of two parts. The first part 1976 * indicates what actions are included in the action set, as well as 1977 * extra quantitative values (in example, the number of VLAN tags to 1978 * push). The second part comprises resource IDs used by the actions. 1979 * 1980 * A resource, in example, a counter, is allocated from the hardware 1981 * by the client, and it's the client who is responsible for keeping 1982 * track of allocated resources and comparing resource IDs if needed. 1983 * 1984 * In this API, don't compare resource IDs in the two specifications. 1985 */ 1986 1987 return ((memcmp(left, right, cmp_size) == 0) ? B_TRUE : B_FALSE); 1988 } 1989 1990 __checkReturn efx_rc_t 1991 efx_mae_match_specs_class_cmp( 1992 __in efx_nic_t *enp, 1993 __in const efx_mae_match_spec_t *left, 1994 __in const efx_mae_match_spec_t *right, 1995 __out boolean_t *have_same_classp) 1996 { 1997 efx_mae_t *maep = enp->en_maep; 1998 unsigned int field_ncaps = maep->em_max_nfields; 1999 const efx_mae_field_cap_t *field_caps; 2000 const efx_mae_mv_desc_t *desc_setp; 2001 unsigned int desc_set_nentries; 2002 const efx_mae_mv_bit_desc_t *bit_desc_setp; 2003 unsigned int bit_desc_set_nentries; 2004 boolean_t have_same_class = B_TRUE; 2005 efx_mae_field_id_t field_id; 2006 const uint8_t *mvpl; 2007 const uint8_t *mvpr; 2008 efx_rc_t rc; 2009 2010 switch (left->emms_type) { 2011 case EFX_MAE_RULE_OUTER: 2012 field_caps = maep->em_outer_rule_field_caps; 2013 desc_setp = __efx_mae_outer_rule_mv_desc_set; 2014 desc_set_nentries = 2015 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set); 2016 bit_desc_setp = __efx_mae_outer_rule_mv_bit_desc_set; 2017 bit_desc_set_nentries = 2018 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_bit_desc_set); 2019 mvpl = left->emms_mask_value_pairs.outer; 2020 mvpr = right->emms_mask_value_pairs.outer; 2021 break; 2022 case EFX_MAE_RULE_ACTION: 2023 field_caps = maep->em_action_rule_field_caps; 2024 desc_setp = __efx_mae_action_rule_mv_desc_set; 2025 desc_set_nentries = 2026 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set); 2027 bit_desc_setp = __efx_mae_action_rule_mv_bit_desc_set; 2028 bit_desc_set_nentries = 2029 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_bit_desc_set); 2030 mvpl = left->emms_mask_value_pairs.action; 2031 mvpr = right->emms_mask_value_pairs.action; 2032 break; 2033 default: 2034 rc = ENOTSUP; 2035 goto fail1; 2036 } 2037 2038 if (field_caps == NULL) { 2039 rc = EAGAIN; 2040 goto fail2; 2041 } 2042 2043 if (left->emms_type != right->emms_type || 2044 left->emms_prio != right->emms_prio) { 2045 /* 2046 * Rules of different types can never map to the same class. 2047 * 2048 * The FW can support some set of match criteria for one 2049 * priority and not support the very same set for 2050 * another priority. Thus, two rules which have 2051 * different priorities can never map to 2052 * the same class. 2053 */ 2054 *have_same_classp = B_FALSE; 2055 return (0); 2056 } 2057 2058 for (field_id = 0; (unsigned int)field_id < desc_set_nentries; 2059 ++field_id) { 2060 const efx_mae_mv_desc_t *descp = &desc_setp[field_id]; 2061 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id; 2062 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset; 2063 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset; 2064 size_t mask_size = descp->emmd_mask_size; 2065 const uint8_t *lvalp = mvpl + descp->emmd_value_offset; 2066 const uint8_t *rvalp = mvpr + descp->emmd_value_offset; 2067 size_t value_size = descp->emmd_value_size; 2068 2069 if (mask_size == 0) 2070 continue; /* Skip array gap */ 2071 2072 if ((unsigned int)field_cap_id >= field_ncaps) { 2073 /* 2074 * The FW has not reported capability status for this 2075 * field. It's unknown whether any difference between 2076 * the two masks / values affects the class. The only 2077 * case when the class must be the same is when these 2078 * mask-value pairs match. Otherwise, report mismatch. 2079 */ 2080 if ((memcmp(lmaskp, rmaskp, mask_size) == 0) && 2081 (memcmp(lvalp, rvalp, value_size) == 0)) 2082 continue; 2083 else 2084 break; 2085 } 2086 2087 if (field_caps[field_cap_id].emfc_mask_affects_class) { 2088 if (memcmp(lmaskp, rmaskp, mask_size) != 0) { 2089 have_same_class = B_FALSE; 2090 break; 2091 } 2092 } 2093 2094 if (field_caps[field_cap_id].emfc_match_affects_class) { 2095 if (memcmp(lvalp, rvalp, value_size) != 0) { 2096 have_same_class = B_FALSE; 2097 break; 2098 } 2099 } 2100 } 2101 2102 if (have_same_class == B_FALSE) 2103 goto done; 2104 2105 for (field_id = 0; (unsigned int)field_id < bit_desc_set_nentries; 2106 ++field_id) { 2107 const efx_mae_mv_bit_desc_t *bit_descp = 2108 &bit_desc_setp[field_id]; 2109 efx_mae_field_cap_id_t bit_cap_id = 2110 bit_descp->emmbd_bit_cap_id; 2111 unsigned int byte_idx; 2112 unsigned int bit_idx; 2113 2114 if (bit_descp->emmbd_entry_is_valid == B_FALSE) 2115 continue; /* Skip array gap */ 2116 2117 if ((unsigned int)bit_cap_id >= field_ncaps) 2118 break; 2119 2120 byte_idx = 2121 bit_descp->emmbd_mask_ofst + 2122 bit_descp->emmbd_mask_lbn / 8; 2123 bit_idx = 2124 bit_descp->emmbd_mask_lbn % 8; 2125 2126 if (field_caps[bit_cap_id].emfc_mask_affects_class && 2127 (mvpl[byte_idx] & (1U << bit_idx)) != 2128 (mvpr[byte_idx] & (1U << bit_idx))) { 2129 have_same_class = B_FALSE; 2130 break; 2131 } 2132 2133 byte_idx = 2134 bit_descp->emmbd_value_ofst + 2135 bit_descp->emmbd_value_lbn / 8; 2136 bit_idx = 2137 bit_descp->emmbd_value_lbn % 8; 2138 2139 if (field_caps[bit_cap_id].emfc_match_affects_class && 2140 (mvpl[byte_idx] & (1U << bit_idx)) != 2141 (mvpr[byte_idx] & (1U << bit_idx))) { 2142 have_same_class = B_FALSE; 2143 break; 2144 } 2145 } 2146 2147 done: 2148 *have_same_classp = have_same_class; 2149 2150 return (0); 2151 2152 fail2: 2153 EFSYS_PROBE(fail2); 2154 fail1: 2155 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2156 return (rc); 2157 } 2158 2159 __checkReturn efx_rc_t 2160 efx_mae_outer_rule_recirc_id_set( 2161 __in efx_mae_match_spec_t *spec, 2162 __in uint8_t recirc_id) 2163 { 2164 efx_rc_t rc; 2165 2166 if (spec->emms_type != EFX_MAE_RULE_OUTER) { 2167 rc = EINVAL; 2168 goto fail1; 2169 } 2170 2171 spec->emms_outer_rule_recirc_id = recirc_id; 2172 2173 return (0); 2174 2175 fail1: 2176 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2177 return (rc); 2178 } 2179 2180 __checkReturn efx_rc_t 2181 efx_mae_outer_rule_insert( 2182 __in efx_nic_t *enp, 2183 __in const efx_mae_match_spec_t *spec, 2184 __in efx_tunnel_protocol_t encap_type, 2185 __out efx_mae_rule_id_t *or_idp) 2186 { 2187 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2188 efx_mcdi_req_t req; 2189 EFX_MCDI_DECLARE_BUF(payload, 2190 MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2, 2191 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 2192 uint32_t encap_type_mcdi; 2193 efx_mae_rule_id_t or_id; 2194 size_t offset; 2195 efx_rc_t rc; 2196 2197 EFX_STATIC_ASSERT(sizeof (or_idp->id) == 2198 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN); 2199 2200 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 2201 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL); 2202 2203 if (encp->enc_mae_supported == B_FALSE) { 2204 rc = ENOTSUP; 2205 goto fail1; 2206 } 2207 2208 if (spec->emms_type != EFX_MAE_RULE_OUTER) { 2209 rc = EINVAL; 2210 goto fail2; 2211 } 2212 2213 switch (encap_type) { 2214 case EFX_TUNNEL_PROTOCOL_NONE: 2215 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE; 2216 break; 2217 case EFX_TUNNEL_PROTOCOL_VXLAN: 2218 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN; 2219 break; 2220 case EFX_TUNNEL_PROTOCOL_GENEVE: 2221 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE; 2222 break; 2223 case EFX_TUNNEL_PROTOCOL_NVGRE: 2224 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE; 2225 break; 2226 default: 2227 rc = ENOTSUP; 2228 goto fail3; 2229 } 2230 2231 req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT; 2232 req.emr_in_buf = payload; 2233 req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2; 2234 req.emr_out_buf = payload; 2235 req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN; 2236 2237 MCDI_IN_SET_DWORD(req, 2238 MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi); 2239 2240 MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio); 2241 2242 /* 2243 * Mask-value pairs have been stored in the byte order needed for the 2244 * MCDI request and are thus safe to be copied directly to the buffer. 2245 * The library cares about byte order in efx_mae_match_spec_field_set(). 2246 */ 2247 EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >= 2248 MAE_ENC_FIELD_PAIRS_LEN); 2249 offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST; 2250 memcpy(payload + offset, spec->emms_mask_value_pairs.outer, 2251 MAE_ENC_FIELD_PAIRS_LEN); 2252 2253 MCDI_IN_SET_DWORD_FIELD(req, MAE_OUTER_RULE_INSERT_IN_LOOKUP_CONTROL, 2254 MAE_OUTER_RULE_INSERT_IN_RECIRC_ID, 2255 spec->emms_outer_rule_recirc_id); 2256 2257 efx_mcdi_execute(enp, &req); 2258 2259 if (req.emr_rc != 0) { 2260 rc = req.emr_rc; 2261 goto fail4; 2262 } 2263 2264 if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) { 2265 rc = EMSGSIZE; 2266 goto fail5; 2267 } 2268 2269 or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 2270 if (or_id.id == EFX_MAE_RSRC_ID_INVALID) { 2271 rc = ENOENT; 2272 goto fail6; 2273 } 2274 2275 or_idp->id = or_id.id; 2276 2277 return (0); 2278 2279 fail6: 2280 EFSYS_PROBE(fail6); 2281 fail5: 2282 EFSYS_PROBE(fail5); 2283 fail4: 2284 EFSYS_PROBE(fail4); 2285 fail3: 2286 EFSYS_PROBE(fail3); 2287 fail2: 2288 EFSYS_PROBE(fail2); 2289 fail1: 2290 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2291 return (rc); 2292 } 2293 2294 __checkReturn efx_rc_t 2295 efx_mae_outer_rule_remove( 2296 __in efx_nic_t *enp, 2297 __in const efx_mae_rule_id_t *or_idp) 2298 { 2299 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2300 efx_mcdi_req_t req; 2301 EFX_MCDI_DECLARE_BUF(payload, 2302 MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1), 2303 MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 2304 efx_rc_t rc; 2305 2306 if (encp->enc_mae_supported == B_FALSE) { 2307 rc = ENOTSUP; 2308 goto fail1; 2309 } 2310 2311 req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE; 2312 req.emr_in_buf = payload; 2313 req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1); 2314 req.emr_out_buf = payload; 2315 req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1); 2316 2317 MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id); 2318 2319 efx_mcdi_execute(enp, &req); 2320 2321 if (req.emr_rc != 0) { 2322 rc = req.emr_rc; 2323 goto fail2; 2324 } 2325 2326 if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LENMIN) { 2327 rc = EMSGSIZE; 2328 goto fail3; 2329 } 2330 2331 if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != 2332 or_idp->id) { 2333 /* Firmware failed to remove the outer rule. */ 2334 rc = EAGAIN; 2335 goto fail4; 2336 } 2337 2338 return (0); 2339 2340 fail4: 2341 EFSYS_PROBE(fail4); 2342 fail3: 2343 EFSYS_PROBE(fail3); 2344 fail2: 2345 EFSYS_PROBE(fail2); 2346 fail1: 2347 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2348 return (rc); 2349 } 2350 2351 __checkReturn efx_rc_t 2352 efx_mae_match_spec_outer_rule_id_set( 2353 __in efx_mae_match_spec_t *spec, 2354 __in const efx_mae_rule_id_t *or_idp) 2355 { 2356 uint32_t full_mask = UINT32_MAX; 2357 efx_rc_t rc; 2358 2359 if (spec->emms_type != EFX_MAE_RULE_ACTION) { 2360 rc = EINVAL; 2361 goto fail1; 2362 } 2363 2364 if (or_idp == NULL) { 2365 rc = EINVAL; 2366 goto fail2; 2367 } 2368 2369 rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID, 2370 sizeof (or_idp->id), (const uint8_t *)&or_idp->id, 2371 sizeof (full_mask), (const uint8_t *)&full_mask); 2372 if (rc != 0) 2373 goto fail3; 2374 2375 return (0); 2376 2377 fail3: 2378 EFSYS_PROBE(fail3); 2379 fail2: 2380 EFSYS_PROBE(fail2); 2381 fail1: 2382 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2383 return (rc); 2384 } 2385 2386 __checkReturn efx_rc_t 2387 efx_mae_mac_addr_alloc( 2388 __in efx_nic_t *enp, 2389 __in uint8_t addr_bytes[EFX_MAC_ADDR_LEN], 2390 __out efx_mae_mac_id_t *mac_idp) 2391 { 2392 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2393 efx_mcdi_req_t req; 2394 EFX_MCDI_DECLARE_BUF(payload, 2395 MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN, 2396 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN); 2397 efx_mae_mac_id_t mac_id; 2398 efx_rc_t rc; 2399 2400 EFX_STATIC_ASSERT(sizeof (mac_idp->id) == 2401 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_LEN); 2402 2403 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 2404 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 2405 2406 if (encp->enc_mae_supported == B_FALSE) { 2407 rc = ENOTSUP; 2408 goto fail1; 2409 } 2410 2411 if (encp->enc_mae_aset_v2_supported == B_FALSE) { 2412 rc = ENOTSUP; 2413 goto fail2; 2414 } 2415 2416 req.emr_cmd = MC_CMD_MAE_MAC_ADDR_ALLOC; 2417 req.emr_in_buf = payload; 2418 req.emr_in_length = MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN; 2419 req.emr_out_buf = payload; 2420 req.emr_out_length = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN; 2421 2422 memcpy(payload + MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_OFST, 2423 addr_bytes, EFX_MAC_ADDR_LEN); 2424 2425 efx_mcdi_execute(enp, &req); 2426 2427 if (req.emr_rc != 0) { 2428 rc = req.emr_rc; 2429 goto fail3; 2430 } 2431 2432 if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN) { 2433 rc = EMSGSIZE; 2434 goto fail4; 2435 } 2436 2437 mac_id.id = MCDI_OUT_DWORD(req, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID); 2438 if (mac_id.id == EFX_MAE_RSRC_ID_INVALID) { 2439 rc = ENOENT; 2440 goto fail5; 2441 } 2442 2443 mac_idp->id = mac_id.id; 2444 2445 return (0); 2446 2447 fail5: 2448 EFSYS_PROBE(fail5); 2449 fail4: 2450 EFSYS_PROBE(fail4); 2451 fail3: 2452 EFSYS_PROBE(fail3); 2453 fail2: 2454 EFSYS_PROBE(fail2); 2455 fail1: 2456 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2457 return (rc); 2458 } 2459 2460 __checkReturn efx_rc_t 2461 efx_mae_mac_addr_free( 2462 __in efx_nic_t *enp, 2463 __in const efx_mae_mac_id_t *mac_idp) 2464 { 2465 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2466 efx_mcdi_req_t req; 2467 EFX_MCDI_DECLARE_BUF(payload, 2468 MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1), 2469 MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1)); 2470 efx_rc_t rc; 2471 2472 if (encp->enc_mae_supported == B_FALSE) { 2473 rc = ENOTSUP; 2474 goto fail1; 2475 } 2476 2477 if (encp->enc_mae_aset_v2_supported == B_FALSE) { 2478 rc = ENOTSUP; 2479 goto fail2; 2480 } 2481 2482 req.emr_cmd = MC_CMD_MAE_MAC_ADDR_FREE; 2483 req.emr_in_buf = payload; 2484 req.emr_in_length = MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1); 2485 req.emr_out_buf = payload; 2486 req.emr_out_length = MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1); 2487 2488 MCDI_IN_SET_DWORD(req, MAE_MAC_ADDR_FREE_IN_MAC_ID, mac_idp->id); 2489 2490 efx_mcdi_execute(enp, &req); 2491 2492 if (req.emr_rc != 0) { 2493 rc = req.emr_rc; 2494 goto fail3; 2495 } 2496 2497 if (req.emr_out_length_used < MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1)) { 2498 rc = EMSGSIZE; 2499 goto fail4; 2500 } 2501 2502 if (MCDI_OUT_DWORD(req, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) != 2503 mac_idp->id) { 2504 /* Firmware failed to remove the MAC address entry. */ 2505 rc = EAGAIN; 2506 goto fail5; 2507 } 2508 2509 return (0); 2510 2511 fail5: 2512 EFSYS_PROBE(fail5); 2513 fail4: 2514 EFSYS_PROBE(fail4); 2515 fail3: 2516 EFSYS_PROBE(fail3); 2517 fail2: 2518 EFSYS_PROBE(fail2); 2519 fail1: 2520 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2521 return (rc); 2522 } 2523 2524 __checkReturn efx_rc_t 2525 efx_mae_action_set_fill_in_dst_mac_id( 2526 __in efx_mae_actions_t *spec, 2527 __in const efx_mae_mac_id_t *mac_idp) 2528 { 2529 efx_rc_t rc; 2530 2531 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) == 0) { 2532 /* 2533 * The caller has not intended to have this action originally, 2534 * hence, they cannot indicate the MAC address entry ID. 2535 */ 2536 rc = EINVAL; 2537 goto fail1; 2538 } 2539 2540 if (spec->ema_rsrc.emar_dst_mac_id.id != EFX_MAE_RSRC_ID_INVALID) { 2541 /* An attempt to indicate the MAC address entry ID twice. */ 2542 rc = EINVAL; 2543 goto fail2; 2544 } 2545 2546 if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) { 2547 rc = EINVAL; 2548 goto fail3; 2549 } 2550 2551 spec->ema_rsrc.emar_dst_mac_id.id = mac_idp->id; 2552 2553 return (0); 2554 2555 fail3: 2556 EFSYS_PROBE(fail3); 2557 fail2: 2558 EFSYS_PROBE(fail2); 2559 fail1: 2560 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2561 return (rc); 2562 } 2563 2564 __checkReturn efx_rc_t 2565 efx_mae_action_set_fill_in_src_mac_id( 2566 __in efx_mae_actions_t *spec, 2567 __in const efx_mae_mac_id_t *mac_idp) 2568 { 2569 efx_rc_t rc; 2570 2571 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) == 0) { 2572 /* 2573 * The caller has not intended to have this action originally, 2574 * hence, they cannot indicate the MAC address entry ID. 2575 */ 2576 rc = EINVAL; 2577 goto fail1; 2578 } 2579 2580 if (spec->ema_rsrc.emar_src_mac_id.id != EFX_MAE_RSRC_ID_INVALID) { 2581 /* An attempt to indicate the MAC address entry ID twice. */ 2582 rc = EINVAL; 2583 goto fail2; 2584 } 2585 2586 if (mac_idp->id == EFX_MAE_RSRC_ID_INVALID) { 2587 rc = EINVAL; 2588 goto fail3; 2589 } 2590 2591 spec->ema_rsrc.emar_src_mac_id.id = mac_idp->id; 2592 2593 return (0); 2594 2595 fail3: 2596 EFSYS_PROBE(fail3); 2597 fail2: 2598 EFSYS_PROBE(fail2); 2599 fail1: 2600 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2601 return (rc); 2602 } 2603 2604 __checkReturn efx_rc_t 2605 efx_mae_encap_header_alloc( 2606 __in efx_nic_t *enp, 2607 __in efx_tunnel_protocol_t encap_type, 2608 __in_bcount(header_size) uint8_t *header_data, 2609 __in size_t header_size, 2610 __out efx_mae_eh_id_t *eh_idp) 2611 { 2612 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2613 efx_mcdi_req_t req; 2614 EFX_MCDI_DECLARE_BUF(payload, 2615 MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LENMAX_MCDI2, 2616 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN); 2617 uint32_t encap_type_mcdi; 2618 efx_mae_eh_id_t eh_id; 2619 efx_rc_t rc; 2620 2621 EFX_STATIC_ASSERT(sizeof (eh_idp->id) == 2622 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_LEN); 2623 2624 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 2625 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); 2626 2627 if (encp->enc_mae_supported == B_FALSE) { 2628 rc = ENOTSUP; 2629 goto fail1; 2630 } 2631 2632 switch (encap_type) { 2633 case EFX_TUNNEL_PROTOCOL_NONE: 2634 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE; 2635 break; 2636 case EFX_TUNNEL_PROTOCOL_VXLAN: 2637 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN; 2638 break; 2639 case EFX_TUNNEL_PROTOCOL_GENEVE: 2640 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE; 2641 break; 2642 case EFX_TUNNEL_PROTOCOL_NVGRE: 2643 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE; 2644 break; 2645 default: 2646 rc = ENOTSUP; 2647 goto fail2; 2648 } 2649 2650 if (header_size > 2651 MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_MAXNUM_MCDI2) { 2652 rc = EINVAL; 2653 goto fail3; 2654 } 2655 2656 req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_ALLOC; 2657 req.emr_in_buf = payload; 2658 req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(header_size); 2659 req.emr_out_buf = payload; 2660 req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN; 2661 2662 MCDI_IN_SET_DWORD(req, 2663 MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, encap_type_mcdi); 2664 2665 memcpy(payload + MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA_OFST, 2666 header_data, header_size); 2667 2668 efx_mcdi_execute(enp, &req); 2669 2670 if (req.emr_rc != 0) { 2671 rc = req.emr_rc; 2672 goto fail4; 2673 } 2674 2675 if (req.emr_out_length_used < MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN) { 2676 rc = EMSGSIZE; 2677 goto fail5; 2678 } 2679 2680 eh_id.id = MCDI_OUT_DWORD(req, 2681 MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID); 2682 2683 if (eh_id.id == EFX_MAE_RSRC_ID_INVALID) { 2684 rc = ENOENT; 2685 goto fail6; 2686 } 2687 2688 eh_idp->id = eh_id.id; 2689 2690 return (0); 2691 2692 fail6: 2693 EFSYS_PROBE(fail6); 2694 fail5: 2695 EFSYS_PROBE(fail5); 2696 fail4: 2697 EFSYS_PROBE(fail4); 2698 fail3: 2699 EFSYS_PROBE(fail3); 2700 fail2: 2701 EFSYS_PROBE(fail2); 2702 fail1: 2703 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2704 return (rc); 2705 } 2706 2707 __checkReturn efx_rc_t 2708 efx_mae_encap_header_free( 2709 __in efx_nic_t *enp, 2710 __in const efx_mae_eh_id_t *eh_idp) 2711 { 2712 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2713 efx_mcdi_req_t req; 2714 EFX_MCDI_DECLARE_BUF(payload, 2715 MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1), 2716 MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1)); 2717 efx_rc_t rc; 2718 2719 if (encp->enc_mae_supported == B_FALSE) { 2720 rc = ENOTSUP; 2721 goto fail1; 2722 } 2723 2724 req.emr_cmd = MC_CMD_MAE_ENCAP_HEADER_FREE; 2725 req.emr_in_buf = payload; 2726 req.emr_in_length = MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1); 2727 req.emr_out_buf = payload; 2728 req.emr_out_length = MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1); 2729 2730 MCDI_IN_SET_DWORD(req, MAE_ENCAP_HEADER_FREE_IN_EH_ID, eh_idp->id); 2731 2732 efx_mcdi_execute(enp, &req); 2733 2734 if (req.emr_rc != 0) { 2735 rc = req.emr_rc; 2736 goto fail2; 2737 } 2738 2739 if (MCDI_OUT_DWORD(req, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) != 2740 eh_idp->id) { 2741 /* Firmware failed to remove the encap. header. */ 2742 rc = EAGAIN; 2743 goto fail3; 2744 } 2745 2746 return (0); 2747 2748 fail3: 2749 EFSYS_PROBE(fail3); 2750 fail2: 2751 EFSYS_PROBE(fail2); 2752 fail1: 2753 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2754 return (rc); 2755 } 2756 2757 __checkReturn efx_rc_t 2758 efx_mae_action_set_fill_in_eh_id( 2759 __in efx_mae_actions_t *spec, 2760 __in const efx_mae_eh_id_t *eh_idp) 2761 { 2762 efx_rc_t rc; 2763 2764 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) == 0) { 2765 /* 2766 * The caller has not intended to have action ENCAP originally, 2767 * hence, this attempt to indicate encap. header ID is invalid. 2768 */ 2769 rc = EINVAL; 2770 goto fail1; 2771 } 2772 2773 if (spec->ema_rsrc.emar_eh_id.id != EFX_MAE_RSRC_ID_INVALID) { 2774 /* The caller attempts to indicate encap. header ID twice. */ 2775 rc = EINVAL; 2776 goto fail2; 2777 } 2778 2779 if (eh_idp->id == EFX_MAE_RSRC_ID_INVALID) { 2780 rc = EINVAL; 2781 goto fail3; 2782 } 2783 2784 spec->ema_rsrc.emar_eh_id.id = eh_idp->id; 2785 2786 return (0); 2787 2788 fail3: 2789 EFSYS_PROBE(fail3); 2790 fail2: 2791 EFSYS_PROBE(fail2); 2792 fail1: 2793 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2794 return (rc); 2795 } 2796 2797 __checkReturn efx_rc_t 2798 efx_mae_action_set_alloc( 2799 __in efx_nic_t *enp, 2800 __in const efx_mae_actions_t *spec, 2801 __out efx_mae_aset_id_t *aset_idp) 2802 { 2803 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2804 efx_mcdi_req_t req; 2805 EFX_MCDI_DECLARE_BUF(payload, 2806 MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN, 2807 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 2808 efx_mae_aset_id_t aset_id; 2809 efx_rc_t rc; 2810 2811 if (encp->enc_mae_supported == B_FALSE) { 2812 rc = ENOTSUP; 2813 goto fail1; 2814 } 2815 2816 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_DST_MAC)) != 0 && 2817 spec->ema_rsrc.emar_dst_mac_id.id == EFX_MAE_RSRC_ID_INVALID) { 2818 rc = EINVAL; 2819 goto fail2; 2820 } 2821 2822 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_SET_SRC_MAC)) != 0 && 2823 spec->ema_rsrc.emar_src_mac_id.id == EFX_MAE_RSRC_ID_INVALID) { 2824 rc = EINVAL; 2825 goto fail3; 2826 } 2827 2828 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_ENCAP)) != 0 && 2829 spec->ema_rsrc.emar_eh_id.id == EFX_MAE_RSRC_ID_INVALID) { 2830 rc = EINVAL; 2831 goto fail4; 2832 } 2833 2834 if (spec->ema_n_count_actions == 1 && 2835 spec->ema_rsrc.emar_counter_id.id == EFX_MAE_RSRC_ID_INVALID) { 2836 rc = EINVAL; 2837 goto fail5; 2838 } 2839 2840 req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC; 2841 req.emr_in_buf = payload; 2842 req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN; 2843 req.emr_out_buf = payload; 2844 req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN; 2845 2846 /* 2847 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the 2848 * corresponding resource types are supported by the implementation. 2849 * Use proper resource ID assignments instead. 2850 */ 2851 MCDI_IN_SET_DWORD(req, 2852 MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID); 2853 2854 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECAP)) != 0) { 2855 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2856 MAE_ACTION_SET_ALLOC_IN_DECAP, 1); 2857 } 2858 2859 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2860 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop); 2861 2862 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 2863 spec->ema_rsrc.emar_dst_mac_id.id); 2864 2865 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 2866 spec->ema_rsrc.emar_src_mac_id.id); 2867 2868 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_DECR_IP_TTL)) != 0) { 2869 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2870 MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL, 1); 2871 } 2872 2873 if (spec->ema_n_vlan_tags_to_push > 0) { 2874 unsigned int outer_tag_idx; 2875 2876 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2877 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, 2878 spec->ema_n_vlan_tags_to_push); 2879 2880 if (spec->ema_n_vlan_tags_to_push == 2881 EFX_MAE_VLAN_PUSH_MAX_NTAGS) { 2882 MCDI_IN_SET_WORD(req, 2883 MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE, 2884 spec->ema_vlan_push_descs[0].emavp_tpid_be); 2885 MCDI_IN_SET_WORD(req, 2886 MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE, 2887 spec->ema_vlan_push_descs[0].emavp_tci_be); 2888 } 2889 2890 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1; 2891 2892 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE, 2893 spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be); 2894 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE, 2895 spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be); 2896 } 2897 2898 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 2899 spec->ema_rsrc.emar_eh_id.id); 2900 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 2901 spec->ema_rsrc.emar_counter_id.id); 2902 2903 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) { 2904 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2905 MAE_ACTION_SET_ALLOC_IN_FLAG, 1); 2906 } 2907 2908 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) { 2909 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 2910 MAE_ACTION_SET_ALLOC_IN_MARK, 1); 2911 2912 MCDI_IN_SET_DWORD(req, 2913 MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value); 2914 } 2915 2916 MCDI_IN_SET_DWORD(req, 2917 MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel); 2918 2919 efx_mcdi_execute(enp, &req); 2920 2921 if (req.emr_rc != 0) { 2922 rc = req.emr_rc; 2923 goto fail6; 2924 } 2925 2926 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) { 2927 rc = EMSGSIZE; 2928 goto fail7; 2929 } 2930 2931 aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 2932 if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) { 2933 rc = ENOENT; 2934 goto fail8; 2935 } 2936 2937 aset_idp->id = aset_id.id; 2938 2939 return (0); 2940 2941 fail8: 2942 EFSYS_PROBE(fail8); 2943 fail7: 2944 EFSYS_PROBE(fail7); 2945 fail6: 2946 EFSYS_PROBE(fail6); 2947 fail5: 2948 EFSYS_PROBE(fail5); 2949 fail4: 2950 EFSYS_PROBE(fail4); 2951 fail3: 2952 EFSYS_PROBE(fail3); 2953 fail2: 2954 EFSYS_PROBE(fail2); 2955 fail1: 2956 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2957 return (rc); 2958 } 2959 2960 __checkReturn unsigned int 2961 efx_mae_action_set_get_nb_count( 2962 __in const efx_mae_actions_t *spec) 2963 { 2964 return (spec->ema_n_count_actions); 2965 } 2966 2967 __checkReturn efx_rc_t 2968 efx_mae_action_set_fill_in_counter_id( 2969 __in efx_mae_actions_t *spec, 2970 __in const efx_counter_t *counter_idp) 2971 { 2972 efx_rc_t rc; 2973 2974 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_COUNT)) == 0) { 2975 /* 2976 * Invalid to add counter ID if spec does not have COUNT action. 2977 */ 2978 rc = EINVAL; 2979 goto fail1; 2980 } 2981 2982 if (spec->ema_n_count_actions != 1) { 2983 /* 2984 * Having multiple COUNT actions in the spec requires a counter 2985 * list to be used. This API must only be used for a single 2986 * counter per spec. Turn down the request as inappropriate. 2987 */ 2988 rc = EINVAL; 2989 goto fail2; 2990 } 2991 2992 if (spec->ema_rsrc.emar_counter_id.id != EFX_MAE_RSRC_ID_INVALID) { 2993 /* The caller attempts to indicate counter ID twice. */ 2994 rc = EALREADY; 2995 goto fail3; 2996 } 2997 2998 if (counter_idp->id == EFX_MAE_RSRC_ID_INVALID) { 2999 rc = EINVAL; 3000 goto fail4; 3001 } 3002 3003 spec->ema_rsrc.emar_counter_id.id = counter_idp->id; 3004 3005 return (0); 3006 3007 fail4: 3008 EFSYS_PROBE(fail4); 3009 fail3: 3010 EFSYS_PROBE(fail3); 3011 fail2: 3012 EFSYS_PROBE(fail2); 3013 fail1: 3014 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3015 return (rc); 3016 } 3017 3018 __checkReturn efx_rc_t 3019 efx_mae_counters_alloc( 3020 __in efx_nic_t *enp, 3021 __in uint32_t n_counters, 3022 __out uint32_t *n_allocatedp, 3023 __out_ecount(n_counters) efx_counter_t *countersp, 3024 __out_opt uint32_t *gen_countp) 3025 { 3026 EFX_MCDI_DECLARE_BUF(payload, 3027 MC_CMD_MAE_COUNTER_ALLOC_IN_LEN, 3028 MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMAX_MCDI2); 3029 efx_mae_t *maep = enp->en_maep; 3030 uint32_t n_allocated; 3031 efx_mcdi_req_t req; 3032 unsigned int i; 3033 efx_rc_t rc; 3034 3035 if (n_counters > maep->em_max_ncounters || 3036 n_counters < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM || 3037 n_counters > MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MAXNUM_MCDI2) { 3038 rc = EINVAL; 3039 goto fail1; 3040 } 3041 3042 req.emr_cmd = MC_CMD_MAE_COUNTER_ALLOC; 3043 req.emr_in_buf = payload; 3044 req.emr_in_length = MC_CMD_MAE_COUNTER_ALLOC_IN_LEN; 3045 req.emr_out_buf = payload; 3046 req.emr_out_length = MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(n_counters); 3047 3048 MCDI_IN_SET_DWORD(req, MAE_COUNTER_ALLOC_IN_REQUESTED_COUNT, 3049 n_counters); 3050 3051 efx_mcdi_execute(enp, &req); 3052 3053 if (req.emr_rc != 0) { 3054 rc = req.emr_rc; 3055 goto fail2; 3056 } 3057 3058 if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_ALLOC_OUT_LENMIN) { 3059 rc = EMSGSIZE; 3060 goto fail3; 3061 } 3062 3063 n_allocated = MCDI_OUT_DWORD(req, 3064 MAE_COUNTER_ALLOC_OUT_COUNTER_ID_COUNT); 3065 if (n_allocated < MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_MINNUM) { 3066 rc = EFAULT; 3067 goto fail4; 3068 } 3069 3070 for (i = 0; i < n_allocated; i++) { 3071 countersp[i].id = MCDI_OUT_INDEXED_DWORD(req, 3072 MAE_COUNTER_ALLOC_OUT_COUNTER_ID, i); 3073 } 3074 3075 if (gen_countp != NULL) { 3076 *gen_countp = MCDI_OUT_DWORD(req, 3077 MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT); 3078 } 3079 3080 *n_allocatedp = n_allocated; 3081 3082 return (0); 3083 3084 fail4: 3085 EFSYS_PROBE(fail4); 3086 fail3: 3087 EFSYS_PROBE(fail3); 3088 fail2: 3089 EFSYS_PROBE(fail2); 3090 fail1: 3091 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3092 3093 return (rc); 3094 } 3095 3096 __checkReturn efx_rc_t 3097 efx_mae_counters_free( 3098 __in efx_nic_t *enp, 3099 __in uint32_t n_counters, 3100 __out uint32_t *n_freedp, 3101 __in_ecount(n_counters) const efx_counter_t *countersp, 3102 __out_opt uint32_t *gen_countp) 3103 { 3104 EFX_MCDI_DECLARE_BUF(payload, 3105 MC_CMD_MAE_COUNTER_FREE_IN_LENMAX_MCDI2, 3106 MC_CMD_MAE_COUNTER_FREE_OUT_LENMAX_MCDI2); 3107 efx_mae_t *maep = enp->en_maep; 3108 efx_mcdi_req_t req; 3109 uint32_t n_freed; 3110 unsigned int i; 3111 efx_rc_t rc; 3112 3113 if (n_counters > maep->em_max_ncounters || 3114 n_counters < MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MINNUM || 3115 n_counters > 3116 MC_CMD_MAE_COUNTER_FREE_IN_FREE_COUNTER_ID_MAXNUM_MCDI2) { 3117 rc = EINVAL; 3118 goto fail1; 3119 } 3120 3121 req.emr_cmd = MC_CMD_MAE_COUNTER_FREE; 3122 req.emr_in_buf = payload; 3123 req.emr_in_length = MC_CMD_MAE_COUNTER_FREE_IN_LEN(n_counters); 3124 req.emr_out_buf = payload; 3125 req.emr_out_length = MC_CMD_MAE_COUNTER_FREE_OUT_LEN(n_counters); 3126 3127 for (i = 0; i < n_counters; i++) { 3128 MCDI_IN_SET_INDEXED_DWORD(req, 3129 MAE_COUNTER_FREE_IN_FREE_COUNTER_ID, i, countersp[i].id); 3130 } 3131 MCDI_IN_SET_DWORD(req, MAE_COUNTER_FREE_IN_COUNTER_ID_COUNT, 3132 n_counters); 3133 3134 efx_mcdi_execute(enp, &req); 3135 3136 if (req.emr_rc != 0) { 3137 rc = req.emr_rc; 3138 goto fail2; 3139 } 3140 3141 if (req.emr_out_length_used < MC_CMD_MAE_COUNTER_FREE_OUT_LENMIN) { 3142 rc = EMSGSIZE; 3143 goto fail3; 3144 } 3145 3146 n_freed = MCDI_OUT_DWORD(req, MAE_COUNTER_FREE_OUT_COUNTER_ID_COUNT); 3147 3148 if (n_freed < MC_CMD_MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID_MINNUM) { 3149 rc = EFAULT; 3150 goto fail4; 3151 } 3152 3153 if (gen_countp != NULL) { 3154 *gen_countp = MCDI_OUT_DWORD(req, 3155 MAE_COUNTER_FREE_OUT_GENERATION_COUNT); 3156 } 3157 3158 *n_freedp = n_freed; 3159 3160 return (0); 3161 3162 fail4: 3163 EFSYS_PROBE(fail4); 3164 fail3: 3165 EFSYS_PROBE(fail3); 3166 fail2: 3167 EFSYS_PROBE(fail2); 3168 fail1: 3169 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3170 3171 return (rc); 3172 } 3173 3174 __checkReturn efx_rc_t 3175 efx_mae_counters_stream_start( 3176 __in efx_nic_t *enp, 3177 __in uint16_t rxq_id, 3178 __in uint16_t packet_size, 3179 __in uint32_t flags_in, 3180 __out uint32_t *flags_out) 3181 { 3182 efx_mcdi_req_t req; 3183 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN, 3184 MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN); 3185 efx_rc_t rc; 3186 3187 EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_IN_ZERO_SQUASH_DISABLE == 3188 1U << MC_CMD_MAE_COUNTERS_STREAM_START_IN_ZERO_SQUASH_DISABLE_LBN); 3189 3190 EFX_STATIC_ASSERT(EFX_MAE_COUNTERS_STREAM_OUT_USES_CREDITS == 3191 1U << MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_LBN); 3192 3193 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_START; 3194 req.emr_in_buf = payload; 3195 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_START_IN_LEN; 3196 req.emr_out_buf = payload; 3197 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN; 3198 3199 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_QID, rxq_id); 3200 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_START_IN_PACKET_SIZE, 3201 packet_size); 3202 MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_START_IN_FLAGS, flags_in); 3203 3204 efx_mcdi_execute(enp, &req); 3205 3206 if (req.emr_rc != 0) { 3207 rc = req.emr_rc; 3208 goto fail1; 3209 } 3210 3211 if (req.emr_out_length_used < 3212 MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN) { 3213 rc = EMSGSIZE; 3214 goto fail2; 3215 } 3216 3217 *flags_out = MCDI_OUT_DWORD(req, MAE_COUNTERS_STREAM_START_OUT_FLAGS); 3218 3219 return (0); 3220 3221 fail2: 3222 EFSYS_PROBE(fail2); 3223 fail1: 3224 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3225 3226 return (rc); 3227 } 3228 3229 __checkReturn efx_rc_t 3230 efx_mae_counters_stream_stop( 3231 __in efx_nic_t *enp, 3232 __in uint16_t rxq_id, 3233 __out_opt uint32_t *gen_countp) 3234 { 3235 efx_mcdi_req_t req; 3236 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN, 3237 MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN); 3238 efx_rc_t rc; 3239 3240 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_STOP; 3241 req.emr_in_buf = payload; 3242 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN; 3243 req.emr_out_buf = payload; 3244 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN; 3245 3246 MCDI_IN_SET_WORD(req, MAE_COUNTERS_STREAM_STOP_IN_QID, rxq_id); 3247 3248 efx_mcdi_execute(enp, &req); 3249 3250 if (req.emr_rc != 0) { 3251 rc = req.emr_rc; 3252 goto fail1; 3253 } 3254 3255 if (req.emr_out_length_used < 3256 MC_CMD_MAE_COUNTERS_STREAM_STOP_OUT_LEN) { 3257 rc = EMSGSIZE; 3258 goto fail2; 3259 } 3260 3261 if (gen_countp != NULL) { 3262 *gen_countp = MCDI_OUT_DWORD(req, 3263 MAE_COUNTERS_STREAM_STOP_OUT_GENERATION_COUNT); 3264 } 3265 3266 return (0); 3267 3268 fail2: 3269 EFSYS_PROBE(fail2); 3270 fail1: 3271 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3272 3273 return (rc); 3274 } 3275 3276 __checkReturn efx_rc_t 3277 efx_mae_counters_stream_give_credits( 3278 __in efx_nic_t *enp, 3279 __in uint32_t n_credits) 3280 { 3281 efx_mcdi_req_t req; 3282 EFX_MCDI_DECLARE_BUF(payload, 3283 MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN, 3284 MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN); 3285 efx_rc_t rc; 3286 3287 req.emr_cmd = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS; 3288 req.emr_in_buf = payload; 3289 req.emr_in_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN; 3290 req.emr_out_buf = payload; 3291 req.emr_out_length = MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN; 3292 3293 MCDI_IN_SET_DWORD(req, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS, 3294 n_credits); 3295 3296 efx_mcdi_execute(enp, &req); 3297 3298 if (req.emr_rc != 0) { 3299 rc = req.emr_rc; 3300 goto fail1; 3301 } 3302 3303 return (0); 3304 3305 fail1: 3306 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3307 3308 return (rc); 3309 } 3310 3311 __checkReturn efx_rc_t 3312 efx_mae_action_set_free( 3313 __in efx_nic_t *enp, 3314 __in const efx_mae_aset_id_t *aset_idp) 3315 { 3316 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3317 efx_mcdi_req_t req; 3318 EFX_MCDI_DECLARE_BUF(payload, 3319 MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1), 3320 MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 3321 efx_rc_t rc; 3322 3323 if (encp->enc_mae_supported == B_FALSE) { 3324 rc = ENOTSUP; 3325 goto fail1; 3326 } 3327 3328 req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE; 3329 req.emr_in_buf = payload; 3330 req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1); 3331 req.emr_out_buf = payload; 3332 req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1); 3333 3334 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id); 3335 3336 efx_mcdi_execute(enp, &req); 3337 3338 if (req.emr_rc != 0) { 3339 rc = req.emr_rc; 3340 goto fail2; 3341 } 3342 3343 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_FREE_OUT_LENMIN) { 3344 rc = EMSGSIZE; 3345 goto fail3; 3346 } 3347 3348 if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != 3349 aset_idp->id) { 3350 /* Firmware failed to free the action set. */ 3351 rc = EAGAIN; 3352 goto fail4; 3353 } 3354 3355 return (0); 3356 3357 fail4: 3358 EFSYS_PROBE(fail4); 3359 fail3: 3360 EFSYS_PROBE(fail3); 3361 fail2: 3362 EFSYS_PROBE(fail2); 3363 fail1: 3364 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3365 return (rc); 3366 } 3367 3368 __checkReturn efx_rc_t 3369 efx_mae_action_rule_insert( 3370 __in efx_nic_t *enp, 3371 __in const efx_mae_match_spec_t *spec, 3372 __in const efx_mae_aset_list_id_t *asl_idp, 3373 __in const efx_mae_aset_id_t *as_idp, 3374 __out efx_mae_rule_id_t *ar_idp) 3375 { 3376 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3377 efx_mcdi_req_t req; 3378 EFX_MCDI_DECLARE_BUF(payload, 3379 MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2, 3380 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 3381 efx_oword_t *rule_response; 3382 efx_mae_rule_id_t ar_id; 3383 size_t offset; 3384 efx_rc_t rc; 3385 3386 EFX_STATIC_ASSERT(sizeof (ar_idp->id) == 3387 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN); 3388 3389 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 3390 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 3391 3392 if (encp->enc_mae_supported == B_FALSE) { 3393 rc = ENOTSUP; 3394 goto fail1; 3395 } 3396 3397 if (spec->emms_type != EFX_MAE_RULE_ACTION || 3398 (asl_idp != NULL && as_idp != NULL) || 3399 (asl_idp == NULL && as_idp == NULL)) { 3400 rc = EINVAL; 3401 goto fail2; 3402 } 3403 3404 req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT; 3405 req.emr_in_buf = payload; 3406 req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2; 3407 req.emr_out_buf = payload; 3408 req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN; 3409 3410 EFX_STATIC_ASSERT(sizeof (*rule_response) <= 3411 MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN); 3412 offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST; 3413 rule_response = (efx_oword_t *)(payload + offset); 3414 EFX_POPULATE_OWORD_3(*rule_response, 3415 MAE_ACTION_RULE_RESPONSE_ASL_ID, 3416 (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID, 3417 MAE_ACTION_RULE_RESPONSE_AS_ID, 3418 (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID, 3419 MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID); 3420 3421 MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio); 3422 3423 /* 3424 * Mask-value pairs have been stored in the byte order needed for the 3425 * MCDI request and are thus safe to be copied directly to the buffer. 3426 */ 3427 EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >= 3428 MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN); 3429 offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST; 3430 memcpy(payload + offset, spec->emms_mask_value_pairs.action, 3431 MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN); 3432 3433 efx_mcdi_execute(enp, &req); 3434 3435 if (req.emr_rc != 0) { 3436 rc = req.emr_rc; 3437 goto fail3; 3438 } 3439 3440 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) { 3441 rc = EMSGSIZE; 3442 goto fail4; 3443 } 3444 3445 ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 3446 if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) { 3447 rc = ENOENT; 3448 goto fail5; 3449 } 3450 3451 ar_idp->id = ar_id.id; 3452 3453 return (0); 3454 3455 fail5: 3456 EFSYS_PROBE(fail5); 3457 fail4: 3458 EFSYS_PROBE(fail4); 3459 fail3: 3460 EFSYS_PROBE(fail3); 3461 fail2: 3462 EFSYS_PROBE(fail2); 3463 fail1: 3464 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3465 return (rc); 3466 } 3467 3468 __checkReturn efx_rc_t 3469 efx_mae_action_rule_remove( 3470 __in efx_nic_t *enp, 3471 __in const efx_mae_rule_id_t *ar_idp) 3472 { 3473 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3474 efx_mcdi_req_t req; 3475 EFX_MCDI_DECLARE_BUF(payload, 3476 MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1), 3477 MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 3478 efx_rc_t rc; 3479 3480 if (encp->enc_mae_supported == B_FALSE) { 3481 rc = ENOTSUP; 3482 goto fail1; 3483 } 3484 3485 req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE; 3486 req.emr_in_buf = payload; 3487 req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1); 3488 req.emr_out_buf = payload; 3489 req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1); 3490 3491 MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id); 3492 3493 efx_mcdi_execute(enp, &req); 3494 3495 if (req.emr_rc != 0) { 3496 rc = req.emr_rc; 3497 goto fail2; 3498 } 3499 3500 if (req.emr_out_length_used < 3501 MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LENMIN) { 3502 rc = EMSGSIZE; 3503 goto fail3; 3504 } 3505 3506 if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != 3507 ar_idp->id) { 3508 /* Firmware failed to delete the action rule. */ 3509 rc = EAGAIN; 3510 goto fail4; 3511 } 3512 3513 return (0); 3514 3515 fail4: 3516 EFSYS_PROBE(fail4); 3517 fail3: 3518 EFSYS_PROBE(fail3); 3519 fail2: 3520 EFSYS_PROBE(fail2); 3521 fail1: 3522 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3523 return (rc); 3524 } 3525 3526 __checkReturn efx_rc_t 3527 efx_mcdi_mport_alloc_alias( 3528 __in efx_nic_t *enp, 3529 __out efx_mport_id_t *mportp, 3530 __out_opt uint32_t *labelp) 3531 { 3532 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3533 efx_mcdi_req_t req; 3534 EFX_MCDI_DECLARE_BUF(payload, 3535 MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN, 3536 MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN); 3537 efx_rc_t rc; 3538 3539 if (encp->enc_mae_supported == B_FALSE) { 3540 rc = ENOTSUP; 3541 goto fail1; 3542 } 3543 3544 req.emr_cmd = MC_CMD_MAE_MPORT_ALLOC; 3545 req.emr_in_buf = payload; 3546 req.emr_in_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN; 3547 req.emr_out_buf = payload; 3548 req.emr_out_length = MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN; 3549 3550 MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_IN_TYPE, 3551 MC_CMD_MAE_MPORT_ALLOC_IN_MPORT_TYPE_ALIAS); 3552 MCDI_IN_SET_DWORD(req, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT, 3553 MAE_MPORT_SELECTOR_ASSIGNED); 3554 3555 efx_mcdi_execute(enp, &req); 3556 3557 if (req.emr_rc != 0) { 3558 rc = req.emr_rc; 3559 goto fail2; 3560 } 3561 3562 mportp->id = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_OUT_MPORT_ID); 3563 if (labelp != NULL) 3564 *labelp = MCDI_OUT_DWORD(req, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL); 3565 3566 return (0); 3567 3568 fail2: 3569 EFSYS_PROBE(fail2); 3570 fail1: 3571 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3572 return (rc); 3573 } 3574 3575 __checkReturn efx_rc_t 3576 efx_mae_mport_free( 3577 __in efx_nic_t *enp, 3578 __in const efx_mport_id_t *mportp) 3579 { 3580 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3581 efx_mcdi_req_t req; 3582 EFX_MCDI_DECLARE_BUF(payload, 3583 MC_CMD_MAE_MPORT_FREE_IN_LEN, 3584 MC_CMD_MAE_MPORT_FREE_OUT_LEN); 3585 efx_rc_t rc; 3586 3587 if (encp->enc_mae_supported == B_FALSE) { 3588 rc = ENOTSUP; 3589 goto fail1; 3590 } 3591 3592 req.emr_cmd = MC_CMD_MAE_MPORT_FREE; 3593 req.emr_in_buf = payload; 3594 req.emr_in_length = MC_CMD_MAE_MPORT_FREE_IN_LEN; 3595 req.emr_out_buf = payload; 3596 req.emr_out_length = MC_CMD_MAE_MPORT_FREE_OUT_LEN; 3597 3598 MCDI_IN_SET_DWORD(req, MAE_MPORT_FREE_IN_MPORT_ID, mportp->id); 3599 3600 efx_mcdi_execute(enp, &req); 3601 3602 if (req.emr_rc != 0) { 3603 rc = req.emr_rc; 3604 goto fail2; 3605 } 3606 3607 return (0); 3608 3609 fail2: 3610 EFSYS_PROBE(fail2); 3611 fail1: 3612 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3613 return (rc); 3614 } 3615 3616 static __checkReturn efx_rc_t 3617 efx_mae_read_mport_journal_single( 3618 __in uint8_t *entry_buf, 3619 __out efx_mport_desc_t *desc) 3620 { 3621 uint32_t pcie_intf; 3622 efx_rc_t rc; 3623 3624 memset(desc, 0, sizeof (*desc)); 3625 3626 desc->emd_id.id = MCDI_STRUCT_DWORD(entry_buf, 3627 MAE_MPORT_DESC_V2_MPORT_ID); 3628 3629 desc->emd_can_receive_on = MCDI_STRUCT_DWORD_FIELD(entry_buf, 3630 MAE_MPORT_DESC_V2_FLAGS, 3631 MAE_MPORT_DESC_V2_CAN_RECEIVE_ON); 3632 3633 desc->emd_can_deliver_to = MCDI_STRUCT_DWORD_FIELD(entry_buf, 3634 MAE_MPORT_DESC_V2_FLAGS, 3635 MAE_MPORT_DESC_V2_CAN_DELIVER_TO); 3636 3637 desc->emd_can_delete = MCDI_STRUCT_DWORD_FIELD(entry_buf, 3638 MAE_MPORT_DESC_V2_FLAGS, 3639 MAE_MPORT_DESC_V2_CAN_DELETE); 3640 3641 desc->emd_zombie = MCDI_STRUCT_DWORD_FIELD(entry_buf, 3642 MAE_MPORT_DESC_V2_FLAGS, 3643 MAE_MPORT_DESC_V2_IS_ZOMBIE); 3644 3645 desc->emd_type = MCDI_STRUCT_DWORD(entry_buf, 3646 MAE_MPORT_DESC_V2_MPORT_TYPE); 3647 3648 /* 3649 * We can't check everything here. If some additional checks are 3650 * required, they should be performed by the callback function. 3651 */ 3652 switch (desc->emd_type) { 3653 case EFX_MPORT_TYPE_NET_PORT: 3654 desc->emd_net_port.ep_index = 3655 MCDI_STRUCT_DWORD(entry_buf, 3656 MAE_MPORT_DESC_V2_NET_PORT_IDX); 3657 break; 3658 case EFX_MPORT_TYPE_ALIAS: 3659 desc->emd_alias.ea_target_mport_id.id = 3660 MCDI_STRUCT_DWORD(entry_buf, 3661 MAE_MPORT_DESC_V2_ALIAS_DELIVER_MPORT_ID); 3662 break; 3663 case EFX_MPORT_TYPE_VNIC: 3664 desc->emd_vnic.ev_client_type = 3665 MCDI_STRUCT_DWORD(entry_buf, 3666 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE); 3667 if (desc->emd_vnic.ev_client_type != 3668 EFX_MPORT_VNIC_CLIENT_FUNCTION) 3669 break; 3670 3671 pcie_intf = MCDI_STRUCT_DWORD(entry_buf, 3672 MAE_MPORT_DESC_V2_VNIC_FUNCTION_INTERFACE); 3673 rc = efx_mcdi_intf_from_pcie(pcie_intf, 3674 &desc->emd_vnic.ev_intf); 3675 if (rc != 0) 3676 goto fail1; 3677 3678 desc->emd_vnic.ev_pf = MCDI_STRUCT_WORD(entry_buf, 3679 MAE_MPORT_DESC_V2_VNIC_FUNCTION_PF_IDX); 3680 desc->emd_vnic.ev_vf = MCDI_STRUCT_WORD(entry_buf, 3681 MAE_MPORT_DESC_V2_VNIC_FUNCTION_VF_IDX); 3682 desc->emd_vnic.ev_handle = MCDI_STRUCT_DWORD(entry_buf, 3683 MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE); 3684 break; 3685 default: 3686 rc = EINVAL; 3687 goto fail2; 3688 } 3689 3690 return (0); 3691 3692 fail2: 3693 EFSYS_PROBE(fail2); 3694 fail1: 3695 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3696 return (rc); 3697 } 3698 3699 static __checkReturn efx_rc_t 3700 efx_mae_read_mport_journal_batch( 3701 __in efx_nic_t *enp, 3702 __in efx_mae_read_mport_journal_cb *cbp, 3703 __in void *cb_datap, 3704 __out uint32_t *morep) 3705 { 3706 efx_mcdi_req_t req; 3707 EFX_MCDI_DECLARE_BUF(payload, 3708 MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN, 3709 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2); 3710 uint32_t n_entries; 3711 uint32_t entry_sz; 3712 uint8_t *entry_buf; 3713 unsigned int i; 3714 efx_rc_t rc; 3715 3716 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_NET_PORT == 3717 MAE_MPORT_DESC_V2_MPORT_TYPE_NET_PORT); 3718 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_ALIAS == 3719 MAE_MPORT_DESC_V2_MPORT_TYPE_ALIAS); 3720 EFX_STATIC_ASSERT(EFX_MPORT_TYPE_VNIC == 3721 MAE_MPORT_DESC_V2_MPORT_TYPE_VNIC); 3722 3723 EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_FUNCTION == 3724 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_FUNCTION); 3725 EFX_STATIC_ASSERT(EFX_MPORT_VNIC_CLIENT_PLUGIN == 3726 MAE_MPORT_DESC_V2_VNIC_CLIENT_TYPE_PLUGIN); 3727 3728 if (cbp == NULL) { 3729 rc = EINVAL; 3730 goto fail1; 3731 } 3732 3733 req.emr_cmd = MC_CMD_MAE_MPORT_READ_JOURNAL; 3734 req.emr_in_buf = payload; 3735 req.emr_in_length = MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN; 3736 req.emr_out_buf = payload; 3737 req.emr_out_length = MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2; 3738 3739 MCDI_IN_SET_DWORD(req, MAE_MPORT_READ_JOURNAL_IN_FLAGS, 0); 3740 3741 efx_mcdi_execute(enp, &req); 3742 3743 if (req.emr_rc != 0) { 3744 rc = req.emr_rc; 3745 goto fail2; 3746 } 3747 3748 if (req.emr_out_length_used < 3749 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN) { 3750 rc = EMSGSIZE; 3751 goto fail3; 3752 } 3753 3754 if (morep != NULL) { 3755 *morep = MCDI_OUT_DWORD_FIELD(req, 3756 MAE_MPORT_READ_JOURNAL_OUT_FLAGS, 3757 MAE_MPORT_READ_JOURNAL_OUT_MORE); 3758 } 3759 n_entries = MCDI_OUT_DWORD(req, 3760 MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT); 3761 entry_sz = MCDI_OUT_DWORD(req, 3762 MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC); 3763 entry_buf = MCDI_OUT2(req, uint8_t, 3764 MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA); 3765 3766 if (entry_sz < MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_OFST + 3767 MAE_MPORT_DESC_V2_VNIC_CLIENT_HANDLE_LEN) { 3768 rc = EINVAL; 3769 goto fail4; 3770 } 3771 if (n_entries * entry_sz / entry_sz != n_entries) { 3772 rc = EINVAL; 3773 goto fail5; 3774 } 3775 if (req.emr_out_length_used != 3776 MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMIN + n_entries * entry_sz) { 3777 rc = EINVAL; 3778 goto fail6; 3779 } 3780 3781 for (i = 0; i < n_entries; i++) { 3782 efx_mport_desc_t desc; 3783 3784 rc = efx_mae_read_mport_journal_single(entry_buf, &desc); 3785 if (rc != 0) 3786 continue; 3787 3788 (*cbp)(cb_datap, &desc, sizeof (desc)); 3789 entry_buf += entry_sz; 3790 } 3791 3792 return (0); 3793 3794 fail6: 3795 EFSYS_PROBE(fail6); 3796 fail5: 3797 EFSYS_PROBE(fail5); 3798 fail4: 3799 EFSYS_PROBE(fail4); 3800 fail3: 3801 EFSYS_PROBE(fail3); 3802 fail2: 3803 EFSYS_PROBE(fail2); 3804 fail1: 3805 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3806 return (rc); 3807 } 3808 3809 __checkReturn efx_rc_t 3810 efx_mae_read_mport_journal( 3811 __in efx_nic_t *enp, 3812 __in efx_mae_read_mport_journal_cb *cbp, 3813 __in void *cb_datap) 3814 { 3815 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 3816 uint32_t more = 0; 3817 efx_rc_t rc; 3818 3819 if (encp->enc_mae_supported == B_FALSE) { 3820 rc = ENOTSUP; 3821 goto fail1; 3822 } 3823 3824 do { 3825 rc = efx_mae_read_mport_journal_batch(enp, cbp, cb_datap, 3826 &more); 3827 if (rc != 0) 3828 goto fail2; 3829 } while (more != 0); 3830 3831 return (0); 3832 3833 fail2: 3834 EFSYS_PROBE(fail2); 3835 fail1: 3836 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3837 return (rc); 3838 } 3839 3840 #endif /* EFSYS_OPT_MAE */ 3841