RE: [PATCH net] octeontx2-af: poll for TX link credits before link mode change
"Jagielski, Jedrzej" <[email protected]>
| Newsgroups | gmane.linux.network,gmane.linux.kernel |
|---|---|
| Message-ID | <PH0PR11MB5902CB2559DB564EA0F2488EF0A62@PH0PR11MB5902.namprd11.prod.outlook.com> |
From: Ratheesh Kannoth <[email protected]> Sent: Tuesday, August 18, 2026 5:37 AM Hi Naveen, Ratheesh >From: Naveen Mamindlapalli <[email protected]> > >When a CGX/RPM link mode change is performed while traffic is flowing, >the link is temporarily disabled. NIX TX link credits can drop below >zero during this window and are not restored when the link comes back, >leading to a TX hang. > >Set TL1 SW_XOFF before initiating a link mode change and poll until TX >link credits return to their original value. Clear TL1 SW_XOFF when the >link comes back up. > >Fixes: 56b6d5398613 ("octeontx2-af: Physical link configuration support") >Signed-off-by: Naveen Mamindlapalli <[email protected]> >Signed-off-by: Ratheesh Kannoth <[email protected]> >--- > .../net/ethernet/marvell/octeontx2/af/rvu.h | 2 + > .../ethernet/marvell/octeontx2/af/rvu_cgx.c | 19 +++++++- > .../ethernet/marvell/octeontx2/af/rvu_nix.c | 48 +++++++++++++++++++ > 3 files changed, 68 insertions(+), 1 deletion(-) > >diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h >index 9d5b7b51bdfa..66e46528e3bd 100644 >--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h >+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h >@@ -1048,6 +1048,8 @@ int rvu_nix_mcast_get_mce_index(struct rvu *rvu, u16 pcifunc, > u32 mcast_grp_idx); > int rvu_nix_mcast_update_mcam_entry(struct rvu *rvu, u16 pcifunc, > u32 mcast_grp_idx, u16 mcam_index); >+int rvu_nix_tl1_xoff_wait_for_link_credits(struct rvu *rvu, u16 pcifunc); >+int rvu_nix_tl1_xoff_clear(struct rvu *rvu, u16 pcifunc); > void rvu_nix_flr_free_bpids(struct rvu *rvu, u16 pcifunc); > int rvu_alloc_cint_qint_mem(struct rvu *rvu, struct rvu_pfvf *pfvf, > int blkaddr, int nixlf); >diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c >index 87d21889dc49..85143684bb6f 100644 >--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c >+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cgx.c >@@ -234,7 +234,7 @@ static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu) > struct cgx_link_user_info *linfo; > struct cgx_link_info_msg *msg; > unsigned long pfmap; >- int pfid; >+ int pfid, err; > > linfo = &event->link_uinfo; > pfmap = cgxlmac_to_pfmap(rvu, event->cgx_id, event->lmac_id); >@@ -249,6 +249,15 @@ static void cgx_notify_pfs(struct cgx_link_event *event, struct rvu *rvu) > rvu->cgx_cnt_max * rvu->hw->lmac_per_cgx); > clear_bit(pfid, &pfmap); > >+ /* clear TL1 sw_xoff */ >+ if (linfo->link_up) { >+ err = rvu_nix_tl1_xoff_clear(rvu, pfid << 10); >+ if (err) >+ dev_warn(rvu->dev, >+ "tl1 sw_xoff clear unsuccessful, cgx=%d lmac=%d\n", >+ event->cgx_id, event->lmac_id); >+ } >+ > /* check if notification is enabled */ > if (!test_bit(pfid, &rvu->pf_notify_bmap)) { > dev_info(rvu->dev, "cgx %d: lmac %d Link status %s\n", >@@ -1221,6 +1230,7 @@ int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu, > struct cgx_lmac_fwdata_s *linkmodes; > u8 cgx_idx, lmac; > void *cgxd; >+ int err; > > if (!rvu->fwdata) > return LMAC_AF_ERR_FIRMWARE_DATA_NOT_MAPPED; >@@ -1230,11 +1240,18 @@ int rvu_mbox_handler_cgx_set_link_mode(struct rvu *rvu, > > rvu_get_cgx_lmac_id(rvu->pf2cgxlmac_map[pf], &cgx_idx, &lmac); > cgxd = rvu_cgx_pdata(cgx_idx, rvu); >+ intentional or leftover? > if (rvu->hw->lmac_per_cgx == CGX_LMACS_USX) > linkmodes = &rvu->fwdata->cgx_fw_data_usx[cgx_idx][lmac]; > else > linkmodes = &rvu->fwdata->cgx_fw_data[cgx_idx][lmac]; > >+ err = rvu_nix_tl1_xoff_wait_for_link_credits(rvu, req->hdr.pcifunc); >+ if (err) >+ dev_warn(rvu->dev, >+ "tl1 sw_xoff/link_credit_poll unsuccessful, cgx=%d lmac=%d\n", >+ cgx_idx, lmac); >+ > rsp->status = cgx_set_link_mode(cgxd, req->args, linkmodes, > cgx_idx, lmac); > return 0; >diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c >index 964bcaae098e..92d8f318783d 100644 >--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c >+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c >@@ -6704,3 +6704,51 @@ void rvu_block_bcast_xon(struct rvu *rvu, int blkaddr) > cfg = rvu_read64(rvu, blkaddr, NIX_AF_RX_CHANX_CFG(0)); > rvu_write64(rvu, blkaddr, NIX_AF_RX_CHANX_CFG(0), cfg); > } >+ >+int rvu_nix_tl1_xoff_wait_for_link_credits(struct rvu *rvu, u16 pcifunc) >+{ >+ int link, blkaddr, count = 1000; count can be declared inside the loop as it's not used outside same for regval moreover defs instead of magic is always better choice >+ u64 tx_credits, regval; >+ struct nix_hw *nix_hw; >+ >+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); >+ if (blkaddr < 0) >+ return NIX_AF_ERR_AF_LF_INVALID; >+ >+ nix_hw = get_nix_hw(rvu->hw, blkaddr); >+ if (!nix_hw) >+ return NIX_AF_ERR_INVALID_NIXBLK; >+ >+ /* set TL1 sw_xoff */ >+ link = nix_get_tx_link(rvu, pcifunc); >+ rvu_write64(rvu, blkaddr, NIX_AF_TL1X_SW_XOFF(link), 1); >+ >+ /* wait for link credits to return */ >+ tx_credits = nix_hw->tx_credits[link]; >+ while (1) { cant we use just for loop if this is simple cnt decrementing? >+ regval = rvu_read64(rvu, blkaddr, NIX_AF_TX_LINKX_NORM_CREDIT(link)); >+ if (((regval >> 12) & 0xFFFFF) == tx_credits) FIELD_GET(GENMASK(31, 12), regval) ? >+ break; >+ count--; >+ if (!count) { >+ dev_err(rvu->dev, "TX link(%d) credit poll timeout\n", link); >+ return -ETIMEDOUT; >+ } >+ cpu_relax(); >+ udelay(1); >+ } >+ return 0; >+} >+ >+int rvu_nix_tl1_xoff_clear(struct rvu *rvu, u16 pcifunc) >+{ >+ int blkaddr; >+ >+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NIX, pcifunc); >+ if (blkaddr < 0) >+ return NIX_AF_ERR_AF_LF_INVALID; >+ >+ nix_clear_tx_xoff(rvu, blkaddr, NIX_TXSCH_LVL_TL1, >+ nix_get_tx_link(rvu, pcifunc)); >+ return 0; >+} >-- >2.43.0