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. 486 */ 487 int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, 488 struct netlink_ext_ack *extack) 489 { 490 u8 *supported_fields = efx->tc->caps->outer_rule_fields; 491 int rc; 492 493 if (CHECK(ENC_ETHER_TYPE)) 494 return rc; 495 if (ipv6) { 496 if (CHECK(ENC_SRC_IP6) || 497 CHECK(ENC_DST_IP6)) 498 return rc; 499 } else { 500 if (CHECK(ENC_SRC_IP4) || 501 CHECK(ENC_DST_IP4)) 502 return rc; 503 } 504 if (CHECK(ENC_L4_DPORT) || 505 CHECK(ENC_IP_PROTO)) 506 return rc; 507 return 0; 508 } 509 #undef CHECK 510 511 int efx_mae_check_encap_type_supported(struct efx_nic *efx, enum efx_encap_type typ) 512 { 513 unsigned int bit; 514 515 switch (typ & EFX_ENCAP_TYPES_MASK) { 516 case EFX_ENCAP_TYPE_VXLAN: 517 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN_LBN; 518 break; 519 case EFX_ENCAP_TYPE_GENEVE: 520 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE_LBN; 521 break; 522 default: 523 return -EOPNOTSUPP; 524 } 525 if (efx->tc->caps->encap_types & BIT(bit)) 526 return 0; 527 return -EOPNOTSUPP; 528 } 529 530 int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt) 531 { 532 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1)); 533 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN); 534 size_t outlen; 535 int rc; 536 537 if (!cnt) 538 return -EINVAL; 539 540 MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT, 1); 541 MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE, cnt->type); 542 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_ALLOC, inbuf, sizeof(inbuf), 543 outbuf, sizeof(outbuf), &outlen); 544 if (rc) 545 return rc; 546 /* pcol says this can't happen, since count is 1 */ 547 if (outlen < sizeof(outbuf)) 548 return -EIO; 549 cnt->fw_id = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_COUNTER_ID); 550 cnt->gen = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT); 551 return 0; 552 } 553 554 int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt) 555 { 556 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_FREE_OUT_LEN(1)); 557 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN); 558 size_t outlen; 559 int rc; 560 561 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT, 1); 562 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID, cnt->fw_id); 563 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE, cnt->type); 564 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_FREE, inbuf, sizeof(inbuf), 565 outbuf, sizeof(outbuf), &outlen); 566 if (rc) 567 return rc; 568 /* pcol says this can't happen, since count is 1 */ 569 if (outlen < sizeof(outbuf)) 570 return -EIO; 571 /* FW freed a different ID than we asked for, should also never happen. 572 * Warn because it means we've now got a different idea to the FW of 573 * what counters exist, which could cause mayhem later. 574 */ 575 if (WARN_ON(MCDI_DWORD(outbuf, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID) != 576 cnt->fw_id)) 577 return -EIO; 578 return 0; 579 } 580 581 static int efx_mae_encap_type_to_mae_type(enum efx_encap_type type) 582 { 583 switch (type & EFX_ENCAP_TYPES_MASK) { 584 case EFX_ENCAP_TYPE_NONE: 585 return MAE_MCDI_ENCAP_TYPE_NONE; 586 case EFX_ENCAP_TYPE_VXLAN: 587 return MAE_MCDI_ENCAP_TYPE_VXLAN; 588 case EFX_ENCAP_TYPE_GENEVE: 589 return MAE_MCDI_ENCAP_TYPE_GENEVE; 590 default: 591 return -EOPNOTSUPP; 592 } 593 } 594 595 int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id) 596 { 597 struct ef100_nic_data *nic_data = efx->nic_data; 598 struct efx_mae *mae = efx->mae; 599 struct rhashtable_iter walk; 600 struct mae_mport_desc *m; 601 int rc = -ENOENT; 602 603 rhashtable_walk_enter(&mae->mports_ht, &walk); 604 rhashtable_walk_start(&walk); 605 while ((m = rhashtable_walk_next(&walk)) != NULL) { 606 if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC && 607 m->interface_idx == nic_data->local_mae_intf && 608 m->pf_idx == 0 && 609 m->vf_idx == vf_idx) { 610 *id = m->mport_id; 611 rc = 0; 612 break; 613 } 614 } 615 rhashtable_walk_stop(&walk); 616 rhashtable_walk_exit(&walk); 617 return rc; 618 } 619 620 static bool efx_mae_asl_id(u32 id) 621 { 622 return !!(id & BIT(31)); 623 } 624 625 /* mport handling */ 626 static const struct rhashtable_params efx_mae_mports_ht_params = { 627 .key_len = sizeof(u32), 628 .key_offset = offsetof(struct mae_mport_desc, mport_id), 629 .head_offset = offsetof(struct mae_mport_desc, linkage), 630 }; 631 632 struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id) 633 { 634 return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id, 635 efx_mae_mports_ht_params); 636 } 637 638 static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc) 639 { 640 struct efx_mae *mae = efx->mae; 641 int rc; 642 643 rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage, 644 efx_mae_mports_ht_params); 645 646 if (rc) { 647 pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n", 648 desc->mport_id, rc); 649 kfree(desc); 650 return rc; 651 } 652 653 return rc; 654 } 655 656 void efx_mae_remove_mport(void *desc, void *arg) 657 { 658 struct mae_mport_desc *mport = desc; 659 660 synchronize_rcu(); 661 kfree(mport); 662 } 663 664 static int efx_mae_process_mport(struct efx_nic *efx, 665 struct mae_mport_desc *desc) 666 { 667 struct ef100_nic_data *nic_data = efx->nic_data; 668 struct mae_mport_desc *mport; 669 670 mport = efx_mae_get_mport(efx, desc->mport_id); 671 if (!IS_ERR_OR_NULL(mport)) { 672 netif_err(efx, drv, efx->net_dev, 673 "mport with id %u does exist!!!\n", desc->mport_id); 674 return -EEXIST; 675 } 676 677 if (nic_data->have_own_mport && 678 desc->mport_id == nic_data->own_mport) { 679 WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC); 680 WARN_ON(desc->vnic_client_type != 681 MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION); 682 nic_data->local_mae_intf = desc->interface_idx; 683 nic_data->have_local_intf = true; 684 pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n", 685 nic_data->local_mae_intf); 686 } 687 688 return efx_mae_add_mport(efx, desc); 689 } 690 691 #define MCDI_MPORT_JOURNAL_LEN \ 692 ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4) 693 694 int efx_mae_enumerate_mports(struct efx_nic *efx) 695 { 696 efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL); 697 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN); 698 MCDI_DECLARE_STRUCT_PTR(desc); 699 size_t outlen, stride, count; 700 int rc = 0, i; 701 702 if (!outbuf) 703 return -ENOMEM; 704 do { 705 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf, 706 sizeof(inbuf), outbuf, 707 MCDI_MPORT_JOURNAL_LEN, &outlen); 708 if (rc) 709 goto fail; 710 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) { 711 rc = -EIO; 712 goto fail; 713 } 714 count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT); 715 if (!count) 716 continue; /* not break; we want to look at MORE flag */ 717 stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC); 718 if (stride < MAE_MPORT_DESC_LEN) { 719 rc = -EIO; 720 goto fail; 721 } 722 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) { 723 rc = -EIO; 724 goto fail; 725 } 726 727 for (i = 0; i < count; i++) { 728 struct mae_mport_desc *d; 729 730 d = kzalloc(sizeof(*d), GFP_KERNEL); 731 if (!d) { 732 rc = -ENOMEM; 733 goto fail; 734 } 735 736 desc = (efx_dword_t *) 737 _MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST + 738 i * stride); 739 d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID); 740 d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS); 741 d->caller_flags = MCDI_STRUCT_DWORD(desc, 742 MAE_MPORT_DESC_CALLER_FLAGS); 743 d->mport_type = MCDI_STRUCT_DWORD(desc, 744 MAE_MPORT_DESC_MPORT_TYPE); 745 switch (d->mport_type) { 746 case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT: 747 d->port_idx = MCDI_STRUCT_DWORD(desc, 748 MAE_MPORT_DESC_NET_PORT_IDX); 749 break; 750 case MAE_MPORT_DESC_MPORT_TYPE_ALIAS: 751 d->alias_mport_id = MCDI_STRUCT_DWORD(desc, 752 MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID); 753 break; 754 case MAE_MPORT_DESC_MPORT_TYPE_VNIC: 755 d->vnic_client_type = MCDI_STRUCT_DWORD(desc, 756 MAE_MPORT_DESC_VNIC_CLIENT_TYPE); 757 d->interface_idx = MCDI_STRUCT_DWORD(desc, 758 MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE); 759 d->pf_idx = MCDI_STRUCT_WORD(desc, 760 MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX); 761 d->vf_idx = MCDI_STRUCT_WORD(desc, 762 MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX); 763 break; 764 default: 765 /* Unknown mport_type, just accept it */ 766 break; 767 } 768 rc = efx_mae_process_mport(efx, d); 769 /* Any failure will be due to memory allocation faiure, 770 * so there is no point to try subsequent entries. 771 */ 772 if (rc) 773 goto fail; 774 } 775 } while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) && 776 !WARN_ON(!count)); 777 fail: 778 kfree(outbuf); 779 return rc; 780 } 781 782 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) 783 { 784 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 785 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN); 786 size_t outlen; 787 int rc; 788 789 MCDI_POPULATE_DWORD_3(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS, 790 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, act->vlan_push, 791 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop, 792 MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap); 793 794 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 795 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 796 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 797 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 798 if (act->count && !WARN_ON(!act->count->cnt)) 799 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 800 act->count->cnt->fw_id); 801 else 802 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 803 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 804 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, 805 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL); 806 if (act->vlan_push) { 807 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE, 808 act->vlan_tci[0]); 809 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE, 810 act->vlan_proto[0]); 811 } 812 if (act->vlan_push >= 2) { 813 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE, 814 act->vlan_tci[1]); 815 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE, 816 act->vlan_proto[1]); 817 } 818 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 819 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); 820 if (act->deliver) 821 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER, 822 act->dest_mport); 823 BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL); 824 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf), 825 outbuf, sizeof(outbuf), &outlen); 826 if (rc) 827 return rc; 828 if (outlen < sizeof(outbuf)) 829 return -EIO; 830 act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 831 /* We rely on the high bit of AS IDs always being clear. 832 * The firmware API guarantees this, but let's check it ourselves. 833 */ 834 if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) { 835 efx_mae_free_action_set(efx, act->fw_id); 836 return -EIO; 837 } 838 return 0; 839 } 840 841 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id) 842 { 843 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 844 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1)); 845 size_t outlen; 846 int rc; 847 848 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id); 849 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf), 850 outbuf, sizeof(outbuf), &outlen); 851 if (rc) 852 return rc; 853 if (outlen < sizeof(outbuf)) 854 return -EIO; 855 /* FW freed a different ID than we asked for, should never happen. 856 * Warn because it means we've now got a different idea to the FW of 857 * what action-sets exist, which could cause mayhem later. 858 */ 859 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id)) 860 return -EIO; 861 return 0; 862 } 863 864 int efx_mae_alloc_action_set_list(struct efx_nic *efx, 865 struct efx_tc_action_set_list *acts) 866 { 867 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN); 868 struct efx_tc_action_set *act; 869 size_t inlen, outlen, i = 0; 870 efx_dword_t *inbuf; 871 int rc; 872 873 list_for_each_entry(act, &acts->list, list) 874 i++; 875 if (i == 0) 876 return -EINVAL; 877 if (i == 1) { 878 /* Don't wrap an ASL around a single AS, just use the AS_ID 879 * directly. ASLs are a more limited resource. 880 */ 881 act = list_first_entry(&acts->list, struct efx_tc_action_set, list); 882 acts->fw_id = act->fw_id; 883 return 0; 884 } 885 if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2) 886 return -EOPNOTSUPP; /* Too many actions */ 887 inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i); 888 inbuf = kzalloc(inlen, GFP_KERNEL); 889 if (!inbuf) 890 return -ENOMEM; 891 i = 0; 892 list_for_each_entry(act, &acts->list, list) { 893 MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS, 894 i, act->fw_id); 895 i++; 896 } 897 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i); 898 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen, 899 outbuf, sizeof(outbuf), &outlen); 900 if (rc) 901 goto out_free; 902 if (outlen < sizeof(outbuf)) { 903 rc = -EIO; 904 goto out_free; 905 } 906 acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID); 907 /* We rely on the high bit of ASL IDs always being set. 908 * The firmware API guarantees this, but let's check it ourselves. 909 */ 910 if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) { 911 efx_mae_free_action_set_list(efx, acts); 912 rc = -EIO; 913 } 914 out_free: 915 kfree(inbuf); 916 return rc; 917 } 918 919 int efx_mae_free_action_set_list(struct efx_nic *efx, 920 struct efx_tc_action_set_list *acts) 921 { 922 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1)); 923 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1)); 924 size_t outlen; 925 int rc; 926 927 /* If this is just an AS_ID with no ASL wrapper, then there is 928 * nothing for us to free. (The AS will be freed later.) 929 */ 930 if (efx_mae_asl_id(acts->fw_id)) { 931 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID, 932 acts->fw_id); 933 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf, 934 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 935 if (rc) 936 return rc; 937 if (outlen < sizeof(outbuf)) 938 return -EIO; 939 /* FW freed a different ID than we asked for, should never happen. 940 * Warn because it means we've now got a different idea to the FW of 941 * what action-set-lists exist, which could cause mayhem later. 942 */ 943 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id)) 944 return -EIO; 945 } 946 /* We're probably about to free @acts, but let's just make sure its 947 * fw_id is blatted so that it won't look valid if it leaks out. 948 */ 949 acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL; 950 return 0; 951 } 952 953 int efx_mae_register_encap_match(struct efx_nic *efx, 954 struct efx_tc_encap_match *encap) 955 { 956 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN)); 957 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 958 MCDI_DECLARE_STRUCT_PTR(match_crit); 959 size_t outlen; 960 int rc; 961 962 rc = efx_mae_encap_type_to_mae_type(encap->tun_type); 963 if (rc < 0) 964 return rc; 965 match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA); 966 /* The struct contains IP src and dst, and udp dport. 967 * So we actually need to filter on IP src and dst, L4 dport, and 968 * ipproto == udp. 969 */ 970 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, rc); 971 #ifdef CONFIG_IPV6 972 if (encap->src_ip | encap->dst_ip) { 973 #endif 974 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE, 975 encap->src_ip); 976 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK, 977 ~(__be32)0); 978 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE, 979 encap->dst_ip); 980 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK, 981 ~(__be32)0); 982 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 983 htons(ETH_P_IP)); 984 #ifdef CONFIG_IPV6 985 } else { 986 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE), 987 &encap->src_ip6, sizeof(encap->src_ip6)); 988 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK), 989 0xff, sizeof(encap->src_ip6)); 990 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE), 991 &encap->dst_ip6, sizeof(encap->dst_ip6)); 992 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK), 993 0xff, sizeof(encap->dst_ip6)); 994 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 995 htons(ETH_P_IPV6)); 996 } 997 #endif 998 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK, 999 ~(__be16)0); 1000 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1001 encap->udp_dport); 1002 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1003 ~(__be16)0); 1004 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, IPPROTO_UDP); 1005 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, ~0); 1006 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf, 1007 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1008 if (rc) 1009 return rc; 1010 if (outlen < sizeof(outbuf)) 1011 return -EIO; 1012 encap->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 1013 return 0; 1014 } 1015 1016 int efx_mae_unregister_encap_match(struct efx_nic *efx, 1017 struct efx_tc_encap_match *encap) 1018 { 1019 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 1020 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1)); 1021 size_t outlen; 1022 int rc; 1023 1024 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, encap->fw_id); 1025 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf, 1026 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1027 if (rc) 1028 return rc; 1029 if (outlen < sizeof(outbuf)) 1030 return -EIO; 1031 /* FW freed a different ID than we asked for, should also never happen. 1032 * Warn because it means we've now got a different idea to the FW of 1033 * what encap_mds exist, which could cause mayhem later. 1034 */ 1035 if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != encap->fw_id)) 1036 return -EIO; 1037 /* We're probably about to free @encap, but let's just make sure its 1038 * fw_id is blatted so that it won't look valid if it leaks out. 1039 */ 1040 encap->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL; 1041 return 0; 1042 } 1043 1044 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 1045 const struct efx_tc_match *match) 1046 { 1047 if (match->mask.ingress_port) { 1048 if (~match->mask.ingress_port) 1049 return -EOPNOTSUPP; 1050 MCDI_STRUCT_SET_DWORD(match_crit, 1051 MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR, 1052 match->value.ingress_port); 1053 } 1054 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK, 1055 match->mask.ingress_port); 1056 EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS), 1057 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 1058 match->value.ip_frag, 1059 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 1060 match->value.ip_firstfrag); 1061 EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK), 1062 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 1063 match->mask.ip_frag, 1064 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 1065 match->mask.ip_firstfrag); 1066 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID, 1067 match->value.recirc_id); 1068 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK, 1069 match->mask.recirc_id); 1070 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE, 1071 match->value.eth_proto); 1072 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK, 1073 match->mask.eth_proto); 1074 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE, 1075 match->value.vlan_tci[0]); 1076 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK, 1077 match->mask.vlan_tci[0]); 1078 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE, 1079 match->value.vlan_proto[0]); 1080 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK, 1081 match->mask.vlan_proto[0]); 1082 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE, 1083 match->value.vlan_tci[1]); 1084 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK, 1085 match->mask.vlan_tci[1]); 1086 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE, 1087 match->value.vlan_proto[1]); 1088 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK, 1089 match->mask.vlan_proto[1]); 1090 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE), 1091 match->value.eth_saddr, ETH_ALEN); 1092 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK), 1093 match->mask.eth_saddr, ETH_ALEN); 1094 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE), 1095 match->value.eth_daddr, ETH_ALEN); 1096 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK), 1097 match->mask.eth_daddr, ETH_ALEN); 1098 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO, 1099 match->value.ip_proto); 1100 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK, 1101 match->mask.ip_proto); 1102 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS, 1103 match->value.ip_tos); 1104 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK, 1105 match->mask.ip_tos); 1106 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL, 1107 match->value.ip_ttl); 1108 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK, 1109 match->mask.ip_ttl); 1110 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE, 1111 match->value.src_ip); 1112 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK, 1113 match->mask.src_ip); 1114 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE, 1115 match->value.dst_ip); 1116 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK, 1117 match->mask.dst_ip); 1118 #ifdef CONFIG_IPV6 1119 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE), 1120 &match->value.src_ip6, sizeof(struct in6_addr)); 1121 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK), 1122 &match->mask.src_ip6, sizeof(struct in6_addr)); 1123 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE), 1124 &match->value.dst_ip6, sizeof(struct in6_addr)); 1125 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK), 1126 &match->mask.dst_ip6, sizeof(struct in6_addr)); 1127 #endif 1128 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE, 1129 match->value.l4_sport); 1130 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK, 1131 match->mask.l4_sport); 1132 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE, 1133 match->value.l4_dport); 1134 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK, 1135 match->mask.l4_dport); 1136 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE, 1137 match->value.tcp_flags); 1138 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK, 1139 match->mask.tcp_flags); 1140 /* enc-keys are handled indirectly, through encap_match ID */ 1141 if (match->encap) { 1142 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID, 1143 match->encap->fw_id); 1144 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK, 1145 U32_MAX); 1146 /* enc_keyid (VNI/VSID) is not part of the encap_match */ 1147 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE, 1148 match->value.enc_keyid); 1149 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK, 1150 match->mask.enc_keyid); 1151 } else if (WARN_ON_ONCE(match->mask.enc_src_ip) || 1152 WARN_ON_ONCE(match->mask.enc_dst_ip) || 1153 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)) || 1154 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)) || 1155 WARN_ON_ONCE(match->mask.enc_ip_tos) || 1156 WARN_ON_ONCE(match->mask.enc_ip_ttl) || 1157 WARN_ON_ONCE(match->mask.enc_sport) || 1158 WARN_ON_ONCE(match->mask.enc_dport) || 1159 WARN_ON_ONCE(match->mask.enc_keyid)) { 1160 /* No enc-keys should appear in a rule without an encap_match */ 1161 return -EOPNOTSUPP; 1162 } 1163 return 0; 1164 } 1165 1166 int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, 1167 u32 prio, u32 acts_id, u32 *id) 1168 { 1169 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN)); 1170 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 1171 MCDI_DECLARE_STRUCT_PTR(match_crit); 1172 MCDI_DECLARE_STRUCT_PTR(response); 1173 size_t outlen; 1174 int rc; 1175 1176 if (!id) 1177 return -EINVAL; 1178 1179 match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA); 1180 response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE); 1181 if (efx_mae_asl_id(acts_id)) { 1182 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); 1183 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 1184 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 1185 } else { 1186 /* We only had one AS, so we didn't wrap it in an ASL */ 1187 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 1188 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 1189 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); 1190 } 1191 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio); 1192 rc = efx_mae_populate_match_criteria(match_crit, match); 1193 if (rc) 1194 return rc; 1195 1196 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf), 1197 outbuf, sizeof(outbuf), &outlen); 1198 if (rc) 1199 return rc; 1200 if (outlen < sizeof(outbuf)) 1201 return -EIO; 1202 *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 1203 return 0; 1204 } 1205 1206 int efx_mae_delete_rule(struct efx_nic *efx, u32 id) 1207 { 1208 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 1209 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1)); 1210 size_t outlen; 1211 int rc; 1212 1213 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id); 1214 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf), 1215 outbuf, sizeof(outbuf), &outlen); 1216 if (rc) 1217 return rc; 1218 if (outlen < sizeof(outbuf)) 1219 return -EIO; 1220 /* FW freed a different ID than we asked for, should also never happen. 1221 * Warn because it means we've now got a different idea to the FW of 1222 * what rules exist, which could cause mayhem later. 1223 */ 1224 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id)) 1225 return -EIO; 1226 return 0; 1227 } 1228 1229 int efx_init_mae(struct efx_nic *efx) 1230 { 1231 struct ef100_nic_data *nic_data = efx->nic_data; 1232 struct efx_mae *mae; 1233 int rc; 1234 1235 if (!nic_data->have_mport) 1236 return -EINVAL; 1237 1238 mae = kmalloc(sizeof(*mae), GFP_KERNEL); 1239 if (!mae) 1240 return -ENOMEM; 1241 1242 rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params); 1243 if (rc < 0) { 1244 kfree(mae); 1245 return rc; 1246 } 1247 efx->mae = mae; 1248 mae->efx = efx; 1249 return 0; 1250 } 1251 1252 void efx_fini_mae(struct efx_nic *efx) 1253 { 1254 struct efx_mae *mae = efx->mae; 1255 1256 kfree(mae); 1257 efx->mae = NULL; 1258 } 1259