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 <sriharsha.basavapatna@broadcom.com> Signed-off-by: Sathya Perla <sathya.perla@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0aff1fbfe7
commit
92fbb1df83
|
@ -573,6 +573,8 @@ struct be_adapter {
|
|||
u32 uc_macs; /* Count of secondary UC MAC programmed */
|
||||
unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
u16 vlans_added;
|
||||
bool update_uc_list;
|
||||
bool update_mc_list;
|
||||
|
||||
u32 beacon_state; /* for set_phys_id */
|
||||
|
||||
|
|
|
@ -1420,8 +1420,8 @@ static int be_vid_config(struct be_adapter *adapter)
|
|||
u16 num = 0, i = 0;
|
||||
int status = 0;
|
||||
|
||||
/* No need to further configure vids if in promiscuous mode */
|
||||
if (be_in_all_promisc(adapter))
|
||||
/* No need to change the VLAN state if the I/F is in promiscuous */
|
||||
if (adapter->netdev->flags & IFF_PROMISC)
|
||||
return 0;
|
||||
|
||||
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)
|
|||
return be_vid_config(adapter);
|
||||
}
|
||||
|
||||
static void be_clear_all_promisc(struct be_adapter *adapter)
|
||||
{
|
||||
be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, OFF);
|
||||
adapter->if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS;
|
||||
}
|
||||
|
||||
static void be_set_all_promisc(struct be_adapter *adapter)
|
||||
{
|
||||
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)
|
|||
adapter->if_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS;
|
||||
}
|
||||
|
||||
static void be_set_mc_list(struct be_adapter *adapter)
|
||||
static void be_set_uc_promisc(struct be_adapter *adapter)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, ON);
|
||||
if (adapter->if_flags & BE_IF_FLAGS_PROMISCUOUS)
|
||||
return;
|
||||
|
||||
status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_PROMISCUOUS, ON);
|
||||
if (!status)
|
||||
adapter->if_flags &= ~BE_IF_FLAGS_MCAST_PROMISCUOUS;
|
||||
else
|
||||
adapter->if_flags |= BE_IF_FLAGS_PROMISCUOUS;
|
||||
}
|
||||
|
||||
static void be_clear_uc_promisc(struct be_adapter *adapter)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (!(adapter->if_flags & BE_IF_FLAGS_PROMISCUOUS))
|
||||
return;
|
||||
|
||||
status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_PROMISCUOUS, OFF);
|
||||
if (!status)
|
||||
adapter->if_flags &= ~BE_IF_FLAGS_PROMISCUOUS;
|
||||
}
|
||||
|
||||
/* The below 2 functions are the callback args for __dev_mc_sync/dev_uc_sync().
|
||||
* We use a single callback function for both sync and unsync. We really don't
|
||||
* add/remove addresses through this callback. But, we use it to detect changes
|
||||
* to the uc/mc lists. The entire uc/mc list is programmed in be_set_rx_mode().
|
||||
*/
|
||||
static int be_uc_list_update(struct net_device *netdev,
|
||||
const unsigned char *addr)
|
||||
{
|
||||
struct be_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
adapter->update_uc_list = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int be_mc_list_update(struct net_device *netdev,
|
||||
const unsigned char *addr)
|
||||
{
|
||||
struct be_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
adapter->update_mc_list = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void be_set_mc_list(struct be_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
bool mc_promisc = false;
|
||||
int status;
|
||||
|
||||
__dev_mc_sync(netdev, be_mc_list_update, be_mc_list_update);
|
||||
|
||||
if (netdev->flags & IFF_PROMISC) {
|
||||
adapter->update_mc_list = false;
|
||||
} else if (netdev->flags & IFF_ALLMULTI ||
|
||||
netdev_mc_count(netdev) > be_max_mc(adapter)) {
|
||||
/* Enable multicast promisc if num configured exceeds
|
||||
* what we support
|
||||
*/
|
||||
mc_promisc = true;
|
||||
adapter->update_mc_list = false;
|
||||
} else if (adapter->if_flags & BE_IF_FLAGS_MCAST_PROMISCUOUS) {
|
||||
/* Update mc-list unconditionally if the iface was previously
|
||||
* in mc-promisc mode and now is out of that mode.
|
||||
*/
|
||||
adapter->update_mc_list = true;
|
||||
}
|
||||
|
||||
if (mc_promisc) {
|
||||
be_set_mc_promisc(adapter);
|
||||
} else if (adapter->update_mc_list) {
|
||||
status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, ON);
|
||||
if (!status)
|
||||
adapter->if_flags &= ~BE_IF_FLAGS_MCAST_PROMISCUOUS;
|
||||
else
|
||||
be_set_mc_promisc(adapter);
|
||||
|
||||
adapter->update_mc_list = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void be_clear_mc_list(struct be_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
|
||||
__dev_mc_unsync(netdev, NULL);
|
||||
be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, OFF);
|
||||
}
|
||||
|
||||
static void be_set_uc_list(struct be_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct netdev_hw_addr *ha;
|
||||
bool uc_promisc = false;
|
||||
int i = 1; /* First slot is claimed by the Primary MAC */
|
||||
|
||||
for (; adapter->uc_macs > 0; adapter->uc_macs--, i++)
|
||||
be_cmd_pmac_del(adapter, adapter->if_handle,
|
||||
adapter->pmac_id[i], 0);
|
||||
__dev_uc_sync(netdev, be_uc_list_update, be_uc_list_update);
|
||||
|
||||
if (netdev_uc_count(adapter->netdev) > be_max_uc(adapter)) {
|
||||
be_set_all_promisc(adapter);
|
||||
return;
|
||||
if (netdev->flags & IFF_PROMISC) {
|
||||
adapter->update_uc_list = false;
|
||||
} else if (netdev_uc_count(netdev) > (be_max_uc(adapter) - 1)) {
|
||||
uc_promisc = true;
|
||||
adapter->update_uc_list = false;
|
||||
} else if (adapter->if_flags & BE_IF_FLAGS_PROMISCUOUS) {
|
||||
/* Update uc-list unconditionally if the iface was previously
|
||||
* in uc-promisc mode and now is out of that mode.
|
||||
*/
|
||||
adapter->update_uc_list = true;
|
||||
}
|
||||
|
||||
netdev_for_each_uc_addr(ha, adapter->netdev) {
|
||||
adapter->uc_macs++; /* First slot is for Primary MAC */
|
||||
be_cmd_pmac_add(adapter, (u8 *)ha->addr, adapter->if_handle,
|
||||
&adapter->pmac_id[adapter->uc_macs], 0);
|
||||
if (uc_promisc) {
|
||||
be_set_uc_promisc(adapter);
|
||||
} else if (adapter->update_uc_list) {
|
||||
be_clear_uc_promisc(adapter);
|
||||
|
||||
for (; adapter->uc_macs > 0; adapter->uc_macs--, i++)
|
||||
be_cmd_pmac_del(adapter, adapter->if_handle,
|
||||
adapter->pmac_id[i], 0);
|
||||
|
||||
netdev_for_each_uc_addr(ha, adapter->netdev) {
|
||||
adapter->uc_macs++; /* First slot is for Primary MAC */
|
||||
be_cmd_pmac_add(adapter,
|
||||
(u8 *)ha->addr, adapter->if_handle,
|
||||
&adapter->pmac_id[adapter->uc_macs], 0);
|
||||
}
|
||||
adapter->update_uc_list = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void be_clear_uc_list(struct be_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
int i;
|
||||
|
||||
__dev_uc_unsync(netdev, NULL);
|
||||
for (i = 1; i < (adapter->uc_macs + 1); i++)
|
||||
be_cmd_pmac_del(adapter, adapter->if_handle,
|
||||
adapter->pmac_id[i], 0);
|
||||
|
@ -1554,27 +1650,17 @@ static void be_set_rx_mode(struct net_device *netdev)
|
|||
struct be_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
if (netdev->flags & IFF_PROMISC) {
|
||||
be_set_all_promisc(adapter);
|
||||
return;
|
||||
if (!be_in_all_promisc(adapter))
|
||||
be_set_all_promisc(adapter);
|
||||
} else if (be_in_all_promisc(adapter)) {
|
||||
/* We need to re-program the vlan-list or clear
|
||||
* vlan-promisc mode (if needed) when the interface
|
||||
* comes out of promisc mode.
|
||||
*/
|
||||
be_vid_config(adapter);
|
||||
}
|
||||
|
||||
/* Interface was previously in promiscuous mode; disable it */
|
||||
if (be_in_all_promisc(adapter)) {
|
||||
be_clear_all_promisc(adapter);
|
||||
if (adapter->vlans_added)
|
||||
be_vid_config(adapter);
|
||||
}
|
||||
|
||||
/* Enable multicast promisc if num configured exceeds what we support */
|
||||
if (netdev->flags & IFF_ALLMULTI ||
|
||||
netdev_mc_count(netdev) > be_max_mc(adapter)) {
|
||||
be_set_mc_promisc(adapter);
|
||||
return;
|
||||
}
|
||||
|
||||
if (netdev_uc_count(netdev) != adapter->uc_macs)
|
||||
be_set_uc_list(adapter);
|
||||
|
||||
be_set_uc_list(adapter);
|
||||
be_set_mc_list(adapter);
|
||||
}
|
||||
|
||||
|
@ -3426,6 +3512,7 @@ static void be_disable_if_filters(struct be_adapter *adapter)
|
|||
adapter->pmac_id[0], 0);
|
||||
|
||||
be_clear_uc_list(adapter);
|
||||
be_clear_mc_list(adapter);
|
||||
|
||||
/* The IFACE flags are enabled in the open path and cleared
|
||||
* in the close path. When a VF gets detached from the host and
|
||||
|
|
Loading…
Reference in New Issue