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->action_prios = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ACTION_PRIOS); 245 return 0; 246 } 247 248 static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd, 249 u8 *field_support) 250 { 251 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS)); 252 MCDI_DECLARE_STRUCT_PTR(caps); 253 unsigned int count; 254 size_t outlen; 255 int rc, i; 256 257 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN); 258 259 rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen); 260 if (rc) 261 return rc; 262 count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT); 263 memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS); 264 caps = _MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS); 265 /* We're only interested in the support status enum, not any other 266 * flags, so just extract that from each entry. 267 */ 268 for (i = 0; i < count; i++) 269 if (i * sizeof(*outbuf) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen) 270 field_support[i] = EFX_DWORD_FIELD(caps[i], MAE_FIELD_FLAGS_SUPPORT_STATUS); 271 return 0; 272 } 273 274 int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps) 275 { 276 int rc; 277 278 rc = efx_mae_get_basic_caps(efx, caps); 279 if (rc) 280 return rc; 281 return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS, 282 caps->action_rule_fields); 283 } 284 285 /* Bit twiddling: 286 * Prefix: 1...110...0 287 * ~: 0...001...1 288 * + 1: 0...010...0 is power of two 289 * so (~x) & ((~x) + 1) == 0. Converse holds also. 290 */ 291 #define is_prefix_byte(_x) !(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1)) 292 293 enum mask_type { MASK_ONES, MASK_ZEROES, MASK_PREFIX, MASK_OTHER }; 294 295 static const char *mask_type_name(enum mask_type typ) 296 { 297 switch (typ) { 298 case MASK_ONES: 299 return "all-1s"; 300 case MASK_ZEROES: 301 return "all-0s"; 302 case MASK_PREFIX: 303 return "prefix"; 304 case MASK_OTHER: 305 return "arbitrary"; 306 default: /* can't happen */ 307 return "unknown"; 308 } 309 } 310 311 /* Checks a (big-endian) bytestring is a bit prefix */ 312 static enum mask_type classify_mask(const u8 *mask, size_t len) 313 { 314 bool zeroes = true; /* All bits seen so far are zeroes */ 315 bool ones = true; /* All bits seen so far are ones */ 316 bool prefix = true; /* Valid prefix so far */ 317 size_t i; 318 319 for (i = 0; i < len; i++) { 320 if (ones) { 321 if (!is_prefix_byte(mask[i])) 322 prefix = false; 323 } else if (mask[i]) { 324 prefix = false; 325 } 326 if (mask[i] != 0xff) 327 ones = false; 328 if (mask[i]) 329 zeroes = false; 330 } 331 if (ones) 332 return MASK_ONES; 333 if (zeroes) 334 return MASK_ZEROES; 335 if (prefix) 336 return MASK_PREFIX; 337 return MASK_OTHER; 338 } 339 340 static int efx_mae_match_check_cap_typ(u8 support, enum mask_type typ) 341 { 342 switch (support) { 343 case MAE_FIELD_UNSUPPORTED: 344 case MAE_FIELD_SUPPORTED_MATCH_NEVER: 345 if (typ == MASK_ZEROES) 346 return 0; 347 return -EOPNOTSUPP; 348 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL: 349 if (typ == MASK_ZEROES) 350 return 0; 351 fallthrough; 352 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: 353 if (typ == MASK_ONES) 354 return 0; 355 return -EINVAL; 356 case MAE_FIELD_SUPPORTED_MATCH_PREFIX: 357 if (typ == MASK_OTHER) 358 return -EOPNOTSUPP; 359 return 0; 360 case MAE_FIELD_SUPPORTED_MATCH_MASK: 361 return 0; 362 default: 363 return -EIO; 364 } 365 } 366 367 /* Validate field mask against hardware capabilities. Captures caller's 'rc' */ 368 #define CHECK(_mcdi, _field) ({ \ 369 enum mask_type typ = classify_mask((const u8 *)&mask->_field, \ 370 sizeof(mask->_field)); \ 371 \ 372 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 373 typ); \ 374 if (rc) \ 375 NL_SET_ERR_MSG_FMT_MOD(extack, \ 376 "No support for %s mask in field %s", \ 377 mask_type_name(typ), #_field); \ 378 rc; \ 379 }) 380 /* Booleans need special handling */ 381 #define CHECK_BIT(_mcdi, _field) ({ \ 382 enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES; \ 383 \ 384 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 385 typ); \ 386 if (rc) \ 387 NL_SET_ERR_MSG_FMT_MOD(extack, \ 388 "No support for %s mask in field %s", \ 389 mask_type_name(typ), #_field); \ 390 rc; \ 391 }) 392 393 int efx_mae_match_check_caps(struct efx_nic *efx, 394 const struct efx_tc_match_fields *mask, 395 struct netlink_ext_ack *extack) 396 { 397 const u8 *supported_fields = efx->tc->caps->action_rule_fields; 398 __be32 ingress_port = cpu_to_be32(mask->ingress_port); 399 enum mask_type ingress_port_mask_type; 400 int rc; 401 402 /* Check for _PREFIX assumes big-endian, so we need to convert */ 403 ingress_port_mask_type = classify_mask((const u8 *)&ingress_port, 404 sizeof(ingress_port)); 405 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT], 406 ingress_port_mask_type); 407 if (rc) { 408 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field ingress_port", 409 mask_type_name(ingress_port_mask_type)); 410 return rc; 411 } 412 if (CHECK(ETHER_TYPE, eth_proto) || 413 CHECK(VLAN0_TCI, vlan_tci[0]) || 414 CHECK(VLAN0_PROTO, vlan_proto[0]) || 415 CHECK(VLAN1_TCI, vlan_tci[1]) || 416 CHECK(VLAN1_PROTO, vlan_proto[1]) || 417 CHECK(ETH_SADDR, eth_saddr) || 418 CHECK(ETH_DADDR, eth_daddr) || 419 CHECK(IP_PROTO, ip_proto) || 420 CHECK(IP_TOS, ip_tos) || 421 CHECK(IP_TTL, ip_ttl) || 422 CHECK(SRC_IP4, src_ip) || 423 CHECK(DST_IP4, dst_ip) || 424 #ifdef CONFIG_IPV6 425 CHECK(SRC_IP6, src_ip6) || 426 CHECK(DST_IP6, dst_ip6) || 427 #endif 428 CHECK(L4_SPORT, l4_sport) || 429 CHECK(L4_DPORT, l4_dport) || 430 CHECK(TCP_FLAGS, tcp_flags) || 431 CHECK_BIT(IS_IP_FRAG, ip_frag) || 432 CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) || 433 CHECK(RECIRC_ID, recirc_id)) 434 return rc; 435 return 0; 436 } 437 #undef CHECK_BIT 438 #undef CHECK 439 440 int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt) 441 { 442 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1)); 443 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN); 444 size_t outlen; 445 int rc; 446 447 if (!cnt) 448 return -EINVAL; 449 450 MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT, 1); 451 MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE, cnt->type); 452 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_ALLOC, inbuf, sizeof(inbuf), 453 outbuf, sizeof(outbuf), &outlen); 454 if (rc) 455 return rc; 456 /* pcol says this can't happen, since count is 1 */ 457 if (outlen < sizeof(outbuf)) 458 return -EIO; 459 cnt->fw_id = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_COUNTER_ID); 460 cnt->gen = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT); 461 return 0; 462 } 463 464 int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt) 465 { 466 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_FREE_OUT_LEN(1)); 467 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN); 468 size_t outlen; 469 int rc; 470 471 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT, 1); 472 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID, cnt->fw_id); 473 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE, cnt->type); 474 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_FREE, inbuf, sizeof(inbuf), 475 outbuf, sizeof(outbuf), &outlen); 476 if (rc) 477 return rc; 478 /* pcol says this can't happen, since count is 1 */ 479 if (outlen < sizeof(outbuf)) 480 return -EIO; 481 /* FW freed a different ID than we asked for, should also never happen. 482 * Warn because it means we've now got a different idea to the FW of 483 * what counters exist, which could cause mayhem later. 484 */ 485 if (WARN_ON(MCDI_DWORD(outbuf, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID) != 486 cnt->fw_id)) 487 return -EIO; 488 return 0; 489 } 490 491 int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id) 492 { 493 struct ef100_nic_data *nic_data = efx->nic_data; 494 struct efx_mae *mae = efx->mae; 495 struct rhashtable_iter walk; 496 struct mae_mport_desc *m; 497 int rc = -ENOENT; 498 499 rhashtable_walk_enter(&mae->mports_ht, &walk); 500 rhashtable_walk_start(&walk); 501 while ((m = rhashtable_walk_next(&walk)) != NULL) { 502 if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC && 503 m->interface_idx == nic_data->local_mae_intf && 504 m->pf_idx == 0 && 505 m->vf_idx == vf_idx) { 506 *id = m->mport_id; 507 rc = 0; 508 break; 509 } 510 } 511 rhashtable_walk_stop(&walk); 512 rhashtable_walk_exit(&walk); 513 return rc; 514 } 515 516 static bool efx_mae_asl_id(u32 id) 517 { 518 return !!(id & BIT(31)); 519 } 520 521 /* mport handling */ 522 static const struct rhashtable_params efx_mae_mports_ht_params = { 523 .key_len = sizeof(u32), 524 .key_offset = offsetof(struct mae_mport_desc, mport_id), 525 .head_offset = offsetof(struct mae_mport_desc, linkage), 526 }; 527 528 struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id) 529 { 530 return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id, 531 efx_mae_mports_ht_params); 532 } 533 534 static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc) 535 { 536 struct efx_mae *mae = efx->mae; 537 int rc; 538 539 rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage, 540 efx_mae_mports_ht_params); 541 542 if (rc) { 543 pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n", 544 desc->mport_id, rc); 545 kfree(desc); 546 return rc; 547 } 548 549 return rc; 550 } 551 552 void efx_mae_remove_mport(void *desc, void *arg) 553 { 554 struct mae_mport_desc *mport = desc; 555 556 synchronize_rcu(); 557 kfree(mport); 558 } 559 560 static int efx_mae_process_mport(struct efx_nic *efx, 561 struct mae_mport_desc *desc) 562 { 563 struct ef100_nic_data *nic_data = efx->nic_data; 564 struct mae_mport_desc *mport; 565 566 mport = efx_mae_get_mport(efx, desc->mport_id); 567 if (!IS_ERR_OR_NULL(mport)) { 568 netif_err(efx, drv, efx->net_dev, 569 "mport with id %u does exist!!!\n", desc->mport_id); 570 return -EEXIST; 571 } 572 573 if (nic_data->have_own_mport && 574 desc->mport_id == nic_data->own_mport) { 575 WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC); 576 WARN_ON(desc->vnic_client_type != 577 MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION); 578 nic_data->local_mae_intf = desc->interface_idx; 579 nic_data->have_local_intf = true; 580 pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n", 581 nic_data->local_mae_intf); 582 } 583 584 return efx_mae_add_mport(efx, desc); 585 } 586 587 #define MCDI_MPORT_JOURNAL_LEN \ 588 ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4) 589 590 int efx_mae_enumerate_mports(struct efx_nic *efx) 591 { 592 efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL); 593 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN); 594 MCDI_DECLARE_STRUCT_PTR(desc); 595 size_t outlen, stride, count; 596 int rc = 0, i; 597 598 if (!outbuf) 599 return -ENOMEM; 600 do { 601 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf, 602 sizeof(inbuf), outbuf, 603 MCDI_MPORT_JOURNAL_LEN, &outlen); 604 if (rc) 605 goto fail; 606 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) { 607 rc = -EIO; 608 goto fail; 609 } 610 count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT); 611 if (!count) 612 continue; /* not break; we want to look at MORE flag */ 613 stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC); 614 if (stride < MAE_MPORT_DESC_LEN) { 615 rc = -EIO; 616 goto fail; 617 } 618 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) { 619 rc = -EIO; 620 goto fail; 621 } 622 623 for (i = 0; i < count; i++) { 624 struct mae_mport_desc *d; 625 626 d = kzalloc(sizeof(*d), GFP_KERNEL); 627 if (!d) { 628 rc = -ENOMEM; 629 goto fail; 630 } 631 632 desc = (efx_dword_t *) 633 _MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST + 634 i * stride); 635 d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID); 636 d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS); 637 d->caller_flags = MCDI_STRUCT_DWORD(desc, 638 MAE_MPORT_DESC_CALLER_FLAGS); 639 d->mport_type = MCDI_STRUCT_DWORD(desc, 640 MAE_MPORT_DESC_MPORT_TYPE); 641 switch (d->mport_type) { 642 case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT: 643 d->port_idx = MCDI_STRUCT_DWORD(desc, 644 MAE_MPORT_DESC_NET_PORT_IDX); 645 break; 646 case MAE_MPORT_DESC_MPORT_TYPE_ALIAS: 647 d->alias_mport_id = MCDI_STRUCT_DWORD(desc, 648 MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID); 649 break; 650 case MAE_MPORT_DESC_MPORT_TYPE_VNIC: 651 d->vnic_client_type = MCDI_STRUCT_DWORD(desc, 652 MAE_MPORT_DESC_VNIC_CLIENT_TYPE); 653 d->interface_idx = MCDI_STRUCT_DWORD(desc, 654 MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE); 655 d->pf_idx = MCDI_STRUCT_WORD(desc, 656 MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX); 657 d->vf_idx = MCDI_STRUCT_WORD(desc, 658 MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX); 659 break; 660 default: 661 /* Unknown mport_type, just accept it */ 662 break; 663 } 664 rc = efx_mae_process_mport(efx, d); 665 /* Any failure will be due to memory allocation faiure, 666 * so there is no point to try subsequent entries. 667 */ 668 if (rc) 669 goto fail; 670 } 671 } while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) && 672 !WARN_ON(!count)); 673 fail: 674 kfree(outbuf); 675 return rc; 676 } 677 678 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) 679 { 680 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 681 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN); 682 size_t outlen; 683 int rc; 684 685 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 686 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 687 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 688 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 689 if (act->count && !WARN_ON(!act->count->cnt)) 690 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 691 act->count->cnt->fw_id); 692 else 693 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 694 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 695 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, 696 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL); 697 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 698 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); 699 if (act->deliver) 700 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER, 701 act->dest_mport); 702 BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL); 703 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf), 704 outbuf, sizeof(outbuf), &outlen); 705 if (rc) 706 return rc; 707 if (outlen < sizeof(outbuf)) 708 return -EIO; 709 act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 710 /* We rely on the high bit of AS IDs always being clear. 711 * The firmware API guarantees this, but let's check it ourselves. 712 */ 713 if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) { 714 efx_mae_free_action_set(efx, act->fw_id); 715 return -EIO; 716 } 717 return 0; 718 } 719 720 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id) 721 { 722 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 723 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1)); 724 size_t outlen; 725 int rc; 726 727 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id); 728 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf), 729 outbuf, sizeof(outbuf), &outlen); 730 if (rc) 731 return rc; 732 if (outlen < sizeof(outbuf)) 733 return -EIO; 734 /* FW freed a different ID than we asked for, should never happen. 735 * Warn because it means we've now got a different idea to the FW of 736 * what action-sets exist, which could cause mayhem later. 737 */ 738 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id)) 739 return -EIO; 740 return 0; 741 } 742 743 int efx_mae_alloc_action_set_list(struct efx_nic *efx, 744 struct efx_tc_action_set_list *acts) 745 { 746 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN); 747 struct efx_tc_action_set *act; 748 size_t inlen, outlen, i = 0; 749 efx_dword_t *inbuf; 750 int rc; 751 752 list_for_each_entry(act, &acts->list, list) 753 i++; 754 if (i == 0) 755 return -EINVAL; 756 if (i == 1) { 757 /* Don't wrap an ASL around a single AS, just use the AS_ID 758 * directly. ASLs are a more limited resource. 759 */ 760 act = list_first_entry(&acts->list, struct efx_tc_action_set, list); 761 acts->fw_id = act->fw_id; 762 return 0; 763 } 764 if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2) 765 return -EOPNOTSUPP; /* Too many actions */ 766 inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i); 767 inbuf = kzalloc(inlen, GFP_KERNEL); 768 if (!inbuf) 769 return -ENOMEM; 770 i = 0; 771 list_for_each_entry(act, &acts->list, list) { 772 MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS, 773 i, act->fw_id); 774 i++; 775 } 776 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i); 777 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen, 778 outbuf, sizeof(outbuf), &outlen); 779 if (rc) 780 goto out_free; 781 if (outlen < sizeof(outbuf)) { 782 rc = -EIO; 783 goto out_free; 784 } 785 acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID); 786 /* We rely on the high bit of ASL IDs always being set. 787 * The firmware API guarantees this, but let's check it ourselves. 788 */ 789 if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) { 790 efx_mae_free_action_set_list(efx, acts); 791 rc = -EIO; 792 } 793 out_free: 794 kfree(inbuf); 795 return rc; 796 } 797 798 int efx_mae_free_action_set_list(struct efx_nic *efx, 799 struct efx_tc_action_set_list *acts) 800 { 801 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1)); 802 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1)); 803 size_t outlen; 804 int rc; 805 806 /* If this is just an AS_ID with no ASL wrapper, then there is 807 * nothing for us to free. (The AS will be freed later.) 808 */ 809 if (efx_mae_asl_id(acts->fw_id)) { 810 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID, 811 acts->fw_id); 812 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf, 813 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 814 if (rc) 815 return rc; 816 if (outlen < sizeof(outbuf)) 817 return -EIO; 818 /* FW freed a different ID than we asked for, should never happen. 819 * Warn because it means we've now got a different idea to the FW of 820 * what action-set-lists exist, which could cause mayhem later. 821 */ 822 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id)) 823 return -EIO; 824 } 825 /* We're probably about to free @acts, but let's just make sure its 826 * fw_id is blatted so that it won't look valid if it leaks out. 827 */ 828 acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL; 829 return 0; 830 } 831 832 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 833 const struct efx_tc_match *match) 834 { 835 if (match->mask.ingress_port) { 836 if (~match->mask.ingress_port) 837 return -EOPNOTSUPP; 838 MCDI_STRUCT_SET_DWORD(match_crit, 839 MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR, 840 match->value.ingress_port); 841 } 842 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK, 843 match->mask.ingress_port); 844 EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS), 845 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 846 match->value.ip_frag, 847 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 848 match->value.ip_firstfrag); 849 EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK), 850 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 851 match->mask.ip_frag, 852 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 853 match->mask.ip_firstfrag); 854 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID, 855 match->value.recirc_id); 856 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK, 857 match->mask.recirc_id); 858 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE, 859 match->value.eth_proto); 860 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK, 861 match->mask.eth_proto); 862 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE, 863 match->value.vlan_tci[0]); 864 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK, 865 match->mask.vlan_tci[0]); 866 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE, 867 match->value.vlan_proto[0]); 868 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK, 869 match->mask.vlan_proto[0]); 870 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE, 871 match->value.vlan_tci[1]); 872 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK, 873 match->mask.vlan_tci[1]); 874 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE, 875 match->value.vlan_proto[1]); 876 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK, 877 match->mask.vlan_proto[1]); 878 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE), 879 match->value.eth_saddr, ETH_ALEN); 880 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK), 881 match->mask.eth_saddr, ETH_ALEN); 882 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE), 883 match->value.eth_daddr, ETH_ALEN); 884 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK), 885 match->mask.eth_daddr, ETH_ALEN); 886 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO, 887 match->value.ip_proto); 888 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK, 889 match->mask.ip_proto); 890 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS, 891 match->value.ip_tos); 892 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK, 893 match->mask.ip_tos); 894 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL, 895 match->value.ip_ttl); 896 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK, 897 match->mask.ip_ttl); 898 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE, 899 match->value.src_ip); 900 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK, 901 match->mask.src_ip); 902 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE, 903 match->value.dst_ip); 904 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK, 905 match->mask.dst_ip); 906 #ifdef CONFIG_IPV6 907 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE), 908 &match->value.src_ip6, sizeof(struct in6_addr)); 909 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK), 910 &match->mask.src_ip6, sizeof(struct in6_addr)); 911 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE), 912 &match->value.dst_ip6, sizeof(struct in6_addr)); 913 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK), 914 &match->mask.dst_ip6, sizeof(struct in6_addr)); 915 #endif 916 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE, 917 match->value.l4_sport); 918 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK, 919 match->mask.l4_sport); 920 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE, 921 match->value.l4_dport); 922 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK, 923 match->mask.l4_dport); 924 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE, 925 match->value.tcp_flags); 926 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK, 927 match->mask.tcp_flags); 928 return 0; 929 } 930 931 int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, 932 u32 prio, u32 acts_id, u32 *id) 933 { 934 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN)); 935 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 936 MCDI_DECLARE_STRUCT_PTR(match_crit); 937 MCDI_DECLARE_STRUCT_PTR(response); 938 size_t outlen; 939 int rc; 940 941 if (!id) 942 return -EINVAL; 943 944 match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA); 945 response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE); 946 if (efx_mae_asl_id(acts_id)) { 947 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); 948 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 949 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 950 } else { 951 /* We only had one AS, so we didn't wrap it in an ASL */ 952 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 953 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 954 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); 955 } 956 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio); 957 rc = efx_mae_populate_match_criteria(match_crit, match); 958 if (rc) 959 return rc; 960 961 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf), 962 outbuf, sizeof(outbuf), &outlen); 963 if (rc) 964 return rc; 965 if (outlen < sizeof(outbuf)) 966 return -EIO; 967 *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 968 return 0; 969 } 970 971 int efx_mae_delete_rule(struct efx_nic *efx, u32 id) 972 { 973 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 974 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1)); 975 size_t outlen; 976 int rc; 977 978 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id); 979 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf), 980 outbuf, sizeof(outbuf), &outlen); 981 if (rc) 982 return rc; 983 if (outlen < sizeof(outbuf)) 984 return -EIO; 985 /* FW freed a different ID than we asked for, should also never happen. 986 * Warn because it means we've now got a different idea to the FW of 987 * what rules exist, which could cause mayhem later. 988 */ 989 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id)) 990 return -EIO; 991 return 0; 992 } 993 994 int efx_init_mae(struct efx_nic *efx) 995 { 996 struct ef100_nic_data *nic_data = efx->nic_data; 997 struct efx_mae *mae; 998 int rc; 999 1000 if (!nic_data->have_mport) 1001 return -EINVAL; 1002 1003 mae = kmalloc(sizeof(*mae), GFP_KERNEL); 1004 if (!mae) 1005 return -ENOMEM; 1006 1007 rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params); 1008 if (rc < 0) { 1009 kfree(mae); 1010 return rc; 1011 } 1012 efx->mae = mae; 1013 mae->efx = efx; 1014 return 0; 1015 } 1016 1017 void efx_fini_mae(struct efx_nic *efx) 1018 { 1019 struct efx_mae *mae = efx->mae; 1020 1021 kfree(mae); 1022 efx->mae = NULL; 1023 } 1024