@@ -331,13 +331,9 @@ static void a5psw_flooding_set_resolution(struct a5psw *a5psw, int port,
331331 A5PSW_MCAST_DEF_MASK };
332332 int i ;
333333
334- if (set )
335- a5psw -> bridged_ports |= BIT (port );
336- else
337- a5psw -> bridged_ports &= ~BIT (port );
338-
339334 for (i = 0 ; i < ARRAY_SIZE (offsets ); i ++ )
340- a5psw_reg_writel (a5psw , offsets [i ], a5psw -> bridged_ports );
335+ a5psw_reg_rmw (a5psw , offsets [i ], BIT (port ),
336+ set ? BIT (port ) : 0 );
341337}
342338
343339static void a5psw_port_set_standalone (struct a5psw * a5psw , int port ,
@@ -365,6 +361,8 @@ static int a5psw_port_bridge_join(struct dsa_switch *ds, int port,
365361 a5psw -> br_dev = bridge .dev ;
366362 a5psw_port_set_standalone (a5psw , port , false);
367363
364+ a5psw -> bridged_ports |= BIT (port );
365+
368366 return 0 ;
369367}
370368
@@ -373,16 +371,72 @@ static void a5psw_port_bridge_leave(struct dsa_switch *ds, int port,
373371{
374372 struct a5psw * a5psw = ds -> priv ;
375373
374+ a5psw -> bridged_ports &= ~BIT (port );
375+
376376 a5psw_port_set_standalone (a5psw , port , true);
377377
378378 /* No more ports bridged */
379379 if (a5psw -> bridged_ports == BIT (A5PSW_CPU_PORT ))
380380 a5psw -> br_dev = NULL ;
381381}
382382
383+ static int a5psw_port_pre_bridge_flags (struct dsa_switch * ds , int port ,
384+ struct switchdev_brport_flags flags ,
385+ struct netlink_ext_ack * extack )
386+ {
387+ if (flags .mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD |
388+ BR_BCAST_FLOOD ))
389+ return - EINVAL ;
390+
391+ return 0 ;
392+ }
393+
394+ static int
395+ a5psw_port_bridge_flags (struct dsa_switch * ds , int port ,
396+ struct switchdev_brport_flags flags ,
397+ struct netlink_ext_ack * extack )
398+ {
399+ struct a5psw * a5psw = ds -> priv ;
400+ u32 val ;
401+
402+ /* If a port is set as standalone, we do not want to be able to
403+ * configure flooding nor learning which would result in joining the
404+ * unique bridge. This can happen when a port leaves the bridge, in
405+ * which case the DSA core will try to "clear" all flags for the
406+ * standalone port (ie enable flooding, disable learning). In that case
407+ * do not fail but do not apply the flags.
408+ */
409+ if (!(a5psw -> bridged_ports & BIT (port )))
410+ return 0 ;
411+
412+ if (flags .mask & BR_LEARNING ) {
413+ val = flags .val & BR_LEARNING ? 0 : A5PSW_INPUT_LEARN_DIS (port );
414+ a5psw_reg_rmw (a5psw , A5PSW_INPUT_LEARN ,
415+ A5PSW_INPUT_LEARN_DIS (port ), val );
416+ }
417+
418+ if (flags .mask & BR_FLOOD ) {
419+ val = flags .val & BR_FLOOD ? BIT (port ) : 0 ;
420+ a5psw_reg_rmw (a5psw , A5PSW_UCAST_DEF_MASK , BIT (port ), val );
421+ }
422+
423+ if (flags .mask & BR_MCAST_FLOOD ) {
424+ val = flags .val & BR_MCAST_FLOOD ? BIT (port ) : 0 ;
425+ a5psw_reg_rmw (a5psw , A5PSW_MCAST_DEF_MASK , BIT (port ), val );
426+ }
427+
428+ if (flags .mask & BR_BCAST_FLOOD ) {
429+ val = flags .val & BR_BCAST_FLOOD ? BIT (port ) : 0 ;
430+ a5psw_reg_rmw (a5psw , A5PSW_BCAST_DEF_MASK , BIT (port ), val );
431+ }
432+
433+ return 0 ;
434+ }
435+
383436static void a5psw_port_stp_state_set (struct dsa_switch * ds , int port , u8 state )
384437{
385438 bool learning_enabled , rx_enabled , tx_enabled ;
439+ struct dsa_port * dp = dsa_to_port (ds , port );
386440 struct a5psw * a5psw = ds -> priv ;
387441
388442 switch (state ) {
@@ -396,12 +450,12 @@ static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
396450 case BR_STATE_LEARNING :
397451 rx_enabled = false;
398452 tx_enabled = false;
399- learning_enabled = true ;
453+ learning_enabled = dp -> learning ;
400454 break ;
401455 case BR_STATE_FORWARDING :
402456 rx_enabled = true;
403457 tx_enabled = true;
404- learning_enabled = true ;
458+ learning_enabled = dp -> learning ;
405459 break ;
406460 default :
407461 dev_err (ds -> dev , "invalid STP state: %d\n" , state );
@@ -585,6 +639,146 @@ static int a5psw_port_fdb_dump(struct dsa_switch *ds, int port,
585639 return ret ;
586640}
587641
642+ static int a5psw_port_vlan_filtering (struct dsa_switch * ds , int port ,
643+ bool vlan_filtering ,
644+ struct netlink_ext_ack * extack )
645+ {
646+ u32 mask = BIT (port + A5PSW_VLAN_VERI_SHIFT ) |
647+ BIT (port + A5PSW_VLAN_DISC_SHIFT );
648+ u32 val = vlan_filtering ? mask : 0 ;
649+ struct a5psw * a5psw = ds -> priv ;
650+
651+ /* Disable/enable vlan tagging */
652+ a5psw_reg_rmw (a5psw , A5PSW_VLAN_IN_MODE_ENA , BIT (port ),
653+ vlan_filtering ? BIT (port ) : 0 );
654+
655+ /* Disable/enable vlan input filtering */
656+ a5psw_reg_rmw (a5psw , A5PSW_VLAN_VERIFY , mask , val );
657+
658+ return 0 ;
659+ }
660+
661+ static int a5psw_find_vlan_entry (struct a5psw * a5psw , u16 vid )
662+ {
663+ u32 vlan_res ;
664+ int i ;
665+
666+ /* Find vlan for this port */
667+ for (i = 0 ; i < A5PSW_VLAN_COUNT ; i ++ ) {
668+ vlan_res = a5psw_reg_readl (a5psw , A5PSW_VLAN_RES (i ));
669+ if (FIELD_GET (A5PSW_VLAN_RES_VLANID , vlan_res ) == vid )
670+ return i ;
671+ }
672+
673+ return -1 ;
674+ }
675+
676+ static int a5psw_new_vlan_res_entry (struct a5psw * a5psw , u16 newvid )
677+ {
678+ u32 vlan_res ;
679+ int i ;
680+
681+ /* Find a free VLAN entry */
682+ for (i = 0 ; i < A5PSW_VLAN_COUNT ; i ++ ) {
683+ vlan_res = a5psw_reg_readl (a5psw , A5PSW_VLAN_RES (i ));
684+ if (!(FIELD_GET (A5PSW_VLAN_RES_PORTMASK , vlan_res ))) {
685+ vlan_res = FIELD_PREP (A5PSW_VLAN_RES_VLANID , newvid );
686+ a5psw_reg_writel (a5psw , A5PSW_VLAN_RES (i ), vlan_res );
687+ return i ;
688+ }
689+ }
690+
691+ return -1 ;
692+ }
693+
694+ static void a5psw_port_vlan_tagged_cfg (struct a5psw * a5psw ,
695+ unsigned int vlan_res_id , int port ,
696+ bool set )
697+ {
698+ u32 mask = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_RD_TAGMASK |
699+ BIT (port );
700+ u32 vlan_res_off = A5PSW_VLAN_RES (vlan_res_id );
701+ u32 val = A5PSW_VLAN_RES_WR_TAGMASK , reg ;
702+
703+ if (set )
704+ val |= BIT (port );
705+
706+ /* Toggle tag mask read */
707+ a5psw_reg_writel (a5psw , vlan_res_off , A5PSW_VLAN_RES_RD_TAGMASK );
708+ reg = a5psw_reg_readl (a5psw , vlan_res_off );
709+ a5psw_reg_writel (a5psw , vlan_res_off , A5PSW_VLAN_RES_RD_TAGMASK );
710+
711+ reg &= ~mask ;
712+ reg |= val ;
713+ a5psw_reg_writel (a5psw , vlan_res_off , reg );
714+ }
715+
716+ static void a5psw_port_vlan_cfg (struct a5psw * a5psw , unsigned int vlan_res_id ,
717+ int port , bool set )
718+ {
719+ u32 mask = A5PSW_VLAN_RES_WR_TAGMASK | BIT (port );
720+ u32 reg = A5PSW_VLAN_RES_WR_PORTMASK ;
721+
722+ if (set )
723+ reg |= BIT (port );
724+
725+ a5psw_reg_rmw (a5psw , A5PSW_VLAN_RES (vlan_res_id ), mask , reg );
726+ }
727+
728+ static int a5psw_port_vlan_add (struct dsa_switch * ds , int port ,
729+ const struct switchdev_obj_port_vlan * vlan ,
730+ struct netlink_ext_ack * extack )
731+ {
732+ bool tagged = !(vlan -> flags & BRIDGE_VLAN_INFO_UNTAGGED );
733+ bool pvid = vlan -> flags & BRIDGE_VLAN_INFO_PVID ;
734+ struct a5psw * a5psw = ds -> priv ;
735+ u16 vid = vlan -> vid ;
736+ int vlan_res_id ;
737+
738+ dev_dbg (a5psw -> dev , "Add VLAN %d on port %d, %s, %s\n" ,
739+ vid , port , tagged ? "tagged" : "untagged" ,
740+ pvid ? "PVID" : "no PVID" );
741+
742+ vlan_res_id = a5psw_find_vlan_entry (a5psw , vid );
743+ if (vlan_res_id < 0 ) {
744+ vlan_res_id = a5psw_new_vlan_res_entry (a5psw , vid );
745+ if (vlan_res_id < 0 )
746+ return - ENOSPC ;
747+ }
748+
749+ a5psw_port_vlan_cfg (a5psw , vlan_res_id , port , true);
750+ if (tagged )
751+ a5psw_port_vlan_tagged_cfg (a5psw , vlan_res_id , port , true);
752+
753+ /* Configure port to tag with corresponding VID, but do not enable it
754+ * yet: wait for vlan filtering to be enabled to enable vlan port
755+ * tagging
756+ */
757+ if (pvid )
758+ a5psw_reg_writel (a5psw , A5PSW_SYSTEM_TAGINFO (port ), vid );
759+
760+ return 0 ;
761+ }
762+
763+ static int a5psw_port_vlan_del (struct dsa_switch * ds , int port ,
764+ const struct switchdev_obj_port_vlan * vlan )
765+ {
766+ struct a5psw * a5psw = ds -> priv ;
767+ u16 vid = vlan -> vid ;
768+ int vlan_res_id ;
769+
770+ dev_dbg (a5psw -> dev , "Removing VLAN %d on port %d\n" , vid , port );
771+
772+ vlan_res_id = a5psw_find_vlan_entry (a5psw , vid );
773+ if (vlan_res_id < 0 )
774+ return - EINVAL ;
775+
776+ a5psw_port_vlan_cfg (a5psw , vlan_res_id , port , false);
777+ a5psw_port_vlan_tagged_cfg (a5psw , vlan_res_id , port , false);
778+
779+ return 0 ;
780+ }
781+
588782static u64 a5psw_read_stat (struct a5psw * a5psw , u32 offset , int port )
589783{
590784 u32 reg_lo , reg_hi ;
@@ -702,6 +896,27 @@ static void a5psw_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
702896 ctrl_stats -> MACControlFramesReceived = stat ;
703897}
704898
899+ static void a5psw_vlan_setup (struct a5psw * a5psw , int port )
900+ {
901+ u32 reg ;
902+
903+ /* Enable TAG always mode for the port, this is actually controlled
904+ * by VLAN_IN_MODE_ENA field which will be used for PVID insertion
905+ */
906+ reg = A5PSW_VLAN_IN_MODE_TAG_ALWAYS ;
907+ reg <<= A5PSW_VLAN_IN_MODE_PORT_SHIFT (port );
908+ a5psw_reg_rmw (a5psw , A5PSW_VLAN_IN_MODE , A5PSW_VLAN_IN_MODE_PORT (port ),
909+ reg );
910+
911+ /* Set transparent mode for output frame manipulation, this will depend
912+ * on the VLAN_RES configuration mode
913+ */
914+ reg = A5PSW_VLAN_OUT_MODE_TRANSPARENT ;
915+ reg <<= A5PSW_VLAN_OUT_MODE_PORT_SHIFT (port );
916+ a5psw_reg_rmw (a5psw , A5PSW_VLAN_OUT_MODE ,
917+ A5PSW_VLAN_OUT_MODE_PORT (port ), reg );
918+ }
919+
705920static int a5psw_setup (struct dsa_switch * ds )
706921{
707922 struct a5psw * a5psw = ds -> priv ;
@@ -776,6 +991,8 @@ static int a5psw_setup(struct dsa_switch *ds)
776991 /* Enable standalone mode for user ports */
777992 if (dsa_port_is_user (dp ))
778993 a5psw_port_set_standalone (a5psw , port , true);
994+
995+ a5psw_vlan_setup (a5psw , port );
779996 }
780997
781998 return 0 ;
@@ -801,8 +1018,13 @@ static const struct dsa_switch_ops a5psw_switch_ops = {
8011018 .set_ageing_time = a5psw_set_ageing_time ,
8021019 .port_bridge_join = a5psw_port_bridge_join ,
8031020 .port_bridge_leave = a5psw_port_bridge_leave ,
1021+ .port_pre_bridge_flags = a5psw_port_pre_bridge_flags ,
1022+ .port_bridge_flags = a5psw_port_bridge_flags ,
8041023 .port_stp_state_set = a5psw_port_stp_state_set ,
8051024 .port_fast_age = a5psw_port_fast_age ,
1025+ .port_vlan_filtering = a5psw_port_vlan_filtering ,
1026+ .port_vlan_add = a5psw_port_vlan_add ,
1027+ .port_vlan_del = a5psw_port_vlan_del ,
8061028 .port_fdb_add = a5psw_port_fdb_add ,
8071029 .port_fdb_del = a5psw_port_fdb_del ,
8081030 .port_fdb_dump = a5psw_port_fdb_dump ,
@@ -992,6 +1214,8 @@ static int a5psw_probe(struct platform_device *pdev)
9921214 if (IS_ERR (a5psw -> base ))
9931215 return PTR_ERR (a5psw -> base );
9941216
1217+ a5psw -> bridged_ports = BIT (A5PSW_CPU_PORT );
1218+
9951219 ret = a5psw_pcs_get (a5psw );
9961220 if (ret )
9971221 return ret ;
0 commit comments