Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2026-01-13 (ice, igc)

For ice:
Jake adds missing initialization calls to u64_stats_init().

Dave stops deletion of VLAN 0 from prune list when device is primary
LAG interface.

Ding Hui adds a missed unit conversion function for proper timeout
value.

For igc:
Kurt Kanzenbach adds a call to re-set default Qbv schedule when number
of channels changes.

Chwee-Lin Choong reworks Tx timestamp detection logic to resolve a race
condition and reverts changes to TSN packet buffer size causing Tx
hangs under heavy load.

* '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/net-queue:
  igc: Reduce TSN TX packet buffer from 7KB to 5KB per queue
  igc: fix race condition in TX timestamp read for register 0
  igc: Restore default Qbv schedule when changing channels
  ice: Fix incorrect timeout ice_release_res()
  ice: Avoid detrimental cleanup for bond during interface stop
  ice: initialize ring_stats->syncp
====================

Link: https://patch.msgid.link/20260113220220.1034638-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-01-15 19:59:40 -08:00
commit 2c68d5eacc
6 changed files with 57 additions and 31 deletions

View File

@ -2251,7 +2251,7 @@ void ice_release_res(struct ice_hw *hw, enum ice_aq_res_ids res)
/* there are some rare cases when trying to release the resource
* results in an admin queue timeout, so handle them correctly
*/
timeout = jiffies + 10 * ICE_CTL_Q_SQ_CMD_TIMEOUT;
timeout = jiffies + 10 * usecs_to_jiffies(ICE_CTL_Q_SQ_CMD_TIMEOUT);
do {
status = ice_aq_release_res(hw, res, 0, NULL);
if (status != -EIO)

View File

@ -398,6 +398,8 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
if (!ring_stats)
goto err_out;
u64_stats_init(&ring_stats->syncp);
WRITE_ONCE(tx_ring_stats[i], ring_stats);
}
@ -417,6 +419,8 @@ static int ice_vsi_alloc_ring_stats(struct ice_vsi *vsi)
if (!ring_stats)
goto err_out;
u64_stats_init(&ring_stats->syncp);
WRITE_ONCE(rx_ring_stats[i], ring_stats);
}
@ -3805,22 +3809,31 @@ int ice_vsi_add_vlan_zero(struct ice_vsi *vsi)
int ice_vsi_del_vlan_zero(struct ice_vsi *vsi)
{
struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
struct ice_pf *pf = vsi->back;
struct ice_vlan vlan;
int err;
vlan = ICE_VLAN(0, 0, 0);
err = vlan_ops->del_vlan(vsi, &vlan);
if (err && err != -EEXIST)
return err;
if (pf->lag && pf->lag->primary) {
dev_dbg(ice_pf_to_dev(pf), "Interface is primary in aggregate - not deleting prune list\n");
} else {
vlan = ICE_VLAN(0, 0, 0);
err = vlan_ops->del_vlan(vsi, &vlan);
if (err && err != -EEXIST)
return err;
}
/* in SVM both VLAN 0 filters are identical */
if (!ice_is_dvm_ena(&vsi->back->hw))
return 0;
vlan = ICE_VLAN(ETH_P_8021Q, 0, 0);
err = vlan_ops->del_vlan(vsi, &vlan);
if (err && err != -EEXIST)
return err;
if (pf->lag && pf->lag->primary) {
dev_dbg(ice_pf_to_dev(pf), "Interface is primary in aggregate - not deleting QinQ prune list\n");
} else {
vlan = ICE_VLAN(ETH_P_8021Q, 0, 0);
err = vlan_ops->del_vlan(vsi, &vlan);
if (err && err != -EEXIST)
return err;
}
/* when deleting the last VLAN filter, make sure to disable the VLAN
* promisc mode so the filter isn't left by accident

View File

@ -443,9 +443,10 @@
#define IGC_TXPBSIZE_DEFAULT ( \
IGC_TXPB0SIZE(20) | IGC_TXPB1SIZE(0) | IGC_TXPB2SIZE(0) | \
IGC_TXPB3SIZE(0) | IGC_OS2BMCPBSIZE(4))
/* TSN value following I225/I226 SW User Manual Section 7.5.4 */
#define IGC_TXPBSIZE_TSN ( \
IGC_TXPB0SIZE(7) | IGC_TXPB1SIZE(7) | IGC_TXPB2SIZE(7) | \
IGC_TXPB3SIZE(7) | IGC_OS2BMCPBSIZE(4))
IGC_TXPB0SIZE(5) | IGC_TXPB1SIZE(5) | IGC_TXPB2SIZE(5) | \
IGC_TXPB3SIZE(5) | IGC_OS2BMCPBSIZE(4))
#define IGC_DTXMXPKTSZ_TSN 0x19 /* 1600 bytes of max TX DMA packet size */
#define IGC_DTXMXPKTSZ_DEFAULT 0x98 /* 9728-byte Jumbo frames */

