Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / net / ethernet / microchip / sparx5 / sparx5_tc_matchall.c
blob6b4d1d7b9730220e5954791a3bf35e7fbd580dac
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip VCAP API
4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5 */
7 #include "sparx5_tc.h"
8 #include "vcap_api.h"
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)
21 return entry;
24 return NULL;
27 static void sparx5_tc_matchall_parse_action(struct sparx5_port *port,
28 struct sparx5_mall_entry *entry,
29 struct flow_action_entry *action,
30 bool ingress,
31 unsigned long cookie)
33 entry->port = port;
34 entry->type = action->id;
35 entry->ingress = ingress;
36 entry->cookie = cookie;
39 static void
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,
48 bool ingress)
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;
54 int err;
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");
59 return -EOPNOTSUPP;
61 action = &tmo->rule->action.entries[0];
63 mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL);
64 if (!mall_entry)
65 return -ENOMEM;
67 sparx5_tc_matchall_parse_action(port,
68 mall_entry,
69 action,
70 ingress,
71 tmo->cookie);
73 sparx5 = port->sparx5;
74 switch (action->id) {
75 case FLOW_ACTION_MIRRED:
76 sparx5_tc_matchall_parse_mirror_action(mall_entry, action);
77 err = sparx5_mirror_add(mall_entry);
78 if (err) {
79 switch (err) {
80 case -EEXIST:
81 NL_SET_ERR_MSG_MOD(tmo->common.extack,
82 "Mirroring already exists");
83 break;
84 case -EINVAL:
85 NL_SET_ERR_MSG_MOD(tmo->common.extack,
86 "Cannot mirror a monitor port");
87 break;
88 case -ENOENT:
89 NL_SET_ERR_MSG_MOD(tmo->common.extack,
90 "No more mirror probes available");
91 break;
92 default:
93 NL_SET_ERR_MSG_MOD(tmo->common.extack,
94 "Unknown error");
95 break;
97 return err;
99 /* Get baseline stats for this port */
100 sparx5_mirror_stats(mall_entry, &tmo->stats);
101 break;
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,
106 true);
107 if (err == -EFAULT) {
108 NL_SET_ERR_MSG_MOD(tmo->common.extack,
109 "Unsupported goto chain");
110 return -EOPNOTSUPP;
112 if (err == -EADDRINUSE) {
113 NL_SET_ERR_MSG_MOD(tmo->common.extack,
114 "VCAP already enabled");
115 return -EOPNOTSUPP;
117 if (err == -EADDRNOTAVAIL) {
118 NL_SET_ERR_MSG_MOD(tmo->common.extack,
119 "Already matching this chain");
120 return -EOPNOTSUPP;
122 if (err) {
123 NL_SET_ERR_MSG_MOD(tmo->common.extack,
124 "Could not enable VCAP lookups");
125 return err;
127 break;
128 default:
129 NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
130 return -EOPNOTSUPP;
133 list_add_tail(&mall_entry->list, &sparx5->mall_entries);
135 return 0;
138 static int sparx5_tc_matchall_destroy(struct net_device *ndev,
139 struct tc_cls_matchall_offload *tmo,
140 bool ingress)
142 struct sparx5_port *port = netdev_priv(ndev);
143 struct sparx5 *sparx5 = port->sparx5;
144 struct sparx5_mall_entry *entry;
145 int err = 0;
147 entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries,
148 tmo->cookie);
149 if (!entry)
150 return -ENOENT;
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);
157 } else {
158 NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
159 err = -EOPNOTSUPP;
162 list_del(&entry->list);
164 return err;
167 static int sparx5_tc_matchall_stats(struct net_device *ndev,
168 struct tc_cls_matchall_offload *tmo,
169 bool ingress)
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,
176 tmo->cookie);
177 if (!entry)
178 return -ENOENT;
180 if (entry->type == FLOW_ACTION_MIRRED) {
181 sparx5_mirror_stats(entry, &tmo->stats);
182 } else {
183 NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
184 return -EOPNOTSUPP;
187 return 0;
190 int sparx5_tc_matchall(struct net_device *ndev,
191 struct tc_cls_matchall_offload *tmo,
192 bool ingress)
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);
201 default:
202 return -EOPNOTSUPP;