GNU Linux-libre 6.8.9-gnu
[releases.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 void efx_mae_mport_vf(struct efx_nic *efx __always_unused, u32 vf_id, u32 *out)
80 {
81         efx_dword_t mport;
82
83         EFX_POPULATE_DWORD_3(mport,
84                              MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_FUNC,
85                              MAE_MPORT_SELECTOR_FUNC_PF_ID, MAE_MPORT_SELECTOR_FUNC_PF_ID_CALLER,
86                              MAE_MPORT_SELECTOR_FUNC_VF_ID, vf_id);
87         *out = EFX_DWORD_VAL(mport);
88 }
89
90 /* Constructs an mport selector from an mport ID, because they're not the same */
91 void efx_mae_mport_mport(struct efx_nic *efx __always_unused, u32 mport_id, u32 *out)
92 {
93         efx_dword_t mport;
94
95         EFX_POPULATE_DWORD_2(mport,
96                              MAE_MPORT_SELECTOR_TYPE, MAE_MPORT_SELECTOR_TYPE_MPORT_ID,
97                              MAE_MPORT_SELECTOR_MPORT_ID, mport_id);
98         *out = EFX_DWORD_VAL(mport);
99 }
100
101 /* id is really only 24 bits wide */
102 int efx_mae_fw_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
103 {
104         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MPORT_LOOKUP_OUT_LEN);
105         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_LOOKUP_IN_LEN);
106         size_t outlen;
107         int rc;
108
109         MCDI_SET_DWORD(inbuf, MAE_MPORT_LOOKUP_IN_MPORT_SELECTOR, selector);
110         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_LOOKUP, inbuf, sizeof(inbuf),
111                           outbuf, sizeof(outbuf), &outlen);
112         if (rc)
113                 return rc;
114         if (outlen < sizeof(outbuf))
115                 return -EIO;
116         *id = MCDI_DWORD(outbuf, MAE_MPORT_LOOKUP_OUT_MPORT_ID);
117         return 0;
118 }
119
120 int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
121 {
122         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_START_V2_IN_LEN);
123         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
124         u32 out_flags;
125         size_t outlen;
126         int rc;
127
128         MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_QID,
129                       efx_rx_queue_index(rx_queue));
130         MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_PACKET_SIZE,
131                       efx->net_dev->mtu);
132         MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_COUNTER_TYPES_MASK,
133                        BIT(MAE_COUNTER_TYPE_AR) | BIT(MAE_COUNTER_TYPE_CT) |
134                        BIT(MAE_COUNTER_TYPE_OR));
135         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_START,
136                           inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
137         if (rc)
138                 return rc;
139         if (outlen < sizeof(outbuf))
140                 return -EIO;
141         out_flags = MCDI_DWORD(outbuf, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
142         if (out_flags & BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST)) {
143                 netif_dbg(efx, drv, efx->net_dev,
144                           "MAE counter stream uses credits\n");
145                 rx_queue->grant_credits = true;
146                 out_flags &= ~BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST);
147         }
148         if (out_flags) {
149                 netif_err(efx, drv, efx->net_dev,
150                           "MAE counter stream start: unrecognised flags %x\n",
151                           out_flags);
152                 goto out_stop;
153         }
154         return 0;
155 out_stop:
156         efx_mae_stop_counters(efx, rx_queue);
157         return -EOPNOTSUPP;
158 }
159
160 static bool efx_mae_counters_flushed(u32 *flush_gen, u32 *seen_gen)
161 {
162         int i;
163
164         for (i = 0; i < EFX_TC_COUNTER_TYPE_MAX; i++)
165                 if ((s32)(flush_gen[i] - seen_gen[i]) > 0)
166                         return false;
167         return true;
168 }
169
170 int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
171 {
172         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_V2_OUT_LENMAX);
173         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN);
174         size_t outlen;
175         int rc, i;
176
177         MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_STOP_IN_QID,
178                       efx_rx_queue_index(rx_queue));
179         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_STOP,
180                           inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
181
182         if (rc)
183                 return rc;
184
185         netif_dbg(efx, drv, efx->net_dev, "Draining counters:\n");
186         /* Only process received generation counts */
187         for (i = 0; (i < (outlen / 4)) && (i < EFX_TC_COUNTER_TYPE_MAX); i++) {
188                 efx->tc->flush_gen[i] = MCDI_ARRAY_DWORD(outbuf,
189                                                          MAE_COUNTERS_STREAM_STOP_V2_OUT_GENERATION_COUNT,
190                                                          i);
191                 netif_dbg(efx, drv, efx->net_dev,
192                           "\ttype %u, awaiting gen %u\n", i,
193                           efx->tc->flush_gen[i]);
194         }
195
196         efx->tc->flush_counters = true;
197
198         /* Drain can take up to 2 seconds owing to FWRIVERHD-2884; whatever
199          * timeout we use, that delay is added to unload on nonresponsive
200          * hardware, so 2500ms seems like a reasonable compromise.
201          */
202         if (!wait_event_timeout(efx->tc->flush_wq,
203                                 efx_mae_counters_flushed(efx->tc->flush_gen,
204                                                          efx->tc->seen_gen),
205                                 msecs_to_jiffies(2500)))
206                 netif_warn(efx, drv, efx->net_dev,
207                            "Failed to drain counters RXQ, FW may be unhappy\n");
208
209         efx->tc->flush_counters = false;
210
211         return rc;
212 }
213
214 void efx_mae_counters_grant_credits(struct work_struct *work)
215 {
216         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN);
217         struct efx_rx_queue *rx_queue = container_of(work, struct efx_rx_queue,
218                                                      grant_work);
219         struct efx_nic *efx = rx_queue->efx;
220         unsigned int credits;
221
222         BUILD_BUG_ON(MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
223         credits = READ_ONCE(rx_queue->notified_count) - rx_queue->granted_count;
224         MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
225                        credits);
226         if (!efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS,
227                           inbuf, sizeof(inbuf), NULL, 0, NULL))
228                 rx_queue->granted_count += credits;
229 }
230
231 static int efx_mae_table_get_desc(struct efx_nic *efx,
232                                   struct efx_tc_table_desc *desc,
233                                   u32 table_id)
234 {
235         MCDI_DECLARE_BUF(outbuf, MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(16));
236         MCDI_DECLARE_BUF(inbuf, MC_CMD_TABLE_DESCRIPTOR_IN_LEN);
237         unsigned int offset = 0, i;
238         size_t outlen;
239         int rc;
240
241         memset(desc, 0, sizeof(*desc));
242
243         MCDI_SET_DWORD(inbuf, TABLE_DESCRIPTOR_IN_TABLE_ID, table_id);
244 more:
245         MCDI_SET_DWORD(inbuf, TABLE_DESCRIPTOR_IN_FIRST_FIELDS_INDEX, offset);
246         rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_DESCRIPTOR, inbuf, sizeof(inbuf),
247                           outbuf, sizeof(outbuf), &outlen);
248         if (rc)
249                 goto fail;
250         if (outlen < MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(1)) {
251                 rc = -EIO;
252                 goto fail;
253         }
254         if (!offset) { /* first iteration: get metadata */
255                 desc->type = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_TYPE);
256                 desc->key_width = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_KEY_WIDTH);
257                 desc->resp_width = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_RESP_WIDTH);
258                 desc->n_keys = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_KEY_FIELDS);
259                 desc->n_resps = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_RESP_FIELDS);
260                 desc->n_prios = MCDI_WORD(outbuf, TABLE_DESCRIPTOR_OUT_N_PRIORITIES);
261                 desc->flags = MCDI_BYTE(outbuf, TABLE_DESCRIPTOR_OUT_FLAGS);
262                 rc = -EOPNOTSUPP;
263                 if (desc->flags)
264                         goto fail;
265                 desc->scheme = MCDI_BYTE(outbuf, TABLE_DESCRIPTOR_OUT_SCHEME);
266                 if (desc->scheme)
267                         goto fail;
268                 rc = -ENOMEM;
269                 desc->keys = kcalloc(desc->n_keys,
270                                      sizeof(struct efx_tc_table_field_fmt),
271                                      GFP_KERNEL);
272                 if (!desc->keys)
273                         goto fail;
274                 desc->resps = kcalloc(desc->n_resps,
275                                       sizeof(struct efx_tc_table_field_fmt),
276                                       GFP_KERNEL);
277                 if (!desc->resps)
278                         goto fail;
279         }
280         /* FW could have returned more than the 16 field_descrs we
281          * made room for in our outbuf
282          */
283         outlen = min(outlen, sizeof(outbuf));
284         for (i = 0; i + offset < desc->n_keys + desc->n_resps; i++) {
285                 struct efx_tc_table_field_fmt *field;
286                 MCDI_DECLARE_STRUCT_PTR(fdesc);
287
288                 if (outlen < MC_CMD_TABLE_DESCRIPTOR_OUT_LEN(i + 1)) {
289                         offset += i;
290                         goto more;
291                 }
292                 if (i + offset < desc->n_keys)
293                         field = desc->keys + i + offset;
294                 else
295                         field = desc->resps + (i + offset - desc->n_keys);
296                 fdesc = MCDI_ARRAY_STRUCT_PTR(outbuf,
297                                               TABLE_DESCRIPTOR_OUT_FIELDS, i);
298                 field->field_id = MCDI_STRUCT_WORD(fdesc,
299                                                    TABLE_FIELD_DESCR_FIELD_ID);
300                 field->lbn = MCDI_STRUCT_WORD(fdesc, TABLE_FIELD_DESCR_LBN);
301                 field->width = MCDI_STRUCT_WORD(fdesc, TABLE_FIELD_DESCR_WIDTH);
302                 field->masking = MCDI_STRUCT_BYTE(fdesc, TABLE_FIELD_DESCR_MASK_TYPE);
303                 field->scheme = MCDI_STRUCT_BYTE(fdesc, TABLE_FIELD_DESCR_SCHEME);
304         }
305         return 0;
306
307 fail:
308         kfree(desc->keys);
309         kfree(desc->resps);
310         return rc;
311 }
312
313 static int efx_mae_table_hook_find(u16 n_fields,
314                                    struct efx_tc_table_field_fmt *fields,
315                                    u16 field_id)
316 {
317         unsigned int i;
318
319         for (i = 0; i < n_fields; i++) {
320                 if (fields[i].field_id == field_id)
321                         return i;
322         }
323         return -EPROTO;
324 }
325
326 #define TABLE_FIND_KEY(_desc, _id)      \
327         efx_mae_table_hook_find((_desc)->n_keys, (_desc)->keys, _id)
328 #define TABLE_FIND_RESP(_desc, _id)     \
329         efx_mae_table_hook_find((_desc)->n_resps, (_desc)->resps, _id)
330
331 #define TABLE_HOOK_KEY(_meta, _name, _mcdi_name)        ({                      \
332         int _rc = TABLE_FIND_KEY(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name);    \
333                                                                                 \
334         if (_rc > U8_MAX)                                                       \
335                 _rc = -EOPNOTSUPP;                                              \
336         if (_rc >= 0) {                                                         \
337                 _meta->keys._name##_idx = _rc;                                  \
338                 _rc = 0;                                                        \
339         }                                                                       \
340         _rc;                                                                    \
341 })
342 #define TABLE_HOOK_RESP(_meta, _name, _mcdi_name)       ({                      \
343         int _rc = TABLE_FIND_RESP(&_meta->desc, TABLE_FIELD_ID_##_mcdi_name);   \
344                                                                                 \
345         if (_rc > U8_MAX)                                                       \
346                 _rc = -EOPNOTSUPP;                                              \
347         if (_rc >= 0) {                                                         \
348                 _meta->resps._name##_idx = _rc;                                 \
349                 _rc = 0;                                                        \
350         }                                                                       \
351         _rc;                                                                    \
352 })
353
354 static int efx_mae_table_hook_ct(struct efx_nic *efx,
355                                  struct efx_tc_table_ct *meta_ct)
356 {
357         int rc;
358
359         rc = TABLE_HOOK_KEY(meta_ct, eth_proto, ETHER_TYPE);
360         if (rc)
361                 return rc;
362         rc = TABLE_HOOK_KEY(meta_ct, ip_proto, IP_PROTO);
363         if (rc)
364                 return rc;
365         rc = TABLE_HOOK_KEY(meta_ct, src_ip, SRC_IP);
366         if (rc)
367                 return rc;
368         rc = TABLE_HOOK_KEY(meta_ct, dst_ip, DST_IP);
369         if (rc)
370                 return rc;
371         rc = TABLE_HOOK_KEY(meta_ct, l4_sport, SRC_PORT);
372         if (rc)
373                 return rc;
374         rc = TABLE_HOOK_KEY(meta_ct, l4_dport, DST_PORT);
375         if (rc)
376                 return rc;
377         rc = TABLE_HOOK_KEY(meta_ct, zone, DOMAIN);
378         if (rc)
379                 return rc;
380         rc = TABLE_HOOK_RESP(meta_ct, dnat, NAT_DIR);
381         if (rc)
382                 return rc;
383         rc = TABLE_HOOK_RESP(meta_ct, nat_ip, NAT_IP);
384         if (rc)
385                 return rc;
386         rc = TABLE_HOOK_RESP(meta_ct, l4_natport, NAT_PORT);
387         if (rc)
388                 return rc;
389         rc = TABLE_HOOK_RESP(meta_ct, mark, CT_MARK);
390         if (rc)
391                 return rc;
392         rc = TABLE_HOOK_RESP(meta_ct, counter_id, COUNTER_ID);
393         if (rc)
394                 return rc;
395         meta_ct->hooked = true;
396         return 0;
397 }
398
399 static void efx_mae_table_free_desc(struct efx_tc_table_desc *desc)
400 {
401         kfree(desc->keys);
402         kfree(desc->resps);
403         memset(desc, 0, sizeof(*desc));
404 }
405
406 static bool efx_mae_check_table_exists(struct efx_nic *efx, u32 tbl_req)
407 {
408         MCDI_DECLARE_BUF(outbuf, MC_CMD_TABLE_LIST_OUT_LEN(16));
409         MCDI_DECLARE_BUF(inbuf, MC_CMD_TABLE_LIST_IN_LEN);
410         u32 tbl_id, tbl_total, tbl_cnt, pos = 0;
411         size_t outlen, msg_max;
412         bool ct_tbl = false;
413         int rc, idx;
414
415         msg_max = sizeof(outbuf);
416         efx->tc->meta_ct.hooked = false;
417 more:
418         memset(outbuf, 0, sizeof(*outbuf));
419         MCDI_SET_DWORD(inbuf, TABLE_LIST_IN_FIRST_TABLE_ID_INDEX, pos);
420         rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_LIST, inbuf, sizeof(inbuf), outbuf,
421                           msg_max, &outlen);
422         if (rc)
423                 return false;
424
425         if (outlen < MC_CMD_TABLE_LIST_OUT_LEN(1))
426                 return false;
427
428         tbl_total = MCDI_DWORD(outbuf, TABLE_LIST_OUT_N_TABLES);
429         tbl_cnt = MC_CMD_TABLE_LIST_OUT_TABLE_ID_NUM(min(outlen, msg_max));
430
431         for (idx = 0; idx < tbl_cnt; idx++) {
432                 tbl_id = MCDI_ARRAY_DWORD(outbuf, TABLE_LIST_OUT_TABLE_ID, idx);
433                 if (tbl_id == tbl_req) {
434                         ct_tbl = true;
435                         break;
436                 }
437         }
438
439         pos += tbl_cnt;
440         if (!ct_tbl && pos < tbl_total)
441                 goto more;
442
443         return ct_tbl;
444 }
445
446 int efx_mae_get_tables(struct efx_nic *efx)
447 {
448         int rc;
449
450         efx->tc->meta_ct.hooked = false;
451         if (efx_mae_check_table_exists(efx, TABLE_ID_CONNTRACK_TABLE)) {
452                 rc = efx_mae_table_get_desc(efx, &efx->tc->meta_ct.desc,
453                                             TABLE_ID_CONNTRACK_TABLE);
454                 if (rc) {
455                         pci_info(efx->pci_dev,
456                                  "FW does not support conntrack desc rc %d\n",
457                                  rc);
458                         return 0;
459                 }
460
461                 rc = efx_mae_table_hook_ct(efx, &efx->tc->meta_ct);
462                 if (rc) {
463                         pci_info(efx->pci_dev,
464                                  "FW does not support conntrack hook rc %d\n",
465                                  rc);
466                         return 0;
467                 }
468         } else {
469                 pci_info(efx->pci_dev,
470                          "FW does not support conntrack table\n");
471         }
472         return 0;
473 }
474
475 void efx_mae_free_tables(struct efx_nic *efx)
476 {
477         efx_mae_table_free_desc(&efx->tc->meta_ct.desc);
478         efx->tc->meta_ct.hooked = false;
479 }
480
481 static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)
482 {
483         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN);
484         size_t outlen;
485         int rc;
486
487         BUILD_BUG_ON(MC_CMD_MAE_GET_CAPS_IN_LEN);
488
489         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_GET_CAPS, NULL, 0, outbuf,
490                           sizeof(outbuf), &outlen);
491         if (rc)
492                 return rc;
493         if (outlen < sizeof(outbuf))
494                 return -EIO;
495         caps->match_field_count = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_MATCH_FIELD_COUNT);
496         caps->encap_types = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ENCAP_TYPES_SUPPORTED);
497         caps->action_prios = MCDI_DWORD(outbuf, MAE_GET_CAPS_OUT_ACTION_PRIOS);
498         return 0;
499 }
500
501 static int efx_mae_get_rule_fields(struct efx_nic *efx, u32 cmd,
502                                    u8 *field_support)
503 {
504         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS));
505         MCDI_DECLARE_STRUCT_PTR(caps);
506         unsigned int count;
507         size_t outlen;
508         int rc, i;
509
510         /* AR and OR caps MCDIs have identical layout, so we are using the
511          * same code for both.
512          */
513         BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_LEN(MAE_NUM_FIELDS) <
514                      MC_CMD_MAE_GET_OR_CAPS_OUT_LEN(MAE_NUM_FIELDS));
515         BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_IN_LEN);
516         BUILD_BUG_ON(MC_CMD_MAE_GET_OR_CAPS_IN_LEN);
517
518         rc = efx_mcdi_rpc(efx, cmd, NULL, 0, outbuf, sizeof(outbuf), &outlen);
519         if (rc)
520                 return rc;
521         BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_COUNT_OFST !=
522                      MC_CMD_MAE_GET_OR_CAPS_OUT_COUNT_OFST);
523         count = MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_COUNT);
524         memset(field_support, MAE_FIELD_UNSUPPORTED, MAE_NUM_FIELDS);
525         BUILD_BUG_ON(MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST !=
526                      MC_CMD_MAE_GET_OR_CAPS_OUT_FIELD_FLAGS_OFST);
527         caps = _MCDI_DWORD(outbuf, MAE_GET_AR_CAPS_OUT_FIELD_FLAGS);
528         /* We're only interested in the support status enum, not any other
529          * flags, so just extract that from each entry.
530          */
531         for (i = 0; i < count; i++)
532                 if (i * sizeof(*outbuf) + MC_CMD_MAE_GET_AR_CAPS_OUT_FIELD_FLAGS_OFST < outlen)
533                         field_support[i] = EFX_DWORD_FIELD(caps[i], MAE_FIELD_FLAGS_SUPPORT_STATUS);
534         return 0;
535 }
536
537 int efx_mae_get_caps(struct efx_nic *efx, struct mae_caps *caps)
538 {
539         int rc;
540
541         rc = efx_mae_get_basic_caps(efx, caps);
542         if (rc)
543                 return rc;
544         rc = efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_AR_CAPS,
545                                      caps->action_rule_fields);
546         if (rc)
547                 return rc;
548         return efx_mae_get_rule_fields(efx, MC_CMD_MAE_GET_OR_CAPS,
549                                        caps->outer_rule_fields);
550 }
551
552 /* Bit twiddling:
553  * Prefix: 1...110...0
554  *      ~: 0...001...1
555  *    + 1: 0...010...0 is power of two
556  * so (~x) & ((~x) + 1) == 0.  Converse holds also.
557  */
558 #define is_prefix_byte(_x)      !(((_x) ^ 0xff) & (((_x) ^ 0xff) + 1))
559
560 enum mask_type { MASK_ONES, MASK_ZEROES, MASK_PREFIX, MASK_OTHER };
561
562 static const char *mask_type_name(enum mask_type typ)
563 {
564         switch (typ) {
565         case MASK_ONES:
566                 return "all-1s";
567         case MASK_ZEROES:
568                 return "all-0s";
569         case MASK_PREFIX:
570                 return "prefix";
571         case MASK_OTHER:
572                 return "arbitrary";
573         default: /* can't happen */
574                 return "unknown";
575         }
576 }
577
578 /* Checks a (big-endian) bytestring is a bit prefix */
579 static enum mask_type classify_mask(const u8 *mask, size_t len)
580 {
581         bool zeroes = true; /* All bits seen so far are zeroes */
582         bool ones = true; /* All bits seen so far are ones */
583         bool prefix = true; /* Valid prefix so far */
584         size_t i;
585
586         for (i = 0; i < len; i++) {
587                 if (ones) {
588                         if (!is_prefix_byte(mask[i]))
589                                 prefix = false;
590                 } else if (mask[i]) {
591                         prefix = false;
592                 }
593                 if (mask[i] != 0xff)
594                         ones = false;
595                 if (mask[i])
596                         zeroes = false;
597         }
598         if (ones)
599                 return MASK_ONES;
600         if (zeroes)
601                 return MASK_ZEROES;
602         if (prefix)
603                 return MASK_PREFIX;
604         return MASK_OTHER;
605 }
606
607 static int efx_mae_match_check_cap_typ(u8 support, enum mask_type typ)
608 {
609         switch (support) {
610         case MAE_FIELD_UNSUPPORTED:
611         case MAE_FIELD_SUPPORTED_MATCH_NEVER:
612                 if (typ == MASK_ZEROES)
613                         return 0;
614                 return -EOPNOTSUPP;
615         case MAE_FIELD_SUPPORTED_MATCH_OPTIONAL:
616                 if (typ == MASK_ZEROES)
617                         return 0;
618                 fallthrough;
619         case MAE_FIELD_SUPPORTED_MATCH_ALWAYS:
620                 if (typ == MASK_ONES)
621                         return 0;
622                 return -EINVAL;
623         case MAE_FIELD_SUPPORTED_MATCH_PREFIX:
624                 if (typ == MASK_OTHER)
625                         return -EOPNOTSUPP;
626                 return 0;
627         case MAE_FIELD_SUPPORTED_MATCH_MASK:
628                 return 0;
629         default:
630                 return -EIO;
631         }
632 }
633
634 /* Validate field mask against hardware capabilities.  Captures caller's 'rc' */
635 #define CHECK(_mcdi, _field)    ({                                             \
636         enum mask_type typ = classify_mask((const u8 *)&mask->_field,          \
637                                            sizeof(mask->_field));              \
638                                                                                \
639         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
640                                          typ);                                 \
641         if (rc)                                                                \
642                 NL_SET_ERR_MSG_FMT_MOD(extack,                                 \
643                                        "No support for %s mask in field %s",   \
644                                        mask_type_name(typ), #_field);          \
645         rc;                                                                    \
646 })
647 /* Booleans need special handling */
648 #define CHECK_BIT(_mcdi, _field)        ({                                     \
649         enum mask_type typ = mask->_field ? MASK_ONES : MASK_ZEROES;           \
650                                                                                \
651         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
652                                          typ);                                 \
653         if (rc)                                                                \
654                 NL_SET_ERR_MSG_FMT_MOD(extack,                                 \
655                                        "No support for %s mask in field %s",   \
656                                        mask_type_name(typ), #_field);          \
657         rc;                                                                    \
658 })
659
660 int efx_mae_match_check_caps(struct efx_nic *efx,
661                              const struct efx_tc_match_fields *mask,
662                              struct netlink_ext_ack *extack)
663 {
664         const u8 *supported_fields = efx->tc->caps->action_rule_fields;
665         __be32 ingress_port = cpu_to_be32(mask->ingress_port);
666         enum mask_type ingress_port_mask_type;
667         int rc;
668
669         /* Check for _PREFIX assumes big-endian, so we need to convert */
670         ingress_port_mask_type = classify_mask((const u8 *)&ingress_port,
671                                                sizeof(ingress_port));
672         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT],
673                                          ingress_port_mask_type);
674         if (rc) {
675                 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field ingress_port",
676                                        mask_type_name(ingress_port_mask_type));
677                 return rc;
678         }
679         if (CHECK(ETHER_TYPE, eth_proto) ||
680             CHECK(VLAN0_TCI, vlan_tci[0]) ||
681             CHECK(VLAN0_PROTO, vlan_proto[0]) ||
682             CHECK(VLAN1_TCI, vlan_tci[1]) ||
683             CHECK(VLAN1_PROTO, vlan_proto[1]) ||
684             CHECK(ETH_SADDR, eth_saddr) ||
685             CHECK(ETH_DADDR, eth_daddr) ||
686             CHECK(IP_PROTO, ip_proto) ||
687             CHECK(IP_TOS, ip_tos) ||
688             CHECK(IP_TTL, ip_ttl) ||
689             CHECK(SRC_IP4, src_ip) ||
690             CHECK(DST_IP4, dst_ip) ||
691 #ifdef CONFIG_IPV6
692             CHECK(SRC_IP6, src_ip6) ||
693             CHECK(DST_IP6, dst_ip6) ||
694 #endif
695             CHECK(L4_SPORT, l4_sport) ||
696             CHECK(L4_DPORT, l4_dport) ||
697             CHECK(TCP_FLAGS, tcp_flags) ||
698             CHECK_BIT(TCP_SYN_FIN_RST, tcp_syn_fin_rst) ||
699             CHECK_BIT(IS_IP_FRAG, ip_frag) ||
700             CHECK_BIT(IP_FIRST_FRAG, ip_firstfrag) ||
701             CHECK_BIT(DO_CT, ct_state_trk) ||
702             CHECK_BIT(CT_HIT, ct_state_est) ||
703             CHECK(CT_MARK, ct_mark) ||
704             CHECK(CT_DOMAIN, ct_zone) ||
705             CHECK(RECIRC_ID, recirc_id))
706                 return rc;
707         /* Matches on outer fields are done in a separate hardware table,
708          * the Outer Rule table.  Thus the Action Rule merely does an
709          * exact match on Outer Rule ID if any outer field matches are
710          * present.  The exception is the VNI/VSID (enc_keyid), which is
711          * available to the Action Rule match iff the Outer Rule matched
712          * (and thus identified the encap protocol to use to extract it).
713          */
714         if (efx_tc_match_is_encap(mask)) {
715                 rc = efx_mae_match_check_cap_typ(
716                                 supported_fields[MAE_FIELD_OUTER_RULE_ID],
717                                 MASK_ONES);
718                 if (rc) {
719                         NL_SET_ERR_MSG_MOD(extack, "No support for encap rule ID matches");
720                         return rc;
721                 }
722                 if (CHECK(ENC_VNET_ID, enc_keyid))
723                         return rc;
724         } else if (mask->enc_keyid) {
725                 NL_SET_ERR_MSG_MOD(extack, "Match on enc_keyid requires other encap fields");
726                 return -EINVAL;
727         }
728         return 0;
729 }
730
731 /* Checks for match fields not supported in LHS Outer Rules */
732 #define UNSUPPORTED(_field)     ({                                             \
733         enum mask_type typ = classify_mask((const u8 *)&mask->_field,          \
734                                            sizeof(mask->_field));              \
735                                                                                \
736         if (typ != MASK_ZEROES) {                                              \
737                 NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\
738                 rc = -EOPNOTSUPP;                                              \
739         }                                                                      \
740         rc;                                                                    \
741 })
742 #define UNSUPPORTED_BIT(_field) ({                                             \
743         if (mask->_field) {                                                    \
744                 NL_SET_ERR_MSG_MOD(extack, "Unsupported match field " #_field);\
745                 rc = -EOPNOTSUPP;                                              \
746         }                                                                      \
747         rc;                                                                    \
748 })
749
750 /* LHS rules are (normally) inserted in the Outer Rule table, which means
751  * they use ENC_ fields in hardware to match regular (not enc_) fields from
752  * &struct efx_tc_match_fields.
753  */
754 int efx_mae_match_check_caps_lhs(struct efx_nic *efx,
755                                  const struct efx_tc_match_fields *mask,
756                                  struct netlink_ext_ack *extack)
757 {
758         const u8 *supported_fields = efx->tc->caps->outer_rule_fields;
759         __be32 ingress_port = cpu_to_be32(mask->ingress_port);
760         enum mask_type ingress_port_mask_type;
761         int rc;
762
763         /* Check for _PREFIX assumes big-endian, so we need to convert */
764         ingress_port_mask_type = classify_mask((const u8 *)&ingress_port,
765                                                sizeof(ingress_port));
766         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_INGRESS_PORT],
767                                          ingress_port_mask_type);
768         if (rc) {
769                 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s\n",
770                                        mask_type_name(ingress_port_mask_type),
771                                        "ingress_port");
772                 return rc;
773         }
774         if (CHECK(ENC_ETHER_TYPE, eth_proto) ||
775             CHECK(ENC_VLAN0_TCI, vlan_tci[0]) ||
776             CHECK(ENC_VLAN0_PROTO, vlan_proto[0]) ||
777             CHECK(ENC_VLAN1_TCI, vlan_tci[1]) ||
778             CHECK(ENC_VLAN1_PROTO, vlan_proto[1]) ||
779             CHECK(ENC_ETH_SADDR, eth_saddr) ||
780             CHECK(ENC_ETH_DADDR, eth_daddr) ||
781             CHECK(ENC_IP_PROTO, ip_proto) ||
782             CHECK(ENC_IP_TOS, ip_tos) ||
783             CHECK(ENC_IP_TTL, ip_ttl) ||
784             CHECK_BIT(ENC_IP_FRAG, ip_frag) ||
785             UNSUPPORTED_BIT(ip_firstfrag) ||
786             CHECK(ENC_SRC_IP4, src_ip) ||
787             CHECK(ENC_DST_IP4, dst_ip) ||
788 #ifdef CONFIG_IPV6
789             CHECK(ENC_SRC_IP6, src_ip6) ||
790             CHECK(ENC_DST_IP6, dst_ip6) ||
791 #endif
792             CHECK(ENC_L4_SPORT, l4_sport) ||
793             CHECK(ENC_L4_DPORT, l4_dport) ||
794             UNSUPPORTED(tcp_flags) ||
795             CHECK_BIT(TCP_SYN_FIN_RST, tcp_syn_fin_rst))
796                 return rc;
797         if (efx_tc_match_is_encap(mask)) {
798                 /* can't happen; disallowed for local rules, translated
799                  * for foreign rules.
800                  */
801                 NL_SET_ERR_MSG_MOD(extack, "Unexpected encap match in LHS rule");
802                 return -EOPNOTSUPP;
803         }
804         if (UNSUPPORTED(enc_keyid) ||
805             /* Can't filter on conntrack in LHS rules */
806             UNSUPPORTED_BIT(ct_state_trk) ||
807             UNSUPPORTED_BIT(ct_state_est) ||
808             UNSUPPORTED(ct_mark) ||
809             UNSUPPORTED(recirc_id))
810                 return rc;
811         return 0;
812 }
813 #undef UNSUPPORTED
814 #undef CHECK_BIT
815 #undef CHECK
816
817 #define CHECK(_mcdi)    ({                                                     \
818         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ ## _mcdi],\
819                                          MASK_ONES);                           \
820         if (rc)                                                                \
821                 NL_SET_ERR_MSG_FMT_MOD(extack,                                 \
822                                        "No support for field %s", #_mcdi);     \
823         rc;                                                                    \
824 })
825 /* Checks that the fields needed for encap-rule matches are supported by the
826  * MAE.  All the fields are exact-match, except possibly ENC_IP_TOS.
827  */
828 int efx_mae_check_encap_match_caps(struct efx_nic *efx, bool ipv6,
829                                    u8 ip_tos_mask, __be16 udp_sport_mask,
830                                    struct netlink_ext_ack *extack)
831 {
832         u8 *supported_fields = efx->tc->caps->outer_rule_fields;
833         enum mask_type typ;
834         int rc;
835
836         if (CHECK(ENC_ETHER_TYPE))
837                 return rc;
838         if (ipv6) {
839                 if (CHECK(ENC_SRC_IP6) ||
840                     CHECK(ENC_DST_IP6))
841                         return rc;
842         } else {
843                 if (CHECK(ENC_SRC_IP4) ||
844                     CHECK(ENC_DST_IP4))
845                         return rc;
846         }
847         if (CHECK(ENC_L4_DPORT) ||
848             CHECK(ENC_IP_PROTO))
849                 return rc;
850         typ = classify_mask((const u8 *)&udp_sport_mask, sizeof(udp_sport_mask));
851         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_L4_SPORT],
852                                          typ);
853         if (rc) {
854                 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s",
855                                        mask_type_name(typ), "enc_src_port");
856                 return rc;
857         }
858         typ = classify_mask(&ip_tos_mask, sizeof(ip_tos_mask));
859         rc = efx_mae_match_check_cap_typ(supported_fields[MAE_FIELD_ENC_IP_TOS],
860                                          typ);
861         if (rc) {
862                 NL_SET_ERR_MSG_FMT_MOD(extack, "No support for %s mask in field %s",
863                                        mask_type_name(typ), "enc_ip_tos");
864                 return rc;
865         }
866         return 0;
867 }
868 #undef CHECK
869
870 int efx_mae_check_encap_type_supported(struct efx_nic *efx, enum efx_encap_type typ)
871 {
872         unsigned int bit;
873
874         switch (typ & EFX_ENCAP_TYPES_MASK) {
875         case EFX_ENCAP_TYPE_VXLAN:
876                 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_VXLAN_LBN;
877                 break;
878         case EFX_ENCAP_TYPE_GENEVE:
879                 bit = MC_CMD_MAE_GET_CAPS_OUT_ENCAP_TYPE_GENEVE_LBN;
880                 break;
881         default:
882                 return -EOPNOTSUPP;
883         }
884         if (efx->tc->caps->encap_types & BIT(bit))
885                 return 0;
886         return -EOPNOTSUPP;
887 }
888
889 int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
890 {
891         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1));
892         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN);
893         size_t outlen;
894         int rc;
895
896         if (!cnt)
897                 return -EINVAL;
898
899         MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT, 1);
900         MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE, cnt->type);
901         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_ALLOC, inbuf, sizeof(inbuf),
902                           outbuf, sizeof(outbuf), &outlen);
903         if (rc)
904                 return rc;
905         /* pcol says this can't happen, since count is 1 */
906         if (outlen < sizeof(outbuf))
907                 return -EIO;
908         cnt->fw_id = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_COUNTER_ID);
909         cnt->gen = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
910         return 0;
911 }
912
913 int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
914 {
915         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_FREE_OUT_LEN(1));
916         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN);
917         size_t outlen;
918         int rc;
919
920         MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT, 1);
921         MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID, cnt->fw_id);
922         MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE, cnt->type);
923         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_FREE, inbuf, sizeof(inbuf),
924                           outbuf, sizeof(outbuf), &outlen);
925         if (rc)
926                 return rc;
927         /* pcol says this can't happen, since count is 1 */
928         if (outlen < sizeof(outbuf))
929                 return -EIO;
930         /* FW freed a different ID than we asked for, should also never happen.
931          * Warn because it means we've now got a different idea to the FW of
932          * what counters exist, which could cause mayhem later.
933          */
934         if (WARN_ON(MCDI_DWORD(outbuf, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID) !=
935                     cnt->fw_id))
936                 return -EIO;
937         return 0;
938 }
939
940 static int efx_mae_encap_type_to_mae_type(enum efx_encap_type type)
941 {
942         switch (type & EFX_ENCAP_TYPES_MASK) {
943         case EFX_ENCAP_TYPE_NONE:
944                 return MAE_MCDI_ENCAP_TYPE_NONE;
945         case EFX_ENCAP_TYPE_VXLAN:
946                 return MAE_MCDI_ENCAP_TYPE_VXLAN;
947         case EFX_ENCAP_TYPE_GENEVE:
948                 return MAE_MCDI_ENCAP_TYPE_GENEVE;
949         default:
950                 return -EOPNOTSUPP;
951         }
952 }
953
954 int efx_mae_allocate_encap_md(struct efx_nic *efx,
955                               struct efx_tc_encap_action *encap)
956 {
957         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(EFX_TC_MAX_ENCAP_HDR));
958         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_LEN);
959         size_t inlen, outlen;
960         int rc;
961
962         rc = efx_mae_encap_type_to_mae_type(encap->type);
963         if (rc < 0)
964                 return rc;
965         MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_ENCAP_TYPE, rc);
966         inlen = MC_CMD_MAE_ENCAP_HEADER_ALLOC_IN_LEN(encap->encap_hdr_len);
967         if (WARN_ON(inlen > sizeof(inbuf))) /* can't happen */
968                 return -EINVAL;
969         memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_ALLOC_IN_HDR_DATA),
970                encap->encap_hdr,
971                encap->encap_hdr_len);
972         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_ALLOC, inbuf,
973                           inlen, outbuf, sizeof(outbuf), &outlen);
974         if (rc)
975                 return rc;
976         if (outlen < sizeof(outbuf))
977                 return -EIO;
978         encap->fw_id = MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID);
979         return 0;
980 }
981
982 int efx_mae_update_encap_md(struct efx_nic *efx,
983                             struct efx_tc_encap_action *encap)
984 {
985         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(EFX_TC_MAX_ENCAP_HDR));
986         size_t inlen;
987         int rc;
988
989         rc = efx_mae_encap_type_to_mae_type(encap->type);
990         if (rc < 0)
991                 return rc;
992         MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_ENCAP_TYPE, rc);
993         MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_EH_ID,
994                        encap->fw_id);
995         inlen = MC_CMD_MAE_ENCAP_HEADER_UPDATE_IN_LEN(encap->encap_hdr_len);
996         if (WARN_ON(inlen > sizeof(inbuf))) /* can't happen */
997                 return -EINVAL;
998         memcpy(MCDI_PTR(inbuf, MAE_ENCAP_HEADER_UPDATE_IN_HDR_DATA),
999                encap->encap_hdr,
1000                encap->encap_hdr_len);
1001
1002         BUILD_BUG_ON(MC_CMD_MAE_ENCAP_HEADER_UPDATE_OUT_LEN != 0);
1003         return efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_UPDATE, inbuf,
1004                             inlen, NULL, 0, NULL);
1005 }
1006
1007 int efx_mae_free_encap_md(struct efx_nic *efx,
1008                           struct efx_tc_encap_action *encap)
1009 {
1010         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ENCAP_HEADER_FREE_OUT_LEN(1));
1011         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ENCAP_HEADER_FREE_IN_LEN(1));
1012         size_t outlen;
1013         int rc;
1014
1015         MCDI_SET_DWORD(inbuf, MAE_ENCAP_HEADER_FREE_IN_EH_ID, encap->fw_id);
1016         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ENCAP_HEADER_FREE, inbuf,
1017                           sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
1018         if (rc)
1019                 return rc;
1020         if (outlen < sizeof(outbuf))
1021                 return -EIO;
1022         /* FW freed a different ID than we asked for, should also never happen.
1023          * Warn because it means we've now got a different idea to the FW of
1024          * what encap_mds exist, which could cause mayhem later.
1025          */
1026         if (WARN_ON(MCDI_DWORD(outbuf, MAE_ENCAP_HEADER_FREE_OUT_FREED_EH_ID) != encap->fw_id))
1027                 return -EIO;
1028         /* We're probably about to free @encap, but let's just make sure its
1029          * fw_id is blatted so that it won't look valid if it leaks out.
1030          */
1031         encap->fw_id = MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL;
1032         return 0;
1033 }
1034
1035 int efx_mae_lookup_mport(struct efx_nic *efx, u32 vf_idx, u32 *id)
1036 {
1037         struct ef100_nic_data *nic_data = efx->nic_data;
1038         struct efx_mae *mae = efx->mae;
1039         struct rhashtable_iter walk;
1040         struct mae_mport_desc *m;
1041         int rc = -ENOENT;
1042
1043         rhashtable_walk_enter(&mae->mports_ht, &walk);
1044         rhashtable_walk_start(&walk);
1045         while ((m = rhashtable_walk_next(&walk)) != NULL) {
1046                 if (m->mport_type == MAE_MPORT_DESC_MPORT_TYPE_VNIC &&
1047                     m->interface_idx == nic_data->local_mae_intf &&
1048                     m->pf_idx == 0 &&
1049                     m->vf_idx == vf_idx) {
1050                         *id = m->mport_id;
1051                         rc = 0;
1052                         break;
1053                 }
1054         }
1055         rhashtable_walk_stop(&walk);
1056         rhashtable_walk_exit(&walk);
1057         return rc;
1058 }
1059
1060 static bool efx_mae_asl_id(u32 id)
1061 {
1062         return !!(id & BIT(31));
1063 }
1064
1065 /* mport handling */
1066 static const struct rhashtable_params efx_mae_mports_ht_params = {
1067         .key_len        = sizeof(u32),
1068         .key_offset     = offsetof(struct mae_mport_desc, mport_id),
1069         .head_offset    = offsetof(struct mae_mport_desc, linkage),
1070 };
1071
1072 struct mae_mport_desc *efx_mae_get_mport(struct efx_nic *efx, u32 mport_id)
1073 {
1074         return rhashtable_lookup_fast(&efx->mae->mports_ht, &mport_id,
1075                                       efx_mae_mports_ht_params);
1076 }
1077
1078 static int efx_mae_add_mport(struct efx_nic *efx, struct mae_mport_desc *desc)
1079 {
1080         struct efx_mae *mae = efx->mae;
1081         int rc;
1082
1083         rc = rhashtable_insert_fast(&mae->mports_ht, &desc->linkage,
1084                                     efx_mae_mports_ht_params);
1085
1086         if (rc) {
1087                 pci_err(efx->pci_dev, "Failed to insert MPORT %08x, rc %d\n",
1088                         desc->mport_id, rc);
1089                 kfree(desc);
1090                 return rc;
1091         }
1092
1093         return rc;
1094 }
1095
1096 void efx_mae_remove_mport(void *desc, void *arg)
1097 {
1098         struct mae_mport_desc *mport = desc;
1099
1100         synchronize_rcu();
1101         kfree(mport);
1102 }
1103
1104 static int efx_mae_process_mport(struct efx_nic *efx,
1105                                  struct mae_mport_desc *desc)
1106 {
1107         struct ef100_nic_data *nic_data = efx->nic_data;
1108         struct mae_mport_desc *mport;
1109
1110         mport = efx_mae_get_mport(efx, desc->mport_id);
1111         if (!IS_ERR_OR_NULL(mport)) {
1112                 netif_err(efx, drv, efx->net_dev,
1113                           "mport with id %u does exist!!!\n", desc->mport_id);
1114                 return -EEXIST;
1115         }
1116
1117         if (nic_data->have_own_mport &&
1118             desc->mport_id == nic_data->own_mport) {
1119                 WARN_ON(desc->mport_type != MAE_MPORT_DESC_MPORT_TYPE_VNIC);
1120                 WARN_ON(desc->vnic_client_type !=
1121                         MAE_MPORT_DESC_VNIC_CLIENT_TYPE_FUNCTION);
1122                 nic_data->local_mae_intf = desc->interface_idx;
1123                 nic_data->have_local_intf = true;
1124                 pci_dbg(efx->pci_dev, "MAE interface_idx is %u\n",
1125                         nic_data->local_mae_intf);
1126         }
1127
1128         return efx_mae_add_mport(efx, desc);
1129 }
1130
1131 #define MCDI_MPORT_JOURNAL_LEN \
1132         ALIGN(MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LENMAX_MCDI2, 4)
1133
1134 int efx_mae_enumerate_mports(struct efx_nic *efx)
1135 {
1136         efx_dword_t *outbuf = kzalloc(MCDI_MPORT_JOURNAL_LEN, GFP_KERNEL);
1137         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_IN_LEN);
1138         MCDI_DECLARE_STRUCT_PTR(desc);
1139         size_t outlen, stride, count;
1140         int rc = 0, i;
1141
1142         if (!outbuf)
1143                 return -ENOMEM;
1144         do {
1145                 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MPORT_READ_JOURNAL, inbuf,
1146                                   sizeof(inbuf), outbuf,
1147                                   MCDI_MPORT_JOURNAL_LEN, &outlen);
1148                 if (rc)
1149                         goto fail;
1150                 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST) {
1151                         rc = -EIO;
1152                         goto fail;
1153                 }
1154                 count = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_COUNT);
1155                 if (!count)
1156                         continue; /* not break; we want to look at MORE flag */
1157                 stride = MCDI_DWORD(outbuf, MAE_MPORT_READ_JOURNAL_OUT_SIZEOF_MPORT_DESC);
1158                 if (stride < MAE_MPORT_DESC_LEN) {
1159                         rc = -EIO;
1160                         goto fail;
1161                 }
1162                 if (outlen < MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_LEN(count * stride)) {
1163                         rc = -EIO;
1164                         goto fail;
1165                 }
1166
1167                 for (i = 0; i < count; i++) {
1168                         struct mae_mport_desc *d;
1169
1170                         d = kzalloc(sizeof(*d), GFP_KERNEL);
1171                         if (!d) {
1172                                 rc = -ENOMEM;
1173                                 goto fail;
1174                         }
1175
1176                         desc = (efx_dword_t *)
1177                                 _MCDI_PTR(outbuf, MC_CMD_MAE_MPORT_READ_JOURNAL_OUT_MPORT_DESC_DATA_OFST +
1178                                           i * stride);
1179                         d->mport_id = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_MPORT_ID);
1180                         d->flags = MCDI_STRUCT_DWORD(desc, MAE_MPORT_DESC_FLAGS);
1181                         d->caller_flags = MCDI_STRUCT_DWORD(desc,
1182                                                             MAE_MPORT_DESC_CALLER_FLAGS);
1183                         d->mport_type = MCDI_STRUCT_DWORD(desc,
1184                                                           MAE_MPORT_DESC_MPORT_TYPE);
1185                         switch (d->mport_type) {
1186                         case MAE_MPORT_DESC_MPORT_TYPE_NET_PORT:
1187                                 d->port_idx = MCDI_STRUCT_DWORD(desc,
1188                                                                 MAE_MPORT_DESC_NET_PORT_IDX);
1189                                 break;
1190                         case MAE_MPORT_DESC_MPORT_TYPE_ALIAS:
1191                                 d->alias_mport_id = MCDI_STRUCT_DWORD(desc,
1192                                                                       MAE_MPORT_DESC_ALIAS_DELIVER_MPORT_ID);
1193                                 break;
1194                         case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
1195                                 d->vnic_client_type = MCDI_STRUCT_DWORD(desc,
1196                                                                         MAE_MPORT_DESC_VNIC_CLIENT_TYPE);
1197                                 d->interface_idx = MCDI_STRUCT_DWORD(desc,
1198                                                                      MAE_MPORT_DESC_VNIC_FUNCTION_INTERFACE);
1199                                 d->pf_idx = MCDI_STRUCT_WORD(desc,
1200                                                              MAE_MPORT_DESC_VNIC_FUNCTION_PF_IDX);
1201                                 d->vf_idx = MCDI_STRUCT_WORD(desc,
1202                                                              MAE_MPORT_DESC_VNIC_FUNCTION_VF_IDX);
1203                                 break;
1204                         default:
1205                                 /* Unknown mport_type, just accept it */
1206                                 break;
1207                         }
1208                         rc = efx_mae_process_mport(efx, d);
1209                         /* Any failure will be due to memory allocation faiure,
1210                          * so there is no point to try subsequent entries.
1211                          */
1212                         if (rc)
1213                                 goto fail;
1214                 }
1215         } while (MCDI_FIELD(outbuf, MAE_MPORT_READ_JOURNAL_OUT, MORE) &&
1216                  !WARN_ON(!count));
1217 fail:
1218         kfree(outbuf);
1219         return rc;
1220 }
1221
1222 /**
1223  * efx_mae_allocate_pedit_mac() - allocate pedit MAC address in HW.
1224  * @efx:        NIC we're installing a pedit MAC address on
1225  * @ped:        pedit MAC action to be installed
1226  *
1227  * Attempts to install @ped in HW and populates its id with an index of this
1228  * entry in the firmware MAC address table on success.
1229  *
1230  * Return: negative value on error, 0 in success.
1231  */
1232 int efx_mae_allocate_pedit_mac(struct efx_nic *efx,
1233                                struct efx_tc_mac_pedit_action *ped)
1234 {
1235         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_LEN);
1236         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MAC_ADDR_ALLOC_IN_LEN);
1237         size_t outlen;
1238         int rc;
1239
1240         BUILD_BUG_ON(MC_CMD_MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR_LEN !=
1241                      sizeof(ped->h_addr));
1242         memcpy(MCDI_PTR(inbuf, MAE_MAC_ADDR_ALLOC_IN_MAC_ADDR), ped->h_addr,
1243                sizeof(ped->h_addr));
1244         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MAC_ADDR_ALLOC, inbuf, sizeof(inbuf),
1245                           outbuf, sizeof(outbuf), &outlen);
1246         if (rc)
1247                 return rc;
1248         if (outlen < sizeof(outbuf))
1249                 return -EIO;
1250         ped->fw_id = MCDI_DWORD(outbuf, MAE_MAC_ADDR_ALLOC_OUT_MAC_ID);
1251         return 0;
1252 }
1253
1254 /**
1255  * efx_mae_free_pedit_mac() - free pedit MAC address in HW.
1256  * @efx:        NIC we're installing a pedit MAC address on
1257  * @ped:        pedit MAC action that needs to be freed
1258  *
1259  * Frees @ped in HW, check that firmware did not free a different one and clears
1260  * the id (which denotes the index of the entry in the MAC address table).
1261  */
1262 void efx_mae_free_pedit_mac(struct efx_nic *efx,
1263                             struct efx_tc_mac_pedit_action *ped)
1264 {
1265         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_MAC_ADDR_FREE_OUT_LEN(1));
1266         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_MAC_ADDR_FREE_IN_LEN(1));
1267         size_t outlen;
1268         int rc;
1269
1270         MCDI_SET_DWORD(inbuf, MAE_MAC_ADDR_FREE_IN_MAC_ID, ped->fw_id);
1271         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_MAC_ADDR_FREE, inbuf,
1272                           sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
1273         if (rc || outlen < sizeof(outbuf))
1274                 return;
1275         /* FW freed a different ID than we asked for, should also never happen.
1276          * Warn because it means we've now got a different idea to the FW of
1277          * what MAC addresses exist, which could cause mayhem later.
1278          */
1279         if (WARN_ON(MCDI_DWORD(outbuf, MAE_MAC_ADDR_FREE_OUT_FREED_MAC_ID) != ped->fw_id))
1280                 return;
1281         /* We're probably about to free @ped, but let's just make sure its
1282          * fw_id is blatted so that it won't look valid if it leaks out.
1283          */
1284         ped->fw_id = MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL;
1285 }
1286
1287 int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
1288 {
1289         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_ALLOC_OUT_LEN);
1290         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_ALLOC_IN_LEN);
1291         size_t outlen;
1292         int rc;
1293
1294         MCDI_POPULATE_DWORD_5(inbuf, MAE_ACTION_SET_ALLOC_IN_FLAGS,
1295                               MAE_ACTION_SET_ALLOC_IN_VLAN_PUSH, act->vlan_push,
1296                               MAE_ACTION_SET_ALLOC_IN_VLAN_POP, act->vlan_pop,
1297                               MAE_ACTION_SET_ALLOC_IN_DECAP, act->decap,
1298                               MAE_ACTION_SET_ALLOC_IN_DO_NAT, act->do_nat,
1299                               MAE_ACTION_SET_ALLOC_IN_DO_DECR_IP_TTL,
1300                               act->do_ttl_dec);
1301
1302         if (act->src_mac)
1303                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1304                                act->src_mac->fw_id);
1305         else
1306                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_SRC_MAC_ID,
1307                                MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1308
1309         if (act->dst_mac)
1310                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1311                                act->dst_mac->fw_id);
1312         else
1313                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
1314                                MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
1315
1316         if (act->count && !WARN_ON(!act->count->cnt))
1317                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
1318                                act->count->cnt->fw_id);
1319         else
1320                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
1321                                MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1322         MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID,
1323                        MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL);
1324         if (act->vlan_push) {
1325                 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_TCI_BE,
1326                                  act->vlan_tci[0]);
1327                 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN0_PROTO_BE,
1328                                  act->vlan_proto[0]);
1329         }
1330         if (act->vlan_push >= 2) {
1331                 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_TCI_BE,
1332                                  act->vlan_tci[1]);
1333                 MCDI_SET_WORD_BE(inbuf, MAE_ACTION_SET_ALLOC_IN_VLAN1_PROTO_BE,
1334                                  act->vlan_proto[1]);
1335         }
1336         if (act->encap_md)
1337                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
1338                                act->encap_md->fw_id);
1339         else
1340                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,
1341                                MC_CMD_MAE_ENCAP_HEADER_ALLOC_OUT_ENCAP_HEADER_ID_NULL);
1342         if (act->deliver)
1343                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DELIVER,
1344                                act->dest_mport);
1345         BUILD_BUG_ON(MAE_MPORT_SELECTOR_NULL);
1346         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_ALLOC, inbuf, sizeof(inbuf),
1347                           outbuf, sizeof(outbuf), &outlen);
1348         if (rc)
1349                 return rc;
1350         if (outlen < sizeof(outbuf))
1351                 return -EIO;
1352         act->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_ALLOC_OUT_AS_ID);
1353         /* We rely on the high bit of AS IDs always being clear.
1354          * The firmware API guarantees this, but let's check it ourselves.
1355          */
1356         if (WARN_ON_ONCE(efx_mae_asl_id(act->fw_id))) {
1357                 efx_mae_free_action_set(efx, act->fw_id);
1358                 return -EIO;
1359         }
1360         return 0;
1361 }
1362
1363 int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id)
1364 {
1365         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_FREE_OUT_LEN(1));
1366         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_FREE_IN_LEN(1));
1367         size_t outlen;
1368         int rc;
1369
1370         MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_FREE_IN_AS_ID, fw_id);
1371         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_FREE, inbuf, sizeof(inbuf),
1372                           outbuf, sizeof(outbuf), &outlen);
1373         if (rc)
1374                 return rc;
1375         if (outlen < sizeof(outbuf))
1376                 return -EIO;
1377         /* FW freed a different ID than we asked for, should never happen.
1378          * Warn because it means we've now got a different idea to the FW of
1379          * what action-sets exist, which could cause mayhem later.
1380          */
1381         if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_FREE_OUT_FREED_AS_ID) != fw_id))
1382                 return -EIO;
1383         return 0;
1384 }
1385
1386 int efx_mae_alloc_action_set_list(struct efx_nic *efx,
1387                                   struct efx_tc_action_set_list *acts)
1388 {
1389         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_LEN);
1390         struct efx_tc_action_set *act;
1391         size_t inlen, outlen, i = 0;
1392         efx_dword_t *inbuf;
1393         int rc;
1394
1395         list_for_each_entry(act, &acts->list, list)
1396                 i++;
1397         if (i == 0)
1398                 return -EINVAL;
1399         if (i == 1) {
1400                 /* Don't wrap an ASL around a single AS, just use the AS_ID
1401                  * directly.  ASLs are a more limited resource.
1402                  */
1403                 act = list_first_entry(&acts->list, struct efx_tc_action_set, list);
1404                 acts->fw_id = act->fw_id;
1405                 return 0;
1406         }
1407         if (i > MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS_MAXNUM_MCDI2)
1408                 return -EOPNOTSUPP; /* Too many actions */
1409         inlen = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_IN_LEN(i);
1410         inbuf = kzalloc(inlen, GFP_KERNEL);
1411         if (!inbuf)
1412                 return -ENOMEM;
1413         i = 0;
1414         list_for_each_entry(act, &acts->list, list) {
1415                 MCDI_SET_ARRAY_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_AS_IDS,
1416                                      i, act->fw_id);
1417                 i++;
1418         }
1419         MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_ALLOC_IN_COUNT, i);
1420         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_ALLOC, inbuf, inlen,
1421                           outbuf, sizeof(outbuf), &outlen);
1422         if (rc)
1423                 goto out_free;
1424         if (outlen < sizeof(outbuf)) {
1425                 rc = -EIO;
1426                 goto out_free;
1427         }
1428         acts->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_ALLOC_OUT_ASL_ID);
1429         /* We rely on the high bit of ASL IDs always being set.
1430          * The firmware API guarantees this, but let's check it ourselves.
1431          */
1432         if (WARN_ON_ONCE(!efx_mae_asl_id(acts->fw_id))) {
1433                 efx_mae_free_action_set_list(efx, acts);
1434                 rc = -EIO;
1435         }
1436 out_free:
1437         kfree(inbuf);
1438         return rc;
1439 }
1440
1441 int efx_mae_free_action_set_list(struct efx_nic *efx,
1442                                  struct efx_tc_action_set_list *acts)
1443 {
1444         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_OUT_LEN(1));
1445         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_SET_LIST_FREE_IN_LEN(1));
1446         size_t outlen;
1447         int rc;
1448
1449         /* If this is just an AS_ID with no ASL wrapper, then there is
1450          * nothing for us to free.  (The AS will be freed later.)
1451          */
1452         if (efx_mae_asl_id(acts->fw_id)) {
1453                 MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_LIST_FREE_IN_ASL_ID,
1454                                acts->fw_id);
1455                 rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_SET_LIST_FREE, inbuf,
1456                                   sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
1457                 if (rc)
1458                         return rc;
1459                 if (outlen < sizeof(outbuf))
1460                         return -EIO;
1461                 /* FW freed a different ID than we asked for, should never happen.
1462                  * Warn because it means we've now got a different idea to the FW of
1463                  * what action-set-lists exist, which could cause mayhem later.
1464                  */
1465                 if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_SET_LIST_FREE_OUT_FREED_ASL_ID) != acts->fw_id))
1466                         return -EIO;
1467         }
1468         /* We're probably about to free @acts, but let's just make sure its
1469          * fw_id is blatted so that it won't look valid if it leaks out.
1470          */
1471         acts->fw_id = MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL;
1472         return 0;
1473 }
1474
1475 int efx_mae_register_encap_match(struct efx_nic *efx,
1476                                  struct efx_tc_encap_match *encap)
1477 {
1478         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN));
1479         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1480         MCDI_DECLARE_STRUCT_PTR(match_crit);
1481         size_t outlen;
1482         int rc;
1483
1484         rc = efx_mae_encap_type_to_mae_type(encap->tun_type);
1485         if (rc < 0)
1486                 return rc;
1487         match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA);
1488         /* The struct contains IP src and dst, and udp dport.
1489          * So we actually need to filter on IP src and dst, L4 dport, and
1490          * ipproto == udp.
1491          */
1492         MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, rc);
1493 #ifdef CONFIG_IPV6
1494         if (encap->src_ip | encap->dst_ip) {
1495 #endif
1496                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE,
1497                                          encap->src_ip);
1498                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK,
1499                                          ~(__be32)0);
1500                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE,
1501                                          encap->dst_ip);
1502                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK,
1503                                          ~(__be32)0);
1504                 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE,
1505                                         htons(ETH_P_IP));
1506 #ifdef CONFIG_IPV6
1507         } else {
1508                 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE),
1509                        &encap->src_ip6, sizeof(encap->src_ip6));
1510                 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK),
1511                        0xff, sizeof(encap->src_ip6));
1512                 memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE),
1513                        &encap->dst_ip6, sizeof(encap->dst_ip6));
1514                 memset(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK),
1515                        0xff, sizeof(encap->dst_ip6));
1516                 MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE,
1517                                         htons(ETH_P_IPV6));
1518         }
1519 #endif
1520         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK,
1521                                 ~(__be16)0);
1522         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE,
1523                                 encap->udp_dport);
1524         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK,
1525                                 ~(__be16)0);
1526         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE,
1527                                 encap->udp_sport);
1528         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK,
1529                                 encap->udp_sport_mask);
1530         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO, IPPROTO_UDP);
1531         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK, ~0);
1532         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS,
1533                              encap->ip_tos);
1534         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK,
1535                              encap->ip_tos_mask);
1536         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf,
1537                           sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
1538         if (rc)
1539                 return rc;
1540         if (outlen < sizeof(outbuf))
1541                 return -EIO;
1542         encap->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1543         return 0;
1544 }
1545
1546 int efx_mae_unregister_encap_match(struct efx_nic *efx,
1547                                    struct efx_tc_encap_match *encap)
1548 {
1549         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1550         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1));
1551         size_t outlen;
1552         int rc;
1553
1554         MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, encap->fw_id);
1555         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf,
1556                           sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
1557         if (rc)
1558                 return rc;
1559         if (outlen < sizeof(outbuf))
1560                 return -EIO;
1561         /* FW freed a different ID than we asked for, should also never happen.
1562          * Warn because it means we've now got a different idea to the FW of
1563          * what encap_mds exist, which could cause mayhem later.
1564          */
1565         if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != encap->fw_id))
1566                 return -EIO;
1567         /* We're probably about to free @encap, but let's just make sure its
1568          * fw_id is blatted so that it won't look valid if it leaks out.
1569          */
1570         encap->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL;
1571         return 0;
1572 }
1573
1574 static int efx_mae_populate_lhs_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
1575                                                const struct efx_tc_match *match)
1576 {
1577         if (match->mask.ingress_port) {
1578                 if (~match->mask.ingress_port)
1579                         return -EOPNOTSUPP;
1580                 MCDI_STRUCT_SET_DWORD(match_crit,
1581                                       MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR,
1582                                       match->value.ingress_port);
1583         }
1584         MCDI_STRUCT_SET_DWORD(match_crit, MAE_ENC_FIELD_PAIRS_INGRESS_MPORT_SELECTOR_MASK,
1585                               match->mask.ingress_port);
1586         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE,
1587                                 match->value.eth_proto);
1588         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETHER_TYPE_BE_MASK,
1589                                 match->mask.eth_proto);
1590         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE,
1591                                 match->value.vlan_tci[0]);
1592         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_TCI_BE_MASK,
1593                                 match->mask.vlan_tci[0]);
1594         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE,
1595                                 match->value.vlan_proto[0]);
1596         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN0_PROTO_BE_MASK,
1597                                 match->mask.vlan_proto[0]);
1598         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE,
1599                                 match->value.vlan_tci[1]);
1600         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_TCI_BE_MASK,
1601                                 match->mask.vlan_tci[1]);
1602         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE,
1603                                 match->value.vlan_proto[1]);
1604         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_VLAN1_PROTO_BE_MASK,
1605                                 match->mask.vlan_proto[1]);
1606         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE),
1607                match->value.eth_saddr, ETH_ALEN);
1608         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_SADDR_BE_MASK),
1609                match->mask.eth_saddr, ETH_ALEN);
1610         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE),
1611                match->value.eth_daddr, ETH_ALEN);
1612         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_ETH_DADDR_BE_MASK),
1613                match->mask.eth_daddr, ETH_ALEN);
1614         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO,
1615                              match->value.ip_proto);
1616         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_PROTO_MASK,
1617                              match->mask.ip_proto);
1618         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS,
1619                              match->value.ip_tos);
1620         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TOS_MASK,
1621                              match->mask.ip_tos);
1622         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL,
1623                              match->value.ip_ttl);
1624         MCDI_STRUCT_SET_BYTE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_IP_TTL_MASK,
1625                              match->mask.ip_ttl);
1626         MCDI_STRUCT_POPULATE_BYTE_1(match_crit,
1627                                     MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS,
1628                                     MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG,
1629                                     match->value.ip_frag);
1630         MCDI_STRUCT_POPULATE_BYTE_1(match_crit,
1631                                     MAE_ENC_FIELD_PAIRS_ENC_VLAN_FLAGS_MASK,
1632                                     MAE_ENC_FIELD_PAIRS_ENC_IP_FRAG_MASK,
1633                                     match->mask.ip_frag);
1634         MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE,
1635                                  match->value.src_ip);
1636         MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP4_BE_MASK,
1637                                  match->mask.src_ip);
1638         MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE,
1639                                  match->value.dst_ip);
1640         MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP4_BE_MASK,
1641                                  match->mask.dst_ip);
1642 #ifdef CONFIG_IPV6
1643         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE),
1644                &match->value.src_ip6, sizeof(struct in6_addr));
1645         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_SRC_IP6_BE_MASK),
1646                &match->mask.src_ip6, sizeof(struct in6_addr));
1647         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE),
1648                &match->value.dst_ip6, sizeof(struct in6_addr));
1649         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_ENC_FIELD_PAIRS_ENC_DST_IP6_BE_MASK),
1650                &match->mask.dst_ip6, sizeof(struct in6_addr));
1651 #endif
1652         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE,
1653                                 match->value.l4_sport);
1654         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_SPORT_BE_MASK,
1655                                 match->mask.l4_sport);
1656         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE,
1657                                 match->value.l4_dport);
1658         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_ENC_FIELD_PAIRS_ENC_L4_DPORT_BE_MASK,
1659                                 match->mask.l4_dport);
1660         /* No enc-keys in LHS rules.  Caps check should have caught this; any
1661          * enc-keys from an fLHS should have been translated to regular keys
1662          * and any EM should be a pseudo (we're an OR so can't have a direct
1663          * EM with another OR).
1664          */
1665         if (WARN_ON_ONCE(match->encap && !match->encap->type))
1666                 return -EOPNOTSUPP;
1667         if (WARN_ON_ONCE(match->mask.enc_src_ip))
1668                 return -EOPNOTSUPP;
1669         if (WARN_ON_ONCE(match->mask.enc_dst_ip))
1670                 return -EOPNOTSUPP;
1671 #ifdef CONFIG_IPV6
1672         if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)))
1673                 return -EOPNOTSUPP;
1674         if (WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)))
1675                 return -EOPNOTSUPP;
1676 #endif
1677         if (WARN_ON_ONCE(match->mask.enc_ip_tos))
1678                 return -EOPNOTSUPP;
1679         if (WARN_ON_ONCE(match->mask.enc_ip_ttl))
1680                 return -EOPNOTSUPP;
1681         if (WARN_ON_ONCE(match->mask.enc_sport))
1682                 return -EOPNOTSUPP;
1683         if (WARN_ON_ONCE(match->mask.enc_dport))
1684                 return -EOPNOTSUPP;
1685         if (WARN_ON_ONCE(match->mask.enc_keyid))
1686                 return -EOPNOTSUPP;
1687         return 0;
1688 }
1689
1690 static int efx_mae_insert_lhs_outer_rule(struct efx_nic *efx,
1691                                          struct efx_tc_lhs_rule *rule, u32 prio)
1692 {
1693         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_INSERT_IN_LEN(MAE_ENC_FIELD_PAIRS_LEN));
1694         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_INSERT_OUT_LEN);
1695         MCDI_DECLARE_STRUCT_PTR(match_crit);
1696         const struct efx_tc_lhs_action *act;
1697         size_t outlen;
1698         int rc;
1699
1700         MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_PRIO, prio);
1701         /* match */
1702         match_crit = _MCDI_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_FIELD_MATCH_CRITERIA);
1703         rc = efx_mae_populate_lhs_match_criteria(match_crit, &rule->match);
1704         if (rc)
1705                 return rc;
1706
1707         /* action */
1708         act = &rule->lhs_act;
1709         rc = efx_mae_encap_type_to_mae_type(act->tun_type);
1710         if (rc < 0)
1711                 return rc;
1712         MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_ENCAP_TYPE, rc);
1713         /* We always inhibit CT lookup on TCP_INTERESTING_FLAGS, since the
1714          * SW path needs to process the packet to update the conntrack tables
1715          * on connection establishment (SYN) or termination (FIN, RST).
1716          */
1717         MCDI_POPULATE_DWORD_6(inbuf, MAE_OUTER_RULE_INSERT_IN_LOOKUP_CONTROL,
1718                               MAE_OUTER_RULE_INSERT_IN_DO_CT, !!act->zone,
1719                               MAE_OUTER_RULE_INSERT_IN_CT_TCP_FLAGS_INHIBIT, 1,
1720                               MAE_OUTER_RULE_INSERT_IN_CT_DOMAIN,
1721                               act->zone ? act->zone->zone : 0,
1722                               MAE_OUTER_RULE_INSERT_IN_CT_VNI_MODE,
1723                               MAE_CT_VNI_MODE_ZERO,
1724                               MAE_OUTER_RULE_INSERT_IN_DO_COUNT, !!act->count,
1725                               MAE_OUTER_RULE_INSERT_IN_RECIRC_ID,
1726                               act->rid ? act->rid->fw_id : 0);
1727         if (act->count)
1728                 MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_INSERT_IN_COUNTER_ID,
1729                                act->count->cnt->fw_id);
1730         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_INSERT, inbuf,
1731                           sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
1732         if (rc)
1733                 return rc;
1734         if (outlen < sizeof(outbuf))
1735                 return -EIO;
1736         rule->fw_id = MCDI_DWORD(outbuf, MAE_OUTER_RULE_INSERT_OUT_OR_ID);
1737         return 0;
1738 }
1739
1740 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
1741                                            const struct efx_tc_match *match);
1742
1743 static int efx_mae_insert_lhs_action_rule(struct efx_nic *efx,
1744                                           struct efx_tc_lhs_rule *rule,
1745                                           u32 prio)
1746 {
1747         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN));
1748         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
1749         struct efx_tc_lhs_action *act = &rule->lhs_act;
1750         MCDI_DECLARE_STRUCT_PTR(match_crit);
1751         MCDI_DECLARE_STRUCT_PTR(response);
1752         size_t outlen;
1753         int rc;
1754
1755         match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA);
1756         response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE);
1757         MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID,
1758                               MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
1759         MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID,
1760                               MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL);
1761         EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(response, MAE_ACTION_RULE_RESPONSE_LOOKUP_CONTROL),
1762                              MAE_ACTION_RULE_RESPONSE_DO_CT, !!act->zone,
1763                              MAE_ACTION_RULE_RESPONSE_DO_RECIRC,
1764                              act->rid && !act->zone,
1765                              MAE_ACTION_RULE_RESPONSE_CT_VNI_MODE,
1766                              MAE_CT_VNI_MODE_ZERO,
1767                              MAE_ACTION_RULE_RESPONSE_RECIRC_ID,
1768                              act->rid ? act->rid->fw_id : 0,
1769                              MAE_ACTION_RULE_RESPONSE_CT_DOMAIN,
1770                              act->zone ? act->zone->zone : 0);
1771         MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_COUNTER_ID,
1772                               act->count ? act->count->cnt->fw_id :
1773                               MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
1774         MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio);
1775         rc = efx_mae_populate_match_criteria(match_crit, &rule->match);
1776         if (rc)
1777                 return rc;
1778
1779         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf),
1780                           outbuf, sizeof(outbuf), &outlen);
1781         if (rc)
1782                 return rc;
1783         if (outlen < sizeof(outbuf))
1784                 return -EIO;
1785         rule->fw_id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
1786         return 0;
1787 }
1788
1789 int efx_mae_insert_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule,
1790                             u32 prio)
1791 {
1792         if (rule->is_ar)
1793                 return efx_mae_insert_lhs_action_rule(efx, rule, prio);
1794         return efx_mae_insert_lhs_outer_rule(efx, rule, prio);
1795 }
1796
1797 static int efx_mae_remove_lhs_outer_rule(struct efx_nic *efx,
1798                                          struct efx_tc_lhs_rule *rule)
1799 {
1800         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_OUT_LEN(1));
1801         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_OUTER_RULE_REMOVE_IN_LEN(1));
1802         size_t outlen;
1803         int rc;
1804
1805         MCDI_SET_DWORD(inbuf, MAE_OUTER_RULE_REMOVE_IN_OR_ID, rule->fw_id);
1806         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_OUTER_RULE_REMOVE, inbuf,
1807                           sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
1808         if (rc)
1809                 return rc;
1810         if (outlen < sizeof(outbuf))
1811                 return -EIO;
1812         /* FW freed a different ID than we asked for, should also never happen.
1813          * Warn because it means we've now got a different idea to the FW of
1814          * what encap_mds exist, which could cause mayhem later.
1815          */
1816         if (WARN_ON(MCDI_DWORD(outbuf, MAE_OUTER_RULE_REMOVE_OUT_REMOVED_OR_ID) != rule->fw_id))
1817                 return -EIO;
1818         /* We're probably about to free @rule, but let's just make sure its
1819          * fw_id is blatted so that it won't look valid if it leaks out.
1820          */
1821         rule->fw_id = MC_CMD_MAE_OUTER_RULE_INSERT_OUT_OUTER_RULE_ID_NULL;
1822         return 0;
1823 }
1824
1825 int efx_mae_remove_lhs_rule(struct efx_nic *efx, struct efx_tc_lhs_rule *rule)
1826 {
1827         if (rule->is_ar)
1828                 return efx_mae_delete_rule(efx, rule->fw_id);
1829         return efx_mae_remove_lhs_outer_rule(efx, rule);
1830 }
1831
1832 /* Populating is done by taking each byte of @value in turn and storing
1833  * it in the appropriate bits of @row.  @value must be big-endian; we
1834  * convert it to little-endianness as we go.
1835  */
1836 static int efx_mae_table_populate(struct efx_tc_table_field_fmt field,
1837                                   __le32 *row, size_t row_bits,
1838                                   void *value, size_t value_size)
1839 {
1840         unsigned int i;
1841
1842         /* For now only scheme 0 is supported for any field, so we check here
1843          * (rather than, say, in calling code, which knows the semantics and
1844          * could in principle encode for other schemes).
1845          */
1846         if (field.scheme)
1847                 return -EOPNOTSUPP;
1848         if (DIV_ROUND_UP(field.width, 8) != value_size)
1849                 return -EINVAL;
1850         if (field.lbn + field.width > row_bits)
1851                 return -EINVAL;
1852         for (i = 0; i < value_size; i++) {
1853                 unsigned int bn = field.lbn + i * 8;
1854                 unsigned int wn = bn / 32;
1855                 u64 v;
1856
1857                 v = ((u8 *)value)[value_size - i - 1];
1858                 v <<= (bn % 32);
1859                 row[wn] |= cpu_to_le32(v & 0xffffffff);
1860                 if (wn * 32 < row_bits)
1861                         row[wn + 1] |= cpu_to_le32(v >> 32);
1862         }
1863         return 0;
1864 }
1865
1866 static int efx_mae_table_populate_bool(struct efx_tc_table_field_fmt field,
1867                                        __le32 *row, size_t row_bits, bool value)
1868 {
1869         u8 v = value ? 1 : 0;
1870
1871         if (field.width != 1)
1872                 return -EINVAL;
1873         return efx_mae_table_populate(field, row, row_bits, &v, 1);
1874 }
1875
1876 static int efx_mae_table_populate_ipv4(struct efx_tc_table_field_fmt field,
1877                                        __le32 *row, size_t row_bits, __be32 value)
1878 {
1879         /* IPv4 is placed in the first 4 bytes of an IPv6-sized field */
1880         struct in6_addr v = {};
1881
1882         if (field.width != 128)
1883                 return -EINVAL;
1884         v.s6_addr32[0] = value;
1885         return efx_mae_table_populate(field, row, row_bits, &v, sizeof(v));
1886 }
1887
1888 static int efx_mae_table_populate_u24(struct efx_tc_table_field_fmt field,
1889                                       __le32 *row, size_t row_bits, u32 value)
1890 {
1891         __be32 v = cpu_to_be32(value);
1892
1893         /* We adjust value_size here since just 3 bytes will be copied, and
1894          * the pointer to the value is set discarding the first byte which is
1895          * the most significant byte for a big-endian 4-bytes value.
1896          */
1897         return efx_mae_table_populate(field, row, row_bits, ((void *)&v) + 1,
1898                                       sizeof(v) - 1);
1899 }
1900
1901 #define _TABLE_POPULATE(dst, dw, _field, _value) ({     \
1902         typeof(_value) _v = _value;                     \
1903                                                         \
1904         (_field.width == sizeof(_value) * 8) ?          \
1905          efx_mae_table_populate(_field, dst, dw, &_v,   \
1906                                 sizeof(_v)) : -EINVAL;  \
1907 })
1908 #define TABLE_POPULATE_KEY_IPV4(dst, _table, _field, _value)                   \
1909         efx_mae_table_populate_ipv4(efx->tc->meta_##_table.desc.keys           \
1910                                     [efx->tc->meta_##_table.keys._field##_idx],\
1911                                     dst, efx->tc->meta_##_table.desc.key_width,\
1912                                     _value)
1913 #define TABLE_POPULATE_KEY(dst, _table, _field, _value)                 \
1914         _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.key_width,     \
1915                         efx->tc->meta_##_table.desc.keys                \
1916                         [efx->tc->meta_##_table.keys._field##_idx],     \
1917                         _value)
1918
1919 #define TABLE_POPULATE_RESP_BOOL(dst, _table, _field, _value)                   \
1920         efx_mae_table_populate_bool(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 #define TABLE_POPULATE_RESP(dst, _table, _field, _value)                \
1925         _TABLE_POPULATE(dst, efx->tc->meta_##_table.desc.resp_width,    \
1926                         efx->tc->meta_##_table.desc.resps               \
1927                         [efx->tc->meta_##_table.resps._field##_idx],    \
1928                         _value)
1929
1930 #define TABLE_POPULATE_RESP_U24(dst, _table, _field, _value)                   \
1931         efx_mae_table_populate_u24(efx->tc->meta_##_table.desc.resps           \
1932                                    [efx->tc->meta_##_table.resps._field##_idx],\
1933                                    dst, efx->tc->meta_##_table.desc.resp_width,\
1934                                    _value)
1935
1936 static int efx_mae_populate_ct_key(struct efx_nic *efx, __le32 *key, size_t kw,
1937                                    struct efx_tc_ct_entry *conn)
1938 {
1939         bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6);
1940         int rc;
1941
1942         rc = TABLE_POPULATE_KEY(key, ct, eth_proto, conn->eth_proto);
1943         if (rc)
1944                 return rc;
1945         rc = TABLE_POPULATE_KEY(key, ct, ip_proto, conn->ip_proto);
1946         if (rc)
1947                 return rc;
1948         if (ipv6)
1949                 rc = TABLE_POPULATE_KEY(key, ct, src_ip, conn->src_ip6);
1950         else
1951                 rc = TABLE_POPULATE_KEY_IPV4(key, ct, src_ip, conn->src_ip);
1952         if (rc)
1953                 return rc;
1954         if (ipv6)
1955                 rc = TABLE_POPULATE_KEY(key, ct, dst_ip, conn->dst_ip6);
1956         else
1957                 rc = TABLE_POPULATE_KEY_IPV4(key, ct, dst_ip, conn->dst_ip);
1958         if (rc)
1959                 return rc;
1960         rc = TABLE_POPULATE_KEY(key, ct, l4_sport, conn->l4_sport);
1961         if (rc)
1962                 return rc;
1963         rc = TABLE_POPULATE_KEY(key, ct, l4_dport, conn->l4_dport);
1964         if (rc)
1965                 return rc;
1966         return TABLE_POPULATE_KEY(key, ct, zone, cpu_to_be16(conn->zone->zone));
1967 }
1968
1969 int efx_mae_insert_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
1970 {
1971         bool ipv6 = conn->eth_proto == htons(ETH_P_IPV6);
1972         __le32 *key = NULL, *resp = NULL;
1973         size_t inlen, kw, rw;
1974         efx_dword_t *inbuf;
1975         int rc = -ENOMEM;
1976
1977         /* Check table access is supported */
1978         if (!efx->tc->meta_ct.hooked)
1979                 return -EOPNOTSUPP;
1980
1981         /* key/resp widths are in bits; convert to dwords for IN_LEN */
1982         kw = DIV_ROUND_UP(efx->tc->meta_ct.desc.key_width, 32);
1983         rw = DIV_ROUND_UP(efx->tc->meta_ct.desc.resp_width, 32);
1984         BUILD_BUG_ON(sizeof(__le32) != MC_CMD_TABLE_INSERT_IN_DATA_LEN);
1985         inlen = MC_CMD_TABLE_INSERT_IN_LEN(kw + rw);
1986         if (inlen > MC_CMD_TABLE_INSERT_IN_LENMAX_MCDI2)
1987                 return -E2BIG;
1988         inbuf = kzalloc(inlen, GFP_KERNEL);
1989         if (!inbuf)
1990                 return -ENOMEM;
1991
1992         key = kcalloc(kw, sizeof(__le32), GFP_KERNEL);
1993         if (!key)
1994                 goto out_free;
1995         resp = kcalloc(rw, sizeof(__le32), GFP_KERNEL);
1996         if (!resp)
1997                 goto out_free;
1998
1999         rc = efx_mae_populate_ct_key(efx, key, kw, conn);
2000         if (rc)
2001                 goto out_free;
2002
2003         rc = TABLE_POPULATE_RESP_BOOL(resp, ct, dnat, conn->dnat);
2004         if (rc)
2005                 goto out_free;
2006         /* No support in hw for IPv6 NAT; field is only 32 bits */
2007         if (!ipv6)
2008                 rc = TABLE_POPULATE_RESP(resp, ct, nat_ip, conn->nat_ip);
2009         if (rc)
2010                 goto out_free;
2011         rc = TABLE_POPULATE_RESP(resp, ct, l4_natport, conn->l4_natport);
2012         if (rc)
2013                 goto out_free;
2014         rc = TABLE_POPULATE_RESP(resp, ct, mark, cpu_to_be32(conn->mark));
2015         if (rc)
2016                 goto out_free;
2017         rc = TABLE_POPULATE_RESP_U24(resp, ct, counter_id, conn->cnt->fw_id);
2018         if (rc)
2019                 goto out_free;
2020
2021         MCDI_SET_DWORD(inbuf, TABLE_INSERT_IN_TABLE_ID, TABLE_ID_CONNTRACK_TABLE);
2022         MCDI_SET_WORD(inbuf, TABLE_INSERT_IN_KEY_WIDTH,
2023                       efx->tc->meta_ct.desc.key_width);
2024         /* MASK_WIDTH is zero as CT is a BCAM */
2025         MCDI_SET_WORD(inbuf, TABLE_INSERT_IN_RESP_WIDTH,
2026                       efx->tc->meta_ct.desc.resp_width);
2027         memcpy(MCDI_PTR(inbuf, TABLE_INSERT_IN_DATA), key, kw * sizeof(__le32));
2028         memcpy(MCDI_PTR(inbuf, TABLE_INSERT_IN_DATA) + kw * sizeof(__le32),
2029                resp, rw * sizeof(__le32));
2030
2031         BUILD_BUG_ON(MC_CMD_TABLE_INSERT_OUT_LEN);
2032
2033         rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_INSERT, inbuf, inlen, NULL, 0, NULL);
2034
2035 out_free:
2036         kfree(resp);
2037         kfree(key);
2038         kfree(inbuf);
2039         return rc;
2040 }
2041
2042 int efx_mae_remove_ct(struct efx_nic *efx, struct efx_tc_ct_entry *conn)
2043 {
2044         __le32 *key = NULL;
2045         efx_dword_t *inbuf;
2046         size_t inlen, kw;
2047         int rc = -ENOMEM;
2048
2049         /* Check table access is supported */
2050         if (!efx->tc->meta_ct.hooked)
2051                 return -EOPNOTSUPP;
2052
2053         /* key width is in bits; convert to dwords for IN_LEN */
2054         kw = DIV_ROUND_UP(efx->tc->meta_ct.desc.key_width, 32);
2055         BUILD_BUG_ON(sizeof(__le32) != MC_CMD_TABLE_DELETE_IN_DATA_LEN);
2056         inlen = MC_CMD_TABLE_DELETE_IN_LEN(kw);
2057         if (inlen > MC_CMD_TABLE_DELETE_IN_LENMAX_MCDI2)
2058                 return -E2BIG;
2059         inbuf = kzalloc(inlen, GFP_KERNEL);
2060         if (!inbuf)
2061                 return -ENOMEM;
2062
2063         key = kcalloc(kw, sizeof(__le32), GFP_KERNEL);
2064         if (!key)
2065                 goto out_free;
2066
2067         rc = efx_mae_populate_ct_key(efx, key, kw, conn);
2068         if (rc)
2069                 goto out_free;
2070
2071         MCDI_SET_DWORD(inbuf, TABLE_DELETE_IN_TABLE_ID, TABLE_ID_CONNTRACK_TABLE);
2072         MCDI_SET_WORD(inbuf, TABLE_DELETE_IN_KEY_WIDTH,
2073                       efx->tc->meta_ct.desc.key_width);
2074         /* MASK_WIDTH is zero as CT is a BCAM */
2075         /* RESP_WIDTH is zero for DELETE */
2076         memcpy(MCDI_PTR(inbuf, TABLE_DELETE_IN_DATA), key, kw * sizeof(__le32));
2077
2078         BUILD_BUG_ON(MC_CMD_TABLE_DELETE_OUT_LEN);
2079
2080         rc = efx_mcdi_rpc(efx, MC_CMD_TABLE_DELETE, inbuf, inlen, NULL, 0, NULL);
2081
2082 out_free:
2083         kfree(key);
2084         kfree(inbuf);
2085         return rc;
2086 }
2087
2088 static int efx_mae_populate_match_criteria(MCDI_DECLARE_STRUCT_PTR(match_crit),
2089                                            const struct efx_tc_match *match)
2090 {
2091         if (match->mask.ingress_port) {
2092                 if (~match->mask.ingress_port)
2093                         return -EOPNOTSUPP;
2094                 MCDI_STRUCT_SET_DWORD(match_crit,
2095                                       MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR,
2096                                       match->value.ingress_port);
2097         }
2098         MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_INGRESS_MPORT_SELECTOR_MASK,
2099                               match->mask.ingress_port);
2100         EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS),
2101                              MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT,
2102                              match->value.ct_state_trk,
2103                              MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT,
2104                              match->value.ct_state_est,
2105                              MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG,
2106                              match->value.ip_frag,
2107                              MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG,
2108                              match->value.ip_firstfrag,
2109                              MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST,
2110                              match->value.tcp_syn_fin_rst);
2111         EFX_POPULATE_DWORD_5(*_MCDI_STRUCT_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_FLAGS_MASK),
2112                              MAE_FIELD_MASK_VALUE_PAIRS_V2_DO_CT,
2113                              match->mask.ct_state_trk,
2114                              MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_HIT,
2115                              match->mask.ct_state_est,
2116                              MAE_FIELD_MASK_VALUE_PAIRS_V2_IS_IP_FRAG,
2117                              match->mask.ip_frag,
2118                              MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_FIRST_FRAG,
2119                              match->mask.ip_firstfrag,
2120                              MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_SYN_FIN_RST,
2121                              match->mask.tcp_syn_fin_rst);
2122         MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID,
2123                              match->value.recirc_id);
2124         MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_RECIRC_ID_MASK,
2125                              match->mask.recirc_id);
2126         MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK,
2127                               match->value.ct_mark);
2128         MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_MARK_MASK,
2129                               match->mask.ct_mark);
2130         MCDI_STRUCT_SET_WORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN,
2131                              match->value.ct_zone);
2132         MCDI_STRUCT_SET_WORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_CT_DOMAIN_MASK,
2133                              match->mask.ct_zone);
2134         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE,
2135                                 match->value.eth_proto);
2136         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETHER_TYPE_BE_MASK,
2137                                 match->mask.eth_proto);
2138         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE,
2139                                 match->value.vlan_tci[0]);
2140         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_TCI_BE_MASK,
2141                                 match->mask.vlan_tci[0]);
2142         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE,
2143                                 match->value.vlan_proto[0]);
2144         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN0_PROTO_BE_MASK,
2145                                 match->mask.vlan_proto[0]);
2146         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE,
2147                                 match->value.vlan_tci[1]);
2148         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_TCI_BE_MASK,
2149                                 match->mask.vlan_tci[1]);
2150         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE,
2151                                 match->value.vlan_proto[1]);
2152         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_VLAN1_PROTO_BE_MASK,
2153                                 match->mask.vlan_proto[1]);
2154         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE),
2155                match->value.eth_saddr, ETH_ALEN);
2156         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_SADDR_BE_MASK),
2157                match->mask.eth_saddr, ETH_ALEN);
2158         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE),
2159                match->value.eth_daddr, ETH_ALEN);
2160         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ETH_DADDR_BE_MASK),
2161                match->mask.eth_daddr, ETH_ALEN);
2162         MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO,
2163                              match->value.ip_proto);
2164         MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_PROTO_MASK,
2165                              match->mask.ip_proto);
2166         MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS,
2167                              match->value.ip_tos);
2168         MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TOS_MASK,
2169                              match->mask.ip_tos);
2170         MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL,
2171                              match->value.ip_ttl);
2172         MCDI_STRUCT_SET_BYTE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_IP_TTL_MASK,
2173                              match->mask.ip_ttl);
2174         MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE,
2175                                  match->value.src_ip);
2176         MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP4_BE_MASK,
2177                                  match->mask.src_ip);
2178         MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE,
2179                                  match->value.dst_ip);
2180         MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP4_BE_MASK,
2181                                  match->mask.dst_ip);
2182 #ifdef CONFIG_IPV6
2183         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE),
2184                &match->value.src_ip6, sizeof(struct in6_addr));
2185         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_SRC_IP6_BE_MASK),
2186                &match->mask.src_ip6, sizeof(struct in6_addr));
2187         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE),
2188                &match->value.dst_ip6, sizeof(struct in6_addr));
2189         memcpy(MCDI_STRUCT_PTR(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_DST_IP6_BE_MASK),
2190                &match->mask.dst_ip6, sizeof(struct in6_addr));
2191 #endif
2192         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE,
2193                                 match->value.l4_sport);
2194         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_SPORT_BE_MASK,
2195                                 match->mask.l4_sport);
2196         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE,
2197                                 match->value.l4_dport);
2198         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_L4_DPORT_BE_MASK,
2199                                 match->mask.l4_dport);
2200         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE,
2201                                 match->value.tcp_flags);
2202         MCDI_STRUCT_SET_WORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_TCP_FLAGS_BE_MASK,
2203                                 match->mask.tcp_flags);
2204         /* enc-keys are handled indirectly, through encap_match ID */
2205         if (match->encap) {
2206                 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID,
2207                                       match->encap->fw_id);
2208                 MCDI_STRUCT_SET_DWORD(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_OUTER_RULE_ID_MASK,
2209                                       U32_MAX);
2210                 /* enc_keyid (VNI/VSID) is not part of the encap_match */
2211                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE,
2212                                          match->value.enc_keyid);
2213                 MCDI_STRUCT_SET_DWORD_BE(match_crit, MAE_FIELD_MASK_VALUE_PAIRS_V2_ENC_VNET_ID_BE_MASK,
2214                                          match->mask.enc_keyid);
2215         } else if (WARN_ON_ONCE(match->mask.enc_src_ip) ||
2216                    WARN_ON_ONCE(match->mask.enc_dst_ip) ||
2217                    WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_src_ip6)) ||
2218                    WARN_ON_ONCE(!ipv6_addr_any(&match->mask.enc_dst_ip6)) ||
2219                    WARN_ON_ONCE(match->mask.enc_ip_tos) ||
2220                    WARN_ON_ONCE(match->mask.enc_ip_ttl) ||
2221                    WARN_ON_ONCE(match->mask.enc_sport) ||
2222                    WARN_ON_ONCE(match->mask.enc_dport) ||
2223                    WARN_ON_ONCE(match->mask.enc_keyid)) {
2224                 /* No enc-keys should appear in a rule without an encap_match */
2225                 return -EOPNOTSUPP;
2226         }
2227         return 0;
2228 }
2229
2230 int efx_mae_insert_rule(struct efx_nic *efx, const struct efx_tc_match *match,
2231                         u32 prio, u32 acts_id, u32 *id)
2232 {
2233         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_INSERT_IN_LEN(MAE_FIELD_MASK_VALUE_PAIRS_V2_LEN));
2234         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_INSERT_OUT_LEN);
2235         MCDI_DECLARE_STRUCT_PTR(match_crit);
2236         MCDI_DECLARE_STRUCT_PTR(response);
2237         size_t outlen;
2238         int rc;
2239
2240         if (!id)
2241                 return -EINVAL;
2242
2243         match_crit = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_MATCH_CRITERIA);
2244         response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_RESPONSE);
2245         if (efx_mae_asl_id(acts_id)) {
2246                 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id);
2247                 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID,
2248                                       MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL);
2249         } else {
2250                 /* We only had one AS, so we didn't wrap it in an ASL */
2251                 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID,
2252                                       MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
2253                 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id);
2254         }
2255         MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_INSERT_IN_PRIO, prio);
2256         rc = efx_mae_populate_match_criteria(match_crit, match);
2257         if (rc)
2258                 return rc;
2259
2260         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_INSERT, inbuf, sizeof(inbuf),
2261                           outbuf, sizeof(outbuf), &outlen);
2262         if (rc)
2263                 return rc;
2264         if (outlen < sizeof(outbuf))
2265                 return -EIO;
2266         *id = MCDI_DWORD(outbuf, MAE_ACTION_RULE_INSERT_OUT_AR_ID);
2267         return 0;
2268 }
2269
2270 int efx_mae_update_rule(struct efx_nic *efx, u32 acts_id, u32 id)
2271 {
2272         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_UPDATE_IN_LEN);
2273         MCDI_DECLARE_STRUCT_PTR(response);
2274
2275         BUILD_BUG_ON(MC_CMD_MAE_ACTION_RULE_UPDATE_OUT_LEN);
2276         response = _MCDI_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_RESPONSE);
2277
2278         MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_UPDATE_IN_AR_ID, id);
2279         if (efx_mae_asl_id(acts_id)) {
2280                 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID, acts_id);
2281                 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID,
2282                                       MC_CMD_MAE_ACTION_SET_ALLOC_OUT_ACTION_SET_ID_NULL);
2283         } else {
2284                 /* We only had one AS, so we didn't wrap it in an ASL */
2285                 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_ASL_ID,
2286                                       MC_CMD_MAE_ACTION_SET_LIST_ALLOC_OUT_ACTION_SET_LIST_ID_NULL);
2287                 MCDI_STRUCT_SET_DWORD(response, MAE_ACTION_RULE_RESPONSE_AS_ID, acts_id);
2288         }
2289         return efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_UPDATE, inbuf, sizeof(inbuf),
2290                             NULL, 0, NULL);
2291 }
2292
2293 int efx_mae_delete_rule(struct efx_nic *efx, u32 id)
2294 {
2295         MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_ACTION_RULE_DELETE_OUT_LEN(1));
2296         MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_ACTION_RULE_DELETE_IN_LEN(1));
2297         size_t outlen;
2298         int rc;
2299
2300         MCDI_SET_DWORD(inbuf, MAE_ACTION_RULE_DELETE_IN_AR_ID, id);
2301         rc = efx_mcdi_rpc(efx, MC_CMD_MAE_ACTION_RULE_DELETE, inbuf, sizeof(inbuf),
2302                           outbuf, sizeof(outbuf), &outlen);
2303         if (rc)
2304                 return rc;
2305         if (outlen < sizeof(outbuf))
2306                 return -EIO;
2307         /* FW freed a different ID than we asked for, should also never happen.
2308          * Warn because it means we've now got a different idea to the FW of
2309          * what rules exist, which could cause mayhem later.
2310          */
2311         if (WARN_ON(MCDI_DWORD(outbuf, MAE_ACTION_RULE_DELETE_OUT_DELETED_AR_ID) != id))
2312                 return -EIO;
2313         return 0;
2314 }
2315
2316 int efx_init_mae(struct efx_nic *efx)
2317 {
2318         struct ef100_nic_data *nic_data = efx->nic_data;
2319         struct efx_mae *mae;
2320         int rc;
2321
2322         if (!nic_data->have_mport)
2323                 return -EINVAL;
2324
2325         mae = kmalloc(sizeof(*mae), GFP_KERNEL);
2326         if (!mae)
2327                 return -ENOMEM;
2328
2329         rc = rhashtable_init(&mae->mports_ht, &efx_mae_mports_ht_params);
2330         if (rc < 0) {
2331                 kfree(mae);
2332                 return rc;
2333         }
2334         efx->mae = mae;
2335         mae->efx = efx;
2336         return 0;
2337 }
2338
2339 void efx_fini_mae(struct efx_nic *efx)
2340 {
2341         struct efx_mae *mae = efx->mae;
2342
2343         kfree(mae);
2344         efx->mae = NULL;
2345 }