View File

@ -1565,8 +1565,8 @@ static int igc_ethtool_set_channels(struct net_device *netdev,
if (ch->other_count != NON_Q_VECTORS)
return -EINVAL;
/* Do not allow channel reconfiguration when mqprio is enabled */
if (adapter->strict_priority_enable)
/* Do not allow channel reconfiguration when any TSN qdisc is enabled */
if (adapter->flags & IGC_FLAG_TSN_ANY_ENABLED)
return -EINVAL;
/* Verify the number of channels doesn't exceed hw limits */

View File

@ -7759,6 +7759,11 @@ int igc_reinit_queues(struct igc_adapter *adapter)
if (netif_running(netdev))
err = igc_open(netdev);
if (!err) {
/* Restore default IEEE 802.1Qbv schedule after queue reinit */
igc_tsn_clear_schedule(adapter);
}
return err;
}

View File

@ -774,36 +774,43 @@ static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter,
static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
u32 txstmpl_old;
u64 regval;
u32 mask;
int i;
/* Establish baseline of TXSTMPL_0 before checking TXTT_0.
* This baseline is used to detect if a new timestamp arrives in
* register 0 during the hardware bug workaround below.
*/
txstmpl_old = rd32(IGC_TXSTMPL);
mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY;
if (mask & IGC_TSYNCTXCTL_TXTT_0) {
regval = rd32(IGC_TXSTMPL);
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
} else {
/* There's a bug in the hardware that could cause
* missing interrupts for TX timestamping. The issue
* is that for new interrupts to be triggered, the
* IGC_TXSTMPH_0 register must be read.
/* TXTT_0 not set - register 0 has no new timestamp initially.
*
* To avoid discarding a valid timestamp that just
* happened at the "wrong" time, we need to confirm
* that there was no timestamp captured, we do that by
* assuming that no two timestamps in sequence have
* the same nanosecond value.
* Hardware bug: Future timestamp interrupts won't fire unless
* TXSTMPH_0 is read, even if the timestamp was captured in
* registers 1-3.
*
* So, we read the "low" register, read the "high"
* register (to latch a new timestamp) and read the
* "low" register again, if "old" and "new" versions
* of the "low" register are different, a valid
* timestamp was captured, we can read the "high"
* register again.
* Workaround: Read TXSTMPH_0 here to enable future interrupts.
* However, this read clears TXTT_0. If a timestamp arrives in
* register 0 after checking TXTT_0 but before this read, it
* would be lost.
*
* To detect this race: We saved a baseline read of TXSTMPL_0
* before TXTT_0 check. After performing the workaround read of
* TXSTMPH_0, we read TXSTMPL_0 again. Since consecutive
* timestamps never share the same nanosecond value, a change
* between the baseline and new TXSTMPL_0 indicates a timestamp
* arrived during the race window. If so, read the complete
* timestamp.
*/
u32 txstmpl_old, txstmpl_new;
u32 txstmpl_new;
txstmpl_old = rd32(IGC_TXSTMPL);
rd32(IGC_TXSTMPH);
txstmpl_new = rd32(IGC_TXSTMPL);
@ -818,7 +825,7 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
done:
/* Now that the problematic first register was handled, we can
* use retrieve the timestamps from the other registers
* retrieve the timestamps from the other registers
* (starting from '1') with less complications.
*/
for (i = 1; i < IGC_MAX_TX_TSTAMP_REGS; i++) {