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 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 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 * 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 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 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 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 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 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 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 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 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