mae.c (cecdd52a3dd312564f81a39df08378b7b39a2654) mae.c (b9d5c9b7d8a47ca4af5e32f576265c388a467af5)
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

--- 240 unchanged lines hidden (view full) ---

249 u8 *field_support)
250{
251 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS));
252 MCDI_DECLARE_STRUCT_PTR(caps);
253 unsigned int count;
254 size_t outlen;
255 int rc, i;
256
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

--- 240 unchanged lines hidden (view full) ---

249 u8 *field_support)
250{
251 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS));
252 MCDI_DECLARE_STRUCT_PTR(caps);
253 unsigned int count;
254 size_t outlen;
255 int rc, i;
256
257 /* AR and OR caps MCDIs have identical layout, so we are using the
258 * same code for both.
259 */
260 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS) <
261 MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(MAE_NUM_FIELDS));
257 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN);
262 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN);
263 BUILD_BUG_ON(MC_CMD_MAE_GET_OR_CAPS_IN_LEN);
258
259 rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen);
260 if (rc)
261 return rc;
264
265 rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen);
266 if (rc)
267 return rc;
268 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_COUNT_OFST !=
269 MC_CMD_MAE_GET_OR_CAPS_OUT_COUNT_OFST);
262 count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT);
263 memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS);
270 count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT);
271 memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS);
272 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST !=
273 MC_CMD_MAE_GET_OR_CAPS_OUT_FIELD_FLAGS_OFST);
264 caps = _MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS);
265 /* We're only interested in the support status enum, not any other
266 * flags, so just extract that from each entry.
267 */
268 for (i = 0; i < count; i++)
269 if (i * sizeof(*outbuf) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen)
270 field_support[i] = EFX_DWORD_FIELD(caps[i], MAE_FIELD_FLAGS_SUPPORT_STATUS);
271 return 0;
272}
273
274int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps)
275{
276 int rc;
277
278 rc = efx_mae_get_basic_caps(efx, caps);
279 if (rc)
280 return rc;
274 caps = _MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS);
275 /* We're only interested in the support status enum, not any other
276 * flags, so just extract that from each entry.
277 */
278 for (i = 0; i < count; i++)
279 if (i * sizeof(*outbuf) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen)
280 field_support[i] = EFX_DWORD_FIELD(caps[i], MAE_FIELD_FLAGS_SUPPORT_STATUS);
281 return 0;
282}
283
284int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps)
285{
286 int rc;
287
288 rc = efx_mae_get_basic_caps(efx, caps);
289 if (rc)
290 return rc;
281 return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS,
282 caps->action_rule_fields);
291 rc = efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS,
292 caps->action_rule_fields);
293 if (rc)
294 return rc;
295 return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_OR_CAPS,
296 caps->outer_rule_fields);
283}
284
285/* Bit twiddling:
286 * Prefix: 1...110...0
287 * ~: 0...001...1
288 * + 1: 0...010...0 is power of two
289 * so (~x) & ((~x) + 1) == 0. Converse holds also.
290 */

--- 136 unchanged lines hidden (view full) ---

427#endif
428 CHECK(L4_SPORT, l4_sport) ||
429 CHECK(L4_DPORT, l4_dport) ||
430 CHECK(TCP_FLAGS, tcp_flags) ||
431 CHECK_BIT(IS_IP_FRAG, ip_frag) ||
432 CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) ||
433 CHECK(RECIRC_ID, recirc_id))
434 return rc;
297}
298
299/* Bit twiddling:
300 * Prefix: 1...110...0
301 * ~: 0...001...1
302 * + 1: 0...010...0 is power of two
303 * so (~x) & ((~x) + 1) == 0. Converse holds also.
304 */

--- 136 unchanged lines hidden (view full) ---

