1 // SPDX-License-Identifier: GPL-2.0+
4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
9 #include "vcap_api_client.h"
10 #include "sparx5_main_regs.h"
11 #include "sparx5_main.h"
12 #include "sparx5_vcap_impl.h"
14 static struct sparx5_mall_entry
*
15 sparx5_tc_matchall_entry_find(struct list_head
*entries
, unsigned long cookie
)
17 struct sparx5_mall_entry
*entry
;
19 list_for_each_entry(entry
, entries
, list
) {
20 if (entry
->cookie
== cookie
)
27 static void sparx5_tc_matchall_parse_action(struct sparx5_port
*port
,
28 struct sparx5_mall_entry
*entry
,
29 struct flow_action_entry
*action
,
34 entry
->type
= action
->id
;
35 entry
->ingress
= ingress
;
36 entry
->cookie
= cookie
;
40 sparx5_tc_matchall_parse_mirror_action(struct sparx5_mall_entry
*entry
,
41 struct flow_action_entry
*action
)
43 entry
->mirror
.port
= netdev_priv(action
->dev
);
46 static int sparx5_tc_matchall_replace(struct net_device
*ndev
,
47 struct tc_cls_matchall_offload
*tmo
,
50 struct sparx5_port
*port
= netdev_priv(ndev
);
51 struct sparx5_mall_entry
*mall_entry
;
52 struct flow_action_entry
*action
;
53 struct sparx5
*sparx5
;
56 if (!flow_offload_has_one_action(&tmo
->rule
->action
)) {
57 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
58 "Only one action per filter is supported");
61 action
= &tmo
->rule
->action
.entries
[0];
63 mall_entry
= kzalloc(sizeof(*mall_entry
), GFP_KERNEL
);
67 sparx5_tc_matchall_parse_action(port
,
73 sparx5
= port
->sparx5
;
75 case FLOW_ACTION_MIRRED
:
76 sparx5_tc_matchall_parse_mirror_action(mall_entry
, action
);
77 err
= sparx5_mirror_add(mall_entry
);
81 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
82 "Mirroring already exists");
85 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
86 "Cannot mirror a monitor port");
89 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
90 "No more mirror probes available");
93 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
99 /* Get baseline stats for this port */
100 sparx5_mirror_stats(mall_entry
, &tmo
->stats
);
102 case FLOW_ACTION_GOTO
:
103 err
= vcap_enable_lookups(sparx5
->vcap_ctrl
, ndev
,
104 tmo
->common
.chain_index
,
105 action
->chain_index
, tmo
->cookie
,
107 if (err
== -EFAULT
) {
108 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
109 "Unsupported goto chain");
112 if (err
== -EADDRINUSE
) {
113 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
114 "VCAP already enabled");
117 if (err
== -EADDRNOTAVAIL
) {
118 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
119 "Already matching this chain");
123 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
,
124 "Could not enable VCAP lookups");
129 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
, "Unsupported action");
133 list_add_tail(&mall_entry
->list
, &sparx5
->mall_entries
);
138 static int sparx5_tc_matchall_destroy(struct net_device
*ndev
,
139 struct tc_cls_matchall_offload
*tmo
,
142 struct sparx5_port
*port
= netdev_priv(ndev
);
143 struct sparx5
*sparx5
= port
->sparx5
;
144 struct sparx5_mall_entry
*entry
;
147 entry
= sparx5_tc_matchall_entry_find(&sparx5
->mall_entries
,
152 if (entry
->type
== FLOW_ACTION_MIRRED
) {
153 sparx5_mirror_del(entry
);
154 } else if (entry
->type
== FLOW_ACTION_GOTO
) {
155 err
= vcap_enable_lookups(sparx5
->vcap_ctrl
, ndev
,
156 0, 0, tmo
->cookie
, false);
158 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
, "Unsupported action");
162 list_del(&entry
->list
);
167 static int sparx5_tc_matchall_stats(struct net_device
*ndev
,
168 struct tc_cls_matchall_offload
*tmo
,
171 struct sparx5_port
*port
= netdev_priv(ndev
);
172 struct sparx5
*sparx5
= port
->sparx5
;
173 struct sparx5_mall_entry
*entry
;
175 entry
= sparx5_tc_matchall_entry_find(&sparx5
->mall_entries
,
180 if (entry
->type
== FLOW_ACTION_MIRRED
) {
181 sparx5_mirror_stats(entry
, &tmo
->stats
);
183 NL_SET_ERR_MSG_MOD(tmo
->common
.extack
, "Unsupported action");
190 int sparx5_tc_matchall(struct net_device
*ndev
,
191 struct tc_cls_matchall_offload
*tmo
,
194 switch (tmo
->command
) {
195 case TC_CLSMATCHALL_REPLACE
:
196 return sparx5_tc_matchall_replace(ndev
, tmo
, ingress
);
197 case TC_CLSMATCHALL_DESTROY
:
198 return sparx5_tc_matchall_destroy(ndev
, tmo
, ingress
);
199 case TC_CLSMATCHALL_STATS
:
200 return sparx5_tc_matchall_stats(ndev
, tmo
, ingress
);