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