@@ -1420,8 +1420,8 @@ static int be_vid_config(struct be_adapter *adapter)
14201420 u16 num = 0 , i = 0 ;
14211421 int status = 0 ;
14221422
1423- /* No need to further configure vids if in promiscuous mode */
1424- if (be_in_all_promisc ( adapter ) )
1423+ /* No need to change the VLAN state if the I/F is in promiscuous */
1424+ if (adapter -> netdev -> flags & IFF_PROMISC )
14251425 return 0 ;
14261426
14271427 if (adapter -> vlans_added > be_max_vlans (adapter ))
@@ -1483,12 +1483,6 @@ static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid)
14831483 return be_vid_config (adapter );
14841484}
14851485
1486- static void be_clear_all_promisc (struct be_adapter * adapter )
1487- {
1488- be_cmd_rx_filter (adapter , BE_IF_FLAGS_ALL_PROMISCUOUS , OFF );
1489- adapter -> if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS ;
1490- }
1491-
14921486static void be_set_all_promisc (struct be_adapter * adapter )
14931487{
14941488 be_cmd_rx_filter (adapter , BE_IF_FLAGS_ALL_PROMISCUOUS , ON );
@@ -1507,42 +1501,144 @@ static void be_set_mc_promisc(struct be_adapter *adapter)
15071501 adapter -> if_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS ;
15081502}
15091503
1510- static void be_set_mc_list (struct be_adapter * adapter )
1504+ static void be_set_uc_promisc (struct be_adapter * adapter )
15111505{
15121506 int status ;
15131507
1514- status = be_cmd_rx_filter (adapter , BE_IF_FLAGS_MULTICAST , ON );
1508+ if (adapter -> if_flags & BE_IF_FLAGS_PROMISCUOUS )
1509+ return ;
1510+
1511+ status = be_cmd_rx_filter (adapter , BE_IF_FLAGS_PROMISCUOUS , ON );
15151512 if (!status )
1516- adapter -> if_flags &= ~BE_IF_FLAGS_MCAST_PROMISCUOUS ;
1517- else
1513+ adapter -> if_flags |= BE_IF_FLAGS_PROMISCUOUS ;
1514+ }
1515+
1516+ static void be_clear_uc_promisc (struct be_adapter * adapter )
1517+ {
1518+ int status ;
1519+
1520+ if (!(adapter -> if_flags & BE_IF_FLAGS_PROMISCUOUS ))
1521+ return ;
1522+
1523+ status = be_cmd_rx_filter (adapter , BE_IF_FLAGS_PROMISCUOUS , OFF );
1524+ if (!status )
1525+ adapter -> if_flags &= ~BE_IF_FLAGS_PROMISCUOUS ;
1526+ }
1527+
1528+ /* The below 2 functions are the callback args for __dev_mc_sync/dev_uc_sync().
1529+ * We use a single callback function for both sync and unsync. We really don't
1530+ * add/remove addresses through this callback. But, we use it to detect changes
1531+ * to the uc/mc lists. The entire uc/mc list is programmed in be_set_rx_mode().
1532+ */
1533+ static int be_uc_list_update (struct net_device * netdev ,
1534+ const unsigned char * addr )
1535+ {
1536+ struct be_adapter * adapter = netdev_priv (netdev );
1537+
1538+ adapter -> update_uc_list = true;
1539+ return 0 ;
1540+ }
1541+
1542+ static int be_mc_list_update (struct net_device * netdev ,
1543+ const unsigned char * addr )
1544+ {
1545+ struct be_adapter * adapter = netdev_priv (netdev );
1546+
1547+ adapter -> update_mc_list = true;
1548+ return 0 ;
1549+ }
1550+
1551+ static void be_set_mc_list (struct be_adapter * adapter )
1552+ {
1553+ struct net_device * netdev = adapter -> netdev ;
1554+ bool mc_promisc = false;
1555+ int status ;
1556+
1557+ __dev_mc_sync (netdev , be_mc_list_update , be_mc_list_update );
1558+
1559+ if (netdev -> flags & IFF_PROMISC ) {
1560+ adapter -> update_mc_list = false;
1561+ } else if (netdev -> flags & IFF_ALLMULTI ||
1562+ netdev_mc_count (netdev ) > be_max_mc (adapter )) {
1563+ /* Enable multicast promisc if num configured exceeds
1564+ * what we support
1565+ */
1566+ mc_promisc = true;
1567+ adapter -> update_mc_list = false;
1568+ } else if (adapter -> if_flags & BE_IF_FLAGS_MCAST_PROMISCUOUS ) {
1569+ /* Update mc-list unconditionally if the iface was previously
1570+ * in mc-promisc mode and now is out of that mode.
1571+ */
1572+ adapter -> update_mc_list = true;
1573+ }
1574+
1575+ if (mc_promisc ) {
15181576 be_set_mc_promisc (adapter );
1577+ } else if (adapter -> update_mc_list ) {
1578+ status = be_cmd_rx_filter (adapter , BE_IF_FLAGS_MULTICAST , ON );
1579+ if (!status )
1580+ adapter -> if_flags &= ~BE_IF_FLAGS_MCAST_PROMISCUOUS ;
1581+ else
1582+ be_set_mc_promisc (adapter );
1583+
1584+ adapter -> update_mc_list = false;
1585+ }
1586+ }
1587+
1588+ static void be_clear_mc_list (struct be_adapter * adapter )
1589+ {
1590+ struct net_device * netdev = adapter -> netdev ;
1591+
1592+ __dev_mc_unsync (netdev , NULL );
1593+ be_cmd_rx_filter (adapter , BE_IF_FLAGS_MULTICAST , OFF );
15191594}
15201595
15211596static void be_set_uc_list (struct be_adapter * adapter )
15221597{
1598+ struct net_device * netdev = adapter -> netdev ;
15231599 struct netdev_hw_addr * ha ;
1600+ bool uc_promisc = false;
15241601 int i = 1 ; /* First slot is claimed by the Primary MAC */
15251602
1526- for (; adapter -> uc_macs > 0 ; adapter -> uc_macs -- , i ++ )
1527- be_cmd_pmac_del (adapter , adapter -> if_handle ,
1528- adapter -> pmac_id [i ], 0 );
1603+ __dev_uc_sync (netdev , be_uc_list_update , be_uc_list_update );
15291604
1530- if (netdev_uc_count (adapter -> netdev ) > be_max_uc (adapter )) {
1531- be_set_all_promisc (adapter );
1532- return ;
1605+ if (netdev -> flags & IFF_PROMISC ) {
1606+ adapter -> update_uc_list = false;
1607+ } else if (netdev_uc_count (netdev ) > (be_max_uc (adapter ) - 1 )) {
1608+ uc_promisc = true;
1609+ adapter -> update_uc_list = false;
1610+ } else if (adapter -> if_flags & BE_IF_FLAGS_PROMISCUOUS ) {
1611+ /* Update uc-list unconditionally if the iface was previously
1612+ * in uc-promisc mode and now is out of that mode.
1613+ */
1614+ adapter -> update_uc_list = true;
15331615 }
15341616
1535- netdev_for_each_uc_addr (ha , adapter -> netdev ) {
1536- adapter -> uc_macs ++ ; /* First slot is for Primary MAC */
1537- be_cmd_pmac_add (adapter , (u8 * )ha -> addr , adapter -> if_handle ,
1538- & adapter -> pmac_id [adapter -> uc_macs ], 0 );
1617+ if (uc_promisc ) {
1618+ be_set_uc_promisc (adapter );
1619+ } else if (adapter -> update_uc_list ) {
1620+ be_clear_uc_promisc (adapter );
1621+
1622+ for (; adapter -> uc_macs > 0 ; adapter -> uc_macs -- , i ++ )
1623+ be_cmd_pmac_del (adapter , adapter -> if_handle ,
1624+ adapter -> pmac_id [i ], 0 );
1625+
1626+ netdev_for_each_uc_addr (ha , adapter -> netdev ) {
1627+ adapter -> uc_macs ++ ; /* First slot is for Primary MAC */
1628+ be_cmd_pmac_add (adapter ,
1629+ (u8 * )ha -> addr , adapter -> if_handle ,
1630+ & adapter -> pmac_id [adapter -> uc_macs ], 0 );
1631+ }
1632+ adapter -> update_uc_list = false;
15391633 }
15401634}
15411635
15421636static void be_clear_uc_list (struct be_adapter * adapter )
15431637{
1638+ struct net_device * netdev = adapter -> netdev ;
15441639 int i ;
15451640
1641+ __dev_uc_unsync (netdev , NULL );
15461642 for (i = 1 ; i < (adapter -> uc_macs + 1 ); i ++ )
15471643 be_cmd_pmac_del (adapter , adapter -> if_handle ,
15481644 adapter -> pmac_id [i ], 0 );
@@ -1554,27 +1650,17 @@ static void be_set_rx_mode(struct net_device *netdev)
15541650 struct be_adapter * adapter = netdev_priv (netdev );
15551651
15561652 if (netdev -> flags & IFF_PROMISC ) {
1557- be_set_all_promisc (adapter );
1558- return ;
1559- }
1560-
1561- /* Interface was previously in promiscuous mode; disable it */
1562- if (be_in_all_promisc (adapter )) {
1563- be_clear_all_promisc (adapter );
1564- if (adapter -> vlans_added )
1565- be_vid_config (adapter );
1566- }
1567-
1568- /* Enable multicast promisc if num configured exceeds what we support */
1569- if (netdev -> flags & IFF_ALLMULTI ||
1570- netdev_mc_count (netdev ) > be_max_mc (adapter )) {
1571- be_set_mc_promisc (adapter );
1572- return ;
1653+ if (!be_in_all_promisc (adapter ))
1654+ be_set_all_promisc (adapter );
1655+ } else if (be_in_all_promisc (adapter )) {
1656+ /* We need to re-program the vlan-list or clear
1657+ * vlan-promisc mode (if needed) when the interface
1658+ * comes out of promisc mode.
1659+ */
1660+ be_vid_config (adapter );
15731661 }
15741662
1575- if (netdev_uc_count (netdev ) != adapter -> uc_macs )
1576- be_set_uc_list (adapter );
1577-
1663+ be_set_uc_list (adapter );
15781664 be_set_mc_list (adapter );
15791665}
15801666
@@ -3426,6 +3512,7 @@ static void be_disable_if_filters(struct be_adapter *adapter)
34263512 adapter -> pmac_id [0 ], 0 );
34273513
34283514 be_clear_uc_list (adapter );
3515+ be_clear_mc_list (adapter );
34293516
34303517 /* The IFACE flags are enabled in the open path and cleared
34313518 * in the close path. When a VF gets detached from the host and
0 commit comments