]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/net/cxgb4vf/cxgb4vf_main.c
Merge branches 'x86-fixes-for-linus', 'perf-fixes-for-linus' and 'sched-fixes-for...
[linux-beck.git] / drivers / net / cxgb4vf / cxgb4vf_main.c
index 4487b1ace660f168734fb910e7bce48287531e8f..d887a76cd39dad036eb289d88f5a666d898eb63a 100644 (file)
@@ -753,7 +753,9 @@ static int cxgb4vf_open(struct net_device *dev)
        if (err)
                return err;
        set_bit(pi->port_id, &adapter->open_device_map);
-       link_start(dev);
+       err = link_start(dev);
+       if (err)
+               return err;
        netif_tx_start_all_queues(dev);
        return 0;
 }
@@ -814,40 +816,48 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev)
 }
 
 /*
- * Collect up to maxaddrs worth of a netdevice's unicast addresses into an
- * array of addrss pointers and return the number collected.
+ * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting
+ * at a specified offset within the list, into an array of addrss pointers and
+ * return the number collected.
  */
-static inline int collect_netdev_uc_list_addrs(const struct net_device *dev,
-                                              const u8 **addr,
-                                              unsigned int maxaddrs)
+static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev,
+                                                       const u8 **addr,
+                                                       unsigned int offset,
+                                                       unsigned int maxaddrs)
 {
+       unsigned int index = 0;
        unsigned int naddr = 0;
        const struct netdev_hw_addr *ha;
 
-       for_each_dev_addr(dev, ha) {
-               addr[naddr++] = ha->addr;
-               if (naddr >= maxaddrs)
-                       break;
-       }
+       for_each_dev_addr(dev, ha)
+               if (index++ >= offset) {
+                       addr[naddr++] = ha->addr;
+                       if (naddr >= maxaddrs)
+                               break;
+               }
        return naddr;
 }
 
 /*
- * Collect up to maxaddrs worth of a netdevice's multicast addresses into an
- * array of addrss pointers and return the number collected.
+ * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting
+ * at a specified offset within the list, into an array of addrss pointers and
+ * return the number collected.
  */
-static inline int collect_netdev_mc_list_addrs(const struct net_device *dev,
-                                              const u8 **addr,
-                                              unsigned int maxaddrs)
+static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev,
+                                                       const u8 **addr,
+                                                       unsigned int offset,
+                                                       unsigned int maxaddrs)
 {
+       unsigned int index = 0;
        unsigned int naddr = 0;
        const struct netdev_hw_addr *ha;
 
-       netdev_for_each_mc_addr(ha, dev) {
-               addr[naddr++] = ha->addr;
-               if (naddr >= maxaddrs)
-                       break;
-       }
+       netdev_for_each_mc_addr(ha, dev)
+               if (index++ >= offset) {
+                       addr[naddr++] = ha->addr;
+                       if (naddr >= maxaddrs)
+                               break;
+               }
        return naddr;
 }
 
@@ -860,16 +870,20 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
        u64 mhash = 0;
        u64 uhash = 0;
        bool free = true;
-       u16 filt_idx[7];
+       unsigned int offset, naddr;
        const u8 *addr[7];
-       int ret, naddr = 0;
+       int ret;
        const struct port_info *pi = netdev_priv(dev);
 
        /* first do the secondary unicast addresses */
-       naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr));
-       if (naddr > 0) {
+       for (offset = 0; ; offset += naddr) {
+               naddr = collect_netdev_uc_list_addrs(dev, addr, offset,
+                                                    ARRAY_SIZE(addr));
+               if (naddr == 0)
+                       break;
+
                ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
-                                         naddr, addr, filt_idx, &uhash, sleep);
+                                         naddr, addr, NULL, &uhash, sleep);
                if (ret < 0)
                        return ret;
 
@@ -877,12 +891,17 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
        }
 
        /* next set up the multicast addresses */
-       naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr));
-       if (naddr > 0) {
+       for (offset = 0; ; offset += naddr) {
+               naddr = collect_netdev_mc_list_addrs(dev, addr, offset,
+                                                    ARRAY_SIZE(addr));
+               if (naddr == 0)
+                       break;
+
                ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
-                                         naddr, addr, filt_idx, &mhash, sleep);
+                                         naddr, addr, NULL, &mhash, sleep);
                if (ret < 0)
                        return ret;
+               free = false;
        }
 
        return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
@@ -2062,6 +2081,22 @@ static int adap_init0(struct adapter *adapter)
                return err;
        }
 
+       /*
+        * Some environments do not properly handle PCIE FLRs -- e.g. in Linux
+        * 2.6.31 and later we can't call pci_reset_function() in order to
+        * issue an FLR because of a self- deadlock on the device semaphore.
+        * Meanwhile, the OS infrastructure doesn't issue FLRs in all the
+        * cases where they're needed -- for instance, some versions of KVM
+        * fail to reset "Assigned Devices" when the VM reboots.  Therefore we
+        * use the firmware based reset in order to reset any per function
+        * state.
+        */
+       err = t4vf_fw_reset(adapter);
+       if (err < 0) {
+               dev_err(adapter->pdev_dev, "FW reset failed: err=%d\n", err);
+               return err;
+       }
+
        /*
         * Grab basic operational parameters.  These will predominantly have
         * been set up by the Physical Function Driver or will be hard coded