diff options
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 11 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 34 | ||||
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 19 |
3 files changed, 51 insertions, 13 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index e56c1bb36141..fa4317611fd6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -848,10 +848,17 @@ struct qlcnic_cardrsp_tx_ctx { #define QLCNIC_MAC_VLAN_ADD 3 #define QLCNIC_MAC_VLAN_DEL 4 +enum qlcnic_mac_type { + QLCNIC_UNICAST_MAC, + QLCNIC_MULTICAST_MAC, + QLCNIC_BROADCAST_MAC, +}; + struct qlcnic_mac_vlan_list { struct list_head list; uint8_t mac_addr[ETH_ALEN+2]; u16 vlan_id; + enum qlcnic_mac_type mac_type; }; /* MAC Learn */ @@ -1615,7 +1622,9 @@ void qlcnic_watchdog_task(struct work_struct *work); void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring, u8 ring_id); void qlcnic_set_multi(struct net_device *netdev); -int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16); +void qlcnic_flush_mcast_mac(struct qlcnic_adapter *); +int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16, + enum qlcnic_mac_type); int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *); void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter); int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 69b46c051cc0..3e0f705a4311 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -487,7 +487,8 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr) return err; } -int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan) +int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan, + enum qlcnic_mac_type mac_type) { struct qlcnic_mac_vlan_list *cur; struct list_head *head; @@ -513,10 +514,29 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan) } cur->vlan_id = vlan; + cur->mac_type = mac_type; + list_add_tail(&cur->list, &adapter->mac_list); return 0; } +void qlcnic_flush_mcast_mac(struct qlcnic_adapter *adapter) +{ + struct qlcnic_mac_vlan_list *cur; + struct list_head *head, *tmp; + + list_for_each_safe(head, tmp, &adapter->mac_list) { + cur = list_entry(head, struct qlcnic_mac_vlan_list, list); + if (cur->mac_type != QLCNIC_MULTICAST_MAC) + continue; + + qlcnic_sre_macaddr_change(adapter, cur->mac_addr, + cur->vlan_id, QLCNIC_MAC_DEL); + list_del(&cur->list); + kfree(cur); + } +} + static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -530,8 +550,9 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) return; - qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan); - qlcnic_nic_add_mac(adapter, bcast_addr, vlan); + qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan, + QLCNIC_UNICAST_MAC); + qlcnic_nic_add_mac(adapter, bcast_addr, vlan, QLCNIC_BROADCAST_MAC); if (netdev->flags & IFF_PROMISC) { if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) @@ -540,8 +561,10 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) (netdev_mc_count(netdev) > ahw->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; } else if (!netdev_mc_empty(netdev)) { + qlcnic_flush_mcast_mac(adapter); netdev_for_each_mc_addr(ha, netdev) - qlcnic_nic_add_mac(adapter, ha->addr, vlan); + qlcnic_nic_add_mac(adapter, ha->addr, vlan, + QLCNIC_MULTICAST_MAC); } /* configure unicast MAC address, if there is not sufficient space @@ -551,7 +574,8 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) mode = VPORT_MISS_MODE_ACCEPT_ALL; } else if (!netdev_uc_empty(netdev)) { netdev_for_each_uc_addr(ha, netdev) - qlcnic_nic_add_mac(adapter, ha->addr, vlan); + qlcnic_nic_add_mac(adapter, ha->addr, vlan, + QLCNIC_UNICAST_MAC); } if (mode == VPORT_MISS_MODE_ACCEPT_ALL && diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 1659c804f1d5..e6312465fe45 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -1489,7 +1489,8 @@ out: return ret; } -static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac) +static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac, + enum qlcnic_mac_type mac_type) { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_sriov *sriov = adapter->ahw->sriov; @@ -1500,17 +1501,18 @@ static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac) vf = &adapter->ahw->sriov->vf_info[0]; if (!qlcnic_sriov_check_any_vlan(vf)) { - qlcnic_nic_add_mac(adapter, mac, 0); + qlcnic_nic_add_mac(adapter, mac, 0, mac_type); } else { spin_lock(&vf->vlan_list_lock); for (i = 0; i < sriov->num_allowed_vlans; i++) { vlan_id = vf->sriov_vlans[i]; if (vlan_id) - qlcnic_nic_add_mac(adapter, mac, vlan_id); + qlcnic_nic_add_mac(adapter, mac, vlan_id, + mac_type); } spin_unlock(&vf->vlan_list_lock); if (qlcnic_84xx_check(adapter)) - qlcnic_nic_add_mac(adapter, mac, 0); + qlcnic_nic_add_mac(adapter, mac, 0, mac_type); } } @@ -1549,10 +1551,12 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev) (netdev_mc_count(netdev) > ahw->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; } else { - qlcnic_vf_add_mc_list(netdev, bcast_addr); + qlcnic_vf_add_mc_list(netdev, bcast_addr, QLCNIC_BROADCAST_MAC); if (!netdev_mc_empty(netdev)) { + qlcnic_flush_mcast_mac(adapter); netdev_for_each_mc_addr(ha, netdev) - qlcnic_vf_add_mc_list(netdev, ha->addr); + qlcnic_vf_add_mc_list(netdev, ha->addr, + QLCNIC_MULTICAST_MAC); } } @@ -1563,7 +1567,8 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev) mode = VPORT_MISS_MODE_ACCEPT_ALL; } else if (!netdev_uc_empty(netdev)) { netdev_for_each_uc_addr(ha, netdev) - qlcnic_vf_add_mc_list(netdev, ha->addr); + qlcnic_vf_add_mc_list(netdev, ha->addr, + QLCNIC_UNICAST_MAC); } if (adapter->pdev->is_virtfn) { |