1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2020 Marvell.
3 */
4 #include "cn10k_flow.h"
5 #include "cn10k_ethdev.h"
6 #include "cn10k_rx.h"
7 #include "cnxk_ethdev_mcs.h"
8 #include <cnxk_flow.h>
9
10 static int
cn10k_mtr_connect(struct rte_eth_dev * eth_dev,uint32_t mtr_id)11 cn10k_mtr_connect(struct rte_eth_dev *eth_dev, uint32_t mtr_id)
12 {
13 return nix_mtr_connect(eth_dev, mtr_id);
14 }
15
16 static int
cn10k_mtr_destroy(struct rte_eth_dev * eth_dev,uint32_t mtr_id)17 cn10k_mtr_destroy(struct rte_eth_dev *eth_dev, uint32_t mtr_id)
18 {
19 struct rte_mtr_error mtr_error;
20
21 return nix_mtr_destroy(eth_dev, mtr_id, &mtr_error);
22 }
23
24 static int
cn10k_mtr_configure(struct rte_eth_dev * eth_dev,const struct rte_flow_action actions[])25 cn10k_mtr_configure(struct rte_eth_dev *eth_dev,
26 const struct rte_flow_action actions[])
27 {
28 uint32_t mtr_id = 0xffff, prev_mtr_id = 0xffff, next_mtr_id = 0xffff;
29 const struct rte_flow_action_meter *mtr_conf;
30 const struct rte_flow_action_queue *q_conf;
31 const struct rte_flow_action_rss *rss_conf;
32 struct cnxk_mtr_policy_node *policy;
33 bool is_mtr_act = false;
34 int tree_level = 0;
35 int rc = -EINVAL, i;
36
37 for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
38 if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
39 mtr_conf = (const struct rte_flow_action_meter
40 *)(actions[i].conf);
41 mtr_id = mtr_conf->mtr_id;
42 is_mtr_act = true;
43 }
44 if (actions[i].type == RTE_FLOW_ACTION_TYPE_QUEUE) {
45 q_conf = (const struct rte_flow_action_queue
46 *)(actions[i].conf);
47 if (is_mtr_act)
48 nix_mtr_rq_update(eth_dev, mtr_id, 1,
49 &q_conf->index);
50 }
51 if (actions[i].type == RTE_FLOW_ACTION_TYPE_RSS) {
52 rss_conf = (const struct rte_flow_action_rss
53 *)(actions[i].conf);
54 if (is_mtr_act)
55 nix_mtr_rq_update(eth_dev, mtr_id,
56 rss_conf->queue_num,
57 rss_conf->queue);
58 }
59 }
60
61 if (!is_mtr_act)
62 return rc;
63
64 prev_mtr_id = mtr_id;
65 next_mtr_id = mtr_id;
66 while (next_mtr_id != 0xffff) {
67 rc = nix_mtr_validate(eth_dev, next_mtr_id);
68 if (rc)
69 return rc;
70
71 rc = nix_mtr_policy_act_get(eth_dev, next_mtr_id, &policy);
72 if (rc)
73 return rc;
74
75 rc = nix_mtr_color_action_validate(eth_dev, mtr_id,
76 &prev_mtr_id, &next_mtr_id,
77 policy, &tree_level);
78 if (rc)
79 return rc;
80 }
81
82 return nix_mtr_configure(eth_dev, mtr_id);
83 }
84
85 static int
cn10k_rss_action_validate(struct rte_eth_dev * eth_dev,const struct rte_flow_attr * attr,const struct rte_flow_action * act)86 cn10k_rss_action_validate(struct rte_eth_dev *eth_dev,
87 const struct rte_flow_attr *attr,
88 const struct rte_flow_action *act)
89 {
90 const struct rte_flow_action_rss *rss;
91
92 if (act == NULL)
93 return -EINVAL;
94
95 rss = (const struct rte_flow_action_rss *)act->conf;
96
97 if (attr->egress) {
98 plt_err("No support of RSS in egress");
99 return -EINVAL;
100 }
101
102 if (eth_dev->data->dev_conf.rxmode.mq_mode != RTE_ETH_MQ_RX_RSS) {
103 plt_err("multi-queue mode is disabled");
104 return -ENOTSUP;
105 }
106
107 if (!rss || !rss->queue_num) {
108 plt_err("no valid queues");
109 return -EINVAL;
110 }
111
112 if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
113 plt_err("non-default RSS hash functions are not supported");
114 return -ENOTSUP;
115 }
116
117 if (rss->key_len && rss->key_len > ROC_NIX_RSS_KEY_LEN) {
118 plt_err("RSS hash key too large");
119 return -ENOTSUP;
120 }
121
122 return 0;
123 }
124
125 struct rte_flow *
cn10k_flow_create(struct rte_eth_dev * eth_dev,const struct rte_flow_attr * attr,const struct rte_flow_item pattern[],const struct rte_flow_action actions[],struct rte_flow_error * error)126 cn10k_flow_create(struct rte_eth_dev *eth_dev, const struct rte_flow_attr *attr,
127 const struct rte_flow_item pattern[],
128 const struct rte_flow_action actions[],
129 struct rte_flow_error *error)
130 {
131 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
132 const struct rte_flow_action *action_rss = NULL;
133 const struct rte_flow_action_meter *mtr = NULL;
134 const struct rte_flow_action *act_q = NULL;
135 struct roc_npc *npc = &dev->npc;
136 struct roc_npc_flow *flow;
137 void *mcs_flow = NULL;
138 int vtag_actions = 0;
139 uint32_t req_act = 0;
140 int mark_actions;
141 int i, rc;
142
143 for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
144 if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER)
145 req_act |= ROC_NPC_ACTION_TYPE_METER;
146
147 if (actions[i].type == RTE_FLOW_ACTION_TYPE_QUEUE) {
148 req_act |= ROC_NPC_ACTION_TYPE_QUEUE;
149 act_q = &actions[i];
150 }
151 if (actions[i].type == RTE_FLOW_ACTION_TYPE_RSS) {
152 req_act |= ROC_NPC_ACTION_TYPE_RSS;
153 action_rss = &actions[i];
154 }
155 }
156
157 if (req_act & ROC_NPC_ACTION_TYPE_METER) {
158 if ((req_act & ROC_NPC_ACTION_TYPE_RSS) &&
159 ((req_act & ROC_NPC_ACTION_TYPE_QUEUE))) {
160 return NULL;
161 }
162 if (req_act & ROC_NPC_ACTION_TYPE_RSS) {
163 rc = cn10k_rss_action_validate(eth_dev, attr,
164 action_rss);
165 if (rc)
166 return NULL;
167 } else if (req_act & ROC_NPC_ACTION_TYPE_QUEUE) {
168 const struct rte_flow_action_queue *act_queue;
169 act_queue = (const struct rte_flow_action_queue *)
170 act_q->conf;
171 if (act_queue->index > eth_dev->data->nb_rx_queues)
172 return NULL;
173 } else {
174 return NULL;
175 }
176 }
177 for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
178 if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
179 mtr = (const struct rte_flow_action_meter *)actions[i]
180 .conf;
181 rc = cn10k_mtr_configure(eth_dev, actions);
182 if (rc) {
183 rte_flow_error_set(error, rc,
184 RTE_FLOW_ERROR_TYPE_ACTION, NULL,
185 "Failed to configure mtr ");
186 return NULL;
187 }
188 break;
189 }
190 }
191
192 if (actions[0].type == RTE_FLOW_ACTION_TYPE_SECURITY &&
193 cnxk_eth_macsec_sess_get_by_sess(dev, actions[0].conf) != NULL) {
194 rc = cnxk_mcs_flow_configure(eth_dev, attr, pattern, actions, error, &mcs_flow);
195 if (rc) {
196 rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_ACTION, NULL,
197 "Failed to configure mcs flow");
198 return NULL;
199 }
200 return (struct rte_flow *)mcs_flow;
201 }
202
203 flow = cnxk_flow_create(eth_dev, attr, pattern, actions, error);
204 if (!flow) {
205 if (mtr)
206 nix_mtr_chain_reset(eth_dev, mtr->mtr_id);
207
208 return NULL;
209 } else {
210 if (mtr)
211 cn10k_mtr_connect(eth_dev, mtr->mtr_id);
212 }
213
214 mark_actions = roc_npc_mark_actions_get(npc);
215 if (mark_actions) {
216 dev->rx_offload_flags |= NIX_RX_OFFLOAD_MARK_UPDATE_F;
217 cn10k_eth_set_rx_function(eth_dev);
218 }
219
220 vtag_actions = roc_npc_vtag_actions_get(npc);
221
222 if (vtag_actions) {
223 dev->rx_offload_flags |= NIX_RX_OFFLOAD_VLAN_STRIP_F;
224 cn10k_eth_set_rx_function(eth_dev);
225 }
226
227 return (struct rte_flow *)flow;
228 }
229
230 int
cn10k_flow_info_get(struct rte_eth_dev * dev,struct rte_flow_port_info * port_info,struct rte_flow_queue_info * queue_info,struct rte_flow_error * err)231 cn10k_flow_info_get(struct rte_eth_dev *dev, struct rte_flow_port_info *port_info,
232 struct rte_flow_queue_info *queue_info, struct rte_flow_error *err)
233 {
234 RTE_SET_USED(dev);
235 RTE_SET_USED(err);
236
237 memset(port_info, 0, sizeof(*port_info));
238 memset(queue_info, 0, sizeof(*queue_info));
239
240 port_info->max_nb_counters = CN10K_NPC_COUNTERS_MAX;
241 port_info->max_nb_meters = CNXK_NIX_MTR_COUNT_MAX;
242
243 return 0;
244 }
245
246 int
cn10k_flow_destroy(struct rte_eth_dev * eth_dev,struct rte_flow * rte_flow,struct rte_flow_error * error)247 cn10k_flow_destroy(struct rte_eth_dev *eth_dev, struct rte_flow *rte_flow,
248 struct rte_flow_error *error)
249 {
250 struct roc_npc_flow *flow = (struct roc_npc_flow *)rte_flow;
251 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
252 struct roc_npc *npc = &dev->npc;
253 int vtag_actions = 0;
254 int mark_actions;
255 uint16_t match_id;
256 uint32_t mtr_id;
257 int rc;
258
259 match_id = (flow->npc_action >> NPC_RX_ACT_MATCH_OFFSET) &
260 NPC_RX_ACT_MATCH_MASK;
261 if (match_id) {
262 mark_actions = roc_npc_mark_actions_sub_return(npc, 1);
263 if (mark_actions == 0) {
264 dev->rx_offload_flags &= ~NIX_RX_OFFLOAD_MARK_UPDATE_F;
265 cn10k_eth_set_rx_function(eth_dev);
266 }
267 }
268
269 vtag_actions = roc_npc_vtag_actions_get(npc);
270 if (vtag_actions) {
271 if (flow->nix_intf == ROC_NPC_INTF_RX) {
272 vtag_actions = roc_npc_vtag_actions_sub_return(npc, 1);
273 if (vtag_actions == 0) {
274 dev->rx_offload_flags &=
275 ~NIX_RX_OFFLOAD_VLAN_STRIP_F;
276 cn10k_eth_set_rx_function(eth_dev);
277 }
278 }
279 }
280
281 if (cnxk_eth_macsec_sess_get_by_sess(dev, (void *)flow) != NULL) {
282 rc = cnxk_mcs_flow_destroy(dev, (void *)flow);
283 if (rc < 0)
284 rte_flow_error_set(error, rc, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
285 NULL, "Failed to free mcs flow");
286 return rc;
287 }
288
289 mtr_id = flow->mtr_id;
290 rc = cnxk_flow_destroy(eth_dev, flow, error);
291 if (!rc && mtr_id != ROC_NIX_MTR_ID_INVALID) {
292 rc = cn10k_mtr_destroy(eth_dev, mtr_id);
293 if (rc) {
294 rte_flow_error_set(error, ENXIO,
295 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
296 "Meter attached to this flow does not exist");
297 }
298 }
299 return rc;
300 }
301