qlcnic: Support atomic commands
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / qlogic / qlcnic / qlcnic_hw.c
index f89cc7a3fe6c545702de105308e44490b530302e..ddc130b23378c6be4bcd2aae31a6659eeae7761a 100644 (file)
@@ -496,7 +496,7 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr)
        return 0;
 }
 
-void qlcnic_set_multi(struct net_device *netdev)
+void __qlcnic_set_multi(struct net_device *netdev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct netdev_hw_addr *ha;
@@ -508,7 +508,8 @@ void qlcnic_set_multi(struct net_device *netdev)
        if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
                return;
 
-       qlcnic_nic_add_mac(adapter, adapter->mac_addr);
+       if (!qlcnic_sriov_vf_check(adapter))
+               qlcnic_nic_add_mac(adapter, adapter->mac_addr);
        qlcnic_nic_add_mac(adapter, bcast_addr);
 
        if (netdev->flags & IFF_PROMISC) {
@@ -523,23 +524,53 @@ void qlcnic_set_multi(struct net_device *netdev)
                goto send_fw_cmd;
        }
 
-       if (!netdev_mc_empty(netdev)) {
+       if (!netdev_mc_empty(netdev) && !qlcnic_sriov_vf_check(adapter)) {
                netdev_for_each_mc_addr(ha, netdev) {
                        qlcnic_nic_add_mac(adapter, ha->addr);
                }
        }
 
+       if (qlcnic_sriov_vf_check(adapter))
+               qlcnic_vf_add_mc_list(netdev);
+
 send_fw_cmd:
-       if (mode == VPORT_MISS_MODE_ACCEPT_ALL && !adapter->fdb_mac_learn) {
-               qlcnic_alloc_lb_filters_mem(adapter);
-               adapter->drv_mac_learn = true;
-       } else {
-               adapter->drv_mac_learn = false;
+       if (!qlcnic_sriov_vf_check(adapter)) {
+               if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
+                   !adapter->fdb_mac_learn) {
+                       qlcnic_alloc_lb_filters_mem(adapter);
+                       adapter->drv_mac_learn = true;
+               } else {
+                       adapter->drv_mac_learn = false;
+               }
        }
 
        qlcnic_nic_set_promisc(adapter, mode);
 }
 
+void qlcnic_set_multi(struct net_device *netdev)
+{
+       struct qlcnic_adapter *adapter = netdev_priv(netdev);
+       struct netdev_hw_addr *ha;
+       struct qlcnic_mac_list_s *cur;
+
+       if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
+               return;
+       if (qlcnic_sriov_vf_check(adapter)) {
+               if (!netdev_mc_empty(netdev)) {
+                       netdev_for_each_mc_addr(ha, netdev) {
+                               cur = kzalloc(sizeof(struct qlcnic_mac_list_s),
+                                             GFP_ATOMIC);
+                               memcpy(cur->mac_addr,
+                                      ha->addr, ETH_ALEN);
+                               list_add_tail(&cur->list, &adapter->vf_mc_list);
+                       }
+               }
+               qlcnic_sriov_vf_schedule_multi(adapter->netdev);
+               return;
+       }
+       __qlcnic_set_multi(netdev);
+}
+
 int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
 {
        struct qlcnic_nic_req req;