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