net/mvpp2: fix port speed overflow
[dpdk.git] / drivers / net / mvpp2 / mrvl_mtr.c
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         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
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 *
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
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
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(&params, 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(&params, &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
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
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
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
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
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
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 }