From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, kuba@kernel.org, edumazet@google.com,
pabeni@redhat.com, horms@kernel.org, andrew@lunn.ch,
Willem de Bruijn <willemb@google.com>
Subject: [PATCH net-next 1/7] net: ethtool: add hardware pacing offload support to rings
Date: Mon, 6 Jul 2026 09:34:03 -0400 [thread overview]
Message-ID: <20260706133433.3142805-2-willemdebruijn.kernel@gmail.com> (raw)
In-Reply-To: <20260706133433.3142805-1-willemdebruijn.kernel@gmail.com>
From: Willem de Bruijn <willemb@google.com>
Add two ethtool rings operations:
- get pacing offload horizon: active and max
- set pacing offload horizon: active
Replace u64 max_pacing_offload_horizon with u32 active and max fields.
This occupies the same original 8 bytes. Reduce precision from nsec to
usec, which is sufficient.
Update the FQ scheduler to test against the active limit instead of
max. It is the administrator responsibility to set the active limit
before installing FQ.
Assisted-by: Gemini:gemini-3
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
Documentation/netlink/specs/ethtool.yaml | 6 ++++
.../networking/net_cachelines/net_device.rst | 3 +-
include/linux/ethtool.h | 6 ++++
include/linux/netdevice.h | 6 ++--
.../uapi/linux/ethtool_netlink_generated.h | 2 ++
net/core/rtnetlink.c | 2 +-
net/ethtool/common.c | 3 ++
net/ethtool/netlink.h | 2 +-
net/ethtool/rings.c | 30 +++++++++++++++++--
net/sched/sch_fq.c | 3 +-
10 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml
index 5dd4d1b5d94b..48f43dda2e6e 100644
--- a/Documentation/netlink/specs/ethtool.yaml
+++ b/Documentation/netlink/specs/ethtool.yaml
@@ -448,6 +448,12 @@ attribute-sets:
-
name: hds-thresh-max
type: u32
+ -
+ name: pacing-offload-horizon
+ type: u32
+ -
+ name: pacing-offload-horizon-max
+ type: u32
-
name: mm-stat
diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst
index 512f6d6fa3d8..3b9ce1c6e105 100644
--- a/Documentation/networking/net_cachelines/net_device.rst
+++ b/Documentation/networking/net_cachelines/net_device.rst
@@ -183,7 +183,8 @@ struct devlink_port* devlink_port
struct dpll_pin* dpll_pin
struct hlist_head page_pools
struct dim_irq_moder* irq_moder
-u64 max_pacing_offload_horizon
+u32 pacing_offload_horizon
+u32 max_pacing_offload_horizon
struct_napi_config* napi_config
unsigned_long gro_flush_timeout
u32 napi_defer_hard_irqs
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index 5d491a98265e..5759be3fcd7f 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -85,6 +85,8 @@ enum {
* @tx_push_buf_max_len: Maximum allowed size of TX push buffer
* @hds_thresh: Packet size threshold for header data split (HDS)
* @hds_thresh_max: Maximum supported setting for @hds_threshold
+ * @pacing_offload_horizon: pacing offload horizon value in usec.
+ * @max_pacing_offload_horizon: max pacing offload horizon value in usec.
*
*/
struct kernel_ethtool_ringparam {
@@ -97,6 +99,8 @@ struct kernel_ethtool_ringparam {
u32 tx_push_buf_max_len;
u32 hds_thresh;
u32 hds_thresh_max;
+ u32 pacing_offload_horizon;
+ u32 max_pacing_offload_horizon;
};
/**
@@ -108,6 +112,7 @@ struct kernel_ethtool_ringparam {
* @ETHTOOL_RING_USE_TX_PUSH_BUF_LEN: capture for setting tx_push_buf_len
* @ETHTOOL_RING_USE_TCP_DATA_SPLIT: capture for setting tcp_data_split
* @ETHTOOL_RING_USE_HDS_THRS: capture for setting header-data-split-thresh
+ * @ETHTOOL_RING_USE_PACING_OFFLOAD_HORIZON: capture for setting pacing offload horizon
*/
enum ethtool_supported_ring_param {
ETHTOOL_RING_USE_RX_BUF_LEN = BIT(0),
@@ -117,6 +122,7 @@ enum ethtool_supported_ring_param {
ETHTOOL_RING_USE_TX_PUSH_BUF_LEN = BIT(4),
ETHTOOL_RING_USE_TCP_DATA_SPLIT = BIT(5),
ETHTOOL_RING_USE_HDS_THRS = BIT(6),
+ ETHTOOL_RING_USE_PACING_OFFLOAD_HORIZON = BIT(7),
};
#define __ETH_RSS_HASH_BIT(bit) ((u32)1 << (bit))
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9981d637f8b5..cf777a58b328 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -2127,7 +2127,8 @@ enum netdev_reg_state {
* @dpll_pin: Pointer to the SyncE source pin of a DPLL subsystem,
* where the clock is recovered.
*
- * @max_pacing_offload_horizon: max EDT offload horizon in nsec.
+ * @pacing_offload_horizon: active pacing offload horizon in usec.
+ * @max_pacing_offload_horizon: max pacing offload horizon in usec.
* @napi_config: An array of napi_config structures containing per-NAPI
* settings.
* @num_napi_configs: number of allocated NAPI config structs,
@@ -2547,7 +2548,8 @@ struct net_device {
/** @irq_moder: dim parameters used if IS_ENABLED(CONFIG_DIMLIB). */
struct dim_irq_moder *irq_moder;
- u64 max_pacing_offload_horizon;
+ u32 pacing_offload_horizon;
+ u32 max_pacing_offload_horizon;
struct napi_config *napi_config;
u32 num_napi_configs;
u32 napi_defer_hard_irqs;
diff --git a/include/uapi/linux/ethtool_netlink_generated.h b/include/uapi/linux/ethtool_netlink_generated.h
index 8134baf7860f..6f1a2fa36157 100644
--- a/include/uapi/linux/ethtool_netlink_generated.h
+++ b/include/uapi/linux/ethtool_netlink_generated.h
@@ -193,6 +193,8 @@ enum {
ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN_MAX,
ETHTOOL_A_RINGS_HDS_THRESH,
ETHTOOL_A_RINGS_HDS_THRESH_MAX,
+ ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON,
+ ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON_MAX,
__ETHTOOL_A_RINGS_CNT,
ETHTOOL_A_RINGS_MAX = (__ETHTOOL_A_RINGS_CNT - 1)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 12aa3aa1688b..efcb219561ea 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -2124,7 +2124,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
nla_put_u32(skb, IFLA_TSO_MAX_SEGS,
READ_ONCE(dev->tso_max_segs)) ||
nla_put_uint(skb, IFLA_MAX_PACING_OFFLOAD_HORIZON,
- READ_ONCE(dev->max_pacing_offload_horizon)) ||
+ (u64)READ_ONCE(dev->max_pacing_offload_horizon) * NSEC_PER_USEC) ||
#ifdef CONFIG_RPS
nla_put_u32(skb, IFLA_NUM_RX_QUEUES,
READ_ONCE(dev->num_rx_queues)) ||
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 23db40618fed..5c2323aaa02b 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -954,6 +954,9 @@ void ethtool_ringparam_get_cfg(struct net_device *dev,
/* Driver gives us current state, we want to return current config */
kparam->tcp_data_split = dev->cfg->hds_config;
kparam->hds_thresh = dev->cfg->hds_thresh;
+
+ kparam->pacing_offload_horizon = dev->pacing_offload_horizon;
+ kparam->max_pacing_offload_horizon = dev->max_pacing_offload_horizon;
}
static void ethtool_init_tsinfo(struct kernel_ethtool_ts_info *info)
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 4ca2eca2e94b..fb0d99fd8cfd 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -466,7 +466,7 @@ extern const struct nla_policy ethnl_features_set_policy[ETHTOOL_A_FEATURES_WANT
extern const struct nla_policy ethnl_privflags_get_policy[ETHTOOL_A_PRIVFLAGS_HEADER + 1];
extern const struct nla_policy ethnl_privflags_set_policy[ETHTOOL_A_PRIVFLAGS_FLAGS + 1];
extern const struct nla_policy ethnl_rings_get_policy[ETHTOOL_A_RINGS_HEADER + 1];
-extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_HDS_THRESH_MAX + 1];
+extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON_MAX + 1];
extern const struct nla_policy ethnl_channels_get_policy[ETHTOOL_A_CHANNELS_HEADER + 1];
extern const struct nla_policy ethnl_channels_set_policy[ETHTOOL_A_CHANNELS_COMBINED_COUNT + 1];
extern const struct nla_policy ethnl_coalesce_get_policy[ETHTOOL_A_COALESCE_HEADER + 1];
diff --git a/net/ethtool/rings.c b/net/ethtool/rings.c
index 9054c89c5d7b..3ff0cb57d03c 100644
--- a/net/ethtool/rings.c
+++ b/net/ethtool/rings.c
@@ -42,6 +42,8 @@ static int rings_prepare_data(const struct ethnl_req_info *req_base,
data->kernel_ringparam.tcp_data_split = dev->cfg->hds_config;
data->kernel_ringparam.hds_thresh = dev->cfg->hds_thresh;
+ data->kernel_ringparam.pacing_offload_horizon = dev->pacing_offload_horizon;
+ data->kernel_ringparam.max_pacing_offload_horizon = dev->max_pacing_offload_horizon;
dev->ethtool_ops->get_ringparam(dev, &data->ringparam,
&data->kernel_ringparam, info->extack);
@@ -69,7 +71,9 @@ static int rings_reply_size(const struct ethnl_req_info *req_base,
nla_total_size(sizeof(u32)) + /* _RINGS_TX_PUSH_BUF_LEN */
nla_total_size(sizeof(u32)) + /* _RINGS_TX_PUSH_BUF_LEN_MAX */
nla_total_size(sizeof(u32)) + /* _RINGS_HDS_THRESH */
- nla_total_size(sizeof(u32)); /* _RINGS_HDS_THRESH_MAX*/
+ nla_total_size(sizeof(u32)) + /* _RINGS_HDS_THRESH_MAX*/
+ nla_total_size(sizeof(u32)) + /* _RINGS_PACING_OFFLOAD_HORIZON */
+ nla_total_size(sizeof(u32)); /* _RINGS_PACING_OFFLOAD_HORIZON_MAX */
}
static int rings_fill_reply(struct sk_buff *skb,
@@ -121,7 +125,12 @@ static int rings_fill_reply(struct sk_buff *skb,
(nla_put_u32(skb, ETHTOOL_A_RINGS_HDS_THRESH,
kr->hds_thresh) ||
nla_put_u32(skb, ETHTOOL_A_RINGS_HDS_THRESH_MAX,
- kr->hds_thresh_max))))
+ kr->hds_thresh_max))) ||
+ ((supported_ring_params & ETHTOOL_RING_USE_PACING_OFFLOAD_HORIZON) &&
+ (nla_put_u32(skb, ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON,
+ kr->pacing_offload_horizon) ||
+ nla_put_u32(skb, ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON_MAX,
+ kr->max_pacing_offload_horizon))))
return -EMSGSIZE;
return 0;
@@ -144,6 +153,7 @@ const struct nla_policy ethnl_rings_set_policy[] = {
[ETHTOOL_A_RINGS_RX_PUSH] = NLA_POLICY_MAX(NLA_U8, 1),
[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN] = { .type = NLA_U32 },
[ETHTOOL_A_RINGS_HDS_THRESH] = { .type = NLA_U32 },
+ [ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON] = { .type = NLA_U32 },
};
static int
@@ -177,6 +187,14 @@ ethnl_set_rings_validate(struct ethnl_req_info *req_info,
return -EOPNOTSUPP;
}
+ if (tb[ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON] &&
+ !(ops->supported_ring_params & ETHTOOL_RING_USE_PACING_OFFLOAD_HORIZON)) {
+ NL_SET_ERR_MSG_ATTR(info->extack,
+ tb[ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON],
+ "setting pacing offload horizon is not supported");
+ return -EOPNOTSUPP;
+ }
+
if (tb[ETHTOOL_A_RINGS_CQE_SIZE] &&
!(ops->supported_ring_params & ETHTOOL_RING_USE_CQE_SIZE)) {
NL_SET_ERR_MSG_ATTR(info->extack,
@@ -246,6 +264,8 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
tb[ETHTOOL_A_RINGS_TX_PUSH_BUF_LEN], &mod);
ethnl_update_u32(&kernel_ringparam.hds_thresh,
tb[ETHTOOL_A_RINGS_HDS_THRESH], &mod);
+ ethnl_update_u32(&kernel_ringparam.pacing_offload_horizon,
+ tb[ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON], &mod);
if (!mod)
return 0;
@@ -281,6 +301,9 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
err_attr = tb[ETHTOOL_A_RINGS_TX];
else if (kernel_ringparam.hds_thresh > kernel_ringparam.hds_thresh_max)
err_attr = tb[ETHTOOL_A_RINGS_HDS_THRESH];
+ else if (kernel_ringparam.pacing_offload_horizon >
+ kernel_ringparam.max_pacing_offload_horizon)
+ err_attr = tb[ETHTOOL_A_RINGS_PACING_OFFLOAD_HORIZON];
else
err_attr = NULL;
if (err_attr) {
@@ -302,6 +325,9 @@ ethnl_set_rings(struct ethnl_req_info *req_info, struct genl_info *info)
ret = dev->ethtool_ops->set_ringparam(dev, &ringparam,
&kernel_ringparam, info->extack);
+ if (!ret)
+ dev->pacing_offload_horizon = kernel_ringparam.pacing_offload_horizon;
+
return ret < 0 ? ret : 1;
}
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 7cae082a9847..d4cc8bc9fa06 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -1179,7 +1179,8 @@ static int fq_change(struct Qdisc *sch, struct nlattr *opt,
u64 offload_horizon = (u64)NSEC_PER_USEC *
nla_get_u32(tb[TCA_FQ_OFFLOAD_HORIZON]);
- if (offload_horizon <= qdisc_dev(sch)->max_pacing_offload_horizon) {
+ if (offload_horizon <=
+ (u64)qdisc_dev(sch)->pacing_offload_horizon * NSEC_PER_USEC) {
WRITE_ONCE(q->offload_horizon, offload_horizon);
} else {
NL_SET_ERR_MSG_MOD(extack, "invalid offload_horizon");
--
2.55.0.795.g602f6c329a-goog
next prev parent reply other threads:[~2026-07-06 13:34 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-06 13:34 [PATCH net-next 0/7] hardware pacing offload Willem de Bruijn
2026-07-06 13:34 ` Willem de Bruijn [this message]
2026-07-06 13:34 ` [PATCH net-next 2/7] net_sched: sch_fq: clear past skb->tstamp if offloading pacing Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 3/7] idpf: support pacing offload Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 4/7] selftests: drv-net: refactor so_txtime errqueue handling Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 5/7] selftests: drv-net: in so_txtime tell apart sw from hw pacing Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 6/7] selftests: drv-net: extend so_txtime with hw offload Willem de Bruijn
2026-07-06 13:34 ` [PATCH net-next 7/7] net: pktgen: add support for SO_TXTIME Willem de Bruijn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260706133433.3142805-2-willemdebruijn.kernel@gmail.com \
--to=willemdebruijn.kernel@gmail.com \
--cc=andrew@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=willemb@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox