net/cnxk: support meter action to flow create
[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_configure(struct rte_eth_dev *eth_dev,
17                     const struct rte_flow_action actions[])
18 {
19         uint32_t mtr_id = 0xffff, prev_mtr_id = 0xffff, next_mtr_id = 0xffff;
20         const struct rte_flow_action_meter *mtr_conf;
21         const struct rte_flow_action_queue *q_conf;
22         const struct rte_flow_action_rss *rss_conf;
23         struct cnxk_mtr_policy_node *policy;
24         bool is_mtr_act = false;
25         int tree_level = 0;
26         int rc = -EINVAL, i;
27
28         for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
29                 if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
30                         mtr_conf = (const struct rte_flow_action_meter
31                                             *)(actions->conf);
32                         mtr_id = mtr_conf->mtr_id;
33                         is_mtr_act = true;
34                 }
35                 if (actions[i].type == RTE_FLOW_ACTION_TYPE_QUEUE) {
36                         q_conf = (const struct rte_flow_action_queue
37                                           *)(actions->conf);
38                         if (is_mtr_act)
39                                 nix_mtr_rq_update(eth_dev, mtr_id, 1,
40                                                   &q_conf->index);
41                 }
42                 if (actions[i].type == RTE_FLOW_ACTION_TYPE_RSS) {
43                         rss_conf = (const struct rte_flow_action_rss
44                                             *)(actions->conf);
45                         if (is_mtr_act)
46                                 nix_mtr_rq_update(eth_dev, mtr_id,
47                                                   rss_conf->queue_num,
48                                                   rss_conf->queue);
49                 }
50         }
51
52         if (!is_mtr_act)
53                 return rc;
54
55         prev_mtr_id = mtr_id;
56         next_mtr_id = mtr_id;
57         while (next_mtr_id != 0xffff) {
58                 rc = nix_mtr_validate(eth_dev, next_mtr_id);
59                 if (rc)
60                         return rc;
61
62                 rc = nix_mtr_policy_act_get(eth_dev, next_mtr_id, &policy);
63                 if (rc)
64                         return rc;
65
66                 rc = nix_mtr_color_action_validate(eth_dev, mtr_id,
67                                                    &prev_mtr_id, &next_mtr_id,
68                                                    policy, &tree_level);
69                 if (rc)
70                         return rc;
71         }
72
73         return nix_mtr_configure(eth_dev, mtr_id);
74 }
75
76 static int
77 cn10k_rss_action_validate(struct rte_eth_dev *eth_dev,
78                           const struct rte_flow_attr *attr,
79                           const struct rte_flow_action *act)
80 {
81         const struct rte_flow_action_rss *rss;
82
83         if (act == NULL)
84                 return -EINVAL;
85
86         rss = (const struct rte_flow_action_rss *)act->conf;
87
88         if (attr->egress) {
89                 plt_err("No support of RSS in egress");
90                 return -EINVAL;
91         }
92
93         if (eth_dev->data->dev_conf.rxmode.mq_mode != ETH_MQ_RX_RSS) {
94                 plt_err("multi-queue mode is disabled");
95                 return -ENOTSUP;
96         }
97
98         if (!rss || !rss->queue_num) {
99                 plt_err("no valid queues");
100                 return -EINVAL;
101         }
102
103         if (rss->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
104                 plt_err("non-default RSS hash functions are not supported");
105                 return -ENOTSUP;
106         }
107
108         if (rss->key_len && rss->key_len > ROC_NIX_RSS_KEY_LEN) {
109                 plt_err("RSS hash key too large");
110                 return -ENOTSUP;
111         }
112
113         return 0;
114 }
115
116 struct rte_flow *
117 cn10k_flow_create(struct rte_eth_dev *eth_dev, const struct rte_flow_attr *attr,
118                   const struct rte_flow_item pattern[],
119                   const struct rte_flow_action actions[],
120                   struct rte_flow_error *error)
121 {
122         struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
123         const struct rte_flow_action *action_rss = NULL;
124         const struct rte_flow_action_meter *mtr = NULL;
125         const struct rte_flow_action *act_q = NULL;
126         int mark_actions = 0, vtag_actions = 0;
127         struct roc_npc *npc = &dev->npc;
128         struct roc_npc_flow *flow;
129         uint32_t req_act = 0;
130         int i, rc;
131
132         for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
133                 if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER)
134                         req_act |= ROC_NPC_ACTION_TYPE_METER;
135
136                 if (actions[i].type == RTE_FLOW_ACTION_TYPE_QUEUE) {
137                         req_act |= ROC_NPC_ACTION_TYPE_QUEUE;
138                         act_q = &actions[i];
139                 }
140                 if (actions[i].type == RTE_FLOW_ACTION_TYPE_RSS) {
141                         req_act |= ROC_NPC_ACTION_TYPE_RSS;
142                         action_rss = &actions[i];
143                 }
144         }
145
146         if (req_act & ROC_NPC_ACTION_TYPE_METER) {
147                 if ((req_act & ROC_NPC_ACTION_TYPE_RSS) &&
148                     ((req_act & ROC_NPC_ACTION_TYPE_QUEUE))) {
149                         return NULL;
150                 }
151                 if (req_act & ROC_NPC_ACTION_TYPE_RSS) {
152                         rc = cn10k_rss_action_validate(eth_dev, attr,
153                                                        action_rss);
154                         if (rc)
155                                 return NULL;
156                 } else if (req_act & ROC_NPC_ACTION_TYPE_QUEUE) {
157                         const struct rte_flow_action_queue *act_queue;
158                         act_queue = (const struct rte_flow_action_queue *)
159                                             act_q->conf;
160                         if (act_queue->index > eth_dev->data->nb_rx_queues)
161                                 return NULL;
162                 } else {
163                         return NULL;
164                 }
165         }
166
167         for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
168                 if (actions[i].type == RTE_FLOW_ACTION_TYPE_METER) {
169                         mtr = (const struct rte_flow_action_meter *)actions[i]
170                                       .conf;
171                         rc = cn10k_mtr_configure(eth_dev, actions);
172                         if (rc) {
173                                 rte_flow_error_set(error, rc,
174                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
175                                         "Failed to configure mtr ");
176                                 return NULL;
177                         }
178                         break;
179                 }
180         }
181
182         flow = cnxk_flow_create(eth_dev, attr, pattern, actions, error);
183         if (!flow) {
184                 if (mtr)
185                         nix_mtr_chain_reset(eth_dev, mtr->mtr_id);
186
187                 return NULL;
188         } else {
189                 if (mtr)
190                         cn10k_mtr_connect(eth_dev, mtr->mtr_id);
191         }
192
193         mark_actions = roc_npc_mark_actions_get(npc);
194
195         if (mark_actions) {
196                 dev->rx_offload_flags |= NIX_RX_OFFLOAD_MARK_UPDATE_F;
197                 cn10k_eth_set_rx_function(eth_dev);
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         int mark_actions = 0, vtag_actions = 0;
217         struct roc_npc *npc = &dev->npc;
218
219         mark_actions = roc_npc_mark_actions_get(npc);
220         if (mark_actions) {
221                 mark_actions = roc_npc_mark_actions_sub_return(npc, 1);
222                 if (mark_actions == 0) {
223                         dev->rx_offload_flags &= ~NIX_RX_OFFLOAD_MARK_UPDATE_F;
224                         cn10k_eth_set_rx_function(eth_dev);
225                 }
226         }
227
228         vtag_actions = roc_npc_vtag_actions_get(npc);
229         if (vtag_actions) {
230                 if (flow->nix_intf == ROC_NPC_INTF_RX) {
231                         vtag_actions = roc_npc_vtag_actions_sub_return(npc, 1);
232                         if (vtag_actions == 0) {
233                                 dev->rx_offload_flags &=
234                                         ~NIX_RX_OFFLOAD_VLAN_STRIP_F;
235                                 cn10k_eth_set_rx_function(eth_dev);
236                         }
237                 }
238         }
239
240         return cnxk_flow_destroy(eth_dev, flow, error);
241 }