xref: /dpdk/drivers/net/cnxk/cn10k_flow.c (revision 4c8c8516)
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