From: Jakub Kicinski <kuba@kernel.org>
To: Ratheesh Kannoth <rkannoth@marvell.com>
Cc: <bpf@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<netdev@vger.kernel.org>, <andrew+netdev@lunn.ch>,
<ast@kernel.org>, <daniel@iogearbox.net>, <davem@davemloft.net>,
<edumazet@kernel.org>, <hawk@kernel.org>,
<john.fastabend@gmail.com>, <pabeni@redhat.com>,
<sdf@fomichev.me>, <sgoutham@marvell.com>,
Simon Horman <horms@kernel.org>
Subject: Re: [PATCH v21 net-next 2/2] octeontx2: add mqprio bandwidth offload for NIX TX schedulers
Date: Fri, 13 Nov 2026 18:42:02 -0800 [thread overview]
Message-ID: <20261113184202.678ed2f7@kernel.org> (raw)
In-Reply-To: <20261109033154.2161803-3-rkannoth@marvell.com>
On Mon, 9 Nov 2026 09:01:53 +0530 Ratheesh Kannoth wrote:
> Add TC_SETUP_QDISC_MQPRIO offload with TC_MQPRIO_SHAPER_BW_RATE on PF and
> VF netdevs. Program per-queue MDQ CIR/PIR via the NIX TX scheduler mailbox;
> when active, allocate one SMQ per non-QoS queue under TL4[0].
>
> The TX scheduler cannot be reprogrammed live, so add/replace/delete and
> failed setup bounce the netdev through ndo_stop()/ndo_open(). Cache rates
> in software and restore them from otx2_mqprio_up() on open, failing closed
> on error.
>
> Stage tc replace in mq_offload_snap snapshots committed on TC_ROOT_GRAFT or
> replaced-qdisc teardown.
>
> Require a running interface with CIR+PIR support. Reject offload with PFC,
> XDP, HTB, SDP representors, per-TC rates on multi-queue classes, and
> ethtool channel changes while active.
>
> Reviewed-by: Simon Horman <horms@kernel.org>
> Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
> ---
> .../marvell/octeontx2/nic/otx2_common.c | 143 ++-
> .../marvell/octeontx2/nic/otx2_common.h | 34 +
> .../marvell/octeontx2/nic/otx2_dcbnl.c | 6 +
> .../marvell/octeontx2/nic/otx2_ethtool.c | 8 +
> .../ethernet/marvell/octeontx2/nic/otx2_pf.c | 34 +-
> .../ethernet/marvell/octeontx2/nic/otx2_tc.c | 936 ++++++++++++++++++
> .../ethernet/marvell/octeontx2/nic/otx2_vf.c | 28 +-
> .../net/ethernet/marvell/octeontx2/nic/qos.c | 11 +
> 8 files changed, 1179 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
> index f4047b0d5d96..b4a738cf9a8b 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
> @@ -615,6 +615,139 @@ void otx2_get_mac_from_af(struct net_device *netdev)
> }
> EXPORT_SYMBOL(otx2_get_mac_from_af);
>
> +static int
> +otx2_nix_tmq_reg_write(struct otx2_nic *pfvf, int cnt,
> + u64 reg_addr[MAX_REGS_PER_MBOX_MSG],
> + u64 reg_val[MAX_REGS_PER_MBOX_MSG])
> +{
> + struct mbox *mbox = &pfvf->mbox;
> + struct nix_txschq_config *req;
> + int i, err;
> +
> + mutex_lock(&mbox->lock);
> + req = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox);
> + if (!req) {
> + mutex_unlock(&mbox->lock);
> + return -ENOMEM;
> + }
> +
> + req->lvl = NIX_TXSCH_LVL_MDQ;
> + req->num_regs = cnt;
> +
> + for (i = 0; i < cnt; i++) {
> + req->reg[i] = reg_addr[i];
> + req->regval[i] = reg_val[i];
> + }
> +
> + err = otx2_sync_mbox_msg(mbox);
> + mutex_unlock(&mbox->lock);
> +
> + return err;
> +}
> +
> +int otx2_nix_tm_clear_queue_shaper(struct otx2_nic *pfvf)
> +{
> + u64 reg_addr[MAX_REGS_PER_MBOX_MSG];
> + u64 reg_val[MAX_REGS_PER_MBOX_MSG];
> + int err, smq, i, cnt = 0;
> +
> + for (i = 0; i < pfvf->hw.txschq_cnt[NIX_TXSCH_LVL_SMQ]; i++) {
> + smq = pfvf->hw.txschq_list[NIX_TXSCH_LVL_SMQ][i];
> +
> + reg_addr[cnt] = NIX_AF_MDQX_PIR(smq);
> + reg_val[cnt] = 0;
> + cnt++;
> +
> + reg_addr[cnt] = NIX_AF_MDQX_CIR(smq);
> + reg_val[cnt] = 0;
> + cnt++;
> +
> + if (cnt < MAX_REGS_PER_MBOX_MSG - 1)
> + continue;
> +
> + err = otx2_nix_tmq_reg_write(pfvf, cnt,
> + reg_addr, reg_val);
> + if (err)
> + goto fail;
> + cnt = 0;
> + }
> +
> + if (cnt) {
> + err = otx2_nix_tmq_reg_write(pfvf, cnt,
> + reg_addr, reg_val);
> + if (err)
> + goto fail;
> + }
> +
> + return 0;
> +fail:
> + return err;
just return err; why the label ?
> +struct mq_offload_snap {
> + u64 min_rate[TC_QOPT_MAX_QUEUE];
> + u64 max_rate[TC_QOPT_MAX_QUEUE];
> + u32 flags;
> + __u8 num_tc;
> + __u16 count[TC_QOPT_MAX_QUEUE];
> + __u16 offset[TC_QOPT_MAX_QUEUE];
> + __u8 prio_tc_map[TC_QOPT_BITMASK + 1];
Why is this using __u types?
> diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
> index 4fe473d9ea0d..5428b3d1b332 100644
> --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
> +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c
> @@ -287,6 +287,14 @@ static int otx2_set_channels(struct net_device *dev,
> return -EINVAL;
> }
>
> + if (pfvf->mqprio.rate_limit &&
> + (channel->tx_count != pfvf->hw.tx_queues ||
> + channel->rx_count != pfvf->hw.rx_queues)) {
> + netdev_info(dev,
> + "Not permitted to change channel count while MQ prio is active\n");
Why? This seems quite limiting.
User has to remove the root qdisc to change the queue count?
> + return -EINVAL;
> + }
> +
> if (if_up)
> dev->netdev_ops->ndo_stop(dev);
> + if (prog && pf->mqprio.rate_limit) {
> + netdev_err(dev,
> + "XDP: cannot attach while mqprio bandwidth offload is active\n");
Again - why?
> + return -EOPNOTSUPP;
> + }
> +
> if (prog && dev->mtu > MAX_XDP_MTU) {
> netdev_warn(dev, "Jumbo frames not yet supported with XDP\n");
> return -EOPNOTSUPP;
> +static void otx2_mqprio_free_cache(struct otx2_nic *pfvf)
> +{
> + devm_kfree(pfvf->dev, pfvf->mqprio.min_rate);
> + devm_kfree(pfvf->dev, pfvf->mqprio.max_rate);
devm_kfree() is a red flag, either this is something tied to the
lifetime of the driver, or you need to clean this up. Saying that
something "doesn't leak because it was devm_kmalloc()ed" is invalid.
Drivers don't get re-probed in real life, memory parked in devm_ is
as bad as leaked.
> +static int otx2_mqprio_restart_netdev(struct net_device *netdev, bool rate_limit)
> +{
> + struct otx2_nic *pfvf = netdev_priv(netdev);
> + const struct net_device_ops *ops = netdev->netdev_ops;
> + bool running = netif_running(netdev);
> + int err;
> +
> + /* TODO: Explore live TX scheduler reprogramming to avoid a full
> + * ndo_stop()/ndo_open() bounce on every mqprio change.
> + */
> + netdev_dbg(netdev,
> + "mqprio: restarting interface to reprogram TX scheduler\n");
> +
> + if (running) {
> + clear_bit(__LINK_STATE_START, &netdev->state);
Messing with internal netdev state like this from the driver is
obviously unacceptable.
> + smp_mb__after_atomic(); /* Commit netif_running(). */
> + }
> + /* TODO: per-TC TL4 shapers or equal per-queue MDQ split for multi-queue TC rates. */
> + netdev_err(netdev,
> + "mqprio: %s rate for tc %d not supported with %u queues\n",
> + name, tc, qcount);
> + NL_SET_ERR_MSG_FMT_MOD(extack,
> + "mqprio: tc %d rate needs 1 queue (has %u)",
> + tc, qcount);
Doubling out output to extack and dmesg is not okay, user space should
look at the extack. And a decade after it was added it mostly does.
You are at v21 this is nowhere near the acceptable quality. You should
probably give up.
prev parent reply other threads:[~2026-11-14 2:42 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 3:31 [PATCH v21 net-next 0/2] octeontx2: mqprio bandwidth offload for NIX TX schedulers Ratheesh Kannoth
2026-11-09 3:31 ` [PATCH v21 net-next 1/2] octeontx2: use atomic bitops for PF/VF and rep flags Ratheesh Kannoth
2026-11-11 21:32 ` netdev-bot+sashiko
2026-11-12 1:56 ` Ratheesh Kannoth
2026-11-09 3:31 ` [PATCH v21 net-next 2/2] octeontx2: add mqprio bandwidth offload for NIX TX schedulers Ratheesh Kannoth
2026-11-11 21:32 ` netdev-bot+sashiko
2026-11-12 1:55 ` Ratheesh Kannoth
2026-11-14 2:42 ` Jakub Kicinski [this message]
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=20261113184202.678ed2f7@kernel.org \
--to=kuba@kernel.org \
--cc=andrew+netdev@lunn.ch \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=hawk@kernel.org \
--cc=horms@kernel.org \
--cc=john.fastabend@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=rkannoth@marvell.com \
--cc=sdf@fomichev.me \
--cc=sgoutham@marvell.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