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