> -----Original Message-----
> From: Stephen Hemminger <[email protected]>
> Sent: Wednesday, May 27, 2026 11:22 PM
> To: Zaiyu Wang <[email protected]>; Zaiyu Wang 
> <[email protected]>
> Cc: [email protected]; [email protected]
> Subject: Re: [PATCH v5 00/21] Wangxun Fixes
> 
> On Wed, 27 May 2026 21:02:00 +0800
> Zaiyu Wang <[email protected]> wrote:
> 
> > This series fixes several issues found on Wangxun Emerald, Sapphire
> > and Amber-lite NICs, with a focus on link-related problems.
> > ---
> > v5:
> > - Fixed issues identified by AI review
> > ---
> > v4:
> > - Fixed issues identified by devtools scripts
> > ---
> > v3:
> > - Addressed Stephen's comments
> > ---
> > v2:
> > - Fixed compilation error and code style issues
> > ---
> >
> > Zaiyu Wang (21):
> >   net/txgbe: remove duplicate xstats counters
> >   net/ngbe: remove duplicate xstats counters
> >   net/ngbe: add missing CDR config for YT PHY
> >   net/ngbe: fix VF promiscuous and allmulticast
> >   net/txgbe: fix inaccuracy in Tx rate limiting
> >   net/txgbe: fix link status check condition
> >   net/txgbe: fix Tx desc free logic
> >   net/txgbe: fix link flow control registers for Amber-Lite
> >   net/txgbe: fix link flow control config for Sapphire
> >   net/txgbe: fix a mass of unknown interrupts
> >   net/txgbe: fix traffic class priority configuration
> >   net/txgbe: fix link stability for 25G NIC
> >   net/txgbe: fix link stability for 40G NIC
> >   net/txgbe: fix link stability for Amber-Lite backplane mode
> >   net/txgbe: fix FEC mode configuration on 25G NIC
> >   net/txgbe: fix SFP module identification
> >   net/txgbe: fix get module info operation
> >   net/txgbe: fix get EEPROM operation
> >   net/txgbe: fix to reset Tx write-back pointer
> >   net/txgbe: fix to enable Tx desc check
> >   net/txgbe: fix temperature track for AML NIC
> >
> >  drivers/net/ngbe/base/ngbe_phy_yt.c       |    3 +
> >  drivers/net/ngbe/ngbe_ethdev.c            |    5 -
> >  drivers/net/ngbe/ngbe_ethdev_vf.c         |   11 +-
> >  drivers/net/txgbe/base/meson.build        |    2 +
> >  drivers/net/txgbe/base/txgbe.h            |    2 +
> >  drivers/net/txgbe/base/txgbe_aml.c        |  185 +-
> >  drivers/net/txgbe/base/txgbe_aml.h        |    6 +-
> >  drivers/net/txgbe/base/txgbe_aml40.c      |  114 +-
> >  drivers/net/txgbe/base/txgbe_aml40.h      |    6 +-
> >  drivers/net/txgbe/base/txgbe_dcb_hw.c     |    2 +-
> >  drivers/net/txgbe/base/txgbe_e56.c        | 3773 +++++++++++++++++++++
> >  drivers/net/txgbe/base/txgbe_e56.h        | 1753 ++++++++++
> >  drivers/net/txgbe/base/txgbe_e56_bp.c     | 2597 ++++++++++++++
> >  drivers/net/txgbe/base/txgbe_e56_bp.h     |  282 ++
> >  drivers/net/txgbe/base/txgbe_hw.c         |   54 +-
> >  drivers/net/txgbe/base/txgbe_hw.h         |    4 +-
> >  drivers/net/txgbe/base/txgbe_osdep.h      |    4 +
> >  drivers/net/txgbe/base/txgbe_phy.c        |  362 +-
> >  drivers/net/txgbe/base/txgbe_phy.h        |   45 +-
> >  drivers/net/txgbe/base/txgbe_regs.h       |   13 +-
> >  drivers/net/txgbe/base/txgbe_type.h       |   43 +-
> >  drivers/net/txgbe/txgbe_ethdev.c          |  458 ++-
> >  drivers/net/txgbe/txgbe_ethdev.h          |    7 +-
> >  drivers/net/txgbe/txgbe_rxtx.c            |  107 +-
> >  drivers/net/txgbe/txgbe_rxtx.h            |   36 +
> >  drivers/net/txgbe/txgbe_rxtx_vec_common.h |   16 +-
> >  26 files changed, 9445 insertions(+), 445 deletions(-)  create mode
> > 100644 drivers/net/txgbe/base/txgbe_e56.c
> >  create mode 100644 drivers/net/txgbe/base/txgbe_e56.h
> >  create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.c
> >  create mode 100644 drivers/net/txgbe/base/txgbe_e56_bp.h
> >
> 
> More AI review feedback summary:
> 
> 
> 18/21 — get EEPROM (Error): page is declared once before the for loop and 
> never reset, so after
> crossing the 256-byte boundary every subsequent iteration walks one page 
> further into the
> module than it should. Plus two related issues: data[0x2] reads the output 
> buffer not the module
> byte, and the skip branch leaves stale databyte carrying over from the 
> previous iteration.
> 
> 20/21 — Tx desc check (Error): #ifdef RTE_LIBRTE_SECURITY uses the
> pre-2020 macro name; the modern name is RTE_LIB_SECURITY (and the surrounding 
> code in the
> same file uses it correctly). The IPsec guard is therefore always compiled 
> out and the wr32m runs
> for every queue, including IPsec ones.
> 
> 16/21 & 17/21 — whitespace: \t if (tab-then-space) on two lines. Checkpatch 
> will catch it, but
> worth a pass.
> 
> 17/21 — TXGBE_SFF_DDM_IMPLEMENTED: value 0x40 is correct as a bit-6 mask of 
> byte 0x5C, but
> it is defined next to register-offset macros which makes it read as an offset.
> 
> 14/21 — kr_read_poll macro: uses usleep() directly; everything else in the 
> txgbe base layer uses
> usec_delay().
> 
> 7/21 — type pun: the atomic load casts a volatile uint32_t * to volatile 
> uint16_t *. Works on all
> DPDK platforms but is strict-aliasing-iffy; a u32 load with a u16 cast at the 
> use site would be
> cleaner.
> 
> Longer full review:
> 
> Review of [PATCH v5 00/21] net/{txgbe,ngbe} fixes from Zaiyu Wang
> 
> This revision addresses the substantive issues raised on v4:
> 
>   - 07/21: Tx desc free now uses a documented helper
>     txgbe_tx_headwb_desc_done() that correctly handles the head==next
>     boundary, and switches the headwb_mem read from a plain volatile
>     access to rte_atomic_load_explicit(... acquire).
>   - 08/21: AML xon/xoff stats no longer use plain assignment.  The
>     counter now goes through the new TXGBE_UPDATE_COUNTER_32BIT_GENERIC
>     macro with offset tracking, and txgbe_clear_hw_cntrs() write-clears
>     the AML registers and zeroes hw->last_stats on reset.
>   - 11/21: traffic class priority is consistent across all three
>     callers.  TXGBE_RPUP2TC_UP_SHIFT is bumped to 4, TXGBE_DCBUP2TC_MAP
>     is updated to match, txgbe_vmdq_dcb_configure() uses the macros
>     instead of a hardcoded *3 shift, and the unused TXGBE_DCBUP2TC_DEC
>     is removed.  The bonus fix of redirecting
>     txgbe_dcb_config_tx_data_arbiter_raptor() to TXGBE_PBTXUP2TC instead
>     of TXGBE_PBRXUP2TC is welcome.
>   - 12/21: txgbe_setup_phy_link_aml() now sets link_up = false before
>     'goto out' on TXGBE_ERR_TIMEOUT, so the out: block correctly routes
>     to *need_reset = true.  The generic 'compare' qsort helper has been
>     renamed to txgbe_e56_int_cmp().
> 
> Remaining findings on v5 below.
> 
> ----------------------------------------------------------------
> 
> Patch 18/21 (net/txgbe: fix get EEPROM operation)
> 
> Error: page accumulation across loop iterations in
> txgbe_get_module_eeprom() will return wrong bytes for any QSFP read that 
> crosses the 256-byte
> page boundary.
> 
>   +   uint8_t page = 0;
>   ...
>   +   for (i = info->offset; i < info->offset + info->length; i++) {
>   +           if (is_sfp) {
>   ...
>   +           } else {
>   +                   offset = i;
>   +                   while (offset >= RTE_ETH_MODULE_SFF_8436_LEN) {
>   +                           offset -= RTE_ETH_MODULE_SFF_8436_LEN / 2;
>   +                           page++;
>   +                   }
>   +                   if (page == 0 || !(data[0x2] & 0x4)) {
>   +                           status = hw->phy.read_i2c_sff8636(hw, page, 
> offset,
>   +                                          &databyte);
> 
> 'page' is declared once before the for loop and never reset, but the while 
> loop only increments it.
> For i = 256 the math is correct
> (page=0 entering, page=1 leaving, offset=128).  For i = 257 the loop enters 
> with page=1 already
> set from the previous iteration and ends with page=2, offset=129 - it should 
> still be page=1.
> Every subsequent iteration adds one more page, so the function reads bytes 
> from ever-higher
> pages instead of staying on page 1, 2, 3, ...
> 
> Reset page (and rebuild offset) at each iteration:
> 
>       uint16_t addr;
>       uint8_t  page;
> 
>       for (i = info->offset; i < info->offset + info->length; i++) {
>               ...
>               } else {
>                       page = 0;
>                       addr = i;
>                       while (addr >= RTE_ETH_MODULE_SFF_8436_LEN) {
>                               addr -= RTE_ETH_MODULE_SFF_8436_LEN / 2;
>                               page++;
>                       }
>                       ...
>               }
>       }
> 
> Two related concerns in the same block:
> 
>   - The flat-memory check '!(data[0x2] & 0x4)' inspects byte 2 of the
>     caller's output buffer rather than module byte 2.  If info->offset
>     > 2 the byte was never read, so the test reads the value left by
>     memset (zero) and always evaluates to true.  Read module byte 2
>     explicitly before the loop and stash it in a local.
> 
>   - When the skip branch is taken (paged read on flat memory), the
>     loop still does 'data[i - info->offset] = databyte', so the byte
>     written is whatever databyte held from the previous iteration.
>     Set databyte to 0 (or 0xff) before each iteration, or set the
>     output byte directly inside the skip branch.
> 
> Patch 20/21 (net/txgbe: fix to enable Tx desc check)
> 
> Error: the new IPsec guard uses the wrong macro name and is always compiled 
> out.
> 
>   +#ifdef RTE_LIBRTE_SECURITY
>   +           if (!txq->using_ipsec)
>   +#endif
>   +                   wr32m(hw, TXGBE_TDM_DESC_CHK(txq->reg_idx / 32),
>   +                         RTE_BIT32(txq->reg_idx % 32), 
> RTE_BIT32(txq->reg_idx % 32));
> 
> The DPDK build macro is RTE_LIB_SECURITY; RTE_LIBRTE_SECURITY is the
> pre-2020 name and is no longer defined anywhere in the tree (the rest of this 
> same driver uses
> RTE_LIB_SECURITY in the surrounding code, including the deleted block this 
> patch replaces).
> Result: the 'if (!txq->using_ipsec)' line is never preprocessed in, the wr32m 
> runs for every queue
> unconditionally, and IPsec-enabled queues get the desc-check bit set even 
> though the existing
> intent was to skip them.
> 
> Replace with RTE_LIB_SECURITY.  Matches the existing pattern elsewhere in 
> txgbe_rxtx.c
> (txgbe_rxtx.c:64, :444, :882, ...).
> 
> Patch 16/21 (net/txgbe: fix SFP module identification)
> 
> Warning: stray space in indentation of txgbe_read_i2c_sff8636() body.
> 
>   +   s32 err = hw->phy.write_i2c_byte(hw, TXGBE_SFF_QSFP_PAGE_SELECT,
>   +                                   TXGBE_I2C_EEPROM_DEV_ADDR,
>   +                                   page);
>   +    if (err != 0)
>   +           return err;
> 
> The 'if' line is indented with tab+space instead of a single tab.
> checkpatch will flag this.
> 
> Info: this patch refactors away phy.read_i2c_byte_unlocked and 
> phy.write_i2c_byte_unlocked and
> merges them into the existing phy.read_i2c_byte / phy.write_i2c_byte slots, 
> which now no longer
> acquire the swfw semaphore.  Patches 17 and 18 add explicit acquire/release 
> around their own
> callers, which is correct, but it is worth double-checking that no other 
> in-tree caller of
> phy.read_i2c_eeprom / phy.read_i2c_sff8472 / phy.read_i2c_byte runs without 
> holding
> TXGBE_MNGSEM_SWPHY after this patch.  The lock change and the callsite 
> updates would
> arguably read better squashed together or at least kept adjacent in the 
> series.
> 
> Patch 17/21 (net/txgbe: fix get module info operation)
> 
> Warning: stray space in indentation - same checkpatch issue as above.
> 
>   +   if (hw->mac.type == txgbe_mac_aml) {
>   +           value = rd32(hw, TXGBE_GPIOEXT);
>   +            if (value & TXGBE_SFP1_MOD_ABS_LS) {
> 
> 'if' is tab+space indented; should be two tabs.
> 
> Info: TXGBE_SFF_DDM_IMPLEMENTED is added next to the SFP register offset 
> definitions, but is
> then used as a bit mask of byte 0x5C:
> 
>   #define TXGBE_SFF_DDM_IMPLEMENTED    0x40
>   #define TXGBE_SFF_SFF_8472_SWAP      0x5C
>   ...
>   if (sff8472_rev == TXGBE_SFF_SFF_8472_UNSUP || page_swap ||
>       !(addr_mode & TXGBE_SFF_DDM_IMPLEMENTED)) {
> 
> The value 0x40 is correct as bit 6 of the diagnostic-monitoring-type byte at 
> offset 0x5C, but placing
> it alongside register offsets makes the macro look like an offset.  Consider 
> moving it into a
> bit-mask group or renaming the offset/mask pair to make the intent obvious 
> (e.g. _ADDR vs
> _MASK suffix).
> 
> Patch 14/21 (net/txgbe: fix link stability for Amber-Lite)
> 
> Warning: the new kr_read_poll() macro in txgbe_phy.h uses usleep() directly, 
> while the rest of the
> txgbe base layer uses the
> usec_delay() abstraction (which expands to rte_delay_us_block() on DPDK).  
> Mixing the two is
> inconsistent and pulls in a POSIX dependency in a base/ file:
> 
>   +#define kr_read_poll(op, val, cond, sleep_us, \
>   +                times, args...) \
>   +({ \
>   ...
>   +           usleep(__sleep_us);\
>   ...
>   +})
> 
> Switch to usec_delay() to match txgbe_eeprom.c, txgbe_hw.c, and the rest of 
> the same file.
> 
> Patch 7/21 (net/txgbe: fix Tx desc free logic)
> 
> Info: txq->headwb_mem is declared 'volatile uint32_t *', but the new atomic 
> read reads it as
> 'volatile uint16_t *':
> 
>   +   const uint16_t head = rte_atomic_load_explicit((volatile uint16_t 
> *)txq->headwb_mem,
>   +                                                  
> rte_memory_order_acquire);
> 
> This works on every architecture DPDK supports (lower 16 bits of an aligned 
> 32-bit object are
> accessible as a 16-bit atomic and head fits in 16 bits), but it is a type pun 
> on a hardware-written
> object and a strict-aliasing violation in pure C.  A 32-bit atomic load with 
> an explicit cast at use site
> would be cleaner:
> 
>       uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
>                                             rte_memory_order_acquire);
>       const uint16_t head = (uint16_t)h;
> 
> Stephen Hemminger <[email protected]>
> 
> 
Thanks.
All the comments above have been addressed in v6.

Reply via email to