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\n", 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 static int efx_mae_process_mport(struct efx_nic *efx, 1094 struct mae_mport_desc *desc) 1095 { 1096 struct ef100_nic_data *nic_data = efx->nic_data; 1097 struct mae_mport_desc *mport; 1098 1099 mport = efx_mae_get_mport(efx, desc->mport_id); 1100 if (!IS_ERR_OR_NULL(mport)) { 1101 netif_err(efx, drv, efx->net_dev, 1102 "mport with id %u does exist!!!\n", desc->mport_id); 1103 return -EEXIST; 1104 } 1105 1106 if (nic_data->have_own_mport && 1107 desc->mport_id == nic_data->own_mport) { 1108 WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC); 1109 WARN_ON(desc->vnic_client_type != 1110 MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION); 1111 nic_data->local_mae_intf = desc->interface_idx; 1112 nic_data->have_local_intf = true; 1113 pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n", 1114 nic_data->local_mae_intf); 1115 } 1116 1117 return efx_mae_add_mport(efx, desc); 1118 } 1119 1120 #define MCDI_MPORT_JOURNAL_LEN \ 1121 ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4) 1122 1123 int efx_mae_enumerate_mports(struct efx_nic *efx) 1124 { 1125 efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL); 1126 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN); 1127 MCDI_DECLARE_STRUCT_PTR(desc); 1128 size_t outlen, stride, count; 1129 int rc = 0, i; 1130 1131 if (!outbuf) 1132 return -ENOMEM; 1133 do { 1134 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf, 1135 sizeof(inbuf), outbuf, 1136 MCDI_MPORT_JOURNAL_LEN, &outlen); 1137 if (rc) 1138 goto fail; 1139 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) { 1140 rc = -EIO; 1141 goto fail; 1142 } 1143 count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT); 1144 if (!count) 1145 continue; /* not break; we want to look at MORE flag */ 1146 stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC); 1147 if (stride < MAE_MPORT_DESC_LEN) { 1148 rc = -EIO; 1149 goto fail; 1150 } 1151 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) { 1152 rc = -EIO; 1153 goto fail; 1154 } 1155 1156 for (i = 0; i < count; i++) { 1157 struct mae_mport_desc *d; 1158 1159 d = kzalloc(sizeof(*d), GFP_KERNEL); 1160 if (!d) { 1161 rc = -ENOMEM; 1162 goto fail; 1163 } 1164 1165 desc = (efx_dword_t *) 1166 _MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST + 1167 i * stride); 1168 d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID); 1169 d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS); 1170 d->caller_flags = MCDI_STRUCT_DWORD(desc, 1171 MAE_MPORT_DESC_CALLER_FLAGS); 1172 d->mport_type = MCDI_STRUCT_DWORD(desc, 1173 MAE_MPORT_DESC_MPORT_TYPE); 1174 switch (d->mport_type) { 1175 case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT: 1176 d->port_idx = MCDI_STRUCT_DWORD(desc, 1177 MAE_MPORT_DESC_NET_PORT_IDX); 1178 break; 1179 case MAE_MPORT_DESC_MPORT_TYPE_ALIAS: 1180 d->alias_mport_id = MCDI_STRUCT_DWORD(desc, 1181 MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID); 1182 break; 1183 case MAE_MPORT_DESC_MPORT_TYPE_VNIC: 1184 d->vnic_client_type = MCDI_STRUCT_DWORD(desc, 1185 MAE_MPORT_DESC_VNIC_CLIENT_TYPE); 1186 d->interface_idx = MCDI_STRUCT_DWORD(desc, 1187 MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE); 1188 d->pf_idx = MCDI_STRUCT_WORD(desc, 1189 MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX); 1190 d->vf_idx = MCDI_STRUCT_WORD(desc, 1191 MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX); 1192 break; 1193 default: 1194 /* Unknown mport_type, just accept it */ 1195 break; 1196 } 1197 rc = efx_mae_process_mport(efx, d); 1198 /* Any failure will be due to memory allocation faiure, 1199 * so there is no point to try subsequent entries. 1200 */ 1201 if (rc) 1202 goto fail; 1203 } 1204 } while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) && 1205 !WARN_ON(!count)); 1206 fail: 1207 kfree(outbuf); 1208 return rc; 1209 } 1210 1211 /** 1212 * efx_mae_allocate_pedit_mac() - allocate pedit MAC address in HW. 1213 * @efx: NIC we're installing a pedit MAC address on 1214 * @ped: pedit MAC action to be installed 1215 * 1216 * Attempts to install @ped in HW and populates its id with an index of this 1217 * entry in the firmware MAC address table on success. 1218 * 1219 * Return: negative value on error, 0 in success. 1220 */ 1221 int efx_mae_allocate_pedit_mac(struct efx_nic *efx, 1222 struct efx_tc_mac_pedit_action *ped) 1223 { 1224 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN); 1225 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN); 1226 size_t outlen; 1227 int rc; 1228 1229 BUILD_BUG_ON(MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_LEN != 1230 sizeof(ped->h_addr)); 1231 memcpy(MCDI_PTR(inbuf, MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR), ped->h_addr, 1232 sizeof(ped->h_addr)); 1233 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MAC_ADDR_ALLOC, inbuf, sizeof(inbuf), 1234 outbuf, sizeof(outbuf), &outlen); 1235 if (rc) 1236 return rc; 1237 if (outlen < sizeof(outbuf)) 1238 return -EIO; 1239 ped->fw_id = MCDI_DWORD(outbuf, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID); 1240 return 0; 1241 } 1242 1243 /** 1244 * efx_mae_free_pedit_mac() - free pedit MAC address in HW. 1245 * @efx: NIC we're installing a pedit MAC address on 1246 * @ped: pedit MAC action that needs to be freed 1247 * 1248 * Frees @ped in HW, check that firmware did not free a different one and clears 1249 * the id (which denotes the index of the entry in the MAC address table). 1250 */ 1251 void efx_mae_free_pedit_mac(struct efx_nic *efx, 1252 struct efx_tc_mac_pedit_action *ped) 1253 { 1254 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1)); 1255 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1)); 1256 size_t outlen; 1257 int rc; 1258 1259 MCDI_SET_DWORD(inbuf, MAE_MAC_ADDR_FREE_IN_MAC_ID, ped->fw_id); 1260 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MAC_ADDR_FREE, inbuf, 1261 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1262 if (rc || outlen < sizeof(outbuf)) 1263 return; 1264 /* FW freed a different ID than we asked for, should also never happen. 1265 * Warn because it means we've now got a different idea to the FW of 1266 * what MAC addresses exist, which could cause mayhem later. 1267 */ 1268 if (WARN_ON(MCDI_DWORD(outbuf, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) != ped->fw_id)) 1269 return; 1270 /* We're probably about to free @ped, but let's just make sure its 1271 * fw_id is blatted so that it won't look valid if it leaks out. 1272 */ 1273 ped->fw_id = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL; 1274 } 1275 1276 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act) 1277 { 1278 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN); 1279 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN); 1280 size_t outlen; 1281 int rc; 1282 1283 MCDI_POPULATE_DWORD_5(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS, 1284 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, act->vlan_push, 1285 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop, 1286 MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap, 1287 MAE_ACTION_SET_ALLOC_IN_DO_NAT, act->do_nat, 1288 MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL, 1289 act->do_ttl_dec); 1290 1291 if (act->src_mac) 1292 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 1293 act->src_mac->fw_id); 1294 else 1295 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID, 1296 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 1297 1298 if (act->dst_mac) 1299 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 1300 act->dst_mac->fw_id); 1301 else 1302 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID, 1303 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL); 1304 1305 if (act->count && !WARN_ON(!act->count->cnt)) 1306 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 1307 act->count->cnt->fw_id); 1308 else 1309 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID, 1310 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 1311 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID, 1312 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL); 1313 if (act->vlan_push) { 1314 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE, 1315 act->vlan_tci[0]); 1316 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE, 1317 act->vlan_proto[0]); 1318 } 1319 if (act->vlan_push >= 2) { 1320 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE, 1321 act->vlan_tci[1]); 1322 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE, 1323 act->vlan_proto[1]); 1324 } 1325 if (act->encap_md) 1326 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 1327 act->encap_md->fw_id); 1328 else 1329 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID, 1330 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL); 1331 if (act->deliver) 1332 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER, 1333 act->dest_mport); 1334 BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL); 1335 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf), 1336 outbuf, sizeof(outbuf), &outlen); 1337 if (rc) 1338 return rc; 1339 if (outlen < sizeof(outbuf)) 1340 return -EIO; 1341 act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID); 1342 /* We rely on the high bit of AS IDs always being clear. 1343 * The firmware API guarantees this, but let's check it ourselves. 1344 */ 1345 if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) { 1346 efx_mae_free_action_set(efx, act->fw_id); 1347 return -EIO; 1348 } 1349 return 0; 1350 } 1351 1352 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id) 1353 { 1354 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1)); 1355 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1)); 1356 size_t outlen; 1357 int rc; 1358 1359 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id); 1360 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf), 1361 outbuf, sizeof(outbuf), &outlen); 1362 if (rc) 1363 return rc; 1364 if (outlen < sizeof(outbuf)) 1365 return -EIO; 1366 /* FW freed a different ID than we asked for, should never happen. 1367 * Warn because it means we've now got a different idea to the FW of 1368 * what action-sets exist, which could cause mayhem later. 1369 */ 1370 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id)) 1371 return -EIO; 1372 return 0; 1373 } 1374 1375 int efx_mae_alloc_action_set_list(struct efx_nic *efx, 1376 struct efx_tc_action_set_list *acts) 1377 { 1378 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN); 1379 struct efx_tc_action_set *act; 1380 size_t inlen, outlen, i = 0; 1381 efx_dword_t *inbuf; 1382 int rc; 1383 1384 list_for_each_entry(act, &acts->list, list) 1385 i++; 1386 if (i == 0) 1387 return -EINVAL; 1388 if (i == 1) { 1389 /* Don't wrap an ASL around a single AS, just use the AS_ID 1390 * directly. ASLs are a more limited resource. 1391 */ 1392 act = list_first_entry(&acts->list, struct efx_tc_action_set, list); 1393 acts->fw_id = act->fw_id; 1394 return 0; 1395 } 1396 if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2) 1397 return -EOPNOTSUPP; /* Too many actions */ 1398 inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i); 1399 inbuf = kzalloc(inlen, GFP_KERNEL); 1400 if (!inbuf) 1401 return -ENOMEM; 1402 i = 0; 1403 list_for_each_entry(act, &acts->list, list) { 1404 MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS, 1405 i, act->fw_id); 1406 i++; 1407 } 1408 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i); 1409 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen, 1410 outbuf, sizeof(outbuf), &outlen); 1411 if (rc) 1412 goto out_free; 1413 if (outlen < sizeof(outbuf)) { 1414 rc = -EIO; 1415 goto out_free; 1416 } 1417 acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID); 1418 /* We rely on the high bit of ASL IDs always being set. 1419 * The firmware API guarantees this, but let's check it ourselves. 1420 */ 1421 if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) { 1422 efx_mae_free_action_set_list(efx, acts); 1423 rc = -EIO; 1424 } 1425 out_free: 1426 kfree(inbuf); 1427 return rc; 1428 } 1429 1430 int efx_mae_free_action_set_list(struct efx_nic *efx, 1431 struct efx_tc_action_set_list *acts) 1432 { 1433 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1)); 1434 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1)); 1435 size_t outlen; 1436 int rc; 1437 1438 /* If this is just an AS_ID with no ASL wrapper, then there is 1439 * nothing for us to free. (The AS will be freed later.) 1440 */ 1441 if (efx_mae_asl_id(acts->fw_id)) { 1442 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID, 1443 acts->fw_id); 1444 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf, 1445 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1446 if (rc) 1447 return rc; 1448 if (outlen < sizeof(outbuf)) 1449 return -EIO; 1450 /* FW freed a different ID than we asked for, should never happen. 1451 * Warn because it means we've now got a different idea to the FW of 1452 * what action-set-lists exist, which could cause mayhem later. 1453 */ 1454 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id)) 1455 return -EIO; 1456 } 1457 /* We're probably about to free @acts, but let's just make sure its 1458 * fw_id is blatted so that it won't look valid if it leaks out. 1459 */ 1460 acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL; 1461 return 0; 1462 } 1463 1464 int efx_mae_register_encap_match(struct efx_nic *efx, 1465 struct efx_tc_encap_match *encap) 1466 { 1467 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN)); 1468 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 1469 MCDI_DECLARE_STRUCT_PTR(match_crit); 1470 size_t outlen; 1471 int rc; 1472 1473 rc = efx_mae_encap_type_to_mae_type(encap->tun_type); 1474 if (rc < 0) 1475 return rc; 1476 match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA); 1477 /* The struct contains IP src and dst, and udp dport. 1478 * So we actually need to filter on IP src and dst, L4 dport, and 1479 * ipproto == udp. 1480 */ 1481 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, rc); 1482 #ifdef CONFIG_IPV6 1483 if (encap->src_ip | encap->dst_ip) { 1484 #endif 1485 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE, 1486 encap->src_ip); 1487 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK, 1488 ~(__be32)0); 1489 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE, 1490 encap->dst_ip); 1491 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK, 1492 ~(__be32)0); 1493 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 1494 htons(ETH_P_IP)); 1495 #ifdef CONFIG_IPV6 1496 } else { 1497 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE), 1498 &encap->src_ip6, sizeof(encap->src_ip6)); 1499 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK), 1500 0xff, sizeof(encap->src_ip6)); 1501 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE), 1502 &encap->dst_ip6, sizeof(encap->dst_ip6)); 1503 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK), 1504 0xff, sizeof(encap->dst_ip6)); 1505 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 1506 htons(ETH_P_IPV6)); 1507 } 1508 #endif 1509 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK, 1510 ~(__be16)0); 1511 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1512 encap->udp_dport); 1513 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1514 ~(__be16)0); 1515 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1516 encap->udp_sport); 1517 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1518 encap->udp_sport_mask); 1519 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, IPPROTO_UDP); 1520 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, ~0); 1521 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS, 1522 encap->ip_tos); 1523 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK, 1524 encap->ip_tos_mask); 1525 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf, 1526 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1527 if (rc) 1528 return rc; 1529 if (outlen < sizeof(outbuf)) 1530 return -EIO; 1531 encap->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 1532 return 0; 1533 } 1534 1535 int efx_mae_unregister_encap_match(struct efx_nic *efx, 1536 struct efx_tc_encap_match *encap) 1537 { 1538 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 1539 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1)); 1540 size_t outlen; 1541 int rc; 1542 1543 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, encap->fw_id); 1544 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf, 1545 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1546 if (rc) 1547 return rc; 1548 if (outlen < sizeof(outbuf)) 1549 return -EIO; 1550 /* FW freed a different ID than we asked for, should also never happen. 1551 * Warn because it means we've now got a different idea to the FW of 1552 * what encap_mds exist, which could cause mayhem later. 1553 */ 1554 if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != encap->fw_id)) 1555 return -EIO; 1556 /* We're probably about to free @encap, but let's just make sure its 1557 * fw_id is blatted so that it won't look valid if it leaks out. 1558 */ 1559 encap->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL; 1560 return 0; 1561 } 1562 1563 static int efx_mae_populate_lhs_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 1564 const struct efx_tc_match *match) 1565 { 1566 if (match->mask.ingress_port) { 1567 if (~match->mask.ingress_port) 1568 return -EOPNOTSUPP; 1569 MCDI_STRUCT_SET_DWORD(match_crit, 1570 MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR, 1571 match->value.ingress_port); 1572 } 1573 MCDI_STRUCT_SET_DWORD(match_crit, MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR_MASK, 1574 match->mask.ingress_port); 1575 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE, 1576 match->value.eth_proto); 1577 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK, 1578 match->mask.eth_proto); 1579 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE, 1580 match->value.vlan_tci[0]); 1581 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE_MASK, 1582 match->mask.vlan_tci[0]); 1583 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE, 1584 match->value.vlan_proto[0]); 1585 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE_MASK, 1586 match->mask.vlan_proto[0]); 1587 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE, 1588 match->value.vlan_tci[1]); 1589 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE_MASK, 1590 match->mask.vlan_tci[1]); 1591 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE, 1592 match->value.vlan_proto[1]); 1593 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE_MASK, 1594 match->mask.vlan_proto[1]); 1595 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE), 1596 match->value.eth_saddr, ETH_ALEN); 1597 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE_MASK), 1598 match->mask.eth_saddr, ETH_ALEN); 1599 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE), 1600 match->value.eth_daddr, ETH_ALEN); 1601 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE_MASK), 1602 match->mask.eth_daddr, ETH_ALEN); 1603 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, 1604 match->value.ip_proto); 1605 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, 1606 match->mask.ip_proto); 1607 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS, 1608 match->value.ip_tos); 1609 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK, 1610 match->mask.ip_tos); 1611 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL, 1612 match->value.ip_ttl); 1613 MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL_MASK, 1614 match->mask.ip_ttl); 1615 MCDI_STRUCT_POPULATE_BYTE_1(match_crit, 1616 MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS, 1617 MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG, 1618 match->value.ip_frag); 1619 MCDI_STRUCT_POPULATE_BYTE_1(match_crit, 1620 MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS_MASK, 1621 MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG_MASK, 1622 match->mask.ip_frag); 1623 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE, 1624 match->value.src_ip); 1625 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK, 1626 match->mask.src_ip); 1627 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE, 1628 match->value.dst_ip); 1629 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK, 1630 match->mask.dst_ip); 1631 #ifdef CONFIG_IPV6 1632 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE), 1633 &match->value.src_ip6, sizeof(struct in6_addr)); 1634 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK), 1635 &match->mask.src_ip6, sizeof(struct in6_addr)); 1636 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE), 1637 &match->value.dst_ip6, sizeof(struct in6_addr)); 1638 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK), 1639 &match->mask.dst_ip6, sizeof(struct in6_addr)); 1640 #endif 1641 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE, 1642 match->value.l4_sport); 1643 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE_MASK, 1644 match->mask.l4_sport); 1645 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE, 1646 match->value.l4_dport); 1647 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK, 1648 match->mask.l4_dport); 1649 /* No enc-keys in LHS rules. Caps check should have caught this; any 1650 * enc-keys from an fLHS should have been translated to regular keys 1651 * and any EM should be a pseudo (we're an OR so can't have a direct 1652 * EM with another OR). 1653 */ 1654 if (WARN_ON_ONCE(match->encap && !match->encap->type)) 1655 return -EOPNOTSUPP; 1656 if (WARN_ON_ONCE(match->mask.enc_src_ip)) 1657 return -EOPNOTSUPP; 1658 if (WARN_ON_ONCE(match->mask.enc_dst_ip)) 1659 return -EOPNOTSUPP; 1660 #ifdef CONFIG_IPV6 1661 if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6))) 1662 return -EOPNOTSUPP; 1663 if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6))) 1664 return -EOPNOTSUPP; 1665 #endif 1666 if (WARN_ON_ONCE(match->mask.enc_ip_tos)) 1667 return -EOPNOTSUPP; 1668 if (WARN_ON_ONCE(match->mask.enc_ip_ttl)) 1669 return -EOPNOTSUPP; 1670 if (WARN_ON_ONCE(match->mask.enc_sport)) 1671 return -EOPNOTSUPP; 1672 if (WARN_ON_ONCE(match->mask.enc_dport)) 1673 return -EOPNOTSUPP; 1674 if (WARN_ON_ONCE(match->mask.enc_keyid)) 1675 return -EOPNOTSUPP; 1676 return 0; 1677 } 1678 1679 static int efx_mae_insert_lhs_outer_rule(struct efx_nic *efx, 1680 struct efx_tc_lhs_rule *rule, u32 prio) 1681 { 1682 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN)); 1683 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN); 1684 MCDI_DECLARE_STRUCT_PTR(match_crit); 1685 const struct efx_tc_lhs_action *act; 1686 size_t outlen; 1687 int rc; 1688 1689 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_PRIO, prio); 1690 /* match */ 1691 match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA); 1692 rc = efx_mae_populate_lhs_match_criteria(match_crit, &rule->match); 1693 if (rc) 1694 return rc; 1695 1696 /* action */ 1697 act = &rule->lhs_act; 1698 rc = efx_mae_encap_type_to_mae_type(act->tun_type); 1699 if (rc < 0) 1700 return rc; 1701 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, rc); 1702 /* We always inhibit CT lookup on TCP_INTERESTING_FLAGS, since the 1703 * SW path needs to process the packet to update the conntrack tables 1704 * on connection establishment (SYN) or termination (FIN, RST). 1705 */ 1706 MCDI_POPULATE_DWORD_6(inbuf, MAE_OUTER_RULE_INSERT_IN_LOOKUP_CONTROL, 1707 MAE_OUTER_RULE_INSERT_IN_DO_CT, !!act->zone, 1708 MAE_OUTER_RULE_INSERT_IN_CT_TCP_FLAGS_INHIBIT, 1, 1709 MAE_OUTER_RULE_INSERT_IN_CT_DOMAIN, 1710 act->zone ? act->zone->zone : 0, 1711 MAE_OUTER_RULE_INSERT_IN_CT_VNI_MODE, 1712 MAE_CT_VNI_MODE_ZERO, 1713 MAE_OUTER_RULE_INSERT_IN_DO_COUNT, !!act->count, 1714 MAE_OUTER_RULE_INSERT_IN_RECIRC_ID, 1715 act->rid ? act->rid->fw_id : 0); 1716 if (act->count) 1717 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_COUNTER_ID, 1718 act->count->cnt->fw_id); 1719 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf, 1720 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1721 if (rc) 1722 return rc; 1723 if (outlen < sizeof(outbuf)) 1724 return -EIO; 1725 rule->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID); 1726 return 0; 1727 } 1728 1729 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 1730 const struct efx_tc_match *match); 1731 1732 static int efx_mae_insert_lhs_action_rule(struct efx_nic *efx, 1733 struct efx_tc_lhs_rule *rule, 1734 u32 prio) 1735 { 1736 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN)); 1737 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 1738 struct efx_tc_lhs_action *act = &rule->lhs_act; 1739 MCDI_DECLARE_STRUCT_PTR(match_crit); 1740 MCDI_DECLARE_STRUCT_PTR(response); 1741 size_t outlen; 1742 int rc; 1743 1744 match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA); 1745 response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE); 1746 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 1747 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 1748 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 1749 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 1750 EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(response, MAE_ACTION_RULE_RESPONSE_LOOKUP_CONTROL), 1751 MAE_ACTION_RULE_RESPONSE_DO_CT, !!act->zone, 1752 MAE_ACTION_RULE_RESPONSE_DO_RECIRC, 1753 act->rid && !act->zone, 1754 MAE_ACTION_RULE_RESPONSE_CT_VNI_MODE, 1755 MAE_CT_VNI_MODE_ZERO, 1756 MAE_ACTION_RULE_RESPONSE_RECIRC_ID, 1757 act->rid ? act->rid->fw_id : 0, 1758 MAE_ACTION_RULE_RESPONSE_CT_DOMAIN, 1759 act->zone ? act->zone->zone : 0); 1760 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_COUNTER_ID, 1761 act->count ? act->count->cnt->fw_id : 1762 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL); 1763 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio); 1764 rc = efx_mae_populate_match_criteria(match_crit, &rule->match); 1765 if (rc) 1766 return rc; 1767 1768 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf), 1769 outbuf, sizeof(outbuf), &outlen); 1770 if (rc) 1771 return rc; 1772 if (outlen < sizeof(outbuf)) 1773 return -EIO; 1774 rule->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 1775 return 0; 1776 } 1777 1778 int efx_mae_insert_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule, 1779 u32 prio) 1780 { 1781 if (rule->is_ar) 1782 return efx_mae_insert_lhs_action_rule(efx, rule, prio); 1783 return efx_mae_insert_lhs_outer_rule(efx, rule, prio); 1784 } 1785 1786 static int efx_mae_remove_lhs_outer_rule(struct efx_nic *efx, 1787 struct efx_tc_lhs_rule *rule) 1788 { 1789 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1)); 1790 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1)); 1791 size_t outlen; 1792 int rc; 1793 1794 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, rule->fw_id); 1795 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf, 1796 sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); 1797 if (rc) 1798 return rc; 1799 if (outlen < sizeof(outbuf)) 1800 return -EIO; 1801 /* FW freed a different ID than we asked for, should also never happen. 1802 * Warn because it means we've now got a different idea to the FW of 1803 * what encap_mds exist, which could cause mayhem later. 1804 */ 1805 if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != rule->fw_id)) 1806 return -EIO; 1807 /* We're probably about to free @rule, but let's just make sure its 1808 * fw_id is blatted so that it won't look valid if it leaks out. 1809 */ 1810 rule->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL; 1811 return 0; 1812 } 1813 1814 int efx_mae_remove_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule) 1815 { 1816 if (rule->is_ar) 1817 return efx_mae_delete_rule(efx, rule->fw_id); 1818 return efx_mae_remove_lhs_outer_rule(efx, rule); 1819 } 1820 1821 /* Populating is done by taking each byte of @value in turn and storing 1822 * it in the appropriate bits of @row. @value must be big-endian; we 1823 * convert it to little-endianness as we go. 1824 */ 1825 static int efx_mae_table_populate(struct efx_tc_table_field_fmt field, 1826 __le32 *row, size_t row_bits, 1827 void *value, size_t value_size) 1828 { 1829 unsigned int i; 1830 1831 /* For now only scheme 0 is supported for any field, so we check here 1832 * (rather than, say, in calling code, which knows the semantics and 1833 * could in principle encode for other schemes). 1834 */ 1835 if (field.scheme) 1836 return -EOPNOTSUPP; 1837 if (DIV_ROUND_UP(field.width, 8) != value_size) 1838 return -EINVAL; 1839 if (field.lbn + field.width > row_bits) 1840 return -EINVAL; 1841 for (i = 0; i < value_size; i++) { 1842 unsigned int bn = field.lbn + i * 8; 1843 unsigned int wn = bn / 32; 1844 u64 v; 1845 1846 v = ((u8 *)value)[value_size - i - 1]; 1847 v <<= (bn % 32); 1848 row[wn] |= cpu_to_le32(v & 0xffffffff); 1849 if (wn * 32 < row_bits) 1850 row[wn + 1] |= cpu_to_le32(v >> 32); 1851 } 1852 return 0; 1853 } 1854 1855 static int efx_mae_table_populate_bool(struct efx_tc_table_field_fmt field, 1856 __le32 *row, size_t row_bits, bool value) 1857 { 1858 u8 v = value ? 1 : 0; 1859 1860 if (field.width != 1) 1861 return -EINVAL; 1862 return efx_mae_table_populate(field, row, row_bits, &v, 1); 1863 } 1864 1865 static int efx_mae_table_populate_ipv4(struct efx_tc_table_field_fmt field, 1866 __le32 *row, size_t row_bits, __be32 value) 1867 { 1868 /* IPv4 is placed in the first 4 bytes of an IPv6-sized field */ 1869 struct in6_addr v = {}; 1870 1871 if (field.width != 128) 1872 return -EINVAL; 1873 v.s6_addr32[0] = value; 1874 return efx_mae_table_populate(field, row, row_bits, &v, sizeof(v)); 1875 } 1876 1877 static int efx_mae_table_populate_u24(struct efx_tc_table_field_fmt field, 1878 __le32 *row, size_t row_bits, u32 value) 1879 { 1880 __be32 v = cpu_to_be32(value); 1881 1882 /* We adjust value_size here since just 3 bytes will be copied, and 1883 * the pointer to the value is set discarding the first byte which is 1884 * the most significant byte for a big-endian 4-bytes value. 1885 */ 1886 return efx_mae_table_populate(field, row, row_bits, ((void *)&v) + 1, 1887 sizeof(v) - 1); 1888 } 1889 1890 #define _TABLE_POPULATE(dst, dw, _field, _value) ({ \ 1891 typeof(_value) _v = _value; \ 1892 \ 1893 (_field.width == sizeof(_value) * 8) ? \ 1894 efx_mae_table_populate(_field, dst, dw, &_v, \ 1895 sizeof(_v)) : -EINVAL; \ 1896 }) 1897 #define TABLE_POPULATE_KEY_IPV4(dst, _table, _field, _value) \ 1898 efx_mae_table_populate_ipv4(efx->tc->meta_##_table.desc.keys \ 1899 [efx->tc->meta_##_table.keys._field##_idx],\ 1900 dst, efx->tc->meta_##_table.desc.key_width,\ 1901 _value) 1902 #define TABLE_POPULATE_KEY(dst, _table, _field, _value) \ 1903 _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.key_width, \ 1904 efx->tc->meta_##_table.desc.keys \ 1905 [efx->tc->meta_##_table.keys._field##_idx], \ 1906 _value) 1907 1908 #define TABLE_POPULATE_RESP_BOOL(dst, _table, _field, _value) \ 1909 efx_mae_table_populate_bool(efx->tc->meta_##_table.desc.resps \ 1910 [efx->tc->meta_##_table.resps._field##_idx],\ 1911 dst, efx->tc->meta_##_table.desc.resp_width,\ 1912 _value) 1913 #define TABLE_POPULATE_RESP(dst, _table, _field, _value) \ 1914 _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.resp_width, \ 1915 efx->tc->meta_##_table.desc.resps \ 1916 [efx->tc->meta_##_table.resps._field##_idx], \ 1917 _value) 1918 1919 #define TABLE_POPULATE_RESP_U24(dst, _table, _field, _value) \ 1920 efx_mae_table_populate_u24(efx->tc->meta_##_table.desc.resps \ 1921 [efx->tc->meta_##_table.resps._field##_idx],\ 1922 dst, efx->tc->meta_##_table.desc.resp_width,\ 1923 _value) 1924 1925 static int efx_mae_populate_ct_key(struct efx_nic *efx, __le32 *key, size_t kw, 1926 struct efx_tc_ct_entry *conn) 1927 { 1928 bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6); 1929 int rc; 1930 1931 rc = TABLE_POPULATE_KEY(key, ct, eth_proto, conn->eth_proto); 1932 if (rc) 1933 return rc; 1934 rc = TABLE_POPULATE_KEY(key, ct, ip_proto, conn->ip_proto); 1935 if (rc) 1936 return rc; 1937 if (ipv6) 1938 rc = TABLE_POPULATE_KEY(key, ct, src_ip, conn->src_ip6); 1939 else 1940 rc = TABLE_POPULATE_KEY_IPV4(key, ct, src_ip, conn->src_ip); 1941 if (rc) 1942 return rc; 1943 if (ipv6) 1944 rc = TABLE_POPULATE_KEY(key, ct, dst_ip, conn->dst_ip6); 1945 else 1946 rc = TABLE_POPULATE_KEY_IPV4(key, ct, dst_ip, conn->dst_ip); 1947 if (rc) 1948 return rc; 1949 rc = TABLE_POPULATE_KEY(key, ct, l4_sport, conn->l4_sport); 1950 if (rc) 1951 return rc; 1952 rc = TABLE_POPULATE_KEY(key, ct, l4_dport, conn->l4_dport); 1953 if (rc) 1954 return rc; 1955 return TABLE_POPULATE_KEY(key, ct, zone, cpu_to_be16(conn->zone->zone)); 1956 } 1957 1958 int efx_mae_insert_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn) 1959 { 1960 bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6); 1961 __le32 *key = NULL, *resp = NULL; 1962 size_t inlen, kw, rw; 1963 efx_dword_t *inbuf; 1964 int rc = -ENOMEM; 1965 1966 /* Check table access is supported */ 1967 if (!efx->tc->meta_ct.hooked) 1968 return -EOPNOTSUPP; 1969 1970 /* key/resp widths are in bits; convert to dwords for IN_LEN */ 1971 kw = DIV_ROUND_UP(efx->tc->meta_ct.desc.key_width, 32); 1972 rw = DIV_ROUND_UP(efx->tc->meta_ct.desc.resp_width, 32); 1973 BUILD_BUG_ON(sizeof(__le32) != MC_CMD_TABLE_INSERT_IN_DATA_LEN); 1974 inlen = MC_CMD_TABLE_INSERT_IN_LEN(kw + rw); 1975 if (inlen > MC_CMD_TABLE_INSERT_IN_LENMAX_MCDI2) 1976 return -E2BIG; 1977 inbuf = kzalloc(inlen, GFP_KERNEL); 1978 if (!inbuf) 1979 return -ENOMEM; 1980 1981 key = kcalloc(kw, sizeof(__le32), GFP_KERNEL); 1982 if (!key) 1983 goto out_free; 1984 resp = kcalloc(rw, sizeof(__le32), GFP_KERNEL); 1985 if (!resp) 1986 goto out_free; 1987 1988 rc = efx_mae_populate_ct_key(efx, key, kw, conn); 1989 if (rc) 1990 goto out_free; 1991 1992 rc = TABLE_POPULATE_RESP_BOOL(resp, ct, dnat, conn->dnat); 1993 if (rc) 1994 goto out_free; 1995 /* No support in hw for IPv6 NAT; field is only 32 bits */ 1996 if (!ipv6) 1997 rc = TABLE_POPULATE_RESP(resp, ct, nat_ip, conn->nat_ip); 1998 if (rc) 1999 goto out_free; 2000 rc = TABLE_POPULATE_RESP(resp, ct, l4_natport, conn->l4_natport); 2001 if (rc) 2002 goto out_free; 2003 rc = TABLE_POPULATE_RESP(resp, ct, mark, cpu_to_be32(conn->mark)); 2004 if (rc) 2005 goto out_free; 2006 rc = TABLE_POPULATE_RESP_U24(resp, ct, counter_id, conn->cnt->fw_id); 2007 if (rc) 2008 goto out_free; 2009 2010 MCDI_SET_DWORD(inbuf, TABLE_INSERT_IN_TABLE_ID, TABLE_ID_CONNTRACK_TABLE); 2011 MCDI_SET_WORD(inbuf, TABLE_INSERT_IN_KEY_WIDTH, 2012 efx->tc->meta_ct.desc.key_width); 2013 /* MASK_WIDTH is zero as CT is a BCAM */ 2014 MCDI_SET_WORD(inbuf, TABLE_INSERT_IN_RESP_WIDTH, 2015 efx->tc->meta_ct.desc.resp_width); 2016 memcpy(MCDI_PTR(inbuf, TABLE_INSERT_IN_DATA), key, kw * sizeof(__le32)); 2017 memcpy(MCDI_PTR(inbuf, TABLE_INSERT_IN_DATA) + kw * sizeof(__le32), 2018 resp, rw * sizeof(__le32)); 2019 2020 BUILD_BUG_ON(MC_CMD_TABLE_INSERT_OUT_LEN); 2021 2022 rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_INSERT, inbuf, inlen, NULL, 0, NULL); 2023 2024 out_free: 2025 kfree(resp); 2026 kfree(key); 2027 kfree(inbuf); 2028 return rc; 2029 } 2030 2031 int efx_mae_remove_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn) 2032 { 2033 __le32 *key = NULL; 2034 efx_dword_t *inbuf; 2035 size_t inlen, kw; 2036 int rc = -ENOMEM; 2037 2038 /* Check table access is supported */ 2039 if (!efx->tc->meta_ct.hooked) 2040 return -EOPNOTSUPP; 2041 2042 /* key width is in bits; convert to dwords for IN_LEN */ 2043 kw = DIV_ROUND_UP(efx->tc->meta_ct.desc.key_width, 32); 2044 BUILD_BUG_ON(sizeof(__le32) != MC_CMD_TABLE_DELETE_IN_DATA_LEN); 2045 inlen = MC_CMD_TABLE_DELETE_IN_LEN(kw); 2046 if (inlen > MC_CMD_TABLE_DELETE_IN_LENMAX_MCDI2) 2047 return -E2BIG; 2048 inbuf = kzalloc(inlen, GFP_KERNEL); 2049 if (!inbuf) 2050 return -ENOMEM; 2051 2052 key = kcalloc(kw, sizeof(__le32), GFP_KERNEL); 2053 if (!key) 2054 goto out_free; 2055 2056 rc = efx_mae_populate_ct_key(efx, key, kw, conn); 2057 if (rc) 2058 goto out_free; 2059 2060 MCDI_SET_DWORD(inbuf, TABLE_DELETE_IN_TABLE_ID, TABLE_ID_CONNTRACK_TABLE); 2061 MCDI_SET_WORD(inbuf, TABLE_DELETE_IN_KEY_WIDTH, 2062 efx->tc->meta_ct.desc.key_width); 2063 /* MASK_WIDTH is zero as CT is a BCAM */ 2064 /* RESP_WIDTH is zero for DELETE */ 2065 memcpy(MCDI_PTR(inbuf, TABLE_DELETE_IN_DATA), key, kw * sizeof(__le32)); 2066 2067 BUILD_BUG_ON(MC_CMD_TABLE_DELETE_OUT_LEN); 2068 2069 rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_DELETE, inbuf, inlen, NULL, 0, NULL); 2070 2071 out_free: 2072 kfree(key); 2073 kfree(inbuf); 2074 return rc; 2075 } 2076 2077 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit), 2078 const struct efx_tc_match *match) 2079 { 2080 if (match->mask.ingress_port) { 2081 if (~match->mask.ingress_port) 2082 return -EOPNOTSUPP; 2083 MCDI_STRUCT_SET_DWORD(match_crit, 2084 MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR, 2085 match->value.ingress_port); 2086 } 2087 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK, 2088 match->mask.ingress_port); 2089 EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS), 2090 MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT, 2091 match->value.ct_state_trk, 2092 MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT, 2093 match->value.ct_state_est, 2094 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 2095 match->value.ip_frag, 2096 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 2097 match->value.ip_firstfrag, 2098 MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST, 2099 match->value.tcp_syn_fin_rst); 2100 EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK), 2101 MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT, 2102 match->mask.ct_state_trk, 2103 MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT, 2104 match->mask.ct_state_est, 2105 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG, 2106 match->mask.ip_frag, 2107 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG, 2108 match->mask.ip_firstfrag, 2109 MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST, 2110 match->mask.tcp_syn_fin_rst); 2111 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID, 2112 match->value.recirc_id); 2113 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK, 2114 match->mask.recirc_id); 2115 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK, 2116 match->value.ct_mark); 2117 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK_MASK, 2118 match->mask.ct_mark); 2119 MCDI_STRUCT_SET_WORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN, 2120 match->value.ct_zone); 2121 MCDI_STRUCT_SET_WORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN_MASK, 2122 match->mask.ct_zone); 2123 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE, 2124 match->value.eth_proto); 2125 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK, 2126 match->mask.eth_proto); 2127 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE, 2128 match->value.vlan_tci[0]); 2129 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK, 2130 match->mask.vlan_tci[0]); 2131 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE, 2132 match->value.vlan_proto[0]); 2133 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK, 2134 match->mask.vlan_proto[0]); 2135 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE, 2136 match->value.vlan_tci[1]); 2137 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK, 2138 match->mask.vlan_tci[1]); 2139 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE, 2140 match->value.vlan_proto[1]); 2141 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK, 2142 match->mask.vlan_proto[1]); 2143 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE), 2144 match->value.eth_saddr, ETH_ALEN); 2145 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK), 2146 match->mask.eth_saddr, ETH_ALEN); 2147 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE), 2148 match->value.eth_daddr, ETH_ALEN); 2149 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK), 2150 match->mask.eth_daddr, ETH_ALEN); 2151 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO, 2152 match->value.ip_proto); 2153 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK, 2154 match->mask.ip_proto); 2155 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS, 2156 match->value.ip_tos); 2157 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK, 2158 match->mask.ip_tos); 2159 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL, 2160 match->value.ip_ttl); 2161 MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK, 2162 match->mask.ip_ttl); 2163 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE, 2164 match->value.src_ip); 2165 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK, 2166 match->mask.src_ip); 2167 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE, 2168 match->value.dst_ip); 2169 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK, 2170 match->mask.dst_ip); 2171 #ifdef CONFIG_IPV6 2172 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE), 2173 &match->value.src_ip6, sizeof(struct in6_addr)); 2174 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK), 2175 &match->mask.src_ip6, sizeof(struct in6_addr)); 2176 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE), 2177 &match->value.dst_ip6, sizeof(struct in6_addr)); 2178 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK), 2179 &match->mask.dst_ip6, sizeof(struct in6_addr)); 2180 #endif 2181 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE, 2182 match->value.l4_sport); 2183 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK, 2184 match->mask.l4_sport); 2185 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE, 2186 match->value.l4_dport); 2187 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK, 2188 match->mask.l4_dport); 2189 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE, 2190 match->value.tcp_flags); 2191 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK, 2192 match->mask.tcp_flags); 2193 /* enc-keys are handled indirectly, through encap_match ID */ 2194 if (match->encap) { 2195 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID, 2196 match->encap->fw_id); 2197 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK, 2198 U32_MAX); 2199 /* enc_keyid (VNI/VSID) is not part of the encap_match */ 2200 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE, 2201 match->value.enc_keyid); 2202 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK, 2203 match->mask.enc_keyid); 2204 } else if (WARN_ON_ONCE(match->mask.enc_src_ip) || 2205 WARN_ON_ONCE(match->mask.enc_dst_ip) || 2206 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)) || 2207 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)) || 2208 WARN_ON_ONCE(match->mask.enc_ip_tos) || 2209 WARN_ON_ONCE(match->mask.enc_ip_ttl) || 2210 WARN_ON_ONCE(match->mask.enc_sport) || 2211 WARN_ON_ONCE(match->mask.enc_dport) || 2212 WARN_ON_ONCE(match->mask.enc_keyid)) { 2213 /* No enc-keys should appear in a rule without an encap_match */ 2214 return -EOPNOTSUPP; 2215 } 2216 return 0; 2217 } 2218 2219 int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match, 2220 u32 prio, u32 acts_id, u32 *id) 2221 { 2222 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN)); 2223 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN); 2224 MCDI_DECLARE_STRUCT_PTR(match_crit); 2225 MCDI_DECLARE_STRUCT_PTR(response); 2226 size_t outlen; 2227 int rc; 2228 2229 if (!id) 2230 return -EINVAL; 2231 2232 match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA); 2233 response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE); 2234 if (efx_mae_asl_id(acts_id)) { 2235 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); 2236 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 2237 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 2238 } else { 2239 /* We only had one AS, so we didn't wrap it in an ASL */ 2240 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 2241 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 2242 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); 2243 } 2244 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio); 2245 rc = efx_mae_populate_match_criteria(match_crit, match); 2246 if (rc) 2247 return rc; 2248 2249 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf), 2250 outbuf, sizeof(outbuf), &outlen); 2251 if (rc) 2252 return rc; 2253 if (outlen < sizeof(outbuf)) 2254 return -EIO; 2255 *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID); 2256 return 0; 2257 } 2258 2259 int efx_mae_update_rule(struct efx_nic *efx, u32 acts_id, u32 id) 2260 { 2261 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_UPDATE_IN_LEN); 2262 MCDI_DECLARE_STRUCT_PTR(response); 2263 2264 BUILD_BUG_ON(MC_CMD_MAE_ACTION_RULE_UPDATE_OUT_LEN); 2265 response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_RESPONSE); 2266 2267 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_AR_ID, id); 2268 if (efx_mae_asl_id(acts_id)) { 2269 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id); 2270 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, 2271 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL); 2272 } else { 2273 /* We only had one AS, so we didn't wrap it in an ASL */ 2274 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, 2275 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL); 2276 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id); 2277 } 2278 return efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_UPDATE, inbuf, sizeof(inbuf), 2279 NULL, 0, NULL); 2280 } 2281 2282 int efx_mae_delete_rule(struct efx_nic *efx, u32 id) 2283 { 2284 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1)); 2285 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1)); 2286 size_t outlen; 2287 int rc; 2288 2289 MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id); 2290 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf), 2291 outbuf, sizeof(outbuf), &outlen); 2292 if (rc) 2293 return rc; 2294 if (outlen < sizeof(outbuf)) 2295 return -EIO; 2296 /* FW freed a different ID than we asked for, should also never happen. 2297 * Warn because it means we've now got a different idea to the FW of 2298 * what rules exist, which could cause mayhem later. 2299 */ 2300 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id)) 2301 return -EIO; 2302 return 0; 2303 } 2304 2305 int efx_init_mae(struct efx_nic *efx) 2306 { 2307 struct ef100_nic_data *nic_data = efx->nic_data; 2308 struct efx_mae *mae; 2309 int rc; 2310 2311 if (!nic_data->have_mport) 2312 return -EINVAL; 2313 2314 mae = kmalloc(sizeof(*mae), GFP_KERNEL); 2315 if (!mae) 2316 return -ENOMEM; 2317 2318 rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params); 2319 if (rc < 0) { 2320 kfree(mae); 2321 return rc; 2322 } 2323 efx->mae = mae; 2324 mae->efx = efx; 2325 return 0; 2326 } 2327 2328 void efx_fini_mae(struct efx_nic *efx) 2329 { 2330 struct efx_mae *mae = efx->mae; 2331 2332 kfree(mae); 2333 efx->mae = NULL; 2334 } 2335