Commit 6081ac20 authored by Tao Liu's avatar Tao Liu Committed by David S. Miller
Browse files

gve: Add tx|rx-coalesce-usec for DQO



Adding ethtool support for changing rx-coalesce-usec and tx-coalesce-usec
when using the DQO queue format.

Signed-off-by: default avatarTao Liu <xliutaox@google.com>
Signed-off-by: default avatarJeroen de Borst <jeroendb@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2c919835
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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 {
+17 −5
Original line number Diff line number Diff line
@@ -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_ */
+61 −0
Original line number Diff line number Diff line
@@ -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,
+9 −6
Original line number Diff line number Diff line
@@ -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)