diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index cabe1b892722..03fc3dbe3872 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -309,6 +309,8 @@ struct be_vf_cfg { #define BE_FLAGS_LINK_STATUS_INIT 1 #define BE_FLAGS_WORKER_SCHEDULED (1 << 3) +#define BE_UC_PMAC_COUNT 30 +#define BE_VF_UC_PMAC_COUNT 2 struct be_adapter { struct pci_dev *pdev; @@ -361,7 +363,7 @@ struct be_adapter { /* Ethtool knobs and info */ char fw_ver[FW_VER_LEN]; int if_handle; /* Used to configure filtering */ - u32 pmac_id; /* MAC addr handle used by BE card */ + u32 *pmac_id; /* MAC addr handle used by BE card */ u32 beacon_state; /* for set_phys_id */ bool eeh_err; @@ -391,6 +393,8 @@ struct be_adapter { u16 pvid; u8 wol_cap; bool wol; + u32 max_pmac_cnt; /* Max secondary UC MACs programmable */ + u32 uc_macs; /* Count of secondary UC MAC programmed */ }; #define be_physfn(adapter) (!adapter->is_virtfn) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 050e3ebd4fb3..b4348b8ee529 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -235,7 +235,7 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) struct sockaddr *addr = p; int status = 0; u8 current_mac[ETH_ALEN]; - u32 pmac_id = adapter->pmac_id; + u32 pmac_id = adapter->pmac_id[0]; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; @@ -248,7 +248,7 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) if (memcmp(addr->sa_data, current_mac, ETH_ALEN)) { status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, - adapter->if_handle, &adapter->pmac_id, 0); + adapter->if_handle, &adapter->pmac_id[0], 0); if (status) goto err; @@ -885,6 +885,29 @@ static void be_set_rx_mode(struct net_device *netdev) goto done; } + if (netdev_uc_count(netdev) != adapter->uc_macs) { + struct netdev_hw_addr *ha; + 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); + } + + if (netdev_uc_count(netdev) > adapter->max_pmac_cnt) { + be_cmd_rx_filter(adapter, IFF_PROMISC, ON); + adapter->promiscuous = true; + goto done; + } + + 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); + } + } + be_cmd_rx_filter(adapter, IFF_MULTICAST, ON); done: return; @@ -2458,6 +2481,8 @@ static void be_vf_clear(struct be_adapter *adapter) static int be_clear(struct be_adapter *adapter) { + int i = 1; + if (adapter->flags & BE_FLAGS_WORKER_SCHEDULED) { cancel_delayed_work_sync(&adapter->work); adapter->flags &= ~BE_FLAGS_WORKER_SCHEDULED; @@ -2466,6 +2491,10 @@ static int be_clear(struct be_adapter *adapter) if (sriov_enabled(adapter)) be_vf_clear(adapter); + for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) + be_cmd_pmac_del(adapter, adapter->if_handle, + adapter->pmac_id[i], 0); + be_cmd_if_destroy(adapter, adapter->if_handle, 0); be_mcc_queues_destroy(adapter); @@ -2477,6 +2506,7 @@ static int be_clear(struct be_adapter *adapter) be_cmd_fw_clean(adapter); be_msix_disable(adapter); + kfree(adapter->pmac_id); return 0; } @@ -2552,10 +2582,10 @@ static int be_add_mac_from_list(struct be_adapter *adapter, u8 *mac) false, adapter->if_handle, pmac_id); if (!status) - adapter->pmac_id = pmac_id; + adapter->pmac_id[0] = pmac_id; } else { status = be_cmd_pmac_add(adapter, mac, - adapter->if_handle, &adapter->pmac_id, 0); + adapter->if_handle, &adapter->pmac_id[0], 0); } do_none: return status; @@ -2610,7 +2640,7 @@ static int be_setup(struct be_adapter *adapter) } status = be_cmd_if_create(adapter, cap_flags, en_flags, netdev->dev_addr, &adapter->if_handle, - &adapter->pmac_id, 0); + &adapter->pmac_id[0], 0); if (status != 0) goto err; @@ -3059,6 +3089,8 @@ static void be_netdev_init(struct net_device *netdev) netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + netdev->priv_flags |= IFF_UNICAST_FLT; + netdev->flags |= IFF_MULTICAST; netif_set_gso_max_size(netdev, 65535); @@ -3264,6 +3296,17 @@ static int be_get_config(struct be_adapter *adapter) else adapter->max_vlans = BE_NUM_VLANS_SUPPORTED; + if (be_physfn(adapter)) + adapter->max_pmac_cnt = BE_UC_PMAC_COUNT; + else + adapter->max_pmac_cnt = BE_VF_UC_PMAC_COUNT; + + /* primary mac needs 1 pmac entry */ + adapter->pmac_id = kcalloc(adapter->max_pmac_cnt + 1, + sizeof(u32), GFP_KERNEL); + if (!adapter->pmac_id) + return -ENOMEM; + status = be_cmd_get_cntl_attributes(adapter); if (status) return status;