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