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