e1000e: Add interrupt moderation run-time ethtool interface
authorAuke Kok <auke-jan.h.kok@intel.com>
Wed, 23 Apr 2008 18:09:08 +0000 (11:09 -0700)
committerJeff Garzik <jgarzik@redhat.com>
Fri, 25 Apr 2008 06:07:12 +0000 (02:07 -0400)
The ethtool -c / -C interface can now be used to modify the
irq moderation algorithm. This change does not require an
adapter reset and can thus be used at all times. The adapter
only supports changing/reading rx-usecs which has special
values for 0, 1 and 3:

0 - no irq moderation whatsoever
1 - normal moderation favoring regular mixed traffic (default)
3 - best attempt at low latency possible at cost of CPU

For values between 10 and 10000 the rx-usecs defines "the minimum
time between successive irqs" in usec, unlike the module parameter.

Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
drivers/net/e1000e/e1000.h
drivers/net/e1000e/ethtool.c

index 4d3d1c2991c9a52d461e930d7cd686ab89ada14b..79a426feffb7a8ca45ff3cdcacfb938d42b6297a 100644 (file)
@@ -70,6 +70,9 @@ struct e1000_info;
 #define E1000_MAX_RXD                  4096
 #define E1000_MIN_RXD                  80
 
+#define E1000_MIN_ITR_USECS            10 /* 100000 irq/sec */
+#define E1000_MAX_ITR_USECS            10000 /* 100    irq/sec */
+
 /* Early Receive defines */
 #define E1000_ERT_2048                 0x100
 
index c894a6f03bb454a43c7f782d4d53cfa8b2e705bc..ce045acce63e99b79685e291a8993e3acd940508 100644 (file)
@@ -1770,6 +1770,47 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
        return 0;
 }
 
+static int e1000_get_coalesce(struct net_device *netdev,
+                             struct ethtool_coalesce *ec)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+
+       if (adapter->itr_setting <= 3)
+               ec->rx_coalesce_usecs = adapter->itr_setting;
+       else
+               ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting;
+
+       return 0;
+}
+
+static int e1000_set_coalesce(struct net_device *netdev,
+                             struct ethtool_coalesce *ec)
+{
+       struct e1000_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+
+       if ((ec->rx_coalesce_usecs > E1000_MAX_ITR_USECS) ||
+           ((ec->rx_coalesce_usecs > 3) &&
+            (ec->rx_coalesce_usecs < E1000_MIN_ITR_USECS)) ||
+           (ec->rx_coalesce_usecs == 2))
+               return -EINVAL;
+
+       if (ec->rx_coalesce_usecs <= 3) {
+               adapter->itr = 20000;
+               adapter->itr_setting = ec->rx_coalesce_usecs;
+       } else {
+               adapter->itr = (1000000 / ec->rx_coalesce_usecs);
+               adapter->itr_setting = adapter->itr & ~3;
+       }
+
+       if (adapter->itr_setting != 0)
+               ew32(ITR, 1000000000 / (adapter->itr * 256));
+       else
+               ew32(ITR, 0);
+
+       return 0;
+}
+
 static int e1000_nway_reset(struct net_device *netdev)
 {
        struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1845,6 +1886,8 @@ static const struct ethtool_ops e1000_ethtool_ops = {
        .phys_id                = e1000_phys_id,
        .get_ethtool_stats      = e1000_get_ethtool_stats,
        .get_sset_count         = e1000e_get_sset_count,
+       .get_coalesce           = e1000_get_coalesce,
+       .set_coalesce           = e1000_set_coalesce,
 };
 
 void e1000e_set_ethtool_ops(struct net_device *netdev)