mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 10:33:41 +02:00
Merge branch 'gve-improve-rx-buffer-length-management'
Ankit Garg says:
====================
gve: Improve RX buffer length management
This patch series improves the management of the RX buffer length for
the DQO queue format in the gve driver. The goal is to make RX buffer
length config more explicit, easy to change, and performant by default.
We accomplish that in four patches:
1. Currently, the buffer length is implicitly coupled with the header
split setting, which is an unintuitive and restrictive design. The
first patch decouples the RX buffer length from the header split
configuration.
2. The second patch is a preparatory step for third. It converts the XDP
config verification method to use extack for better error reporting.
3. The third patch exposes the `rx_buf_len` parameter to userspace via
ethtool, allowing user to directly view or modify the RX buffer length
if supported by the device.
4. The final patch improves the out-of-the-box RX single stream throughput
by >10% by changing the driver's default behavior to select the
maximum supported RX buffer length advertised by the device during
initialization.
====================
Link: https://patch.msgid.link/20251106192746.243525-1-joshwash@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
d5a9ae217b
|
|
@ -59,8 +59,6 @@
|
|||
|
||||
#define GVE_DEFAULT_RX_BUFFER_SIZE 2048
|
||||
|
||||
#define GVE_MAX_RX_BUFFER_SIZE 4096
|
||||
|
||||
#define GVE_XDP_RX_BUFFER_SIZE_DQO 4096
|
||||
|
||||
#define GVE_DEFAULT_RX_BUFFER_OFFSET 2048
|
||||
|
|
@ -1169,6 +1167,12 @@ static inline bool gve_is_gqi(struct gve_priv *priv)
|
|||
priv->queue_format == GVE_GQI_QPL_FORMAT;
|
||||
}
|
||||
|
||||
static inline bool gve_is_dqo(struct gve_priv *priv)
|
||||
{
|
||||
return priv->queue_format == GVE_DQO_RDA_FORMAT ||
|
||||
priv->queue_format == GVE_DQO_QPL_FORMAT;
|
||||
}
|
||||
|
||||
static inline u32 gve_num_tx_queues(struct gve_priv *priv)
|
||||
{
|
||||
return priv->tx_cfg.num_queues + priv->tx_cfg.num_xdp_queues;
|
||||
|
|
@ -1249,8 +1253,10 @@ void gve_rx_free_rings_gqi(struct gve_priv *priv,
|
|||
struct gve_rx_alloc_rings_cfg *cfg);
|
||||
void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx);
|
||||
void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx);
|
||||
u16 gve_get_pkt_buf_size(const struct gve_priv *priv, bool enable_hplit);
|
||||
bool gve_header_split_supported(const struct gve_priv *priv);
|
||||
int gve_set_rx_buf_len_config(struct gve_priv *priv, u32 rx_buf_len,
|
||||
struct netlink_ext_ack *extack,
|
||||
struct gve_rx_alloc_rings_cfg *rx_alloc_cfg);
|
||||
int gve_set_hsplit_config(struct gve_priv *priv, u8 tcp_data_split,
|
||||
struct gve_rx_alloc_rings_cfg *rx_alloc_cfg);
|
||||
/* rx buffer handling */
|
||||
|
|
|
|||
|
|
@ -987,6 +987,10 @@ static void gve_enable_supported_features(struct gve_priv *priv,
|
|||
dev_info(&priv->pdev->dev,
|
||||
"BUFFER SIZES device option enabled with max_rx_buffer_size of %u, header_buf_size of %u.\n",
|
||||
priv->max_rx_buffer_size, priv->header_buf_size);
|
||||
if (gve_is_dqo(priv) &&
|
||||
priv->max_rx_buffer_size > GVE_DEFAULT_RX_BUFFER_SIZE)
|
||||
priv->rx_cfg.packet_buffer_size =
|
||||
priv->max_rx_buffer_size;
|
||||
}
|
||||
|
||||
/* Read and store ring size ranges given by device */
|
||||
|
|
|
|||
|
|
@ -529,6 +529,8 @@ static void gve_get_ringparam(struct net_device *netdev,
|
|||
cmd->rx_pending = priv->rx_desc_cnt;
|
||||
cmd->tx_pending = priv->tx_desc_cnt;
|
||||
|
||||
kernel_cmd->rx_buf_len = priv->rx_cfg.packet_buffer_size;
|
||||
|
||||
if (!gve_header_split_supported(priv))
|
||||
kernel_cmd->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_UNKNOWN;
|
||||
else if (priv->header_split_enabled)
|
||||
|
|
@ -589,6 +591,12 @@ static int gve_set_ringparam(struct net_device *netdev,
|
|||
int err;
|
||||
|
||||
gve_get_curr_alloc_cfgs(priv, &tx_alloc_cfg, &rx_alloc_cfg);
|
||||
|
||||
err = gve_set_rx_buf_len_config(priv, kernel_cmd->rx_buf_len, extack,
|
||||
&rx_alloc_cfg);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = gve_set_hsplit_config(priv, kernel_cmd->tcp_data_split,
|
||||
&rx_alloc_cfg);
|
||||
if (err)
|
||||
|
|
@ -605,9 +613,9 @@ static int gve_set_ringparam(struct net_device *netdev,
|
|||
return err;
|
||||
} else {
|
||||
/* Set ring params for the next up */
|
||||
priv->header_split_enabled = rx_alloc_cfg.enable_header_split;
|
||||
priv->rx_cfg.packet_buffer_size =
|
||||
rx_alloc_cfg.packet_buffer_size;
|
||||
priv->header_split_enabled = rx_alloc_cfg.enable_header_split;
|
||||
priv->tx_desc_cnt = tx_alloc_cfg.ring_size;
|
||||
priv->rx_desc_cnt = rx_alloc_cfg.ring_size;
|
||||
}
|
||||
|
|
@ -946,7 +954,8 @@ static int gve_get_ts_info(struct net_device *netdev,
|
|||
|
||||
const struct ethtool_ops gve_ethtool_ops = {
|
||||
.supported_coalesce_params = ETHTOOL_COALESCE_USECS,
|
||||
.supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT,
|
||||
.supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT |
|
||||
ETHTOOL_RING_USE_RX_BUF_LEN,
|
||||
.get_drvinfo = gve_get_drvinfo,
|
||||
.get_strings = gve_get_strings,
|
||||
.get_sset_count = gve_get_sset_count,
|
||||
|
|
|
|||
|
|
@ -1707,18 +1707,28 @@ static int gve_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int verify_xdp_configuration(struct net_device *dev)
|
||||
static int gve_verify_xdp_configuration(struct net_device *dev,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct gve_priv *priv = netdev_priv(dev);
|
||||
u16 max_xdp_mtu;
|
||||
|
||||
if (dev->features & NETIF_F_LRO) {
|
||||
netdev_warn(dev, "XDP is not supported when LRO is on.\n");
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"XDP is not supported when LRO is on.");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (priv->header_split_enabled) {
|
||||
netdev_warn(dev, "XDP is not supported when header-data split is enabled.\n");
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"XDP is not supported when header-data split is enabled.");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (priv->rx_cfg.packet_buffer_size != SZ_2K) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack,
|
||||
"XDP is not supported for Rx buf len %d, only %d supported.",
|
||||
priv->rx_cfg.packet_buffer_size, SZ_2K);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
|
@ -1727,17 +1737,20 @@ static int verify_xdp_configuration(struct net_device *dev)
|
|||
max_xdp_mtu -= GVE_RX_PAD;
|
||||
|
||||
if (dev->mtu > max_xdp_mtu) {
|
||||
netdev_warn(dev, "XDP is not supported for mtu %d.\n",
|
||||
dev->mtu);
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack,
|
||||
"XDP is not supported for mtu %d.",
|
||||
dev->mtu);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (priv->rx_cfg.num_queues != priv->tx_cfg.num_queues ||
|
||||
(2 * priv->tx_cfg.num_queues > priv->tx_cfg.max_queues)) {
|
||||
netdev_warn(dev, "XDP load failed: The number of configured RX queues %d should be equal to the number of configured TX queues %d and the number of configured RX/TX queues should be less than or equal to half the maximum number of RX/TX queues %d",
|
||||
priv->rx_cfg.num_queues,
|
||||
priv->tx_cfg.num_queues,
|
||||
netdev_warn(dev,
|
||||
"XDP load failed: The number of configured RX queues %d should be equal to the number of configured TX queues %d and the number of configured RX/TX queues should be less than or equal to half the maximum number of RX/TX queues %d.",
|
||||
priv->rx_cfg.num_queues, priv->tx_cfg.num_queues,
|
||||
priv->tx_cfg.max_queues);
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"XDP load failed: The number of configured RX queues should be equal to the number of configured TX queues and the number of configured RX/TX queues should be less than or equal to half the maximum number of RX/TX queues");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1748,7 +1761,7 @@ static int gve_xdp(struct net_device *dev, struct netdev_bpf *xdp)
|
|||
struct gve_priv *priv = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
err = verify_xdp_configuration(dev);
|
||||
err = gve_verify_xdp_configuration(dev, xdp->extack);
|
||||
if (err)
|
||||
return err;
|
||||
switch (xdp->command) {
|
||||
|
|
@ -2041,14 +2054,6 @@ static void gve_tx_timeout(struct net_device *dev, unsigned int txqueue)
|
|||
priv->tx_timeo_cnt++;
|
||||
}
|
||||
|
||||
u16 gve_get_pkt_buf_size(const struct gve_priv *priv, bool enable_hsplit)
|
||||
{
|
||||
if (enable_hsplit && priv->max_rx_buffer_size >= GVE_MAX_RX_BUFFER_SIZE)
|
||||
return GVE_MAX_RX_BUFFER_SIZE;
|
||||
else
|
||||
return GVE_DEFAULT_RX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
/* Header split is only supported on DQ RDA queue format. If XDP is enabled,
|
||||
* header split is not allowed.
|
||||
*/
|
||||
|
|
@ -2058,6 +2063,38 @@ bool gve_header_split_supported(const struct gve_priv *priv)
|
|||
priv->queue_format == GVE_DQO_RDA_FORMAT && !priv->xdp_prog;
|
||||
}
|
||||
|
||||
int gve_set_rx_buf_len_config(struct gve_priv *priv, u32 rx_buf_len,
|
||||
struct netlink_ext_ack *extack,
|
||||
struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
|
||||
{
|
||||
u32 old_rx_buf_len = rx_alloc_cfg->packet_buffer_size;
|
||||
|
||||
if (rx_buf_len == old_rx_buf_len)
|
||||
return 0;
|
||||
|
||||
/* device options may not always contain support for 4K buffers */
|
||||
if (!gve_is_dqo(priv) || priv->max_rx_buffer_size < SZ_4K) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Modifying Rx buf len is not supported");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (priv->xdp_prog && rx_buf_len != SZ_2K) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Rx buf len can only be 2048 when XDP is on");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rx_buf_len != SZ_2K && rx_buf_len != SZ_4K) {
|
||||
NL_SET_ERR_MSG_MOD(extack,
|
||||
"Rx buf len can only be 2048 or 4096");
|
||||
return -EINVAL;
|
||||
}
|
||||
rx_alloc_cfg->packet_buffer_size = rx_buf_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gve_set_hsplit_config(struct gve_priv *priv, u8 tcp_data_split,
|
||||
struct gve_rx_alloc_rings_cfg *rx_alloc_cfg)
|
||||
{
|
||||
|
|
@ -2080,8 +2117,6 @@ int gve_set_hsplit_config(struct gve_priv *priv, u8 tcp_data_split,
|
|||
return 0;
|
||||
|
||||
rx_alloc_cfg->enable_header_split = enable_hdr_split;
|
||||
rx_alloc_cfg->packet_buffer_size =
|
||||
gve_get_pkt_buf_size(priv, enable_hdr_split);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user