.. | .. |
---|
7 | 7 | #include <linux/gfp.h> |
---|
8 | 8 | #include <linux/refcount.h> |
---|
9 | 9 | #include <linux/rhashtable.h> |
---|
| 10 | +#define CREATE_TRACE_POINTS |
---|
| 11 | +#include <trace/events/mlxsw.h> |
---|
10 | 12 | |
---|
11 | 13 | #include "reg.h" |
---|
12 | 14 | #include "core.h" |
---|
.. | .. |
---|
14 | 16 | #include "spectrum_acl_tcam.h" |
---|
15 | 17 | #include "core_acl_flex_keys.h" |
---|
16 | 18 | |
---|
17 | | -#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_START 6 |
---|
18 | | -#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_END 11 |
---|
| 19 | +#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START 0 |
---|
| 20 | +#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END 5 |
---|
19 | 21 | |
---|
20 | 22 | struct mlxsw_sp_acl_atcam_lkey_id_ht_key { |
---|
21 | 23 | char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN]; /* MSB blocks */ |
---|
.. | .. |
---|
34 | 36 | void (*fini)(struct mlxsw_sp_acl_atcam_region *aregion); |
---|
35 | 37 | struct mlxsw_sp_acl_atcam_lkey_id * |
---|
36 | 38 | (*lkey_id_get)(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
37 | | - struct mlxsw_sp_acl_rule_info *rulei, u8 erp_id); |
---|
| 39 | + char *enc_key, u8 erp_id); |
---|
38 | 40 | void (*lkey_id_put)(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
39 | 41 | struct mlxsw_sp_acl_atcam_lkey_id *lkey_id); |
---|
40 | 42 | }; |
---|
.. | .. |
---|
64 | 66 | static bool |
---|
65 | 67 | mlxsw_sp_acl_atcam_is_centry(const struct mlxsw_sp_acl_atcam_entry *aentry) |
---|
66 | 68 | { |
---|
67 | | - return mlxsw_sp_acl_erp_is_ctcam_erp(aentry->erp); |
---|
| 69 | + return mlxsw_sp_acl_erp_mask_is_ctcam(aentry->erp_mask); |
---|
68 | 70 | } |
---|
69 | 71 | |
---|
70 | 72 | static int |
---|
.. | .. |
---|
90 | 92 | |
---|
91 | 93 | static struct mlxsw_sp_acl_atcam_lkey_id * |
---|
92 | 94 | mlxsw_sp_acl_atcam_generic_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
93 | | - struct mlxsw_sp_acl_rule_info *rulei, |
---|
94 | | - u8 erp_id) |
---|
| 95 | + char *enc_key, u8 erp_id) |
---|
95 | 96 | { |
---|
96 | 97 | struct mlxsw_sp_acl_atcam_region_generic *region_generic; |
---|
97 | 98 | |
---|
.. | .. |
---|
220 | 221 | |
---|
221 | 222 | static struct mlxsw_sp_acl_atcam_lkey_id * |
---|
222 | 223 | mlxsw_sp_acl_atcam_12kb_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
223 | | - struct mlxsw_sp_acl_rule_info *rulei, |
---|
224 | | - u8 erp_id) |
---|
| 224 | + char *enc_key, u8 erp_id) |
---|
225 | 225 | { |
---|
226 | 226 | struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv; |
---|
227 | 227 | struct mlxsw_sp_acl_tcam_region *region = aregion->region; |
---|
.. | .. |
---|
230 | 230 | struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); |
---|
231 | 231 | struct mlxsw_sp_acl_atcam_lkey_id *lkey_id; |
---|
232 | 232 | |
---|
233 | | - mlxsw_afk_encode(afk, region->key_info, &rulei->values, ht_key.enc_key, |
---|
234 | | - NULL, MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_START, |
---|
235 | | - MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_END); |
---|
| 233 | + memcpy(ht_key.enc_key, enc_key, sizeof(ht_key.enc_key)); |
---|
| 234 | + mlxsw_afk_clear(afk, ht_key.enc_key, |
---|
| 235 | + MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START, |
---|
| 236 | + MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END); |
---|
236 | 237 | ht_key.erp_id = erp_id; |
---|
237 | 238 | lkey_id = rhashtable_lookup_fast(®ion_12kb->lkey_ht, &ht_key, |
---|
238 | 239 | mlxsw_sp_acl_atcam_lkey_id_ht_params); |
---|
.. | .. |
---|
317 | 318 | struct mlxsw_sp_acl_atcam *atcam, |
---|
318 | 319 | struct mlxsw_sp_acl_atcam_region *aregion, |
---|
319 | 320 | struct mlxsw_sp_acl_tcam_region *region, |
---|
| 321 | + void *hints_priv, |
---|
320 | 322 | const struct mlxsw_sp_acl_ctcam_region_ops *ops) |
---|
321 | 323 | { |
---|
322 | 324 | int err; |
---|
.. | .. |
---|
324 | 326 | aregion->region = region; |
---|
325 | 327 | aregion->atcam = atcam; |
---|
326 | 328 | mlxsw_sp_acl_atcam_region_type_init(aregion); |
---|
| 329 | + INIT_LIST_HEAD(&aregion->entries_list); |
---|
327 | 330 | |
---|
328 | 331 | err = rhashtable_init(&aregion->entries_ht, |
---|
329 | 332 | &mlxsw_sp_acl_atcam_entries_ht_params); |
---|
.. | .. |
---|
332 | 335 | err = aregion->ops->init(aregion); |
---|
333 | 336 | if (err) |
---|
334 | 337 | goto err_ops_init; |
---|
335 | | - err = mlxsw_sp_acl_erp_region_init(aregion); |
---|
| 338 | + err = mlxsw_sp_acl_erp_region_init(aregion, hints_priv); |
---|
336 | 339 | if (err) |
---|
337 | 340 | goto err_erp_region_init; |
---|
338 | 341 | err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, &aregion->cregion, |
---|
.. | .. |
---|
357 | 360 | mlxsw_sp_acl_erp_region_fini(aregion); |
---|
358 | 361 | aregion->ops->fini(aregion); |
---|
359 | 362 | rhashtable_destroy(&aregion->entries_ht); |
---|
| 363 | + WARN_ON(!list_empty(&aregion->entries_list)); |
---|
360 | 364 | } |
---|
361 | 365 | |
---|
362 | 366 | void mlxsw_sp_acl_atcam_chunk_init(struct mlxsw_sp_acl_atcam_region *aregion, |
---|
.. | .. |
---|
379 | 383 | struct mlxsw_sp_acl_rule_info *rulei) |
---|
380 | 384 | { |
---|
381 | 385 | struct mlxsw_sp_acl_tcam_region *region = aregion->region; |
---|
382 | | - u8 erp_id = mlxsw_sp_acl_erp_id(aentry->erp); |
---|
| 386 | + u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask); |
---|
383 | 387 | struct mlxsw_sp_acl_atcam_lkey_id *lkey_id; |
---|
384 | 388 | char ptce3_pl[MLXSW_REG_PTCE3_LEN]; |
---|
385 | 389 | u32 kvdl_index, priority; |
---|
.. | .. |
---|
389 | 393 | if (err) |
---|
390 | 394 | return err; |
---|
391 | 395 | |
---|
392 | | - lkey_id = aregion->ops->lkey_id_get(aregion, rulei, erp_id); |
---|
| 396 | + lkey_id = aregion->ops->lkey_id_get(aregion, aentry->enc_key, erp_id); |
---|
393 | 397 | if (IS_ERR(lkey_id)) |
---|
394 | 398 | return PTR_ERR(lkey_id); |
---|
395 | 399 | aentry->lkey_id = lkey_id; |
---|
.. | .. |
---|
397 | 401 | kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block); |
---|
398 | 402 | mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_WRITE, |
---|
399 | 403 | priority, region->tcam_region_info, |
---|
400 | | - aentry->ht_key.enc_key, erp_id, |
---|
| 404 | + aentry->enc_key, erp_id, |
---|
| 405 | + aentry->delta_info.start, |
---|
| 406 | + aentry->delta_info.mask, |
---|
| 407 | + aentry->delta_info.value, |
---|
401 | 408 | refcount_read(&lkey_id->refcnt) != 1, lkey_id->id, |
---|
402 | 409 | kvdl_index); |
---|
403 | 410 | err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl); |
---|
.. | .. |
---|
418 | 425 | { |
---|
419 | 426 | struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id; |
---|
420 | 427 | struct mlxsw_sp_acl_tcam_region *region = aregion->region; |
---|
421 | | - u8 erp_id = mlxsw_sp_acl_erp_id(aentry->erp); |
---|
| 428 | + u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask); |
---|
422 | 429 | char ptce3_pl[MLXSW_REG_PTCE3_LEN]; |
---|
423 | 430 | |
---|
424 | 431 | mlxsw_reg_ptce3_pack(ptce3_pl, false, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 0, |
---|
425 | | - region->tcam_region_info, aentry->ht_key.enc_key, |
---|
426 | | - erp_id, refcount_read(&lkey_id->refcnt) != 1, |
---|
| 432 | + region->tcam_region_info, |
---|
| 433 | + aentry->enc_key, erp_id, |
---|
| 434 | + aentry->delta_info.start, |
---|
| 435 | + aentry->delta_info.mask, |
---|
| 436 | + aentry->delta_info.value, |
---|
| 437 | + refcount_read(&lkey_id->refcnt) != 1, |
---|
427 | 438 | lkey_id->id, 0); |
---|
428 | 439 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl); |
---|
429 | 440 | aregion->ops->lkey_id_put(aregion, lkey_id); |
---|
| 441 | +} |
---|
| 442 | + |
---|
| 443 | +static int |
---|
| 444 | +mlxsw_sp_acl_atcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp, |
---|
| 445 | + struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 446 | + struct mlxsw_sp_acl_atcam_entry *aentry, |
---|
| 447 | + struct mlxsw_sp_acl_rule_info *rulei) |
---|
| 448 | +{ |
---|
| 449 | + struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id; |
---|
| 450 | + u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask); |
---|
| 451 | + struct mlxsw_sp_acl_tcam_region *region = aregion->region; |
---|
| 452 | + char ptce3_pl[MLXSW_REG_PTCE3_LEN]; |
---|
| 453 | + u32 kvdl_index, priority; |
---|
| 454 | + int err; |
---|
| 455 | + |
---|
| 456 | + err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true); |
---|
| 457 | + if (err) |
---|
| 458 | + return err; |
---|
| 459 | + kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block); |
---|
| 460 | + mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_UPDATE, |
---|
| 461 | + priority, region->tcam_region_info, |
---|
| 462 | + aentry->enc_key, erp_id, |
---|
| 463 | + aentry->delta_info.start, |
---|
| 464 | + aentry->delta_info.mask, |
---|
| 465 | + aentry->delta_info.value, |
---|
| 466 | + refcount_read(&lkey_id->refcnt) != 1, lkey_id->id, |
---|
| 467 | + kvdl_index); |
---|
| 468 | + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl); |
---|
430 | 469 | } |
---|
431 | 470 | |
---|
432 | 471 | static int |
---|
.. | .. |
---|
438 | 477 | struct mlxsw_sp_acl_tcam_region *region = aregion->region; |
---|
439 | 478 | char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 }; |
---|
440 | 479 | struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl); |
---|
441 | | - struct mlxsw_sp_acl_erp *erp; |
---|
442 | | - unsigned int blocks_count; |
---|
| 480 | + const struct mlxsw_sp_acl_erp_delta *delta; |
---|
| 481 | + struct mlxsw_sp_acl_erp_mask *erp_mask; |
---|
443 | 482 | int err; |
---|
444 | 483 | |
---|
445 | | - blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info); |
---|
446 | 484 | mlxsw_afk_encode(afk, region->key_info, &rulei->values, |
---|
447 | | - aentry->ht_key.enc_key, mask, 0, blocks_count - 1); |
---|
| 485 | + aentry->ht_key.full_enc_key, mask); |
---|
448 | 486 | |
---|
449 | | - erp = mlxsw_sp_acl_erp_get(aregion, mask, false); |
---|
450 | | - if (IS_ERR(erp)) |
---|
451 | | - return PTR_ERR(erp); |
---|
452 | | - aentry->erp = erp; |
---|
453 | | - aentry->ht_key.erp_id = mlxsw_sp_acl_erp_id(erp); |
---|
| 487 | + erp_mask = mlxsw_sp_acl_erp_mask_get(aregion, mask, false); |
---|
| 488 | + if (IS_ERR(erp_mask)) |
---|
| 489 | + return PTR_ERR(erp_mask); |
---|
| 490 | + aentry->erp_mask = erp_mask; |
---|
| 491 | + aentry->ht_key.erp_id = mlxsw_sp_acl_erp_mask_erp_id(erp_mask); |
---|
| 492 | + memcpy(aentry->enc_key, aentry->ht_key.full_enc_key, |
---|
| 493 | + sizeof(aentry->enc_key)); |
---|
| 494 | + |
---|
| 495 | + /* Compute all needed delta information and clear the delta bits |
---|
| 496 | + * from the encrypted key. |
---|
| 497 | + */ |
---|
| 498 | + delta = mlxsw_sp_acl_erp_delta(aentry->erp_mask); |
---|
| 499 | + aentry->delta_info.start = mlxsw_sp_acl_erp_delta_start(delta); |
---|
| 500 | + aentry->delta_info.mask = mlxsw_sp_acl_erp_delta_mask(delta); |
---|
| 501 | + aentry->delta_info.value = |
---|
| 502 | + mlxsw_sp_acl_erp_delta_value(delta, |
---|
| 503 | + aentry->ht_key.full_enc_key); |
---|
| 504 | + mlxsw_sp_acl_erp_delta_clear(delta, aentry->enc_key); |
---|
| 505 | + |
---|
| 506 | + /* Add rule to the list of A-TCAM rules, assuming this |
---|
| 507 | + * rule is intended to A-TCAM. In case this rule does |
---|
| 508 | + * not fit into A-TCAM it will be removed from the list. |
---|
| 509 | + */ |
---|
| 510 | + list_add(&aentry->list, &aregion->entries_list); |
---|
454 | 511 | |
---|
455 | 512 | /* We can't insert identical rules into the A-TCAM, so fail and |
---|
456 | 513 | * let the rule spill into C-TCAM |
---|
.. | .. |
---|
461 | 518 | if (err) |
---|
462 | 519 | goto err_rhashtable_insert; |
---|
463 | 520 | |
---|
| 521 | + /* Bloom filter must be updated here, before inserting the rule into |
---|
| 522 | + * the A-TCAM. |
---|
| 523 | + */ |
---|
| 524 | + err = mlxsw_sp_acl_erp_bf_insert(mlxsw_sp, aregion, erp_mask, aentry); |
---|
| 525 | + if (err) |
---|
| 526 | + goto err_bf_insert; |
---|
| 527 | + |
---|
464 | 528 | err = mlxsw_sp_acl_atcam_region_entry_insert(mlxsw_sp, aregion, aentry, |
---|
465 | 529 | rulei); |
---|
466 | 530 | if (err) |
---|
.. | .. |
---|
469 | 533 | return 0; |
---|
470 | 534 | |
---|
471 | 535 | err_rule_insert: |
---|
| 536 | + mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, erp_mask, aentry); |
---|
| 537 | +err_bf_insert: |
---|
472 | 538 | rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node, |
---|
473 | 539 | mlxsw_sp_acl_atcam_entries_ht_params); |
---|
474 | 540 | err_rhashtable_insert: |
---|
475 | | - mlxsw_sp_acl_erp_put(aregion, erp); |
---|
| 541 | + list_del(&aentry->list); |
---|
| 542 | + mlxsw_sp_acl_erp_mask_put(aregion, erp_mask); |
---|
476 | 543 | return err; |
---|
477 | 544 | } |
---|
478 | 545 | |
---|
.. | .. |
---|
482 | 549 | struct mlxsw_sp_acl_atcam_entry *aentry) |
---|
483 | 550 | { |
---|
484 | 551 | mlxsw_sp_acl_atcam_region_entry_remove(mlxsw_sp, aregion, aentry); |
---|
| 552 | + mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, aentry->erp_mask, aentry); |
---|
485 | 553 | rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node, |
---|
486 | 554 | mlxsw_sp_acl_atcam_entries_ht_params); |
---|
487 | | - mlxsw_sp_acl_erp_put(aregion, aentry->erp); |
---|
| 555 | + list_del(&aentry->list); |
---|
| 556 | + mlxsw_sp_acl_erp_mask_put(aregion, aentry->erp_mask); |
---|
| 557 | +} |
---|
| 558 | + |
---|
| 559 | +static int |
---|
| 560 | +__mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, |
---|
| 561 | + struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 562 | + struct mlxsw_sp_acl_atcam_entry *aentry, |
---|
| 563 | + struct mlxsw_sp_acl_rule_info *rulei) |
---|
| 564 | +{ |
---|
| 565 | + return mlxsw_sp_acl_atcam_region_entry_action_replace(mlxsw_sp, aregion, |
---|
| 566 | + aentry, rulei); |
---|
488 | 567 | } |
---|
489 | 568 | |
---|
490 | 569 | int mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp, |
---|
.. | .. |
---|
502 | 581 | /* It is possible we failed to add the rule to the A-TCAM due to |
---|
503 | 582 | * exceeded number of masks. Try to spill into C-TCAM. |
---|
504 | 583 | */ |
---|
| 584 | + trace_mlxsw_sp_acl_atcam_entry_add_ctcam_spill(mlxsw_sp, aregion); |
---|
505 | 585 | err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &aregion->cregion, |
---|
506 | 586 | &achunk->cchunk, &aentry->centry, |
---|
507 | 587 | rulei, true); |
---|
.. | .. |
---|
523 | 603 | __mlxsw_sp_acl_atcam_entry_del(mlxsw_sp, aregion, aentry); |
---|
524 | 604 | } |
---|
525 | 605 | |
---|
| 606 | +int |
---|
| 607 | +mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp, |
---|
| 608 | + struct mlxsw_sp_acl_atcam_region *aregion, |
---|
| 609 | + struct mlxsw_sp_acl_atcam_entry *aentry, |
---|
| 610 | + struct mlxsw_sp_acl_rule_info *rulei) |
---|
| 611 | +{ |
---|
| 612 | + int err; |
---|
| 613 | + |
---|
| 614 | + if (mlxsw_sp_acl_atcam_is_centry(aentry)) |
---|
| 615 | + err = mlxsw_sp_acl_ctcam_entry_action_replace(mlxsw_sp, |
---|
| 616 | + &aregion->cregion, |
---|
| 617 | + &aentry->centry, |
---|
| 618 | + rulei); |
---|
| 619 | + else |
---|
| 620 | + err = __mlxsw_sp_acl_atcam_entry_action_replace(mlxsw_sp, |
---|
| 621 | + aregion, aentry, |
---|
| 622 | + rulei); |
---|
| 623 | + |
---|
| 624 | + return err; |
---|
| 625 | +} |
---|
| 626 | + |
---|
526 | 627 | int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp, |
---|
527 | 628 | struct mlxsw_sp_acl_atcam *atcam) |
---|
528 | 629 | { |
---|
.. | .. |
---|
534 | 635 | { |
---|
535 | 636 | mlxsw_sp_acl_erps_fini(mlxsw_sp, atcam); |
---|
536 | 637 | } |
---|
| 638 | + |
---|
| 639 | +void * |
---|
| 640 | +mlxsw_sp_acl_atcam_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion) |
---|
| 641 | +{ |
---|
| 642 | + return mlxsw_sp_acl_erp_rehash_hints_get(aregion); |
---|
| 643 | +} |
---|
| 644 | + |
---|
| 645 | +void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv) |
---|
| 646 | +{ |
---|
| 647 | + mlxsw_sp_acl_erp_rehash_hints_put(hints_priv); |
---|
| 648 | +} |
---|