ixgbe: fix bug when EITR=0 causing no writebacks
[deliverable/linux.git] / drivers / net / ixgbe / ixgbe_ethtool.c
index 7949a446e4c7673f2587ec6da3b33c1a06574cae..5f8c6ab7a98ab2581aa26db50d21554e7a78a909 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/types.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
@@ -1853,6 +1854,26 @@ static void ixgbe_diag_test(struct net_device *netdev,
                if (ixgbe_link_test(adapter, &data[4]))
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
+               if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
+                       int i;
+                       for (i = 0; i < adapter->num_vfs; i++) {
+                               if (adapter->vfinfo[i].clear_to_send) {
+                                       netdev_warn(netdev, "%s",
+                                                   "offline diagnostic is not "
+                                                   "supported when VFs are "
+                                                   "present\n");
+                                       data[0] = 1;
+                                       data[1] = 1;
+                                       data[2] = 1;
+                                       data[3] = 1;
+                                       eth_test->flags |= ETH_TEST_FL_FAILED;
+                                       clear_bit(__IXGBE_TESTING,
+                                                 &adapter->state);
+                                       goto skip_ol_tests;
+                               }
+                       }
+               }
+
                if (if_running)
                        /* indicate we're in test mode */
                        dev_close(netdev);
@@ -1908,6 +1929,7 @@ skip_loopback:
 
                clear_bit(__IXGBE_TESTING, &adapter->state);
        }
+skip_ol_tests:
        msleep_interruptible(4 * 1000);
 }
 
@@ -2057,12 +2079,32 @@ static int ixgbe_get_coalesce(struct net_device *netdev,
        return 0;
 }
 
+/*
+ * this function must be called before setting the new value of
+ * rx_itr_setting
+ */
+static bool ixgbe_reenable_rsc(struct ixgbe_adapter *adapter,
+                               struct ethtool_coalesce *ec)
+{
+       /* check the old value and enable RSC if necessary */
+       if ((adapter->rx_itr_setting == 0) &&
+           (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)) {
+               adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
+               adapter->netdev->features |= NETIF_F_LRO;
+               DPRINTK(PROBE, INFO, "rx-usecs set to %d, re-enabling RSC\n",
+                       ec->rx_coalesce_usecs);
+               return true;
+       }
+       return false;
+}
+
 static int ixgbe_set_coalesce(struct net_device *netdev,
                               struct ethtool_coalesce *ec)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_q_vector *q_vector;
        int i;
+       bool need_reset = false;
 
        /* don't accept tx specific changes if we've got mixed RxTx vectors */
        if (adapter->q_vector[0]->txr_count && adapter->q_vector[0]->rxr_count
@@ -2073,11 +2115,20 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                adapter->tx_ring[0]->work_limit = ec->tx_max_coalesced_frames_irq;
 
        if (ec->rx_coalesce_usecs > 1) {
+               u32 max_int;
+               if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
+                       max_int = IXGBE_MAX_RSC_INT_RATE;
+               else
+                       max_int = IXGBE_MAX_INT_RATE;
+
                /* check the limits */
-               if ((1000000/ec->rx_coalesce_usecs > IXGBE_MAX_INT_RATE) ||
+               if ((1000000/ec->rx_coalesce_usecs > max_int) ||
                    (1000000/ec->rx_coalesce_usecs < IXGBE_MIN_INT_RATE))
                        return -EINVAL;
 
+               /* check the old value and enable RSC if necessary */
+               need_reset = ixgbe_reenable_rsc(adapter, ec);
+
                /* store the value in ints/second */
                adapter->rx_eitr_param = 1000000/ec->rx_coalesce_usecs;
 
@@ -2086,6 +2137,9 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                /* clear the lower bit as its used for dynamic state */
                adapter->rx_itr_setting &= ~1;
        } else if (ec->rx_coalesce_usecs == 1) {
+               /* check the old value and enable RSC if necessary */
+               need_reset = ixgbe_reenable_rsc(adapter, ec);
+
                /* 1 means dynamic mode */
                adapter->rx_eitr_param = 20000;
                adapter->rx_itr_setting = 1;
@@ -2094,14 +2148,30 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                 * any other value means disable eitr, which is best
                 * served by setting the interrupt rate very high
                 */
-               if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)
-                       adapter->rx_eitr_param = IXGBE_MAX_RSC_INT_RATE;
-               else
-                       adapter->rx_eitr_param = IXGBE_MAX_INT_RATE;
+               adapter->rx_eitr_param = IXGBE_MAX_INT_RATE;
                adapter->rx_itr_setting = 0;
+
+               /*
+                * if hardware RSC is enabled, disable it when
+                * setting low latency mode, to avoid errata, assuming
+                * that when the user set low latency mode they want
+                * it at the cost of anything else
+                */
+               if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
+                       adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
+                       netdev->features &= ~NETIF_F_LRO;
+                       DPRINTK(PROBE, INFO,
+                               "rx-usecs set to 0, disabling RSC\n");
+
+                       need_reset = true;
+               }
        }
 
        if (ec->tx_coalesce_usecs > 1) {
+               /*
+                * don't have to worry about max_int as above because
+                * tx vectors don't do hardware RSC (an rx function)
+                */
                /* check the limits */
                if ((1000000/ec->tx_coalesce_usecs > IXGBE_MAX_INT_RATE) ||
                    (1000000/ec->tx_coalesce_usecs < IXGBE_MIN_INT_RATE))
@@ -2145,6 +2215,18 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                ixgbe_write_eitr(q_vector);
        }
 
+       /*
+        * do reset here at the end to make sure EITR==0 case is handled
+        * correctly w.r.t stopping tx, and changing TXDCTL.WTHRESH settings
+        * also locks in RSC enable/disable which requires reset
+        */
+       if (need_reset) {
+               if (netif_running(netdev))
+                       ixgbe_reinit_locked(adapter);
+               else
+                       ixgbe_reset(adapter);
+       }
+
        return 0;
 }
 
@@ -2156,10 +2238,26 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
        ethtool_op_set_flags(netdev, data);
 
        /* if state changes we need to update adapter->flags and reset */
-       if ((!!(data & ETH_FLAG_LRO)) != 
-           (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) {
-               adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
-               need_reset = true;
+       if (adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) {
+               /*
+                * cast both to bool and verify if they are set the same
+                * but only enable RSC if itr is non-zero, as
+                * itr=0 and RSC are mutually exclusive
+                */
+               if (((!!(data & ETH_FLAG_LRO)) !=
+                    (!!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))) &&
+                   adapter->rx_itr_setting) {
+                       adapter->flags2 ^= IXGBE_FLAG2_RSC_ENABLED;
+                       switch (adapter->hw.mac.type) {
+                       case ixgbe_mac_82599EB:
+                               need_reset = true;
+                               break;
+                       default:
+                               break;
+                       }
+               } else if (!adapter->rx_itr_setting) {
+                       netdev->features &= ~ETH_FLAG_LRO;
+               }
        }
 
        /*
This page took 0.028982 seconds and 5 git commands to generate.