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