xref: /dpdk/drivers/net/mvpp2/mrvl_mtr.c (revision 784b83495bc5c40c5aa91d1e4d3966ec22e59e38)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Marvell International Ltd.
3  * Copyright(c) 2018 Semihalf.
4  * All rights reserved.
5  */
6 
7 #include <rte_log.h>
8 #include <rte_malloc.h>
9 
10 #include "mrvl_mtr.h"
11 
12 /** Maximum meter rate */
13 #define MRVL_SRTCM_RFC2697_CIR_MAX 1023000
14 
15 /** Invalid plcr bit */
16 #define MRVL_PLCR_BIT_INVALID -1
17 
18 /**
19  * Return meter object capabilities.
20  *
21  * @param dev Pointer to the device (unused).
22  * @param cap Pointer to the meter object capabilities.
23  * @param error Pointer to the error (unused).
24  * @returns 0 always.
25  */
26 static int
mrvl_capabilities_get(struct rte_eth_dev * dev __rte_unused,struct rte_mtr_capabilities * cap,struct rte_mtr_error * error __rte_unused)27 mrvl_capabilities_get(struct rte_eth_dev *dev __rte_unused,
28 			  struct rte_mtr_capabilities *cap,
29 			  struct rte_mtr_error *error __rte_unused)
30 {
31 	struct rte_mtr_capabilities capa = {
32 		.n_max = PP2_CLS_PLCR_NUM,
33 		.n_shared_max = PP2_CLS_PLCR_NUM,
34 		.shared_n_flows_per_mtr_max = -1,
35 		.meter_srtcm_rfc2697_n_max = PP2_CLS_PLCR_NUM,
36 		.meter_rate_max = MRVL_SRTCM_RFC2697_CIR_MAX,
37 	};
38 
39 	memcpy(cap, &capa, sizeof(capa));
40 
41 	return 0;
42 }
43 
44 /**
45  * Get profile using it's id.
46  *
47  * @param priv Pointer to the port's private data.
48  * @param meter_profile_id Profile id used by the meter.
49  * @returns Pointer to the profile if exists, NULL otherwise.
50  */
51 static struct mrvl_mtr_profile *
mrvl_mtr_profile_from_id(struct mrvl_priv * priv,uint32_t meter_profile_id)52 mrvl_mtr_profile_from_id(struct mrvl_priv *priv, uint32_t meter_profile_id)
53 {
54 	struct mrvl_mtr_profile *profile = NULL;
55 
56 	LIST_FOREACH(profile, &priv->profiles, next)
57 		if (profile->profile_id == meter_profile_id)
58 			break;
59 
60 	return profile;
61 }
62 
63 /**
64  * Add profile to the list of profiles.
65  *
66  * @param dev Pointer to the device.
67  * @param meter_profile_id Id of the new profile.
68  * @param profile Pointer to the profile configuration.
69  * @param error Pointer to the error.
70  * @returns 0 on success, negative value otherwise.
71  */
72 static int
mrvl_meter_profile_add(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_meter_profile * profile,struct rte_mtr_error * error)73 mrvl_meter_profile_add(struct rte_eth_dev *dev, uint32_t meter_profile_id,
74 		       struct rte_mtr_meter_profile *profile,
75 		       struct rte_mtr_error *error)
76 {
77 	struct mrvl_priv *priv = dev->data->dev_private;
78 	struct mrvl_mtr_profile *prof;
79 
80 	if (!profile)
81 		return -rte_mtr_error_set(error, EINVAL,
82 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
83 					  NULL, NULL);
84 
85 	if (profile->alg != RTE_MTR_SRTCM_RFC2697)
86 		return -rte_mtr_error_set(error, EINVAL,
87 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
88 					  NULL,
89 					  "Only srTCM RFC 2697 is supported\n");
90 
91 	if (profile->packet_mode)
92 		return -rte_mtr_error_set(error, EINVAL,
93 				RTE_MTR_ERROR_TYPE_METER_PROFILE_PACKET_MODE,
94 				NULL,
95 				"Packet mode is not supported\n");
96 
97 	prof = mrvl_mtr_profile_from_id(priv, meter_profile_id);
98 	if (prof)
99 		return -rte_mtr_error_set(error, EEXIST,
100 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
101 					  NULL, "Profile id already exists\n");
102 
103 	prof = rte_zmalloc_socket(NULL, sizeof(*prof), 0, rte_socket_id());
104 	if (!prof)
105 		return -rte_mtr_error_set(error, ENOMEM,
106 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
107 					  NULL, NULL);
108 
109 	prof->profile_id = meter_profile_id;
110 	memcpy(&prof->profile, profile, sizeof(*profile));
111 
112 	LIST_INSERT_HEAD(&priv->profiles, prof, next);
113 
114 	return 0;
115 }
116 
117 /**
118  * Remove profile from the list of profiles.
119  *
120  * @param dev Pointer to the device.
121  * @param meter_profile_id Id of the profile to remove.
122  * @param error Pointer to the error.
123  * @returns 0 on success, negative value otherwise.
124  */
125 static int
mrvl_meter_profile_delete(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_error * error)126 mrvl_meter_profile_delete(struct rte_eth_dev *dev,
127 			      uint32_t meter_profile_id,
128 			      struct rte_mtr_error *error)
129 {
130 	struct mrvl_priv *priv = dev->data->dev_private;
131 	struct mrvl_mtr_profile *profile;
132 
133 	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
134 	if (!profile)
135 		return -rte_mtr_error_set(error, ENODEV,
136 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
137 					  NULL, "Profile id does not exist\n");
138 
139 	if (profile->refcnt)
140 		return -rte_mtr_error_set(error, EPERM,
141 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
142 					  NULL, "Profile is used\n");
143 
144 	LIST_REMOVE(profile, next);
145 	rte_free(profile);
146 
147 	return 0;
148 }
149 
150 /**
151  * Get meter using it's id.
152  *
153  * @param priv Pointer to port's private data.
154  * @param mtr_id Id of the meter.
155  * @returns Pointer to the meter if exists, NULL otherwise.
156  */
157 static struct mrvl_mtr *
mrvl_mtr_from_id(struct mrvl_priv * priv,uint32_t mtr_id)158 mrvl_mtr_from_id(struct mrvl_priv *priv, uint32_t mtr_id)
159 {
160 	struct mrvl_mtr *mtr = NULL;
161 
162 	LIST_FOREACH(mtr, &priv->mtrs, next)
163 		if (mtr->mtr_id == mtr_id)
164 			break;
165 
166 	return mtr;
167 }
168 
169 /**
170  * Reserve a policer bit in a bitmap.
171  *
172  * @param plcrs Pointer to the policers bitmap.
173  * @returns Reserved bit number on success, negative value otherwise.
174  */
175 static int
mrvl_reserve_plcr(uint32_t * plcrs)176 mrvl_reserve_plcr(uint32_t *plcrs)
177 {
178 	uint32_t i, num;
179 
180 	num = PP2_CLS_PLCR_NUM;
181 	if (num > sizeof(uint32_t) * 8) {
182 		num = sizeof(uint32_t) * 8;
183 		MRVL_LOG(WARNING, "Plcrs number was limited to 32.");
184 	}
185 
186 	for (i = 0; i < num; i++) {
187 		uint32_t bit = BIT(i);
188 
189 		if (!(*plcrs & bit)) {
190 			*plcrs |= bit;
191 
192 			return i;
193 		}
194 	}
195 
196 	return -1;
197 }
198 
199 /**
200  * Enable meter object.
201  *
202  * @param dev Pointer to the device.
203  * @param mtr_id Id of the meter.
204  * @param error Pointer to the error.
205  * @returns 0 in success, negative value otherwise.
206  */
207 static int
mrvl_meter_enable(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)208 mrvl_meter_enable(struct rte_eth_dev *dev, uint32_t mtr_id,
209 		  struct rte_mtr_error *error)
210 {
211 	struct mrvl_priv *priv = dev->data->dev_private;
212 	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
213 	struct pp2_cls_plcr_params params;
214 	char match[MRVL_MATCH_LEN];
215 	struct rte_flow *flow;
216 	int ret;
217 
218 	if (!priv->ppio)
219 		return -rte_mtr_error_set(error, EPERM,
220 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
221 					  NULL, "Port is uninitialized\n");
222 
223 	if (!mtr)
224 		return -rte_mtr_error_set(error, ENODEV,
225 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
226 					  "Meter id does not exist\n");
227 
228 	if (mtr->plcr)
229 		goto skip;
230 
231 	mtr->plcr_bit = mrvl_reserve_plcr(&priv->used_plcrs);
232 	if (mtr->plcr_bit < 0)
233 		return -rte_mtr_error_set(error, ENOSPC,
234 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
235 					  NULL,
236 					  "Failed to reserve plcr entry\n");
237 
238 	memset(&params, 0, sizeof(params));
239 	snprintf(match, sizeof(match), "policer-%d:%d", priv->pp_id,
240 		 mtr->plcr_bit);
241 	params.match = match;
242 	params.token_unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
243 	params.color_mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
244 	params.cir = mtr->profile->profile.srtcm_rfc2697.cir;
245 	params.cbs = mtr->profile->profile.srtcm_rfc2697.cbs;
246 	params.ebs = mtr->profile->profile.srtcm_rfc2697.ebs;
247 
248 	ret = pp2_cls_plcr_init(&params, &mtr->plcr);
249 	if (ret) {
250 		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
251 		mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
252 
253 		return -rte_mtr_error_set(error, -ret,
254 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
255 					  NULL, "Failed to setup policer\n");
256 	}
257 
258 	mtr->enabled = 1;
259 skip:
260 	/* iterate over flows that have this mtr attached */
261 	LIST_FOREACH(flow, &priv->flows, next) {
262 		if (flow->mtr != mtr)
263 			continue;
264 
265 		flow->action.plcr = mtr->plcr;
266 
267 		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
268 					      &flow->action);
269 		if (ret)
270 			return -rte_mtr_error_set(error, -ret,
271 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
272 					  NULL, "Failed to update cls rule\n");
273 	}
274 
275 	return 0;
276 }
277 
278 /**
279  * Disable meter object.
280  *
281  * @param dev Pointer to the device.
282  * @param mtr Id of the meter.
283  * @param error Pointer to the error.
284  * @returns 0 on success, negative value otherwise.
285  */
286 static int
mrvl_meter_disable(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)287 mrvl_meter_disable(struct rte_eth_dev *dev, uint32_t mtr_id,
288 		       struct rte_mtr_error *error)
289 {
290 	struct mrvl_priv *priv = dev->data->dev_private;
291 	struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
292 	struct rte_flow *flow;
293 	int ret;
294 
295 	if (!mtr)
296 		return -rte_mtr_error_set(error, ENODEV,
297 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
298 					  "Meter id does not exist\n");
299 
300 	LIST_FOREACH(flow, &priv->flows, next) {
301 		if (flow->mtr != mtr)
302 			continue;
303 
304 		flow->action.plcr = NULL;
305 
306 		ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
307 					      &flow->action);
308 		if (ret)
309 			return -rte_mtr_error_set(error, -ret,
310 					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
311 					NULL, "Failed to disable meter\n");
312 	}
313 
314 	mtr->enabled = 0;
315 
316 	return 0;
317 }
318 
319 /**
320  * Create new meter.
321  *
322  * @param dev Pointer to the device.
323  * @param mtr_id Id of the meter.
324  * @param params Pointer to the meter parameters.
325  * @param shared Flags indicating whether meter is shared.
326  * @param error Pointer to the error.
327  * @returns 0 on success, negative value otherwise.
328  */
329 static int
mrvl_create(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_params * params,int shared,struct rte_mtr_error * error)330 mrvl_create(struct rte_eth_dev *dev, uint32_t mtr_id,
331 	    struct rte_mtr_params *params, int shared,
332 	    struct rte_mtr_error *error)
333 {
334 	struct mrvl_priv *priv = dev->data->dev_private;
335 	struct mrvl_mtr_profile *profile;
336 	struct mrvl_mtr *mtr;
337 
338 	profile = mrvl_mtr_profile_from_id(priv, params->meter_profile_id);
339 	if (!profile)
340 		return -rte_mtr_error_set(error, EINVAL,
341 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
342 					  NULL, "Profile id does not exist\n");
343 
344 	mtr = mrvl_mtr_from_id(priv, mtr_id);
345 	if (mtr)
346 		return -rte_mtr_error_set(error, EEXIST,
347 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
348 					  "Meter id already exists\n");
349 
350 	mtr = rte_zmalloc_socket(NULL, sizeof(*mtr), 0, rte_socket_id());
351 	if (!mtr)
352 		return -rte_mtr_error_set(error, ENOMEM,
353 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
354 					  NULL, NULL);
355 
356 	mtr->shared = shared;
357 	mtr->mtr_id = mtr_id;
358 	mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
359 	mtr->profile = profile;
360 	profile->refcnt++;
361 	LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
362 
363 	if (params->meter_enable)
364 		return mrvl_meter_enable(dev, mtr_id, error);
365 
366 	return 0;
367 }
368 
369 /**
370  * Destroy meter object.
371  *
372  * @param dev Pointer to the device.
373  * @param mtr_id Id of the meter object.
374  * @param error Pointer to the error.
375  * @returns 0 on success, negative value otherwise.
376  */
377 static int
mrvl_destroy(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)378 mrvl_destroy(struct rte_eth_dev *dev, uint32_t mtr_id,
379 		 struct rte_mtr_error *error)
380 {
381 	struct mrvl_priv *priv = dev->data->dev_private;
382 	struct mrvl_mtr *mtr;
383 
384 	if (!priv->ppio)
385 		return -rte_mtr_error_set(error, EPERM,
386 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
387 					  NULL, "Port is uninitialized\n");
388 
389 	mtr = mrvl_mtr_from_id(priv, mtr_id);
390 	if (!mtr)
391 		return -rte_mtr_error_set(error, EEXIST,
392 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
393 					  "Meter id does not exist\n");
394 
395 	if (mtr->refcnt)
396 		return -rte_mtr_error_set(error, EPERM,
397 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
398 					  "Meter is used\n");
399 
400 	LIST_REMOVE(mtr, next);
401 	mtr->profile->refcnt--;
402 
403 	if (mtr->plcr_bit != MRVL_PLCR_BIT_INVALID)
404 		priv->used_plcrs &= ~BIT(mtr->plcr_bit);
405 
406 	if (mtr->plcr)
407 		pp2_cls_plcr_deinit(mtr->plcr);
408 
409 	rte_free(mtr);
410 
411 	return 0;
412 }
413 
414 /**
415  * Update profile used by the meter.
416  *
417  * @param dev Pointer to the device.
418  * @param mtr_id Id of the meter object.
419  * @param error Pointer to the error.
420  * @returns 0 on success, negative value otherwise.
421  */
422 static int
mrvl_meter_profile_update(struct rte_eth_dev * dev,uint32_t mtr_id,uint32_t meter_profile_id,struct rte_mtr_error * error)423 mrvl_meter_profile_update(struct rte_eth_dev *dev, uint32_t mtr_id,
424 			  uint32_t meter_profile_id,
425 			  struct rte_mtr_error *error)
426 {
427 	struct mrvl_priv *priv = dev->data->dev_private;
428 	struct mrvl_mtr_profile *profile;
429 	struct mrvl_mtr *mtr;
430 	int ret, enabled = 0;
431 
432 	if (!priv->ppio)
433 		return -rte_mtr_error_set(error, EPERM,
434 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
435 					  NULL, "Port is uninitialized\n");
436 
437 	mtr = mrvl_mtr_from_id(priv, mtr_id);
438 	if (!mtr)
439 		return -rte_mtr_error_set(error, EEXIST,
440 					  RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
441 					  "Meter id does not exist\n");
442 
443 	profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
444 	if (!profile)
445 		return -rte_mtr_error_set(error, EINVAL,
446 					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
447 					  NULL, "Profile id does not exist\n");
448 
449 	ret = mrvl_meter_disable(dev, mtr_id, error);
450 	if (ret)
451 		return -rte_mtr_error_set(error, EPERM,
452 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
453 					  NULL);
454 
455 	if (mtr->plcr) {
456 		enabled = 1;
457 		pp2_cls_plcr_deinit(mtr->plcr);
458 		mtr->plcr = NULL;
459 	}
460 
461 	mtr->profile->refcnt--;
462 	mtr->profile = profile;
463 	profile->refcnt++;
464 
465 	if (enabled)
466 		return mrvl_meter_enable(dev, mtr_id, error);
467 
468 	return 0;
469 }
470 
471 const struct rte_mtr_ops mrvl_mtr_ops = {
472 	.capabilities_get = mrvl_capabilities_get,
473 	.meter_profile_add = mrvl_meter_profile_add,
474 	.meter_profile_delete = mrvl_meter_profile_delete,
475 	.create = mrvl_create,
476 	.destroy = mrvl_destroy,
477 	.meter_enable = mrvl_meter_enable,
478 	.meter_disable = mrvl_meter_disable,
479 	.meter_profile_update = mrvl_meter_profile_update,
480 };
481 
482 /**
483  * Initialize metering resources.
484  *
485  * @param dev Pointer to the device.
486  */
487 void
mrvl_mtr_init(struct rte_eth_dev * dev)488 mrvl_mtr_init(struct rte_eth_dev *dev)
489 {
490 	struct mrvl_priv *priv = dev->data->dev_private;
491 
492 	LIST_INIT(&priv->profiles);
493 	LIST_INIT(&priv->mtrs);
494 }
495 
496 /**
497  * Cleanup metering resources.
498  *
499  * @param dev Pointer to the device.
500  */
501 void
mrvl_mtr_deinit(struct rte_eth_dev * dev)502 mrvl_mtr_deinit(struct rte_eth_dev *dev)
503 {
504 	struct mrvl_priv *priv = dev->data->dev_private;
505 	struct mrvl_mtr_profile *profile, *tmp_profile;
506 	struct mrvl_mtr *mtr, *tmp_mtr;
507 
508 	for (mtr = LIST_FIRST(&priv->mtrs);
509 	     mtr && (tmp_mtr = LIST_NEXT(mtr, next), 1);
510 	     mtr = tmp_mtr)
511 		mrvl_destroy(dev, mtr->mtr_id, NULL);
512 
513 	for (profile = LIST_FIRST(&priv->profiles);
514 	     profile && (tmp_profile = LIST_NEXT(profile, next), 1);
515 	     profile = tmp_profile)
516 		mrvl_meter_profile_delete(dev, profile->profile_id, NULL);
517 }
518