441#endif
442 CHECK(L4_SPORT, l4_sport) ||
443 CHECK(L4_DPORT, l4_dport) ||
444 CHECK(TCP_FLAGS, tcp_flags) ||
445 CHECK_BIT(IS_IP_FRAG, ip_frag) ||
446 CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) ||
447 CHECK(RECIRC_ID, recirc_id))
448 return rc;
449 /* Matches on outer fields are done in a separate hardware table,
450 * the Outer Rule table. Thus the Action Rule merely does an
451 * exact match on Outer Rule ID if any outer field matches are
452 * present. The exception is the VNI/VSID (enc_keyid), which is
453 * available to the Action Rule match iff the Outer Rule matched
454 * (and thus identified the encap protocol to use to extract it).
455 */
456 if (efx_tc_match_is_encap(mask)) {
457 rc = efx_mae_match_check_cap_typ(
458 supported_fields[MAE_FIELD_OUTER_RULE_ID],
459 MASK_ONES);
460 if (rc) {
461 NL_SET_ERR_MSG_MOD(extack, "No support for encap rule ID matches");
462 return rc;
463 }
464 if (CHECK(ENC_VNET_ID, enc_keyid))
465 return rc;
466 } else if (mask->enc_keyid) {
467 NL_SET_ERR_MSG_MOD(extack, "Match on enc_keyid requires other encap fields");
468 return -EINVAL;
469 }
435 return 0;
436}
437#undef CHECK_BIT
438#undef CHECK
439
470 return 0;
471}
472#undef CHECK_BIT
473#undef CHECK
474
475#define CHECK(_mcdi) ({ \
476 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
477 MASK_ONES); \
478 if (rc) \
479 NL_SET_ERR_MSG_FMT_MOD(extack, \
480 "No support for field %s", #_mcdi); \
481 rc; \
482})
483/* Checks that the fields needed for encap-rule matches are supported by the
484 * MAE. All the fields are exact-match.
485 */
486int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6,
487 struct netlink_ext_ack *extack)
488{
489 u8 *supported_fields = efx->tc->caps->outer_rule_fields;
490 int rc;
491
492 if (CHECK(ENC_ETHER_TYPE))
493 return rc;
494 if (ipv6) {
495 if (CHECK(ENC_SRC_IP6) ||
496 CHECK(ENC_DST_IP6))
497 return rc;
498 } else {
499 if (CHECK(ENC_SRC_IP4) ||
500 CHECK(ENC_DST_IP4))
501 return rc;
502 }
503 if (CHECK(ENC_L4_DPORT) ||
504 CHECK(ENC_IP_PROTO))
505 return rc;
506 return 0;
507}
508#undef CHECK
509
440int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
441{
442 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1));
443 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN);
444 size_t outlen;
445 int rc;
446
447 if (!cnt)

--- 229 unchanged lines hidden (view full) ---

677
678int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
679{
680 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
681 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN);
682 size_t outlen;
683 int rc;
684
510int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
511{
512 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1));
513 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN);
514 size_t outlen;
515 int rc;
516
517 if (!cnt)

--- 229 unchanged lines hidden (view full) ---

747
748int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
749{
750 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
751 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN);
752 size_t outlen;
753 int rc;
754
755 MCDI_POPULATE_DWORD_2(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS,
756 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, act->vlan_push,
757 MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop);
758
685 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
686 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
687 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
688 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
689 if (act->count && !WARN_ON(!act->count->cnt))
690 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
691 act->count->cnt->fw_id);
692 else
693 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
694 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
695 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID,
696 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL);
759 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
760 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
761 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
762 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
763 if (act->count && !WARN_ON(!act->count->cnt))
764 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
765 act->count->cnt->fw_id);
766 else
767 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
768 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
769 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID,
770 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL);
771 if (act->vlan_push) {
772 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
773 act->vlan_tci[0]);
774 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
775 act->vlan_proto[0]);
776 }
777 if (act->vlan_push >= 2) {
778 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
779 act->vlan_tci[1]);
780 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
781 act->vlan_proto[1]);
782 }
697 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
698 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
699 if (act->deliver)
700 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER,
701 act->dest_mport);
702 BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL);
703 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf),
704 outbuf, sizeof(outbuf), &outlen);

--- 215 unchanged lines hidden (view full) ---

920 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE,
921 match->value.l4_dport);
922 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK,
923 match->mask.l4_dport);
924 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE,
925 match->value.tcp_flags);
926 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK,
927 match->mask.tcp_flags);
783 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
784 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
785 if (act->deliver)
786 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER,
787 act->dest_mport);
788 BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL);
789 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf),
790 outbuf, sizeof(outbuf), &outlen);

--- 215 unchanged lines hidden (view full) ---

1006 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE,
1007 match->value.l4_dport);
1008 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK,
1009 match->mask.l4_dport);
1010 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE,
1011 match->value.tcp_flags);
1012 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK,
1013 match->mask.tcp_flags);
1014 /* enc-keys are handled indirectly, through encap_match ID */
1015 if (match->encap) {
1016 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID,
1017 match->encap->fw_id);
1018 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK,
1019 U32_MAX);
1020 /* enc_keyid (VNI/VSID) is not part of the encap_match */
1021 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE,
1022 match->value.enc_keyid);
1023 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK,
1024 match->mask.enc_keyid);
1025 } else if (WARN_ON_ONCE(match->mask.enc_src_ip) ||
1026 WARN_ON_ONCE(match->mask.enc_dst_ip) ||
1027 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)) ||
1028 WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)) ||
1029 WARN_ON_ONCE(match->mask.enc_ip_tos) ||
1030 WARN_ON_ONCE(match->mask.enc_ip_ttl) ||
1031 WARN_ON_ONCE(match->mask.enc_sport) ||
1032 WARN_ON_ONCE(match->mask.enc_dport) ||
1033 WARN_ON_ONCE(match->mask.enc_keyid)) {
1034 /* No enc-keys should appear in a rule without an encap_match */
1035 return -EOPNOTSUPP;
1036 }
928 return 0;
929}
930
931int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
932 u32 prio, u32 acts_id, u32 *id)
933{
934 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN));
935 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);

--- 88 unchanged lines hidden ---
1037 return 0;
1038}
1039
1040int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
1041 u32 prio, u32 acts_id, u32 *id)
1042{
1043 MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN));
1044 MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);

--- 88 unchanged lines hidden ---