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 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
mrvl_meter_profile_delete(struct rte_eth_dev * dev,uint32_t meter_profile_id,struct rte_mtr_error * error)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 *
mrvl_mtr_from_id(struct mrvl_priv * priv,uint32_t mtr_id)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
mrvl_reserve_plcr(uint32_t * plcrs)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
mrvl_meter_enable(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)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(¶ms, 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(¶ms, &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
mrvl_meter_disable(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)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
mrvl_create(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_params * params,int shared,struct rte_mtr_error * error)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
mrvl_destroy(struct rte_eth_dev * dev,uint32_t mtr_id,struct rte_mtr_error * error)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
mrvl_meter_profile_update(struct rte_eth_dev * dev,uint32_t mtr_id,uint32_t meter_profile_id,struct rte_mtr_error * error)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
mrvl_mtr_init(struct rte_eth_dev * dev)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
mrvl_mtr_deinit(struct rte_eth_dev * dev)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