]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/net/ethernet/mellanox/mlx5/core/steering/dr_matcher.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[mirror_ubuntu-jammy-kernel.git] / drivers / net / ethernet / mellanox / mlx5 / core / steering / dr_matcher.c
CommitLineData
852f660b
AV
1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2/* Copyright (c) 2019 Mellanox Technologies. */
3
4#include "dr_types.h"
5
6static bool dr_mask_is_smac_set(struct mlx5dr_match_spec *spec)
7{
8 return (spec->smac_47_16 || spec->smac_15_0);
9}
10
11static bool dr_mask_is_dmac_set(struct mlx5dr_match_spec *spec)
12{
13 return (spec->dmac_47_16 || spec->dmac_15_0);
14}
15
16static bool dr_mask_is_src_addr_set(struct mlx5dr_match_spec *spec)
17{
18 return (spec->src_ip_127_96 || spec->src_ip_95_64 ||
19 spec->src_ip_63_32 || spec->src_ip_31_0);
20}
21
22static bool dr_mask_is_dst_addr_set(struct mlx5dr_match_spec *spec)
23{
24 return (spec->dst_ip_127_96 || spec->dst_ip_95_64 ||
25 spec->dst_ip_63_32 || spec->dst_ip_31_0);
26}
27
28static bool dr_mask_is_l3_base_set(struct mlx5dr_match_spec *spec)
29{
30 return (spec->ip_protocol || spec->frag || spec->tcp_flags ||
31 spec->ip_ecn || spec->ip_dscp);
32}
33
34static bool dr_mask_is_tcp_udp_base_set(struct mlx5dr_match_spec *spec)
35{
36 return (spec->tcp_sport || spec->tcp_dport ||
37 spec->udp_sport || spec->udp_dport);
38}
39
40static bool dr_mask_is_ipv4_set(struct mlx5dr_match_spec *spec)
41{
42 return (spec->dst_ip_31_0 || spec->src_ip_31_0);
43}
44
45static bool dr_mask_is_ipv4_5_tuple_set(struct mlx5dr_match_spec *spec)
46{
47 return (dr_mask_is_l3_base_set(spec) ||
48 dr_mask_is_tcp_udp_base_set(spec) ||
49 dr_mask_is_ipv4_set(spec));
50}
51
52static bool dr_mask_is_eth_l2_tnl_set(struct mlx5dr_match_misc *misc)
53{
54 return misc->vxlan_vni;
55}
56
57static bool dr_mask_is_ttl_set(struct mlx5dr_match_spec *spec)
58{
59 return spec->ttl_hoplimit;
60}
61
62#define DR_MASK_IS_L2_DST(_spec, _misc, _inner_outer) (_spec.first_vid || \
63 (_spec).first_cfi || (_spec).first_prio || (_spec).cvlan_tag || \
64 (_spec).svlan_tag || (_spec).dmac_47_16 || (_spec).dmac_15_0 || \
65 (_spec).ethertype || (_spec).ip_version || \
66 (_misc)._inner_outer##_second_vid || \
67 (_misc)._inner_outer##_second_cfi || \
68 (_misc)._inner_outer##_second_prio || \
69 (_misc)._inner_outer##_second_cvlan_tag || \
70 (_misc)._inner_outer##_second_svlan_tag)
71
72#define DR_MASK_IS_ETH_L4_SET(_spec, _misc, _inner_outer) ( \
73 dr_mask_is_l3_base_set(&(_spec)) || \
74 dr_mask_is_tcp_udp_base_set(&(_spec)) || \
75 dr_mask_is_ttl_set(&(_spec)) || \
76 (_misc)._inner_outer##_ipv6_flow_label)
77
78#define DR_MASK_IS_ETH_L4_MISC_SET(_misc3, _inner_outer) ( \
79 (_misc3)._inner_outer##_tcp_seq_num || \
80 (_misc3)._inner_outer##_tcp_ack_num)
81
82#define DR_MASK_IS_FIRST_MPLS_SET(_misc2, _inner_outer) ( \
83 (_misc2)._inner_outer##_first_mpls_label || \
84 (_misc2)._inner_outer##_first_mpls_exp || \
85 (_misc2)._inner_outer##_first_mpls_s_bos || \
86 (_misc2)._inner_outer##_first_mpls_ttl)
87
88static bool dr_mask_is_gre_set(struct mlx5dr_match_misc *misc)
89{
90 return (misc->gre_key_h || misc->gre_key_l ||
91 misc->gre_protocol || misc->gre_c_present ||
92 misc->gre_k_present || misc->gre_s_present);
93}
94
95#define DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET(_misc2, gre_udp) ( \
96 (_misc2).outer_first_mpls_over_##gre_udp##_label || \
97 (_misc2).outer_first_mpls_over_##gre_udp##_exp || \
98 (_misc2).outer_first_mpls_over_##gre_udp##_s_bos || \
99 (_misc2).outer_first_mpls_over_##gre_udp##_ttl)
100
101#define DR_MASK_IS_FLEX_PARSER_0_SET(_misc2) ( \
102 DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET((_misc2), gre) || \
103 DR_MASK_IS_OUTER_MPLS_OVER_GRE_UDP_SET((_misc2), udp))
104
6e9e286e
YK
105static bool
106dr_mask_is_misc3_vxlan_gpe_set(struct mlx5dr_match_misc3 *misc3)
852f660b
AV
107{
108 return (misc3->outer_vxlan_gpe_vni ||
109 misc3->outer_vxlan_gpe_next_protocol ||
110 misc3->outer_vxlan_gpe_flags);
111}
112
6e9e286e
YK
113static bool
114dr_matcher_supp_flex_parser_vxlan_gpe(struct mlx5dr_cmd_caps *caps)
115{
116 return caps->flex_protocols &
117 MLX5_FLEX_PARSER_VXLAN_GPE_ENABLED;
118}
119
120static bool
121dr_mask_is_flex_parser_tnl_vxlan_gpe_set(struct mlx5dr_match_param *mask,
122 struct mlx5dr_domain *dmn)
123{
124 return dr_mask_is_misc3_vxlan_gpe_set(&mask->misc3) &&
125 dr_matcher_supp_flex_parser_vxlan_gpe(&dmn->info.caps);
126}
127
b6d12238
YK
128static bool dr_mask_is_misc_geneve_set(struct mlx5dr_match_misc *misc)
129{
130 return misc->geneve_vni ||
131 misc->geneve_oam ||
132 misc->geneve_protocol_type ||
133 misc->geneve_opt_len;
134}
135
136static bool
137dr_matcher_supp_flex_parser_geneve(struct mlx5dr_cmd_caps *caps)
138{
139 return caps->flex_protocols &
140 MLX5_FLEX_PARSER_GENEVE_ENABLED;
141}
142
143static bool
144dr_mask_is_flex_parser_tnl_geneve_set(struct mlx5dr_match_param *mask,
145 struct mlx5dr_domain *dmn)
146{
147 return dr_mask_is_misc_geneve_set(&mask->misc) &&
148 dr_matcher_supp_flex_parser_geneve(&dmn->info.caps);
149}
150
852f660b
AV
151static bool dr_mask_is_flex_parser_icmpv6_set(struct mlx5dr_match_misc3 *misc3)
152{
153 return (misc3->icmpv6_type || misc3->icmpv6_code ||
154 misc3->icmpv6_header_data);
155}
156
157static bool dr_mask_is_wqe_metadata_set(struct mlx5dr_match_misc2 *misc2)
158{
159 return misc2->metadata_reg_a;
160}
161
162static bool dr_mask_is_reg_c_0_3_set(struct mlx5dr_match_misc2 *misc2)
163{
164 return (misc2->metadata_reg_c_0 || misc2->metadata_reg_c_1 ||
165 misc2->metadata_reg_c_2 || misc2->metadata_reg_c_3);
166}
167
168static bool dr_mask_is_reg_c_4_7_set(struct mlx5dr_match_misc2 *misc2)
169{
170 return (misc2->metadata_reg_c_4 || misc2->metadata_reg_c_5 ||
171 misc2->metadata_reg_c_6 || misc2->metadata_reg_c_7);
172}
173
174static bool dr_mask_is_gvmi_or_qpn_set(struct mlx5dr_match_misc *misc)
175{
176 return (misc->source_sqn || misc->source_port);
177}
178
852f660b
AV
179int mlx5dr_matcher_select_builders(struct mlx5dr_matcher *matcher,
180 struct mlx5dr_matcher_rx_tx *nic_matcher,
667f2646
AV
181 enum mlx5dr_ipv outer_ipv,
182 enum mlx5dr_ipv inner_ipv)
852f660b 183{
667f2646
AV
184 nic_matcher->ste_builder =
185 nic_matcher->ste_builder_arr[outer_ipv][inner_ipv];
186 nic_matcher->num_of_builders =
187 nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv];
852f660b 188
86bb811b 189 if (!nic_matcher->num_of_builders) {
852f660b
AV
190 mlx5dr_dbg(matcher->tbl->dmn,
191 "Rule not supported on this matcher due to IP related fields\n");
192 return -EINVAL;
193 }
194
195 return 0;
196}
197
198static int dr_matcher_set_ste_builders(struct mlx5dr_matcher *matcher,
199 struct mlx5dr_matcher_rx_tx *nic_matcher,
667f2646
AV
200 enum mlx5dr_ipv outer_ipv,
201 enum mlx5dr_ipv inner_ipv)
852f660b
AV
202{
203 struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn;
204 struct mlx5dr_domain *dmn = matcher->tbl->dmn;
205 struct mlx5dr_match_param mask = {};
206 struct mlx5dr_match_misc3 *misc3;
207 struct mlx5dr_ste_build *sb;
852f660b
AV
208 bool inner, rx;
209 int idx = 0;
210 int ret, i;
211
667f2646 212 sb = nic_matcher->ste_builder_arr[outer_ipv][inner_ipv];
852f660b
AV
213 rx = nic_dmn->ste_type == MLX5DR_STE_TYPE_RX;
214
215 /* Create a temporary mask to track and clear used mask fields */
216 if (matcher->match_criteria & DR_MATCHER_CRITERIA_OUTER)
217 mask.outer = matcher->mask.outer;
218
219 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC)
220 mask.misc = matcher->mask.misc;
221
222 if (matcher->match_criteria & DR_MATCHER_CRITERIA_INNER)
223 mask.inner = matcher->mask.inner;
224
225 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC2)
226 mask.misc2 = matcher->mask.misc2;
227
228 if (matcher->match_criteria & DR_MATCHER_CRITERIA_MISC3)
229 mask.misc3 = matcher->mask.misc3;
230
231 ret = mlx5dr_ste_build_pre_check(dmn, matcher->match_criteria,
232 &matcher->mask, NULL);
233 if (ret)
234 return ret;
235
236 /* Outer */
237 if (matcher->match_criteria & (DR_MATCHER_CRITERIA_OUTER |
238 DR_MATCHER_CRITERIA_MISC |
239 DR_MATCHER_CRITERIA_MISC2 |
240 DR_MATCHER_CRITERIA_MISC3)) {
241 inner = false;
242
243 if (dr_mask_is_wqe_metadata_set(&mask.misc2))
244 mlx5dr_ste_build_general_purpose(&sb[idx++], &mask, inner, rx);
245
246 if (dr_mask_is_reg_c_0_3_set(&mask.misc2))
247 mlx5dr_ste_build_register_0(&sb[idx++], &mask, inner, rx);
248
249 if (dr_mask_is_reg_c_4_7_set(&mask.misc2))
250 mlx5dr_ste_build_register_1(&sb[idx++], &mask, inner, rx);
251
252 if (dr_mask_is_gvmi_or_qpn_set(&mask.misc) &&
253 (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
254 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX)) {
255 ret = mlx5dr_ste_build_src_gvmi_qpn(&sb[idx++], &mask,
640bdb1f 256 dmn, inner, rx);
852f660b
AV
257 if (ret)
258 return ret;
259 }
260
261 if (dr_mask_is_smac_set(&mask.outer) &&
262 dr_mask_is_dmac_set(&mask.outer)) {
263 ret = mlx5dr_ste_build_eth_l2_src_des(&sb[idx++], &mask,
264 inner, rx);
265 if (ret)
266 return ret;
267 }
268
269 if (dr_mask_is_smac_set(&mask.outer))
270 mlx5dr_ste_build_eth_l2_src(&sb[idx++], &mask, inner, rx);
271
272 if (DR_MASK_IS_L2_DST(mask.outer, mask.misc, outer))
273 mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx);
274
667f2646 275 if (outer_ipv == DR_RULE_IPV6) {
852f660b
AV
276 if (dr_mask_is_dst_addr_set(&mask.outer))
277 mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask,
278 inner, rx);
279
280 if (dr_mask_is_src_addr_set(&mask.outer))
281 mlx5dr_ste_build_eth_l3_ipv6_src(&sb[idx++], &mask,
282 inner, rx);
283
284 if (DR_MASK_IS_ETH_L4_SET(mask.outer, mask.misc, outer))
285 mlx5dr_ste_build_ipv6_l3_l4(&sb[idx++], &mask,
286 inner, rx);
287 } else {
288 if (dr_mask_is_ipv4_5_tuple_set(&mask.outer))
289 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(&sb[idx++], &mask,
290 inner, rx);
291
292 if (dr_mask_is_ttl_set(&mask.outer))
293 mlx5dr_ste_build_eth_l3_ipv4_misc(&sb[idx++], &mask,
294 inner, rx);
295 }
296
6e9e286e
YK
297 if (dr_mask_is_flex_parser_tnl_vxlan_gpe_set(&mask, dmn))
298 mlx5dr_ste_build_flex_parser_tnl_vxlan_gpe(&sb[idx++],
299 &mask,
300 inner, rx);
b6d12238
YK
301 else if (dr_mask_is_flex_parser_tnl_geneve_set(&mask, dmn))
302 mlx5dr_ste_build_flex_parser_tnl_geneve(&sb[idx++],
303 &mask,
304 inner, rx);
852f660b
AV
305
306 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, outer))
307 mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx);
308
309 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, outer))
310 mlx5dr_ste_build_mpls(&sb[idx++], &mask, inner, rx);
311
312 if (DR_MASK_IS_FLEX_PARSER_0_SET(mask.misc2))
313 mlx5dr_ste_build_flex_parser_0(&sb[idx++], &mask,
314 inner, rx);
315
316 misc3 = &mask.misc3;
317 if ((DR_MASK_IS_FLEX_PARSER_ICMPV4_SET(misc3) &&
318 mlx5dr_matcher_supp_flex_parser_icmp_v4(&dmn->info.caps)) ||
319 (dr_mask_is_flex_parser_icmpv6_set(&mask.misc3) &&
320 mlx5dr_matcher_supp_flex_parser_icmp_v6(&dmn->info.caps))) {
321 ret = mlx5dr_ste_build_flex_parser_1(&sb[idx++],
322 &mask, &dmn->info.caps,
323 inner, rx);
324 if (ret)
325 return ret;
326 }
327 if (dr_mask_is_gre_set(&mask.misc))
328 mlx5dr_ste_build_gre(&sb[idx++], &mask, inner, rx);
329 }
330
331 /* Inner */
332 if (matcher->match_criteria & (DR_MATCHER_CRITERIA_INNER |
333 DR_MATCHER_CRITERIA_MISC |
334 DR_MATCHER_CRITERIA_MISC2 |
335 DR_MATCHER_CRITERIA_MISC3)) {
336 inner = true;
337
338 if (dr_mask_is_eth_l2_tnl_set(&mask.misc))
339 mlx5dr_ste_build_eth_l2_tnl(&sb[idx++], &mask, inner, rx);
340
341 if (dr_mask_is_smac_set(&mask.inner) &&
342 dr_mask_is_dmac_set(&mask.inner)) {
343 ret = mlx5dr_ste_build_eth_l2_src_des(&sb[idx++],
344 &mask, inner, rx);
345 if (ret)
346 return ret;
347 }
348
349 if (dr_mask_is_smac_set(&mask.inner))
350 mlx5dr_ste_build_eth_l2_src(&sb[idx++], &mask, inner, rx);
351
352 if (DR_MASK_IS_L2_DST(mask.inner, mask.misc, inner))
353 mlx5dr_ste_build_eth_l2_dst(&sb[idx++], &mask, inner, rx);
354
667f2646 355 if (inner_ipv == DR_RULE_IPV6) {
852f660b
AV
356 if (dr_mask_is_dst_addr_set(&mask.inner))
357 mlx5dr_ste_build_eth_l3_ipv6_dst(&sb[idx++], &mask,
358 inner, rx);
359
360 if (dr_mask_is_src_addr_set(&mask.inner))
361 mlx5dr_ste_build_eth_l3_ipv6_src(&sb[idx++], &mask,
362 inner, rx);
363
364 if (DR_MASK_IS_ETH_L4_SET(mask.inner, mask.misc, inner))
365 mlx5dr_ste_build_ipv6_l3_l4(&sb[idx++], &mask,
366 inner, rx);
367 } else {
368 if (dr_mask_is_ipv4_5_tuple_set(&mask.inner))
369 mlx5dr_ste_build_eth_l3_ipv4_5_tuple(&sb[idx++], &mask,
370 inner, rx);
371
372 if (dr_mask_is_ttl_set(&mask.inner))
373 mlx5dr_ste_build_eth_l3_ipv4_misc(&sb[idx++], &mask,
374 inner, rx);
375 }
376
377 if (DR_MASK_IS_ETH_L4_MISC_SET(mask.misc3, inner))
378 mlx5dr_ste_build_eth_l4_misc(&sb[idx++], &mask, inner, rx);
379
380 if (DR_MASK_IS_FIRST_MPLS_SET(mask.misc2, inner))
381 mlx5dr_ste_build_mpls(&sb[idx++], &mask, inner, rx);
382
383 if (DR_MASK_IS_FLEX_PARSER_0_SET(mask.misc2))
384 mlx5dr_ste_build_flex_parser_0(&sb[idx++], &mask, inner, rx);
385 }
386 /* Empty matcher, takes all */
387 if (matcher->match_criteria == DR_MATCHER_CRITERIA_EMPTY)
388 mlx5dr_ste_build_empty_always_hit(&sb[idx++], rx);
389
390 if (idx == 0) {
391 mlx5dr_dbg(dmn, "Cannot generate any valid rules from mask\n");
392 return -EINVAL;
393 }
394
395 /* Check that all mask fields were consumed */
396 for (i = 0; i < sizeof(struct mlx5dr_match_param); i++) {
397 if (((u8 *)&mask)[i] != 0) {
398 mlx5dr_info(dmn, "Mask contains unsupported parameters\n");
399 return -EOPNOTSUPP;
400 }
401 }
402
667f2646
AV
403 nic_matcher->ste_builder = sb;
404 nic_matcher->num_of_builders_arr[outer_ipv][inner_ipv] = idx;
852f660b
AV
405
406 return 0;
407}
408
409static int dr_matcher_connect(struct mlx5dr_domain *dmn,
410 struct mlx5dr_matcher_rx_tx *curr_nic_matcher,
411 struct mlx5dr_matcher_rx_tx *next_nic_matcher,
412 struct mlx5dr_matcher_rx_tx *prev_nic_matcher)
413{
414 struct mlx5dr_table_rx_tx *nic_tbl = curr_nic_matcher->nic_tbl;
415 struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
416 struct mlx5dr_htbl_connect_info info;
417 struct mlx5dr_ste_htbl *prev_htbl;
418 int ret;
419
420 /* Connect end anchor hash table to next_htbl or to the default address */
421 if (next_nic_matcher) {
422 info.type = CONNECT_HIT;
423 info.hit_next_htbl = next_nic_matcher->s_htbl;
424 } else {
425 info.type = CONNECT_MISS;
426 info.miss_icm_addr = nic_tbl->default_icm_addr;
427 }
428 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
429 curr_nic_matcher->e_anchor,
430 &info, info.type == CONNECT_HIT);
431 if (ret)
432 return ret;
433
434 /* Connect start hash table to end anchor */
435 info.type = CONNECT_MISS;
436 info.miss_icm_addr = curr_nic_matcher->e_anchor->chunk->icm_addr;
437 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
438 curr_nic_matcher->s_htbl,
439 &info, false);
440 if (ret)
441 return ret;
442
443 /* Connect previous hash table to matcher start hash table */
444 if (prev_nic_matcher)
445 prev_htbl = prev_nic_matcher->e_anchor;
446 else
447 prev_htbl = nic_tbl->s_anchor;
448
449 info.type = CONNECT_HIT;
450 info.hit_next_htbl = curr_nic_matcher->s_htbl;
451 ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_htbl,
452 &info, true);
453 if (ret)
454 return ret;
455
456 /* Update the pointing ste and next hash table */
457 curr_nic_matcher->s_htbl->pointing_ste = prev_htbl->ste_arr;
458 prev_htbl->ste_arr[0].next_htbl = curr_nic_matcher->s_htbl;
459
460 if (next_nic_matcher) {
461 next_nic_matcher->s_htbl->pointing_ste = curr_nic_matcher->e_anchor->ste_arr;
462 curr_nic_matcher->e_anchor->ste_arr[0].next_htbl = next_nic_matcher->s_htbl;
463 }
464
465 return 0;
466}
467
468static int dr_matcher_add_to_tbl(struct mlx5dr_matcher *matcher)
469{
470 struct mlx5dr_matcher *next_matcher, *prev_matcher, *tmp_matcher;
471 struct mlx5dr_table *tbl = matcher->tbl;
472 struct mlx5dr_domain *dmn = tbl->dmn;
473 bool first = true;
474 int ret;
475
476 next_matcher = NULL;
477 if (!list_empty(&tbl->matcher_list))
478 list_for_each_entry(tmp_matcher, &tbl->matcher_list, matcher_list) {
479 if (tmp_matcher->prio >= matcher->prio) {
480 next_matcher = tmp_matcher;
481 break;
482 }
483 first = false;
484 }
485
486 prev_matcher = NULL;
487 if (next_matcher && !first)
48cbde4b 488 prev_matcher = list_prev_entry(next_matcher, matcher_list);
852f660b 489 else if (!first)
48cbde4b
AV
490 prev_matcher = list_last_entry(&tbl->matcher_list,
491 struct mlx5dr_matcher,
492 matcher_list);
852f660b
AV
493
494 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
495 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) {
496 ret = dr_matcher_connect(dmn, &matcher->rx,
497 next_matcher ? &next_matcher->rx : NULL,
498 prev_matcher ? &prev_matcher->rx : NULL);
499 if (ret)
500 return ret;
501 }
502
503 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
504 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) {
505 ret = dr_matcher_connect(dmn, &matcher->tx,
506 next_matcher ? &next_matcher->tx : NULL,
507 prev_matcher ? &prev_matcher->tx : NULL);
508 if (ret)
509 return ret;
510 }
511
512 if (prev_matcher)
513 list_add(&matcher->matcher_list, &prev_matcher->matcher_list);
514 else if (next_matcher)
515 list_add_tail(&matcher->matcher_list,
516 &next_matcher->matcher_list);
517 else
518 list_add(&matcher->matcher_list, &tbl->matcher_list);
519
520 return 0;
521}
522
523static void dr_matcher_uninit_nic(struct mlx5dr_matcher_rx_tx *nic_matcher)
524{
525 mlx5dr_htbl_put(nic_matcher->s_htbl);
526 mlx5dr_htbl_put(nic_matcher->e_anchor);
527}
528
529static void dr_matcher_uninit_fdb(struct mlx5dr_matcher *matcher)
530{
531 dr_matcher_uninit_nic(&matcher->rx);
532 dr_matcher_uninit_nic(&matcher->tx);
533}
534
535static void dr_matcher_uninit(struct mlx5dr_matcher *matcher)
536{
537 struct mlx5dr_domain *dmn = matcher->tbl->dmn;
538
539 switch (dmn->type) {
540 case MLX5DR_DOMAIN_TYPE_NIC_RX:
541 dr_matcher_uninit_nic(&matcher->rx);
542 break;
543 case MLX5DR_DOMAIN_TYPE_NIC_TX:
544 dr_matcher_uninit_nic(&matcher->tx);
545 break;
546 case MLX5DR_DOMAIN_TYPE_FDB:
547 dr_matcher_uninit_fdb(matcher);
548 break;
549 default:
550 WARN_ON(true);
551 break;
552 }
553}
554
667f2646
AV
555static int dr_matcher_set_all_ste_builders(struct mlx5dr_matcher *matcher,
556 struct mlx5dr_matcher_rx_tx *nic_matcher)
852f660b
AV
557{
558 struct mlx5dr_domain *dmn = matcher->tbl->dmn;
852f660b 559
667f2646
AV
560 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV4);
561 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV4, DR_RULE_IPV6);
562 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV4);
563 dr_matcher_set_ste_builders(matcher, nic_matcher, DR_RULE_IPV6, DR_RULE_IPV6);
852f660b 564
667f2646 565 if (!nic_matcher->ste_builder) {
852f660b
AV
566 mlx5dr_dbg(dmn, "Cannot generate IPv4 or IPv6 rules with given mask\n");
567 return -EINVAL;
568 }
569
667f2646
AV
570 return 0;
571}
572
573static int dr_matcher_init_nic(struct mlx5dr_matcher *matcher,
574 struct mlx5dr_matcher_rx_tx *nic_matcher)
575{
576 struct mlx5dr_domain *dmn = matcher->tbl->dmn;
577 int ret;
578
579 ret = dr_matcher_set_all_ste_builders(matcher, nic_matcher);
580 if (ret)
581 return ret;
852f660b
AV
582
583 nic_matcher->e_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
584 DR_CHUNK_SIZE_1,
585 MLX5DR_STE_LU_TYPE_DONT_CARE,
586 0);
587 if (!nic_matcher->e_anchor)
588 return -ENOMEM;
589
590 nic_matcher->s_htbl = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
591 DR_CHUNK_SIZE_1,
592 nic_matcher->ste_builder[0].lu_type,
593 nic_matcher->ste_builder[0].byte_mask);
594 if (!nic_matcher->s_htbl) {
595 ret = -ENOMEM;
596 goto free_e_htbl;
597 }
598
599 /* make sure the tables exist while empty */
600 mlx5dr_htbl_get(nic_matcher->s_htbl);
601 mlx5dr_htbl_get(nic_matcher->e_anchor);
602
603 return 0;
604
605free_e_htbl:
606 mlx5dr_ste_htbl_free(nic_matcher->e_anchor);
607 return ret;
608}
609
610static int dr_matcher_init_fdb(struct mlx5dr_matcher *matcher)
611{
612 int ret;
613
614 ret = dr_matcher_init_nic(matcher, &matcher->rx);
615 if (ret)
616 return ret;
617
618 ret = dr_matcher_init_nic(matcher, &matcher->tx);
619 if (ret)
620 goto uninit_nic_rx;
621
622 return 0;
623
624uninit_nic_rx:
625 dr_matcher_uninit_nic(&matcher->rx);
626 return ret;
627}
628
629static int dr_matcher_init(struct mlx5dr_matcher *matcher,
630 struct mlx5dr_match_parameters *mask)
631{
632 struct mlx5dr_table *tbl = matcher->tbl;
633 struct mlx5dr_domain *dmn = tbl->dmn;
634 int ret;
635
636 if (matcher->match_criteria >= DR_MATCHER_CRITERIA_MAX) {
637 mlx5dr_info(dmn, "Invalid match criteria attribute\n");
638 return -EINVAL;
639 }
640
641 if (mask) {
642 if (mask->match_sz > sizeof(struct mlx5dr_match_param)) {
643 mlx5dr_info(dmn, "Invalid match size attribute\n");
644 return -EINVAL;
645 }
646 mlx5dr_ste_copy_param(matcher->match_criteria,
647 &matcher->mask, mask);
648 }
649
650 switch (dmn->type) {
651 case MLX5DR_DOMAIN_TYPE_NIC_RX:
652 matcher->rx.nic_tbl = &tbl->rx;
653 ret = dr_matcher_init_nic(matcher, &matcher->rx);
654 break;
655 case MLX5DR_DOMAIN_TYPE_NIC_TX:
656 matcher->tx.nic_tbl = &tbl->tx;
657 ret = dr_matcher_init_nic(matcher, &matcher->tx);
658 break;
659 case MLX5DR_DOMAIN_TYPE_FDB:
660 matcher->rx.nic_tbl = &tbl->rx;
661 matcher->tx.nic_tbl = &tbl->tx;
662 ret = dr_matcher_init_fdb(matcher);
663 break;
664 default:
665 WARN_ON(true);
666 return -EINVAL;
667 }
668
669 return ret;
670}
671
672struct mlx5dr_matcher *
673mlx5dr_matcher_create(struct mlx5dr_table *tbl,
674 u16 priority,
675 u8 match_criteria_enable,
676 struct mlx5dr_match_parameters *mask)
677{
678 struct mlx5dr_matcher *matcher;
679 int ret;
680
681 refcount_inc(&tbl->refcount);
682
683 matcher = kzalloc(sizeof(*matcher), GFP_KERNEL);
684 if (!matcher)
685 goto dec_ref;
686
687 matcher->tbl = tbl;
688 matcher->prio = priority;
689 matcher->match_criteria = match_criteria_enable;
690 refcount_set(&matcher->refcount, 1);
691 INIT_LIST_HEAD(&matcher->matcher_list);
692
693 mutex_lock(&tbl->dmn->mutex);
694
695 ret = dr_matcher_init(matcher, mask);
696 if (ret)
697 goto free_matcher;
698
699 ret = dr_matcher_add_to_tbl(matcher);
700 if (ret)
701 goto matcher_uninit;
702
703 mutex_unlock(&tbl->dmn->mutex);
704
705 return matcher;
706
707matcher_uninit:
708 dr_matcher_uninit(matcher);
709free_matcher:
710 mutex_unlock(&tbl->dmn->mutex);
711 kfree(matcher);
712dec_ref:
713 refcount_dec(&tbl->refcount);
714 return NULL;
715}
716
717static int dr_matcher_disconnect(struct mlx5dr_domain *dmn,
718 struct mlx5dr_table_rx_tx *nic_tbl,
719 struct mlx5dr_matcher_rx_tx *next_nic_matcher,
720 struct mlx5dr_matcher_rx_tx *prev_nic_matcher)
721{
722 struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
723 struct mlx5dr_htbl_connect_info info;
724 struct mlx5dr_ste_htbl *prev_anchor;
725
726 if (prev_nic_matcher)
727 prev_anchor = prev_nic_matcher->e_anchor;
728 else
729 prev_anchor = nic_tbl->s_anchor;
730
731 /* Connect previous anchor hash table to next matcher or to the default address */
732 if (next_nic_matcher) {
733 info.type = CONNECT_HIT;
734 info.hit_next_htbl = next_nic_matcher->s_htbl;
735 next_nic_matcher->s_htbl->pointing_ste = prev_anchor->ste_arr;
736 prev_anchor->ste_arr[0].next_htbl = next_nic_matcher->s_htbl;
737 } else {
738 info.type = CONNECT_MISS;
739 info.miss_icm_addr = nic_tbl->default_icm_addr;
740 prev_anchor->ste_arr[0].next_htbl = NULL;
741 }
742
743 return mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, prev_anchor,
744 &info, true);
745}
746
747static int dr_matcher_remove_from_tbl(struct mlx5dr_matcher *matcher)
748{
749 struct mlx5dr_matcher *prev_matcher, *next_matcher;
750 struct mlx5dr_table *tbl = matcher->tbl;
751 struct mlx5dr_domain *dmn = tbl->dmn;
752 int ret = 0;
753
754 if (list_is_last(&matcher->matcher_list, &tbl->matcher_list))
755 next_matcher = NULL;
756 else
757 next_matcher = list_next_entry(matcher, matcher_list);
758
759 if (matcher->matcher_list.prev == &tbl->matcher_list)
760 prev_matcher = NULL;
761 else
762 prev_matcher = list_prev_entry(matcher, matcher_list);
763
764 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
765 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) {
766 ret = dr_matcher_disconnect(dmn, &tbl->rx,
767 next_matcher ? &next_matcher->rx : NULL,
768 prev_matcher ? &prev_matcher->rx : NULL);
769 if (ret)
770 return ret;
771 }
772
773 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB ||
774 dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) {
775 ret = dr_matcher_disconnect(dmn, &tbl->tx,
776 next_matcher ? &next_matcher->tx : NULL,
777 prev_matcher ? &prev_matcher->tx : NULL);
778 if (ret)
779 return ret;
780 }
781
782 list_del(&matcher->matcher_list);
783
784 return 0;
785}
786
787int mlx5dr_matcher_destroy(struct mlx5dr_matcher *matcher)
788{
789 struct mlx5dr_table *tbl = matcher->tbl;
790
791 if (refcount_read(&matcher->refcount) > 1)
792 return -EBUSY;
793
794 mutex_lock(&tbl->dmn->mutex);
795
796 dr_matcher_remove_from_tbl(matcher);
797 dr_matcher_uninit(matcher);
798 refcount_dec(&matcher->tbl->refcount);
799
800 mutex_unlock(&tbl->dmn->mutex);
801 kfree(matcher);
802
803 return 0;
804}