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
efx_mae_allocate_mport(struct efx_nic * efx,u32 * id,u32 * label)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
efx_mae_free_mport(struct efx_nic * efx,u32 id)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
efx_mae_mport_wire(struct efx_nic * efx,u32 * out)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
efx_mae_mport_uplink(struct efx_nic * efx __always_unused,u32 * out)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
efx_mae_mport_vf(struct efx_nic * efx __always_unused,u32 vf_id,u32 * out)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 */
efx_mae_mport_mport(struct efx_nic * efx __always_unused,u32 mport_id,u32 * out)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 */
efx_mae_fw_lookup_mport(struct efx_nic * efx,u32 selector,u32 * id)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
efx_mae_start_counters(struct efx_nic * efx,struct efx_rx_queue * rx_queue)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
efx_mae_counters_flushed(u32 * flush_gen,u32 * seen_gen)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
efx_mae_stop_counters(struct efx_nic * efx,struct efx_rx_queue * rx_queue)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
efx_mae_counters_grant_credits(struct work_struct * work)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
efx_mae_get_basic_caps(struct efx_nic * efx,struct mae_caps * caps)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
efx_mae_get_rule_fields(struct efx_nic * efx,u32 cmd,u8 * field_support)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
efx_mae_get_caps(struct efx_nic * efx,struct mae_caps * caps)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
mask_type_name(enum mask_type typ)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 */
classify_mask(const u8 * mask,size_t len)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
efx_mae_match_check_cap_typ(u8 support,enum mask_type typ)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
efx_mae_match_check_caps(struct efx_nic * efx,const struct efx_tc_match_fields * mask,struct netlink_ext_ack * extack)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
efx_mae_allocate_counter(struct efx_nic * efx,struct efx_tc_counter * cnt)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
efx_mae_free_counter(struct efx_nic * efx,struct efx_tc_counter * cnt)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
efx_mae_lookup_mport(struct efx_nic * efx,u32 vf_idx,u32 * id)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
efx_mae_asl_id(u32 id)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
efx_mae_get_mport(struct efx_nic * efx,u32 mport_id)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
efx_mae_add_mport(struct efx_nic * efx,struct mae_mport_desc * desc)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
efx_mae_remove_mport(void * desc,void * arg)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
efx_mae_process_mport(struct efx_nic * efx,struct mae_mport_desc * desc)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
efx_mae_enumerate_mports(struct efx_nic * efx)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
efx_mae_alloc_action_set(struct efx_nic * efx,struct efx_tc_action_set * act)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
efx_mae_free_action_set(struct efx_nic * efx,u32 fw_id)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
efx_mae_alloc_action_set_list(struct efx_nic * efx,struct efx_tc_action_set_list * acts)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
efx_mae_free_action_set_list(struct efx_nic * efx,struct efx_tc_action_set_list * acts)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
efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR (match_crit),const struct efx_tc_match * match)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
efx_mae_insert_rule(struct efx_nic * efx,const struct efx_tc_match * match,u32 prio,u32 acts_id,u32 * id)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
efx_mae_delete_rule(struct efx_nic * efx,u32 id)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
efx_init_mae(struct efx_nic * efx)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
efx_fini_mae(struct efx_nic * efx)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