xref: /openbmc/linux/drivers/net/ethernet/sfc/mae.c (revision d47a97bd)
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 
19 int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
20 {
21 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
22 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN);
23 	size_t outlen;
24 	int rc;
25 
26 	if (WARN_ON_ONCE(!id))
27 		return -EINVAL;
28 	if (WARN_ON_ONCE(!label))
29 		return -EINVAL;
30 
31 	MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_TYPE,
32 		       MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_MPORT_TYPE_ALIAS);
33 	MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
34 		       MAE_MPORT_SELECTOR_ASSIGNED);
35 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_ALLOC, inbuf, sizeof(inbuf),
36 			  outbuf, sizeof(outbuf), &outlen);
37 	if (rc)
38 		return rc;
39 	if (outlen < sizeof(outbuf))
40 		return -EIO;
41 	*id = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_MPORT_ID);
42 	*label = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
43 	return 0;
44 }
45 
46 int efx_mae_free_mport(struct efx_nic *efx, u32 id)
47 {
48 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_FREE_IN_LEN);
49 
50 	BUILD_BUG_ON(MC_CMD_MAE_MPORT_FREE_OUT_LEN);
51 	MCDI_SET_DWORD(inbuf, MAE_MPORT_FREE_IN_MPORT_ID, id);
52 	return efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_FREE, inbuf, sizeof(inbuf),
53 			    NULL, 0, NULL);
54 }
55 
56 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out)
57 {
58 	efx_dword_t mport;
59 
60 	EFX_POPULATE_DWORD_2(mport,
61 			     MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
62 			     MAE_MPORT_SELECTOR_PPORT_ID, efx->port_num);
63 	*out = EFX_DWORD_VAL(mport);
64 }
65 
66 void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out)
67 {
68 	efx_dword_t mport;
69 
70 	EFX_POPULATE_DWORD_3(mport,
71 			     MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
72 			     MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER,
73 			     MAE_MPORT_SELECTOR_FUNC_VF_ID, MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
74 	*out = EFX_DWORD_VAL(mport);
75 }
76 
77 void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out)
78 {
79 	efx_dword_t mport;
80 
81 	EFX_POPULATE_DWORD_3(mport,
82 			     MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
83 			     MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER,
84 			     MAE_MPORT_SELECTOR_FUNC_VF_ID, vf_id);
85 	*out = EFX_DWORD_VAL(mport);
86 }
87 
88 /* Constructs an mport selector from an mport ID, because they're not the same */
89 void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out)
90 {
91 	efx_dword_t mport;
92 
93 	EFX_POPULATE_DWORD_2(mport,
94 			     MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID,
95 			     MAE_MPORT_SELECTOR_MPORT_ID, mport_id);
96 	*out = EFX_DWORD_VAL(mport);
97 }
98 
99 /* id is really only 24 bits wide */
100 int efx_mae_fw_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
101 {
102 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
103 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_LOOKUP_IN_LEN);
104 	size_t outlen;
105 	int rc;
106 
107 	MCDI_SET_DWORD(inbuf, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR, selector);
108 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_LOOKUP, inbuf, sizeof(inbuf),
109 			  outbuf, sizeof(outbuf), &outlen);
110 	if (rc)
111 		return rc;
112 	if (outlen < sizeof(outbuf))
113 		return -EIO;
114 	*id = MCDI_DWORD(outbuf, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
115 	return 0;
116 }
117 
118 int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
119 {
120 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_START_V2_IN_LEN);
121 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
122 	u32 out_flags;
123 	size_t outlen;
124 	int rc;
125 
126 	MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_QID,
127 		      efx_rx_queue_index(rx_queue));
128 	MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_PACKET_SIZE,
129 		      efx->net_dev->mtu);
130 	MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_COUNTER_TYPES_MASK,
131 		       BIT(MAE_COUNTER_TYPE_AR) | BIT(MAE_COUNTER_TYPE_CT) |
132 		       BIT(MAE_COUNTER_TYPE_OR));
133 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_START,
134 			  inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
135 	if (rc)
136 		return rc;
137 	if (outlen < sizeof(outbuf))
138 		return -EIO;
139 	out_flags = MCDI_DWORD(outbuf, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
140 	if (out_flags & BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST)) {
141 		netif_dbg(efx, drv, efx->net_dev,
142 			  "MAE counter stream uses credits\n");
143 		rx_queue->grant_credits = true;
144 		out_flags &= ~BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST);
145 	}
146 	if (out_flags) {
147 		netif_err(efx, drv, efx->net_dev,
148 			  "MAE counter stream start: unrecognised flags %x\n",
149 			  out_flags);
150 		goto out_stop;
151 	}
152 	return 0;
153 out_stop:
154 	efx_mae_stop_counters(efx, rx_queue);
155 	return -EOPNOTSUPP;
156 }
157 
158 static bool efx_mae_counters_flushed(u32 *flush_gen, u32 *seen_gen)
159 {
160 	int i;
161 
162 	for (i = 0; i < EFX_TC_COUNTER_TYPE_MAX; i++)
163 		if ((s32)(flush_gen[i] - seen_gen[i]) > 0)
164 			return false;
165 	return true;
166 }
167 
168 int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
169 {
170 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_V2_OUT_LENMAX);
171 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN);
172 	size_t outlen;
173 	int rc, i;
174 
175 	MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_STOP_IN_QID,
176 		      efx_rx_queue_index(rx_queue));
177 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_STOP,
178 			  inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
179 
180 	if (rc)
181 		return rc;
182 
183 	netif_dbg(efx, drv, efx->net_dev, "Draining counters:\n");
184 	/* Only process received generation counts */
185 	for (i = 0; (i < (outlen / 4)) && (i < EFX_TC_COUNTER_TYPE_MAX); i++) {
186 		efx->tc->flush_gen[i] = MCDI_ARRAY_DWORD(outbuf,
187 							 MAE_COUNTERS_STREAM_STOP_V2_OUT_GENERATION_COUNT,
188 							 i);
189 		netif_dbg(efx, drv, efx->net_dev,
190 			  "\ttype %u, awaiting gen %u\n", i,
191 			  efx->tc->flush_gen[i]);
192 	}
193 
194 	efx->tc->flush_counters = true;
195 
196 	/* Drain can take up to 2 seconds owing to FWRIVERHD-2884; whatever
197 	 * timeout we use, that delay is added to unload on nonresponsive
198 	 * hardware, so 2500ms seems like a reasonable compromise.
199 	 */
200 	if (!wait_event_timeout(efx->tc->flush_wq,
201 				efx_mae_counters_flushed(efx->tc->flush_gen,
202 							 efx->tc->seen_gen),
203 				msecs_to_jiffies(2500)))
204 		netif_warn(efx, drv, efx->net_dev,
205 			   "Failed to drain counters RXQ, FW may be unhappy\n");
206 
207 	efx->tc->flush_counters = false;
208 
209 	return rc;
210 }
211 
212 void efx_mae_counters_grant_credits(struct work_struct *work)
213 {
214 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN);
215 	struct efx_rx_queue *rx_queue = container_of(work, struct efx_rx_queue,
216 						     grant_work);
217 	struct efx_nic *efx = rx_queue->efx;
218 	unsigned int credits;
219 
220 	BUILD_BUG_ON(MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
221 	credits = READ_ONCE(rx_queue->notified_count) - rx_queue->granted_count;
222 	MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
223 		       credits);
224 	if (!efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS,
225 			  inbuf, sizeof(inbuf), NULL, 0, NULL))
226 		rx_queue->granted_count += credits;
227 }
228 
229 static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)
230 {
231 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN);
232 	size_t outlen;
233 	int rc;
234 
235 	BUILD_BUG_ON(MC_CMD_MAE_GET_CAPS_IN_LEN);
236 
237 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_GET_CAPS, NULL, 0, outbuf,
238 			  sizeof(outbuf), &outlen);
239 	if (rc)
240 		return rc;
241 	if (outlen < sizeof(outbuf))
242 		return -EIO;
243 	caps->match_field_count = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
244 	caps->action_prios = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ACTION_PRIOS);
245 	return 0;
246 }
247 
248 static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd,
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 	BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN);
258 
259 	rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen);
260 	if (rc)
261 		return rc;
262 	count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT);
263 	memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS);
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 
274 int 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;
281 	return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS,
282 				       caps->action_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  */
291 #define is_prefix_byte(_x)	!(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1))
292 
293 enum mask_type { MASK_ONES, MASK_ZEROES, MASK_PREFIX, MASK_OTHER };
294 
295 static const char *mask_type_name(enum mask_type typ)
296 {
297 	switch (typ) {
298 	case MASK_ONES:
299 		return "all-1s";
300 	case MASK_ZEROES:
301 		return "all-0s";
302 	case MASK_PREFIX:
303 		return "prefix";
304 	case MASK_OTHER:
305 		return "arbitrary";
306 	default: /* can't happen */
307 		return "unknown";
308 	}
309 }
310 
311 /* Checks a (big-endian) bytestring is a bit prefix */
312 static enum mask_type classify_mask(const u8 *mask, size_t len)
313 {
314 	bool zeroes = true; /* All bits seen so far are zeroes */
315 	bool ones = true; /* All bits seen so far are ones */
316 	bool prefix = true; /* Valid prefix so far */
317 	size_t i;
318 
319 	for (i = 0; i < len; i++) {
320 		if (ones) {
321 			if (!is_prefix_byte(mask[i]))
322 				prefix = false;
323 		} else if (mask[i]) {
324 			prefix = false;
325 		}
326 		if (mask[i] != 0xff)
327 			ones = false;
328 		if (mask[i])
329 			zeroes = false;
330 	}
331 	if (ones)
332 		return MASK_ONES;
333 	if (zeroes)
334 		return MASK_ZEROES;
335 	if (prefix)
336 		return MASK_PREFIX;
337 	return MASK_OTHER;
338 }
339 
340 static int efx_mae_match_check_cap_typ(u8 support, enum mask_type typ)
341 {
342 	switch (support) {
343 	case MAE_FIELD_UNSUPPORTED:
344 	case MAE_FIELD_SUPPORTED_MATCH_NEVER:
345 		if (typ == MASK_ZEROES)
346 			return 0;
347 		return -EOPNOTSUPP;
348 	case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
349 		if (typ == MASK_ZEROES)
350 			return 0;
351 		fallthrough;
352 	case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
353 		if (typ == MASK_ONES)
354 			return 0;
355 		return -EINVAL;
356 	case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
357 		if (typ == MASK_OTHER)
358 			return -EOPNOTSUPP;
359 		return 0;
360 	case MAE_FIELD_SUPPORTED_MATCH_MASK:
361 		return 0;
362 	default:
363 		return -EIO;
364 	}
365 }
366 
367 /* Validate field mask against hardware capabilities.  Captures caller's 'rc' */
368 #define CHECK(_mcdi, _field)	({					       \
369 	enum mask_type typ = classify_mask((const u8 *)&mask->_field,	       \
370 					   sizeof(mask->_field));	       \
371 									       \
372 	rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
373 					 typ);				       \
374 	if (rc)								       \
375 		NL_SET_ERR_MSG_FMT_MOD(extack,				       \
376 				       "No support for %s mask in field %s",   \
377 				       mask_type_name(typ), #_field);	       \
378 	rc;								       \
379 })
380 /* Booleans need special handling */
381 #define CHECK_BIT(_mcdi, _field)	({				       \
382 	enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES;	       \
383 									       \
384 	rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
385 					 typ);				       \
386 	if (rc)								       \
387 		NL_SET_ERR_MSG_FMT_MOD(extack,				       \
388 				       "No support for %s mask in field %s",   \
389 				       mask_type_name(typ), #_field);	       \
390 	rc;								       \
391 })
392 
393 int efx_mae_match_check_caps(struct efx_nic *efx,
394 			     const struct efx_tc_match_fields *mask,
395 			     struct netlink_ext_ack *extack)
396 {
397 	const u8 *supported_fields = efx->tc->caps->action_rule_fields;
398 	__be32 ingress_port = cpu_to_be32(mask->ingress_port);
399 	enum mask_type ingress_port_mask_type;
400 	int rc;
401 
402 	/* Check for _PREFIX assumes big-endian, so we need to convert */
403 	ingress_port_mask_type = classify_mask((const u8 *)&ingress_port,
404 					       sizeof(ingress_port));
405 	rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT],
406 					 ingress_port_mask_type);
407 	if (rc) {
408 		NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field ingress_port",
409 				       mask_type_name(ingress_port_mask_type));
410 		return rc;
411 	}
412 	if (CHECK(ETHER_TYPE, eth_proto) ||
413 	    CHECK(VLAN0_TCI, vlan_tci[0]) ||
414 	    CHECK(VLAN0_PROTO, vlan_proto[0]) ||
415 	    CHECK(VLAN1_TCI, vlan_tci[1]) ||
416 	    CHECK(VLAN1_PROTO, vlan_proto[1]) ||
417 	    CHECK(ETH_SADDR, eth_saddr) ||
418 	    CHECK(ETH_DADDR, eth_daddr) ||
419 	    CHECK(IP_PROTO, ip_proto) ||
420 	    CHECK(IP_TOS, ip_tos) ||
421 	    CHECK(IP_TTL, ip_ttl) ||
422 	    CHECK(SRC_IP4, src_ip) ||
423 	    CHECK(DST_IP4, dst_ip) ||
424 #ifdef CONFIG_IPV6
425 	    CHECK(SRC_IP6, src_ip6) ||
426 	    CHECK(DST_IP6, dst_ip6) ||
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;
435 	return 0;
436 }
437 #undef CHECK_BIT
438 #undef CHECK
439 
440 int 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)
448 		return -EINVAL;
449 
450 	MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT, 1);
451 	MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE, cnt->type);
452 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_ALLOC, inbuf, sizeof(inbuf),
453 			  outbuf, sizeof(outbuf), &outlen);
454 	if (rc)
455 		return rc;
456 	/* pcol says this can't happen, since count is 1 */
457 	if (outlen < sizeof(outbuf))
458 		return -EIO;
459 	cnt->fw_id = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_COUNTER_ID);
460 	cnt->gen = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
461 	return 0;
462 }
463 
464 int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
465 {
466 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_FREE_OUT_LEN(1));
467 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN);
468 	size_t outlen;
469 	int rc;
470 
471 	MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT, 1);
472 	MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID, cnt->fw_id);
473 	MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE, cnt->type);
474 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_FREE, inbuf, sizeof(inbuf),
475 			  outbuf, sizeof(outbuf), &outlen);
476 	if (rc)
477 		return rc;
478 	/* pcol says this can't happen, since count is 1 */
479 	if (outlen < sizeof(outbuf))
480 		return -EIO;
481 	/* FW freed a different ID than we asked for, should also never happen.
482 	 * Warn because it means we've now got a different idea to the FW of
483 	 * what counters exist, which could cause mayhem later.
484 	 */
485 	if (WARN_ON(MCDI_DWORD(outbuf, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID) !=
486 		    cnt->fw_id))
487 		return -EIO;
488 	return 0;
489 }
490 
491 int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id)
492 {
493 	struct ef100_nic_data *nic_data = efx->nic_data;
494 	struct efx_mae *mae = efx->mae;
495 	struct rhashtable_iter walk;
496 	struct mae_mport_desc *m;
497 	int rc = -ENOENT;
498 
499 	rhashtable_walk_enter(&mae->mports_ht, &walk);
500 	rhashtable_walk_start(&walk);
501 	while ((m = rhashtable_walk_next(&walk)) != NULL) {
502 		if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
503 		    m->interface_idx == nic_data->local_mae_intf &&
504 		    m->pf_idx == 0 &&
505 		    m->vf_idx == vf_idx) {
506 			*id = m->mport_id;
507 			rc = 0;
508 			break;
509 		}
510 	}
511 	rhashtable_walk_stop(&walk);
512 	rhashtable_walk_exit(&walk);
513 	return rc;
514 }
515 
516 static bool efx_mae_asl_id(u32 id)
517 {
518 	return !!(id & BIT(31));
519 }
520 
521 /* mport handling */
522 static const struct rhashtable_params efx_mae_mports_ht_params = {
523 	.key_len	= sizeof(u32),
524 	.key_offset	= offsetof(struct mae_mport_desc, mport_id),
525 	.head_offset	= offsetof(struct mae_mport_desc, linkage),
526 };
527 
528 struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id)
529 {
530 	return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id,
531 				      efx_mae_mports_ht_params);
532 }
533 
534 static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc)
535 {
536 	struct efx_mae *mae = efx->mae;
537 	int rc;
538 
539 	rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage,
540 				    efx_mae_mports_ht_params);
541 
542 	if (rc) {
543 		pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n",
544 			desc->mport_id, rc);
545 		kfree(desc);
546 		return rc;
547 	}
548 
549 	return rc;
550 }
551 
552 void efx_mae_remove_mport(void *desc, void *arg)
553 {
554 	struct mae_mport_desc *mport = desc;
555 
556 	synchronize_rcu();
557 	kfree(mport);
558 }
559 
560 static int efx_mae_process_mport(struct efx_nic *efx,
561 				 struct mae_mport_desc *desc)
562 {
563 	struct ef100_nic_data *nic_data = efx->nic_data;
564 	struct mae_mport_desc *mport;
565 
566 	mport = efx_mae_get_mport(efx, desc->mport_id);
567 	if (!IS_ERR_OR_NULL(mport)) {
568 		netif_err(efx, drv, efx->net_dev,
569 			  "mport with id %u does exist!!!\n", desc->mport_id);
570 		return -EEXIST;
571 	}
572 
573 	if (nic_data->have_own_mport &&
574 	    desc->mport_id == nic_data->own_mport) {
575 		WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC);
576 		WARN_ON(desc->vnic_client_type !=
577 			MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION);
578 		nic_data->local_mae_intf = desc->interface_idx;
579 		nic_data->have_local_intf = true;
580 		pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n",
581 			nic_data->local_mae_intf);
582 	}
583 
584 	return efx_mae_add_mport(efx, desc);
585 }
586 
587 #define MCDI_MPORT_JOURNAL_LEN \
588 	ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4)
589 
590 int efx_mae_enumerate_mports(struct efx_nic *efx)
591 {
592 	efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL);
593 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN);
594 	MCDI_DECLARE_STRUCT_PTR(desc);
595 	size_t outlen, stride, count;
596 	int rc = 0, i;
597 
598 	if (!outbuf)
599 		return -ENOMEM;
600 	do {
601 		rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf,
602 				  sizeof(inbuf), outbuf,
603 				  MCDI_MPORT_JOURNAL_LEN, &outlen);
604 		if (rc)
605 			goto fail;
606 		if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) {
607 			rc = -EIO;
608 			goto fail;
609 		}
610 		count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
611 		if (!count)
612 			continue; /* not break; we want to look at MORE flag */
613 		stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC);
614 		if (stride < MAE_MPORT_DESC_LEN) {
615 			rc = -EIO;
616 			goto fail;
617 		}
618 		if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) {
619 			rc = -EIO;
620 			goto fail;
621 		}
622 
623 		for (i = 0; i < count; i++) {
624 			struct mae_mport_desc *d;
625 
626 			d = kzalloc(sizeof(*d), GFP_KERNEL);
627 			if (!d) {
628 				rc = -ENOMEM;
629 				goto fail;
630 			}
631 
632 			desc = (efx_dword_t *)
633 				_MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST +
634 					  i * stride);
635 			d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID);
636 			d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS);
637 			d->caller_flags = MCDI_STRUCT_DWORD(desc,
638 							    MAE_MPORT_DESC_CALLER_FLAGS);
639 			d->mport_type = MCDI_STRUCT_DWORD(desc,
640 							  MAE_MPORT_DESC_MPORT_TYPE);
641 			switch (d->mport_type) {
642 			case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
643 				d->port_idx = MCDI_STRUCT_DWORD(desc,
644 								MAE_MPORT_DESC_NET_PORT_IDX);
645 				break;
646 			case MAE_MPORT_DESC_MPORT_TYPE_ALIAS:
647 				d->alias_mport_id = MCDI_STRUCT_DWORD(desc,
648 								      MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID);
649 				break;
650 			case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
651 				d->vnic_client_type = MCDI_STRUCT_DWORD(desc,
652 									MAE_MPORT_DESC_VNIC_CLIENT_TYPE);
653 				d->interface_idx = MCDI_STRUCT_DWORD(desc,
654 								     MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE);
655 				d->pf_idx = MCDI_STRUCT_WORD(desc,
656 							     MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX);
657 				d->vf_idx = MCDI_STRUCT_WORD(desc,
658 							     MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX);
659 				break;
660 			default:
661 				/* Unknown mport_type, just accept it */
662 				break;
663 			}
664 			rc = efx_mae_process_mport(efx, d);
665 			/* Any failure will be due to memory allocation faiure,
666 			 * so there is no point to try subsequent entries.
667 			 */
668 			if (rc)
669 				goto fail;
670 		}
671 	} while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) &&
672 		 !WARN_ON(!count));
673 fail:
674 	kfree(outbuf);
675 	return rc;
676 }
677 
678 int 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 
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);
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);
705 	if (rc)
706 		return rc;
707 	if (outlen < sizeof(outbuf))
708 		return -EIO;
709 	act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
710 	/* We rely on the high bit of AS IDs always being clear.
711 	 * The firmware API guarantees this, but let's check it ourselves.
712 	 */
713 	if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) {
714 		efx_mae_free_action_set(efx, act->fw_id);
715 		return -EIO;
716 	}
717 	return 0;
718 }
719 
720 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id)
721 {
722 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
723 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1));
724 	size_t outlen;
725 	int rc;
726 
727 	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id);
728 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf),
729 			  outbuf, sizeof(outbuf), &outlen);
730 	if (rc)
731 		return rc;
732 	if (outlen < sizeof(outbuf))
733 		return -EIO;
734 	/* FW freed a different ID than we asked for, should never happen.
735 	 * Warn because it means we've now got a different idea to the FW of
736 	 * what action-sets exist, which could cause mayhem later.
737 	 */
738 	if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id))
739 		return -EIO;
740 	return 0;
741 }
742 
743 int efx_mae_alloc_action_set_list(struct efx_nic *efx,
744 				  struct efx_tc_action_set_list *acts)
745 {
746 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN);
747 	struct efx_tc_action_set *act;
748 	size_t inlen, outlen, i = 0;
749 	efx_dword_t *inbuf;
750 	int rc;
751 
752 	list_for_each_entry(act, &acts->list, list)
753 		i++;
754 	if (i == 0)
755 		return -EINVAL;
756 	if (i == 1) {
757 		/* Don't wrap an ASL around a single AS, just use the AS_ID
758 		 * directly.  ASLs are a more limited resource.
759 		 */
760 		act = list_first_entry(&acts->list, struct efx_tc_action_set, list);
761 		acts->fw_id = act->fw_id;
762 		return 0;
763 	}
764 	if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2)
765 		return -EOPNOTSUPP; /* Too many actions */
766 	inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i);
767 	inbuf = kzalloc(inlen, GFP_KERNEL);
768 	if (!inbuf)
769 		return -ENOMEM;
770 	i = 0;
771 	list_for_each_entry(act, &acts->list, list) {
772 		MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS,
773 				     i, act->fw_id);
774 		i++;
775 	}
776 	MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i);
777 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen,
778 			  outbuf, sizeof(outbuf), &outlen);
779 	if (rc)
780 		goto out_free;
781 	if (outlen < sizeof(outbuf)) {
782 		rc = -EIO;
783 		goto out_free;
784 	}
785 	acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID);
786 	/* We rely on the high bit of ASL IDs always being set.
787 	 * The firmware API guarantees this, but let's check it ourselves.
788 	 */
789 	if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) {
790 		efx_mae_free_action_set_list(efx, acts);
791 		rc = -EIO;
792 	}
793 out_free:
794 	kfree(inbuf);
795 	return rc;
796 }
797 
798 int efx_mae_free_action_set_list(struct efx_nic *efx,
799 				 struct efx_tc_action_set_list *acts)
800 {
801 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1));
802 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1));
803 	size_t outlen;
804 	int rc;
805 
806 	/* If this is just an AS_ID with no ASL wrapper, then there is
807 	 * nothing for us to free.  (The AS will be freed later.)
808 	 */
809 	if (efx_mae_asl_id(acts->fw_id)) {
810 		MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID,
811 			       acts->fw_id);
812 		rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf,
813 				  sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
814 		if (rc)
815 			return rc;
816 		if (outlen < sizeof(outbuf))
817 			return -EIO;
818 		/* FW freed a different ID than we asked for, should never happen.
819 		 * Warn because it means we've now got a different idea to the FW of
820 		 * what action-set-lists exist, which could cause mayhem later.
821 		 */
822 		if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id))
823 			return -EIO;
824 	}
825 	/* We're probably about to free @acts, but let's just make sure its
826 	 * fw_id is blatted so that it won't look valid if it leaks out.
827 	 */
828 	acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL;
829 	return 0;
830 }
831 
832 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
833 					   const struct efx_tc_match *match)
834 {
835 	if (match->mask.ingress_port) {
836 		if (~match->mask.ingress_port)
837 			return -EOPNOTSUPP;
838 		MCDI_STRUCT_SET_DWORD(match_crit,
839 				      MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR,
840 				      match->value.ingress_port);
841 	}
842 	MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK,
843 			      match->mask.ingress_port);
844 	EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS),
845 			     MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG,
846 			     match->value.ip_frag,
847 			     MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG,
848 			     match->value.ip_firstfrag);
849 	EFX_POPULATE_DWORD_2(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK),
850 			     MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG,
851 			     match->mask.ip_frag,
852 			     MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG,
853 			     match->mask.ip_firstfrag);
854 	MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID,
855 			     match->value.recirc_id);
856 	MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK,
857 			     match->mask.recirc_id);
858 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE,
859 				match->value.eth_proto);
860 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK,
861 				match->mask.eth_proto);
862 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE,
863 				match->value.vlan_tci[0]);
864 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK,
865 				match->mask.vlan_tci[0]);
866 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE,
867 				match->value.vlan_proto[0]);
868 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK,
869 				match->mask.vlan_proto[0]);
870 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE,
871 				match->value.vlan_tci[1]);
872 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK,
873 				match->mask.vlan_tci[1]);
874 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE,
875 				match->value.vlan_proto[1]);
876 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK,
877 				match->mask.vlan_proto[1]);
878 	memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE),
879 	       match->value.eth_saddr, ETH_ALEN);
880 	memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK),
881 	       match->mask.eth_saddr, ETH_ALEN);
882 	memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE),
883 	       match->value.eth_daddr, ETH_ALEN);
884 	memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK),
885 	       match->mask.eth_daddr, ETH_ALEN);
886 	MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO,
887 			     match->value.ip_proto);
888 	MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK,
889 			     match->mask.ip_proto);
890 	MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS,
891 			     match->value.ip_tos);
892 	MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK,
893 			     match->mask.ip_tos);
894 	MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL,
895 			     match->value.ip_ttl);
896 	MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK,
897 			     match->mask.ip_ttl);
898 	MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE,
899 				 match->value.src_ip);
900 	MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK,
901 				 match->mask.src_ip);
902 	MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE,
903 				 match->value.dst_ip);
904 	MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK,
905 				 match->mask.dst_ip);
906 #ifdef CONFIG_IPV6
907 	memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE),
908 	       &match->value.src_ip6, sizeof(struct in6_addr));
909 	memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK),
910 	       &match->mask.src_ip6, sizeof(struct in6_addr));
911 	memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE),
912 	       &match->value.dst_ip6, sizeof(struct in6_addr));
913 	memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK),
914 	       &match->mask.dst_ip6, sizeof(struct in6_addr));
915 #endif
916 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE,
917 				match->value.l4_sport);
918 	MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK,
919 				match->mask.l4_sport);
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);
928 	return 0;
929 }
930 
931 int 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);
936 	MCDI_DECLARE_STRUCT_PTR(match_crit);
937 	MCDI_DECLARE_STRUCT_PTR(response);
938 	size_t outlen;
939 	int rc;
940 
941 	if (!id)
942 		return -EINVAL;
943 
944 	match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA);
945 	response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE);
946 	if (efx_mae_asl_id(acts_id)) {
947 		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id);
948 		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID,
949 				      MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL);
950 	} else {
951 		/* We only had one AS, so we didn't wrap it in an ASL */
952 		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID,
953 				      MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
954 		MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id);
955 	}
956 	MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio);
957 	rc = efx_mae_populate_match_criteria(match_crit, match);
958 	if (rc)
959 		return rc;
960 
961 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf),
962 			  outbuf, sizeof(outbuf), &outlen);
963 	if (rc)
964 		return rc;
965 	if (outlen < sizeof(outbuf))
966 		return -EIO;
967 	*id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
968 	return 0;
969 }
970 
971 int efx_mae_delete_rule(struct efx_nic *efx, u32 id)
972 {
973 	MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
974 	MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1));
975 	size_t outlen;
976 	int rc;
977 
978 	MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id);
979 	rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf),
980 			  outbuf, sizeof(outbuf), &outlen);
981 	if (rc)
982 		return rc;
983 	if (outlen < sizeof(outbuf))
984 		return -EIO;
985 	/* FW freed a different ID than we asked for, should also never happen.
986 	 * Warn because it means we've now got a different idea to the FW of
987 	 * what rules exist, which could cause mayhem later.
988 	 */
989 	if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id))
990 		return -EIO;
991 	return 0;
992 }
993 
994 int efx_init_mae(struct efx_nic *efx)
995 {
996 	struct ef100_nic_data *nic_data = efx->nic_data;
997 	struct efx_mae *mae;
998 	int rc;
999 
1000 	if (!nic_data->have_mport)
1001 		return -EINVAL;
1002 
1003 	mae = kmalloc(sizeof(*mae), GFP_KERNEL);
1004 	if (!mae)
1005 		return -ENOMEM;
1006 
1007 	rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params);
1008 	if (rc < 0) {
1009 		kfree(mae);
1010 		return rc;
1011 	}
1012 	efx->mae = mae;
1013 	mae->efx = efx;
1014 	return 0;
1015 }
1016 
1017 void efx_fini_mae(struct efx_nic *efx)
1018 {
1019 	struct efx_mae *mae = efx->mae;
1020 
1021 	kfree(mae);
1022 	efx->mae = NULL;
1023 }
1024