|
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,327 +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].used) { |
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->used = true; |
553 |
| - span_entry->id = index; |
554 |
| - span_entry->ref_count = 1; |
555 |
| - span_entry->local_port = local_port; |
556 |
| - return span_entry; |
557 |
| -} |
558 |
| - |
559 |
| -static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp, |
560 |
| - struct mlxsw_sp_span_entry *span_entry) |
561 |
| -{ |
562 |
| - u8 local_port = span_entry->local_port; |
563 |
| - char mpat_pl[MLXSW_REG_MPAT_LEN]; |
564 |
| - int pa_id = span_entry->id; |
565 |
| - |
566 |
| - mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false); |
567 |
| - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl); |
568 |
| - span_entry->used = false; |
569 |
| -} |
570 |
| - |
571 |
| -struct mlxsw_sp_span_entry * |
572 |
| -mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port) |
573 |
| -{ |
574 |
| - int i; |
575 |
| - |
576 |
| - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { |
577 |
| - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; |
578 |
| - |
579 |
| - if (curr->used && curr->local_port == local_port) |
580 |
| - return curr; |
581 |
| - } |
582 |
| - return NULL; |
583 |
| -} |
584 |
| - |
585 |
| -static struct mlxsw_sp_span_entry |
586 |
| -*mlxsw_sp_span_entry_get(struct mlxsw_sp_port *port) |
587 |
| -{ |
588 |
| - struct mlxsw_sp_span_entry *span_entry; |
589 |
| - |
590 |
| - span_entry = mlxsw_sp_span_entry_find(port->mlxsw_sp, |
591 |
| - port->local_port); |
592 |
| - if (span_entry) { |
593 |
| - /* Already exists, just take a reference */ |
594 |
| - span_entry->ref_count++; |
595 |
| - return span_entry; |
596 |
| - } |
597 |
| - |
598 |
| - return mlxsw_sp_span_entry_create(port); |
599 |
| -} |
600 |
| - |
601 |
| -static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, |
602 |
| - struct mlxsw_sp_span_entry *span_entry) |
603 |
| -{ |
604 |
| - WARN_ON(!span_entry->ref_count); |
605 |
| - if (--span_entry->ref_count == 0) |
606 |
| - mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry); |
607 |
| - return 0; |
608 |
| -} |
609 |
| - |
610 |
| -static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port) |
611 |
| -{ |
612 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
613 |
| - struct mlxsw_sp_span_inspected_port *p; |
614 |
| - int i; |
615 |
| - |
616 |
| - for (i = 0; i < mlxsw_sp->span.entries_count; i++) { |
617 |
| - struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; |
618 |
| - |
619 |
| - list_for_each_entry(p, &curr->bound_ports_list, list) |
620 |
| - if (p->local_port == port->local_port && |
621 |
| - p->type == MLXSW_SP_SPAN_EGRESS) |
622 |
| - return true; |
623 |
| - } |
624 |
| - |
625 |
| - return false; |
626 |
| -} |
627 |
| - |
628 |
| -static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp *mlxsw_sp, |
629 |
| - int mtu) |
630 |
| -{ |
631 |
| - return mlxsw_sp_bytes_cells(mlxsw_sp, mtu * 5 / 2) + 1; |
632 |
| -} |
633 |
| - |
634 |
| -static int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu) |
635 |
| -{ |
636 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
637 |
| - char sbib_pl[MLXSW_REG_SBIB_LEN]; |
638 |
| - int err; |
639 |
| - |
640 |
| - /* If port is egress mirrored, the shared buffer size should be |
641 |
| - * updated according to the mtu value |
642 |
| - */ |
643 |
| - if (mlxsw_sp_span_is_egress_mirror(port)) { |
644 |
| - u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, mtu); |
645 |
| - |
646 |
| - mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize); |
647 |
| - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); |
648 |
| - if (err) { |
649 |
| - netdev_err(port->dev, "Could not update shared buffer for mirroring\n"); |
650 |
| - return err; |
651 |
| - } |
652 |
| - } |
653 |
| - |
654 |
| - return 0; |
655 |
| -} |
656 |
| - |
657 |
| -static struct mlxsw_sp_span_inspected_port * |
658 |
| -mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_port *port, |
659 |
| - struct mlxsw_sp_span_entry *span_entry) |
660 |
| -{ |
661 |
| - struct mlxsw_sp_span_inspected_port *p; |
662 |
| - |
663 |
| - list_for_each_entry(p, &span_entry->bound_ports_list, list) |
664 |
| - if (port->local_port == p->local_port) |
665 |
| - return p; |
666 |
| - return NULL; |
667 |
| -} |
668 |
| - |
669 |
| -static int |
670 |
| -mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port, |
671 |
| - struct mlxsw_sp_span_entry *span_entry, |
672 |
| - enum mlxsw_sp_span_type type, |
673 |
| - bool bind) |
674 |
| -{ |
675 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
676 |
| - char mpar_pl[MLXSW_REG_MPAR_LEN]; |
677 |
| - int pa_id = span_entry->id; |
678 |
| - |
679 |
| - /* bind the port to the SPAN entry */ |
680 |
| - mlxsw_reg_mpar_pack(mpar_pl, port->local_port, |
681 |
| - (enum mlxsw_reg_mpar_i_e) type, bind, pa_id); |
682 |
| - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl); |
683 |
| -} |
684 |
| - |
685 |
| -static int |
686 |
| -mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port, |
687 |
| - struct mlxsw_sp_span_entry *span_entry, |
688 |
| - enum mlxsw_sp_span_type type, |
689 |
| - bool bind) |
690 |
| -{ |
691 |
| - struct mlxsw_sp_span_inspected_port *inspected_port; |
692 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
693 |
| - char sbib_pl[MLXSW_REG_SBIB_LEN]; |
694 |
| - int err; |
695 |
| - |
696 |
| - /* if it is an egress SPAN, bind a shared buffer to it */ |
697 |
| - if (type == MLXSW_SP_SPAN_EGRESS) { |
698 |
| - u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, |
699 |
| - port->dev->mtu); |
700 |
| - |
701 |
| - mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize); |
702 |
| - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); |
703 |
| - if (err) { |
704 |
| - netdev_err(port->dev, "Could not create shared buffer for mirroring\n"); |
705 |
| - return err; |
706 |
| - } |
707 |
| - } |
708 |
| - |
709 |
| - if (bind) { |
710 |
| - err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type, |
711 |
| - true); |
712 |
| - if (err) |
713 |
| - goto err_port_bind; |
714 |
| - } |
715 |
| - |
716 |
| - inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL); |
717 |
| - if (!inspected_port) { |
718 |
| - err = -ENOMEM; |
719 |
| - goto err_inspected_port_alloc; |
720 |
| - } |
721 |
| - inspected_port->local_port = port->local_port; |
722 |
| - inspected_port->type = type; |
723 |
| - list_add_tail(&inspected_port->list, &span_entry->bound_ports_list); |
724 |
| - |
725 |
| - return 0; |
726 |
| - |
727 |
| -err_inspected_port_alloc: |
728 |
| - if (bind) |
729 |
| - mlxsw_sp_span_inspected_port_bind(port, span_entry, type, |
730 |
| - false); |
731 |
| -err_port_bind: |
732 |
| - if (type == MLXSW_SP_SPAN_EGRESS) { |
733 |
| - mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0); |
734 |
| - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); |
735 |
| - } |
736 |
| - return err; |
737 |
| -} |
738 |
| - |
739 |
| -static void |
740 |
| -mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port, |
741 |
| - struct mlxsw_sp_span_entry *span_entry, |
742 |
| - enum mlxsw_sp_span_type type, |
743 |
| - bool bind) |
744 |
| -{ |
745 |
| - struct mlxsw_sp_span_inspected_port *inspected_port; |
746 |
| - struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; |
747 |
| - char sbib_pl[MLXSW_REG_SBIB_LEN]; |
748 |
| - |
749 |
| - inspected_port = mlxsw_sp_span_entry_bound_port_find(port, span_entry); |
750 |
| - if (!inspected_port) |
751 |
| - return; |
752 |
| - |
753 |
| - if (bind) |
754 |
| - mlxsw_sp_span_inspected_port_bind(port, span_entry, type, |
755 |
| - false); |
756 |
| - /* remove the SBIB buffer if it was egress SPAN */ |
757 |
| - if (type == MLXSW_SP_SPAN_EGRESS) { |
758 |
| - mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0); |
759 |
| - mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl); |
760 |
| - } |
761 |
| - |
762 |
| - mlxsw_sp_span_entry_put(mlxsw_sp, span_entry); |
763 |
| - |
764 |
| - list_del(&inspected_port->list); |
765 |
| - kfree(inspected_port); |
766 |
| -} |
767 |
| - |
768 |
| -int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, |
769 |
| - struct mlxsw_sp_port *to, |
770 |
| - enum mlxsw_sp_span_type type, bool bind) |
771 |
| -{ |
772 |
| - struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp; |
773 |
| - struct mlxsw_sp_span_entry *span_entry; |
774 |
| - int err; |
775 |
| - |
776 |
| - span_entry = mlxsw_sp_span_entry_get(to); |
777 |
| - if (!span_entry) |
778 |
| - return -ENOENT; |
779 |
| - |
780 |
| - netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n", |
781 |
| - span_entry->id); |
782 |
| - |
783 |
| - err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind); |
784 |
| - if (err) |
785 |
| - goto err_port_bind; |
786 |
| - |
787 |
| - return 0; |
788 |
| - |
789 |
| -err_port_bind: |
790 |
| - mlxsw_sp_span_entry_put(mlxsw_sp, span_entry); |
791 |
| - return err; |
792 |
| -} |
793 |
| - |
794 |
| -void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port, |
795 |
| - enum mlxsw_sp_span_type type, bool bind) |
796 |
| -{ |
797 |
| - struct mlxsw_sp_span_entry *span_entry; |
798 |
| - |
799 |
| - span_entry = mlxsw_sp_span_entry_find(from->mlxsw_sp, |
800 |
| - destination_port); |
801 |
| - if (!span_entry) { |
802 |
| - netdev_err(from->dev, "no span entry found\n"); |
803 |
| - return; |
804 |
| - } |
805 |
| - |
806 |
| - netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n", |
807 |
| - span_entry->id); |
808 |
| - mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind); |
809 |
| -} |
810 |
| - |
811 | 491 | static int mlxsw_sp_port_sample_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
812 | 492 | bool enable, u32 rate)
|
813 | 493 | {
|
|
0 commit comments