Skip to content

Commit 92fbb1d

Browse files
sbasavapatnadavem330
authored andcommitted
be2net: Avoid unnecessary firmware updates of multicast list
Eachtime the ndo_set_rx_mode() routine is called, the driver programs the multicast list in the adapter without checking if there are any changes to the list. This leads to a flood of RX_FILTER cmds when a number of vlan interfaces are configured over the device, as the ndo_ gets called for each vlan interface. To avoid this, we now use __dev_mc_sync() and __dev_uc_sync() API, but only to detect if there is a change in the mc/uc lists. Now that we use this API, the code has to be-designed to issue these API calls for each invocation of the be_set_rx_mode() call. Signed-off-by: Sriharsha Basavapatna <[email protected]> Signed-off-by: Sathya Perla <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0aff1fb commit 92fbb1d

File tree

2 files changed

+130
-41
lines changed

2 files changed

+130
-41
lines changed

drivers/net/ethernet/emulex/benet/be.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,8 @@ struct be_adapter {
573573
u32 uc_macs; /* Count of secondary UC MAC programmed */
574574
unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)];
575575
u16 vlans_added;
576+
bool update_uc_list;
577+
bool update_mc_list;
576578

577579
u32 beacon_state; /* for set_phys_id */
578580

drivers/net/ethernet/emulex/benet/be_main.c

Lines changed: 128 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
14921486
static 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

15211596
static 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

15421636
static 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

Comments
 (0)