13
13
#include <net/dsa.h>
14
14
#include <linux/bitmap.h>
15
15
#include <net/flow_offload.h>
16
+ #include <net/switchdev.h>
17
+ #include <uapi/linux/if_bridge.h>
16
18
17
19
#include "bcm_sf2.h"
18
20
#include "bcm_sf2_regs.h"
@@ -261,16 +263,27 @@ static int bcm_sf2_cfp_act_pol_set(struct bcm_sf2_priv *priv,
261
263
static void bcm_sf2_cfp_slice_ipv4 (struct bcm_sf2_priv * priv ,
262
264
struct flow_dissector_key_ipv4_addrs * addrs ,
263
265
struct flow_dissector_key_ports * ports ,
264
- unsigned int slice_num ,
266
+ const __be16 vlan_tci ,
267
+ unsigned int slice_num , u8 num_udf ,
265
268
bool mask )
266
269
{
267
270
u32 reg , offset ;
268
271
272
+ /* UDF_Valid[7:0] [31:24]
273
+ * S-Tag [23:8]
274
+ * C-Tag [7:0]
275
+ */
276
+ reg = udf_lower_bits (num_udf ) << 24 | be16_to_cpu (vlan_tci ) >> 8 ;
277
+ if (mask )
278
+ core_writel (priv , reg , CORE_CFP_MASK_PORT (5 ));
279
+ else
280
+ core_writel (priv , reg , CORE_CFP_DATA_PORT (5 ));
281
+
269
282
/* C-Tag [31:24]
270
283
* UDF_n_A8 [23:8]
271
284
* UDF_n_A7 [7:0]
272
285
*/
273
- reg = 0 ;
286
+ reg = ( u32 )( be16_to_cpu ( vlan_tci ) & 0xff ) << 24 ;
274
287
if (mask )
275
288
offset = CORE_CFP_MASK_PORT (4 );
276
289
else
@@ -336,6 +349,7 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
336
349
struct ethtool_rx_flow_spec * fs )
337
350
{
338
351
struct ethtool_rx_flow_spec_input input = {};
352
+ __be16 vlan_tci = 0 , vlan_m_tci = 0xffff ;
339
353
const struct cfp_udf_layout * layout ;
340
354
unsigned int slice_num , rule_index ;
341
355
struct ethtool_rx_flow_rule * flow ;
@@ -360,6 +374,12 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
360
374
361
375
ip_frag = !!(be32_to_cpu (fs -> h_ext .data [0 ]) & 1 );
362
376
377
+ /* Extract VLAN TCI */
378
+ if (fs -> flow_type & FLOW_EXT ) {
379
+ vlan_tci = fs -> h_ext .vlan_tci ;
380
+ vlan_m_tci = fs -> m_ext .vlan_tci ;
381
+ }
382
+
363
383
/* Locate the first rule available */
364
384
if (fs -> location == RX_CLS_LOC_ANY )
365
385
rule_index = find_first_zero_bit (priv -> cfp .used ,
@@ -421,18 +441,11 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
421
441
core_writel (priv , layout -> udfs [slice_num ].mask_value |
422
442
udf_upper_bits (num_udf ), CORE_CFP_MASK_PORT (6 ));
423
443
424
- /* UDF_Valid[7:0] [31:24]
425
- * S-Tag [23:8]
426
- * C-Tag [7:0]
427
- */
428
- core_writel (priv , udf_lower_bits (num_udf ) << 24 , CORE_CFP_DATA_PORT (5 ));
429
-
430
- /* Mask all but valid UDFs */
431
- core_writel (priv , udf_lower_bits (num_udf ) << 24 , CORE_CFP_MASK_PORT (5 ));
432
-
433
444
/* Program the match and the mask */
434
- bcm_sf2_cfp_slice_ipv4 (priv , ipv4 .key , ports .key , slice_num , false);
435
- bcm_sf2_cfp_slice_ipv4 (priv , ipv4 .mask , ports .mask , SLICE_NUM_MASK , true);
445
+ bcm_sf2_cfp_slice_ipv4 (priv , ipv4 .key , ports .key , vlan_tci ,
446
+ slice_num , num_udf , false);
447
+ bcm_sf2_cfp_slice_ipv4 (priv , ipv4 .mask , ports .mask , vlan_m_tci ,
448
+ SLICE_NUM_MASK , num_udf , true);
436
449
437
450
/* Insert into TCAM now */
438
451
bcm_sf2_cfp_rule_addr_set (priv , rule_index );
@@ -468,17 +481,29 @@ static int bcm_sf2_cfp_ipv4_rule_set(struct bcm_sf2_priv *priv, int port,
468
481
469
482
static void bcm_sf2_cfp_slice_ipv6 (struct bcm_sf2_priv * priv ,
470
483
const __be32 * ip6_addr , const __be16 port ,
471
- unsigned int slice_num ,
484
+ const __be16 vlan_tci ,
485
+ unsigned int slice_num , u32 udf_bits ,
472
486
bool mask )
473
487
{
474
488
u32 reg , tmp , val , offset ;
475
489
490
+ /* UDF_Valid[7:0] [31:24]
491
+ * S-Tag [23:8]
492
+ * C-Tag [7:0]
493
+ */
494
+ reg = udf_bits << 24 | be16_to_cpu (vlan_tci ) >> 8 ;
495
+ if (mask )
496
+ core_writel (priv , reg , CORE_CFP_MASK_PORT (5 ));
497
+ else
498
+ core_writel (priv , reg , CORE_CFP_DATA_PORT (5 ));
499
+
476
500
/* C-Tag [31:24]
477
501
* UDF_n_B8 [23:8] (port)
478
502
* UDF_n_B7 (upper) [7:0] (addr[15:8])
479
503
*/
480
504
reg = be32_to_cpu (ip6_addr [3 ]);
481
505
val = (u32 )be16_to_cpu (port ) << 8 | ((reg >> 8 ) & 0xff );
506
+ val |= (u32 )(be16_to_cpu (vlan_tci ) & 0xff ) << 24 ;
482
507
if (mask )
483
508
offset = CORE_CFP_MASK_PORT (4 );
484
509
else
@@ -587,6 +612,11 @@ static int bcm_sf2_cfp_rule_cmp(struct bcm_sf2_priv *priv, int port,
587
612
588
613
ret = memcmp (& rule -> fs .h_u , & fs -> h_u , fs_size );
589
614
ret |= memcmp (& rule -> fs .m_u , & fs -> m_u , fs_size );
615
+ /* Compare VLAN TCI values as well */
616
+ if (rule -> fs .flow_type & FLOW_EXT ) {
617
+ ret |= rule -> fs .h_ext .vlan_tci != fs -> h_ext .vlan_tci ;
618
+ ret |= rule -> fs .m_ext .vlan_tci != fs -> m_ext .vlan_tci ;
619
+ }
590
620
if (ret == 0 )
591
621
break ;
592
622
}
@@ -600,6 +630,7 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
600
630
struct ethtool_rx_flow_spec * fs )
601
631
{
602
632
struct ethtool_rx_flow_spec_input input = {};
633
+ __be16 vlan_tci = 0 , vlan_m_tci = 0xffff ;
603
634
unsigned int slice_num , rule_index [2 ];
604
635
const struct cfp_udf_layout * layout ;
605
636
struct ethtool_rx_flow_rule * flow ;
@@ -623,6 +654,12 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
623
654
624
655
ip_frag = !!(be32_to_cpu (fs -> h_ext .data [0 ]) & 1 );
625
656
657
+ /* Extract VLAN TCI */
658
+ if (fs -> flow_type & FLOW_EXT ) {
659
+ vlan_tci = fs -> h_ext .vlan_tci ;
660
+ vlan_m_tci = fs -> m_ext .vlan_tci ;
661
+ }
662
+
626
663
layout = & udf_tcpip6_layout ;
627
664
slice_num = bcm_sf2_get_slice_number (layout , 0 );
628
665
if (slice_num == UDF_NUM_SLICES )
@@ -704,20 +741,13 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
704
741
reg = layout -> udfs [slice_num ].mask_value | udf_upper_bits (num_udf );
705
742
core_writel (priv , reg , CORE_CFP_MASK_PORT (6 ));
706
743
707
- /* UDF_Valid[7:0] [31:24]
708
- * S-Tag [23:8]
709
- * C-Tag [7:0]
710
- */
711
- core_writel (priv , udf_lower_bits (num_udf ) << 24 , CORE_CFP_DATA_PORT (5 ));
712
-
713
- /* Mask all but valid UDFs */
714
- core_writel (priv , udf_lower_bits (num_udf ) << 24 , CORE_CFP_MASK_PORT (5 ));
715
-
716
744
/* Slice the IPv6 source address and port */
717
745
bcm_sf2_cfp_slice_ipv6 (priv , ipv6 .key -> src .in6_u .u6_addr32 ,
718
- ports .key -> src , slice_num , false);
746
+ ports .key -> src , vlan_tci , slice_num ,
747
+ udf_lower_bits (num_udf ), false);
719
748
bcm_sf2_cfp_slice_ipv6 (priv , ipv6 .mask -> src .in6_u .u6_addr32 ,
720
- ports .mask -> src , SLICE_NUM_MASK , true);
749
+ ports .mask -> src , vlan_m_tci , SLICE_NUM_MASK ,
750
+ udf_lower_bits (num_udf ), true);
721
751
722
752
/* Insert into TCAM now because we need to insert a second rule */
723
753
bcm_sf2_cfp_rule_addr_set (priv , rule_index [0 ]);
@@ -768,16 +798,12 @@ static int bcm_sf2_cfp_ipv6_rule_set(struct bcm_sf2_priv *priv, int port,
768
798
udf_lower_bits (num_udf ) << 8 ;
769
799
core_writel (priv , reg , CORE_CFP_MASK_PORT (6 ));
770
800
771
- /* Don't care */
772
- core_writel (priv , 0 , CORE_CFP_DATA_PORT (5 ));
773
-
774
- /* Mask all */
775
- core_writel (priv , 0 , CORE_CFP_MASK_PORT (5 ));
776
-
777
801
bcm_sf2_cfp_slice_ipv6 (priv , ipv6 .key -> dst .in6_u .u6_addr32 ,
778
- ports .key -> dst , slice_num , false);
802
+ ports .key -> dst , 0 , slice_num ,
803
+ 0 , false);
779
804
bcm_sf2_cfp_slice_ipv6 (priv , ipv6 .mask -> dst .in6_u .u6_addr32 ,
780
- ports .key -> dst , SLICE_NUM_MASK , true);
805
+ ports .key -> dst , 0 , SLICE_NUM_MASK ,
806
+ 0 , true);
781
807
782
808
/* Insert into TCAM now */
783
809
bcm_sf2_cfp_rule_addr_set (priv , rule_index [1 ]);
@@ -823,7 +849,9 @@ static int bcm_sf2_cfp_rule_insert(struct dsa_switch *ds, int port,
823
849
struct bcm_sf2_priv * priv = bcm_sf2_to_priv (ds );
824
850
s8 cpu_port = dsa_to_port (ds , port )-> cpu_dp -> index ;
825
851
__u64 ring_cookie = fs -> ring_cookie ;
852
+ struct switchdev_obj_port_vlan vlan ;
826
853
unsigned int queue_num , port_num ;
854
+ u16 vid ;
827
855
int ret ;
828
856
829
857
/* This rule is a Wake-on-LAN filter and we must specifically
@@ -843,6 +871,34 @@ static int bcm_sf2_cfp_rule_insert(struct dsa_switch *ds, int port,
843
871
dsa_is_cpu_port (ds , port_num )) ||
844
872
port_num >= priv -> hw_params .num_ports )
845
873
return - EINVAL ;
874
+
875
+ /* If the rule is matching a particular VLAN, make sure that we honor
876
+ * the matching and have it tagged or untagged on the destination port,
877
+ * we do this on egress with a VLAN entry. The egress tagging attribute
878
+ * is expected to be provided in h_ext.data[1] bit 0. A 1 means untagged,
879
+ * a 0 means tagged.
880
+ */
881
+ if (fs -> flow_type & FLOW_EXT ) {
882
+ /* We cannot support matching multiple VLAN IDs yet */
883
+ if ((be16_to_cpu (fs -> m_ext .vlan_tci ) & VLAN_VID_MASK ) !=
884
+ VLAN_VID_MASK )
885
+ return - EINVAL ;
886
+
887
+ vid = be16_to_cpu (fs -> h_ext .vlan_tci ) & VLAN_VID_MASK ;
888
+ vlan .vid_begin = vid ;
889
+ vlan .vid_end = vid ;
890
+ if (cpu_to_be32 (fs -> h_ext .data [1 ]) & 1 )
891
+ vlan .flags = BRIDGE_VLAN_INFO_UNTAGGED ;
892
+ else
893
+ vlan .flags = 0 ;
894
+
895
+ ret = ds -> ops -> port_vlan_prepare (ds , port_num , & vlan );
896
+ if (ret )
897
+ return ret ;
898
+
899
+ ds -> ops -> port_vlan_add (ds , port_num , & vlan );
900
+ }
901
+
846
902
/*
847
903
* We have a small oddity where Port 6 just does not have a
848
904
* valid bit here (so we substract by one).
@@ -878,21 +934,22 @@ static int bcm_sf2_cfp_rule_set(struct dsa_switch *ds, int port,
878
934
int ret = - EINVAL ;
879
935
880
936
/* Check for unsupported extensions */
881
- if ((fs -> flow_type & FLOW_EXT ) && (fs -> m_ext .vlan_etype ||
882
- fs -> m_ext .data [1 ]))
937
+ if (fs -> flow_type & FLOW_MAC_EXT )
883
938
return - EINVAL ;
884
939
885
- if (fs -> location != RX_CLS_LOC_ANY && fs -> location >= CFP_NUM_RULES )
940
+ if (fs -> location != RX_CLS_LOC_ANY &&
941
+ fs -> location > bcm_sf2_cfp_rule_size (priv ))
886
942
return - EINVAL ;
887
943
944
+ if ((fs -> flow_type & FLOW_EXT ) &&
945
+ !(ds -> ops -> port_vlan_prepare || ds -> ops -> port_vlan_add ||
946
+ ds -> ops -> port_vlan_del ))
947
+ return - EOPNOTSUPP ;
948
+
888
949
if (fs -> location != RX_CLS_LOC_ANY &&
889
950
test_bit (fs -> location , priv -> cfp .used ))
890
951
return - EBUSY ;
891
952
892
- if (fs -> location != RX_CLS_LOC_ANY &&
893
- fs -> location > bcm_sf2_cfp_rule_size (priv ))
894
- return - EINVAL ;
895
-
896
953
ret = bcm_sf2_cfp_rule_cmp (priv , port , fs );
897
954
if (ret == 0 )
898
955
return - EEXIST ;
@@ -973,7 +1030,7 @@ static int bcm_sf2_cfp_rule_del(struct bcm_sf2_priv *priv, int port, u32 loc)
973
1030
struct cfp_rule * rule ;
974
1031
int ret ;
975
1032
976
- if (loc >= CFP_NUM_RULES )
1033
+ if (loc > bcm_sf2_cfp_rule_size ( priv ) )
977
1034
return - EINVAL ;
978
1035
979
1036
/* Refuse deleting unused rules, and those that are not unique since
0 commit comments