OSDN Git Service

gve: Add tx|rx-coalesce-usec for DQO
authorTao Liu <xliutaox@google.com>
Thu, 16 Dec 2021 00:46:52 +0000 (16:46 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 16 Dec 2021 10:41:54 +0000 (10:41 +0000)
Adding ethtool support for changing rx-coalesce-usec and tx-coalesce-usec
when using the DQO queue format.

Signed-off-by: Tao Liu <xliutaox@google.com>
Signed-off-by: Jeroen de Borst <jeroendb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/google/gve/gve.h
drivers/net/ethernet/google/gve/gve_dqo.h
drivers/net/ethernet/google/gve/gve_ethtool.c
drivers/net/ethernet/google/gve/gve_main.c

index 950dff7..5f5d4f7 100644 (file)
@@ -584,6 +584,10 @@ struct gve_priv {
        int data_buffer_size_dqo;
 
        enum gve_queue_format queue_format;
+
+       /* Interrupt coalescing settings */
+       u32 tx_coalesce_usecs;
+       u32 rx_coalesce_usecs;
 };
 
 enum gve_service_task_flags_bit {
index b2e2fb0..1eb4d5f 100644 (file)
@@ -18,6 +18,7 @@
 
 #define GVE_TX_IRQ_RATELIMIT_US_DQO 50
 #define GVE_RX_IRQ_RATELIMIT_US_DQO 20
+#define GVE_MAX_ITR_INTERVAL_DQO (GVE_ITR_INTERVAL_DQO_MASK * 2)
 
 /* Timeout in seconds to wait for a reinjection completion after receiving
  * its corresponding miss completion.
@@ -54,17 +55,17 @@ gve_tx_put_doorbell_dqo(const struct gve_priv *priv,
 }
 
 /* Builds register value to write to DQO IRQ doorbell to enable with specified
- * ratelimit.
+ * ITR interval.
  */
-static inline u32 gve_set_itr_ratelimit_dqo(u32 ratelimit_us)
+static inline u32 gve_setup_itr_interval_dqo(u32 interval_us)
 {
        u32 result = GVE_ITR_ENABLE_BIT_DQO;
 
        /* Interval has 2us granularity. */
-       ratelimit_us >>= 1;
+       interval_us >>= 1;
 
-       ratelimit_us &= GVE_ITR_INTERVAL_DQO_MASK;
-       result |= (ratelimit_us << GVE_ITR_INTERVAL_DQO_SHIFT);
+       interval_us &= GVE_ITR_INTERVAL_DQO_MASK;
+       result |= (interval_us << GVE_ITR_INTERVAL_DQO_SHIFT);
 
        return result;
 }
@@ -78,4 +79,15 @@ gve_write_irq_doorbell_dqo(const struct gve_priv *priv,
        iowrite32(val, &priv->db_bar2[index]);
 }
 
+/* Sets interrupt throttling interval and enables interrupt
+ * by writing to IRQ doorbell.
+ */
+static inline void
+gve_set_itr_coalesce_usecs_dqo(struct gve_priv *priv,
+                              struct gve_notify_block *block,
+                              u32 usecs)
+{
+       gve_write_irq_doorbell_dqo(priv, block,
+                                  gve_setup_itr_interval_dqo(usecs));
+}
 #endif /* _GVE_DQO_H_ */
index e0815bb..50b3849 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/rtnetlink.h>
 #include "gve.h"
 #include "gve_adminq.h"
+#include "gve_dqo.h"
 
 static void gve_get_drvinfo(struct net_device *netdev,
                            struct ethtool_drvinfo *info)
@@ -540,7 +541,65 @@ static int gve_get_link_ksettings(struct net_device *netdev,
        return err;
 }
 
+static int gve_get_coalesce(struct net_device *netdev,
+                           struct ethtool_coalesce *ec,
+                           struct kernel_ethtool_coalesce *kernel_ec,
+                           struct netlink_ext_ack *extack)
+{
+       struct gve_priv *priv = netdev_priv(netdev);
+
+       if (gve_is_gqi(priv))
+               return -EOPNOTSUPP;
+       ec->tx_coalesce_usecs = priv->tx_coalesce_usecs;
+       ec->rx_coalesce_usecs = priv->rx_coalesce_usecs;
+
+       return 0;
+}
+
+static int gve_set_coalesce(struct net_device *netdev,
+                           struct ethtool_coalesce *ec,
+                           struct kernel_ethtool_coalesce *kernel_ec,
+                           struct netlink_ext_ack *extack)
+{
+       struct gve_priv *priv = netdev_priv(netdev);
+       u32 tx_usecs_orig = priv->tx_coalesce_usecs;
+       u32 rx_usecs_orig = priv->rx_coalesce_usecs;
+       int idx;
+
+       if (gve_is_gqi(priv))
+               return -EOPNOTSUPP;
+
+       if (ec->tx_coalesce_usecs > GVE_MAX_ITR_INTERVAL_DQO ||
+           ec->rx_coalesce_usecs > GVE_MAX_ITR_INTERVAL_DQO)
+               return -EINVAL;
+       priv->tx_coalesce_usecs = ec->tx_coalesce_usecs;
+       priv->rx_coalesce_usecs = ec->rx_coalesce_usecs;
+
+       if (tx_usecs_orig != priv->tx_coalesce_usecs) {
+               for (idx = 0; idx < priv->tx_cfg.num_queues; idx++) {
+                       int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx);
+                       struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+                       gve_set_itr_coalesce_usecs_dqo(priv, block,
+                                                      priv->tx_coalesce_usecs);
+               }
+       }
+
+       if (rx_usecs_orig != priv->rx_coalesce_usecs) {
+               for (idx = 0; idx < priv->rx_cfg.num_queues; idx++) {
+                       int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx);
+                       struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx];
+
+                       gve_set_itr_coalesce_usecs_dqo(priv, block,
+                                                      priv->rx_coalesce_usecs);
+               }
+       }
+
+       return 0;
+}
+
 const struct ethtool_ops gve_ethtool_ops = {
+       .supported_coalesce_params = ETHTOOL_COALESCE_USECS,
        .get_drvinfo = gve_get_drvinfo,
        .get_strings = gve_get_strings,
        .get_sset_count = gve_get_sset_count,
@@ -550,6 +609,8 @@ const struct ethtool_ops gve_ethtool_ops = {
        .set_channels = gve_set_channels,
        .get_channels = gve_get_channels,
        .get_link = ethtool_op_get_link,
+       .get_coalesce = gve_get_coalesce,
+       .set_coalesce = gve_set_coalesce,
        .get_ringparam = gve_get_ringparam,
        .reset = gve_user_reset,
        .get_tunable = gve_get_tunable,
index e545618..f7f65c4 100644 (file)
@@ -1113,9 +1113,8 @@ static void gve_turnup(struct gve_priv *priv)
                if (gve_is_gqi(priv)) {
                        iowrite32be(0, gve_irq_doorbell(priv, block));
                } else {
-                       u32 val = gve_set_itr_ratelimit_dqo(GVE_TX_IRQ_RATELIMIT_US_DQO);
-
-                       gve_write_irq_doorbell_dqo(priv, block, val);
+                       gve_set_itr_coalesce_usecs_dqo(priv, block,
+                                                      priv->tx_coalesce_usecs);
                }
        }
        for (idx = 0; idx < priv->rx_cfg.num_queues; idx++) {
@@ -1126,9 +1125,8 @@ static void gve_turnup(struct gve_priv *priv)
                if (gve_is_gqi(priv)) {
                        iowrite32be(0, gve_irq_doorbell(priv, block));
                } else {
-                       u32 val = gve_set_itr_ratelimit_dqo(GVE_RX_IRQ_RATELIMIT_US_DQO);
-
-                       gve_write_irq_doorbell_dqo(priv, block, val);
+                       gve_set_itr_coalesce_usecs_dqo(priv, block,
+                                                      priv->rx_coalesce_usecs);
                }
        }
 
@@ -1425,6 +1423,11 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device)
        dev_info(&priv->pdev->dev, "Max TX queues %d, Max RX queues %d\n",
                 priv->tx_cfg.max_queues, priv->rx_cfg.max_queues);
 
+       if (!gve_is_gqi(priv)) {
+               priv->tx_coalesce_usecs = GVE_TX_IRQ_RATELIMIT_US_DQO;
+               priv->rx_coalesce_usecs = GVE_RX_IRQ_RATELIMIT_US_DQO;
+       }
+
 setup_device:
        err = gve_setup_device_resources(priv);
        if (!err)