]> Git Repo - J-linux.git/blob - drivers/net/ethernet/sfc/mae.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / net / ethernet / sfc / mae.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /****************************************************************************
3  * Driver for Solarflare network controllers and boards
4  * Copyright 2019 Solarflare Communications Inc.
5  * Copyright 2020-2022 Xilinx Inc.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published
9  * by the Free Software Foundation, incorporated herein by reference.
10  */
11
12 #include <linux/rhashtable.h>
13 #include "ef100_nic.h"
14 #include "mae.h"
15 #include "mcdi.h"
16 #include "mcdi_pcol.h"
17 #include "mcdi_pcol_mae.h"
18 #include "tc_encap_actions.h"
19 #include "tc_conntrack.h"
20
21 int efx_mae_allocate_mport(struct efx_nic *efx, u32 *id, u32 *label)
22 {
23         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_OUT_LEN);
24         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_LEN);
25         size_t outlen;
26         int rc;
27
28         if (WARN_ON_ONCE(!id))
29                 return -EINVAL;
30         if (WARN_ON_ONCE(!label))
31                 return -EINVAL;
32
33         MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_TYPE,
34                        MC_CMD_MAE_MPORT_ALLOC_ALIAS_IN_MPORT_TYPE_ALIAS);
35         MCDI_SET_DWORD(inbuf, MAE_MPORT_ALLOC_ALIAS_IN_DELIVER_MPORT,
36                        MAE_MPORT_SELECTOR_ASSIGNED);
37         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_ALLOC, inbuf, sizeof(inbuf),
38                           outbuf, sizeof(outbuf), &outlen);
39         if (rc)
40                 return rc;
41         if (outlen < sizeof(outbuf))
42                 return -EIO;
43         *id = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_MPORT_ID);
44         *label = MCDI_DWORD(outbuf, MAE_MPORT_ALLOC_ALIAS_OUT_LABEL);
45         return 0;
46 }
47
48 int efx_mae_free_mport(struct efx_nic *efx, u32 id)
49 {
50         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_FREE_IN_LEN);
51
52         BUILD_BUG_ON(MC_CMD_MAE_MPORT_FREE_OUT_LEN);
53         MCDI_SET_DWORD(inbuf, MAE_MPORT_FREE_IN_MPORT_ID, id);
54         return efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_FREE, inbuf, sizeof(inbuf),
55                             NULL, 0, NULL);
56 }
57
58 void efx_mae_mport_wire(struct efx_nic *efx, u32 *out)
59 {
60         efx_dword_t mport;
61
62         EFX_POPULATE_DWORD_2(mport,
63                              MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_PPORT,
64                              MAE_MPORT_SELECTOR_PPORT_ID, efx->port_num);
65         *out = EFX_DWORD_VAL(mport);
66 }
67
68 void efx_mae_mport_uplink(struct efx_nic *efx __always_unused, u32 *out)
69 {
70         efx_dword_t mport;
71
72         EFX_POPULATE_DWORD_3(mport,
73                              MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
74                              MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER,
75                              MAE_MPORT_SELECTOR_FUNC_VF_ID, MAE_MPORT_SELECTOR_FUNC_VF_ID_NULL);
76         *out = EFX_DWORD_VAL(mport);
77 }
78
79 /* 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)
81 {
82         efx_dword_t mport;
83
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);
88 }
89
90 /* id is really only 24 bits wide */
91 int efx_mae_fw_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
92 {
93         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
94         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_LOOKUP_IN_LEN);
95         size_t outlen;
96         int rc;
97
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);
101         if (rc)
102                 return rc;
103         if (outlen < sizeof(outbuf))
104                 return -EIO;
105         *id = MCDI_DWORD(outbuf, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
106         return 0;
107 }
108
109 int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
110 {
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);
113         u32 out_flags;
114         size_t outlen;
115         int rc;
116
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,
120                       efx->net_dev->mtu);
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);
126         if (rc)
127                 return rc;
128         if (outlen < sizeof(outbuf))
129                 return -EIO;
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);
136         }
137         if (out_flags) {
138                 netif_err(efx, drv, efx->net_dev,
139                           "MAE counter stream start: unrecognised flags %x\n",
140                           out_flags);
141                 goto out_stop;
142         }
143         return 0;
144 out_stop:
145         efx_mae_stop_counters(efx, rx_queue);
146         return -EOPNOTSUPP;
147 }
148
149 static bool efx_mae_counters_flushed(u32 *flush_gen, u32 *seen_gen)
150 {
151         int i;
152
153         for (i = 0; i < EFX_TC_COUNTER_TYPE_MAX; i++)
154                 if ((s32)(flush_gen[i] - seen_gen[i]) > 0)
155                         return false;
156         return true;
157 }
158
159 int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
160 {
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);
163         size_t outlen;
164         int rc, i;
165
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);
170
171         if (rc)
172                 return rc;
173
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,
179                                                          i);
180                 netif_dbg(efx, drv, efx->net_dev,
181                           "\ttype %u, awaiting gen %u\n", i,
182                           efx->tc->flush_gen[i]);
183         }
184
185         efx->tc->flush_counters = true;
186
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.
190          */
191         if (!wait_event_timeout(efx->tc->flush_wq,
192                                 efx_mae_counters_flushed(efx->tc->flush_gen,
193                                                          efx->tc->seen_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");
197
198         efx->tc->flush_counters = false;
199
200         return rc;
201 }
202
203 void efx_mae_counters_grant_credits(struct work_struct *work)
204 {
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,
207                                                      grant_work);
208         struct efx_nic *efx = rx_queue->efx;
209         unsigned int credits;
210
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,
214                        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;
218 }
219
220 static int efx_mae_table_get_desc(struct efx_nic *efx,
221                                   struct efx_tc_table_desc *desc,
222                                   u32 table_id)
223 {
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;
227         size_t outlen;
228         int rc;
229
230         memset(desc, 0, sizeof(*desc));
231
232         MCDI_SET_DWORD(inbuf, TABLE_DESCRIPTOR_IN_TABLE_ID, table_id);
233 more:
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);
237         if (rc)
238                 goto fail;
239         if (outlen < MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(1)) {
240                 rc = -EIO;
241                 goto fail;
242         }
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);
251                 rc = -EOPNOTSUPP;
252                 if (desc->flags)
253                         goto fail;
254                 desc->scheme = MCDI_BYTE(outbuf, TABLE_DESCRIPTOR_OUT_SCHEME);
255                 if (desc->scheme)
256                         goto fail;
257                 rc = -ENOMEM;
258                 desc->keys = kcalloc(desc->n_keys,
259                                      sizeof(struct efx_tc_table_field_fmt),
260                                      GFP_KERNEL);
261                 if (!desc->keys)
262                         goto fail;
263                 desc->resps = kcalloc(desc->n_resps,
264                                       sizeof(struct efx_tc_table_field_fmt),
265                                       GFP_KERNEL);
266                 if (!desc->resps)
267                         goto fail;
268         }
269         /* FW could have returned more than the 16 field_descrs we
270          * made room for in our outbuf
271          */
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);
276
277                 if (outlen < MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(i + 1)) {
278                         offset += i;
279                         goto more;
280                 }
281                 if (i + offset < desc->n_keys)
282                         field = desc->keys + i + offset;
283                 else
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);
293         }
294         return 0;
295
296 fail:
297         kfree(desc->keys);
298         kfree(desc->resps);
299         return rc;
300 }
301
302 static int efx_mae_table_hook_find(u16 n_fields,
303                                    struct efx_tc_table_field_fmt *fields,
304                                    u16 field_id)
305 {
306         unsigned int i;
307
308         for (i = 0; i < n_fields; i++) {
309                 if (fields[i].field_id == field_id)
310                         return i;
311         }
312         return -EPROTO;
313 }
314
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)
319
320 #define TABLE_HOOK_KEY(_meta, _name, _mcdi_name)        ({                      \
321         int _rc = TABLE_FIND_KEY(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name);    \
322                                                                                 \
323         if (_rc > U8_MAX)                                                       \
324                 _rc = -EOPNOTSUPP;                                              \
325         if (_rc >= 0) {                                                         \
326                 _meta->keys._name##_idx = _rc;                                  \
327                 _rc = 0;                                                        \
328         }                                                                       \
329         _rc;                                                                    \
330 })
331 #define TABLE_HOOK_RESP(_meta, _name, _mcdi_name)       ({                      \
332         int _rc = TABLE_FIND_RESP(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name);   \
333                                                                                 \
334         if (_rc > U8_MAX)                                                       \
335                 _rc = -EOPNOTSUPP;                                              \
336         if (_rc >= 0) {                                                         \
337                 _meta->resps._name##_idx = _rc;                                 \
338                 _rc = 0;                                                        \
339         }                                                                       \
340         _rc;                                                                    \
341 })
342
343 static int efx_mae_table_hook_ct(struct efx_nic *efx,
344                                  struct efx_tc_table_ct *meta_ct)
345 {
346         int rc;
347
348         rc = TABLE_HOOK_KEY(meta_ct, eth_proto, ETHER_TYPE);
349         if (rc)
350                 return rc;
351         rc = TABLE_HOOK_KEY(meta_ct, ip_proto, IP_PROTO);
352         if (rc)
353                 return rc;
354         rc = TABLE_HOOK_KEY(meta_ct, src_ip, SRC_IP);
355         if (rc)
356                 return rc;
357         rc = TABLE_HOOK_KEY(meta_ct, dst_ip, DST_IP);
358         if (rc)
359                 return rc;
360         rc = TABLE_HOOK_KEY(meta_ct, l4_sport, SRC_PORT);
361         if (rc)
362                 return rc;
363         rc = TABLE_HOOK_KEY(meta_ct, l4_dport, DST_PORT);
364         if (rc)
365                 return rc;
366         rc = TABLE_HOOK_KEY(meta_ct, zone, DOMAIN);
367         if (rc)
368                 return rc;
369         rc = TABLE_HOOK_RESP(meta_ct, dnat, NAT_DIR);
370         if (rc)
371                 return rc;
372         rc = TABLE_HOOK_RESP(meta_ct, nat_ip, NAT_IP);
373         if (rc)
374                 return rc;
375         rc = TABLE_HOOK_RESP(meta_ct, l4_natport, NAT_PORT);
376         if (rc)
377                 return rc;
378         rc = TABLE_HOOK_RESP(meta_ct, mark, CT_MARK);
379         if (rc)
380                 return rc;
381         rc = TABLE_HOOK_RESP(meta_ct, counter_id, COUNTER_ID);
382         if (rc)
383                 return rc;
384         meta_ct->hooked = true;
385         return 0;
386 }
387
388 static void efx_mae_table_free_desc(struct efx_tc_table_desc *desc)
389 {
390         kfree(desc->keys);
391         kfree(desc->resps);
392         memset(desc, 0, sizeof(*desc));
393 }
394
395 static bool efx_mae_check_table_exists(struct efx_nic *efx, u32 tbl_req)
396 {
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;
401         bool ct_tbl = false;
402         int rc, idx;
403
404         msg_max = sizeof(outbuf);
405         efx->tc->meta_ct.hooked = false;
406 more:
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,
410                           msg_max, &outlen);
411         if (rc)
412                 return false;
413
414         if (outlen < MC_CMD_TABLE_LIST_OUT_LEN(1))
415                 return false;
416
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));
419
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) {
423                         ct_tbl = true;
424                         break;
425                 }
426         }
427
428         pos += tbl_cnt;
429         if (!ct_tbl && pos < tbl_total)
430                 goto more;
431
432         return ct_tbl;
433 }
434
435 int efx_mae_get_tables(struct efx_nic *efx)
436 {
437         int rc;
438
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);
443                 if (rc) {
444                         pci_info(efx->pci_dev,
445                                  "FW does not support conntrack desc rc %d\n",
446                                  rc);
447                         return 0;
448                 }
449
450                 rc = efx_mae_table_hook_ct(efx, &efx->tc->meta_ct);
451                 if (rc) {
452                         pci_info(efx->pci_dev,
453                                  "FW does not support conntrack hook rc %d\n",
454                                  rc);
455                         return 0;
456                 }
457         } else {
458                 pci_info(efx->pci_dev,
459                          "FW does not support conntrack table\n");
460         }
461         return 0;
462 }
463
464 void efx_mae_free_tables(struct efx_nic *efx)
465 {
466         efx_mae_table_free_desc(&efx->tc->meta_ct.desc);
467         efx->tc->meta_ct.hooked = false;
468 }
469
470 static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)
471 {
472         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN);
473         size_t outlen;
474         int rc;
475
476         BUILD_BUG_ON(MC_CMD_MAE_GET_CAPS_IN_LEN);
477
478         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_GET_CAPS, NULL, 0, outbuf,
479                           sizeof(outbuf), &outlen);
480         if (rc)
481                 return rc;
482         if (outlen < sizeof(outbuf))
483                 return -EIO;
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);
487         return 0;
488 }
489
490 static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd,
491                                    u8 *field_support)
492 {
493         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS));
494         MCDI_DECLARE_STRUCT_PTR(caps);
495         unsigned int count;
496         size_t outlen;
497         int rc, i;
498
499         /* AR and OR caps MCDIs have identical layout, so we are using the
500          * same code for both.
501          */
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);
506
507         rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen);
508         if (rc)
509                 return rc;
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.
519          */
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);
523         return 0;
524 }
525
526 int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps)
527 {
528         int rc;
529
530         rc = efx_mae_get_basic_caps(efx, caps);
531         if (rc)
532                 return rc;
533         rc = efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS,
534                                      caps->action_rule_fields);
535         if (rc)
536                 return rc;
537         return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_OR_CAPS,
538                                        caps->outer_rule_fields);
539 }
540
541 /* Bit twiddling:
542  * Prefix: 1...110...0
543  *      ~: 0...001...1
544  *    + 1: 0...010...0 is power of two
545  * so (~x) & ((~x) + 1) == 0.  Converse holds also.
546  */
547 #define is_prefix_byte(_x)      !(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1))
548
549 enum mask_type { MASK_ONES, MASK_ZEROES, MASK_PREFIX, MASK_OTHER };
550
551 static const char *mask_type_name(enum mask_type typ)
552 {
553         switch (typ) {
554         case MASK_ONES:
555                 return "all-1s";
556         case MASK_ZEROES:
557                 return "all-0s";
558         case MASK_PREFIX:
559                 return "prefix";
560         case MASK_OTHER:
561                 return "arbitrary";
562         default: /* can't happen */
563                 return "unknown";
564         }
565 }
566
567 /* Checks a (big-endian) bytestring is a bit prefix */
568 static enum mask_type classify_mask(const u8 *mask, size_t len)
569 {
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 */
573         size_t i;
574
575         for (i = 0; i < len; i++) {
576                 if (ones) {
577                         if (!is_prefix_byte(mask[i]))
578                                 prefix = false;
579                 } else if (mask[i]) {
580                         prefix = false;
581                 }
582                 if (mask[i] != 0xff)
583                         ones = false;
584                 if (mask[i])
585                         zeroes = false;
586         }
587         if (ones)
588                 return MASK_ONES;
589         if (zeroes)
590                 return MASK_ZEROES;
591         if (prefix)
592                 return MASK_PREFIX;
593         return MASK_OTHER;
594 }
595
596 static int efx_mae_match_check_cap_typ(u8 support, enum mask_type typ)
597 {
598         switch (support) {
599         case MAE_FIELD_UNSUPPORTED:
600         case MAE_FIELD_SUPPORTED_MATCH_NEVER:
601                 if (typ == MASK_ZEROES)
602                         return 0;
603                 return -EOPNOTSUPP;
604         case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
605                 if (typ == MASK_ZEROES)
606                         return 0;
607                 fallthrough;
608         case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
609                 if (typ == MASK_ONES)
610                         return 0;
611                 return -EINVAL;
612         case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
613                 if (typ == MASK_OTHER)
614                         return -EOPNOTSUPP;
615                 return 0;
616         case MAE_FIELD_SUPPORTED_MATCH_MASK:
617                 return 0;
618         default:
619                 return -EIO;
620         }
621 }
622
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));              \
627                                                                                \
628         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
629                                          typ);                                 \
630         if (rc)                                                                \
631                 NL_SET_ERR_MSG_FMT_MOD(extack,                                 \
632                                        "No support for %s mask in field %s",   \
633                                        mask_type_name(typ), #_field);          \
634         rc;                                                                    \
635 })
636 /* Booleans need special handling */
637 #define CHECK_BIT(_mcdi, _field)        ({                                     \
638         enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES;           \
639                                                                                \
640         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
641                                          typ);                                 \
642         if (rc)                                                                \
643                 NL_SET_ERR_MSG_FMT_MOD(extack,                                 \
644                                        "No support for %s mask in field %s",   \
645                                        mask_type_name(typ), #_field);          \
646         rc;                                                                    \
647 })
648
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)
652 {
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;
656         int rc;
657
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);
663         if (rc) {
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));
666                 return rc;
667         }
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) ||
680 #ifdef CONFIG_IPV6
681             CHECK(SRC_IP6, src_ip6) ||
682             CHECK(DST_IP6, dst_ip6) ||
683 #endif
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))
695                 return rc;
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).
702          */
703         if (efx_tc_match_is_encap(mask)) {
704                 rc = efx_mae_match_check_cap_typ(
705                                 supported_fields[MAE_FIELD_OUTER_RULE_ID],
706                                 MASK_ONES);
707                 if (rc) {
708                         NL_SET_ERR_MSG_MOD(extack, "No support for encap rule ID matches");
709                         return rc;
710                 }
711                 if (CHECK(ENC_VNET_ID, enc_keyid))
712                         return rc;
713         } else if (mask->enc_keyid) {
714                 NL_SET_ERR_MSG_MOD(extack, "Match on enc_keyid requires other encap fields");
715                 return -EINVAL;
716         }
717         return 0;
718 }
719
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));              \
724                                                                                \
725         if (typ != MASK_ZEROES) {                                              \
726                 NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\
727                 rc = -EOPNOTSUPP;                                              \
728         }                                                                      \
729         rc;                                                                    \
730 })
731 #define UNSUPPORTED_BIT(_field) ({                                             \
732         if (mask->_field) {                                                    \
733                 NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\
734                 rc = -EOPNOTSUPP;                                              \
735         }                                                                      \
736         rc;                                                                    \
737 })
738
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.
742  */
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)
746 {
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;
750         int rc;
751
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);
757         if (rc) {
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),
760                                        "ingress_port");
761                 return rc;
762         }
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) ||
777 #ifdef CONFIG_IPV6
778             CHECK(ENC_SRC_IP6, src_ip6) ||
779             CHECK(ENC_DST_IP6, dst_ip6) ||
780 #endif
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))
785                 return rc;
786         if (efx_tc_match_is_encap(mask)) {
787                 /* can't happen; disallowed for local rules, translated
788                  * for foreign rules.
789                  */
790                 NL_SET_ERR_MSG_MOD(extack, "Unexpected encap match in LHS rule");
791                 return -EOPNOTSUPP;
792         }
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))
799                 return rc;
800         return 0;
801 }
802 #undef UNSUPPORTED
803 #undef CHECK_BIT
804 #undef CHECK
805
806 #define CHECK(_mcdi)    ({                                                     \
807         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
808                                          MASK_ONES);                           \
809         if (rc)                                                                \
810                 NL_SET_ERR_MSG_FMT_MOD(extack,                                 \
811                                        "No support for field %s", #_mcdi);     \
812         rc;                                                                    \
813 })
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.
816  */
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)
820 {
821         u8 *supported_fields = efx->tc->caps->outer_rule_fields;
822         enum mask_type typ;
823         int rc;
824
825         if (CHECK(ENC_ETHER_TYPE))
826                 return rc;
827         if (ipv6) {
828                 if (CHECK(ENC_SRC_IP6) ||
829                     CHECK(ENC_DST_IP6))
830                         return rc;
831         } else {
832                 if (CHECK(ENC_SRC_IP4) ||
833                     CHECK(ENC_DST_IP4))
834                         return rc;
835         }
836         if (CHECK(ENC_L4_DPORT) ||
837             CHECK(ENC_IP_PROTO))
838                 return rc;
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],
841                                          typ);
842         if (rc) {
843                 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s",
844                                        mask_type_name(typ), "enc_src_port");
845                 return rc;
846         }
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],
849                                          typ);
850         if (rc) {
851                 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s",
852                                        mask_type_name(typ), "enc_ip_tos");
853                 return rc;
854         }
855         return 0;
856 }
857 #undef CHECK
858
859 int efx_mae_check_encap_type_supported(struct efx_nic *efx, enum efx_encap_type typ)
860 {
861         unsigned int bit;
862
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;
866                 break;
867         case EFX_ENCAP_TYPE_GENEVE:
868                 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE_LBN;
869                 break;
870         default:
871                 return -EOPNOTSUPP;
872         }
873         if (efx->tc->caps->encap_types & BIT(bit))
874                 return 0;
875         return -EOPNOTSUPP;
876 }
877
878 int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
879 {
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);
882         size_t outlen;
883         int rc;
884
885         if (!cnt)
886                 return -EINVAL;
887
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);
892         if (rc)
893                 return rc;
894         /* pcol says this can't happen, since count is 1 */
895         if (outlen < sizeof(outbuf))
896                 return -EIO;
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);
899         return 0;
900 }
901
902 int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
903 {
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);
906         size_t outlen;
907         int rc;
908
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);
914         if (rc)
915                 return rc;
916         /* pcol says this can't happen, since count is 1 */
917         if (outlen < sizeof(outbuf))
918                 return -EIO;
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.
922          */
923         if (WARN_ON(MCDI_DWORD(outbuf, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID) !=
924                     cnt->fw_id))
925                 return -EIO;
926         return 0;
927 }
928
929 static int efx_mae_encap_type_to_mae_type(enum efx_encap_type type)
930 {
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;
938         default:
939                 return -EOPNOTSUPP;
940         }
941 }
942
943 int efx_mae_allocate_encap_md(struct efx_nic *efx,
944                               struct efx_tc_encap_action *encap)
945 {
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;
949         int rc;
950
951         rc = efx_mae_encap_type_to_mae_type(encap->type);
952         if (rc < 0)
953                 return rc;
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 */
957                 return -EINVAL;
958         memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA),
959                encap->encap_hdr,
960                encap->encap_hdr_len);
961         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_ALLOC, inbuf,
962                           inlen, outbuf, sizeof(outbuf), &outlen);
963         if (rc)
964                 return rc;
965         if (outlen < sizeof(outbuf))
966                 return -EIO;
967         encap->fw_id = MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
968         return 0;
969 }
970
971 int efx_mae_update_encap_md(struct efx_nic *efx,
972                             struct efx_tc_encap_action *encap)
973 {
974         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(EFX_TC_MAX_ENCAP_HDR));
975         size_t inlen;
976         int rc;
977
978         rc = efx_mae_encap_type_to_mae_type(encap->type);
979         if (rc < 0)
980                 return rc;
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,
983                        encap->fw_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 */
986                 return -EINVAL;
987         memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_HDR_DATA),
988                encap->encap_hdr,
989                encap->encap_hdr_len);
990
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);
994 }
995
996 int efx_mae_free_encap_md(struct efx_nic *efx,
997                           struct efx_tc_encap_action *encap)
998 {
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));
1001         size_t outlen;
1002         int rc;
1003
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);
1007         if (rc)
1008                 return rc;
1009         if (outlen < sizeof(outbuf))
1010                 return -EIO;
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.
1014          */
1015         if (WARN_ON(MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) != encap->fw_id))
1016                 return -EIO;
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.
1019          */
1020         encap->fw_id = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL;
1021         return 0;
1022 }
1023
1024 int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id)
1025 {
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;
1030         int rc = -ENOENT;
1031
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 &&
1037                     m->pf_idx == 0 &&
1038                     m->vf_idx == vf_idx) {
1039                         *id = m->mport_id;
1040                         rc = 0;
1041                         break;
1042                 }
1043         }
1044         rhashtable_walk_stop(&walk);
1045         rhashtable_walk_exit(&walk);
1046         return rc;
1047 }
1048
1049 static bool efx_mae_asl_id(u32 id)
1050 {
1051         return !!(id & BIT(31));
1052 }
1053
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),
1059 };
1060
1061 struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id)
1062 {
1063         return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id,
1064                                       efx_mae_mports_ht_params);
1065 }
1066
1067 static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc)
1068 {
1069         struct efx_mae *mae = efx->mae;
1070         int rc;
1071
1072         rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage,
1073                                     efx_mae_mports_ht_params);
1074
1075         if (rc) {
1076                 pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n",
1077                         desc->mport_id, rc);
1078                 kfree(desc);
1079                 return rc;
1080         }
1081
1082         return rc;
1083 }
1084
1085 void efx_mae_remove_mport(void *desc, void *arg)
1086 {
1087         struct mae_mport_desc *mport = desc;
1088
1089         synchronize_rcu();
1090         kfree(mport);
1091 }
1092
1093 static int efx_mae_process_mport(struct efx_nic *efx,
1094                                  struct mae_mport_desc *desc)
1095 {
1096         struct ef100_nic_data *nic_data = efx->nic_data;
1097         struct mae_mport_desc *mport;
1098
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);
1103                 return -EEXIST;
1104         }
1105
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);
1115         }
1116
1117         return efx_mae_add_mport(efx, desc);
1118 }
1119
1120 #define MCDI_MPORT_JOURNAL_LEN \
1121         ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4)
1122
1123 int efx_mae_enumerate_mports(struct efx_nic *efx)
1124 {
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;
1129         int rc = 0, i;
1130
1131         if (!outbuf)
1132                 return -ENOMEM;
1133         do {
1134                 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf,
1135                                   sizeof(inbuf), outbuf,
1136                                   MCDI_MPORT_JOURNAL_LEN, &outlen);
1137                 if (rc)
1138                         goto fail;
1139                 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) {
1140                         rc = -EIO;
1141                         goto fail;
1142                 }
1143                 count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
1144                 if (!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) {
1148                         rc = -EIO;
1149                         goto fail;
1150                 }
1151                 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) {
1152                         rc = -EIO;
1153                         goto fail;
1154                 }
1155
1156                 for (i = 0; i < count; i++) {
1157                         struct mae_mport_desc *d;
1158
1159                         d = kzalloc(sizeof(*d), GFP_KERNEL);
1160                         if (!d) {
1161                                 rc = -ENOMEM;
1162                                 goto fail;
1163                         }
1164
1165                         desc = (efx_dword_t *)
1166                                 _MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST +
1167                                           i * stride);
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);
1178                                 break;
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);
1182                                 break;
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);
1192                                 break;
1193                         default:
1194                                 /* Unknown mport_type, just accept it */
1195                                 break;
1196                         }
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.
1200                          */
1201                         if (rc)
1202                                 goto fail;
1203                 }
1204         } while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) &&
1205                  !WARN_ON(!count));
1206 fail:
1207         kfree(outbuf);
1208         return rc;
1209 }
1210
1211 /**
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
1215  *
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.
1218  *
1219  * Return: negative value on error, 0 in success.
1220  */
1221 int efx_mae_allocate_pedit_mac(struct efx_nic *efx,
1222                                struct efx_tc_mac_pedit_action *ped)
1223 {
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);
1226         size_t outlen;
1227         int rc;
1228
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);
1235         if (rc)
1236                 return rc;
1237         if (outlen < sizeof(outbuf))
1238                 return -EIO;
1239         ped->fw_id = MCDI_DWORD(outbuf, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID);
1240         return 0;
1241 }
1242
1243 /**
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
1247  *
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).
1250  */
1251 void efx_mae_free_pedit_mac(struct efx_nic *efx,
1252                             struct efx_tc_mac_pedit_action *ped)
1253 {
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));
1256         size_t outlen;
1257         int rc;
1258
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))
1263                 return;
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.
1267          */
1268         if (WARN_ON(MCDI_DWORD(outbuf, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) != ped->fw_id))
1269                 return;
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.
1272          */
1273         ped->fw_id = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL;
1274 }
1275
1276 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
1277 {
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);
1280         size_t outlen;
1281         int rc;
1282
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,
1289                               act->do_ttl_dec);
1290
1291         if (act->src_mac)
1292                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1293                                act->src_mac->fw_id);
1294         else
1295                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1296                                MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1297
1298         if (act->dst_mac)
1299                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1300                                act->dst_mac->fw_id);
1301         else
1302                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1303                                MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1304
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);
1308         else
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,
1315                                  act->vlan_tci[0]);
1316                 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1317                                  act->vlan_proto[0]);
1318         }
1319         if (act->vlan_push >= 2) {
1320                 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1321                                  act->vlan_tci[1]);
1322                 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1323                                  act->vlan_proto[1]);
1324         }
1325         if (act->encap_md)
1326                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
1327                                act->encap_md->fw_id);
1328         else
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);
1331         if (act->deliver)
1332                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER,
1333                                act->dest_mport);
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);
1337         if (rc)
1338                 return rc;
1339         if (outlen < sizeof(outbuf))
1340                 return -EIO;
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.
1344          */
1345         if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) {
1346                 efx_mae_free_action_set(efx, act->fw_id);
1347                 return -EIO;
1348         }
1349         return 0;
1350 }
1351
1352 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id)
1353 {
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));
1356         size_t outlen;
1357         int rc;
1358
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);
1362         if (rc)
1363                 return rc;
1364         if (outlen < sizeof(outbuf))
1365                 return -EIO;
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.
1369          */
1370         if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id))
1371                 return -EIO;
1372         return 0;
1373 }
1374
1375 int efx_mae_alloc_action_set_list(struct efx_nic *efx,
1376                                   struct efx_tc_action_set_list *acts)
1377 {
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;
1381         efx_dword_t *inbuf;
1382         int rc;
1383
1384         list_for_each_entry(act, &acts->list, list)
1385                 i++;
1386         if (i == 0)
1387                 return -EINVAL;
1388         if (i == 1) {
1389                 /* Don't wrap an ASL around a single AS, just use the AS_ID
1390                  * directly.  ASLs are a more limited resource.
1391                  */
1392                 act = list_first_entry(&acts->list, struct efx_tc_action_set, list);
1393                 acts->fw_id = act->fw_id;
1394                 return 0;
1395         }
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);
1400         if (!inbuf)
1401                 return -ENOMEM;
1402         i = 0;
1403         list_for_each_entry(act, &acts->list, list) {
1404                 MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS,
1405                                      i, act->fw_id);
1406                 i++;
1407         }
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);
1411         if (rc)
1412                 goto out_free;
1413         if (outlen < sizeof(outbuf)) {
1414                 rc = -EIO;
1415                 goto out_free;
1416         }
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.
1420          */
1421         if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) {
1422                 efx_mae_free_action_set_list(efx, acts);
1423                 rc = -EIO;
1424         }
1425 out_free:
1426         kfree(inbuf);
1427         return rc;
1428 }
1429
1430 int efx_mae_free_action_set_list(struct efx_nic *efx,
1431                                  struct efx_tc_action_set_list *acts)
1432 {
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));
1435         size_t outlen;
1436         int rc;
1437
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.)
1440          */
1441         if (efx_mae_asl_id(acts->fw_id)) {
1442                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID,
1443                                acts->fw_id);
1444                 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf,
1445                                   sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
1446                 if (rc)
1447                         return rc;
1448                 if (outlen < sizeof(outbuf))
1449                         return -EIO;
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.
1453                  */
1454                 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id))
1455                         return -EIO;
1456         }
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.
1459          */
1460         acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL;
1461         return 0;
1462 }
1463
1464 int efx_mae_register_encap_match(struct efx_nic *efx,
1465                                  struct efx_tc_encap_match *encap)
1466 {
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);
1470         size_t outlen;
1471         int rc;
1472
1473         rc = efx_mae_encap_type_to_mae_type(encap->tun_type);
1474         if (rc < 0)
1475                 return rc;
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
1479          * ipproto == udp.
1480          */
1481         MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, rc);
1482 #ifdef CONFIG_IPV6
1483         if (encap->src_ip | encap->dst_ip) {
1484 #endif
1485                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE,
1486                                          encap->src_ip);
1487                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK,
1488                                          ~(__be32)0);
1489                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE,
1490                                          encap->dst_ip);
1491                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK,
1492                                          ~(__be32)0);
1493                 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE,
1494                                         htons(ETH_P_IP));
1495 #ifdef CONFIG_IPV6
1496         } else {
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,
1506                                         htons(ETH_P_IPV6));
1507         }
1508 #endif
1509         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK,
1510                                 ~(__be16)0);
1511         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE,
1512                                 encap->udp_dport);
1513         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK,
1514                                 ~(__be16)0);
1515         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE,
1516                                 encap->udp_sport);
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,
1522                              encap->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);
1527         if (rc)
1528                 return rc;
1529         if (outlen < sizeof(outbuf))
1530                 return -EIO;
1531         encap->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1532         return 0;
1533 }
1534
1535 int efx_mae_unregister_encap_match(struct efx_nic *efx,
1536                                    struct efx_tc_encap_match *encap)
1537 {
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));
1540         size_t outlen;
1541         int rc;
1542
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);
1546         if (rc)
1547                 return rc;
1548         if (outlen < sizeof(outbuf))
1549                 return -EIO;
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.
1553          */
1554         if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != encap->fw_id))
1555                 return -EIO;
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.
1558          */
1559         encap->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL;
1560         return 0;
1561 }
1562
1563 static int efx_mae_populate_lhs_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
1564                                                const struct efx_tc_match *match)
1565 {
1566         if (match->mask.ingress_port) {
1567                 if (~match->mask.ingress_port)
1568                         return -EOPNOTSUPP;
1569                 MCDI_STRUCT_SET_DWORD(match_crit,
1570                                       MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR,
1571                                       match->value.ingress_port);
1572         }
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);
1631 #ifdef CONFIG_IPV6
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));
1640 #endif
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).
1653          */
1654         if (WARN_ON_ONCE(match->encap && !match->encap->type))
1655                 return -EOPNOTSUPP;
1656         if (WARN_ON_ONCE(match->mask.enc_src_ip))
1657                 return -EOPNOTSUPP;
1658         if (WARN_ON_ONCE(match->mask.enc_dst_ip))
1659                 return -EOPNOTSUPP;
1660 #ifdef CONFIG_IPV6
1661         if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)))
1662                 return -EOPNOTSUPP;
1663         if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)))
1664                 return -EOPNOTSUPP;
1665 #endif
1666         if (WARN_ON_ONCE(match->mask.enc_ip_tos))
1667                 return -EOPNOTSUPP;
1668         if (WARN_ON_ONCE(match->mask.enc_ip_ttl))
1669                 return -EOPNOTSUPP;
1670         if (WARN_ON_ONCE(match->mask.enc_sport))
1671                 return -EOPNOTSUPP;
1672         if (WARN_ON_ONCE(match->mask.enc_dport))
1673                 return -EOPNOTSUPP;
1674         if (WARN_ON_ONCE(match->mask.enc_keyid))
1675                 return -EOPNOTSUPP;
1676         return 0;
1677 }
1678
1679 static int efx_mae_insert_lhs_outer_rule(struct efx_nic *efx,
1680                                          struct efx_tc_lhs_rule *rule, u32 prio)
1681 {
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;
1686         size_t outlen;
1687         int rc;
1688
1689         MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_PRIO, prio);
1690         /* match */
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);
1693         if (rc)
1694                 return rc;
1695
1696         /* action */
1697         act = &rule->lhs_act;
1698         rc = efx_mae_encap_type_to_mae_type(act->tun_type);
1699         if (rc < 0)
1700                 return rc;
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).
1705          */
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);
1716         if (act->count)
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);
1721         if (rc)
1722                 return rc;
1723         if (outlen < sizeof(outbuf))
1724                 return -EIO;
1725         rule->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1726         return 0;
1727 }
1728
1729 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
1730                                            const struct efx_tc_match *match);
1731
1732 static int efx_mae_insert_lhs_action_rule(struct efx_nic *efx,
1733                                           struct efx_tc_lhs_rule *rule,
1734                                           u32 prio)
1735 {
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);
1741         size_t outlen;
1742         int rc;
1743
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);
1765         if (rc)
1766                 return rc;
1767
1768         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf),
1769                           outbuf, sizeof(outbuf), &outlen);
1770         if (rc)
1771                 return rc;
1772         if (outlen < sizeof(outbuf))
1773                 return -EIO;
1774         rule->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1775         return 0;
1776 }
1777
1778 int efx_mae_insert_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule,
1779                             u32 prio)
1780 {
1781         if (rule->is_ar)
1782                 return efx_mae_insert_lhs_action_rule(efx, rule, prio);
1783         return efx_mae_insert_lhs_outer_rule(efx, rule, prio);
1784 }
1785
1786 static int efx_mae_remove_lhs_outer_rule(struct efx_nic *efx,
1787                                          struct efx_tc_lhs_rule *rule)
1788 {
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));
1791         size_t outlen;
1792         int rc;
1793
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);
1797         if (rc)
1798                 return rc;
1799         if (outlen < sizeof(outbuf))
1800                 return -EIO;
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.
1804          */
1805         if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != rule->fw_id))
1806                 return -EIO;
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.
1809          */
1810         rule->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL;
1811         return 0;
1812 }
1813
1814 int efx_mae_remove_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule)
1815 {
1816         if (rule->is_ar)
1817                 return efx_mae_delete_rule(efx, rule->fw_id);
1818         return efx_mae_remove_lhs_outer_rule(efx, rule);
1819 }
1820
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.
1824  */
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)
1828 {
1829         unsigned int i;
1830
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).
1834          */
1835         if (field.scheme)
1836                 return -EOPNOTSUPP;
1837         if (DIV_ROUND_UP(field.width, 8) != value_size)
1838                 return -EINVAL;
1839         if (field.lbn + field.width > row_bits)
1840                 return -EINVAL;
1841         for (i = 0; i < value_size; i++) {
1842                 unsigned int bn = field.lbn + i * 8;
1843                 unsigned int wn = bn / 32;
1844                 u64 v;
1845
1846                 v = ((u8 *)value)[value_size - i - 1];
1847                 v <<= (bn % 32);
1848                 row[wn] |= cpu_to_le32(v & 0xffffffff);
1849                 if (wn * 32 < row_bits)
1850                         row[wn + 1] |= cpu_to_le32(v >> 32);
1851         }
1852         return 0;
1853 }
1854
1855 static int efx_mae_table_populate_bool(struct efx_tc_table_field_fmt field,
1856                                        __le32 *row, size_t row_bits, bool value)
1857 {
1858         u8 v = value ? 1 : 0;
1859
1860         if (field.width != 1)
1861                 return -EINVAL;
1862         return efx_mae_table_populate(field, row, row_bits, &v, 1);
1863 }
1864
1865 static int efx_mae_table_populate_ipv4(struct efx_tc_table_field_fmt field,
1866                                        __le32 *row, size_t row_bits, __be32 value)
1867 {
1868         /* IPv4 is placed in the first 4 bytes of an IPv6-sized field */
1869         struct in6_addr v = {};
1870
1871         if (field.width != 128)
1872                 return -EINVAL;
1873         v.s6_addr32[0] = value;
1874         return efx_mae_table_populate(field, row, row_bits, &v, sizeof(v));
1875 }
1876
1877 static int efx_mae_table_populate_u24(struct efx_tc_table_field_fmt field,
1878                                       __le32 *row, size_t row_bits, u32 value)
1879 {
1880         __be32 v = cpu_to_be32(value);
1881
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.
1885          */
1886         return efx_mae_table_populate(field, row, row_bits, ((void *)&v) + 1,
1887                                       sizeof(v) - 1);
1888 }
1889
1890 #define _TABLE_POPULATE(dst, dw, _field, _value) ({     \
1891         typeof(_value) _v = _value;                     \
1892                                                         \
1893         (_field.width == sizeof(_value) * 8) ?          \
1894          efx_mae_table_populate(_field, dst, dw, &_v,   \
1895                                 sizeof(_v)) : -EINVAL;  \
1896 })
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,\
1901                                     _value)
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],     \
1906                         _value)
1907
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,\
1912                                     _value)
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],    \
1917                         _value)
1918
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,\
1923                                    _value)
1924
1925 static int efx_mae_populate_ct_key(struct efx_nic *efx, __le32 *key, size_t kw,
1926                                    struct efx_tc_ct_entry *conn)
1927 {
1928         bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6);
1929         int rc;
1930
1931         rc = TABLE_POPULATE_KEY(key, ct, eth_proto, conn->eth_proto);
1932         if (rc)
1933                 return rc;
1934         rc = TABLE_POPULATE_KEY(key, ct, ip_proto, conn->ip_proto);
1935         if (rc)
1936                 return rc;
1937         if (ipv6)
1938                 rc = TABLE_POPULATE_KEY(key, ct, src_ip, conn->src_ip6);
1939         else
1940                 rc = TABLE_POPULATE_KEY_IPV4(key, ct, src_ip, conn->src_ip);
1941         if (rc)
1942                 return rc;
1943         if (ipv6)
1944                 rc = TABLE_POPULATE_KEY(key, ct, dst_ip, conn->dst_ip6);
1945         else
1946                 rc = TABLE_POPULATE_KEY_IPV4(key, ct, dst_ip, conn->dst_ip);
1947         if (rc)
1948                 return rc;
1949         rc = TABLE_POPULATE_KEY(key, ct, l4_sport, conn->l4_sport);
1950         if (rc)
1951                 return rc;
1952         rc = TABLE_POPULATE_KEY(key, ct, l4_dport, conn->l4_dport);
1953         if (rc)
1954                 return rc;
1955         return TABLE_POPULATE_KEY(key, ct, zone, cpu_to_be16(conn->zone->zone));
1956 }
1957
1958 int efx_mae_insert_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
1959 {
1960         bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6);
1961         __le32 *key = NULL, *resp = NULL;
1962         size_t inlen, kw, rw;
1963         efx_dword_t *inbuf;
1964         int rc = -ENOMEM;
1965
1966         /* Check table access is supported */
1967         if (!efx->tc->meta_ct.hooked)
1968                 return -EOPNOTSUPP;
1969
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)
1976                 return -E2BIG;
1977         inbuf = kzalloc(inlen, GFP_KERNEL);
1978         if (!inbuf)
1979                 return -ENOMEM;
1980
1981         key = kcalloc(kw, sizeof(__le32), GFP_KERNEL);
1982         if (!key)
1983                 goto out_free;
1984         resp = kcalloc(rw, sizeof(__le32), GFP_KERNEL);
1985         if (!resp)
1986                 goto out_free;
1987
1988         rc = efx_mae_populate_ct_key(efx, key, kw, conn);
1989         if (rc)
1990                 goto out_free;
1991
1992         rc = TABLE_POPULATE_RESP_BOOL(resp, ct, dnat, conn->dnat);
1993         if (rc)
1994                 goto out_free;
1995         /* No support in hw for IPv6 NAT; field is only 32 bits */
1996         if (!ipv6)
1997                 rc = TABLE_POPULATE_RESP(resp, ct, nat_ip, conn->nat_ip);
1998         if (rc)
1999                 goto out_free;
2000         rc = TABLE_POPULATE_RESP(resp, ct, l4_natport, conn->l4_natport);
2001         if (rc)
2002                 goto out_free;
2003         rc = TABLE_POPULATE_RESP(resp, ct, mark, cpu_to_be32(conn->mark));
2004         if (rc)
2005                 goto out_free;
2006         rc = TABLE_POPULATE_RESP_U24(resp, ct, counter_id, conn->cnt->fw_id);
2007         if (rc)
2008                 goto out_free;
2009
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));
2019
2020         BUILD_BUG_ON(MC_CMD_TABLE_INSERT_OUT_LEN);
2021
2022         rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_INSERT, inbuf, inlen, NULL, 0, NULL);
2023
2024 out_free:
2025         kfree(resp);
2026         kfree(key);
2027         kfree(inbuf);
2028         return rc;
2029 }
2030
2031 int efx_mae_remove_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
2032 {
2033         __le32 *key = NULL;
2034         efx_dword_t *inbuf;
2035         size_t inlen, kw;
2036         int rc = -ENOMEM;
2037
2038         /* Check table access is supported */
2039         if (!efx->tc->meta_ct.hooked)
2040                 return -EOPNOTSUPP;
2041
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)
2047                 return -E2BIG;
2048         inbuf = kzalloc(inlen, GFP_KERNEL);
2049         if (!inbuf)
2050                 return -ENOMEM;
2051
2052         key = kcalloc(kw, sizeof(__le32), GFP_KERNEL);
2053         if (!key)
2054                 goto out_free;
2055
2056         rc = efx_mae_populate_ct_key(efx, key, kw, conn);
2057         if (rc)
2058                 goto out_free;
2059
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));
2066
2067         BUILD_BUG_ON(MC_CMD_TABLE_DELETE_OUT_LEN);
2068
2069         rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_DELETE, inbuf, inlen, NULL, 0, NULL);
2070
2071 out_free:
2072         kfree(key);
2073         kfree(inbuf);
2074         return rc;
2075 }
2076
2077 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
2078                                            const struct efx_tc_match *match)
2079 {
2080         if (match->mask.ingress_port) {
2081                 if (~match->mask.ingress_port)
2082                         return -EOPNOTSUPP;
2083                 MCDI_STRUCT_SET_DWORD(match_crit,
2084                                       MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR,
2085                                       match->value.ingress_port);
2086         }
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);
2171 #ifdef CONFIG_IPV6
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));
2180 #endif
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 */
2194         if (match->encap) {
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,
2198                                       U32_MAX);
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 */
2214                 return -EOPNOTSUPP;
2215         }
2216         return 0;
2217 }
2218
2219 int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
2220                         u32 prio, u32 acts_id, u32 *id)
2221 {
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);
2226         size_t outlen;
2227         int rc;
2228
2229         if (!id)
2230                 return -EINVAL;
2231
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);
2238         } else {
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);
2243         }
2244         MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio);
2245         rc = efx_mae_populate_match_criteria(match_crit, match);
2246         if (rc)
2247                 return rc;
2248
2249         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf),
2250                           outbuf, sizeof(outbuf), &outlen);
2251         if (rc)
2252                 return rc;
2253         if (outlen < sizeof(outbuf))
2254                 return -EIO;
2255         *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2256         return 0;
2257 }
2258
2259 int efx_mae_update_rule(struct efx_nic *efx, u32 acts_id, u32 id)
2260 {
2261         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_UPDATE_IN_LEN);
2262         MCDI_DECLARE_STRUCT_PTR(response);
2263
2264         BUILD_BUG_ON(MC_CMD_MAE_ACTION_RULE_UPDATE_OUT_LEN);
2265         response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_RESPONSE);
2266
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);
2272         } else {
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);
2277         }
2278         return efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_UPDATE, inbuf, sizeof(inbuf),
2279                             NULL, 0, NULL);
2280 }
2281
2282 int efx_mae_delete_rule(struct efx_nic *efx, u32 id)
2283 {
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));
2286         size_t outlen;
2287         int rc;
2288
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);
2292         if (rc)
2293                 return rc;
2294         if (outlen < sizeof(outbuf))
2295                 return -EIO;
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.
2299          */
2300         if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id))
2301                 return -EIO;
2302         return 0;
2303 }
2304
2305 int efx_init_mae(struct efx_nic *efx)
2306 {
2307         struct ef100_nic_data *nic_data = efx->nic_data;
2308         struct efx_mae *mae;
2309         int rc;
2310
2311         if (!nic_data->have_mport)
2312                 return -EINVAL;
2313
2314         mae = kmalloc(sizeof(*mae), GFP_KERNEL);
2315         if (!mae)
2316                 return -ENOMEM;
2317
2318         rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params);
2319         if (rc < 0) {
2320                 kfree(mae);
2321                 return rc;
2322         }
2323         efx->mae = mae;
2324         mae->efx = efx;
2325         return 0;
2326 }
2327
2328 void efx_fini_mae(struct efx_nic *efx)
2329 {
2330         struct efx_mae *mae = efx->mae;
2331
2332         kfree(mae);
2333         efx->mae = NULL;
2334 }
This page took 0.164519 seconds and 4 git commands to generate.