|
71 | 71 | #include "spectrum_cnt.h"
|
72 | 72 | #include "spectrum_dpipe.h"
|
73 | 73 | #include "spectrum_acl_flex_actions.h"
|
| 74 | +#include "spectrum_span.h" |
74 | 75 | #include "../mlxfw/mlxfw.h"
|
75 | 76 |
|
76 | 77 | #define MLXSW_FWREV_MAJOR 13
|
@@ -487,325 +488,6 @@ static int mlxsw_sp_base_mac_get(struct mlxsw_sp *mlxsw_sp)
|
487 | 488 | return 0;
|
488 | 489 | }
|
489 | 490 |
|
490 |
| -static int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) |
491 |
| -{ |
492 |
| - int i; |
493 |
| - |
494 |
| - if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN)) |
495 |
| - return -EIO; |
496 |
| - |
497 |
| - mlxsw_sp->span.entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, |
498 |
| - MAX_SPAN); |
499 |
| - mlxsw_sp->span.entries = kcalloc(mlxsw_sp->span.entries_count, |
500 |
| - sizeof(struct mlxsw_sp_span_entry), |
501 |
| - GFP_KERNEL); |
502 |
| - if (!mlxsw_sp->span.entries) |
503 |
| - return -ENOMEM; |
504 |
| - |
505 |
| - for (i = 0; i < mlxsw_sp->span.entries_count; i++) |
506 |
| - INIT_LIST_HEAD(&mlxsw_sp->span.entries[i].bound_ports_list); |
507 |
| - |
508 |
| - return 0; |
509 |
| -} |
510 |
| - |
511 |
| -static void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp) |
512 |
| -{ |
513 |
| - int i; |
514 |
| - |
515 |
| - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { |
516 |
| - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; |
517 |
| - |
518 |
| - WARN_ON_ONCE(!list_empty(&curr->bound_ports_list)); |
519 |
| - } |
520 |
| - kfree(mlxsw_sp->span.entries); |
521 |
| -} |
522 |
| - |
523 |
| -static struct mlxsw_sp_span_entry * |
524 |
| -mlxsw_sp_span_entry_create(struct mlxsw_sp_port *port) |
525 |
| -{ |
526 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
527 |
| - struct mlxsw_sp_span_entry *span_entry; |
528 |
| - char mpat_pl[MLXSW_REG_MPAT_LEN]; |
529 |
| - u8 local_port = port->local_port; |
530 |
| - int index; |
531 |
| - int i; |
532 |
| - int err; |
533 |
| - |
534 |
| - /* find a free entry to use */ |
535 |
| - index = -1; |
536 |
| - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { |
537 |
| - if (!mlxsw_sp->span.entries[i].ref_count) { |
538 |
| - index = i; |
539 |
| - span_entry = &mlxsw_sp->span.entries[i]; |
540 |
| - break; |
541 |
| - } |
542 |
| - } |
543 |
| - if (index < 0) |
544 |
| - return NULL; |
545 |
| - |
546 |
| - /* create a new port analayzer entry for local_port */ |
547 |
| - mlxsw_reg_mpat_pack(mpat_pl, index, local_port, true); |
548 |
| - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); |
549 |
| - if (err) |
550 |
| - return NULL; |
551 |
| - |
552 |
| - span_entry->id = index; |
553 |
| - span_entry->ref_count = 1; |
554 |
| - span_entry->local_port = local_port; |
555 |
| - return span_entry; |
556 |
| -} |
557 |
| - |
558 |
| -static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp, |
559 |
| - struct mlxsw_sp_span_entry *span_entry) |
560 |
| -{ |
561 |
| - u8 local_port = span_entry->local_port; |
562 |
| - char mpat_pl[MLXSW_REG_MPAT_LEN]; |
563 |
| - int pa_id = span_entry->id; |
564 |
| - |
565 |
| - mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false); |
566 |
| - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); |
567 |
| -} |
568 |
| - |
569 |
| -struct mlxsw_sp_span_entry * |
570 |
| -mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port) |
571 |
| -{ |
572 |
| - int i; |
573 |
| - |
574 |
| - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { |
575 |
| - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; |
576 |
| - |
577 |
| - if (curr->ref_count && curr->local_port == local_port) |
578 |
| - return curr; |
579 |
| - } |
580 |
| - return NULL; |
581 |
| -} |
582 |
| - |
583 |
| -static struct mlxsw_sp_span_entry * |
584 |
| -mlxsw_sp_span_entry_get(struct mlxsw_sp_port *port) |
585 |
| -{ |
586 |
| - struct mlxsw_sp_span_entry *span_entry; |
587 |
| - |
588 |
| - span_entry = mlxsw_sp_span_entry_find(port->mlxsw_sp, |
589 |
| - port->local_port); |
590 |
| - if (span_entry) { |
591 |
| - /* Already exists, just take a reference */ |
592 |
| - span_entry->ref_count++; |
593 |
| - return span_entry; |
594 |
| - } |
595 |
| - |
596 |
| - return mlxsw_sp_span_entry_create(port); |
597 |
| -} |
598 |
| - |
599 |
| -static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, |
600 |
| - struct mlxsw_sp_span_entry *span_entry) |
601 |
| -{ |
602 |
| - WARN_ON(!span_entry->ref_count); |
603 |
| - if (--span_entry->ref_count == 0) |
604 |
| - mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry); |
605 |
| - return 0; |
606 |
| -} |
607 |
| - |
608 |
| -static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port) |
609 |
| -{ |
610 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
611 |
| - struct mlxsw_sp_span_inspected_port *p; |
612 |
| - int i; |
613 |
| - |
614 |
| - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { |
615 |
| - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; |
616 |
| - |
617 |
| - list_for_each_entry(p, &curr->bound_ports_list, list) |
618 |
| - if (p->local_port == port->local_port && |
619 |
| - p->type == MLXSW_SP_SPAN_EGRESS) |
620 |
| - return true; |
621 |
| - } |
622 |
| - |
623 |
| - return false; |
624 |
| -} |
625 |
| - |
626 |
| -static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp *mlxsw_sp, |
627 |
| - int mtu) |
628 |
| -{ |
629 |
| - return mlxsw_sp_bytes_cells(mlxsw_sp, mtu * 5 / 2) + 1; |
630 |
| -} |
631 |
| - |
632 |
| -static int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu) |
633 |
| -{ |
634 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
635 |
| - char sbib_pl[MLXSW_REG_SBIB_LEN]; |
636 |
| - int err; |
637 |
| - |
638 |
| - /* If port is egress mirrored, the shared buffer size should be |
639 |
| - * updated according to the mtu value |
640 |
| - */ |
641 |
| - if (mlxsw_sp_span_is_egress_mirror(port)) { |
642 |
| - u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, mtu); |
643 |
| - |
644 |
| - mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize); |
645 |
| - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); |
646 |
| - if (err) { |
647 |
| - netdev_err(port->dev, "Could not update shared buffer for mirroring\n"); |
648 |
| - return err; |
649 |
| - } |
650 |
| - } |
651 |
| - |
652 |
| - return 0; |
653 |
| -} |
654 |
| - |
655 |
| -static struct mlxsw_sp_span_inspected_port * |
656 |
| -mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_port *port, |
657 |
| - struct mlxsw_sp_span_entry *span_entry) |
658 |
| -{ |
659 |
| - struct mlxsw_sp_span_inspected_port *p; |
660 |
| - |
661 |
| - list_for_each_entry(p, &span_entry->bound_ports_list, list) |
662 |
| - if (port->local_port == p->local_port) |
663 |
| - return p; |
664 |
| - return NULL; |
665 |
| -} |
666 |
| - |
667 |
| -static int |
668 |
| -mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port, |
669 |
| - struct mlxsw_sp_span_entry *span_entry, |
670 |
| - enum mlxsw_sp_span_type type, |
671 |
| - bool bind) |
672 |
| -{ |
673 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
674 |
| - char mpar_pl[MLXSW_REG_MPAR_LEN]; |
675 |
| - int pa_id = span_entry->id; |
676 |
| - |
677 |
| - /* bind the port to the SPAN entry */ |
678 |
| - mlxsw_reg_mpar_pack(mpar_pl, port->local_port, |
679 |
| - (enum mlxsw_reg_mpar_i_e) type, bind, pa_id); |
680 |
| - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl); |
681 |
| -} |
682 |
| - |
683 |
| -static int |
684 |
| -mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port, |
685 |
| - struct mlxsw_sp_span_entry *span_entry, |
686 |
| - enum mlxsw_sp_span_type type, |
687 |
| - bool bind) |
688 |
| -{ |
689 |
| - struct mlxsw_sp_span_inspected_port *inspected_port; |
690 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
691 |
| - char sbib_pl[MLXSW_REG_SBIB_LEN]; |
692 |
| - int err; |
693 |
| - |
694 |
| - /* if it is an egress SPAN, bind a shared buffer to it */ |
695 |
| - if (type == MLXSW_SP_SPAN_EGRESS) { |
696 |
| - u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, |
697 |
| - port->dev->mtu); |
698 |
| - |
699 |
| - mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize); |
700 |
| - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); |
701 |
| - if (err) { |
702 |
| - netdev_err(port->dev, "Could not create shared buffer for mirroring\n"); |
703 |
| - return err; |
704 |
| - } |
705 |
| - } |
706 |
| - |
707 |
| - if (bind) { |
708 |
| - err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type, |
709 |
| - true); |
710 |
| - if (err) |
711 |
| - goto err_port_bind; |
712 |
| - } |
713 |
| - |
714 |
| - inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL); |
715 |
| - if (!inspected_port) { |
716 |
| - err = -ENOMEM; |
717 |
| - goto err_inspected_port_alloc; |
718 |
| - } |
719 |
| - inspected_port->local_port = port->local_port; |
720 |
| - inspected_port->type = type; |
721 |
| - list_add_tail(&inspected_port->list, &span_entry->bound_ports_list); |
722 |
| - |
723 |
| - return 0; |
724 |
| - |
725 |
| -err_inspected_port_alloc: |
726 |
| - if (bind) |
727 |
| - mlxsw_sp_span_inspected_port_bind(port, span_entry, type, |
728 |
| - false); |
729 |
| -err_port_bind: |
730 |
| - if (type == MLXSW_SP_SPAN_EGRESS) { |
731 |
| - mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0); |
732 |
| - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); |
733 |
| - } |
734 |
| - return err; |
735 |
| -} |
736 |
| - |
737 |
| -static void |
738 |
| -mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port, |
739 |
| - struct mlxsw_sp_span_entry *span_entry, |
740 |
| - enum mlxsw_sp_span_type type, |
741 |
| - bool bind) |
742 |
| -{ |
743 |
| - struct mlxsw_sp_span_inspected_port *inspected_port; |
744 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
745 |
| - char sbib_pl[MLXSW_REG_SBIB_LEN]; |
746 |
| - |
747 |
| - inspected_port = mlxsw_sp_span_entry_bound_port_find(port, span_entry); |
748 |
| - if (!inspected_port) |
749 |
| - return; |
750 |
| - |
751 |
| - if (bind) |
752 |
| - mlxsw_sp_span_inspected_port_bind(port, span_entry, type, |
753 |
| - false); |
754 |
| - /* remove the SBIB buffer if it was egress SPAN */ |
755 |
| - if (type == MLXSW_SP_SPAN_EGRESS) { |
756 |
| - mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0); |
757 |
| - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); |
758 |
| - } |
759 |
| - |
760 |
| - mlxsw_sp_span_entry_put(mlxsw_sp, span_entry); |
761 |
| - |
762 |
| - list_del(&inspected_port->list); |
763 |
| - kfree(inspected_port); |
764 |
| -} |
765 |
| - |
766 |
| -int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, |
767 |
| - struct mlxsw_sp_port *to, |
768 |
| - enum mlxsw_sp_span_type type, bool bind) |
769 |
| -{ |
770 |
| - struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp; |
771 |
| - struct mlxsw_sp_span_entry *span_entry; |
772 |
| - int err; |
773 |
| - |
774 |
| - span_entry = mlxsw_sp_span_entry_get(to); |
775 |
| - if (!span_entry) |
776 |
| - return -ENOENT; |
777 |
| - |
778 |
| - netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n", |
779 |
| - span_entry->id); |
780 |
| - |
781 |
| - err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind); |
782 |
| - if (err) |
783 |
| - goto err_port_bind; |
784 |
| - |
785 |
| - return 0; |
786 |
| - |
787 |
| -err_port_bind: |
788 |
| - mlxsw_sp_span_entry_put(mlxsw_sp, span_entry); |
789 |
| - return err; |
790 |
| -} |
791 |
| - |
792 |
| -void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port, |
793 |
| - enum mlxsw_sp_span_type type, bool bind) |
794 |
| -{ |
795 |
| - struct mlxsw_sp_span_entry *span_entry; |
796 |
| - |
797 |
| - span_entry = mlxsw_sp_span_entry_find(from->mlxsw_sp, |
798 |
| - destination_port); |
799 |
| - if (!span_entry) { |
800 |
| - netdev_err(from->dev, "no span entry found\n"); |
801 |
| - return; |
802 |
| - } |
803 |
| - |
804 |
| - netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n", |
805 |
| - span_entry->id); |
806 |
| - mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind); |
807 |
| -} |
808 |
| - |
809 | 491 | static int mlxsw_sp_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
810 | 492 | bool enable, u32 rate)
|
811 | 493 | {
|
|
0 commit comments