In head writeback mode ixl_isc_txd_credits_update_hwb() returns the
distance from tx_cidx_processed to the head index reported by the
hardware, which is the next descriptor the hardware will process and is
0 after ixl_init_tx_ring(). ixl_init_tx_cidx() initialized
tx_cidx_processed to the end of the ring (ntxd - 1), the value that
ixl_init_tx_rsqs() uses for the report status queue, where it stands
for the last descriptor done. As a result, the first credits update
after every (re)initialization reported one descriptor more than the
hardware had processed.
iflib's own TX path does not notice: DESC_RECLAIMABLE() keeps
isc_tx_nsegments descriptors in hand. iflib_netmap_txsync() uses the
count as it is to advance nr_hwtail, so as soon as a reclaim runs after
the NIC has caught up, nr_hwtail equals nr_hwcur and the netmap TX ring
looks full from then on. With the NIC attached to a VALE switch
(valectl -h) the switch stops forwarding packets to the NIC after a
few packets, while reception keeps working.
Initialize tx_cidx_processed to 0 in head writeback mode. Linux's i40e
reads the same head write-back value and starts from 0 as well:
i40e_setup_tx_descriptors() sets next_to_clean to 0, and
i40e_clean_xdp_tx_irq() (AF_XDP zero-copy) computes the completed
descriptors as i40e_get_head() - next_to_clean.
Signed-off-by: Wanpeng Qian <wanpengqian@gmail.com>
Sponsored by: keelos.dev