hc
2024-01-03 2f7c68cb55ecb7331f2381deb497c27155f32faf
kernel/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
....@@ -3,6 +3,10 @@
33
44 #include <linux/if_bridge.h>
55 #include <linux/list.h>
6
+#include <linux/mutex.h>
7
+#include <linux/refcount.h>
8
+#include <linux/rtnetlink.h>
9
+#include <linux/workqueue.h>
610 #include <net/arp.h>
711 #include <net/gre.h>
812 #include <net/lag.h>
....@@ -14,45 +18,155 @@
1418 #include "spectrum_span.h"
1519 #include "spectrum_switchdev.h"
1620
21
+struct mlxsw_sp_span {
22
+ struct work_struct work;
23
+ struct mlxsw_sp *mlxsw_sp;
24
+ const struct mlxsw_sp_span_trigger_ops **span_trigger_ops_arr;
25
+ const struct mlxsw_sp_span_entry_ops **span_entry_ops_arr;
26
+ size_t span_entry_ops_arr_size;
27
+ struct list_head analyzed_ports_list;
28
+ struct mutex analyzed_ports_lock; /* Protects analyzed_ports_list */
29
+ struct list_head trigger_entries_list;
30
+ u16 policer_id_base;
31
+ refcount_t policer_id_base_ref_count;
32
+ atomic_t active_entries_count;
33
+ int entries_count;
34
+ struct mlxsw_sp_span_entry entries[];
35
+};
36
+
37
+struct mlxsw_sp_span_analyzed_port {
38
+ struct list_head list; /* Member of analyzed_ports_list */
39
+ refcount_t ref_count;
40
+ u8 local_port;
41
+ bool ingress;
42
+};
43
+
44
+struct mlxsw_sp_span_trigger_entry {
45
+ struct list_head list; /* Member of trigger_entries_list */
46
+ struct mlxsw_sp_span *span;
47
+ const struct mlxsw_sp_span_trigger_ops *ops;
48
+ refcount_t ref_count;
49
+ u8 local_port;
50
+ enum mlxsw_sp_span_trigger trigger;
51
+ struct mlxsw_sp_span_trigger_parms parms;
52
+};
53
+
54
+enum mlxsw_sp_span_trigger_type {
55
+ MLXSW_SP_SPAN_TRIGGER_TYPE_PORT,
56
+ MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL,
57
+};
58
+
59
+struct mlxsw_sp_span_trigger_ops {
60
+ int (*bind)(struct mlxsw_sp_span_trigger_entry *trigger_entry);
61
+ void (*unbind)(struct mlxsw_sp_span_trigger_entry *trigger_entry);
62
+ bool (*matches)(struct mlxsw_sp_span_trigger_entry *trigger_entry,
63
+ enum mlxsw_sp_span_trigger trigger,
64
+ struct mlxsw_sp_port *mlxsw_sp_port);
65
+ int (*enable)(struct mlxsw_sp_span_trigger_entry *trigger_entry,
66
+ struct mlxsw_sp_port *mlxsw_sp_port, u8 tc);
67
+ void (*disable)(struct mlxsw_sp_span_trigger_entry *trigger_entry,
68
+ struct mlxsw_sp_port *mlxsw_sp_port, u8 tc);
69
+};
70
+
71
+static void mlxsw_sp_span_respin_work(struct work_struct *work);
72
+
73
+static u64 mlxsw_sp_span_occ_get(void *priv)
74
+{
75
+ const struct mlxsw_sp *mlxsw_sp = priv;
76
+
77
+ return atomic_read(&mlxsw_sp->span->active_entries_count);
78
+}
79
+
1780 int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp)
1881 {
19
- int i;
82
+ struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
83
+ struct mlxsw_sp_span *span;
84
+ int i, entries_count, err;
2085
2186 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_SPAN))
2287 return -EIO;
2388
24
- mlxsw_sp->span.entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core,
25
- MAX_SPAN);
26
- mlxsw_sp->span.entries = kcalloc(mlxsw_sp->span.entries_count,
27
- sizeof(struct mlxsw_sp_span_entry),
28
- GFP_KERNEL);
29
- if (!mlxsw_sp->span.entries)
89
+ entries_count = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_SPAN);
90
+ span = kzalloc(struct_size(span, entries, entries_count), GFP_KERNEL);
91
+ if (!span)
3092 return -ENOMEM;
93
+ refcount_set(&span->policer_id_base_ref_count, 0);
94
+ span->entries_count = entries_count;
95
+ atomic_set(&span->active_entries_count, 0);
96
+ mutex_init(&span->analyzed_ports_lock);
97
+ INIT_LIST_HEAD(&span->analyzed_ports_list);
98
+ INIT_LIST_HEAD(&span->trigger_entries_list);
99
+ span->mlxsw_sp = mlxsw_sp;
100
+ mlxsw_sp->span = span;
31101
32
- for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
33
- struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
102
+ for (i = 0; i < mlxsw_sp->span->entries_count; i++)
103
+ mlxsw_sp->span->entries[i].id = i;
34104
35
- INIT_LIST_HEAD(&curr->bound_ports_list);
36
- curr->id = i;
37
- }
105
+ err = mlxsw_sp->span_ops->init(mlxsw_sp);
106
+ if (err)
107
+ goto err_init;
108
+
109
+ devlink_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_SPAN,
110
+ mlxsw_sp_span_occ_get, mlxsw_sp);
111
+ INIT_WORK(&span->work, mlxsw_sp_span_respin_work);
38112
39113 return 0;
114
+
115
+err_init:
116
+ mutex_destroy(&mlxsw_sp->span->analyzed_ports_lock);
117
+ kfree(mlxsw_sp->span);
118
+ return err;
40119 }
41120
42121 void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp)
43122 {
44
- int i;
123
+ struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
45124
46
- for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
47
- struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
125
+ cancel_work_sync(&mlxsw_sp->span->work);
126
+ devlink_resource_occ_get_unregister(devlink, MLXSW_SP_RESOURCE_SPAN);
48127
49
- WARN_ON_ONCE(!list_empty(&curr->bound_ports_list));
50
- }
51
- kfree(mlxsw_sp->span.entries);
128
+ WARN_ON_ONCE(!list_empty(&mlxsw_sp->span->trigger_entries_list));
129
+ WARN_ON_ONCE(!list_empty(&mlxsw_sp->span->analyzed_ports_list));
130
+ mutex_destroy(&mlxsw_sp->span->analyzed_ports_lock);
131
+ kfree(mlxsw_sp->span);
132
+}
133
+
134
+static bool mlxsw_sp1_span_cpu_can_handle(const struct net_device *dev)
135
+{
136
+ return !dev;
137
+}
138
+
139
+static int mlxsw_sp1_span_entry_cpu_parms(struct mlxsw_sp *mlxsw_sp,
140
+ const struct net_device *to_dev,
141
+ struct mlxsw_sp_span_parms *sparmsp)
142
+{
143
+ return -EOPNOTSUPP;
52144 }
53145
54146 static int
55
-mlxsw_sp_span_entry_phys_parms(const struct net_device *to_dev,
147
+mlxsw_sp1_span_entry_cpu_configure(struct mlxsw_sp_span_entry *span_entry,
148
+ struct mlxsw_sp_span_parms sparms)
149
+{
150
+ return -EOPNOTSUPP;
151
+}
152
+
153
+static void
154
+mlxsw_sp1_span_entry_cpu_deconfigure(struct mlxsw_sp_span_entry *span_entry)
155
+{
156
+}
157
+
158
+static const
159
+struct mlxsw_sp_span_entry_ops mlxsw_sp1_span_entry_ops_cpu = {
160
+ .is_static = true,
161
+ .can_handle = mlxsw_sp1_span_cpu_can_handle,
162
+ .parms_set = mlxsw_sp1_span_entry_cpu_parms,
163
+ .configure = mlxsw_sp1_span_entry_cpu_configure,
164
+ .deconfigure = mlxsw_sp1_span_entry_cpu_deconfigure,
165
+};
166
+
167
+static int
168
+mlxsw_sp_span_entry_phys_parms(struct mlxsw_sp *mlxsw_sp,
169
+ const struct net_device *to_dev,
56170 struct mlxsw_sp_span_parms *sparmsp)
57171 {
58172 sparmsp->dest_port = netdev_priv(to_dev);
....@@ -72,6 +186,8 @@
72186 /* Create a new port analayzer entry for local_port. */
73187 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
74188 MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH);
189
+ mlxsw_reg_mpat_pide_set(mpat_pl, sparms.policer_enable);
190
+ mlxsw_reg_mpat_pid_set(mpat_pl, sparms.policer_id);
75191
76192 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
77193 }
....@@ -99,8 +215,9 @@
99215
100216 static const
101217 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = {
218
+ .is_static = true,
102219 .can_handle = mlxsw_sp_port_dev_check,
103
- .parms = mlxsw_sp_span_entry_phys_parms,
220
+ .parms_set = mlxsw_sp_span_entry_phys_parms,
104221 .configure = mlxsw_sp_span_entry_phys_configure,
105222 .deconfigure = mlxsw_sp_span_entry_phys_deconfigure,
106223 };
....@@ -305,7 +422,7 @@
305422
306423 parms = mlxsw_sp_ipip_netdev_parms4(to_dev);
307424 ip_tunnel_init_flow(&fl4, parms.iph.protocol, *daddrp, *saddrp,
308
- 0, 0, parms.link, tun->fwmark);
425
+ 0, 0, parms.link, tun->fwmark, 0);
309426
310427 rt = ip_route_output_key(tun->net, &fl4);
311428 if (IS_ERR(rt))
....@@ -316,7 +433,11 @@
316433
317434 dev = rt->dst.dev;
318435 *saddrp = fl4.saddr;
319
- *daddrp = rt->rt_gateway;
436
+ if (rt->rt_gw_family == AF_INET)
437
+ *daddrp = rt->rt_gw4;
438
+ /* can not offload if route has an IPv6 gateway */
439
+ else if (rt->rt_gw_family == AF_INET6)
440
+ dev = NULL;
320441
321442 out:
322443 ip_rt_put(rt);
....@@ -324,7 +445,8 @@
324445 }
325446
326447 static int
327
-mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev,
448
+mlxsw_sp_span_entry_gretap4_parms(struct mlxsw_sp *mlxsw_sp,
449
+ const struct net_device *to_dev,
328450 struct mlxsw_sp_span_parms *sparmsp)
329451 {
330452 struct ip_tunnel_parm tparm = mlxsw_sp_ipip_netdev_parms4(to_dev);
....@@ -363,6 +485,8 @@
363485 /* Create a new port analayzer entry for local_port. */
364486 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
365487 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
488
+ mlxsw_reg_mpat_pide_set(mpat_pl, sparms.policer_enable);
489
+ mlxsw_reg_mpat_pid_set(mpat_pl, sparms.policer_id);
366490 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl, sparms.vid);
367491 mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl,
368492 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER,
....@@ -383,8 +507,8 @@
383507 }
384508
385509 static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap4 = {
386
- .can_handle = is_gretap_dev,
387
- .parms = mlxsw_sp_span_entry_gretap4_parms,
510
+ .can_handle = netif_is_gretap,
511
+ .parms_set = mlxsw_sp_span_entry_gretap4_parms,
388512 .configure = mlxsw_sp_span_entry_gretap4_configure,
389513 .deconfigure = mlxsw_sp_span_entry_gretap4_deconfigure,
390514 };
....@@ -425,7 +549,8 @@
425549 }
426550
427551 static int
428
-mlxsw_sp_span_entry_gretap6_parms(const struct net_device *to_dev,
552
+mlxsw_sp_span_entry_gretap6_parms(struct mlxsw_sp *mlxsw_sp,
553
+ const struct net_device *to_dev,
429554 struct mlxsw_sp_span_parms *sparmsp)
430555 {
431556 struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(to_dev);
....@@ -464,6 +589,8 @@
464589 /* Create a new port analayzer entry for local_port. */
465590 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
466591 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
592
+ mlxsw_reg_mpat_pide_set(mpat_pl, sparms.policer_enable);
593
+ mlxsw_reg_mpat_pid_set(mpat_pl, sparms.policer_id);
467594 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl, sparms.vid);
468595 mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl,
469596 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER,
....@@ -484,8 +611,8 @@
484611
485612 static const
486613 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap6 = {
487
- .can_handle = is_ip6gretap_dev,
488
- .parms = mlxsw_sp_span_entry_gretap6_parms,
614
+ .can_handle = netif_is_ip6gretap,
615
+ .parms_set = mlxsw_sp_span_entry_gretap6_parms,
489616 .configure = mlxsw_sp_span_entry_gretap6_configure,
490617 .deconfigure = mlxsw_sp_span_entry_gretap6_deconfigure,
491618 };
....@@ -499,7 +626,8 @@
499626 }
500627
501628 static int
502
-mlxsw_sp_span_entry_vlan_parms(const struct net_device *to_dev,
629
+mlxsw_sp_span_entry_vlan_parms(struct mlxsw_sp *mlxsw_sp,
630
+ const struct net_device *to_dev,
503631 struct mlxsw_sp_span_parms *sparmsp)
504632 {
505633 struct net_device *real_dev;
....@@ -526,6 +654,8 @@
526654
527655 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
528656 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH);
657
+ mlxsw_reg_mpat_pide_set(mpat_pl, sparms.policer_enable);
658
+ mlxsw_reg_mpat_pid_set(mpat_pl, sparms.policer_id);
529659 mlxsw_reg_mpat_eth_rspan_pack(mpat_pl, sparms.vid);
530660
531661 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
....@@ -541,13 +671,68 @@
541671 static const
542672 struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_vlan = {
543673 .can_handle = mlxsw_sp_span_vlan_can_handle,
544
- .parms = mlxsw_sp_span_entry_vlan_parms,
674
+ .parms_set = mlxsw_sp_span_entry_vlan_parms,
545675 .configure = mlxsw_sp_span_entry_vlan_configure,
546676 .deconfigure = mlxsw_sp_span_entry_vlan_deconfigure,
547677 };
548678
549679 static const
550
-struct mlxsw_sp_span_entry_ops *const mlxsw_sp_span_entry_types[] = {
680
+struct mlxsw_sp_span_entry_ops *mlxsw_sp1_span_entry_ops_arr[] = {
681
+ &mlxsw_sp1_span_entry_ops_cpu,
682
+ &mlxsw_sp_span_entry_ops_phys,
683
+#if IS_ENABLED(CONFIG_NET_IPGRE)
684
+ &mlxsw_sp_span_entry_ops_gretap4,
685
+#endif
686
+#if IS_ENABLED(CONFIG_IPV6_GRE)
687
+ &mlxsw_sp_span_entry_ops_gretap6,
688
+#endif
689
+ &mlxsw_sp_span_entry_ops_vlan,
690
+};
691
+
692
+static bool mlxsw_sp2_span_cpu_can_handle(const struct net_device *dev)
693
+{
694
+ return !dev;
695
+}
696
+
697
+static int mlxsw_sp2_span_entry_cpu_parms(struct mlxsw_sp *mlxsw_sp,
698
+ const struct net_device *to_dev,
699
+ struct mlxsw_sp_span_parms *sparmsp)
700
+{
701
+ sparmsp->dest_port = mlxsw_sp->ports[MLXSW_PORT_CPU_PORT];
702
+ return 0;
703
+}
704
+
705
+static int
706
+mlxsw_sp2_span_entry_cpu_configure(struct mlxsw_sp_span_entry *span_entry,
707
+ struct mlxsw_sp_span_parms sparms)
708
+{
709
+ /* Mirroring to the CPU port is like mirroring to any other physical
710
+ * port. Its local port is used instead of that of the physical port.
711
+ */
712
+ return mlxsw_sp_span_entry_phys_configure(span_entry, sparms);
713
+}
714
+
715
+static void
716
+mlxsw_sp2_span_entry_cpu_deconfigure(struct mlxsw_sp_span_entry *span_entry)
717
+{
718
+ enum mlxsw_reg_mpat_span_type span_type;
719
+
720
+ span_type = MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH;
721
+ mlxsw_sp_span_entry_deconfigure_common(span_entry, span_type);
722
+}
723
+
724
+static const
725
+struct mlxsw_sp_span_entry_ops mlxsw_sp2_span_entry_ops_cpu = {
726
+ .is_static = true,
727
+ .can_handle = mlxsw_sp2_span_cpu_can_handle,
728
+ .parms_set = mlxsw_sp2_span_entry_cpu_parms,
729
+ .configure = mlxsw_sp2_span_entry_cpu_configure,
730
+ .deconfigure = mlxsw_sp2_span_entry_cpu_deconfigure,
731
+};
732
+
733
+static const
734
+struct mlxsw_sp_span_entry_ops *mlxsw_sp2_span_entry_ops_arr[] = {
735
+ &mlxsw_sp2_span_entry_ops_cpu,
551736 &mlxsw_sp_span_entry_ops_phys,
552737 #if IS_ENABLED(CONFIG_NET_IPGRE)
553738 &mlxsw_sp_span_entry_ops_gretap4,
....@@ -559,7 +744,8 @@
559744 };
560745
561746 static int
562
-mlxsw_sp_span_entry_nop_parms(const struct net_device *to_dev,
747
+mlxsw_sp_span_entry_nop_parms(struct mlxsw_sp *mlxsw_sp,
748
+ const struct net_device *to_dev,
563749 struct mlxsw_sp_span_parms *sparmsp)
564750 {
565751 return mlxsw_sp_span_entry_unoffloadable(sparmsp);
....@@ -578,7 +764,7 @@
578764 }
579765
580766 static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_nop = {
581
- .parms = mlxsw_sp_span_entry_nop_parms,
767
+ .parms_set = mlxsw_sp_span_entry_nop_parms,
582768 .configure = mlxsw_sp_span_entry_nop_configure,
583769 .deconfigure = mlxsw_sp_span_entry_nop_deconfigure,
584770 };
....@@ -588,18 +774,26 @@
588774 struct mlxsw_sp_span_entry *span_entry,
589775 struct mlxsw_sp_span_parms sparms)
590776 {
591
- if (sparms.dest_port) {
592
- if (sparms.dest_port->mlxsw_sp != mlxsw_sp) {
593
- netdev_err(span_entry->to_dev, "Cannot mirror to %s, which belongs to a different mlxsw instance",
594
- sparms.dest_port->dev->name);
595
- sparms.dest_port = NULL;
596
- } else if (span_entry->ops->configure(span_entry, sparms)) {
597
- netdev_err(span_entry->to_dev, "Failed to offload mirror to %s",
598
- sparms.dest_port->dev->name);
599
- sparms.dest_port = NULL;
600
- }
777
+ int err;
778
+
779
+ if (!sparms.dest_port)
780
+ goto set_parms;
781
+
782
+ if (sparms.dest_port->mlxsw_sp != mlxsw_sp) {
783
+ dev_err(mlxsw_sp->bus_info->dev,
784
+ "Cannot mirror to a port which belongs to a different mlxsw instance\n");
785
+ sparms.dest_port = NULL;
786
+ goto set_parms;
601787 }
602788
789
+ err = span_entry->ops->configure(span_entry, sparms);
790
+ if (err) {
791
+ dev_err(mlxsw_sp->bus_info->dev, "Failed to offload mirror\n");
792
+ sparms.dest_port = NULL;
793
+ goto set_parms;
794
+ }
795
+
796
+set_parms:
603797 span_entry->parms = sparms;
604798 }
605799
....@@ -608,6 +802,46 @@
608802 {
609803 if (span_entry->parms.dest_port)
610804 span_entry->ops->deconfigure(span_entry);
805
+}
806
+
807
+static int mlxsw_sp_span_policer_id_base_set(struct mlxsw_sp_span *span,
808
+ u16 policer_id)
809
+{
810
+ struct mlxsw_sp *mlxsw_sp = span->mlxsw_sp;
811
+ u16 policer_id_base;
812
+ int err;
813
+
814
+ /* Policers set on SPAN agents must be in the range of
815
+ * `policer_id_base .. policer_id_base + max_span_agents - 1`. If the
816
+ * base is set and the new policer is not within the range, then we
817
+ * must error out.
818
+ */
819
+ if (refcount_read(&span->policer_id_base_ref_count)) {
820
+ if (policer_id < span->policer_id_base ||
821
+ policer_id >= span->policer_id_base + span->entries_count)
822
+ return -EINVAL;
823
+
824
+ refcount_inc(&span->policer_id_base_ref_count);
825
+ return 0;
826
+ }
827
+
828
+ /* Base must be even. */
829
+ policer_id_base = policer_id % 2 == 0 ? policer_id : policer_id - 1;
830
+ err = mlxsw_sp->span_ops->policer_id_base_set(mlxsw_sp,
831
+ policer_id_base);
832
+ if (err)
833
+ return err;
834
+
835
+ span->policer_id_base = policer_id_base;
836
+ refcount_set(&span->policer_id_base_ref_count, 1);
837
+
838
+ return 0;
839
+}
840
+
841
+static void mlxsw_sp_span_policer_id_base_unset(struct mlxsw_sp_span *span)
842
+{
843
+ if (refcount_dec_and_test(&span->policer_id_base_ref_count))
844
+ span->policer_id_base = 0;
611845 }
612846
613847 static struct mlxsw_sp_span_entry *
....@@ -620,26 +854,40 @@
620854 int i;
621855
622856 /* find a free entry to use */
623
- for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
624
- if (!mlxsw_sp->span.entries[i].ref_count) {
625
- span_entry = &mlxsw_sp->span.entries[i];
857
+ for (i = 0; i < mlxsw_sp->span->entries_count; i++) {
858
+ if (!refcount_read(&mlxsw_sp->span->entries[i].ref_count)) {
859
+ span_entry = &mlxsw_sp->span->entries[i];
626860 break;
627861 }
628862 }
629863 if (!span_entry)
630864 return NULL;
631865
866
+ if (sparms.policer_enable) {
867
+ int err;
868
+
869
+ err = mlxsw_sp_span_policer_id_base_set(mlxsw_sp->span,
870
+ sparms.policer_id);
871
+ if (err)
872
+ return NULL;
873
+ }
874
+
875
+ atomic_inc(&mlxsw_sp->span->active_entries_count);
632876 span_entry->ops = ops;
633
- span_entry->ref_count = 1;
877
+ refcount_set(&span_entry->ref_count, 1);
634878 span_entry->to_dev = to_dev;
635879 mlxsw_sp_span_entry_configure(mlxsw_sp, span_entry, sparms);
636880
637881 return span_entry;
638882 }
639883
640
-static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp_span_entry *span_entry)
884
+static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp,
885
+ struct mlxsw_sp_span_entry *span_entry)
641886 {
642887 mlxsw_sp_span_entry_deconfigure(span_entry);
888
+ atomic_dec(&mlxsw_sp->span->active_entries_count);
889
+ if (span_entry->parms.policer_enable)
890
+ mlxsw_sp_span_policer_id_base_unset(mlxsw_sp->span);
643891 }
644892
645893 struct mlxsw_sp_span_entry *
....@@ -648,10 +896,10 @@
648896 {
649897 int i;
650898
651
- for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
652
- struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
899
+ for (i = 0; i < mlxsw_sp->span->entries_count; i++) {
900
+ struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i];
653901
654
- if (curr->ref_count && curr->to_dev == to_dev)
902
+ if (refcount_read(&curr->ref_count) && curr->to_dev == to_dev)
655903 return curr;
656904 }
657905 return NULL;
....@@ -669,10 +917,28 @@
669917 {
670918 int i;
671919
672
- for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
673
- struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
920
+ for (i = 0; i < mlxsw_sp->span->entries_count; i++) {
921
+ struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i];
674922
675
- if (curr->ref_count && curr->id == span_id)
923
+ if (refcount_read(&curr->ref_count) && curr->id == span_id)
924
+ return curr;
925
+ }
926
+ return NULL;
927
+}
928
+
929
+static struct mlxsw_sp_span_entry *
930
+mlxsw_sp_span_entry_find_by_parms(struct mlxsw_sp *mlxsw_sp,
931
+ const struct net_device *to_dev,
932
+ const struct mlxsw_sp_span_parms *sparms)
933
+{
934
+ int i;
935
+
936
+ for (i = 0; i < mlxsw_sp->span->entries_count; i++) {
937
+ struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i];
938
+
939
+ if (refcount_read(&curr->ref_count) && curr->to_dev == to_dev &&
940
+ curr->parms.policer_enable == sparms->policer_enable &&
941
+ curr->parms.policer_id == sparms->policer_id)
676942 return curr;
677943 }
678944 return NULL;
....@@ -686,10 +952,11 @@
686952 {
687953 struct mlxsw_sp_span_entry *span_entry;
688954
689
- span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, to_dev);
955
+ span_entry = mlxsw_sp_span_entry_find_by_parms(mlxsw_sp, to_dev,
956
+ &sparms);
690957 if (span_entry) {
691958 /* Already exists, just take a reference */
692
- span_entry->ref_count++;
959
+ refcount_inc(&span_entry->ref_count);
693960 return span_entry;
694961 }
695962
....@@ -699,273 +966,83 @@
699966 static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
700967 struct mlxsw_sp_span_entry *span_entry)
701968 {
702
- WARN_ON(!span_entry->ref_count);
703
- if (--span_entry->ref_count == 0)
704
- mlxsw_sp_span_entry_destroy(span_entry);
969
+ if (refcount_dec_and_test(&span_entry->ref_count))
970
+ mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry);
705971 return 0;
706972 }
707973
708
-static bool mlxsw_sp_span_is_egress_mirror(struct mlxsw_sp_port *port)
974
+static int mlxsw_sp_span_port_buffer_update(struct mlxsw_sp_port *mlxsw_sp_port, bool enable)
709975 {
710
- struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
711
- struct mlxsw_sp_span_inspected_port *p;
712
- int i;
976
+ struct mlxsw_sp_hdroom hdroom;
713977
714
- for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
715
- struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
978
+ hdroom = *mlxsw_sp_port->hdroom;
979
+ hdroom.int_buf.enable = enable;
980
+ mlxsw_sp_hdroom_bufs_reset_sizes(mlxsw_sp_port, &hdroom);
716981
717
- list_for_each_entry(p, &curr->bound_ports_list, list)
718
- if (p->local_port == port->local_port &&
719
- p->type == MLXSW_SP_SPAN_EGRESS)
720
- return true;
982
+ return mlxsw_sp_hdroom_configure(mlxsw_sp_port, &hdroom);
983
+}
984
+
985
+static int
986
+mlxsw_sp_span_port_buffer_enable(struct mlxsw_sp_port *mlxsw_sp_port)
987
+{
988
+ return mlxsw_sp_span_port_buffer_update(mlxsw_sp_port, true);
989
+}
990
+
991
+static void mlxsw_sp_span_port_buffer_disable(struct mlxsw_sp_port *mlxsw_sp_port)
992
+{
993
+ mlxsw_sp_span_port_buffer_update(mlxsw_sp_port, false);
994
+}
995
+
996
+static struct mlxsw_sp_span_analyzed_port *
997
+mlxsw_sp_span_analyzed_port_find(struct mlxsw_sp_span *span, u8 local_port,
998
+ bool ingress)
999
+{
1000
+ struct mlxsw_sp_span_analyzed_port *analyzed_port;
1001
+
1002
+ list_for_each_entry(analyzed_port, &span->analyzed_ports_list, list) {
1003
+ if (analyzed_port->local_port == local_port &&
1004
+ analyzed_port->ingress == ingress)
1005
+ return analyzed_port;
7211006 }
7221007
723
- return false;
724
-}
725
-
726
-static int mlxsw_sp_span_mtu_to_buffsize(const struct mlxsw_sp *mlxsw_sp,
727
- int mtu)
728
-{
729
- return mlxsw_sp_bytes_cells(mlxsw_sp, mtu * 5 / 2) + 1;
730
-}
731
-
732
-int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu)
733
-{
734
- struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
735
- char sbib_pl[MLXSW_REG_SBIB_LEN];
736
- int err;
737
-
738
- /* If port is egress mirrored, the shared buffer size should be
739
- * updated according to the mtu value
740
- */
741
- if (mlxsw_sp_span_is_egress_mirror(port)) {
742
- u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp, mtu);
743
-
744
- mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
745
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
746
- if (err) {
747
- netdev_err(port->dev, "Could not update shared buffer for mirroring\n");
748
- return err;
749
- }
750
- }
751
-
752
- return 0;
753
-}
754
-
755
-static struct mlxsw_sp_span_inspected_port *
756
-mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_span_entry *span_entry,
757
- enum mlxsw_sp_span_type type,
758
- struct mlxsw_sp_port *port,
759
- bool bind)
760
-{
761
- struct mlxsw_sp_span_inspected_port *p;
762
-
763
- list_for_each_entry(p, &span_entry->bound_ports_list, list)
764
- if (type == p->type &&
765
- port->local_port == p->local_port &&
766
- bind == p->bound)
767
- return p;
7681008 return NULL;
769
-}
770
-
771
-static int
772
-mlxsw_sp_span_inspected_port_bind(struct mlxsw_sp_port *port,
773
- struct mlxsw_sp_span_entry *span_entry,
774
- enum mlxsw_sp_span_type type,
775
- bool bind)
776
-{
777
- struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
778
- char mpar_pl[MLXSW_REG_MPAR_LEN];
779
- int pa_id = span_entry->id;
780
-
781
- /* bind the port to the SPAN entry */
782
- mlxsw_reg_mpar_pack(mpar_pl, port->local_port,
783
- (enum mlxsw_reg_mpar_i_e)type, bind, pa_id);
784
- return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl);
785
-}
786
-
787
-static int
788
-mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port,
789
- struct mlxsw_sp_span_entry *span_entry,
790
- enum mlxsw_sp_span_type type,
791
- bool bind)
792
-{
793
- struct mlxsw_sp_span_inspected_port *inspected_port;
794
- struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
795
- char sbib_pl[MLXSW_REG_SBIB_LEN];
796
- int i;
797
- int err;
798
-
799
- /* A given (source port, direction) can only be bound to one analyzer,
800
- * so if a binding is requested, check for conflicts.
801
- */
802
- if (bind)
803
- for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
804
- struct mlxsw_sp_span_entry *curr =
805
- &mlxsw_sp->span.entries[i];
806
-
807
- if (mlxsw_sp_span_entry_bound_port_find(curr, type,
808
- port, bind))
809
- return -EEXIST;
810
- }
811
-
812
- /* if it is an egress SPAN, bind a shared buffer to it */
813
- if (type == MLXSW_SP_SPAN_EGRESS) {
814
- u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp,
815
- port->dev->mtu);
816
-
817
- mlxsw_reg_sbib_pack(sbib_pl, port->local_port, buffsize);
818
- err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
819
- if (err) {
820
- netdev_err(port->dev, "Could not create shared buffer for mirroring\n");
821
- return err;
822
- }
823
- }
824
-
825
- if (bind) {
826
- err = mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
827
- true);
828
- if (err)
829
- goto err_port_bind;
830
- }
831
-
832
- inspected_port = kzalloc(sizeof(*inspected_port), GFP_KERNEL);
833
- if (!inspected_port) {
834
- err = -ENOMEM;
835
- goto err_inspected_port_alloc;
836
- }
837
- inspected_port->local_port = port->local_port;
838
- inspected_port->type = type;
839
- inspected_port->bound = bind;
840
- list_add_tail(&inspected_port->list, &span_entry->bound_ports_list);
841
-
842
- return 0;
843
-
844
-err_inspected_port_alloc:
845
- if (bind)
846
- mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
847
- false);
848
-err_port_bind:
849
- if (type == MLXSW_SP_SPAN_EGRESS) {
850
- mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0);
851
- mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
852
- }
853
- return err;
854
-}
855
-
856
-static void
857
-mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port,
858
- struct mlxsw_sp_span_entry *span_entry,
859
- enum mlxsw_sp_span_type type,
860
- bool bind)
861
-{
862
- struct mlxsw_sp_span_inspected_port *inspected_port;
863
- struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
864
- char sbib_pl[MLXSW_REG_SBIB_LEN];
865
-
866
- inspected_port = mlxsw_sp_span_entry_bound_port_find(span_entry, type,
867
- port, bind);
868
- if (!inspected_port)
869
- return;
870
-
871
- if (bind)
872
- mlxsw_sp_span_inspected_port_bind(port, span_entry, type,
873
- false);
874
- /* remove the SBIB buffer if it was egress SPAN */
875
- if (type == MLXSW_SP_SPAN_EGRESS) {
876
- mlxsw_reg_sbib_pack(sbib_pl, port->local_port, 0);
877
- mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sbib), sbib_pl);
878
- }
879
-
880
- mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
881
-
882
- list_del(&inspected_port->list);
883
- kfree(inspected_port);
8841009 }
8851010
8861011 static const struct mlxsw_sp_span_entry_ops *
8871012 mlxsw_sp_span_entry_ops(struct mlxsw_sp *mlxsw_sp,
8881013 const struct net_device *to_dev)
8891014 {
1015
+ struct mlxsw_sp_span *span = mlxsw_sp->span;
8901016 size_t i;
8911017
892
- for (i = 0; i < ARRAY_SIZE(mlxsw_sp_span_entry_types); ++i)
893
- if (mlxsw_sp_span_entry_types[i]->can_handle(to_dev))
894
- return mlxsw_sp_span_entry_types[i];
1018
+ for (i = 0; i < span->span_entry_ops_arr_size; ++i)
1019
+ if (span->span_entry_ops_arr[i]->can_handle(to_dev))
1020
+ return span->span_entry_ops_arr[i];
8951021
8961022 return NULL;
8971023 }
8981024
899
-int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
900
- const struct net_device *to_dev,
901
- enum mlxsw_sp_span_type type, bool bind,
902
- int *p_span_id)
1025
+static void mlxsw_sp_span_respin_work(struct work_struct *work)
9031026 {
904
- struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp;
905
- const struct mlxsw_sp_span_entry_ops *ops;
906
- struct mlxsw_sp_span_parms sparms = {NULL};
907
- struct mlxsw_sp_span_entry *span_entry;
908
- int err;
1027
+ struct mlxsw_sp_span *span;
1028
+ struct mlxsw_sp *mlxsw_sp;
1029
+ int i, err;
9091030
910
- ops = mlxsw_sp_span_entry_ops(mlxsw_sp, to_dev);
911
- if (!ops) {
912
- netdev_err(to_dev, "Cannot mirror to %s", to_dev->name);
913
- return -EOPNOTSUPP;
914
- }
1031
+ span = container_of(work, struct mlxsw_sp_span, work);
1032
+ mlxsw_sp = span->mlxsw_sp;
9151033
916
- err = ops->parms(to_dev, &sparms);
917
- if (err)
918
- return err;
919
-
920
- span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev, ops, sparms);
921
- if (!span_entry)
922
- return -ENOBUFS;
923
-
924
- netdev_dbg(from->dev, "Adding inspected port to SPAN entry %d\n",
925
- span_entry->id);
926
-
927
- err = mlxsw_sp_span_inspected_port_add(from, span_entry, type, bind);
928
- if (err)
929
- goto err_port_bind;
930
-
931
- *p_span_id = span_entry->id;
932
- return 0;
933
-
934
-err_port_bind:
935
- mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
936
- return err;
937
-}
938
-
939
-void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, int span_id,
940
- enum mlxsw_sp_span_type type, bool bind)
941
-{
942
- struct mlxsw_sp_span_entry *span_entry;
943
-
944
- span_entry = mlxsw_sp_span_entry_find_by_id(from->mlxsw_sp, span_id);
945
- if (!span_entry) {
946
- netdev_err(from->dev, "no span entry found\n");
947
- return;
948
- }
949
-
950
- netdev_dbg(from->dev, "removing inspected port from SPAN entry %d\n",
951
- span_entry->id);
952
- mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind);
953
-}
954
-
955
-void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp)
956
-{
957
- int i;
958
- int err;
959
-
960
- ASSERT_RTNL();
961
- for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
962
- struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
1034
+ rtnl_lock();
1035
+ for (i = 0; i < mlxsw_sp->span->entries_count; i++) {
1036
+ struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span->entries[i];
9631037 struct mlxsw_sp_span_parms sparms = {NULL};
9641038
965
- if (!curr->ref_count)
1039
+ if (!refcount_read(&curr->ref_count))
9661040 continue;
9671041
968
- err = curr->ops->parms(curr->to_dev, &sparms);
1042
+ if (curr->ops->is_static)
1043
+ continue;
1044
+
1045
+ err = curr->ops->parms_set(mlxsw_sp, curr->to_dev, &sparms);
9691046 if (err)
9701047 continue;
9711048
....@@ -974,4 +1051,662 @@
9741051 mlxsw_sp_span_entry_configure(mlxsw_sp, curr, sparms);
9751052 }
9761053 }
1054
+ rtnl_unlock();
9771055 }
1056
+
1057
+void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp)
1058
+{
1059
+ if (atomic_read(&mlxsw_sp->span->active_entries_count) == 0)
1060
+ return;
1061
+ mlxsw_core_schedule_work(&mlxsw_sp->span->work);
1062
+}
1063
+
1064
+int mlxsw_sp_span_agent_get(struct mlxsw_sp *mlxsw_sp, int *p_span_id,
1065
+ const struct mlxsw_sp_span_agent_parms *parms)
1066
+{
1067
+ const struct net_device *to_dev = parms->to_dev;
1068
+ const struct mlxsw_sp_span_entry_ops *ops;
1069
+ struct mlxsw_sp_span_entry *span_entry;
1070
+ struct mlxsw_sp_span_parms sparms;
1071
+ int err;
1072
+
1073
+ ASSERT_RTNL();
1074
+
1075
+ ops = mlxsw_sp_span_entry_ops(mlxsw_sp, to_dev);
1076
+ if (!ops) {
1077
+ dev_err(mlxsw_sp->bus_info->dev, "Cannot mirror to requested destination\n");
1078
+ return -EOPNOTSUPP;
1079
+ }
1080
+
1081
+ memset(&sparms, 0, sizeof(sparms));
1082
+ err = ops->parms_set(mlxsw_sp, to_dev, &sparms);
1083
+ if (err)
1084
+ return err;
1085
+
1086
+ sparms.policer_id = parms->policer_id;
1087
+ sparms.policer_enable = parms->policer_enable;
1088
+ span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev, ops, sparms);
1089
+ if (!span_entry)
1090
+ return -ENOBUFS;
1091
+
1092
+ *p_span_id = span_entry->id;
1093
+
1094
+ return 0;
1095
+}
1096
+
1097
+void mlxsw_sp_span_agent_put(struct mlxsw_sp *mlxsw_sp, int span_id)
1098
+{
1099
+ struct mlxsw_sp_span_entry *span_entry;
1100
+
1101
+ ASSERT_RTNL();
1102
+
1103
+ span_entry = mlxsw_sp_span_entry_find_by_id(mlxsw_sp, span_id);
1104
+ if (WARN_ON_ONCE(!span_entry))
1105
+ return;
1106
+
1107
+ mlxsw_sp_span_entry_put(mlxsw_sp, span_entry);
1108
+}
1109
+
1110
+static struct mlxsw_sp_span_analyzed_port *
1111
+mlxsw_sp_span_analyzed_port_create(struct mlxsw_sp_span *span,
1112
+ struct mlxsw_sp_port *mlxsw_sp_port,
1113
+ bool ingress)
1114
+{
1115
+ struct mlxsw_sp_span_analyzed_port *analyzed_port;
1116
+ int err;
1117
+
1118
+ analyzed_port = kzalloc(sizeof(*analyzed_port), GFP_KERNEL);
1119
+ if (!analyzed_port)
1120
+ return ERR_PTR(-ENOMEM);
1121
+
1122
+ refcount_set(&analyzed_port->ref_count, 1);
1123
+ analyzed_port->local_port = mlxsw_sp_port->local_port;
1124
+ analyzed_port->ingress = ingress;
1125
+ list_add_tail(&analyzed_port->list, &span->analyzed_ports_list);
1126
+
1127
+ /* An egress mirror buffer should be allocated on the egress port which
1128
+ * does the mirroring.
1129
+ */
1130
+ if (!ingress) {
1131
+ err = mlxsw_sp_span_port_buffer_enable(mlxsw_sp_port);
1132
+ if (err)
1133
+ goto err_buffer_update;
1134
+ }
1135
+
1136
+ return analyzed_port;
1137
+
1138
+err_buffer_update:
1139
+ list_del(&analyzed_port->list);
1140
+ kfree(analyzed_port);
1141
+ return ERR_PTR(err);
1142
+}
1143
+
1144
+static void
1145
+mlxsw_sp_span_analyzed_port_destroy(struct mlxsw_sp_port *mlxsw_sp_port,
1146
+ struct mlxsw_sp_span_analyzed_port *
1147
+ analyzed_port)
1148
+{
1149
+ /* Remove egress mirror buffer now that port is no longer analyzed
1150
+ * at egress.
1151
+ */
1152
+ if (!analyzed_port->ingress)
1153
+ mlxsw_sp_span_port_buffer_disable(mlxsw_sp_port);
1154
+
1155
+ list_del(&analyzed_port->list);
1156
+ kfree(analyzed_port);
1157
+}
1158
+
1159
+int mlxsw_sp_span_analyzed_port_get(struct mlxsw_sp_port *mlxsw_sp_port,
1160
+ bool ingress)
1161
+{
1162
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1163
+ struct mlxsw_sp_span_analyzed_port *analyzed_port;
1164
+ u8 local_port = mlxsw_sp_port->local_port;
1165
+ int err = 0;
1166
+
1167
+ mutex_lock(&mlxsw_sp->span->analyzed_ports_lock);
1168
+
1169
+ analyzed_port = mlxsw_sp_span_analyzed_port_find(mlxsw_sp->span,
1170
+ local_port, ingress);
1171
+ if (analyzed_port) {
1172
+ refcount_inc(&analyzed_port->ref_count);
1173
+ goto out_unlock;
1174
+ }
1175
+
1176
+ analyzed_port = mlxsw_sp_span_analyzed_port_create(mlxsw_sp->span,
1177
+ mlxsw_sp_port,
1178
+ ingress);
1179
+ if (IS_ERR(analyzed_port))
1180
+ err = PTR_ERR(analyzed_port);
1181
+
1182
+out_unlock:
1183
+ mutex_unlock(&mlxsw_sp->span->analyzed_ports_lock);
1184
+ return err;
1185
+}
1186
+
1187
+void mlxsw_sp_span_analyzed_port_put(struct mlxsw_sp_port *mlxsw_sp_port,
1188
+ bool ingress)
1189
+{
1190
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1191
+ struct mlxsw_sp_span_analyzed_port *analyzed_port;
1192
+ u8 local_port = mlxsw_sp_port->local_port;
1193
+
1194
+ mutex_lock(&mlxsw_sp->span->analyzed_ports_lock);
1195
+
1196
+ analyzed_port = mlxsw_sp_span_analyzed_port_find(mlxsw_sp->span,
1197
+ local_port, ingress);
1198
+ if (WARN_ON_ONCE(!analyzed_port))
1199
+ goto out_unlock;
1200
+
1201
+ if (!refcount_dec_and_test(&analyzed_port->ref_count))
1202
+ goto out_unlock;
1203
+
1204
+ mlxsw_sp_span_analyzed_port_destroy(mlxsw_sp_port, analyzed_port);
1205
+
1206
+out_unlock:
1207
+ mutex_unlock(&mlxsw_sp->span->analyzed_ports_lock);
1208
+}
1209
+
1210
+static int
1211
+__mlxsw_sp_span_trigger_port_bind(struct mlxsw_sp_span *span,
1212
+ struct mlxsw_sp_span_trigger_entry *
1213
+ trigger_entry, bool enable)
1214
+{
1215
+ char mpar_pl[MLXSW_REG_MPAR_LEN];
1216
+ enum mlxsw_reg_mpar_i_e i_e;
1217
+
1218
+ switch (trigger_entry->trigger) {
1219
+ case MLXSW_SP_SPAN_TRIGGER_INGRESS:
1220
+ i_e = MLXSW_REG_MPAR_TYPE_INGRESS;
1221
+ break;
1222
+ case MLXSW_SP_SPAN_TRIGGER_EGRESS:
1223
+ i_e = MLXSW_REG_MPAR_TYPE_EGRESS;
1224
+ break;
1225
+ default:
1226
+ WARN_ON_ONCE(1);
1227
+ return -EINVAL;
1228
+ }
1229
+
1230
+ mlxsw_reg_mpar_pack(mpar_pl, trigger_entry->local_port, i_e, enable,
1231
+ trigger_entry->parms.span_id);
1232
+ return mlxsw_reg_write(span->mlxsw_sp->core, MLXSW_REG(mpar), mpar_pl);
1233
+}
1234
+
1235
+static int
1236
+mlxsw_sp_span_trigger_port_bind(struct mlxsw_sp_span_trigger_entry *
1237
+ trigger_entry)
1238
+{
1239
+ return __mlxsw_sp_span_trigger_port_bind(trigger_entry->span,
1240
+ trigger_entry, true);
1241
+}
1242
+
1243
+static void
1244
+mlxsw_sp_span_trigger_port_unbind(struct mlxsw_sp_span_trigger_entry *
1245
+ trigger_entry)
1246
+{
1247
+ __mlxsw_sp_span_trigger_port_bind(trigger_entry->span, trigger_entry,
1248
+ false);
1249
+}
1250
+
1251
+static bool
1252
+mlxsw_sp_span_trigger_port_matches(struct mlxsw_sp_span_trigger_entry *
1253
+ trigger_entry,
1254
+ enum mlxsw_sp_span_trigger trigger,
1255
+ struct mlxsw_sp_port *mlxsw_sp_port)
1256
+{
1257
+ return trigger_entry->trigger == trigger &&
1258
+ trigger_entry->local_port == mlxsw_sp_port->local_port;
1259
+}
1260
+
1261
+static int
1262
+mlxsw_sp_span_trigger_port_enable(struct mlxsw_sp_span_trigger_entry *
1263
+ trigger_entry,
1264
+ struct mlxsw_sp_port *mlxsw_sp_port, u8 tc)
1265
+{
1266
+ /* Port trigger are enabled during binding. */
1267
+ return 0;
1268
+}
1269
+
1270
+static void
1271
+mlxsw_sp_span_trigger_port_disable(struct mlxsw_sp_span_trigger_entry *
1272
+ trigger_entry,
1273
+ struct mlxsw_sp_port *mlxsw_sp_port, u8 tc)
1274
+{
1275
+}
1276
+
1277
+static const struct mlxsw_sp_span_trigger_ops
1278
+mlxsw_sp_span_trigger_port_ops = {
1279
+ .bind = mlxsw_sp_span_trigger_port_bind,
1280
+ .unbind = mlxsw_sp_span_trigger_port_unbind,
1281
+ .matches = mlxsw_sp_span_trigger_port_matches,
1282
+ .enable = mlxsw_sp_span_trigger_port_enable,
1283
+ .disable = mlxsw_sp_span_trigger_port_disable,
1284
+};
1285
+
1286
+static int
1287
+mlxsw_sp1_span_trigger_global_bind(struct mlxsw_sp_span_trigger_entry *
1288
+ trigger_entry)
1289
+{
1290
+ return -EOPNOTSUPP;
1291
+}
1292
+
1293
+static void
1294
+mlxsw_sp1_span_trigger_global_unbind(struct mlxsw_sp_span_trigger_entry *
1295
+ trigger_entry)
1296
+{
1297
+}
1298
+
1299
+static bool
1300
+mlxsw_sp1_span_trigger_global_matches(struct mlxsw_sp_span_trigger_entry *
1301
+ trigger_entry,
1302
+ enum mlxsw_sp_span_trigger trigger,
1303
+ struct mlxsw_sp_port *mlxsw_sp_port)
1304
+{
1305
+ WARN_ON_ONCE(1);
1306
+ return false;
1307
+}
1308
+
1309
+static int
1310
+mlxsw_sp1_span_trigger_global_enable(struct mlxsw_sp_span_trigger_entry *
1311
+ trigger_entry,
1312
+ struct mlxsw_sp_port *mlxsw_sp_port,
1313
+ u8 tc)
1314
+{
1315
+ return -EOPNOTSUPP;
1316
+}
1317
+
1318
+static void
1319
+mlxsw_sp1_span_trigger_global_disable(struct mlxsw_sp_span_trigger_entry *
1320
+ trigger_entry,
1321
+ struct mlxsw_sp_port *mlxsw_sp_port,
1322
+ u8 tc)
1323
+{
1324
+}
1325
+
1326
+static const struct mlxsw_sp_span_trigger_ops
1327
+mlxsw_sp1_span_trigger_global_ops = {
1328
+ .bind = mlxsw_sp1_span_trigger_global_bind,
1329
+ .unbind = mlxsw_sp1_span_trigger_global_unbind,
1330
+ .matches = mlxsw_sp1_span_trigger_global_matches,
1331
+ .enable = mlxsw_sp1_span_trigger_global_enable,
1332
+ .disable = mlxsw_sp1_span_trigger_global_disable,
1333
+};
1334
+
1335
+static const struct mlxsw_sp_span_trigger_ops *
1336
+mlxsw_sp1_span_trigger_ops_arr[] = {
1337
+ [MLXSW_SP_SPAN_TRIGGER_TYPE_PORT] = &mlxsw_sp_span_trigger_port_ops,
1338
+ [MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL] =
1339
+ &mlxsw_sp1_span_trigger_global_ops,
1340
+};
1341
+
1342
+static int
1343
+mlxsw_sp2_span_trigger_global_bind(struct mlxsw_sp_span_trigger_entry *
1344
+ trigger_entry)
1345
+{
1346
+ struct mlxsw_sp *mlxsw_sp = trigger_entry->span->mlxsw_sp;
1347
+ enum mlxsw_reg_mpagr_trigger trigger;
1348
+ char mpagr_pl[MLXSW_REG_MPAGR_LEN];
1349
+
1350
+ switch (trigger_entry->trigger) {
1351
+ case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP:
1352
+ trigger = MLXSW_REG_MPAGR_TRIGGER_INGRESS_SHARED_BUFFER;
1353
+ break;
1354
+ case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP:
1355
+ trigger = MLXSW_REG_MPAGR_TRIGGER_INGRESS_WRED;
1356
+ break;
1357
+ case MLXSW_SP_SPAN_TRIGGER_ECN:
1358
+ trigger = MLXSW_REG_MPAGR_TRIGGER_EGRESS_ECN;
1359
+ break;
1360
+ default:
1361
+ WARN_ON_ONCE(1);
1362
+ return -EINVAL;
1363
+ }
1364
+
1365
+ mlxsw_reg_mpagr_pack(mpagr_pl, trigger, trigger_entry->parms.span_id,
1366
+ 1);
1367
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpagr), mpagr_pl);
1368
+}
1369
+
1370
+static void
1371
+mlxsw_sp2_span_trigger_global_unbind(struct mlxsw_sp_span_trigger_entry *
1372
+ trigger_entry)
1373
+{
1374
+ /* There is no unbinding for global triggers. The trigger should be
1375
+ * disabled on all ports by now.
1376
+ */
1377
+}
1378
+
1379
+static bool
1380
+mlxsw_sp2_span_trigger_global_matches(struct mlxsw_sp_span_trigger_entry *
1381
+ trigger_entry,
1382
+ enum mlxsw_sp_span_trigger trigger,
1383
+ struct mlxsw_sp_port *mlxsw_sp_port)
1384
+{
1385
+ return trigger_entry->trigger == trigger;
1386
+}
1387
+
1388
+static int
1389
+__mlxsw_sp2_span_trigger_global_enable(struct mlxsw_sp_span_trigger_entry *
1390
+ trigger_entry,
1391
+ struct mlxsw_sp_port *mlxsw_sp_port,
1392
+ u8 tc, bool enable)
1393
+{
1394
+ struct mlxsw_sp *mlxsw_sp = trigger_entry->span->mlxsw_sp;
1395
+ char momte_pl[MLXSW_REG_MOMTE_LEN];
1396
+ enum mlxsw_reg_momte_type type;
1397
+ int err;
1398
+
1399
+ switch (trigger_entry->trigger) {
1400
+ case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP:
1401
+ type = MLXSW_REG_MOMTE_TYPE_SHARED_BUFFER_TCLASS;
1402
+ break;
1403
+ case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP:
1404
+ type = MLXSW_REG_MOMTE_TYPE_WRED;
1405
+ break;
1406
+ case MLXSW_SP_SPAN_TRIGGER_ECN:
1407
+ type = MLXSW_REG_MOMTE_TYPE_ECN;
1408
+ break;
1409
+ default:
1410
+ WARN_ON_ONCE(1);
1411
+ return -EINVAL;
1412
+ }
1413
+
1414
+ /* Query existing configuration in order to only change the state of
1415
+ * the specified traffic class.
1416
+ */
1417
+ mlxsw_reg_momte_pack(momte_pl, mlxsw_sp_port->local_port, type);
1418
+ err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(momte), momte_pl);
1419
+ if (err)
1420
+ return err;
1421
+
1422
+ mlxsw_reg_momte_tclass_en_set(momte_pl, tc, enable);
1423
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(momte), momte_pl);
1424
+}
1425
+
1426
+static int
1427
+mlxsw_sp2_span_trigger_global_enable(struct mlxsw_sp_span_trigger_entry *
1428
+ trigger_entry,
1429
+ struct mlxsw_sp_port *mlxsw_sp_port,
1430
+ u8 tc)
1431
+{
1432
+ return __mlxsw_sp2_span_trigger_global_enable(trigger_entry,
1433
+ mlxsw_sp_port, tc, true);
1434
+}
1435
+
1436
+static void
1437
+mlxsw_sp2_span_trigger_global_disable(struct mlxsw_sp_span_trigger_entry *
1438
+ trigger_entry,
1439
+ struct mlxsw_sp_port *mlxsw_sp_port,
1440
+ u8 tc)
1441
+{
1442
+ __mlxsw_sp2_span_trigger_global_enable(trigger_entry, mlxsw_sp_port, tc,
1443
+ false);
1444
+}
1445
+
1446
+static const struct mlxsw_sp_span_trigger_ops
1447
+mlxsw_sp2_span_trigger_global_ops = {
1448
+ .bind = mlxsw_sp2_span_trigger_global_bind,
1449
+ .unbind = mlxsw_sp2_span_trigger_global_unbind,
1450
+ .matches = mlxsw_sp2_span_trigger_global_matches,
1451
+ .enable = mlxsw_sp2_span_trigger_global_enable,
1452
+ .disable = mlxsw_sp2_span_trigger_global_disable,
1453
+};
1454
+
1455
+static const struct mlxsw_sp_span_trigger_ops *
1456
+mlxsw_sp2_span_trigger_ops_arr[] = {
1457
+ [MLXSW_SP_SPAN_TRIGGER_TYPE_PORT] = &mlxsw_sp_span_trigger_port_ops,
1458
+ [MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL] =
1459
+ &mlxsw_sp2_span_trigger_global_ops,
1460
+};
1461
+
1462
+static void
1463
+mlxsw_sp_span_trigger_ops_set(struct mlxsw_sp_span_trigger_entry *trigger_entry)
1464
+{
1465
+ struct mlxsw_sp_span *span = trigger_entry->span;
1466
+ enum mlxsw_sp_span_trigger_type type;
1467
+
1468
+ switch (trigger_entry->trigger) {
1469
+ case MLXSW_SP_SPAN_TRIGGER_INGRESS:
1470
+ case MLXSW_SP_SPAN_TRIGGER_EGRESS:
1471
+ type = MLXSW_SP_SPAN_TRIGGER_TYPE_PORT;
1472
+ break;
1473
+ case MLXSW_SP_SPAN_TRIGGER_TAIL_DROP:
1474
+ case MLXSW_SP_SPAN_TRIGGER_EARLY_DROP:
1475
+ case MLXSW_SP_SPAN_TRIGGER_ECN:
1476
+ type = MLXSW_SP_SPAN_TRIGGER_TYPE_GLOBAL;
1477
+ break;
1478
+ default:
1479
+ WARN_ON_ONCE(1);
1480
+ return;
1481
+ }
1482
+
1483
+ trigger_entry->ops = span->span_trigger_ops_arr[type];
1484
+}
1485
+
1486
+static struct mlxsw_sp_span_trigger_entry *
1487
+mlxsw_sp_span_trigger_entry_create(struct mlxsw_sp_span *span,
1488
+ enum mlxsw_sp_span_trigger trigger,
1489
+ struct mlxsw_sp_port *mlxsw_sp_port,
1490
+ const struct mlxsw_sp_span_trigger_parms
1491
+ *parms)
1492
+{
1493
+ struct mlxsw_sp_span_trigger_entry *trigger_entry;
1494
+ int err;
1495
+
1496
+ trigger_entry = kzalloc(sizeof(*trigger_entry), GFP_KERNEL);
1497
+ if (!trigger_entry)
1498
+ return ERR_PTR(-ENOMEM);
1499
+
1500
+ refcount_set(&trigger_entry->ref_count, 1);
1501
+ trigger_entry->local_port = mlxsw_sp_port ? mlxsw_sp_port->local_port :
1502
+ 0;
1503
+ trigger_entry->trigger = trigger;
1504
+ memcpy(&trigger_entry->parms, parms, sizeof(trigger_entry->parms));
1505
+ trigger_entry->span = span;
1506
+ mlxsw_sp_span_trigger_ops_set(trigger_entry);
1507
+ list_add_tail(&trigger_entry->list, &span->trigger_entries_list);
1508
+
1509
+ err = trigger_entry->ops->bind(trigger_entry);
1510
+ if (err)
1511
+ goto err_trigger_entry_bind;
1512
+
1513
+ return trigger_entry;
1514
+
1515
+err_trigger_entry_bind:
1516
+ list_del(&trigger_entry->list);
1517
+ kfree(trigger_entry);
1518
+ return ERR_PTR(err);
1519
+}
1520
+
1521
+static void
1522
+mlxsw_sp_span_trigger_entry_destroy(struct mlxsw_sp_span *span,
1523
+ struct mlxsw_sp_span_trigger_entry *
1524
+ trigger_entry)
1525
+{
1526
+ trigger_entry->ops->unbind(trigger_entry);
1527
+ list_del(&trigger_entry->list);
1528
+ kfree(trigger_entry);
1529
+}
1530
+
1531
+static struct mlxsw_sp_span_trigger_entry *
1532
+mlxsw_sp_span_trigger_entry_find(struct mlxsw_sp_span *span,
1533
+ enum mlxsw_sp_span_trigger trigger,
1534
+ struct mlxsw_sp_port *mlxsw_sp_port)
1535
+{
1536
+ struct mlxsw_sp_span_trigger_entry *trigger_entry;
1537
+
1538
+ list_for_each_entry(trigger_entry, &span->trigger_entries_list, list) {
1539
+ if (trigger_entry->ops->matches(trigger_entry, trigger,
1540
+ mlxsw_sp_port))
1541
+ return trigger_entry;
1542
+ }
1543
+
1544
+ return NULL;
1545
+}
1546
+
1547
+int mlxsw_sp_span_agent_bind(struct mlxsw_sp *mlxsw_sp,
1548
+ enum mlxsw_sp_span_trigger trigger,
1549
+ struct mlxsw_sp_port *mlxsw_sp_port,
1550
+ const struct mlxsw_sp_span_trigger_parms *parms)
1551
+{
1552
+ struct mlxsw_sp_span_trigger_entry *trigger_entry;
1553
+ int err = 0;
1554
+
1555
+ ASSERT_RTNL();
1556
+
1557
+ if (!mlxsw_sp_span_entry_find_by_id(mlxsw_sp, parms->span_id))
1558
+ return -EINVAL;
1559
+
1560
+ trigger_entry = mlxsw_sp_span_trigger_entry_find(mlxsw_sp->span,
1561
+ trigger,
1562
+ mlxsw_sp_port);
1563
+ if (trigger_entry) {
1564
+ if (trigger_entry->parms.span_id != parms->span_id)
1565
+ return -EINVAL;
1566
+ refcount_inc(&trigger_entry->ref_count);
1567
+ goto out;
1568
+ }
1569
+
1570
+ trigger_entry = mlxsw_sp_span_trigger_entry_create(mlxsw_sp->span,
1571
+ trigger,
1572
+ mlxsw_sp_port,
1573
+ parms);
1574
+ if (IS_ERR(trigger_entry))
1575
+ err = PTR_ERR(trigger_entry);
1576
+
1577
+out:
1578
+ return err;
1579
+}
1580
+
1581
+void mlxsw_sp_span_agent_unbind(struct mlxsw_sp *mlxsw_sp,
1582
+ enum mlxsw_sp_span_trigger trigger,
1583
+ struct mlxsw_sp_port *mlxsw_sp_port,
1584
+ const struct mlxsw_sp_span_trigger_parms *parms)
1585
+{
1586
+ struct mlxsw_sp_span_trigger_entry *trigger_entry;
1587
+
1588
+ ASSERT_RTNL();
1589
+
1590
+ if (WARN_ON_ONCE(!mlxsw_sp_span_entry_find_by_id(mlxsw_sp,
1591
+ parms->span_id)))
1592
+ return;
1593
+
1594
+ trigger_entry = mlxsw_sp_span_trigger_entry_find(mlxsw_sp->span,
1595
+ trigger,
1596
+ mlxsw_sp_port);
1597
+ if (WARN_ON_ONCE(!trigger_entry))
1598
+ return;
1599
+
1600
+ if (!refcount_dec_and_test(&trigger_entry->ref_count))
1601
+ return;
1602
+
1603
+ mlxsw_sp_span_trigger_entry_destroy(mlxsw_sp->span, trigger_entry);
1604
+}
1605
+
1606
+int mlxsw_sp_span_trigger_enable(struct mlxsw_sp_port *mlxsw_sp_port,
1607
+ enum mlxsw_sp_span_trigger trigger, u8 tc)
1608
+{
1609
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1610
+ struct mlxsw_sp_span_trigger_entry *trigger_entry;
1611
+
1612
+ ASSERT_RTNL();
1613
+
1614
+ trigger_entry = mlxsw_sp_span_trigger_entry_find(mlxsw_sp->span,
1615
+ trigger,
1616
+ mlxsw_sp_port);
1617
+ if (WARN_ON_ONCE(!trigger_entry))
1618
+ return -EINVAL;
1619
+
1620
+ return trigger_entry->ops->enable(trigger_entry, mlxsw_sp_port, tc);
1621
+}
1622
+
1623
+void mlxsw_sp_span_trigger_disable(struct mlxsw_sp_port *mlxsw_sp_port,
1624
+ enum mlxsw_sp_span_trigger trigger, u8 tc)
1625
+{
1626
+ struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1627
+ struct mlxsw_sp_span_trigger_entry *trigger_entry;
1628
+
1629
+ ASSERT_RTNL();
1630
+
1631
+ trigger_entry = mlxsw_sp_span_trigger_entry_find(mlxsw_sp->span,
1632
+ trigger,
1633
+ mlxsw_sp_port);
1634
+ if (WARN_ON_ONCE(!trigger_entry))
1635
+ return;
1636
+
1637
+ return trigger_entry->ops->disable(trigger_entry, mlxsw_sp_port, tc);
1638
+}
1639
+
1640
+static int mlxsw_sp1_span_init(struct mlxsw_sp *mlxsw_sp)
1641
+{
1642
+ size_t arr_size = ARRAY_SIZE(mlxsw_sp1_span_entry_ops_arr);
1643
+
1644
+ /* Must be first to avoid NULL pointer dereference by subsequent
1645
+ * can_handle() callbacks.
1646
+ */
1647
+ if (WARN_ON(mlxsw_sp1_span_entry_ops_arr[0] !=
1648
+ &mlxsw_sp1_span_entry_ops_cpu))
1649
+ return -EINVAL;
1650
+
1651
+ mlxsw_sp->span->span_trigger_ops_arr = mlxsw_sp1_span_trigger_ops_arr;
1652
+ mlxsw_sp->span->span_entry_ops_arr = mlxsw_sp1_span_entry_ops_arr;
1653
+ mlxsw_sp->span->span_entry_ops_arr_size = arr_size;
1654
+
1655
+ return 0;
1656
+}
1657
+
1658
+static int mlxsw_sp1_span_policer_id_base_set(struct mlxsw_sp *mlxsw_sp,
1659
+ u16 policer_id_base)
1660
+{
1661
+ return -EOPNOTSUPP;
1662
+}
1663
+
1664
+const struct mlxsw_sp_span_ops mlxsw_sp1_span_ops = {
1665
+ .init = mlxsw_sp1_span_init,
1666
+ .policer_id_base_set = mlxsw_sp1_span_policer_id_base_set,
1667
+};
1668
+
1669
+static int mlxsw_sp2_span_init(struct mlxsw_sp *mlxsw_sp)
1670
+{
1671
+ size_t arr_size = ARRAY_SIZE(mlxsw_sp2_span_entry_ops_arr);
1672
+
1673
+ /* Must be first to avoid NULL pointer dereference by subsequent
1674
+ * can_handle() callbacks.
1675
+ */
1676
+ if (WARN_ON(mlxsw_sp2_span_entry_ops_arr[0] !=
1677
+ &mlxsw_sp2_span_entry_ops_cpu))
1678
+ return -EINVAL;
1679
+
1680
+ mlxsw_sp->span->span_trigger_ops_arr = mlxsw_sp2_span_trigger_ops_arr;
1681
+ mlxsw_sp->span->span_entry_ops_arr = mlxsw_sp2_span_entry_ops_arr;
1682
+ mlxsw_sp->span->span_entry_ops_arr_size = arr_size;
1683
+
1684
+ return 0;
1685
+}
1686
+
1687
+#define MLXSW_SP2_SPAN_EG_MIRROR_BUFFER_FACTOR 38
1688
+#define MLXSW_SP3_SPAN_EG_MIRROR_BUFFER_FACTOR 50
1689
+
1690
+static int mlxsw_sp2_span_policer_id_base_set(struct mlxsw_sp *mlxsw_sp,
1691
+ u16 policer_id_base)
1692
+{
1693
+ char mogcr_pl[MLXSW_REG_MOGCR_LEN];
1694
+ int err;
1695
+
1696
+ err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);
1697
+ if (err)
1698
+ return err;
1699
+
1700
+ mlxsw_reg_mogcr_mirroring_pid_base_set(mogcr_pl, policer_id_base);
1701
+ return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);
1702
+}
1703
+
1704
+const struct mlxsw_sp_span_ops mlxsw_sp2_span_ops = {
1705
+ .init = mlxsw_sp2_span_init,
1706
+ .policer_id_base_set = mlxsw_sp2_span_policer_id_base_set,
1707
+};
1708
+
1709
+const struct mlxsw_sp_span_ops mlxsw_sp3_span_ops = {
1710
+ .init = mlxsw_sp2_span_init,
1711
+ .policer_id_base_set = mlxsw_sp2_span_policer_id_base_set,
1712
+};