1 // SPDX-License-Identifier: GPL-2.0-only 2 /**************************************************************************** 3 * Driver for Solarflare network controllers and boards 4 * Copyright 2019 Solarflare Communications Inc. 5 * Copyright 2020-2022 Xilinx Inc. 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published 9 * by the Free Software Foundation, incorporated herein by reference. 10 */ 11 12 #include <linux/rhashtable.h> 13 #include "ef100_nic.h" 14 #include "mae.h" 15 #include "mcdi.h" 16 #include "mcdi_pcol.h" 17 #include "mcdi_pcol_mae.h" 18 19 int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label) 20 { 21 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN); 22 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN); 23 size_t outlen; 24 int rc; 25 26 if (WARN_ON_ONCE(!id)) 27 return -EINVAL; 28 if (WARN_ON_ONCE(!label)) 29 return -EINVAL; 30 31 MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_TYPE, 32 MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_MPORT_TYPE_ALIAS); 33 MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT, 34 MAE_MPORT_SELECTOR_ASSIGNED); 35 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_ALLOC, inbuf, sizeof(inbuf), 36 outbuf, sizeof(outbuf), &outlen); 37 if (rc) 38 return rc; 39 if (outlen < sizeof(outbuf)) 40 return -EIO; 41 *id = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_MPORT_ID); 42 *label = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL); 43 return 0; 44 } 45 46 int efx_mae_free_mport(struct efx_nic *efx, u32 id) 47 { 48 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_FREE_IN_LEN); 49 50 BUILD_BUG_ON(MC_CMD_MAE_MPORT_FREE_OUT_LEN); 51 MCDI_SET_DWORD(inbuf, MAE_MPORT_FREE_IN_MPORT_ID, id); 52 return efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_FREE, inbuf, sizeof(inbuf), 53 NULL, 0, NULL); 54 } 55 56 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out) 57 { 58 efx_dword_t mport; 59 60 EFX_POPULATE_DWORD_2(mport, 61 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT, 62 MAE_MPORT_SELECTOR_PPORT_ID, efx->port_num); 63 *out = EFX_DWORD_VAL(mport); 64 } 65 66 void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out) 67 { 68 efx_dword_t mport; 69 70 EFX_POPULATE_DWORD_3(mport, 71 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC, 72 MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER, 73 MAE_MPORT_SELECTOR_FUNC_VF_ID, MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL); 74 *out = EFX_DWORD_VAL(mport); 75 } 76 77 void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out) 78 { 79 efx_dword_t mport; 80 81 EFX_POPULATE_DWORD_3(mport, 82 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC, 83 MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER, 84 MAE_MPORT_SELECTOR_FUNC_VF_ID, vf_id); 85 *out = EFX_DWORD_VAL(mport); 86 } 87 88 /* Constructs an mport selector from an mport ID, because they're not the same */ 89 void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out) 90 { 91 efx_dword_t mport; 92 93 EFX_POPULATE_DWORD_2(mport, 94 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID, 95 MAE_MPORT_SELECTOR_MPORT_ID, mport_id); 96 *out = EFX_DWORD_VAL(mport); 97 } 98 99 /* id is really only 24 bits wide */ 100 int efx_mae_fw_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id) 101 { 102 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN); 103 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_LOOKUP_IN_LEN); 104 size_t outlen; 105 int rc; 106 107 MCDI_SET_DWORD(inbuf, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR, selector); 108 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_LOOKUP, inbuf, sizeof(inbuf), 109 outbuf, sizeof(outbuf), &outlen); 110 if (rc) 111 return rc; 112 if (outlen < sizeof(outbuf)) 113 return -EIO; 114 *id = MCDI_DWORD(outbuf, MAE_MPORT_LOOKUP_OUT_MPORT_ID); 115 return 0; 116 } 117 118 int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue) 119 { 120 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_START_V2_IN_LEN); 121 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN); 122 u32 out_flags; 123 size_t outlen; 124 int rc; 125 126 MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_QID, 127 efx_rx_queue_index(rx_queue)); 128 MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_PACKET_SIZE, 129 efx->net_dev->mtu); 130 MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_COUNTER_TYPES_MASK, 131 BIT(MAE_COUNTER_TYPE_AR) | BIT(MAE_COUNTER_TYPE_CT) | 132 BIT(MAE_COUNTER_TYPE_OR)); 133 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_START, 134 inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 135 if (rc) 136 return rc; 137 if (outlen < sizeof(outbuf)) 138 return -EIO; 139 out_flags = MCDI_DWORD(outbuf, MAE_COUNTERS_STREAM_START_OUT_FLAGS); 140 if (out_flags & BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST)) { 141 netif_dbg(efx, drv, efx->net_dev, 142 "MAE counter stream uses credits\n"); 143 rx_queue->grant_credits = true; 144 out_flags &= ~BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST); 145 } 146 if (out_flags) { 147 netif_err(efx, drv, efx->net_dev, 148 "MAE counter stream start: unrecognised flags %x\n", 149 out_flags); 150 goto out_stop; 151 } 152 return 0; 153 out_stop: 154 efx_mae_stop_counters(efx, rx_queue); 155 return -EOPNOTSUPP; 156 } 157 158 static bool efx_mae_counters_flushed(u32 *flush_gen, u32 *seen_gen) 159 { 160 int i; 161 162 for (i = 0; i < EFX_TC_COUNTER_TYPE_MAX; i++) 163 if ((s32)(flush_gen[i] - seen_gen[i]) > 0) 164 return false; 165 return true; 166 } 167 168 int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue) 169 { 170 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_V2_OUT_LENMAX); 171 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN); 172 size_t outlen; 173 int rc, i; 174 175 MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_STOP_IN_QID, 176 efx_rx_queue_index(rx_queue)); 177 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_STOP, 178 inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 179 180 if (rc) 181 return rc; 182 183 netif_dbg(efx, drv, efx->net_dev, "Draining counters:\n"); 184 /* Only process received generation counts */ 185 for (i = 0; (i < (outlen / 4)) && (i < EFX_TC_COUNTER_TYPE_MAX); i++) { 186 efx->tc->flush_gen[i] = MCDI_ARRAY_DWORD(outbuf, 187 MAE_COUNTERS_STREAM_STOP_V2_OUT_GENERATION_COUNT, 188 i); 189 netif_dbg(efx, drv, efx->net_dev, 190 "\ttype %u, awaiting gen %u\n", i, 191 efx->tc->flush_gen[i]); 192 } 193 194 efx->tc->flush_counters = true; 195 196 /* Drain can take up to 2 seconds owing to FWRIVERHD-2884; whatever 197 * timeout we use, that delay is added to unload on nonresponsive 198 * hardware, so 2500ms seems like a reasonable compromise. 199 */ 200 if (!wait_event_timeout(efx->tc->flush_wq, 201 efx_mae_counters_flushed(efx->tc->flush_gen, 202 efx->tc->seen_gen), 203 msecs_to_jiffies(2500))) 204 netif_warn(efx, drv, efx->net_dev, 205 "Failed to drain counters RXQ, FW may be unhappy\n"); 206 207 efx->tc->flush_counters = false; 208 209 return rc; 210 } 211 212 void efx_mae_counters_grant_credits(struct work_struct *work) 213 { 214 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN); 215 struct efx_rx_queue *rx_queue = container_of(work, struct efx_rx_queue, 216 grant_work); 217 struct efx_nic *efx = rx_queue->efx; 218 unsigned int credits; 219 220 BUILD_BUG_ON(MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN); 221 credits = READ_ONCE(rx_queue->notified_count) - rx_queue->granted_count; 222 MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS, 223 credits); 224 if (!efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS, 225 inbuf, sizeof(inbuf), NULL, 0, NULL)) 226 rx_queue->granted_count += credits; 227 } 228 229 static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps) 230 { 231 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN); 232 size_t outlen; 233 int rc; 234 235 BUILD_BUG_ON(MC_CMD_MAE_GET_CAPS_IN_LEN); 236 237 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_GET_CAPS, NULL, 0, outbuf, 238 sizeof(outbuf), &outlen); 239 if (rc) 240 return rc; 241 if (outlen < sizeof(outbuf)) 242 return -EIO; 243 caps->match_field_count = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT); 244 caps->encap_types = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED); 245 caps->action_prios = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ACTION_PRIOS); 246 return 0; 247 } 248 249 static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd, 250 u8 *field_support) 251 { 252 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS)); 253 MCDI_DECLARE_STRUCT_PTR(caps); 254 unsigned int count; 255 size_t outlen; 256 int rc, i; 257 258 /* AR and OR caps MCDIs have identical layout, so we are using the 259 * same code for both. 260 */ 261 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS) < 262 MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(MAE_NUM_FIELDS)); 263 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN); 264 BUILD_BUG_ON(MC_CMD_MAE_GET_OR_CAPS_IN_LEN); 265 266 rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen); 267 if (rc) 268 return rc; 269 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_COUNT_OFST != 270 MC_CMD_MAE_GET_OR_CAPS_OUT_COUNT_OFST); 271 count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT); 272 memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS); 273 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST != 274 MC_CMD_MAE_GET_OR_CAPS_OUT_FIELD_FLAGS_OFST); 275 caps = _MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS); 276 /* We're only interested in the support status enum, not any other 277 * flags, so just extract that from each entry. 278 */ 279 for (i = 0; i < count; i++) 280 if (i * sizeof(*outbuf) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen) 281 field_support[i] = EFX_DWORD_FIELD(caps[i], MAE_FIELD_FLAGS_SUPPORT_STATUS); 282 return 0; 283 } 284 285 int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps) 286 { 287 int rc; 288 289 rc = efx_mae_get_basic_caps(efx, caps); 290 if (rc) 291 return rc; 292 rc = efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS, 293 caps->action_rule_fields); 294 if (rc) 295 return rc; 296 return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_OR_CAPS, 297 caps->outer_rule_fields); 298 } 299 300 /* Bit twiddling: 301 * Prefix: 1...110...0 302 * ~: 0...001...1 303 * + 1: 0...010...0 is power of two 304 * so (~x) & ((~x) + 1) == 0. Converse holds also. 305 */ 306 #define is_prefix_byte(_x) !(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1)) 307 308 enum mask_type { MASK_ONES, MASK_ZEROES, MASK_PREFIX, MASK_OTHER }; 309 310 static const char *mask_type_name(enum mask_type typ) 311 { 312 switch (typ) { 313 case MASK_ONES: 314 return "all-1s"; 315 case MASK_ZEROES: 316 return "all-0s"; 317 case MASK_PREFIX: 318 return "prefix"; 319 case MASK_OTHER: 320 return "arbitrary"; 321 default: /* can't happen */ 322 return "unknown"; 323 } 324 } 325 326 /* Checks a (big-endian) bytestring is a bit prefix */ 327 static enum mask_type classify_mask(const u8 *mask, size_t len) 328 { 329 bool zeroes = true; /* All bits seen so far are zeroes */ 330 bool ones = true; /* All bits seen so far are ones */ 331 bool prefix = true; /* Valid prefix so far */ 332 size_t i; 333 334 for (i = 0; i < len; i++) { 335 if (ones) { 336 if (!is_prefix_byte(mask[i])) 337 prefix = false; 338 } else if (mask[i]) { 339 prefix = false; 340 } 341 if (mask[i] != 0xff) 342 ones = false; 343 if (mask[i]) 344 zeroes = false; 345 } 346 if (ones) 347 return MASK_ONES; 348 if (zeroes) 349 return MASK_ZEROES; 350 if (prefix) 351 return MASK_PREFIX; 352 return MASK_OTHER; 353 } 354 355 static int efx_mae_match_check_cap_typ(u8 support, enum mask_type typ) 356 { 357 switch (support) { 358 case MAE_FIELD_UNSUPPORTED: 359 case MAE_FIELD_SUPPORTED_MATCH_NEVER: 360 if (typ == MASK_ZEROES) 361 return 0; 362 return -EOPNOTSUPP; 363 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL: 364 if (typ == MASK_ZEROES) 365 return 0; 366 fallthrough; 367 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: 368 if (typ == MASK_ONES) 369 return 0; 370 return -EINVAL; 371 case MAE_FIELD_SUPPORTED_MATCH_PREFIX: 372 if (typ == MASK_OTHER) 373 return -EOPNOTSUPP; 374 return 0; 375 case MAE_FIELD_SUPPORTED_MATCH_MASK: 376 return 0; 377 default: 378 return -EIO; 379 } 380 } 381 382 /* Validate field mask against hardware capabilities. Captures caller's 'rc' */ 383 #define CHECK(_mcdi, _field) ({ \ 384 enum mask_type typ = classify_mask((const u8 *)&mask->_field, \ 385 sizeof(mask->_field)); \ 386 \ 387 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 388 typ); \ 389 if (rc) \ 390 NL_SET_ERR_MSG_FMT_MOD(extack, \ 391 "No support for %s mask in field %s", \ 392 mask_type_name(typ), #_field); \ 393 rc; \ 394 }) 395 /* Booleans need special handling */ 396 #define CHECK_BIT(_mcdi, _field) ({ \ 397 enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES; \ 398 \ 399 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 400 typ); \ 401 if (rc) \ 402 NL_SET_ERR_MSG_FMT_MOD(extack, \ 403 "No support for %s mask in field %s", \ 404 mask_type_name(typ), #_field); \ 405 rc; \ 406 }) 407 408 int efx_mae_match_check_caps(struct efx_nic *efx, 409 const struct efx_tc_match_fields *mask, 410 struct netlink_ext_ack *extack) 411 { 412 const u8 *supported_fields = efx->tc->caps->action_rule_fields; 413 __be32 ingress_port = cpu_to_be32(mask->ingress_port); 414 enum mask_type ingress_port_mask_type; 415 int rc; 416 417 /* Check for _PREFIX assumes big-endian, so we need to convert */ 418 ingress_port_mask_type = classify_mask((const u8 *)&ingress_port, 419 sizeof(ingress_port)); 420 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT], 421 ingress_port_mask_type); 422 if (rc) { 423 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field ingress_port", 424 mask_type_name(ingress_port_mask_type)); 425 return rc; 426 } 427 if (CHECK(ETHER_TYPE, eth_proto) || 428 CHECK(VLAN0_TCI, vlan_tci[0]) || 429 CHECK(VLAN0_PROTO, vlan_proto[0]) || 430 CHECK(VLAN1_TCI, vlan_tci[1]) || 431 CHECK(VLAN1_PROTO, vlan_proto[1]) || 432 CHECK(ETH_SADDR, eth_saddr) || 433 CHECK(ETH_DADDR, eth_daddr) || 434 CHECK(IP_PROTO, ip_proto) || 435 CHECK(IP_TOS, ip_tos) || 436 CHECK(IP_TTL, ip_ttl) || 437 CHECK(SRC_IP4, src_ip) || 438 CHECK(DST_IP4, dst_ip) || 439 #ifdef CONFIG_IPV6 440 CHECK(SRC_IP6, src_ip6) || 441 CHECK(DST_IP6, dst_ip6) || 442 #endif 443 CHECK(L4_SPORT, l4_sport) || 444 CHECK(L4_DPORT, l4_dport) || 445 CHECK(TCP_FLAGS, tcp_flags) || 446 CHECK_BIT(IS_IP_FRAG, ip_frag) || 447 CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) || 448 CHECK(RECIRC_ID, recirc_id)) 449 return rc; 450 /* Matches on outer fields are done in a separate hardware table, 451 * the Outer Rule table. Thus the Action Rule merely does an 452 * exact match on Outer Rule ID if any outer field matches are 453 * present. The exception is the VNI/VSID (enc_keyid), which is 454 * available to the Action Rule match iff the Outer Rule matched 455 * (and thus identified the encap protocol to use to extract it). 456 */ 457 if (efx_tc_match_is_encap(mask)) { 458 rc = efx_mae_match_check_cap_typ( 459 supported_fields[MAE_FIELD_OUTER_RULE_ID], 460 MASK_ONES); 461 if (rc) { 462 NL_SET_ERR_MSG_MOD(extack, "No support for encap rule ID matches"); 463 return rc; 464 } 465 if (CHECK(ENC_VNET_ID, enc_keyid)) 466 return rc; 467 } else if (mask->enc_keyid) { 468 NL_SET_ERR_MSG_MOD(extack, "Match on enc_keyid requires other encap fields"); 469 return -EINVAL; 470 } 471 return 0; 472 } 473 #undef CHECK_BIT 474 #undef CHECK 475 476 #define CHECK(_mcdi) ({ \ 477 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 478 MASK_ONES); \ 479 if (rc) \ 480 NL_SET_ERR_MSG_FMT_MOD(extack, \ 481 "No support for field %s", #_mcdi); \ 482 rc; \ 483 }) 484 /* Checks that the fields needed for encap-rule matches are supported by the 485 * MAE. All the fields are exact-match, except possibly ENC_IP_TOS. 486 */ 487 int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, 488 u8 ip_tos_mask, __be16 udp_sport_mask, 489 struct netlink_ext_ack *extack) 490 { 491 u8 *supported_fields = efx->tc->caps->outer_rule_fields; 492 enum mask_type typ; 493 int rc; 494 495 if (CHECK(ENC_ETHER_TYPE)) 496 return rc; 497 if (ipv6) { 498 if (CHECK(ENC_SRC_IP6) || 499 CHECK(ENC_DST_IP6)) 500 return rc; 501 } else { 502 if (CHECK(ENC_SRC_IP4) || 503 CHECK(ENC_DST_IP4)) 504 return rc; 505 } 506 if (CHECK(ENC_L4_DPORT) || 507 CHECK(ENC_IP_PROTO)) 508 return rc; 509 typ = classify_mask((const u8 *)&udp_sport_mask, sizeof(udp_sport_mask)); 510 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_L4_SPORT], 511 typ); 512 if (rc) { 513 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s", 514 mask_type_name(typ), "enc_src_port"); 515 return rc; 516 } 517 typ = classify_mask(&ip_tos_mask, sizeof(ip_tos_mask)); 518 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_IP_TOS], 519 typ); 520 if (rc) { 521 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s", 522 mask_type_name(typ), "enc_ip_tos"); 523 return rc; 524 } 525 return 0; 526 } 527 #undef CHECK 528 529 int efx_mae_check_encap_type_supported(struct efx_nic *efx, enum efx_encap_type typ) 530 { 531 unsigned int bit; 532 533 switch (typ & EFX_ENCAP_TYPES_MASK) { 534 case EFX_ENCAP_TYPE_VXLAN: 535 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN_LBN; 536 break; 537 case EFX_ENCAP_TYPE_GENEVE: 538 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE_LBN; 539 break; 540 default: 541 return -EOPNOTSUPP; 542 } 543 if (efx->tc->caps->encap_types & BIT(bit)) 544 return 0; 545 return -EOPNOTSUPP; 546 } 547 548 int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt) 549 { 550 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1)); 551 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN); 552 size_t outlen; 553 int rc; 554 555 if (!cnt) 556 return -EINVAL; 557 558 MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT, 1); 559 MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE, cnt->type); 560 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_ALLOC, inbuf, sizeof(inbuf), 561 outbuf, sizeof(outbuf), &outlen); 562 if (rc) 563 return rc; 564 /* pcol says this can't happen, since count is 1 */ 565 if (outlen < sizeof(outbuf)) 566 return -EIO; 567 cnt->fw_id = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_COUNTER_ID); 568 cnt->gen = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT); 569 return 0; 570 } 571 572 int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt) 573 { 574 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_FREE_OUT_LEN(1)); 575 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN); 576 size_t outlen; 577 int rc; 578 579 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT, 1); 580 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID, cnt->fw_id); 581 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE, cnt->type); 582 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_FREE, inbuf, sizeof(inbuf), 583 outbuf, sizeof(outbuf), &outlen); 584 if (rc) 585 return rc; 586 /* pcol says this can't happen, since count is 1 */ 587 if (outlen < sizeof(outbuf)) 588 return -EIO; 589 /* FW freed a different ID than we asked for, should also never happen. 590 * Warn because it means we've now got a different idea to the FW of 591 * what counters exist, which could cause mayhem later. 592 */ 593 if (WARN_ON(MCDI_DWORD(outbuf, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID) != 594 cnt->fw_id)) 595 return -EIO; 596 return 0; 597 } 598 599 static int efx_mae_encap_type_to_mae_type(enum efx_encap_type type) 600 { 601 switch (type & EFX_ENCAP_TYPES_MASK) { 602 case EFX_ENCAP_TYPE_NONE: 603 return MAE_MCDI_ENCAP_TYPE_NONE; 604 case EFX_ENCAP_TYPE_VXLAN: 605 return MAE_MCDI_ENCAP_TYPE_VXLAN; 606 case EFX_ENCAP_TYPE_GENEVE: 607 return MAE_MCDI_ENCAP_TYPE_GENEVE; 608 default: 609 return -EOPNOTSUPP; 610 } 611 } 612 613 int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id) 614 { 615 struct ef100_nic_data *nic_data = efx->nic_data; 616 struct efx_mae *mae = efx->mae; 617 struct rhashtable_iter walk; 618 struct mae_mport_desc *m; 619 int rc = -ENOENT; 620 621 rhashtable_walk_enter(&mae->mports_ht, &walk); 622 rhashtable_walk_start(&walk); 623 while ((m = rhashtable_walk_next(&walk)) != NULL) { 624 if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC && 625 m->interface_idx == nic_data->local_mae_intf && 626 m->pf_idx == 0 && 627 m->vf_idx == vf_idx) { 628 *id = m->mport_id; 629 rc = 0; 630 break; 631 } 632 } 633 rhashtable_walk_stop(&walk); 634 rhashtable_walk_exit(&walk); 635 return rc; 636 } 637 638 static bool efx_mae_asl_id(u32 id) 639 { 640 return !!(id & BIT(31)); 641 } 642 643 /* mport handling */ 644 static const struct rhashtable_params efx_mae_mports_ht_params = { 645 .key_len = sizeof(u32), 646 .key_offset = offsetof(struct mae_mport_desc, mport_id), 647 .head_offset = offsetof(struct mae_mport_desc, linkage), 648 }; 649 650 struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id) 651 { 652 return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id, 653 efx_mae_mports_ht_params); 654 } 655 656 static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc) 657 { 658 struct efx_mae *mae = efx->mae; 659 int rc; 660 661 rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage, 662 efx_mae_mports_ht_params); 663 664 if (rc) { 665 pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n", 666 desc->mport_id, rc); 667 kfree(desc); 668 return rc; 669 } 670 671 return rc; 672 } 673 674 void efx_mae_remove_mport(void *desc, void *arg) 675 { 676 struct mae_mport_desc *mport = desc; 677 678 synchronize_rcu(); 679 kfree(mport); 680 } 681 682 static int efx_mae_process_mport(struct efx_nic *efx, 683 struct mae_mport_desc *desc) 684 { 685 struct ef100_nic_data *nic_data = efx->nic_data; 686 struct mae_mport_desc *mport; 687 688 mport = efx_mae_get_mport(efx, desc->mport_id); 689 if (!IS_ERR_OR_NULL(mport)) { 690 netif_err(efx, drv, efx->net_dev, 691 "mport with id %u does exist!!!\n", desc->mport_id); 692 return -EEXIST; 693 } 694 695 if (nic_data->have_own_mport && 696 desc->mport_id == nic_data->own_mport) { 697 WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC); 698 WARN_ON(desc->vnic_client_type != 699 MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION); 700 nic_data->local_mae_intf = desc->interface_idx; 701 nic_data->have_local_intf = true; 702 pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n", 703 nic_data->local_mae_intf); 704 } 705 706 return efx_mae_add_mport(efx, desc); 707 } 708 709 #define MCDI_MPORT_JOURNAL_LEN \ 710 ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4) 711 712 int efx_mae_enumerate_mports(struct efx_nic *efx) 713 { 714 efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL); 715 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN); 716 MCDI_DECLARE_STRUCT_PTR(desc); 717 size_t outlen, stride, count; 718 int rc = 0, i; 719 720 if (!outbuf) 721 return -ENOMEM; 722 do { 723 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf, 724 sizeof(inbuf), outbuf, 725 MCDI_MPORT_JOURNAL_LEN, &outlen); 726 if (rc) 727 goto fail; 728 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) { 729 rc = -EIO; 730 goto fail; 731 } 732 count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT); 733 if (!count) 734 continue; /* not break; we want to look at MORE flag */ 735 stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC); 736 if (stride < MAE_MPORT_DESC_LEN) { 737 rc = -EIO; 738 goto fail; 739 } 740 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) { 741 rc = -EIO; 742 goto fail; 743 } 744 745 for (i = 0; i < count; i++) { 746 struct mae_mport_desc *d; 747 748 d = kzalloc(sizeof(*d), GFP_KERNEL); 749 if (!d) { 750 rc = -ENOMEM; 751 goto fail; 752 } 753 754 desc = (efx_dword_t *) 755 _MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST + 756 i * stride); 757 d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID); 758 d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS); 759 d->caller_flags = MCDI_STRUCT_DWORD(desc, 760 MAE_MPORT_DESC_CALLER_FLAGS); 761 d->mport_type = MCDI_STRUCT_DWORD(desc, 762 MAE_MPORT_DESC_MPORT_TYPE); 763 switch (d->mport_type) { 764 case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT: 765 d->port_idx = MCDI_STRUCT_DWORD(desc, 766 MAE_MPORT_DESC_NET_PORT_IDX); 767 break; 768 case MAE_MPORT_DESC_MPORT_TYPE_ALIAS: 769 d->alias_mport_id = MCDI_STRUCT_DWORD(desc, 770 MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID); 771 break; 772 case MAE_MPORT_DESC_MPORT_TYPE_VNIC: 773 d->vnic_client_type = MCDI_STRUCT_DWORD(desc, 774 MAE_MPORT_DESC_VNIC_CLIENT_TYPE); 775 d->interface_idx = MCDI_STRUCT_DWORD(desc, 776 MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE); 777 d->pf_idx = MCDI_STRUCT_WORD(desc, 778 MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX); 779 d->vf_idx = MCDI_STRUCT_WORD(desc, 780 MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX); 781 break; 782 default: 783 /* Unknown mport_type, just accept it */ 784 break; 785 } 786 rc = efx_mae_process_mport(efx, d); 787 /* Any failure will be due to memory allocation faiure, 788 * so there is no point to try subsequent entries. 789 */ 790 if (rc) 791 goto fail; 792 } 793 } while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) && 794 !WARN_ON(!count)); 795 fail: 796 kfree(outbuf); 797 return rc; 798 } 799 800 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) 801 { 802 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 803 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN); 804 size_t outlen; 805 int rc; 806 807 MCDI_POPULATE_DWORD_3(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS, 808 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, act->vlan_push, 809 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop, 810 MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap); 811 812 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 813 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 814 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 815 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 816 if (act->count && !WARN_ON(!act->count->cnt)) 817 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 818 act->count->cnt->fw_id); 819 else 820 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 821 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 822 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, 823 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL); 824 if (act->vlan_push) { 825 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE, 826 act->vlan_tci[0]); 827 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE, 828 act->vlan_proto[0]); 829 } 830 if (act->vlan_push >= 2) { 831 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE, 832 act->vlan_tci[1]); 833 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE, 834 act->vlan_proto[1]); 835 } 836 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 837 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); 838 if (act->deliver) 839 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER, 840 act->dest_mport); 841 BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL); 842 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf), 843 outbuf, sizeof(outbuf), &outlen); 844 if (rc) 845 return rc; 846 if (outlen < sizeof(outbuf)) 847 return -EIO; 848 act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 849 /* We rely on the high bit of AS IDs always being clear. 850 * The firmware API guarantees this, but let's check it ourselves. 851 */ 852 if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) { 853 efx_mae_free_action_set(efx, act->fw_id); 854 return -EIO; 855 } 856 return 0; 857 } 858 859 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id) 860 { 861 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 862 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1)); 863 size_t outlen; 864 int rc; 865 866 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id); 867 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf), 868 outbuf, sizeof(outbuf), &outlen); 869 if (rc) 870 return rc; 871 if (outlen < sizeof(outbuf)) 872 return -EIO; 873 /* FW freed a different ID than we asked for, should never happen. 874 * Warn because it means we've now got a different idea to the FW of 875 * what action-sets exist, which could cause mayhem later. 876 */ 877 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id)) 878 return -EIO; 879 return 0; 880 } 881 882 int efx_mae_alloc_action_set_list(struct efx_nic *efx, 883 struct efx_tc_action_set_list *acts) 884 { 885 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN); 886 struct efx_tc_action_set *act; 887 size_t inlen, outlen, i = 0; 888 efx_dword_t *inbuf; 889 int rc; 890 891 list_for_each_entry(act, &acts->list, list) 892 i++; 893 if (i == 0) 894 return -EINVAL; 895 if (i == 1) { 896 /* Don't wrap an ASL around a single AS, just use the AS_ID 897 * directly. ASLs are a more limited resource. 898 */ 899 act = list_first_entry(&acts->list, struct efx_tc_action_set, list); 900 acts->fw_id = act->fw_id; 901 return 0; 902 } 903 if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2) 904 return -EOPNOTSUPP; /* Too many actions */ 905 inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i); 906 inbuf = kzalloc(inlen, GFP_KERNEL); 907 if (!inbuf) 908 return -ENOMEM; 909 i = 0; 910 list_for_each_entry(act, &acts->list, list) { 911 MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS, 912 i, act->fw_id); 913 i++; 914 } 915 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i); 916 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen, 917 outbuf, sizeof(outbuf), &outlen); 918 if (rc) 919 goto out_free; 920 if (outlen < sizeof(outbuf)) { 921 rc = -EIO; 922 goto out_free; 923 } 924 acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID); 925 /* We rely on the high bit of ASL IDs always being set. 926 * The firmware API guarantees this, but let's check it ourselves. 927 */ 928 if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) { 929 efx_mae_free_action_set_list(efx, acts); 930 rc = -EIO; 931 } 932 out_free: 933 kfree(inbuf); 934 return rc; 935 } 936 937 int efx_mae_free_action_set_list(struct efx_nic *efx, 938 struct efx_tc_action_set_list *acts) 939 { 940 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1)); 941 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1)); 942 size_t outlen; 943 int rc; 944 945 /* If this is just an AS_ID with no ASL wrapper, then there is 946 * nothing for us to free. (The AS will be freed later.) 947 */ 948 if (efx_mae_asl_id(acts->fw_id)) { 949 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID, 950 acts->fw_id); 951 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf, 952 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 953 if (rc) 954 return rc; 955 if (outlen < sizeof(outbuf)) 956 return -EIO; 957 /* FW freed a different ID than we asked for, should never happen. 958 * Warn because it means we've now got a different idea to the FW of 959 * what action-set-lists exist, which could cause mayhem later. 960 */ 961 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id)) 962 return -EIO; 963 } 964 /* We're probably about to free @acts, but let's just make sure its 965 * fw_id is blatted so that it won't look valid if it leaks out. 966 */ 967 acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL; 968 return 0; 969 } 970 971 int efx_mae_register_encap_match(struct efx_nic *efx, 972 struct efx_tc_encap_match *encap) 973 { 974 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN)); 975 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 976 MCDI_DECLARE_STRUCT_PTR(match_crit); 977 size_t outlen; 978 int rc; 979 980 rc = efx_mae_encap_type_to_mae_type(encap->tun_type); 981 if (rc < 0) 982 return rc; 983 match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA); 984 /* The struct contains IP src and dst, and udp dport. 985 * So we actually need to filter on IP src and dst, L4 dport, and 986 * ipproto == udp. 987 */ 988 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, rc); 989 #ifdef CONFIG_IPV6 990 if (encap->src_ip | encap->dst_ip) { 991 #endif 992 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE, 993 encap->src_ip); 994 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK, 995 ~(__be32)0); 996 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE, 997 encap->dst_ip); 998 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK, 999 ~(__be32)0); 1000 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 1001 htons(ETH_P_IP)); 1002 #ifdef CONFIG_IPV6 1003 } else { 1004 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE), 1005 &encap->src_ip6, sizeof(encap->src_ip6)); 1006 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK), 1007 0xff, sizeof(encap->src_ip6)); 1008 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE), 1009 &encap->dst_ip6, sizeof(encap->dst_ip6)); 1010 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK), 1011 0xff, sizeof(encap->dst_ip6)); 1012 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 1013 htons(ETH_P_IPV6)); 1014 } 1015 #endif 1016 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK, 1017 ~(__be16)0); 1018 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1019 encap->udp_dport); 1020 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1021 ~(__be16)0); 1022 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1023 encap->udp_sport); 1024 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1025 encap->udp_sport_mask); 1026 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, IPPROTO_UDP); 1027 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, ~0); 1028 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS, 1029 encap->ip_tos); 1030 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK, 1031 encap->ip_tos_mask); 1032 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf, 1033 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1034 if (rc) 1035 return rc; 1036 if (outlen < sizeof(outbuf)) 1037 return -EIO; 1038 encap->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 1039 return 0; 1040 } 1041 1042 int efx_mae_unregister_encap_match(struct efx_nic *efx, 1043 struct efx_tc_encap_match *encap) 1044 { 1045 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 1046 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1)); 1047 size_t outlen; 1048 int rc; 1049 1050 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, encap->fw_id); 1051 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf, 1052 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1053 if (rc) 1054 return rc; 1055 if (outlen < sizeof(outbuf)) 1056 return -EIO; 1057 /* FW freed a different ID than we asked for, should also never happen. 1058 * Warn because it means we've now got a different idea to the FW of 1059 * what encap_mds exist, which could cause mayhem later. 1060 */ 1061 if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != encap->fw_id)) 1062 return -EIO; 1063 /* We're probably about to free @encap, but let's just make sure its 1064 * fw_id is blatted so that it won't look valid if it leaks out. 1065 */ 1066 encap->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL; 1067 return 0; 1068 } 1069 1070 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 1071 const struct efx_tc_match *match) 1072 { 1073 if (match->mask.ingress_port) { 1074 if (~match->mask.ingress_port) 1075 return -EOPNOTSUPP; 1076 MCDI_STRUCT_SET_DWORD(match_crit, 1077 MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR, 1078 match->value.ingress_port); 1079 } 1080 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK, 1081 match->mask.ingress_port); 1082 EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS), 1083 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 1084 match->value.ip_frag, 1085 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 1086 match->value.ip_firstfrag); 1087 EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK), 1088 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 1089 match->mask.ip_frag, 1090 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 1091 match->mask.ip_firstfrag); 1092 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID, 1093 match->value.recirc_id); 1094 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK, 1095 match->mask.recirc_id); 1096 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE, 1097 match->value.eth_proto); 1098 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK, 1099 match->mask.eth_proto); 1100 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE, 1101 match->value.vlan_tci[0]); 1102 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK, 1103 match->mask.vlan_tci[0]); 1104 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE, 1105 match->value.vlan_proto[0]); 1106 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK, 1107 match->mask.vlan_proto[0]); 1108 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE, 1109 match->value.vlan_tci[1]); 1110 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK, 1111 match->mask.vlan_tci[1]); 1112 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE, 1113 match->value.vlan_proto[1]); 1114 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK, 1115 match->mask.vlan_proto[1]); 1116 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE), 1117 match->value.eth_saddr, ETH_ALEN); 1118 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK), 1119 match->mask.eth_saddr, ETH_ALEN); 1120 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE), 1121 match->value.eth_daddr, ETH_ALEN); 1122 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK), 1123 match->mask.eth_daddr, ETH_ALEN); 1124 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO, 1125 match->value.ip_proto); 1126 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK, 1127 match->mask.ip_proto); 1128 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS, 1129 match->value.ip_tos); 1130 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK, 1131 match->mask.ip_tos); 1132 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL, 1133 match->value.ip_ttl); 1134 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK, 1135 match->mask.ip_ttl); 1136 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE, 1137 match->value.src_ip); 1138 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK, 1139 match->mask.src_ip); 1140 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE, 1141 match->value.dst_ip); 1142 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK, 1143 match->mask.dst_ip); 1144 #ifdef CONFIG_IPV6 1145 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE), 1146 &match->value.src_ip6, sizeof(struct in6_addr)); 1147 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK), 1148 &match->mask.src_ip6, sizeof(struct in6_addr)); 1149 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE), 1150 &match->value.dst_ip6, sizeof(struct in6_addr)); 1151 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK), 1152 &match->mask.dst_ip6, sizeof(struct in6_addr)); 1153 #endif 1154 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE, 1155 match->value.l4_sport); 1156 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK, 1157 match->mask.l4_sport); 1158 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE, 1159 match->value.l4_dport); 1160 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK, 1161 match->mask.l4_dport); 1162 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE, 1163 match->value.tcp_flags); 1164 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK, 1165 match->mask.tcp_flags); 1166 /* enc-keys are handled indirectly, through encap_match ID */ 1167 if (match->encap) { 1168 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID, 1169 match->encap->fw_id); 1170 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK, 1171 U32_MAX); 1172 /* enc_keyid (VNI/VSID) is not part of the encap_match */ 1173 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE, 1174 match->value.enc_keyid); 1175 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK, 1176 match->mask.enc_keyid); 1177 } else if (WARN_ON_ONCE(match->mask.enc_src_ip) || 1178 WARN_ON_ONCE(match->mask.enc_dst_ip) || 1179 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)) || 1180 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)) || 1181 WARN_ON_ONCE(match->mask.enc_ip_tos) || 1182 WARN_ON_ONCE(match->mask.enc_ip_ttl) || 1183 WARN_ON_ONCE(match->mask.enc_sport) || 1184 WARN_ON_ONCE(match->mask.enc_dport) || 1185 WARN_ON_ONCE(match->mask.enc_keyid)) { 1186 /* No enc-keys should appear in a rule without an encap_match */ 1187 return -EOPNOTSUPP; 1188 } 1189 return 0; 1190 } 1191 1192 int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, 1193 u32 prio, u32 acts_id, u32 *id) 1194 { 1195 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN)); 1196 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 1197 MCDI_DECLARE_STRUCT_PTR(match_crit); 1198 MCDI_DECLARE_STRUCT_PTR(response); 1199 size_t outlen; 1200 int rc; 1201 1202 if (!id) 1203 return -EINVAL; 1204 1205 match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA); 1206 response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE); 1207 if (efx_mae_asl_id(acts_id)) { 1208 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); 1209 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 1210 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 1211 } else { 1212 /* We only had one AS, so we didn't wrap it in an ASL */ 1213 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 1214 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 1215 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); 1216 } 1217 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio); 1218 rc = efx_mae_populate_match_criteria(match_crit, match); 1219 if (rc) 1220 return rc; 1221 1222 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf), 1223 outbuf, sizeof(outbuf), &outlen); 1224 if (rc) 1225 return rc; 1226 if (outlen < sizeof(outbuf)) 1227 return -EIO; 1228 *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 1229 return 0; 1230 } 1231 1232 int efx_mae_delete_rule(struct efx_nic *efx, u32 id) 1233 { 1234 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 1235 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1)); 1236 size_t outlen; 1237 int rc; 1238 1239 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id); 1240 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf), 1241 outbuf, sizeof(outbuf), &outlen); 1242 if (rc) 1243 return rc; 1244 if (outlen < sizeof(outbuf)) 1245 return -EIO; 1246 /* FW freed a different ID than we asked for, should also never happen. 1247 * Warn because it means we've now got a different idea to the FW of 1248 * what rules exist, which could cause mayhem later. 1249 */ 1250 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id)) 1251 return -EIO; 1252 return 0; 1253 } 1254 1255 int efx_init_mae(struct efx_nic *efx) 1256 { 1257 struct ef100_nic_data *nic_data = efx->nic_data; 1258 struct efx_mae *mae; 1259 int rc; 1260 1261 if (!nic_data->have_mport) 1262 return -EINVAL; 1263 1264 mae = kmalloc(sizeof(*mae), GFP_KERNEL); 1265 if (!mae) 1266 return -ENOMEM; 1267 1268 rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params); 1269 if (rc < 0) { 1270 kfree(mae); 1271 return rc; 1272 } 1273 efx->mae = mae; 1274 mae->efx = efx; 1275 return 0; 1276 } 1277 1278 void efx_fini_mae(struct efx_nic *efx) 1279 { 1280 struct efx_mae *mae = efx->mae; 1281 1282 kfree(mae); 1283 efx->mae = NULL; 1284 } 1285