1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Marvell International Ltd.
3 * Copyright(c) 2018 Semihalf.
8 #include <rte_malloc.h>
12 /** Maximum meter rate */
13 #define MRVL_SRTCM_RFC2697_CIR_MAX 1023000
15 /** Invalid plcr bit */
16 #define MRVL_PLCR_BIT_INVALID -1
19 * Return meter object capabilities.
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).
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)
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,
39 memcpy(cap, &capa, sizeof(capa));
45 * Get profile using it's id.
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.
51 static struct mrvl_mtr_profile *
52 mrvl_mtr_profile_from_id(struct mrvl_priv *priv, uint32_t meter_profile_id)
54 struct mrvl_mtr_profile *profile = NULL;
56 LIST_FOREACH(profile, &priv->profiles, next)
57 if (profile->profile_id == meter_profile_id)
64 * Add profile to the list of profiles.
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.
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)
77 struct mrvl_priv *priv = dev->data->dev_private;
78 struct mrvl_mtr_profile *prof;
81 return -rte_mtr_error_set(error, EINVAL,
82 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
85 if (profile->alg != RTE_MTR_SRTCM_RFC2697)
86 return -rte_mtr_error_set(error, EINVAL,
87 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
89 "Only srTCM RFC 2697 is supported\n");
91 prof = mrvl_mtr_profile_from_id(priv, meter_profile_id);
93 return -rte_mtr_error_set(error, EEXIST,
94 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
95 NULL, "Profile id already exists\n");
97 prof = rte_zmalloc_socket(NULL, sizeof(*prof), 0, rte_socket_id());
99 return -rte_mtr_error_set(error, ENOMEM,
100 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
103 prof->profile_id = meter_profile_id;
104 memcpy(&prof->profile, profile, sizeof(*profile));
106 LIST_INSERT_HEAD(&priv->profiles, prof, next);
112 * Remove profile from the list of profiles.
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.
120 mrvl_meter_profile_delete(struct rte_eth_dev *dev,
121 uint32_t meter_profile_id,
122 struct rte_mtr_error *error)
124 struct mrvl_priv *priv = dev->data->dev_private;
125 struct mrvl_mtr_profile *profile;
127 profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
129 return -rte_mtr_error_set(error, ENODEV,
130 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
131 NULL, "Profile id does not exist\n");
134 return -rte_mtr_error_set(error, EPERM,
135 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
136 NULL, "Profile is used\n");
138 LIST_REMOVE(profile, next);
145 * Get meter using it's id.
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.
151 static struct mrvl_mtr *
152 mrvl_mtr_from_id(struct mrvl_priv *priv, uint32_t mtr_id)
154 struct mrvl_mtr *mtr = NULL;
156 LIST_FOREACH(mtr, &priv->mtrs, next)
157 if (mtr->mtr_id == mtr_id)
164 * Reserve a policer bit in a bitmap.
166 * @param plcrs Pointer to the policers bitmap.
167 * @returns Reserved bit number on success, negative value otherwise.
170 mrvl_reserve_plcr(uint32_t *plcrs)
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.");
180 for (i = 0; i < num; i++) {
181 uint32_t bit = BIT(i);
183 if (!(*plcrs & bit)) {
194 * Enable meter object.
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.
202 mrvl_meter_enable(struct rte_eth_dev *dev, uint32_t mtr_id,
203 struct rte_mtr_error *error)
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;
213 return -rte_mtr_error_set(error, EPERM,
214 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
215 NULL, "Port is uninitialized\n");
218 return -rte_mtr_error_set(error, ENODEV,
219 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
220 "Meter id does not exist\n");
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,
230 "Failed to reserve plcr entry\n");
232 memset(¶ms, 0, sizeof(params));
233 snprintf(match, sizeof(match), "policer-%d:%d", priv->pp_id,
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;
242 ret = pp2_cls_plcr_init(¶ms, &mtr->plcr);
244 priv->used_plcrs &= ~BIT(mtr->plcr_bit);
245 mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
247 return -rte_mtr_error_set(error, -ret,
248 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
249 NULL, "Failed to setup policer\n");
254 /* iterate over flows that have this mtr attached */
255 LIST_FOREACH(flow, &priv->flows, next) {
256 if (flow->mtr != mtr)
259 flow->action.plcr = mtr->plcr;
261 ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
264 return -rte_mtr_error_set(error, -ret,
265 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
266 NULL, "Failed to update cls rule\n");
273 * Disable meter object.
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.
281 mrvl_meter_disable(struct rte_eth_dev *dev, uint32_t mtr_id,
282 struct rte_mtr_error *error)
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;
290 return -rte_mtr_error_set(error, ENODEV,
291 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
292 "Meter id does not exist\n");
294 LIST_FOREACH(flow, &priv->flows, next) {
295 if (flow->mtr != mtr)
298 flow->action.plcr = NULL;
300 ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
303 return -rte_mtr_error_set(error, -ret,
304 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
305 NULL, "Failed to disable meter\n");
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.
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)
328 struct mrvl_priv *priv = dev->data->dev_private;
329 struct mrvl_mtr_profile *profile;
330 struct mrvl_mtr *mtr;
332 profile = mrvl_mtr_profile_from_id(priv, params->meter_profile_id);
334 return -rte_mtr_error_set(error, EINVAL,
335 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
336 NULL, "Profile id does not exist\n");
338 mtr = mrvl_mtr_from_id(priv, mtr_id);
340 return -rte_mtr_error_set(error, EEXIST,
341 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
342 "Meter id already exists\n");
344 mtr = rte_zmalloc_socket(NULL, sizeof(*mtr), 0, rte_socket_id());
346 return -rte_mtr_error_set(error, ENOMEM,
347 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
350 mtr->shared = shared;
351 mtr->mtr_id = mtr_id;
352 mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
353 mtr->profile = profile;
355 LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
357 if (params->meter_enable)
358 return mrvl_meter_enable(dev, mtr_id, error);
364 * Destroy meter object.
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.
372 mrvl_destroy(struct rte_eth_dev *dev, uint32_t mtr_id,
373 struct rte_mtr_error *error)
375 struct mrvl_priv *priv = dev->data->dev_private;
376 struct mrvl_mtr *mtr;
379 return -rte_mtr_error_set(error, EPERM,
380 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
381 NULL, "Port is uninitialized\n");
383 mtr = mrvl_mtr_from_id(priv, mtr_id);
385 return -rte_mtr_error_set(error, EEXIST,
386 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
387 "Meter id does not exist\n");
390 return -rte_mtr_error_set(error, EPERM,
391 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
394 LIST_REMOVE(mtr, next);
395 mtr->profile->refcnt--;
397 if (mtr->plcr_bit != MRVL_PLCR_BIT_INVALID)
398 priv->used_plcrs &= ~BIT(mtr->plcr_bit);
401 pp2_cls_plcr_deinit(mtr->plcr);
409 * Update profile used by the meter.
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.
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)
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;
427 return -rte_mtr_error_set(error, EPERM,
428 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
429 NULL, "Port is uninitialized\n");
431 mtr = mrvl_mtr_from_id(priv, mtr_id);
433 return -rte_mtr_error_set(error, EEXIST,
434 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
435 "Meter id does not exist\n");
437 profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
439 return -rte_mtr_error_set(error, EINVAL,
440 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
441 NULL, "Profile id does not exist\n");
443 ret = mrvl_meter_disable(dev, mtr_id, error);
445 return -rte_mtr_error_set(error, EPERM,
446 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
451 pp2_cls_plcr_deinit(mtr->plcr);
455 mtr->profile->refcnt--;
456 mtr->profile = profile;
460 return mrvl_meter_enable(dev, mtr_id, error);
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,
477 * Initialize metering resources.
479 * @param dev Pointer to the device.
482 mrvl_mtr_init(struct rte_eth_dev *dev)
484 struct mrvl_priv *priv = dev->data->dev_private;
486 LIST_INIT(&priv->profiles);
487 LIST_INIT(&priv->mtrs);
491 * Cleanup metering resources.
493 * @param dev Pointer to the device.
496 mrvl_mtr_deinit(struct rte_eth_dev *dev)
498 struct mrvl_priv *priv = dev->data->dev_private;
499 struct mrvl_mtr_profile *profile, *tmp_profile;
500 struct mrvl_mtr *mtr, *tmp_mtr;
502 for (mtr = LIST_FIRST(&priv->mtrs);
503 mtr && (tmp_mtr = LIST_NEXT(mtr, next), 1);
505 mrvl_destroy(dev, mtr->mtr_id, NULL);
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);