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