ixgbe: Implement PCI SR-IOV sysfs callback operation
[firefly-linux-kernel-4.4.55.git] / drivers / net / ethernet / intel / ixgbe / ixgbe_sriov.c
index 8a284ac4b4009b590e2dd39580b0370dd144ad56..ee3507f0ea530c309475c9799f2b2067e998501f 100644 (file)
@@ -207,11 +207,12 @@ static bool ixgbe_vfs_are_assigned(struct ixgbe_adapter *adapter)
 }
 
 #endif /* #ifdef CONFIG_PCI_IOV */
-void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
+int ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        u32 gpie;
        u32 vmdctl;
+       int rss;
 
        /* set num VFs to 0 to prevent access to vfinfo */
        adapter->num_vfs = 0;
@@ -226,7 +227,7 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
 
        /* if SR-IOV is already disabled then there is nothing to do */
        if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
-               return;
+               return 0;
 
 #ifdef CONFIG_PCI_IOV
        /*
@@ -236,7 +237,7 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
         */
        if (ixgbe_vfs_are_assigned(adapter)) {
                e_dev_warn("Unloading driver while VFs are assigned - VFs will not be deallocated\n");
-               return;
+               return -EPERM;
        }
        /* disable iov and allow time for transactions to clear */
        pci_disable_sriov(adapter->pdev);
@@ -259,10 +260,94 @@ void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
                adapter->flags &= ~IXGBE_FLAG_VMDQ_ENABLED;
        adapter->ring_feature[RING_F_VMDQ].offset = 0;
 
+       rss = min_t(int, IXGBE_MAX_RSS_INDICES, num_online_cpus());
+       adapter->ring_feature[RING_F_RSS].limit = rss;
+
        /* take a breather then clean up driver data */
        msleep(100);
 
        adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
+       return 0;
+}
+
+static int ixgbe_pci_sriov_enable(struct pci_dev *dev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+       struct ixgbe_adapter *adapter = pci_get_drvdata(dev);
+       int err = 0;
+       int i;
+       int pre_existing_vfs = pci_num_vf(dev);
+
+       if (pre_existing_vfs && pre_existing_vfs != num_vfs)
+               err = ixgbe_disable_sriov(adapter);
+       else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
+               goto out;
+
+       if (err)
+               goto err_out;
+
+       /* While the SR-IOV capability structure reports total VFs to be
+        * 64 we limit the actual number that can be allocated to 63 so
+        * that some transmit/receive resources can be reserved to the
+        * PF.  The PCI bus driver already checks for other values out of
+        * range.
+        */
+       if (num_vfs > 63) {
+               err = -EPERM;
+               goto err_out;
+       }
+
+       adapter->num_vfs = num_vfs;
+
+       err = __ixgbe_enable_sriov(adapter);
+       if (err)
+               goto err_out;
+
+       for (i = 0; i < adapter->num_vfs; i++)
+               ixgbe_vf_configuration(dev, (i | 0x10000000));
+
+       err = pci_enable_sriov(dev, num_vfs);
+       if (err) {
+               e_dev_warn("Failed to enable PCI sriov: %d\n", err);
+               goto err_out;
+       }
+       ixgbe_sriov_reinit(adapter);
+
+out:
+       return num_vfs;
+
+err_out:
+       return err;
+#endif
+       return 0;
+}
+
+static int ixgbe_pci_sriov_disable(struct pci_dev *dev)
+{
+       struct ixgbe_adapter *adapter = pci_get_drvdata(dev);
+       int err;
+       u32 current_flags = adapter->flags;
+
+       err = ixgbe_disable_sriov(adapter);
+
+       /* Only reinit if no error and state changed */
+       if (!err && current_flags != adapter->flags) {
+               /* ixgbe_disable_sriov() doesn't clear VMDQ flag */
+               adapter->flags &= ~IXGBE_FLAG_VMDQ_ENABLED;
+#ifdef CONFIG_PCI_IOV
+               ixgbe_sriov_reinit(adapter);
+#endif
+       }
+
+       return err;
+}
+
+int ixgbe_pci_sriov_configure(struct pci_dev *dev, int num_vfs)
+{
+       if (num_vfs == 0)
+               return ixgbe_pci_sriov_disable(dev);
+       else
+               return ixgbe_pci_sriov_enable(dev, num_vfs);
 }
 
 static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,