examples/l3fwd: share queue size variables
[dpdk.git] / drivers / net / cnxk / cn10k_flow.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Marvell.
3  */
4 #include <cnxk_flow.h>
5 #include "cn10k_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[i].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[i].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[i].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 != RTE_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         struct roc_npc *npc = &dev->npc;
135         struct roc_npc_flow *flow;
136         int vtag_actions = 0;
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         for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
175                 if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
176                         mtr = (const struct rte_flow_action_meter *)actions[i]
177                                       .conf;
178                         rc = cn10k_mtr_configure(eth_dev, actions);
179                         if (rc) {
180                                 rte_flow_error_set(error, rc,
181                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
182                                         "Failed to configure mtr ");
183                                 return NULL;
184                         }
185                         break;
186                 }
187         }
188
189         flow = cnxk_flow_create(eth_dev, attr, pattern, actions, error);
190         if (!flow) {
191                 if (mtr)
192                         nix_mtr_chain_reset(eth_dev, mtr->mtr_id);
193
194                 return NULL;
195         } else {
196                 if (mtr)
197                         cn10k_mtr_connect(eth_dev, mtr->mtr_id);
198         }
199
200         vtag_actions = roc_npc_vtag_actions_get(npc);
201
202         if (vtag_actions) {
203                 dev->rx_offload_flags |= NIX_RX_OFFLOAD_VLAN_STRIP_F;
204                 cn10k_eth_set_rx_function(eth_dev);
205         }
206
207         return (struct rte_flow *)flow;
208 }
209
210 int
211 cn10k_flow_destroy(struct rte_eth_dev *eth_dev, struct rte_flow *rte_flow,
212                    struct rte_flow_error *error)
213 {
214         struct roc_npc_flow *flow = (struct roc_npc_flow *)rte_flow;
215         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
216         struct roc_npc *npc = &dev->npc;
217         int vtag_actions = 0;
218         uint32_t mtr_id;
219         int rc;
220
221         vtag_actions = roc_npc_vtag_actions_get(npc);
222         if (vtag_actions) {
223                 if (flow->nix_intf == ROC_NPC_INTF_RX) {
224                         vtag_actions = roc_npc_vtag_actions_sub_return(npc, 1);
225                         if (vtag_actions == 0) {
226                                 dev->rx_offload_flags &=
227                                         ~NIX_RX_OFFLOAD_VLAN_STRIP_F;
228                                 cn10k_eth_set_rx_function(eth_dev);
229                         }
230                 }
231         }
232
233         mtr_id = flow->mtr_id;
234         rc = cnxk_flow_destroy(eth_dev, flow, error);
235         if (!rc && mtr_id != ROC_NIX_MTR_ID_INVALID) {
236                 rc = cn10k_mtr_destroy(eth_dev, mtr_id);
237                 if (rc) {
238                         rte_flow_error_set(error, ENXIO,
239                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
240                                 "Meter attached to this flow does not exist");
241                 }
242         }
243         return rc;
244 }