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.
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.
12 #include <linux/rhashtable.h>
13 #include "ef100_nic.h"
16 #include "mcdi_pcol.h"
17 #include "mcdi_pcol_mae.h"
18 #include "tc_encap_actions.h"
19 #include "tc_conntrack.h"
21 int efx_mae_allocate_mport(struct efx_nic
*efx
, u32
*id
, u32
*label
)
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
);
28 if (WARN_ON_ONCE(!id
))
30 if (WARN_ON_ONCE(!label
))
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
);
41 if (outlen
< sizeof(outbuf
))
43 *id
= MCDI_DWORD(outbuf
, MAE_MPORT_ALLOC_ALIAS_OUT_MPORT_ID
);
44 *label
= MCDI_DWORD(outbuf
, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL
);
48 int efx_mae_free_mport(struct efx_nic
*efx
, u32 id
)
50 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_MPORT_FREE_IN_LEN
);
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
),
58 void efx_mae_mport_wire(struct efx_nic
*efx
, u32
*out
)
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
);
68 void efx_mae_mport_uplink(struct efx_nic
*efx __always_unused
, u32
*out
)
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
);
79 /* Constructs an mport selector from an mport ID, because they're not the same */
80 void efx_mae_mport_mport(struct efx_nic
*efx __always_unused
, u32 mport_id
, u32
*out
)
84 EFX_POPULATE_DWORD_2(mport
,
85 MAE_MPORT_SELECTOR_TYPE
, MAE_MPORT_SELECTOR_TYPE_MPORT_ID
,
86 MAE_MPORT_SELECTOR_MPORT_ID
, mport_id
);
87 *out
= EFX_DWORD_VAL(mport
);
90 /* id is really only 24 bits wide */
91 int efx_mae_fw_lookup_mport(struct efx_nic
*efx
, u32 selector
, u32
*id
)
93 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN
);
94 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_MPORT_LOOKUP_IN_LEN
);
98 MCDI_SET_DWORD(inbuf
, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR
, selector
);
99 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_MPORT_LOOKUP
, inbuf
, sizeof(inbuf
),
100 outbuf
, sizeof(outbuf
), &outlen
);
103 if (outlen
< sizeof(outbuf
))
105 *id
= MCDI_DWORD(outbuf
, MAE_MPORT_LOOKUP_OUT_MPORT_ID
);
109 int efx_mae_start_counters(struct efx_nic
*efx
, struct efx_rx_queue
*rx_queue
)
111 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_COUNTERS_STREAM_START_V2_IN_LEN
);
112 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN
);
117 MCDI_SET_WORD(inbuf
, MAE_COUNTERS_STREAM_START_V2_IN_QID
,
118 efx_rx_queue_index(rx_queue
));
119 MCDI_SET_WORD(inbuf
, MAE_COUNTERS_STREAM_START_V2_IN_PACKET_SIZE
,
121 MCDI_SET_DWORD(inbuf
, MAE_COUNTERS_STREAM_START_V2_IN_COUNTER_TYPES_MASK
,
122 BIT(MAE_COUNTER_TYPE_AR
) | BIT(MAE_COUNTER_TYPE_CT
) |
123 BIT(MAE_COUNTER_TYPE_OR
));
124 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_COUNTERS_STREAM_START
,
125 inbuf
, sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
128 if (outlen
< sizeof(outbuf
))
130 out_flags
= MCDI_DWORD(outbuf
, MAE_COUNTERS_STREAM_START_OUT_FLAGS
);
131 if (out_flags
& BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST
)) {
132 netif_dbg(efx
, drv
, efx
->net_dev
,
133 "MAE counter stream uses credits\n");
134 rx_queue
->grant_credits
= true;
135 out_flags
&= ~BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST
);
138 netif_err(efx
, drv
, efx
->net_dev
,
139 "MAE counter stream start: unrecognised flags %x\n",
145 efx_mae_stop_counters(efx
, rx_queue
);
149 static bool efx_mae_counters_flushed(u32
*flush_gen
, u32
*seen_gen
)
153 for (i
= 0; i
< EFX_TC_COUNTER_TYPE_MAX
; i
++)
154 if ((s32
)(flush_gen
[i
] - seen_gen
[i
]) > 0)
159 int efx_mae_stop_counters(struct efx_nic
*efx
, struct efx_rx_queue
*rx_queue
)
161 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_COUNTERS_STREAM_STOP_V2_OUT_LENMAX
);
162 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN
);
166 MCDI_SET_WORD(inbuf
, MAE_COUNTERS_STREAM_STOP_IN_QID
,
167 efx_rx_queue_index(rx_queue
));
168 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_COUNTERS_STREAM_STOP
,
169 inbuf
, sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
174 netif_dbg(efx
, drv
, efx
->net_dev
, "Draining counters:\n");
175 /* Only process received generation counts */
176 for (i
= 0; (i
< (outlen
/ 4)) && (i
< EFX_TC_COUNTER_TYPE_MAX
); i
++) {
177 efx
->tc
->flush_gen
[i
] = MCDI_ARRAY_DWORD(outbuf
,
178 MAE_COUNTERS_STREAM_STOP_V2_OUT_GENERATION_COUNT
,
180 netif_dbg(efx
, drv
, efx
->net_dev
,
181 "\ttype %u, awaiting gen %u\n", i
,
182 efx
->tc
->flush_gen
[i
]);
185 efx
->tc
->flush_counters
= true;
187 /* Drain can take up to 2 seconds owing to FWRIVERHD-2884; whatever
188 * timeout we use, that delay is added to unload on nonresponsive
189 * hardware, so 2500ms seems like a reasonable compromise.
191 if (!wait_event_timeout(efx
->tc
->flush_wq
,
192 efx_mae_counters_flushed(efx
->tc
->flush_gen
,
194 msecs_to_jiffies(2500)))
195 netif_warn(efx
, drv
, efx
->net_dev
,
196 "Failed to drain counters RXQ, FW may be unhappy\n");
198 efx
->tc
->flush_counters
= false;
203 void efx_mae_counters_grant_credits(struct work_struct
*work
)
205 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN
);
206 struct efx_rx_queue
*rx_queue
= container_of(work
, struct efx_rx_queue
,
208 struct efx_nic
*efx
= rx_queue
->efx
;
209 unsigned int credits
;
211 BUILD_BUG_ON(MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN
);
212 credits
= READ_ONCE(rx_queue
->notified_count
) - rx_queue
->granted_count
;
213 MCDI_SET_DWORD(inbuf
, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS
,
215 if (!efx_mcdi_rpc(efx
, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS
,
216 inbuf
, sizeof(inbuf
), NULL
, 0, NULL
))
217 rx_queue
->granted_count
+= credits
;
220 static int efx_mae_table_get_desc(struct efx_nic
*efx
,
221 struct efx_tc_table_desc
*desc
,
224 MCDI_DECLARE_BUF(outbuf
, MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(16));
225 MCDI_DECLARE_BUF(inbuf
, MC_CMD_TABLE_DESCRIPTOR_IN_LEN
);
226 unsigned int offset
= 0, i
;
230 memset(desc
, 0, sizeof(*desc
));
232 MCDI_SET_DWORD(inbuf
, TABLE_DESCRIPTOR_IN_TABLE_ID
, table_id
);
234 MCDI_SET_DWORD(inbuf
, TABLE_DESCRIPTOR_IN_FIRST_FIELDS_INDEX
, offset
);
235 rc
= efx_mcdi_rpc(efx
, MC_CMD_TABLE_DESCRIPTOR
, inbuf
, sizeof(inbuf
),
236 outbuf
, sizeof(outbuf
), &outlen
);
239 if (outlen
< MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(1)) {
243 if (!offset
) { /* first iteration: get metadata */
244 desc
->type
= MCDI_WORD(outbuf
, TABLE_DESCRIPTOR_OUT_TYPE
);
245 desc
->key_width
= MCDI_WORD(outbuf
, TABLE_DESCRIPTOR_OUT_KEY_WIDTH
);
246 desc
->resp_width
= MCDI_WORD(outbuf
, TABLE_DESCRIPTOR_OUT_RESP_WIDTH
);
247 desc
->n_keys
= MCDI_WORD(outbuf
, TABLE_DESCRIPTOR_OUT_N_KEY_FIELDS
);
248 desc
->n_resps
= MCDI_WORD(outbuf
, TABLE_DESCRIPTOR_OUT_N_RESP_FIELDS
);
249 desc
->n_prios
= MCDI_WORD(outbuf
, TABLE_DESCRIPTOR_OUT_N_PRIORITIES
);
250 desc
->flags
= MCDI_BYTE(outbuf
, TABLE_DESCRIPTOR_OUT_FLAGS
);
254 desc
->scheme
= MCDI_BYTE(outbuf
, TABLE_DESCRIPTOR_OUT_SCHEME
);
258 desc
->keys
= kcalloc(desc
->n_keys
,
259 sizeof(struct efx_tc_table_field_fmt
),
263 desc
->resps
= kcalloc(desc
->n_resps
,
264 sizeof(struct efx_tc_table_field_fmt
),
269 /* FW could have returned more than the 16 field_descrs we
270 * made room for in our outbuf
272 outlen
= min(outlen
, sizeof(outbuf
));
273 for (i
= 0; i
+ offset
< desc
->n_keys
+ desc
->n_resps
; i
++) {
274 struct efx_tc_table_field_fmt
*field
;
275 MCDI_DECLARE_STRUCT_PTR(fdesc
);
277 if (outlen
< MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(i
+ 1)) {
281 if (i
+ offset
< desc
->n_keys
)
282 field
= desc
->keys
+ i
+ offset
;
284 field
= desc
->resps
+ (i
+ offset
- desc
->n_keys
);
285 fdesc
= MCDI_ARRAY_STRUCT_PTR(outbuf
,
286 TABLE_DESCRIPTOR_OUT_FIELDS
, i
);
287 field
->field_id
= MCDI_STRUCT_WORD(fdesc
,
288 TABLE_FIELD_DESCR_FIELD_ID
);
289 field
->lbn
= MCDI_STRUCT_WORD(fdesc
, TABLE_FIELD_DESCR_LBN
);
290 field
->width
= MCDI_STRUCT_WORD(fdesc
, TABLE_FIELD_DESCR_WIDTH
);
291 field
->masking
= MCDI_STRUCT_BYTE(fdesc
, TABLE_FIELD_DESCR_MASK_TYPE
);
292 field
->scheme
= MCDI_STRUCT_BYTE(fdesc
, TABLE_FIELD_DESCR_SCHEME
);
302 static int efx_mae_table_hook_find(u16 n_fields
,
303 struct efx_tc_table_field_fmt
*fields
,
308 for (i
= 0; i
< n_fields
; i
++) {
309 if (fields
[i
].field_id
== field_id
)
315 #define TABLE_FIND_KEY(_desc, _id) \
316 efx_mae_table_hook_find((_desc)->n_keys, (_desc)->keys, _id)
317 #define TABLE_FIND_RESP(_desc, _id) \
318 efx_mae_table_hook_find((_desc)->n_resps, (_desc)->resps, _id)
320 #define TABLE_HOOK_KEY(_meta, _name, _mcdi_name) ({ \
321 int _rc = TABLE_FIND_KEY(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name); \
326 _meta->keys._name##_idx = _rc; \
331 #define TABLE_HOOK_RESP(_meta, _name, _mcdi_name) ({ \
332 int _rc = TABLE_FIND_RESP(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name); \
337 _meta->resps._name##_idx = _rc; \
343 static int efx_mae_table_hook_ct(struct efx_nic
*efx
,
344 struct efx_tc_table_ct
*meta_ct
)
348 rc
= TABLE_HOOK_KEY(meta_ct
, eth_proto
, ETHER_TYPE
);
351 rc
= TABLE_HOOK_KEY(meta_ct
, ip_proto
, IP_PROTO
);
354 rc
= TABLE_HOOK_KEY(meta_ct
, src_ip
, SRC_IP
);
357 rc
= TABLE_HOOK_KEY(meta_ct
, dst_ip
, DST_IP
);
360 rc
= TABLE_HOOK_KEY(meta_ct
, l4_sport
, SRC_PORT
);
363 rc
= TABLE_HOOK_KEY(meta_ct
, l4_dport
, DST_PORT
);
366 rc
= TABLE_HOOK_KEY(meta_ct
, zone
, DOMAIN
);
369 rc
= TABLE_HOOK_RESP(meta_ct
, dnat
, NAT_DIR
);
372 rc
= TABLE_HOOK_RESP(meta_ct
, nat_ip
, NAT_IP
);
375 rc
= TABLE_HOOK_RESP(meta_ct
, l4_natport
, NAT_PORT
);
378 rc
= TABLE_HOOK_RESP(meta_ct
, mark
, CT_MARK
);
381 rc
= TABLE_HOOK_RESP(meta_ct
, counter_id
, COUNTER_ID
);
384 meta_ct
->hooked
= true;
388 static void efx_mae_table_free_desc(struct efx_tc_table_desc
*desc
)
392 memset(desc
, 0, sizeof(*desc
));
395 static bool efx_mae_check_table_exists(struct efx_nic
*efx
, u32 tbl_req
)
397 MCDI_DECLARE_BUF(outbuf
, MC_CMD_TABLE_LIST_OUT_LEN(16));
398 MCDI_DECLARE_BUF(inbuf
, MC_CMD_TABLE_LIST_IN_LEN
);
399 u32 tbl_id
, tbl_total
, tbl_cnt
, pos
= 0;
400 size_t outlen
, msg_max
;
404 msg_max
= sizeof(outbuf
);
405 efx
->tc
->meta_ct
.hooked
= false;
407 memset(outbuf
, 0, sizeof(*outbuf
));
408 MCDI_SET_DWORD(inbuf
, TABLE_LIST_IN_FIRST_TABLE_ID_INDEX
, pos
);
409 rc
= efx_mcdi_rpc(efx
, MC_CMD_TABLE_LIST
, inbuf
, sizeof(inbuf
), outbuf
,
414 if (outlen
< MC_CMD_TABLE_LIST_OUT_LEN(1))
417 tbl_total
= MCDI_DWORD(outbuf
, TABLE_LIST_OUT_N_TABLES
);
418 tbl_cnt
= MC_CMD_TABLE_LIST_OUT_TABLE_ID_NUM(min(outlen
, msg_max
));
420 for (idx
= 0; idx
< tbl_cnt
; idx
++) {
421 tbl_id
= MCDI_ARRAY_DWORD(outbuf
, TABLE_LIST_OUT_TABLE_ID
, idx
);
422 if (tbl_id
== tbl_req
) {
429 if (!ct_tbl
&& pos
< tbl_total
)
435 int efx_mae_get_tables(struct efx_nic
*efx
)
439 efx
->tc
->meta_ct
.hooked
= false;
440 if (efx_mae_check_table_exists(efx
, TABLE_ID_CONNTRACK_TABLE
)) {
441 rc
= efx_mae_table_get_desc(efx
, &efx
->tc
->meta_ct
.desc
,
442 TABLE_ID_CONNTRACK_TABLE
);
444 pci_info(efx
->pci_dev
,
445 "FW does not support conntrack desc rc %d\n",
450 rc
= efx_mae_table_hook_ct(efx
, &efx
->tc
->meta_ct
);
452 pci_info(efx
->pci_dev
,
453 "FW does not support conntrack hook rc %d\n",
458 pci_info(efx
->pci_dev
,
459 "FW does not support conntrack table\n");
464 void efx_mae_free_tables(struct efx_nic
*efx
)
466 efx_mae_table_free_desc(&efx
->tc
->meta_ct
.desc
);
467 efx
->tc
->meta_ct
.hooked
= false;
470 static int efx_mae_get_basic_caps(struct efx_nic
*efx
, struct mae_caps
*caps
)
472 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_GET_CAPS_OUT_LEN
);
476 BUILD_BUG_ON(MC_CMD_MAE_GET_CAPS_IN_LEN
);
478 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_GET_CAPS
, NULL
, 0, outbuf
,
479 sizeof(outbuf
), &outlen
);
482 if (outlen
< sizeof(outbuf
))
484 caps
->match_field_count
= MCDI_DWORD(outbuf
, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT
);
485 caps
->encap_types
= MCDI_DWORD(outbuf
, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED
);
486 caps
->action_prios
= MCDI_DWORD(outbuf
, MAE_GET_CAPS_OUT_ACTION_PRIOS
);
490 static int efx_mae_get_rule_fields(struct efx_nic
*efx
, u32 cmd
,
493 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS
));
494 MCDI_DECLARE_STRUCT_PTR(caps
);
499 /* AR and OR caps MCDIs have identical layout, so we are using the
500 * same code for both.
502 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS
) <
503 MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(MAE_NUM_FIELDS
));
504 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN
);
505 BUILD_BUG_ON(MC_CMD_MAE_GET_OR_CAPS_IN_LEN
);
507 rc
= efx_mcdi_rpc(efx
, cmd
, NULL
, 0, outbuf
, sizeof(outbuf
), &outlen
);
510 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_COUNT_OFST
!=
511 MC_CMD_MAE_GET_OR_CAPS_OUT_COUNT_OFST
);
512 count
= MCDI_DWORD(outbuf
, MAE_GET_AR_CAPS_OUT_COUNT
);
513 memset(field_support
, MAE_FIELD_UNSUPPORTED
, MAE_NUM_FIELDS
);
514 BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST
!=
515 MC_CMD_MAE_GET_OR_CAPS_OUT_FIELD_FLAGS_OFST
);
516 caps
= _MCDI_DWORD(outbuf
, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS
);
517 /* We're only interested in the support status enum, not any other
518 * flags, so just extract that from each entry.
520 for (i
= 0; i
< count
; i
++)
521 if (i
* sizeof(*outbuf
) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST
< outlen
)
522 field_support
[i
] = EFX_DWORD_FIELD(caps
[i
], MAE_FIELD_FLAGS_SUPPORT_STATUS
);
526 int efx_mae_get_caps(struct efx_nic
*efx
, struct mae_caps
*caps
)
530 rc
= efx_mae_get_basic_caps(efx
, caps
);
533 rc
= efx_mae_get_rule_fields(efx
, MC_CMD_MAE_GET_AR_CAPS
,
534 caps
->action_rule_fields
);
537 return efx_mae_get_rule_fields(efx
, MC_CMD_MAE_GET_OR_CAPS
,
538 caps
->outer_rule_fields
);
542 * Prefix: 1...110...0
544 * + 1: 0...010...0 is power of two
545 * so (~x) & ((~x) + 1) == 0. Converse holds also.
547 #define is_prefix_byte(_x) !(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1))
549 enum mask_type
{ MASK_ONES
, MASK_ZEROES
, MASK_PREFIX
, MASK_OTHER
};
551 static const char *mask_type_name(enum mask_type typ
)
562 default: /* can't happen */
567 /* Checks a (big-endian) bytestring is a bit prefix */
568 static enum mask_type
classify_mask(const u8
*mask
, size_t len
)
570 bool zeroes
= true; /* All bits seen so far are zeroes */
571 bool ones
= true; /* All bits seen so far are ones */
572 bool prefix
= true; /* Valid prefix so far */
575 for (i
= 0; i
< len
; i
++) {
577 if (!is_prefix_byte(mask
[i
]))
579 } else if (mask
[i
]) {
596 static int efx_mae_match_check_cap_typ(u8 support
, enum mask_type typ
)
599 case MAE_FIELD_UNSUPPORTED
:
600 case MAE_FIELD_SUPPORTED_MATCH_NEVER
:
601 if (typ
== MASK_ZEROES
)
604 case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL
:
605 if (typ
== MASK_ZEROES
)
608 case MAE_FIELD_SUPPORTED_MATCH_ALWAYS
:
609 if (typ
== MASK_ONES
)
612 case MAE_FIELD_SUPPORTED_MATCH_PREFIX
:
613 if (typ
== MASK_OTHER
)
616 case MAE_FIELD_SUPPORTED_MATCH_MASK
:
623 /* Validate field mask against hardware capabilities. Captures caller's 'rc' */
624 #define CHECK(_mcdi, _field) ({ \
625 enum mask_type typ = classify_mask((const u8 *)&mask->_field, \
626 sizeof(mask->_field)); \
628 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
631 NL_SET_ERR_MSG_FMT_MOD(extack, \
632 "No support for %s mask in field %s", \
633 mask_type_name(typ), #_field); \
636 /* Booleans need special handling */
637 #define CHECK_BIT(_mcdi, _field) ({ \
638 enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES; \
640 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
643 NL_SET_ERR_MSG_FMT_MOD(extack, \
644 "No support for %s mask in field %s", \
645 mask_type_name(typ), #_field); \
649 int efx_mae_match_check_caps(struct efx_nic
*efx
,
650 const struct efx_tc_match_fields
*mask
,
651 struct netlink_ext_ack
*extack
)
653 const u8
*supported_fields
= efx
->tc
->caps
->action_rule_fields
;
654 __be32 ingress_port
= cpu_to_be32(mask
->ingress_port
);
655 enum mask_type ingress_port_mask_type
;
658 /* Check for _PREFIX assumes big-endian, so we need to convert */
659 ingress_port_mask_type
= classify_mask((const u8
*)&ingress_port
,
660 sizeof(ingress_port
));
661 rc
= efx_mae_match_check_cap_typ(supported_fields
[MAE_FIELD_INGRESS_PORT
],
662 ingress_port_mask_type
);
664 NL_SET_ERR_MSG_FMT_MOD(extack
, "No support for %s mask in field ingress_port",
665 mask_type_name(ingress_port_mask_type
));
668 if (CHECK(ETHER_TYPE
, eth_proto
) ||
669 CHECK(VLAN0_TCI
, vlan_tci
[0]) ||
670 CHECK(VLAN0_PROTO
, vlan_proto
[0]) ||
671 CHECK(VLAN1_TCI
, vlan_tci
[1]) ||
672 CHECK(VLAN1_PROTO
, vlan_proto
[1]) ||
673 CHECK(ETH_SADDR
, eth_saddr
) ||
674 CHECK(ETH_DADDR
, eth_daddr
) ||
675 CHECK(IP_PROTO
, ip_proto
) ||
676 CHECK(IP_TOS
, ip_tos
) ||
677 CHECK(IP_TTL
, ip_ttl
) ||
678 CHECK(SRC_IP4
, src_ip
) ||
679 CHECK(DST_IP4
, dst_ip
) ||
681 CHECK(SRC_IP6
, src_ip6
) ||
682 CHECK(DST_IP6
, dst_ip6
) ||
684 CHECK(L4_SPORT
, l4_sport
) ||
685 CHECK(L4_DPORT
, l4_dport
) ||
686 CHECK(TCP_FLAGS
, tcp_flags
) ||
687 CHECK_BIT(TCP_SYN_FIN_RST
, tcp_syn_fin_rst
) ||
688 CHECK_BIT(IS_IP_FRAG
, ip_frag
) ||
689 CHECK_BIT(IP_FIRST_FRAG
, ip_firstfrag
) ||
690 CHECK_BIT(DO_CT
, ct_state_trk
) ||
691 CHECK_BIT(CT_HIT
, ct_state_est
) ||
692 CHECK(CT_MARK
, ct_mark
) ||
693 CHECK(CT_DOMAIN
, ct_zone
) ||
694 CHECK(RECIRC_ID
, recirc_id
))
696 /* Matches on outer fields are done in a separate hardware table,
697 * the Outer Rule table. Thus the Action Rule merely does an
698 * exact match on Outer Rule ID if any outer field matches are
699 * present. The exception is the VNI/VSID (enc_keyid), which is
700 * available to the Action Rule match iff the Outer Rule matched
701 * (and thus identified the encap protocol to use to extract it).
703 if (efx_tc_match_is_encap(mask
)) {
704 rc
= efx_mae_match_check_cap_typ(
705 supported_fields
[MAE_FIELD_OUTER_RULE_ID
],
708 NL_SET_ERR_MSG_MOD(extack
, "No support for encap rule ID matches");
711 if (CHECK(ENC_VNET_ID
, enc_keyid
))
713 } else if (mask
->enc_keyid
) {
714 NL_SET_ERR_MSG_MOD(extack
, "Match on enc_keyid requires other encap fields");
720 /* Checks for match fields not supported in LHS Outer Rules */
721 #define UNSUPPORTED(_field) ({ \
722 enum mask_type typ = classify_mask((const u8 *)&mask->_field, \
723 sizeof(mask->_field)); \
725 if (typ != MASK_ZEROES) { \
726 NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\
731 #define UNSUPPORTED_BIT(_field) ({ \
732 if (mask->_field) { \
733 NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\
739 /* LHS rules are (normally) inserted in the Outer Rule table, which means
740 * they use ENC_ fields in hardware to match regular (not enc_) fields from
741 * &struct efx_tc_match_fields.
743 int efx_mae_match_check_caps_lhs(struct efx_nic
*efx
,
744 const struct efx_tc_match_fields
*mask
,
745 struct netlink_ext_ack
*extack
)
747 const u8
*supported_fields
= efx
->tc
->caps
->outer_rule_fields
;
748 __be32 ingress_port
= cpu_to_be32(mask
->ingress_port
);
749 enum mask_type ingress_port_mask_type
;
752 /* Check for _PREFIX assumes big-endian, so we need to convert */
753 ingress_port_mask_type
= classify_mask((const u8
*)&ingress_port
,
754 sizeof(ingress_port
));
755 rc
= efx_mae_match_check_cap_typ(supported_fields
[MAE_FIELD_INGRESS_PORT
],
756 ingress_port_mask_type
);
758 NL_SET_ERR_MSG_FMT_MOD(extack
, "No support for %s mask in field %s\n",
759 mask_type_name(ingress_port_mask_type
),
763 if (CHECK(ENC_ETHER_TYPE
, eth_proto
) ||
764 CHECK(ENC_VLAN0_TCI
, vlan_tci
[0]) ||
765 CHECK(ENC_VLAN0_PROTO
, vlan_proto
[0]) ||
766 CHECK(ENC_VLAN1_TCI
, vlan_tci
[1]) ||
767 CHECK(ENC_VLAN1_PROTO
, vlan_proto
[1]) ||
768 CHECK(ENC_ETH_SADDR
, eth_saddr
) ||
769 CHECK(ENC_ETH_DADDR
, eth_daddr
) ||
770 CHECK(ENC_IP_PROTO
, ip_proto
) ||
771 CHECK(ENC_IP_TOS
, ip_tos
) ||
772 CHECK(ENC_IP_TTL
, ip_ttl
) ||
773 CHECK_BIT(ENC_IP_FRAG
, ip_frag
) ||
774 UNSUPPORTED_BIT(ip_firstfrag
) ||
775 CHECK(ENC_SRC_IP4
, src_ip
) ||
776 CHECK(ENC_DST_IP4
, dst_ip
) ||
778 CHECK(ENC_SRC_IP6
, src_ip6
) ||
779 CHECK(ENC_DST_IP6
, dst_ip6
) ||
781 CHECK(ENC_L4_SPORT
, l4_sport
) ||
782 CHECK(ENC_L4_DPORT
, l4_dport
) ||
783 UNSUPPORTED(tcp_flags
) ||
784 CHECK_BIT(TCP_SYN_FIN_RST
, tcp_syn_fin_rst
))
786 if (efx_tc_match_is_encap(mask
)) {
787 /* can't happen; disallowed for local rules, translated
790 NL_SET_ERR_MSG_MOD(extack
, "Unexpected encap match in LHS rule");
793 if (UNSUPPORTED(enc_keyid
) ||
794 /* Can't filter on conntrack in LHS rules */
795 UNSUPPORTED_BIT(ct_state_trk
) ||
796 UNSUPPORTED_BIT(ct_state_est
) ||
797 UNSUPPORTED(ct_mark
) ||
798 UNSUPPORTED(recirc_id
))
806 #define CHECK(_mcdi) ({ \
807 rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
810 NL_SET_ERR_MSG_FMT_MOD(extack, \
811 "No support for field %s", #_mcdi); \
814 /* Checks that the fields needed for encap-rule matches are supported by the
815 * MAE. All the fields are exact-match, except possibly ENC_IP_TOS.
817 int efx_mae_check_encap_match_caps(struct efx_nic
*efx
, bool ipv6
,
818 u8 ip_tos_mask
, __be16 udp_sport_mask
,
819 struct netlink_ext_ack
*extack
)
821 u8
*supported_fields
= efx
->tc
->caps
->outer_rule_fields
;
825 if (CHECK(ENC_ETHER_TYPE
))
828 if (CHECK(ENC_SRC_IP6
) ||
832 if (CHECK(ENC_SRC_IP4
) ||
836 if (CHECK(ENC_L4_DPORT
) ||
839 typ
= classify_mask((const u8
*)&udp_sport_mask
, sizeof(udp_sport_mask
));
840 rc
= efx_mae_match_check_cap_typ(supported_fields
[MAE_FIELD_ENC_L4_SPORT
],
843 NL_SET_ERR_MSG_FMT_MOD(extack
, "No support for %s mask in field %s",
844 mask_type_name(typ
), "enc_src_port");
847 typ
= classify_mask(&ip_tos_mask
, sizeof(ip_tos_mask
));
848 rc
= efx_mae_match_check_cap_typ(supported_fields
[MAE_FIELD_ENC_IP_TOS
],
851 NL_SET_ERR_MSG_FMT_MOD(extack
, "No support for %s mask in field %s",
852 mask_type_name(typ
), "enc_ip_tos");
859 int efx_mae_check_encap_type_supported(struct efx_nic
*efx
, enum efx_encap_type typ
)
863 switch (typ
& EFX_ENCAP_TYPES_MASK
) {
864 case EFX_ENCAP_TYPE_VXLAN
:
865 bit
= MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN_LBN
;
867 case EFX_ENCAP_TYPE_GENEVE
:
868 bit
= MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE_LBN
;
873 if (efx
->tc
->caps
->encap_types
& BIT(bit
))
878 int efx_mae_allocate_counter(struct efx_nic
*efx
, struct efx_tc_counter
*cnt
)
880 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1));
881 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN
);
888 MCDI_SET_DWORD(inbuf
, MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT
, 1);
889 MCDI_SET_DWORD(inbuf
, MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE
, cnt
->type
);
890 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_COUNTER_ALLOC
, inbuf
, sizeof(inbuf
),
891 outbuf
, sizeof(outbuf
), &outlen
);
894 /* pcol says this can't happen, since count is 1 */
895 if (outlen
< sizeof(outbuf
))
897 cnt
->fw_id
= MCDI_DWORD(outbuf
, MAE_COUNTER_ALLOC_OUT_COUNTER_ID
);
898 cnt
->gen
= MCDI_DWORD(outbuf
, MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT
);
902 int efx_mae_free_counter(struct efx_nic
*efx
, struct efx_tc_counter
*cnt
)
904 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_COUNTER_FREE_OUT_LEN(1));
905 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN
);
909 MCDI_SET_DWORD(inbuf
, MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT
, 1);
910 MCDI_SET_DWORD(inbuf
, MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID
, cnt
->fw_id
);
911 MCDI_SET_DWORD(inbuf
, MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE
, cnt
->type
);
912 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_COUNTER_FREE
, inbuf
, sizeof(inbuf
),
913 outbuf
, sizeof(outbuf
), &outlen
);
916 /* pcol says this can't happen, since count is 1 */
917 if (outlen
< sizeof(outbuf
))
919 /* FW freed a different ID than we asked for, should also never happen.
920 * Warn because it means we've now got a different idea to the FW of
921 * what counters exist, which could cause mayhem later.
923 if (WARN_ON(MCDI_DWORD(outbuf
, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID
) !=
929 static int efx_mae_encap_type_to_mae_type(enum efx_encap_type type
)
931 switch (type
& EFX_ENCAP_TYPES_MASK
) {
932 case EFX_ENCAP_TYPE_NONE
:
933 return MAE_MCDI_ENCAP_TYPE_NONE
;
934 case EFX_ENCAP_TYPE_VXLAN
:
935 return MAE_MCDI_ENCAP_TYPE_VXLAN
;
936 case EFX_ENCAP_TYPE_GENEVE
:
937 return MAE_MCDI_ENCAP_TYPE_GENEVE
;
943 int efx_mae_allocate_encap_md(struct efx_nic
*efx
,
944 struct efx_tc_encap_action
*encap
)
946 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(EFX_TC_MAX_ENCAP_HDR
));
947 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN
);
948 size_t inlen
, outlen
;
951 rc
= efx_mae_encap_type_to_mae_type(encap
->type
);
954 MCDI_SET_DWORD(inbuf
, MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE
, rc
);
955 inlen
= MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(encap
->encap_hdr_len
);
956 if (WARN_ON(inlen
> sizeof(inbuf
))) /* can't happen */
958 memcpy(MCDI_PTR(inbuf
, MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA
),
960 encap
->encap_hdr_len
);
961 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ENCAP_HEADER_ALLOC
, inbuf
,
962 inlen
, outbuf
, sizeof(outbuf
), &outlen
);
965 if (outlen
< sizeof(outbuf
))
967 encap
->fw_id
= MCDI_DWORD(outbuf
, MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID
);
971 int efx_mae_update_encap_md(struct efx_nic
*efx
,
972 struct efx_tc_encap_action
*encap
)
974 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(EFX_TC_MAX_ENCAP_HDR
));
978 rc
= efx_mae_encap_type_to_mae_type(encap
->type
);
981 MCDI_SET_DWORD(inbuf
, MAE_ENCAP_HEADER_UPDATE_IN_ENCAP_TYPE
, rc
);
982 MCDI_SET_DWORD(inbuf
, MAE_ENCAP_HEADER_UPDATE_IN_EH_ID
,
984 inlen
= MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(encap
->encap_hdr_len
);
985 if (WARN_ON(inlen
> sizeof(inbuf
))) /* can't happen */
987 memcpy(MCDI_PTR(inbuf
, MAE_ENCAP_HEADER_UPDATE_IN_HDR_DATA
),
989 encap
->encap_hdr_len
);
991 BUILD_BUG_ON(MC_CMD_MAE_ENCAP_HEADER_UPDATE_OUT_LEN
!= 0);
992 return efx_mcdi_rpc(efx
, MC_CMD_MAE_ENCAP_HEADER_UPDATE
, inbuf
,
993 inlen
, NULL
, 0, NULL
);
996 int efx_mae_free_encap_md(struct efx_nic
*efx
,
997 struct efx_tc_encap_action
*encap
)
999 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
1000 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1));
1004 MCDI_SET_DWORD(inbuf
, MAE_ENCAP_HEADER_FREE_IN_EH_ID
, encap
->fw_id
);
1005 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ENCAP_HEADER_FREE
, inbuf
,
1006 sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
1009 if (outlen
< sizeof(outbuf
))
1011 /* FW freed a different ID than we asked for, should also never happen.
1012 * Warn because it means we've now got a different idea to the FW of
1013 * what encap_mds exist, which could cause mayhem later.
1015 if (WARN_ON(MCDI_DWORD(outbuf
, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID
) != encap
->fw_id
))
1017 /* We're probably about to free @encap, but let's just make sure its
1018 * fw_id is blatted so that it won't look valid if it leaks out.
1020 encap
->fw_id
= MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL
;
1024 int efx_mae_lookup_mport(struct efx_nic
*efx
, u32 vf_idx
, u32
*id
)
1026 struct ef100_nic_data
*nic_data
= efx
->nic_data
;
1027 struct efx_mae
*mae
= efx
->mae
;
1028 struct rhashtable_iter walk
;
1029 struct mae_mport_desc
*m
;
1032 rhashtable_walk_enter(&mae
->mports_ht
, &walk
);
1033 rhashtable_walk_start(&walk
);
1034 while ((m
= rhashtable_walk_next(&walk
)) != NULL
) {
1035 if (m
->mport_type
== MAE_MPORT_DESC_MPORT_TYPE_VNIC
&&
1036 m
->interface_idx
== nic_data
->local_mae_intf
&&
1038 m
->vf_idx
== vf_idx
) {
1044 rhashtable_walk_stop(&walk
);
1045 rhashtable_walk_exit(&walk
);
1049 static bool efx_mae_asl_id(u32 id
)
1051 return !!(id
& BIT(31));
1054 /* mport handling */
1055 static const struct rhashtable_params efx_mae_mports_ht_params
= {
1056 .key_len
= sizeof(u32
),
1057 .key_offset
= offsetof(struct mae_mport_desc
, mport_id
),
1058 .head_offset
= offsetof(struct mae_mport_desc
, linkage
),
1061 struct mae_mport_desc
*efx_mae_get_mport(struct efx_nic
*efx
, u32 mport_id
)
1063 return rhashtable_lookup_fast(&efx
->mae
->mports_ht
, &mport_id
,
1064 efx_mae_mports_ht_params
);
1067 static int efx_mae_add_mport(struct efx_nic
*efx
, struct mae_mport_desc
*desc
)
1069 struct efx_mae
*mae
= efx
->mae
;
1072 rc
= rhashtable_insert_fast(&mae
->mports_ht
, &desc
->linkage
,
1073 efx_mae_mports_ht_params
);
1076 pci_err(efx
->pci_dev
, "Failed to insert MPORT %08x, rc %d\n",
1077 desc
->mport_id
, rc
);
1085 void efx_mae_remove_mport(void *desc
, void *arg
)
1087 struct mae_mport_desc
*mport
= desc
;
1093 static int efx_mae_process_mport(struct efx_nic
*efx
,
1094 struct mae_mport_desc
*desc
)
1096 struct ef100_nic_data
*nic_data
= efx
->nic_data
;
1097 struct mae_mport_desc
*mport
;
1099 mport
= efx_mae_get_mport(efx
, desc
->mport_id
);
1100 if (!IS_ERR_OR_NULL(mport
)) {
1101 netif_err(efx
, drv
, efx
->net_dev
,
1102 "mport with id %u does exist!!!\n", desc
->mport_id
);
1106 if (nic_data
->have_own_mport
&&
1107 desc
->mport_id
== nic_data
->own_mport
) {
1108 WARN_ON(desc
->mport_type
!= MAE_MPORT_DESC_MPORT_TYPE_VNIC
);
1109 WARN_ON(desc
->vnic_client_type
!=
1110 MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION
);
1111 nic_data
->local_mae_intf
= desc
->interface_idx
;
1112 nic_data
->have_local_intf
= true;
1113 pci_dbg(efx
->pci_dev
, "MAE interface_idx is %u\n",
1114 nic_data
->local_mae_intf
);
1117 return efx_mae_add_mport(efx
, desc
);
1120 #define MCDI_MPORT_JOURNAL_LEN \
1121 ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4)
1123 int efx_mae_enumerate_mports(struct efx_nic
*efx
)
1125 efx_dword_t
*outbuf
= kzalloc(MCDI_MPORT_JOURNAL_LEN
, GFP_KERNEL
);
1126 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN
);
1127 MCDI_DECLARE_STRUCT_PTR(desc
);
1128 size_t outlen
, stride
, count
;
1134 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_MPORT_READ_JOURNAL
, inbuf
,
1135 sizeof(inbuf
), outbuf
,
1136 MCDI_MPORT_JOURNAL_LEN
, &outlen
);
1139 if (outlen
< MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST
) {
1143 count
= MCDI_DWORD(outbuf
, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT
);
1145 continue; /* not break; we want to look at MORE flag */
1146 stride
= MCDI_DWORD(outbuf
, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC
);
1147 if (stride
< MAE_MPORT_DESC_LEN
) {
1151 if (outlen
< MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count
* stride
)) {
1156 for (i
= 0; i
< count
; i
++) {
1157 struct mae_mport_desc
*d
;
1159 d
= kzalloc(sizeof(*d
), GFP_KERNEL
);
1165 desc
= (efx_dword_t
*)
1166 _MCDI_PTR(outbuf
, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST
+
1168 d
->mport_id
= MCDI_STRUCT_DWORD(desc
, MAE_MPORT_DESC_MPORT_ID
);
1169 d
->flags
= MCDI_STRUCT_DWORD(desc
, MAE_MPORT_DESC_FLAGS
);
1170 d
->caller_flags
= MCDI_STRUCT_DWORD(desc
,
1171 MAE_MPORT_DESC_CALLER_FLAGS
);
1172 d
->mport_type
= MCDI_STRUCT_DWORD(desc
,
1173 MAE_MPORT_DESC_MPORT_TYPE
);
1174 switch (d
->mport_type
) {
1175 case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT
:
1176 d
->port_idx
= MCDI_STRUCT_DWORD(desc
,
1177 MAE_MPORT_DESC_NET_PORT_IDX
);
1179 case MAE_MPORT_DESC_MPORT_TYPE_ALIAS
:
1180 d
->alias_mport_id
= MCDI_STRUCT_DWORD(desc
,
1181 MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID
);
1183 case MAE_MPORT_DESC_MPORT_TYPE_VNIC
:
1184 d
->vnic_client_type
= MCDI_STRUCT_DWORD(desc
,
1185 MAE_MPORT_DESC_VNIC_CLIENT_TYPE
);
1186 d
->interface_idx
= MCDI_STRUCT_DWORD(desc
,
1187 MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE
);
1188 d
->pf_idx
= MCDI_STRUCT_WORD(desc
,
1189 MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX
);
1190 d
->vf_idx
= MCDI_STRUCT_WORD(desc
,
1191 MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX
);
1194 /* Unknown mport_type, just accept it */
1197 rc
= efx_mae_process_mport(efx
, d
);
1198 /* Any failure will be due to memory allocation faiure,
1199 * so there is no point to try subsequent entries.
1204 } while (MCDI_FIELD(outbuf
, MAE_MPORT_READ_JOURNAL_OUT
, MORE
) &&
1212 * efx_mae_allocate_pedit_mac() - allocate pedit MAC address in HW.
1213 * @efx: NIC we're installing a pedit MAC address on
1214 * @ped: pedit MAC action to be installed
1216 * Attempts to install @ped in HW and populates its id with an index of this
1217 * entry in the firmware MAC address table on success.
1219 * Return: negative value on error, 0 in success.
1221 int efx_mae_allocate_pedit_mac(struct efx_nic
*efx
,
1222 struct efx_tc_mac_pedit_action
*ped
)
1224 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN
);
1225 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN
);
1229 BUILD_BUG_ON(MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_LEN
!=
1230 sizeof(ped
->h_addr
));
1231 memcpy(MCDI_PTR(inbuf
, MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR
), ped
->h_addr
,
1232 sizeof(ped
->h_addr
));
1233 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_MAC_ADDR_ALLOC
, inbuf
, sizeof(inbuf
),
1234 outbuf
, sizeof(outbuf
), &outlen
);
1237 if (outlen
< sizeof(outbuf
))
1239 ped
->fw_id
= MCDI_DWORD(outbuf
, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID
);
1244 * efx_mae_free_pedit_mac() - free pedit MAC address in HW.
1245 * @efx: NIC we're installing a pedit MAC address on
1246 * @ped: pedit MAC action that needs to be freed
1248 * Frees @ped in HW, check that firmware did not free a different one and clears
1249 * the id (which denotes the index of the entry in the MAC address table).
1251 void efx_mae_free_pedit_mac(struct efx_nic
*efx
,
1252 struct efx_tc_mac_pedit_action
*ped
)
1254 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1));
1255 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1));
1259 MCDI_SET_DWORD(inbuf
, MAE_MAC_ADDR_FREE_IN_MAC_ID
, ped
->fw_id
);
1260 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_MAC_ADDR_FREE
, inbuf
,
1261 sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
1262 if (rc
|| outlen
< sizeof(outbuf
))
1264 /* FW freed a different ID than we asked for, should also never happen.
1265 * Warn because it means we've now got a different idea to the FW of
1266 * what MAC addresses exist, which could cause mayhem later.
1268 if (WARN_ON(MCDI_DWORD(outbuf
, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID
) != ped
->fw_id
))
1270 /* We're probably about to free @ped, but let's just make sure its
1271 * fw_id is blatted so that it won't look valid if it leaks out.
1273 ped
->fw_id
= MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL
;
1276 int efx_mae_alloc_action_set(struct efx_nic
*efx
, struct efx_tc_action_set
*act
)
1278 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN
);
1279 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN
);
1283 MCDI_POPULATE_DWORD_5(inbuf
, MAE_ACTION_SET_ALLOC_IN_FLAGS
,
1284 MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH
, act
->vlan_push
,
1285 MAE_ACTION_SET_ALLOC_IN_VLAN_POP
, act
->vlan_pop
,
1286 MAE_ACTION_SET_ALLOC_IN_DECAP
, act
->decap
,
1287 MAE_ACTION_SET_ALLOC_IN_DO_NAT
, act
->do_nat
,
1288 MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL
,
1292 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID
,
1293 act
->src_mac
->fw_id
);
1295 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID
,
1296 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL
);
1299 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID
,
1300 act
->dst_mac
->fw_id
);
1302 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID
,
1303 MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL
);
1305 if (act
->count
&& !WARN_ON(!act
->count
->cnt
))
1306 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID
,
1307 act
->count
->cnt
->fw_id
);
1309 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID
,
1310 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL
);
1311 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID
,
1312 MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL
);
1313 if (act
->vlan_push
) {
1314 MCDI_SET_WORD_BE(inbuf
, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE
,
1316 MCDI_SET_WORD_BE(inbuf
, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE
,
1317 act
->vlan_proto
[0]);
1319 if (act
->vlan_push
>= 2) {
1320 MCDI_SET_WORD_BE(inbuf
, MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE
,
1322 MCDI_SET_WORD_BE(inbuf
, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE
,
1323 act
->vlan_proto
[1]);
1326 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID
,
1327 act
->encap_md
->fw_id
);
1329 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID
,
1330 MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL
);
1332 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_ALLOC_IN_DELIVER
,
1334 BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL
);
1335 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ACTION_SET_ALLOC
, inbuf
, sizeof(inbuf
),
1336 outbuf
, sizeof(outbuf
), &outlen
);
1339 if (outlen
< sizeof(outbuf
))
1341 act
->fw_id
= MCDI_DWORD(outbuf
, MAE_ACTION_SET_ALLOC_OUT_AS_ID
);
1342 /* We rely on the high bit of AS IDs always being clear.
1343 * The firmware API guarantees this, but let's check it ourselves.
1345 if (WARN_ON_ONCE(efx_mae_asl_id(act
->fw_id
))) {
1346 efx_mae_free_action_set(efx
, act
->fw_id
);
1352 int efx_mae_free_action_set(struct efx_nic
*efx
, u32 fw_id
)
1354 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1355 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1));
1359 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_FREE_IN_AS_ID
, fw_id
);
1360 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ACTION_SET_FREE
, inbuf
, sizeof(inbuf
),
1361 outbuf
, sizeof(outbuf
), &outlen
);
1364 if (outlen
< sizeof(outbuf
))
1366 /* FW freed a different ID than we asked for, should never happen.
1367 * Warn because it means we've now got a different idea to the FW of
1368 * what action-sets exist, which could cause mayhem later.
1370 if (WARN_ON(MCDI_DWORD(outbuf
, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID
) != fw_id
))
1375 int efx_mae_alloc_action_set_list(struct efx_nic
*efx
,
1376 struct efx_tc_action_set_list
*acts
)
1378 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN
);
1379 struct efx_tc_action_set
*act
;
1380 size_t inlen
, outlen
, i
= 0;
1384 list_for_each_entry(act
, &acts
->list
, list
)
1389 /* Don't wrap an ASL around a single AS, just use the AS_ID
1390 * directly. ASLs are a more limited resource.
1392 act
= list_first_entry(&acts
->list
, struct efx_tc_action_set
, list
);
1393 acts
->fw_id
= act
->fw_id
;
1396 if (i
> MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2
)
1397 return -EOPNOTSUPP
; /* Too many actions */
1398 inlen
= MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i
);
1399 inbuf
= kzalloc(inlen
, GFP_KERNEL
);
1403 list_for_each_entry(act
, &acts
->list
, list
) {
1404 MCDI_SET_ARRAY_DWORD(inbuf
, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS
,
1408 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT
, i
);
1409 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ACTION_SET_LIST_ALLOC
, inbuf
, inlen
,
1410 outbuf
, sizeof(outbuf
), &outlen
);
1413 if (outlen
< sizeof(outbuf
)) {
1417 acts
->fw_id
= MCDI_DWORD(outbuf
, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID
);
1418 /* We rely on the high bit of ASL IDs always being set.
1419 * The firmware API guarantees this, but let's check it ourselves.
1421 if (WARN_ON_ONCE(!efx_mae_asl_id(acts
->fw_id
))) {
1422 efx_mae_free_action_set_list(efx
, acts
);
1430 int efx_mae_free_action_set_list(struct efx_nic
*efx
,
1431 struct efx_tc_action_set_list
*acts
)
1433 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1));
1434 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1));
1438 /* If this is just an AS_ID with no ASL wrapper, then there is
1439 * nothing for us to free. (The AS will be freed later.)
1441 if (efx_mae_asl_id(acts
->fw_id
)) {
1442 MCDI_SET_DWORD(inbuf
, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID
,
1444 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ACTION_SET_LIST_FREE
, inbuf
,
1445 sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
1448 if (outlen
< sizeof(outbuf
))
1450 /* FW freed a different ID than we asked for, should never happen.
1451 * Warn because it means we've now got a different idea to the FW of
1452 * what action-set-lists exist, which could cause mayhem later.
1454 if (WARN_ON(MCDI_DWORD(outbuf
, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID
) != acts
->fw_id
))
1457 /* We're probably about to free @acts, but let's just make sure its
1458 * fw_id is blatted so that it won't look valid if it leaks out.
1460 acts
->fw_id
= MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL
;
1464 int efx_mae_register_encap_match(struct efx_nic
*efx
,
1465 struct efx_tc_encap_match
*encap
)
1467 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN
));
1468 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN
);
1469 MCDI_DECLARE_STRUCT_PTR(match_crit
);
1473 rc
= efx_mae_encap_type_to_mae_type(encap
->tun_type
);
1476 match_crit
= _MCDI_DWORD(inbuf
, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA
);
1477 /* The struct contains IP src and dst, and udp dport.
1478 * So we actually need to filter on IP src and dst, L4 dport, and
1481 MCDI_SET_DWORD(inbuf
, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE
, rc
);
1483 if (encap
->src_ip
| encap
->dst_ip
) {
1485 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE
,
1487 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK
,
1489 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE
,
1491 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK
,
1493 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE
,
1497 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE
),
1498 &encap
->src_ip6
, sizeof(encap
->src_ip6
));
1499 memset(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK
),
1500 0xff, sizeof(encap
->src_ip6
));
1501 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE
),
1502 &encap
->dst_ip6
, sizeof(encap
->dst_ip6
));
1503 memset(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK
),
1504 0xff, sizeof(encap
->dst_ip6
));
1505 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE
,
1509 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK
,
1511 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE
,
1513 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK
,
1515 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE
,
1517 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK
,
1518 encap
->udp_sport_mask
);
1519 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO
, IPPROTO_UDP
);
1520 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK
, ~0);
1521 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS
,
1523 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK
,
1524 encap
->ip_tos_mask
);
1525 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_OUTER_RULE_INSERT
, inbuf
,
1526 sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
1529 if (outlen
< sizeof(outbuf
))
1531 encap
->fw_id
= MCDI_DWORD(outbuf
, MAE_OUTER_RULE_INSERT_OUT_OR_ID
);
1535 int efx_mae_unregister_encap_match(struct efx_nic
*efx
,
1536 struct efx_tc_encap_match
*encap
)
1538 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1539 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1));
1543 MCDI_SET_DWORD(inbuf
, MAE_OUTER_RULE_REMOVE_IN_OR_ID
, encap
->fw_id
);
1544 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_OUTER_RULE_REMOVE
, inbuf
,
1545 sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
1548 if (outlen
< sizeof(outbuf
))
1550 /* FW freed a different ID than we asked for, should also never happen.
1551 * Warn because it means we've now got a different idea to the FW of
1552 * what encap_mds exist, which could cause mayhem later.
1554 if (WARN_ON(MCDI_DWORD(outbuf
, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID
) != encap
->fw_id
))
1556 /* We're probably about to free @encap, but let's just make sure its
1557 * fw_id is blatted so that it won't look valid if it leaks out.
1559 encap
->fw_id
= MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL
;
1563 static int efx_mae_populate_lhs_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit
),
1564 const struct efx_tc_match
*match
)
1566 if (match
->mask
.ingress_port
) {
1567 if (~match
->mask
.ingress_port
)
1569 MCDI_STRUCT_SET_DWORD(match_crit
,
1570 MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR
,
1571 match
->value
.ingress_port
);
1573 MCDI_STRUCT_SET_DWORD(match_crit
, MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR_MASK
,
1574 match
->mask
.ingress_port
);
1575 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE
,
1576 match
->value
.eth_proto
);
1577 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK
,
1578 match
->mask
.eth_proto
);
1579 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE
,
1580 match
->value
.vlan_tci
[0]);
1581 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE_MASK
,
1582 match
->mask
.vlan_tci
[0]);
1583 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE
,
1584 match
->value
.vlan_proto
[0]);
1585 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE_MASK
,
1586 match
->mask
.vlan_proto
[0]);
1587 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE
,
1588 match
->value
.vlan_tci
[1]);
1589 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE_MASK
,
1590 match
->mask
.vlan_tci
[1]);
1591 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE
,
1592 match
->value
.vlan_proto
[1]);
1593 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE_MASK
,
1594 match
->mask
.vlan_proto
[1]);
1595 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE
),
1596 match
->value
.eth_saddr
, ETH_ALEN
);
1597 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE_MASK
),
1598 match
->mask
.eth_saddr
, ETH_ALEN
);
1599 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE
),
1600 match
->value
.eth_daddr
, ETH_ALEN
);
1601 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE_MASK
),
1602 match
->mask
.eth_daddr
, ETH_ALEN
);
1603 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO
,
1604 match
->value
.ip_proto
);
1605 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK
,
1606 match
->mask
.ip_proto
);
1607 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS
,
1608 match
->value
.ip_tos
);
1609 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK
,
1610 match
->mask
.ip_tos
);
1611 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL
,
1612 match
->value
.ip_ttl
);
1613 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL_MASK
,
1614 match
->mask
.ip_ttl
);
1615 MCDI_STRUCT_POPULATE_BYTE_1(match_crit
,
1616 MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS
,
1617 MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG
,
1618 match
->value
.ip_frag
);
1619 MCDI_STRUCT_POPULATE_BYTE_1(match_crit
,
1620 MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS_MASK
,
1621 MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG_MASK
,
1622 match
->mask
.ip_frag
);
1623 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE
,
1624 match
->value
.src_ip
);
1625 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK
,
1626 match
->mask
.src_ip
);
1627 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE
,
1628 match
->value
.dst_ip
);
1629 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK
,
1630 match
->mask
.dst_ip
);
1632 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE
),
1633 &match
->value
.src_ip6
, sizeof(struct in6_addr
));
1634 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK
),
1635 &match
->mask
.src_ip6
, sizeof(struct in6_addr
));
1636 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE
),
1637 &match
->value
.dst_ip6
, sizeof(struct in6_addr
));
1638 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK
),
1639 &match
->mask
.dst_ip6
, sizeof(struct in6_addr
));
1641 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE
,
1642 match
->value
.l4_sport
);
1643 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE_MASK
,
1644 match
->mask
.l4_sport
);
1645 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE
,
1646 match
->value
.l4_dport
);
1647 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK
,
1648 match
->mask
.l4_dport
);
1649 /* No enc-keys in LHS rules. Caps check should have caught this; any
1650 * enc-keys from an fLHS should have been translated to regular keys
1651 * and any EM should be a pseudo (we're an OR so can't have a direct
1652 * EM with another OR).
1654 if (WARN_ON_ONCE(match
->encap
&& !match
->encap
->type
))
1656 if (WARN_ON_ONCE(match
->mask
.enc_src_ip
))
1658 if (WARN_ON_ONCE(match
->mask
.enc_dst_ip
))
1661 if (WARN_ON_ONCE(!ipv6_addr_any(&match
->mask
.enc_src_ip6
)))
1663 if (WARN_ON_ONCE(!ipv6_addr_any(&match
->mask
.enc_dst_ip6
)))
1666 if (WARN_ON_ONCE(match
->mask
.enc_ip_tos
))
1668 if (WARN_ON_ONCE(match
->mask
.enc_ip_ttl
))
1670 if (WARN_ON_ONCE(match
->mask
.enc_sport
))
1672 if (WARN_ON_ONCE(match
->mask
.enc_dport
))
1674 if (WARN_ON_ONCE(match
->mask
.enc_keyid
))
1679 static int efx_mae_insert_lhs_outer_rule(struct efx_nic
*efx
,
1680 struct efx_tc_lhs_rule
*rule
, u32 prio
)
1682 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN
));
1683 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN
);
1684 MCDI_DECLARE_STRUCT_PTR(match_crit
);
1685 const struct efx_tc_lhs_action
*act
;
1689 MCDI_SET_DWORD(inbuf
, MAE_OUTER_RULE_INSERT_IN_PRIO
, prio
);
1691 match_crit
= _MCDI_DWORD(inbuf
, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA
);
1692 rc
= efx_mae_populate_lhs_match_criteria(match_crit
, &rule
->match
);
1697 act
= &rule
->lhs_act
;
1698 rc
= efx_mae_encap_type_to_mae_type(act
->tun_type
);
1701 MCDI_SET_DWORD(inbuf
, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE
, rc
);
1702 /* We always inhibit CT lookup on TCP_INTERESTING_FLAGS, since the
1703 * SW path needs to process the packet to update the conntrack tables
1704 * on connection establishment (SYN) or termination (FIN, RST).
1706 MCDI_POPULATE_DWORD_6(inbuf
, MAE_OUTER_RULE_INSERT_IN_LOOKUP_CONTROL
,
1707 MAE_OUTER_RULE_INSERT_IN_DO_CT
, !!act
->zone
,
1708 MAE_OUTER_RULE_INSERT_IN_CT_TCP_FLAGS_INHIBIT
, 1,
1709 MAE_OUTER_RULE_INSERT_IN_CT_DOMAIN
,
1710 act
->zone
? act
->zone
->zone
: 0,
1711 MAE_OUTER_RULE_INSERT_IN_CT_VNI_MODE
,
1712 MAE_CT_VNI_MODE_ZERO
,
1713 MAE_OUTER_RULE_INSERT_IN_DO_COUNT
, !!act
->count
,
1714 MAE_OUTER_RULE_INSERT_IN_RECIRC_ID
,
1715 act
->rid
? act
->rid
->fw_id
: 0);
1717 MCDI_SET_DWORD(inbuf
, MAE_OUTER_RULE_INSERT_IN_COUNTER_ID
,
1718 act
->count
->cnt
->fw_id
);
1719 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_OUTER_RULE_INSERT
, inbuf
,
1720 sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
1723 if (outlen
< sizeof(outbuf
))
1725 rule
->fw_id
= MCDI_DWORD(outbuf
, MAE_OUTER_RULE_INSERT_OUT_OR_ID
);
1729 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit
),
1730 const struct efx_tc_match
*match
);
1732 static int efx_mae_insert_lhs_action_rule(struct efx_nic
*efx
,
1733 struct efx_tc_lhs_rule
*rule
,
1736 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN
));
1737 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN
);
1738 struct efx_tc_lhs_action
*act
= &rule
->lhs_act
;
1739 MCDI_DECLARE_STRUCT_PTR(match_crit
);
1740 MCDI_DECLARE_STRUCT_PTR(response
);
1744 match_crit
= _MCDI_DWORD(inbuf
, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA
);
1745 response
= _MCDI_DWORD(inbuf
, MAE_ACTION_RULE_INSERT_IN_RESPONSE
);
1746 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_ASL_ID
,
1747 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL
);
1748 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_AS_ID
,
1749 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL
);
1750 EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(response
, MAE_ACTION_RULE_RESPONSE_LOOKUP_CONTROL
),
1751 MAE_ACTION_RULE_RESPONSE_DO_CT
, !!act
->zone
,
1752 MAE_ACTION_RULE_RESPONSE_DO_RECIRC
,
1753 act
->rid
&& !act
->zone
,
1754 MAE_ACTION_RULE_RESPONSE_CT_VNI_MODE
,
1755 MAE_CT_VNI_MODE_ZERO
,
1756 MAE_ACTION_RULE_RESPONSE_RECIRC_ID
,
1757 act
->rid
? act
->rid
->fw_id
: 0,
1758 MAE_ACTION_RULE_RESPONSE_CT_DOMAIN
,
1759 act
->zone
? act
->zone
->zone
: 0);
1760 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_COUNTER_ID
,
1761 act
->count
? act
->count
->cnt
->fw_id
:
1762 MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL
);
1763 MCDI_SET_DWORD(inbuf
, MAE_ACTION_RULE_INSERT_IN_PRIO
, prio
);
1764 rc
= efx_mae_populate_match_criteria(match_crit
, &rule
->match
);
1768 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ACTION_RULE_INSERT
, inbuf
, sizeof(inbuf
),
1769 outbuf
, sizeof(outbuf
), &outlen
);
1772 if (outlen
< sizeof(outbuf
))
1774 rule
->fw_id
= MCDI_DWORD(outbuf
, MAE_ACTION_RULE_INSERT_OUT_AR_ID
);
1778 int efx_mae_insert_lhs_rule(struct efx_nic
*efx
, struct efx_tc_lhs_rule
*rule
,
1782 return efx_mae_insert_lhs_action_rule(efx
, rule
, prio
);
1783 return efx_mae_insert_lhs_outer_rule(efx
, rule
, prio
);
1786 static int efx_mae_remove_lhs_outer_rule(struct efx_nic
*efx
,
1787 struct efx_tc_lhs_rule
*rule
)
1789 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1790 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1));
1794 MCDI_SET_DWORD(inbuf
, MAE_OUTER_RULE_REMOVE_IN_OR_ID
, rule
->fw_id
);
1795 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_OUTER_RULE_REMOVE
, inbuf
,
1796 sizeof(inbuf
), outbuf
, sizeof(outbuf
), &outlen
);
1799 if (outlen
< sizeof(outbuf
))
1801 /* FW freed a different ID than we asked for, should also never happen.
1802 * Warn because it means we've now got a different idea to the FW of
1803 * what encap_mds exist, which could cause mayhem later.
1805 if (WARN_ON(MCDI_DWORD(outbuf
, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID
) != rule
->fw_id
))
1807 /* We're probably about to free @rule, but let's just make sure its
1808 * fw_id is blatted so that it won't look valid if it leaks out.
1810 rule
->fw_id
= MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL
;
1814 int efx_mae_remove_lhs_rule(struct efx_nic
*efx
, struct efx_tc_lhs_rule
*rule
)
1817 return efx_mae_delete_rule(efx
, rule
->fw_id
);
1818 return efx_mae_remove_lhs_outer_rule(efx
, rule
);
1821 /* Populating is done by taking each byte of @value in turn and storing
1822 * it in the appropriate bits of @row. @value must be big-endian; we
1823 * convert it to little-endianness as we go.
1825 static int efx_mae_table_populate(struct efx_tc_table_field_fmt field
,
1826 __le32
*row
, size_t row_bits
,
1827 void *value
, size_t value_size
)
1831 /* For now only scheme 0 is supported for any field, so we check here
1832 * (rather than, say, in calling code, which knows the semantics and
1833 * could in principle encode for other schemes).
1837 if (DIV_ROUND_UP(field
.width
, 8) != value_size
)
1839 if (field
.lbn
+ field
.width
> row_bits
)
1841 for (i
= 0; i
< value_size
; i
++) {
1842 unsigned int bn
= field
.lbn
+ i
* 8;
1843 unsigned int wn
= bn
/ 32;
1846 v
= ((u8
*)value
)[value_size
- i
- 1];
1848 row
[wn
] |= cpu_to_le32(v
& 0xffffffff);
1849 if (wn
* 32 < row_bits
)
1850 row
[wn
+ 1] |= cpu_to_le32(v
>> 32);
1855 static int efx_mae_table_populate_bool(struct efx_tc_table_field_fmt field
,
1856 __le32
*row
, size_t row_bits
, bool value
)
1858 u8 v
= value
? 1 : 0;
1860 if (field
.width
!= 1)
1862 return efx_mae_table_populate(field
, row
, row_bits
, &v
, 1);
1865 static int efx_mae_table_populate_ipv4(struct efx_tc_table_field_fmt field
,
1866 __le32
*row
, size_t row_bits
, __be32 value
)
1868 /* IPv4 is placed in the first 4 bytes of an IPv6-sized field */
1869 struct in6_addr v
= {};
1871 if (field
.width
!= 128)
1873 v
.s6_addr32
[0] = value
;
1874 return efx_mae_table_populate(field
, row
, row_bits
, &v
, sizeof(v
));
1877 static int efx_mae_table_populate_u24(struct efx_tc_table_field_fmt field
,
1878 __le32
*row
, size_t row_bits
, u32 value
)
1880 __be32 v
= cpu_to_be32(value
);
1882 /* We adjust value_size here since just 3 bytes will be copied, and
1883 * the pointer to the value is set discarding the first byte which is
1884 * the most significant byte for a big-endian 4-bytes value.
1886 return efx_mae_table_populate(field
, row
, row_bits
, ((void *)&v
) + 1,
1890 #define _TABLE_POPULATE(dst, dw, _field, _value) ({ \
1891 typeof(_value) _v = _value; \
1893 (_field.width == sizeof(_value) * 8) ? \
1894 efx_mae_table_populate(_field, dst, dw, &_v, \
1895 sizeof(_v)) : -EINVAL; \
1897 #define TABLE_POPULATE_KEY_IPV4(dst, _table, _field, _value) \
1898 efx_mae_table_populate_ipv4(efx->tc->meta_##_table.desc.keys \
1899 [efx->tc->meta_##_table.keys._field##_idx],\
1900 dst, efx->tc->meta_##_table.desc.key_width,\
1902 #define TABLE_POPULATE_KEY(dst, _table, _field, _value) \
1903 _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.key_width, \
1904 efx->tc->meta_##_table.desc.keys \
1905 [efx->tc->meta_##_table.keys._field##_idx], \
1908 #define TABLE_POPULATE_RESP_BOOL(dst, _table, _field, _value) \
1909 efx_mae_table_populate_bool(efx->tc->meta_##_table.desc.resps \
1910 [efx->tc->meta_##_table.resps._field##_idx],\
1911 dst, efx->tc->meta_##_table.desc.resp_width,\
1913 #define TABLE_POPULATE_RESP(dst, _table, _field, _value) \
1914 _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.resp_width, \
1915 efx->tc->meta_##_table.desc.resps \
1916 [efx->tc->meta_##_table.resps._field##_idx], \
1919 #define TABLE_POPULATE_RESP_U24(dst, _table, _field, _value) \
1920 efx_mae_table_populate_u24(efx->tc->meta_##_table.desc.resps \
1921 [efx->tc->meta_##_table.resps._field##_idx],\
1922 dst, efx->tc->meta_##_table.desc.resp_width,\
1925 static int efx_mae_populate_ct_key(struct efx_nic
*efx
, __le32
*key
, size_t kw
,
1926 struct efx_tc_ct_entry
*conn
)
1928 bool ipv6
= conn
->eth_proto
== htons(ETH_P_IPV6
);
1931 rc
= TABLE_POPULATE_KEY(key
, ct
, eth_proto
, conn
->eth_proto
);
1934 rc
= TABLE_POPULATE_KEY(key
, ct
, ip_proto
, conn
->ip_proto
);
1938 rc
= TABLE_POPULATE_KEY(key
, ct
, src_ip
, conn
->src_ip6
);
1940 rc
= TABLE_POPULATE_KEY_IPV4(key
, ct
, src_ip
, conn
->src_ip
);
1944 rc
= TABLE_POPULATE_KEY(key
, ct
, dst_ip
, conn
->dst_ip6
);
1946 rc
= TABLE_POPULATE_KEY_IPV4(key
, ct
, dst_ip
, conn
->dst_ip
);
1949 rc
= TABLE_POPULATE_KEY(key
, ct
, l4_sport
, conn
->l4_sport
);
1952 rc
= TABLE_POPULATE_KEY(key
, ct
, l4_dport
, conn
->l4_dport
);
1955 return TABLE_POPULATE_KEY(key
, ct
, zone
, cpu_to_be16(conn
->zone
->zone
));
1958 int efx_mae_insert_ct(struct efx_nic
*efx
, struct efx_tc_ct_entry
*conn
)
1960 bool ipv6
= conn
->eth_proto
== htons(ETH_P_IPV6
);
1961 __le32
*key
= NULL
, *resp
= NULL
;
1962 size_t inlen
, kw
, rw
;
1966 /* Check table access is supported */
1967 if (!efx
->tc
->meta_ct
.hooked
)
1970 /* key/resp widths are in bits; convert to dwords for IN_LEN */
1971 kw
= DIV_ROUND_UP(efx
->tc
->meta_ct
.desc
.key_width
, 32);
1972 rw
= DIV_ROUND_UP(efx
->tc
->meta_ct
.desc
.resp_width
, 32);
1973 BUILD_BUG_ON(sizeof(__le32
) != MC_CMD_TABLE_INSERT_IN_DATA_LEN
);
1974 inlen
= MC_CMD_TABLE_INSERT_IN_LEN(kw
+ rw
);
1975 if (inlen
> MC_CMD_TABLE_INSERT_IN_LENMAX_MCDI2
)
1977 inbuf
= kzalloc(inlen
, GFP_KERNEL
);
1981 key
= kcalloc(kw
, sizeof(__le32
), GFP_KERNEL
);
1984 resp
= kcalloc(rw
, sizeof(__le32
), GFP_KERNEL
);
1988 rc
= efx_mae_populate_ct_key(efx
, key
, kw
, conn
);
1992 rc
= TABLE_POPULATE_RESP_BOOL(resp
, ct
, dnat
, conn
->dnat
);
1995 /* No support in hw for IPv6 NAT; field is only 32 bits */
1997 rc
= TABLE_POPULATE_RESP(resp
, ct
, nat_ip
, conn
->nat_ip
);
2000 rc
= TABLE_POPULATE_RESP(resp
, ct
, l4_natport
, conn
->l4_natport
);
2003 rc
= TABLE_POPULATE_RESP(resp
, ct
, mark
, cpu_to_be32(conn
->mark
));
2006 rc
= TABLE_POPULATE_RESP_U24(resp
, ct
, counter_id
, conn
->cnt
->fw_id
);
2010 MCDI_SET_DWORD(inbuf
, TABLE_INSERT_IN_TABLE_ID
, TABLE_ID_CONNTRACK_TABLE
);
2011 MCDI_SET_WORD(inbuf
, TABLE_INSERT_IN_KEY_WIDTH
,
2012 efx
->tc
->meta_ct
.desc
.key_width
);
2013 /* MASK_WIDTH is zero as CT is a BCAM */
2014 MCDI_SET_WORD(inbuf
, TABLE_INSERT_IN_RESP_WIDTH
,
2015 efx
->tc
->meta_ct
.desc
.resp_width
);
2016 memcpy(MCDI_PTR(inbuf
, TABLE_INSERT_IN_DATA
), key
, kw
* sizeof(__le32
));
2017 memcpy(MCDI_PTR(inbuf
, TABLE_INSERT_IN_DATA
) + kw
* sizeof(__le32
),
2018 resp
, rw
* sizeof(__le32
));
2020 BUILD_BUG_ON(MC_CMD_TABLE_INSERT_OUT_LEN
);
2022 rc
= efx_mcdi_rpc(efx
, MC_CMD_TABLE_INSERT
, inbuf
, inlen
, NULL
, 0, NULL
);
2031 int efx_mae_remove_ct(struct efx_nic
*efx
, struct efx_tc_ct_entry
*conn
)
2038 /* Check table access is supported */
2039 if (!efx
->tc
->meta_ct
.hooked
)
2042 /* key width is in bits; convert to dwords for IN_LEN */
2043 kw
= DIV_ROUND_UP(efx
->tc
->meta_ct
.desc
.key_width
, 32);
2044 BUILD_BUG_ON(sizeof(__le32
) != MC_CMD_TABLE_DELETE_IN_DATA_LEN
);
2045 inlen
= MC_CMD_TABLE_DELETE_IN_LEN(kw
);
2046 if (inlen
> MC_CMD_TABLE_DELETE_IN_LENMAX_MCDI2
)
2048 inbuf
= kzalloc(inlen
, GFP_KERNEL
);
2052 key
= kcalloc(kw
, sizeof(__le32
), GFP_KERNEL
);
2056 rc
= efx_mae_populate_ct_key(efx
, key
, kw
, conn
);
2060 MCDI_SET_DWORD(inbuf
, TABLE_DELETE_IN_TABLE_ID
, TABLE_ID_CONNTRACK_TABLE
);
2061 MCDI_SET_WORD(inbuf
, TABLE_DELETE_IN_KEY_WIDTH
,
2062 efx
->tc
->meta_ct
.desc
.key_width
);
2063 /* MASK_WIDTH is zero as CT is a BCAM */
2064 /* RESP_WIDTH is zero for DELETE */
2065 memcpy(MCDI_PTR(inbuf
, TABLE_DELETE_IN_DATA
), key
, kw
* sizeof(__le32
));
2067 BUILD_BUG_ON(MC_CMD_TABLE_DELETE_OUT_LEN
);
2069 rc
= efx_mcdi_rpc(efx
, MC_CMD_TABLE_DELETE
, inbuf
, inlen
, NULL
, 0, NULL
);
2077 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit
),
2078 const struct efx_tc_match
*match
)
2080 if (match
->mask
.ingress_port
) {
2081 if (~match
->mask
.ingress_port
)
2083 MCDI_STRUCT_SET_DWORD(match_crit
,
2084 MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR
,
2085 match
->value
.ingress_port
);
2087 MCDI_STRUCT_SET_DWORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK
,
2088 match
->mask
.ingress_port
);
2089 EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS
),
2090 MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT
,
2091 match
->value
.ct_state_trk
,
2092 MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT
,
2093 match
->value
.ct_state_est
,
2094 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG
,
2095 match
->value
.ip_frag
,
2096 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG
,
2097 match
->value
.ip_firstfrag
,
2098 MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST
,
2099 match
->value
.tcp_syn_fin_rst
);
2100 EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK
),
2101 MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT
,
2102 match
->mask
.ct_state_trk
,
2103 MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT
,
2104 match
->mask
.ct_state_est
,
2105 MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG
,
2106 match
->mask
.ip_frag
,
2107 MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG
,
2108 match
->mask
.ip_firstfrag
,
2109 MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST
,
2110 match
->mask
.tcp_syn_fin_rst
);
2111 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID
,
2112 match
->value
.recirc_id
);
2113 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK
,
2114 match
->mask
.recirc_id
);
2115 MCDI_STRUCT_SET_DWORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK
,
2116 match
->value
.ct_mark
);
2117 MCDI_STRUCT_SET_DWORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK_MASK
,
2118 match
->mask
.ct_mark
);
2119 MCDI_STRUCT_SET_WORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN
,
2120 match
->value
.ct_zone
);
2121 MCDI_STRUCT_SET_WORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN_MASK
,
2122 match
->mask
.ct_zone
);
2123 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE
,
2124 match
->value
.eth_proto
);
2125 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK
,
2126 match
->mask
.eth_proto
);
2127 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE
,
2128 match
->value
.vlan_tci
[0]);
2129 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK
,
2130 match
->mask
.vlan_tci
[0]);
2131 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE
,
2132 match
->value
.vlan_proto
[0]);
2133 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK
,
2134 match
->mask
.vlan_proto
[0]);
2135 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE
,
2136 match
->value
.vlan_tci
[1]);
2137 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK
,
2138 match
->mask
.vlan_tci
[1]);
2139 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE
,
2140 match
->value
.vlan_proto
[1]);
2141 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK
,
2142 match
->mask
.vlan_proto
[1]);
2143 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE
),
2144 match
->value
.eth_saddr
, ETH_ALEN
);
2145 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK
),
2146 match
->mask
.eth_saddr
, ETH_ALEN
);
2147 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE
),
2148 match
->value
.eth_daddr
, ETH_ALEN
);
2149 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK
),
2150 match
->mask
.eth_daddr
, ETH_ALEN
);
2151 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO
,
2152 match
->value
.ip_proto
);
2153 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK
,
2154 match
->mask
.ip_proto
);
2155 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS
,
2156 match
->value
.ip_tos
);
2157 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK
,
2158 match
->mask
.ip_tos
);
2159 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL
,
2160 match
->value
.ip_ttl
);
2161 MCDI_STRUCT_SET_BYTE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK
,
2162 match
->mask
.ip_ttl
);
2163 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE
,
2164 match
->value
.src_ip
);
2165 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK
,
2166 match
->mask
.src_ip
);
2167 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE
,
2168 match
->value
.dst_ip
);
2169 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK
,
2170 match
->mask
.dst_ip
);
2172 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE
),
2173 &match
->value
.src_ip6
, sizeof(struct in6_addr
));
2174 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK
),
2175 &match
->mask
.src_ip6
, sizeof(struct in6_addr
));
2176 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE
),
2177 &match
->value
.dst_ip6
, sizeof(struct in6_addr
));
2178 memcpy(MCDI_STRUCT_PTR(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK
),
2179 &match
->mask
.dst_ip6
, sizeof(struct in6_addr
));
2181 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE
,
2182 match
->value
.l4_sport
);
2183 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK
,
2184 match
->mask
.l4_sport
);
2185 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE
,
2186 match
->value
.l4_dport
);
2187 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK
,
2188 match
->mask
.l4_dport
);
2189 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE
,
2190 match
->value
.tcp_flags
);
2191 MCDI_STRUCT_SET_WORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK
,
2192 match
->mask
.tcp_flags
);
2193 /* enc-keys are handled indirectly, through encap_match ID */
2195 MCDI_STRUCT_SET_DWORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID
,
2196 match
->encap
->fw_id
);
2197 MCDI_STRUCT_SET_DWORD(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK
,
2199 /* enc_keyid (VNI/VSID) is not part of the encap_match */
2200 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE
,
2201 match
->value
.enc_keyid
);
2202 MCDI_STRUCT_SET_DWORD_BE(match_crit
, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK
,
2203 match
->mask
.enc_keyid
);
2204 } else if (WARN_ON_ONCE(match
->mask
.enc_src_ip
) ||
2205 WARN_ON_ONCE(match
->mask
.enc_dst_ip
) ||
2206 WARN_ON_ONCE(!ipv6_addr_any(&match
->mask
.enc_src_ip6
)) ||
2207 WARN_ON_ONCE(!ipv6_addr_any(&match
->mask
.enc_dst_ip6
)) ||
2208 WARN_ON_ONCE(match
->mask
.enc_ip_tos
) ||
2209 WARN_ON_ONCE(match
->mask
.enc_ip_ttl
) ||
2210 WARN_ON_ONCE(match
->mask
.enc_sport
) ||
2211 WARN_ON_ONCE(match
->mask
.enc_dport
) ||
2212 WARN_ON_ONCE(match
->mask
.enc_keyid
)) {
2213 /* No enc-keys should appear in a rule without an encap_match */
2219 int efx_mae_insert_rule(struct efx_nic
*efx
, const struct efx_tc_match
*match
,
2220 u32 prio
, u32 acts_id
, u32
*id
)
2222 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN
));
2223 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN
);
2224 MCDI_DECLARE_STRUCT_PTR(match_crit
);
2225 MCDI_DECLARE_STRUCT_PTR(response
);
2232 match_crit
= _MCDI_DWORD(inbuf
, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA
);
2233 response
= _MCDI_DWORD(inbuf
, MAE_ACTION_RULE_INSERT_IN_RESPONSE
);
2234 if (efx_mae_asl_id(acts_id
)) {
2235 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_ASL_ID
, acts_id
);
2236 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_AS_ID
,
2237 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL
);
2239 /* We only had one AS, so we didn't wrap it in an ASL */
2240 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_ASL_ID
,
2241 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL
);
2242 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_AS_ID
, acts_id
);
2244 MCDI_SET_DWORD(inbuf
, MAE_ACTION_RULE_INSERT_IN_PRIO
, prio
);
2245 rc
= efx_mae_populate_match_criteria(match_crit
, match
);
2249 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ACTION_RULE_INSERT
, inbuf
, sizeof(inbuf
),
2250 outbuf
, sizeof(outbuf
), &outlen
);
2253 if (outlen
< sizeof(outbuf
))
2255 *id
= MCDI_DWORD(outbuf
, MAE_ACTION_RULE_INSERT_OUT_AR_ID
);
2259 int efx_mae_update_rule(struct efx_nic
*efx
, u32 acts_id
, u32 id
)
2261 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ACTION_RULE_UPDATE_IN_LEN
);
2262 MCDI_DECLARE_STRUCT_PTR(response
);
2264 BUILD_BUG_ON(MC_CMD_MAE_ACTION_RULE_UPDATE_OUT_LEN
);
2265 response
= _MCDI_DWORD(inbuf
, MAE_ACTION_RULE_UPDATE_IN_RESPONSE
);
2267 MCDI_SET_DWORD(inbuf
, MAE_ACTION_RULE_UPDATE_IN_AR_ID
, id
);
2268 if (efx_mae_asl_id(acts_id
)) {
2269 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_ASL_ID
, acts_id
);
2270 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_AS_ID
,
2271 MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL
);
2273 /* We only had one AS, so we didn't wrap it in an ASL */
2274 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_ASL_ID
,
2275 MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL
);
2276 MCDI_STRUCT_SET_DWORD(response
, MAE_ACTION_RULE_RESPONSE_AS_ID
, acts_id
);
2278 return efx_mcdi_rpc(efx
, MC_CMD_MAE_ACTION_RULE_UPDATE
, inbuf
, sizeof(inbuf
),
2282 int efx_mae_delete_rule(struct efx_nic
*efx
, u32 id
)
2284 MCDI_DECLARE_BUF(outbuf
, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2285 MCDI_DECLARE_BUF(inbuf
, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1));
2289 MCDI_SET_DWORD(inbuf
, MAE_ACTION_RULE_DELETE_IN_AR_ID
, id
);
2290 rc
= efx_mcdi_rpc(efx
, MC_CMD_MAE_ACTION_RULE_DELETE
, inbuf
, sizeof(inbuf
),
2291 outbuf
, sizeof(outbuf
), &outlen
);
2294 if (outlen
< sizeof(outbuf
))
2296 /* FW freed a different ID than we asked for, should also never happen.
2297 * Warn because it means we've now got a different idea to the FW of
2298 * what rules exist, which could cause mayhem later.
2300 if (WARN_ON(MCDI_DWORD(outbuf
, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID
) != id
))
2305 int efx_init_mae(struct efx_nic
*efx
)
2307 struct ef100_nic_data
*nic_data
= efx
->nic_data
;
2308 struct efx_mae
*mae
;
2311 if (!nic_data
->have_mport
)
2314 mae
= kmalloc(sizeof(*mae
), GFP_KERNEL
);
2318 rc
= rhashtable_init(&mae
->mports_ht
, &efx_mae_mports_ht_params
);
2328 void efx_fini_mae(struct efx_nic
*efx
)
2330 struct efx_mae
*mae
= efx
->mae
;