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(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN) == 1) { 50 maep->em_encap_types_supported |= 51 (1U << EFX_TUNNEL_PROTOCOL_VXLAN); 52 } 53 54 if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE) == 1) { 55 maep->em_encap_types_supported |= 56 (1U << EFX_TUNNEL_PROTOCOL_GENEVE); 57 } 58 59 if (MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_ENCAP_TYPE_NVGRE) == 1) { 60 maep->em_encap_types_supported |= 61 (1U << EFX_TUNNEL_PROTOCOL_NVGRE); 62 } 63 64 maep->em_max_nfields = 65 MCDI_OUT_DWORD(req, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT); 66 67 return (0); 68 69 fail2: 70 EFSYS_PROBE(fail2); 71 fail1: 72 EFSYS_PROBE1(fail1, efx_rc_t, rc); 73 return (rc); 74 } 75 76 static __checkReturn efx_rc_t 77 efx_mae_get_outer_rule_caps( 78 __in efx_nic_t *enp, 79 __in unsigned int field_ncaps, 80 __out_ecount(field_ncaps) efx_mae_field_cap_t *field_caps) 81 { 82 efx_mcdi_req_t req; 83 EFX_MCDI_DECLARE_BUF(payload, 84 MC_CMD_MAE_GET_OR_CAPS_IN_LEN, 85 MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2); 86 unsigned int mcdi_field_ncaps; 87 unsigned int i; 88 efx_rc_t rc; 89 90 if (MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps) > 91 MC_CMD_MAE_GET_OR_CAPS_OUT_LENMAX_MCDI2) { 92 rc = EINVAL; 93 goto fail1; 94 } 95 96 req.emr_cmd = MC_CMD_MAE_GET_OR_CAPS; 97 req.emr_in_buf = payload; 98 req.emr_in_length = MC_CMD_MAE_GET_OR_CAPS_IN_LEN; 99 req.emr_out_buf = payload; 100 req.emr_out_length = MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(field_ncaps); 101 102 efx_mcdi_execute(enp, &req); 103 104 if (req.emr_rc != 0) { 105 rc = req.emr_rc; 106 goto fail2; 107 } 108 109 mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT); 110 111 if (req.emr_out_length_used < 112 MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(mcdi_field_ncaps)) { 113 rc = EMSGSIZE; 114 goto fail3; 115 } 116 117 if (mcdi_field_ncaps > field_ncaps) { 118 rc = EMSGSIZE; 119 goto fail4; 120 } 121 122 for (i = 0; i < mcdi_field_ncaps; ++i) { 123 uint32_t match_flag; 124 uint32_t mask_flag; 125 126 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req, 127 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i, 128 MAE_FIELD_FLAGS_SUPPORT_STATUS); 129 130 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req, 131 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i, 132 MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS); 133 134 field_caps[i].emfc_match_affects_class = 135 (match_flag != 0) ? B_TRUE : B_FALSE; 136 137 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req, 138 MAE_GET_OR_CAPS_OUT_FIELD_FLAGS, i, 139 MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS); 140 141 field_caps[i].emfc_mask_affects_class = 142 (mask_flag != 0) ? B_TRUE : B_FALSE; 143 } 144 145 return (0); 146 147 fail4: 148 EFSYS_PROBE(fail4); 149 fail3: 150 EFSYS_PROBE(fail3); 151 fail2: 152 EFSYS_PROBE(fail2); 153 fail1: 154 EFSYS_PROBE1(fail1, efx_rc_t, rc); 155 return (rc); 156 } 157 158 static __checkReturn efx_rc_t 159 efx_mae_get_action_rule_caps( 160 __in efx_nic_t *enp, 161 __in unsigned int field_ncaps, 162 __out_ecount(field_ncaps) efx_mae_field_cap_t *field_caps) 163 { 164 efx_mcdi_req_t req; 165 EFX_MCDI_DECLARE_BUF(payload, 166 MC_CMD_MAE_GET_AR_CAPS_IN_LEN, 167 MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2); 168 unsigned int mcdi_field_ncaps; 169 unsigned int i; 170 efx_rc_t rc; 171 172 if (MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps) > 173 MC_CMD_MAE_GET_AR_CAPS_OUT_LENMAX_MCDI2) { 174 rc = EINVAL; 175 goto fail1; 176 } 177 178 req.emr_cmd = MC_CMD_MAE_GET_AR_CAPS; 179 req.emr_in_buf = payload; 180 req.emr_in_length = MC_CMD_MAE_GET_AR_CAPS_IN_LEN; 181 req.emr_out_buf = payload; 182 req.emr_out_length = MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(field_ncaps); 183 184 efx_mcdi_execute(enp, &req); 185 186 if (req.emr_rc != 0) { 187 rc = req.emr_rc; 188 goto fail2; 189 } 190 191 mcdi_field_ncaps = MCDI_OUT_DWORD(req, MAE_GET_OR_CAPS_OUT_COUNT); 192 193 if (req.emr_out_length_used < 194 MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(mcdi_field_ncaps)) { 195 rc = EMSGSIZE; 196 goto fail3; 197 } 198 199 if (mcdi_field_ncaps > field_ncaps) { 200 rc = EMSGSIZE; 201 goto fail4; 202 } 203 204 for (i = 0; i < mcdi_field_ncaps; ++i) { 205 uint32_t match_flag; 206 uint32_t mask_flag; 207 208 field_caps[i].emfc_support = MCDI_OUT_INDEXED_DWORD_FIELD(req, 209 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i, 210 MAE_FIELD_FLAGS_SUPPORT_STATUS); 211 212 match_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req, 213 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i, 214 MAE_FIELD_FLAGS_MATCH_AFFECTS_CLASS); 215 216 field_caps[i].emfc_match_affects_class = 217 (match_flag != 0) ? B_TRUE : B_FALSE; 218 219 mask_flag = MCDI_OUT_INDEXED_DWORD_FIELD(req, 220 MAE_GET_AR_CAPS_OUT_FIELD_FLAGS, i, 221 MAE_FIELD_FLAGS_MASK_AFFECTS_CLASS); 222 223 field_caps[i].emfc_mask_affects_class = 224 (mask_flag != 0) ? B_TRUE : B_FALSE; 225 } 226 227 return (0); 228 229 fail4: 230 EFSYS_PROBE(fail4); 231 fail3: 232 EFSYS_PROBE(fail3); 233 fail2: 234 EFSYS_PROBE(fail2); 235 fail1: 236 EFSYS_PROBE1(fail1, efx_rc_t, rc); 237 return (rc); 238 } 239 240 __checkReturn efx_rc_t 241 efx_mae_init( 242 __in efx_nic_t *enp) 243 { 244 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 245 efx_mae_field_cap_t *or_fcaps; 246 size_t or_fcaps_size; 247 efx_mae_field_cap_t *ar_fcaps; 248 size_t ar_fcaps_size; 249 efx_mae_t *maep; 250 efx_rc_t rc; 251 252 if (encp->enc_mae_supported == B_FALSE) { 253 rc = ENOTSUP; 254 goto fail1; 255 } 256 257 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*maep), maep); 258 if (maep == NULL) { 259 rc = ENOMEM; 260 goto fail2; 261 } 262 263 enp->en_maep = maep; 264 265 rc = efx_mae_get_capabilities(enp); 266 if (rc != 0) 267 goto fail3; 268 269 or_fcaps_size = maep->em_max_nfields * sizeof (*or_fcaps); 270 EFSYS_KMEM_ALLOC(enp->en_esip, or_fcaps_size, or_fcaps); 271 if (or_fcaps == NULL) { 272 rc = ENOMEM; 273 goto fail4; 274 } 275 276 maep->em_outer_rule_field_caps_size = or_fcaps_size; 277 maep->em_outer_rule_field_caps = or_fcaps; 278 279 rc = efx_mae_get_outer_rule_caps(enp, maep->em_max_nfields, or_fcaps); 280 if (rc != 0) 281 goto fail5; 282 283 ar_fcaps_size = maep->em_max_nfields * sizeof (*ar_fcaps); 284 EFSYS_KMEM_ALLOC(enp->en_esip, ar_fcaps_size, ar_fcaps); 285 if (ar_fcaps == NULL) { 286 rc = ENOMEM; 287 goto fail6; 288 } 289 290 maep->em_action_rule_field_caps_size = ar_fcaps_size; 291 maep->em_action_rule_field_caps = ar_fcaps; 292 293 rc = efx_mae_get_action_rule_caps(enp, maep->em_max_nfields, ar_fcaps); 294 if (rc != 0) 295 goto fail7; 296 297 return (0); 298 299 fail7: 300 EFSYS_PROBE(fail5); 301 EFSYS_KMEM_FREE(enp->en_esip, ar_fcaps_size, ar_fcaps); 302 fail6: 303 EFSYS_PROBE(fail4); 304 fail5: 305 EFSYS_PROBE(fail5); 306 EFSYS_KMEM_FREE(enp->en_esip, or_fcaps_size, or_fcaps); 307 fail4: 308 EFSYS_PROBE(fail4); 309 fail3: 310 EFSYS_PROBE(fail3); 311 EFSYS_KMEM_FREE(enp->en_esip, sizeof (struct efx_mae_s), enp->en_maep); 312 enp->en_maep = NULL; 313 fail2: 314 EFSYS_PROBE(fail2); 315 fail1: 316 EFSYS_PROBE1(fail1, efx_rc_t, rc); 317 return (rc); 318 } 319 320 void 321 efx_mae_fini( 322 __in efx_nic_t *enp) 323 { 324 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 325 efx_mae_t *maep = enp->en_maep; 326 327 if (encp->enc_mae_supported == B_FALSE) 328 return; 329 330 EFSYS_KMEM_FREE(enp->en_esip, maep->em_action_rule_field_caps_size, 331 maep->em_action_rule_field_caps); 332 EFSYS_KMEM_FREE(enp->en_esip, maep->em_outer_rule_field_caps_size, 333 maep->em_outer_rule_field_caps); 334 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*maep), maep); 335 enp->en_maep = NULL; 336 } 337 338 __checkReturn efx_rc_t 339 efx_mae_get_limits( 340 __in efx_nic_t *enp, 341 __out efx_mae_limits_t *emlp) 342 { 343 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 344 struct efx_mae_s *maep = enp->en_maep; 345 efx_rc_t rc; 346 347 if (encp->enc_mae_supported == B_FALSE) { 348 rc = ENOTSUP; 349 goto fail1; 350 } 351 352 emlp->eml_max_n_outer_prios = maep->em_max_n_outer_prios; 353 emlp->eml_max_n_action_prios = maep->em_max_n_action_prios; 354 emlp->eml_encap_types_supported = maep->em_encap_types_supported; 355 356 return (0); 357 358 fail1: 359 EFSYS_PROBE1(fail1, efx_rc_t, rc); 360 return (rc); 361 } 362 363 __checkReturn efx_rc_t 364 efx_mae_match_spec_init( 365 __in efx_nic_t *enp, 366 __in efx_mae_rule_type_t type, 367 __in uint32_t prio, 368 __out efx_mae_match_spec_t **specp) 369 { 370 efx_mae_match_spec_t *spec; 371 efx_rc_t rc; 372 373 switch (type) { 374 case EFX_MAE_RULE_OUTER: 375 break; 376 case EFX_MAE_RULE_ACTION: 377 break; 378 default: 379 rc = ENOTSUP; 380 goto fail1; 381 } 382 383 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec); 384 if (spec == NULL) { 385 rc = ENOMEM; 386 goto fail2; 387 } 388 389 spec->emms_type = type; 390 spec->emms_prio = prio; 391 392 *specp = spec; 393 394 return (0); 395 396 fail2: 397 EFSYS_PROBE(fail2); 398 fail1: 399 EFSYS_PROBE1(fail1, efx_rc_t, rc); 400 return (rc); 401 } 402 403 void 404 efx_mae_match_spec_fini( 405 __in efx_nic_t *enp, 406 __in efx_mae_match_spec_t *spec) 407 { 408 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 409 } 410 411 /* Named identifiers which are valid indices to efx_mae_field_cap_t */ 412 typedef enum efx_mae_field_cap_id_e { 413 EFX_MAE_FIELD_ID_INGRESS_MPORT_SELECTOR = MAE_FIELD_INGRESS_PORT, 414 EFX_MAE_FIELD_ID_ETHER_TYPE_BE = MAE_FIELD_ETHER_TYPE, 415 EFX_MAE_FIELD_ID_ETH_SADDR_BE = MAE_FIELD_ETH_SADDR, 416 EFX_MAE_FIELD_ID_ETH_DADDR_BE = MAE_FIELD_ETH_DADDR, 417 EFX_MAE_FIELD_ID_VLAN0_TCI_BE = MAE_FIELD_VLAN0_TCI, 418 EFX_MAE_FIELD_ID_VLAN0_PROTO_BE = MAE_FIELD_VLAN0_PROTO, 419 EFX_MAE_FIELD_ID_VLAN1_TCI_BE = MAE_FIELD_VLAN1_TCI, 420 EFX_MAE_FIELD_ID_VLAN1_PROTO_BE = MAE_FIELD_VLAN1_PROTO, 421 EFX_MAE_FIELD_ID_SRC_IP4_BE = MAE_FIELD_SRC_IP4, 422 EFX_MAE_FIELD_ID_DST_IP4_BE = MAE_FIELD_DST_IP4, 423 EFX_MAE_FIELD_ID_IP_PROTO = MAE_FIELD_IP_PROTO, 424 EFX_MAE_FIELD_ID_IP_TOS = MAE_FIELD_IP_TOS, 425 EFX_MAE_FIELD_ID_IP_TTL = MAE_FIELD_IP_TTL, 426 EFX_MAE_FIELD_ID_SRC_IP6_BE = MAE_FIELD_SRC_IP6, 427 EFX_MAE_FIELD_ID_DST_IP6_BE = MAE_FIELD_DST_IP6, 428 EFX_MAE_FIELD_ID_L4_SPORT_BE = MAE_FIELD_L4_SPORT, 429 EFX_MAE_FIELD_ID_L4_DPORT_BE = MAE_FIELD_L4_DPORT, 430 EFX_MAE_FIELD_ID_TCP_FLAGS_BE = MAE_FIELD_TCP_FLAGS, 431 EFX_MAE_FIELD_ID_ENC_ETHER_TYPE_BE = MAE_FIELD_ENC_ETHER_TYPE, 432 EFX_MAE_FIELD_ID_ENC_ETH_SADDR_BE = MAE_FIELD_ENC_ETH_SADDR, 433 EFX_MAE_FIELD_ID_ENC_ETH_DADDR_BE = MAE_FIELD_ENC_ETH_DADDR, 434 EFX_MAE_FIELD_ID_ENC_VLAN0_TCI_BE = MAE_FIELD_ENC_VLAN0_TCI, 435 EFX_MAE_FIELD_ID_ENC_VLAN0_PROTO_BE = MAE_FIELD_ENC_VLAN0_PROTO, 436 EFX_MAE_FIELD_ID_ENC_VLAN1_TCI_BE = MAE_FIELD_ENC_VLAN1_TCI, 437 EFX_MAE_FIELD_ID_ENC_VLAN1_PROTO_BE = MAE_FIELD_ENC_VLAN1_PROTO, 438 EFX_MAE_FIELD_ID_ENC_SRC_IP4_BE = MAE_FIELD_ENC_SRC_IP4, 439 EFX_MAE_FIELD_ID_ENC_DST_IP4_BE = MAE_FIELD_ENC_DST_IP4, 440 EFX_MAE_FIELD_ID_ENC_IP_PROTO = MAE_FIELD_ENC_IP_PROTO, 441 EFX_MAE_FIELD_ID_ENC_IP_TOS = MAE_FIELD_ENC_IP_TOS, 442 EFX_MAE_FIELD_ID_ENC_IP_TTL = MAE_FIELD_ENC_IP_TTL, 443 EFX_MAE_FIELD_ID_ENC_SRC_IP6_BE = MAE_FIELD_ENC_SRC_IP6, 444 EFX_MAE_FIELD_ID_ENC_DST_IP6_BE = MAE_FIELD_ENC_DST_IP6, 445 EFX_MAE_FIELD_ID_ENC_L4_SPORT_BE = MAE_FIELD_ENC_L4_SPORT, 446 EFX_MAE_FIELD_ID_ENC_L4_DPORT_BE = MAE_FIELD_ENC_L4_DPORT, 447 EFX_MAE_FIELD_ID_ENC_VNET_ID_BE = MAE_FIELD_ENC_VNET_ID, 448 EFX_MAE_FIELD_ID_OUTER_RULE_ID = MAE_FIELD_OUTER_RULE_ID, 449 450 EFX_MAE_FIELD_CAP_NIDS 451 } efx_mae_field_cap_id_t; 452 453 typedef enum efx_mae_field_endianness_e { 454 EFX_MAE_FIELD_LE = 0, 455 EFX_MAE_FIELD_BE, 456 457 EFX_MAE_FIELD_ENDIANNESS_NTYPES 458 } efx_mae_field_endianness_t; 459 460 /* 461 * The following structure is a means to describe an MAE field. 462 * The information in it is meant to be used internally by 463 * APIs for addressing a given field in a mask-value pairs 464 * structure and for validation purposes. 465 * 466 * A field may have an alternative one. This structure 467 * has additional members to reference the alternative 468 * field's mask. See efx_mae_match_spec_is_valid(). 469 */ 470 typedef struct efx_mae_mv_desc_s { 471 efx_mae_field_cap_id_t emmd_field_cap_id; 472 473 size_t emmd_value_size; 474 size_t emmd_value_offset; 475 size_t emmd_mask_size; 476 size_t emmd_mask_offset; 477 478 /* 479 * Having the alternative field's mask size set to 0 480 * means that there's no alternative field specified. 481 */ 482 size_t emmd_alt_mask_size; 483 size_t emmd_alt_mask_offset; 484 485 /* Primary field and the alternative one are of the same endianness. */ 486 efx_mae_field_endianness_t emmd_endianness; 487 } efx_mae_mv_desc_t; 488 489 /* Indices to this array are provided by efx_mae_field_id_t */ 490 static const efx_mae_mv_desc_t __efx_mae_action_rule_mv_desc_set[] = { 491 #define EFX_MAE_MV_DESC(_name, _endianness) \ 492 [EFX_MAE_FIELD_##_name] = \ 493 { \ 494 EFX_MAE_FIELD_ID_##_name, \ 495 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_LEN, \ 496 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_OFST, \ 497 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_LEN, \ 498 MAE_FIELD_MASK_VALUE_PAIRS_##_name##_MASK_OFST, \ 499 0, 0 /* no alternative field */, \ 500 _endianness \ 501 } 502 503 EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE), 504 EFX_MAE_MV_DESC(ETHER_TYPE_BE, EFX_MAE_FIELD_BE), 505 EFX_MAE_MV_DESC(ETH_SADDR_BE, EFX_MAE_FIELD_BE), 506 EFX_MAE_MV_DESC(ETH_DADDR_BE, EFX_MAE_FIELD_BE), 507 EFX_MAE_MV_DESC(VLAN0_TCI_BE, EFX_MAE_FIELD_BE), 508 EFX_MAE_MV_DESC(VLAN0_PROTO_BE, EFX_MAE_FIELD_BE), 509 EFX_MAE_MV_DESC(VLAN1_TCI_BE, EFX_MAE_FIELD_BE), 510 EFX_MAE_MV_DESC(VLAN1_PROTO_BE, EFX_MAE_FIELD_BE), 511 EFX_MAE_MV_DESC(SRC_IP4_BE, EFX_MAE_FIELD_BE), 512 EFX_MAE_MV_DESC(DST_IP4_BE, EFX_MAE_FIELD_BE), 513 EFX_MAE_MV_DESC(IP_PROTO, EFX_MAE_FIELD_BE), 514 EFX_MAE_MV_DESC(IP_TOS, EFX_MAE_FIELD_BE), 515 EFX_MAE_MV_DESC(IP_TTL, EFX_MAE_FIELD_BE), 516 EFX_MAE_MV_DESC(SRC_IP6_BE, EFX_MAE_FIELD_BE), 517 EFX_MAE_MV_DESC(DST_IP6_BE, EFX_MAE_FIELD_BE), 518 EFX_MAE_MV_DESC(L4_SPORT_BE, EFX_MAE_FIELD_BE), 519 EFX_MAE_MV_DESC(L4_DPORT_BE, EFX_MAE_FIELD_BE), 520 EFX_MAE_MV_DESC(TCP_FLAGS_BE, EFX_MAE_FIELD_BE), 521 EFX_MAE_MV_DESC(ENC_VNET_ID_BE, EFX_MAE_FIELD_BE), 522 EFX_MAE_MV_DESC(OUTER_RULE_ID, EFX_MAE_FIELD_LE), 523 524 #undef EFX_MAE_MV_DESC 525 }; 526 527 /* Indices to this array are provided by efx_mae_field_id_t */ 528 static const efx_mae_mv_desc_t __efx_mae_outer_rule_mv_desc_set[] = { 529 #define EFX_MAE_MV_DESC(_name, _endianness) \ 530 [EFX_MAE_FIELD_##_name] = \ 531 { \ 532 EFX_MAE_FIELD_ID_##_name, \ 533 MAE_ENC_FIELD_PAIRS_##_name##_LEN, \ 534 MAE_ENC_FIELD_PAIRS_##_name##_OFST, \ 535 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN, \ 536 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \ 537 0, 0 /* no alternative field */, \ 538 _endianness \ 539 } 540 541 /* Same as EFX_MAE_MV_DESC(), but also indicates an alternative field. */ 542 #define EFX_MAE_MV_DESC_ALT(_name, _alt_name, _endianness) \ 543 [EFX_MAE_FIELD_##_name] = \ 544 { \ 545 EFX_MAE_FIELD_ID_##_name, \ 546 MAE_ENC_FIELD_PAIRS_##_name##_LEN, \ 547 MAE_ENC_FIELD_PAIRS_##_name##_OFST, \ 548 MAE_ENC_FIELD_PAIRS_##_name##_MASK_LEN, \ 549 MAE_ENC_FIELD_PAIRS_##_name##_MASK_OFST, \ 550 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_LEN, \ 551 MAE_ENC_FIELD_PAIRS_##_alt_name##_MASK_OFST, \ 552 _endianness \ 553 } 554 555 EFX_MAE_MV_DESC(INGRESS_MPORT_SELECTOR, EFX_MAE_FIELD_LE), 556 EFX_MAE_MV_DESC(ENC_ETHER_TYPE_BE, EFX_MAE_FIELD_BE), 557 EFX_MAE_MV_DESC(ENC_ETH_SADDR_BE, EFX_MAE_FIELD_BE), 558 EFX_MAE_MV_DESC(ENC_ETH_DADDR_BE, EFX_MAE_FIELD_BE), 559 EFX_MAE_MV_DESC(ENC_VLAN0_TCI_BE, EFX_MAE_FIELD_BE), 560 EFX_MAE_MV_DESC(ENC_VLAN0_PROTO_BE, EFX_MAE_FIELD_BE), 561 EFX_MAE_MV_DESC(ENC_VLAN1_TCI_BE, EFX_MAE_FIELD_BE), 562 EFX_MAE_MV_DESC(ENC_VLAN1_PROTO_BE, EFX_MAE_FIELD_BE), 563 EFX_MAE_MV_DESC_ALT(ENC_SRC_IP4_BE, ENC_SRC_IP6_BE, EFX_MAE_FIELD_BE), 564 EFX_MAE_MV_DESC_ALT(ENC_DST_IP4_BE, ENC_DST_IP6_BE, EFX_MAE_FIELD_BE), 565 EFX_MAE_MV_DESC(ENC_IP_PROTO, EFX_MAE_FIELD_BE), 566 EFX_MAE_MV_DESC(ENC_IP_TOS, EFX_MAE_FIELD_BE), 567 EFX_MAE_MV_DESC(ENC_IP_TTL, EFX_MAE_FIELD_BE), 568 EFX_MAE_MV_DESC_ALT(ENC_SRC_IP6_BE, ENC_SRC_IP4_BE, EFX_MAE_FIELD_BE), 569 EFX_MAE_MV_DESC_ALT(ENC_DST_IP6_BE, ENC_DST_IP4_BE, EFX_MAE_FIELD_BE), 570 EFX_MAE_MV_DESC(ENC_L4_SPORT_BE, EFX_MAE_FIELD_BE), 571 EFX_MAE_MV_DESC(ENC_L4_DPORT_BE, EFX_MAE_FIELD_BE), 572 573 #undef EFX_MAE_MV_DESC_ALT 574 #undef EFX_MAE_MV_DESC 575 }; 576 577 __checkReturn efx_rc_t 578 efx_mae_mport_by_phy_port( 579 __in uint32_t phy_port, 580 __out efx_mport_sel_t *mportp) 581 { 582 efx_dword_t dword; 583 efx_rc_t rc; 584 585 if (phy_port > EFX_MASK32(MAE_MPORT_SELECTOR_PPORT_ID)) { 586 rc = EINVAL; 587 goto fail1; 588 } 589 590 EFX_POPULATE_DWORD_2(dword, 591 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT, 592 MAE_MPORT_SELECTOR_PPORT_ID, phy_port); 593 594 memset(mportp, 0, sizeof (*mportp)); 595 /* 596 * The constructed DWORD is little-endian, 597 * but the resulting value is meant to be 598 * passed to MCDIs, where it will undergo 599 * host-order to little endian conversion. 600 */ 601 mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 602 603 return (0); 604 605 fail1: 606 EFSYS_PROBE1(fail1, efx_rc_t, rc); 607 return (rc); 608 } 609 610 __checkReturn efx_rc_t 611 efx_mae_mport_by_pcie_function( 612 __in uint32_t pf, 613 __in uint32_t vf, 614 __out efx_mport_sel_t *mportp) 615 { 616 efx_dword_t dword; 617 efx_rc_t rc; 618 619 EFX_STATIC_ASSERT(EFX_PCI_VF_INVALID == 620 MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL); 621 622 if (pf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_PF_ID)) { 623 rc = EINVAL; 624 goto fail1; 625 } 626 627 if (vf > EFX_MASK32(MAE_MPORT_SELECTOR_FUNC_VF_ID)) { 628 rc = EINVAL; 629 goto fail2; 630 } 631 632 EFX_POPULATE_DWORD_3(dword, 633 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC, 634 MAE_MPORT_SELECTOR_FUNC_PF_ID, pf, 635 MAE_MPORT_SELECTOR_FUNC_VF_ID, vf); 636 637 memset(mportp, 0, sizeof (*mportp)); 638 /* 639 * The constructed DWORD is little-endian, 640 * but the resulting value is meant to be 641 * passed to MCDIs, where it will undergo 642 * host-order to little endian conversion. 643 */ 644 mportp->sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 645 646 return (0); 647 648 fail2: 649 EFSYS_PROBE(fail2); 650 fail1: 651 EFSYS_PROBE1(fail1, efx_rc_t, rc); 652 return (rc); 653 } 654 655 __checkReturn efx_rc_t 656 efx_mae_match_spec_field_set( 657 __in efx_mae_match_spec_t *spec, 658 __in efx_mae_field_id_t field_id, 659 __in size_t value_size, 660 __in_bcount(value_size) const uint8_t *value, 661 __in size_t mask_size, 662 __in_bcount(mask_size) const uint8_t *mask) 663 { 664 const efx_mae_mv_desc_t *descp; 665 unsigned int desc_set_nentries; 666 uint8_t *mvp; 667 efx_rc_t rc; 668 669 switch (spec->emms_type) { 670 case EFX_MAE_RULE_OUTER: 671 desc_set_nentries = 672 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set); 673 descp = &__efx_mae_outer_rule_mv_desc_set[field_id]; 674 mvp = spec->emms_mask_value_pairs.outer; 675 break; 676 case EFX_MAE_RULE_ACTION: 677 desc_set_nentries = 678 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set); 679 descp = &__efx_mae_action_rule_mv_desc_set[field_id]; 680 mvp = spec->emms_mask_value_pairs.action; 681 break; 682 default: 683 rc = ENOTSUP; 684 goto fail1; 685 } 686 687 if ((unsigned int)field_id >= desc_set_nentries) { 688 rc = EINVAL; 689 goto fail2; 690 } 691 692 if (descp->emmd_mask_size == 0) { 693 /* The ID points to a gap in the array of field descriptors. */ 694 rc = EINVAL; 695 goto fail3; 696 } 697 698 if (value_size != descp->emmd_value_size) { 699 rc = EINVAL; 700 goto fail4; 701 } 702 703 if (mask_size != descp->emmd_mask_size) { 704 rc = EINVAL; 705 goto fail5; 706 } 707 708 if (descp->emmd_endianness == EFX_MAE_FIELD_BE) { 709 unsigned int i; 710 711 /* 712 * The mask/value are in network (big endian) order. 713 * The MCDI request field is also big endian. 714 */ 715 716 EFSYS_ASSERT3U(value_size, ==, mask_size); 717 718 for (i = 0; i < value_size; ++i) { 719 uint8_t *v_bytep = mvp + descp->emmd_value_offset + i; 720 uint8_t *m_bytep = mvp + descp->emmd_mask_offset + i; 721 722 /* 723 * Apply the mask (which may be all-zeros) to the value. 724 * 725 * If this API is provided with some value to set for a 726 * given field in one specification and with some other 727 * value to set for this field in another specification, 728 * then, if the two masks are all-zeros, the field will 729 * avoid being counted as a mismatch when comparing the 730 * specifications using efx_mae_match_specs_equal() API. 731 */ 732 *v_bytep = value[i] & mask[i]; 733 *m_bytep = mask[i]; 734 } 735 } else { 736 efx_dword_t dword; 737 738 /* 739 * The mask/value are in host byte order. 740 * The MCDI request field is little endian. 741 */ 742 switch (value_size) { 743 case 4: 744 EFX_POPULATE_DWORD_1(dword, 745 EFX_DWORD_0, *(const uint32_t *)value); 746 747 memcpy(mvp + descp->emmd_value_offset, 748 &dword, sizeof (dword)); 749 break; 750 default: 751 EFSYS_ASSERT(B_FALSE); 752 } 753 754 switch (mask_size) { 755 case 4: 756 EFX_POPULATE_DWORD_1(dword, 757 EFX_DWORD_0, *(const uint32_t *)mask); 758 759 memcpy(mvp + descp->emmd_mask_offset, 760 &dword, sizeof (dword)); 761 break; 762 default: 763 EFSYS_ASSERT(B_FALSE); 764 } 765 } 766 767 return (0); 768 769 fail5: 770 EFSYS_PROBE(fail5); 771 fail4: 772 EFSYS_PROBE(fail4); 773 fail3: 774 EFSYS_PROBE(fail3); 775 fail2: 776 EFSYS_PROBE(fail2); 777 fail1: 778 EFSYS_PROBE1(fail1, efx_rc_t, rc); 779 return (rc); 780 } 781 782 __checkReturn efx_rc_t 783 efx_mae_match_spec_mport_set( 784 __in efx_mae_match_spec_t *spec, 785 __in const efx_mport_sel_t *valuep, 786 __in_opt const efx_mport_sel_t *maskp) 787 { 788 uint32_t full_mask = UINT32_MAX; 789 const uint8_t *vp; 790 const uint8_t *mp; 791 efx_rc_t rc; 792 793 if (valuep == NULL) { 794 rc = EINVAL; 795 goto fail1; 796 } 797 798 vp = (const uint8_t *)&valuep->sel; 799 if (maskp != NULL) 800 mp = (const uint8_t *)&maskp->sel; 801 else 802 mp = (const uint8_t *)&full_mask; 803 804 rc = efx_mae_match_spec_field_set(spec, 805 EFX_MAE_FIELD_INGRESS_MPORT_SELECTOR, 806 sizeof (valuep->sel), vp, sizeof (maskp->sel), mp); 807 if (rc != 0) 808 goto fail2; 809 810 return (0); 811 812 fail2: 813 EFSYS_PROBE(fail2); 814 fail1: 815 EFSYS_PROBE1(fail1, efx_rc_t, rc); 816 return (rc); 817 } 818 819 __checkReturn boolean_t 820 efx_mae_match_specs_equal( 821 __in const efx_mae_match_spec_t *left, 822 __in const efx_mae_match_spec_t *right) 823 { 824 return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE); 825 } 826 827 #define EFX_MASK_BIT_IS_SET(_mask, _mask_page_nbits, _bit) \ 828 ((_mask)[(_bit) / (_mask_page_nbits)] & \ 829 (1ULL << ((_bit) & ((_mask_page_nbits) - 1)))) 830 831 static boolean_t 832 efx_mask_is_prefix( 833 __in size_t mask_nbytes, 834 __in_bcount(mask_nbytes) const uint8_t *maskp) 835 { 836 boolean_t prev_bit_is_set = B_TRUE; 837 unsigned int i; 838 839 for (i = 0; i < 8 * mask_nbytes; ++i) { 840 boolean_t bit_is_set = EFX_MASK_BIT_IS_SET(maskp, 8, i); 841 842 if (!prev_bit_is_set && bit_is_set) 843 return B_FALSE; 844 845 prev_bit_is_set = bit_is_set; 846 } 847 848 return B_TRUE; 849 } 850 851 static boolean_t 852 efx_mask_is_all_ones( 853 __in size_t mask_nbytes, 854 __in_bcount(mask_nbytes) const uint8_t *maskp) 855 { 856 unsigned int i; 857 uint8_t t = ~0; 858 859 for (i = 0; i < mask_nbytes; ++i) 860 t &= maskp[i]; 861 862 return (t == (uint8_t)(~0)); 863 } 864 865 static boolean_t 866 efx_mask_is_all_zeros( 867 __in size_t mask_nbytes, 868 __in_bcount(mask_nbytes) const uint8_t *maskp) 869 { 870 unsigned int i; 871 uint8_t t = 0; 872 873 for (i = 0; i < mask_nbytes; ++i) 874 t |= maskp[i]; 875 876 return (t == 0); 877 } 878 879 __checkReturn boolean_t 880 efx_mae_match_spec_is_valid( 881 __in efx_nic_t *enp, 882 __in const efx_mae_match_spec_t *spec) 883 { 884 efx_mae_t *maep = enp->en_maep; 885 unsigned int field_ncaps = maep->em_max_nfields; 886 const efx_mae_field_cap_t *field_caps; 887 const efx_mae_mv_desc_t *desc_setp; 888 unsigned int desc_set_nentries; 889 boolean_t is_valid = B_TRUE; 890 efx_mae_field_id_t field_id; 891 const uint8_t *mvp; 892 893 switch (spec->emms_type) { 894 case EFX_MAE_RULE_OUTER: 895 field_caps = maep->em_outer_rule_field_caps; 896 desc_setp = __efx_mae_outer_rule_mv_desc_set; 897 desc_set_nentries = 898 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set); 899 mvp = spec->emms_mask_value_pairs.outer; 900 break; 901 case EFX_MAE_RULE_ACTION: 902 field_caps = maep->em_action_rule_field_caps; 903 desc_setp = __efx_mae_action_rule_mv_desc_set; 904 desc_set_nentries = 905 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set); 906 mvp = spec->emms_mask_value_pairs.action; 907 break; 908 default: 909 return (B_FALSE); 910 } 911 912 if (field_caps == NULL) 913 return (B_FALSE); 914 915 for (field_id = 0; (unsigned int)field_id < desc_set_nentries; 916 ++field_id) { 917 const efx_mae_mv_desc_t *descp = &desc_setp[field_id]; 918 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id; 919 const uint8_t *alt_m_buf = mvp + descp->emmd_alt_mask_offset; 920 const uint8_t *m_buf = mvp + descp->emmd_mask_offset; 921 size_t alt_m_size = descp->emmd_alt_mask_size; 922 size_t m_size = descp->emmd_mask_size; 923 924 if (m_size == 0) 925 continue; /* Skip array gap */ 926 927 if ((unsigned int)field_cap_id >= field_ncaps) { 928 /* 929 * The FW has not reported capability status for 930 * this field. Make sure that its mask is zeroed. 931 */ 932 is_valid = efx_mask_is_all_zeros(m_size, m_buf); 933 if (is_valid != B_FALSE) 934 continue; 935 else 936 break; 937 } 938 939 switch (field_caps[field_cap_id].emfc_support) { 940 case MAE_FIELD_SUPPORTED_MATCH_MASK: 941 is_valid = B_TRUE; 942 break; 943 case MAE_FIELD_SUPPORTED_MATCH_PREFIX: 944 is_valid = efx_mask_is_prefix(m_size, m_buf); 945 break; 946 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL: 947 is_valid = (efx_mask_is_all_ones(m_size, m_buf) || 948 efx_mask_is_all_zeros(m_size, m_buf)); 949 break; 950 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: 951 is_valid = efx_mask_is_all_ones(m_size, m_buf); 952 953 if ((is_valid == B_FALSE) && (alt_m_size != 0)) { 954 /* 955 * This field has an alternative one. The FW 956 * reports ALWAYS for both implying that one 957 * of them is required to have all-ones mask. 958 * 959 * The primary field's mask is incorrect; go 960 * on to check that of the alternative field. 961 */ 962 is_valid = efx_mask_is_all_ones(alt_m_size, 963 alt_m_buf); 964 } 965 break; 966 case MAE_FIELD_SUPPORTED_MATCH_NEVER: 967 case MAE_FIELD_UNSUPPORTED: 968 default: 969 is_valid = efx_mask_is_all_zeros(m_size, m_buf); 970 break; 971 } 972 973 if (is_valid == B_FALSE) 974 break; 975 } 976 977 return (is_valid); 978 } 979 980 __checkReturn efx_rc_t 981 efx_mae_action_set_spec_init( 982 __in efx_nic_t *enp, 983 __out efx_mae_actions_t **specp) 984 { 985 efx_mae_actions_t *spec; 986 efx_rc_t rc; 987 988 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), spec); 989 if (spec == NULL) { 990 rc = ENOMEM; 991 goto fail1; 992 } 993 994 *specp = spec; 995 996 return (0); 997 998 fail1: 999 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1000 return (rc); 1001 } 1002 1003 void 1004 efx_mae_action_set_spec_fini( 1005 __in efx_nic_t *enp, 1006 __in efx_mae_actions_t *spec) 1007 { 1008 EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 1009 } 1010 1011 static __checkReturn efx_rc_t 1012 efx_mae_action_set_add_vlan_pop( 1013 __in efx_mae_actions_t *spec, 1014 __in size_t arg_size, 1015 __in_bcount(arg_size) const uint8_t *arg) 1016 { 1017 efx_rc_t rc; 1018 1019 if (arg_size != 0) { 1020 rc = EINVAL; 1021 goto fail1; 1022 } 1023 1024 if (arg != NULL) { 1025 rc = EINVAL; 1026 goto fail2; 1027 } 1028 1029 if (spec->ema_n_vlan_tags_to_pop == EFX_MAE_VLAN_POP_MAX_NTAGS) { 1030 rc = ENOTSUP; 1031 goto fail3; 1032 } 1033 1034 ++spec->ema_n_vlan_tags_to_pop; 1035 1036 return (0); 1037 1038 fail3: 1039 EFSYS_PROBE(fail3); 1040 fail2: 1041 EFSYS_PROBE(fail2); 1042 fail1: 1043 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1044 return (rc); 1045 } 1046 1047 static __checkReturn efx_rc_t 1048 efx_mae_action_set_add_vlan_push( 1049 __in efx_mae_actions_t *spec, 1050 __in size_t arg_size, 1051 __in_bcount(arg_size) const uint8_t *arg) 1052 { 1053 unsigned int n_tags = spec->ema_n_vlan_tags_to_push; 1054 efx_rc_t rc; 1055 1056 if (arg_size != sizeof (*spec->ema_vlan_push_descs)) { 1057 rc = EINVAL; 1058 goto fail1; 1059 } 1060 1061 if (arg == NULL) { 1062 rc = EINVAL; 1063 goto fail2; 1064 } 1065 1066 if (n_tags == EFX_MAE_VLAN_PUSH_MAX_NTAGS) { 1067 rc = ENOTSUP; 1068 goto fail3; 1069 } 1070 1071 memcpy(&spec->ema_vlan_push_descs[n_tags], arg, arg_size); 1072 ++(spec->ema_n_vlan_tags_to_push); 1073 1074 return (0); 1075 1076 fail3: 1077 EFSYS_PROBE(fail3); 1078 fail2: 1079 EFSYS_PROBE(fail2); 1080 fail1: 1081 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1082 return (rc); 1083 } 1084 1085 static __checkReturn efx_rc_t 1086 efx_mae_action_set_add_flag( 1087 __in efx_mae_actions_t *spec, 1088 __in size_t arg_size, 1089 __in_bcount(arg_size) const uint8_t *arg) 1090 { 1091 efx_rc_t rc; 1092 1093 _NOTE(ARGUNUSED(spec)) 1094 1095 if (arg_size != 0) { 1096 rc = EINVAL; 1097 goto fail1; 1098 } 1099 1100 if (arg != NULL) { 1101 rc = EINVAL; 1102 goto fail2; 1103 } 1104 1105 /* This action does not have any arguments, so do nothing here. */ 1106 1107 return (0); 1108 1109 fail2: 1110 EFSYS_PROBE(fail2); 1111 fail1: 1112 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1113 return (rc); 1114 } 1115 1116 static __checkReturn efx_rc_t 1117 efx_mae_action_set_add_mark( 1118 __in efx_mae_actions_t *spec, 1119 __in size_t arg_size, 1120 __in_bcount(arg_size) const uint8_t *arg) 1121 { 1122 efx_rc_t rc; 1123 1124 if (arg_size != sizeof (spec->ema_mark_value)) { 1125 rc = EINVAL; 1126 goto fail1; 1127 } 1128 1129 if (arg == NULL) { 1130 rc = EINVAL; 1131 goto fail2; 1132 } 1133 1134 memcpy(&spec->ema_mark_value, arg, arg_size); 1135 1136 return (0); 1137 1138 fail2: 1139 EFSYS_PROBE(fail2); 1140 fail1: 1141 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1142 return (rc); 1143 } 1144 1145 static __checkReturn efx_rc_t 1146 efx_mae_action_set_add_deliver( 1147 __in efx_mae_actions_t *spec, 1148 __in size_t arg_size, 1149 __in_bcount(arg_size) const uint8_t *arg) 1150 { 1151 efx_rc_t rc; 1152 1153 if (arg_size != sizeof (spec->ema_deliver_mport)) { 1154 rc = EINVAL; 1155 goto fail1; 1156 } 1157 1158 if (arg == NULL) { 1159 rc = EINVAL; 1160 goto fail2; 1161 } 1162 1163 memcpy(&spec->ema_deliver_mport, arg, arg_size); 1164 1165 return (0); 1166 1167 fail2: 1168 EFSYS_PROBE(fail2); 1169 fail1: 1170 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1171 return (rc); 1172 } 1173 1174 typedef struct efx_mae_action_desc_s { 1175 /* Action specific handler */ 1176 efx_rc_t (*emad_add)(efx_mae_actions_t *, 1177 size_t, const uint8_t *); 1178 } efx_mae_action_desc_t; 1179 1180 static const efx_mae_action_desc_t efx_mae_actions[EFX_MAE_NACTIONS] = { 1181 [EFX_MAE_ACTION_VLAN_POP] = { 1182 .emad_add = efx_mae_action_set_add_vlan_pop 1183 }, 1184 [EFX_MAE_ACTION_VLAN_PUSH] = { 1185 .emad_add = efx_mae_action_set_add_vlan_push 1186 }, 1187 [EFX_MAE_ACTION_FLAG] = { 1188 .emad_add = efx_mae_action_set_add_flag 1189 }, 1190 [EFX_MAE_ACTION_MARK] = { 1191 .emad_add = efx_mae_action_set_add_mark 1192 }, 1193 [EFX_MAE_ACTION_DELIVER] = { 1194 .emad_add = efx_mae_action_set_add_deliver 1195 } 1196 }; 1197 1198 static const uint32_t efx_mae_action_ordered_map = 1199 (1U << EFX_MAE_ACTION_VLAN_POP) | 1200 (1U << EFX_MAE_ACTION_VLAN_PUSH) | 1201 (1U << EFX_MAE_ACTION_FLAG) | 1202 (1U << EFX_MAE_ACTION_MARK) | 1203 (1U << EFX_MAE_ACTION_DELIVER); 1204 1205 /* 1206 * These actions must not be added after DELIVER, but 1207 * they can have any place among the rest of 1208 * strictly ordered actions. 1209 */ 1210 static const uint32_t efx_mae_action_nonstrict_map = 1211 (1U << EFX_MAE_ACTION_FLAG) | 1212 (1U << EFX_MAE_ACTION_MARK); 1213 1214 static const uint32_t efx_mae_action_repeat_map = 1215 (1U << EFX_MAE_ACTION_VLAN_POP) | 1216 (1U << EFX_MAE_ACTION_VLAN_PUSH); 1217 1218 /* 1219 * Add an action to an action set. 1220 * 1221 * This has to be invoked in the desired action order. 1222 * An out-of-order action request will be turned down. 1223 */ 1224 static __checkReturn efx_rc_t 1225 efx_mae_action_set_spec_populate( 1226 __in efx_mae_actions_t *spec, 1227 __in efx_mae_action_t type, 1228 __in size_t arg_size, 1229 __in_bcount(arg_size) const uint8_t *arg) 1230 { 1231 uint32_t action_mask; 1232 efx_rc_t rc; 1233 1234 EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <= 1235 (sizeof (efx_mae_action_ordered_map) * 8)); 1236 EFX_STATIC_ASSERT(EFX_MAE_NACTIONS <= 1237 (sizeof (efx_mae_action_repeat_map) * 8)); 1238 1239 EFX_STATIC_ASSERT(EFX_MAE_ACTION_DELIVER + 1 == EFX_MAE_NACTIONS); 1240 EFX_STATIC_ASSERT(EFX_MAE_ACTION_FLAG + 1 == EFX_MAE_ACTION_MARK); 1241 EFX_STATIC_ASSERT(EFX_MAE_ACTION_MARK + 1 == EFX_MAE_ACTION_DELIVER); 1242 1243 if (type >= EFX_ARRAY_SIZE(efx_mae_actions)) { 1244 rc = EINVAL; 1245 goto fail1; 1246 } 1247 1248 action_mask = (1U << type); 1249 1250 if ((spec->ema_actions & action_mask) != 0) { 1251 /* The action set already contains this action. */ 1252 if ((efx_mae_action_repeat_map & action_mask) == 0) { 1253 /* Cannot add another non-repeatable action. */ 1254 rc = ENOTSUP; 1255 goto fail2; 1256 } 1257 } 1258 1259 if ((efx_mae_action_ordered_map & action_mask) != 0) { 1260 uint32_t strict_ordered_map = 1261 efx_mae_action_ordered_map & ~efx_mae_action_nonstrict_map; 1262 uint32_t later_actions_mask = 1263 strict_ordered_map & ~(action_mask | (action_mask - 1)); 1264 1265 if ((spec->ema_actions & later_actions_mask) != 0) { 1266 /* Cannot add an action after later ordered actions. */ 1267 rc = ENOTSUP; 1268 goto fail3; 1269 } 1270 } 1271 1272 if (efx_mae_actions[type].emad_add != NULL) { 1273 rc = efx_mae_actions[type].emad_add(spec, arg_size, arg); 1274 if (rc != 0) 1275 goto fail4; 1276 } 1277 1278 spec->ema_actions |= action_mask; 1279 1280 return (0); 1281 1282 fail4: 1283 EFSYS_PROBE(fail4); 1284 fail3: 1285 EFSYS_PROBE(fail3); 1286 fail2: 1287 EFSYS_PROBE(fail2); 1288 fail1: 1289 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1290 return (rc); 1291 } 1292 1293 __checkReturn efx_rc_t 1294 efx_mae_action_set_populate_vlan_pop( 1295 __in efx_mae_actions_t *spec) 1296 { 1297 return (efx_mae_action_set_spec_populate(spec, 1298 EFX_MAE_ACTION_VLAN_POP, 0, NULL)); 1299 } 1300 1301 __checkReturn efx_rc_t 1302 efx_mae_action_set_populate_vlan_push( 1303 __in efx_mae_actions_t *spec, 1304 __in uint16_t tpid_be, 1305 __in uint16_t tci_be) 1306 { 1307 efx_mae_action_vlan_push_t action; 1308 const uint8_t *arg = (const uint8_t *)&action; 1309 1310 action.emavp_tpid_be = tpid_be; 1311 action.emavp_tci_be = tci_be; 1312 1313 return (efx_mae_action_set_spec_populate(spec, 1314 EFX_MAE_ACTION_VLAN_PUSH, sizeof (action), arg)); 1315 } 1316 1317 __checkReturn efx_rc_t 1318 efx_mae_action_set_populate_flag( 1319 __in efx_mae_actions_t *spec) 1320 { 1321 return (efx_mae_action_set_spec_populate(spec, 1322 EFX_MAE_ACTION_FLAG, 0, NULL)); 1323 } 1324 1325 __checkReturn efx_rc_t 1326 efx_mae_action_set_populate_mark( 1327 __in efx_mae_actions_t *spec, 1328 __in uint32_t mark_value) 1329 { 1330 const uint8_t *arg = (const uint8_t *)&mark_value; 1331 1332 return (efx_mae_action_set_spec_populate(spec, 1333 EFX_MAE_ACTION_MARK, sizeof (mark_value), arg)); 1334 } 1335 1336 __checkReturn efx_rc_t 1337 efx_mae_action_set_populate_deliver( 1338 __in efx_mae_actions_t *spec, 1339 __in const efx_mport_sel_t *mportp) 1340 { 1341 const uint8_t *arg; 1342 efx_rc_t rc; 1343 1344 if (mportp == NULL) { 1345 rc = EINVAL; 1346 goto fail1; 1347 } 1348 1349 arg = (const uint8_t *)&mportp->sel; 1350 1351 return (efx_mae_action_set_spec_populate(spec, 1352 EFX_MAE_ACTION_DELIVER, sizeof (mportp->sel), arg)); 1353 1354 fail1: 1355 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1356 return (rc); 1357 } 1358 1359 __checkReturn efx_rc_t 1360 efx_mae_action_set_populate_drop( 1361 __in efx_mae_actions_t *spec) 1362 { 1363 efx_mport_sel_t mport; 1364 const uint8_t *arg; 1365 efx_dword_t dword; 1366 1367 EFX_POPULATE_DWORD_1(dword, 1368 MAE_MPORT_SELECTOR_FLAT, MAE_MPORT_SELECTOR_NULL); 1369 1370 /* 1371 * The constructed DWORD is little-endian, 1372 * but the resulting value is meant to be 1373 * passed to MCDIs, where it will undergo 1374 * host-order to little endian conversion. 1375 */ 1376 mport.sel = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 1377 1378 arg = (const uint8_t *)&mport.sel; 1379 1380 return (efx_mae_action_set_spec_populate(spec, 1381 EFX_MAE_ACTION_DELIVER, sizeof (mport.sel), arg)); 1382 } 1383 1384 __checkReturn boolean_t 1385 efx_mae_action_set_specs_equal( 1386 __in const efx_mae_actions_t *left, 1387 __in const efx_mae_actions_t *right) 1388 { 1389 return ((memcmp(left, right, sizeof (*left)) == 0) ? B_TRUE : B_FALSE); 1390 } 1391 1392 __checkReturn efx_rc_t 1393 efx_mae_match_specs_class_cmp( 1394 __in efx_nic_t *enp, 1395 __in const efx_mae_match_spec_t *left, 1396 __in const efx_mae_match_spec_t *right, 1397 __out boolean_t *have_same_classp) 1398 { 1399 efx_mae_t *maep = enp->en_maep; 1400 unsigned int field_ncaps = maep->em_max_nfields; 1401 const efx_mae_field_cap_t *field_caps; 1402 const efx_mae_mv_desc_t *desc_setp; 1403 unsigned int desc_set_nentries; 1404 boolean_t have_same_class = B_TRUE; 1405 efx_mae_field_id_t field_id; 1406 const uint8_t *mvpl; 1407 const uint8_t *mvpr; 1408 efx_rc_t rc; 1409 1410 switch (left->emms_type) { 1411 case EFX_MAE_RULE_OUTER: 1412 field_caps = maep->em_outer_rule_field_caps; 1413 desc_setp = __efx_mae_outer_rule_mv_desc_set; 1414 desc_set_nentries = 1415 EFX_ARRAY_SIZE(__efx_mae_outer_rule_mv_desc_set); 1416 mvpl = left->emms_mask_value_pairs.outer; 1417 mvpr = right->emms_mask_value_pairs.outer; 1418 break; 1419 case EFX_MAE_RULE_ACTION: 1420 field_caps = maep->em_action_rule_field_caps; 1421 desc_setp = __efx_mae_action_rule_mv_desc_set; 1422 desc_set_nentries = 1423 EFX_ARRAY_SIZE(__efx_mae_action_rule_mv_desc_set); 1424 mvpl = left->emms_mask_value_pairs.action; 1425 mvpr = right->emms_mask_value_pairs.action; 1426 break; 1427 default: 1428 rc = ENOTSUP; 1429 goto fail1; 1430 } 1431 1432 if (field_caps == NULL) { 1433 rc = EAGAIN; 1434 goto fail2; 1435 } 1436 1437 if (left->emms_type != right->emms_type || 1438 left->emms_prio != right->emms_prio) { 1439 /* 1440 * Rules of different types can never map to the same class. 1441 * 1442 * The FW can support some set of match criteria for one 1443 * priority and not support the very same set for 1444 * another priority. Thus, two rules which have 1445 * different priorities can never map to 1446 * the same class. 1447 */ 1448 *have_same_classp = B_FALSE; 1449 return (0); 1450 } 1451 1452 for (field_id = 0; (unsigned int)field_id < desc_set_nentries; 1453 ++field_id) { 1454 const efx_mae_mv_desc_t *descp = &desc_setp[field_id]; 1455 efx_mae_field_cap_id_t field_cap_id = descp->emmd_field_cap_id; 1456 const uint8_t *lmaskp = mvpl + descp->emmd_mask_offset; 1457 const uint8_t *rmaskp = mvpr + descp->emmd_mask_offset; 1458 size_t mask_size = descp->emmd_mask_size; 1459 const uint8_t *lvalp = mvpl + descp->emmd_value_offset; 1460 const uint8_t *rvalp = mvpr + descp->emmd_value_offset; 1461 size_t value_size = descp->emmd_value_size; 1462 1463 if (mask_size == 0) 1464 continue; /* Skip array gap */ 1465 1466 if ((unsigned int)field_cap_id >= field_ncaps) { 1467 /* 1468 * The FW has not reported capability status for this 1469 * field. It's unknown whether any difference between 1470 * the two masks / values affects the class. The only 1471 * case when the class must be the same is when these 1472 * mask-value pairs match. Otherwise, report mismatch. 1473 */ 1474 if ((memcmp(lmaskp, rmaskp, mask_size) == 0) && 1475 (memcmp(lvalp, rvalp, value_size) == 0)) 1476 continue; 1477 else 1478 break; 1479 } 1480 1481 if (field_caps[field_cap_id].emfc_mask_affects_class) { 1482 if (memcmp(lmaskp, rmaskp, mask_size) != 0) { 1483 have_same_class = B_FALSE; 1484 break; 1485 } 1486 } 1487 1488 if (field_caps[field_cap_id].emfc_match_affects_class) { 1489 if (memcmp(lvalp, rvalp, value_size) != 0) { 1490 have_same_class = B_FALSE; 1491 break; 1492 } 1493 } 1494 } 1495 1496 *have_same_classp = have_same_class; 1497 1498 return (0); 1499 1500 fail2: 1501 EFSYS_PROBE(fail2); 1502 fail1: 1503 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1504 return (rc); 1505 } 1506 1507 __checkReturn efx_rc_t 1508 efx_mae_outer_rule_insert( 1509 __in efx_nic_t *enp, 1510 __in const efx_mae_match_spec_t *spec, 1511 __in efx_tunnel_protocol_t encap_type, 1512 __out efx_mae_rule_id_t *or_idp) 1513 { 1514 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 1515 efx_mcdi_req_t req; 1516 EFX_MCDI_DECLARE_BUF(payload, 1517 MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2, 1518 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 1519 uint32_t encap_type_mcdi; 1520 efx_mae_rule_id_t or_id; 1521 size_t offset; 1522 efx_rc_t rc; 1523 1524 EFX_STATIC_ASSERT(sizeof (or_idp->id) == 1525 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OR_ID_LEN); 1526 1527 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 1528 MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL); 1529 1530 if (encp->enc_mae_supported == B_FALSE) { 1531 rc = ENOTSUP; 1532 goto fail1; 1533 } 1534 1535 if (spec->emms_type != EFX_MAE_RULE_OUTER) { 1536 rc = EINVAL; 1537 goto fail2; 1538 } 1539 1540 switch (encap_type) { 1541 case EFX_TUNNEL_PROTOCOL_NONE: 1542 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NONE; 1543 break; 1544 case EFX_TUNNEL_PROTOCOL_VXLAN: 1545 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_VXLAN; 1546 break; 1547 case EFX_TUNNEL_PROTOCOL_GENEVE: 1548 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_GENEVE; 1549 break; 1550 case EFX_TUNNEL_PROTOCOL_NVGRE: 1551 encap_type_mcdi = MAE_MCDI_ENCAP_TYPE_NVGRE; 1552 break; 1553 default: 1554 rc = ENOTSUP; 1555 goto fail3; 1556 } 1557 1558 req.emr_cmd = MC_CMD_MAE_OUTER_RULE_INSERT; 1559 req.emr_in_buf = payload; 1560 req.emr_in_length = MC_CMD_MAE_OUTER_RULE_INSERT_IN_LENMAX_MCDI2; 1561 req.emr_out_buf = payload; 1562 req.emr_out_length = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN; 1563 1564 MCDI_IN_SET_DWORD(req, 1565 MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, encap_type_mcdi); 1566 1567 MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_INSERT_IN_PRIO, spec->emms_prio); 1568 1569 /* 1570 * Mask-value pairs have been stored in the byte order needed for the 1571 * MCDI request and are thus safe to be copied directly to the buffer. 1572 * The library cares about byte order in efx_mae_match_spec_field_set(). 1573 */ 1574 EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.outer) >= 1575 MAE_ENC_FIELD_PAIRS_LEN); 1576 offset = MC_CMD_MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA_OFST; 1577 memcpy(payload + offset, spec->emms_mask_value_pairs.outer, 1578 MAE_ENC_FIELD_PAIRS_LEN); 1579 1580 efx_mcdi_execute(enp, &req); 1581 1582 if (req.emr_rc != 0) { 1583 rc = req.emr_rc; 1584 goto fail4; 1585 } 1586 1587 if (req.emr_out_length_used < MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN) { 1588 rc = EMSGSIZE; 1589 goto fail5; 1590 } 1591 1592 or_id.id = MCDI_OUT_DWORD(req, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 1593 if (or_id.id == EFX_MAE_RSRC_ID_INVALID) { 1594 rc = ENOENT; 1595 goto fail6; 1596 } 1597 1598 or_idp->id = or_id.id; 1599 1600 return (0); 1601 1602 fail6: 1603 EFSYS_PROBE(fail6); 1604 fail5: 1605 EFSYS_PROBE(fail5); 1606 fail4: 1607 EFSYS_PROBE(fail4); 1608 fail3: 1609 EFSYS_PROBE(fail3); 1610 fail2: 1611 EFSYS_PROBE(fail2); 1612 fail1: 1613 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1614 return (rc); 1615 } 1616 1617 __checkReturn efx_rc_t 1618 efx_mae_outer_rule_remove( 1619 __in efx_nic_t *enp, 1620 __in const efx_mae_rule_id_t *or_idp) 1621 { 1622 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 1623 efx_mcdi_req_t req; 1624 EFX_MCDI_DECLARE_BUF(payload, 1625 MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1), 1626 MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 1627 efx_rc_t rc; 1628 1629 if (encp->enc_mae_supported == B_FALSE) { 1630 rc = ENOTSUP; 1631 goto fail1; 1632 } 1633 1634 req.emr_cmd = MC_CMD_MAE_OUTER_RULE_REMOVE; 1635 req.emr_in_buf = payload; 1636 req.emr_in_length = MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1); 1637 req.emr_out_buf = payload; 1638 req.emr_out_length = MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1); 1639 1640 MCDI_IN_SET_DWORD(req, MAE_OUTER_RULE_REMOVE_IN_OR_ID, or_idp->id); 1641 1642 efx_mcdi_execute(enp, &req); 1643 1644 if (req.emr_rc != 0) { 1645 rc = req.emr_rc; 1646 goto fail2; 1647 } 1648 1649 if (MCDI_OUT_DWORD(req, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != 1650 or_idp->id) { 1651 /* Firmware failed to remove the outer rule. */ 1652 rc = EAGAIN; 1653 goto fail3; 1654 } 1655 1656 return (0); 1657 1658 fail3: 1659 EFSYS_PROBE(fail3); 1660 fail2: 1661 EFSYS_PROBE(fail2); 1662 fail1: 1663 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1664 return (rc); 1665 } 1666 1667 __checkReturn efx_rc_t 1668 efx_mae_match_spec_outer_rule_id_set( 1669 __in efx_mae_match_spec_t *spec, 1670 __in const efx_mae_rule_id_t *or_idp) 1671 { 1672 uint32_t full_mask = UINT32_MAX; 1673 efx_rc_t rc; 1674 1675 if (spec->emms_type != EFX_MAE_RULE_ACTION) { 1676 rc = EINVAL; 1677 goto fail1; 1678 } 1679 1680 if (or_idp == NULL) { 1681 rc = EINVAL; 1682 goto fail2; 1683 } 1684 1685 rc = efx_mae_match_spec_field_set(spec, EFX_MAE_FIELD_OUTER_RULE_ID, 1686 sizeof (or_idp->id), (const uint8_t *)&or_idp->id, 1687 sizeof (full_mask), (const uint8_t *)&full_mask); 1688 if (rc != 0) 1689 goto fail3; 1690 1691 return (0); 1692 1693 fail3: 1694 EFSYS_PROBE(fail3); 1695 fail2: 1696 EFSYS_PROBE(fail2); 1697 fail1: 1698 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1699 return (rc); 1700 } 1701 1702 __checkReturn efx_rc_t 1703 efx_mae_action_set_alloc( 1704 __in efx_nic_t *enp, 1705 __in const efx_mae_actions_t *spec, 1706 __out efx_mae_aset_id_t *aset_idp) 1707 { 1708 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 1709 efx_mcdi_req_t req; 1710 EFX_MCDI_DECLARE_BUF(payload, 1711 MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN, 1712 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 1713 efx_mae_aset_id_t aset_id; 1714 efx_rc_t rc; 1715 1716 if (encp->enc_mae_supported == B_FALSE) { 1717 rc = ENOTSUP; 1718 goto fail1; 1719 } 1720 1721 req.emr_cmd = MC_CMD_MAE_ACTION_SET_ALLOC; 1722 req.emr_in_buf = payload; 1723 req.emr_in_length = MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN; 1724 req.emr_out_buf = payload; 1725 req.emr_out_length = MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN; 1726 1727 /* 1728 * TODO: Remove these EFX_MAE_RSRC_ID_INVALID assignments once the 1729 * corresponding resource types are supported by the implementation. 1730 * Use proper resource ID assignments instead. 1731 */ 1732 MCDI_IN_SET_DWORD(req, 1733 MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, EFX_MAE_RSRC_ID_INVALID); 1734 MCDI_IN_SET_DWORD(req, 1735 MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID); 1736 MCDI_IN_SET_DWORD(req, 1737 MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, EFX_MAE_RSRC_ID_INVALID); 1738 1739 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 1740 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, spec->ema_n_vlan_tags_to_pop); 1741 1742 if (spec->ema_n_vlan_tags_to_push > 0) { 1743 unsigned int outer_tag_idx; 1744 1745 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 1746 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, 1747 spec->ema_n_vlan_tags_to_push); 1748 1749 if (spec->ema_n_vlan_tags_to_push == 1750 EFX_MAE_VLAN_PUSH_MAX_NTAGS) { 1751 MCDI_IN_SET_WORD(req, 1752 MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE, 1753 spec->ema_vlan_push_descs[0].emavp_tpid_be); 1754 MCDI_IN_SET_WORD(req, 1755 MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE, 1756 spec->ema_vlan_push_descs[0].emavp_tci_be); 1757 } 1758 1759 outer_tag_idx = spec->ema_n_vlan_tags_to_push - 1; 1760 1761 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE, 1762 spec->ema_vlan_push_descs[outer_tag_idx].emavp_tpid_be); 1763 MCDI_IN_SET_WORD(req, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE, 1764 spec->ema_vlan_push_descs[outer_tag_idx].emavp_tci_be); 1765 } 1766 1767 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_FLAG)) != 0) { 1768 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 1769 MAE_ACTION_SET_ALLOC_IN_FLAG, 1); 1770 } 1771 1772 if ((spec->ema_actions & (1U << EFX_MAE_ACTION_MARK)) != 0) { 1773 MCDI_IN_SET_DWORD_FIELD(req, MAE_ACTION_SET_ALLOC_IN_FLAGS, 1774 MAE_ACTION_SET_ALLOC_IN_MARK, 1); 1775 1776 MCDI_IN_SET_DWORD(req, 1777 MAE_ACTION_SET_ALLOC_IN_MARK_VALUE, spec->ema_mark_value); 1778 } 1779 1780 MCDI_IN_SET_DWORD(req, 1781 MAE_ACTION_SET_ALLOC_IN_DELIVER, spec->ema_deliver_mport.sel); 1782 1783 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 1784 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 1785 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 1786 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 1787 1788 efx_mcdi_execute(enp, &req); 1789 1790 if (req.emr_rc != 0) { 1791 rc = req.emr_rc; 1792 goto fail2; 1793 } 1794 1795 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN) { 1796 rc = EMSGSIZE; 1797 goto fail3; 1798 } 1799 1800 aset_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 1801 if (aset_id.id == EFX_MAE_RSRC_ID_INVALID) { 1802 rc = ENOENT; 1803 goto fail4; 1804 } 1805 1806 aset_idp->id = aset_id.id; 1807 1808 return (0); 1809 1810 fail4: 1811 EFSYS_PROBE(fail4); 1812 fail3: 1813 EFSYS_PROBE(fail3); 1814 fail2: 1815 EFSYS_PROBE(fail2); 1816 fail1: 1817 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1818 return (rc); 1819 } 1820 1821 __checkReturn efx_rc_t 1822 efx_mae_action_set_free( 1823 __in efx_nic_t *enp, 1824 __in const efx_mae_aset_id_t *aset_idp) 1825 { 1826 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 1827 efx_mcdi_req_t req; 1828 EFX_MCDI_DECLARE_BUF(payload, 1829 MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1), 1830 MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 1831 efx_rc_t rc; 1832 1833 if (encp->enc_mae_supported == B_FALSE) { 1834 rc = ENOTSUP; 1835 goto fail1; 1836 } 1837 1838 req.emr_cmd = MC_CMD_MAE_ACTION_SET_FREE; 1839 req.emr_in_buf = payload; 1840 req.emr_in_length = MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1); 1841 req.emr_out_buf = payload; 1842 req.emr_out_length = MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1); 1843 1844 MCDI_IN_SET_DWORD(req, MAE_ACTION_SET_FREE_IN_AS_ID, aset_idp->id); 1845 1846 efx_mcdi_execute(enp, &req); 1847 1848 if (req.emr_rc != 0) { 1849 rc = req.emr_rc; 1850 goto fail2; 1851 } 1852 1853 if (MCDI_OUT_DWORD(req, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != 1854 aset_idp->id) { 1855 /* Firmware failed to free the action set. */ 1856 rc = EAGAIN; 1857 goto fail3; 1858 } 1859 1860 return (0); 1861 1862 fail3: 1863 EFSYS_PROBE(fail3); 1864 fail2: 1865 EFSYS_PROBE(fail2); 1866 fail1: 1867 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1868 return (rc); 1869 } 1870 1871 __checkReturn efx_rc_t 1872 efx_mae_action_rule_insert( 1873 __in efx_nic_t *enp, 1874 __in const efx_mae_match_spec_t *spec, 1875 __in const efx_mae_aset_list_id_t *asl_idp, 1876 __in const efx_mae_aset_id_t *as_idp, 1877 __out efx_mae_rule_id_t *ar_idp) 1878 { 1879 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 1880 efx_mcdi_req_t req; 1881 EFX_MCDI_DECLARE_BUF(payload, 1882 MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2, 1883 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 1884 efx_oword_t *rule_response; 1885 efx_mae_rule_id_t ar_id; 1886 size_t offset; 1887 efx_rc_t rc; 1888 1889 EFX_STATIC_ASSERT(sizeof (ar_idp->id) == 1890 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_AR_ID_LEN); 1891 1892 EFX_STATIC_ASSERT(EFX_MAE_RSRC_ID_INVALID == 1893 MC_CMD_MAE_ACTION_RULE_INSERT_OUT_ACTION_RULE_ID_NULL); 1894 1895 if (encp->enc_mae_supported == B_FALSE) { 1896 rc = ENOTSUP; 1897 goto fail1; 1898 } 1899 1900 if (spec->emms_type != EFX_MAE_RULE_ACTION || 1901 (asl_idp != NULL && as_idp != NULL) || 1902 (asl_idp == NULL && as_idp == NULL)) { 1903 rc = EINVAL; 1904 goto fail2; 1905 } 1906 1907 req.emr_cmd = MC_CMD_MAE_ACTION_RULE_INSERT; 1908 req.emr_in_buf = payload; 1909 req.emr_in_length = MC_CMD_MAE_ACTION_RULE_INSERT_IN_LENMAX_MCDI2; 1910 req.emr_out_buf = payload; 1911 req.emr_out_length = MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN; 1912 1913 EFX_STATIC_ASSERT(sizeof (*rule_response) <= 1914 MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_LEN); 1915 offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_RESPONSE_OFST; 1916 rule_response = (efx_oword_t *)(payload + offset); 1917 EFX_POPULATE_OWORD_3(*rule_response, 1918 MAE_ACTION_RULE_RESPONSE_ASL_ID, 1919 (asl_idp != NULL) ? asl_idp->id : EFX_MAE_RSRC_ID_INVALID, 1920 MAE_ACTION_RULE_RESPONSE_AS_ID, 1921 (as_idp != NULL) ? as_idp->id : EFX_MAE_RSRC_ID_INVALID, 1922 MAE_ACTION_RULE_RESPONSE_COUNTER_ID, EFX_MAE_RSRC_ID_INVALID); 1923 1924 MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_INSERT_IN_PRIO, spec->emms_prio); 1925 1926 /* 1927 * Mask-value pairs have been stored in the byte order needed for the 1928 * MCDI request and are thus safe to be copied directly to the buffer. 1929 */ 1930 EFX_STATIC_ASSERT(sizeof (spec->emms_mask_value_pairs.action) >= 1931 MAE_FIELD_MASK_VALUE_PAIRS_LEN); 1932 offset = MC_CMD_MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA_OFST; 1933 memcpy(payload + offset, spec->emms_mask_value_pairs.action, 1934 MAE_FIELD_MASK_VALUE_PAIRS_LEN); 1935 1936 efx_mcdi_execute(enp, &req); 1937 1938 if (req.emr_rc != 0) { 1939 rc = req.emr_rc; 1940 goto fail3; 1941 } 1942 1943 if (req.emr_out_length_used < MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN) { 1944 rc = EMSGSIZE; 1945 goto fail4; 1946 } 1947 1948 ar_id.id = MCDI_OUT_DWORD(req, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 1949 if (ar_id.id == EFX_MAE_RSRC_ID_INVALID) { 1950 rc = ENOENT; 1951 goto fail5; 1952 } 1953 1954 ar_idp->id = ar_id.id; 1955 1956 return (0); 1957 1958 fail5: 1959 EFSYS_PROBE(fail5); 1960 fail4: 1961 EFSYS_PROBE(fail4); 1962 fail3: 1963 EFSYS_PROBE(fail3); 1964 fail2: 1965 EFSYS_PROBE(fail2); 1966 fail1: 1967 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1968 return (rc); 1969 } 1970 1971 __checkReturn efx_rc_t 1972 efx_mae_action_rule_remove( 1973 __in efx_nic_t *enp, 1974 __in const efx_mae_rule_id_t *ar_idp) 1975 { 1976 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 1977 efx_mcdi_req_t req; 1978 EFX_MCDI_DECLARE_BUF(payload, 1979 MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1), 1980 MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 1981 efx_rc_t rc; 1982 1983 if (encp->enc_mae_supported == B_FALSE) { 1984 rc = ENOTSUP; 1985 goto fail1; 1986 } 1987 1988 req.emr_cmd = MC_CMD_MAE_ACTION_RULE_DELETE; 1989 req.emr_in_buf = payload; 1990 req.emr_in_length = MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1); 1991 req.emr_out_buf = payload; 1992 req.emr_out_length = MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1); 1993 1994 MCDI_IN_SET_DWORD(req, MAE_ACTION_RULE_DELETE_IN_AR_ID, ar_idp->id); 1995 1996 efx_mcdi_execute(enp, &req); 1997 1998 if (req.emr_rc != 0) { 1999 rc = req.emr_rc; 2000 goto fail2; 2001 } 2002 2003 if (MCDI_OUT_DWORD(req, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != 2004 ar_idp->id) { 2005 /* Firmware failed to delete the action rule. */ 2006 rc = EAGAIN; 2007 goto fail3; 2008 } 2009 2010 return (0); 2011 2012 fail3: 2013 EFSYS_PROBE(fail3); 2014 fail2: 2015 EFSYS_PROBE(fail2); 2016 fail1: 2017 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2018 return (rc); 2019 } 2020 2021 #endif /* EFSYS_OPT_MAE */ 2022