2 * SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2018 Marvell International Ltd.
4 * Copyright(c) 2018 Semihalf.
9 #include <rte_malloc.h>
13 /** Maximum meter rate */
14 #define MRVL_SRTCM_RFC2697_CIR_MAX 1023000
16 /** Invalid plcr bit */
17 #define MRVL_PLCR_BIT_INVALID -1
20 * Return meter object capabilities.
22 * @param dev Pointer to the device (unused).
23 * @param cap Pointer to the meter object capabilities.
24 * @param error Pointer to the error (unused).
28 mrvl_capabilities_get(struct rte_eth_dev *dev __rte_unused,
29 struct rte_mtr_capabilities *cap,
30 struct rte_mtr_error *error __rte_unused)
32 struct rte_mtr_capabilities capa = {
33 .n_max = PP2_CLS_PLCR_NUM,
34 .n_shared_max = PP2_CLS_PLCR_NUM,
35 .shared_n_flows_per_mtr_max = -1,
36 .meter_srtcm_rfc2697_n_max = PP2_CLS_PLCR_NUM,
37 .meter_rate_max = MRVL_SRTCM_RFC2697_CIR_MAX,
40 memcpy(cap, &capa, sizeof(capa));
46 * Get profile using it's id.
48 * @param priv Pointer to the port's private data.
49 * @param meter_profile_id Profile id used by the meter.
50 * @returns Pointer to the profile if exists, NULL otherwise.
52 static struct mrvl_mtr_profile *
53 mrvl_mtr_profile_from_id(struct mrvl_priv *priv, uint32_t meter_profile_id)
55 struct mrvl_mtr_profile *profile = NULL;
57 LIST_FOREACH(profile, &priv->profiles, next)
58 if (profile->profile_id == meter_profile_id)
65 * Add profile to the list of profiles.
67 * @param dev Pointer to the device.
68 * @param meter_profile_id Id of the new profile.
69 * @param profile Pointer to the profile configuration.
70 * @param error Pointer to the error.
71 * @returns 0 on success, negative value otherwise.
74 mrvl_meter_profile_add(struct rte_eth_dev *dev, uint32_t meter_profile_id,
75 struct rte_mtr_meter_profile *profile,
76 struct rte_mtr_error *error)
78 struct mrvl_priv *priv = dev->data->dev_private;
79 struct mrvl_mtr_profile *prof;
82 return -rte_mtr_error_set(error, EINVAL,
83 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
86 if (profile->alg != RTE_MTR_SRTCM_RFC2697)
87 return -rte_mtr_error_set(error, EINVAL,
88 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
90 "Only srTCM RFC 2697 is supported\n");
92 prof = mrvl_mtr_profile_from_id(priv, meter_profile_id);
94 return -rte_mtr_error_set(error, EEXIST,
95 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
96 NULL, "Profile id already exists\n");
98 prof = rte_zmalloc_socket(NULL, sizeof(*prof), 0, rte_socket_id());
100 return -rte_mtr_error_set(error, ENOMEM,
101 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
104 prof->profile_id = meter_profile_id;
105 memcpy(&prof->profile, profile, sizeof(*profile));
107 LIST_INSERT_HEAD(&priv->profiles, prof, next);
113 * Remove profile from the list of profiles.
115 * @param dev Pointer to the device.
116 * @param meter_profile_id Id of the profile to remove.
117 * @param error Pointer to the error.
118 * @returns 0 on success, negative value otherwise.
121 mrvl_meter_profile_delete(struct rte_eth_dev *dev,
122 uint32_t meter_profile_id,
123 struct rte_mtr_error *error)
125 struct mrvl_priv *priv = dev->data->dev_private;
126 struct mrvl_mtr_profile *profile;
128 profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
130 return -rte_mtr_error_set(error, ENODEV,
131 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
132 NULL, "Profile id does not exist\n");
135 return -rte_mtr_error_set(error, EPERM,
136 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
137 NULL, "Profile is used\n");
139 LIST_REMOVE(profile, next);
146 * Get meter using it's id.
148 * @param priv Pointer to port's private data.
149 * @param mtr_id Id of the meter.
150 * @returns Pointer to the meter if exists, NULL otherwise.
152 static struct mrvl_mtr *
153 mrvl_mtr_from_id(struct mrvl_priv *priv, uint32_t mtr_id)
155 struct mrvl_mtr *mtr = NULL;
157 LIST_FOREACH(mtr, &priv->mtrs, next)
158 if (mtr->mtr_id == mtr_id)
165 * Reserve a policer bit in a bitmap.
167 * @param plcrs Pointer to the policers bitmap.
168 * @returns Reserved bit number on success, negative value otherwise.
171 mrvl_reserve_plcr(uint32_t *plcrs)
175 num = PP2_CLS_PLCR_NUM;
176 if (num > sizeof(uint32_t) * 8) {
177 num = sizeof(uint32_t) * 8;
178 MRVL_LOG(WARNING, "Plcrs number was limited to 32.");
181 for (i = 0; i < num; i++) {
182 uint32_t bit = BIT(i);
184 if (!(*plcrs & bit)) {
195 * Enable meter object.
197 * @param dev Pointer to the device.
198 * @param mtr_id Id of the meter.
199 * @param error Pointer to the error.
200 * @returns 0 in success, negative value otherwise.
203 mrvl_meter_enable(struct rte_eth_dev *dev, uint32_t mtr_id,
204 struct rte_mtr_error *error)
206 struct mrvl_priv *priv = dev->data->dev_private;
207 struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
208 struct pp2_cls_plcr_params params;
209 char match[MRVL_MATCH_LEN];
210 struct rte_flow *flow;
214 return -rte_mtr_error_set(error, EPERM,
215 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
216 NULL, "Port is uninitialized\n");
219 return -rte_mtr_error_set(error, ENODEV,
220 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
221 "Meter id does not exist\n");
226 mtr->plcr_bit = mrvl_reserve_plcr(&priv->used_plcrs);
227 if (mtr->plcr_bit < 0)
228 return -rte_mtr_error_set(error, ENOSPC,
229 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
231 "Failed to reserve plcr entry\n");
233 memset(¶ms, 0, sizeof(params));
234 snprintf(match, sizeof(match), "policer-%d:%d", priv->pp_id,
236 params.match = match;
237 params.token_unit = PP2_CLS_PLCR_BYTES_TOKEN_UNIT;
238 params.color_mode = PP2_CLS_PLCR_COLOR_BLIND_MODE;
239 params.cir = mtr->profile->profile.srtcm_rfc2697.cir;
240 params.cbs = mtr->profile->profile.srtcm_rfc2697.cbs;
241 params.ebs = mtr->profile->profile.srtcm_rfc2697.ebs;
243 ret = pp2_cls_plcr_init(¶ms, &mtr->plcr);
245 priv->used_plcrs &= ~BIT(mtr->plcr_bit);
246 mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
248 return -rte_mtr_error_set(error, -ret,
249 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
250 NULL, "Failed to setup policer\n");
255 /* iterate over flows that have this mtr attached */
256 LIST_FOREACH(flow, &priv->flows, next) {
257 if (flow->mtr != mtr)
260 flow->action.plcr = mtr->plcr;
262 ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
265 return -rte_mtr_error_set(error, -ret,
266 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
267 NULL, "Failed to update cls rule\n");
274 * Disable meter object.
276 * @param dev Pointer to the device.
277 * @param mtr Id of the meter.
278 * @param error Pointer to the error.
279 * @returns 0 on success, negative value otherwise.
282 mrvl_meter_disable(struct rte_eth_dev *dev, uint32_t mtr_id,
283 struct rte_mtr_error *error)
285 struct mrvl_priv *priv = dev->data->dev_private;
286 struct mrvl_mtr *mtr = mrvl_mtr_from_id(priv, mtr_id);
287 struct rte_flow *flow;
291 return -rte_mtr_error_set(error, ENODEV,
292 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
293 "Meter id does not exist\n");
295 LIST_FOREACH(flow, &priv->flows, next) {
296 if (flow->mtr != mtr)
299 flow->action.plcr = NULL;
301 ret = pp2_cls_tbl_modify_rule(priv->cls_tbl, &flow->rule,
304 return -rte_mtr_error_set(error, -ret,
305 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
306 NULL, "Failed to disable meter\n");
317 * @param dev Pointer to the device.
318 * @param mtr_id Id of the meter.
319 * @param params Pointer to the meter parameters.
320 * @param shared Flags indicating whether meter is shared.
321 * @param error Pointer to the error.
322 * @returns 0 on success, negative value otherwise.
325 mrvl_create(struct rte_eth_dev *dev, uint32_t mtr_id,
326 struct rte_mtr_params *params, int shared,
327 struct rte_mtr_error *error)
329 struct mrvl_priv *priv = dev->data->dev_private;
330 struct mrvl_mtr_profile *profile;
331 struct mrvl_mtr *mtr;
333 mtr = mrvl_mtr_from_id(priv, mtr_id);
335 return -rte_mtr_error_set(error, EEXIST,
336 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
337 "Meter id already exists\n");
339 mtr = rte_zmalloc_socket(NULL, sizeof(*mtr), 0, rte_socket_id());
341 return -rte_mtr_error_set(error, ENOMEM,
342 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
345 profile = mrvl_mtr_profile_from_id(priv, params->meter_profile_id);
347 return -rte_mtr_error_set(error, EINVAL,
348 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
349 NULL, "Profile id does not exist\n");
351 mtr->shared = shared;
352 mtr->mtr_id = mtr_id;
353 mtr->plcr_bit = MRVL_PLCR_BIT_INVALID;
354 mtr->profile = profile;
356 LIST_INSERT_HEAD(&priv->mtrs, mtr, next);
358 if (params->meter_enable)
359 return mrvl_meter_enable(dev, mtr_id, error);
365 * Destroy meter object.
367 * @param dev Pointer to the device.
368 * @param mtr_id Id of the meter object.
369 * @param error Pointer to the error.
370 * @returns 0 on success, negative value otherwise.
373 mrvl_destroy(struct rte_eth_dev *dev, uint32_t mtr_id,
374 struct rte_mtr_error *error)
376 struct mrvl_priv *priv = dev->data->dev_private;
377 struct mrvl_mtr *mtr;
380 return -rte_mtr_error_set(error, EPERM,
381 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
382 NULL, "Port is uninitialized\n");
384 mtr = mrvl_mtr_from_id(priv, mtr_id);
386 return -rte_mtr_error_set(error, EEXIST,
387 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
388 "Meter id does not exist\n");
391 return -rte_mtr_error_set(error, EPERM,
392 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
395 LIST_REMOVE(mtr, next);
396 mtr->profile->refcnt--;
398 if (mtr->plcr_bit != MRVL_PLCR_BIT_INVALID)
399 priv->used_plcrs &= ~BIT(mtr->plcr_bit);
402 pp2_cls_plcr_deinit(mtr->plcr);
410 * Update profile used by the meter.
412 * @param dev Pointer to the device.
413 * @param mtr_id Id of the meter object.
414 * @param error Pointer to the error.
415 * @returns 0 on success, negative value otherwise.
418 mrvl_meter_profile_update(struct rte_eth_dev *dev, uint32_t mtr_id,
419 uint32_t meter_profile_id,
420 struct rte_mtr_error *error)
422 struct mrvl_priv *priv = dev->data->dev_private;
423 struct mrvl_mtr_profile *profile;
424 struct mrvl_mtr *mtr;
425 int ret, enabled = 0;
428 return -rte_mtr_error_set(error, EPERM,
429 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
430 NULL, "Port is uninitialized\n");
432 mtr = mrvl_mtr_from_id(priv, mtr_id);
434 return -rte_mtr_error_set(error, EEXIST,
435 RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
436 "Meter id does not exist\n");
438 profile = mrvl_mtr_profile_from_id(priv, meter_profile_id);
440 return -rte_mtr_error_set(error, EINVAL,
441 RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
442 NULL, "Profile id does not exist\n");
444 ret = mrvl_meter_disable(dev, mtr_id, error);
446 return -rte_mtr_error_set(error, EPERM,
447 RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
452 pp2_cls_plcr_deinit(mtr->plcr);
456 mtr->profile->refcnt--;
457 mtr->profile = profile;
461 return mrvl_meter_enable(dev, mtr_id, error);
466 const struct rte_mtr_ops mrvl_mtr_ops = {
467 .capabilities_get = mrvl_capabilities_get,
468 .meter_profile_add = mrvl_meter_profile_add,
469 .meter_profile_delete = mrvl_meter_profile_delete,
470 .create = mrvl_create,
471 .destroy = mrvl_destroy,
472 .meter_enable = mrvl_meter_enable,
473 .meter_disable = mrvl_meter_disable,
474 .meter_profile_update = mrvl_meter_profile_update,
478 * Initialize metering resources.
480 * @param dev Pointer to the device.
483 mrvl_mtr_init(struct rte_eth_dev *dev)
485 struct mrvl_priv *priv = dev->data->dev_private;
487 LIST_INIT(&priv->profiles);
488 LIST_INIT(&priv->mtrs);
492 * Cleanup metering resources.
494 * @param dev Pointer to the device.
497 mrvl_mtr_deinit(struct rte_eth_dev *dev)
499 struct mrvl_priv *priv = dev->data->dev_private;
500 struct mrvl_mtr_profile *profile, *tmp_profile;
501 struct mrvl_mtr *mtr, *tmp_mtr;
503 for (mtr = LIST_FIRST(&priv->mtrs);
504 mtr && (tmp_mtr = LIST_NEXT(mtr, next), 1);
506 mrvl_destroy(dev, mtr->mtr_id, NULL);
508 for (profile = LIST_FIRST(&priv->profiles);
509 profile && (tmp_profile = LIST_NEXT(profile, next), 1);
510 profile = tmp_profile)
511 mrvl_meter_profile_delete(dev, profile->profile_id, NULL);