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