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
cn10k_mtr_connect(struct rte_eth_dev * eth_dev,uint32_t mtr_id)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
cn10k_mtr_destroy(struct rte_eth_dev * eth_dev,uint32_t mtr_id)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
cn10k_mtr_configure(struct rte_eth_dev * eth_dev,const struct rte_flow_action actions[])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
cn10k_rss_action_validate(struct rte_eth_dev * eth_dev,const struct rte_flow_attr * attr,const struct rte_flow_action * act)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 *
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)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
cn10k_flow_destroy(struct rte_eth_dev * eth_dev,struct rte_flow * rte_flow,struct rte_flow_error * error)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 }
245