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