@@ -1420,8 +1420,8 @@ static int be_vid_config(struct be_adapter *adapter)
1420
1420
u16 num = 0 , i = 0 ;
1421
1421
int status = 0 ;
1422
1422
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 )
1425
1425
return 0 ;
1426
1426
1427
1427
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)
1483
1483
return be_vid_config (adapter );
1484
1484
}
1485
1485
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
-
1492
1486
static void be_set_all_promisc (struct be_adapter * adapter )
1493
1487
{
1494
1488
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)
1507
1501
adapter -> if_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS ;
1508
1502
}
1509
1503
1510
- static void be_set_mc_list (struct be_adapter * adapter )
1504
+ static void be_set_uc_promisc (struct be_adapter * adapter )
1511
1505
{
1512
1506
int status ;
1513
1507
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 );
1515
1512
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 ) {
1518
1576
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 );
1519
1594
}
1520
1595
1521
1596
static void be_set_uc_list (struct be_adapter * adapter )
1522
1597
{
1598
+ struct net_device * netdev = adapter -> netdev ;
1523
1599
struct netdev_hw_addr * ha ;
1600
+ bool uc_promisc = false;
1524
1601
int i = 1 ; /* First slot is claimed by the Primary MAC */
1525
1602
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 );
1529
1604
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;
1533
1615
}
1534
1616
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;
1539
1633
}
1540
1634
}
1541
1635
1542
1636
static void be_clear_uc_list (struct be_adapter * adapter )
1543
1637
{
1638
+ struct net_device * netdev = adapter -> netdev ;
1544
1639
int i ;
1545
1640
1641
+ __dev_uc_unsync (netdev , NULL );
1546
1642
for (i = 1 ; i < (adapter -> uc_macs + 1 ); i ++ )
1547
1643
be_cmd_pmac_del (adapter , adapter -> if_handle ,
1548
1644
adapter -> pmac_id [i ], 0 );
@@ -1554,27 +1650,17 @@ static void be_set_rx_mode(struct net_device *netdev)
1554
1650
struct be_adapter * adapter = netdev_priv (netdev );
1555
1651
1556
1652
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 );
1573
1661
}
1574
1662
1575
- if (netdev_uc_count (netdev ) != adapter -> uc_macs )
1576
- be_set_uc_list (adapter );
1577
-
1663
+ be_set_uc_list (adapter );
1578
1664
be_set_mc_list (adapter );
1579
1665
}
1580
1666
@@ -3426,6 +3512,7 @@ static void be_disable_if_filters(struct be_adapter *adapter)
3426
3512
adapter -> pmac_id [0 ], 0 );
3427
3513
3428
3514
be_clear_uc_list (adapter );
3515
+ be_clear_mc_list (adapter );
3429
3516
3430
3517
/* The IFACE flags are enabled in the open path and cleared
3431
3518
* in the close path. When a VF gets detached from the host and
0 commit comments