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(¶ms, 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(¶ms, &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