From: Marcin Szycik <marcin.szycik@linux.intel.com>
To: Jacob Keller <jacob.e.keller@intel.com>,
Intel Wired LAN <intel-wired-lan@lists.osuosl.org>,
Grzegorz Nitka <grzegorz.nitka@intel.com>,
Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>,
Przemek Kitszel <przemyslaw.kitszel@intel.com>,
Aleksandr Loktionov <aleksandr.loktionov@intel.com>,
Przemyslaw Korba <przemyslaw.korba@intel.com>,
Anthony Nguyen <anthony.l.nguyen@intel.com>
Cc: netdev@vger.kernel.org
Subject: Re: [Intel-wired-lan] [PATCH iwl-net] ice: fix E810 low latency timestamp interrupt handling
Date: Tue, 2 Jun 2026 12:15:21 +0200 [thread overview]
Message-ID: <961dca76-3025-45a4-b11e-0ee8f241d290@linux.intel.com> (raw)
In-Reply-To: <20260529-jk-fix-e810-ll-interface-function-v1-1-ec84a408af7e@intel.com>
On 29/05/2026 22:22, Jacob Keller wrote:
> The driver has supported a low latency timestamp interface since commit
> 82e71b226e0e ("ice: Enable SW interrupt from FW for LL TS").
>
> This interface is triggered by calling ice_ptp_req_tx_single_tstamp(),
> which is called by ice_ptp_ts_irq(), which in turn is called when the
> driver gets an interrupt from hardware indicating that a timestamp is
> available.
>
> This function doesn't check if a timestamp request is already in progress,
> and as a result could trash an existing outstanding requests when called.
> It turns out that this is unlikely in practice due to a number of
> circumstances that prevent most of the ways that could happen.
>
> 1. The ice_misc_intr_thread_fn() might trigger a software-generated
> interrupt with the PFINT_OICR_TSYN_TX flag. However, we don't enter the
> thread function since ice_ptp_ts_irq() always returns IRQ_HANDLED for
> E810 devices which support the low latency firmware interface.
>
> 2. The ice_ptp_maybe_trigger_tx_interrupt() function might trigger a
> software-generated interrupt if it detects waiting timetstamps. However
> it checks ptp.port.tx.has_ready_bitmap which is always false for E810,
> so never enters the code path.
>
> However, it is still possible that another Tx timestamp request could
> happen and complete and race with the firmware completing the outstanding
> low latency timestamp request.
>
> This doesn't happen often in practice because many applications only
> trigger a single outstanding Tx timestamp at once. However, if the user
> runs multiple copies of ptp4l or uses other userspace stack which does,
> they might miss timestamps or get corrupted timestamp data.
>
> To fix this, have the ice_ptp_req_tX_single_tstamp() function check and
> only begin the operation if the ATQBAL_FLAGS_INTR_IN_PROGRESS flag was not
> yet set. This prevents a new possible request from trashing an outstanding
> request. Note that on completion of a request, the ice_ll_ts_intr()
> function will initiate a request for the next outstanding timestamp, so no
> timestamps will be lost.
>
> Additionally, although the ice_ptp_tx_tstamps_pending() function doesn't
> currently get called for E810 devices, it should still not return true for
> devices which support the low latency interrupt. If for some reason code is
> refactored and the miscellaneous thread function does execute, it should
> not trigger a new software interrupt for devices using the low latency
> interrupt interface. Add an explicit check to make this function always
> return false when the device is operating in this mode.
>
> Finally, convert the atqbal_flags to DECLARE_BITMAP and use test/set bit
> functions. This helps in clarity as we can use test_and_set_bit and
> test_and_clear_bit.
>
> Fixes: 82e71b226e0e ("ice: Enable SW interrupt from FW for LL TS")
> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed-by: Marcin Szycik <marcin.szycik@linux.intel.com>
+ some nits
> ---
> This was originally motivated by changes in our out-of-tree release where
> the issue of a software-generated interrupt was causing significantly more
> issues. After further investigation it seems that the upstream
> implementation is more robust, preventing the thread function from running
> for E810. However, there appears to be a small window where issues can crop
> up if multiple outstanding timestamps are requested near concurrently. This
> change is motivated at closing that gap and ensuring consistency of
> timestamps returned through the low latency interface.
>
> To trigger the issue you will need to issue multiple Tx timestamp requests
> near but not quite simultaneously, and it may be quite a rare race
> condition.
> ---
> drivers/net/ethernet/intel/ice/ice_type.h | 8 ++++++--
> drivers/net/ethernet/intel/ice/ice_ptp.c | 24 +++++++++++++++++++-----
> drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 12 ++++++------
> 3 files changed, 31 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
> index 1e82f4c40b32..7035ea6c59db 100644
> --- a/drivers/net/ethernet/intel/ice/ice_type.h
> +++ b/drivers/net/ethernet/intel/ice/ice_type.h
> @@ -859,12 +859,16 @@ struct ice_mbx_data {
> #define ICE_PORTS_PER_QUAD 4
> #define ICE_GET_QUAD_NUM(port) ((port) / ICE_PORTS_PER_QUAD)
>
> -#define ATQBAL_FLAGS_INTR_IN_PROGRESS BIT(0)
> +enum ice_atqbal_flags {
> + ATQBAL_FLAGS_INTR_IN_PROGRESS,
> +
> + ATQBAL_FLAGS_NBITS, /* must be last */
Nit: no comma
> +};
>
> struct ice_e810_params {
> /* The wait queue lock also protects the low latency interface */
> wait_queue_head_t atqbal_wq;
> - unsigned int atqbal_flags;
> + DECLARE_BITMAP(atqbal_flags, ATQBAL_FLAGS_NBITS);
> };
>
> struct ice_eth56g_params {
> diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
> index 36df742c326c..11059deb5d41 100644
> --- a/drivers/net/ethernet/intel/ice/ice_ptp.c
> +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
> @@ -382,6 +382,7 @@ void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
> struct ice_ptp_port *ptp_port;
> unsigned long flags;
> struct sk_buff *skb;
> + struct device *dev;
> struct ice_pf *pf;
>
> if (!tx->init)
> @@ -389,6 +390,7 @@ void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
>
> ptp_port = container_of(tx, struct ice_ptp_port, tx);
> pf = ptp_port_to_pf(ptp_port);
> + dev = ice_pf_to_dev(pf);
> params = &pf->hw.ptp.phy.e810;
>
> /* Drop packets which have waited for more than 2 seconds */
> @@ -408,7 +410,13 @@ void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
>
> spin_lock_irqsave(¶ms->atqbal_wq.lock, flags);
>
> - params->atqbal_flags |= ATQBAL_FLAGS_INTR_IN_PROGRESS;
> + if (test_and_set_bit(ATQBAL_FLAGS_INTR_IN_PROGRESS,
> + params->atqbal_flags)) {
> + dev_dbg(dev, "%s: low latency interrupt request already in progress?\n",
Why the '?', are we not certain it's in progress?
> + __func__);
> + spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
> + return;
Nit: could be an unroll.
> + }
>
> /* Write TS index to read to the PF register so the FW can read it */
> wr32(&pf->hw, REG_LL_PROXY_H,
> @@ -449,7 +457,8 @@ void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx)
>
> spin_lock_irqsave(¶ms->atqbal_wq.lock, flags);
>
> - if (!(params->atqbal_flags & ATQBAL_FLAGS_INTR_IN_PROGRESS))
> + if (!test_and_clear_bit(ATQBAL_FLAGS_INTR_IN_PROGRESS,
> + params->atqbal_flags))
> dev_dbg(dev, "%s: low latency interrupt request not in progress?\n",
> __func__);
>
> @@ -459,8 +468,6 @@ void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx)
> reg_ll_high = rd32(&pf->hw, REG_LL_PROXY_H);
>
> /* Wake up threads waiting on low latency interface */
> - params->atqbal_flags &= ~ATQBAL_FLAGS_INTR_IN_PROGRESS;
> -
> wake_up_locked(¶ms->atqbal_wq);
>
> spin_unlock_irqrestore(¶ms->atqbal_wq.lock, flags);
> @@ -2712,7 +2719,14 @@ bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf)
> struct ice_hw *hw = &pf->hw;
> int ret;
>
> - /* Check software indicator */
> + /* E810 devices with support for the low latency timestamp interrupt
> + * have specialized handling for timestamps. They should not
> + * re-schedule the miscellaneous interrupt.
> + */
> + if (hw->mac_type == ICE_MAC_E810 &&
> + hw->dev_caps.ts_dev_info.ts_ll_int_read)
> + return false;
> +
> switch (pf->ptp.tx_interrupt_mode) {
> case ICE_PTP_TX_INTERRUPT_NONE:
> return false;
> diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
> index 2c18e16fe053..02d4cc942c8d 100644
> --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
> +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c
> @@ -4521,8 +4521,8 @@ ice_read_phy_tstamp_ll_e810(struct ice_hw *hw, u8 idx, u8 *hi, u32 *lo)
>
> /* Wait for any pending in-progress low latency interrupt */
> err = wait_event_interruptible_locked_irq(params->atqbal_wq,
> - !(params->atqbal_flags &
> - ATQBAL_FLAGS_INTR_IN_PROGRESS));
> + !test_bit(ATQBAL_FLAGS_INTR_IN_PROGRESS,
> + params->atqbal_flags));
> if (err) {
> spin_unlock_irq(¶ms->atqbal_wq.lock);
> return err;
> @@ -4754,8 +4754,8 @@ static int ice_ptp_prep_phy_adj_ll_e810(struct ice_hw *hw, s32 adj)
>
> /* Wait for any pending in-progress low latency interrupt */
> err = wait_event_interruptible_locked_irq(params->atqbal_wq,
> - !(params->atqbal_flags &
> - ATQBAL_FLAGS_INTR_IN_PROGRESS));
> + !test_bit(ATQBAL_FLAGS_INTR_IN_PROGRESS,
> + params->atqbal_flags));
> if (err) {
> spin_unlock_irq(¶ms->atqbal_wq.lock);
> return err;
> @@ -4846,8 +4846,8 @@ static int ice_ptp_prep_phy_incval_ll_e810(struct ice_hw *hw, u64 incval)
>
> /* Wait for any pending in-progress low latency interrupt */
> err = wait_event_interruptible_locked_irq(params->atqbal_wq,
> - !(params->atqbal_flags &
> - ATQBAL_FLAGS_INTR_IN_PROGRESS));
> + !test_bit(ATQBAL_FLAGS_INTR_IN_PROGRESS,
> + params->atqbal_flags));
> if (err) {
> spin_unlock_irq(¶ms->atqbal_wq.lock);
> return err;
>
> ---
> base-commit: 2412591cfe66e681374c5265e691695cd913d099
> change-id: 20260528-jk-fix-e810-ll-interface-function-5dad155217d8
>
> Best regards,
> --
> Jacob Keller <jacob.e.keller@intel.com>
>
>
next prev parent reply other threads:[~2026-06-02 10:15 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-29 20:22 [PATCH iwl-net] ice: fix E810 low latency timestamp interrupt handling Jacob Keller
2026-06-02 10:15 ` Marcin Szycik [this message]
2026-06-02 23:54 ` [Intel-wired-lan] " Jacob Keller
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=961dca76-3025-45a4-b11e-0ee8f241d290@linux.intel.com \
--to=marcin.szycik@linux.intel.com \
--cc=aleksandr.loktionov@intel.com \
--cc=anthony.l.nguyen@intel.com \
--cc=arkadiusz.kubalewski@intel.com \
--cc=grzegorz.nitka@intel.com \
--cc=intel-wired-lan@lists.osuosl.org \
--cc=jacob.e.keller@intel.com \
--cc=netdev@vger.kernel.org \
--cc=przemyslaw.kitszel@intel.com \
--cc=przemyslaw.korba@intel.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