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