@@ -561,61 +561,134 @@ const struct icss_iep_clockops prueth_iep_clockops = {
561561
562562static int icssg_prueth_add_mcast (struct net_device * ndev , const u8 * addr )
563563{
564- struct prueth_emac * emac = netdev_priv (ndev );
565- int port_mask = BIT (emac -> port_id );
564+ struct net_device * real_dev ;
565+ struct prueth_emac * emac ;
566+ int port_mask ;
567+ u8 vlan_id ;
566568
567- port_mask |= icssg_fdb_lookup (emac , addr , 0 );
568- icssg_fdb_add_del (emac , addr , 0 , port_mask , true);
569- icssg_vtbl_modify (emac , 0 , port_mask , port_mask , true);
569+ vlan_id = is_vlan_dev (ndev ) ? vlan_dev_vlan_id (ndev ) : PRUETH_DFLT_VLAN_MAC ;
570+ real_dev = is_vlan_dev (ndev ) ? vlan_dev_real_dev (ndev ) : ndev ;
571+ emac = netdev_priv (real_dev );
572+
573+ port_mask = BIT (emac -> port_id ) | icssg_fdb_lookup (emac , addr , vlan_id );
574+ icssg_fdb_add_del (emac , addr , vlan_id , port_mask , true);
575+ icssg_vtbl_modify (emac , vlan_id , port_mask , port_mask , true);
570576
571577 return 0 ;
572578}
573579
574580static int icssg_prueth_del_mcast (struct net_device * ndev , const u8 * addr )
575581{
576- struct prueth_emac * emac = netdev_priv ( ndev ) ;
577- int port_mask = BIT ( emac -> port_id ) ;
582+ struct net_device * real_dev ;
583+ struct prueth_emac * emac ;
578584 int other_port_mask ;
585+ int port_mask ;
586+ u8 vlan_id ;
587+
588+ vlan_id = is_vlan_dev (ndev ) ? vlan_dev_vlan_id (ndev ) : PRUETH_DFLT_VLAN_MAC ;
589+ real_dev = is_vlan_dev (ndev ) ? vlan_dev_real_dev (ndev ) : ndev ;
590+ emac = netdev_priv (real_dev );
579591
580- other_port_mask = port_mask ^ icssg_fdb_lookup (emac , addr , 0 );
592+ port_mask = BIT (emac -> port_id );
593+ other_port_mask = port_mask ^ icssg_fdb_lookup (emac , addr , vlan_id );
581594
582- icssg_fdb_add_del (emac , addr , 0 , port_mask , false);
583- icssg_vtbl_modify (emac , 0 , port_mask , port_mask , false);
595+ icssg_fdb_add_del (emac , addr , vlan_id , port_mask , false);
596+ icssg_vtbl_modify (emac , vlan_id , port_mask , port_mask , false);
584597
585598 if (other_port_mask ) {
586- icssg_fdb_add_del (emac , addr , 0 , other_port_mask , true);
587- icssg_vtbl_modify (emac , 0 , other_port_mask , other_port_mask , true);
599+ icssg_fdb_add_del (emac , addr , vlan_id , other_port_mask , true);
600+ icssg_vtbl_modify (emac , vlan_id , other_port_mask ,
601+ other_port_mask , true);
588602 }
589603
590604 return 0 ;
591605}
592606
593- static int icssg_prueth_hsr_add_mcast (struct net_device * ndev , const u8 * addr )
607+ static void icssg_prueth_hsr_fdb_add_del (struct prueth_emac * emac ,
608+ const u8 * addr , u8 vid , bool add )
594609{
595- struct prueth_emac * emac = netdev_priv (ndev );
596- struct prueth * prueth = emac -> prueth ;
597-
598- icssg_fdb_add_del (emac , addr , prueth -> default_vlan ,
610+ icssg_fdb_add_del (emac , addr , vid ,
599611 ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
600612 ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
601613 ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
602- ICSSG_FDB_ENTRY_BLOCK , true);
614+ ICSSG_FDB_ENTRY_BLOCK , add );
615+
616+ if (add )
617+ icssg_vtbl_modify (emac , vid , BIT (emac -> port_id ),
618+ BIT (emac -> port_id ), add );
619+ }
620+
621+ static int icssg_prueth_hsr_add_mcast (struct net_device * ndev , const u8 * addr )
622+ {
623+ struct net_device * real_dev ;
624+ struct prueth_emac * emac ;
625+ u8 vlan_id , i ;
626+
627+ vlan_id = is_vlan_dev (ndev ) ? vlan_dev_vlan_id (ndev ) : PRUETH_DFLT_VLAN_HSR ;
628+ real_dev = is_vlan_dev (ndev ) ? vlan_dev_real_dev (ndev ) : ndev ;
629+
630+ if (is_hsr_master (real_dev )) {
631+ for (i = HSR_PT_SLAVE_A ; i < HSR_PT_INTERLINK ; i ++ ) {
632+ emac = netdev_priv (hsr_get_port_ndev (real_dev , i ));
633+ if (!emac )
634+ return - EINVAL ;
635+ icssg_prueth_hsr_fdb_add_del (emac , addr , vlan_id ,
636+ true);
637+ }
638+ } else {
639+ emac = netdev_priv (real_dev );
640+ icssg_prueth_hsr_fdb_add_del (emac , addr , vlan_id , true);
641+ }
603642
604- icssg_vtbl_modify (emac , emac -> port_vlan , BIT (emac -> port_id ),
605- BIT (emac -> port_id ), true);
606643 return 0 ;
607644}
608645
609646static int icssg_prueth_hsr_del_mcast (struct net_device * ndev , const u8 * addr )
610647{
611- struct prueth_emac * emac = netdev_priv (ndev );
612- struct prueth * prueth = emac -> prueth ;
648+ struct net_device * real_dev ;
649+ struct prueth_emac * emac ;
650+ u8 vlan_id , i ;
651+
652+ vlan_id = is_vlan_dev (ndev ) ? vlan_dev_vlan_id (ndev ) : PRUETH_DFLT_VLAN_HSR ;
653+ real_dev = is_vlan_dev (ndev ) ? vlan_dev_real_dev (ndev ) : ndev ;
654+
655+ if (is_hsr_master (real_dev )) {
656+ for (i = HSR_PT_SLAVE_A ; i < HSR_PT_INTERLINK ; i ++ ) {
657+ emac = netdev_priv (hsr_get_port_ndev (real_dev , i ));
658+ if (!emac )
659+ return - EINVAL ;
660+ icssg_prueth_hsr_fdb_add_del (emac , addr , vlan_id ,
661+ false);
662+ }
663+ } else {
664+ emac = netdev_priv (real_dev );
665+ icssg_prueth_hsr_fdb_add_del (emac , addr , vlan_id , false);
666+ }
613667
614- icssg_fdb_add_del (emac , addr , prueth -> default_vlan ,
615- ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
616- ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
617- ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
618- ICSSG_FDB_ENTRY_BLOCK , false);
668+ return 0 ;
669+ }
670+
671+ static int icssg_update_vlan_mcast (struct net_device * vdev , int vid ,
672+ void * args )
673+ {
674+ struct prueth_emac * emac = args ;
675+
676+ if (!vdev || !vid )
677+ return 0 ;
678+
679+ netif_addr_lock_bh (vdev );
680+ __hw_addr_sync_multiple (& emac -> vlan_mcast_list [vid ], & vdev -> mc ,
681+ vdev -> addr_len );
682+ netif_addr_unlock_bh (vdev );
683+
684+ if (emac -> prueth -> is_hsr_offload_mode )
685+ __hw_addr_sync_dev (& emac -> vlan_mcast_list [vid ], vdev ,
686+ icssg_prueth_hsr_add_mcast ,
687+ icssg_prueth_hsr_del_mcast );
688+ else
689+ __hw_addr_sync_dev (& emac -> vlan_mcast_list [vid ], vdev ,
690+ icssg_prueth_add_mcast ,
691+ icssg_prueth_del_mcast );
619692
620693 return 0 ;
621694}
@@ -857,12 +930,22 @@ static void emac_ndo_set_rx_mode_work(struct work_struct *work)
857930 return ;
858931 }
859932
860- if (emac -> prueth -> is_hsr_offload_mode )
933+ if (emac -> prueth -> is_hsr_offload_mode ) {
861934 __dev_mc_sync (ndev , icssg_prueth_hsr_add_mcast ,
862935 icssg_prueth_hsr_del_mcast );
863- else
936+ if (rtnl_trylock ()) {
937+ vlan_for_each (emac -> prueth -> hsr_dev ,
938+ icssg_update_vlan_mcast , emac );
939+ rtnl_unlock ();
940+ }
941+ } else {
864942 __dev_mc_sync (ndev , icssg_prueth_add_mcast ,
865943 icssg_prueth_del_mcast );
944+ if (rtnl_trylock ()) {
945+ vlan_for_each (ndev , icssg_update_vlan_mcast , emac );
946+ rtnl_unlock ();
947+ }
948+ }
866949}
867950
868951/**
@@ -907,19 +990,19 @@ static int emac_ndo_vlan_rx_add_vid(struct net_device *ndev,
907990{
908991 struct prueth_emac * emac = netdev_priv (ndev );
909992 struct prueth * prueth = emac -> prueth ;
993+ int port_mask = BIT (emac -> port_id );
910994 int untag_mask = 0 ;
911- int port_mask ;
912995
913- if (prueth -> is_hsr_offload_mode ) {
914- port_mask = BIT (PRUETH_PORT_HOST ) | BIT (emac -> port_id );
915- untag_mask = 0 ;
996+ if (prueth -> is_hsr_offload_mode )
997+ port_mask |= BIT (PRUETH_PORT_HOST );
916998
917- netdev_dbg (emac -> ndev , "VID add vid:%u port_mask:%X untag_mask %X\n" ,
918- vid , port_mask , untag_mask );
999+ __hw_addr_init (& emac -> vlan_mcast_list [vid ]);
1000+ netdev_dbg (emac -> ndev , "VID add vid:%u port_mask:%X untag_mask %X\n" ,
1001+ vid , port_mask , untag_mask );
1002+
1003+ icssg_vtbl_modify (emac , vid , port_mask , untag_mask , true);
1004+ icssg_set_pvid (emac -> prueth , vid , emac -> port_id );
9191005
920- icssg_vtbl_modify (emac , vid , port_mask , untag_mask , true);
921- icssg_set_pvid (emac -> prueth , vid , emac -> port_id );
922- }
9231006 return 0 ;
9241007}
9251008
@@ -928,18 +1011,16 @@ static int emac_ndo_vlan_rx_del_vid(struct net_device *ndev,
9281011{
9291012 struct prueth_emac * emac = netdev_priv (ndev );
9301013 struct prueth * prueth = emac -> prueth ;
1014+ int port_mask = BIT (emac -> port_id );
9311015 int untag_mask = 0 ;
932- int port_mask ;
9331016
934- if (prueth -> is_hsr_offload_mode ) {
1017+ if (prueth -> is_hsr_offload_mode )
9351018 port_mask = BIT (PRUETH_PORT_HOST );
936- untag_mask = 0 ;
9371019
938- netdev_dbg (emac -> ndev , "VID del vid:%u port_mask:%X untag_mask %X\n" ,
939- vid , port_mask , untag_mask );
1020+ netdev_dbg (emac -> ndev , "VID del vid:%u port_mask:%X untag_mask %X\n" ,
1021+ vid , port_mask , untag_mask );
1022+ icssg_vtbl_modify (emac , vid , port_mask , untag_mask , false);
9401023
941- icssg_vtbl_modify (emac , vid , port_mask , untag_mask , false);
942- }
9431024 return 0 ;
9441025}
9451026
@@ -1254,7 +1335,7 @@ static int prueth_netdevice_port_link(struct net_device *ndev,
12541335 if (prueth -> br_members & BIT (PRUETH_PORT_MII0 ) &&
12551336 prueth -> br_members & BIT (PRUETH_PORT_MII1 )) {
12561337 prueth -> is_switch_mode = true;
1257- prueth -> default_vlan = 1 ;
1338+ prueth -> default_vlan = PRUETH_DFLT_VLAN_SW ;
12581339 emac -> port_vlan = prueth -> default_vlan ;
12591340 icssg_change_mode (prueth );
12601341 }
@@ -1312,7 +1393,7 @@ static int prueth_hsr_port_link(struct net_device *ndev)
13121393 NETIF_PRUETH_HSR_OFFLOAD_FEATURES ))
13131394 return - EOPNOTSUPP ;
13141395 prueth -> is_hsr_offload_mode = true;
1315- prueth -> default_vlan = 1 ;
1396+ prueth -> default_vlan = PRUETH_DFLT_VLAN_HSR ;
13161397 emac0 -> port_vlan = prueth -> default_vlan ;
13171398 emac1 -> port_vlan = prueth -> default_vlan ;
13181399 icssg_change_mode (prueth );
0 commit comments