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 #include "tc_conntrack.h" 20 21 int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label) 22 { 23 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN); 24 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN); 25 size_t outlen; 26 int rc; 27 28 if (WARN_ON_ONCE(!id)) 29 return -EINVAL; 30 if (WARN_ON_ONCE(!label)) 31 return -EINVAL; 32 33 MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_TYPE, 34 MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_MPORT_TYPE_ALIAS); 35 MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT, 36 MAE_MPORT_SELECTOR_ASSIGNED); 37 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_ALLOC, inbuf, sizeof(inbuf), 38 outbuf, sizeof(outbuf), &outlen); 39 if (rc) 40 return rc; 41 if (outlen < sizeof(outbuf)) 42 return -EIO; 43 *id = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_MPORT_ID); 44 *label = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL); 45 return 0; 46 } 47 48 int efx_mae_free_mport(struct efx_nic *efx, u32 id) 49 { 50 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_FREE_IN_LEN); 51 52 BUILD_BUG_ON(MC_CMD_MAE_MPORT_FREE_OUT_LEN); 53 MCDI_SET_DWORD(inbuf, MAE_MPORT_FREE_IN_MPORT_ID, id); 54 return efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_FREE, inbuf, sizeof(inbuf), 55 NULL, 0, NULL); 56 } 57 58 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out) 59 { 60 efx_dword_t mport; 61 62 EFX_POPULATE_DWORD_2(mport, 63 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT, 64 MAE_MPORT_SELECTOR_PPORT_ID, efx->port_num); 65 *out = EFX_DWORD_VAL(mport); 66 } 67 68 void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out) 69 { 70 efx_dword_t mport; 71 72 EFX_POPULATE_DWORD_3(mport, 73 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC, 74 MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER, 75 MAE_MPORT_SELECTOR_FUNC_VF_ID, MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL); 76 *out = EFX_DWORD_VAL(mport); 77 } 78 79 void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out) 80 { 81 efx_dword_t mport; 82 83 EFX_POPULATE_DWORD_3(mport, 84 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC, 85 MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER, 86 MAE_MPORT_SELECTOR_FUNC_VF_ID, vf_id); 87 *out = EFX_DWORD_VAL(mport); 88 } 89 90 /* Constructs an mport selector from an mport ID, because they're not the same */ 91 void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out) 92 { 93 efx_dword_t mport; 94 95 EFX_POPULATE_DWORD_2(mport, 96 MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID, 97 MAE_MPORT_SELECTOR_MPORT_ID, mport_id); 98 *out = EFX_DWORD_VAL(mport); 99 } 100 101 /* id is really only 24 bits wide */ 102 int efx_mae_fw_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id) 103 { 104 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN); 105 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_LOOKUP_IN_LEN); 106 size_t outlen; 107 int rc; 108 109 MCDI_SET_DWORD(inbuf, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR, selector); 110 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_LOOKUP, inbuf, sizeof(inbuf), 111 outbuf, sizeof(outbuf), &outlen); 112 if (rc) 113 return rc; 114 if (outlen < sizeof(outbuf)) 115 return -EIO; 116 *id = MCDI_DWORD(outbuf, MAE_MPORT_LOOKUP_OUT_MPORT_ID); 117 return 0; 118 } 119 120 int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue) 121 { 122 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_START_V2_IN_LEN); 123 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN); 124 u32 out_flags; 125 size_t outlen; 126 int rc; 127 128 MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_QID, 129 efx_rx_queue_index(rx_queue)); 130 MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_PACKET_SIZE, 131 efx->net_dev->mtu); 132 MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_COUNTER_TYPES_MASK, 133 BIT(MAE_COUNTER_TYPE_AR) | BIT(MAE_COUNTER_TYPE_CT) | 134 BIT(MAE_COUNTER_TYPE_OR)); 135 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_START, 136 inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 137 if (rc) 138 return rc; 139 if (outlen < sizeof(outbuf)) 140 return -EIO; 141 out_flags = MCDI_DWORD(outbuf, MAE_COUNTERS_STREAM_START_OUT_FLAGS); 142 if (out_flags & BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST)) { 143 netif_dbg(efx, drv, efx->net_dev, 144 "MAE counter stream uses credits\n"); 145 rx_queue->grant_credits = true; 146 out_flags &= ~BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST); 147 } 148 if (out_flags) { 149 netif_err(efx, drv, efx->net_dev, 150 "MAE counter stream start: unrecognised flags %x\n", 151 out_flags); 152 goto out_stop; 153 } 154 return 0; 155 out_stop: 156 efx_mae_stop_counters(efx, rx_queue); 157 return -EOPNOTSUPP; 158 } 159 160 static bool efx_mae_counters_flushed(u32 *flush_gen, u32 *seen_gen) 161 { 162 int i; 163 164 for (i = 0; i < EFX_TC_COUNTER_TYPE_MAX; i++) 165 if ((s32)(flush_gen[i] - seen_gen[i]) > 0) 166 return false; 167 return true; 168 } 169 170 int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue) 171 { 172 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_V2_OUT_LENMAX); 173 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN); 174 size_t outlen; 175 int rc, i; 176 177 MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_STOP_IN_QID, 178 efx_rx_queue_index(rx_queue)); 179 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_STOP, 180 inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 181 182 if (rc) 183 return rc; 184 185 netif_dbg(efx, drv, efx->net_dev, "Draining counters:\n"); 186 /* Only process received generation counts */ 187 for (i = 0; (i < (outlen / 4)) && (i < EFX_TC_COUNTER_TYPE_MAX); i++) { 188 efx->tc->flush_gen[i] = MCDI_ARRAY_DWORD(outbuf, 189 MAE_COUNTERS_STREAM_STOP_V2_OUT_GENERATION_COUNT, 190 i); 191 netif_dbg(efx, drv, efx->net_dev, 192 "\ttype %u, awaiting gen %u\n", i, 193 efx->tc->flush_gen[i]); 194 } 195 196 efx->tc->flush_counters = true; 197 198 /* Drain can take up to 2 seconds owing to FWRIVERHD-2884; whatever 199 * timeout we use, that delay is added to unload on nonresponsive 200 * hardware, so 2500ms seems like a reasonable compromise. 201 */ 202 if (!wait_event_timeout(efx->tc->flush_wq, 203 efx_mae_counters_flushed(efx->tc->flush_gen, 204 efx->tc->seen_gen), 205 msecs_to_jiffies(2500))) 206 netif_warn(efx, drv, efx->net_dev, 207 "Failed to drain counters RXQ, FW may be unhappy\n"); 208 209 efx->tc->flush_counters = false; 210 211 return rc; 212 } 213 214 void efx_mae_counters_grant_credits(struct work_struct *work) 215 { 216 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN); 217 struct efx_rx_queue *rx_queue = container_of(work, struct efx_rx_queue, 218 grant_work); 219 struct efx_nic *efx = rx_queue->efx; 220 unsigned int credits; 221 222 BUILD_BUG_ON(MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN); 223 credits = READ_ONCE(rx_queue->notified_count) - rx_queue->granted_count; 224 MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS, 225 credits); 226 if (!efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS, 227 inbuf, sizeof(inbuf), NULL, 0, NULL)) 228 rx_queue->granted_count += credits; 229 } 230 231 static int efx_mae_table_get_desc(struct efx_nic *efx, 232 struct efx_tc_table_desc *desc, 233 u32 table_id) 234 { 235 MCDI_DECLARE_BUF(outbuf, MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(16)); 236 MCDI_DECLARE_BUF(inbuf, MC_CMD_TABLE_DESCRIPTOR_IN_LEN); 237 unsigned int offset = 0, i; 238 size_t outlen; 239 int rc; 240 241 memset(desc, 0, sizeof(*desc)); 242 243 MCDI_SET_DWORD(inbuf, TABLE_DESCRIPTOR_IN_TABLE_ID, table_id); 244 more: 245 MCDI_SET_DWORD(inbuf, TABLE_DESCRIPTOR_IN_FIRST_FIELDS_INDEX, offset); 246 rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_DESCRIPTOR, inbuf, sizeof(inbuf), 247 outbuf, sizeof(outbuf), &outlen); 248 if (rc) 249 goto fail; 250 if (outlen < MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(1)) { 251 rc = -EIO; 252 goto fail; 253 } 254 if (!offset) { /* first iteration: get metadata */ 255 desc->type = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_TYPE); 256 desc->key_width = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_KEY_WIDTH); 257 desc->resp_width = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_RESP_WIDTH); 258 desc->n_keys = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_KEY_FIELDS); 259 desc->n_resps = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_RESP_FIELDS); 260 desc->n_prios = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_PRIORITIES); 261 desc->flags = MCDI_BYTE(outbuf, TABLE_DESCRIPTOR_OUT_FLAGS); 262 rc = -EOPNOTSUPP; 263 if (desc->flags) 264 goto fail; 265 desc->scheme = MCDI_BYTE(outbuf, TABLE_DESCRIPTOR_OUT_SCHEME); 266 if (desc->scheme) 267 goto fail; 268 rc = -ENOMEM; 269 desc->keys = kcalloc(desc->n_keys, 270 sizeof(struct efx_tc_table_field_fmt), 271 GFP_KERNEL); 272 if (!desc->keys) 273 goto fail; 274 desc->resps = kcalloc(desc->n_resps, 275 sizeof(struct efx_tc_table_field_fmt), 276 GFP_KERNEL); 277 if (!desc->resps) 278 goto fail; 279 } 280 /* FW could have returned more than the 16 field_descrs we 281 * made room for in our outbuf 282 */ 283 outlen = min(outlen, sizeof(outbuf)); 284 for (i = 0; i + offset < desc->n_keys + desc->n_resps; i++) { 285 struct efx_tc_table_field_fmt *field; 286 MCDI_DECLARE_STRUCT_PTR(fdesc); 287 288 if (outlen < MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(i + 1)) { 289 offset += i; 290 goto more; 291 } 292 if (i + offset < desc->n_keys) 293 field = desc->keys + i + offset; 294 else 295 field = desc->resps + (i + offset - desc->n_keys); 296 fdesc = MCDI_ARRAY_STRUCT_PTR(outbuf, 297 TABLE_DESCRIPTOR_OUT_FIELDS, i); 298 field->field_id = MCDI_STRUCT_WORD(fdesc, 299 TABLE_FIELD_DESCR_FIELD_ID); 300 field->lbn = MCDI_STRUCT_WORD(fdesc, TABLE_FIELD_DESCR_LBN); 301 field->width = MCDI_STRUCT_WORD(fdesc, TABLE_FIELD_DESCR_WIDTH); 302 field->masking = MCDI_STRUCT_BYTE(fdesc, TABLE_FIELD_DESCR_MASK_TYPE); 303 field->scheme = MCDI_STRUCT_BYTE(fdesc, TABLE_FIELD_DESCR_SCHEME); 304 } 305 return 0; 306 307 fail: 308 kfree(desc->keys); 309 kfree(desc->resps); 310 return rc; 311 } 312 313 static int efx_mae_table_hook_find(u16 n_fields, 314 struct efx_tc_table_field_fmt *fields, 315 u16 field_id) 316 { 317 unsigned int i; 318 319 for (i = 0; i < n_fields; i++) { 320 if (fields[i].field_id == field_id) 321 return i; 322 } 323 return -EPROTO; 324 } 325 326 #define TABLE_FIND_KEY(_desc, _id) \ 327 efx_mae_table_hook_find((_desc)->n_keys, (_desc)->keys, _id) 328 #define TABLE_FIND_RESP(_desc, _id) \ 329 efx_mae_table_hook_find((_desc)->n_resps, (_desc)->resps, _id) 330 331 #define TABLE_HOOK_KEY(_meta, _name, _mcdi_name) ({ \ 332 int _rc = TABLE_FIND_KEY(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name); \ 333 \ 334 if (_rc > U8_MAX) \ 335 _rc = -EOPNOTSUPP; \ 336 if (_rc >= 0) { \ 337 _meta->keys._name##_idx = _rc; \ 338 _rc = 0; \ 339 } \ 340 _rc; \ 341 }) 342 #define TABLE_HOOK_RESP(_meta, _name, _mcdi_name) ({ \ 343 int _rc = TABLE_FIND_RESP(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name); \ 344 \ 345 if (_rc > U8_MAX) \ 346 _rc = -EOPNOTSUPP; \ 347 if (_rc >= 0) { \ 348 _meta->resps._name##_idx = _rc; \ 349 _rc = 0; \ 350 } \ 351 _rc; \ 352 }) 353 354 static int efx_mae_table_hook_ct(struct efx_nic *efx, 355 struct efx_tc_table_ct *meta_ct) 356 { 357 int rc; 358 359 rc = TABLE_HOOK_KEY(meta_ct, eth_proto, ETHER_TYPE); 360 if (rc) 361 return rc; 362 rc = TABLE_HOOK_KEY(meta_ct, ip_proto, IP_PROTO); 363 if (rc) 364 return rc; 365 rc = TABLE_HOOK_KEY(meta_ct, src_ip, SRC_IP); 366 if (rc) 367 return rc; 368 rc = TABLE_HOOK_KEY(meta_ct, dst_ip, DST_IP); 369 if (rc) 370 return rc; 371 rc = TABLE_HOOK_KEY(meta_ct, l4_sport, SRC_PORT); 372 if (rc) 373 return rc; 374 rc = TABLE_HOOK_KEY(meta_ct, l4_dport, DST_PORT); 375 if (rc) 376 return rc; 377 rc = TABLE_HOOK_KEY(meta_ct, zone, DOMAIN); 378 if (rc) 379 return rc; 380 rc = TABLE_HOOK_RESP(meta_ct, dnat, NAT_DIR); 381 if (rc) 382 return rc; 383 rc = TABLE_HOOK_RESP(meta_ct, nat_ip, NAT_IP); 384 if (rc) 385 return rc; 386 rc = TABLE_HOOK_RESP(meta_ct, l4_natport, NAT_PORT); 387 if (rc) 388 return rc; 389 rc = TABLE_HOOK_RESP(meta_ct, mark, CT_MARK); 390 if (rc) 391 return rc; 392 rc = TABLE_HOOK_RESP(meta_ct, counter_id, COUNTER_ID); 393 if (rc) 394 return rc; 395 meta_ct->hooked = true; 396 return 0; 397 } 398 399 static void efx_mae_table_free_desc(struct efx_tc_table_desc *desc) 400 { 401 kfree(desc->keys); 402 kfree(desc->resps); 403 memset(desc, 0, sizeof(*desc)); 404 } 405 406 static bool efx_mae_check_table_exists(struct efx_nic *efx, u32 tbl_req) 407 { 408 MCDI_DECLARE_BUF(outbuf, MC_CMD_TABLE_LIST_OUT_LEN(16)); 409 MCDI_DECLARE_BUF(inbuf, MC_CMD_TABLE_LIST_IN_LEN); 410 u32 tbl_id, tbl_total, tbl_cnt, pos = 0; 411 size_t outlen, msg_max; 412 bool ct_tbl = false; 413 int rc, idx; 414 415 msg_max = sizeof(outbuf); 416 efx->tc->meta_ct.hooked = false; 417 more: 418 memset(outbuf, 0, sizeof(*outbuf)); 419 MCDI_SET_DWORD(inbuf, TABLE_LIST_IN_FIRST_TABLE_ID_INDEX, pos); 420 rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_LIST, inbuf, sizeof(inbuf), outbuf, 421 msg_max, &outlen); 422 if (rc) 423 return false; 424 425 if (outlen < MC_CMD_TABLE_LIST_OUT_LEN(1)) 426 return false; 427 428 tbl_total = MCDI_DWORD(outbuf, TABLE_LIST_OUT_N_TABLES); 429 tbl_cnt = MC_CMD_TABLE_LIST_OUT_TABLE_ID_NUM(min(outlen, msg_max)); 430 431 for (idx = 0; idx < tbl_cnt; idx++) { 432 tbl_id = MCDI_ARRAY_DWORD(outbuf, TABLE_LIST_OUT_TABLE_ID, idx); 433 if (tbl_id == tbl_req) { 434 ct_tbl = true; 435 break; 436 } 437 } 438 439 pos += tbl_cnt; 440 if (!ct_tbl && pos < tbl_total) 441 goto more; 442 443 return ct_tbl; 444 } 445 446 int efx_mae_get_tables(struct efx_nic *efx) 447 { 448 int rc; 449 450 efx->tc->meta_ct.hooked = false; 451 if (efx_mae_check_table_exists(efx, TABLE_ID_CONNTRACK_TABLE)) { 452 rc = efx_mae_table_get_desc(efx, &efx->tc->meta_ct.desc, 453 TABLE_ID_CONNTRACK_TABLE); 454 if (rc) { 455 pci_info(efx->pci_dev, 456 "FW does not support conntrack desc rc %d\n", 457 rc); 458 return 0; 459 } 460 461 rc = efx_mae_table_hook_ct(efx, &efx->tc->meta_ct); 462 if (rc) { 463 pci_info(efx->pci_dev, 464 "FW does not support conntrack hook rc %d\n", 465 rc); 466 return 0; 467 } 468 } else { 469 pci_info(efx->pci_dev, 470 "FW does not support conntrack table\n"); 471 } 472 return 0; 473 } 474 475 void efx_mae_free_tables(struct efx_nic *efx) 476 { 477 efx_mae_table_free_desc(&efx->tc->meta_ct.desc); 478 efx->tc->meta_ct.hooked = false; 479 } 480 481 static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps) 482 { 483 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN); 484 size_t outlen; 485 int rc; 486 487 BUILD_BUG_ON(MC_CMD_MAE_GET_CAPS_IN_LEN); 488 489 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_GET_CAPS, NULL, 0, outbuf, 490 sizeof(outbuf), &outlen); 491 if (rc) 492 return rc; 493 if (outlen < sizeof(outbuf)) 494 return -EIO; 495 caps->match_field_count = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT); 496 caps->encap_types = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED); 497 caps->action_prios = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ACTION_PRIOS); 498 return 0; 499 } 500 501 static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd, 502 u8 *field_support) 503 { 504 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS)); 505 MCDI_DECLARE_STRUCT_PTR(caps); 506 unsigned int count; 507 size_t outlen; 508 int rc, i; 509 510 /* AR and OR caps MCDIs have identical layout, so we are using the 511 * same code for both. 512 */ 513 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS) < 514 MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(MAE_NUM_FIELDS)); 515 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN); 516 BUILD_BUG_ON(MC_CMD_MAE_GET_OR_CAPS_IN_LEN); 517 518 rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen); 519 if (rc) 520 return rc; 521 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_COUNT_OFST != 522 MC_CMD_MAE_GET_OR_CAPS_OUT_COUNT_OFST); 523 count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT); 524 memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS); 525 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST != 526 MC_CMD_MAE_GET_OR_CAPS_OUT_FIELD_FLAGS_OFST); 527 caps = _MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS); 528 /* We're only interested in the support status enum, not any other 529 * flags, so just extract that from each entry. 530 */ 531 for (i = 0; i < count; i++) 532 if (i * sizeof(*outbuf) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen) 533 field_support[i] = EFX_DWORD_FIELD(caps[i], MAE_FIELD_FLAGS_SUPPORT_STATUS); 534 return 0; 535 } 536 537 int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps) 538 { 539 int rc; 540 541 rc = efx_mae_get_basic_caps(efx, caps); 542 if (rc) 543 return rc; 544 rc = efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS, 545 caps->action_rule_fields); 546 if (rc) 547 return rc; 548 return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_OR_CAPS, 549 caps->outer_rule_fields); 550 } 551 552 /* Bit twiddling: 553 * Prefix: 1...110...0 554 * ~: 0...001...1 555 * + 1: 0...010...0 is power of two 556 * so (~x) & ((~x) + 1) == 0. Converse holds also. 557 */ 558 #define is_prefix_byte(_x) !(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1)) 559 560 enum mask_type { MASK_ONES, MASK_ZEROES, MASK_PREFIX, MASK_OTHER }; 561 562 static const char *mask_type_name(enum mask_type typ) 563 { 564 switch (typ) { 565 case MASK_ONES: 566 return "all-1s"; 567 case MASK_ZEROES: 568 return "all-0s"; 569 case MASK_PREFIX: 570 return "prefix"; 571 case MASK_OTHER: 572 return "arbitrary"; 573 default: /* can't happen */ 574 return "unknown"; 575 } 576 } 577 578 /* Checks a (big-endian) bytestring is a bit prefix */ 579 static enum mask_type classify_mask(const u8 *mask, size_t len) 580 { 581 bool zeroes = true; /* All bits seen so far are zeroes */ 582 bool ones = true; /* All bits seen so far are ones */ 583 bool prefix = true; /* Valid prefix so far */ 584 size_t i; 585 586 for (i = 0; i < len; i++) { 587 if (ones) { 588 if (!is_prefix_byte(mask[i])) 589 prefix = false; 590 } else if (mask[i]) { 591 prefix = false; 592 } 593 if (mask[i] != 0xff) 594 ones = false; 595 if (mask[i]) 596 zeroes = false; 597 } 598 if (ones) 599 return MASK_ONES; 600 if (zeroes) 601 return MASK_ZEROES; 602 if (prefix) 603 return MASK_PREFIX; 604 return MASK_OTHER; 605 } 606 607 static int efx_mae_match_check_cap_typ(u8 support, enum mask_type typ) 608 { 609 switch (support) { 610 case MAE_FIELD_UNSUPPORTED: 611 case MAE_FIELD_SUPPORTED_MATCH_NEVER: 612 if (typ == MASK_ZEROES) 613 return 0; 614 return -EOPNOTSUPP; 615 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL: 616 if (typ == MASK_ZEROES) 617 return 0; 618 fallthrough; 619 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS: 620 if (typ == MASK_ONES) 621 return 0; 622 return -EINVAL; 623 case MAE_FIELD_SUPPORTED_MATCH_PREFIX: 624 if (typ == MASK_OTHER) 625 return -EOPNOTSUPP; 626 return 0; 627 case MAE_FIELD_SUPPORTED_MATCH_MASK: 628 return 0; 629 default: 630 return -EIO; 631 } 632 } 633 634 /* Validate field mask against hardware capabilities. Captures caller's 'rc' */ 635 #define CHECK(_mcdi, _field) ({ \ 636 enum mask_type typ = classify_mask((const u8 *)&mask->_field, \ 637 sizeof(mask->_field)); \ 638 \ 639 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 640 typ); \ 641 if (rc) \ 642 NL_SET_ERR_MSG_FMT_MOD(extack, \ 643 "No support for %s mask in field %s", \ 644 mask_type_name(typ), #_field); \ 645 rc; \ 646 }) 647 /* Booleans need special handling */ 648 #define CHECK_BIT(_mcdi, _field) ({ \ 649 enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES; \ 650 \ 651 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 652 typ); \ 653 if (rc) \ 654 NL_SET_ERR_MSG_FMT_MOD(extack, \ 655 "No support for %s mask in field %s", \ 656 mask_type_name(typ), #_field); \ 657 rc; \ 658 }) 659 660 int efx_mae_match_check_caps(struct efx_nic *efx, 661 const struct efx_tc_match_fields *mask, 662 struct netlink_ext_ack *extack) 663 { 664 const u8 *supported_fields = efx->tc->caps->action_rule_fields; 665 __be32 ingress_port = cpu_to_be32(mask->ingress_port); 666 enum mask_type ingress_port_mask_type; 667 int rc; 668 669 /* Check for _PREFIX assumes big-endian, so we need to convert */ 670 ingress_port_mask_type = classify_mask((const u8 *)&ingress_port, 671 sizeof(ingress_port)); 672 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT], 673 ingress_port_mask_type); 674 if (rc) { 675 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field ingress_port", 676 mask_type_name(ingress_port_mask_type)); 677 return rc; 678 } 679 if (CHECK(ETHER_TYPE, eth_proto) || 680 CHECK(VLAN0_TCI, vlan_tci[0]) || 681 CHECK(VLAN0_PROTO, vlan_proto[0]) || 682 CHECK(VLAN1_TCI, vlan_tci[1]) || 683 CHECK(VLAN1_PROTO, vlan_proto[1]) || 684 CHECK(ETH_SADDR, eth_saddr) || 685 CHECK(ETH_DADDR, eth_daddr) || 686 CHECK(IP_PROTO, ip_proto) || 687 CHECK(IP_TOS, ip_tos) || 688 CHECK(IP_TTL, ip_ttl) || 689 CHECK(SRC_IP4, src_ip) || 690 CHECK(DST_IP4, dst_ip) || 691 #ifdef CONFIG_IPV6 692 CHECK(SRC_IP6, src_ip6) || 693 CHECK(DST_IP6, dst_ip6) || 694 #endif 695 CHECK(L4_SPORT, l4_sport) || 696 CHECK(L4_DPORT, l4_dport) || 697 CHECK(TCP_FLAGS, tcp_flags) || 698 CHECK_BIT(TCP_SYN_FIN_RST, tcp_syn_fin_rst) || 699 CHECK_BIT(IS_IP_FRAG, ip_frag) || 700 CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) || 701 CHECK_BIT(DO_CT, ct_state_trk) || 702 CHECK_BIT(CT_HIT, ct_state_est) || 703 CHECK(CT_MARK, ct_mark) || 704 CHECK(CT_DOMAIN, ct_zone) || 705 CHECK(RECIRC_ID, recirc_id)) 706 return rc; 707 /* Matches on outer fields are done in a separate hardware table, 708 * the Outer Rule table. Thus the Action Rule merely does an 709 * exact match on Outer Rule ID if any outer field matches are 710 * present. The exception is the VNI/VSID (enc_keyid), which is 711 * available to the Action Rule match iff the Outer Rule matched 712 * (and thus identified the encap protocol to use to extract it). 713 */ 714 if (efx_tc_match_is_encap(mask)) { 715 rc = efx_mae_match_check_cap_typ( 716 supported_fields[MAE_FIELD_OUTER_RULE_ID], 717 MASK_ONES); 718 if (rc) { 719 NL_SET_ERR_MSG_MOD(extack, "No support for encap rule ID matches"); 720 return rc; 721 } 722 if (CHECK(ENC_VNET_ID, enc_keyid)) 723 return rc; 724 } else if (mask->enc_keyid) { 725 NL_SET_ERR_MSG_MOD(extack, "Match on enc_keyid requires other encap fields"); 726 return -EINVAL; 727 } 728 return 0; 729 } 730 731 /* Checks for match fields not supported in LHS Outer Rules */ 732 #define UNSUPPORTED(_field) ({ \ 733 enum mask_type typ = classify_mask((const u8 *)&mask->_field, \ 734 sizeof(mask->_field)); \ 735 \ 736 if (typ != MASK_ZEROES) { \ 737 NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\ 738 rc = -EOPNOTSUPP; \ 739 } \ 740 rc; \ 741 }) 742 #define UNSUPPORTED_BIT(_field) ({ \ 743 if (mask->_field) { \ 744 NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\ 745 rc = -EOPNOTSUPP; \ 746 } \ 747 rc; \ 748 }) 749 750 /* LHS rules are (normally) inserted in the Outer Rule table, which means 751 * they use ENC_ fields in hardware to match regular (not enc_) fields from 752 * &struct efx_tc_match_fields. 753 */ 754 int efx_mae_match_check_caps_lhs(struct efx_nic *efx, 755 const struct efx_tc_match_fields *mask, 756 struct netlink_ext_ack *extack) 757 { 758 const u8 *supported_fields = efx->tc->caps->outer_rule_fields; 759 __be32 ingress_port = cpu_to_be32(mask->ingress_port); 760 enum mask_type ingress_port_mask_type; 761 int rc; 762 763 /* Check for _PREFIX assumes big-endian, so we need to convert */ 764 ingress_port_mask_type = classify_mask((const u8 *)&ingress_port, 765 sizeof(ingress_port)); 766 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT], 767 ingress_port_mask_type); 768 if (rc) { 769 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s\n", 770 mask_type_name(ingress_port_mask_type), 771 "ingress_port"); 772 return rc; 773 } 774 if (CHECK(ENC_ETHER_TYPE, eth_proto) || 775 CHECK(ENC_VLAN0_TCI, vlan_tci[0]) || 776 CHECK(ENC_VLAN0_PROTO, vlan_proto[0]) || 777 CHECK(ENC_VLAN1_TCI, vlan_tci[1]) || 778 CHECK(ENC_VLAN1_PROTO, vlan_proto[1]) || 779 CHECK(ENC_ETH_SADDR, eth_saddr) || 780 CHECK(ENC_ETH_DADDR, eth_daddr) || 781 CHECK(ENC_IP_PROTO, ip_proto) || 782 CHECK(ENC_IP_TOS, ip_tos) || 783 CHECK(ENC_IP_TTL, ip_ttl) || 784 CHECK_BIT(ENC_IP_FRAG, ip_frag) || 785 UNSUPPORTED_BIT(ip_firstfrag) || 786 CHECK(ENC_SRC_IP4, src_ip) || 787 CHECK(ENC_DST_IP4, dst_ip) || 788 #ifdef CONFIG_IPV6 789 CHECK(ENC_SRC_IP6, src_ip6) || 790 CHECK(ENC_DST_IP6, dst_ip6) || 791 #endif 792 CHECK(ENC_L4_SPORT, l4_sport) || 793 CHECK(ENC_L4_DPORT, l4_dport) || 794 UNSUPPORTED(tcp_flags) || 795 CHECK_BIT(TCP_SYN_FIN_RST, tcp_syn_fin_rst)) 796 return rc; 797 if (efx_tc_match_is_encap(mask)) { 798 /* can't happen; disallowed for local rules, translated 799 * for foreign rules. 800 */ 801 NL_SET_ERR_MSG_MOD(extack, "Unexpected encap match in LHS rule"); 802 return -EOPNOTSUPP; 803 } 804 if (UNSUPPORTED(enc_keyid) || 805 /* Can't filter on conntrack in LHS rules */ 806 UNSUPPORTED_BIT(ct_state_trk) || 807 UNSUPPORTED_BIT(ct_state_est) || 808 UNSUPPORTED(ct_mark) || 809 UNSUPPORTED(recirc_id)) 810 return rc; 811 return 0; 812 } 813 #undef UNSUPPORTED 814 #undef CHECK_BIT 815 #undef CHECK 816 817 #define CHECK(_mcdi) ({ \ 818 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\ 819 MASK_ONES); \ 820 if (rc) \ 821 NL_SET_ERR_MSG_FMT_MOD(extack, \ 822 "No support for field %s", #_mcdi); \ 823 rc; \ 824 }) 825 /* Checks that the fields needed for encap-rule matches are supported by the 826 * MAE. All the fields are exact-match, except possibly ENC_IP_TOS. 827 */ 828 int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6, 829 u8 ip_tos_mask, __be16 udp_sport_mask, 830 struct netlink_ext_ack *extack) 831 { 832 u8 *supported_fields = efx->tc->caps->outer_rule_fields; 833 enum mask_type typ; 834 int rc; 835 836 if (CHECK(ENC_ETHER_TYPE)) 837 return rc; 838 if (ipv6) { 839 if (CHECK(ENC_SRC_IP6) || 840 CHECK(ENC_DST_IP6)) 841 return rc; 842 } else { 843 if (CHECK(ENC_SRC_IP4) || 844 CHECK(ENC_DST_IP4)) 845 return rc; 846 } 847 if (CHECK(ENC_L4_DPORT) || 848 CHECK(ENC_IP_PROTO)) 849 return rc; 850 typ = classify_mask((const u8 *)&udp_sport_mask, sizeof(udp_sport_mask)); 851 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_L4_SPORT], 852 typ); 853 if (rc) { 854 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s", 855 mask_type_name(typ), "enc_src_port"); 856 return rc; 857 } 858 typ = classify_mask(&ip_tos_mask, sizeof(ip_tos_mask)); 859 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_IP_TOS], 860 typ); 861 if (rc) { 862 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s", 863 mask_type_name(typ), "enc_ip_tos"); 864 return rc; 865 } 866 return 0; 867 } 868 #undef CHECK 869 870 int efx_mae_check_encap_type_supported(struct efx_nic *efx, enum efx_encap_type typ) 871 { 872 unsigned int bit; 873 874 switch (typ & EFX_ENCAP_TYPES_MASK) { 875 case EFX_ENCAP_TYPE_VXLAN: 876 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN_LBN; 877 break; 878 case EFX_ENCAP_TYPE_GENEVE: 879 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE_LBN; 880 break; 881 default: 882 return -EOPNOTSUPP; 883 } 884 if (efx->tc->caps->encap_types & BIT(bit)) 885 return 0; 886 return -EOPNOTSUPP; 887 } 888 889 int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt) 890 { 891 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1)); 892 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN); 893 size_t outlen; 894 int rc; 895 896 if (!cnt) 897 return -EINVAL; 898 899 MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT, 1); 900 MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE, cnt->type); 901 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_ALLOC, inbuf, sizeof(inbuf), 902 outbuf, sizeof(outbuf), &outlen); 903 if (rc) 904 return rc; 905 /* pcol says this can't happen, since count is 1 */ 906 if (outlen < sizeof(outbuf)) 907 return -EIO; 908 cnt->fw_id = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_COUNTER_ID); 909 cnt->gen = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT); 910 return 0; 911 } 912 913 int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt) 914 { 915 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_FREE_OUT_LEN(1)); 916 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN); 917 size_t outlen; 918 int rc; 919 920 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT, 1); 921 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID, cnt->fw_id); 922 MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE, cnt->type); 923 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_FREE, inbuf, sizeof(inbuf), 924 outbuf, sizeof(outbuf), &outlen); 925 if (rc) 926 return rc; 927 /* pcol says this can't happen, since count is 1 */ 928 if (outlen < sizeof(outbuf)) 929 return -EIO; 930 /* FW freed a different ID than we asked for, should also never happen. 931 * Warn because it means we've now got a different idea to the FW of 932 * what counters exist, which could cause mayhem later. 933 */ 934 if (WARN_ON(MCDI_DWORD(outbuf, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID) != 935 cnt->fw_id)) 936 return -EIO; 937 return 0; 938 } 939 940 static int efx_mae_encap_type_to_mae_type(enum efx_encap_type type) 941 { 942 switch (type & EFX_ENCAP_TYPES_MASK) { 943 case EFX_ENCAP_TYPE_NONE: 944 return MAE_MCDI_ENCAP_TYPE_NONE; 945 case EFX_ENCAP_TYPE_VXLAN: 946 return MAE_MCDI_ENCAP_TYPE_VXLAN; 947 case EFX_ENCAP_TYPE_GENEVE: 948 return MAE_MCDI_ENCAP_TYPE_GENEVE; 949 default: 950 return -EOPNOTSUPP; 951 } 952 } 953 954 int efx_mae_allocate_encap_md(struct efx_nic *efx, 955 struct efx_tc_encap_action *encap) 956 { 957 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(EFX_TC_MAX_ENCAP_HDR)); 958 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN); 959 size_t inlen, outlen; 960 int rc; 961 962 rc = efx_mae_encap_type_to_mae_type(encap->type); 963 if (rc < 0) 964 return rc; 965 MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, rc); 966 inlen = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(encap->encap_hdr_len); 967 if (WARN_ON(inlen > sizeof(inbuf))) /* can't happen */ 968 return -EINVAL; 969 memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA), 970 encap->encap_hdr, 971 encap->encap_hdr_len); 972 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_ALLOC, inbuf, 973 inlen, outbuf, sizeof(outbuf), &outlen); 974 if (rc) 975 return rc; 976 if (outlen < sizeof(outbuf)) 977 return -EIO; 978 encap->fw_id = MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID); 979 return 0; 980 } 981 982 int efx_mae_update_encap_md(struct efx_nic *efx, 983 struct efx_tc_encap_action *encap) 984 { 985 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(EFX_TC_MAX_ENCAP_HDR)); 986 size_t inlen; 987 int rc; 988 989 rc = efx_mae_encap_type_to_mae_type(encap->type); 990 if (rc < 0) 991 return rc; 992 MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_ENCAP_TYPE, rc); 993 MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_EH_ID, 994 encap->fw_id); 995 inlen = MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(encap->encap_hdr_len); 996 if (WARN_ON(inlen > sizeof(inbuf))) /* can't happen */ 997 return -EINVAL; 998 memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_HDR_DATA), 999 encap->encap_hdr, 1000 encap->encap_hdr_len); 1001 1002 BUILD_BUG_ON(MC_CMD_MAE_ENCAP_HEADER_UPDATE_OUT_LEN != 0); 1003 return efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_UPDATE, inbuf, 1004 inlen, NULL, 0, NULL); 1005 } 1006 1007 int efx_mae_free_encap_md(struct efx_nic *efx, 1008 struct efx_tc_encap_action *encap) 1009 { 1010 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1)); 1011 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1)); 1012 size_t outlen; 1013 int rc; 1014 1015 MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_FREE_IN_EH_ID, encap->fw_id); 1016 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_FREE, inbuf, 1017 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1018 if (rc) 1019 return rc; 1020 if (outlen < sizeof(outbuf)) 1021 return -EIO; 1022 /* FW freed a different ID than we asked for, should also never happen. 1023 * Warn because it means we've now got a different idea to the FW of 1024 * what encap_mds exist, which could cause mayhem later. 1025 */ 1026 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) != encap->fw_id)) 1027 return -EIO; 1028 /* We're probably about to free @encap, but let's just make sure its 1029 * fw_id is blatted so that it won't look valid if it leaks out. 1030 */ 1031 encap->fw_id = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL; 1032 return 0; 1033 } 1034 1035 int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id) 1036 { 1037 struct ef100_nic_data *nic_data = efx->nic_data; 1038 struct efx_mae *mae = efx->mae; 1039 struct rhashtable_iter walk; 1040 struct mae_mport_desc *m; 1041 int rc = -ENOENT; 1042 1043 rhashtable_walk_enter(&mae->mports_ht, &walk); 1044 rhashtable_walk_start(&walk); 1045 while ((m = rhashtable_walk_next(&walk)) != NULL) { 1046 if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC && 1047 m->interface_idx == nic_data->local_mae_intf && 1048 m->pf_idx == 0 && 1049 m->vf_idx == vf_idx) { 1050 *id = m->mport_id; 1051 rc = 0; 1052 break; 1053 } 1054 } 1055 rhashtable_walk_stop(&walk); 1056 rhashtable_walk_exit(&walk); 1057 return rc; 1058 } 1059 1060 static bool efx_mae_asl_id(u32 id) 1061 { 1062 return !!(id & BIT(31)); 1063 } 1064 1065 /* mport handling */ 1066 static const struct rhashtable_params efx_mae_mports_ht_params = { 1067 .key_len = sizeof(u32), 1068 .key_offset = offsetof(struct mae_mport_desc, mport_id), 1069 .head_offset = offsetof(struct mae_mport_desc, linkage), 1070 }; 1071 1072 struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id) 1073 { 1074 return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id, 1075 efx_mae_mports_ht_params); 1076 } 1077 1078 static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc) 1079 { 1080 struct efx_mae *mae = efx->mae; 1081 int rc; 1082 1083 rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage, 1084 efx_mae_mports_ht_params); 1085 1086 if (rc) { 1087 pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n", 1088 desc->mport_id, rc); 1089 kfree(desc); 1090 return rc; 1091 } 1092 1093 return rc; 1094 } 1095 1096 void efx_mae_remove_mport(void *desc, void *arg) 1097 { 1098 struct mae_mport_desc *mport = desc; 1099 1100 synchronize_rcu(); 1101 kfree(mport); 1102 } 1103 1104 static int efx_mae_process_mport(struct efx_nic *efx, 1105 struct mae_mport_desc *desc) 1106 { 1107 struct ef100_nic_data *nic_data = efx->nic_data; 1108 struct mae_mport_desc *mport; 1109 1110 mport = efx_mae_get_mport(efx, desc->mport_id); 1111 if (!IS_ERR_OR_NULL(mport)) { 1112 netif_err(efx, drv, efx->net_dev, 1113 "mport with id %u does exist!!!\n", desc->mport_id); 1114 return -EEXIST; 1115 } 1116 1117 if (nic_data->have_own_mport && 1118 desc->mport_id == nic_data->own_mport) { 1119 WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC); 1120 WARN_ON(desc->vnic_client_type != 1121 MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION); 1122 nic_data->local_mae_intf = desc->interface_idx; 1123 nic_data->have_local_intf = true; 1124 pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n", 1125 nic_data->local_mae_intf); 1126 } 1127 1128 return efx_mae_add_mport(efx, desc); 1129 } 1130 1131 #define MCDI_MPORT_JOURNAL_LEN \ 1132 ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4) 1133 1134 int efx_mae_enumerate_mports(struct efx_nic *efx) 1135 { 1136 efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL); 1137 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN); 1138 MCDI_DECLARE_STRUCT_PTR(desc); 1139 size_t outlen, stride, count; 1140 int rc = 0, i; 1141 1142 if (!outbuf) 1143 return -ENOMEM; 1144 do { 1145 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf, 1146 sizeof(inbuf), outbuf, 1147 MCDI_MPORT_JOURNAL_LEN, &outlen); 1148 if (rc) 1149 goto fail; 1150 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) { 1151 rc = -EIO; 1152 goto fail; 1153 } 1154 count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT); 1155 if (!count) 1156 continue; /* not break; we want to look at MORE flag */ 1157 stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC); 1158 if (stride < MAE_MPORT_DESC_LEN) { 1159 rc = -EIO; 1160 goto fail; 1161 } 1162 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) { 1163 rc = -EIO; 1164 goto fail; 1165 } 1166 1167 for (i = 0; i < count; i++) { 1168 struct mae_mport_desc *d; 1169 1170 d = kzalloc(sizeof(*d), GFP_KERNEL); 1171 if (!d) { 1172 rc = -ENOMEM; 1173 goto fail; 1174 } 1175 1176 desc = (efx_dword_t *) 1177 _MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST + 1178 i * stride); 1179 d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID); 1180 d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS); 1181 d->caller_flags = MCDI_STRUCT_DWORD(desc, 1182 MAE_MPORT_DESC_CALLER_FLAGS); 1183 d->mport_type = MCDI_STRUCT_DWORD(desc, 1184 MAE_MPORT_DESC_MPORT_TYPE); 1185 switch (d->mport_type) { 1186 case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT: 1187 d->port_idx = MCDI_STRUCT_DWORD(desc, 1188 MAE_MPORT_DESC_NET_PORT_IDX); 1189 break; 1190 case MAE_MPORT_DESC_MPORT_TYPE_ALIAS: 1191 d->alias_mport_id = MCDI_STRUCT_DWORD(desc, 1192 MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID); 1193 break; 1194 case MAE_MPORT_DESC_MPORT_TYPE_VNIC: 1195 d->vnic_client_type = MCDI_STRUCT_DWORD(desc, 1196 MAE_MPORT_DESC_VNIC_CLIENT_TYPE); 1197 d->interface_idx = MCDI_STRUCT_DWORD(desc, 1198 MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE); 1199 d->pf_idx = MCDI_STRUCT_WORD(desc, 1200 MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX); 1201 d->vf_idx = MCDI_STRUCT_WORD(desc, 1202 MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX); 1203 break; 1204 default: 1205 /* Unknown mport_type, just accept it */ 1206 break; 1207 } 1208 rc = efx_mae_process_mport(efx, d); 1209 /* Any failure will be due to memory allocation faiure, 1210 * so there is no point to try subsequent entries. 1211 */ 1212 if (rc) 1213 goto fail; 1214 } 1215 } while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) && 1216 !WARN_ON(!count)); 1217 fail: 1218 kfree(outbuf); 1219 return rc; 1220 } 1221 1222 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) 1223 { 1224 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 1225 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN); 1226 size_t outlen; 1227 int rc; 1228 1229 MCDI_POPULATE_DWORD_3(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS, 1230 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, act->vlan_push, 1231 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop, 1232 MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap); 1233 1234 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 1235 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 1236 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 1237 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 1238 if (act->count && !WARN_ON(!act->count->cnt)) 1239 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 1240 act->count->cnt->fw_id); 1241 else 1242 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 1243 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 1244 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, 1245 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL); 1246 if (act->vlan_push) { 1247 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE, 1248 act->vlan_tci[0]); 1249 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE, 1250 act->vlan_proto[0]); 1251 } 1252 if (act->vlan_push >= 2) { 1253 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE, 1254 act->vlan_tci[1]); 1255 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE, 1256 act->vlan_proto[1]); 1257 } 1258 if (act->encap_md) 1259 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 1260 act->encap_md->fw_id); 1261 else 1262 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 1263 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); 1264 if (act->deliver) 1265 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER, 1266 act->dest_mport); 1267 BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL); 1268 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf), 1269 outbuf, sizeof(outbuf), &outlen); 1270 if (rc) 1271 return rc; 1272 if (outlen < sizeof(outbuf)) 1273 return -EIO; 1274 act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 1275 /* We rely on the high bit of AS IDs always being clear. 1276 * The firmware API guarantees this, but let's check it ourselves. 1277 */ 1278 if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) { 1279 efx_mae_free_action_set(efx, act->fw_id); 1280 return -EIO; 1281 } 1282 return 0; 1283 } 1284 1285 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id) 1286 { 1287 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 1288 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1)); 1289 size_t outlen; 1290 int rc; 1291 1292 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id); 1293 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf), 1294 outbuf, sizeof(outbuf), &outlen); 1295 if (rc) 1296 return rc; 1297 if (outlen < sizeof(outbuf)) 1298 return -EIO; 1299 /* FW freed a different ID than we asked for, should never happen. 1300 * Warn because it means we've now got a different idea to the FW of 1301 * what action-sets exist, which could cause mayhem later. 1302 */ 1303 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id)) 1304 return -EIO; 1305 return 0; 1306 } 1307 1308 int efx_mae_alloc_action_set_list(struct efx_nic *efx, 1309 struct efx_tc_action_set_list *acts) 1310 { 1311 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN); 1312 struct efx_tc_action_set *act; 1313 size_t inlen, outlen, i = 0; 1314 efx_dword_t *inbuf; 1315 int rc; 1316 1317 list_for_each_entry(act, &acts->list, list) 1318 i++; 1319 if (i == 0) 1320 return -EINVAL; 1321 if (i == 1) { 1322 /* Don't wrap an ASL around a single AS, just use the AS_ID 1323 * directly. ASLs are a more limited resource. 1324 */ 1325 act = list_first_entry(&acts->list, struct efx_tc_action_set, list); 1326 acts->fw_id = act->fw_id; 1327 return 0; 1328 } 1329 if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2) 1330 return -EOPNOTSUPP; /* Too many actions */ 1331 inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i); 1332 inbuf = kzalloc(inlen, GFP_KERNEL); 1333 if (!inbuf) 1334 return -ENOMEM; 1335 i = 0; 1336 list_for_each_entry(act, &acts->list, list) { 1337 MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS, 1338 i, act->fw_id); 1339 i++; 1340 } 1341 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i); 1342 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen, 1343 outbuf, sizeof(outbuf), &outlen); 1344 if (rc) 1345 goto out_free; 1346 if (outlen < sizeof(outbuf)) { 1347 rc = -EIO; 1348 goto out_free; 1349 } 1350 acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID); 1351 /* We rely on the high bit of ASL IDs always being set. 1352 * The firmware API guarantees this, but let's check it ourselves. 1353 */ 1354 if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) { 1355 efx_mae_free_action_set_list(efx, acts); 1356 rc = -EIO; 1357 } 1358 out_free: 1359 kfree(inbuf); 1360 return rc; 1361 } 1362 1363 int efx_mae_free_action_set_list(struct efx_nic *efx, 1364 struct efx_tc_action_set_list *acts) 1365 { 1366 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1)); 1367 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1)); 1368 size_t outlen; 1369 int rc; 1370 1371 /* If this is just an AS_ID with no ASL wrapper, then there is 1372 * nothing for us to free. (The AS will be freed later.) 1373 */ 1374 if (efx_mae_asl_id(acts->fw_id)) { 1375 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID, 1376 acts->fw_id); 1377 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf, 1378 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1379 if (rc) 1380 return rc; 1381 if (outlen < sizeof(outbuf)) 1382 return -EIO; 1383 /* FW freed a different ID than we asked for, should never happen. 1384 * Warn because it means we've now got a different idea to the FW of 1385 * what action-set-lists exist, which could cause mayhem later. 1386 */ 1387 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id)) 1388 return -EIO; 1389 } 1390 /* We're probably about to free @acts, but let's just make sure its 1391 * fw_id is blatted so that it won't look valid if it leaks out. 1392 */ 1393 acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL; 1394 return 0; 1395 } 1396 1397 int efx_mae_register_encap_match(struct efx_nic *efx, 1398 struct efx_tc_encap_match *encap) 1399 { 1400 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN)); 1401 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 1402 MCDI_DECLARE_STRUCT_PTR(match_crit); 1403 size_t outlen; 1404 int rc; 1405 1406 rc = efx_mae_encap_type_to_mae_type(encap->tun_type); 1407 if (rc < 0) 1408 return rc; 1409 match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA); 1410 /* The struct contains IP src and dst, and udp dport. 1411 * So we actually need to filter on IP src and dst, L4 dport, and 1412 * ipproto == udp. 1413 */ 1414 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, rc); 1415 #ifdef CONFIG_IPV6 1416 if (encap->src_ip | encap->dst_ip) { 1417 #endif 1418 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE, 1419 encap->src_ip); 1420 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK, 1421 ~(__be32)0); 1422 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE, 1423 encap->dst_ip); 1424 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK, 1425 ~(__be32)0); 1426 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 1427 htons(ETH_P_IP)); 1428 #ifdef CONFIG_IPV6 1429 } else { 1430 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE), 1431 &encap->src_ip6, sizeof(encap->src_ip6)); 1432 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK), 1433 0xff, sizeof(encap->src_ip6)); 1434 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE), 1435 &encap->dst_ip6, sizeof(encap->dst_ip6)); 1436 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK), 1437 0xff, sizeof(encap->dst_ip6)); 1438 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 1439 htons(ETH_P_IPV6)); 1440 } 1441 #endif 1442 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK, 1443 ~(__be16)0); 1444 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1445 encap->udp_dport); 1446 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1447 ~(__be16)0); 1448 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1449 encap->udp_sport); 1450 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1451 encap->udp_sport_mask); 1452 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, IPPROTO_UDP); 1453 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, ~0); 1454 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS, 1455 encap->ip_tos); 1456 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK, 1457 encap->ip_tos_mask); 1458 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf, 1459 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1460 if (rc) 1461 return rc; 1462 if (outlen < sizeof(outbuf)) 1463 return -EIO; 1464 encap->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 1465 return 0; 1466 } 1467 1468 int efx_mae_unregister_encap_match(struct efx_nic *efx, 1469 struct efx_tc_encap_match *encap) 1470 { 1471 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 1472 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1)); 1473 size_t outlen; 1474 int rc; 1475 1476 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, encap->fw_id); 1477 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf, 1478 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1479 if (rc) 1480 return rc; 1481 if (outlen < sizeof(outbuf)) 1482 return -EIO; 1483 /* FW freed a different ID than we asked for, should also never happen. 1484 * Warn because it means we've now got a different idea to the FW of 1485 * what encap_mds exist, which could cause mayhem later. 1486 */ 1487 if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != encap->fw_id)) 1488 return -EIO; 1489 /* We're probably about to free @encap, but let's just make sure its 1490 * fw_id is blatted so that it won't look valid if it leaks out. 1491 */ 1492 encap->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL; 1493 return 0; 1494 } 1495 1496 static int efx_mae_populate_lhs_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 1497 const struct efx_tc_match *match) 1498 { 1499 if (match->mask.ingress_port) { 1500 if (~match->mask.ingress_port) 1501 return -EOPNOTSUPP; 1502 MCDI_STRUCT_SET_DWORD(match_crit, 1503 MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR, 1504 match->value.ingress_port); 1505 } 1506 MCDI_STRUCT_SET_DWORD(match_crit, MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR_MASK, 1507 match->mask.ingress_port); 1508 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 1509 match->value.eth_proto); 1510 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK, 1511 match->mask.eth_proto); 1512 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE, 1513 match->value.vlan_tci[0]); 1514 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE_MASK, 1515 match->mask.vlan_tci[0]); 1516 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE, 1517 match->value.vlan_proto[0]); 1518 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE_MASK, 1519 match->mask.vlan_proto[0]); 1520 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE, 1521 match->value.vlan_tci[1]); 1522 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE_MASK, 1523 match->mask.vlan_tci[1]); 1524 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE, 1525 match->value.vlan_proto[1]); 1526 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE_MASK, 1527 match->mask.vlan_proto[1]); 1528 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE), 1529 match->value.eth_saddr, ETH_ALEN); 1530 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE_MASK), 1531 match->mask.eth_saddr, ETH_ALEN); 1532 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE), 1533 match->value.eth_daddr, ETH_ALEN); 1534 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE_MASK), 1535 match->mask.eth_daddr, ETH_ALEN); 1536 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, 1537 match->value.ip_proto); 1538 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, 1539 match->mask.ip_proto); 1540 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS, 1541 match->value.ip_tos); 1542 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK, 1543 match->mask.ip_tos); 1544 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL, 1545 match->value.ip_ttl); 1546 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL_MASK, 1547 match->mask.ip_ttl); 1548 MCDI_STRUCT_POPULATE_BYTE_1(match_crit, 1549 MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS, 1550 MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG, 1551 match->value.ip_frag); 1552 MCDI_STRUCT_POPULATE_BYTE_1(match_crit, 1553 MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS_MASK, 1554 MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG_MASK, 1555 match->mask.ip_frag); 1556 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE, 1557 match->value.src_ip); 1558 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK, 1559 match->mask.src_ip); 1560 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE, 1561 match->value.dst_ip); 1562 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK, 1563 match->mask.dst_ip); 1564 #ifdef CONFIG_IPV6 1565 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE), 1566 &match->value.src_ip6, sizeof(struct in6_addr)); 1567 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK), 1568 &match->mask.src_ip6, sizeof(struct in6_addr)); 1569 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE), 1570 &match->value.dst_ip6, sizeof(struct in6_addr)); 1571 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK), 1572 &match->mask.dst_ip6, sizeof(struct in6_addr)); 1573 #endif 1574 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE, 1575 match->value.l4_sport); 1576 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE_MASK, 1577 match->mask.l4_sport); 1578 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1579 match->value.l4_dport); 1580 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1581 match->mask.l4_dport); 1582 /* No enc-keys in LHS rules. Caps check should have caught this; any 1583 * enc-keys from an fLHS should have been translated to regular keys 1584 * and any EM should be a pseudo (we're an OR so can't have a direct 1585 * EM with another OR). 1586 */ 1587 if (WARN_ON_ONCE(match->encap && !match->encap->type)) 1588 return -EOPNOTSUPP; 1589 if (WARN_ON_ONCE(match->mask.enc_src_ip)) 1590 return -EOPNOTSUPP; 1591 if (WARN_ON_ONCE(match->mask.enc_dst_ip)) 1592 return -EOPNOTSUPP; 1593 #ifdef CONFIG_IPV6 1594 if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6))) 1595 return -EOPNOTSUPP; 1596 if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6))) 1597 return -EOPNOTSUPP; 1598 #endif 1599 if (WARN_ON_ONCE(match->mask.enc_ip_tos)) 1600 return -EOPNOTSUPP; 1601 if (WARN_ON_ONCE(match->mask.enc_ip_ttl)) 1602 return -EOPNOTSUPP; 1603 if (WARN_ON_ONCE(match->mask.enc_sport)) 1604 return -EOPNOTSUPP; 1605 if (WARN_ON_ONCE(match->mask.enc_dport)) 1606 return -EOPNOTSUPP; 1607 if (WARN_ON_ONCE(match->mask.enc_keyid)) 1608 return -EOPNOTSUPP; 1609 return 0; 1610 } 1611 1612 static int efx_mae_insert_lhs_outer_rule(struct efx_nic *efx, 1613 struct efx_tc_lhs_rule *rule, u32 prio) 1614 { 1615 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN)); 1616 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 1617 MCDI_DECLARE_STRUCT_PTR(match_crit); 1618 const struct efx_tc_lhs_action *act; 1619 size_t outlen; 1620 int rc; 1621 1622 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_PRIO, prio); 1623 /* match */ 1624 match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA); 1625 rc = efx_mae_populate_lhs_match_criteria(match_crit, &rule->match); 1626 if (rc) 1627 return rc; 1628 1629 /* action */ 1630 act = &rule->lhs_act; 1631 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, 1632 MAE_MCDI_ENCAP_TYPE_NONE); 1633 /* We always inhibit CT lookup on TCP_INTERESTING_FLAGS, since the 1634 * SW path needs to process the packet to update the conntrack tables 1635 * on connection establishment (SYN) or termination (FIN, RST). 1636 */ 1637 MCDI_POPULATE_DWORD_6(inbuf, MAE_OUTER_RULE_INSERT_IN_LOOKUP_CONTROL, 1638 MAE_OUTER_RULE_INSERT_IN_DO_CT, !!act->zone, 1639 MAE_OUTER_RULE_INSERT_IN_CT_TCP_FLAGS_INHIBIT, 1, 1640 MAE_OUTER_RULE_INSERT_IN_CT_DOMAIN, 1641 act->zone ? act->zone->zone : 0, 1642 MAE_OUTER_RULE_INSERT_IN_CT_VNI_MODE, 1643 MAE_CT_VNI_MODE_ZERO, 1644 MAE_OUTER_RULE_INSERT_IN_DO_COUNT, !!act->count, 1645 MAE_OUTER_RULE_INSERT_IN_RECIRC_ID, 1646 act->rid ? act->rid->fw_id : 0); 1647 if (act->count) 1648 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_COUNTER_ID, 1649 act->count->cnt->fw_id); 1650 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf, 1651 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1652 if (rc) 1653 return rc; 1654 if (outlen < sizeof(outbuf)) 1655 return -EIO; 1656 rule->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 1657 return 0; 1658 } 1659 1660 int efx_mae_insert_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule, 1661 u32 prio) 1662 { 1663 return efx_mae_insert_lhs_outer_rule(efx, rule, prio); 1664 } 1665 1666 static int efx_mae_remove_lhs_outer_rule(struct efx_nic *efx, 1667 struct efx_tc_lhs_rule *rule) 1668 { 1669 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 1670 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1)); 1671 size_t outlen; 1672 int rc; 1673 1674 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, rule->fw_id); 1675 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf, 1676 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1677 if (rc) 1678 return rc; 1679 if (outlen < sizeof(outbuf)) 1680 return -EIO; 1681 /* FW freed a different ID than we asked for, should also never happen. 1682 * Warn because it means we've now got a different idea to the FW of 1683 * what encap_mds exist, which could cause mayhem later. 1684 */ 1685 if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != rule->fw_id)) 1686 return -EIO; 1687 /* We're probably about to free @rule, but let's just make sure its 1688 * fw_id is blatted so that it won't look valid if it leaks out. 1689 */ 1690 rule->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL; 1691 return 0; 1692 } 1693 1694 int efx_mae_remove_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule) 1695 { 1696 return efx_mae_remove_lhs_outer_rule(efx, rule); 1697 } 1698 1699 /* Populating is done by taking each byte of @value in turn and storing 1700 * it in the appropriate bits of @row. @value must be big-endian; we 1701 * convert it to little-endianness as we go. 1702 */ 1703 static int efx_mae_table_populate(struct efx_tc_table_field_fmt field, 1704 __le32 *row, size_t row_bits, 1705 void *value, size_t value_size) 1706 { 1707 unsigned int i; 1708 1709 /* For now only scheme 0 is supported for any field, so we check here 1710 * (rather than, say, in calling code, which knows the semantics and 1711 * could in principle encode for other schemes). 1712 */ 1713 if (field.scheme) 1714 return -EOPNOTSUPP; 1715 if (DIV_ROUND_UP(field.width, 8) != value_size) 1716 return -EINVAL; 1717 if (field.lbn + field.width > row_bits) 1718 return -EINVAL; 1719 for (i = 0; i < value_size; i++) { 1720 unsigned int bn = field.lbn + i * 8; 1721 unsigned int wn = bn / 32; 1722 u64 v; 1723 1724 v = ((u8 *)value)[value_size - i - 1]; 1725 v <<= (bn % 32); 1726 row[wn] |= cpu_to_le32(v & 0xffffffff); 1727 if (wn * 32 < row_bits) 1728 row[wn + 1] |= cpu_to_le32(v >> 32); 1729 } 1730 return 0; 1731 } 1732 1733 static int efx_mae_table_populate_bool(struct efx_tc_table_field_fmt field, 1734 __le32 *row, size_t row_bits, bool value) 1735 { 1736 u8 v = value ? 1 : 0; 1737 1738 if (field.width != 1) 1739 return -EINVAL; 1740 return efx_mae_table_populate(field, row, row_bits, &v, 1); 1741 } 1742 1743 static int efx_mae_table_populate_ipv4(struct efx_tc_table_field_fmt field, 1744 __le32 *row, size_t row_bits, __be32 value) 1745 { 1746 /* IPv4 is placed in the first 4 bytes of an IPv6-sized field */ 1747 struct in6_addr v = {}; 1748 1749 if (field.width != 128) 1750 return -EINVAL; 1751 v.s6_addr32[0] = value; 1752 return efx_mae_table_populate(field, row, row_bits, &v, sizeof(v)); 1753 } 1754 1755 static int efx_mae_table_populate_u24(struct efx_tc_table_field_fmt field, 1756 __le32 *row, size_t row_bits, u32 value) 1757 { 1758 __be32 v = cpu_to_be32(value); 1759 1760 /* We adjust value_size here since just 3 bytes will be copied, and 1761 * the pointer to the value is set discarding the first byte which is 1762 * the most significant byte for a big-endian 4-bytes value. 1763 */ 1764 return efx_mae_table_populate(field, row, row_bits, ((void *)&v) + 1, 1765 sizeof(v) - 1); 1766 } 1767 1768 #define _TABLE_POPULATE(dst, dw, _field, _value) ({ \ 1769 typeof(_value) _v = _value; \ 1770 \ 1771 (_field.width == sizeof(_value) * 8) ? \ 1772 efx_mae_table_populate(_field, dst, dw, &_v, \ 1773 sizeof(_v)) : -EINVAL; \ 1774 }) 1775 #define TABLE_POPULATE_KEY_IPV4(dst, _table, _field, _value) \ 1776 efx_mae_table_populate_ipv4(efx->tc->meta_##_table.desc.keys \ 1777 [efx->tc->meta_##_table.keys._field##_idx],\ 1778 dst, efx->tc->meta_##_table.desc.key_width,\ 1779 _value) 1780 #define TABLE_POPULATE_KEY(dst, _table, _field, _value) \ 1781 _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.key_width, \ 1782 efx->tc->meta_##_table.desc.keys \ 1783 [efx->tc->meta_##_table.keys._field##_idx], \ 1784 _value) 1785 1786 #define TABLE_POPULATE_RESP_BOOL(dst, _table, _field, _value) \ 1787 efx_mae_table_populate_bool(efx->tc->meta_##_table.desc.resps \ 1788 [efx->tc->meta_##_table.resps._field##_idx],\ 1789 dst, efx->tc->meta_##_table.desc.resp_width,\ 1790 _value) 1791 #define TABLE_POPULATE_RESP(dst, _table, _field, _value) \ 1792 _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.resp_width, \ 1793 efx->tc->meta_##_table.desc.resps \ 1794 [efx->tc->meta_##_table.resps._field##_idx], \ 1795 _value) 1796 1797 #define TABLE_POPULATE_RESP_U24(dst, _table, _field, _value) \ 1798 efx_mae_table_populate_u24(efx->tc->meta_##_table.desc.resps \ 1799 [efx->tc->meta_##_table.resps._field##_idx],\ 1800 dst, efx->tc->meta_##_table.desc.resp_width,\ 1801 _value) 1802 1803 static int efx_mae_populate_ct_key(struct efx_nic *efx, __le32 *key, size_t kw, 1804 struct efx_tc_ct_entry *conn) 1805 { 1806 bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6); 1807 int rc; 1808 1809 rc = TABLE_POPULATE_KEY(key, ct, eth_proto, conn->eth_proto); 1810 if (rc) 1811 return rc; 1812 rc = TABLE_POPULATE_KEY(key, ct, ip_proto, conn->ip_proto); 1813 if (rc) 1814 return rc; 1815 if (ipv6) 1816 rc = TABLE_POPULATE_KEY(key, ct, src_ip, conn->src_ip6); 1817 else 1818 rc = TABLE_POPULATE_KEY_IPV4(key, ct, src_ip, conn->src_ip); 1819 if (rc) 1820 return rc; 1821 if (ipv6) 1822 rc = TABLE_POPULATE_KEY(key, ct, dst_ip, conn->dst_ip6); 1823 else 1824 rc = TABLE_POPULATE_KEY_IPV4(key, ct, dst_ip, conn->dst_ip); 1825 if (rc) 1826 return rc; 1827 rc = TABLE_POPULATE_KEY(key, ct, l4_sport, conn->l4_sport); 1828 if (rc) 1829 return rc; 1830 rc = TABLE_POPULATE_KEY(key, ct, l4_dport, conn->l4_dport); 1831 if (rc) 1832 return rc; 1833 return TABLE_POPULATE_KEY(key, ct, zone, cpu_to_be16(conn->zone->zone)); 1834 } 1835 1836 int efx_mae_insert_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn) 1837 { 1838 bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6); 1839 __le32 *key = NULL, *resp = NULL; 1840 size_t inlen, kw, rw; 1841 efx_dword_t *inbuf; 1842 int rc = -ENOMEM; 1843 1844 /* Check table access is supported */ 1845 if (!efx->tc->meta_ct.hooked) 1846 return -EOPNOTSUPP; 1847 1848 /* key/resp widths are in bits; convert to dwords for IN_LEN */ 1849 kw = DIV_ROUND_UP(efx->tc->meta_ct.desc.key_width, 32); 1850 rw = DIV_ROUND_UP(efx->tc->meta_ct.desc.resp_width, 32); 1851 BUILD_BUG_ON(sizeof(__le32) != MC_CMD_TABLE_INSERT_IN_DATA_LEN); 1852 inlen = MC_CMD_TABLE_INSERT_IN_LEN(kw + rw); 1853 if (inlen > MC_CMD_TABLE_INSERT_IN_LENMAX_MCDI2) 1854 return -E2BIG; 1855 inbuf = kzalloc(inlen, GFP_KERNEL); 1856 if (!inbuf) 1857 return -ENOMEM; 1858 1859 key = kcalloc(kw, sizeof(__le32), GFP_KERNEL); 1860 if (!key) 1861 goto out_free; 1862 resp = kcalloc(rw, sizeof(__le32), GFP_KERNEL); 1863 if (!resp) 1864 goto out_free; 1865 1866 rc = efx_mae_populate_ct_key(efx, key, kw, conn); 1867 if (rc) 1868 goto out_free; 1869 1870 rc = TABLE_POPULATE_RESP_BOOL(resp, ct, dnat, conn->dnat); 1871 if (rc) 1872 goto out_free; 1873 /* No support in hw for IPv6 NAT; field is only 32 bits */ 1874 if (!ipv6) 1875 rc = TABLE_POPULATE_RESP(resp, ct, nat_ip, conn->nat_ip); 1876 if (rc) 1877 goto out_free; 1878 rc = TABLE_POPULATE_RESP(resp, ct, l4_natport, conn->l4_natport); 1879 if (rc) 1880 goto out_free; 1881 rc = TABLE_POPULATE_RESP(resp, ct, mark, cpu_to_be32(conn->mark)); 1882 if (rc) 1883 goto out_free; 1884 rc = TABLE_POPULATE_RESP_U24(resp, ct, counter_id, conn->cnt->fw_id); 1885 if (rc) 1886 goto out_free; 1887 1888 MCDI_SET_DWORD(inbuf, TABLE_INSERT_IN_TABLE_ID, TABLE_ID_CONNTRACK_TABLE); 1889 MCDI_SET_WORD(inbuf, TABLE_INSERT_IN_KEY_WIDTH, 1890 efx->tc->meta_ct.desc.key_width); 1891 /* MASK_WIDTH is zero as CT is a BCAM */ 1892 MCDI_SET_WORD(inbuf, TABLE_INSERT_IN_RESP_WIDTH, 1893 efx->tc->meta_ct.desc.resp_width); 1894 memcpy(MCDI_PTR(inbuf, TABLE_INSERT_IN_DATA), key, kw * sizeof(__le32)); 1895 memcpy(MCDI_PTR(inbuf, TABLE_INSERT_IN_DATA) + kw * sizeof(__le32), 1896 resp, rw * sizeof(__le32)); 1897 1898 BUILD_BUG_ON(MC_CMD_TABLE_INSERT_OUT_LEN); 1899 1900 rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_INSERT, inbuf, inlen, NULL, 0, NULL); 1901 1902 out_free: 1903 kfree(resp); 1904 kfree(key); 1905 kfree(inbuf); 1906 return rc; 1907 } 1908 1909 int efx_mae_remove_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn) 1910 { 1911 __le32 *key = NULL; 1912 efx_dword_t *inbuf; 1913 size_t inlen, kw; 1914 int rc = -ENOMEM; 1915 1916 /* Check table access is supported */ 1917 if (!efx->tc->meta_ct.hooked) 1918 return -EOPNOTSUPP; 1919 1920 /* key width is in bits; convert to dwords for IN_LEN */ 1921 kw = DIV_ROUND_UP(efx->tc->meta_ct.desc.key_width, 32); 1922 BUILD_BUG_ON(sizeof(__le32) != MC_CMD_TABLE_DELETE_IN_DATA_LEN); 1923 inlen = MC_CMD_TABLE_DELETE_IN_LEN(kw); 1924 if (inlen > MC_CMD_TABLE_DELETE_IN_LENMAX_MCDI2) 1925 return -E2BIG; 1926 inbuf = kzalloc(inlen, GFP_KERNEL); 1927 if (!inbuf) 1928 return -ENOMEM; 1929 1930 key = kcalloc(kw, sizeof(__le32), GFP_KERNEL); 1931 if (!key) 1932 goto out_free; 1933 1934 rc = efx_mae_populate_ct_key(efx, key, kw, conn); 1935 if (rc) 1936 goto out_free; 1937 1938 MCDI_SET_DWORD(inbuf, TABLE_DELETE_IN_TABLE_ID, TABLE_ID_CONNTRACK_TABLE); 1939 MCDI_SET_WORD(inbuf, TABLE_DELETE_IN_KEY_WIDTH, 1940 efx->tc->meta_ct.desc.key_width); 1941 /* MASK_WIDTH is zero as CT is a BCAM */ 1942 /* RESP_WIDTH is zero for DELETE */ 1943 memcpy(MCDI_PTR(inbuf, TABLE_DELETE_IN_DATA), key, kw * sizeof(__le32)); 1944 1945 BUILD_BUG_ON(MC_CMD_TABLE_DELETE_OUT_LEN); 1946 1947 rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_DELETE, inbuf, inlen, NULL, 0, NULL); 1948 1949 out_free: 1950 kfree(key); 1951 kfree(inbuf); 1952 return rc; 1953 } 1954 1955 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 1956 const struct efx_tc_match *match) 1957 { 1958 if (match->mask.ingress_port) { 1959 if (~match->mask.ingress_port) 1960 return -EOPNOTSUPP; 1961 MCDI_STRUCT_SET_DWORD(match_crit, 1962 MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR, 1963 match->value.ingress_port); 1964 } 1965 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK, 1966 match->mask.ingress_port); 1967 EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS), 1968 MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT, 1969 match->value.ct_state_trk, 1970 MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT, 1971 match->value.ct_state_est, 1972 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 1973 match->value.ip_frag, 1974 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 1975 match->value.ip_firstfrag, 1976 MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST, 1977 match->value.tcp_syn_fin_rst); 1978 EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK), 1979 MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT, 1980 match->mask.ct_state_trk, 1981 MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT, 1982 match->mask.ct_state_est, 1983 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 1984 match->mask.ip_frag, 1985 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 1986 match->mask.ip_firstfrag, 1987 MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST, 1988 match->mask.tcp_syn_fin_rst); 1989 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID, 1990 match->value.recirc_id); 1991 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK, 1992 match->mask.recirc_id); 1993 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK, 1994 match->value.ct_mark); 1995 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK_MASK, 1996 match->mask.ct_mark); 1997 MCDI_STRUCT_SET_WORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN, 1998 match->value.ct_zone); 1999 MCDI_STRUCT_SET_WORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN_MASK, 2000 match->mask.ct_zone); 2001 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE, 2002 match->value.eth_proto); 2003 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK, 2004 match->mask.eth_proto); 2005 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE, 2006 match->value.vlan_tci[0]); 2007 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK, 2008 match->mask.vlan_tci[0]); 2009 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE, 2010 match->value.vlan_proto[0]); 2011 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK, 2012 match->mask.vlan_proto[0]); 2013 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE, 2014 match->value.vlan_tci[1]); 2015 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK, 2016 match->mask.vlan_tci[1]); 2017 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE, 2018 match->value.vlan_proto[1]); 2019 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK, 2020 match->mask.vlan_proto[1]); 2021 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE), 2022 match->value.eth_saddr, ETH_ALEN); 2023 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK), 2024 match->mask.eth_saddr, ETH_ALEN); 2025 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE), 2026 match->value.eth_daddr, ETH_ALEN); 2027 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK), 2028 match->mask.eth_daddr, ETH_ALEN); 2029 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO, 2030 match->value.ip_proto); 2031 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK, 2032 match->mask.ip_proto); 2033 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS, 2034 match->value.ip_tos); 2035 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK, 2036 match->mask.ip_tos); 2037 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL, 2038 match->value.ip_ttl); 2039 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK, 2040 match->mask.ip_ttl); 2041 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE, 2042 match->value.src_ip); 2043 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK, 2044 match->mask.src_ip); 2045 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE, 2046 match->value.dst_ip); 2047 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK, 2048 match->mask.dst_ip); 2049 #ifdef CONFIG_IPV6 2050 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE), 2051 &match->value.src_ip6, sizeof(struct in6_addr)); 2052 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK), 2053 &match->mask.src_ip6, sizeof(struct in6_addr)); 2054 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE), 2055 &match->value.dst_ip6, sizeof(struct in6_addr)); 2056 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK), 2057 &match->mask.dst_ip6, sizeof(struct in6_addr)); 2058 #endif 2059 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE, 2060 match->value.l4_sport); 2061 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK, 2062 match->mask.l4_sport); 2063 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE, 2064 match->value.l4_dport); 2065 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK, 2066 match->mask.l4_dport); 2067 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE, 2068 match->value.tcp_flags); 2069 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK, 2070 match->mask.tcp_flags); 2071 /* enc-keys are handled indirectly, through encap_match ID */ 2072 if (match->encap) { 2073 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID, 2074 match->encap->fw_id); 2075 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK, 2076 U32_MAX); 2077 /* enc_keyid (VNI/VSID) is not part of the encap_match */ 2078 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE, 2079 match->value.enc_keyid); 2080 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK, 2081 match->mask.enc_keyid); 2082 } else if (WARN_ON_ONCE(match->mask.enc_src_ip) || 2083 WARN_ON_ONCE(match->mask.enc_dst_ip) || 2084 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)) || 2085 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)) || 2086 WARN_ON_ONCE(match->mask.enc_ip_tos) || 2087 WARN_ON_ONCE(match->mask.enc_ip_ttl) || 2088 WARN_ON_ONCE(match->mask.enc_sport) || 2089 WARN_ON_ONCE(match->mask.enc_dport) || 2090 WARN_ON_ONCE(match->mask.enc_keyid)) { 2091 /* No enc-keys should appear in a rule without an encap_match */ 2092 return -EOPNOTSUPP; 2093 } 2094 return 0; 2095 } 2096 2097 int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, 2098 u32 prio, u32 acts_id, u32 *id) 2099 { 2100 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN)); 2101 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 2102 MCDI_DECLARE_STRUCT_PTR(match_crit); 2103 MCDI_DECLARE_STRUCT_PTR(response); 2104 size_t outlen; 2105 int rc; 2106 2107 if (!id) 2108 return -EINVAL; 2109 2110 match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA); 2111 response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE); 2112 if (efx_mae_asl_id(acts_id)) { 2113 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); 2114 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 2115 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 2116 } else { 2117 /* We only had one AS, so we didn't wrap it in an ASL */ 2118 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 2119 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 2120 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); 2121 } 2122 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio); 2123 rc = efx_mae_populate_match_criteria(match_crit, match); 2124 if (rc) 2125 return rc; 2126 2127 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf), 2128 outbuf, sizeof(outbuf), &outlen); 2129 if (rc) 2130 return rc; 2131 if (outlen < sizeof(outbuf)) 2132 return -EIO; 2133 *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 2134 return 0; 2135 } 2136 2137 int efx_mae_update_rule(struct efx_nic *efx, u32 acts_id, u32 id) 2138 { 2139 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_UPDATE_IN_LEN); 2140 MCDI_DECLARE_STRUCT_PTR(response); 2141 2142 BUILD_BUG_ON(MC_CMD_MAE_ACTION_RULE_UPDATE_OUT_LEN); 2143 response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_RESPONSE); 2144 2145 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_AR_ID, id); 2146 if (efx_mae_asl_id(acts_id)) { 2147 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); 2148 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 2149 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 2150 } else { 2151 /* We only had one AS, so we didn't wrap it in an ASL */ 2152 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 2153 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 2154 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); 2155 } 2156 return efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_UPDATE, inbuf, sizeof(inbuf), 2157 NULL, 0, NULL); 2158 } 2159 2160 int efx_mae_delete_rule(struct efx_nic *efx, u32 id) 2161 { 2162 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 2163 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1)); 2164 size_t outlen; 2165 int rc; 2166 2167 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id); 2168 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf), 2169 outbuf, sizeof(outbuf), &outlen); 2170 if (rc) 2171 return rc; 2172 if (outlen < sizeof(outbuf)) 2173 return -EIO; 2174 /* FW freed a different ID than we asked for, should also never happen. 2175 * Warn because it means we've now got a different idea to the FW of 2176 * what rules exist, which could cause mayhem later. 2177 */ 2178 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id)) 2179 return -EIO; 2180 return 0; 2181 } 2182 2183 int efx_init_mae(struct efx_nic *efx) 2184 { 2185 struct ef100_nic_data *nic_data = efx->nic_data; 2186 struct efx_mae *mae; 2187 int rc; 2188 2189 if (!nic_data->have_mport) 2190 return -EINVAL; 2191 2192 mae = kmalloc(sizeof(*mae), GFP_KERNEL); 2193 if (!mae) 2194 return -ENOMEM; 2195 2196 rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params); 2197 if (rc < 0) { 2198 kfree(mae); 2199 return rc; 2200 } 2201 efx->mae = mae; 2202 mae->efx = efx; 2203 return 0; 2204 } 2205 2206 void efx_fini_mae(struct efx_nic *efx) 2207 { 2208 struct efx_mae *mae = efx->mae; 2209 2210 kfree(mae); 2211 efx->mae = NULL; 2212 } 2213