mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ratheesh Kannoth <rkannoth@marvell.com>
To: Simon Horman <horms@kernel.org>
Cc: <davem@davemloft.net>, <hkelam@marvell.com>,
	<linux-kernel@vger.kernel.org>, <naveenm@marvell.com>,
	<netdev@vger.kernel.org>, <sgoutham@marvell.com>,
	<andrew+netdev@lunn.ch>, <edumazet@google.com>, <kuba@kernel.org>,
	<pabeni@redhat.com>
Subject: Re: [PATCH v3 net] octeontx2-pf: reset HTB scheduler topology before freeing queues
Date: Thu, 3 Sep 2026 07:58:01 +0530	[thread overview]
Message-ID: <apjbMTi10xfCOS5s@rkannoth-OptiPlex-7090> (raw)
In-Reply-To: <20260902172428.534936-1-horms@kernel.org>

On 2026-09-02 at 22:54:28, Simon Horman (horms@kernel.org) wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> Full review at: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260828035231.46911-1-rkannoth@marvell.com?part=1
> ---
> octeontx2-pf: reset HTB scheduler topology before freeing queues
>
> This adds otx2_qos_reset_schq_topology() and a wrapper
> otx2_qos_free_hw_schq() so that NIX_AF_TLxX_TOPOLOGY is zeroed for TL4
> through TL2 before a QoS scheduler queue is returned to the AF.  The new
> wrapper replaces otx2_txschq_free_one() in the class node teardown path and
> in the cfg rollback path.
>
> > diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
> > index 69c0911e28e91..ab9661334e6f9 100644
> > --- a/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
> > +++ b/drivers/net/ethernet/marvell/octeontx2/nic/qos.c
> > @@ -235,6 +235,58 @@ static int otx2_qos_txschq_set_parent_topology(struct otx2_nic *pfvf,
> >  	return rc;
> >  }
> >
> > +static int otx2_qos_reset_schq_topology(struct otx2_nic *pfvf, u16 lvl,
> > +					u16 schq)
> > +{
> > +	struct mbox *mbox = &pfvf->mbox;
> > +	struct nix_txschq_config *cfg;
> > +	int rc;
> > +
> > +	if (lvl < NIX_TXSCH_LVL_TL4 || lvl >= NIX_TXSCH_LVL_TL1)
> > +		return 0;
> > +
> > +	mutex_lock(&mbox->lock);
> > +
> > +	cfg = otx2_mbox_alloc_msg_nix_txschq_cfg(mbox);
> > +	if (!cfg) {
> > +		mutex_unlock(&mbox->lock);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	cfg->lvl = lvl;
> > +	cfg->num_regs = 1;
> > +
> > +	if (lvl == NIX_TXSCH_LVL_TL4)
> > +		cfg->reg[0] = NIX_AF_TL4X_TOPOLOGY(schq);
> > +	else if (lvl == NIX_TXSCH_LVL_TL3)
> > +		cfg->reg[0] = NIX_AF_TL3X_TOPOLOGY(schq);
> > +	else if (lvl == NIX_TXSCH_LVL_TL2)
> > +		cfg->reg[0] = NIX_AF_TL2X_TOPOLOGY(schq);
> > +	else
> > +		cfg->reg[0] = NIX_AF_TL1X_TOPOLOGY(schq);
> > +
> > +	cfg->regval[0] = 0;
> > +
> > +	rc = otx2_sync_mbox_msg(mbox);
> > +
> > +	mutex_unlock(&mbox->lock);
> > +
> > +	return rc;
> > +}
> > +
> > +static void otx2_qos_free_hw_schq(struct otx2_nic *pfvf, u16 lvl, u16 schq)
> > +{
> > +	int err;
> > +
> > +	err = otx2_qos_reset_schq_topology(pfvf, lvl, schq);
> > +	if (err)
> > +		netdev_warn(pfvf->netdev,
> > +			    "QoS: failed to reset topology for schq %u at level %u: %d\n",
> > +			    schq, lvl, err);
> > +
> > +	otx2_txschq_free_one(pfvf, lvl, schq);
> > +}
> > +
> >  static void otx2_qos_free_hw_node_schq(struct otx2_nic *pfvf,
> >  				       struct otx2_qos_node *parent)
> >  {
>
> [Severity: Low]
> The trailing else here cannot be reached.  In the mbox level enum
> NIX_TXSCH_LVL_TL4 is 1, TL3 is 2, TL2 is 3 and TL1 is 4, and the guard
> at the top of otx2_qos_reset_schq_topology() already bails out with:
>
> 	if (lvl < NIX_TXSCH_LVL_TL4 || lvl >= NIX_TXSCH_LVL_TL1)
> 		return 0;
>
> so only lvl 1, 2 and 3 ever get past it, and those three values are
> exhaustively covered by the TL4/TL3/TL2 arms above.  The
> NIX_AF_TL1X_TOPOLOGY(schq) assignment is dead code.
>
> Beyond being unreachable, it actively contradicts the commit message,
> which says the aggregation level is deliberately skipped because TL1 is
> shared with the PF, the default Tx hierarchy and the VFs and is never
> returned to the AF by nix_txschq_free_one().  A reader who only sees the
> else arm will conclude the opposite, and if the guard is ever relaxed the
> function will silently start zeroing a TL1 TOPOLOGY that other users
> depend on.
>
> Would you drop the else arm and make the last case an explicit
> "else if (lvl == NIX_TXSCH_LVL_TL2)", or convert the chain to a switch
> with the TL1 case omitted, so the code and the commit message agree on
> which levels are handled?
>
> [Severity: High]
> Was otx2_qos_free_hw_node_schq() intentionally left on the bare
> otx2_txschq_free_one() path?  It still reads:
>
> drivers/net/ethernet/marvell/octeontx2/nic/qos.c:otx2_qos_free_hw_node_schq() {
> 	list_for_each_entry_reverse(node, &parent->child_schq_list, list)
> 		otx2_txschq_free_one(pfvf, node->level, node->schq);
> }
>
> These child_schq_list entries are the intermediate chain created by
> otx2_qos_alloc_txschq_node() for every level from node->level - 1 down to
> MDQ:
>
> 	for (lvl = node->level - 1; lvl >= NIX_TXSCH_LVL_MDQ; lvl--) {
>
> so they sit at exactly the TL4/TL3/TL2 levels the commit message says are
> sanitized.
>
> They also carry TOPOLOGY, since otx2_qos_txschq_push_cfg_schq() programs it
> for each chain entry's parent:
>
> 	list_for_each_entry(tmp, &node->child_schq_list, list) {
> 		ret = otx2_qos_txschq_config(pfvf, tmp);
> 		if (ret)
> 			return -EIO;
> 		ret = otx2_qos_txschq_set_parent_topology(pfvf, tmp->parent);
>
> Two cases where those chain schqs would reach nix_txschq_free_one() with a
> non-zero TOPOLOGY:
>
> 1) HTB set up while the interface is down.  otx2_qos_push_txschq_cfg() and
>    otx2_qos_root_add() only fill the cfg and skip hardware programming:
>
> 	if (!(pfvf->netdev->flags & IFF_UP)) {
> 		otx2_qos_txschq_fill_cfg(pfvf, node, cfg);
> 		return 0;
> 	}
>
>    A following "tc qdisc del" while still down goes
>    otx2_qos_root_destroy() -> otx2_qos_destroy_node() ->
>    otx2_qos_free_hw_cfg() -> otx2_qos_free_hw_node_schq(), returning the
>    queue with whatever TOPOLOGY the previous owner left.
>
> 2) A partially failed push, for example otx2_qos_txschq_update_config()
>    failing in the restore paths of otx2_qos_leaf_to_inner() /
>    otx2_qos_leaf_alloc(), or otx2_qos_config_txschq() failing on ifup.  The
>    chain is left unprogrammed and later freed through the same helper.
>
> On the AF side nix_txschq_free_one() only touches XOFF, linkcfg, shaping and
> schedule:
>
> drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c:nix_txschq_free_one() {
> 	nix_clear_tx_xoff(rvu, blkaddr, lvl, schq);
> 	nix_reset_tx_linkcfg(rvu, blkaddr, lvl, schq);
> 	nix_reset_tx_shaping(rvu, blkaddr, nixlf, lvl, schq);
> 	...
> 	nix_reset_tx_schedule(rvu, blkaddr, lvl, schq);
> }
>
> so a stale PRIO_ANCHOR/RR_PRIO in those chain queues would still survive
> into the shared pool, which is the case the commit message describes.
>
> > @@ -252,7 +304,7 @@ static void otx2_qos_free_hw_node(struct otx2_nic *pfvf,
> >  	list_for_each_entry_safe(node, tmp, &parent->child_list, list) {
> >  		otx2_qos_free_hw_node(pfvf, node);
> >  		otx2_qos_free_hw_node_schq(pfvf, node);
> > -		otx2_txschq_free_one(pfvf, node->level, node->schq);
> > +		otx2_qos_free_hw_schq(pfvf, node->level, node->schq);
> >  	}
> >  }
> >
> > @@ -913,7 +965,7 @@ static void otx2_qos_free_cfg(struct otx2_nic *pfvf, struct otx2_qos_cfg *cfg)
> >  	for (lvl = 0; lvl < NIX_TXSCH_LVL_CNT; lvl++) {
> >  		for (idx = 0; idx < cfg->schq[lvl]; idx++) {
> >  			schq = cfg->schq_list[lvl][idx];
> > -			otx2_txschq_free_one(pfvf, lvl, schq);
> > +			otx2_qos_free_hw_schq(pfvf, lvl, schq);
> >  		}
> >  	}
> >
>
> Is the difference between the two paths deliberate?  cfg->schq_list is
> filled from child_schq_list by otx2_qos_read_txschq_cfg_schq(), so the
> rollback path here does reset TOPOLOGY for the same queues that the
> hierarchy teardown in otx2_qos_free_hw_node_schq() frees without a reset.
> Would routing the child_schq_list loop through otx2_qos_free_hw_schq() as
> well make the two paths symmetric?
>
> [ ... ]

ACK.

pw-bot: changes-requested

      reply	other threads:[~2026-09-03  2:28 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-28  3:52 Ratheesh Kannoth
2026-09-02 17:24 ` Simon Horman
2026-09-03  2:28   ` Ratheesh Kannoth [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=apjbMTi10xfCOS5s@rkannoth-OptiPlex-7090 \
    --to=rkannoth@marvell.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=hkelam@marvell.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=naveenm@marvell.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --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

all inboxes | Powered by JetHome®